uniapp小程序七牛云QNRTC实时音视频视频通话实现

 前置准备工作

  1. 请在微信小程序后台 -> 开发 -> 开发设置 -> 服务器域名配置中,将 wss://rtmpgate.cloudvdn.com 加到 socket 合法域名中,将 https://pili-rtc-qos.qiniuapi.com 添加到 request 合法域名中
  2. 在小程序的开发后台打开实时播放/录制音视频流的开关(小程序后台 -> 开发 -> 接口设置)。 

首先,先引入QNRTC,

npm install --save qnwxapp-rtc

 然后在需要接入视频的地方

  1. 初始化client
  2. 绑定监听事件
  3. 获取roomtoken
  4. 调用join加入房间
	        import QNRTC, { QNLogLevel } from 'qnwxapp-rtc'

            // 创建连接
            this.client = QNRTC.createClient()
			// 设置日志级别 避免太多log影响数据观测
            QNRTC.setLogLevel(QNLogLevel.ERROR);

            
            // 绑定监听事件
            this.client.on("user-joined", (user, userData) => {
		        console.log("event: user-joined - 用户加入房间", user, userData);
	        });
			  
	        this.client.on("user-left", (user) => {
	            console.log("event: user-left - 用户离开房间", user);
		        uni.$u.toast('对方已挂断通话')
	        });		  
	        this.client.on("user-published", async (user, tracks) => {
			    console.log("event: user-published - 用户发布", user, tracks);
				if (user === userId) {
				  return false;
				}
				let config = {};
				let videoTrackIndex = remoteTracks.findIndex((item) => item.isVideo());
				let audioTrackIndex = remoteTracks.findIndex((item) => item.isAudio());
				if (videoTrackIndex >= 0) {
				  config.videoTrack = remoteTracks[videoTrackIndex];
				}
				if (audioTrackIndex >= 0) {
				  config.audioTrack = remoteTracks[audioTrackIndex];
				}
				const url = await client.subscribe(config);
				me.subscribeList = [...me.subscribeList,{
				    url,
				    key: user + Math.random().toString(36).slice(-8),
				    userID: user,
				    audioTrack: remoteTracks[audioTrackIndex],
				    videoTrack: remoteTracks[videoTrackIndex]
				  }]
				console.log(me.subscribeList,'订阅列表')
			  });
			  this.client.on("user-unpublished", (user, tracks) => {
			    console.log("event: user-unpublished - 用户取消发布", user, tracks);
			    for (const track of tracks) {
			      this.subscribeList.map((ele, index) => {
			        if (ele.url.indexOf(track.trackID) !== -1) {
						 this.subscribeList.splice(index, 1);
			        }
			      });
			    }
			  });
			  this.client.on("connection-state-changed", (state, info) => {
			    console.log("event: connection-state-changed - 用户连接状态发生改变", state, info);
			    if (state === "DISCONNECTED" && info.reason === "ERROR") {
			      this.reconnect();
			    }
			  });
                
            
            // 获取rooktoken     getRoomToken(后端提供)
            const {status,message, result}  =await me.$api.getRoomToken({data:{room:'XXXX'}})
			if(status === 200){
				// 加入房间
				await this.client.join(result,userInfo.get().userId);
				this.publishHandler(this.client)
			}else{
				uni.$u.toast(message);
			}
            

            // 发布主题
            publishHandler(client){
				const me = this
				me.client.publish((status, data) => {
				  /**
				   * status 共有 READY 、COMPLETED、ERROR 三种状态
				   * 其中 READY 表示推流就绪,返回推流的 rtmp 地址
				   * COMPLETED 表示推流成功,返回推流生成的音频轨和视频轨
				   * ERROR 则表示推流失败
				   */
				  if(status === "READY") {
					  me.publishPath = data.url
					  console.log(data,'READY')
				  }else if(status === 'COMPLETED') {
					  console.log(data.tracks,'COMPLETED')
				  }else if(status === 'ERROR') {
					  console.log("发布失败")
				  }else{
					  console.log(status,data,'err')
				  }
				})
				
				console.log('已调用发布')
			}
			




 视频通话页面,基本代码源码  ,简单的参考下

