更新记录

1.0.4(2026-04-19)

优化一对一通话。更新文档

1.0.3(2026-04-17)

更新安卓版

1.0.2(2026-04-16)

更新文档,优化一对一通话视图,增加音频设置

查看更多

平台兼容性

uni-app(4.81)

Vue2 Vue2插件版本 Vue3 Vue3插件版本 Chrome Safari app-vue app-nvue app-nvue插件版本 Android iOS iOS插件版本 鸿蒙
1.0.0 1.0.0 - - - 1.0.0 5.0 12 1.0.0 -
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
- - - - - - - - - - - -

RTC VolcEngine 组件

火山引擎实时音视频 SDK UTS 插件,支持 AI 语音通话、视频通话、字幕、录制等功能。

安装

rtc-volcengine 插件放入 uni_modules 目录。


基础用法

<template>
  <view class="container">
    <!-- RTC 组件,会自动创建本地和远端视频视图 -->
    <rtc-volcengine 
      ref="rtcRef" 
      @onEngineReady="onEngineReady"
      @onRoomStateChanged="onRoomStateChanged"
      @onUserJoined="onUserJoined"
      @onUserLeave="onUserLeave"
      @onAudioRouteChanged="onAudioRouteChanged"
      @onLog="onRTCLog"
      @onTokenWillExpire="handleTokenWillExpire"
    />

    <button @click="joinRoom">加入房间</button>
    <button @click="leaveRoom">离开房间</button>
    <button @click="interruptAI">打断AI</button>
    <button @click="toggleMute">静音/取消静音</button>
    <button @click="toggleSpeaker">扬声器/听筒</button>
    <button @click="switchCamera">切换摄像头</button>
  </view>
</template>

<script>
export default {
  data() {
    return {
      isMuted: false,
      isSpeaker: true
    }
  },
  methods: {
    // 初始化并加入房间
    joinRoom() {
      this.$refs.rtcRef.initEngine('YOUR_APP_ID', false)
    },

    // 引擎初始化完成回调
    onEngineReady(e) {
      const { success, message } = e.detail
      if (!success) return

      // 设置音频场景
      this.$refs.rtcRef.setAudioScenario(5)  // AI客户端
      this.$refs.rtcRef.setAnsMode(4)         // 自动降噪
      this.$refs.rtcRef.enablePlaybackDucking(true)
      this.$refs.rtcRef.enableVocalInstrumentBalance(true)
      this.$refs.rtcRef.enableAudioPropertiesReport(500)

      // 设置默认音频路由为扬声器
      this.$refs.rtcRef.setDefaultAudioRoute(3)
      this.$refs.rtcRef.setAudioRoute(-1)

      // 显示本地视频
      this.$refs.rtcRef.showLocalVideo()

      // 加入房间
      this.$refs.rtcRef.joinRoom(
        'ROOM_ID', 'USER_ID', 'TOKEN',
        true, true,    // 发布音频、发布视频
        true, true,    // 订阅音频、订阅视频
        true, true,    // 启动音频采集、启动视频采集
        19             // Call 通话模式
      )
    },

    // 房间状态变化
    onRoomStateChanged(e) {
      const { roomId, userId, state, extraInfo } = e.detail
      // state: 0=加入房间成功, !0=失败/异常退房/警告或错误
      if (state === 0) {
        console.log('加入房间成功')
      } else {
        console.log('房间异常, state=', state)
      }
    },

    // 远端用户加入 - 绑定远端视频
    onUserJoined(e) {
      const remoteUserId = e.detail.userId
      this.$refs.rtcRef.setupRemoteVideo(remoteUserId)
    },

    // 用户离开
    onUserLeave(e) {
      this.$refs.rtcRef.hideRemoteVideo()
    },

    // 离开房间
    leaveRoom() {
      this.$refs.rtcRef.hideLocalVideo()
      this.$refs.rtcRef.hideRemoteVideo()
      this.$refs.rtcRef.leaveRoom()
      this.$refs.rtcRef.destroyEngine()
    },

    // 打断AI说话
    interruptAI() {
      this.$refs.rtcRef.sendInterruptMessage('AI_BOT_ID')
    },

    // 静音/取消静音
    toggleMute() {
      this.isMuted = !this.isMuted
      this.$refs.rtcRef.muteAudioCapture(this.isMuted)
    },

    // 扬声器/听筒切换
    toggleSpeaker() {
      this.isSpeaker = !this.isSpeaker
      this.$refs.rtcRef.setDefaultAudioRoute(this.isSpeaker ? 3 : 2)
      this.$refs.rtcRef.setAudioRoute(-1)
    },

    // 切换摄像头
    switchCamera() {
      this.$refs.rtcRef.switchCamera()
    },

    // 音频路由变化回调
    onAudioRouteChanged(e) {
      const route = e.detail.route
      console.log('音频路由变化:', route)
    },

    // 原生日志回调
    onRTCLog(e) {
      console.log('[Native]', e.detail.message)
    },

    // Token 即将过期
    handleTokenWillExpire() {
      // 调用后端获取新 Token,然后更新
      this.$refs.rtcRef.updateToken(newToken)
    }
  },

  onUnload() {
    this.$refs.rtcRef.leaveRoom()
    this.$refs.rtcRef.destroyEngine()
  }
}
</script>

