全部开发者教程

企业级在线办公系统

首页 慕课教程 企业级在线办公系统 企业级在线办公系统 9-6 推送本地视频流,订阅远端视频流

上个小节我们通过TRTC官方文档,掌握了创建TrtcClient对象和推送本地流、订阅远端流的方法,这节课咱们把学到的这些内容应用在meeting_video.vue页面吧。

一、熟悉前端页面

我们动手写JS程序之前,还是要先熟悉前端页面和视频会议的流程。例如当用户进入到meeting_video.vue页面,并不意味着连接上了在线视频会议室。而是需要我们手动点击右下角的电话图标,才会创建TrtcClient对象连接视频会议室,订阅远端流、推送本地流。当我再次点击电话图标,则会退出在线视频会议室,然后销毁本地流和远端流。

图片描述
为什么不设计成进入到meeting_video.vue页面就自动连接视频会议室,推送本地流和订阅远端流?在技术上是可以实现的,但是不太符合情理。比如说用户希望先整理一下仪容仪表然后再进入视频会议室,如果你写的程序一上来就执行本地推流了,这就不太合适吧。

视频墙中每个格子里面都有用于播放流数据的DIV控件,这些控件的id就是某个参会人的userId。一会儿我们接收到远端流或者本地流的时候,可以从流中取出userId,然后找到对应的DIV控件播放流数据。

<div class="video-list">
    <!--当前用户排在视频墙第一位-->
    <div class="video">
        <div class="user">
            <img class="photo" :src="mine.photo" />
            <span class="name">{{ mine.name }}{{ shareStatus ? '(共享中)' : '' }}</span>
        </div>
        <div id="localStream"></div>
    </div>
    <!--其他参会人-->
    <div class="video" v-for="one in memberList">
        <div class="user">
            <img class="photo" :src="one.photo" />
            <span class="name">{{ one.name }}</span>
        </div>
        <div :id="one.id" class="remote-stream" @dblclick="bigVideoHandle(one.id)"></div>
    </div>
</div>

二、连接视频会议室,订阅远程流,推送本地流

meeting_video.vue页面右下角有电话图标,这个图标设置了点击事件,我们写代码去实现phoneHandle()回调函数。当我们第一次点击的时候是进入视频会议室并签到,再点击一次是退出视频会议室。当然了,你可以反复点击,那就是返回进入和退出视频会议室。

<div class="meeting-operate">
    <button :class="meetingStatus ? 'phone-btn-off' : 'phone-btn-on'" @click="phoneHandle"/>
    <button :class="videoStatus ? 'video-btn-on' : 'video-btn-off'" @click="videoHandle"/>
    <button :class="micStatus ? 'mic-btn-on' : 'mic-btn-off'" @click="micHandle"/>
    <button :class="shareStatus ? 'share-btn-on' : 'share-btn-off'" @click="shareHandle"/>
</div>
phoneHandle: function() {
    let that = this;
    //检查浏览器是否支持在线视频会议
    TRTC.checkSystemRequirements().then(checkResult => {
        if (!checkResult.result) {
            that.$alert('当前浏览器不支持在线视频会议', '提示信息', {
                confirmButtonText: '确定'
            });
        } else {
            that.meetingStatus = !that.meetingStatus;
            if (that.meetingStatus) {
                //记录摄像头和话筒的状态
                that.videoStatus = true;
                that.micStatus = true;
                //TRTC日志输出级别为Error
                TRTC.Logger.setLogLevel(TRTC.Logger.LogLevel.ERROR);

                //生成用户签名(进入视频会才需要用户签名,不需要提前生成)
                that.$http('meeting/searchMyUserSig', 'GET', {}, false, function(resp) {
                    that.appId = resp.appId;
                    that.userSig = resp.userSig;
                    that.userId = resp.userId;
                });

                //创建TrtcClient对象
                let client = TRTC.createClient({
                    mode: 'rtc',
                    sdkAppId: that.appId,
                    userId: that.userId + '',
                    userSig: that.userSig
                });
                that.client = client;

                //监听新增远端流事件(用户进入会议室时候触发)
                client.on('stream-added', event => {
                    let remoteStream = event.stream;
                    //订阅远端流
                    client.subscribe(remoteStream);
                    //从远端流获得远程用户userId(创建TrtcClient对象时候的参数)
                    let userId = remoteStream.getUserId(); 
                    //TODO 把新上线的用户添加到页面右侧的在线人员列表中
                    
                    //把远端流保存到模型层JSON中,将来大屏显示的时候要找到某个远端流停止小窗口播放,切换到大窗口播放
                    that.stream[userId] = remoteStream;
                });

                //远端流订阅成功事件
                client.on('stream-subscribed', event => {
                    let remoteStream = event.stream;
                    let userId = remoteStream.getUserId();
                    //找到视频墙中某个远端用户的格子,把其中用于显示视频的DIV,置顶覆盖用户信息
                    $('#' + userId).css({ 'z-index': 1 }); 
                    //在这个置顶的DIV中播放远端音视频讯号
                    remoteStream.play(userId + ''); 
                });

                //订阅远端删除流事件(远端用户退出会议室)
                client.on('stream-removed', event => {
                    let remoteStream = event.stream;
                    //取消订阅该远端流
                    client.unsubscribe(remoteStream); 
                    let userId = remoteStream.getUserId();
                    //TODO 在页面右侧的用户列表中删除该用户

                    //停止播放远端流视频,并且关闭远端流
                    remoteStream.stop();
                    remoteStream.close();
                    //删除模型层JSON中保存的远端流对象
                    delete that.stream[userId];
                    //把视频墙中该用户格子的视频DIV控件置底,显示用户基本信息
                    $('#' + userId).css({ 'z-index': '-1' });
                    $('#' + userId).html('');
                });
                
                client
                    .join({ roomId: that.roomId })
                    .then(() => {
                        //TODO 执行签到

                        //成功进入会议室,然后创建本地流
                        let localStream = TRTC.createStream({
                            userId: that.userId + '',
                            audio: true,
                            video: true
                        });
                        that.localStream = localStream;
                        localStream.setVideoProfile('480p'); //设置分辨率

                        //TODO 把自己添加到上线用户列表中

                        //初始化本地音视频流
                        localStream
                            .initialize()
                            .catch(error => {
                                console.error('初始化本地流失败 ' + error);
                            })
                            .then(() => {
                                console.log('初始化本地流成功');
                                //视频墙中第一个格子中的视频DIV置顶
                                $('#localStream').css({ 'z-index': 1 });
                                //播放本地音视频流
                                localStream.play('localStream'); 
                                //向远端用户推送本地流
                                client
                                    .publish(localStream)
                                    .catch(error => {
                                        console.error('本地流发布失败 ' + error);
                                    })
                                    .then(() => {
                                        console.log('本地流发布成功');
                                    });
                            });
                    })
                    .catch(error => {
                        console.error('进入房间失败: ' + error);
                    });
            } else {
                //TODO 关闭视频会议
            }
        }
    });
},

写完这些代码,咱们可以找两个都带有摄像头和麦克风的电脑,以不同的员工帐户进入到同一个在线会议,这时候,你看看视频墙上有没有本地流和远端流。

假设我们本地电脑被称作A,另一台电脑称作B,我们在B电脑上模拟其他参会人访问A电脑上的前端项目,必然要写A电脑的IP地址和端口号。但是现在有个问题,浏览器的WebRTC只支持HTTPS访问远端网站,我们在B电脑上用HTTP协议连接A电脑的网站是无法使用TRTC的。所以我们要想个办法,给B电脑上的浏览器添加参数,允许在HTTP协议下远程使用TRTC服务。

如果你用的是MacOS系统,需要用命令行启动Chrome浏览器,并且把其中的IP和端口都改成A电脑的。

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --unsafely-treat-insecure-origin-as-secure="http://ip:port" --user-data-dir=/Users/test/code

如果你用的是Windows系统,需要在Chrome浏览器图标上点击右键,在目标的结尾添加上下面这句话,然后把IP和端口改成A主机的。

--unsafely-treat-insecure-origin-as-secure="http://ip:port" --user-data-dir="C:/temp"

还有一个非常重要的注意事项,那就是前端项目main.js文件中封装baseUrl地址,如果你写的是localhost,一定要改成Windows主机的IP地址。否则B主机的浏览器加载了前端页面之后,所有的Ajax请求都发送给B主机。B主机上面又没运行emos-api项目,所以就会报错。记住,baseUrl变量一定要写A主机的IP地址,切记!