diff options
Diffstat (limited to 'src/client/views/webcam/WebCamLogic.js')
-rw-r--r-- | src/client/views/webcam/WebCamLogic.js | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/src/client/views/webcam/WebCamLogic.js b/src/client/views/webcam/WebCamLogic.js new file mode 100644 index 000000000..5f6202bc8 --- /dev/null +++ b/src/client/views/webcam/WebCamLogic.js @@ -0,0 +1,292 @@ +'use strict'; +import io from "socket.io-client"; + +var socket; +var isChannelReady = false; +var isInitiator = false; +var isStarted = false; +var localStream; +var pc; +var remoteStream; +var turnReady; +var room; + +export function initialize(roomName, handlerUI) { + + 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 + }; + + ///////////////////////////////////////////// + + room = roomName; + + 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); + }); + + //////////////////////////////////////////////// + + + // 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'); + + const gotStream = (stream) => { + console.log('Adding local stream.'); + localStream = stream; + localVideo.srcObject = stream; + sendMessage('got user media'); + if (isInitiator) { + maybeStart(); + } + } + + + navigator.mediaDevices.getUserMedia({ + audio: true, + video: true + }) + .then(gotStream) + .catch(function (e) { + alert('getUserMedia() error: ' + e.name); + }); + + + + var constraints = { + video: true + }; + + console.log('Getting user media with constraints', constraints); + + 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(); + } + } + + + + + if (location.hostname !== 'localhost') { + requestTurn( + `${window.location.origin}/corsProxy/${encodeURIComponent("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 handleRemoteStreamAdded = (event) => { + console.log('Remote stream added.'); + remoteStream = event.stream; + remoteVideo.srcObject = remoteStream; + handlerUI(); + + }; + + const handleRemoteStreamRemoved = (event) => { + console.log('Remote stream removed. Event: ', event); + } +} + +export function hangup() { + console.log('Hanging up.'); + stop(); + sendMessage('bye'); + if (localStream) { + localStream.getTracks().forEach(track => track.stop()); + } +} + +function stop() { + isStarted = false; + if (pc) { + pc.close(); + } + pc = null; +} + +function handleRemoteHangup() { + console.log('Session terminated.'); + stop(); + isInitiator = false; + if (localStream) { + localStream.getTracks().forEach(track => track.stop()); + } +} + +function sendMessage(message) { + console.log('Client sending message: ', message); + socket.emit('message', message, room); +}; + +export function refreshVideos() { + var localVideo = document.querySelector('#localVideo'); + var remoteVideo = document.querySelector('#remoteVideo'); + if (localVideo) { + localVideo.srcObject = localStream; + } + if (remoteVideo) { + remoteVideo.srcObject = remoteStream; + } + +}
\ No newline at end of file |