Advertisement
Guest User

Untitled

a guest
Apr 13th, 2025
68
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.91 KB | None | 0 0
  1. (async () => {
  2. // Define the host URL and authentication details for the SFU
  3. // The host URL is the endpoint for the SFU server
  4. // The secret is the authentication token required to interact with the SFU server
  5. // The sfuAppId is the unique identifier for the SFU application
  6. const host = "https://global.sfu.metered.ca";
  7. const sfuAppId = "67fa4de8b7bb83e8a72d4e70";
  8. const secret = "/xOkk86ZBH+C8eQZ";
  9.  
  10. // Creating a PeerConnection for userA to connect to the SFU
  11. // The RTCPeerConnection is used to establish a connection to the SFU
  12. // The iceServers array contains the STUN server configuration used for NAT traversal
  13. const peerConnectionUserA = new RTCPeerConnection({
  14. iceServers: [
  15. {
  16. urls: "stun:stun.metered.ca:80"
  17. }
  18. ]
  19. });
  20.  
  21. // Request access to userA's video device (e.g., webcam)
  22. // The getUserMedia function prompts the user for permission to use their video device
  23. // The video constraints specify the desired resolution for the video feed
  24. const streamUserA = await navigator.mediaDevices.getUserMedia({
  25. video: {
  26. width: 1920,
  27. height: 1080,
  28. }
  29. });
  30.  
  31. // Add each track from the stream to the peer connection to be sent to the SFU
  32. // The getTracks function returns an array of MediaStreamTrack objects representing the video tracks
  33. // The addTrack function adds each track to the peer connection
  34. streamUserA.getTracks().map(track => peerConnectionUserA.addTrack(track, streamUserA));
  35.  
  36. // Showing userA's local video
  37. // The srcObject property of the video element is set to the MediaStream object
  38. // This displays the local video feed in the video element with the id 'localVideo'
  39. document.getElementById('localVideo').srcObject = streamUserA;
  40.  
  41. // Create an SDP offer for userA
  42. // The createOffer function generates an SDP offer for the peer connection
  43. // The setLocalDescription function sets the local description of the peer connection to the generated offer
  44. const offerSdpUserA = await peerConnectionUserA.createOffer();
  45. await peerConnectionUserA.setLocalDescription(offerSdpUserA);
  46.  
  47. // Send the SDP offer to the SFU to establish a connection for userA
  48. // The fetch function sends a POST request to the SFU server with the SDP offer in the request body
  49. // The response from the SFU server contains the session description and session ID
  50. const responseUserA = await fetch(host + `/api/sfu/${sfuAppId}/session/new`, {
  51. method: 'POST',
  52. headers: {
  53. 'Content-Type': 'application/json',
  54. 'Authorization': `Bearer ${secret}`
  55. },
  56. body: JSON.stringify({
  57. sessionDescription: offerSdpUserA
  58. })
  59. });
  60.  
  61. // Parse the JSON response from the SFU server
  62. const responseJsonUserA = await responseUserA.json();
  63. console.log(responseJsonUserA);
  64.  
  65. // Obtain the session ID for userA
  66. // The session ID is used to identify the session on the SFU server
  67. const sessionIdUserA = responseJsonUserA.sessionId;
  68.  
  69. // Set the remote description for userA's peer connection
  70. // The setRemoteDescription function sets the remote description of the peer connection to the session description received from the SFU server
  71. await peerConnectionUserA.setRemoteDescription(responseJsonUserA.sessionDescription);
  72.  
  73. // Check if the peer connection state is connected for userA
  74. // The oniceconnectionstatechange event is triggered when the ICE connection state changes
  75. // If the ICE connection state is 'connected', the startRemoteUserConnection function is called after a 1-second delay
  76. peerConnectionUserA.oniceconnectionstatechange = () => {
  77. if (peerConnectionUserA.iceConnectionState === 'connected') {
  78. console.log('UserA Connected');
  79. setTimeout(startRemoteUserConnection, 1000);
  80. }
  81. }
  82.  
  83. /**
  84. * Function to create a new session and subscribe to the track published by userA
  85. */
  86. async function startRemoteUserConnection() {
  87. // Creating a PeerConnection for userB to connect to the SFU
  88. // The RTCPeerConnection is used to establish a connection to the SFU
  89. // The iceServers array contains the STUN server configuration used for NAT traversal
  90. const peerConnectionUserB = new RTCPeerConnection({
  91. iceServers: [
  92. {
  93. urls: "stun:stun.metered.ca:80"
  94. }
  95. ]
  96. });
  97.  
  98. // Add a transceiver for video for userB
  99. // The addTransceiver function adds a transceiver for the video track
  100. // This allows userB to receive the video track from the SFU
  101. peerConnectionUserB.addTransceiver('video');
  102.  
  103. // Create an SDP offer for userB
  104. // The createOffer function generates an SDP offer for the peer connection
  105. // The setLocalDescription function sets the local description of the peer connection to the generated offer
  106. const offerSdpUserB = await peerConnectionUserB.createOffer();
  107. await peerConnectionUserB.setLocalDescription(offerSdpUserB);
  108.  
  109. // Handle incoming tracks for userB
  110. // The ontrack event is triggered when a new track is received on the peer connection
  111. // A new video element is created for each incoming track and added to the 'remoteVideoContainer' div
  112. peerConnectionUserB.ontrack = (e) => {
  113. const videoElement = document.createElement('video');
  114. videoElement.srcObject = new MediaStream([e.track]);
  115. videoElement.autoplay = true;
  116. videoElement.controls = true;
  117. document.getElementById('remoteVideoContainer').appendChild(videoElement);
  118. }
  119.  
  120. // Send the SDP offer to the SFU to establish a connection for userB
  121. // The fetch function sends a POST request to the SFU server with the SDP offer in the request body
  122. // The response from the SFU server contains the session description and session ID
  123. const sessionResponseUserB = await fetch(host + `/api/sfu/${sfuAppId}/session/new`, {
  124. method: 'POST',
  125. headers: {
  126. 'Content-Type': 'application/json',
  127. 'Authorization': `Bearer ${secret}`
  128. },
  129. body: JSON.stringify({
  130. sessionDescription: offerSdpUserB
  131. })
  132. });
  133.  
  134. // Parse the JSON response from the SFU server
  135. const sessionResponseJsonUserB = await sessionResponseUserB.json();
  136. const sessionIdUserB = sessionResponseJsonUserB.sessionId;
  137. await peerConnectionUserB.setRemoteDescription(sessionResponseJsonUserB.sessionDescription);
  138.  
  139. // Get the list of tracks from the Remote SFU for userA
  140. // The fetch function sends a GET request to the SFU server to retrieve the list of tracks for the session
  141. // The response from the SFU server contains the list of tracks
  142. const remoteTracksUserA = await fetch(host + `/api/sfu/${sfuAppId}/session/${sessionIdUserA}/tracks`, {
  143. method: 'GET',
  144. headers: {
  145. 'Content-Type': 'application/json',
  146. 'Authorization': `Bearer ${secret}`
  147. }
  148. });
  149.  
  150. // Parse the JSON response from the SFU server
  151. const remoteTracksJsonUserA = await remoteTracksUserA.json();
  152. console.log(remoteTracksJsonUserA);
  153.  
  154. // Subscribe to the remote tracks for userB
  155. // The trackIdUserA is the unique identifier for the track published by userA
  156. // The fetch function sends a POST request to the SFU server to subscribe to the track
  157. // The request body contains the remote session ID and remote track ID
  158. const trackIdUserA = remoteTracksJsonUserA[0].trackId;
  159. const responseUserB = await fetch(`${host}/api/sfu/${sfuAppId}/session/${sessionIdUserB}/track/subscribe`, {
  160. method: 'POST',
  161. headers: {
  162. 'Content-Type': 'application/json',
  163. 'Authorization': `Bearer ${secret}`
  164. },
  165. body: JSON.stringify({
  166. tracks: [
  167. {
  168. "remoteSessionId": sessionIdUserA,
  169. "remoteTrackId": trackIdUserA
  170. }
  171. ]
  172. })
  173. });
  174.  
  175. // Parse the JSON response from the SFU server
  176. const jsonUserB = await responseUserB.json();
  177.  
  178. // Set the remote description for userB's peer connection
  179. // The setRemoteDescription function sets the remote description of the peer connection to the session description received from the SFU server
  180. await peerConnectionUserB.setRemoteDescription(new RTCSessionDescription(jsonUserB.sessionDescription));
  181. const answerUserB = await peerConnectionUserB.createAnswer();
  182. await peerConnectionUserB.setLocalDescription(answerUserB);
  183.  
  184. // Renegotiate the session for userB
  185. // The fetch function sends a PUT request to the SFU server to renegotiate the session
  186. // The request body contains the session description generated by the createAnswer function
  187. await fetch(`${host}/api/sfu/${sfuAppId}/session/${sessionIdUserB}/renegotiate`, {
  188. method: 'PUT',
  189. headers: {
  190. 'Content-Type': 'application/json',
  191. 'Authorization': `Bearer ${secret}`
  192. },
  193. body: JSON.stringify({
  194. sessionDescription: answerUserB
  195. })
  196. });
  197. }
  198. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement