AKStream.Next · 文档中心

Web、H5 与 WebView 使用 RTC SDK

Web、H5 与 WebView 使用 RTC SDK

Web、移动 H5、Android WebView 和 iOS WKWebView 的会议核心使用同一个 @akstream/rtc-web-sdk。WebView 宿主仍要负责证书信任、相机/麦克风授权、前后台和需要的原生共享能力。正式服务地址使用可被设备信任的 HTTPS;localhost 的开发例外不能照搬到手机局域网地址。

flowchart LR
    A["业务后端给入会票据"] --> B["SDK join 与准入"]
    B --> C["远端 onRemoteTrack"]
    C --> D["页面 attachRemoteMedia"]
    D --> E["离会时 SDK leave 并移除视图"]

先做只看入会

从同一批 SDK 交付物安装 Web 包。serverUrl、roomId、一次性 accessTicket 由你的业务后端在用户通过授权后返回,票据不要放在可分享的网页 URL。

交付方提供 npm tarball 时,在应用根目录执行 npm install ./vendor/akstream-rtc-web-sdk.tgz;使用源码包时保留包内 src、dist 和离线白板资源,不要只复制入口 JS。公共 npm 上同名包的版本号不能代替本次交付核对。

<div id="remote"></div>
<p id="meeting-status" role="status"></p>

下面的代码放在有 ESM 打包器的页面模块中,meeting 是业务后端返回的入会信息:

import { AkRtcWebClient } from '@akstream/rtc-web-sdk'

const remote = document.getElementById('remote')
const status = document.getElementById('meeting-status')
const views = new Map()
const client = new AkRtcWebClient(meeting.serverUrl, {
  onState: (state, detail) => { status.textContent = detail || state },
  onRemoteTrack: ({ subscriptionId, track }) => {
    const element = document.createElement(track.kind === 'audio' ? 'audio' : 'video')
    element.autoplay = true
    if (element instanceof HTMLVideoElement) element.playsInline = true
    remote.append(element)
    views.set(subscriptionId, element)
    void client.attachRemoteMedia(subscriptionId, element)
  },
  onRemoteTrackRemoved: id => {
    const element = views.get(id)
    if (element) { client.detachRemoteMedia(id, element); element.remove() }
    views.delete(id)
  }
})

const joined = await client.join(meeting.roomId, meeting.accessTicket, { platform: 'pc-web' })
if (joined.admissionStatus === 'Waiting') status.textContent = '等待主持人准入'

// 页面离开时调用,并移除自己创建的视图。
async function leaveMeeting() {
  await client.leave()
  for (const element of views.values()) element.remove()
  views.clear()
}

成功时,准入后能看到房间成员与远端发布;只看模式无需申请本地摄像头和麦克风。等只看成功后,再由用户点击开启采集:startCameraAndMicrophone({audio:true,video:true}),并把返回的流交给 attachLocalPreview。拒绝系统授权时保留只看能力,不要显示“已开麦”。

从只看切到真实发布

页面放一个带用户手势的“开启摄像头和麦克风”按钮。点击时先判断 SDK 返回的实际会议能力和主持限制,再调用 startCameraAndMicrophone({audio:true,video:true});将返回的 MediaStream 交给 attachLocalPreview(localVideo, stream)。播放器上的本地预览应静音,避免扬声器回授。随后请第二台设备确认确实收到了视频帧与声音;只看本机预览不足以证明 WHIP 已发布成功。

关闭摄像头和麦克风分别使用 setTrackEnabled('CameraVideo', false)、setTrackEnabled('MicrophoneAudio', false)。按钮文字以 onLocalMediaState 的实际状态更新,不要点击后自己翻转布尔值。对方的音频元素可能受浏览器自动播放策略限制;若看得到画面却无声,先要求用户点击页面完成播放激活,再检查接收统计、输出设备与音量。

屏幕共享只能从用户点击事件调用 startScreenShare(),并由用户在浏览器选择屏幕或窗口。摄像头、麦克风和屏幕是不同发布;停止共享只调用 stopScreenShare()。一个成员同时发两路视频时,每一路都要有独立视图和 publicationId。

页面负责什么

  • 每个远端发布用自己的 publicationId 区分摄像头和屏幕,用 subscriptionId 管视图绑定;同名成员不能把两路合成一张卡片。
  • 静音、相机和共享状态以 SDK 回调的实际结果更新按钮。共享屏幕需要用户手势和系统选择器。
  • 页面布局和视觉效果由业务应用决定;SDK 提供媒体、状态、录制数据与资源接口。录制状态可用 getContinuousRecording() 查询,并通过 onContinuousRecordingChanged 接收变更,但新接口需服务端与 SDK 同批更新。
  • 离会、路由切换和页面销毁应走同一清理路径;重复创建客户端会造成多条会话。

Android WebView 需要宿主处理相机/麦克风权限请求并只授权用户实际允许的资源;iOS WKWebView 同样需要宿主处理媒体采集权限。原生宿主还负责前后台、音频路由和平台证书信任。Web SDK 不会绕过系统授权,也不能把局域网 HTTP 页面当成安全的正式采集环境。

Web Demo 展示了一种宿主写法,不是生产业务身份系统。需要下载会议录像与附件时,使用独立档案授权,不能复用入会票据。

公开的 AkRtcWebClient 方法、入参出参及全部重要事件见Web/H5 函数参考;主持人控制 payload 见会议动作,会后档案方法见档案 SDK。

失败时从哪里查

现象 先检查 页面应怎样处理
入会返回 Waiting 房间等候室与主持准入 只显示等待,不提前开启采集
401 或票据已消费 是否复用了同一张入会票据 向业务后端取新票,不循环重放
本机有预览,对方没视频 发布状态、WHIP/ICE、媒体节点和编码 保留本地预览,显示发布失败原因
接收有画面没声音 浏览器播放限制、接收音频包、输出设备 给用户一个“点击开启声音”入口
WebView 只在真机失败 宿主证书、系统采集授权、原生音频路由 分别记录系统权限和 SDK 错误,避免归因混乱