基于阿里云的摄像头与屏幕分享共存


基于阿里云的摄像头与屏幕分享共存

由于需求改变,由一开始的摄像头直播,转向屏幕分享直播,再到摄像头与屏幕共享同时存在的直播,由此记录

由于是共存,我的想法是创建两个阿里云的实例,最后同一个推流地址推流即可

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是我们一开始就定义好的推流地址
},

以上都是封装好的一整套,只需要在合适的地方调用即可,例如开启直播,则调用初始化和推流两个函数,如果用户不小心推出网页,可以要求后端给你一个直播状态的数据,在进行调取,结束则调用停止推流,以及分享则是调用分享的函数

后续小屏并非是固定在左下角,而是可以让用户放在任何位置,在我的下一篇文章总结,希望对在写基于阿里云直播的兄弟们有帮助


文章作者: 冷杨威
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 冷杨威 !
  目录
-->