From 5e8d325329b9bc6ec52e70329b8cb77372f005ce Mon Sep 17 00:00:00 2001
From: netpro2k <netpro2k@gmail.com>
Date: Wed, 15 Nov 2017 18:33:08 -0800
Subject: [PATCH] WIP screensharing support

---
 .babelrc               |   8 ++-
 public/room.html       |   4 ++
 src/config.js          |   3 +-
 src/index.js           | 113 ++++++++++++++++++++++++++++++++++++++++-
 src/input-mappings.js  |   1 +
 src/network-schemas.js |   5 ++
 6 files changed, 131 insertions(+), 3 deletions(-)

diff --git a/.babelrc b/.babelrc
index 4ffef06db..88f0c0ac5 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,3 +1,9 @@
 {
-  "presets": ["env", "react"]
+  "presets": [
+    "react",
+    ["env", {
+      "exclude": ["transform-regenerator"],
+      "useBuiltins": true
+    }]
+  ]
 }
diff --git a/public/room.html b/public/room.html
index a8c44617f..2edb82aeb 100644
--- a/public/room.html
+++ b/public/room.html
@@ -57,6 +57,10 @@
                 <a-box class="hand" personal-space-invader scale="0.2 0.1 0.3"></a-box>
             </script>
 
+            <script id="video-template" type="text/html">
+                <a-entity class="video" geometry="primitive: plane;" material="side: double" networked-video-player></a-entity>
+            </script>
+
             <script id="nametag-template" type="text/html">
                 <a-entity
                     class="nametag"
diff --git a/src/config.js b/src/config.js
index 194137a54..4eefb9bc7 100644
--- a/src/config.js
+++ b/src/config.js
@@ -1,5 +1,6 @@
 export default {
-  janus_server_url: "wss://dev-janus.reticulum.io",
+  // janus_server_url: "wss://dev-janus.reticulum.io",
+  janus_server_url: "wss://quander.me:8989",
   public_rooms: [1, 2, 3, 4, 5],
   default_room: 1
 };
diff --git a/src/index.js b/src/index.js
index 9cc589523..58b492b63 100644
--- a/src/index.js
+++ b/src/index.js
@@ -26,8 +26,101 @@ import Config from "./config";
 registerNetworkScheams();
 registerInputMappings();
 
+const waitForConnected = function() {
+  return new Promise(resolve => {
+    NAF.clientId
+      ? resolve()
+      : document.body.addEventListener("connected", resolve);
+  });
+};
+AFRAME.registerComponent("networked-video-player", {
+  schema: {},
+  init() {
+    waitForConnected()
+      .then(() => {
+        const networkedEl = NAF.utils.getNetworkedEntity(this.el);
+        if (!networkedEl) {
+          return Promise.reject(
+            "Vdeo player must be added on a node, or a child of a node, with the `networked` component."
+          );
+        }
+        const ownerId = networkedEl.components.networked.data.owner;
+        console.log("video player for " + ownerId);
+        return NAF.connection.adapter.getMediaStream(ownerId);
+      })
+      .then(stream => {
+        console.log("Stream", stream);
+        if (!stream) {
+          return;
+        }
+
+        const v = document.createElement("video");
+        v.srcObject = stream;
+        v.style.position = "absolute";
+        v.style.bottom = 0;
+        v.style.height = "100px";
+        v.style.background = "black";
+        document.body.appendChild(v);
+        v.play();
+
+        this.videoEl = v;
+
+        v.onloadedmetadata = () => {
+          const ratio = v.videoWidth / v.videoHeight;
+          this.el.setAttribute("geometry", {
+            width: ratio * 1,
+            height: 1
+          });
+          //this.el.setAttribute("visible", true);
+          this.el.setAttribute("material", "src", v);
+        };
+      });
+  },
+
+  remove() {
+    if (this.videoEl) {
+      this.videoEl.parent.removeChild(this.videoEl);
+    }
+  }
+});
+
+function updateVideoElementPosition(entity) {
+  const headEl = document.querySelector("#head");
+
+  const offset = new THREE.Vector3(0, 0, -2);
+  headEl.object3D.localToWorld(offset);
+  entity.setAttribute("position", offset);
+
+  const headWorldRotation = headEl.object3D.getWorldRotation();
+  entity.setAttribute("rotation", {
+    x: headWorldRotation.x * THREE.Math.RAD2DEG,
+    y: headWorldRotation.y * THREE.Math.RAD2DEG,
+    z: headWorldRotation.z * THREE.Math.RAD2DEG
+  });
+}
+
+function shareScreen() {
+  const track = NAF.connection.adapter.localMediaStream.getVideoTracks()[0];
+
+  const id = `${NAF.clientId}-screen`;
+  let entity = document.getElementById(id);
+  if (!entity) {
+    const sceneEl = document.querySelector("a-scene");
+    entity = document.createElement("a-entity");
+    entity.id = id;
+    entity.setAttribute("networked", "template: #video-template");
+    sceneEl.appendChild(entity);
+  }
+
+  track.enabled = !track.enabled;
+  entity.setAttribute("visible", track.enabled);
+  if (track.enabled) {
+    updateVideoElementPosition(entity);
+  }
+}
+
 window.App = {
-  onSceneLoad() {
+  async onSceneLoad() {
     const qs = queryString.parse(location.search);
     const scene = document.querySelector("a-scene");
 
@@ -57,7 +150,25 @@ window.App = {
 
     document.body.addEventListener("connected", App.onConnect);
 
+    scene.addEventListener("action_share_screen", shareScreen);
+
+    const mediaStream = await navigator.mediaDevices.getUserMedia({
+      audio: true,
+      video:
+        qs.screen === "true"
+          ? { mediaSource: "screen", height: 720, frameRate: 30 }
+          : false
+    });
+
+    // Don't send video by deafult
+    const videoTracks = mediaStream.getVideoTracks();
+    if (videoTracks.length) {
+      videoTracks[0].enabled = false;
+    }
+
     scene.components["networked-scene"].connect();
+    // @TODO ideally the adapter should exist before connect, but it currently doesnt so we have to do this after calling connect. This might be a race condition in other adapters.
+    NAF.connection.adapter.setLocalMediaStream(mediaStream);
   },
 
   onConnect() {
diff --git a/src/input-mappings.js b/src/input-mappings.js
index d1e8c6d4f..9035563b1 100644
--- a/src/input-mappings.js
+++ b/src/input-mappings.js
@@ -24,6 +24,7 @@ export default function registerInputMappings() {
         m_press: "action_mute",
         q_press: "action_snap_rotate_left",
         e_press: "action_snap_rotate_right",
+        v_press: "action_share_screen",
         w_down: "action_move_forward",
         w_up: "action_dont_move_forward",
         a_down: "action_move_left",
diff --git a/src/network-schemas.js b/src/network-schemas.js
index ac56e2be8..0f0070641 100644
--- a/src/network-schemas.js
+++ b/src/network-schemas.js
@@ -14,6 +14,11 @@ function registerNetworkSchemas() {
     template: "#hand-template",
     components: ["position", "rotation", "visible"]
   });
+
+  NAF.schemas.add({
+    template: "#video-template",
+    components: ["position", "rotation", "visible"]
+  });
 }
 
 export default registerNetworkSchemas;
-- 
GitLab