aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Amoush <47069173+mamoush34@users.noreply.github.com>2020-02-07 21:52:49 -0500
committerMohammad Amoush <47069173+mamoush34@users.noreply.github.com>2020-02-07 21:52:49 -0500
commitd3db291c2587bf1284f9d0a8ee7d06fd8ec7a252 (patch)
treebbd1fef6e9cccf813318d0bf0088698a1c358d46
parentce5980ddf7cdd247f8e31be1c437b9c40d46e29d (diff)
Another refactor with modules
-rw-r--r--src/client/views/webcam/DashWebRTCVideo.scss31
-rw-r--r--src/client/views/webcam/DashWebRTCVideo.tsx575
-rw-r--r--src/client/views/webcam/WebCamLogic.js268
-rw-r--r--src/server/Websocket/Websocket.ts51
4 files changed, 607 insertions, 318 deletions
diff --git a/src/client/views/webcam/DashWebRTCVideo.scss b/src/client/views/webcam/DashWebRTCVideo.scss
index ccb0a626b..262528d8e 100644
--- a/src/client/views/webcam/DashWebRTCVideo.scss
+++ b/src/client/views/webcam/DashWebRTCVideo.scss
@@ -27,14 +27,14 @@
border: 1px solid #BBBBBBBB;
}
- // #localVideo {
- // width: 25%;
- // height: 20%;
- // position: absolute;
- // top: 65%;
- // z-index: 2;
- // right: 5%;
- // }
+ #localVideo {
+ width: 50%;
+ height: 50%;
+ position: relative;
+ // top: 65%;
+ // z-index: 2;
+ // right: 5%;
+ }
.side {
width: 25%;
@@ -53,13 +53,12 @@
align-self: center;
}
- // #remoteVideo {
- // position: absolute;
- // width: 95%;
- // height: 75%;
- // top: 20%;
- // align-self: center;
-
- // }
+ #remoteVideo {
+ position: relative;
+ width: 50%;
+ height: 50%;
+ // top: 20%;
+ // align-self: center;
+ }
} \ No newline at end of file
diff --git a/src/client/views/webcam/DashWebRTCVideo.tsx b/src/client/views/webcam/DashWebRTCVideo.tsx
index 290ca7a48..191f5750d 100644
--- a/src/client/views/webcam/DashWebRTCVideo.tsx
+++ b/src/client/views/webcam/DashWebRTCVideo.tsx
@@ -12,9 +12,7 @@ import { DocServer } from "../../DocServer";
import { DocumentView } from "../nodes/DocumentView";
import { Utils } from "../../../Utils";
import { MessageStore } from "../../../server/Message";
-
-
-
+import { initialize } from "./WebCamLogic";
const mediaStreamConstraints = {
video: true,
@@ -24,358 +22,335 @@ const offerOptions = {
offerToReceiveVideo: 1,
};
-
/**
* This models the component that will be rendered, that can be used as a doc that will reflect the video cams.
*/
@observer
export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentViewProps & FieldViewProps> {
-
@observable private localVideoEl: HTMLVideoElement | undefined;
@observable private peerVideoEl: HTMLVideoElement | undefined;
- private roomText: HTMLInputElement | undefined;
- private roomOfCam: string = "";
- private isChannelReady = false;
- private isInitiator = false;
- private isStarted = false;
- @observable remoteVideoAdded: boolean = false;
- localStream: MediaStream | undefined;
- private pc: any;
- remoteStream: MediaStream | undefined;
- private turnReady: boolean | undefined;
- //localVideo: HTMLVideoElement | undefined;
- //remoteVideo: HTMLVideoElement | undefined;
- curRoom: string = "";
-
-
- private pcConfig = {
- 'iceServers': [{
- 'urls': 'stun:stun.l.google.com:19302'
- }]
- };
-
- // Set up audio and video regardless of what devices are present.
- private sdpConstraints = {
- offerToReceiveAudio: true,
- offerToReceiveVideo: true
- };
+ // private roomText: HTMLInputElement | undefined;
+ // private roomOfCam: string = "";
+ // private isChannelReady = false;
+ // private isInitiator = false;
+ // private isStarted = false;
+ // @observable remoteVideoAdded: boolean = false;
+ // localStream: MediaStream | undefined;
+ // private pc: any;
+ // remoteStream: MediaStream | undefined;
+ // private turnReady: boolean | undefined;
+ // //localVideo: HTMLVideoElement | undefined;
+ // //remoteVideo: HTMLVideoElement | undefined;
+ // curRoom: string = "";
+
+ // private pcConfig = {
+ // 'iceServers': [{
+ // 'urls': 'stun:stun.l.google.com:19302'
+ // }]
+ // };
+
+ // // Set up audio and video regardless of what devices are present.
+ // private sdpConstraints = {
+ // offerToReceiveAudio: true,
+ // offerToReceiveVideo: true
+ // };
componentDidMount() {
- DocumentDecorations.Instance.addCloseCall(this.closeConnection);
- let self = this;
- window.onbeforeunload = function () {
- self.sendMessage('bye');
- };
+ // DocumentDecorations.Instance.addCloseCall(this.closeConnection);
+ setTimeout(() => initialize(), 10000);
+ // let self = this;
+ // window.onbeforeunload = function () {
+ // self.sendMessage('bye');
+ // };
}
- closeConnection: CloseCall = () => {
- this.hangup();
- }
+ // closeConnection: CloseCall = () => {
+ // this.hangup();
+ // }
- componentWillUnmount() {
- }
+ // componentWillUnmount() {
+ // }
- init(room: string) {
+ // init(room: string) {
+
+ // this.curRoom = room;
+ // let self = this;
+
+ // 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);
+ // self.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 + '!');
+ // self.isChannelReady = true;
+ // });
+
+
+ // DocServer._socket.on('joined', function (room: string) {
+ // console.log('joined: ' + room);
+ // self.isChannelReady = true;
+ // });
+
+
+ // DocServer._socket.on('log', function (array: any) {
+ // console.log.apply(console, array);
+ // });
+
+ // // This client receives a message
+ // DocServer._socket.on('message', async function (message: any) {
+ // console.log('Client received message:', message);
+ // if (message.message === 'got user media') {
+ // self.maybeStart();
+ // } else if (message.message.type === 'offer') {
+ // if (!self.isInitiator && !self.isStarted) {
+ // self.maybeStart();
+ // }
+ // await self.pc.setRemoteDescription(new RTCSessionDescription(message.message));
+ // self.doAnswer();
+ // } else if (message.message.type === 'answer' && self.isStarted) {
+ // await self.pc.setRemoteDescription(new RTCSessionDescription(message.message));
+ // } else if (message.message.type === 'candidate' && self.isStarted) {
+ // let candidate = new RTCIceCandidate({
+ // sdpMLineIndex: message.message.label,
+ // candidate: message.message.candidate
+ // });
+ // self.pc.addIceCandidate(candidate);
+ // } else if (message.message === 'bye' && self.isStarted) {
+ // self.handleRemoteHangup();
+ // }
+ // });
+
+ // navigator.mediaDevices.getUserMedia({
+ // audio: true,
+ // video: true
+ // })
+ // .then(this.gotStream)
+ // .catch(function (e) {
+ // alert('getUserMedia() error: ' + e.name);
+ // });
+
+ // //Trying this one out!!!
+ // console.log('Getting user media with constraints', this.constraints);
+
+ // if (location.hostname !== 'localhost') {
+ // this.requestTurn(
+ // 'https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913'
+ // );
+ // }
- this.curRoom = room;
- let self = this;
- 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);
- self.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 + '!');
- self.isChannelReady = true;
- });
-
-
- DocServer._socket.on('joined', function (room: string) {
- console.log('joined: ' + room);
- self.isChannelReady = true;
- });
-
-
- DocServer._socket.on('log', function (array: any) {
- console.log.apply(console, array);
- });
-
- // This client receives a message
- DocServer._socket.on('message', function (message: any) {
- console.log('Client received message:', message);
- if (message.message === 'got user media') {
- self.maybeStart();
- } else if (message.message.type === 'offer') {
- if (!self.isInitiator && !self.isStarted) {
- self.maybeStart();
- }
- self.pc.setRemoteDescription(new RTCSessionDescription(message.message));
- self.doAnswer();
- } else if (message.message.type === 'answer' && self.isStarted) {
- self.pc.setRemoteDescription(new RTCSessionDescription(message.message));
- } else if (message.message.type === 'candidate' && self.isStarted) {
- let candidate = new RTCIceCandidate({
- sdpMLineIndex: message.message.label,
- candidate: message.message.candidate
- });
- self.pc.addIceCandidate(candidate);
- } else if (message.message === 'bye' && self.isStarted) {
- self.handleRemoteHangup();
- }
- });
-
- navigator.mediaDevices.getUserMedia({
- audio: true,
- video: true
- })
- .then(this.gotStream)
- .catch(function (e) {
- alert('getUserMedia() error: ' + e.name);
- });
-
- //Trying this one out!!!
- console.log('Getting user media with constraints', this.constraints);
-
- if (location.hostname !== 'localhost') {
- this.requestTurn(
- 'https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913'
- );
- }
+ // private sendMessage = (message: any) => {
+ // console.log('Client sending message: ', message);
+ // Utils.Emit(DocServer._socket, MessageStore.NotifyRoommates, { message: message, room: this.curRoom });
+ // //DocServer._socket.emit('message', message);
+ // }
- }
+ // private gotStream = (stream: any) => {
+ // console.log('Adding local stream.');
+ // this.localStream = stream;
+ // this.localVideoEl!.srcObject = stream;
+ // this.sendMessage('got user media');
+ // if (this.isInitiator) {
+ // this.maybeStart();
+ // }
+ // }
- private sendMessage = (message: any) => {
- console.log('Client sending message: ', message);
- Utils.Emit(DocServer._socket, MessageStore.NotifyRoommates, { message: message, room: this.curRoom });
- //DocServer._socket.emit('message', message);
- }
+ // constraints = {
+ // video: true,
+ // audio: true
+ // };
- // setVideoObjects(localVideo: HTMLVideoElement, remoteVideo: HTMLVideoElement) {
- // this.localVideo = localVideo;
- // this.remoteVideo = remoteVideo;
+ // private maybeStart = () => {
+ // console.log('>>>>>>> maybeStart() ', this.isStarted, this.localStream, this.isChannelReady);
+ // if (!this.isStarted && typeof this.localStream !== 'undefined' && this.isChannelReady) {
+ // console.log('>>>>>> creating peer connection');
+ // this.createPeerConnection();
+ // this.pc.addStream(this.localStream);
+ // this.isStarted = true;
+ // console.log('isInitiator', this.isInitiator);
+ // if (this.isInitiator) {
+ // this.doCall();
+ // }
+ // }
// }
- // setLocalVideoObject(localVideoRef: HTMLVideoElement) {
- // this.localVideo = localVideoRef;
+ // // //this will need to be changed to our version of hangUp
+ // // window.onbeforeunload = function () {
+ // // sendMessage('bye');
+ // // };
+
+ // private createPeerConnection = () => {
+ // try {
+ // this.pc = new RTCPeerConnection(undefined);
+ // this.pc.onicecandidate = this.handleIceCandidate;
+ // this.pc.onaddstream = this.handleRemoteStreamAdded;
+ // this.pc.onremovestream = this.handleRemoteStreamRemoved;
+ // console.log('Created RTCPeerConnnection');
+ // } catch (e) {
+ // console.log('Failed to create PeerConnection, exception: ' + e.message);
+ // alert('Cannot create RTCPeerConnection object.');
+ // return;
+ // }
// }
- // setRemoteVideoObject(remoteVideoRef: HTMLVideoElement) {
- // this.remoteVideo = remoteVideoRef;
+ // private handleIceCandidate = (event: any) => {
+ // console.log('icecandidate event: ', event);
+ // if (event.candidate) {
+ // this.sendMessage({
+ // type: 'candidate',
+ // label: event.candidate.sdpMLineIndex,
+ // id: event.candidate.sdpMid,
+ // candidate: event.candidate.candidate
+ // });
+ // } else {
+ // console.log('End of candidates.');
+ // }
// }
+ // private handleCreateOfferError = (event: any) => {
+ // console.log('createOffer() error: ', event);
+ // }
+ // private doCall = () => {
+ // console.log('Sending offer to peer');
+ // this.pc.createOffer(this.setLocalAndSendMessage, this.handleCreateOfferError);
+ // }
+ // private doAnswer = () => {
+ // console.log('Sending answer to peer.');
+ // this.pc.createAnswer().then(
+ // this.setLocalAndSendMessage,
+ // this.onCreateSessionDescriptionError
+ // );
+ // }
- private gotStream = (stream: any) => {
- console.log('Adding local stream.');
- this.localStream = stream;
- this.localVideoEl!.srcObject = stream;
- this.sendMessage('got user media');
- if (this.isInitiator) {
- this.maybeStart();
- }
- }
-
- constraints = {
- video: true,
- audio: true
- };
-
-
-
-
-
- private maybeStart = () => {
- console.log('>>>>>>> maybeStart() ', this.isStarted, this.localStream, this.isChannelReady);
- if (!this.isStarted && typeof this.localStream !== 'undefined' && this.isChannelReady) {
- console.log('>>>>>> creating peer connection');
- this.createPeerConnection();
- this.pc.addStream(this.localStream);
- this.isStarted = true;
- console.log('isInitiator', this.isInitiator);
- if (this.isInitiator) {
- this.doCall();
- }
- }
- }
-
-
- // //this will need to be changed to our version of hangUp
- // window.onbeforeunload = function () {
- // sendMessage('bye');
- // };
-
- private createPeerConnection = () => {
- try {
- this.pc = new RTCPeerConnection(undefined);
- this.pc.onicecandidate = this.handleIceCandidate;
- this.pc.onaddstream = this.handleRemoteStreamAdded;
- this.pc.onremovestream = this.handleRemoteStreamRemoved;
- console.log('Created RTCPeerConnnection');
- } catch (e) {
- console.log('Failed to create PeerConnection, exception: ' + e.message);
- alert('Cannot create RTCPeerConnection object.');
- return;
- }
- }
-
- private handleIceCandidate = (event: any) => {
- console.log('icecandidate event: ', event);
- if (event.candidate) {
- this.sendMessage({
- type: 'candidate',
- label: event.candidate.sdpMLineIndex,
- id: event.candidate.sdpMid,
- candidate: event.candidate.candidate
- });
- } else {
- console.log('End of candidates.');
- }
- }
-
- private handleCreateOfferError = (event: any) => {
- console.log('createOffer() error: ', event);
- }
-
- private doCall = () => {
- console.log('Sending offer to peer');
- this.pc.createOffer(this.setLocalAndSendMessage, this.handleCreateOfferError);
- }
-
- private doAnswer = () => {
- console.log('Sending answer to peer.');
- this.pc.createAnswer().then(
- this.setLocalAndSendMessage,
- this.onCreateSessionDescriptionError
- );
- }
-
- private setLocalAndSendMessage = (sessionDescription: any) => {
- this.pc.setLocalDescription(sessionDescription);
- console.log('setLocalAndSendMessage sending message', sessionDescription);
- this.sendMessage(sessionDescription);
- }
+ // private setLocalAndSendMessage = (sessionDescription: any) => {
+ // this.pc.setLocalDescription(sessionDescription);
+ // console.log('setLocalAndSendMessage sending message', sessionDescription);
+ // this.sendMessage(sessionDescription);
+ // }
- private onCreateSessionDescriptionError = (error: any) => {
- console.log('Failed to create session description: ' + error.toString());
- }
+ // private onCreateSessionDescriptionError = (error: any) => {
+ // console.log('Failed to create session description: ' + error.toString());
+ // }
- private requestTurn = (turnURL: any) => {
- var turnExists = false;
- let self = this;
- for (var i in this.pcConfig.iceServers) {
- if (this.pcConfig.iceServers[i].urls.substr(0, 5) === 'turn:') {
- turnExists = true;
- this.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);
- self.pcConfig.iceServers.push({
- 'urls': 'turn:' + turnServer.username + '@' + turnServer.turn,
- //'credential': turnServer.password
- });
- self.turnReady = true;
- }
- };
- xhr.open('GET', turnURL, true);
- xhr.send();
- }
- }
- @action
- private handleRemoteStreamAdded = (event: MediaStreamEvent) => {
- console.log('Remote stream added.');
- this.remoteStream = event.stream!;
- this.peerVideoEl!.srcObject = this.remoteStream;
- this.remoteVideoAdded = true;
- }
+ // private requestTurn = (turnURL: any) => {
+ // var turnExists = false;
+ // let self = this;
+ // for (var i in this.pcConfig.iceServers) {
+ // if (this.pcConfig.iceServers[i].urls.substr(0, 5) === 'turn:') {
+ // turnExists = true;
+ // this.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);
+ // self.pcConfig.iceServers.push({
+ // 'urls': 'turn:' + turnServer.username + '@' + turnServer.turn,
+ // //'credential': turnServer.password
+ // });
+ // self.turnReady = true;
+ // }
+ // };
+ // xhr.open('GET', turnURL, true);
+ // xhr.send();
+ // }
+ // }
+ // @action
+ // private handleRemoteStreamAdded = (event: MediaStreamEvent) => {
+ // console.log('Remote stream added.');
+ // this.remoteStream = event.stream!;
+ // this.peerVideoEl!.srcObject = this.remoteStream;
+ // this.remoteVideoAdded = true;
+ // }
- private handleRemoteStreamRemoved = (event: MediaStreamEvent) => {
- console.log('Remote stream removed. Event: ', event);
- }
+ // private handleRemoteStreamRemoved = (event: MediaStreamEvent) => {
+ // console.log('Remote stream removed. Event: ', event);
+ // }
- private hangup = () => {
- console.log('Hanging up.');
- if (this.pc) {
- stop();
- this.sendMessage('bye');
- }
+ // private hangup = () => {
+ // console.log('Hanging up.');
+ // if (this.pc) {
+ // stop();
+ // this.sendMessage('bye');
+ // }
- if (this.localStream) {
- this.localStream.getTracks().forEach(track => track.stop());
- }
+ // if (this.localStream) {
+ // this.localStream.getTracks().forEach(track => track.stop());
+ // }
- }
+ // }
- private handleRemoteHangup = () => {
- console.log('Session terminated.');
- this.stop();
- this.isInitiator = false;
+ // private handleRemoteHangup = () => {
+ // console.log('Session terminated.');
+ // this.stop();
+ // this.isInitiator = false;
- if (this.localStream) {
- this.localStream.getTracks().forEach(track => track.stop());
- }
+ // if (this.localStream) {
+ // this.localStream.getTracks().forEach(track => track.stop());
+ // }
- }
+ // }
- private stop = () => {
- this.isStarted = false;
- this.pc.close();
- this.pc = null;
- }
+ // private stop = () => {
+ // this.isStarted = false;
+ // this.pc.close();
+ // this.pc = null;
+ // }
- /**
- * Function that submits the title entered by user on enter press.
- */
- private onEnterKeyDown = (e: React.KeyboardEvent) => {
- if (e.keyCode === 13) {
- let submittedTitle = this.roomText!.value;
- this.roomText!.value = "";
- this.roomText!.blur();
- this.roomOfCam = submittedTitle;
- this.init(submittedTitle);
- }
- }
+ // /**
+ // * Function that submits the title entered by user on enter press.
+ // */
+ // private onEnterKeyDown = (e: React.KeyboardEvent) => {
+ // if (e.keyCode === 13) {
+ // let submittedTitle = this.roomText!.value;
+ // this.roomText!.value = "";
+ // this.roomText!.blur();
+ // this.roomOfCam = submittedTitle;
+ // this.init(submittedTitle);
+ // }
+ // }
public static LayoutString(fieldKey: string) { return FieldView.LayoutString(DashWebRTCVideo, fieldKey); }
-
-
_ignore = 0;
onPreWheel = (e: React.WheelEvent) => {
this._ignore = e.timeStamp;
@@ -394,17 +369,15 @@ export class DashWebRTCVideo extends React.Component<CollectionFreeFormDocumentV
}
}
-
-
render() {
let content =
<div className="webcam-cont" style={{ width: "100%", height: "100%" }} onWheel={this.onPostWheel} onPointerDown={this.onPostPointer} onPointerMove={this.onPostPointer} onPointerUp={this.onPostPointer}>
<div className="webcam-header">DashWebRTC</div>
- <input id="roomName" type="text" placeholder="Enter room name" ref={(e) => this.roomText = e!} onKeyDown={this.onEnterKeyDown} />
- <video id="localVideo" className={"RTCVideo" + (this.remoteVideoAdded ? " side" : " main")} autoPlay playsInline ref={(e) => {
+ {/* <input id="roomName" type="text" placeholder="Enter room name" ref={(e) => this.roomText = e!} onKeyDown={this.onEnterKeyDown} /> */}
+ <video id="localVideo" autoPlay playsInline ref={(e) => {
this.localVideoEl = e!;
}}></video>
- <video id="remoteVideo" className="RTCVideo main" autoPlay playsInline ref={(e) => {
+ <video id="remoteVideo" autoPlay playsInline ref={(e) => {
this.peerVideoEl = e!;
}}></video>
diff --git a/src/client/views/webcam/WebCamLogic.js b/src/client/views/webcam/WebCamLogic.js
new file mode 100644
index 000000000..d4798f72f
--- /dev/null
+++ b/src/client/views/webcam/WebCamLogic.js
@@ -0,0 +1,268 @@
+'use strict';
+import io from "socket.io-client";
+
+export function initialize() {
+
+ var isChannelReady = false;
+ var isInitiator = false;
+ var isStarted = false;
+ var localStream;
+ var pc;
+ var remoteStream;
+ var turnReady;
+
+ var pcConfig = {
+ 'iceServers': [{
+ 'urls': 'stun:stun.l.google.com:19302'
+ }]
+ };
+
+ // Set up audio and video regardless of what devices are present.
+ var sdpConstraints = {
+ offerToReceiveAudio: true,
+ offerToReceiveVideo: true
+ };
+
+ /////////////////////////////////////////////
+
+ var room = 'foo';
+ // Could prompt for room name:
+ // room = prompt('Enter room name:');
+
+ var socket = io.connect(`${window.location.protocol}//${window.location.hostname}:${4321}`);
+
+ if (room !== '') {
+ socket.emit('create or join', room);
+ console.log('Attempted to create or join room', room);
+ }
+
+ socket.on('created', function (room) {
+ console.log('Created room ' + room);
+ isInitiator = true;
+ });
+
+ socket.on('full', function (room) {
+ console.log('Room ' + room + ' is full');
+ });
+
+ socket.on('join', function (room) {
+ console.log('Another peer made a request to join room ' + room);
+ console.log('This peer is the initiator of room ' + room + '!');
+ isChannelReady = true;
+ });
+
+ socket.on('joined', function (room) {
+ console.log('joined: ' + room);
+ isChannelReady = true;
+ });
+
+ socket.on('log', function (array) {
+ console.log.apply(console, array);
+ });
+
+ ////////////////////////////////////////////////
+
+ const sendMessage = (message) => {
+ console.log('Client sending message: ', message);
+ socket.emit('message', message);
+ };
+
+ // This client receives a message
+ socket.on('message', function (message) {
+ 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();
+ }
+ });
+
+ ////////////////////////////////////////////////////
+
+ var localVideo = document.querySelector('#localVideo');
+ var remoteVideo = document.querySelector('#remoteVideo');
+
+ console.log("Local Video: ", localVideo);
+ console.log("Remote Video: ", remoteVideo);
+
+ const gotStream = (stream) => {
+ console.log('Adding local stream.');
+ localStream = stream;
+ localVideo.srcObject = stream;
+ sendMessage('got user media');
+ if (isInitiator) {
+ maybeStart();
+ }
+ }
+
+
+ navigator.mediaDevices.getUserMedia({
+ audio: false,
+ video: true
+ })
+ .then(gotStream)
+ .catch(function (e) {
+ alert('getUserMedia() error: ' + e.name);
+ });
+
+
+
+ var constraints = {
+ video: true
+ };
+
+ console.log('Getting user media with constraints', constraints);
+
+ if (location.hostname !== 'localhost') {
+ requestTurn(
+ 'https://computeengineondemand.appspot.com/turn?username=41784574&key=4080218913'
+ );
+ }
+
+ const 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();
+ }
+ }
+ };
+
+ window.onbeforeunload = function () {
+ sendMessage('bye');
+ };
+
+ /////////////////////////////////////////////////////////
+
+ const createPeerConnection = () => {
+ try {
+ pc = new RTCPeerConnection(null);
+ 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;
+ }
+ }
+
+ const handleIceCandidate = (event) => {
+ 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.');
+ }
+ }
+
+ const handleCreateOfferError = (event) => {
+ console.log('createOffer() error: ', event);
+ }
+
+ const doCall = () => {
+ console.log('Sending offer to peer');
+ pc.createOffer(setLocalAndSendMessage, handleCreateOfferError);
+ }
+
+ const doAnswer = () => {
+ console.log('Sending answer to peer.');
+ pc.createAnswer().then(
+ setLocalAndSendMessage,
+ onCreateSessionDescriptionError
+ );
+ }
+
+ const setLocalAndSendMessage = (sessionDescription) => {
+ pc.setLocalDescription(sessionDescription);
+ console.log('setLocalAndSendMessage sending message', sessionDescription);
+ sendMessage(sessionDescription);
+ }
+
+ const onCreateSessionDescriptionError = (error) => {
+ trace('Failed to create session description: ' + error.toString());
+ }
+
+ const requestTurn = (turnURL) => {
+ 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();
+ }
+ }
+
+ const handleRemoteStreamAdded = (event) => {
+ console.log('Remote stream added.');
+ remoteStream = event.stream;
+ remoteVideo.srcObject = remoteStream;
+ };
+
+ const handleRemoteStreamRemoved = (event) => {
+ console.log('Remote stream removed. Event: ', event);
+ }
+
+ const hangup = () => {
+ console.log('Hanging up.');
+ stop();
+ sendMessage('bye');
+ }
+
+ const handleRemoteHangup = () => {
+ console.log('Session terminated.');
+ stop();
+ isInitiator = false;
+ }
+
+ const stop = () => {
+ isStarted = false;
+ pc.close();
+ pc = null;
+ }
+
+} \ No newline at end of file
diff --git a/src/server/Websocket/Websocket.ts b/src/server/Websocket/Websocket.ts
index ff208d917..96694bf72 100644
--- a/src/server/Websocket/Websocket.ts
+++ b/src/server/Websocket/Websocket.ts
@@ -10,6 +10,7 @@ import { GoogleCredentialsLoader } from "../credentials/CredentialsLoader";
import { logPort } from "../ActionUtilities";
import { timeMap } from "../ApiManagers/UserManager";
import { green } from "colors";
+import { networkInterfaces } from "os";
export namespace WebSocket {
@@ -40,6 +41,55 @@ export namespace WebSocket {
next();
});
+ // convenience function to log server messages on the client
+ function log(message?: any, ...optionalParams: any[]) {
+ socket.emit('log', ['Message from server:', message, ...optionalParams]);
+ }
+
+ socket.on('message', function (message) {
+ log('Client said: ', message);
+ // for a real app, would be room-only (not broadcast)
+ socket.broadcast.emit('message', message);
+ });
+
+ socket.on('create or join', function (room) {
+ log('Received request to create or join room ' + room);
+
+ var clientsInRoom = socket.adapter.rooms[room];
+ var numClients = clientsInRoom ? Object.keys(clientsInRoom.sockets).length : 0;
+ log('Room ' + room + ' now has ' + numClients + ' client(s)');
+
+ if (numClients === 0) {
+ socket.join(room);
+ log('Client ID ' + socket.id + ' created room ' + room);
+ socket.emit('created', room, socket.id);
+
+ } else if (numClients === 1) {
+ log('Client ID ' + socket.id + ' joined room ' + room);
+ socket.in(room).emit('join', room);
+ socket.join(room);
+ socket.emit('joined', room, socket.id);
+ socket.in(room).emit('ready');
+ } else { // max two clients
+ socket.emit('full', room);
+ }
+ });
+
+ socket.on('ipaddr', function () {
+ var ifaces = networkInterfaces();
+ for (var dev in ifaces) {
+ ifaces[dev].forEach(function (details) {
+ if (details.family === 'IPv4' && details.address !== '127.0.0.1') {
+ socket.emit('ipaddr', details.address);
+ }
+ });
+ }
+ });
+
+ socket.on('bye', function () {
+ console.log('received bye');
+ });
+
Utils.Emit(socket, MessageStore.Foo, "handshooken");
Utils.AddServerHandler(socket, MessageStore.Bar, guid => barReceived(socket, guid));
@@ -61,7 +111,6 @@ export namespace WebSocket {
Utils.AddServerHandler(socket, MessageStore.HangUpCall, message => HandleHangUp(socket, message));
Utils.AddRoomHandler(socket, "create or join", HandleCreateOrJoin);
-
disconnect = () => {
socket.broadcast.emit("connection_terminated", Date.now());
socket.disconnect(true);