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 m_pendingRoomRequests; // accumulation list of room invites and the room owner private List 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 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 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(); m_invites = new List(); Notifications.GetRoomInviteNotifications().OnComplete(GetRoomInviteNotificationsCallback); } // task 13572454: add the type to callback definition void GetRoomInviteNotificationsCallback(Message msg_untyped) { Message msg = (Message)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 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 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 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 } }