Files
2026-07-20 19:01:03 +08:00

2.6 KiB

语音通信

用户流程:按下 PTT 按钮 → 发送语音 → 松开 PTT 按钮 → 停止语音 对应程序流程:前置条件检查 → StartCapture → 循环 TsClient.sendVoice(clientID, codec, frame) → StopCapture


一、状态树

语音状态

flowchart TD
    VOICE[语音状态<br/>维护 Opus 帧发送过程]

    VOICE --> V0[静默 Silent<br/>没有发送语音帧]
    VOICE --> V1[采集中 Capturing<br/>上层正在生成 Opus 帧]
    VOICE --> V2[发送中 Sending<br/>循环调用 sendVoice]
    VOICE --> V3[受阻 Blocked<br/>未连接、采集失败或发送异常]

二、时序:发送语音帧与异常停止

sequenceDiagram
    participant UI as PTT 控件<br/>接收按下、松开和取消操作
    participant VFSM as 语音发送状态机<br/>检查连接与频道前置条件
    participant CAP as 音频采集与编码器<br/>生成原始 Opus 帧
    participant BRIDGE as TSBridge<br/>调用 TsClient API
    participant SDK as Go SDK (gomobile)<br/>通过 SendVoice 发送语音
    participant TS as TeamSpeak 服务器<br/>转发语音给频道成员

    UI->>VFSM: PttPressed
    VFSM->>VFSM: 检查 connected 和 joinedChannel

    alt 前置条件不满足
        VFSM-->>UI: Blocked(reason)
    else 前置条件满足
        VFSM->>CAP: StartCapture()
        CAP-->>VFSM: CaptureReady
        VFSM->>VFSM: 状态改为 transmitting
        loop 每个 Opus 帧
            CAP-->>VFSM: opusFrame
            VFSM->>BRIDGE: sendVoice(clientID, codec, frame)
            BRIDGE->>SDK: gomobile SendVoice
            SDK->>TS: UDP voice frame
        end

        alt 用户松开或取消
            UI->>VFSM: PttReleased / PointerCancelled
            VFSM->>CAP: StopCapture()
            VFSM->>VFSM: 状态恢复 silent
        else 连接断开
            SDK-->>VFSM: onDisconnected(error)
            VFSM->>CAP: StopCapture()
            VFSM->>VFSM: 状态改为 blocked
        end
    end

三、事件依赖

语音前置依赖矩阵

操作或事件 必须依赖 建议依赖 依赖失败时的处理
TsClient.sendVoice 已连接、已有可发送的 Opus 帧 当前用户已在有效频道 任一前置失效立即停止发送

权威性划分

数据 推荐权威来源 原因
语音发送结果 TsClient.sendVoice 返回值 表示本次本地发送调用结果,不代表对方播放成功

统一实现原则(语音相关)

  • 语音只在连接和频道前置条件满足时发送。 断开或被踢必须立即停止。