JsSIP icon indicating copy to clipboard operation
JsSIP copied to clipboard

JsSIP 3.7.1 doesn't allow sending DTMF during EarlyMedia

Open divisumma18 opened this issue 3 years ago • 9 comments

JsSIP 3.7.1 seems to have the same issue described here: https://twinklephone.yahoogroups.narkive.com/aXB3Vk5Q/twinkle-doesn-t-allow-sending-dtmf-during-earlymedia

TLDR: Sending a DTMF tone with JsSIP.RTCSession.sendDTMF() after a "183 Session Progress" and before a "SIP/2.0 200 OK" should be possibile, but JsSIP raises an "INVALID_STATE_ERROR: Invalid status: 2" error instead.

divisumma18 avatar Feb 26 '21 12:02 divisumma18

Wow, your pointing a 13 year old forum content.

Can you try this patch:

diff --git a/lib/RTCSession.js b/lib/RTCSession.js
index 7003c25..dcb41c3 100644
--- a/lib/RTCSession.js
+++ b/lib/RTCSession.js
@@ -962,7 +962,11 @@ module.exports = class RTCSession extends EventEmitter
     }

     // Check Session Status.
-    if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK)
+    if (
+      this._status !== C.STATUS_CONFIRMED &&
+      this._status !== C.STATUS_WAITING_FOR_ACK &&
+      this._status !== C.STATUS_1XX_RECEIVED
+    )
     {
       throw new Exceptions.InvalidStateError(this._status);
     }

Please also try what would happen if you call sendDtmfs() after receiving a 100 but before receiving 18X.

jmillan avatar Feb 26 '21 12:02 jmillan

Wow, your pointing a 13 year old forum content.

I thought an old post from Iñaki would still be pretty convincing! :wink:

Can you try this patch:

I tried that and similarly patched DTMF.js

diff --git a/lib/RTCSession/DTMF.js b/lib/RTCSession/DTMF.js
index d27b4ac..5665c40 100644
--- a/lib/RTCSession/DTMF.js
+++ b/lib/RTCSession/DTMF.js
@@ -48,9 +48,9 @@ module.exports = class DTMF extends EventEmitter
     this._direction = 'outgoing';
 
     // Check RTCSession Status.
