Skip to content

Proposal_统一浏览器与移动端的 WebRTC 上层抽象 #10

Description

@pionxe

RFC:浏览器与移动端 WebRTC 实现差异及统一抽象提议

一、提议摘要

UniSpeaking 计划同时支持以下客户端:

  • Web 浏览器
  • Android 原生应用
  • iOS 原生应用

三端都可以使用 WebRTC 完成实时语音通信,但它们的具体实现方式并不完全相同。

本 RFC 提议:

三端统一 WebRTC 的业务流程、状态和上层接口,但分别实现浏览器、Android 和 iOS 的平台适配层。

需要特别说明:

  • 本 RFC 不是具体编码方案。
  • 文中的接口仅为伪代码,用于表达抽象关系。
  • 当前阶段的目标是统一团队对跨平台 WebRTC 的理解。

二、为什么需要讨论这个问题

从协议层面看,浏览器与移动端使用的都是 WebRTC,基本连接流程一致:

获取会话凭证
    ↓
创建 WebRTC 连接
    ↓
获取麦克风音频
    ↓
交换 SDP Offer / Answer
    ↓
完成 ICE 连接
    ↓
传输实时音频

因此,三端在业务上都需要完成以下操作:

  • 开始连接
  • 开启或关闭麦克风
  • 监听连接状态
  • 处理断线和重连
  • 获取延迟、丢包等统计信息
  • 结束连接

但这些能力在不同平台上的具体实现不同。

如果业务代码直接依赖各个平台的 WebRTC API,后续会出现以下问题:

  • 三端业务流程不一致
  • 状态和错误定义不一致
  • 供应商接入逻辑重复实现
  • 每增加一个功能都需要修改三套业务代码
  • WebRTC 实现细节扩散到上层业务模块

因此,需要区分:

业务想做什么

和:

各个平台具体怎么做

三、浏览器与移动端的核心差异

3.1 WebRTC 引擎来源不同

平台 WebRTC 能力来源
浏览器 浏览器内置 WebRTC 引擎
Android Android WebRTC SDK 或 libwebrtc
iOS iOS WebRTC SDK 或 libwebrtc

浏览器可以直接调用标准 Web API。

原生移动端则需要在应用中集成 WebRTC SDK,并与系统音频、权限和生命周期能力配合。

3.2 浏览器实现相对简单

浏览器通常通过以下 API 完成 WebRTC 通信:

getUserMedia
RTCPeerConnection
MediaStreamTrack
RTCDataChannel
getStats

浏览器会帮助应用处理大量底层工作,例如:

  • 麦克风采集
  • 音频编解码
  • 回声消除
  • 网络抖动缓冲
  • ICE 连通性检测
  • 音频加密传输

Web 端主要关注:

  • 请求麦克风权限
  • 创建连接
  • 交换 SDP
  • 监听连接状态
  • 页面关闭和断线恢复

3.3 原生移动端需要处理更多系统能力

原生移动端除了建立 WebRTC 连接,还需要处理操作系统相关问题。

Android 需要重点处理

  • 麦克风运行时权限
  • 音频焦点
  • 扬声器和听筒切换
  • 蓝牙耳机连接
  • Wi-Fi 与蜂窝网络切换
  • 前后台生命周期
  • 其他应用或系统电话抢占音频

iOS 需要重点处理

  • 麦克风权限
  • AVAudioSession 配置
  • 扬声器、听筒和蓝牙音频路由
  • 系统来电和音频中断
  • 网络状态变化
  • 前后台生命周期

因此,移动端并不是简单地将浏览器代码改写成 Kotlin 或 Swift。

真正的差异主要集中在:

音频设备管理
系统权限
生命周期
网络切换
平台中断处理

四、哪些内容相同,哪些内容不同

4.1 三端应保持一致的内容

以下内容属于业务层和协议层,应尽量统一:

  • 会话启动流程
  • SDP Offer / Answer 交换流程
  • 连接状态定义
  • 断线和重连规则
  • 错误类型
  • 统计指标格式
  • 业务事件格式
  • 模型供应商适配规则

