1 微信小程式原生推拉流組件功能簡介 本文將介紹如何使用微信小程式原生推拉流組件 <live-pusher> 和 <live-player> 進行推拉流,快速實現一個簡單的實時音視頻通話。 由於微信小程式原生推拉流組件使用起來比較複雜,推薦開發者使用即構封裝的音視頻SDK <zego-push> 和 ...
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 調用時序可參考下圖: