获取直播rtmp地址
备注: 1.萤石开发手册:https://open.ys7.com/doc/zh/uikit/wechat_miniapp.html
2.微信公众平台:在微信公众平台里注册小程序必须选用企业账号(需要审核)
3.可以采用复核资质快速注册小程序(无需任何费用和审核)
4.萤石云小程序依赖微信实时音视频播放组件live-player,需要通过类目审核。审核通过后开启该组件的接口权限。
5.在微信小程序中请求萤石开放平台API时,需预先设置通讯域名,小程序只可以和指定的域名进行网络通讯。您可以登录微信公众平台,在左侧导航栏单击 「开发」,然后单击 「开发设置」,在 「服务器域名」 区域,单击 「修改」,进行配置。
wxml(视频播放区块)
注释:
bindstatechange:监听播放状态变化,通过e.detail.code获取当前播放状态值
mode属性默认为live(直播模式),萤石云小程序live-player组件为实时通话模式(mode="RTC"),该模式时延更低。
let livePlayerContext
page({
data: {
videoSrc: '' // 视频播放地址
},
onLoad: function () {
livePlayerContext = wx.createLivePlayerContext('videoPlayr');
//创建 LivePlayerContext 对象,以操作live-player组件
// 调用接口获取videoSrc视频播放地址,videoPlayr为组件的id名
},
// 开始播放
videoPlayer(){
this.setData({
play:'none',
play2:'block'
})
livePlayerContext.play({
success: ()=>{
console.log("播放成功")
},
fail: (error)=>{
console.log("播放失败:",error)
}
})
},
//暂停播放
closePlayer(){
this.setData({
play:'block',
play2:'none'
})
livePlayerContext.pause({
success:()=>{
console.log("暂停播放")
},
fail:(error)=>{
console.log("暂停播放失败",error)
}
})
},
statechange(e) { // 播放状态监听
const { code } = e.detail;
switch (code){
case 2007: //启动loading
break;
case 2001: //连接服务器
break;
case 2002: //已经连接 RTMP 服务器,开始拉流
break;
case 2008: // 解码器启动
console.log("case 2008: //解码器启动");
break;
case 2009: //视频分辨率改动
console.log("case 2009: //视频分辨率改动");
this.handlePlay(); // 视频分辨率改动可能导致播放暂停,可调用handlePlay()重启播放
break;
case 2004:
console.log("case 2004: // 视频播放开始");
break;
case 2003:
console.log("case 2003: //网络接收到首个视频数据包(IDR)");
break;
case 2103: //网络断连, 已启动自动重连(本小程序不自动重连)
break;
case 3001:
case 3002:
case 3003:
case 3005: // RTMP 读/写失败,之后会发起网络重试
console.log("播放失败");
break;
case 2105: // 当前视频播放出现卡顿
break;
case -2301: // 经多次重连抢救无效,更多重试请自行重启播放
break;
}
},
})
注释:livePlayerContext讲解
直播组件控制 - LivePlayerContext - 《百度智能小程序API文档(202003)》 - 书栈网 · BookStackLivePlayerContext示例扫码体验图片示例代码示例错误码AndroidiOS 智能小程序,智能连接人与信息、人与服务、人与万物的开放生态,依托以百度App为代表的全域流量,通过百度AI开放式赋能, 精准连接用户,无需下载安装便可享受智慧超前的使用体验。https://www.bookstack.cn/read/smartprogram-apilist-202003/6ef21e6bf6f825a5.md
注释:
1.返回数据,返回字段url为rtmp直播地址
2.需要注册“萤石云”账号
3.AccessToken在萤石云“我的账号”下的应用信息里
page({
onLoad:function(){
//请求rtmp直播地址
wx.request({
url: 'https://open.ys7.com/api/lapp/v2/live/address/get',
method: 'POST',
data: {
accessToken:"",
deviceSerial:"",//设备序列号
channelNo:"1",//通道号
protocol:"3",//流轮播协议
quality:"1",//视频清晰度
expireTime:'86400'//过期时间
},
header: {
'content-type': 'application/x-www-form-urlencoded' // 默认值(一定要加,不然会提
示"deviceSerial不能为空", code: "10001")
},
success:(res) =>{
console.log(res.data);
if(res.data.code ==200 && res.data.data){
console.log("请求rtmp直播地址成功!",res.data.data.url)
this.setData({
videoSrc:res.data.data.url
})
console.log(this.data.videoSrc)
}else {
// 微信提供的错误信息弹出框
wx.showToast({
title: res.data.msg,
icon: 'none'
})
}
}
})
}
})
在前面两项的基础上来进行云台控制
注释:
1.目前萤石云小程序只支持设备上、下、左、右四个方位的转向
2.我们通过微信提供的 catchtouchstart 和 catchtouchend 监听手势移动开始和结束时的坐标值
page({
// 计算移动起始方位
handlePtzTouchStart(event){
wx.createSelectorQuery().select('#ptz-img-container').boundingClientRect( (rect)
=> {
let { clientX,clientY} = event.touches[0]; // 移动起始坐标值
let rectLeft = rect.left; // 计算云台控制组件的位置
let rectTop = rect.top; // 计算云台控制组件的位置
var centerLeft = 104 + rectLeft; // 组件实际坐标值
var centerTop = 104 + rectTop;// 组件实际坐标值
var left = clientX - centerLeft; // 移动偏移量
var top = clientY - centerTop; // 移动偏移量
if(Math.abs(left) > Math.abs(top)){
if(left>0){
this.handlePtzControl(3); // 向右移动
}else {
this.handlePtzControl(2); // 向左移动
}
} else {
if (top > 0) {
this.handlePtzControl(1); // 向下移动
} else {
this.handlePtzControl(0); // 向上移动
}
}
}).exec();
},
// 计算移动结束时方位
handlePtzTouchEnd(event) {
let { clientX, clientY } = event.changedTouches[0]; //移动结束坐标值
const _this = this;
wx.createSelectorQuery().select('#ptz-img-container').boundingClientRect( (rect)
=> {
let rectLeft = rect.left;// 计算云台控制组件的位置
let rectTop = rect.top;// 计算云台控制组件的位置
var centerLeft = 104 + rectLeft; // 组件实际坐标值
var centerTop = 104 + rectTop;// 组件实际坐标值
var left = clientX - centerLeft;// 移动偏移量
var top = clientY - centerTop;// 移动偏移量
if (Math.abs(left) > Math.abs(top)) {
if (left > 0) {
_this.handlePtzControl(3,'stop');
} else {
_this.handlePtzControl(2, 'stop');
}
} else {
if (top > 0) {
_this.handlePtzControl(1, 'stop');
} else {
_this.handlePtzControl(0,'stop');
}
}
}).exec();
},
// 调用接口控制云台转向(被执行两次开始点击一次,结束点击一次)
handlePtzControl(position,type){ //position是方向(3:右,2:左,1:下,0:上),type是判断
开始还是结束
const { accessToken, deviceSerial, channelNo } = this.data;
var url = 'https://open.ys7.com/api/lapp/device/ptz/start'; //请求开始云台控制地址
if(type == 'stop'){
url = 'https://open.ys7.com/api/lapp/device/ptz/stop'//请求结束云台控制地址
}
wx.request({
url: url, //请求地址上面的url局部变量(判断是开始云台控制地址/结束云台控制地址)
method: 'POST',
data: {
"accessToken": accessToken,
"deviceSerial": deviceSerial,//设备序列号
"channelNo": channelNo,//通道号
"direction": position, //操作命令:0-上,1-下,2-左,3-右,8-放大,9-缩小
speed:1,
},
header: {
'content-type': 'application/x-www-form-urlencoded' // 默认值
},
success: (res) => {
console.log(res.data)
const code = res.data.code;
if(code == 10029){
wx.showToast({
title: '个人版接口调用超限,请升级企业版',
icon: 'none',
})
}
if(code == 200){
console.log('控制成功')
}
}
})
},
})
closeSound(){
this.setData({
abc:'none',
abc2:'block'
})
livePlayerContext.mute({
success: ()=>{
console.log("关闭声音")
},
fail: (error)=>{
console.log(error)
console.log('关闭声音失败')
}
})
},
openSound(){
this.setData({
abc:'block',
abc2:'none'
})
livePlayerContext.resume({
success: ()=>{
console.log("开启声音")
},
fail: (error)=>{
console.log(error)
console.log('开启声音失败')
}
})
},
// 创建recorderManager对象
const recorderManager = wx.getRecorderManager();
const options = {
duration: 60000, //指定录音的时长,单位 ms,最大为10分钟(600000),默认为1分钟(60000)
sampleRate: 16000, //采样率
numberOfChannels: 1, //录音通道数
format: 'mp3', //音频格式,有效值 aac/mp3
}
page({
onLoad:function(){
// 监听录音结束事件
recorderManager.onStop((res) => {
const { recoderTime } = this.data;
const { tempFilePath } = res;
wx.uploadFile({
url: 'https://open.ys7.com/api/lapp/voice/sendonce', //临时语音下发接口
filePath: tempFilePath, //tempFilePaths[0],
name: 'voiceFile',
formData: {
accessToken: accessToken,
deviceSerial: deviceSerial,
channelNo: channelNo,
},
header: {
'content-type': 'amultipart/form-data' // 默认值
},
success:(res)=>{
let data=res.data;
if(!data.code){
data=JSON.parse(data);
}
if(data.code==200){
console.log('发送成功');
}
},
fail:(error)=>{
console.log('发送失败:',error);
}
})
})
},
// 开始对讲
speakStart(event){
recorderManager.start(options);
console.log("开始对讲");
this.setData({
a:'none',
a2:'block',
})
},
// 结束对讲
speakEnd(event) {
console.log("结束对讲")
recorderManager.stop();
this.setData({
a:'block',
a2:'none',
})
}
})