Skip to content

Commit

Permalink
enhanced jssip
Browse files Browse the repository at this point in the history
Decouple signaling and WebRTC stuff versatica#427
rpid parser
add async modifier for local and remote description
add option to use reinvite instead update for session timer
  • Loading branch information
michelepra committed Oct 20, 2017
1 parent 130561c commit dcaa09f
Show file tree
Hide file tree
Showing 10 changed files with 6,178 additions and 3,903 deletions.
9,333 changes: 5,480 additions & 3,853 deletions dist/jssip.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions dist/jssip.min.js

Large diffs are not rendered by default.

419 changes: 418 additions & 1 deletion lib/Grammar.js

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions lib/Grammar.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -879,3 +879,27 @@ from_tag = "from-tag" EQUAL from_tag: token {

early_flag = "early-only" {
data.early_only = true; }

// Remote-Party-ID

Remote_Party_Id = ( display_name )* LAQUOT SIP_URI RAQUOT ( SEMI rpi_token )* {
try {
data = new NameAddrHeader(data.uri, data.display_name, data.params);
if (data.screen) {data.setParam('screen', data.screen)}
if (data.party) {data.setParam('party',data.party)}
if (data.type) {data.setParam('type',data.type)}
if (data.privacy) {data.setParam('privacy',data.privacy)}
} catch(e) {
data = -1;
}}

rpi_token = rpi_screen / rpi_pty_type / rpi_id_type / rpi_privacy / generic_param

rpi_screen = "screen"i EQUAL rpi_screen_value: ( "no"i / "yes"i ) { data.screen = rpi_screen_value.toLowerCase(); }

rpi_pty_type = "party"i EQUAL rpi_pty_type_value: ( "calling"i / "called"i ) { data.party = rpi_pty_type_value.toLowerCase(); }

rpi_id_type = "id_type"i EQUAL rpi_id_type_value: ( "subscriber"i / "user"i / "alias"i / "return"i / "term"i ) { data.type = rpi_id_type_value.toLowerCase(); }

rpi_privacy = "privacy"i EQUAL rpi_privacy_value: ("full"i / "name"i / "uri"i / "off"i )[ "-" ( "network"i ) ] { data.privacy = rpi_privacy_value.toLowerCase(); }

7 changes: 7 additions & 0 deletions lib/Parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,13 @@ function parseHeader(message, data, headerStart, headerEnd) {
message.event = parsed;
}
break;
case 'remote-party-id':
message.setHeader('remote-party-id', headerValue);
parsed = message.parseHeader('remote-party-id');
if(parsed) {
message.rpid = parsed;
}
break;
default:
// Do not parse this header.
message.setHeader(headerName, headerValue);
Expand Down
171 changes: 129 additions & 42 deletions lib/RTCSession.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ var Timers = require('./Timers');
var SIPMessage = require('./SIPMessage');
var Dialog = require('./Dialog');
var RequestSender = require('./RequestSender');
var PureSipConnection = require('./RTCSession/PureSipConnection');
var RTCSession_Request = require('./RTCSession/Request');
var RTCSession_DTMF = require('./RTCSession/DTMF');
var RTCSession_Info = require('./RTCSession/Info');
Expand All @@ -62,6 +63,19 @@ function RTCSession(ua) {
this.earlyDialogs = {};
this.connection = null; // The RTCPeerConnection instance (public attribute).

this.connectionConfig = {
enable_webrtc: this.ua.configuration.use_webrtc,
localDescriptionFactory: function () {
throw new Exceptions.NotSupportedError('localDescriptionFactory not set, please call setLocalDescriptionFactory');
},
localDescriptionModifier: function(description) {
return Promise.resolve(description);
},
remoteDescriptionModifier: function(description) {
return Promise.resolve(description);
}
};

// RTCSession confirmation flag
this.is_confirmed = false;

Expand Down Expand Up @@ -224,7 +238,10 @@ RTCSession.prototype.connect = function(target, options, initCallback) {
mediaStream = options.mediaStream || null,
pcConfig = options.pcConfig || {iceServers:[]},
rtcConstraints = options.rtcConstraints || null,
rtcOfferConstraints = options.rtcOfferConstraints || null;
rtcOfferConstraints = options.rtcOfferConstraints || null,
call_id = options.call_id || null,
display_name = options.display_name || null,
from_uri = options.from_uri || null;

this.rtcOfferConstraints = rtcOfferConstraints;
this.rtcAnswerConstraints = options.rtcAnswerConstraints || null;
Expand All @@ -248,7 +265,7 @@ RTCSession.prototype.connect = function(target, options, initCallback) {
}

// Check WebRTC support.
if (!window.RTCPeerConnection) {
if (this.connectionConfig.enable_webrtc && !window.RTCPeerConnection) {
throw new Exceptions.NotSupportedError('WebRTC not supported');
}

Expand Down Expand Up @@ -277,7 +294,7 @@ RTCSession.prototype.connect = function(target, options, initCallback) {
// OutgoingSession specific parameters
this.isCanceled = false;

requestParams = {from_tag: this.from_tag};
requestParams = {from_tag: this.from_tag, call_id: call_id, from_display_name: display_name, from_uri: from_uri};

this.contact = this.ua.contact.toString({
anonymous: this.anonymous,
Expand Down Expand Up @@ -553,7 +570,7 @@ RTCSession.prototype.answer = function(options) {
// If at least audio or video is requested prompt getUserMedia.
} else if (mediaConstraints.audio || mediaConstraints.video) {
self.localMediaStreamLocallyGenerated = true;
navigator.mediaDevices.getUserMedia(mediaConstraints)
Promise.resolve(this.connectionConfig.enable_webrtc ? navigator.mediaDevices.getUserMedia(mediaConstraints) : null)
.then(userMediaSucceeded)
.catch(function(error) {
userMediaFailed(error);
Expand Down Expand Up @@ -588,9 +605,12 @@ RTCSession.prototype.answer = function(options) {
debug('emit "sdp"');
self.emit('sdp', e);

var offer = new RTCSessionDescription({type:'offer', sdp:e.sdp});
var offer = self.newRTCSessionDescription({type:'offer', sdp:e.sdp});

self.connection.setRemoteDescription(offer)
self.connectionConfig.remoteDescriptionModifier(offer)
.then(function(offer) {
return self.connection.setRemoteDescription(offer);
})
.then(remoteDescriptionSucceededOrNotNeeded)
.catch(function(error) {
request.reply(488);
Expand Down Expand Up @@ -1054,8 +1074,8 @@ RTCSession.prototype.hold = function(options, done) {
onhold.call(this, 'local');

eventHandlers = {
succeeded: function() {
if (done) { done(); }
succeeded: function(response) {
if (done) { done(response); }
},
failed: function() {
self.terminate({
Expand Down Expand Up @@ -1107,8 +1127,8 @@ RTCSession.prototype.unhold = function(options, done) {
onunhold.call(this, 'local');

eventHandlers = {
succeeded: function() {
if (done) { done(); }
succeeded: function(response) {
if (done) { done(response); }
},
failed: function() {
self.terminate({
Expand Down Expand Up @@ -1154,8 +1174,8 @@ RTCSession.prototype.renegotiate = function(options, done) {
}

eventHandlers = {
succeeded: function() {
if (done) { done(); }
succeeded: function(response) {
if (done) { done(response); }
},
failed: function() {
self.terminate({
Expand Down Expand Up @@ -1278,11 +1298,14 @@ RTCSession.prototype.receiveRequest = function(request) {
}

var e = {originator:'remote', type:'answer', sdp:request.body};
var answer = new RTCSessionDescription({type:'answer', sdp:e.sdp});
var answer = this.newRTCSessionDescription({type:'answer', sdp:e.sdp});

this.emit('sdp', e);

this.connection.setRemoteDescription(answer)
this.connectionConfig.remoteDescriptionModifier(answer)
.then(function(answer) {
return self.connection.setRemoteDescription(answer);
})
.then(function() {
if (!self.is_confirmed) {
confirmed.call(self, 'remote', request);
Expand Down Expand Up @@ -1451,6 +1474,40 @@ RTCSession.prototype.resetLocalMedia = function() {
setLocalMediaStatus.call(this);
};

RTCSession.prototype.setLocalDescriptionFactory = function (localDescriptionFactory) {
if(localDescriptionFactory && typeof localDescriptionFactory === 'function') {
this.connectionConfig.localDescriptionFactory = function (type, constraints) {
return Promise.resolve(localDescriptionFactory(type, constraints));
};
} else {
throw new Exceptions.ConfigurationError('localDescriptionFactory', localDescriptionFactory);
}
};

RTCSession.prototype.setLocalDescriptionModifier = function (localDescriptionModifier) {
if(localDescriptionModifier && typeof localDescriptionModifier === 'function') {
this.connectionConfig.localDescriptionModifier = function (description) {
return Promise.resolve(localDescriptionModifier(description));
};
} else {
throw new Exceptions.ConfigurationError('localDescriptionModifier', localDescriptionModifier);
}
};

RTCSession.prototype.setRemoteDescriptionModifier = function (remoteDescriptionModifier) {
if(remoteDescriptionModifier && typeof remoteDescriptionModifier === 'function') {
this.connectionConfig.remoteDescriptionModifier = function (description) {
return Promise.resolve(remoteDescriptionModifier(description));
};
} else {
throw new Exceptions.ConfigurationError('remoteDescriptionModifier', remoteDescriptionModifier);
}
};

RTCSession.prototype.newRTCSessionDescription = function(sessionDescriptionInit) {
return this.connectionConfig.enable_webrtc ? new RTCSessionDescription(sessionDescriptionInit) : sessionDescriptionInit;
};


/**
* Private API.
Expand Down Expand Up @@ -1510,20 +1567,26 @@ function setACKTimer() {
function createRTCConnection(pcConfig, rtcConstraints) {
var self = this;

this.connection = new RTCPeerConnection(pcConfig, rtcConstraints);

this.connection.addEventListener('iceconnectionstatechange', function() {
var state = self.connection.iceConnectionState;

// TODO: Do more with different states.
if (state === 'failed') {
self.terminate({
cause: JsSIP_C.causes.RTP_TIMEOUT,
status_code: 408,
reason_phrase: JsSIP_C.causes.RTP_TIMEOUT
});
}
});
if(this.connectionConfig.enable_webrtc) {
this.connection = new RTCPeerConnection(pcConfig, rtcConstraints);
this.connection.addEventListener('iceconnectionstatechange', function() {
var state = self.connection.iceConnectionState;

// TODO: Do more with different states.
if (state === 'failed') {
self.terminate({
cause: JsSIP_C.causes.RTP_TIMEOUT,
status_code: 408,
reason_phrase: JsSIP_C.causes.RTP_TIMEOUT
});
}
});
} else {
var localDescriptionFactory = function(type, constraints) {
return self.connectionConfig.localDescriptionFactory.call(self, type, constraints);
};
this.connection = new PureSipConnection(localDescriptionFactory);
}
}

function createLocalDescription(type, onSuccess, onFailure, constraints) {
Expand Down Expand Up @@ -1585,7 +1648,10 @@ function createLocalDescription(type, onSuccess, onFailure, constraints) {
}
});

connection.setLocalDescription(desc)
self.connectionConfig.localDescriptionModifier(desc)
.then(function (desc) {
return connection.setLocalDescription(desc);
})
.then(function() {
if (connection.iceGatheringState === 'complete') {
self.rtcReady = true;
Expand Down Expand Up @@ -1746,11 +1812,14 @@ function receiveReinvite(request) {
}

var e = {originator:'remote', type:'offer', sdp:request.body};
var offer = new RTCSessionDescription({type:'offer', sdp:e.sdp});
var offer = this.newRTCSessionDescription({type:'offer', sdp:e.sdp});

this.emit('sdp', e);

this.connection.setRemoteDescription(offer)
this.connectionConfig.remoteDescriptionModifier(offer)
.then(function(offer) {
return self.connection.setRemoteDescription(offer);
})
.then(doAnswer)
.catch(function(error) {
request.reply(488);
Expand Down Expand Up @@ -1899,9 +1968,12 @@ function receiveUpdate(request) {
debug('emit "sdp"');
this.emit('sdp', e);

var offer = new RTCSessionDescription({type:'offer', sdp:e.sdp});
var offer = this.newRTCSessionDescription({type:'offer', sdp:e.sdp});

this.connection.setRemoteDescription(offer)
this.connectionConfig.remoteDescriptionModifier(offer)
.then(function(offer) {
return self.connection.setRemoteDescription(offer);
})
.then(function() {
if (self.remoteHold === true && hold === false) {
self.remoteHold = false;
Expand Down Expand Up @@ -2120,7 +2192,7 @@ function sendInitialRequest(mediaConstraints, rtcOfferConstraints, mediaStream)
// If at least audio or video is requested prompt getUserMedia.
} else if (mediaConstraints.audio || mediaConstraints.video) {
this.localMediaStreamLocallyGenerated = true;
navigator.mediaDevices.getUserMedia(mediaConstraints)
Promise.resolve(this.connectionConfig.enable_webrtc ? navigator.mediaDevices.getUserMedia(mediaConstraints) : null)
.then(userMediaSucceeded)
.catch(function(error)
{
Expand Down Expand Up @@ -2289,9 +2361,12 @@ function receiveInviteResponse(response) {

this.emit('sdp', e);

answer = new RTCSessionDescription({type:'answer', sdp:e.sdp});
answer = this.newRTCSessionDescription({type:'answer', sdp:e.sdp});

this.connection.setRemoteDescription(answer)
this.connectionConfig.remoteDescriptionModifier(answer)
.then(function(answer) {
return self.connection.setRemoteDescription(answer);
})
.catch(function(error) {
debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);

Expand All @@ -2318,14 +2393,17 @@ function receiveInviteResponse(response) {
debug('emit "sdp"');
this.emit('sdp', e);

answer = new RTCSessionDescription({type:'answer', sdp:e.sdp});
answer = this.newRTCSessionDescription({type:'answer', sdp:e.sdp});

Promise.resolve()
.then(function() {
// Be ready for 200 with SDP after a 180/183 with SDP. We created a SDP 'answer'
// for it, so check the current signaling state.
if (self.connection.signalingState === 'stable') {
return self.connection.createOffer()
.then(function (offer) {
return self.connectionConfig.localDescriptionModifier(offer);
})
.then(function(offer) {
return self.connection.setLocalDescription(offer);
})
Expand All @@ -2340,7 +2418,10 @@ function receiveInviteResponse(response) {
}
})
.then(function() {
self.connection.setRemoteDescription(answer)
self.connectionConfig.remoteDescriptionModifier(answer)
.then(function(answer) {
return self.connection.setRemoteDescription(answer);
})
.then(function() {
// Handle Session Timers.
handleSessionTimersInIncomingResponse.call(self, response);
Expand Down Expand Up @@ -2454,9 +2535,12 @@ function sendReinvite(options) {
debug('emit "sdp"');
self.emit('sdp', e);

var answer = new RTCSessionDescription({type:'answer', sdp:e.sdp});
var answer = self.newRTCSessionDescription({type:'answer', sdp:e.sdp});

self.connection.setRemoteDescription(answer)
self.connectionConfig.remoteDescriptionModifier(answer)
.then(function(answer) {
return self.connection.setRemoteDescription(answer);
})
.then(function() {
if (eventHandlers.succeeded) {
eventHandlers.succeeded(response);
Expand Down Expand Up @@ -2595,9 +2679,12 @@ function sendUpdate(options) {
debug('emit "sdp"');
self.emit('sdp', e);

var answer = new RTCSessionDescription({type:'answer', sdp:e.sdp});
var answer = this.newRTCSessionDescription({type:'answer', sdp:e.sdp});

self.connection.setRemoteDescription(answer)
self.connectionConfig.remoteDescriptionModifier(answer)
.then(function(answer) {
return self.connection.setRemoteDescription(answer);
})
.then(function() {
if (eventHandlers.succeeded) {
eventHandlers.succeeded(response);
Expand Down
Loading

0 comments on commit dcaa09f

Please sign in to comment.