From ee03fa6e04dd9dba3099f75154de6ffab566ff5c Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <muhammedamoush@gmail.com>
Date: Fri, 13 Sep 2019 16:43:09 -0400
Subject: Trial 5(Most succesful yet)

---
 src/client/views/MainView.tsx | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index b64986084..62d4fb1b8 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,5 +1,5 @@
 import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-import { faLink, faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faClone, faCloudUploadAlt, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faPenNib, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faUndoAlt, faTv } from '@fortawesome/free-solid-svg-icons';
+import { faLink, faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faClone, faCloudUploadAlt, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faPenNib, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faUndoAlt, faTv, faVideo } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -195,6 +195,7 @@ export class MainView extends React.Component {
         library.add(faArrowUp);
         library.add(faCloudUploadAlt);
         library.add(faBolt);
+        library.add(faVideo);
         this.initEventListeners();
         this.initAuthenticationRouters();
     }
@@ -456,6 +457,7 @@ export class MainView extends React.Component {
         let addImportCollectionNode = action(() => Docs.Create.DirectoryImportDocument({ title: "Directory Import", width: 400, height: 400 }));
         // let youtubeurl = "https://www.youtube.com/embed/TqcApsGRzWw";
         // let addYoutubeSearcher = action(() => Docs.Create.YoutubeDocument(youtubeurl, { width: 600, height: 600, title: "youtube search" }));
+        let addWebCam = action(() => Docs.Create.WebCamDocument("", {}));
 
         let btns: [React.RefObject<HTMLDivElement>, IconName, string, () => Doc][] = [
             [React.createRef<HTMLDivElement>(), "object-group", "Add Collection", addColNode],
@@ -464,6 +466,7 @@ export class MainView extends React.Component {
             [React.createRef<HTMLDivElement>(), "bolt", "Add Button", addButtonDocument],
             [React.createRef<HTMLDivElement>(), "file", "Add Document Dragger", addDragboxNode],
             [React.createRef<HTMLDivElement>(), "cloud-upload-alt", "Import Directory", addImportCollectionNode], //remove at some point in favor of addImportCollectionNode
+            [React.createRef<HTMLDivElement>(), "video", "Add WebCam", addWebCam]
             //[React.createRef<HTMLDivElement>(), "play", "Add Youtube Searcher", addYoutubeSearcher],
         ];
         if (!ClientUtils.RELEASE) btns.unshift([React.createRef<HTMLDivElement>(), "cat", "Add Cat Image", addImageNode]);
-- 
cgit v1.2.3-70-g09d2


From a8f14c501cf676f6a2697b73d7f2a162d4100a9e Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <mohammad_amoush@brown.edu>
Date: Wed, 2 Oct 2019 16:52:57 -0400
Subject: Merge conflicts fixed

---
 src/client/documents/Documents.ts               |  16 +-
 src/client/views/MainView.tsx                   |   4 -
 src/client/views/nodes/DocumentContentsView.tsx |  16 +-
 src/client/views/webcam/DashWebRTC.tsx          | 225 ++++++++++++++++++++++--
 4 files changed, 214 insertions(+), 47 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 3482033d5..6bd91c3b9 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -20,12 +20,8 @@ import { AggregateFunction } from "../northstar/model/idea/idea";
 import { MINIMIZED_ICON_SIZE } from "../views/globalCssVariables.scss";
 import { IconBox } from "../views/nodes/IconBox";
 import { OmitKeys, JSONUtils } from "../../Utils";
-<<<<<<< HEAD
-import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField, WebCamField } from "../../new_fields/URLField";
-=======
 import { Field, Doc, Opt, DocListCastAsync } from "../../new_fields/Doc";
-import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField } from "../../new_fields/URLField";
->>>>>>> 69e4a936c4eb0cc2e35e4e7f3258aed1f72b8da7
+import { ImageField, VideoField, AudioField, PdfField, WebField, YoutubeField, WebCamField } from "../../new_fields/URLField";
 import { HtmlField } from "../../new_fields/HtmlField";
 import { List } from "../../new_fields/List";
 import { Cast, NumCast } from "../../new_fields/Types";
@@ -49,14 +45,9 @@ import { ComputedField } from "../../new_fields/ScriptField";
 import { ProxyField } from "../../new_fields/Proxy";
 import { DocumentType } from "./DocumentTypes";
 import { LinkFollowBox } from "../views/linking/LinkFollowBox";
-<<<<<<< HEAD
 import { DashWebCam } from "../views/webcam/DashWebCam";
 import { DashWebRTC } from "../views/webcam/DashWebRTC";
-//import { PresBox } from "../views/nodes/PresBox";
-//import { PresField } from "../../new_fields/PresField";
-=======
 import { PresElementBox } from "../views/presentationview/PresElementBox";
->>>>>>> 69e4a936c4eb0cc2e35e4e7f3258aed1f72b8da7
 var requestImageSize = require('../util/request-image-size');
 var path = require('path');
 
@@ -186,15 +177,12 @@ export namespace Docs {
             [DocumentType.LINKFOLLOW, {
                 layout: { view: LinkFollowBox }
             }],
-<<<<<<< HEAD
             [DocumentType.WEBCAM, {
                 layout: { view: DashWebRTC }
-            }]
-=======
+            }],
             [DocumentType.PRESELEMENT, {
                 layout: { view: PresElementBox }
             }],
->>>>>>> 69e4a936c4eb0cc2e35e4e7f3258aed1f72b8da7
         ]);
 
         // All document prototypes are initialized with at least these values
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 22d8171c0..7e2b4fa3a 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,9 +1,5 @@
 import { IconName, library } from '@fortawesome/fontawesome-svg-core';
-<<<<<<< HEAD
 import { faLink, faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faClone, faCloudUploadAlt, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faPenNib, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faUndoAlt, faTv, faVideo } from '@fortawesome/free-solid-svg-icons';
-=======
-import { faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faClone, faCloudUploadAlt, faCommentAlt, faCut, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight, faMusic, faObjectGroup, faPause, faPenNib, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt } from '@fortawesome/free-solid-svg-icons';
->>>>>>> 69e4a936c4eb0cc2e35e4e7f3258aed1f72b8da7
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
diff --git a/src/client/views/nodes/DocumentContentsView.tsx b/src/client/views/nodes/DocumentContentsView.tsx
index f1c10f2f2..f1678d4f9 100644
--- a/src/client/views/nodes/DocumentContentsView.tsx
+++ b/src/client/views/nodes/DocumentContentsView.tsx
@@ -30,20 +30,12 @@ import { PresElementBox } from "../presentationview/PresElementBox";
 import { VideoBox } from "./VideoBox";
 import { WebBox } from "./WebBox";
 import React = require("react");
-<<<<<<< HEAD
-import { FieldViewProps } from "./FieldView";
-import { Without, OmitKeys } from "../../../Utils";
-import { Cast, StrCast, NumCast } from "../../../new_fields/Types";
+import { StrCast, NumCast } from "../../../new_fields/Types";
 import { List } from "../../../new_fields/List";
-import { Doc } from "../../../new_fields/Doc";
-import DirectoryImportBox from "../../util/Import & Export/DirectoryImportBox";
-import { ScriptField } from "../../../new_fields/ScriptField";
 import { fromPromise } from "mobx-utils";
 import { DashWebCam } from "../../views/webcam/DashWebCam";
 import { DashWebRTC } from "../webcam/DashWebRTC";
 
-=======
->>>>>>> 69e4a936c4eb0cc2e35e4e7f3258aed1f72b8da7
 const JsxParser = require('react-jsx-parser').default; //TODO Why does this need to be imported like this?
 
 type BindingProps = Without<FieldViewProps, 'fieldKey'>;
