快速开始
如果您是想体验一下 SDK 的基本使用,下面的内容会是很好的选择。但是如果您准备集成 SDK 到您的 Web 应用中,建议阅读这篇更为详细的 实时音视频应用开发实践
注意事项
因为 Chrome 的安全设置,请确保下面代码中的页面在 localhost 下打开。
之后的代码我们会使用 async/await 的方式来编写,请确保下面的代码运行在一个 async 函数包裹之下。比如 async iife。
(async () => {
// code goes here
})();
如果你想使用 promise,可以对下面的代码做一些简单的替换
try {
const a = await some_method();
} catch(e) {
console.log(e);
}
// promise 写法
some_method().then(a => {
}).catch(e => {
console.log(e);
})
以下过程的完整代码可以从这里下载 http://sdk-release.qnsdk.com/qnrtc-web-example.zip
加入房间
好了,准备就绪之后,让我们准备开始吧。 首先准备一个页面命名为 publish.html
, 然后引入我们的 SDK
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Publish</title>
<!-- 这里引入我们的 SDK -->
<script src="./pili-rtc-web.js"></script>
</head>
<body>
<script>
(async() => {
// 使用局部变量,将全局变量的 QNRTC 销毁
const QNRTC = window.QNRTC;
window.QNRTC = undefined;
})()
</script>
</body>
</html>
在这里我们需要 1 个已知参数,roomToken
, 关于这个参数的获取请参照上文提到的 使用 RoomToken
在这里让我们准备在同一个房间下,不同用户的 2 个 roomToken,一个用于发布,一个用于订阅(之后使用)
在 script 下写入如下代码,保存。本地起一个 http 服务,通过 localhost 访问这个 publish.html 页面,打开浏览器 log 后看到 current users
后说明加入房间成功。
const QNRTC = window.QNRTC;
window.QNRTC = undefined;
const roomToken = "Your roomToken1";
const myRTC = new QNRTC.QNRTCSession(); // 初始化我们的 SDK (QNRTC的引入方式见上)
try {
const users = await myRTC.joinRoomWithToken(roomToken); // 加入房间
// 因为 await 的特性,当代码执行到这里的时候,joinRoomWithToken 这个异步请求已经完成
// 如果过程中出现错误,会直接 throw 出来,如果需要处理只要 try/catch 就好
// 这里的 users 表示该房间中已经存在的用户,具体可以参照 API 文档
// 你也随时可以通过 myRTC.users 获取当前的用户列表
console.log('current users', users);
} catch (e) {
// 加入房间失败,关于错误处理可以参考下文的 错误处理 一节
console.log('join room error!', e);
}
采集本地音视频
加入房间完成,开始发布吧 , 在发布之前,我们需要通过本机的媒体设备采集本地的媒体数据。为了能够播放这个媒体数据,我们先修改publish.html
增加一个 div
用来播放我们的媒体数据
<body>
<div id="localplayer" style="width: 640px; height: 480px; background: #000"></div>
<script>...</script>
</body>
在 script
中继续加入代码
// 使用内置的 deviceManager 对象采集本地媒体数据
const stream = await QNRTC.deviceManager.getLocalStream({
video: { enabled: true },
audio: { enabled: true },
});
// 页面上准备用来播放的元素,就是我们刚刚创建的
const localVideo = document.getElementById('localplayer');
// 拿到 stream 对象后,调用 play 就可以播放了
// sdk 会在指定的元素下创建相应的 video/audio 标签完成播放
// 这里第二个参数代表用 静音模式 来播放,本地预览的时候一般我们会设置成静音
stream.play(localVideo, true);
此时刷新打开 publish 页面(注意需要在 localhost 下),就能看到自己的摄像头画面了。
发布采集数据
当我们拿到采集的流后 (刚刚代码中的 stream 对象),就可以将其发布到房间中了。在 script
中继续加入如下代码
// 发布自己本地的流
try {
await myRTC.publish(stream);
console.log("publish success!");
} catch (e) {
console.log('publish error!', e);
}
当 log 看到 punish success!
后就表示已经成功地将采集到的音视频数据发布到房间中了,可以被房间中的其他人订阅观看了。下一步,我们将通过一个新的页面订阅这个刚刚发布的流。
订阅远端数据
SDK不允许用户自己订阅自己,所以这里我们需要另一个用户来做测试,所以这里用到了之前准备的第二个 roomToken。注意这个 roomToken 需要和上一个页面的房间名一致但是用户名不一致。同时,让我们新准备一个页面 subscribe.html
来完成我们的订阅逻辑。这个页面也需要一个div
,用于播放我们订阅到的流。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Subscribe</title>
<!-- 同样,这里引入我们的 SDK -->
<script src="./pili-rtc-web.js"></script>
</head>
<body>
<div id="remoteplayer" style="width: 640px;height: 480px;background: #000"></div>
<button onclick="joinRoom()">加入房间</button>
<script>
// 注意这里我们没有默认运行,而是通过点击加入房间后再运行
// 这是因为 Chrome 最近禁止了在没有用户交互的前提下网页自动播放有声媒体
async function joinRoom() {
// 使用局部变量,将全局变量的 QNRTC 销毁
const QNRTC = window.QNRTC;
window.QNRTC = undefined;
// 同上一章,我们先加入房间,注意这里 roomToken 需要满足上文的要求
const roomToken = "Your roomToken2";
// 准备好用来播放的元素
const remoteVideo = document.getElementById('remoteplayer');
const myRTC = new QNRTC.QNRTCSession();
const users = await myRTC.joinRoomWithToken(roomToken);
}
</script>
</body>
</html>
接下来就来完成订阅的逻辑吧。这里订阅分 2 种情况:
- 当进入房间的时候对方就已经发布了,直接可以订阅
- 当进入房间的时候对方还没有发布,需要等待对方发布才能订阅
我们分别讨论这 2 种情况
直接订阅
在直接订阅之前,我们首先需要判断进入房间的时候对方是否已经发布了,我们注意到 joinRoomWithToken
的返回中有 users
对象,这个对象就是当前房间的用户列表,我们可以通过这个用户列表完成这个判断。
在 script 中加入如下代码
for (let i = 0; i < users.length; i +=1) {
const user = users[i];
// 如果这个用户正在发布并且不是自己,我们就订阅他
if (user.published && user.userId !== myRTC.userId) {
// 通过用户的 userId 订阅目标用户
// 这里返回和我们最初从本地获取媒体流时的返回格式一样
// 都是封装后的 Stream 对象
const remoteStream = await myRTC.subscribe(user.userId);
// 同样,调用 play 方法,选择页面上准备好用来播放的元素,就可以播放啦
remoteStream.play(remoteVideo);
}
}
通过这个 for 循环,我们遍历了当前房间中所有的用户(目前例子中只有 2 人),一旦找到了满足订阅条件的,我们就会调用订阅并把他的流播放出来。先打开之前的 publish 页面,通过 log 确认其已经发布了之后,打开 subscribe 页面点击 加入房间,此时就能在画面上看到刚刚摄像头采集的画面了(通过订阅观看)。
但是如果我们先在 subscribe 页面加入房间,之后再加入这段代码就不管用了。(因为遍历 users 的时候对方还没有发布)。针对这个情况,通过下面的代码来处理。
事件订阅
SDK 提供了丰富的事件回调来通知房间内各种状态的变化,具体可以查阅 API 文档中的 事件列表。这里我们使用的事件叫做 "user-publish" 当房间中有用户发布流的时候触发。
在刚刚的 for 循环之前,joinRoomWithToken
之后,加入如下代码。
...
const users = await myRTC.joinRoomWithToken(roomToken);
myRTC.on("user-publish", async (user) => {
const remoteStream = await myRTC.subscribe(user.userId);
remoteStream.play(remoteVideo);
});
for (let i = 0; i < users.length; i +=1) {
...
这样,无论谁先加入房间,只要 publish 页面发布了,最终都能在这里看到他采集下来的流数据。
至此,我们基本完成了连麦应用的 2 个基本功能的使用——发布和订阅。关于 SDK 所暴露的各个 API 的细节,您之后可以参考我们的 API 文档