1
0
forked from cgvr/DeltaVR

Initial Commit

This commit is contained in:
Toomas Tamm
2020-11-28 16:54:41 +02:00
parent 97292ee26e
commit ea967135f2
4217 changed files with 2945663 additions and 0 deletions

View File

@@ -0,0 +1,213 @@
namespace Oculus.Platform.Samples.VrVoiceChat
{
using UnityEngine;
using System;
using Oculus.Platform;
using Oculus.Platform.Models;
// Helper class to manage a Peer-to-Peer connection to the other user.
// The connection is used to send and received the Transforms for the
// Avatars. The Transforms are sent via unreliable UDP at a fixed
// frequency.
public class P2PManager
{
// number of seconds to delay between transform updates
private static readonly float UPDATE_DELAY = 0.1f;
// the ID of the remote player we expect to be connected to
private ulong m_remoteID;
// the result of the last connection state update message
private PeerConnectionState m_state = PeerConnectionState.Unknown;
// the next time to send an updated transform to the remote User
private float m_timeForNextUpdate;
// the size of the packet we are sending and receiving
private static readonly byte PACKET_SIZE = 29;
// packet format type just in case we want to add new future packet types
private static readonly byte PACKET_FORMAT = 0;
// reusable buffer to serialize the Transform into
private readonly byte[] sendTransformBuffer = new byte[PACKET_SIZE];
// reusable buffer to deserialize the Transform into
private readonly byte[] receiveTransformBuffer = new byte[PACKET_SIZE];
// the last received position update
private Vector3 receivedPosition;
// the previous received position to interpolate from
private Vector3 receivedPositionPrior;
// the last received rotation update
private Quaternion receivedRotation;
// the previous received rotation to interpolate from
private Quaternion receivedRotationPrior;
// when the last transform was received
private float receivedTime;
public P2PManager(Transform initialHeadTransform)
{
receivedPositionPrior = receivedPosition = initialHeadTransform.localPosition;
receivedRotationPrior = receivedRotation = initialHeadTransform.localRotation;
Net.SetPeerConnectRequestCallback(PeerConnectRequestCallback);
Net.SetConnectionStateChangedCallback(ConnectionStateChangedCallback);
}
#region Connection Management
public void ConnectTo(ulong userID)
{
m_remoteID = userID;
// ID comparison is used to decide who calls Connect and who calls Accept
if (PlatformManager.MyID < userID)
{
Net.Connect(userID);
}
}
public void Disconnect()
{
if (m_remoteID != 0)
{
Net.Close(m_remoteID);
m_remoteID = 0;
m_state = PeerConnectionState.Unknown;
}
}
public bool Connected
{
get
{
return m_state == PeerConnectionState.Connected;
}
}
void PeerConnectRequestCallback(Message<NetworkingPeer> msg)
{
Debug.LogFormat("Connection request from {0}, authorized is {1}", msg.Data.ID, m_remoteID);
if (msg.Data.ID == m_remoteID)
{
Net.Accept(msg.Data.ID);
}
}
void ConnectionStateChangedCallback(Message<NetworkingPeer> msg)
{
Debug.LogFormat("Connection state to {0} changed to {1}", msg.Data.ID, msg.Data.State);
if (msg.Data.ID == m_remoteID)
{
m_state = msg.Data.State;
if (m_state == PeerConnectionState.Timeout &&
// ID comparison is used to decide who calls Connect and who calls Accept
PlatformManager.MyID < m_remoteID)
{
// keep trying until hangup!
Net.Connect(m_remoteID);
}
}
PlatformManager.SetBackgroundColorForState();
}
#endregion
#region Send Update
public bool ShouldSendHeadUpdate
{
get
{
return Time.time >= m_timeForNextUpdate && m_state == PeerConnectionState.Connected;
}
}
public void SendHeadTransform(Transform headTransform)
{
m_timeForNextUpdate = Time.time + UPDATE_DELAY;
sendTransformBuffer[0] = PACKET_FORMAT;
int offset = 1;
PackFloat(headTransform.localPosition.x, sendTransformBuffer, ref offset);
PackFloat(headTransform.localPosition.y, sendTransformBuffer, ref offset);
PackFloat(headTransform.localPosition.z, sendTransformBuffer, ref offset);
PackFloat(headTransform.localRotation.x, sendTransformBuffer, ref offset);
PackFloat(headTransform.localRotation.y, sendTransformBuffer, ref offset);
PackFloat(headTransform.localRotation.z, sendTransformBuffer, ref offset);
PackFloat(headTransform.localRotation.w, sendTransformBuffer, ref offset);
Net.SendPacket(m_remoteID, sendTransformBuffer, SendPolicy.Unreliable);
}
void PackFloat(float f, byte[] buf, ref int offset)
{
Buffer.BlockCopy(BitConverter.GetBytes(f), 0, buf, offset, 4);
offset = offset + 4;
}
#endregion
#region Receive Update
public void GetRemoteHeadTransform(Transform headTransform)
{
bool hasNewTransform = false;
Packet packet;
while ((packet = Net.ReadPacket()) != null)
{
if (packet.Size != PACKET_SIZE)
{
Debug.Log("Invalid packet size: " + packet.Size);
continue;
}
packet.ReadBytes(receiveTransformBuffer);
if (receiveTransformBuffer[0] != PACKET_FORMAT)
{
Debug.Log("Invalid packet type: " + packet.Size);
continue;
}
hasNewTransform = true;
}
if (hasNewTransform)
{
receivedPositionPrior = receivedPosition;
receivedPosition.x = BitConverter.ToSingle(receiveTransformBuffer, 1);
receivedPosition.y = BitConverter.ToSingle(receiveTransformBuffer, 5);
receivedPosition.z = BitConverter.ToSingle(receiveTransformBuffer, 9);
receivedRotationPrior = receivedRotation;
receivedRotation.x = BitConverter.ToSingle(receiveTransformBuffer, 13);
receivedRotation.y = BitConverter.ToSingle(receiveTransformBuffer, 17) * -1.0f;
receivedRotation.z = BitConverter.ToSingle(receiveTransformBuffer, 21);
receivedRotation.w = BitConverter.ToSingle(receiveTransformBuffer, 25) * -1.0f;
receivedTime = Time.time;
}
// since we're receiving updates at a slower rate than we render,
// interpolate to make the motion look smoother
float completed = Math.Min(Time.time - receivedTime, UPDATE_DELAY) / UPDATE_DELAY;
headTransform.localPosition =
Vector3.Lerp(receivedPositionPrior, receivedPosition, completed);
headTransform.localRotation =
Quaternion.Slerp(receivedRotationPrior, receivedRotation, completed);
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f0b2606dc17092048b00d7388d73fbb5
timeCreated: 1474493601
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,307 @@
namespace Oculus.Platform.Samples.VrVoiceChat
{
using UnityEngine;
using UnityEngine.UI;
using System.Collections.Generic;
using Oculus.Platform;
using Oculus.Platform.Models;
// This class coordinates communication with the Oculus Platform
// Service running in your device.
public class PlatformManager : MonoBehaviour
{
// the game object to build the invite list in
[SerializeField] private GameObject m_invitesList = null;
// Button to create for the user to answer an invite call
[SerializeField] private GameObject m_invitePrefab = null;
// State transition sets the background color as a visual status indication
[SerializeField] private Camera m_camera = null;
// GameObject that represents the Head of the remote Avatar
[SerializeField] private GameObject m_remoteHead = null;
private State m_currentState;
private static PlatformManager s_instance = null;
private RoomManager m_roomManager;
private P2PManager m_p2pManager;
private VoipManager m_voipManager;
// my Application-scoped Oculus ID
private ulong m_myID;
// my Oculus user name
private string m_myOculusID;
void Update()
{
// occasionally poll for new call invites
if (m_roomManager.ShouldPollInviteList)
{
m_roomManager.UpdateActiveInvitesList();
}
// occasionally send my transform to my interlocutor
if (m_p2pManager.ShouldSendHeadUpdate)
{
m_p2pManager.SendHeadTransform(m_camera.transform);
}
// estimate the remote avatar transforms from the most recent network update
m_p2pManager.GetRemoteHeadTransform(m_remoteHead.transform);
}
#region Initialization and Shutdown
void Awake()
{
// make sure only one instance of this manager ever exists
if (s_instance != null) {
Destroy(gameObject);
return;
}
s_instance = this;
DontDestroyOnLoad(gameObject);
TransitionToState(State.INITIALIZING);
Core.Initialize();
m_roomManager = new RoomManager();
m_p2pManager = new P2PManager(m_remoteHead.transform);
m_voipManager = new VoipManager(m_remoteHead);
}
void Start ()
{
// First thing we should do is perform an entitlement check to make sure
// we successfully connected to the Oculus Platform Service.
Entitlements.IsUserEntitledToApplication().OnComplete(IsEntitledCallback);
}
void IsEntitledCallback(Message msg)
{
if (msg.IsError)
{
TerminateWithError(msg);
return;
}
// Next get the identity of the user that launched the Application.
Users.GetLoggedInUser().OnComplete(GetLoggedInUserCallback);
}
void GetLoggedInUserCallback(Message<User> msg)
{
if (msg.IsError)
{
TerminateWithError(msg);
return;
}
m_myID = msg.Data.ID;
m_myOculusID = msg.Data.OculusID;
TransitionToState(State.WAITING_TO_CALL_OR_ANSWER);
// If the user launched the app by accepting the notification, then we want to
// join that room. Otherwise, start polling for invites.
m_roomManager.CheckForLaunchInvite();
}
void OnApplicationQuit()
{
m_roomManager.LeaveCurrentRoom();
m_p2pManager.Disconnect();
m_voipManager.Disconnect();
}
// For most errors we terminate the Application since this example doesn't make
// sense if the user is disconnected.
public static void TerminateWithError(Message msg)
{
Debug.Log("Error: " + msg.GetError().Message);
UnityEngine.Application.Quit();
}
#endregion
#region Properties
public static State CurrentState
{
get
{
return s_instance.m_currentState;
}
}
public static ulong MyID
{
get
{
if (s_instance != null)
{
return s_instance.m_myID;
}
else
{
return 0;
}
}
}
public static string MyOculusID
{
get
{
if (s_instance != null && s_instance.m_myOculusID != null)
{
return s_instance.m_myOculusID;
}
else
{
return string.Empty;
}
}
}
#endregion
#region Button Clicks
public void CallFriendOnClick()
{
if (CurrentState == State.WAITING_TO_CALL_OR_ANSWER)
{
m_roomManager.CreateRoomAndLaunchInviteMenu();
}
}
public void HangupOnClick()
{
m_roomManager.LeaveCurrentRoom();
}
public void QuitOnClick()
{
UnityEngine.Application.Quit();
}
public static void AnswerCallOnClick(ulong roomID)
{
if (s_instance)
{
s_instance.m_roomManager.JoinExistingRoom(roomID);
}
}
#endregion
#region State Management
public enum State
{
// loading platform library, checking application entitlement,
// getting the local user info
INITIALIZING,
// waiting on the user to invite a friend to chat, or
// accept an invite sent to them
WAITING_TO_CALL_OR_ANSWER,
// in this state we've create a room, and hopefully
// sent some invites, and we're waiting for a response
WAITING_FOR_ANSWER,
// we're in a room as the caller or the callee
CONNECTED_IN_A_ROOM,
// shutdown any connections and leave the current room
HANGUP,
};
public static void TransitionToState(State newState)
{
Debug.LogFormat("State {0} -> {1}", s_instance.m_currentState, newState);
if (s_instance && s_instance.m_currentState != newState)
{
s_instance.m_currentState = newState;
// state transition logic
switch (newState)
{
case State.HANGUP:
s_instance.m_roomManager.LeaveCurrentRoom();
s_instance.m_p2pManager.Disconnect();
s_instance.m_voipManager.Disconnect();
break;
case State.WAITING_TO_CALL_OR_ANSWER:
break;
case State.CONNECTED_IN_A_ROOM:
s_instance.m_p2pManager.ConnectTo(s_instance.m_roomManager.RemoteUserID);
s_instance.m_voipManager.ConnectTo(s_instance.m_roomManager.RemoteUserID);
break;
}
}
// set the background color as a visual aid to the connection status
SetBackgroundColorForState();
}
public static void SetBackgroundColorForState()
{
switch (s_instance.m_currentState)
{
case State.INITIALIZING:
case State.HANGUP:
s_instance.m_camera.backgroundColor = Color.black;
break;
case State.WAITING_TO_CALL_OR_ANSWER:
s_instance.m_camera.backgroundColor = new Color(0f, 0f, .3f);
break;
case State.WAITING_FOR_ANSWER:
s_instance.m_camera.backgroundColor = new Color(0, 0, .6f);
break;
case State.CONNECTED_IN_A_ROOM:
float red = s_instance.m_p2pManager.Connected ? 1.0f : 0;
float green = s_instance.m_voipManager.Connected ? 1.0f : 0;
s_instance.m_camera.backgroundColor = new Color(red, green, 1.0f);
break;
}
}
public static void SetActiveInvites(List<RoomManager.Invite> invites)
{
if (s_instance && s_instance.m_invitesList && s_instance.m_invitePrefab)
{
// first remove all existing Invites
foreach (Transform child in s_instance.m_invitesList.transform)
{
Destroy(child.gameObject);
}
foreach (var invite in invites)
{
GameObject button = Instantiate(s_instance.m_invitePrefab) as GameObject;
button.GetComponentInChildren<Text>().text = invite.OwnerID;
button.name = invite.RoomID.ToString();
button.GetComponent<Button>().onClick.AddListener(
() => PlatformManager.AnswerCallOnClick(invite.RoomID));
button.transform.SetParent(s_instance.m_invitesList.transform, false);
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ffdbd4c8c89d94aae95321b8d5850c7a
timeCreated: 1474236709
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,316 @@
namespace Oculus.Platform.Samples.VrVoiceChat
{
using UnityEngine;
using System;
using System.Collections.Generic;
using Oculus.Platform;
using Oculus.Platform.Models;
// Helper class to manage Room creation, membership and invites.
// Rooms are a mechanism to help Oculus users create a shared experience.
// Users can only be in one Room at a time. If the Owner of a room
// leaves, then ownership is transferred to some other member.
// Here we use rooms to create the notion of a 'call' to help us
// invite a Friend and establish a VOIP and P2P connection.
public class RoomManager
{
// the ID of the Room that I'm in
private ulong m_roomID;
// the other User in the Room
private User m_remoteUser;
// how often I should poll for invites
private static readonly float INVITE_POLL_FREQ_SECONDS = 5.0f;
// the next time I should poll Oculus Platform for valid Room Invite requests
private float m_nextPollTime;
public struct Invite
{
public readonly ulong RoomID;
public readonly string OwnerID;
public Invite(ulong roomID, string owner)
{
this.RoomID = roomID;
this.OwnerID = owner;
}
}
// cached list of rooms that I've been invited to and I'm waiting
// for more information about
private HashSet<ulong> m_pendingRoomRequests;
// accumulation list of room invites and the room owner
private List<Invite> m_invites;
public RoomManager()
{
Rooms.SetRoomInviteAcceptedNotificationCallback(LaunchedFromAcceptingInviteCallback);
Rooms.SetUpdateNotificationCallback(RoomUpdateCallback);
}
public ulong RemoteUserID
{
get
{
return m_remoteUser != null ? m_remoteUser.ID : 0;
}
}
public String RemoteOculusID
{
get
{
return m_remoteUser != null ? m_remoteUser.OculusID : String.Empty;
}
}
#region Launched Application from Accepting Invite
// Callback to check whether the User accepted the invite as
// a notification which caused the Application to launch. If so, then
// we know we need to try to join that room.
void LaunchedFromAcceptingInviteCallback(Message<string> msg)
{
if (msg.IsError)
{
PlatformManager.TerminateWithError(msg);
return;
}
Debug.Log("Launched Invite to join Room: " + msg.Data);
m_roomID = Convert.ToUInt64(msg.GetString());
}
// Check to see if the App was launched by accepting the Notication from the main Oculus app.
// If so, we can directly join that room. (If it's still available.)
public bool CheckForLaunchInvite()
{
if (m_roomID != 0)
{
JoinExistingRoom(m_roomID);
return true;
}
else
{
return false;
}
}
#endregion
#region Create a Room and Invite Friend(s) from the Oculus Universal Menu
public void CreateRoomAndLaunchInviteMenu()
{
Rooms.CreateAndJoinPrivate(RoomJoinPolicy.InvitedUsers, 2, true)
.OnComplete(CreateAndJoinPrivateRoomCallback);
}
void CreateAndJoinPrivateRoomCallback(Message<Room> msg)
{
if (msg.IsError)
{
PlatformManager.TerminateWithError(msg);
return;
}
m_roomID = msg.Data.ID;
m_remoteUser = null;
PlatformManager.TransitionToState(PlatformManager.State.WAITING_FOR_ANSWER);
// launch the Room Invite workflow in the Oculus Univeral Menu
Rooms.LaunchInvitableUserFlow(m_roomID).OnComplete(OnLaunchInviteWorkflowComplete);
}
void OnLaunchInviteWorkflowComplete(Message msg)
{
if (msg.IsError)
{
PlatformManager.TerminateWithError(msg);
return;
}
}
#endregion
#region Polling for Invites
public bool ShouldPollInviteList
{
get
{
return m_pendingRoomRequests == null && Time.time >= m_nextPollTime;
}
}
public void UpdateActiveInvitesList()
{
m_nextPollTime = Time.time + INVITE_POLL_FREQ_SECONDS;
m_pendingRoomRequests = new HashSet<ulong>();
m_invites = new List<Invite>();
Notifications.GetRoomInviteNotifications().OnComplete(GetRoomInviteNotificationsCallback);
}
// task 13572454: add the type to callback definition
void GetRoomInviteNotificationsCallback(Message msg_untyped)
{
Message<RoomInviteNotificationList> msg = (Message<RoomInviteNotificationList>)msg_untyped;
if (msg.IsError)
{
PlatformManager.TerminateWithError(msg);
return;
}
// loop over all the rooms we're invited to and request more info
foreach (RoomInviteNotification invite in msg.Data)
{
m_pendingRoomRequests.Add(invite.RoomID);
Rooms.Get(invite.RoomID).OnComplete(GetRoomInfoCallback);
}
if (msg.Data.Count == 0)
{
m_pendingRoomRequests = null;
PlatformManager.SetActiveInvites(m_invites);
}
}
void GetRoomInfoCallback(Message<Room> msg)
{
if (msg.IsError)
{
PlatformManager.TerminateWithError(msg);
return;
}
if (msg.Data.OwnerOptional != null)
{
Invite invite = new Invite(msg.Data.ID, msg.Data.OwnerOptional.OculusID);
m_pendingRoomRequests.Remove(invite.RoomID);
// make sure the room still looks usable
// (e.g. they aren't currently talking to someone)
if (msg.Data.UsersOptional != null && msg.Data.UsersOptional.Count == 1)
{
m_invites.Add(invite);
}
}
// once we're received all the room info, let the platform update
// its display
if (m_pendingRoomRequests.Count == 0)
{
m_pendingRoomRequests = null;
PlatformManager.SetActiveInvites(m_invites);
}
}
#endregion
#region Accept Invite
public void JoinExistingRoom(ulong roomID)
{
Rooms.Join(roomID, true).OnComplete(JoinRoomCallback);
}
void JoinRoomCallback(Message<Room> msg)
{
if (msg.IsError)
{
// is reasonable if caller called more than 1 person, and I didn't answer first
return;
}
string oculusOwnerID = msg.Data.OwnerOptional != null ? msg.Data.OwnerOptional.OculusID : "";
int numUsers = msg.Data.UsersOptional != null ? msg.Data.UsersOptional.Count : 0;
Debug.LogFormat("Joined room: {0} owner: {1} count: ",
msg.Data.ID, oculusOwnerID, numUsers);
m_roomID = msg.Data.ID;
// if the caller left while I was in the process of joining, just hangup
if (msg.Data.UsersOptional == null || msg.Data.UsersOptional.Count != 2)
{
PlatformManager.TransitionToState(PlatformManager.State.HANGUP);
}
else
{
foreach (User user in msg.Data.UsersOptional)
{
if (user.ID != PlatformManager.MyID)
{
m_remoteUser = user;
}
}
PlatformManager.TransitionToState(PlatformManager.State.CONNECTED_IN_A_ROOM);
}
// update the invite list sooner
m_nextPollTime = Time.time;
}
#endregion
#region Room Updates
void RoomUpdateCallback(Message<Room> msg)
{
if (msg.IsError)
{
PlatformManager.TerminateWithError(msg);
return;
}
string oculusOwnerID = msg.Data.OwnerOptional != null ? msg.Data.OwnerOptional.OculusID : "";
int numUsers = msg.Data.UsersOptional != null ? msg.Data.UsersOptional.Count : 0;
Debug.LogFormat("Room {0} Update: {1} owner: {2} count: ",
msg.Data.ID, oculusOwnerID, numUsers);
// if the Room count is not 2 then the other party has left.
// We'll just hangup the connection here.
// If the other User created then room, ownership would switch to me.
if (msg.Data.UsersOptional == null || msg.Data.UsersOptional.Count != 2)
{
PlatformManager.TransitionToState(PlatformManager.State.HANGUP);
}
else
{
foreach (User user in msg.Data.UsersOptional)
{
if (user.ID != PlatformManager.MyID)
{
m_remoteUser = user;
}
}
PlatformManager.TransitionToState(PlatformManager.State.CONNECTED_IN_A_ROOM);
}
}
#endregion
#region Room Exit
public void LeaveCurrentRoom()
{
if (m_roomID != 0)
{
Rooms.Leave(m_roomID);
m_roomID = 0;
m_remoteUser = null;
}
PlatformManager.TransitionToState(PlatformManager.State.WAITING_TO_CALL_OR_ANSWER);
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: ea89826bdbe52462fb0102692abb3032
timeCreated: 1474235953
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,44 @@
namespace Oculus.Platform.Samples.VrVoiceChat
{
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
// Helper class to attach to the main camera that raycasts where the
// user is looking to select/deselect Buttons.
public class VREyeRaycaster : MonoBehaviour
{
[SerializeField] private UnityEngine.EventSystems.EventSystem m_eventSystem = null;
private Button m_currentButton;
void Update ()
{
RaycastHit hit;
Button button = null;
// do a forward raycast to see if we hit a Button
if (Physics.Raycast(transform.position, transform.forward, out hit, 50f))
{
button = hit.collider.GetComponent<Button>();
}
if (button != null)
{
if (m_currentButton != button)
{
m_currentButton = button;
m_currentButton.Select();
}
}
else if (m_currentButton != null)
{
m_currentButton = null;
if (m_eventSystem != null)
{
m_eventSystem.SetSelectedGameObject(null);
}
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 5a66c6bd0ba312c4b8c6fd2a08491521
timeCreated: 1473882274
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,93 @@
namespace Oculus.Platform.Samples.VrVoiceChat
{
using UnityEngine;
using System.Collections;
using Oculus.Platform;
using Oculus.Platform.Models;
// Helper class to manage the Voice-over-IP connection to the
// remote user
public class VoipManager
{
// the ID of the remote user I expect to talk to
private ulong m_remoteID;
// the last reported state of the VOIP connection
private PeerConnectionState m_state = PeerConnectionState.Unknown;
// the GameObject where the remote VOIP will project from
private readonly GameObject m_remoteHead;
public VoipManager(GameObject remoteHead)
{
m_remoteHead = remoteHead;
Voip.SetVoipConnectRequestCallback(VoipConnectRequestCallback);
Voip.SetVoipStateChangeCallback(VoipStateChangedCallback);
}
public void ConnectTo(ulong userID)
{
m_remoteID = userID;
var audioSource = m_remoteHead.AddComponent<VoipAudioSourceHiLevel>();
audioSource.senderID = userID;
// ID comparison is used to decide who initiates and who gets the Callback
if (PlatformManager.MyID < m_remoteID)
{
Voip.Start(userID);
}
}
public void Disconnect()
{
if (m_remoteID != 0)
{
Voip.Stop(m_remoteID);
Object.Destroy(m_remoteHead.GetComponent<VoipAudioSourceHiLevel>(), 0);
m_remoteID = 0;
m_state = PeerConnectionState.Unknown;
}
}
public bool Connected
{
get
{
return m_state == PeerConnectionState.Connected;
}
}
void VoipConnectRequestCallback(Message<NetworkingPeer> msg)
{
Debug.LogFormat("Voip request from {0}, authorized is {1}", msg.Data.ID, m_remoteID);
if (msg.Data.ID == m_remoteID)
{
Voip.Accept(msg.Data.ID);
}
}
void VoipStateChangedCallback(Message<NetworkingPeer> msg)
{
Debug.LogFormat("Voip state to {0} changed to {1}", msg.Data.ID, msg.Data.State);
if (msg.Data.ID == m_remoteID)
{
m_state = msg.Data.State;
if (m_state == PeerConnectionState.Timeout &&
// ID comparison is used to decide who initiates and who gets the Callback
PlatformManager.MyID < m_remoteID)
{
// keep trying until hangup!
Voip.Start(m_remoteID);
}
}
PlatformManager.SetBackgroundColorForState();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 310e9262e28564c9d9b5c5a872a42e41
timeCreated: 1474561098
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: