Commit db132dd for jssip.net

commit db132ddcf6f05bea4fc10388c0a6bff285ab17aa
Author: Filippo Giacchè <filippo.giacche@gmail.com>
Date:   Fri Dec 19 13:12:57 2025 +0100

    Allow sending DTMF during early dialog #689 (#925)

diff --git a/lib/Dialog.js b/lib/Dialog.js
index 18d0dd7..baa5ed6 100644
--- a/lib/Dialog.js
+++ b/lib/Dialog.js
@@ -83,7 +83,7 @@ module.exports = class Dialog
       this._remote_uri = message.parseHeader('to').uri;
       this._remote_target = contact.uri;
       this._route_set = message.getHeaders('record-route').reverse();
-      this._ack_seqnum = null;
+      this._ack_seqnum = this._local_seqnum;

     }

@@ -202,8 +202,9 @@ module.exports = class Dialog

     if (!this._local_seqnum) { this._local_seqnum = Math.floor(Math.random() * 10000); }

+    // CANCEL and ACK must use the same sequence number as the INVITE.
     const cseq = (method === JsSIP_C.CANCEL || method === JsSIP_C.ACK) ?
-      this._local_seqnum :
+      this._ack_seqnum :
       this._local_seqnum += 1;

     const request = new SIPMessage.OutgoingRequest(
diff --git a/lib/RTCSession.js b/lib/RTCSession.js
index 617ef61..7f623c9 100644
--- a/lib/RTCSession.js
+++ b/lib/RTCSession.js
@@ -1420,7 +1420,23 @@ module.exports = class RTCSession extends EventEmitter
   {
     logger.debug('sendRequest()');

-    return this._dialog.sendRequest(method, options);
+    if (this._dialog)
+    {
+      return this._dialog.sendRequest(method, options);
+    }
+    else
+    {
+      const dialogsArray = Object.values(this._earlyDialogs);
+
+      if (dialogsArray.length > 0)
+      {
+        return dialogsArray[0].sendRequest(method, options);
+      }
+
+      logger.warn('No valid early dialog found to send request');
+
+      return;
+    }
   }

   /**
diff --git a/lib/RTCSession/DTMF.js b/lib/RTCSession/DTMF.js
index e86bb93..b296bae 100644
--- a/lib/RTCSession/DTMF.js
+++ b/lib/RTCSession/DTMF.js
@@ -47,8 +47,11 @@ 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);
     }