-    if (this._session.status !== this._session.C.STATUS_CONFIRMED &&
-      this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK)
-    {
+    if (
+      this._session.status !== this._session.C.STATUS_CONFIRMED && 
+      this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK &&
+      this._session.status !== this._session.C.STATUS_1XX_RECEIVED
+      ) {
       throw new Exceptions.InvalidStateError(this._session.status);
     }

but apparently there's still something wrong:

jssip-senddtmf-err

divisumma18 avatar Feb 26 '21 15:02 divisumma18

but apparently there's still something wrong:

You don't specify whether you were trying to send the DTMF after receiving 100 or 1XX. I'm certain it won't work before 1XX, not 100% sure if it would after 1XX.

jmillan avatar Feb 26 '21 15:02 jmillan

Sorry, you're right, but the error looks exactly the same to me, in both conditions.

This is the console log of a sendDTMF() call just after a SIP 100 Trying:

JsSIP:Transport received text message:
SIP/2.0 100 Trying
Via: SIP/2.0/WSS iifbbidgggba.invalid;branch=z9hG4bK3721326;received=109.106.30.130;rport=39900
From: ...
To: ...
Call-ID: ad7iof3u1dvpk3gfd4ok
CSeq: 2470 INVITE
User-Agent: FreeSWITCH-mod_sofia/1.6.20+git~20180123T214909Z~987c9b9a2a~64bit
Content-Length: 0

 +45ms
JsSIP:RTCSession receiveInviteResponse() +57ms
JsSIP:RTCSession sendDTMF() | tones: 1 +174ms
JsSIP:RTCSession newDTMF() +3ms
JsSIP:RTCSession sendRequest() +1ms
RTCSession.js:1266 Uncaught (in promise) TypeError: Cannot read property 'sendRequest' of null
    at n.value (RTCSession.js:1266)
    at n.value (DTMF.js:116)
    at n.s (RTCSession.js:955)
    at n.value (RTCSession.js:929)
    ...

And this is the log just after a 183 Session progress:

JsSIP:Transport received text message:
SIP/2.0 183 Session Progress
Via: SIP/2.0/WSS dajefeiaclea.invalid;branch=z9hG4bK4945751;received=109.106.30.130;rport=11172
From: ...
To: ...
Call-ID: v6d4ftm2jjooa7dda7g9
CSeq: 4340 INVITE

[...]

JsSIP:RTCSession receiveInviteResponse() +805ms
JsSIP:Dialog new UAC dialog created with status EARLY +0ms
JsSIP:RTCSession emit "sdp" +2ms
JsSIP:RTCSession session progress +5ms
JsSIP:RTCSession emit "progress" +0ms
JsSIP:RTCSession sendDTMF() | tones: 1 +6ms
JsSIP:RTCSession newDTMF() +1ms
JsSIP:RTCSession sendRequest() +1ms
RTCSession.js:1266 Uncaught (in promise) TypeError: Cannot read property 'sendRequest' of null
    at n.value (RTCSession.js:1266)
    at n.value (DTMF.js:116)
    at n.s (RTCSession.js:955)
    at n.value (RTCSession.js:929)

divisumma18 avatar Feb 26 '21 16:02 divisumma18

Just a note that this also exists in 3.9.1, and also in sendInfo. A similar patch also doesn't fix that one; _dialog is null when it goes to do the actual send.

mattdimeo avatar Jun 23 '22 20:06 mattdimeo

Does the 183 response has a Contact header?

ibc avatar Jun 23 '22 20:06 ibc

The 183 in an above comment doesn't have any Contact header so indeed there is no early dialog established yet and hence JsSIP cannot send in-dialog requests to the remote (because there is no remote URI yet).

ibc avatar Jun 23 '22 20:06 ibc

In my case, it looks like this before I try to send dtmf:

JsSIP:Transport received text message:

SIP/2.0 183 Session Progress Via: SIP/2.0/WSS fe9k20u30hek.invalid;rport=52114;received=127.0.0.1;branch=z9hG4bK9015859 Call-ID: ai63m0pjh4i7midd413e From: sip:[email protected];tag=dp1k5cp7tp To: sip:[email protected];tag=37495e77-f108-466d-af9a-d7b68f608615 CSeq: 2145 INVITE Server: FPBX-15.0.23.12(16.17.0) Contact: sip:127.0.0.1:8088;transport=ws Allow: OPTIONS, INVITE, ACK, BYE, CANCEL, UPDATE, PRACK, REGISTER, SUBSCRIBE, NOTIFY, PUBLISH, MESSAGE, REFER Content-Type: application/sdp Content-Length: 905

So in my case, yes, there's a contact header.

mattdimeo avatar Jun 23 '22 20:06 mattdimeo

Wow, your pointing a 13 year old forum content.

Can you try this patch:

diff --git a/lib/RTCSession.js b/lib/RTCSession.js
index 7003c25..dcb41c3 100644
--- a/lib/RTCSession.js
+++ b/lib/RTCSession.js
@@ -962,7 +962,11 @@ module.exports = class RTCSession extends EventEmitter
     }

     // Check Session Status.
-    if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK)
+    if (
+      this._status !== C.STATUS_CONFIRMED &&
+      this._status !== C.STATUS_WAITING_FOR_ACK &&
+      this._status !== C.STATUS_1XX_RECEIVED
+    )
     {
       throw new Exceptions.InvalidStateError(this._status);
     }

Please also try what would happen if you call sendDtmfs() after receiving a 100 but before receiving 18X.

this need to change to sip server of frontend developer ?

I tried this but did not work . Here is how I send DTMF

async DTMFCall(tone) { try { var options = { 'duration': 160, 'interToneGap': 500, 'transportType': 'INFO'

  };
  if (this.currentCallSession) {
    this.currentCallSession.sendDTMF(tone,options);

    console.log('DMTF call: ');
  }
} catch (err) {
  console.error('DMTF call: error ', err);
}

}

Kumargaurav11998 avatar Dec 22 '23 12:12 Kumargaurav11998