腾讯实时语音视频TRTC与Vue的结合开发-PC端


前言

近日,由于公司业务需要实现一个实时的语音视频通话,想起了之前用过的腾讯的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, //当前列表是否有该成员
    }
  },

接下来是方法的调用顺序,这里我们看一个官方给出的数据流
api调用顺序
从上面的数据流转以及方法的调用顺序可以看出
我们在页面加载完成时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


总结

这里讲讲我在使用的时候遇到的几个常见的,难以解决的问题 1. 如果使用台式机进行使用,需要接入外设,也就是摄像头,麦克风,不然会报错 2. API调用的顺序不能乱 3. 本地调试,使用谷歌内核的浏览器只能使用localhost或者https才能有权限调用摄像头和麦克风 4. 部署到服务器时需要安全证书
  • 9
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 27
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值