Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

213 lines
6.1 KiB

  1. namespace Oculus.Platform.Samples.VrVoiceChat
  2. {
  3. using UnityEngine;
  4. using System;
  5. using Oculus.Platform;
  6. using Oculus.Platform.Models;
  7. // Helper class to manage a Peer-to-Peer connection to the other user.
  8. // The connection is used to send and received the Transforms for the
  9. // Avatars. The Transforms are sent via unreliable UDP at a fixed
  10. // frequency.
  11. public class P2PManager
  12. {
  13. // number of seconds to delay between transform updates
  14. private static readonly float UPDATE_DELAY = 0.1f;
  15. // the ID of the remote player we expect to be connected to
  16. private ulong m_remoteID;
  17. // the result of the last connection state update message
  18. private PeerConnectionState m_state = PeerConnectionState.Unknown;
  19. // the next time to send an updated transform to the remote User
  20. private float m_timeForNextUpdate;
  21. // the size of the packet we are sending and receiving
  22. private static readonly byte PACKET_SIZE = 29;
  23. // packet format type just in case we want to add new future packet types
  24. private static readonly byte PACKET_FORMAT = 0;
  25. // reusable buffer to serialize the Transform into
  26. private readonly byte[] sendTransformBuffer = new byte[PACKET_SIZE];
  27. // reusable buffer to deserialize the Transform into
  28. private readonly byte[] receiveTransformBuffer = new byte[PACKET_SIZE];
  29. // the last received position update
  30. private Vector3 receivedPosition;
  31. // the previous received position to interpolate from
  32. private Vector3 receivedPositionPrior;
  33. // the last received rotation update
  34. private Quaternion receivedRotation;
  35. // the previous received rotation to interpolate from
  36. private Quaternion receivedRotationPrior;
  37. // when the last transform was received
  38. private float receivedTime;
  39. public P2PManager(Transform initialHeadTransform)
  40. {
  41. receivedPositionPrior = receivedPosition = initialHeadTransform.localPosition;
  42. receivedRotationPrior = receivedRotation = initialHeadTransform.localRotation;
  43. Net.SetPeerConnectRequestCallback(PeerConnectRequestCallback);
  44. Net.SetConnectionStateChangedCallback(ConnectionStateChangedCallback);
  45. }
  46. #region Connection Management
  47. public void ConnectTo(ulong userID)
  48. {
  49. m_remoteID = userID;
  50. // ID comparison is used to decide who calls Connect and who calls Accept
  51. if (PlatformManager.MyID < userID)
  52. {
  53. Net.Connect(userID);
  54. }
  55. }
  56. public void Disconnect()
  57. {
  58. if (m_remoteID != 0)
  59. {
  60. Net.Close(m_remoteID);
  61. m_remoteID = 0;
  62. m_state = PeerConnectionState.Unknown;
  63. }
  64. }
  65. public bool Connected
  66. {
  67. get
  68. {
  69. return m_state == PeerConnectionState.Connected;
  70. }
  71. }
  72. void PeerConnectRequestCallback(Message<NetworkingPeer> msg)
  73. {
  74. Debug.LogFormat("Connection request from {0}, authorized is {1}", msg.Data.ID, m_remoteID);
  75. if (msg.Data.ID == m_remoteID)
  76. {
  77. Net.Accept(msg.Data.ID);
  78. }
  79. }
  80. void ConnectionStateChangedCallback(Message<NetworkingPeer> msg)
  81. {
  82. Debug.LogFormat("Connection state to {0} changed to {1}", msg.Data.ID, msg.Data.State);
  83. if (msg.Data.ID == m_remoteID)
  84. {
  85. m_state = msg.Data.State;
  86. if (m_state == PeerConnectionState.Timeout &&
  87. // ID comparison is used to decide who calls Connect and who calls Accept
  88. PlatformManager.MyID < m_remoteID)
  89. {
  90. // keep trying until hangup!
  91. Net.Connect(m_remoteID);
  92. }
  93. }
  94. PlatformManager.SetBackgroundColorForState();
  95. }
  96. #endregion
  97. #region Send Update
  98. public bool ShouldSendHeadUpdate
  99. {
  100. get
  101. {
  102. return Time.time >= m_timeForNextUpdate && m_state == PeerConnectionState.Connected;
  103. }
  104. }
  105. public void SendHeadTransform(Transform headTransform)
  106. {
  107. m_timeForNextUpdate = Time.time + UPDATE_DELAY;
  108. sendTransformBuffer[0] = PACKET_FORMAT;
  109. int offset = 1;
  110. PackFloat(headTransform.localPosition.x, sendTransformBuffer, ref offset);
  111. PackFloat(headTransform.localPosition.y, sendTransformBuffer, ref offset);
  112. PackFloat(headTransform.localPosition.z, sendTransformBuffer, ref offset);
  113. PackFloat(headTransform.localRotation.x, sendTransformBuffer, ref offset);
  114. PackFloat(headTransform.localRotation.y, sendTransformBuffer, ref offset);
  115. PackFloat(headTransform.localRotation.z, sendTransformBuffer, ref offset);
  116. PackFloat(headTransform.localRotation.w, sendTransformBuffer, ref offset);
  117. Net.SendPacket(m_remoteID, sendTransformBuffer, SendPolicy.Unreliable);
  118. }
  119. void PackFloat(float f, byte[] buf, ref int offset)
  120. {
  121. Buffer.BlockCopy(BitConverter.GetBytes(f), 0, buf, offset, 4);
  122. offset = offset + 4;
  123. }
  124. #endregion
  125. #region Receive Update
  126. public void GetRemoteHeadTransform(Transform headTransform)
  127. {
  128. bool hasNewTransform = false;
  129. Packet packet;
  130. while ((packet = Net.ReadPacket()) != null)
  131. {
  132. if (packet.Size != PACKET_SIZE)
  133. {
  134. Debug.Log("Invalid packet size: " + packet.Size);
  135. continue;
  136. }
  137. packet.ReadBytes(receiveTransformBuffer);
  138. if (receiveTransformBuffer[0] != PACKET_FORMAT)
  139. {
  140. Debug.Log("Invalid packet type: " + packet.Size);
  141. continue;
  142. }
  143. hasNewTransform = true;
  144. }
  145. if (hasNewTransform)
  146. {
  147. receivedPositionPrior = receivedPosition;
  148. receivedPosition.x = BitConverter.ToSingle(receiveTransformBuffer, 1);
  149. receivedPosition.y = BitConverter.ToSingle(receiveTransformBuffer, 5);
  150. receivedPosition.z = BitConverter.ToSingle(receiveTransformBuffer, 9);
  151. receivedRotationPrior = receivedRotation;
  152. receivedRotation.x = BitConverter.ToSingle(receiveTransformBuffer, 13);
  153. receivedRotation.y = BitConverter.ToSingle(receiveTransformBuffer, 17) * -1.0f;
  154. receivedRotation.z = BitConverter.ToSingle(receiveTransformBuffer, 21);
  155. receivedRotation.w = BitConverter.ToSingle(receiveTransformBuffer, 25) * -1.0f;
  156. receivedTime = Time.time;
  157. }
  158. // since we're receiving updates at a slower rate than we render,
  159. // interpolate to make the motion look smoother
  160. float completed = Math.Min(Time.time - receivedTime, UPDATE_DELAY) / UPDATE_DELAY;
  161. headTransform.localPosition =
  162. Vector3.Lerp(receivedPositionPrior, receivedPosition, completed);
  163. headTransform.localRotation =
  164. Quaternion.Slerp(receivedRotationPrior, receivedRotation, completed);
  165. }
  166. #endregion
  167. }
  168. }