aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/DocServer.ts2
-rw-r--r--src/client/documents/Documents.ts4
-rw-r--r--src/client/views/webcam/DashWebRTC.ts306
-rw-r--r--src/client/views/webcam/DashWebRTC.tsx334
-rw-r--r--src/client/views/webcam/DashWebRTCVideo.tsx339
5 files changed, 648 insertions, 337 deletions
diff --git a/src/client/DocServer.ts b/src/client/DocServer.ts
index 2cec1046b..7ffb43684 100644
--- a/src/client/DocServer.ts
+++ b/src/client/DocServer.ts
@@ -21,7 +21,7 @@ import { Id, HandleUpdate } from '../new_fields/FieldSymbols';
*/
export namespace DocServer {
let _cache: { [id: string]: RefField | Promise<Opt<RefField>> } = {};
- let _socket: SocketIOClient.Socket;
+ export let _socket: SocketIOClient.Socket;
// this client's distinct GUID created at initialization
let GUID: string;
// indicates whether or not a document is currently being udpated, and, if so, its id
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8b3c03866..3df1e0e9a 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -46,8 +46,8 @@ import { ProxyField } from "../../new_fields/Proxy";
import { DocumentType } from "./DocumentTypes";
import { LinkFollowBox } from "../views/linking/LinkFollowBox";
import { DashWebCam } from "../views/webcam/DashWebCam";
-import { DashWebRTC } from "../views/webcam/DashWebRTC";
import { PresElementBox } from "../views/presentationview/PresElementBox";
+import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
var requestImageSize = require('../util/request-image-size');
var path = require('path');
@@ -178,7 +178,7 @@ export namespace Docs {
layout: { view: LinkFollowBox }
}],
[DocumentType.WEBCAM, {
- layout: { view: DashWebRTC }
+ layout: { view: DashWebRTCVideo }
}],
[DocumentType.PRESELEMENT, {
layout: { view: PresElementBox }
diff --git a/src/client/views/webcam/DashWebRTC.ts b/src/client/views/webcam/DashWebRTC.ts
new file mode 100644
index 000000000..4472f5ba5
--- /dev/null
+++ b/src/client/views/webcam/DashWebRTC.ts
@@ -0,0 +1,306 @@
+import { DocServer } from '../../DocServer';
+
+
+
+export namespace DashWebRTC {
+
+
+ let isChannelReady = false;
+ let isInitiator = false;
+ let isStarted = false;
+ let localStream: MediaStream | undefined;
+ let pc: any;
+ let remoteStream: MediaStream | undefined;
+ let turnReady;
+
+ let pcConfig = {
+ 'iceServers': [{
+ 'urls': 'stun:stun.l.google.com:19302'
+ }]
+ };
+
+ // Set up audio and video regardless of what devices are present.
+ let sdpConstraints = {
+ offerToReceiveAudio: true,
+ offerToReceiveVideo: true
+ };
+
+
+ let room = 'test';
+
+ //let socket = io.connect();
+
+ if (room !== '') {
+ DocServer._socket.emit('create or join', room);
+ console.log('Attempted to create or join room', room);
+
+ }
+
+ DocServer._socket.on('created', function (room: string) {
+ console.log('Created room ' + room);
+ isInitiator = true;
+ });
+
+ DocServer._socket.on('full', function (room: string) {
+ console.log('Room ' + room + ' is full');
+ });
+
+ DocServer._socket.on('join', function (room: string) {
+ console.log('Another peer made a request to join room ' + room);
+ console.log('This peer is the initiator of room ' + room + '!');
+ isChannelReady = true;
+ });
+
+
+ DocServer._socket.on('joined', function (room: string) {
+ console.log('joined: ' + room);
+ isChannelReady = true;
+ });
+
+
+ DocServer._socket.on('log', function (array: any) {
+ console.log.apply(console, array);
+ });
+
+
+ function sendMessage(message: any) {
+ console.log('Client sending message: ', message);
+ DocServer._socket.emit('message', message);
+ }
+
+
+ // This client receives a message
+ DocServer._socket.on('message', function (message: any) {
+ console.log('Client received message:', message);
+ if (message === 'got user media') {
+ maybeStart();
+ } else if (message.type === 'offer') {
+ if (!isInitiator && !isStarted) {
+ maybeStart();
+ }
+ pc.setRemoteDescription(new RTCSessionDescription(message));
+ doAnswer();
+ } else if (message.type === 'answer' && isStarted) {
+ pc.setRemoteDescription(new RTCSessionDescription(message));
+ } else if (message.type === 'candidate' && isStarted) {
+ var candidate = new RTCIceCandidate({
+ sdpMLineIndex: message.label,
+ candidate: message.candidate
+ });
+ pc.addIceCandidate(candidate);
+ } else if (message === 'bye' && isStarted) {
+ handleRemoteHangup();
+ }
+ });
+
+ let localVideo: HTMLVideoElement;
+ let remoteVideo: HTMLVideoElement;
+
+ export function setVideoObjects(localVideo: HTMLVideoElement, remoteVideo: HTMLVideoElement) {
+ localVideo = localVideo;
+ remoteVideo = remoteVideo;
+ }
+
+ navigator.mediaDevices.getUserMedia({
+ audio: false,
+ video: true
+ })
+ .then(gotStream)
+ .catch(function (e) {
+ alert('getUserMedia() error: ' + e.name);
+ });
+
+
+ function gotStream(stream: any) {
+ console.log('Adding local stream.');
+ localStream = stream;
+ localVideo.srcObject = stream;
+ sendMessage('got user media');
+ if (isInitiator) {
+ maybeStart();
+ }
+ }
+
+ let constraints = {
+ video: true,
+ audio: true
+ };
+
+
+ //Trying this one out!!!
+ console.log('Getting user media with constraints', constraints);
+
+ if (location.hostname !== 'localhost') {
+ requestTurn(
+ 'https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913'
+ );
+ }
+
+
+ function maybeStart() {
+ console.log('>>>>>>> maybeStart() ', isStarted, localStream, isChannelReady);
+ if (!isStarted && typeof localStream !== 'undefined' && isChannelReady) {
+ console.log('>>>>>> creating peer connection');
+ createPeerConnection();
+ pc.addStream(localStream);
+ isStarted = true;
+ console.log('isInitiator', isInitiator);
+ if (isInitiator) {
+ doCall();
+ }
+ }
+ }
+
+
+ //this will need to be changed to our version of hangUp
+ window.onbeforeunload = function () {
+ sendMessage('bye');
+ };
+
+ function createPeerConnection() {
+ try {
+ pc = new RTCPeerConnection(undefined);
+ pc.onicecandidate = handleIceCandidate;
+ pc.onaddstream = handleRemoteStreamAdded;
+ pc.onremovestream = handleRemoteStreamRemoved;
+ console.log('Created RTCPeerConnnection');
+ } catch (e) {
+ console.log('Failed to create PeerConnection, exception: ' + e.message);
+ alert('Cannot create RTCPeerConnection object.');
+ return;
+ }
+ }
+
+ function handleIceCandidate(event: any) {
+ console.log('icecandidate event: ', event);
+ if (event.candidate) {
+ sendMessage({
+ type: 'candidate',
+ label: event.candidate.sdpMLineIndex,
+ id: event.candidate.sdpMid,
+ candidate: event.candidate.candidate
+ });
+ } else {
+ console.log('End of candidates.');
+ }
+ }
+
+ function handleCreateOfferError(event: any) {
+ console.log('createOffer() error: ', event);
+ }
+
+ function doCall() {
+ console.log('Sending offer to peer');
+ pc.createOffer(setLocalAndSendMessage, handleCreateOfferError);
+ }
+
+ function doAnswer() {
+ console.log('Sending answer to peer.');
+ pc.createAnswer().then(
+ setLocalAndSendMessage,
+ onCreateSessionDescriptionError
+ );
+ }
+
+ function setLocalAndSendMessage(sessionDescription: any) {
+ pc.setLocalDescription(sessionDescription);
+ console.log('setLocalAndSendMessage sending message', sessionDescription);
+ sendMessage(sessionDescription);
+ }
+
+ function onCreateSessionDescriptionError(error: any) {
+ console.log('Failed to create session description: ' + error.toString());
+ }
+
+
+ function requestTurn(turnURL: any) {
+ var turnExists = false;
+ for (var i in pcConfig.iceServers) {
+ if (pcConfig.iceServers[i].urls.substr(0, 5) === 'turn:') {
+ turnExists = true;
+ turnReady = true;
+ break;
+ }
+ }
+ if (!turnExists) {
+ console.log('Getting TURN server from ', turnURL);
+ // No TURN server. Get one from computeengineondemand.appspot.com:
+ var xhr = new XMLHttpRequest();
+ xhr.onreadystatechange = function () {
+ if (xhr.readyState === 4 && xhr.status === 200) {
+ var turnServer = JSON.parse(xhr.responseText);
+ console.log('Got TURN server: ', turnServer);
+ pcConfig.iceServers.push({
+ 'urls': 'turn:' + turnServer.username + '@' + turnServer.turn,
+ //'credential': turnServer.password
+ });
+ turnReady = true;
+ }
+ };
+ xhr.open('GET', turnURL, true);
+ xhr.send();
+ }
+ }
+
+ function handleRemoteStreamAdded(event: MediaStreamEvent) {
+ console.log('Remote stream added.');
+ remoteStream = event.stream!;
+ remoteVideo.srcObject = remoteStream;
+ }
+
+ function handleRemoteStreamRemoved(event: MediaStreamEvent) {
+ console.log('Remote stream removed. Event: ', event);
+ }
+
+ function hangup() {
+ console.log('Hanging up.');
+ stop();
+ sendMessage('bye');
+ }
+
+ function handleRemoteHangup() {
+ console.log('Session terminated.');
+ stop();
+ isInitiator = false;
+ }
+
+ function stop() {
+ isStarted = false;
+ pc.close();
+ pc = null;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+} \ No newline at end of file
diff --git a/src/client/views/webcam/DashWebRTC.tsx b/src/client/views/webcam/DashWebRTC.tsx
deleted file mode 100644
index 9c93fb4cf..000000000
--- a/src/client/views/webcam/DashWebRTC.tsx
+++ /dev/null
@@ -1,334 +0,0 @@
-import { observer } from "mobx-react";
-import React = require("react");
-import { CollectionFreeFormDocumentViewProps } from "../nodes/CollectionFreeFormDocumentView";
-import { FieldViewProps, FieldView } from "../nodes/FieldView";
-import { observable } from "mobx";
-import { DocumentDecorations } from "../DocumentDecorations";
-import { InkingControl } from "../InkingControl";
-import "../../views/nodes/WebBox.scss";
-import "./DashWebRTC.scss"
-import adapter from 'webrtc-adapter';
-
-
-
-
-const mediaStreamConstraints = {
- video: true,
-};
-
-const offerOptions = {
- offerToReceiveVideo: 1,
-};
-
-
-@observer
-export class DashWebRTC extends React.Component<CollectionFreeFormDocumentViewProps & FieldViewProps> {
-
- @observable private localVideoEl: HTMLVideoElement | undefined;
- @observable private peerVideoEl: HTMLVideoElement | undefined;
- @observable private localStream: MediaStream | undefined;
- @observable private startTime: any = null;
- @observable private remoteStream: MediaStream | undefined;
- @observable private localPeerConnection: any;
- @observable private remotePeerConnection: any;
- private callButton: HTMLButtonElement | undefined;
- private startButton: HTMLButtonElement | undefined;
- private hangupButton: HTMLButtonElement | undefined;
-
-
- componentDidMount() {
- this.callButton!.disabled = true;
- this.hangupButton!.disabled = true;
- // 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);
- }
-
-
- gotLocalMediaStream = (mediaStream: MediaStream) => {
- this.localStream = mediaStream;
- if (this.localVideoEl) {
- this.localVideoEl.srcObject = mediaStream;
- }
- this.trace('Received local stream.');
- this.callButton!.disabled = false;
-
- }
-
- gotRemoteMediaStream = (event: MediaStreamEvent) => {
- let mediaStream = event.stream;
- this.peerVideoEl!.srcObject = mediaStream;
- this.remoteStream = mediaStream!;
-
- }
-
- handleLocalMediaStreamError = (error: string) => {
- //console.log("navigator.getUserMedia error: ", error);
- this.trace(`navigator.getUserMedia error: ${error.toString()}.`);
-
- }
-
- logVideoLoaded = (event: any) => {
- let video = event.target;
- this.trace(`${video.id} videoWidth: ${video.videoWidth}px, ` +
- `videoHeight: ${video.videoHeight}px.`);
- }
-
- logResizedVideo = (event: any) => {
- this.logVideoLoaded(event);
-
- if (this.startTime) {
- let elapsedTime = window.performance.now() - this.startTime;
- this.startTime = null;
- 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);
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- public static LayoutString() { return FieldView.LayoutString(DashWebRTC); }
-
-
- _ignore = 0;
- onPreWheel = (e: React.WheelEvent) => {
- this._ignore = e.timeStamp;
- }
- onPrePointer = (e: React.PointerEvent) => {
- this._ignore = e.timeStamp;
- }
- onPostPointer = (e: React.PointerEvent) => {
- if (this._ignore !== e.timeStamp) {
- e.stopPropagation();
- }
- }
- onPostWheel = (e: React.WheelEvent) => {
- if (this._ignore !== e.timeStamp) {
- e.stopPropagation();
- }
- }
-
-
-
- render() {
- let content =
- <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!} 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;
- let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
-
-
- return (
- <>
- <div className={classname} >
- {content}
- </div>
- {!frozen ? (null) : <div className="webBox-overlay" onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} />}
- </>);
- }
-
-
-} \ No newline at end of file
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
new file mode 100644
index 000000000..db9c922fc
--- /dev/null
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -0,0 +1,339 @@
+import { observer } from "mobx-react";
+import React = require("react");
+import { CollectionFreeFormDocumentViewProps } from "../nodes/CollectionFreeFormDocumentView";
+import { FieldViewProps, FieldView } from "../nodes/FieldView";
+import { observable } from "mobx";
+import { DocumentDecorations } from "../DocumentDecorations";
+import { InkingControl } from "../InkingControl";
+import "../../views/nodes/WebBox.scss";
+import "./DashWebRTC.scss";
+import adapter from 'webrtc-adapter';
+import { DashWebRTC } from "./DashWebRTC";
+
+
+
+
+const mediaStreamConstraints = {
+ video: true,
+};
+
+const offerOptions = {
+ offerToReceiveVideo: 1,
+};
+
+
+@observer
+export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentViewProps & FieldViewProps> {
+
+ @observable private localVideoEl: HTMLVideoElement | undefined;
+ @observable private peerVideoEl: HTMLVideoElement | undefined;
+ @observable private localStream: MediaStream | undefined;
+ @observable private startTime: any = null;
+ @observable private remoteStream: MediaStream | undefined;
+ @observable private localPeerConnection: any;
+ @observable private remotePeerConnection: any;
+ private callButton: HTMLButtonElement | undefined;
+ private startButton: HTMLButtonElement | undefined;
+ private hangupButton: HTMLButtonElement | undefined;
+
+ componentDidMount() {
+ DashWebRTC.setVideoObjects(this.localVideoEl!, this.peerVideoEl!);
+ }
+
+
+ // componentDidMount() {
+ // this.callButton!.disabled = true;
+ // this.hangupButton!.disabled = true;
+ // // 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);
+ // }
+
+
+ // gotLocalMediaStream = (mediaStream: MediaStream) => {
+ // this.localStream = mediaStream;
+ // if (this.localVideoEl) {
+ // this.localVideoEl.srcObject = mediaStream;
+ // }
+ // this.trace('Received local stream.');
+ // this.callButton!.disabled = false;
+
+ // }
+
+ // gotRemoteMediaStream = (event: MediaStreamEvent) => {
+ // let mediaStream = event.stream;
+ // this.peerVideoEl!.srcObject = mediaStream;
+ // this.remoteStream = mediaStream!;
+
+ // }
+
+ // handleLocalMediaStreamError = (error: string) => {
+ // //console.log("navigator.getUserMedia error: ", error);
+ // this.trace(`navigator.getUserMedia error: ${error.toString()}.`);
+
+ // }
+
+ // logVideoLoaded = (event: any) => {
+ // let video = event.target;
+ // this.trace(`${video.id} videoWidth: ${video.videoWidth}px, ` +
+ // `videoHeight: ${video.videoHeight}px.`);
+ // }
+
+ // logResizedVideo = (event: any) => {
+ // this.logVideoLoaded(event);
+
+ // if (this.startTime) {
+ // let elapsedTime = window.performance.now() - this.startTime;
+ // this.startTime = null;
+ // 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);
+ // }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ public static LayoutString() { return FieldView.LayoutString(DashWebRTCVideo); }
+
+
+ _ignore = 0;
+ onPreWheel = (e: React.WheelEvent) => {
+ this._ignore = e.timeStamp;
+ }
+ onPrePointer = (e: React.PointerEvent) => {
+ this._ignore = e.timeStamp;
+ }
+ onPostPointer = (e: React.PointerEvent) => {
+ if (this._ignore !== e.timeStamp) {
+ e.stopPropagation();
+ }
+ }
+ onPostWheel = (e: React.WheelEvent) => {
+ if (this._ignore !== e.timeStamp) {
+ e.stopPropagation();
+ }
+ }
+
+
+
+ render() {
+ let content =
+ <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!} 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;
+ let classname = "webBox-cont" + (this.props.isSelected() && !InkingControl.Instance.selectedTool && !DocumentDecorations.Instance.Interacting ? "-interactive" : "");
+
+
+ return (
+ <>
+ <div className={classname} >
+ {content}
+ </div>
+ {!frozen ? (null) : <div className="webBox-overlay" onWheel={this.onPreWheel} onPointerDown={this.onPrePointer} onPointerMove={this.onPrePointer} onPointerUp={this.onPrePointer} />}
+ </>);
+ }
+
+
+} \ No newline at end of file