基于阿里云的摄像头与屏幕分享共存
由于需求改变,由一开始的摄像头直播,转向屏幕分享直播,再到摄像头与屏幕共享同时存在的直播,由此记录
由于是共存,我的想法是创建两个阿里云的实例,最后同一个推流地址推流即可
html结构
<div class="content" v-show="titleInfo?.live_status === 1" id="videoContainer"> <!--videoContainer主要是指定大屏画面位置-->
<span class="finishLive1" @click="doShare">分享</span>
<span class="finishLive" @click="closeLive">结束</span>
<div class="box" v-show="smallVideoFlag" ref="doShareRef"
style="width:180px;height:180px;
position:absolute;right:0;bottom:0; <!--定位至右下角-->
object-fit: fill; <!--视频填充-->
z-index:999;" <!--防止大屏压制住小屏-->
id="videoContainerSmall" > <!--videoContainerSmall主要是指定小屏画面位置-->
</div>
</div>
css
#videoContainerSmall video {
height:180px !important; //设置合适的高度
object-fit: fill; // 小屏视频填充,大屏不要填充,让他自适应,不然内容会扭曲,小屏由于宽高小,则几乎没影响
}
video::-webkit-media-controls-enclosure{
display: none; //关闭所有video的视频控件,主要是小屏是定位在大屏上的,关闭更有利于用户操作
}
vue
data() {
return {
pushClient:AliRTSPusher.createClient(), //创建大屏推流实例
pushClientSmall:AliRTSPusher.createClient(), //创建小屏推流实例
urlTui:'',//用于记录推流地址,方便后续同时推流,而不再二次调用推流接口
}
},
methods:{
// 初始化大屏SDK
initVideo() {
// 将容器ID传给SDK,SDK会在其中创建一个video标签并播放预览画面
this.pushClient.setRenderView('videoContainer');
// 设置直播清晰度
this.pushClient.setVideoQuality('720p_1');
},
// 初始化小屏SDK
initVideoSmall() {
this.pushClientSmall.setRenderView('videoContainerSmall');
this.pushClientSmall.setVideoQuality('720p_1');
this.$nextTick(()=>{
/*这里是由于阿里云它会根据绑定标签,每推流一次而创建一个video
因此分享屏幕可以点多次从而进行多次推流,导致阿里云底层帮你创建多个video
因此我们拿到该标签的子集,但是他是伪数组,需要转变为真数组,
且删除它的第1个,保留第0个,页面上就永远只有一个小屏
*/
if(Array.from(document.getElementById("videoContainerSmall").children).length > 1){document.getElementById("videoContainerSmall").removeChild(Array.from(document.getElementById("videoContainerSmall").children)[1])}
})
},
// 大屏推流
async openLive(){
//调用接口获取推流地址
let res = await syhtAjaxGet('/api/live/xxx',{kid:xxx});
this.pushClient.on("connectStatusChange", (event) => {
console.log(event.status);
});
this.pushClient.on("error", async (err) => {
console.log(err);
if (err.errorCode === "video device not found") {
console.log("video device not found");
}
if(err.errorCode === 10012) {
this.smallVideoFlag = false
await this.pushClient.stopScreenCapture();
await this.pushClient.startCamera();
await this.pushClient.startMicrophone();
}
});
// 打开摄像头 麦克风
await this.pushClient.startCamera();
await this.pushClient.startMicrophone();
this.urlTui = res.data?.push_url //推流地址
// 开始推流
await this.pushClient.startPush(res.data.push_url)
},
// 小屏推流
async openLiveSmall(){
let res = await syhtAjaxGet('/api/live/xxxl',{kid: xxx});
this.pushClientSmall.on("connectStatusChange", (event) => {
console.log(event.status);
});
this.pushClientSmall.on("error", async (err) => {
console.log(err);
if (err.errorCode === "video device not found") {
console.log("video device not found");
}
if(err.errorCode === 10012) {
// 状态码为10012时,即屏幕共享关闭,此时需要停止屏幕共享推流,开启摄像头音频推流
await this.pushClientSmall.stopScreenCapture(); // 屏幕共享关闭
// 打开摄像头 麦克风
await this.pushClientSmall.startCamera();
await this.pushClientSmall.startMicrophone();
}
});
await this.pushClientSmall.startCamera();
await this.pushClientSmall.startMicrophone();
this.urlTui = res.data?.push_url
// 推流开始
await this.pushClientSmall.startPush(res.data.push_url)
},
// 关闭大屏直播 停止推流 关闭视频 关闭麦克风
async stopPushClient() {
//调用关闭直播推流的接口
let res = await syhtAjaxGet('/api/live/xxx');
if(res.ret === 1) {
// 关闭摄像头音频
await this.pushClient.stopCamera();
await this.pushClient.stopMicrophone();
//停止推流
await this.pushClient.stopPush();
}
},
// 关闭小屏直播
async stopPushClient1() {
//调用关闭直播推流的接口
let res = await syhtAjaxGet('/api/live/xxx');
if(res.ret === 1) {
await this.pushClientSmall.stopCamera();
await this.pushClientSmall.stopMicrophone();
await this.pushClientSmall.stopPush();
}
},
}
上此我们写了原生的直播分享,但是并不能真正的直播中,而阿里云他是给我们集成了
直播屏幕分享
async doShare() {
this.smallVideoFlag = true // 这个主要是控制当点击分享时,将我们定义的第二个推流位置展示出来
await this.initVideoSmall() // 初始化阿里云小屏,将人物头像展示在小屏中代码在上方
await this.openLiveSmall() // 小屏开始推流人像
// 开始屏幕共享,他的实参传入true,这是会出现一个开启音频的勾选,我建议加上true,供用户自己做选择
this.pushClient.startScreenCapture(true).then(async res=>{
await this.pushClientSmall.startCamera(); // 如果屏幕共享成功,同时开始小屏的人物头像也开始打开摄像头音频
await this.pushClientSmall.startMicrophone();
}).catch(async err=>{
// 1011状态码即屏幕共享弹窗被用户拒绝,我们则将小屏隐藏,推流大屏为人物头像
if(err.errorCode === 10011) {
this.smallVideoFlag = false
await this.pushClient.stopScreenCapture();
await this.pushClient.startCamera();
await this.pushClient.startMicrophone();
}
})
// 无论怎样结果都需要推流
await this.pushClient.startPush(this.urlTui); //this.urlTui是我们一开始就定义好的推流地址
},
以上都是封装好的一整套,只需要在合适的地方调用即可,例如开启直播,则调用初始化和推流两个函数,如果用户不小心推出网页,可以要求后端给你一个直播状态的数据,在进行调取,结束则调用停止推流,以及分享则是调用分享的函数
后续小屏并非是固定在左下角,而是可以让用户放在任何位置,在我的下一篇文章总结,希望对在写基于阿里云直播的兄弟们有帮助