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