drachtio-srf

Srf

Applications create an instance of Srf in order to create and manage SIP Dialogs and SIP transactions. An application may have one or more Srf instances, although for most cases a single instance is sufficient.

Constructor

new Srf()

Creates an Srf instance. No arguments are supplied.

Source:

connect(opts)

make an inbound connection to a drachtio server

Parameters:
Name Type Description
opts Object

connection options

Properties
Name Type Default Description
host string <optional> 'localhost'

address drachtio server is listening on for client connections

port Number <optional> 9022

address drachtio server is listening on for client connections

secret String

shared secret used to authenticate connections

Example
const Srf = require('drachtio-srf');
const srf = new Srf();

srf.connect({host: '127.0.0.1', port: 9022, secret: 'cymru'});
srf.on('connect', (hostport) => {
  console.log(`connected to drachtio server offering sip endpoints: ${hostport}`);
})
.on('error', (err) => {
  console.error(`error connecting: ${err}`);
});

srf.invite((req, res) => {..});
Source:

listen(opts)

listen for outbound connections from a drachtio server

Parameters:
Name Type Description
opts Object

listen options

Properties
Name Type Description
port number

address drachtio server is listening on for client connections

secret string

shared secret used to authenticate connections

Example
const Srf = require('drachtio-srf');
const srf = new Srf();

srf.listen({port: 9023, secret: 'cymru'});

srf.invite((req, res) => {..});
Source:

createUAS(req, res, opts, callbackopt) → {Srf|Promise}

create a SIP dialog, acting as a UAS (user agent server); i.e. respond to an incoming SIP INVITE with a 200 OK (or to a SUBSCRIBE request with a 202 Accepted).

Note that the Dialog is generated (i.e. the callback invoked / the Promise resolved) at the moment that the 200 OK is sent back towards the requestor, not when the ACK is subsequently received.

Parameters:
Name Type Description
req Object

the incoming sip request object

res Object

the sip response object

opts Object

configuration options

Properties
Name Type Description
localSdp string

the local session description protocol to include in the SIP response

headers Object <optional>

SIP headers to include on the SIP response to the INVITE

callback function <optional>

if provided, callback with signature (err, dialog)

Returns:

if a callback is supplied, a reference to the Srf instance.
If no callback is supplied, then a Promise that is resolved with the sip dialog that is created.

Type
Srf | Promise
Examples

returning a Promise

const Srf = require('drachtio-srf');
const srf = new Srf();

srf.invite((req, res) => {
  const mySdp; // populated somehow with SDP we want to answer in 200 OK
  srf.createUas(req, res, {localSdp: mySdp})
    .then((uas) => {
      console.log(`dialog established, remote uri is ${uas.remote.uri}`);
      uas.on('destroy', () => {
        console.log('caller hung up');
      });
    })
    .catch((err) => {
      console.log(`Error establishing dialog: ${err}`);
    });
});

using callback

const Srf = require('drachtio-srf');
const srf = new Srf();

srf.invite((req, res) => {
  const mySdp; // populated somehow with SDP we want to offer in 200 OK
  srf.createUas(req, res, {localSdp: mySdp},
    (err, uas) => {
      if (err) {
        return console.log(`Error establishing dialog: ${err}`);
      }
      console.log(`dialog established, local tag is ${uas.sip.localTag}`);
      uas.on('destroy', () => {
        console.log('caller hung up');
      });
    });
});

specifying standard or custom headers

srf.createUas(req, res, {
    localSdp: mySdp,
    headers: {
      'User-Agent': 'drachtio/iechyd-da',
      'X-Linked-UUID': '1e2587c'
    }
  }).then((uas) => { ..});
Source:

createUAC(uri, opts, progressCallbacksopt, callbackopt) → {Srf|Promise}

create a SIP dialog, acting as a UAC (user agent client)

Parameters:
Name Type Description
uri string

request uri to send to

opts Object

configuration options

Properties
Name Type Description
headers Object <optional>

SIP headers to include on the SIP INVITE request

localSdp string

the local session description protocol to include in the SIP INVITE request

progressCallbacks Object <optional>

callbacks providing call progress notification

Properties
Name Type Description
cbRequest function <optional>

callback that provides request sent over the wire, with signature (req)

cbProvisional function <optional>

callback that provides a provisional response with signature (provisionalRes)

callback function <optional>

if provided, callback with signature (err, dialog)

Returns:

if a callback is supplied, a reference to the Srf instance.
If no callback is supplied, then a Promise that is resolved with the sip dialog that is created.

Type
Srf | Promise
Examples

returning a Promise

const Srf = require('drachtio-srf');
const srf = new Srf();

const mySdp; // populated somehow with SDP we want to offer
srf.createUac('sip:1234@10.10.100.1', {localSdp: mySdp})
  .then((uac) => {
    console.log(`dialog established, call-id is ${uac.sip.callId}`);
    uac.on('destroy', () => {
      console.log('called party hung up');
    });
  })
  .catch((err) => {
    console.log(`INVITE rejected with status: ${err.status}`);
  });
});

Using a callback

const Srf = require('drachtio-srf');
const srf = new Srf();

const mySdp; // populated somehow with SDP we want to offer
srf.createUac('sip:1234@10.10.100.1', {localSdp: mySdp},
   (err, uac) => {
     if (err) {
       return console.log(`INVITE rejected with status: ${err.status}`);
     }
    uac.on('destroy', () => {
      console.log('called party hung up');
    });
  });

Canceling a request by using a progress callback

const Srf = require('drachtio-srf');
const srf = new Srf();

const mySdp; // populated somehow with SDP we want to offer
let inviteSent;
srf.createUac('sip:1234@10.10.100.1', {localSdp: mySdp},
  {
    cbRequest: (reqSent) => { inviteSent = req; }
  })
  .then((uac) => {
    // unexpected, in this case
    console.log('dialog established before we could cancel');
  })
  .catch((err) => {
    assert(err.status === 487); // expected sip response to a CANCEL
  });
});

// cancel the request after 0.5s
setTimeout(() => {
  inviteSent.cancel();
}, 500);
Source:

createB2BUA(req, res, uri, opts, progressCallbacksopt, callbackopt) → {Srf|Promise}

create back-to-back dialogs; i.e. act as a back-to-back user agent (B2BUA), creating a pair of dialogs {uas, uac} -- a UAS dialog facing the caller or A party, and a UAC dialog facing the callee or B party such that media flows between them

Parameters:
Name Type Description
req Object

incoming sip request object

res Object

incoming sip response object

uri string

sip uri or IP address[:port] to send the UAC INVITE to

opts Object

configuration options

Properties
Name Type Default Description
headers Object <optional>

SIP headers to include on the SIP INVITE request

localSdpA string | function <optional>

the local session description protocol to offer in the response to the SIP INVITE request on the A leg; either a string or a function may be provided. If a function is provided, it will be invoked with two parameters (sdp, res) correspnding to the SDP received from the B party, and the sip response object received on the response from B. The function must return either the SDP (as a string) or a Promise that resolves to the SDP. If no value is provided (neither string nor function), then the SDP returned by the B party in the provisional/final response on the UAC leg will be sent back to the A party in the answer.

localSdpB string

the local session description protocol to offer in the SIP INVITE request on the B leg

proxyRequestHeaders Array <optional>

an array of header names which, if they appear in the INVITE request on the A leg, should be included unchanged on the generated B leg INVITE

proxyResponseHeaders Array <optional>

an array of header names which, if they appear in the response to the outgoing INVITE, should be included unchanged on the generated response to the A leg

passFailure Boolean <optional> true

specifies whether to pass a failure returned from B leg back to the A leg

progressCallbacks Object <optional>

callbacks providing call progress notification

Properties
Name Type Description
cbRequest function <optional>

callback that provides request sent over the wire, with signature (req)

cbProvisional function <optional>

callback that provides a provisional response with signature (provisionalRes)

callback function <optional>

if provided, callback with signature (err, {uas, uac})

Returns:

if a callback is supplied, a reference to the Srf instance.
If no callback is supplied, then a Promise that is resolved with the sip dialog that is created.

Type
Srf | Promise
Examples

simple B2BUA

const Srf = require('drachtio-srf');
const srf = new Srf();

srf.invite((req, res) => {
  srf.createB2BUA('sip:1234@10.10.100.1', req, res, {localSdpB: req.body})
    .then({uas, uac} => {
      console.log('call connected');

      // when one side terminates, hang up the other
      uas.on('destroy', () => { uac.destroy(); });
      uac.on('destroy', () => { uas.destroy(); });
    })
    .catch((err) => {
      console.log(`call failed to connect: ${err}`);
    });
});

use opts.passFailure to attempt a fallback URI on failure

const Srf = require('drachtio-srf');
const srf = new Srf();

function endCall(dlg1, dlg2) {
  dlg1.on('destroy', () => {dlg2.destroy();})
  dlg2.on('destroy', () => {dlg1.destroy();})
}
srf.invite((req, res) => {
  srf.createB2BUA('sip:1234@10.10.100.1', req, res, {localSdpB: req.body, passFailure: false})
    .then({uas, uac} => {
      console.log('call connected to primary destination');
      endcall(uas, uac);
    })
    .catch((err) => {
      // try backup if we got a sip non-success response and the caller did not hang up
      if (err instanceof Srf.SipError && err.status !== 487) {
          console.log(`failed connecting to primary, will try backup: ${err}`);
          srf.createB2BUA('sip:1234@10.10.100.2', req, res, {
            localSdpB: req.body}
          })
            .then({uas, uac} => {
              console.log('call connected to backup destination');
              endcall(uas.uac);
            })
            catch((err) => {
              console.log(`failed connecting to backup uri: ${err}`);
            });
      }
    });
});

B2BUA with media proxy using rtpengine

const Srf = require('drachtio-srf');
const srf = new Srf();
const rtpengine = require('rtpengine-client').Client

// helper functions

// clean up and free rtpengine resources when either side hangs up
function endCall(dlg1, dlg2, details) {
  [dlg1, dlg2].each((dlg) => {
    dlg.on('destroy', () => {(dlg === dlg1 ? dlg2 : dlg1).destroy();});
    rtpengine.delete(details);
  });
}

// function returning a Promise that resolves with the SDP to offer A leg in 18x/200 answer
function getSdpA(details, remoteSdp, res) {
  return rtpengine.answer(Object.assign(details, {
    'sdp': remoteSdp,
    'to-tag': res.getParsedHeader('To').params.tag
   }))
    .then((response) => {
      if (response.result !== 'ok') throw new Error(`Error calling answer: ${response['error-reason']}`);
      return response.sdp;
   })
}

// handle incoming invite
srf.invite((req, res) => {
  const from = req.getParsedHeader('From');
  const details = {'call-id': req.get('Call-Id'), 'from-tag': from.params.tag};

  rtpengine.offer(Object.assign(details, {'sdp': req.body})
    .then((rtpResponse) => {
      if (rtpResponse && rtpResponse.result === 'ok') return rtpResponse.sdp;
      throw new Error('rtpengine failure');
    })
    .then((sdpB) => {
      return srf.createB2BUA('sip:1234@10.10.100.1', req, res, {
        localSdpB: sdpB,
        localSdpA: getSdpA.bind(null, details)
      });
    })
    .then({uas, uac} => {
      console.log('call connected with media proxy');
      endcall(uas, uac, details);
    })
    .catch((err) => {
      console.log(`Error proxying call with media: ${err}`);
    });
});
Source:

proxyRequest(req, destinationopt, optsopt, callbackopt) → {Srf|Promise}

proxy an incoming request

Parameters:
Name Type Description
req Request

drachtio request object representing an incoming SIP request

destination String | Array <optional>

an IP address[:port], or list of same, to proxy the request to

opts Object <optional>

configuration options for the proxy operation

Properties
Name Type Default Description
forking String <optional> sequential

when multiple destinations are provided, this option governs whether they are attempted sequentially or in parallel. Valid values are 'sequential' or 'parallel'

remainInDialog Boolean <optional> false

if true, add Record-Route header and remain in the SIP dialog (i.e. receiving futher SIP messaging for the dialog, including the terminating BYE request). Alias: recordRoute.

provisionalTimeout String <optional>

timeout after which to attempt the next destination if no 100 Trying response has been received. Examples of valid syntax for this property is '1500ms', or '2s'

finalTimeout String <optional>

timeout, in milliseconds, after which to cancel the current request and attempt the next destination if no final response has been received. Syntax is the same as for the provisionalTimeout property.

followRedirects Boolean <optional> false

if true, handle 3XX redirect responses by generating a new request as per the Contact header; otherwise, proxy the 3XX response back upstream without generating a new response

callback function <optional>

callback invoked when proxy operation completes, signature (err, results) where results is a JSON object describing the individual sip call attempts and results

Returns:

returns a Promise if no callback is supplied, otherwise the Srf object

Type
Srf | Promise
Examples

simple proxy

const Srf = require('drachtio-srf');
const srf = new Srf();

srf.invite((req, res) => {
  srf.proxyRequest(req, 'sip.example.com');
});

proxy with options

const Srf = require('drachtio-srf');
const srf = new Srf();

srf.invite((req, res) => {
  srf.proxyRequest(req, ['sip.example1.com', 'sip.example2.com'], {
    recordRoute: true,
    followRedirects: true,
    provisionalTimeout: '2s'
  }).then((results) => {
    console.log(JSON.stringify(result)); // {finalStatus: 200, finalResponse:{..}, responses: [..]}
  });
});
Source:

request(uri, opts, headersopt, bodyopt, callbackopt)

send a SIP request outside of a dialog

Parameters:
Name Type Description
uri string

sip request-uri to send request to

opts Object

configuration options

Properties
Name Type Description
method String

SIP method to send (lower-case)

headers Object <optional>

SIP headers to apply to the outbound request

body String <optional>

body to send with the SIP request

callback function <optional>

callback invoked when sip request has been sent, invoked with signature (err, request) where request is a sip request object representing the sip message that was sent.

Example

sending OPTIONS request

srf.request('sip.example.com', {
  method: 'OPTIONS',
  headers: {
    'User-Agent': 'drachtio'
  }
 }, (err, req) => {
  req.on('response', (res) => {
    console.log(`received ${res.statusCode} response`);
  });
});
Source:

Events

cdr:attempt

a cdr:attempt event is emitted by an Srf instance when a call attempt has been received (inbound) or initiated (outbound)

Parameters:
Name Type Description
source String

'network'|'application', depending on whether the INVITE is \inbound (received), or outbound (sent), respectively

time String

the time (UTC) recorded by the SIP stack corresponding to the attempt

msg Object

the actual message that was sent or received

Source:

cdr:start

a cdr:start event is emitted by an Srf instance when a call attempt has been connected successfully

Parameters:
Name Type Description
source String

'network'|'application', depending on whether the INVITE is inbound (received), or outbound (sent), respectively

time String

the time (UTC) recorded by the SIP stack corresponding to the attempt

role String

'uac'|'uas'|'uac-proxy'|'uas-proxy' indicating whether the application is acting as a user agent client, user agent server, proxy (sending message), or proxy (receiving message) for this cdr

msg Object

the actual message that was sent or received

Source:

cdr:stop

a cdr:stop event is emitted by an Srf instance when a connected call has ended

Parameters:
Name Type Description
source String

'network'|'application', depending on whether the INVITE is inbound (received), or outbound (sent), respectively

time String

the time (UTC) recorded by the SIP stack corresponding to the attempt

reason String

the reason the call was ended

msg Object

the actual message that was sent or received

Source:

connect

a connect event is emitted by an Srf instance when a connect method completes with either success or failure

Parameters:
Name Type Description
err Object

error encountered when attempting to connect

hostport String

the SIP address[:port] drachtio server is listening on for incoming SIP messages

Source:

Dialog

Class representing a SIP Dialog.

Note that instances of this class are not created directly by your code; rather they are returned from the Srf#createUAC, Srf#createUAC, and Srf#createB2BUA

Constructor

new Dialog(srf, type, opts)

Constructor that is called internally by Srf when generating a Dialog instance.

Parameters:
Name Type Description
srf Srf

Srf instance that created this dialog

type string

type of SIP dialog: 'uac', or 'uas'

opts Dialog~Options
Source:

Extends

  • EventEmitter

Members

local :Dialog~SipEndpointInfo

local side of the Dialog

Type:
Source:

remote :Dialog~SipEndpointInfo

local side of the Dialog

Type:
Source:

sip :Dialog~SipInfo

sip properties that uniquely identify this Dialog

Type:
Source:

destroy(callbackopt) → {Promise}

destroy the sip dialog by generating a BYE request (in the case of INVITE dialog), or NOTIFY (in the case of SUBSCRIBE)

Parameters:
Name Type Description
callback Dialog~requestCallback <optional>

callback that returns the generated BYE or NOTIFY message

Returns:

if no callback is supplied, otherwise the function returns a reference to the Dialog

Type
Promise
Source:

modify(sdp, callbackopt) → {Promise}

modify the dialog session by changing attributes of the media connection

Parameters:
Name Type Description
sdp string

'hold', 'unhold', or a session description protocol

callback Dialog~modifySessionCallback <optional>

callback invoked when operation has completed

Returns:

if no callback is supplied, otherwise the function returns a reference to the Dialog

Type
Promise
Source:

request(opts, callbackopt) → {Promise}

send a request within a dialog. Note that you may also call request.info(..) as a shortcut to send an INFO message, request.notify(..) to send a NOTIFY, etc..

Parameters:
Name Type Description
opts Dialog~requestOptions

configuration options

callback Dialog~requestCallback <optional>

callback invoked when operation has completed

Returns:

if no callback is supplied a Promise that resolves to the response received, otherwise the function returns a reference to the Dialog

Type
Promise
Source:

Type Definitions

modifySessionCallback(err)

This callback provides the response a modifySession request.

Parameters:
Name Type Description
err Error

non-success sip response code received from far end

Source:

Options

Arguments provided to Dialog constructor.

Type:
  • Object
Properties:
Name Type Attributes Description
req Object

drachtio Request (only provided when creating a 'uas' dialogs)

res Object

drachtio Response

sent Object <optional>

uas only: actual Response sent when confirming the dialog

Source:

requestCallback(err, req)

This callback provides the SIP request that was generated

Parameters:
Name Type Description
err Error

error returned on non-success

req Request

Request that was generated

Source:

requestCallback(err, response)

This callback provides the response to a sip request sent within the dialog.

Parameters:
Name Type Description
err Error

error, if any

response Response

response received from the far end

Source:

requestOptions

Type:
  • Object
Properties:
Name Type Attributes Description
method String

SIP method to use for the request

headers Object <optional>

SIP headers to apply to the request

body String <optional>

body of the SIP request

Source:

SipEndpointInfo

SIP Endpoint identifiers

Type:
  • Object
Properties:
Name Type Description
uri String

sip

sdp String

session description protocol

Source:

SipInfo

SIP Dialog identifiers

Type:
  • Object
Properties:
Name Type Description
callId String

SIP Call-ID

localTag String

tag generated by local side of the Dialog

remoteTag String

tag generated by the remote side of the Dialog

Source:

Events

destroy

a destroy event is triggered when the Dialog is torn down from the far end

Parameters:
Name Type Description
msg Object

incoming BYE request message

Source:

info

an info event is triggered when the far end sends an INFO message. When an application adds a handler for this event it must generate the SIP response by calling res.send on the provided drachtio response object. When no handler is found for this event a 200 OK will be automatically generated.

Parameters:
Name Type Description
req Object

drachtio request object

res Object

drachtio response object

Source:

modify

a modify event is triggered when the far end modifies the session by sending a re-INVITE. When an application adds a handler for this event it must generate the SIP response by calling res.send on the provided drachtio response object. When no handler is found for this event a 200 OK with the current local SDP will be automatically generated.

Parameters:
Name Type Description
req Object

drachtio request object

res Object

drachtio response object

Source:

notify

a notify event is triggered when the far end sends a NOTIFY message. When an application adds a handler for this event it must generate the SIP response by calling res.send on the provided drachtio response object. When no handler is found for this event a 200 OK will be automatically generated.

Parameters:
Name Type Description
req Object

drachtio request object

res Object

drachtio response object

Source:

refer

a refer event is triggered when the far end sends a REFER message. When an application adds a handler for this event it must generate the SIP response by calling res.send on the provided drachtio response object. When no handler is found for this event a 200 OK will be automatically generated.

Parameters:
Name Type Description
req Object

drachtio request object

res Object

drachtio response object

Source:

refresh

a refresh event is triggered when the far end sends a session refresh. There is no need for the application to respond to this event; this is purely a notification.

Parameters:
Name Type Description
msg Object

incoming re-INVITE request message

Source:

update

an update event is triggered when the far end sends an UPDATE message. When an application adds a handler for this event it must generate the SIP response by calling res.send on the provided drachtio response object. When no handler is found for this event a 200 OK will be automatically generated.

Parameters:
Name Type Description
req Object

drachtio request object

res Object

drachtio response object

Source:

SipError

Class representing a SIP non-success response to a transaction

Constructor

new SipError(status, reasonopt)

Create a SipError object

Parameters:
Name Type Description
status number

SIP final status

reason string <optional>

reason for failure; if not provided the standard reason associated with the provided SIP status is used

Source:

Extends

  • Error