我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第1篇文章,点击查看活动详情
公司新起了一个项目关于小程序相关的,我是用原声写的。
为什么要用原生呢?
- 我是第一次玩小程序---新手上路(掉入了填坑爬坑......)
- 是从一个老的项目直接改的
需求
- 类似微信音视频通讯
- 某一个有身份的可以对其他进入房间里面的人进行截屏(可以截自己、可以截其他人)
- 是否全屏
- 反转摄像头
- 签名(下篇文章写)
需求大不多这样了,我们开干
npm
首先就是关于trtc相关的npm包了,安排
npm i trtc-wx-sdk
我这里的版本是
当然原生小程序开发下完包是不能直接引入使用的,我们这样
这样就会在node_modules的平级出现它
当然没出来也不要紧,我们配置一下下
接下来我们就可以愉快的code了
创建trtc.js
随便在pages下建立一个trtc.js
import TRTC from '../../miniprogram_npm/trtc-wx-sdk/index.js'; //这样引入
Page({
data:{
sdkAppID: '', // 必要参数 开通实时音视频服务创建应用后分配的 sdkAppID
userID: '', // 必要参数 用户 ID 可以由您的帐号系统指定
userSig: '', // 必要参数 身份签名,相当于登录密码的作用
localVideo: false,//本地视频
localAudio: false,//本地音频
webcam: false,//摄像头
pusher: null,//推流数据
playerList: [],//拉流数据
//是否全屏
fullScreenFlag: true,
currentPlayer: '',
}
})
首先就是获取后端数据拿到userID、sdkAppID、userSig
getTRTCConfig().then(res=>{
this.setData({
userID: res.userId,
sdkAppID: res.sdkAppId,
userSig: res.userSig
})
})
里面还有一个处理对象里面关于boolean值用字符串包裹的转换
// 将String 类型的 true false 转换成 boolean
Object.getOwnPropertyNames(options).forEach((key) => {
if (options[key] === 'true') {
options[key] = true
}
if (options[key] === 'false') {
options[key] = false
}
})
初始化
我们需要在onLoad初始化一些东西了
this.init()
this.enterRoom({ roomID: 999 }) //随便写个房间号
this.bindTRTCRoomEvent() //监听各种
init
先让我们看下init里面干了些什么
init () {
// pusher 初始化参数
const pusher = this.TRTC.createPusher()
this.setData({
pusher: pusher.pusherAttributes,
})
},
啥也不是,这是我们开始使用trtc最初的地方
enterRoom
完事就是我们要进入到房间了,_是lodash的方法的简写,感兴趣的大家自己可以下载一下
enterRoom (options) {
const roomID = options.roomID //房间号
const config = _.assign(_.pick(this.data, ['sdkAppID', 'userID', 'userSig']), { roomID })
this.setData({
pusher: this.TRTC.enterRoom(config),
}, () => {
this.TRTC.getPusherInstance().start() // 开始推流
})
},
exitRoom
有进入房间就有退出房间(有主动、有被动)
exitRoom () { //主动
const result = this.TRTC.exitRoom()
this.setData({
pusher: result.pusher,
playerList: result.playerList,
})
},
onKickedout () { //被动
console.log('被服务端踢出或房间被解散')
},
bindTRTCRoomEvent
接下来我们去绑定监听一些东西,就是我们的bindTRTCRoomEvent函数啦,里面监听的东西比较多哦,且让我cv一下哈(主要是推流、拉流各种状态的极限拉扯)
//事件监听
bindTRTCRoomEvent () {
const TRTC_EVENT = this.TRTC.EVENT
// 初始化事件订阅
this.TRTC.on(TRTC_EVENT.LOCAL_JOIN, (event) => {
console.log('* room LOCAL_JOIN', event)
getApp().aegisReportEvent('inMeetingRoom', 'inMeetingRoom-success')
if (this.data.localVideo) {
this.setPusherAttributesHandler({ enableCamera: true })
}
if (this.data.localAudio) {
this.setPusherAttributesHandler({ enableMic: true })
}
})
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_JOIN, (event) => {
console.log('* room REMOTE_USER_JOIN', event)
const { userID } = event.data
wx.showToast({
title: `${userID} 进入了房间`,
icon: 'none',
duration: 2000,
})
})
// 远端用户退出
this.TRTC.on(TRTC_EVENT.REMOTE_USER_LEAVE, (event) => {
console.log('* room REMOTE_USER_LEAVE', event)
const { userID, playerList } = event.data
this.setData({
playerList: playerList
})
wx.showToast({
title: `${userID} 离开了房间`,
icon: 'none',
duration: 2000,
})
})
// 远端用户推送视频
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 })
})
// 远端用户音量更新
this.TRTC.on(TRTC_EVENT.REMOTE_AUDIO_VOLUME_UPDATE, (event) => {
console.log('* room REMOTE_AUDIO_VOLUME_UPDATE', event)
const { playerList } = event.data
this.setData({
playerList: playerList
})
})
// 本地用户音量更新
this.TRTC.on(TRTC_EVENT.LOCAL_AUDIO_VOLUME_UPDATE, (event) => {
// console.log('* room LOCAL_AUDIO_VOLUME_UPDATE', event)
const { pusher } = event.data
this.setData({
pusher: pusher
})
})
//被动退出当前房间
this.TRTC.on(TRTC_EVENT.KICKED_OUT, this.onKickedout)
},
pusher、player
有两个概念。。。。。pusher(我们自己)----player(看到远端的) 安排
// 设置 pusher 属性
setPusherAttributesHandler (options) {
console.log(this.TRTC.setPusherAttributes(options), 'this.TRTC.setPusherAttributes(options)')
this.setData({
pusher: this.TRTC.setPusherAttributes(options),
})
},
// 设置某个 player 属性
setPlayerAttributesHandler (player, options) {
let playerList = this.TRTC.setPlayerAttributes(player.streamID, options)
this.setData({
playerList
})
},
Audio相关
我们要订阅pusher、player的Audio
// 是否订阅某一个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 Audio
_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
}
},
// 订阅 / 取消订阅 Audio
_pusherAudioHandler () {
if (this.data.pusher.enableMic) {
this.setPusherAttributesHandler({ enableMic: false })
} else {
this.setPusherAttributesHandler({ enableMic: true })
}
},
// 订阅 / 取消订阅 Video
_pusherVideoHandler () {
if (this.data.pusher.enableCamera) {
this.setPusherAttributesHandler({ enableCamera: false })
} else {
this.setPusherAttributesHandler({ enableCamera: true })
}
},
其他辅助函数
有一堆他们trtc内部的函数我这里也cv上,我查文档做了注释,他们demo没有
// 请保持跟 wxml 中绑定的事件名称一致
// 推流
// 状态变化事件,detail = {code}
_pusherStateChangeHandler (event) {
this.TRTC.pusherEventHandler(event)
},
// 网络状态通知,detail = {info}
_pusherNetStatusHandler (event) {
this.TRTC.pusherNetStatusHandler(event)
},
// 渲染错误事件,detail = {errMsg, errCode}
_pusherErrorHandler (event) {
this.TRTC.pusherErrorHandler(event)
},
// 背景音开始播放时触发
_pusherBGMStartHandler (event) {
this.TRTC.pusherBGMStartHandler(event)
},
// 背景音进度变化时触发,detail = {progress, duration}
_pusherBGMProgressHandler (event) {
this.TRTC.pusherBGMProgressHandler(event)
},
// 背景音进度变化时触发,detail = {progress, duration}
_pusherBGMCompleteHandler (event) {
this.TRTC.pusherBGMCompleteHandler(event)
},
// 返回麦克风采集的音量大小
_pusherAudioVolumeNotify (event) {
this.TRTC.pusherAudioVolumeNotify(event)
},
// 拉流
// 播放状态变化事件,detail = {code}
_playerStateChange (event) {
this.TRTC.playerEventHandler(event)
},
// 全屏变化事件,detail = {direction, fullScreen}
_playerFullscreenChange (event) {
this.TRTC.playerFullscreenChange(event)
},
// 网络状态通知,detail = {info}
_playerNetStatus (event) {
this.TRTC.playerNetStatus(event)
},
// 播放音量大小通知,detail = {}
_playerAudioVolumeNotify (event) {
this.TRTC.playerAudioVolumeNotify(event)
},
想主动离开退出房间
// 挂断退出房间
_hangUp () {
this.exitRoom()
wx.navigateBack({
delta: 1,
})
},
到这里两个手机小程序就可以悄悄的音视频通话啦!
接下来做一些功能
1.裁剪
可以截自己pusher。 可以截别人playerList的某一个 安排输出一个base64的给到后端大佬
这里的截屏的api 使用的是人家微信原生的(trtc的取不到是undefined)
onReady () {
this.ctx = wx.createLivePusherContext('pusher')
this.ctx_player = wx.createLivePlayerContext('player')
},
const FileSystemManager = wx.getFileSystemManager()
bindTailor () {
this.ctx_player.snapshot({
success: res => {
console.log('res: ', res);
FileSystemManager.readFile({
filePath: res.tempImagePath, //选择图片返回的相对路径
encoding: 'base64', //编码格式
success: res => {
console.log('res: ', res);
let base64 = res.data
// console.log('base64: ', base64);
},
fail: res => {
console.log("readFile失败", res)
wx.showToast({
title: '读取拍照文件失败',
icon: 'none'
})
}
})
},
fail: res => {
console.log("截屏失败", res)
wx.showToast({
title: '截取视频流失败',
icon: 'none'
})
},
})
},
2.是否全屏
这个用的trtc的api
//是否全屏
onFullScreen (event) {
this.setData({
fullScreenFlag: false
})
const player = this.TRTC.getPlayerList()
this.TRTC.getPlayerInstance(player[0].id).requestFullScreen(90).then(res => {
console.log('res: ', res);
}).catch(err => {
console.log('err: ', err);
})
},
unFullScreen (event) {
this.setData({
fullScreenFlag: true
})
const player = this.TRTC.getPlayerList()
this.TRTC.requestExitFullScreen(player[0].id).requestFullScreen(90).then(res => {
console.log('res: ', res);
}).catch(err => {
console.log('err: ', err);
})
},
3.切换摄像头
微信原生api
//切换摄像头
bindSwitchCamera () {
this.ctx.switchCamera({
success: res => {
console.log('switchCamera success')
this.setData({
webcam: !this.data.webcam
})
},
fail: res => {
console.log('switchCamera fail')
}
})
},
wxml 的代码大家可以down一下腾讯的我就不贴了
总结
- 要有钻研精神,解决不了就提工单给腾讯,毕竟看文档找的不如人家快,当然也有他们trtc的api解决不了的,完事就是踢皮球给微信原生api,极限拉扯ing.....
- 累了 毁灭吧 只有一条
- 下篇文章搞一下签名