例如,三端可以统一使用以下连接状态:

空闲
连接中
已连接
重连中
连接失败
已关闭

这样,上层业务不需要关心当前运行在浏览器、Android 还是 iOS。

4.2 三端不应强制统一的内容

以下内容与具体操作系统密切相关,应由各平台独立实现:

  • 麦克风采集方式
  • 音频焦点管理
  • 扬声器和听筒切换
  • 蓝牙设备管理
  • 系统权限申请
  • 前后台生命周期
  • 网络状态监听
  • WebRTC SDK 的具体调用方式

强行共享这些代码,会增加跨平台适配的复杂度,也可能限制移动端对系统音频能力的控制。


五、为什么需要统一上层接口

统一上层接口的目的,不是让三端共用同一份 WebRTC 底层代码,而是让业务层看到相同的能力。

整体关系应当是:

通话界面 / 会话业务
        ↓
统一的实时传输抽象
        ↓
平台 WebRTC 适配层
        ↓
浏览器 / Android / iOS WebRTC 实现

这样,通话界面只需要表达以下操作:

开始连接
关闭连接
打开麦克风
关闭麦克风
查询连接状态
获取网络统计
发送控制事件

至于这些操作在不同平台上如何完成,由平台适配层负责。


六、统一接口的概念形式

下面仅使用伪代码表达上层需要的能力,不代表最终的编程语言、类名或参数设计。

RealtimeTransport

├── connect
│   └── 建立实时语音连接
│
├── disconnect
│   └── 关闭连接并释放资源
│
├── setMicrophoneEnabled
│   └── 开启或关闭麦克风
│
├── sendEvent
│   └── 发送会话控制事件
│
├── getConnectionState
│   └── 获取当前连接状态
│
├── getStats
│   └── 获取延迟、抖动和丢包等指标
│
└── restartConnection
    └── 在网络异常时恢复连接

平台对应关系为:

RealtimeTransport
├── BrowserWebRTCTransport
├── AndroidWebRTCTransport
└── IOSWebRTCTransport

其中:

  • RealtimeTransport 表达业务层需要什么。
  • 三个平台的实现负责表达各自具体怎么做。

七、供应商差异如何处理

除了平台差异,不同实时语音模型供应商的 WebRTC 接入协议也可能不同,例如:

  • 会话凭证获取方式不同
  • SDP 提交接口不同
  • 是否支持 Trickle ICE 不同
  • 控制事件格式不同
  • 鉴权方式不同

这些差异不应由浏览器、Android 和 iOS 分别处理。

更合理的关系是:

平台适配层
负责麦克风、音频设备和 WebRTC 连接

供应商适配层
负责鉴权、SDP 信令和供应商协议差异

例如,是否使用 Trickle ICE,应由供应商接入协议决定,而不是由客户端平台决定。


八、本 RFC 的提议

本 RFC 建议团队形成以下约定:

  1. Web、Android 和 iOS 使用相同的 WebRTC 业务流程。
  2. 三端统一连接状态、错误类型和统计指标。
  3. 业务层只依赖统一的实时传输抽象。
  4. 浏览器、Android 和 iOS 分别维护平台适配实现。
  5. 音频设备、权限和生命周期由各平台独立处理。
  6. 模型供应商协议差异由供应商适配层处理。
  7. 当前仅确定抽象边界,不提前确定具体代码接口。

九、结论

浏览器与移动端使用的是同一套 WebRTC 协议,但它们面对的平台环境不同:

协议流程相同
平台实现不同

因此,UniSpeaking 不应该强行让三端共享同一份 WebRTC 底层代码,也不应该让业务层直接依赖各个平台的具体实现。

最终建议是:

对上统一业务能力,对下保留平台差异。

通过统一上层抽象,可以保证三端的会话行为一致;通过独立的平台适配层,可以正确处理移动端复杂的音频、权限、网络和生命周期问题。

Metadata

Metadata

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions