1 微信小程序原生推拉流组件功能简介
本文将介绍如何使用微信小程序原生推拉流组件 <live-pusher> 和 <live-player> 进行推拉流,快速实现一个简单的实时音视频通话。
由于微信小程序原生推拉流组件使用起来比较复杂,推荐开发者使用即构封装的音视频SDK <zego-push> 和 <zego-player> 组件实现视频通话,可参考 实现视频通话。
2 实现微信小程序音视频通话的前提条件
在实现基本的实时音视频功能之前,请确保:
3 即构音视频SDK实现流程
用户通过 ZEGO Express SDK 即构音视频SDK进行视频通话的基本流程为:
用户 A、B 加入房间,用户 B 预览并将音视频流推送到 ZEGO 云服务(推流),用户 A 收到用户 B 推送音视频流的通知之后,在通知中播放用户 B 的音视频流(拉流)。
3.1 配置微信小程序后台
在初始化 音视频SDK 前,需要在 微信公众平台 中进行如下配置:
3.2 即构音视频SDK初始化
1. 创建音视频通话界面
根据音视频场景需要,为您的项目创建音视频通话的用户界面。我们推荐您在项目中添加如下元素:
- 本地预览窗口
- 远端视频窗口
- 结束按钮
小程序推流组件 <live-pusher> 中的 “video-width” 和 “video-height” 存在兼容性问题,可能会出现设置不生效的情况。
参考界面代码:
<view wx:if="{{canShow== 1}}" class="">
<view class="containerBase">
<live-pusher class="testpusher"
wx:if="{{pusher.url}}"
url="{{pusher.url}}"
mode="{{pusher.mode}}"
autopush="{{pusher.autopush}}"
enable-camera="{{pusher.enableCamera}}"
enable-mic="{{pusher.enableMic}}"
muted="{{!pusher.enableMic}}"
enable-agc="{{pusher.enableAgc}}"
enable-ans="{{pusher.enableAns}}"
zoom="{{pusher.enableZoom}}"
min-bitrate="{{pusher.minBitrate}}"
max-bitrate="{{pusher.maxBitrate}}"
video-width="{{pusher.videoWidth}}"
video-height="{{pusher.videoHeight}}"
beauty="{{pusher.beautyLevel}}"
whiteness="{{pusher.whitenessLevel}}"
orientation="{{pusher.videoOrientation}}"
device-position="{{pusher.frontCamera}}"
remote-mirror="{{pusher.enableRemoteMirror}}"
local-mirror="{{pusher.localMirror}}"
background-mute="{{pusher.enableBackgroundMute}}"
audio-quality="{{pusher.audioQuality}}"
audio-volume-type="{{pusher.audioVolumeType}}"
audio-reverb-type="{{pusher.audioReverbType}}"
waiting-image="{{pusher.waitingImage}}"
beauty-style="{{pusher.beautyStyle}}"
filter="{{pusher.filter}}"
bindstatechange="onPushStateChange"
bindaudiovolumenotify="bindaudiovolumenotify"
bindnetstatus="onPushNetStateChange"
waiting-image="https://storage.zego.im/downloads/pause_publish.png"></live-pusher>
<live-player wx:for="{{playerList}}" wx:key="streamID" id="{{item.id}}"
src= "{{item.url}}"
mode= "RTC"
autoplay= "{{item.autoplay}}"
mute-audio= "{{item.muteAudio}}"
mute-video= "{{item.muteVideo}}"
orientation= "{{item.orientation}}"
object-fit= "{{item.objectFit}}"
min-cache= "{{item.minCache}}"
max-cache= "{{item.maxCache}}"
sound-mode= "{{item.soundMode}}"
enable-recv-message= "{{item.enableRecvMessage}}"
auto-pause-if-navigate= "{{item.autoPauseIfNavigate}}"
auto-pause-if-open-native= "{{item.autoPauseIfOpenNative}}" enable-metadata="true" bindmetadatachange="binddatachange" bindstatechange="onPlayStateChange" bindnetstatus="onPlayNetStateChange"></live-player>
</view>
<view class="index-container">
<view class='input-container'>
<input value="{{roomID}}" bindinput="bindKeyInput" placeholder="请输入房间 ID" placeholder-style='color: #b3b3b3; font-size: 14px;' class="room-input" />
<text class="tip"></text>
</view>
<view class="button-container">
<button bindtap="openRoom" data-role="1" data-option="videoAndAudio" hover-class="none" class="openRoom">
加入房间(推流)
</button>
<button bindtap="logout" hover-class="none">退出房间</button>
</view>
</view>
</view>
<view class="settings">
<button wx:if="{{canShow==0}}" open-type="openSetting" bindopensetting="settingCallback">
授权使用摄像头和麦克风
</button>
</view>
2. 创建音视频SDK引擎
创建 ZegoExpressEngine 引擎实例,将申请到的 AppID 传入参数 “appID”,将获取到的 Server 地址传入参数 “server”。
zg = new ZegoExpressEngine(appID, server);
如果需要注册回调,开发者可根据实际需要,实现 ZegoEvent 中的某些方法,创建引擎后可通过调用 on 接口设置回调。
zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
if (state == 'DISCONNECTED') {
}
if (state == 'CONNECTING') {
}
if (state == 'CONNECTED') {
}
})
3.3 登录音视频房间
1. 获取房间登录 Token
登录房间需要用于验证身份的 Token,获取方式请参考 用户权限控制。如需快速调试,建议使用控制台生成的临时 Token,生成临时 Token 的具体操作请参考 控制台 - 项目管理。
2. 登录音视频房间
您可以调用 SDK 的 loginRoom 接口,传入房间 ID 参数 “roomID”、“token” 和用户参数 “user”,登录房间。您可通过监听 roomStateUpdate 回调实时监控自己在本房间内的连接状态,具体请参考 4.1 常见通知回调 中的“4.1.1 我在房间内的连接状态变化通知”。
roomID 和 user 的参数由您本地生成,但是需要满足以下条件:
- 同一个 AppID 内,需保证 “roomID” 全局唯一。
- 同一个 AppID 内,需保证 “userID” 全局唯一,建议开发者将 “userID” 与自己业务的账号系统进行关联。
为避免错过任何通知,您需要在登录房间前先设置所有的监听回调(如房间状态、用户状态、流状态、推拉流状态等),具体请参考 4.1 常见通知回调 。
const result = await zg.loginRoom(roomID, token, {userID, userName});
3.4 将自己的音视频流推送到 ZEGO 即构音视频云
3.4.1 初始化小程序组件实例
调用 initContext 接口初始化小程序组件。
小程序组件中用于存储推流属性 pusher 和拉流属性列表 playerList 两个字段需要传给 SDK,SDK 后续将通过传入的两个字段对相应的推拉流作状态及视图更新处理。
zg.initContext({
wxContext: this,
pushAtr: "pusher",
playAtr: "playerList"
})
即构音视频SDK 在内部会对推拉流实例进行操作以及视图更新,开发者无需保存推拉流实例和调用小程序 setData 接口更新视图,避免与 SDK 发生冲突。后续可通过 getPusherInstance 和 getPlayerInstance 接口获取推拉流实例。
3.4.2 创建对应业务场景的 WXML
根据您的业务场景需求,编写 WXML 文件,创建推拉流组件 <live-pusher> 和 <live-player>。
WXML 的具体含义与用法请参考微信官网文档中的介绍 WXML。
WXML 中的 pusher 与 playerList,必须与初始化小程序组件 initContext 中定义的这两个字段属性名保持一致,后续 SDK 调用推拉流接口之后才能正确地进行状态及视图更新。
bindstatechange 表示播放状态变化事件;bindaudiovolumenotify 表示播放音量大小通知;bindnetstatus 表示网络状态通知。
<live-pusher class="testpusher"
wx:if="{{pusher.url}}"
url="{{pusher.url}}"
mode="{{pusher.mode}}"
autopush="{{pusher.autopush}}"
enable-camera="{{pusher.enableCamera}}"
enable-mic="{{pusher.enableMic}}"
muted="{{!pusher.enableMic}}"
enable-agc="{{pusher.enableAgc}}"
enable-ans="{{pusher.enableAns}}"
enable-ear-monitor="{{pusher.enableEarMonitor}}"
auto-focus="{{pusher.enableAutoFocus}}"
zoom="{{pusher.enableZoom}}"
min-bitrate="{{pusher.minBitrate}}"
max-bitrate="{{pusher.maxBitrate}}"
video-width="{{pusher.videoWidth}}"
video-height="{{pusher.videoHeight}}"
beauty="{{pusher.beautyLevel}}"
whiteness="{{pusher.whitenessLevel}}"
orientation="{{pusher.videoOrientation}}"
aspect="{{pusher.videoAspect}}"
device-position="{{pusher.frontCamera}}"
remote-mirror="{{pusher.enableRemoteMirror}}"
local-mirror="{{pusher.localMirror}}"
background-mute="{{pusher.enableBackgroundMute}}"
audio-quality="{{pusher.audioQuality}}"
audio-volume-type="{{pusher.audioVolumeType}}"
audio-reverb-type="{{pusher.audioReverbType}}"
waiting-image="{{pusher.waitingImage}}"
beauty-style="{{pusher.beautyStyle}}"
filter="{{pusher.filter}}"
bindstatechange="onPushStateChange"
bindaudiovolumenotify="bindaudiovolumenotify"
bindnetstatus="onPushNetStateChange"
waiting-image="https://storage.zego.im/downloads/pause_publish.png">
</live-pusher>
<live-player wx:for="{{playerList}}" wx:key="streamID" id="{{item.id}}"
src= "{{item.url}}"
mode= "RTC"
autoplay= "{{item.autoplay}}"
mute-audio= "{{item.muteAudio}}"
mute-video= "{{item.muteVideo}}"
orientation= "{{item.orientation}}"
object-fit= "{{item.objectFit}}"
min-cache= "{{item.minCache}}"
max-cache= "{{item.maxCache}}"
sound-mode= "{{item.soundMode}}"
enable-recv-message= "{{item.enableRecvMessage}}"
auto-pause-if-navigate= "{{item.autoPauseIfNavigate}}"
auto-pause-if-open-native= "{{item.autoPauseIfOpenNative}}" enable-metadata="true" bindmetadatachange="binddatachange" bindstatechange="onPlayStateChange" bindnetstatus="onPlayNetStateChange">
</live-player>
3.4.3 推送音视频流到 ZEGO 即构音视频云
必须完成初始化小程序组件实例和创建业务场景的 WXML 之后,才能调用 SDK 接口创建推流和拉流实例。
用户调用 SDK 的 createPusher 接口创建推流实例,并通过调用实例对象上的 start 接口,传入流 ID 参数 “streamID”。您可通过监听 publisherStateUpdate 回调知晓推流是否成功,具体请参考 4.1 常见通知回调 中的“4.1.4 用户推送音视频流的状态通知”。
“streamID” 由您本地生成,但是需要保证:
- 同一个 AppID 下,“streamID” 全局唯一。如果同一个 AppID 下,不同用户各推了一条 “streamID” 相同的流,后推流的用户推流失败。
- “streamID” 长度不超过 256 字节的字符串。仅支持数字,英文字符和 “~”,“!”,“@”,“$”,“%”,“^”,“&”,“*”,“(”,“)”,“_”,“+”,“=”,“-”,“`”,“;”,“’”,“,”,“.”,“<”,“>”,“/”,“\”。
const pusher = zg.createPusher();
pusher.start("streamID_xxx");
3.5 拉取其他用户的音视频
进行视频通话时,我们需要拉取到其他用户的音视频。
用户先调用 getPlayerInstance 接口,根据传入的流 ID 参数 “streamID”,获取 streamID 对应的拉流实例,然后通过调用拉流实例对象的 play 接口开始拉流。您可通过监听 playerStateUpdate 回调知晓是否成功拉取音视频,具体请参考 4.1 常见通知回调 中的“4.1.5 用户拉取音视频流的状态通知”。
远端用户推送的 “streamID” 可以从 roomStreamUpdate 回调中获得,具体回调设置请参考 4.1 常见通知回调 中的“4.1.3 房间内流状态变更的通知”。
zg.on("roomStreamUpdate", (roomID, updateType, streamList) => {
console.log("roomStreamUpdate", roomID, updateType, streamList);
if (updateType === "ADD") {
streamList.forEach(i => {
zg.getPlayerInstance(i.streamID).play();
})
} else {
streamList.forEach(i => {
zg.getPlayerInstance(i.streamID).stop();
})
}
});
4 小程序音视频通话的常用功能
4.1 常见音视频房间通知回调
4.1.1 我在房间内的连接状态变化通知
roomStateUpdate :本地调用 loginRoom 加入房间时,您可通过监听该回调实时监控自己在本房间内的连接状态。
用户可以在回调中根据不同状态处理业务逻辑。
zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
if (state == 'DISCONNECTED') {
}
if (state == 'CONNECTING') {
}
if (state == 'CONNECTED') {
}
})
4.1.2 其他用户进出房间的通知
roomUserUpdate :同一房间内的其他用户进出房间时,您可通过此回调收到通知。登录房间后,当房间内有用户新增或删除时,SDK 会通过该回调通知。
只有调用 loginRoom 接口登录房间时传入 ZegoRoomConfig 配置,且 “userUpdate” 参数取值为 “true” 时,用户才能收到 roomUserUpdate 回调。
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
console.warn(
`roomUserUpdate: room ${roomID}, user ${updateType === 'ADD' ? 'added' : 'left'} `,
JSON.stringify(userList),
);
});
4.1.3 房间内流状态变更的通知
roomStreamUpdate :流状态更新回调。登录房间后,当房间内有用户新推送或删除音视频流时,SDK 会通过该回调通知。
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
if (updateType == 'ADD') {
} else if (updateType == 'DELETE') {
}
});
4.1.4 用户推送音视频流的状态通知
微信小程序会在 <live-pusher> 的 bindstatechange 绑定的方法中通知出推流状态事件,开发者需要:
a. 在 bindstatechange 绑定的回调函数中,调用 SDK 的 updatePlayerState 接口将推流状态事件透传给 SDK。
b. 在 SDK 的 publisherStateUpdate 回调中处理推流的开始、失败状态。
onPushStateChange(e) {
zg.updatePlayerState(this.data.publishStreamID, e);
},
zg.on("publisherStateUpdate", (result) => {
console.log("publishStateUpdate", result.state);
});
微信小程序会在 <live-pusher> 的 bindnetstatus 绑定的方法中通知出推流网络事件,开发者需要在对应的小程序回调中,调用 SDK 的 updatePlayerNetStatus 接口将推流网络事件透传给 SDK。
onPushNetStateChange(e) {
zg.updatePlayerNetStatus(this.data.publishStreamID, e);
},
zg.on("publishQualityUpdate", (streamID, publishStats) => {
console.log("publishQualityUpdate", streamID, publishStats);
});
4.1.5 用户拉取音视频流的状态通知
微信小程序会在 <live-player> 的 bindstatechange 绑定的方法中通知出拉流状态事件,开发者需要:
a. 在 bindstatechange 绑定的回调函数中,调用 SDK 的 updatePlayerState 接口将拉流状态事件透传给 SDK。
b. 在 SDK 提供的 playerStateUpdate 回调中处理拉流的开始或失败状态。
onPlayStateChange(e) {
zg.updatePlayerState(e.currentTarget.id, e);
},
zg.on("playerStateUpdate", (result) => {
console.log("playStateUpdate", result.state);
});
微信小程序会在 <live-player> 的 bindnetstatus 绑定的方法中通知出拉流网络事件,开发者需要在对应的小程序回调中,调用 SDK 的 updatePlayerNetStatus 接口将推流网络事件透传给 SDK。
onPlayNetStateChange(e) {
zg.updatePlayerNetStatus(playStreamID, e);
},
zg.on("playQualityUpdate", (playStreamID, playStats) => {
console.log("playQualityUpdate", playStreamID, playStats);
});
4.2 停止fang jian音视频通话
4.2.1 停止推送/拉取音视频流
1. 停止推流
调用 SDK 的 getPusherInstance 接口获取推流实例,并调用推流实例的 stop 方法停止推流。
zg.getPusherInstance().stop();
2. 停止拉流
调用 SDK 的 getPlayerInstance 接口获取拉流实例,并调用推流实例的 stop 方法停止拉流。
zg.getPlayerInstance(streamID).stop();
4.2.2 退出房间
调用 SDK 的 logoutRoom 接口退出房间。
zg.logoutRoom(roomID);
5 调试视频通话功能
在真机中运行项目,运行成功后,可以看到本端视频画面。
为方便体验,ZEGO 提供了一个 Web 端调试示例 ,在该页面下,输入相同的 AppID、RoomID,输入一个不同的 UserID,即可加入同一房间与真机设备互通。当成功开始音视频通话时,可以听到远端的音频,看到远端的视频画面。
6 视频通话 API 调用时序
整个推拉流过程的 API 调用时序可参考下图:
|