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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 87b4b10d999b6314da1b1d758d7e3b3d
timeCreated: 1473692398
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e8c7a22afb9692c40a32cf6e9d60b1e8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,230 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &100100000
Prefab:
m_ObjectHideFlags: 1
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications: []
m_RemovedComponents: []
m_ParentPrefab: {fileID: 0}
m_RootGameObject: {fileID: 1000011515193694}
m_IsPrefabParent: 1
--- !u!1 &1000011515193694
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 224000012138174124}
- component: {fileID: 222000011973359602}
- component: {fileID: 114000011589085632}
- component: {fileID: 114000010301516032}
- component: {fileID: 114000014144135060}
- component: {fileID: 65000013322816928}
m_Layer: 5
m_Name: SelectFriendButton
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!1 &1000011951986632
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 224000012115001870}
- component: {fileID: 222000010453829726}
- component: {fileID: 114000013055439172}
m_Layer: 5
m_Name: Text
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!65 &65000013322816928
BoxCollider:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011515193694}
m_Material: {fileID: 0}
m_IsTrigger: 0
m_Enabled: 1
serializedVersion: 2
m_Size: {x: 160, y: 30, z: 1}
m_Center: {x: 0, y: 0, z: 0}
--- !u!114 &114000010301516032
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011515193694}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1392445389, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Navigation:
m_Mode: 3
m_SelectOnUp: {fileID: 0}
m_SelectOnDown: {fileID: 0}
m_SelectOnLeft: {fileID: 0}
m_SelectOnRight: {fileID: 0}
m_Transition: 1
m_Colors:
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
m_HighlightedColor: {r: 0.5217605, g: 0.47875214, b: 0.8455882, a: 1}
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
m_ColorMultiplier: 1
m_FadeDuration: 0.1
m_SpriteState:
m_HighlightedSprite: {fileID: 0}
m_PressedSprite: {fileID: 0}
m_DisabledSprite: {fileID: 0}
m_AnimationTriggers:
m_NormalTrigger: Normal
m_HighlightedTrigger: Highlighted
m_PressedTrigger: Pressed
m_DisabledTrigger: Disabled
m_Interactable: 1
m_TargetGraphic: {fileID: 114000011589085632}
m_OnClick:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null
--- !u!114 &114000011589085632
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011515193694}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -765806418, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
m_Type: 1
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
--- !u!114 &114000013055439172
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011951986632}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 708705254, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
m_RaycastTarget: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
m_FontData:
m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0}
m_FontSize: 14
m_FontStyle: 0
m_BestFit: 0
m_MinSize: 10
m_MaxSize: 40
m_Alignment: 4
m_AlignByGeometry: 0
m_RichText: 1
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: '- Friend ID -'
--- !u!114 &114000014144135060
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011515193694}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1679637790, guid: f5f67c52d1564df4a8936ccd202a3bd8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_IgnoreLayout: 0
m_MinWidth: -1
m_MinHeight: 30
m_PreferredWidth: -1
m_PreferredHeight: 30
m_FlexibleWidth: 1
m_FlexibleHeight: -1
--- !u!222 &222000010453829726
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011951986632}
--- !u!222 &222000011973359602
CanvasRenderer:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011515193694}
--- !u!224 &224000012115001870
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011951986632}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 224000012138174124}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!224 &224000012138174124
RectTransform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011515193694}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children:
- {fileID: 224000012115001870}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 160, y: 30}
m_Pivot: {x: 0.5, y: 0.5}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fbdb46efded3719458a17f55fe1ec7cd
timeCreated: 1473867148
licenseType: Store
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,39 @@
# Overview
This example demonstrates creating a Voice Chat application using
Oculus Platform Rooms (for invites), VOIP (sending and receiving
microphone input) and Peer-to-Peer networking (sharing headset
positions and rotations). The application works on both Rift
and Gear VR. Also, by using an Application Grouping, users will be
be able to chat cross-platform.
# Application Setup
1. Open the Project in Unity 5.4 or later
2. Import the OculusPlatform Unity package
## Rift
1. Create your Rift application on the dashboard
2. Copy the Application ID into the Project (Main Menu -> Oculus Platform -> Edit Settings -> Oculus Rift App Id)
## GearVR
1. Create the GearVR application on the dashboard
2. Move the GearVR application into the Rift application's App Grouping
3. Copy the Application ID into the Project (Main Menu -> Oculus Platform -> Edit Settings -> Gear VR App Id)
4. Copy the OSIG files for the GearVR devices you are testing to Assets\Plugins\Android\Assets
# Upload your builds
Build executables from Unity and upload them to your Application Dashboard
* Rift
1. Add the executable and data folder to a zip file
2. Upload the zip to the Alpha channel on your Dashboard
3. Set the executable name you chose in the zip file
4. Add Friends you are testing with as Subscribed Users for the Alpha channel
* GearVR
1. Create an android keystore (if you don't have one) so Unity can sign the build. (Player Settings -> Publishing Settings)
2. Upload the apk to the Alpha channel on your Dashboard
1. Each apk you upload needs a new build number (Player Settings -> Other Settings)
4. Add Friends you are testing with as Subscribed Users for the Alpha channel

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 2de75b4318a350a46af88d5ab1572a32
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3907fe83e926d6845b45dab719e4b2c7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

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: