开始集成音视频通话

开始集成音视频通话

前提条件

  1. 注册腾讯云账号,创建实时音视频应用
  2. 获取临时 userSig ,或者部署 userSig 签发服务
  3. 为了体验完整的 TRTC 能力,建议开发时使用 http://localhost ,生产环境用 https://[域名] 访问页面,参考文档页面访问协议说明
  4. 为了避免防火墙安全策略限制正常的 TRTC 数据传输,需要参考文档应对防火墙策略进行设置。
  5. 为了保证通话体验,建议在正式开始音视频通话前,进行设备检测和浏览器兼容性检测,可以参考文档浏览器兼容信息通话前环境与设备检测

集成 SDK

SDK 提供了 UMD、ES Module 类型的模块,以及 TypeScript Type Definition 文件,满足在不同类型项目中集成。

NPM 集成

  1. 您可以在项目中使用 npm 安装 trtc-js-sdk
npm install trtc-js-sdk --save
  1. 在项目脚本里导入模块。
import TRTC from 'trtc-js-sdk';

Script 集成

  1. 在您的 Web 页面中添加如下代码即可:
<script src="trtc.js"></script>

资源下载

SDK 使用逻辑概览

基本概念

您在使用 TRTC Web SDK 时,会接触到以下概念:

  • Client 类,其实例代表一个本地客户端。Client 的对象方法提供了加入通话房间、发布本地流、订阅远端流等功能。
  • Stream 类,其实例代表一个音视频流对象,包括本地音视频流对象 LocalStream 和远端音视频流对象 RemoteStreamStream 的对象方法主要提供对音视频流的控制操作,包括音频和视频的播放控制。

实现音视频通话基本逻辑

  1. 调用 TRTC.createClient() 方法创建 client 对象。
  2. 调用 client.join() 进入音视频通话房间。
  3. 您进入房间成功后,可以发布本地流,远端用户可以订阅您的流:
    1. 调用 TRTC.createStream() 创建本地音视频流。
    2. 调用 localStream.initialize() 初始化本地音视频流,开始获取系统设备权限,采集音视频。
    3. 在本地流初始化成功后,调用 client.publish() 方法发布本地流。
  4. 当一个远端用户加入房间,并发布音视频流时,您可以订阅远端流进行播放:
    1. 在您进房前监听 client.on('stream-added') 事件,就能收到所有远端用户的推流事件。
    2. 调用 client.subscribe() 方法订阅远端流。
    3. 触发订阅成功事件 client.on('stream-subscribed') 后,调用 remoteStream.play() 方法播放。

下图展示了实现音视频通话全过程的基础 API 调用流程:

创建 Client 对象

通过 TRTC.createClient() 方法创建 Client 对象,关键参数设置:

  • mode: 实时音视频通话模式,设置为 'rtc'。
  • sdkAppId: 您在腾讯云创建的音视频应用的 sdkAppId。
  • userId: 用户 ID,由您指定。
  • userSig: 用户签名,参考获取临时 userSig,或者部署 userSig 签发服务

更详细的参数说明参考接口文档 TRTC.createClient()

const client = TRTC.createClient({ mode: 'rtc', sdkAppId, userId, userSig });

进入音视频通话房间

调用 client.join() 进入音视频通话房间。通常在开始通话按钮的点击回调里进行调用。 关键参数:

  • roomId:房间 ID,由您指定,通常是生成唯一的房间ID。 更详细的参数说明参考接口文档 client.join()
try {
  await client.join({ roomId: 8888 });
  console.log('进房成功');
} catch (error) {
  console.error('进房失败 ' + error);
}

发布本地流和订阅远端流

创建本地音视频流

使用 TRTC.createStream() 方法创建本地音视频流。 以下实例从摄像头及麦克风中采集音视频流,参数设置如下:

  • userId:用户 ID
  • audio:是否开启音频
  • video:是否开启视频
const localStream = TRTC.createStream({ userId, audio: true, video: true });

初始化本地音视频流

接下来调用 initialize() 初始化本地音视频流。

try {
  await localStream.initialize();
  console.log('初始化本地流成功');
} catch (error) {
  console.error('初始化本地流失败 ' + error);
}

发布本地音视频流

在本地流初始化成功后,调用 publish() 方法发布本地流。

try {
  await client.publish(localStream);
  console.log('本地流发布成功');
} catch (error) {
  console.error('本地流发布失败 ' + error);
}

订阅远端音视频流

远端流通过监听事件 client.on('stream-added') 获得,请在 client.join() 进房前注册该事件,确保您不会错过远端用户进房通知。 收到上述事件后要通过 client.subscribe() 订阅远端音视频流。

client.on('stream-added', event => {
  const remoteStream = event.stream;
  console.log('远端流增加: ' + remoteStream.getId());
  //订阅远端流
  client.subscribe(remoteStream);
});
client.on('stream-subscribed', event => {
  const remoteStream = event.stream;
  console.log('远端流订阅成功:' + remoteStream.getId());
  // 播放远端流,传入的元素 ID 必须是页面里存在的 div 元素
  remoteStream.play('remote_stream-' + remoteStream.getId());
});

播放音视频流

在本地流初始化成功的回调中,或远端流订阅成功事件回调中,通过调用 stream.play() 方法在网页中播放音视频。play方法接受一个 div 元素 ID 作为参数,SDK 内部会在该 div 元素下自动创建相应的音视频标签并在其上播放音视频。

  • 初始化本地流成功时播放本地流。
try {
  await localStream.initialize();
  console.log('初始化本地流成功');
  // 播放本地流,'local_stream' 是在 DOM 中的一个 div 标签的 ID
  localStream.play('local_stream');
} catch (error) {
  console.error('初始化本地流失败 ' + error);
}
  • 订阅远端流成功时播放远端流。
client.on('stream-subscribed', event => {
  const remoteStream = event.stream;
  console.log('远端流订阅成功:' + remoteStream.getId());
  // 如果您遇到播放失败的问题,需要使用 remoteStream 监听 error 并处理 0x4043 浏览器限制自动播放的问题
  remoteStream.on('error', error => {
    const errorCode = error.getCode();
    if (errorCode === 0x4043) {
      // PLAY_NOT_ALLOWED, 引导用户手势操作并调用 stream.resume 恢复音视频播放,
      // 在点击回调里调用 remoteStream.resume() 进行恢复播放。
    }
  });
  // 播放远端流,传入的元素 ID 必须是页面里存在的 div 元素
  remoteStream.play('remote_stream-' + remoteStream.getId());
});

退出音视频通话房间

退出房间有主动退房被动退房两种情况,需要分别处理。

主动退出当前房间

通话结束时调用 client.leave() 方法退出音视频通话房间,整个音视频通话会话结束。

await client.leave(); 
// 退房成功,如果没有调用 client.destroy(),可再次调用 client.join 重新进房开启新的通话
// 调用 destroy() 结束当前 client 的生命周期
client.destroy();

被动退出当前房间

除了用户主动退出房间,在以下情况下,用户会收到 CLIENT_BANNED 事件,表示当前用户被动退出房间,这时不需要调用 client.leave(),client 会自动进入退房状态。

client.on('client-banned', error => {
  console.error(`client-banned observed, reason:${error.reason}, message:${error.message}`);
  // error.reason 有以下几种情况
  // 'kick' 由于相同 userId 进房导致先进入的用户被移出房间
  // 'banned' 被管理员移出房间
  // 'room_disband' 管理员解散了房间
});
  • 情况一:被同名用户踢出当前房间 在一个房间内,如果同时出现两个 userId 一样且角色都为主播的用户,那么先进入房间的用户会被踢出房间。 例如:A、B 两个用户,先后以相同的 userId 进入房间, A 会被 B 挤出房间。 同名用户同时进入同一房间是不允许的行为,可能会导致双方音视频通话异常,应避免出现这种情况。

  • 情况二:通过服务端 API 踢出当前房间 您可以通过服务端的 RemoveUser | RemoveUserByStrRoomId 接口将某个用户踢出某个 TRTC 房间,将该用户踢出后,该用户会收到 CLIENT_BANNED 事件。

  • 情况三:通过服务端 API 解散当前房间 通过服务端的 DismissRoom | DismissRoomByStrRoomId接口将某个 TRTC 房间解散,解散房间之后,该房间的所有用户都会 CLIENT_BANNED 事件。

完整代码

HTML:

<!-- 在页面插入代码 -->
<div class="container">
  <input type="number" id="roomId" name="roomId" placeholder="roomId" required>
  <input type="text" id="userId" name="userId" placeholder="userId" required>
  <input type="text" id="userSig" name="userSig" placeholder="userSig" required>
  <button type="button" id="startCall">开始通话</button>
  <button type="button" id="finishCall">结束通话</button>
</div>
<div id="localStreamContainer"></div>
<div id="remoteStreamContainer"></div>

JavaScript:

let sdkAppId = 1400000000; // '填入您创建应用的 sdkAppId'
let roomId ; // '您指定的房间号'
let userId ; // '您指定的用户ID'
let userSig ; // '生成的userSig'
let client, localStream;
document.getElementById("startCall").onclick = async function () {
  roomId = parseInt(document.querySelector('#roomId').value);
  userId = document.querySelector('#userId').value;
  userSig = document.querySelector('#userSig').value;
  client = TRTC.createClient({ mode: 'rtc', sdkAppId, userId, userSig });
  // 1.监听事件
  client.on('stream-added', event => {
    const remoteStream = event.stream;
    console.log('远端流增加: ' + remoteStream.getId());
    //订阅远端流
    client.subscribe(remoteStream);
  });
  client.on('stream-subscribed', event => {
    // 远端流订阅成功
    const remoteStream = event.stream;
    // 播放远端流,传入的元素 ID 必须是页面里存在的 div 元素
    remoteStream.play('remoteStreamContainer');
  });
  // 2.进房成功后开始推流
  try {
    await client.join({ roomId });
    localStream = TRTC.createStream({ userId, audio: true, video: true });
    await localStream.initialize();
    // 播放本地流
    localStream.play("localStreamContainer");
    await client.publish(localStream);
  } catch (error) {
    console.error(error);
  }
}
document.getElementById("finishCall").onclick = async function () {
  // 停止本地流预览
  localStream.close();
  await client.leave();
  // 退房成功,如果没有调用 client.destroy(),可再次调用 client.join 重新进房开启新的通话
  // 调用 destroy() 结束当前 client 的生命周期
  client.destroy();
}

联系我们

如在接入实现过程中遇到问题,欢迎到 GitHub issue 创建 issue,我们会尽快处理。