11-3. 視訊通話架構完整解析

深入理解 SIP+RTP+SDP 如何協同實現視訊通話系統

📹 視訊通話架構完整解析

🎯 視訊通話使用什麼協定?

💡 比喻:打電話 = 訊號系統 + 語音傳輸

視訊通話 = SIP(訊號) + RTP(媒體) + SDP(協商)

完整答案:

視訊通話不是單一協定,而是多個協定協同工作

協定層協定功能比喻
訊號層SIP建立/終止通話撥號系統 📞
描述層SDP協商媒體參數通話規格書 📋
傳輸層RTP傳輸音視訊實際通話 🎙️📹
控制層RTCP監控品質通話品質監測 📊

面試標準答案:

視訊通話主要使用 SIP 協定作為訊號控制,配合 RTP/RTCP 傳輸音視訊數據,並透過 SDP 協商編碼器、解析度等參數。現代系統常結合 WebRTC 技術實現瀏覽器端的視訊通話。


🏗️ 完整架構圖

兩人視訊通話

┌─────────────────────────────────────────────────────┐
│                 視訊通話完整堆疊                      │
└─────────────────────────────────────────────────────┘

Alice                                              Bob
┌──────────┐                                  ┌──────────┐
│ 應用層   │                                  │ 應用層   │
│ (UI)     │                                  │ (UI)     │
└──────────┘                                  └──────────┘
     ↓                                              ↓
┌──────────┐      SIP Signaling Server       ┌──────────┐
│   SIP    │ ←─────────────────────────────→ │   SIP    │
│  Client  │     (INVITE, ACK, BYE)          │  Client  │
└──────────┘                                  └──────────┘
     ↓                                              ↓
┌──────────┐         Exchange SDP             ┌──────────┐
│   SDP    │ ←─────────────────────────────→ │   SDP    │
└──────────┘  (協商編碼器、解析度)            └──────────┘
     ↓                                              ↓
┌──────────┐                                  ┌──────────┐
│   RTP    │ ←══════════════════════════════→ │   RTP    │
│  (音視訊) │     Direct P2P Connection       │  (音視訊) │
└──────────┘                                  └──────────┘
     ↓                                              ↓
┌──────────┐                                  ┌──────────┐
│   RTCP   │ ←──────────────────────────────→ │   RTCP   │
│ (品質監控)│      (Feedback, Statistics)     │ (品質監控)│
└──────────┘                                  └──────────┘
     ↓                                              ↓
┌──────────┐                                  ┌──────────┐
│   UDP    │                                  │   UDP    │
└──────────┘                                  └──────────┘

📨 協定詳解

1️⃣ SIP(訊號控制)

💡 功能:建立和終止通話
就像電話的「撥號」和「掛斷」

流程:

Alice                SIP Server                Bob
  │                      │                      │
  ├─ INVITE ───────────>│                      │  Alice 撥號
  │  (包含 SDP Offer)    │                      │
  │                      ├─ INVITE ───────────>│
  │                      │  (轉發)             │
  │                      │                      │
  │                      │<─ 200 OK ───────────┤  Bob 接聽
  │<─ 200 OK ────────────┤  (包含 SDP Answer)  │
  │                      │                      │
  ├─ ACK ───────────────────────────────────────>│  確認
  │                      │                      │
  │              [SIP 的任務完成]              │
  │                      │                      │
  │<═══════════ RTP 直連(不經過 SIP Server)═══>│

INVITE 訊息範例:

INVITE sip:bob@example.com SIP/2.0
Via: SIP/2.0/UDP alice.com:5060;branch=z9hG4bK776
To: Bob <sip:bob@example.com>
From: Alice <sip:alice@example.com>;tag=123
Call-ID: abc@alice.com
CSeq: 1 INVITE
Contact: <sip:alice@192.168.1.100:5060>
Content-Type: application/sdp
Content-Length: 245

v=0
o=alice 2890844526 2890844526 IN IP4 192.168.1.100
s=Video Call
c=IN IP4 192.168.1.100
t=0 0
m=audio 49170 RTP/AVP 0 8
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
m=video 51372 RTP/AVP 99
a=rtpmap:99 H264/90000
a=fmtp:99 profile-level-id=42e01f;level-asymmetry-allowed=1

2️⃣ SDP(媒體協商)

💡 功能:告訴對方「我支援什麼功能」
就像買手機前先看規格表

SDP 內容:

v=0                                    # 版本
o=alice 2890844526 2890844526 IN IP4 192.168.1.100  # 發起者
s=Video Call                           # 會話名稱
c=IN IP4 192.168.1.100                 # 連線資訊(IP)
t=0 0                                  # 時間(0 0 = 永久)

# 音訊媒體
m=audio 49170 RTP/AVP 0 8              # Port 49170, 支援 0(PCMU) 和 8(PCMA)
a=rtpmap:0 PCMU/8000                   # 0 = PCMU, 8kHz 取樣
a=rtpmap:8 PCMA/8000                   # 8 = PCMA, 8kHz 取樣

# 視訊媒體
m=video 51372 RTP/AVP 99               # Port 51372, 支援 99(H.264)
a=rtpmap:99 H264/90000                 # 99 = H.264, 90kHz 時鐘頻率
a=fmtp:99 profile-level-id=42e01f      # H.264 參數(Baseline Profile)
a=fmtp:99 packetization-mode=1         # 封包模式
a=framesize:99 1920-1080               # 解析度 1080p
a=framerate:30                         # 幀率 30 fps

SDP Offer/Answer 協商:

Alice Offer:
m=video 51372 RTP/AVP 99 96
a=rtpmap:99 H264/90000
a=rtpmap:96 VP8/90000
(Alice 支援 H.264 和 VP8)

Bob Answer:
m=video 38060 RTP/AVP 99
a=rtpmap:99 H264/90000
(Bob 只支援 H.264)

→ 最終使用 H.264

3️⃣ RTP(媒體傳輸)

💡 功能:實際傳輸音視訊封包
就像電話線傳送聲音

RTP 封包格式:

 0                   1                   2                   3
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X|  CC   |M|     PT      |       Sequence Number         |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                           Timestamp                           |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|           SSRC (Synchronization Source)                       |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|                         Payload Data                          |
|                             ....                              |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

欄位說明:

  • PT(Payload Type):99 = H.264, 0 = PCMU, 8 = PCMA
  • Sequence Number:封包序號(用於偵測丟包)
  • Timestamp:時間戳(用於同步)
  • SSRC:來源識別碼

Python 發送 RTP:

import socket
import struct
import time

class RTPSender:
    def __init__(self, dest_ip, dest_port, payload_type):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        self.dest = (dest_ip, dest_port)
        self.payload_type = payload_type
        self.sequence = 0
        self.ssrc = 12345  # 隨機 SSRC

    def send_packet(self, payload):
        # RTP Header (12 bytes)
        version = 2
        padding = 0
        extension = 0
        csrc_count = 0
        marker = 0

        # 組裝 Header
        header = struct.pack(
            '!BBHII',
            (version << 6) | (padding << 5) | (extension << 4) | csrc_count,
            (marker << 7) | self.payload_type,
            self.sequence,
            int(time.time() * 90000),  # Timestamp(90kHz)
            self.ssrc
        )

        # 發送封包
        packet = header + payload
        self.sock.sendto(packet, self.dest)

        self.sequence = (self.sequence + 1) % 65536

# 使用
sender = RTPSender('192.168.1.200', 51372, payload_type=99)

# 發送 H.264 視訊幀
with open('video_frame.h264', 'rb') as f:
    frame_data = f.read()
    sender.send_packet(frame_data)

4️⃣ RTCP(品質監控)

💡 功能:監控通話品質,回報統計資訊
就像網路速度測試

RTCP 封包類型:

  • SR(Sender Report):發送者報告
  • RR(Receiver Report):接收者報告
  • SDES(Source Description):來源描述
  • BYE:離開會話
  • APP:應用自訂

RTCP RR 範例(接收者報告):

class RTCPReceiver:
    def send_receiver_report(self):
        # 統計資訊
        packets_lost = 10          # 丟包數
        packets_received = 1000    # 已收到
        jitter = 5                 # 抖動(ms)

        # RTCP RR 封包
        report = {
            'type': 'RR',
            'ssrc': self.ssrc,
            'fraction_lost': packets_lost / packets_received,
            'cumulative_lost': packets_lost,
            'highest_sequence': self.last_seq,
            'jitter': jitter
        }

        # 發送 RTCP(Port = RTP Port + 1)
        self.sock.sendto(
            self.encode_rtcp(report),
            (self.dest_ip, self.rtp_port + 1)
        )

應用:自適應位元率(ABR)

def on_rtcp_report(report):
    packet_loss = report['fraction_lost']

    if packet_loss > 0.1:  # 丟包率 > 10%
        # 降低視訊位元率
        reduce_bitrate()
    elif packet_loss < 0.01:  # 丟包率 < 1%
        # 提高視訊位元率
        increase_bitrate()

🏢 多人視訊會議架構

1️⃣ MCU(Multipoint Control Unit)混音架構

💡 比喻:電視台導播
把所有人的畫面混合成一個九宮格,再廣播給所有人
┌──────────────────────────────────────┐
│             MCU Server               │
│  ┌────────────────────────────────┐  │
│  │   Video Mixer(影像混合)      │  │
│  │   ┌───┬───┬───┐                │  │
│  │   │ A │ B │ C │ → 合成九宮格   │  │
│  │   ├───┼───┼───┤                │  │
│  │   │ D │ E │ F │                │  │
│  │   └───┴───┴───┘                │  │
│  └────────────────────────────────┘  │
│  ┌────────────────────────────────┐  │
│  │   Audio Mixer(音訊混合)      │  │
│  │   A + B + C + D + E + F → 混音 │  │
│  └────────────────────────────────┘  │
└──────────────────────────────────────┘
         ↓           ↓           ↓
    Alice (1流)  Bob (1流)  Charlie (1流)
    (下載 1 個合成流)

優點:

  • ✅ 客戶端負擔最低(只接收 1 個流)
  • ✅ 適合弱網路環境
  • ✅ 統一的視訊品質

缺點:

  • ❌ 伺服器運算量極大(需要編碼/解碼)
  • ❌ 延遲較高(混合需要時間)
  • ❌ 無法自訂布局(固定九宮格)

架構圖:

Alice ──┐
Bob ────┼──> MCU Server
Charlie─┤    │
Dave ───┘    │ 1. 解碼所有輸入
             │ 2. 混合成九宮格
             │ 3. 重新編碼
             │ 4. 廣播給所有人
             ↓
    [A][B][C]
    [D][E][F]  ← 合成畫面
    [ ][ ][ ]
             ↓
     Alice, Bob, Charlie, Dave 都收到相同的合成畫面

2️⃣ SFU(Selective Forwarding Unit)轉發架構

💡 比喻:郵局轉信
只轉發,不開拆(不編碼/解碼)
┌──────────────────────────────────────┐
│             SFU Server               │
│  ┌────────────────────────────────┐  │
│  │   只轉發(不混合)             │  │
│  │                                │  │
│  │   Alice 的流 ───────→ Bob      │  │
│  │   Alice 的流 ───────→ Charlie  │  │
│  │   Bob 的流 ─────────→ Alice    │  │
│  │   Bob 的流 ─────────→ Charlie  │  │
│  │   ...                          │  │
│  └────────────────────────────────┘  │
└──────────────────────────────────────┘
         ↑           ↑           ↑
    Alice (上傳1個流, 下載N-1個流)
    Bob (上傳1個流, 下載N-1個流)
    Charlie (上傳1個流, 下載N-1個流)

優點:

  • ✅ 延遲極低(只轉發,不處理)
  • ✅ 伺服器負擔低(不需編碼/解碼)
  • ✅ 每個客戶端可自訂布局
  • ✅ 支援 Simulcast(多碼率)

缺點:

  • ❌ 客戶端負擔高(需解碼 N-1 個流)
  • ❌ 頻寬需求高(下載 N-1 個流)

Simulcast 優化:

Alice 上傳 3 種解析度:
- High: 1080p @ 2 Mbps
- Medium: 720p @ 1 Mbps
- Low: 360p @ 300 Kbps

SFU 根據每個接收者的網路狀況選擇:
- Bob (好網路) ← 1080p
- Charlie (普通) ← 720p
- Dave (弱網路) ← 360p

架構圖:

Alice (上傳 1080p/720p/360p)
  ↓
SFU Server
  ├─→ Bob (下載 1080p)
  ├─→ Charlie (下載 720p)
  └─→ Dave (下載 360p)

好處:
- Alice 只上傳 1 次(3 種解析度)
- SFU 自動選擇適合的解析度發送
- 節省頻寬,優化體驗

3️⃣ SFU vs MCU 比較

特性MCUSFU
延遲高(100-300ms)低(10-50ms)
伺服器 CPU極高 🔥🔥🔥低 ✅
客戶端 CPU低 ✅高 🔥🔥
頻寬(客戶端)低(1 個流)高(N-1 個流)
彈性低(固定布局)高(自訂布局)
適用人數大(100+)中(10-50)
典型應用大型網路研討會團隊會議

實務建議:

10 人以下:SFU(低延遲、高品質)
10-50 人:SFU + Simulcast
50-100 人:MCU(減輕客戶端負擔)
100+ 人:MCU + 觀眾模式(只下載,不上傳)

🔗 SIP + WebRTC 整合

💡 讓瀏覽器也能打 SIP 電話

架構

Browser (WebRTC)        Gateway           SIP Client
     │                     │                    │
     ├─ WebSocket ────────>│                    │  WebSocket 訊號
     │  (SIP over WS)       │                    │
     │                     ├─ SIP (UDP) ───────>│  轉換為標準 SIP
     │                     │                    │
     │<────── SDP ──────────┼────── SDP ────────>│  交換 SDP
     │                     │                    │
     │<══════ SRTP ═══════>│<═════ RTP ════════>│  媒體流
     │    (加密)            │   (轉碼)           │

Gateway 功能:

  1. 協定轉換:WebSocket ↔ UDP
  2. 訊號轉換:SIP over WS ↔ 標準 SIP
  3. 媒體轉碼:SRTP(加密)↔ RTP
  4. NAT 穿透:處理 ICE/STUN/TURN

JsSIP + Asterisk 範例:

// 瀏覽器端(JsSIP)
const socket = new JsSIP.WebSocketInterface('wss://pbx.example.com:8089/ws');
const ua = new JsSIP.UA({
    sockets: [socket],
    uri: 'sip:1001@pbx.example.com',
    password: 'secret',
    session_timers: false
});

ua.start();

// 撥打 SIP 分機
const session = ua.call('sip:2002@pbx.example.com', {
    mediaConstraints: { audio: true, video: true }
});

session.on('accepted', () => {
    console.log('通話建立');
});
; Asterisk 配置(/etc/asterisk/http.conf)
[general]
enabled=yes
bindaddr=0.0.0.0
bindport=8088

; WebSocket 支援
enablestatic=yes
; /etc/asterisk/pjsip.conf
[transport-ws]
type=transport
protocol=ws
bind=0.0.0.0:8089

[1001]
type=endpoint
context=internal
disallow=all
allow=ulaw,alaw,vp8,h264
auth=1001
aors=1001
webrtc=yes  ; 啟用 WebRTC

[1001]
type=auth
auth_type=userpass
password=secret
username=1001

[1001]
type=aor
max_contacts=5

🎓 常見面試題

Q1:視訊通話使用什麼協定?(完整回答)

答案:

視訊通話是多協定協同工作的結果:

1. SIP(Session Initiation Protocol):

  • 功能:訊號控制(建立、修改、終止通話)
  • 傳輸:通常使用 UDP 5060(未加密)或 TCP 5061(TLS 加密)
  • 類比:電話的撥號系統

2. SDP(Session Description Protocol):

  • 功能:描述媒體參數(編碼器、解析度、IP/Port)
  • 傳輸:嵌入在 SIP 訊息中(Content-Type: application/sdp)
  • 類比:通話規格書

3. RTP(Real-time Transport Protocol):

  • 功能:傳輸音視訊數據
  • 傳輸:UDP(通常動態分配 Port)
  • 類比:實際的通話內容

4. RTCP(RTP Control Protocol):

  • 功能:監控品質、回報統計
  • 傳輸:UDP(Port = RTP Port + 1)
  • 類比:通話品質監測

完整流程:

1. SIP INVITE(包含 SDP Offer)
   → 協商編碼器、解析度

2. SIP 200 OK(包含 SDP Answer)
   → 確認使用 H.264, 1080p, Port 51372

3. SIP ACK
   → 確認收到

4. RTP 傳輸視訊(UDP Port 51372)
   RTCP 監控品質(UDP Port 51373)
   → 實際視訊通話

5. SIP BYE
   → 結束通話

面試加分:

  • 提到 WebRTC 結合 SIP 的趨勢
  • 提到 SRTP(加密的 RTP)
  • 提到 ICE/STUN/TURN 處理 NAT 穿透

Q2:為什麼 RTP 使用 UDP 而不是 TCP?

答案:

💡 比喻:
UDP = 直播(寧可跳格,不要延遲)
TCP = 下載(寧可慢,也要完整)

UDP 優勢(即時通訊):

  1. 低延遲:
TCP:封包遺失 → 重傳 → 等待 ACK → 延遲累積
UDP:封包遺失 → 直接播放下一個封包(容許跳格)

視訊通話:1 秒前的畫面重傳已無意義
  1. 無重傳機制:
TCP 重傳:
時間 0s:發送封包 A
時間 1s:未收到 ACK,重傳封包 A
時間 2s:收到 ACK
→ 延遲 2 秒

UDP:
時間 0s:發送封包 A
時間 1s:封包 A 遺失,繼續發送封包 B
→ 延遲 0 秒(容許 A 遺失)
  1. Head-of-Line Blocking:
TCP 問題:
封包順序:A B C D
如果 B 遺失:C 和 D 必須等待 B 重傳
→ 所有後續封包阻塞

UDP:
B 遺失 → C, D 照常播放
→ 不阻塞

UDP 缺點與補救:

缺點補救機制
無連線狀態RTCP 監控連線
封包可能亂序RTP Sequence Number 重排
封包可能遺失FEC(Forward Error Correction)冗余編碼
無流量控制RTCP Feedback 調整位元率

程式碼示範(處理亂序):

class RTPReceiver:
    def __init__(self):
        self.buffer = {}  # 緩衝區
        self.last_played = 0

    def on_packet(self, packet):
        seq = packet.sequence_number

        # 放入緩衝區
        self.buffer[seq] = packet

        # 嘗試播放連續的封包
        while (self.last_played + 1) in self.buffer:
            self.play(self.buffer[self.last_played + 1])
            del self.buffer[self.last_played + 1]
            self.last_played += 1

        # 超時處理(跳過遺失的封包)
        if seq > self.last_played + 10:
            print(f"封包 {self.last_played + 1} 遺失,跳過")
            self.last_played = seq - 1

Q3:如何優化視訊通話品質?

答案:

多層優化策略:

1. 網路層優化:

# QoS(Quality of Service)標記
import socket

# 建立 RTP Socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 設定 DSCP(Differentiated Services Code Point)
# EF (Expedited Forwarding) = 46,最高優先級
sock.setsockopt(socket.IPPROTO_IP, socket.IP_TOS, 46 << 2)

# 發送 RTP 封包(路由器會優先處理)
sock.sendto(rtp_packet, (dest_ip, dest_port))

2. 自適應位元率(ABR):

// 根據 RTCP 報告調整位元率
peerConnection.getStats().then(stats => {
    stats.forEach(report => {
        if (report.type === 'inbound-rtp' && report.kind === 'video') {
            const packetsLost = report.packetsLost;
            const packetsReceived = report.packetsReceived;
            const lossRate = packetsLost / (packetsLost + packetsReceived);

            if (lossRate > 0.05) {  // 丟包率 > 5%
                // 降低位元率
                adjustBitrate('down');
            } else if (lossRate < 0.01) {  // 丟包率 < 1%
                // 提高位元率
                adjustBitrate('up');
            }
        }
    });
}, 1000);

function adjustBitrate(direction) {
    const sender = peerConnection.getSenders().find(s => s.track.kind === 'video');
    const parameters = sender.getParameters();

    if (direction === 'down') {
        parameters.encodings[0].maxBitrate *= 0.8;  // 降低 20%
    } else {
        parameters.encodings[0].maxBitrate *= 1.2;  // 提高 20%
    }

    sender.setParameters(parameters);
}

3. FEC(Forward Error Correction):

原理:發送冗余數據,即使部分封包遺失也能恢復

原始封包:A B C D
FEC 封包:E = A ⊕ B ⊕ C ⊕ D(XOR)

如果 B 遺失:
B = A ⊕ C ⊕ D ⊕ E(可恢復!)
// 啟用 FEC(使用 libwebrtc)
const sender = peerConnection.addTransceiver('video', {
    direction: 'sendonly',
    sendEncodings: [{
        fec: {
            ssrc: 123456,
            mechanism: 'red+ulpfec'  // RED + ULP FEC
        }
    }]
}).sender;

4. Jitter Buffer(抖動緩衝):

class JitterBuffer:
    def __init__(self, buffer_size=50):  # 50ms 緩衝
        self.buffer = []
        self.buffer_size = buffer_size

    def add_packet(self, packet):
        self.buffer.append(packet)
        self.buffer.sort(key=lambda p: p.timestamp)

        # 當緩衝區滿時,開始播放
        if len(self.buffer) >= self.buffer_size:
            packet_to_play = self.buffer.pop(0)
            self.play(packet_to_play)

5. Simulcast(多碼率):

// 發送 3 種解析度
const sender = peerConnection.addTransceiver('video', {
    sendEncodings: [
        { rid: 'h', maxBitrate: 900000, scaleResolutionDownBy: 1 },    // 1080p
        { rid: 'm', maxBitrate: 300000, scaleResolutionDownBy: 2 },    // 540p
        { rid: 'l', maxBitrate: 100000, scaleResolutionDownBy: 4 }     // 270p
    ]
}).sender;

// SFU 自動選擇適合的解析度發送給不同接收者

Q4:SRTP 和 RTP 有什麼不同?

答案:

RTP = Real-time Transport Protocol(未加密)
SRTP = Secure RTP(加密)

差異:

特性RTPSRTP
加密❌ 無✅ AES 加密
認證❌ 無✅ HMAC-SHA1
防重放❌ 無✅ Sequence Number 檢查
適用場景內網通話公網通話

SRTP 封包格式:

RTP Packet:
┌────────┬─────────┐
│ Header │ Payload │
└────────┴─────────┘

SRTP Packet:
┌────────┬────────────────┬──────────┐
│ Header │ Encrypted      │ Auth Tag │
│        │ Payload        │ (HMAC)   │
└────────┴────────────────┴──────────┘

SRTP 密鑰交換(使用 DTLS-SRTP):

WebRTC 流程:
1. DTLS 握手(類似 TLS)
   → 交換憑證、協商加密演算法

2. 產生 SRTP Master Key
   → 雙方各自產生對稱金鑰

3. 使用 SRTP 傳輸音視訊
   → 所有 RTP 封包都加密

