实时音视频-旧版
  • iOS
  • Android
  • macOS
  • Windows
  • Linux
  • Web
  • 小程序 : JavaScript
  • uni-app
  • 实现视频通话(2.10.0 以下版本使用-Video)
  • 实现流程(2.10.0 以下版本使用-Audio)
  • 使用 Token 鉴权(Video)
  • 文档中心
  • 实时音视频-旧版
  • 实现视频通话(2.10.0 以下版本使用-Video)

实现视频通话

更新时间:2023-09-20 19:14

ZEGO 已统一环境概念,不再有正式/测试之分,2021-11-16 及之前在 ZEGO 控制台 创建项目的用户,请参考 测试环境废弃说明 进行 SDK 升级和调整相关代码。

1 功能简介

本文将介绍如何快速实现一个简单的实时音视频通话。

相关概念解释:

  • ZEGO Express SDK:由 ZEGO 提供的实时音视频 SDK,能够为开发者提供便捷接入、高清流畅、多平台互通、低延迟、高并发的音视频服务。
  • 推流:把采集阶段封包好的音视频数据流推送到 ZEGO 实时音视频云的过程。
  • 拉流:从 ZEGO 实时音视频云将已有音视频数据流拉取播放的过程。
  • 房间:是 ZEGO 提供的音视频空间服务,用于组织用户群,同一房间内的用户可以互相收发实时音视频及消息。
    1. 用户需要先登录某个房间,才能进行推流、拉流操作。
    2. 用户只能收到自己所在房间内的相关消息(用户进出、音视频流变化等)。

更多相关概念请参考 术语说明

2 前提条件

在实现基本的实时音视频功能之前,请确保:

  • 已在项目中集成 ZEGO Express SDK,详情请参考 微信小程序 - 集成 SDK
  • 已在 ZEGO 控制台 创建项目,申请有效的 AppID 和 AppSign,详情请参考 控制台 - 项目管理
  • 已在 ZEGO 控制台 获取有效的 Server 地址。在 ZEGO 控制台中的对应项目下单击 “配置 > 查看(环境配置) > 小程序”,即可获得 Server 地址(包含 HTTPS、WSS 协议)。
  • 微信公众平台 进行 服务器域名配置。在“小程序后台 > 开发 > 开发设置 > 服务器域名”,按照协议分类,将 Server 地址填到指定的“request合法域名”或“socket合法域名”中。

本产品本平台的功能不是默认开启的,使用前请在 ZEGO 控制台 自助接入服务开通(开通步骤请参考 控制台 - 项目管理 中的“服务接入”),或联系 ZEGO 技术支持开通。

3 使用步骤

以用户 A 拉取用户 B 的流为例,流程如下图:

/Pics/Common/ZegoExpressEngine/common_usage.png

整个推拉流过程的 API 调用时序如下图:

时序图

3.1 创建引擎

1. (可选)创建界面

添加界面元素

在创建引擎之前,推荐开发者添加以下界面元素,方便实现基本的实时音视频功能。

  • 本地预览窗口
  • 远端视频窗口
  • 结束按钮
界面图

2. 创建引擎

创建 ZegoExpressEngine 引擎实例,将申请到的 AppID 传入参数 “appID”,将获取到的 Server 地址传入参数 “server”。

// 初始化实例
const zg = new ZegoExpressEngine(appID, server);

3. (可选)监听事件回调

注册回调

如果需要注册回调,开发者可根据实际需要,实现 ZegoEvent 中的某些方法,创建引擎后可通过调用 on 接口设置回调。

zg.on('roomStateUpdate', (roomID, state, errorCode, extendedData) => {
    if (state == 'DISCONNECTED') {
        // 与房间断开了连接
    // ...
    }

    if (state == 'CONNECTING') {
        // 与房间尝试连接中 
    // ...
    }

    if (state == 'CONNECTED') {
        // 与房间连接成功
    // ...
    }
})

