WebRTC 语音连接时序图

老成员 A ↔ 信令服务器 ↔ 新成员 B,含 STUN/TURN 媒体面打洞过程

sequenceDiagram
    participant A as 老成员 A
    participant S as 信令服务器 (Socket.IO)
    participant T as STUN/TURN (UDP)
    participant B as 新成员 B

    rect rgba(30,60,120,0.15)
    Note over A,S: ① 信令连接(各自与服务器)
    A->>S: Engine.IO 握手 (EIO)
    S-->>A: clientPeerConfig {forceRelayOnly, iceServers}
    B->>S: Engine.IO 握手
    S-->>B: clientPeerConfig {forceRelayOnly, iceServers}
    end

    rect rgba(30,120,60,0.15)
    Note over B,S: ② 进房(游戏状态触发)
    B->>S: leave → id(身份) → join(lobbyCode, isHost)
    S-->>B: setClients(成员表) + setHost
    S-->>A: join(B的socketId, client)
    end

    rect rgba(140,90,20,0.15)
    Note over A,B: ③ SDP 协商(A 是 initiator,经服务器中转)
    A->>S: signal {to:B, type:offer, sdp, connectionId}
    S->>B: signal {from:A, offer}
    B->>S: signal {to:A, type:answer, sdp}
    S->>A: signal {from:B, answer}
    A->>S: signal {candidate} ×N
    S->>B: signal {candidate} ×N
    B->>S: signal {candidate} ×N
    S->>A: signal {candidate} ×N
    end

    rect rgba(120,30,120,0.15)
    Note over A,T: ④ 收集 + 打洞(媒体面,与服务器无关)
    A->>T: STUN Binding
    T-->>A: srflx (公网地址)
    A->>T: TURN Allocate
    T-->>A: relay (中继地址)
    A->>B: 连通性检查 (STUN Binding ×候选对)
    B->>A: 连通性检查
    Note over A,B: 打洞成功 = P2P 直连
双方对称 NAT = relay 对,媒体过 T end rect rgba(30,120,120,0.15) Note over A,B: ⑤ 语音运行中 A<<-->>B: WebRTC 音频流 + DataChannel(P2P,房主经通道下发房间设置) A->>S: VAD(talking) S-->>B: VAD {activity, client, socketId} S-->>A: setClients / setHost / setClient(成员与房主变更) end