事件回调列表

所有事件回调的数据在 e.detail 中获取。

事件名 参数 (e.detail) 说明
onEngineReady { success: boolean, message: string } 引擎初始化结果
onRoomStateChanged { roomId, userId, state, extraInfo } 房间状态变化,state: 0=加入房间成功, !0=失败/异常退房/警告或错误
onUserJoined { roomId, userId, elapsed } 远端用户加入
onUserLeave { roomId, userId, reason } 远端用户离开
onLeaveRoom { roomId, stats } 离开房间统计,stats 含 duration/txBytes/rxBytes
onNetworkQuality { roomId, userId, txQuality, rxQuality } 网络质量
onError { errorCode, errorMessage } 错误回调
onLocalAudioProperties { volume } 本地音频音量,需先调用 enableAudioPropertiesReport
onRemoteAudioProperties { userId, volume } 远端音频音量
onSubtitleMessage { userId, text, language, mode, sequence, definite } 字幕消息,需先调用 startSubtitle
onRoomBinaryMessage { msgid, userId, messageType, message } 房间二进制消息,messageType: "subtitle"/"conversation"
onRecordingState { state, errorCode, filePath, duration, fileSize } 录制状态变化
onConnectionStateChanged { state } SDK 与信令服务器连接状态变化
onTokenWillExpire {} Token 即将过期
onLog { message } 原生日志回调,所有 Swift 端日志通过此回调返回
onAudioRouteChanged { route } 音频路由变化,route 值参见下方路由说明

方法列表

引擎管理

方法 参数 返回值 说明
initEngine(appId, isGameScene) appId: string, isGameScene?: boolean (默认 false) void 初始化引擎,结果通过 onEngineReady 事件通知
destroyEngine() - void 销毁引擎,释放所有资源
isReady() - boolean 引擎是否已初始化

房间管理

方法 参数 返回值 说明
joinRoom(roomId, userId, token, ...) 见下方详细参数 void 加入房间
leaveRoom() - void 离开房间,自动停止音视频采集
updateToken(token) token: string void 更新 Token(收到 onTokenWillExpire 时调用)
isJoined() - boolean 是否已加入房间

音频控制

方法 参数 返回值 说明
enableLocalAudio(enable) enable: boolean void 启用/禁用本地音频采集
muteAudioCapture(mute) mute: boolean void 静音/取消静音本地音频采集(采集仍继续,只是不发数据)
setVolume(volume) volume: number void 设置播放音量
setAudioScenario(scenario) scenario: number (0-5) void 设置音频场景,0=默认, 1=聊天室, 2=游戏串流, 3=合唱, 4=教育, 5=AI客户端
enablePlaybackDucking(enable) enable: boolean void 开关音量闪避,开启后检测到远端人声时本地媒体音量自动减弱
enableVocalInstrumentBalance(enable) enable: boolean void 开关音量均衡,开启后人声响度调整为 -16lufs
setAnsMode(mode) mode: number (0-4) void 设置音频降噪模式,0=禁用, 1=微弱, 2=中度, 3=高度(AI降噪), 4=自动
enableAudioPropertiesReport(interval) interval: number (毫秒) void 启用音频属性上报,建议间隔不低于 100ms

音频路由

方法 参数 返回值 说明
setAudioRoute(route) route: number number (0=成功) 强制切换音频播放路由,仅支持扬声器(3)和默认路由(-1)
setDefaultAudioRoute(route) route: number number (0=成功) 设置默认音频路由,仅支持听筒(2)或扬声器(3)
getAudioRoute() - number 获取当前音频路由值

音频路由值说明:

含义 备注
-1 Default 使用 setDefaultAudioRoute 设置的默认路由
1 Headset 有线耳机
2 Earpiece 听筒
3 Speakerphone 扬声器
4 HeadsetBluetooth 蓝牙耳机
5 HeadsetUSB USB耳机

切换扬声器/听筒的正确方式:

// 切换到扬声器
this.$refs.rtcRef.setDefaultAudioRoute(3)  // 设默认路由为扬声器
this.$refs.rtcRef.setAudioRoute(-1)         // 切到默认路由

// 切换到听筒
this.$refs.rtcRef.setDefaultAudioRoute(2)  // 设默认路由为听筒
this.$refs.rtcRef.setAudioRoute(-1)         // 切到默认路由

注意setAudioRoute 仅支持扬声器和默认路由,不能直接传入听筒(2)。切换听筒必须通过 setDefaultAudioRoute(2) + setAudioRoute(-1) 组合实现。

视频控制

方法 参数 返回值 说明
enableLocalVideo(enable) enable: boolean void 启用/禁用本地视频采集
switchCamera() - void 切换前后摄像头
showLocalVideo() - void 显示本地视频小窗
hideLocalVideo() - void 隐藏本地视频小窗
setupRemoteVideo(userId) userId: string void 绑定远端用户视频视图(使用组件内部视图),Swift 端会自动用正确的 streamId 重新绑定
hideRemoteVideo() - void 隐藏远端视频并清除头像占位
toggleVideoLayout() - void 切换大小窗布局(本地大窗↔远端大窗),零布局开销
setVideoOrientation(orientation) orientation: number void 设置视频帧朝向:0=Adaptive(跟随相机), 1=Portrait(竖屏), 2=Landscape(横屏)
setDummyCaptureImagePath(imagePath) imagePath: string void 摄像头关闭时用静态图片填充本地推送视频流,传空字符串停止发送
setRemoteAvatar(imagePath) imagePath: string void 设置远端用户头像占位图,远端未加入时显示。支持本地路径和网络URL(http/https),传空字符串清除
setLocalVideoView(view) view: UIView void 设置本地视频渲染视图(高级用法)
setRemoteVideoView(userId, view) userId: string, view: UIView void 设置远端用户视频渲染视图(高级用法)

消息发送

方法 参数 返回值 说明
sendUserBinaryMessage(userId, jsonString) userId: string, jsonString: string number (消息ID) 发送点对点二进制消息,JSON 字符串会转为二进制发送
sendInterruptMessage(aiUserId) aiUserId: string number (消息ID) 发送打断 AI 的消息,内部使用 ctrl+interrupt 二进制协议

字幕

方法 参数 返回值 说明
startSubtitle(mode, targetLanguage) mode: number (0=识别, 1=翻译), targetLanguage: string void 开始字幕
stopSubtitle() - void 停止字幕

本地录制

方法 参数 返回值 说明
startFileRecording(dirPath, type, fileType) dirPath: string, type?: number (默认2), fileType?: number (默认1) number 开始录制。type: 0=仅音频, 1=仅视频, 2=音视频; fileType: 0=AAC, 1=MP4
stopFileRecording() - number 停止录制

joinRoom 参数说明

joinRoom(
  roomId,            // string - 房间ID
  userId,            // string - 用户ID
  token,             // string - Token
  publishAudio,      // boolean - 是否发布音频,默认 true
  publishVideo,      // boolean - 是否发布视频,默认 true
  subscribeAudio,    // boolean - 是否订阅音频,默认 true
  subscribeVideo,    // boolean - 是否订阅视频,默认 true
  startAudioCapture, // boolean - 是否启动音频采集,默认 true
  startVideoCapture, // boolean - 是否启动视频采集,默认 true
  roomProfile        // number - 房间模式,默认 0 (Communication),进房后不可更改
)

注意joinRoom 不支持回调参数,加入房间的结果通过 onRoomStateChanged 事件获取。当 state === 0 时表示加入成功,state !== 0 时表示失败或异常。

roomProfile 枚举值

模式 说明
0 Communication 通用通信模式
2 Game 游戏语音模式
3 CloudGame 云游戏模式
4 LowLatency 云渲染低延迟模式
6 ChatRoom 语音聊天室
10 InteractivePodcast 互动直播
12 Chorus 合唱模式
14 GameStreaming 游戏串流
16 Meeting 会议模式
17 MeetingRoom 会议室终端
18 Classroom 课堂互动
19 Call 通话模式
20 Live 直播互动

典型场景示例

AI 语音通话 + 字幕 + 录制

<template>
  <rtc-volcengine 
    ref="rtcRef"
    @onEngineReady="onEngineReady"
    @onRoomStateChanged="onRoomStateChanged"
    @onUserJoined="onUserJoined"
    @onRemoteAudioProperties="onRemoteAudioProperties"
    @onSubtitleMessage="onSubtitleMessage"
    @onRoomBinaryMessage="onRoomBinaryMessage"
    @onTokenWillExpire="handleTokenWillExpire"
    @onRecordingState="onRecordingState"
    @onLog="onRTCLog"
  />
</template>

<script>
export default {
  methods: {
    onEngineReady(e) {
      if (!e.detail.success) return

      // 设置 AI 语音场景
      this.$refs.rtcRef.setAudioScenario(5)  // AI客户端
      this.$refs.rtcRef.setAnsMode(4)        // 自动降噪
      this.$refs.rtcRef.enablePlaybackDucking(true)
      this.$refs.rtcRef.enableVocalInstrumentBalance(true)

      // 启用音量回调
      this.$refs.rtcRef.enableAudioPropertiesReport(200)

      // 设置默认音频路由为扬声器
      this.$refs.rtcRef.setDefaultAudioRoute(3)
      this.$refs.rtcRef.setAudioRoute(-1)

      // 加入房间(结果通过 onRoomStateChanged 事件获取)
      this.$refs.rtcRef.joinRoom(
        'ROOM_ID', 'USER_ID', 'TOKEN',
        true, false,   // 发布音频,不发布视频
        true, false,   // 订阅音频,不订阅视频
        true, false,   // 启动音频采集,不启动视频采集
        19             // Call 通话模式
      )
    },

    onRoomStateChanged(e) {
      const { state } = e.detail
      // state: 0=加入房间成功, !0=失败/异常
      if (state === 0) {
        // 加入成功后开启字幕
        this.$refs.rtcRef.startSubtitle(0, '')  // 识别模式
        // 开始录制
        this.$refs.rtcRef.startFileRecording('/path/to/save', 0, 1)  // 仅音频,MP4
      }
    },

    onUserJoined(e) {
      // 远端用户加入,绑定远端视频
      this.$refs.rtcRef.setupRemoteVideo(e.detail.userId)
    },

    onRemoteAudioProperties(e) {
      console.log(`远端 ${e.detail.userId} 音量: ${e.detail.volume}`)
    },

    onSubtitleMessage(e) {
      const { userId, text, definite } = e.detail
      console.log(`字幕 [${userId}]: ${text} (确定: ${definite})`)
    },

    onRoomBinaryMessage(e) {
      const { messageType, message, userId } = e.detail
      if (messageType === 'conversation') {
        console.log(`AI状态 [${userId}]: ${message}`)
      } else if (messageType === 'subtitle') {
        console.log(`字幕消息 [${userId}]: ${message}`)
      }
    },

    onRecordingState(e) {
      const { state, errorCode, filePath } = e.detail
      console.log(`录制状态: ${state}, 路径: ${filePath}`)
    },

    onRTCLog(e) {
      // 原生日志,可用于调试
      console.log('[Native]', e.detail.message)
    },

    // 打断 AI 说话
    interruptAI() {
      this.$refs.rtcRef.sendInterruptMessage('AI_USER_ID')
    },

    // 发送自定义消息给 AI
    sendCustomMessage() {
      const json = JSON.stringify({ type: 'command', action: 'pause' })
      this.$refs.rtcRef.sendUserBinaryMessage('AI_USER_ID', json)
    },

    // Token 过期处理
    handleTokenWillExpire() {
      // 调用后端获取新 Token
      const newToken = fetchNewToken()
      this.$refs.rtcRef.updateToken(newToken)
    }
  }
}
</script>