3.2 登录房间

1. 获取登录 Token

登录房间需要用于验证身份的 Token,获取方式请参考 用户权限控制。如需快速调试,建议使用控制台生成的临时 Token。

2. 登录房间

调用 SDK 的 loginRoom 接口,传入房间 ID 参数 “roomID”、“token” 和用户参数 “user”,登录房间。

  • “roomID”、“userID” 和 “userName” 参数的取值都为自定义。
  • “roomID” 和 “userID” 都必须唯一,建议开发者将 “userID” 设置为一个有意义的值,可将其与自己的业务账号系统进行关联。
  • 在登录房间之前请设置房间相关的回调监听,成功登录房间后,即可接收房间相关的事件通知。
// 登录房间,成功则返回 true
const result = await zg.loginRoom(roomID, token, {userID, userName});

3. 监听登录房间后的事件回调

根据实际应用需要,在登录房间前监听想要关注的事件通知,比如房间状态更新、用户状态更新、流状态更新等。

  • roomStateUpdate:房间状态更新回调。登录房间后,当房间连接状态发生变更(如出现房间断开,登录认证失败等情况),SDK 会通过该回调通知。

  • roomUserUpdate:用户状态更新回调。登录房间后,当房间内有用户新增或删除时,SDK 会通过该回调通知。

    只有调用 loginRoom 接口登录房间时传入 ZegoRoomConfig 配置,且 “isUserStatusNotify” 参数取值为 “true” 时,用户才能收到 onRoomUserUpdate 回调。

  • roomStreamUpdate:流状态更新回调。登录房间后,当房间内有用户新推送或删除音视频流时,SDK 会通过该回调通知。
  • 只有调用 loginRoom 接口登录房间时传入 ZegoRoomConfig 配置,且 “isUserStatusNotify” 参数取值为 “true” 时,用户才能收到 onRoomUserUpdate 回调。
  • 通常情况下,如果某个用户想要播放其他用户推送的视频,可以在收到流状态更新(新增)的回调中,调用 startPlayingStream 接口拉取远端推送的音视频流。
// 房间状态更新回调
zg.on('roomStateUpdate', (roomID,state,errorCode,extendedData) => {
    if (state == 'DISCONNECTED') {
        // 与房间断开了连接
    }

    if (state == 'CONNECTING') {
        // 与房间尝试连接中 
    }

    if (state == 'CONNECTED') {
        // 与房间连接成功
    }
})

// 用户状态更新回调
zg.on('roomUserUpdate', (roomID, updateType, userList) => {
    console.warn(
        `roomUserUpdate: room ${roomID}, user ${updateType === 'ADD' ? 'added' : 'left'} `,
        JSON.stringify(userList),
    );
});

// 流状态更新回调
zg.on('roomStreamUpdate', async (roomID, updateType, streamList, extendedData) => {
    if (updateType == 'ADD') {
        // 流新增,开始拉流
    } else if (updateType == 'DELETE') {
        // 流删除,停止拉流
    }
});

3.3 推流

1. 开始推流

触发推流后,调用 SDK 的 startPublishingStream 接口,传入流 ID 参数 “streamID”,获取 “streamID” 对应的推流地址。

调用微信小程序的 wx.createLivePusherContext 创建 live-pusher,将获取到的推流地址设置为 live-pusher 的 “url” 属性,然后调用 live-pusher 的 start 录制视频。

“streamID” 的参数取值需要在整个 AppID 内全局唯一,是自定义的、长度不超过 256 字节的字符串。仅支持数字,英文字符和 “~”,“!”,“@”,“$”,“%”,“^”,“&”,“*”,“(”,“)”,“_”,“+”,“=”,“-”,“`”,“;”,“’”,“,”,“.”,“<”,“>”,“/”,“\”。

// 1. 推流方登录房间成功后触发推流。
// 调用 SDK 的 startPublishingStream 获取 streamID 对应的推流地址。
 let { streamID, url } = await zg.startPublishingStream(streamID);
// 2. 调用微信小程序的 wx.createLivePusherContext 创建 live-pusher。
// 将步骤 1 中获取的推流流地址设置为 live-pusher 的 url。
// 然后调用 live-pusher 的 start 录制视频。
try {
    this.setData(
        {
            livePusherUrl: url,
            livePusher: wx.createLivePusherContext(),
        },
        () => {
            this.data.livePusher.start(); 
        }
    );
    } catch (error) {
        console.error("error", error);
    }

2. 推流事件处理

  • 推流状态事件

微信小程序会在 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,type 1 推流
    zg.updatePlayerNetStatus(this.data.publishStreamID, e);
},


// SDK 推流网络质量回调
zg.on("publishQualityUpdate", (streamID, publishStats) => {
    console.log("publishQualityUpdate", streamID, publishStats);
});

3.4 拉流

1. 开始拉流

触发拉流后,调用 SDK 的 startPlayingStream 接口,根据传入的流 ID 参数 “streamID”,获取 streamID 对应的拉流地址。

远端用户推送的 “streamID” 可以从 roomStreamUpdate 回调中获得。

调用微信小程序的 wx.createLivePlayerContext 创建 live-player,将获取到的拉流地址设置为 live-player 的 “src” 属性,然后调用 live-player 的 play 播放视频。开发者也可以设置 live-player 为 autoplay,播放器会自动播放,无需再手动调用 play

// 1. 在 SDK 的回调 roomStreamUpdate 中获取拉流streamID。
// 当用户加入或离开房间时,该事件被触发。
zg.on("roomStreamUpdate", (roomID, updateType, streamList) => {
    console.log("roomStreamUpdate", roomID, updateType, streamList);   
    if (updateType === "ADD") {
        // to play ......
    } else {
        // to stopPlay .....
    }
});
// 2. 开始拉流
let { streamID, url } = await zg.startPlayingStream(playStreamID,{ sourceType: "BGP" });
// 3. 调用微信小程序的 wx.createLivePlayerContext 创建 live-player。
// 将步骤 2 中获取的拉流地址设置为 live-player 的 src.
// 然后调用 live-player 的 play() 播放视频。
// 此步骤也可以设置 live-player 为 autoplay,此时播放器会自动播放,无需再手动调用 play()。
try {             
    this.setData(
    {
        playUrl: url,
        playContext: wx.createLivePlayerContext(),
    },
    () => {
        this.data.playContext.play();
    }
    );
    } catch (error) {
        console.error("error", error);
    }

2. 拉流事件处理

  • 拉流状态事件

微信小程序会在 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);
});

3.5 体验实时音视频功能

在真机中运行项目,运行成功后,可以看到本端视频画面。

为方便体验,ZEGO 提供了一个 Web 端调试示例 ,在该页面下,输入相同的 AppID、RoomID,输入不同的 UserID、以及对应的 Token,即可加入同一房间与真机设备互通。当成功开始音视频通话时,可以听到远端的音频,看到远端的视频画面。

3.6 停止推拉流

1. 停止推流

调用 SDK 的 stopPublishingStream 接口清空推流状态。

调用微信小程序 live-pusher 的 stop 停止推流。

一定要清空推流状态,否则可能导致 SDK 状态异常。

// 停止推流
zg.stopPublishingStream(publishStreamID);
this.data.pusherVideoContext.stop();

3. 停止拉流

调用 SDK 的 stopPlayingStream 接口清空拉流状态。

调用微信小程序 live-player 的 stop 停止拉流。

一定要清空拉流状态,否则可能导致 SDK 状态异常。

// 停止拉流
zg.stopPlayingStream(playStreamID);
this.data.playContext && this.data.playContext.stop();

3.7 退出房间

调用 SDK 的 logoutRoom 接口退出房间。

zg.logoutRoom(roomID)
本篇目录