@@ -115,11 +107,7 @@ export class DocumentContentsView extends React.Component<DocumentViewProps & {
         if (!this.layout && this.props.layoutKey !== "overlayLayout") return (null);
         return <ObserverJsxParser
             blacklistedAttrs={[]}
-<<<<<<< HEAD
-            components={{ FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, DragBox, ButtonBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, DashWebCam, DashWebRTC }}
-=======
-            components={{ FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, DragBox, ButtonBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox }}
->>>>>>> 69e4a936c4eb0cc2e35e4e7f3258aed1f72b8da7
+            components={{ FormattedTextBox, ImageBox, IconBox, DirectoryImportBox, DragBox, ButtonBox, FieldView, CollectionFreeFormView, CollectionDockingView, CollectionSchemaView, CollectionView, CollectionPDFView, CollectionVideoView, WebBox, KeyValueBox, PDFBox, VideoBox, AudioBox, HistogramBox, PresBox, YoutubeBox, LinkFollowBox, PresElementBox, DashWebCam, DashWebRTC }}
             bindings={this.CreateBindings()}
             jsx={this.finalLayout}
             showWarnings={true}
diff --git a/src/client/views/webcam/DashWebRTC.tsx b/src/client/views/webcam/DashWebRTC.tsx
index 9c289b40f..64ddb318f 100644
--- a/src/client/views/webcam/DashWebRTC.tsx
+++ b/src/client/views/webcam/DashWebRTC.tsx
@@ -2,7 +2,7 @@ import { observer } from "mobx-react";
 import React = require("react");
 import { CollectionFreeFormDocumentViewProps } from "../nodes/CollectionFreeFormDocumentView";
 import { FieldViewProps, FieldView } from "../nodes/FieldView";
-import { observable, trace } from "mobx";
+import { observable } from "mobx";
 import { DocumentDecorations } from "../DocumentDecorations";
 import { InkingControl } from "../InkingControl";
 import "../../views/nodes/WebBox.scss";
@@ -11,7 +11,7 @@ import adapter from 'webrtc-adapter';
 
 
 
-const mediaStreamConstaints = {
+const mediaStreamConstraints = {
     video: true,
 };
 
@@ -26,7 +26,7 @@ export class DashWebRTC extends React.Component<CollectionFreeFormDocumentViewPr
     @observable private localVideoEl: HTMLVideoElement | undefined;
     @observable private peerVideoEl: HTMLVideoElement | undefined;
     @observable private localStream: MediaStream | undefined;
-    @observable private startTime = null;
+    @observable private startTime: any = null;
     @observable private remoteStream: MediaStream | undefined;
     @observable private localPeerConnection: any;
     @observable private remotePeerConnection: any;
@@ -38,7 +38,7 @@ export class DashWebRTC extends React.Component<CollectionFreeFormDocumentViewPr
     componentDidMount() {
         this.callButton!.disabled = true;
         this.hangupButton!.disabled = true;
-        navigator.mediaDevices.getUserMedia(mediaStreamConstaints).then(this.gotLocalMediaStream).catch(this.handleLocalMediaStreamError);
+        navigator.mediaDevices.getUserMedia(mediaStreamConstraints).then(this.gotLocalMediaStream).catch(this.handleLocalMediaStreamError);
         this.localVideoEl!.addEventListener('loadedmetadata', this.logVideoLoaded);
         this.peerVideoEl!.addEventListener('loadedmetadata', this.logVideoLoaded);
         this.peerVideoEl!.addEventListener('onresize', this.logResizedVideo);
@@ -50,7 +50,7 @@ export class DashWebRTC extends React.Component<CollectionFreeFormDocumentViewPr
         if (this.localVideoEl) {
             this.localVideoEl.srcObject = mediaStream;
         }
-        trace('Received local stream.');
+        this.trace('Received local stream.');
         this.callButton!.disabled = false;
 
     }
@@ -64,27 +64,222 @@ export class DashWebRTC extends React.Component<CollectionFreeFormDocumentViewPr
 
     handleLocalMediaStreamError = (error: string) => {
         //console.log("navigator.getUserMedia error: ", error);
-        trace(`navigator.getUserMedia error: ${error.toString()}.`);
+        this.trace(`navigator.getUserMedia error: ${error.toString()}.`);
 
     }
 
-    logVideoLoaded(event: any) {
+    logVideoLoaded = (event: any) => {
         let video = event.target;
-        trace(`${video!.id} videoWidth: ${video!.videoWidth}px, ` +
-            `videoHeight: ${video!.videoHeight}px.`);
+        this.trace(`${video.id} videoWidth: ${video.videoWidth}px, ` +
+            `videoHeight: ${video.videoHeight}px.`);
     }
 
-    logResizedVideo(event: any) {
+    logResizedVideo = (event: any) => {
         this.logVideoLoaded(event);
 
         if (this.startTime) {
-            let elapsedTime = window.performance.now() - this.startTime!;
+            let elapsedTime = window.performance.now() - this.startTime;
             this.startTime = null;
-            trace(`Setup time: ${elapsedTime.toFixed(3)}ms.`);
+            this.trace(`Setup time: ${elapsedTime.toFixed(3)}ms.`);
         }
 
     }
 
+    handleConnection = (event: any) => {
+        let peerConnection = event.target;
+        let iceCandidate = event.candidate;
+
+        if (iceCandidate) {
+            let newIceCandidate: RTCIceCandidate = new RTCIceCandidate(iceCandidate);
+            let otherPeer: any = this.getOtherPeer(peerConnection);
+
+            otherPeer.addIceCandidate(newIceCandidate).then(() => {
+                this.handleConnectionSuccess(peerConnection);
+            }).catch((error: any) => {
+                this.handleConnectionFailure(peerConnection, error);
+            });
+
+            this.trace(`${this.getPeerName(peerConnection)} ICE candidate:\n` +
+                `${event.candidate.candidate}.`);
+
+        }
+    }
+
+    // Logs that the connection succeeded.
+    handleConnectionSuccess = (peerConnection: any) => {
+        this.trace(`${this.getPeerName(peerConnection)} addIceCandidate success.`);
+    }
+
+    handleConnectionFailure = (peerConnection: any, error: any) => {
+        this.trace(`${this.getPeerName(peerConnection)} failed to add ICE Candidate:\n` +
+            `${error.toString()}.`);
+    }
+
+    // Logs changes to the connection state.
+    handleConnectionChange = (event: any) => {
+        let peerConnection = event.target;
+        console.log('ICE state change event: ', event);
+        this.trace(`${this.getPeerName(peerConnection)} ICE state: ` +
+            `${peerConnection.iceConnectionState}.`);
+    }
+
+    // Logs error when setting session description fails.
+    setSessionDescriptionError = (error: any) => {
+        this.trace(`Failed to create session description: ${error.toString()}.`);
+    }
+
+    // Logs success when setting session description.
+    setDescriptionSuccess = (peerConnection: any, functionName: any) => {
+        let peerName = this.getPeerName(peerConnection);
+        this.trace(`${peerName} ${functionName} complete.`);
+    }
+
+
+    // Logs success when localDescription is set.
+    setLocalDescriptionSuccess = (peerConnection: any) => {
+        this.setDescriptionSuccess(peerConnection, 'setLocalDescription');
+    }
+
+    // Logs success when remoteDescription is set.
+    setRemoteDescriptionSuccess = (peerConnection: any) => {
+        this.setDescriptionSuccess(peerConnection, 'setRemoteDescription');
+    }
+
+    createdOffer = (description: any) => {
+        this.trace(`Offer from localPeerConnection:\n${description.sdp}`);
+        this.trace('localPeerConnection setLocalDescription start.');
+
+        this.localPeerConnection.setLocalDescription(description).then(() => {
+            this.setLocalDescriptionSuccess(this.localPeerConnection);
+        }).catch(this.setSessionDescriptionError);
+
+
+        this.trace('remotePeerConnection setRemoteDescription start.');
+        this.remotePeerConnection.setRemoteDescription(description)
+            .then(() => {
+                this.setRemoteDescriptionSuccess(this.remotePeerConnection);
+            }).catch(this.setSessionDescriptionError);
+
+        this.trace('remotePeerConnection createAnswer start.');
+        this.remotePeerConnection.createAnswer()
+            .then(this.createdAnswer)
+            .catch(this.setSessionDescriptionError);
+
+    }
+
+    createdAnswer = (description: any) => {
+        this.trace(`Answer from remotePeerConnection:\n${description.sdp}.`);
+
+        this.trace('remotePeerConnection setLocalDescription start.');
+        this.remotePeerConnection.setLocalDescription(description)
+            .then(() => {
+                this.setLocalDescriptionSuccess(this.remotePeerConnection);
+            }).catch(this.setSessionDescriptionError);
+
+        this.trace('localPeerConnection setRemoteDescription start.');
+        this.localPeerConnection.setRemoteDescription(description)
+            .then(() => {
+                this.setRemoteDescriptionSuccess(this.localPeerConnection);
+            }).catch(this.setSessionDescriptionError);
+    }
+
+
+    startAction = () => {
+        this.startButton!.disabled = true;
+        navigator.mediaDevices.getUserMedia(mediaStreamConstraints)
+            .then(this.gotLocalMediaStream).catch(this.handleLocalMediaStreamError);
+        this.trace('Requesting local stream.');
+    }
+
+
+    // Handles call button action: creates peer connection.
+    callAction = () => {
+        this.callButton!.disabled = true;
+        this.hangupButton!.disabled = false;
+
+        this.trace('Starting call.');
+        this.startTime = window.performance.now();
+
+        // Get local media stream tracks.
+        const videoTracks = this.localStream!.getVideoTracks();
+        const audioTracks = this.localStream!.getAudioTracks();
+        if (videoTracks.length > 0) {
+            this.trace(`Using video device: ${videoTracks[0].label}.`);
+        }
+        if (audioTracks.length > 0) {
+            this.trace(`Using audio device: ${audioTracks[0].label}.`);
+        }
+
+        let servers: RTCConfiguration | undefined = undefined;  // Allows for RTC server configuration.
+
+        // Create peer connections and add behavior.
+        this.localPeerConnection = new RTCPeerConnection(servers);
+        this.trace('Created local peer connection object localPeerConnection.');
+
+        this.localPeerConnection.addEventListener('icecandidate', this.handleConnection);
+        this.localPeerConnection.addEventListener(
+            'iceconnectionstatechange', this.handleConnectionChange);
+
+        this.remotePeerConnection = new RTCPeerConnection(servers);
+        this.trace('Created remote peer connection object remotePeerConnection.');
+
+        this.remotePeerConnection.addEventListener('icecandidate', this.handleConnection);
+        this.remotePeerConnection.addEventListener(
+            'iceconnectionstatechange', this.handleConnectionChange);
+        this.remotePeerConnection.addEventListener('addstream', this.gotRemoteMediaStream);
+
+        // Add local stream to connection and create offer to connect.
+        this.localPeerConnection.addStream(this.localStream);
+        this.trace('Added local stream to localPeerConnection.');
+
+        this.trace('localPeerConnection createOffer start.');
+        this.localPeerConnection.createOffer(offerOptions)
+            .then(this.createdOffer).catch(this.setSessionDescriptionError);
+    }
+
+
+    // Handles hangup action: ends up call, closes connections and resets peers.
+    hangupAction = () => {
+        this.localPeerConnection.close();
+        this.remotePeerConnection.close();
+        this.localPeerConnection = null;
+        this.remotePeerConnection = null;
+        this.hangupButton!.disabled = true;
+        this.callButton!.disabled = false;
+        this.trace('Ending call.');
+    }
+
+    // Gets the "other" peer connection.
+    getOtherPeer = (peerConnection: any) => {
+        return (peerConnection === this.localPeerConnection) ?
+            this.remotePeerConnection : this.localPeerConnection;
+    }
+
+    // Gets the name of a certain peer connection.
+    getPeerName = (peerConnection: any) => {
+        return (peerConnection === this.localPeerConnection) ?
+            'localPeerConnection' : 'remotePeerConnection';
+    }
+
+    // Logs an action (text) and the time when it happened on the console.
+    trace = (text: string) => {
+        text = text.trim();
+        const now = (window.performance.now() / 1000).toFixed(3);
+
+        console.log(now, text);
+    }
+
+
+
+
+
+
+
+
+
+
+
+
 
 
 
@@ -116,9 +311,9 @@ export class DashWebRTC extends React.Component<CollectionFreeFormDocumentViewPr
             <div className="webcam-cont" style={{ width: "100%", height: "100%" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
                 <video id="localVideo" autoPlay playsInline ref={(e) => this.localVideoEl = e!}></video>
                 <video id="remoteVideo" autoPlay playsInline ref={(e) => this.peerVideoEl = e!}></video>
-                <button id="startButton" ref={(e) => this.startButton = e!}>Start</button>
-                <button id="callButton" ref={(e) => this.callButton = e!}>Call</button>
-                <button id="hangupButton" ref={(e) => this.hangupButton = e!}>Hang Up</button>
+                <button id="startButton" ref={(e) => this.startButton = e!} onClick={this.startAction}>Start</button>
+                <button id="callButton" ref={(e) => this.callButton = e!} onClick={this.callAction}>Call</button>
+                <button id="hangupButton" ref={(e) => this.hangupButton = e!} onClick={this.hangupAction}>Hang Up</button>
             </div>;
 
         let frozen = !this.props.isSelected() || DocumentDecorations.Instance.Interacting;
-- 
cgit v1.2.3-70-g09d2


From 82583a641ddc40401e0425242221468d45632e5b Mon Sep 17 00:00:00 2001
From: Mohammad Amoush <47069173+mamoush34@users.noreply.github.com>
Date: Sun, 19 Jan 2020 15:24:38 +0300
Subject: quick fix

---
 package-lock.json             | 68 ++++++++++++++++++++++++++++---------------
 package.json                  |  2 +-
 src/client/views/MainView.tsx |  2 +-
 3 files changed, 47 insertions(+), 25 deletions(-)

(limited to 'src/client/views/MainView.tsx')

diff --git a/package-lock.json b/package-lock.json
index 474084fe7..8cd11261e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1987,7 +1987,7 @@
                 },
                 "util": {
                     "version": "0.10.3",
-                    "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+                    "resolved": "http://registry.npmjs.org/util/-/util-0.10.3.tgz",
                     "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
                     "dev": true,
                     "requires": {
@@ -2575,7 +2575,7 @@
         },
         "browserify-aes": {
             "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
+            "resolved": "http://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
             "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
             "requires": {
                 "buffer-xor": "^1.0.3",
@@ -2609,7 +2609,7 @@
         },
         "browserify-rsa": {
             "version": "4.0.1",
-            "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+            "resolved": "http://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
             "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
             "requires": {
                 "bn.js": "^4.1.0",
@@ -2773,7 +2773,7 @@
         },
         "camelcase-keys": {
             "version": "2.1.0",
-            "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
+            "resolved": "http://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
             "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
             "requires": {
                 "camelcase": "^2.0.0",
@@ -3554,7 +3554,7 @@
         },
         "create-hash": {
             "version": "1.2.0",
-            "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+            "resolved": "http://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
             "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
             "requires": {
                 "cipher-base": "^1.0.1",
@@ -3566,7 +3566,7 @@
         },
         "create-hmac": {
             "version": "1.1.7",
-            "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
+            "resolved": "http://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
             "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
             "requires": {
                 "cipher-base": "^1.0.3",
@@ -4094,7 +4094,7 @@
         },
         "diffie-hellman": {
             "version": "5.0.3",
-            "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
+            "resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
             "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
             "requires": {
                 "bn.js": "^4.1.0",
@@ -6925,7 +6925,7 @@
         },
         "is-accessor-descriptor": {
             "version": "0.1.6",
-            "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
+            "resolved": "http://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
             "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
             "requires": {
                 "kind-of": "^3.0.2"
@@ -6980,7 +6980,7 @@
         },
         "is-data-descriptor": {
             "version": "0.1.4",
-            "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
+            "resolved": "http://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
             "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
             "requires": {
                 "kind-of": "^3.0.2"
@@ -7647,7 +7647,7 @@
         },
         "load-json-file": {
             "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+            "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
             "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
             "requires": {
                 "graceful-fs": "^4.1.2",
@@ -7965,7 +7965,7 @@
         },
         "media-typer": {
             "version": "0.3.0",
-            "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+            "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
             "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
         },
         "mem": {
@@ -7997,7 +7997,7 @@
         },
         "meow": {
             "version": "3.7.0",
-            "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+            "resolved": "http://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
             "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
             "requires": {
                 "camelcase-keys": "^2.0.0",
@@ -8172,7 +8172,7 @@
         },
         "mkdirp": {
             "version": "0.5.1",
-            "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+            "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
             "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
             "requires": {
                 "minimist": "0.0.8"
@@ -8483,7 +8483,7 @@
         },
         "next-tick": {
             "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
+            "resolved": "http://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
             "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw="
         },
         "nice-try": {
@@ -8566,7 +8566,7 @@
                 },
                 "semver": {
                     "version": "5.3.0",
-                    "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
+                    "resolved": "http://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
                     "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
                 },
                 "tar": {
@@ -12125,7 +12125,7 @@
         },
         "os-homedir": {
             "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+            "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
             "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
         },
         "os-locale": {
@@ -12138,7 +12138,7 @@
         },
         "os-tmpdir": {
             "version": "1.0.2",
-            "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+            "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
             "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
         },
         "osenv": {
@@ -12378,7 +12378,7 @@
         },
         "path-is-absolute": {
             "version": "1.0.1",
-            "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+            "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
             "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
         },
         "path-is-inside": {
@@ -14500,6 +14500,14 @@
             "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.2.tgz",
             "integrity": "sha512-ku6MFrwEVSVmXLvy3dYph3LAMNS0890K7fabn+0YIRQ2T96T9F4gkFf0vf0WW0JUraNWwGRtInEpH7yO4tbQZg=="
         },
+        "rtcpeerconnection-shim": {
+            "version": "1.2.15",
+            "resolved": "https://registry.npmjs.org/rtcpeerconnection-shim/-/rtcpeerconnection-shim-1.2.15.tgz",
+            "integrity": "sha512-C6DxhXt7bssQ1nHb154lqeL0SXz5Dx4RczXZu2Aa/L1NJFnEVDxFwCBo3fqtuljhHIGceg5JKBV4XJ0gW5JKyw==",
+            "requires": {
+                "sdp": "^2.6.0"
+            }
+        },
         "run-queue": {
             "version": "1.0.3",
             "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz",
@@ -14516,7 +14524,7 @@
         },
         "safe-regex": {
             "version": "1.1.0",
-            "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
+            "resolved": "http://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
             "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
             "requires": {
                 "ret": "~0.1.10"
@@ -14631,6 +14639,11 @@
                 }
             }
         },
+        "sdp": {
+            "version": "2.12.0",
+            "resolved": "https://registry.npmjs.org/sdp/-/sdp-2.12.0.tgz",
+            "integrity": "sha512-jhXqQAQVM+8Xj5EjJGVweuEzgtGWb3tmEEpl3CLP3cStInSbVHSg0QWOGQzNq8pSID4JkpeV2mPqlMDLrm0/Vw=="
+        },
         "section-iterator": {
             "version": "2.0.0",
             "resolved": "https://registry.npmjs.org/section-iterator/-/section-iterator-2.0.0.tgz",
@@ -14786,7 +14799,7 @@
         },
         "sha.js": {
             "version": "2.4.11",
-            "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+            "resolved": "http://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
             "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
             "requires": {
                 "inherits": "^2.0.1",
@@ -15643,7 +15656,7 @@
         },
         "string_decoder": {
             "version": "1.1.1",
-            "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+            "resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
             "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
             "requires": {
                 "safe-buffer": "~5.1.0"
@@ -15689,7 +15702,7 @@
         },
         "strip-eof": {
             "version": "1.0.0",
-            "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+            "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
             "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
         },
         "strip-indent": {
@@ -16451,7 +16464,7 @@
         },
         "tty-browserify": {
             "version": "0.0.0",
-            "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
+            "resolved": "http://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
             "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
             "dev": true
         },
@@ -17677,6 +17690,15 @@
                 }
             }
         },
+        "webrtc-adapter": {
+            "version": "7.4.0",
+            "resolved": "https://registry.npmjs.org/webrtc-adapter/-/webrtc-adapter-7.4.0.tgz",
+            "integrity": "sha512-YeflMTsqnQ6/7satrJzjzN9RjpkDDsEdoRuEkIhk+oOmWgDL1ocdWhZ1lPdB21ZXXY/AmEih4cHgKoW3SYw20A==",
+            "requires": {
+                "rtcpeerconnection-shim": "^1.2.15",
+                "sdp": "^2.12.0"
+            }
+        },
         "websocket-driver": {
             "version": "0.7.3",
             "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
diff --git a/package.json b/package.json
index 5f8b58386..5f6c87f26 100644
--- a/package.json
+++ b/package.json
@@ -236,4 +236,4 @@
         "xoauth2": "^1.2.0",
         "youtube": "^0.1.0"
     }
-}
\ No newline at end of file
+}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index b2d88a8c8..34da7f823 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -1,7 +1,7 @@
 import { library } from '@fortawesome/fontawesome-svg-core';
 import {
     faArrowDown, faArrowUp, faBolt, faCaretUp, faCat, faCheck, faChevronRight, faClone, faCloudUploadAlt, faCommentAlt, faCut, faEllipsisV, faExclamation, faFilePdf, faFilm, faFont, faGlobeAsia, faLongArrowAltRight,
-    faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter, faMicrophone, faCompressArrowsAlt
+    faMusic, faObjectGroup, faPause, faMousePointer, faPenNib, faFileAudio, faPen, faEraser, faPlay, faPortrait, faRedoAlt, faThumbtack, faTree, faTv, faUndoAlt, faHighlighter, faMicrophone, faCompressArrowsAlt, faVideo
 } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
-- 
cgit v1.2.3-70-g09d2

