diff --git c/api/easyrtc_int.js w/api/easyrtc_int.js index 38c987c..f57adad 100644 --- c/api/easyrtc_int.js +++ w/api/easyrtc_int.js @@ -61,6 +61,13 @@ var Easyrtc = function() { var self = this; + // Testing truthy / falsy values with assert/expect + function assert(condition, failureMsg) { + if (!condition) { + throw new Error(failureMsg) + } + } + function logDebug (message, obj) { if (self.debugPrinter) { self.debugPrinter(message, obj); @@ -80,7 +87,7 @@ var Easyrtc = function() { return true; } - /** + /** @private peerConns is a map from caller names to the below object structure { pc: RTCPeerConnection - the WebRTC peer connection object @@ -112,7 +119,6 @@ var Easyrtc = function() { callFailureCB: function(errorCode, string) - see the easyrtc.call documentation wasAcceptedCB: function(boolean, string) - see the easyrtc.call documentation } - @private */ var peerConns = {}; /** @private */ @@ -4088,6 +4094,7 @@ var Easyrtc = function() { // TODO split buildPeerConnection it more thant 500 lines function buildPeerConnection(otherUser, isInitiator, failureCB, streamNames) { var pc; + var message; // Apply peer config var pcConfig = pcConfigToUse || { @@ -4120,17 +4127,10 @@ var Easyrtc = function() { try { - // Prevent peerConn override - if (peerConns[otherUser]) { - var duplicateMsg = "Unable to create duplicate PeerConnection object for peer " + otherUser; - logDebug(duplicateMsg); - throw Error(duplicateMsg); - } - pc = self.createRTCPeerConnection(pcConfig, buildPeerConstraints()); if (!pc) { - var message = "Unable to create PeerConnection object, check your ice configuration(" + JSON.stringify(pcConfig) + ")"; + message = "Unable to create PeerConnection object, check your ice configuration(" + JSON.stringify(pcConfig) + ")"; logDebug(message); throw Error(message); } @@ -4558,7 +4558,6 @@ var Easyrtc = function() { logDebug("calling connectDataConnection(5002,5001)"); pc.connectDataConnection(5002, 5001); } - }, function(message) { newPeerConn.pendingAwnser = false; self.showError(self.errCodes.INTERNAL_ERR, "setLocalDescription: " + message); @@ -4582,40 +4581,38 @@ var Easyrtc = function() { var localStream = self.getLocalStream(); if (!localStream && (self.videoEnabled || self.audioEnabled)) { self.initMediaSource( - function() { - doAnswer(caller, msgData); - }, - function(errorCode, error) { - self.showError(self.errCodes.MEDIA_ERR, self.format(self.getConstantString("localMediaError"))); - } - ); - } - } else { - if (useFreshIceEachPeer) { - self.getFreshIceConfig(function(succeeded) { - if (succeeded) { - doAnswerBody(caller, msgData, streamNames); - } - else { - self.showError(self.errCodes.CALL_ERR, "Failed to get fresh ice config"); - } - }); - } - else { - doAnswerBody(caller, msgData, streamNames); + function() { + doAnswer(caller, msgData); + }, + function(errorCode, error) { + self.showError(self.errCodes.MEDIA_ERR, self.format(self.getConstantString("localMediaError"))); + }); + return; } } + if (useFreshIceEachPeer) { + self.getFreshIceConfig(function(succeeded) { + if (succeeded) { + doAnswerBody(caller, msgData, streamNames); + } + else { + self.showError(self.errCodes.CALL_ERR, "Failed to get fresh ice config"); + } + }); + } + else { + doAnswerBody(caller, msgData, streamNames); + } } /** @private */ // function callBody(otherUser, callSuccessCB, callFailureCB, wasAcceptedCB, streamNames) { - acceptancePending[otherUser] = Date.now() - var pc = buildPeerConnection(otherUser, true, callFailureCB, streamNames); + var message; if (!pc) { - var message = "buildPeerConnection failed, call not completed"; + message = "buildPeerConnection failed, call not completed"; logDebug(message); throw message; } @@ -4629,7 +4626,7 @@ var Easyrtc = function() { function initiateSendOffer(otherUser, eventTarget, signalingState) { var peerConnObj = peerConns[otherUser]; - if (!peerConnObj) { + if( !peerConnObj ) { logDebug("message attempt to send offer for nonexistent peer connection " + otherUser); return; } @@ -4839,20 +4836,25 @@ var Easyrtc = function() { } } - /** @private */ - function hangupBody(otherUser, sendRemoteSignal) { - + /** + * Hang up on a particular user or all users. + * @param {String} otherUser - the easyrtcid of the person to hang up on. + * @example + * easyrtc.hangup(someEasyrtcid); + */ + this.hangup = function(otherUser) { + logDebug("Hanging up on " + otherUser); // Has connection (or acceptancePending also) if (peerConns[otherUser]) { closePeer(otherUser); - if (sendRemoteSignal && self.webSocket) { + if (self.webSocket) { sendSignalling(otherUser, "hangup", null, function() { - logDebug("signaling hangup succeeds"); + logDebug("hangup succeeds"); }, function(errorCode, errorText) { - logDebug("signaling hangup failed:" + errorText); + logDebug("hangup failed:" + errorText); self.showError(errorCode, errorText); }); } @@ -4865,25 +4867,18 @@ var Easyrtc = function() { self.callCancelled(otherUser, true); } - if (sendRemoteSignal && self.webSocket) { - sendSignalling(otherUser, "reject", null, function() { - logDebug("signaling reject succeeds"); - }, function(errorCode, errorText) { - logDebug("signaling reject failed:" + errorText); - self.showError(errorCode, errorText); - }); + if (self.webSocket) { + sendSignalling(otherUser, "reject", null, null, null); } } - } - /** - * Hang up on a particular user or all users. - * @param {String} otherUser - the easyrtcid of the person to hang up on. - * @example - * easyrtc.hangup(someEasyrtcid); - */ - this.hangup = function(otherUser) { - hangupBody(otherUser, true) + /* + // TODO deploy assert on critical code paths + assert(!queuedMessages.hasOwnProperty(otherUser), "Should not have queuedMessages reference for peer: " + otherUser); + assert(!acceptancePending.hasOwnProperty(otherUser), "Should not have acceptancePending reference for peer: " + otherUser); + assert(!offersPending.hasOwnProperty(otherUser), "Should not have offersPending reference for peer: " + otherUser); + assert(!peerConns.hasOwnProperty(otherUser), "Should not have peerConn reference for peer: " + otherUser); + */ }; /** @@ -4894,7 +4889,7 @@ var Easyrtc = function() { this.hangupAll = function() { for (var otherUser in peerConns) { if (peerConns.hasOwnProperty(otherUser)) { - hangupBody(otherUser, true) + this.hangup(otherUser); } } }; @@ -5003,11 +4998,27 @@ var Easyrtc = function() { peerConns[easyrtcId].enableNegotiateListener = true; removeStreamFromPeerConnection(stream, peerConns[easyrtcId].pc); } + }; /** @private */ function onRemoteHangup(otherUser) { - hangupBody(otherUser, false) + + logDebug("Saw onRemote hangup event"); + clearQueuedMessages(otherUser); + + // Has connection or calling user + if (peerConns[otherUser]) { + closePeer(otherUser); + } + // Has incoming call pending + else if (offersPending[otherUser]) { + delete offersPending[otherUser]; + + if (self.callCancelled) { + self.callCancelled(otherUser, true); + } + } } /** @private */ @@ -5373,11 +5384,6 @@ var Easyrtc = function() { pc.addIceCandidate(candidate, iceAddSuccess, iceAddFailure); } - /** @private */ - function isPolitePeer(caller) { - return caller < self.myEasyrtcid - } - /** @private */ function flushCachedCandidates(caller) { var i; @@ -5390,17 +5396,8 @@ var Easyrtc = function() { } /** @private */ - function processCandidateQueue(caller, msgData) { - if (peerConns[caller] && peerConns[caller].pc) { - processCandidateBody(caller, msgData); - } - else { - if (typeof queuedMessages[caller] === "undefined") { - clearQueuedMessages(caller); - } - - queuedMessages[caller].candidates.push(msgData); - } + function isPolitePeer(caller) { + return caller < self.myEasyrtcid } /** @private */ @@ -5605,6 +5602,21 @@ var Easyrtc = function() { flushCachedCandidates(caller); } + /** @private */ + function processCandidateQueue(caller, msgData) { + if (peerConns[caller] && peerConns[caller].pc) { + processCandidateBody(caller, msgData); + } + else { + if (!peerConns[caller]) { + queuedMessages[caller] = { + candidates: [] + }; + } + queuedMessages[caller].candidates.push(msgData); + } + } + /** @private */ function onChannelCmd(msg, ackAcceptorFn) { @@ -5614,6 +5626,12 @@ var Easyrtc = function() { logDebug('received message of type ' + msgType); + + if (typeof queuedMessages[caller] === "undefined") { + clearQueuedMessages(caller); + } + + switch (msgType) { case "sessionData": processSessionData(msgData.sessionData);