1 WebRTC音視頻通話功能簡介
本文介紹如何基于WebRTC快速實作一個簡單的實時音視頻通話,
在開始之前,您可以先了解一些實時音視頻推拉流相關的基礎概念:
- 流:一組按指定編碼格式封裝的音視頻資料內容,一個流可以包含幾個軌道,比如視頻和音頻軌道,
- 推流:把采集階段封包好的音視頻資料流推送到 ZEGO 實時音視頻云的程序,
- 拉流:從 ZEGO 實時音視頻云將已有音視頻資料流拉取播放的程序,
- 房間:是 ZEGO 提供的音視頻空間服務,用于組織用戶群,同一房間內的用戶可以互相收發實時音視頻及訊息,
- 用戶需要先登錄某個房間,才能進行音視頻推流、拉流操作,
- 用戶只能收到自己所在房間內的相關訊息(用戶進出、音視頻流變化等),
更多相關概念可參考即構官網關于音視頻SDK的介紹 術語說明,
2 實作WebRTC視頻通話的前提條件
在實作基本的WebRTC實時音視頻功能之前,請確保:
- 已在專案中集成 ZEGO Express SDK,詳情請參考 快速開始 - 集成,
- 已在 ZEGO 控制臺 創建專案,申請有效的 AppID 和 ServerSecret,詳情請參考 控制臺 - 專案管理 中的“專案資訊”,
3 WebRTC音視頻通話示例代碼
我們提供了一個實作了WebRTC音視頻通話基本流程的完整示例 HTML 檔案,可作為WebRTC開發程序中的參考,
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Zego Express Video Call</title>
<!-- 此處需要改成正確的 SDK 版本號 -->
<script src="https://www.cnblogs.com/zegodeveloper/archive/2022/07/27/ZegoExpressWebRTC-x.x.x.js"></script>
<style type="text/css">
h1,
h4 {
text-align: center;
}
.video-wrapper {
width: 610px;
margin: 0 auto;
}
.video-wrapper h4 {
width: 300px;
display: inline-block;
position: relative;
}
#remote-video, #local-video {
width: 300px;
height: 270px;
display: inline-block;
position: relative;
}
.video-wrapper video {
height: auto;
}
</style>
</head>
<body>
<h1>
Zego RTC Video Call
</h1>
<div >
<h4>Local video</h4>
<h4>Remote video</h4>
<div id="local-video"></div>
<div id="remote-video"></div>
</div>
<script>
// 檔案中的 js 示例代碼可粘貼至此處
// 專案唯一標識 AppID,Number 型別,請從 ZEGO 控制臺獲取
let appID = 0
// 接入服務器地址 Server,String 型別,請從 ZEGO 控制臺獲取(獲取方式請參考上文“前提條件”)
let server = ""
// 初始化實體
const zg = new ZegoExpressEngine(appID, server);
zg.setDebugVerbose(false)
// 房間狀態更新回呼
// 此處在登錄房間成功后,立即進行推流,在實作具體業務時,您可選擇其他時機進行推流,只要保證當前房間連接狀態是連接成功的即可,
// 房間狀態更新回呼
zg.on('roomStateChanged', async (roomID, reason, errorCode, extendedData) => {
if (reason == 'LOGINED') {
console.log("與房間連接成功,只有當房間狀態是連接成功時,才能進行推流、拉流等操作,")
}
})
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
// 其他用戶進出房間的通知
});
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
// 房間內其他用戶音視頻流變化的通知
if (updateType == 'ADD') {
// 流新增,開始拉流
// 此處演示拉取流新增的串列中第一條流的音視頻
const streamID = streamList[0].streamID;
// streamList 中有對應流的 streamID
const remoteStream = await zg.startPlayingStream(streamID);
// 創建媒體流播放組件
const remoteView = zg.createRemoteStreamView(remoteStream);
remoteView.play("remote-video", {enableAutoplayDialog:true});
} else if (updateType == 'DELETE') {
// 流洗掉,通過流洗掉串列 streamList 中每個流的 streamID 進行停止拉流,
const streamID = streamList[0].streamID;
zg.stopPlayingStream(streamID)
}
});
// 登錄房間,成功則回傳 true
// userUpdate 設定為 true 才能收到 roomUserUpdate 回呼,
let userID = "user1"; // userID 用戶自己設定,必須保證全域唯一
let userName = "user1";// userName 用戶自己設定,沒有唯一性要求
let roomID = "123"; // roomID 用戶自己設定,必須保證全域唯一
// token 由用戶自己的服務端生成,為了更快跑通流程,可以通過即構控制臺 https://console.zego.im/ 獲取臨時的音視頻 token,token 為字串
let token = ``;
zg.loginRoom(roomID, token, { userID, userName: userID }, { userUpdate: true }).then(async result => {
if (result == true) {
console.log("login success");
// 與房間連接成功,只有當房間狀態是連接成功時,才能進行推流、拉流等操作,
// 創建流、預覽
// 呼叫 createStream 介面后,需要等待 ZEGO 服務器回傳流媒體物件才能執行后續操作
const localStream = await zg.createStream();
// 創建媒體流播放組件
const localView = zg.createLocalStreamView(localStream);
localView.play("local-video", {enableAutoplayDialog:true});
// 開始推流,將自己的音視頻流推送到 ZEGO 音視頻云,此處 streamID 由用戶定義,需全域唯一
let streamID = new Date().getTime().toString();
zg.startPublishingStream(streamID, localStream)
}
});
// // 登錄房間的第二種寫法
// (async function main(){
// await zg.loginRoom(roomID, token, { userID, userName: userID }, { userUpdate: true })
// })()
</script>
</body>
</html>
4 WebRTC音視頻通話實作流程
以用戶 A 拉取用戶 B 的流為例,一次簡單的WebRTC實時音視頻通話主要流程如下:
- 用戶 A 創建實體,登錄房間,(登錄成功后,可預覽自己的畫面并推流,)
- 用戶 B 創建實體,登錄同一個房間,登錄成功后,用戶 B 開始推流,此時 SDK 會觸發
roomStreamUpdate回呼,表示房間內有流的變化, - 用戶 A 可通過監聽
roomStreamUpdate回呼,當回呼通知有流新增時,獲取用戶 B 的流 ID,來拉取播放用戶 B 剛剛推送的流,

