drachtio / drachtio-server

A SIP call processing server that can be controlled via nodejs applications
https://drachtio.org
MIT License
233 stars 90 forks source link

No mechanism to allow sending of NOTIFY in early dialog #316

Open tinpotnick opened 8 months ago

tinpotnick commented 8 months ago

According to RFC 3261

Dialogs are created through the generation of non-failure responses to requests with specific methods. Within this specification, only 2xx and 101-199 responses with a To tag, where the request was INVITE, will establish a dialog. A dialog established by a non-final response to a request is in the "early" state and it is called an early dialog.

There are several applications where this is needed - after spending some time researching this, Broadsoft documents it for use with line seizing.

I need it for auto-answer on Poly phones (amongst many other phones). Most phones simply answer on the anser-after param, whilst Poly documents that auto-answer is a mechanism support on VVX phones, Edge phones don't appear to support this (I am currently speaking with people at Poly to clarify this further).

Poly Edge (and probably others) phones require

Server --------------- Poly Edge
INVITE -------------->
            <-------------- 100 trying
            <-------------- 180 Ringing (early dialog - contains To tag)
NOTIFY (event Talk) ------------->
            <-------------- 200 (NOTIFY)
            <-------------- 200 (INVITE)
Established

In Freeswitch, this is supported. In mod/endpoints/mod_sofia/sofia.c:7507 nua_notify is called to create an implicit subscription, which is immediately terminated carrying the talk event.

With Drachtio, createUAC returns a dialog only on 200. In some situations, communicating in the early dialog is required, as outlined above.

Within cbProvisional, we can pick up on a 180 or 183 with a To tag, but we have no mechanism to send out further messages as part of that dialog. I have tried

    const incseq = res.getParsedHeader( "CSeq" )

    const opts = {
      "method": "NOTIFY",
      "headers": {
        "Event": "talk",
        "Subscription-State": "terminated;reason=noresource",
        "Allow-Events": "talk, hold, conference, presence, as-feature-event, dialog, line-seize, call-info, sla, include-session-description, presence.winfo, message-summary, refer",
        "Content-Length": "0",
        "CSeq": ( incseq.seq + 1 ) + " NOTIFY",
        "Call-ID": res.getParsedHeader( "call-id" ),
        "To": res.get( "to" ),
        "From": res.get( "from" ),
      }
    }

    callmanager.options.srf.request( this.options.contact + this.options.contactparams, opts, ( err, req ) => {
      if( err ) {
        console.error( err )
        return
      }

      // req is the SIP request that went out over the wire
      req.on( "response", (/*res*/) => {
        //console.log(`received ${res.status} response to our OPTIONS request`)
      } )
    } )

This NOTIFY does make it to the wire and works with regards to auto-answer. But the problem with this is once the dialog is fully established, the cseq in the dialog is now wrong - Drachtio and the phone are out of sequence. Any further message Drachtio sends to the phone (i.e. BYE) is rejected as the cseq is now out of order.

We need another mechanism that either this functionality is built into Drachtio, or there are mechanisms to send messages as part of an early dialog within the Node application.