iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0

複習一下 👉 現在獲取了使用者的資訊要開始交換 SDP,需要完成下圖1~8個步驟,並且創建的offer、answer 需放在 Slignaling Server 也就是前幾篇創建的 firestore db 中,雙方都必須 setLocalDescriptionsetRemoteDescription

https://ithelp.ithome.com.tw/upload/images/20231003/20151124axrGBjZ4aS.jpg

🚀可以複習 [Day10] RTCPeerConnection - SDP 與建立連線

ICE Server 配置

  • iceServers 是一個用於設定 WebRTC ICE server 的陣列。這個陣列包括 STUN 和 TURN 伺服器的資訊,這邊只使用 google 提供免費的 STUN server 。

    🚀可以複習 [Day12] RTCPeerConnection - RTCIceServer STUN/TURN✨

  • iceCandidatePoolSize ICE 協商過程中生成的 ICE 候選人的數量。根據應用程序的需求和性能考慮來配置。較大可能會增加成功建立連接的機會,但也會增加網絡流量和運算成本。

    const configuration = {
        iceServers: [
          {
            urls: ["stun:stun1.l.google.com:19302", "stun:stun2.l.google.com:19302"]
          }
        ],
        iceCandidatePoolSize: 10
      };
    

建立 Offer 與監聽

  • createRoom & joinRoom 的使用者接需要創建一個新的 RTCPeerConnection
  • localStream 是一個 array 包含視訊 + 音訊使用 forEach 獲取後加入至 pc
async function createRoom() {
  // 創建一個新的 RTCPeerConnection
	if (!localStream.current) {
    alert('請先開啟視訊及麥克風');
    return;
  }
  const pc = new RTCPeerConnection(configuration);

  // 創建房間
  const roomRef = await addDoc(collection(db, "rooms"), {});
  const roomId = roomRef.id;
  window.alert(roomId);

  // 將 localStream 中的媒體加入至 pc 中
  localStream.current.getTracks().forEach((track) => {
    pc.addTrack(track, localStream.current);
  });

	// 1. 建立 offer 
  const offer = await pc.createOffer();
  const roomWithOffer = {
    offer: {
      type: offer.type,
      sdp: offer.sdp
    }
  };
	// 2. offer 設定 setLocalDescription,放在 db 中交換
	await pc.setLocalDescription(offer);
	await setDoc(roomRef, roomWithOffer);

	// 7. 監聽並收到 Answer
	// 8. Answer 設定 RemoteDescription
  onSnapshot(roomRef, async (snapshot) => {
    const data = snapshot.data();

    if (data?.answer && !pc.currentRemoteDescription) {
      const rtcSessionDescription = new RTCSessionDescription(data.answer);
      await pc.setRemoteDescription(rtcSessionDescription);
    }
  });
}

收到 Offer 建立 Answer

async function joinRoom(roomId) {
  if (!localStream.current) {
    alert('請先開啟視訊及麥克風');
    return;
  }

  const roomRef = doc(db, "rooms", roomId);
  const roomSnapshot = await getDoc(roomRef);

	if (roomSnapshot.exists() === false) {
    alert('您輸入的聊天室 id 不存在');
    return;
  }

  // 創建一個新的 RTCPeerConnection
  const pc = new RTCPeerConnection(configuration);
  
  localStream.current.getTracks().forEach((track) => {
    pc.addTrack(track, localStream.current);
  });

  // 3. 尋找 db 中的 offer
  // 4. offer 設定 RemoteDescription
  const offer = roomSnapshot.data()?.offer;
  await pc.setRemoteDescription(new RTCSessionDescription(offer));

  // 5. 建立 Answer
  // 6. Answer 設定 LocalDescription,放在 db 中交換
  const answer = await pc.createAnswer();
  await pc.setLocalDescription(answer);

  const roomWithAnswer = {
    answer: {
      type: answer.type,
      sdp: answer.sdp
    }
  };
  await updateDoc(roomRef, roomWithAnswer);
}

此時於createRoom 8. Answer 設定 RemoteDescription console.log(pc) 可以看到 localDescriptionremoteDescription

https://ithelp.ithome.com.tw/upload/images/20231003/20151124O1RDc85LEZ.png

https://ithelp.ithome.com.tw/upload/images/20231003/201511245LI2Y7V5y8.png

這篇文章做了 SDP的交換過程可以在程式碼的註解看到步驟,若有順利交換就可以在 console中發現 localremote皆有 SDP資訊,此時也可以在 firestore db 中看到setDocupdateDoc時增加的資訊。


上一篇
[Day20] 實做 - Firebase Cloud Firestore 創建視訊間
下一篇
[Day22] 實作 - WebRTC ICE 候選者處理
系列文
前端工程師30天 WebRTC + Firebase 視訊通話原理到實作30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言