SIP.js
SIP.js copied to clipboard
Hold not working on Firefox
Describe the bug I am trying to migrate to version 0.17.0
When I try to place the call on "hold" in Firefox, although neither party can hear the other, the second party does not hear any hold music and the status of the call is not set to hold. After some investigation this is what I have found to be the issue: It seems like the sdp is modified AFTER the hold modifier, and the "a=sendrecv" is added back into the sdp (in addition to the "a=sendonly" which is already there)
Logs https://gist.github.com/m-heinemann/b32ff6af8c281e4349b6b2720c3a8dc3
Steps to Reproduce
- Clone the SIP.js repo
- Run
npm install
andnpm run build-demo
- Go to file:///{localPath}/SIP.js/demo/demo-1.html on a Firefox browser
- Click Connect and Place Call. Open the dev tools and clear the console.
- Check the "Hold" checkbox. Now observe the sdp that is printed in the console. You will see that "a=sendrecv" appears in the sdp that is sent from the server to the client, in addition to "a=sendonly" which appears further down.
Expected behavior Placing the call on "hold" should play music for the second party and should set the call status to on hold
Observed behavior Neither party could hear audio from the other party, BUT the second party did not hear music and the call status was not set to hold
Environment Information
- Node.js
- Firefox version 78.0.2
I've reproduced this issue using the demo in 0.17.1 . Working on fixing it. Thanks.
Great, thanks so much for your quick response. Please keep me posted about any updates.
Has there been any progress yet?
why can't I update the 0.17.1 version in npm? the latest is 0.17.0.
https://www.npmjs.com/package/sip.js
0.17.1 is available via NPM, and has been for 16 days.
@john-e-riordan Do you have an ETA for this bug fix? Migrating our code to version 17 is blocked by this issue.
thanks for your working, @james-criscuolo I see the npmjs.com, but when I install the 0.17.1, strangely it fails.
npm info sip.js
should tell you where you are trying to pull from and why it isn't grabbing the latest. Please go to our google group with further questions, as this issue is for a different topic.
@m-heinemann - The way that hold is currently working is legal per the SDP standard. What is happening is that we are changing the track level attribute to sendonly
but the session level attribute is remaining sendrecv
. We are going to adjust the modifier so that both all attributes are set accordingly when a call is placed on hold/unhold. We hope to have this fixed soon.
@egreenmachine Thank you for the update
@egreenmachine Is there an approximate ETA for this?
I do not think this is a bug having to do with the SDP...
The first "a=sendrecv" appears at the session-level of the SDP and the second "a=sendonly" is at the media-level.
From https://tools.ietf.org/html/rfc4566#section-5.13...
Attributes are the primary means for extending SDP. Attributes may be defined to be used as "session-level" attributes, "media-level" attributes, or both.
A media description may have any number of attributes ("a=" fields) that are media specific. These are referred to as "media-level" attributes and add information about the media stream. Attribute fields can also be added before the first media field; these "session-level" attributes convey additional information that applies to the conference as a whole rather than to individual media.
From https://lists.cs.columbia.edu/pipermail/sip-implementors/2015-May/030141.html...
Hi Team,
I've a small doubt. I have a working call where A party is talking to B party. B party putts the call on hold, however I see "Session Attribute" with a value "SendOnly". Mostly I've seen it coming in Media Attribute.
"Session Attribute (a): sendonly" Instead of "Media Attribute (a): SendOnly".
What's the difference?
When used at session level this attribute serves as a default for each media section. So this means sendonly for all the media in the call, except for media sections that explicitly override it.
In the case where there is only one media section (audio) it means exactly the same thing if it only appears at session level as it does if it only appears at media level.
So the SDP being generated by Firefox is correct and should not cause any issues.
I'm now looking at SimpleUser
to check if there is an issue with the way the hold modifier is being applied that might cause hold to music not to be sent by a user agent who placed the call on hold (a user agent capable of sending moh) or to not be received by the remote end.
There is an issue with hold in SimpleUser
. The hold modifier is being incorrectly to the SDP answer from the peer resulting in the received SDP ...
v=0
o=F 1597303635 1597303637 IN IP4 199.7.173.157
s=F
c=IN IP4 199.7.173.74
t=0 0
m=audio 55758 UDP/TLS/RTP/SAVPF 9 101
a=silenceSupp:off - - - -
a=mid:0
a=rtpmap:9 G722/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=recvonly
a=rtcp:55758
a=rtcp-mux
a=setup:active
a=fingerprint:sha-1 6D:02:EE:40:96:11:22:FE:3A:55:76:83:A2:AA:1F:65:4E:CF:A0:01
a=ptime:20
a=ice-ufrag:tcg2UzcY
a=ice-pwd:fIwn1GZVikaagVfYTqYVOP00h7
a=candidate:6JCbJYuYWwaC2UnX 1 UDP 2130706431 199.7.173.74 55758 typ host
... being converted to ...
v=0
o=F 1597303635 1597303637 IN IP4 199.7.173.157
s=F
c=IN IP4 199.7.173.74
t=0 0
m=audio 55758 UDP/TLS/RTP/SAVPF 9 101
a=silenceSupp:off - - - -
a=mid:0
a=rtpmap:9 G722/8000
a=rtpmap:101 telephone-event/8000
a=fmtp:101 0-16
a=inactive
a=rtcp:55758
a=rtcp-mux
a=setup:active
a=fingerprint:sha-1 6D:02:EE:40:96:11:22:FE:3A:55:76:83:A2:AA:1F:65:4E:CF:A0:01
a=ptime:20
a=ice-ufrag:tcg2UzcY
a=ice-pwd:fIwn1GZVikaagVfYTqYVOP00h7
a=candidate:6JCbJYuYWwaC2UnX 1 UDP 2130706431 199.7.173.74 55758 typ host
The a=inactive would cause the user agent which initiated the hold to not send music on hold (or any other media).
Putting a pull request together to fix this.
@m-heinemann Can you please retest your use case using pull request #844 - thanks.
@john-e-riordan Thank you so much for your response. I will retest using pull request #844 and let you know what happens.
@john-e-riordan Unfortunately the pull request did not solve my issue.
@m-heinemann
Are you using SimpleUser
?
In your original gist you show the SDP answer from Freeswitch after the modifier has been applied on like 320: (https://gist.github.com/m-heinemann/b32ff6af8c281e4349b6b2720c3a8dc3#file-sip-js-console-txt-L320)
On line 344 (https://gist.github.com/m-heinemann/b32ff6af8c281e4349b6b2720c3a8dc3#file-sip-js-console-txt-L344), I see a=inactive
which I believe would cause the problem your are reporting. It should be a=recvonly
. Is it still showing up as a=inactive
?
The pull request should fix this for SimpleUser
. I will double check that it is fixed in SimpleUser
. Could check your original example with Freeswitch in the gist?
If you are not using SimpleUser
, please look at how I fixed it in SimpleUser
and patch your code.
Thanks.
@john-e-riordan
I am not using SimpleUser
, so I patched my code the same way you did in the pull request, but although the a=inactive
is not there anymore, the hold functionality is still not working. In fact it is now not working at all and the sound is transmitted both ways.
I am attaching the logs I get when I try to place the call on hold: https://gist.github.com/m-heinemann/f5acead587783baa096eb64d18aa4444
I don't see anything wrong int he gist. The offer in the INVITE from sip.js has a=sendonly
and the answer in the 200 Ok from Freeswitch has a=recvonly
. I would expect that the sip.js side could be sending media if it was coded up to do so. I would expect Freeswitch to be sending nothing.
I looked into this more and I think the issue is related to this: https://groups.google.com/g/discuss-webrtc/c/gsw3OEAwNKo You can specifically see this reply from Taylor Brandstetter:
It does seem to be a Firefox bug. In summary, what's happening is:
1. Firefox offers "actpass"
2. Chrome answers "active". This establishes Chrome as the DTLS client, and Firefox as the DTLS server.
3. Chrome re-offers, with "actpass" (because that's what the spec says, or at least how we interpreted it for a long time)
4. Firefox offers with "active", but with the same DTLS fingerprint. Chrome doesn't like this; it's interpreted as an attempt to change the DTLS role from "server" to "client" without creating a new association.
To work around this, you could:
1. Detect when this occurs and change the DTLS role from "active" to "passive" before passing the SDP into setRemoteDescription.
2. Ensure that the offer/answer direction remains consistent. Meaning, if Firefox generates the initial offer, it generates all subsequent offers as well. I'm not sure how common this practice is, but it probably would avoid a lot of interop bugs.
If you look at the gist you will see that although the offer in the INVITE has a=setup:actpass
, the answer in the 200 OK has a=setup:active
Do you think this is something you can solve from your end?
Going to first try to get the issue reproduced. And then yes, as outlined, it does seem like something that could be addressed in the session description handler as a work around.
@john-e-riordan Were you able to reproduce the issue?
I believe #898 fixes this issue. Sorry for the delay. Can you retest and confirm?
@john-e-riordan I've tested hold in Chrome 88.0.4324.190 - works fine, in Firefox 84.0.2 - throws InvalidAccessError (SIP.js v0.19.0).
Fri Mar 12 2021 18:36:06 GMT+0200 (Eastern European Standard Time) | sip.SessionDescriptionHandler | SessionDescriptionHandler.setDescription failed - InvalidAccessError: Answer tried to set send when offer did not set recv
Fri Mar 12 2021 18:36:06 GMT+0200 (Eastern European Standard Time) | sip.Inviter | Session.setAnswer: SDH setDescription rejected...
Fri Mar 12 2021 18:36:06 GMT+0200 (Eastern European Standard Time) | sip.Inviter | Answer tried to set send when offer did not set recv
Fri Mar 12 2021 18:36:06 GMT+0200 (Eastern European Standard Time) | sip.Inviter | Failed to handle answer in 2xx response to re-INVITE
Fri Mar 12 2021 18:36:06 GMT+0200 (Eastern European Standard Time) | sip.Inviter | Answer tried to set send when offer did not set recv
Code used to put on hold:
session.invite({
sessionDescriptionHandlerOptions: {
hold: true
}
});
Also tried as described in the documentation and with the SimpleUser - same result.
I also get the same InvalidAccessError: Answer tried to set send when offer did not set recv
error when attempting an .invite(...) on a live session in FF v94, using v0.20.0 of SIP.js using the same approach that eternal365 did.
It's a bit hacky, but I found a solution that at least seems to allow the hold functionality to work inside of Firefox as-is with SIP.js v0.20.0. Putting it out there with the hope that maybe it helps someone else as well.
sip.userAgent = new SIP.UserAgent({ ... });
/*
* The following section is a workaround for an issue with placing a call on hold, when using the Firefox browser.
* For whatever reason, when a SIP invite to place a call on hold is sent by Firefox, it includes an extra session
* attribute asking for the SIP PBX to set the call to be both a=sendrecv, and a=sendonly. This confuses the SIP PBX and results
* in the SIP call being dropped. However, this does NOT seem to apply to unholding of the call.
*
* The following conditions must be true in order for the replacement to occur:
* - The originating browser must be mozilla based / Firefox.
* - The SIP message must be an INVITE
* - The SIP message must include the a=sendonly attribute to indicate that this IS a hold request.
* If any of these conditions aren't met, we simply forward the SIP message as-is.
*
* For more information on the bug, see https://github.com/onsip/SIP.js/issues/840
*/
var transport = sip.userAgent._transport;
transport.origSend = transport.send;
transport.send = function (s) {
var cSeqInviteArr = s.match('CSeq: (\\d+) INVITE');
if(s.search('o=mozilla') > -1 && cSeqInviteArr && s.search('a=sendonly\r\n') > -1){
return transport.origSend(s.replace(/a=sendrecv\r\n/g, ''));
}
return transport.origSend(s);
};
Been a while...
I failed to reproduce today with Chrome 105 and Firefox 105 putting each other on hold in all permutations.
Is this still an issue? If so how can I reproduce?
Thanks
I am currently experiencing the same issues as stated above. I am not using simple user, but I am implementing my own setHold function following the one in simpleUser. Sip.js version 0.20.1
It works as expected on Google Chrome. However when I try Firefox (Version 105.0.3) I do not get the hold music on the other parties end.
I am holding the call from web browser side, and my other device is a mobile phone.
Let me know what I can do for you to help us both figure this out.
@jhspyhard Thank you for the hack, this is working for me. Perhaps we can get the mozilla check in the hold option/modifier.
Earlier this week I did try integrating SIPjs v0.20.1 into my code base and pull out my workaround to see if it made a difference, however the a=sendonly
and a=sendrecv
bug still did manifest for me when using Firefox v105. I haven't had time yet to pull a working example out of my code though. I will try and find some time to make a working example here in the next week or so if someone else doesn't do it first.