4.1 創建WebRTC實時音視頻通話界面
為方便實作基本的WebRTC實時音視頻功能,您可參考WebRTC實時音視頻的示例代碼和下圖實作一個簡單實時音視頻功能的頁面,

打開或新建 “index.html” 頁面檔案,并拷貝以下代碼到檔案中,
<html>
<head>
<meta charset="UTF-8">
<title>Zego Express Video Call</title>
<style type="text/css">
* {
font-family: sans-serif;
}
h1,
h4 {
text-align: center;
}
#local-video, #remote-video {
width: 400px;
height: 300px;
border: 1px solid #dfdfdf;
}
#local-video {
position: relative;
margin: 0 auto;
display: block;
}
#remote-video {
display: flex;
margin: auto;
position: relative !important;
}
</style>
</head>
<body>
<h1>
Zego RTC Video Call
</h1>
<h4>Local video</h4>
<div id="local-video"></div>
<h4>Remote video</h4>
<div id="remote-video"></div>
<script>
// 檔案中的 js 示例代碼可粘貼至此處
// const zg = new ZegoExpressEngine(appID, server);
</script>
</body>
</html>
4.2 創建引擎并監聽回呼
-
創建并初始化一個
ZegoExpressEngine的實體,將您專案的 AppID 傳入引數 “appID”,Server 傳入引數 “server”, -
即構實時音視頻SDK 提供如房間連接狀態、音視頻流變化、用戶進出等通知回呼,為避免錯過任何通知,您需要在創建 ZegoExpressEngine 后立即監聽回呼,
// 專案唯一標識 AppID,Number 型別,請從 ZEGO 控制臺獲取
let appID = ;
// 接入服務器地址 Server,String 型別,請從 ZEGO 控制臺獲取(獲取方式請參考上文“前提條件”)
let server = "";
// 初始化實體
const zg = new ZegoExpressEngine(appID, server);
// 房間狀態更新回呼
zg.on('roomStateChanged', (roomID, reason, errorCode, extendData) => {
if (reason == 'LOGINING') {
// 登錄中
} else if (reason == 'LOGINED') {
// 登錄成功
//只有當房間狀態是登錄成功或重連成功時,推流(startPublishingStream)、拉流(startPlayingStream)才能正常收發音視頻
//將自己的音視頻流推送到 ZEGO 音視頻云
} else if (reason == 'LOGIN_FAILED') {
// 登錄失敗
} else if (reason == 'RECONNECTING') {
// 重連中
} else if (reason == 'RECONNECTED') {
// 重連成功
} else if (reason == 'RECONNECT_FAILED') {
// 重連失敗
} else if (reason == 'KICKOUT') {
// 被踢出房間
} else if (reason == 'LOGOUT') {
// 登出成功
} else if (reason == 'LOGOUT_FAILED') {
// 登出失敗
}
});
//房間內其他用戶進出房間的通知
//只有呼叫 loginRoom 登錄房間時傳入 ZegoRoomConfig,且 ZegoRoomConfig 的 userUpdate 引數為 “true” 時,用戶才能收到 roomUserUpdate回呼,
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
if (updateType == 'ADD') {
for (var i = 0; i < userList.length; i++) {
console.log(userList[i]['userID'], '加入了房間:', roomID)
}
} else if (updateType == 'DELETE') {
for (var i = 0; i < userList.length; i++) {
console.log(userList[i]['userID'], '退出了房間:', roomID)
}
}
});
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
// 房間內其他用戶音視頻流變化的通知
});
4.3 檢測瀏覽器WebRTC兼容性
考慮到不同的瀏覽器對 WebRTC 的兼容性不同,在實作實時音視頻推拉流功能之前,您需要檢測瀏覽器能否正常運行 WebRTC,
您可以呼叫 checkSystemRequirements 介面檢測瀏覽器的兼容性,檢測結果的含義,請參考 ZegoCapabilityDetection 介面下的引數描述,
const result = await zg.checkSystemRequirements();
// 回傳的 result 為兼容性檢測結果, webRTC 為 true 時表示支持 webRTC,其他屬性含義可以參考介面 API 檔案,
console.log(result);
// {
// webRTC: true,
// customCapture: true,
// camera: true,
// microphone: true,
// videoCodec: { H264: true, H265: false, VP8: true, VP9: true },
// screenSharing: true,
// errInfo: {}
// }
您還可以通過 ZEGO 提供的實時音視頻推拉流在線檢測工具 在線檢測工具,在需要檢測的瀏覽器中打開,直接檢測瀏覽器的兼容性,請參考 瀏覽器兼容性說明 獲取 音視頻SDK 支持的瀏覽器兼容版本,
4.4 登錄房間
1. 生成 Token
登錄房間需要用于驗證身份的 Token,開發者可直接在 ZEGO 控制臺獲取臨時 Token(有效期為 24 小時)來使用,詳情請參考 控制臺 - 專案管理 中的 “專案資訊”,
臨時 Token 僅供除錯,正式上線前,請從開發者的業務服務器生成 Token,詳情可參考 使用 Token 鑒權,
2. 登錄房間
呼叫 loginRoom 介面,傳入房間 ID 引數 “roomID”、“token” 和用戶引數 “user”,根據實際情況傳入引數 “config”,登錄房間,
- “roomID”、“userID” 和 “userName” 引數的取值都為自定義,
- “roomID” 和 “userID” 都必須唯一,建議開發者將 “userID” 設定為一個有意義的值,可將其與自己的業務賬號系統進行關聯,
- 只有呼叫
loginRoom介面登錄房間時傳入ZegoRoomConfig配置,且 “userUpdate” 引數取值為 “true” 時,用戶才能收到roomUserUpdate回呼,
// 登錄房間,成功則回傳 true
// userUpdate 設定為 true 才能收到 roomUserUpdate 回呼,
let userID = Util.getBrow() + '_' + new Date().getTime();
let userName = "user0001";
let roomID = "0001";
let token = ;
// 為避免錯過任何通知,您需要在登錄房間前先監聽用戶加入/退出房間、房間連接狀態變更、推流狀態變更等回呼,
zg.on('roomStateChanged', async (roomID, reason, errorCode, extendedData) => {
})
zg.loginRoom(roomID, token, { userID, userName: userID }, { userUpdate: true }).then(result => {
if (result == true) {
console.log("login success")
}
});
您可以監聽 roomStateChanged 回呼實時監控自己與房間的連接狀態,只有當房間狀態是連接成功時,才能進行推流、拉流等操作,
4.5 預覽自己的畫面,并推送到 ZEGO 音視頻云
- 創建流并預覽自己的畫面
開始推流前需要創建本端的音視頻流,呼叫 createStream 介面獲取媒體流物件,默認會采集攝像頭畫面和麥克風聲音,媒體流物件可以使用 createLocalStreamView 創建本地媒體流播放組件進行播放,也可以通過 video 元素 srcObject 屬性賦值進行播放,
- 需等待
createStream介面回傳流媒體物件后,再將自己的音視頻流推送到 ZEGO 音視頻云,
呼叫 startPublishingStream 介面,傳入 “streamID” 和創建流得到的流物件 “localStream”,向遠端用戶發送本端的音視頻流,
“streamID” 由您本地生成,但是需要保證同一個 AppID 下,“streamID” 全域唯一,如果同一個 AppID 下,不同用戶各推了一條 “streamID” 相同的流,會導致后推流的用戶推流失敗,
// 此處在登錄房間成功后,立即進行推流,在實作具體業務時,您可選擇其他時機進行推流,只要保證當前房間連接狀態是連接成功的即可,
zg.loginRoom(roomID, token, { userID, userName: userID }, { userUpdate: true }).then(async result => {
if (result == true) {
console.log("login success")
// 創建流、預覽
// 呼叫 createStream 介面后,需要等待 ZEGO 服務器回傳流媒體物件才能執行后續操作
const localStream = await zg.createStream();
// 創建媒體流播放組件物件,用于預覽本地流
const localView = zg.createLocalStreamView(localStream);
// 將播放組件掛載到頁面,"local-video" 為組件容器 DOM 元素的 id ,
localView.play("local-video");
// 開始推流,將自己的音視頻流推送到 ZEGO 音視頻云
let streamID = new Date().getTime().toString();
zg.startPublishingStream(streamID, localStream)
}
});
(可選)設定音視頻采集引數
通過屬性設定相關采集引數
可根據需要通過 createStream 介面中的如下屬性設定音視頻相關采集引數,詳情可參考 自定義視頻采集:
-
camera:攝像頭麥克風采集流相關配置 -
screen:螢屏捕捉采集流相關配置 -
custom:第三方流采集相關配置
4.6 拉取其他用戶的音視頻
進行視頻通話時,我們需要拉取到其他用戶的音視頻,
房間內有其他用戶加入時,SDK 會觸發 roomStreamUpdate 回呼,通知房間內有流新增,基于此可獲取其他用戶的 “streamID”,此時,呼叫 startPlayingStream 介面根據傳入的其他用戶的 “streamID”,拉取遠端已推送到 ZEGO 服務器的音視頻畫面,若需要從 CDN 拉流,可參考 使用 CDN 直播,
// 流狀態更新回呼
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
// 當 updateType 為 ADD 時,代表有音視頻流新增,此時可以呼叫 startPlayingStream 介面拉取播放該音視頻流
if (updateType == 'ADD') {
// 流新增,開始拉流
// 這里為了使示例代碼更加簡潔,我們只拉取新增的音視頻流串列中第的第一條流,在實際的業務中,建議開發者回圈遍歷 streamList ,拉取每一條音視頻流
const streamID = streamList[0].streamID;
// streamList 中有對應流的 streamID
const remoteStream = await zg.startPlayingStream(streamID);
// 創建媒體流播放組件物件,用于播放遠端媒體流 ,
const remoteView = zg.createRemoteStreamView(remoteStream);
// 將播放組件掛載到頁面,"remote-video" 為組件容器 DOM 元素的 id ,
remoteView.play("remote-video");
} else if (updateType == 'DELETE') {
// 流洗掉,停止拉流
}
});
- 部分瀏覽器因自動播放限制策略問題,使用
ZegoStreamView媒體流播放組件進行播放媒體流可能受阻,SDK 默認會在界面上彈窗提示恢復播放, - 您可以將 ZegoStreamView.play() 方法的第二個引數 options.enableAutoplayDialog 設定為 false 關閉自動彈窗,通過在
autoplayFailed事件回呼中,在頁面上顯示一個按鈕,引導用戶點擊恢復播放,
至此,您已經成功實作了簡單的實時音視頻通話,可在瀏覽器中打開 "index.html",體驗實時音視頻功能,
5 實時音視頻SDK常用功能
5.1 常用通知回呼
// 房間連接狀態更新回呼
// 本地呼叫 loginRoom 加入房間時,您可通過監聽 roomStateChanged 回呼實時監控自己在本房間內的連接狀態,
zg.on('roomStateChanged', (roomID, reason, errorCode, extendData) => {
if (reason == 'LOGINING') {
// 登錄中
} else if (reason == 'LOGINED') {
// 登錄成功
//只有當房間狀態是登錄成功或重連成功時,推流(startPublishingStream)、拉流(startPlayingStream)才能正常收發音視頻
//將自己的音視頻流推送到 ZEGO 音視頻云
} else if (reason == 'LOGIN_FAILED') {
// 登錄失敗
} else if (reason == 'RECONNECTING') {
// 重連中
} else if (reason == 'RECONNECTED') {
// 重連成功
} else if (reason == 'RECONNECT_FAILED') {
// 重連失敗
} else if (reason == 'KICKOUT') {
// 被踢出房間
} else if (reason == 'LOGOUT') {
// 登出成功
} else if (reason == 'LOGOUT_FAILED') {
// 登出失敗
}
});
//房間內其他用戶推送的音視頻流新增/減少的通知
//自己推送的流不能在這里接收到通知
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
if (updateType == 'ADD') {
// 流新增
for (var i = 0; i < streamList.length; i++) {
console.log('房間',roomID,'內新增了流:', streamList[i]['streamID'])
}
const message = "其他用戶的視頻流streamID: " + streamID.toString();
} else if (updateType == 'DELETE') {
// 流洗掉
for (var i = 0; i < streamList.length; i++) {
console.log('房間',roomID,'內減少了流:', streamList[i]['streamID'])
}
}
});
//房間內其他用戶進出房間的通知
//只有呼叫 loginRoom 登錄房間時傳入 ZegoRoomConfig,且 ZegoRoomConfig 的 userUpdate 引數為 “true” 時,用戶才能收到 roomUserUpdate回呼,
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
if (updateType == 'ADD') {
for (var i = 0; i < userList.length; i++) {
console.log(userList[i]['userID'], '加入了房間:', roomID)
}
} else if (updateType == 'DELETE') {
for (var i = 0; i < userList.length; i++) {
console.log(userList[i]['userID'], '退出了房間:', roomID)
}
}
});
//用戶推送音視頻流的狀態通知
//用戶推送音視頻流的狀態發生變更時,會收到該回呼,如果網路中斷導致推流例外,SDK 在重試推流的同時也會通知狀態變化,
zg.on('publisherStateUpdate', result => {
// 推流狀態更新回呼
var state = result['state']
var streamID = result['streamID']
var errorCode = result['errorCode']
var extendedData = https://www.cnblogs.com/zegodeveloper/archive/2022/07/27/result['extendedData']
if (state == 'PUBLISHING') {
console.log('成功推送音視頻流:', streamID);
} else if (state == 'NO_PUBLISH') {
console.log('未推送音視頻流');
} else if (state == 'PUBLISH_REQUESTING') {
console.log('請求推送音視頻流:', streamID);
}
console.log('錯誤碼:', errorCode,' 額外資訊:', extendedData)
})
//推流質量回呼,
//成功推流后,您會定時收到回呼音視頻流質量資料(如解析度、幀率、碼率等),
zg.on('publishQualityUpdate', (streamID, stats) => {
// 推流質量回呼
console.log('流質量回呼')
})
//用戶拉取音視頻流的狀態通知
//用戶拉取音視頻流的狀態發生變更時,會收到該回呼,如果網路中斷導致拉流例外,SDK 會自動進行重試,
zg.on('playerStateUpdate', result => {
// 拉流狀態更新回呼
var state = result['state']
var streamID = result['streamID']
var errorCode = result['errorCode']
var extendedData = https://www.cnblogs.com/zegodeveloper/archive/2022/07/27/result['extendedData']
if (state == 'PLAYING') {
console.log('成功拉取音視頻流:', streamID);
} else if (state == 'NO_PLAY') {
console.log('未拉取音視頻流');
} else if (state == 'PLAY_REQUESTING') {
console.log('請求拉取音視頻流:', streamID);
}
console.log('錯誤碼:', errorCode,' 額外資訊:', extendedData)
})
//拉取音視頻流時的質量回呼,
//成功拉流后,您會定時收到拉取音視頻流時的質量資料通知(如解析度、幀率、碼率等),
zg.on('playQualityUpdate', (streamID,stats) => {
// 拉流質量回呼
})
//收到廣播訊息的通知
zg.on('IMRecvBroadcastMessage', (roomID, chatData) => {
console.log('廣播訊息IMRecvBroadcastMessage', roomID, chatData[0].message);
alert(chatData[0].message)
});
//收到彈幕訊息的通知
zg.on('IMRecvBarrageMessage', (roomID, chatData) => {
console.log('彈幕訊息IMRecvBroadcastMessage', roomID, chatData[0].message);
alert(chatData[0].message)
});
//收到自定義信令訊息的通知
zg.on('IMRecvCustomCommand', (roomID, fromUser, command) => {
console.log('自定義訊息IMRecvCustomCommand', roomID, fromUser, command);
alert(command)
});
5.2 停止音視頻通話
1. 停止推流、銷毀流
呼叫 stopPublishingStream 介面停止向遠端用戶發送本端的音視頻流,呼叫 destroyStream 介面銷毀創建的流資料,銷毀流后開發需自行銷毀 video(停止采集),
// 根據本端 streamID 停止推流
zg.stopPublishingStream(streamID)
// localStream 是呼叫 createStream 介面獲取的 MediaStream 物件
zg.destroyStream(localStream)
2. 停止拉流
呼叫 stopPlayingStream 介面停止拉取遠端推送的音視頻流,
// 流狀態更新回呼
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
if (updateType == 'ADD') {
// 流新增,開始拉流
} else if (updateType == 'DELETE') {
// 流洗掉,通過流洗掉串列 streamList 中每個流的 streamID 進行停止拉流,
const streamID = streamList[0].streamID;
zg.stopPlayingStream(streamID)
}
});
3. 退出房間
呼叫 logoutRoom 介面退出房間,
zg.logoutRoom(roomID)
以上整個推拉流程序的 API 呼叫時序可參考下圖:

6 除錯視頻通話功能
在真機中運行專案,運行成功后,可以看到本端視頻畫面,
為方便體驗,ZEGO 提供了一個 Web 端除錯示例 ,在該頁面下,輸入相同的 AppID、RoomID,輸入一個不同的 UserID,即可加入同一房間與真機設備互通,當成功開始音視頻通話時,可以聽到遠端的音頻,看到遠端的視頻畫面,
7 獲取音視頻SDK更多支持
獲取本文的Demo、開發檔案、技術支持,訪問即構檔案中心
近期有開發規劃的開發者可上即構官網查看,恰逢即構七周年全線音視頻產品1折的優惠,聯系商務獲取RTC產品優惠;
音視頻場景解決方案分享,更多詳情可搜索官網(https://zegoguanwang.datasink.sensorsdata.cn/t/pB)轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/500462.html
標籤:其他
上一篇:【cesium】entity屬性和時許系結:SampledProperty方法簡單使用
下一篇:js 關于console物件
