共计 11112 个字符,预计需要花费 28 分钟才能阅读完成。
1 微信小程序原生推拉流组件性能简介
本文将介绍如何应用微信小程序原生推拉流组件 \<live-pusher> 和 \<live-player> 进行推拉流,疾速实现一个简略的实时音视频通话。
因为微信小程序原生推拉流组件应用起来比较复杂,举荐开发者应用即构封装的音视频 SDK \<zego-push> 和 \<zego-player> 组件实现视频通话,可参考 实现视频通话。
2 实现微信小程序音视频通话的前提条件
在实现根本的实时音视频性能之前,请确保:
- 已在我的项目中集成 ZEGO Express SDK 即构音视频 SDK,详情请参考 疾速开始 – 集成。
- 已在 ZEGO 控制台 创立我的项目,申请无效的 AppID 和 ServerSecret,详情请参考 控制台 – 项目管理 中的“我的项目信息”。
3 即构音视频 SDK 实现流程
用户通过 ZEGO Express SDK 即构音视频 SDK 进行视频通话的根本流程为:
用户 A、B 退出房间,用户 B 预览并将音视频流推送到 ZEGO 云服务(推流),用户 A 收到用户 B 推送音视频流的告诉之后,在告诉中播放用户 B 的音视频流(拉流)。
3.1 配置微信小程序后盾
在初始化 音视频 SDK 前,须要在 微信公众平台 中进行如下配置:
- 服务器域名配置:在“小程序后盾 > 开发治理 > 开发设置 > 服务器域名”中,依照协定分类,将即构 Server 地址、LogUrl、以及用户业务须要用到的地址填到指定的“request 非法域名”或“socket 非法域名”中。
- 相干性能开启:在“小程序后盾 > 开发治理 > 接口设置 > 接口权限”中,关上 实时播放音视频流 和 实时录制音视频流 性能开关。
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 常见告诉回调。
// 登录房间,胜利则返回 true | |
const result = await zg.loginRoom(roomID, token, {userID, userName}); |
3.4 将本人的音视频流推送到 ZEGO 即构音视频云
3.4.1 初始化小程序组件实例
调用 initContext
接口初始化小程序组件。
小程序组件中用于存储推流属性 pusher 和拉流属性列表 playerList 两个字段须要传给 SDK,SDK 后续将通过传入的两个字段对相应的推拉流作状态及视图更新解决。
- pusher 字段中的属性值请参考 ZegoWxPusherAttributes。
- playerlist 字段中的属性值请参考 ZegoWxPlayerAttributes。
zg.initContext({ | |
wxContext: this, | |
pushAtr: "pusher", // 对象名,对象属性与 live-pusher 中的属性为映射关系 | |
playAtr: "playerList" // 对象名,对象属性与 live-player 中的属性为映射关系 | |
}) |
即构音视频 SDK 在外部会对推拉流实例进行操作以及视图更新,开发者无需保留推拉流实例和调用小程序 setData 接口更新视图,防止与 SDK 发生冲突。后续可通过 getPusherInstance
和 getPlayerInstance
接口获取推拉流实例。
3.4.2 创立对应业务场景的 WXML
依据您的业务场景需要,编写 WXML 文件,创立推拉流组件 \<live-pusher> 和 \<live-player>。
- \<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 房间内流状态变更的告诉”。
// 在 SDK 的回调 roomStreamUpdate 中获取拉流 streamID | |
// 当用户退出或来到房间时,该事件被触发 | |
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
回调中解决推流的开始、失败状态。
// live-pusher 绑定推流事件 | |
onPushStateChange(e) { | |
// 透传推流事件给 SDK | |
zg.updatePlayerState(this.data.publishStreamID, e); | |
}, | |
// 推流后,服务器被动推过来的,流状态更新 | |
// NO_PUBLISH:未推流状态,PUBLISH_REQUESTING:正在申请推流状态,PUBLISHING:正在推流状态 | |
// state: "PUBLISHING" | "NO_PUBLISH" | "PUBLISH_REQUESTING"; | |
zg.on("publisherStateUpdate", (result) => {console.log("publishStateUpdate", result.state); | |
}); |
- 推流网络事件
微信小程序会在 \<live-pusher> 的 bindnetstatus
绑定的办法中告诉出推流网络事件,开发者须要在对应的小程序回调中,调用 SDK 的 updatePlayerNetStatus
接口将推流网络事件透传给 SDK。
// live-pusher 绑定网络状态事件 | |
onPushNetStateChange(e) { | |
// 透传网络状态事件给 SDK | |
zg.updatePlayerNetStatus(this.data.publishStreamID, e); | |
}, | |
// SDK 推流网络品质回调 | |
zg.on("publishQualityUpdate", (streamID, publishStats) => {console.log("publishQualityUpdate", streamID, publishStats); | |
}); |
4.1.5 用户拉取音视频流的状态告诉
- 拉流状态事件
微信小程序会在 \<live-player> 的 bindstatechange
绑定的办法中告诉出拉流状态事件,开发者须要:
a. 在 bindstatechange
绑定的回调函数中,调用 SDK 的 updatePlayerState
接口将拉流状态事件透传给 SDK。
b. 在 SDK 提供的 playerStateUpdate
回调中解决拉流的开始或失败状态。
// live-player 绑定的拉流事件 | |
onPlayStateChange(e) { | |
// 透传拉流事件给 SDK | |
zg.updatePlayerState(e.currentTarget.id, e); | |
}, | |
// 服务器被动推过来的流的播放状态 | |
// 视频播放状态告诉;state: "NO_PLAY" | "PLAY_REQUESTING" | "PLAYING"; | |
zg.on("playerStateUpdate", (result) => {console.log("playStateUpdate", result.state); | |
}); |
- 拉流网络事件
微信小程序会在 \<live-player> 的 bindnetstatus
绑定的办法中告诉出拉流网络事件,开发者须要在对应的小程序回调中,调用 SDK 的 updatePlayerNetStatus
接口将推流网络事件透传给 SDK。
// live-player 绑定网络状态事件 | |
onPlayNetStateChange(e) { | |
// 透传网络状态事件给 SDK | |
zg.updatePlayerNetStatus(playStreamID, e); | |
}, | |
// SDK 拉流网络品质回调 | |
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 调用时序可参考下图: