跳至主要內容
Skip to content

WebRTC 實戰 (3) —— SDP 交換與媒體協商

有了「信令伺服器」這個報馬仔,現在兩台電腦終於可以說話了。但它們要說什麼呢?

WebRTC 的成功連線,依賴於一場精密的**「媒體協商 (Media Negotiation)」**。這個過程就像是兩個第一次見面的外交官,在交換各自的通訊規格書。這本規格書,就是 SDP (Session Description Protocol)


一、 核心主角:RTCPeerConnection

RTCPeerConnection 是 WebRTC API 的靈魂。它負責處理 P2P 連線的所有黑魔法:封裝、加解密、頻寬管理以及數據傳輸。

連線建立的 5 個經典步驟

  1. A 建立 Offer:A 呼叫 createOffer() 生成自己的 SDP,並透過 setLocalDescription() 給自己存檔。
  2. A 傳送 Offer:透過「信令伺服器」把這份 SDP 傳給 B。
  3. B 接收 Offer:B 收到後,呼叫 setRemoteDescription() 把 A 的資訊記下來。
  4. B 建立 Answer:B 呼叫 createAnswer() 生成回應的 SDP,並透過 setLocalDescription() 自己存檔。
  5. B 傳送 Answer:透過「信令伺服器」把自己的 SDP 回傳給 A。最後 A 呼叫 setRemoteDescription()

二、 揭開 SDP 的面紗:它到底寫了什麼?

SDP 其實是一串看似亂碼的純文字資訊。它記錄了:

  • 媒體類型:我有攝影機、麥克風、資料通道。
  • 編碼格式:我支援 VP8, VP9, H.264。
  • 連線資訊:網路候選位址。
  • 安全性:加密的金鑰指紋。

三、 實作:手寫連線握手

將我們前兩篇學過的內容串聯起來:

javascript
const pc = new RTCPeerConnection({
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] 
});

// 1. 加入本地軌道
stream.getTracks().forEach(track => pc.addTrack(track, stream));

// 2. 處理遠端軌道
pc.ontrack = (event) => {
  const [remoteStream] = event.streams;
  document.querySelector('#remoteVideo').srcObject = remoteStream;
};

// 3. 發起連線 (Offerer)
async function makeCall() {
  const offer = await pc.createOffer();
  await pc.setLocalDescription(offer);
  signaling.send({ type: 'offer', sdp: offer.sdp, to: 'User_B' });
}

// 4. 回應連線 (Answerer)
signaling.onMessage = async (msg) => {
  if (msg.type === 'offer') {
    await pc.setRemoteDescription(new RTCSessionDescription(msg));
    const answer = await pc.createAnswer();
    await pc.setLocalDescription(answer);
    signaling.send({ type: 'answer', sdp: answer.sdp, to: 'User_A' });
  } else if (msg.type === 'answer') {
    await pc.setRemoteDescription(new RTCSessionDescription(msg));
  }
};

總結

今天我們攻克了 WebRTC 最核心的邏輯:RTCPeerConnection 的管理職責、Offer/Answer 的 5 步握手流程,以及 SDP 作為「媒體合約」的重要性。

下一篇,我們將進入網路穿透的最終戰:ICE Candidate 與 NAT 穿越。


️ 進階挑戰

為什麼 WebRTC 不直接在 createOffer 之後就連線,而要搞這麼複雜的 5 步握手?(提示:想想看如果雙方都同時想發起通話,會發生什麼事?)


延伸閱讀與資源

← 上一章:信令伺服器與連線中心 | 返回專案首頁 | 下一章:ICE 候補者與 NAT 穿越