1 WebRTC音视频通话性能简介

本文介绍如何基于WebRTC疾速实现一个简略的实时音视频通话。

在开始之前,您能够先理解一些实时音视频推拉流相干的根底概念:

  • 流:一组按指定编码格局封装的音视频数据内容。一个流能够蕴含几个轨道,比方视频和音频轨道。
  • 推流:把采集阶段封包好的音视频数据流推送到 ZEGO 实时音视频云的过程。
  • 拉流:从 ZEGO 实时音视频云将已有音视频数据流拉取播放的过程。
  • 房间:是 ZEGO 提供的音视频空间服务,用于组织用户群,同一房间内的用户能够相互收发实时音视频及音讯。

    1. 用户须要先登录某个房间,能力进行音视频推流、拉流操作。
    2. 用户只能收到本人所在房间内的相干音讯(用户进出、音视频流变动等)。

更多相干概念可参考即构官网对于音视频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="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 class="video-wrapper">        <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实时音视频通话次要流程如下:

  1. 用户 A 创立实例,登录房间。(登录胜利后,可预览本人的画面并推流。)
  2. 用户 B 创立实例,登录同一个房间。登录胜利后,用户 B 开始推流,此时 SDK 会触发 roomStreamUpdate 回调,示意房间内有流的变动。
  3. 用户 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 创立引擎并监听回调

  1. 创立并初始化一个 ZegoExpressEngine 的实例,将您我的项目的 AppID 传入参数 “appID”,Server 传入参数 “server”。
  2. 即构实时音视频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 音视频云

  1. 创立流并预览本人的画面

开始推流前须要创立本端的音视频流,调用 createStream 接口获取媒体流对象,默认会采集摄像头画面和麦克风声音。媒体流对象能够应用 createLocalStreamView 创立本地媒体流播放组件进行播放,也能够通过 video 元素 srcObject 属性赋值进行播放。

  1. 需期待 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 = 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 = 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产品优惠;