miniprogram-ar-push
v1.0.12
Published
ar-push组件实现将小程序的实时流推送到服务器与其他成员(实时)互动。
Downloads
4
Readme
ar-push 推流组件
ar-push组件实现将小程序的实时流推送到服务器与其他成员(实时)互动。
小程序自定义组件
使用此组件需要依赖小程序基础库 2.2.1 以上版本,同时依赖开发者工具的 npm 构建。具体详情可查阅官方 npm 文档。
准备工作
- 注册微信小程序,登录小程序后台获取微信小程序appid,appSecrert,修改类目审核(社交、教育、医疗、政务民生、金融,目前只有这些支持,具体查看),配置socket合法域名
wss://域名
具体根据SDK文档指定的域名 - 获取开发者信息
- 开发-配置中开启“使用npm模块”,基础库选择2.4.0及以上,打开“不校验合法域名”、真机调试打开“调试”。集成miniprogram-ar-meet、miniprogram-ar-push、miniprogram-ar-play
使用说明
使用方法
- 安装 ar-push
npm install --save miniprogram-ar-push
- 构建npm, 打开微信开发者工具,点击工具-npm构建
- 在需要使用 slide-view 的页面 page.json 中添加 ar-push 自定义组件配置
{
"usingComponents": {
"ar-push": "miniprogram-ar-push"
}
}
WXML 文件中引用 ar-push
<view style="width: 100%; height: 200px;">
<!-- ar推流组件宽高设置的为100%,所以父容器需要设定宽高 -->
<ar-push
id="arPush"
coverImg=""
enableAudio="{{enableAudio}}"
enableVideo="{{enableVideo}}"
pubID="{{pubID}}"
pushURL="{{pushURL}}"
bindPushStatus="handlePushStatus"
bindNetStateChange="handlePushNetChange"
bindRoomEvent="handleRoomEvent">
</ar-push>
</view>
ar-push的属性介绍如下:
|属性名|类型|默认值|是否必须|说明|
|--|--|--|--|--|
|id|String|-|是|自定义组件标识ID,用户通过自定义组件标识ID获取组件的LivePusherContext
来切换摄像头等操作,点击查看详情。|
|pubID|String|-|是|ar-push组件推流标识ID,通过参数通过SDK回调返回|
|pushURL|String|-|是|ar-push组件推流URL,通过参数通过SDK回调返回|
|coverImg|String|-|否|ar-push组件进入后台时推流的等待画面|
|enableAudio|Boolean|true|否|ar-push组件是否静音|
|enableVideo|Boolean|true|否|ar-push组件是否开启摄像头|
|bindNetStateChange|Function|-|是|监听ar-push组件推流网络质量|
|bindRoomEvent|Function|-|是|ar-push组件接收在线人员信息、推流等信息|
ar-push的方法介绍如下
注意:
当需要停止推流、回复推流、切换摄像头等操作时,需要获取到推流组件对象后,才可对其进行操作。
打开/关闭摄像头、打开/关闭麦克风则改变推流组件对外属性enableVideo
和enableAudio
即可。
具体看Demo
- 停止推流
//this为当前页面对象
this.selectComponent('#arPush').pause()
- 恢复推流
//this为当前页面对象
this.selectComponent('#arPush').resume()
- 切换前后置摄像头
//this为当前页面对象
this.selectComponent('#arPush').switchCamera()
- 打开/关闭麦克风
//this为当前页面对象
this.setData({
enableAudio: !this.data.enableAudio
});
- 打开/关闭摄像头
//this为当前页面对象
this.setData({
enableVideo: !this.data.enableVideo
});
完整代码(以实时视频会议为例)
WXML
<!--pages/room/room.wxml-->
<view style="width: 100%; height: 200px;">
<!-- ar推流组件宽高设置的为100%,所以父容器需要设定宽高 -->
<ar-push
id="arPush"
coverImg=""
enableAudio="{{enableAudio}}"
enableVideo="{{enableVideo}}"
pubID="{{pubID}}"
pushURL="{{pushURL}}"
bindPushStatus="handlePushStatus"
bindNetStateChange="handlePushNetChange"
bindRoomEvent="handleRoomEvent">
</ar-push>
</view>
<button class="meet_btn" bindtap="pausePush">暂停推流</button>
<button class="meet_btn" bindtap="resumePush">恢复推流</button>
<button class="meet_btn" bindtap="switchCamera">切换前后摄像头</button>
<button class="" bindtap="enableCamera">开关摄像头 :: 当前状态{{enableVideo ? '开' : '关'}}</button>
<button class="" bindtap="enableMicphone">开关麦克风 :: 当前状态{{enableAudio ? '开' : '关'}}</button>
<!-- 拉流组件,view包裹可自定义样式-->
<view wx:for="{{members}}" wx:key="index">
<ar-play
id="{{item.pubID}}-play"
data-id="{{item.pubID}}"
pubID="{{item.pubID}}"
width="{{item.width}}"
height="{{item.height}}"
playURL="{{item.playURL}}"
bindNetStateChange="handlePlayNetChange"
bindPlayStatus="handlePlayStatus">
</ar-play>
<button class="meet_btn" data-id="{{item.pubID}}" bindtap="pause">暂停</button>
<button class="meet_btn" data-id="{{item.pubID}}" bindtap="play">播放</button>
<button class="meet_btn" data-id="{{item.pubID}}" bindtap="full">全屏</button>
</view>
<button type="button" bindtap="leaveRoom">退出房间</button>
JS
const config = require('../../config.js');
let wxRTMeet = require('miniprogram-ar-meet');
// pages/room/room.js
Page({
/**
* 页面的初始数据
*/
data: {
arPusherComponent: null,
wxmeet: null,
pushURL: '',
enableVideo: true,
enableAudio: false,
members: []
},
//停止推流
pausePush () {
this.data.arPusherComponent.pause();
},
//恢复推流
resumePush () {
this.data.arPusherComponent.resume();
},
//截图
takeSnapshot () {
this.data.arPusherComponent.snapshot(res => {
console.log("截图结果", res);
});
},
//切换摄像头
switchCamera () {
this.data.arPusherComponent.switchCamera();
},
//打开/关闭摄像头
enableCamera () {
this.setData({
enableVideo: !this.data.enableVideo
});
},
//打开/关闭麦克风
enableMicphone () {
this.setData({
enableAudio: !this.data.enableAudio
});
},
//退出房间
leaveRoom() {
this.data.wxmeet.leaveRoom();
wx.navigateBack();
},
/**
* 生命周期函数--监听页面加载
*/
onLoad: function (options) {
let that = this;
let roomId = '' + options.roomid;
//会议实例
let wxmeet = new wxRTMeet();
that.setData({
wxmeet: wxmeet,
//推流组件,可以切换前后摄像头,打开或关闭音视频
arPusherComponent: that.selectComponent('#arPush')
});
wxmeet.initEngine(config.DEV_ID, config.APP_ID, config.APP_KEY, config.APP_TOKEN, config.APP_DOMAIN);
let userid = '' + parseInt(Math.random() * 10000);
let username = '' + parseInt(Math.random() * 1000000);
wxmeet.joinRoom(roomId, userid, username,JSON.stringify({ userid }));
wxmeet.on("onJoinRoomOK", () => {
wx.showToast({
title: '加入房间成功',
});
});
wxmeet.on("onJoinRoomFaild", (code, info) => {
console.log("加入房间失败:", code, info ? info : "");
});
//收到离开房间指令,收到该回调需要离开房间
wxmeet.on("onLeaveMeet", (code, info) => {
console.log("离开房间的原因:", info ? info : "");
});
wxmeet.on("onGetPushUrl", (code, data) => {
console.log('onGetPushUrl', code, data);
if (code === 0) {//成功
that.setData({
pushURL: data.pushURL
});
} else {
wx.showToast({
icon: 'none',
title: '获取房间签名失败',
});
}
});
wxmeet.on("onUserMessage", (strUserId, strUserName, strHeaderUrl, strUserData) => {
console.log("onUserMessage", strUserId, strUserName, strHeaderUrl, strUserData);
});
},
//监听房间事件
handleRoomEvent (e) {
let that = this;
let data = e.detail;
console.log('handleRoomEvent', data);
switch (data.tag) {
case "MemberChange":
let arrMember = data.detail;
arrMember.map(item => {
item.width = 100;
item.height = 100;
});
that.setData({
members: arrMember
});
break;
}
},
//监听推流状态
handlePushStatus (e) {
let that = this;
let data = e.detail;
let code = data.code;
console.log('handlePushStatus', data);
switch (code) {
case 1002:
{
console.log('推流成功')
break
}
case -1301:
{
console.error('打开摄像头失败: ', code)
// that.stop()
break
}
case -1302:
{
console.error('打开麦克风失败: ', code);
// that.stop()
break
}
case -1307:
{
console.error('推流连接断开: ', code)
// that.stop();
break
}
case 5000:
{
console.log('收到5000: ', code)
// 收到5000就退房
// that.stop()
break
}
case 1018:
{
console.log('进房成功', code)
break
}
case 1019:
{
console.log('退出房间', code)
break
}
case 1021:
{
console.log('网络类型发生变化,需要重新进房', code)
//先退出房间
// that.stop()
break
}
case 2007:
{
console.log('视频播放loading: ')
break
};
case 2004:
{
console.log('视频播放开始: ')
break
};
case 10001:
{
console.log('未获取到摄像头功能权限,请删除小程序后重新打开')
break
}
case 10002:
{
console.log('未获取到录音功能权限,请删除小程序后重新打开')
break
}
default:
{
console.log('推流情况:', code)
}
}
};
//监听推流网络质量
handlePushNetChange (e) {
let that = this;
let data = e.detail;
console.log('handlePushNetChange ====> 音频码率: %d , 视频码率: %d , 网络偏移: %d , 帧率:%d , 视频分辨率: %d * %d , GOP: %d', data.audioBitrate, data.videoBitrate, data.netJitter ? data.netJitter : 0, data.videoFPS, data.videoWidth, data.videoHeight, data.videoGOP);
},
//监听拉流网络质量
handlePlayNetChange(e) {
let that = this;
let data = e.detail;
console.log('handlePlayNetChange 用户PubId:', e.currentTarget.id.replace('user_', '').replace('-play', ''), ' , 用户网络状态: ', data);
},
//监听播放状态
handlePlayStatus (e) {
let that = this;
let data = e.detail;
//错误码参考 https://developers.weixin.qq.com/miniprogram/dev/component/live-player.html
console.log('handlePlayStatus', `pubID为 ${data.pubID} 的播放状态为 ${data.code}`);
},
pause (e) {
let that = this;
let data = e.currentTarget.dataset;
console.log('pause', data);
console.log('selectComponent', that.selectComponent(`#${data.id}-play`));
//参考 https://developers.weixin.qq.com/miniprogram/dev/api/media/live/LivePlayerContext.pause.html
that.selectComponent(`#${data.id}-play`).pause({
complete: res => {
console.log('selectComponent pause', res);
}
});
},
play (e) {
let that = this;
let data = e.currentTarget.dataset;
//参考 https://developers.weixin.qq.com/miniprogram/dev/api/media/live/LivePlayerContext.play.html
that.selectComponent(`#${data.id}-play`).play({
complete: res => {
console.log('selectComponent pause', res);
}
});
},
full (e) {
let that = this;
let data = e.currentTarget.dataset;
//参考 https://developers.weixin.qq.com/miniprogram/dev/api/media/live/LivePlayerContext.requestFullScreen.html
that.selectComponent(`#${data.id}-play`).requestFullScreen({
direction: 90,
complete: res => {
console.log('selectComponent pause', res);
}
});
//此处由于只做演示,所以2秒之后结束全屏
setTimeout(() => {
that.selectComponent(`#${data.id}-play`).exitFullScreen({
complete: res => {
console.log('selectComponent pause', res);
}
});
}, 2000);
},
/**
* 生命周期函数--监听页面初次渲染完成
*/
onReady: function () {
},
/**
* 生命周期函数--监听页面显示
*/
onShow: function () {
},
/**
* 生命周期函数--监听页面隐藏
*/
onHide: function () {
},
/**
* 生命周期函数--监听页面卸载
*/
onUnload: function () {
this.data.wxmeet.leaveRoom();
},
})