前言

小伙伴在开发腾讯云直播的时候遇到一点小问题,让我帮忙看看。才我有了这篇水文。具体的开发文档还得去腾讯云官网查看,还可以参考如下链接
TRTC web sdk
错误码参考
实现互动直播连麦

安装

下载依赖

npm install trtc-js-sdk --save

项目中引入依赖

import TRTC from 'trtc-js-sdk';

还需要一个js文件 用来生成临时的userSig
生成签名JS
下载后引入生产签名的JS

import LibGenerateTestUserSig from '@/utils/lib-generate-test-usersig.min';

基本逻辑

因为时间关系 代码中只实现到第三部,关于远端用户加入房间和上面进入房间的逻辑基本差不多,可以生成一个分享的链接,用户点击同意加入后,加入该房间。

  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() 方法播放。

实现

参数说明

参数名类型说明
sdkAppIdnumber腾讯云控制台获取
userIdstring用户ID
roomIdnumber/string房间ID 如果是string的话需要在初始化时指定useStringRoomId为true
userSigstring签名
secretKeystring腾讯云控制台获取(密钥)
<template>
<div>
<button @click="handroom">进入房间</button><br>
<div class="info-container">
<div v-if="isHostMode" class="log-container" ref="logContainer">
<p class="log-label">Log:</p>
<div v-for="(item, index) in logList" :key="index">
<span class="log-state" v-if="item.type === 'success'">🟩 </span>
<span class="log-state" v-if="item.type === 'failed'">🟥 </span>
<span>{{ item.log }}</span>
</div>
</div>
<div class="local-stream-container">
<div id="localStream" class="local-stream-content"></div>
</div>
</div>
</div>
</template>

<script>
import TRTC from 'trtc-js-sdk'
import LibGenerateTestUserSig from '@/assets/js/lib-generate-test-usersig.min';
export default {
name: "live-detail4",
data () {
return {
sdkAppId:xxx,
userId:'xzl001',
roomId:8,
userSig:'',
logList: [],
secretKey:'xxx'
}
},
methods: {
//初始化客户端
async initClient() {
this.client = TRTC.createClient({
mode: 'rtc',
sdkAppId: this.sdkAppId,
userId: this.userId,
userSig: this.userSig
});
this.addSuccessLog(`客户端 [${this.userId}] 创建.`);
},
//初始化本地流
async initLocalStream() {
this.localStream = TRTC.createStream({
audio: true,
video: true,
userId: this.userId,
cameraId: this.cameraId,
microphoneId: this.microphoneId,
});
try {
await this.localStream.initialize();
this.addSuccessLog(`本地流 [${this.userId}] 初始化.`);
} catch (error) {
this.localStream = null;
this.addFailedLog(`本地流初始化失败. Error: ${error.message}.`);
throw error;
}
},
//播放本地获取的流 这个可以弃掉 直接放在初始化后进行 一行可以解决 这样写方便界面判断、记录日志
playLocalStream() {
this.localStream.play('localStream')
.then(() => {
this.isPlayingLocalStream = true;
this.addSuccessLog(`本地流 [${this.userId}] 播放.`);
})
.catch((error) => {
console.log('播放失败',error);
this.addFailedLog(`本地流 [${this.userId}] 播放失败. Error: ${error.message}`);
});
},
//加入房间
async join() {
if (this.isJoining || this.isJoined) {
return;
}
this.isJoining = true;
!this.client && await this.initClient();
try {
await this.client.join({ roomId: this.roomId });
this.isJoining = false;
this.isJoined = true;
this.addSuccessLog(`加入房间 [${this.roomId}] 成功.`);
} catch (error) {
this.isJoining = false;
console.error('加入错误', error);
this.addFailedLog(`加入房间 ${this.roomId} 失败, 请检查参数. Error: ${error.message}`);
throw error;
}
},
//发布本地流 isJoined判断是否加入 isPublishing isPublished 是否推流 这些参数用于界面v-if进行判断显示
async publish() {
if (!this.isJoined || this.isPublishing || this.isPublished) {
return;
}
this.isPublishing = true;
try {
await this.client.publish(this.localStream);
this.isPublishing = false;
this.isPublished = true;
this.addSuccessLog('本地流发布成功.');
} catch (error) {
this.isPublishing = false;
console.log('发布流失败',error);
this.addFailedLog(`本地流发布失败. Error: ${error.message}`);
throw error;
}
},
//点击加入房间
async handroom() {
//生成签名 项目上线时需要在服务端生成签名
const userSigGenerator = new LibGenerateTestUserSig(this.sdkAppId, this.secretKey, 604800);
this.userSig = userSigGenerator.genTestUserSig(this.userId);
console.log(this.userSig);
await this.initClient();
await this.join();
await this.initLocalStream();
await this.playLocalStream();
await this.publish();
},
//显示成功的log 可以去掉
addSuccessLog(log) {
if (!this.isHostMode) {
return;
}
this.logList.push({
type: 'success',
log,
});
const { scrollHeight } = this.$refs.logContainer;
this.$refs.logContainer.scrollTop = scrollHeight;
},
// 显示失败的 Log 可以去掉
addFailedLog(log) {
if (!this.isHostMode) {
return;
}
this.logList.push({
type: 'failed',
log,
});
const { scrollHeight } = this.$refs.logContainer;
this.$refs.logContainer.scrollTop = scrollHeight;
},
},
computed: {
isHostMode() {
return this.type !== 'invite';
},
}
}
</script>

<style lang="less" scoped>
*{
box-sizing: border-box;
margin: 0;
padding: 0;
}
.info-container{
box-sizing: border-box;
margin: 0;
padding: 0;
width: 100%;
display: flex;
justify-content: space-between;
.log-container{
flex-grow: 1;
border: 1px solid #dddddd;
height: 360px;
padding: 10px;
margin-right: 16px;
overflow-y: scroll;
}
}
</style>

效果

img