JavaScript 啟用 SRTP(WebRTC 預設):

// WebRTC 自動使用 SRTP,無需額外設定
const peerConnection = new RTCPeerConnection();

// 檢查是否使用 SRTP
peerConnection.getStats().then(stats => {
    stats.forEach(report => {
        if (report.type === 'transport') {
            console.log('DTLS State:', report.dtlsState);  // "connected"
            console.log('SRTP Cipher:', report.srtpCipher);  // "AES_CM_128_HMAC_SHA1_80"
        }
    });
});

Q5:如何實作斷線重連?

答案:

SIP 層重連:

class ReliableSIPUA {
    constructor(config) {
        this.ua = new JsSIP.UA(config);
        this.setupReconnection();
    }

    setupReconnection() {
        this.ua.on('disconnected', () => {
            console.log('SIP 斷線,5 秒後重連');

            setTimeout(() => {
                this.ua.start();
            }, 5000);
        });

        this.ua.on('connected', () => {
            console.log('SIP 重新連線成功');
        });
    }
}

RTP 層重連(ICE Restart):

session.on('iceconnectionstatechange', async () => {
    const state = session.connection.iceConnectionState;

    if (state === 'disconnected' || state === 'failed') {
        console.log('RTP 斷線,執行 ICE Restart');

        // ICE Restart
        await session.renegotiate({
            iceRestart: true  // 重新進行 ICE 協商
        });
    }
});

完整斷線處理:

class RobustVideoCall {
    constructor() {
        this.maxRetries = 3;
        this.retryCount = 0;
    }

    async call(targetURI) {
        try {
            this.session = this.ua.call(targetURI, options);

            this.session.on('failed', (event) => {
                if (event.cause === 'Request Timeout' && this.retryCount < this.maxRetries) {
                    this.retryCount++;
                    console.log(`重試 ${this.retryCount}/${this.maxRetries}`);

                    setTimeout(() => {
                        this.call(targetURI);  // 重試
                    }, 2000);
                }
            });

            this.session.on('iceconnectionstatechange', () => {
                this.handleICEState();
            });

        } catch (error) {
            console.error('通話失敗:', error);
        }
    }

    async handleICEState() {
        const state = this.session.connection.iceConnectionState;

        switch (state) {
            case 'failed':
                // 嘗試 ICE Restart
                await this.session.renegotiate({ iceRestart: true });
                break;

            case 'disconnected':
                // 等待 5 秒看是否自動恢復
                setTimeout(async () => {
                    if (this.session.connection.iceConnectionState === 'disconnected') {
                        await this.session.renegotiate({ iceRestart: true });
                    }
                }, 5000);
                break;

            case 'connected':
                console.log('RTP 連線已恢復');
                this.retryCount = 0;  // 重置重試計數
                break;
        }
    }
}

📝 總結

視訊通話架構核心要點:

協定層:

  • SIP:訊號控制(撥號、掛斷)📞
  • SDP:媒體協商(編碼器、解析度)📋
  • RTP:媒體傳輸(音視訊數據)🎙️📹
  • RTCP:品質監控(統計、反饋)📊

架構選擇:

  • 小型會議(<10 人):SFU ⚡
  • 中型會議(10-50 人):SFU + Simulcast 🚀
  • 大型會議(50+ 人):MCU 🏢

優化策略:

  • QoS 標記優先級
  • 自適應位元率(ABR)
  • FEC 冗余編碼
  • Jitter Buffer 抖動緩衝
  • Simulcast 多碼率

安全性:

  • SRTP 加密媒體
  • DTLS-SRTP 密鑰交換
  • TLS 加密訊號

🔗 延伸閱讀

  • 上一篇:06-2. SIP 呼叫流程
  • 下一章:07-1. DNS 域名解析
  • RFC 3550(RTP):https://tools.ietf.org/html/rfc3550
  • RFC 3711(SRTP):https://tools.ietf.org/html/rfc3711
  • WebRTC 官方文件:https://webrtc.org/
0%