最近项目有个需求,想实时观看音视频功能
大概逻辑是设备端推流,web端拉流
我们是找个第三方的服务—zego,利用他的实时音视频功能来实现这个需求
大概逻辑是设备端和web端都去服务端获取zego的token然后加入房间,然后设备端推流,web端拉流
一,首先,引入zego的包
npm i zego-express-engine-webrtc --save
或者
cnpm i zego-express-engine-webrtc --save
二,在页面中引入
import { ZegoExpressEngine } from "zego-express-engine-webrtc";
三,在页面中给一个容器,设置宽高
<div id="remote-video" style="max-width: 90%; max-height: 90%"></div>
四,在页面中渲染
想要拉流时,首先获取zego的token信息
//获取视频流token
getStreamToken() {
getStreamToken({
uuid: this.uuid,
}).then((res) => {
this.streamQuery = res.data;
//这里是利用websocket像服务器发请求推流指令的,大家根据实际业务情况来
console.log("发送推流指令");
this.websocket.send(JSON.stringify(startStreaming));
});
},
然后收到服务端返回的已经开始推流的信息后,拿着刚才服务端返回的token等信息初始化实例和登录房间
然后利用zego提供的监听房间流回调和广播消息回调去拉流或者停止拉流,退出房间
//web开始拉流
else if (data.code === 8027) {
this.$message.success("正在获取视频资源");
// 项目唯一标识 AppID,Number 类型,请从 ZEGO 控制台获取
let appID = this.streamQuery.appId;
// 接入服务器地址 Server,String 类型,请从 ZEGO 控制台获取
let server = this.streamQuery.server;
let userID = this.$ls.get("userInfo").id + "-" + this.uuid;
let roomID = this.videoItem.serialNum;
let token = this.streamQuery.token;
if (this.zg == null) {
// 初始化实例
this.zg = new ZegoExpressEngine(appID, server);
//登录房间
this.zg
.loginRoom(
roomID,
token,
{ userID, userName: this.channelQueryParams.channel },
{ userUpdate: true }
)
.then((result) => {
if (result == true) {
console.log("login success");
}
});
//zego token过期处理
this.zg.on("tokenWillExpire", (roomID) => {
// 重新请求开发者服务端获取 Token
getStreamToken({
uid: this.$ls.get("userInfo").id + "-" + this.uuid,
}).then((res) => {
this.streamQuery = res.data;
this.zg.renewToken(this.streamQuery.token);
});
});
// 流状态更新回调
this.zg.on(
"roomStreamUpdate",
async (roomID, updateType, streamList, extendedData) => {
//当updateType为ADD时,代表有音视频流新增,此时可以调用startPlayingStream接口拉取播放该音视频流
if (updateType == "ADD") {
//流新增
console.log("流增加");
//this.streamIdList加入新的流
streamList.forEach((r) => {
this.streamIdList.push(r.streamID);
});
//这里为了使示例代码更加简洁,我们只拉取新增的音视频流列表中第的第一条流,在实际的业务中,建议开发者循环遍历 streamList ,拉取每一条音视频流
this.startPlayingStream();
}
// 流删除,停止拉流
else if (updateType == "DELETE") {
// 流删除,通过流删除列表 streamList 中每个流的 streamID 进行停止拉流。
// const streamID = streamList[0].streamID;
streamList.forEach((element) => {
if (
element.streamID ===
roomID + "-" + this.channelQueryParams.channel
) {
this.zg.stopPlayingStream(element.streamID);
this.streamIdList.splice(
this.streamIdList.indexOf(element.streamID),
1
);
}
});
}
}
);
//收到广播消息的通知
this.zg.on("IMRecvBroadcastMessage", (roomID, chatData) => {
console.log("广播消息IMRecvBroadcastMessage", roomID, chatData);
let message = JSON.parse(chatData[0].message);
//切换流
if (message.msgType === 0) {
message.data.forEach(async (r) => {
//可以拉流
if (
this.streamIdList.includes(
roomID + "-" + this.channelQueryParams.channel
) &&
r.channel === this.channelQueryParams.channel &&
r.status != 0
) {
console.log("可以拉流");
this.startPlayingStream();
} else if (
r.channel === this.channelQueryParams.channel &&
r.status == 0
) {
this.$message.error(r.msg);
}
});
}
//设备在被互动占用
else if (message.msgType === 1) {
if (this.zg != null && this.streamID != null) {
//停止拉流
this.zg.stopPlayingStream(this.streamID);
//退出房间
this.zg.logoutRoom(roomID);
this.streamID = null;
}
this.zg = null;
this.occupied = true;
}
});
}
}
//开始拉流
async startPlayingStream() {
let roomID = this.videoItem.serialNum;
for (let i = 0; i < this.streamIdList.length; i++) {
if (this.streamIdList[i] === roomID + "-" + this.channelQueryParams.channel) {
this.streamID = this.streamIdList[i];
// streamList中有对应流的 streamID
const remoteStream = await this.zg.startPlayingStream(this.streamID);
// 创建媒体流播放组件对象,用于播放远端媒体流 。
const remoteView = this.zg.createRemoteStreamView(remoteStream);
document.getElementById("remote-video").innerHTML = "";
// 将播放组件挂载到页面,"remote-video" 为组件容器 DOM 元素的 id 。
remoteView.play("remote-video");
break;
}
}
},
写的有点潦草,如果有疑问,欢迎私信或留言评论