Is SDP renegotiation possible?

725 views
Skip to first unread message

Petar Velkov

unread,
Aug 3, 2015, 3:36:27 AM8/3/15
to SIP.js
Hello,

I'm trying to implement SDP renegotiation with the goal of being able to start/stop video streams at any time during calls. In the SIP.js API I don't see any method which would allow me to do that and send UPDATE or re-INVITE.

Do I miss something?

Cheers,
Petar

Will Mitchell

unread,
Aug 3, 2015, 3:49:20 PM8/3/15
to SIP.js
Hi Petar,

For a long time, SDP renegotiation was impossible between browsers.  Only in the latest versions have we started putting some of this functionality in.  Specifically, check out version 0.7.1.  The Session object has a function called 'sendReinvite', as well as the ability to receive and process a reinvite.  We use it internally for hold/unhold.  When using it yourself, you can specify a `mangle` argument which is passed the SDP to modify as you wish.

That said, this is still a very new area, and there may be bugs.  Depending on what you are trying to change in the SDP, your results may vary.  Specifically for adding and removing audio/video streams...I am not sure that it will work right now.  Your best bet may be to always start with both audio and video and use hold/unhold and mute/unmute to specify which to transmit at any given time.

Note that in 0.7.0 and earlier, hold and unhold used what we call 'fakeHold'.  That is, they just disable the tracks locally without actually changing the SDP.  This may also get you what you are looking for.

Thanks,

-Will

Petar Velkov

unread,
Aug 4, 2015, 9:59:35 AM8/4/15
to SIP.js
Thanks Will!

I was already looking at the 'sendReinvite' function (with 0.7.0, just updated to 0.7.1, the function itself hasn't changed). I did some tests and it seems like I'm going to make it work. I would avoid workarounds with (un)holding and (un)muting media because otherwise I might have a lot to clean up after renegotiation is properly implemented in the browsers and in SIP.js.

Thanks again!

Petar

kyled...@gmail.com

unread,
Aug 6, 2015, 12:02:00 PM8/6/15
to SIP.js
While waiting for browsers to actually support this, I patched the library to close the peer connection and start a new one when a re-invite is sent/received and media has changed. It's working surprisingly well and only creates annoying permissions dialogs if you aren't using HTTPS, which you should be using in production anyways.

(all of this code is from 0.7.0, I haven't seen what 0.7.1 changed)

First, you'll likely want to let the app know a re-invite was received so it can create/destroy video elements. Inside receiveRequest add an event emission here:

case SIP.C.INVITE:
if(this.status === C.STATUS_CONFIRMED) {
this.emit('reinvite', request); //****alert app that a reinvite has been received
this.logger.log('re-INVITE received');
// Switch these two lines to try re-INVITEs:
this.receiveReinvite(request);
// request.reply(488, null, ['Warning: 399 sipjs "Cannot update media description"']);
}

Next, my receiveReinvite function has this added (text above and below provided for context):

if (request.getHeader('Content-Type') !== 'application/sdp') {
this.logger.warn('invalid Content-Type');
request.reply(415);
return;
}

//******close peerconnection and start a new one if media has changed
if( request.getHeader('Subject') === 'Media change'){

this.mediaHandler.close();
this.mediaHint.constraints.video = /(m=video)/.test(request.body);
this.mediaHandler = this.mediaHandlerFactory(this, {
RTCConstraints: {"optional": [{'DtlsSrtpKeyAgreement': 'true'}]}
});
}
//************

this.mediaHandler.setDescription(request.body)
-------
Lastly, my sendReinvite has this added:

this.receiveResponse = this.receiveReinviteResponse;

//*****check if media has changed on call
if( options.video !== this.mediaHint.constraints.video ){
extraHeaders.push('Subject: Media change');
this.mediaHandler.close();

this.mediaHint.constraints.video = options.video;

this.mediaHandler = this.mediaHandlerFactory(this, {
RTCConstraints: {"optional": [{'DtlsSrtpKeyAgreement': 'true'}]}
});

}
//*******

//REVISIT
this.mediaHandler.getDescription(self.mediaHint)
--------

That said, I'd love to know if there's a better way of doing this and if you (or anyone) has been successful in getting actual renegotiations working.


Best,
Kyle

Mateus Dalepiane

unread,
Aug 7, 2015, 10:13:17 PM8/7/15
to SIP.js
Interesting approach!
Does it cause an interruption on the audio while reconnecting?
I would like to hear more about this.

kyled...@gmail.com

unread,
Aug 7, 2015, 11:02:29 PM8/7/15
to SIP.js

Yeah it cuts out for a few seconds, so that's probably the biggest downside.

I actually got the idea from this old article https://hacks.mozilla.org/2013/09/webrtc-update-and-workarounds/

Petar Velkov

unread,
Aug 21, 2015, 9:48:26 AM8/21/15
to sip...@googlegroups.com
Hi all,

I'm trying to implement the patch from Kyle with closing and reopening the peerConnection (working with 0.7.1).

In the browser console, the following happens:

session.getLocalStreams() and session.getRemoteStreams() are both failing because peerConnection has signalingState = 'closed';
session.mediaHandler.peerConnection has signalingState = 'stable'.

If logging this.peerConnection in getRemoteStreams() function, it logs the old peerConnection which really has a signalingState = 'closed' as it should be.

...so I'm a bit (or a lot) confused about what happens. Any ideas?

Petar
 


--
You received this message because you are subscribed to the Google Groups "SIP.js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to sip_js+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/sip_js/dddba485-e988-4555-ad4f-5447483fe7d7%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Petar Velkov

unread,
Aug 24, 2015, 7:44:03 AM8/24/15
to SIP.js
Okay, I made it work.

The only think I had to do is re-bind the new MediaHandler's getRemoteStreams() and getLocalStreams() to the session:

 this.getRemoteStreams = this.mediaHandler.getRemoteStreams.bind(this.mediaHandler);
 this.getLocalStreams = this.mediaHandler.getLocalStreams.bind(this.mediaHandler);
 ....both in sendReinvite and receiveReinvite.

Thanks, Kyle :)

Cheers,
Petar
Reply all
Reply to author
Forward
0 new messages