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
|
|
}
|
|
}
|