HarmonyOS APP开发—"面对面"视频通话App,需要用到这个库

想做一个视频通话 App,一对一视频、NAT 穿透、回声消除全要?从零写 RTP/SRTP/ICE 协议栈不现实——@ohos/webrtc 把 Google WebRTC 原生项目完整搬进鸿蒙,业界标准 RTC 方案开箱即用。

📦 仓库地址:https://gitcode.com/CPF-ApplicationTPC/ohos_webrtc | 安装:ohpm install @ohos/webrtc


写在前面

"面对面"要实现的是:用户 A 拨打视频电话给用户 B,B 接通后双方实时看到对方画面、听到对方声音,延迟在 200ms 以内。

这背后的技术挑战远超"播放一段视频":

  • NAT 穿透:A 和 B 都在各自的家庭 WiFi 后面,怎么建立 P2P 连接?需要 ICE/STUN/TURN
  • 音频处理:扬声器声音别回灌到麦克风(AEC)、环境噪声要消除(ANS)、音量要自动调节(AGC)
  • 视频编解码:H.264/VP8/VP9 编解码 + 硬件加速
  • 带宽估计 + 拥塞控制:网络差时自动降码率,别卡成 PPT

WebRTC 是 Google 主导的开源项目,把上述所有能力整合进一套统一 API。@ohos/webrtc 是它在 OpenHarmony 上的完整移植 + ArkTS 接口封装。

这篇文章聊什么

  1. 建立连接——创建 PeerConnection + ICE 穿透
  2. 本地采集——getUserMedia 获取摄像头 + 麦克风
  3. 信令交互——通过信令服务器交换 SDP/ICE

A 拨号

A: createOffer

A: setLocalDescription

信令服务器转发 Offer

B: setRemoteDescription

B: createAnswer

B: setLocalDescription

信令服务器转发 Answer

A: setRemoteDescription

ICE 候选交换

P2P 连接建立

音视频互通


第一步:安装与权限

ohpm install @ohos/webrtc
"requestPermissions": [
  { "name": "ohos.permission.INTERNET" },
  { "name": "ohos.permission.CAMERA" },
  { "name": "ohos.permission.MICROPHONE" }
]

第二步:采集本地音视频

通话接通前,先把自己的摄像头画面渲染到本地预览:

import { RTCPeerConnection, mediaDevices, MediaStream } from '@ohos/webrtc'

// 采集本地音视频流
const localStream: MediaStream = await mediaDevices.getUserMedia({
  audio: true,                          // 麦克风(内置 AEC/ANS/AGC)
  video: { width: 1280, height: 720 },  // 摄像头 720p
})

// 将本地流渲染到 XComponent(本地预览)
renderLocalStream(localStream)

WebRTC 的音频 3A(AEC/ANS/AGC)是内置的——回声消除、降噪、自动增益全部自动开启,你不需要写一行音频处理代码。


第三步:创建 PeerConnection 并交换信令

const config: RTCConfiguration = {
  iceServers: [
    { urls: ['stun:stun.l.google.com:19302'] },           // STUN 穿透
    { urls: ['turn:turn.example.com:3478'],                // TURN 中继
      username: 'user', credential: 'pass' },
  ],
}

const pc = new RTCPeerConnection(config)

// 把本地轨道加入连接
localStream.getTracks().forEach((track) => {
  pc.addTrack(track, localStream)
})

// 收到远端流(对方的画面)
pc.ontrack = (event) => {
  renderRemoteStream(event.streams[0]) // 渲染到远端 XComponent
}

// ICE 候选:通过信令服务器发给对方
pc.onicecandidate = (event) => {
  if (event.candidate) {
    signaling.send({ type: 'ice', candidate: event.candidate })
  }
}

// ===== A 端:创建 Offer =====
const offer = await pc.createOffer()
await pc.setLocalDescription(offer)
signaling.send({ type: 'offer', sdp: offer.sdp })

// ===== B 端:收到 Offer,创建 Answer =====
signaling.on('offer', async (data) => {
  await pc.setRemoteDescription({ type: 'offer', sdp: data.sdp })
  const answer = await pc.createAnswer()
  await pc.setLocalDescription(answer)
  signaling.send({ type: 'answer', sdp: answer.sdp })
})

// ===== A 端:收到 Answer =====
signaling.on('answer', async (data) => {
  await pc.setRemoteDescription({ type: 'answer', sdp: data.sdp })
})

// 双方收到对方 ICE 候选
signaling.on('ice', (data) => {
  pc.addIceCandidate(data.candidate)
})

信令服务器可以用 WebSocket / MQTT / gRPC 任意实现——WebRTC 不规定信令协议,只要能把 SDP 和 ICE 候选在 A 和 B 之间转发即可。


第四步:通话统计与质量监控

通话过程中,用 Stats API 监控网络质量:

// 每秒采集一次网络统计
setInterval(async () => {
  const stats = await pc.getStats()
  stats.forEach((report) => {
    if (report.type === 'inbound-rtp') {
      console.info(`丢包率: ${report.packetsLost / (report.packetsReceived + report.packetsLost) * 100}%`)
      console.info(`抖动: ${report.jitter}ms`)
      console.info(`码率: ${report.bitrate}kbps`)
    }
  })
}, 1000)

为什么"面对面"选了 WebRTC?

需求 自研 RTP/SRTP @ohos/webrtc
NAT 穿透 手写 ICE/STUN/TURN ✅ 内置
音频 3A 手写 AEC/ANS/AGC ✅ 内置
视频编解码 手写 H.264/VP8 ✅ 硬件加速
拥塞控制 手写带宽估计 ✅ 内置
加密 手写 SRTP/DTLS ✅ 内置
跨平台互通 ✅ 与浏览器/App 互通

总结

"面对面"这个场景里,@ohos/webrtc 解决了三件事:

  1. NAT 穿透——ICE/STUN/TURN 内置,P2P 直连开箱即用
  2. 音视频质量——3A 音频处理 + 硬件编解码,通话清晰不回声
  3. 跨平台互通——标准 WebRTC 协议,与浏览器、iOS、Android 互通

如果你也在做视频通话、在线会议、互动直播、远程协助等实时音视频场景,@ohos/webrtc 让你站在 Google 十年 RTC 工程积累的肩膀上。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