<template>
	<view class="content" :style="{width: windowWidth + 'px',height: windowHeight + 'px'}">
		<!-- 远端用户 -->
		<view class="video_local_1" >
			<view style="width:200rpx;height: 300rpx;">
				<live-player
					 ref="location" 
					style="width:200rpx;height: 300rpx;" 
					v-for="(item,index) in subscribeList" :key="index"
					min-cache="0.1"
					max-cache="0.1"
					:playerid="item.key"
					mode="RTC"
					object-fit="fillCrop"
					:src="item.url" 
					:muted="volume"
					autoplay='true'
				>
				</live-player>
			</view>
		</view>
		<!-- 本地用户 -->
		<view class="video_local"  :style="{width: windowWidth + 'px',height: windowHeight + 'px'}">
			<view :style="{width: windowWidth + 'px',height: windowHeight + 'px'}">
				<live-pusher
					ref="location"
				  style="width:100%;height: 100%;" 
				  autopush
				  mode="RTC"
				  :url="video? publishPath : ''"
				  min-bitrate="200"
				  max-bitrate="400"
				  :device-position="devicePosition"
					:enable-camera="video"
					:muted="!mic"
				>
				</live-pusher>
			</view>
		</view>
		
		<!-- 相关操作 -->
		<view class="options" >
			<view style="display:flex;flex-direction: row;justify-content:space-around;margin-bottom: 20px;">
				<view class="icon" @click="videoFn">
					<image class="icon_img" src="@/static/vi_on.png" v-if="video"></image>
					<image class="icon_img" src="@/static/vi_in.png" v-else></image>
					<text class="icon_text">视频</text>
				</view>
				<view class="icon" @click="switchCamera">
					<image class="icon_img" src="@/static/camera.png" mode=""></image>
					<text class="icon_text">摄像{
   
   {camera?'前':'后'}}</text>
				</view>
			</view>
			<view style="display:flex;" :style="{flexDirection: 'row',justifyContent: subscribeList.length ? 'space-between':'center'}">
				<view class="icon" @click="audioFn" v-if="subscribeList.length">
					<image class="icon_img" src="@/static/au_in.png" v-if="mic"></image>
					<image class="icon_img" src="@/static/au_on.png" v-else></image>
					<text class="icon_text">静音</text>
				</view>
				<view class="icon" @click="closeFn">
					<image class="icon_img" src="@/static/over.png"></image>
					<text class="icon_text">挂断</text>
				</view>
				<view class="icon" @click="speakerphoneFn" v-if="subscribeList.length">
					<image class="icon_img" src="@/static/icon_speakers.png" v-if="!volume"></image>
					<image class="icon_img" src="@/static/icon_speaker.png" v-else></image>
					<text class="icon_text">扬声器</text>
				</view>
			</view>
		</view>
	</view>
</template>


<script>
	import QNRTC, { QNLogLevel } from 'qnwxapp-rtc'
	export default {
		data() {
			return {
				publishPath:'',
				enableCamera:true,
				playerId:'',
				// 远端视频容器样式
				windowWidth: 200,
				windowHeight: 400,
				
				// 相关操作
				mic: true,
				audio: true, // 音频开关
				Speakerphone: true, // 免提
				video: true, // 视频开关
				camera: true, // 摄像头前后
				switchover: false, // 大小切换
				client:null,
				volume:false,
				ctx:null
			};
		},
        onLoad(){
            this.ctx = wx.createLivePusherContext('pusher')
        },
        methods:{
            speakerphoneFn(){
				this.volume = !this.volume
			},
			// 切换摄像头
			switchCamera() {
				this.ctx.switchCamera()
				this.camera = !this.camera
				// this.devicePosition = this.devicePosition=='front' ? 'back' : 'front'
			  // if (this.pushContext) {
			  //   this.pushContext.switchCamera();
			  // }
			},
			videoFn(){
				this.video = !this.video
			},
			audioFn(){
				this.mic = !this.mic
			},
        }
    }
<script>
<style lang="scss" scoped>
.content {
		background-color: #2F3041;
		position: relative;
		width: 100%;
	}

	.text {
		color: #FFFFFF;
		margin-top: 20px;
	}

	/* 提示 */
	.hint {
		position: fixed;
		align-items: center;
	}
	.location {
		width: 153px;
		height: 204px;
		border-radius: 6px;
		position: fixed;
		top: 60px;
		right: 20px;
		background-color: #2C405A;
	}
	.option {
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
	}
	.location-none {
		flex: 1;
		position: absolute;
		top: 0;
		bottom: 0;
		right: 0;
		justify-content: center;
		align-items: center;
	}

	/* 用户标识 */
	.user-hint {
		position: absolute;
		bottom: 0;
		left: 0;
		background-color: #2F3041;
		opacity: 0.5;
		padding: 4px 10px;
	}
    
	.hint-text {
		color: #FFFFFF;
		opacity: 1;
	}
	
	.CanvasView {
		flex-wrap: wrap;
		flex-direction: row;
		padding: 60px 0 0;
	}

	.video_local {
		flex: 1;
	}

	/* 相关操作 */
	.options {
		position: fixed;
		bottom: 20px;
		margin: 0 20px;
		width: 90vw;
		display:flex;
		flex-direction: column;
		justify-content: space-between;
	}

	.icon {
		display: flex;
		flex-direction: column;
		justify-content: center;
		align-items: center;
	}

	.icon_img {
		width: 60px;
		height: 60px;
	}

	.icon_text {
		font-size: 28rpx;
		color: #FFFFFF;
		margin: 10px;
	}
</style>

参考官方文档:开发准备_快速入门_实时音视频 - 七牛开发者中心WXApp 实时音视频 SDK 开发准备https://developer.qiniu.com/rtc/11119/prepare-wxapp-development

猜你喜欢

转载自blog.csdn.net/weixin_42301688/article/details/130150113