前言
近日,由于公司业务需要实现一个实时的语音视频通话,想起了之前用过的腾讯的TRTC多人会议通话,于是把TRTC这一功能融合到系统中,我们系统用的vue进行开发,所以使用的是TRTC的web-sdk,即trtc-js-sdk。
今天来给大家介绍一下如何在vue中使用它,在进行以下文章的内容学习之前我希望小伙伴们对Vue以及TRTC有相关的了解,Vue会简单的使用即可,TRTC则需要跑通Web版的demo,如果没跑过demo的话,大家可以点击这个链接[web-demo]去进行相关的学习,了解完之后再来进行以下的学习。
使用步骤
1.引入依赖
我们现在任意目录下创建一个Vue项目,我这里使用的是vue-cli 3.0,安装的时候把router相关选项给带上
vue create trtc-test
创建好项目后我们再安装trtc-js-sdk
npm i trtc-js-sdk
安装好后我们在我们的要用的页面进行引入,这里我直接在我们的helloworld组件进行引入,除此之外,我们还需要引入[web-demo]的lib-generate-test-usersig.min.js以及jquery-3.2.1.min.js,我在vue根目录下面创建了一个static文件夹,用于存放静态文件
import LibGenerateTestUserSig from '../../static/js/lib-generate-test-usersig.min.js'
import $ from '../../static/js/jquery-3.2.1.min.js'
import TRTC from 'trtc-js-sdk'
接下来是helloworld组件的template代码
代码如下(示例):
<template>
<div>
<!--视频组件容器-->
<div class="content">
<!--左边成员列表名单-->
<div class="left">
<div id="warp" class="userlist">
<!--本地流-->
<div id='local_stream' @click="switchMain"></div>
<div id='mask' class="maskable" v-show="!isVedio"></div>
</div>
<!--远端流-->
<div class="userlist" v-for="item in list" :class="{active: activeId==item.id}" @click="activeId=item.id">
<div :id="item.id" class="distant-stream" v-html="item.remoteStream" @click="getVideo(item.id)"></div>
</div>
</div>
<!--右边视频盒子-->
<div class="right">
<!--相关的操作-->
<div class="operator">
<div class="item" @click="muteLocalAudio">
<div class="img-warp">
<img id="audio" class="img" src="../../static/images/01语音@2x.png" alt="语音" v-show="isAudio"/>
<img id="unaudio" class="img" src="../../static/images/06取消静音@2x.png" alt="语音" v-show="!isAudio"/>
</div>
<span>{{ isAudio ? '静音' : '取消静音' }}</span>
</div>
<div class="item" @click="muteLocalVideo">
<div class="img-warp">
<img class="img" src="../../static/images/02视频@2x.png" alt="视频" v-show="isVedio"/>
<img class="img" src="../../static/images/07打开摄像头@2x.png" alt="视频" v-show="!isVedio"/>
</div>
<span>{{ isVedio ? '关闭摄像头' : '打开摄像头' }}</span>
</div>
<div class="item">
<div class="img-warp">
<img class="img" src="../../static/images/04挂断@2x.png" alt="离开会议"/>
</div>
<span>离开会议</span>
</div>
</div>
</div>
</div>
</div>
</template>
再接下来是我们会用到的一些data变量
data () {
return {
activeId: '', // 当前视频的播放id
list: [], // 远端流列表
userId: '李易峰_'+Math.floor(Math.random()*100), // 用户id --可更改
roomId: 888888, // 房间号--加入相同房间才能聊
client: '', // 客户端服务
remoteStream: '', // 远方播放流
localStream: '', // 本地流,
isVedio: true, // 当前本地是否打开摄像头
isAudio: true, // 当前本地是否打开麦克风
members_: new Map(), // 成员
isHave: false, //当前列表是否有该成员
}
},
接下来是方法的调用顺序,这里我们看一个官方给出的数据流
从上面的数据流转以及方法的调用顺序可以看出
我们在页面加载完成时createClient方法,先创建本地的一个客户端,在通过joinRoom方法进行一个进房请求的发送,值得注意的是,获取签名这里需要用到大家之前在跑demo的时候用到的SDKAPPID 以及SECRETKEY ,这里我为小伙伴们提供我之前使用的
// 创建链接
createClient (userId) {
// 获取签名
const config = this.genTestUserSig(userId)
const sdkAppId = config.sdkAppId
const userSig = config.userSig
this.client = TRTC.createClient({
mode: 'rtc',
sdkAppId,
userId,
userSig
})
// 初始化后才能加入房间
this.joinRoom()
},
// 获取用户签名
genTestUserSig (userID) {
const SDKAPPID = 1400419566
const EXPIRETIME = 604800
const SECRETKEY =
'c950d8f01b2b2742ead4e1bf9da553bab88f9ba4ac0c8ce4b9b30071e6098d27'
// a soft reminder to guide developer to configure sdkAppId/secretKey
if (SDKAPPID === '' || SECRETKEY === '') {
return false
}
const generator = new LibGenerateTestUserSig(SDKAPPID, SECRETKEY, EXPIRETIME)
const userSig = generator.genTestUserSig(userID)
return {
sdkAppId: SDKAPPID,
userSig: userSig
}
},
创建完本地客户端并且加入房间之后,我们就可以创建本地流了
// 加入房间
async joinRoom () {
await this.client.join({ roomId: this.roomId })// Number(this.videoInfo.roomNumber)
.then(() => {
// 创建本地流
this.createStream()
// 播放远端流
this.playStream()
})
.catch((error) => {
console.error('进房失败 ' + error)
})
// 注册远程监听
this.subscribeStream()
},
// 创建本地音视频流
createStream () {
this.localStream = TRTC.createStream({ userId: this.userId, audio: true, video: true })
this.localStream.initialize().then(() => {
console.log('初始化本地流成功')
// 本地流播放 local_stream 是本地流div的id
this.localStream.play('local_stream')
$('<div>').addClass('info')
.text(this.userId + '(我)')
.appendTo($('#warp'))
.css({
'width': '100%',
'height': '20%',
'line-height': '35px',
'color': '#fff',
'background': '#3c3d40',
'display': 'flex',
'align-items': 'center',
'z-index': '99',
'margin-top': 'auto'
})=
// 创建好后才能发布
this.publishStream()
this.updateStream()
})
.catch((error) => {
console.error('初始化本地流失败 ' + error)
})
},
// 发布本地音视频流
publishStream () {
this.client
.publish(this.localStream)
.catch((error) => {
console.error('本地流发布失败 ' + error)
})
.then(() => {
$('#local_stream').addClass('mainVedio').parent().addClass('active')
console.log('本地流发布成功')
})
},
// 远端监听
updateStream () {
this.client.on('stream-removed', (event) => {
const remoteStream = event.stream
$(`${'#mask_' + remoteStream.getId()}`).hide()
$(`${'#status_' + remoteStream.getId()}`).show()
})
// 关闭摄像头
this.client.on('mute-video', (evt) => {
let streamId = this.getUidByStreamId(evt.userId)
if (streamId) {
$('#mask_' + streamId).show()
}
})
// 打开摄像头
this.client.on('unmute-video', (evt) => {
let streamId = this.getUidByStreamId(evt.userId)
if (streamId) {
$('#mask_' + streamId).hide()
}
})
// 关闭语音
this.client.on('mute-audio', (evt) => {
let streamId = this.getUidByStreamId(evt.userId)
$(`${'#user_' + streamId}`).find('#audio_' + streamId).hide().next().show()
})
// 打开语音
this.client.on('unmute-audio', (evt) => {
let streamId = this.getUidByStreamId(evt.userId)
$(`${'#user_' + streamId}`).find('#unaudio_' + streamId).hide().prev().show()
})
},
// 根据id获取uid
getUidByStreamId (streamId) {
for (let [uid, stream] of this.members_) {
if (stream.getUserId() == streamId) {
return uid
}
}
},
// 订阅远端流--加入房间之前
subscribeStream () {
this.client.on('stream-added', (event) => {
const remoteStream = event.stream
this.isHave = false
for (let [uid, stream] of this.members_) {
if (stream.getUserId() === remoteStream.getUserId()) {
$('#user_' + stream.getId()).remove()
this.members_.delete(stream.getId())
this.isHave = true
}
}
this.members_.set(remoteStream.getId(), remoteStream)
console.log('远端流增加: ', remoteStream.getUserId())
// 订阅远端流
this.client.subscribe(remoteStream)
})
},
// 播放远端流
playStream () {
this.client.on('stream-subscribed', (event) => {
const remoteStream = event.stream
console.log('远端流订阅成功:' + remoteStream.getId())
// 创建远端流标签
const id = remoteStream.getId()
this.remoteStream = `<view id="${'remote_stream-' + id}" style="width:100%;height:100%"></view>`
if (!this.isHave) {
this.list.push({
id,
userId: remoteStream.getUserId(),
remoteStream: this.remoteStream,
origin: remoteStream
})
} else {
this.list.splice(this.list.findIndex((v) => v.userId === remoteStream.getUserId()), 1, {
id,
userId: remoteStream.getUserId(),
remoteStream: this.remoteStream,
origin: remoteStream
})
}
// 做了dom操作 需要使用$nextTick(),否则找不到创建的标签无法进行播放
this.$nextTick(() => {
// 播放
remoteStream.play('remote_stream-' + id)
let audio = $('#audio').clone()
audio.attr('id', 'audio_' + id)
audio.css({
'width': '14px',
'height': '21px',
'background': 'none',
'margin-left': 'auto'
})
let unaudio = $('#unaudio').clone()
unaudio.attr('id', 'unaudio_' + id)
unaudio.css({
'width': '14px',
'height': '21px',
'background': 'none',
'margin-left': 'auto'
})
let mask = $('#mask').clone()
mask.text('')
mask.attr('id', 'mask_' + id)
mask.css({
'width': '100%',
'height': '100%',
'text-align': 'center',
'z-index': '99'
})
mask.appendTo($('#player_' + id))
mask.hide()
let status = $('<div>', {
id: 'status_' + id
})
status.css({
'width': '100%',
'height': '100%',
'text-align': 'center',
'color': '#fff',
'display': 'flex',
'align-items': 'center',
'justify-content': 'center'
})
status.html('<span>已离开会议<span>')
status.appendTo($('#player_' + id))
status.hide()
console.log(4198649, $('#audio').clone())
$('#player_' + id).css({'position': 'relative'})
let bottom = $('<div/>', {id: 'user_' + id})
bottom.html(`<span style="white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">${remoteStream.getUserId()}</span>`)
bottom.css({
'width': '100%',
'height': '20%',
'line-height': '35px',
'color': '#fff',
'background': '#3c3d40',
'display': 'flex',
'align-items': 'center',
'z-index': '99',
'margin-top': 'auto'
})
audio.appendTo(bottom)
unaudio.appendTo(bottom)
bottom.appendTo($('#' + id).parent())
})
})
},
async closeRoom () {
await this.client.unpublish(this.localStream)
// leave the room
await this.client.leave()
this.localStream.stop()
this.localStream.close()
this.localStream = null
// this.isJoined_ = false;
$('#local_stream').parent()
.children('.info')
.remove()
},
// 将自己切换到主视频
switchMain () {
if ($('#local_stream').hasClass('mainVedio')) { return }
$('.mainVedio').removeClass('mainVedio').parent().removeClass('active')
$('#local_stream').addClass('mainVedio')
$('#warp').addClass('active')
},
getVideo (id) {
if ($('#' + id).hasClass('mainVedio')) { return }
$('.mainVedio').removeClass('mainVedio').parent().removeClass('active')
$('#' + id).addClass('mainVedio').css({'height':'93%'}).parent().addClass('active')
},
剩余的代码我也贴出来了,其实没必要太多的去说废话,因为很简单易懂,有不懂的朋友也可以私信找我,实在不行也可以看官方的文档https://trtc-1252463788.file.myqcloud.com/web/docs/tutorial-01-basic-video-call.html
源码地址:https://github.com/DJYang666/trtc.git