腾讯实时音视频SDK[三]:小程序端实现

本文介绍了使用腾讯实时音视频SDK在小程序端实现音视频通信的过程。首先,小程序启动时会建立WebSocket连接,获取房间号。当收到房间号后,小程序进入房间。在代码实现中,SDK的sdkappid、secretKey和签名来自后端接口。在页面使用时,需要注意组件状态和权限问题,例如初始化Pusher时需要避免在无URL状态下操作,以及处理元素显示问题以防止声音消失。
摘要由CSDN通过智能技术生成
说明

小程序这边一进来就会建立websocket链接,将必要参数给到后端,然后等待后端生成房间号并等待客服进入房间,才下发房间号给到小程序.这里是小程序收到房间号后进入房间的实现.

效果图

等待接听…
在这里插入图片描述
接听后…
在这里插入图片描述

安装引入
npm i trtc-wx-sdk
import TRTC from 'trtc-wx-sdk'
代码如下

这里我封装成了组件,这里sdkappid和secretKey以及签名都是来自后端接口,没有使用debug的模拟.

页面使用:
<div class="calling-video">
     <business-tencentCalling id="trtcComponent" :config="playVidoe.input.rtcConfig" ref="trtcComponent" :isEnterRoom.sync="isEnterRoom"></business-tencentCalling>
</div>
组件内部
<template>
  <view class="template-1v1">
    <view v-for="(item,index) in playerList" :key="index" v-if="item.src && (item.hasVideo || item.hasAudio)" :class="['view-container','player-container' ,item.isVisible?'':'none']">
      <live-player
              class="player"
              :id="item.streamID"
              :data-userid="item.userID"
              :data-streamid="item.streamID"
              :data-streamtype="item.streamType"
              :src="item.src"
              :mode="RTC"
              :autoplay="item.autoplay"
              :mute-audio="item.muteAudio"
              :mute-video="item.muteVideo"
              :orientation="item.orientation"
              :object-fit="item.objectFit"
              :background-mute="item.enableBackgroundMute"
              :min-cache="item.minCache"
              :max-cache="item.maxCache"
              :sound-mode="item.soundMode"
              :enable-recv-message="item.enableRecvMessage"
              :auto-pause-if-navigate="item.autoPauseIfNavigate"
              :auto-pause-if-open-native="item.autoPauseIfOpenNative"
              :debug="debug"
              @statechange="_playerStateChange"
              @fullscreenchange="_playerFullscreenChange"
              @netstatus="_playerNetStatus"
              @audiovolumenotify  ="_playerAudioVolumeNotify"
      />
    </view>
    <view v-if="pusher.enableMic" :class="'view-container pusher-container ' + (pusher.isVisible ? '' : 'none') + ' ' +'fullscreen'">
      <live-pusher
              class="pusher"
              v-show="pusher.enableCamera"
              :url="pusher.url"
              :mode="pusher.mode"
              :autopush="pusher.autopush"
              :enable-camera="pusher.enableCamera"
              :enable-mic="pusher.enableMic"
              :muted="!pusher.enableMic"
              :enable-agc="pusher.enableAgc"
              :enable-ans="pusher.enableAns"
              :enable-ear-monitor="pusher.enableEarMonitor"
              :auto-focus="pusher.enableAutoFocus"
              :zoom="pusher.enableZoom"
              :min-bitrate="pusher.minBitrate"
              :max-bitrate="pusher.maxBitrate"
              :video-width="pusher.videoWidth"
              :video-height="pusher.videoHeight"
              :beauty="pusher.beautyLevel"
              :whiteness="pusher.whitenessLevel"
              :orientation="pusher.videoOrientation"
              :aspect="pusher.videoAspect"
              :device-position="pusher.frontCamera"
              :remote-mirror="pusher.enableRemoteMirror"
              :local-mirror="pusher.localMirror"
              :background-mute="pusher.enableBackgroundMute"
              :audio-quality="pusher.audioQuality"
              :audio-volume-type="pusher.audioVolumeType"
              :audio-reverb-type="pusher.audioReverbType"
              :waiting-image="pusher.waitingImage"
              :debug="debug"
              @statechange="pusherStateChangeHandlerFun"
              @netstatus="_pusherNetStatusHandler"
              @error="_pusherErrorHandler"
              @bgmstart="_pusherBGMStartHandler"
              @bgmprogress="_pusherBGMProgressHandler"
              @bgmcomplete="_pusherBGMCompleteHandler"
              @audiovolumenotify="_pusherAudioVolumeNotify"
      />
      <view class="loading" v-if="!_isEnterRoom">
        <view class="loading-text">等待接听中...</view>
      </view>
    </view>
    <cover-view v-if="_isEnterRoom" class="calling-time">通话时间 {{ videoOrVoiceObj.msgIPtime.longTime}}</cover-view>
    <view class="handle-btns" v-if="videoBtnsVisible&&hasEnterRoom">
      <!--视频/语音   toggleVideoFun -->
      <cover-view class="box-wrap">
        <cover-view class="btn-normal" @click="_toggleVideoFun">
          <cover-image class="closeVideoImg" v-if="pusher.enableCamera" src="/static/img/closeCamera.png"></cover-image>
          <cover-image class="videoImg" v-else src="/static/img/camera.png"></cover-image>
        </cover-view>
        <cover-view class="btn-word">{{pusher.enableCamera?'关闭摄像头':'打开摄像头'}}</cover-view>
      </cover-view>
      <!-- 挂断 -->
      <cover-view class="box-wrap">
          <cover-view class="btn-hangup" @click="_hangUp"><cover-image src="/static/img/hangup.png"></cover-image></cover-view>
          <cover-view class="btn-word">挂断</cover-view>
        </cover-view>
      <!-- 翻转镜头 -->
      <cover-view class="box-wrap">
        <cover-view class="btn-normal" @click="_pusherSwitchCamera"><cover-image src="/static/img/turnCamera.png"></cover-image></cover-view>
        <cover-view class="btn-word">翻转镜头</cover-view>
      </cover-view>
    </view>
    <cover-view class="bottom-btns" v-if="videoBtnsVisible&&hasEnterRoom">
      <cover-view class="box-wrap" >
        <cover-view class="btn-normal" @click="_setPlayerSoundMode">
          <cover-image class="closeVideoImg" v-if="playerList[0].soundMode === 'ear'" src="/static/img/ear_sound.png"></cover-image>
          <cover-image class="videoImg" v-else src="/static/img/outer_sound.png"></cover-image>
        </cover-view>
        <cover-view class="btn-word" v-if="playerList[0].soundMode === 'ear'">听筒</cover-view>
        <cover-view class="btn-word" v-else>免提</cover-view>
      </cover-view>
    </cover-view>
  </view>
</template>
<style lang="scss" scoped>
  /* 1v1 视频电话模式 */
  .template-1v1{
    width: 100vw;
    display: flex;
    height: 100vh;
    position: relative;
  }
  .template-1v1 .pusher-container{
    width: 100vw;
    height: 100vh;
    position: absolute;
    right: 0;
    top: 0;
    z-index: 2;
  }

  .template-1v1 .pusher-container.fullscreen{
    width: 100vw;
    height: 100vh !important;
    display: flex;
    height: 0rpx;
    top: 0;
    right: 0;
  }

  .template-1v1 .loading {
    position: absolute;
    top: 40vh;
    left: 50vw;
    transform: translate(-50%, 0);
    width: 300rpx;
    height: 250rpx;
    border-radius: 12rpx;
    background: rgba(0,0,0,0.6);
    color: white;
    padding: 40rpx;
    display: flex;
    flex-direction: column;
  }
  .template-1v1 .loading-img {
    height: 200rpx;
    display:flex;
    justify-content: center;
    align-items: center;
    animation: rotate 2s linear infinite;
  }
  .template-1v1 .rotate-img {
    width:160rpx;
    height: 160rpx;
  }
  .template-1v1 .loading-text {
    width: 100%;
    padding-top: 40rpx;
    text-align: center;
  }
  @keyframes rotate {
    0%{ transform: rotate(0deg);}
    50%{ transform: rotate(180deg);}
    100%{ transform: rotate(360deg);}
  }
  .template-1v1 .player-container:nth-child(1){
    width: 100vw;
    height: 100vh;
  }

  .template-1v1 .handle-btns {
    position: absolute;
    z-index: 3;
    bottom: 18vh;
    right: 0;
    width: 100vw;
    display: flex;
    flex-direction: row;
    justify-content: space-evenly;
  }
  .template-1v1 .bottom-btns {
    position: absolute;
    z-index: 3;
    bottom: 2vh;
    right: 0;
    width: 100vw;
    display: flex;
    flex-direction: row;
    justify-content: center;
    align-items: center;
  }
  .calling-time{
    position: absolute;
    z-index: 3;
    bottom: 35vh;
    font-size: 36rpx;
    left: 0;
    width: 100vw;
    color: #fff;
    text-align: center;
  }
  .template-1v1 .handle-btns .box-wrap,.template-1v1 .bottom-btns .box-wrap{
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 140rpx;
    height: auto;
  }
  .template-1v1 .handle-btns .box-wrap .btn-word,.template-1v1 .bottom-btns .box-wrap .btn-word{
    color: #fff;
    margin-top: 30rpx;
  }

  .template-1v1 .btn-normal {
    width: 110rpx;
    height: 110rpx;
    box-sizing: border-box;
    display: flex;
    border:1rpx solid white;
    border-radius: 50%;
    justify-content: center;
    align-items: center;
    border-radius: 50%;
  }
  .template-1v1 .btn-normal cover-image{
    width: 50rpx;
    height: auto;
    margin-bottom: 2rpx;
  }
  .template-1v1 .btn-normal .closeVideoImg{
    width: 58rpx;
  }
  .template-1v1 .btn-normal .videoImg{
    width: 64rpx;
  }

  .template-1v1 .btn-hangup  {
    width: 110rpx;
    height: 110rpx;
    box-sizing: border-box;
    display: flex;
    justify-content: center;
    align-items: center;
    border-radius: 50%;
  }
  .template-1v1 .btn-hangup cover-image{
    width: 110rpx;
    height: 110rpx;
  }

</style>
import TRTC from 'trtc-wx-sdk'
export default {
	data () {
	    return {
	      TRTC:undefined,
		  pusher:undefined,
		  playerList:[],
		  //控制视频按钮显隐
		  videoBtnsVisible:true,
		  //进房状态
		  // isEnterRoom:false,
		  //控制视频按钮显隐
		  videoBtnsVisible:true,
		  //自己写一个计时功能
		  courentTime:0,
		  videoOrVoiceObj:{
		  //计时器
		    msgIPtime:{
		      timer: "",
		      content: "",
		      hour: 0,
		      minutes: 0,
		      seconds: 0,
		      longTime:'00:00:00'
		    }
		  },
		  //是否执行进房操作
		  hasEnterRoom:false
	    }
	  },
	  beforeMount(options) {
	    this.TRTC = new TRTC()
	    //初始化数据 房间号  签名等
	    this.init(options)
	    this.bindTRTCRoomEvent()
	  },
	  props:{
		 config:{
		    type: Object,
		    default: () => ({
		      sdkAppID: '',
		      userID: '',
		      userSig: '',
		      template: '',
		      debugMode: ''
		    })
		  },
		  //进房结果  成功:true/失败:false
		  isEnterRoom:{
		    type: Boolean,
		    default: false
		  },
	},
	  methods:{
		init() {
		    // pusher 初始化参数
		    const pusherConfig = {
		      beautyLevel: 9,
		    }
		    const pusher = this.TRTC.createPusher(pusherConfig)
		    console.log(pusher.pusherAttributes, '000')
		    this.pusher= pusher.pusherAttributes
		     
		  },
		  toJSON(){
		    return this
		  },
		
		  async enterRoom(options,callback) {
		    //执行了进房操作
		    this.hasEnterRoom = true
		    //进房状态
		    let enterRoomStatus={
		      isOk:false,
		      msg:undefined,
		      info:{}
		    }
		    
		    const roomID = options.roomID
		    const config =  Object.assign(this.config, { roomID })
		
		    //校验参数
		    if (!this.methods('checkParamFun',this.config)) {
		      enterRoomStatus.msg = '缺少必要参数'
		      enterRoomStatus.info = {}
		      callback(enterRoomStatus)
		      return;
		    }
		    //
		    config.enableMic= true, // 进房默认开启音频上行
		    config.enableCamera= false, // 进房默认开启视频上行
		    config.frontCamera= 'back', // 进房默认开启视频上行
		    new Promise((r)=>{
		      try{
		        this.pusher=this.TRTC.enterRoom(config)
		        r()
		      }catch(res){
		        console.error(TAG_NAME, '进房失败', res);
		        enterRoomStatus.msg = '进房失败'
		        enterRoomStatus.info = res
		        wx.showToast({
		          title: '组件内进房失败'+JSON.stringify(res),
		        }) 
		        callback(enterRoomStatus)
		        r()
		      }
		    }).then(()=>{
		      this.TRTC.getPusherInstance().start() // 开始推流(autoPush的模式下不需要)
		      console.log('开始推流',this.pusher)
		      enterRoomStatus.msg = '进房成功'
		      enterRoomStatus.isOk = true
		      enterRoomStatus.info = {}
		      callback(enterRoomStatus)
		    })
		  },
		
		  exitRoom() {
		    const result = this.TRTC.exitRoom()
		    this.pusher= result.pusher
		    this.playerList=result.playerList
		  },
		
		  //隐藏
		  hiddenBtns(){
		    console.log('隐藏')
		    this.videoBtnsVisible = false
		  },
		  //显示
		  refreshBtns(){
		    console.log('显示')
		    this.videoBtnsVisible = true
		  },
		
		  //我写的计时功能
		  initTime() {
		    console.log('不执行吗?')
		    /*时间处理*/
		    this.timer = setInterval(() => {
		      this.courentTime = new Date().getTime();
		    }, 1000);
		  },
		  //通话时长
		  ipVoiceOrVideoLongTimeClick(){
		    this.videoOrVoiceObj.msgIPtime.timer = setInterval(this.startMsgIPtimeTimer, 1000);
		  },
		  startMsgIPtimeTimer () {
		    this.videoOrVoiceObj.msgIPtime.seconds += 1;
		    if ( this.videoOrVoiceObj.msgIPtime.seconds >= 60) {
		      this.videoOrVoiceObj.msgIPtime.seconds = 0;
		      this.videoOrVoiceObj.msgIPtime.minutes += 1;
		    }
		    if ( this.videoOrVoiceObj.msgIPtime.minutes >= 60) {
		      this.videoOrVoiceObj.msgIPtime.minutes = 0;
		      this.videoOrVoiceObj.msgIPtime.hour =  this.videoOrVoiceObj.msgIPtime.hour + 1;
		    }
		  this.videoOrVoiceObj.msgIPtime.longTime =( this.videoOrVoiceObj.msgIPtime.hour < 10 ? '0' +  this.videoOrVoiceObj.msgIPtime.hour :  this.videoOrVoiceObj.msgIPtime.hour) + ':'+ ( this.videoOrVoiceObj.msgIPtime.minutes < 10 ? '0' +  this.videoOrVoiceObj.msgIPtime.minutes :  this.videoOrVoiceObj.msgIPtime.minutes) + ':' + ( this.videoOrVoiceObj.msgIPtime.seconds < 10 ? '0' +  this.videoOrVoiceObj.msgIPtime.seconds :  this.videoOrVoiceObj.msgIPtime.seconds);
		  },
		  resetMsgIPtime(){  //重置
		    clearInterval(this.videoOrVoiceObj.msgIPtime.timer);
		    this.videoOrVoiceObj.msgIPtime.hour=0;
		    this.videoOrVoiceObj.msgIPtime.minute=0;
		    this.videoOrVoiceObj.msgIPtime.ms=0;
		    this.videoOrVoiceObj.msgIPtime.seconds=0;
		    this.videoOrVoiceObj.msgIPtime.longTime="00:00:00";
		  },
		  stopMsgIPtime(){  //暂停
		    clearInterval(this.videoOrVoiceObj.msgIPtime.timer);
		  },
		
		  // 设置某个 player 属性
		  setPlayerAttributesHandler(player, options) {
		    this.playerList=this.TRTC.setPlayerAttributes(player.streamID, options)
		  },
		
		  // 事件监听
		  bindTRTCRoomEvent() {
		    console.log('有被调用')
		    const TRTC_EVENT = this.TRTC.EVENT
		    // 初始化事件订阅
		    this.TRTC.on(TRTC_EVENT.LOCAL_JOIN, (event) => {
		      this._isEnterRoom = true
		      //进房成功  开启计时功能
		      this.initTime()
		      this.ipVoiceOrVideoLongTimeClick()
		      console.log('* room LOCAL_JOIN 进房成功了', event)
		      console.log('进房成功人员',this.playerList)
		    })
		    this.TRTC.on(TRTC_EVENT.LOCAL_LEAVE, (event) => {
		      console.log('* room LOCAL_LEAVE', event)
		    })
		    this.TRTC.on(TRTC_EVENT.ERROR, (event) => {
		      console.log('* room ERROR', event)
		    })
		    // 远端用户退出
		    this.TRTC.on(TRTC_EVENT.REMOTE_USER_LEAVE, (event) => {
		      const { playerList } = event.data
		      this.playerList= playerList
		      console.log('* room REMOTE_USER_LEAVE', event)
		    })
		    // 远端用户推送视频
		    this.TRTC.on(TRTC_EVENT.REMOTE_VIDEO_ADD, (event) => {
		      console.log('* room REMOTE_VIDEO_ADD',  event)
		      const { player } = event.data
		      // 开始播放远端的视频流,默认是不播放的
		      this.setPlayerAttributesHandler(player, { muteVideo: false })
		    })
		    // 远端用户取消推送视频
		    this.TRTC.on(TRTC_EVENT.REMOTE_VIDEO_REMOVE, (event) => {
		      console.log('* room REMOTE_VIDEO_REMOVE', event)
		      const { player } = event.data
		      this.setPlayerAttributesHandler(player, { muteVideo: true })
		    })
		    // 远端用户推送音频
		    this.TRTC.on(TRTC_EVENT.REMOTE_AUDIO_ADD, (event) => {
		      console.log('* room REMOTE_AUDIO_ADD', event)
		      const { player } = event.data
		      this.setPlayerAttributesHandler(player, { muteAudio: false })
		    })
		    // 远端用户取消推送音频
		    this.TRTC.on(TRTC_EVENT.REMOTE_AUDIO_REMOVE, (event) => {
		      console.log('* room REMOTE_AUDIO_REMOVE', event)
		      const { player } = event.data
		      this.setPlayerAttributesHandler(player, { muteAudio: true })
		    })
		  },
		
		  // 是否订阅某一个player Audio
		  _mutePlayerAudio(event) {
		    const player = event.currentTarget.dataset.value
		    if (player.hasAudio && player.muteAudio) {
		      this.setPlayerAttributesHandler(player, { muteAudio: false })
		      return
		    }
		    if (player.hasAudio && !player.muteAudio) {
		      this.setPlayerAttributesHandler(player, { muteAudio: true })
		      return
		    }
		  },
		
		  // 订阅 / 取消订阅某一个player Video
		  _mutePlayerVideo(event) {
		    const player = event.currentTarget.dataset.value
		    if (player.hasVideo && player.muteVideo) {
		      this.setPlayerAttributesHandler(player, { muteVideo: false })
		      return
		    }
		    if (player.hasVideo && !player.muteVideo) {
		      this.setPlayerAttributesHandler(player, { muteVideo: true })
		      return
		    }
		  },
		
		  //打开摄像头
		  _toggleVideoFun() {
		    if (this.pusher.enableCamera) {
		      this.publishLocalVideo(false);
		    } else {
		      this.publishLocalVideo(true);
		    }
		  },
		
		  /**
		 * 摄像头开关
		 * @returns {Promise}
		 */
		  publishLocalVideo(val) {
		    this.setPusherAttributesHandler({enableCamera: val})
		  },
		
		  
		
		/**
		 * 设置推流参数并触发页面渲染更新
		 * @param {Object} options live-pusher 的配置
		 * @returns {Promise}
		 */
		 setPusherAttributesHandler(options) {
		    this.pusher= this.TRTC.setPusherAttributes(options)
		    this.TRTC.getPusherInstance().start() // 开始推流(autoPush的模式下不需要)
		    console.log('看下人员',this.playerList)
		  },
		
		  // 挂断退出房间
		  _hangUp() {
		    this.exitRoom()
		    uni.reLaunch({
		      url: '/pages/callOver/index',
		      fail: e=>{
		        uni.switchTab({
		          url:'/pages/callOver/index'
		        })
		      }
		    })
		    setTimeout(()=>{
		      this.exitRoom();
		      //停止定时器,重置计时时间
		      this.resetMsgIPtime()
		      this.stopMsgIPtime()
		    },300)
		  },
		
		  // 设置美颜
		  _setPusherBeautyHandle() {
		    const  beautyLevel = this.pusher.beautyLevel === 0 ? 3 : 0
		    this.setPusherAttributesHandler({ beautyLevel })
		  },
		
		  // 发布 / 取消发布 Audio
		  _pusherAudioHandler() {
		    if (this.pusher.enableMic) {
		      this.setPusherAttributesHandler({ enableMic: false })
		    } else {
		      this.setPusherAttributesHandler({ enableMic: true })
		    }
		  },
		
		  _pusherSwitchCamera() {
		    const  frontCamera = this.pusher.frontCamera === 'front' ? 'back' : 'front'
		    this.TRTC.getPusherInstance().switchCamera(frontCamera)
		  },
		
		  _setPlayerSoundMode() {
		    if (this.playerList.length === 0) {
		      return
		    }
		    const player = this.TRTC.getPlayerList()
		    const soundMode = player[0].soundMode === 'speaker' ? 'ear' : 'speaker'
		    this.setPlayerAttributesHandler(player[0], { soundMode })
		  },
		  // 请保持跟 wxml 中绑定的事件名称一致
		  pusherStateChangeHandlerFun(event) {
		    const code = event.detail.code;
		    const message = event.detail.message;
		    console.log('监控状态码', 'pusherStateChange:', code, event);
		    this.TRTC.pusherEventHandler(event)
		  },
		  _pusherNetStatusHandler(event) {
		    this.TRTC.pusherNetStatusHandler(event)
		  },
		  _pusherErrorHandler(event) {
		    this.TRTC.pusherErrorHandler(event)
		  },
		  _pusherBGMStartHandler(event) {
		    this.TRTC.pusherBGMStartHandler(event)
		  },
		  _pusherBGMProgressHandler(event) {
		    this.TRTC.pusherBGMProgressHandler(event)
		  },
		  _pusherBGMCompleteHandler(event) {
		    this.TRTC.pusherBGMCompleteHandler(event)
		  },
		  _pusherAudioVolumeNotify(event) {
		    this.TRTC.pusherAudioVolumeNotify(event)
		  },
		  _playerStateChange(event) {
		    this.TRTC.playerEventHandler(event)
		  },
		  _playerFullscreenChange(event) {
		    this.TRTC.playerFullscreenChange(event)
		  },
		  _playerNetStatus(event) {
		    this.TRTC.playerNetStatus(event)
		  },
		  _playerAudioVolumeNotify(event) {
		    this.TRTC.playerAudioVolumeNotify(event)
		  },
		  //校验
		  checkParamFun(rtcConfig){
		    if (!rtcConfig.sdkAppID) {
		      console.error('未设置 sdkAppID');
		      this.methods("tips",'未设置 sdkAppID')
		      return false;
		    }
		
		    if (rtcConfig.roomID === undefined) {
		      console.error('未设置 roomID');
		      this.methods("tips",'未设置 roomID')
		      return false;
		    }
		
		    if (rtcConfig.roomID < 1 || rtcConfig.roomID > 4294967296) {
		      console.error('roomID 超出取值范围 1 ~ 4294967295');
		      this.methods("tips",'roomID 超出取值范围 1 ~ 4294967295')
		      return false;
		    }
		
		    if (!rtcConfig.userID) {
		      console.error('未设置 userID');
		      this.methods("tips",'未设置 userID')
		      return false;
		    }
		
		    if (!rtcConfig.userSig) {
		      console.error('未设置 userSig');
		      this.methods("tips",'未设置 userSig')
		      return false;
		    }
		
		    if (!rtcConfig.template) {
		      console.error('未设置 template');
		      this.methods("tips",'未设置 template')
		      return false;
		    }
		    return true
		  }
		
		
		  //提示
		  tips(str,len){
		    uni.showToast({
		      icon: "none",
		      duration: len?len:1000,
		      position: 'top',
		      title: str,
		    }) 
		  }
	 },
	 watch:{
		 config: {
		    handler: function(newVal, oldVal) {
		      console.log('watch config',newVal);
		    },
		    deep: true
		  },
	},
	computed:{
		_isEnterRoom:{
		    get () {
		      return this.isEnterRoom || false
		    },
		    set (val) {
		      this.$emit('update:isEnterRoom', val)
		    }
		  },
	}
	  
}
注意一些坑sdkId和secretKey一定要对,签名可以先用debug的模拟.

出现这个是因为小程序appid不对

''渲染失败,错误原因:

insertLivePusher:fail jsapi has no permission,

event=insertLivePusher, runningState=foreground, permissionMsg-permission got, detail=jsapi has nopermission

添加v-if使得数据更新,组件在一进页面就加载了,然后初始化了一个pusher,但是没有url,所以没有画面也接不通,等到进房之后重新赋值就友东西触发页面更新了,就有画面了.

无画面问题,但是这个v-if也使得元素消失,写法不对导致元素节点消失,所以关闭摄像头导致没有声音了.

有问题可以私聊详细交流

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
要在两个小程序之间实现实时音视频通话,可以借助腾讯云的实时音视频 SDK(TRTC)和实时音视频云服务。 以下是实现步骤和代码示例: 步骤一:准备工作 1. 在腾讯云官网注册账号并创建云通信应用,获取 SDKAppID。 2. 下载 TRTC 的小程序 SDK,并在小程序项目中引入。 步骤二:初始化 SDK小程序的 App.js 中初始化 TRTC SDK,代码示例如下: ```javascript const trtcConfig = { SDKAppID: 'your_SDKAppID', // 替换为实际的 SDKAppID }; App({ onLaunch: function () { wx.$trtc = require('./path/to/TRTCSDK.js').createInstance(trtcConfig); } }); ``` 步骤实现音视频通话 1. 在小程序页面中创建 TRTC 实例,并设置事件监听: ```javascript const trtcInstance = getApp().$trtc; Page({ data: { roomId: '', localView: '', remoteView: '', }, onLoad: function () { trtcInstance.on('onLocalView', (e) => { this.setData({ localView: e.view }); }); trtcInstance.on('onRemoteView', (e) => { this.setData({ remoteView: e.view }); }); trtcInstance.on('onUserExit', (e) => { // 处理用户退出房间的逻辑 }); }, joinRoom: function () { const roomId = this.data.roomId; const userId = 'your_user_id'; // 替换为实际的用户 ID trtcInstance.joinRoom(roomId, userId); }, exitRoom: function () { trtcInstance.exitRoom(); } }); ``` 2. 在小程序页面的 WXML 中使用 live-player 组件展示本地和远程视频画面: ```html <!-- 本地画面 --> <live-player src="{{localView}}" bindplay="onPlay"></live-player> <!-- 远程画面 --> <live-player src="{{remoteView}}" bindplay="onPlay"></live-player> ``` 3. 在小程序页面的 WXSS 中设置 live-player 的样式: ```css live-player { width: 100%; height: 100%; } ``` 4. 其他用户加入房间后,会触发 `onRemoteView` 事件,将远程视频画面展示在 live-player 组件中。 这样,两个小程序就可以通过 TRTC 实现实时音视频通话了。具体的实现细节还需要根据业务需求进行调整和完善。以上仅为简单示例,更详细的代码和功能可以参考腾讯云 TRTC 小程序 SDK 的官方文档。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_小郑有点困了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值