diff options
author | Mohammad Amoush <47069173+mamoush34@users.noreply.github.com> | 2020-02-07 21:52:49 -0500 |
---|---|---|
committer | Mohammad Amoush <47069173+mamoush34@users.noreply.github.com> | 2020-02-07 21:52:49 -0500 |
commit | d3db291c2587bf1284f9d0a8ee7d06fd8ec7a252 (patch) | |
tree | bbd1fef6e9cccf813318d0bf0088698a1c358d46 | |
parent | ce5980ddf7cdd247f8e31be1c437b9c40d46e29d (diff) |
Another refactor with modules
-rw-r--r-- | src/client/views/webcam/DashWebRTCVideo.scss | 31 | ||||
-rw-r--r-- | src/client/views/webcam/DashWebRTCVideo.tsx | 575 | ||||
-rw-r--r-- | src/client/views/webcam/WebCamLogic.js | 268 | ||||
-rw-r--r-- | src/server/Websocket/Websocket.ts | 51 |
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); |