Methods
connect(opts)
make an inbound connection to a drachtio server
Parameters:
Name | Type | Description | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
opts |
Object | connection options Properties
|
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) => {..});
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
|
||||||||||||||||||||||||||||
progressCallbacks |
Object <optional> | callbacks providing call progress notification Properties
|
||||||||||||||||||||||||||||
callback |
function <optional> | if provided, callback with signature |
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}`);
});
});
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
|
|||||||||
progressCallbacks |
Object <optional> | callbacks providing call progress notification Properties
|
|||||||||
callback |
function <optional> | if provided, callback with signature |
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);
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
|
|||||||||
callback |
function <optional> | if provided, callback with signature |
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) => { ..});
listen(opts)
listen for outbound connections from a drachtio server
Parameters:
Name | Type | Description | |||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
opts |
Object | listen options Properties
|
Example
const Srf = require('drachtio-srf');
const srf = new Srf();
srf.listen({port: 9023, secret: 'cymru'});
srf.invite((req, res) => {..});
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
|
||||||||||||||||||||||||
callback |
function <optional> | callback invoked when proxy operation completes, signature (err, results)
where |
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: [..]}
});
});
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
|
||||||
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 |
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`);
});
});
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 |
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 |
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 |
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 |