视频通话示例

<template>
  <rtc-volcengine 
    ref="rtcRef"
    style="width: 750rpx; height: 1000rpx;"
    @onEngineReady="onEngineReady"
    @onRoomStateChanged="onRoomStateChanged"
    @onUserJoined="onUserJoined"
    @onUserLeave="onUserLeave"
    @onAudioRouteChanged="onAudioRouteChanged"
  />
</template>

<script>
export default {
  data() {
    return {
      isMuted: false,
      isVideoOff: false,
      isSpeaker: true
    }
  },
  methods: {
    onEngineReady(e) {
      if (!e.detail.success) return

      // 通话场景设置
      this.$refs.rtcRef.setAudioScenario(5)
      this.$refs.rtcRef.setAnsMode(4)
      this.$refs.rtcRef.enablePlaybackDucking(true)
      this.$refs.rtcRef.enableVocalInstrumentBalance(true)
      this.$refs.rtcRef.enableAudioPropertiesReport(500)

      // 默认扬声器
      this.$refs.rtcRef.setDefaultAudioRoute(3)
      this.$refs.rtcRef.setAudioRoute(-1)

      // 显示本地视频
      this.$refs.rtcRef.showLocalVideo()

      // 加入视频通话
      this.$refs.rtcRef.joinRoom(
        'ROOM_ID', 'USER_ID', 'TOKEN',
        true, true,    // 发布音频+视频
        true, true,    // 订阅音频+视频
        true, true,    // 启动音频+视频采集
        19             // Call 通话模式
      )
    },

    onRoomStateChanged(e) {
      if (e.detail.state === 0) {
        console.log('加入房间成功')
      }
    },

    onUserJoined(e) {
      // 绑定远端视频
      this.$refs.rtcRef.setupRemoteVideo(e.detail.userId)
    },

    onUserLeave(e) {
      this.$refs.rtcRef.hideRemoteVideo()
    },

    // 音频路由变化
    onAudioRouteChanged(e) {
      const routeMap = { '-1': '默认', '1': '有线耳机', '2': '听筒', '3': '扬声器', '4': '蓝牙耳机', '5': 'USB耳机' }
      this.isSpeaker = (String(e.detail.route) === '3')
    },

    // 控制方法
    toggleMute() {
      this.isMuted = !this.isMuted
      this.$refs.rtcRef.muteAudioCapture(this.isMuted)
    },

    toggleVideo() {
      this.isVideoOff = !this.isVideoOff
      this.$refs.rtcRef.enableLocalVideo(!this.isVideoOff)
      this.isVideoOff ? this.$refs.rtcRef.hideLocalVideo() : this.$refs.rtcRef.showLocalVideo()
    },

    switchCamera() {
      this.$refs.rtcRef.switchCamera()
    },

    toggleSpeaker() {
      this.isSpeaker = !this.isSpeaker
      this.$refs.rtcRef.setDefaultAudioRoute(this.isSpeaker ? 3 : 2)
      this.$refs.rtcRef.setAudioRoute(-1)
    },

    leaveRoom() {
      this.$refs.rtcRef.hideLocalVideo()
      this.$refs.rtcRef.hideRemoteVideo()
      this.$refs.rtcRef.leaveRoom()
      this.$refs.rtcRef.destroyEngine()
    }
  },

  onUnload() {
    this.$refs.rtcRef.leaveRoom()
    this.$refs.rtcRef.destroyEngine()
  }
}
</script>

Token 过期处理流程

1. 加入房间时传入 Token
   │
   ▼
2. 正常通话中...
   │
   ▼
3. Token 过期前 30 秒,触发 onTokenWillExpire 回调
   │
   ▼
4. 调用后端接口获取新 Token
   │
   ▼
5. 调用 updateToken(newToken) 更新 Token
   │
   ▼
6. 继续正常通话...

注意事项

  1. 平台支持:支持 iOS 12+ 和 Android
  2. 初始化顺序:必须先调用 initEngine,等待 onEngineReady 回调成功后才能调用其他方法
  3. Token 有效期:建议设置合理的有效期,并在过期前通过 onTokenWillExpire 回调更新
  4. 打断 AIsendInterruptMessage 使用特殊的 ctrl+interrupt 二进制协议,内部已处理
  5. 静音 vs 停用muteAudioCapture(true) 静音但采集继续;enableLocalAudio(false) 完全停止采集
  6. 录制startFileRecording 的 type 和 fileType 可选,默认录制音视频 MP4
  7. 内存管理:离开页面时务必调用 destroyEngine() 释放资源,组件卸载时会自动离开房间
  8. 回调线程:所有回调已在内部切换到主线程,可直接操作 UI
  9. joinRoom 回调joinRoom 不支持传入 success/fail 回调参数,传入会导致 iOS 闪退。加入房间结果请通过 onRoomStateChanged 事件监听(state === 0 表示加入成功
  10. 音频路由setAudioRoute 仅支持扬声器(3)和默认路由(-1),切换听筒必须通过 setDefaultAudioRoute(2) + setAudioRoute(-1) 组合
  11. 远端视频:调用 setupRemoteVideo(userId) 绑定远端视频后,Swift 端会在收到首帧解码时自动用正确的 streamId 重新绑定画布
  12. 原生日志:Swift 端所有日志通过 onLog 事件回调返回,不在 Xcode 控制台打印
  13. 大小窗切换toggleVideoLayout 仅交换渲染目标,不改 LayoutParams,零布局开销,切换非常快
  14. 视频朝向setVideoOrientation 是 SDK 层面的视频帧朝向设置,影响整个 RTC 链路(采集→编码→传输→渲染),不是简单的 View 旋转
  15. 头像占位setRemoteAvatar 在远端未加入时显示头像占位,远端加入后自动隐藏;退出房间时头像会自动清除
  16. 占位图片setDummyCaptureImagePath 在摄像头关闭(stopVideoCapture)后开始推送静态图片,重新开启采集或传空字符串可停止

隐私、权限声明

1. 本插件需要申请的系统权限列表:

iOS: NSCameraUsageDescription, NSMicrophoneUsageDescription, NSPhotoLibraryAddUsageDescription;相机、麦克风、存储权限

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

暂无用户评论。