zoukankan      html  css  js  c++  java
  • 2020.11.12 屏幕共享功能 “A发布命令让B主动做某事”的逻辑

    11.12

    增加屏幕共享功能。

    面试官点击按钮,要求考生发布自己的屏幕共享。

    发送屏幕共享,A和B方都要init融云,先初始化im,再使用RTClib,再两人都进入房间。然后B获取屏幕信息(先不指定窗口,让考生那边自己选择)然后发布到服务器,然后A订阅到B的媒体流,展示。

    初始化:初始化+进入房间

    A:发送命令,让B主动发布视频共享。然后展示屏幕共享的媒体流

    B:收到某个指令,或某个指令帮B执行发布操作,B就选择屏幕共享弹窗中的窗口发布。

    先考虑,A发送命令,让B主动做事情,这个事情怎么实现。

    B收到很多消息,通过判断extra来判断这是命令还是文本消息。如果是命令,就执行对应的操作,比如获取屏幕并发布。

    (现在要找到在哪里接收信息的……)√发送成功的信息都在message.js里面了,可以实时监听commands有没有变多。

    message.js中,它会return一个messages,这个东西是通过append增加的。append被使用两次,第一次使用是将准备发送的消息发过来,此时extra是PENDING状态,这时候就setMessages(为什么,这时候还没有发送成功啊???),然后sendMessage成功后再append一次,此时extra为空,进入条件分支语句将之前append的那个message的PENDING状态去掉。

    append(message) {
              const {type, content, extra} = message;
              if (type === SELF && extra !== PENDING) {
                  for (const message of _messages) {
                      if (message.extra === PENDING && message.content === content) {
                          message.extra = extra;
                          return setMessages([..._messages]);
                      }
                  }
              }
              _messages = [..._messages, message];
              setMessages(_messages);
          }

    那对方发送的message会怎么加到这个messages里面?

    rongyun.js里面,im.watch中,有一个message的方法,这个方法会在收到函数时触发。可以修改这里的逻辑,通过判断extra,如果是普通message,就append;如果是command,就将message发送到commands中。

    message({message}) {
               const {content: {content}, messageUId: uid, senderUserId: id, sentTime, extra:{extra}} = message;
               if(extra === "screen")
                   imModel.addCommand({content, extra})
               else
                   imModel.append({uid, type: Message.OTHER, content, id, timestamp: sentTime});
          },

     

     

    (useMessages好像是一个管理全局状态的东西,所有我觉得也可以把命令发到这里?)那在useMessages这里增加一个commands相关方法:

    const [commands, setCommands] = useState([]);
    let _commands = [];
    addCommand(message) {
        const {type, command, extra} = message;
        _commands = [..._commands, message];
        setCommands(_commands);
    }

    假设A点击“查看屏幕共享”按钮,就会生成一条message,extra设置为"screenshare",然后addCommands。

    B处(在哪)收到新的commands后,根据不同的extra做不同的事情。比如现在它收到extra = "screenshare",那就立即获取屏幕信息并发布。

    我认为B是在面试过程中收到面试官要查看屏幕的要求的,所有这个”监听“写在interviewee/room中比较好?

    (怎么监听?)发送成功的信息都在message.js里面了,可以实时监听commands有没有变多。

    干脆先这样,反正现在也只有screen这一个command,那只要command里面有东西,就获取屏幕资源并发布。并且发布成功后就清空命令。

    然后看看,怎么在这个组件中使用融云那个组件里的东西

    初始化后,给出send sendCommand sendMessage到rong里面。

    rong在useRongyunVideo里面。

    那我再rong增加一个发布屏幕资源的方法,让考生那边用。然后面试官就用sendCommand。

    const video = useRongyunVideoModel();
    const {setRong, setInfo} = video;

    发布屏幕资源的方法:

    async function screenShare(){
          const mediaStream = await navigator.mediaDevices.getDisplayMedia();
          user.stream = {
              tag: 'ScreenShare',
              type: StreamType.VIDEO,
              mediaStream
          };
          stream.publish(user).then(()=>{
              console.log("screen share success");});
      }

    但是这样使用同一个user的stream会不会覆盖?没有覆盖

    在考生那里,导入commands和useEffect,当commands变化时,调用发布的方法。

    修改了rongyun.js,在订阅资源那里,根据stream的tag来判断,是对方的摄像头资源,还是屏幕共享资源,分别放到不同的标签里去展示。

    成功了!

     

    优化一:

    参考简历上传页面。如果没有屏幕资源,就显示<Result>,如果有屏幕资源,就显示屏幕资源。

    优化二:

    命令存放为数组,每发送一个指令就询问共享哪个窗口。√

    如何更新新的窗口,现在是考生重新共享别的窗口后,也不更新视频信息

    优化三:

    监听考生离开,监听考生回来

    优化四:

    只允许考生选择整个窗口(防止作弊),若未选择整个窗口,就要求重新选择,直到选择整个窗口。(这个我做出来了,只要检测到不是选择整个窗口的行为,包括关掉、拒绝共享、未选择整个窗口等,就重复发起共享请求。不要忘记停止这个资源的获取,有个类似stop track的方法可以做这件事,不然很可能会捕获很多次屏幕资源,风扇嗡嗡响

     

       let screenStream;
       async function screenStart() {

           for (; ;) {
               try {
                   screenStream = await utils.shareScreen();
              } catch {
                   message.warning("请选择整个屏幕");
                   continue;
              }
               if (screenStream.getVideoTracks()[0].label.startsWith('screen')) {
                   break;
              }

               message.warning("请选择整个屏幕");
               screenStream.getVideoTracks()[0].stop();
          }

           const screenUser = {
               ...user,
               stream: {
                   tag: TAG_SCREEN,
                   type: StreamType.VIDEO,
                   mediaStream: screenStream
              }
          };
           stream.publish(screenUser);
           screenStream.getVideoTracks()[0].onended = () => stream.unpublish(screenUser);
      }

       async function screenStop() {
           screenStream.getVideoTracks()[0].stop();
           const screenUser = {
               ...user,
               stream: {
                   tag: TAG_SCREEN,
                   type: StreamType.VIDEO,
                   mediaStream: screenStream
              }
          }
           stream.unpublish(screenUser);
      }

     

  • 相关阅读:
    深入理解Java虚拟机之.class文件的数据结构一
    计算机操作系统之文件管理二
    计算机操作系统之文件管理一
    深入理解Java虚拟机之垃圾收集二
    深入理解Java虚拟机之垃圾收集一
    深入理解Java虚拟机之内存管理
    iscsi remote boot
    Autoconfigure enviroment via Python script
    How to set up a PXE server with REHL 7 OS
    jQuery如何获取动态添加的元素
  • 原文地址:https://www.cnblogs.com/peekapoooo/p/14122446.html
Copyright © 2011-2022 走看看