更新记录

1.1.0(2026-06-16)

1.1.0


平台兼容性

uni-app(5.08)

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

其他

多语言 暗黑模式 宽屏模式

xiaoaping-livekit

基于 LiveKit 的 WebRTC 1v1 音视频通话 UTS 插件,支持 Android & iOS,无需打洞。

功能

  • ✅ 1v1 音视频通话
  • ✅ 切换前/后摄像头
  • ✅ 单独开关摄像头 / 麦克风
  • ✅ Android 分辨率/帧率自定义(H360 / H720 / H1080 等)
  • ✅ 本地/远端视频渲染(视频轨道自动多次重试绑定)
  • ✅ 渲染缩放模式(fit / fill)
  • ✅ 镜像翻转
  • ✅ 切换视频源时自动解绑旧轨道
  • ✅ 清空视频画面(clearView)
  • ✅ 丰富的房间事件回调(含重连成功、取消推流、取消订阅、房间元数据等)

依赖

平台 SDK 版本
Android io.livekit:livekit-android 2.23.1
Android io.livekit:livekit-android-camerax 2.23.1
iOS LiveKitClient (CocoaPod) 2.10.1

快速开始

1. 部署 LiveKit 服务器

# 安装后启动开发服务
livekit-server --dev --bind 0.0.0.0

2. 生成 Token(测试用)

lk token create \
  --api-key devkey --api-secret secret \
  --join --room my-room --identity user1 \
  --valid-for 999h

3. 在 nvue 页面中使用

⚠️ 视频渲染组件必须在 nvue 页面 中使用

import { UTSLiveKitRoom } from '@/uni_modules/xiaoaping-livekit'

const room = new UTSLiveKitRoom()

API

初始化

room.initRoom()

设置事件回调

room.onCallback((resp) => {
  const opt = resp.opt
  switch (opt) {
    case 'onConnect':
      // 连接成功,加入房间
      break
    case 'onFailConnect':
      // 连接失败
      console.log('失败原因:', resp.error)
      break
    case 'onReconnecting':
      // 重连中
      break
    case 'onReconnected':
      // 重连成功
      break
    case 'onDisconnect':
      // 断开连接
      break
    case 'onPublishLocalTrack':
      // 本地推流成功
      // resp.participant.identity, resp.participant.kind (0=音频, 1=视频)
      if (resp.participant.kind === 1) {
        this.showLocalVideo(resp.participant.identity)
      }
      break
    case 'onUnpublishLocalTrack':
      // 本地取消推流
      break
    case 'onParticipantConnected':
      // 对方进入房间
      // resp.participant.identity
      break
    case 'onParticipantDisconnected':
      // 对方离开房间
      break
    case 'onSubscribeRemoteTrack':
      // 收到对方的音视频流
      // resp.participant.identity, resp.publication.kind (0=音频, 1=视频)
      if (resp.publication.kind === 1) {
        this.showRemoteVideo(resp.participant.identity)
      }
      break
    case 'onUnsubscribeRemoteTrack':
      // 取消订阅远端流
      break
    case 'onUpdateSpeakingParticipants':
      // 正在讲话的人列表 resp.speakers[]
      break
    case 'onTrackUpdateMuted':
      // 静音状态变更
      // resp.muted, resp.participant.isMicrophoneEnabled, resp.participant.isCameraEnabled
      break
    case 'onUpdateName':
      // 参与者名称变更
      break
    case 'onUpdateMetadata':
      // 参与者元数据变更
      break
    case 'onUpdateRoomMetadata':
      // 房间元数据变更
      // resp.metadata
      break
  }
})

连接房间

room.connect({
  url: 'wss://your-livekit-server:7880',
  token: 'your-jwt-token'
}, (resp) => {
  if (resp.flag) {
    // 连接成功,打开摄像头和麦克风
    this.openCameraMic()
  } else {
    console.log('连接失败:', resp.error)
  }
})

开启摄像头和麦克风

room.setCameraMic({
  camera: {
    enable: true,
    position: 'front', // 'front' | 'back'
    fps: 30,
    options: {          // 仅 Android 生效
      captureParams: 'H720'  // H360 | H540 | H720 | H1080 | H1440 | H2160
    }
  },
  mic: {
    enable: true
  }
}, () => {
  console.log('摄像头麦克风已开启')
})

单独开关摄像头 (新增)

// 关闭摄像头
room.setCamera({ enabled: false }, (resp) => {
  if (!resp.flag) console.log('操作失败:', resp.error)
})

// 开启摄像头(可指定位置和分辨率)
room.setCamera({
  enabled: true,
  position: 'back',
  fps: 30,
  options: { captureParams: 'H720' }  // 仅 Android 生效
}, (resp) => {
  if (!resp.flag) console.log('操作失败:', resp.error)
})

切换摄像头

room.switchCamera((resp) => {
  if (!resp.flag) {
    console.log('切换失败:', resp.error)
  }
})

开关麦克风

room.setMicrophone({ enabled: false }, (resp) => {
  if (!resp.flag) {
    console.log('操作失败:', resp.error)
  }
})

离开房间

room.disConnect(() => {
  console.log('已离开房间')
})

视频渲染组件

⚠️ 必须在 .nvue 页面中使用

模板

<!-- 本地视频 -->
<xiaoaping-livekit :style="'width:375px;height:500px;'" :params="localParams" />

<!-- 远端视频 -->
<xiaoaping-livekit :style="'width:375px;height:500px;'" :params="remoteParams" />

显示本地视频

// 在 onPublishLocalTrack 回调 kind=1 时调用
showLocalVideo(identity) {
  const newParams = {
    businessArray: [{
      business: 'showLocalView',
      params: {
        identity: identity,
        scaleType: 'fill',  // 'fill' | 'fit',默认 fit
        mirror: true        // 是否镜像,默认 false
      }
    }]
  }
  this.localParams = JSON.stringify(newParams)
}

显示远端视频

// 在 onSubscribeRemoteTrack 回调 kind=1 时调用
showRemoteVideo(identity) {
  const newParams = {
    businessArray: [{
      business: 'showRemoteView',
      params: {
        identity: identity,
        scaleType: 'fit'  // 'fill' | 'fit',默认 fit
      }
    }]
  }
  this.remoteParams = JSON.stringify(newParams)
}

镜像翻转

// 可拼在 showLocalView / showRemoteView 后面,或单独使用
const newParams = {
  businessArray: [
    { business: 'showLocalView', params: { identity: localIdentity } },
    { business: 'setMirror', params: { isMirror: true } }
  ]
}
this.localParams = JSON.stringify(newParams)

设置缩放模式 (新增)

const newParams = {
  businessArray: [
    { business: 'setScalingType', params: { scaleType: 'fill' } }  // 'fill' | 'fit'
  ]
}
this.localParams = JSON.stringify(newParams)

清空视频画面 (新增)

// 解绑当前视频轨道,清空画面(不销毁渲染器)
const newParams = {
  businessArray: [{ business: 'clearView' }]
}
this.localParams = JSON.stringify(newParams)

完整 nvue 页面示例

<template>
  <view class="container">
    <xiaoaping-livekit
      v-if="localParams"
      :style="'width:375px;height:250px;'"
      :params="localParams"
    />
    <xiaoaping-livekit
      v-if="remoteParams"
      :style="'width:375px;height:250px;'"
      :params="remoteParams"
    />
    <button @click="joinRoom">加入房间</button>
    <button @click="leaveRoom">离开房间</button>
    <button @click="toggleMic">切换麦克风</button>
    <button @click="toggleCamera">切换摄像头开关</button>
    <button @click="flipCamera">翻转摄像头</button>
  </view>
</template>

<script>
import { UTSLiveKitRoom } from '@/uni_modules/xiaoaping-livekit'

export default {
  data() {
    return {
      room: null,
      localParams: '',
      remoteParams: '',
      micEnabled: true,
      cameraEnabled: true
    }
  },
  methods: {
    joinRoom() {
      this.room = new UTSLiveKitRoom()
      this.room.initRoom()

      this.room.onCallback((resp) => {
        switch (resp.opt) {
          case 'onConnect':
            this.openCameraMic()
            break
          case 'onPublishLocalTrack':
            if (resp.participant.kind === 1) {
              this.showLocalVideo(resp.participant.identity)
            }
            break
          case 'onSubscribeRemoteTrack':
            if (resp.publication.kind === 1) {
              this.showRemoteVideo(resp.participant.identity)
            }
            break
          case 'onParticipantDisconnected':
            this.remoteParams = ''
            break
        }
      })

      this.room.connect(
        { url: 'wss://192.168.1.100:7880', token: 'YOUR_TOKEN' },
        (resp) => {
          if (!resp.flag) uni.showToast({ title: '连接失败: ' + resp.error })
        }
      )
    },
    openCameraMic() {
      this.room.setCameraMic(
        {
          camera: { enable: true, position: 'front', fps: 30, options: { captureParams: 'H720' } },
          mic: { enable: true }
        },
        () => { console.log('摄像头已开启') }
      )
    },
    showLocalVideo(identity) {
      this.localParams = JSON.stringify({
        businessArray: [{ business: 'showLocalView', params: { identity, mirror: true } }]
      })
    },
    showRemoteVideo(identity) {
      this.remoteParams = JSON.stringify({
        businessArray: [{ business: 'showRemoteView', params: { identity } }]
      })
    },
    leaveRoom() {
      this.room?.disConnect(() => {
        this.localParams = ''
        this.remoteParams = ''
      })
    },
    toggleMic() {
      this.micEnabled = !this.micEnabled
      this.room?.setMicrophone({ enabled: this.micEnabled }, () => {})
    },
    toggleCamera() {
      this.cameraEnabled = !this.cameraEnabled
      this.room?.setCamera({ enabled: this.cameraEnabled }, () => {})
    },
    flipCamera() {
      this.room?.switchCamera(() => {})
    }
  }
}
</script>

事件回调一览

opt 说明 附带字段
onConnect 连接成功 -
onDisconnect 断开连接 -
onReconnecting 重连中 -
onReconnected 重连成功 -
onFailConnect 连接失败 error
onPublishLocalTrack 本地推流成功 participant, publication
onUnpublishLocalTrack 本地取消推流 participant, publication
onSubscribeRemoteTrack 订阅远端流成功 participant, publication
onUnsubscribeRemoteTrack 取消订阅远端流 participant, publication
onParticipantConnected 远端参与者加入 participant
onParticipantDisconnected 远端参与者离开 participant
onUpdateSpeakingParticipants 说话状态变化 speakers[]
onTrackUpdateMuted 静音状态变更 muted, participant
onUpdateName 参与者名称变更 participant
onUpdateMetadata 参与者元数据变更 participant.metadata
onUpdateRoomMetadata 房间元数据变更 metadata

publication.kind: 0=音频, 1=视频
participant.kind(onPublishLocalTrack): 0=音频, 1=视频


注意事项

  1. 需要使用自定义基座打包才能运行(不支持内置基座)
  2. 视频组件必须在 .nvue 文件中使用
  3. Android 需要在 AndroidManifest.xml 中声明摄像头和麦克风权限
  4. iOS 需要在 Info.plist 中声明 NSCameraUsageDescriptionNSMicrophoneUsageDescription
  5. WebSocket 连接建议使用 wss:// 安全协议(生产环境)
  6. Android 分辨率预设 captureParams 支持:H360 H540 H720 H1080 H1440 H2160

隐私、权限声明

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

相机和麦克风

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

使用 LiveKit SDK,详情参考 https://github.com/livekit/livekit

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

暂无用户评论。