Skip to content

Instantly share code, notes, and snippets.

@phanmn
Last active June 20, 2024 19:24
Show Gist options
  • Save phanmn/de0929fc4945c435cebfb6635366e87c to your computer and use it in GitHub Desktop.
Save phanmn/de0929fc4945c435cebfb6635366e87c to your computer and use it in GitHub Desktop.
SIP.js TCP Transport Implementation
const SIP = require('sip.js');
const net = require('net');
const TransportStatus = {
STATUS_CONNECTING: 'STATUS_CONNECTING',
STATUS_CONNECTED: 'STATUS_CONNECTED',
STATUS_CLOSING: 'STATUS_CLOSING',
STATUS_CLOSED: 'STATUS_CLOSED'
};
class SipTcpTransport extends SIP.Transport {
constructor(logger, options) {
super(logger, options);
this.type = SIP.TypeStrings.Transport;
this.status = TransportStatus.STATUS_CONNECTING;
this.configuration = options;
}
isConnected() {
return this.status === TransportStatus.STATUS_CONNECTED;
}
connectPromise(options) {
let socket = new net.Socket();
this._tcpSocket = socket;
let { ip, port } = this.configuration;
let promise = new Promise((resolve, reject) => {
socket.connect(port, ip, {}, () => {
this.status = TransportStatus.STATUS_CONNECTED;
this.emit('connected');
resolve({ overrideEvent: true });
});
});
socket.setEncoding('utf8');
this.boundOnMessage = this.onMessage.bind(this);
this.boundOnError = this.onError.bind(this);
this.boundOnClose = this.onClose.bind(this);
socket.on('data', this.boundOnMessage);
socket.on('error', this.boundOnError);
socket.on('close', this.boundOnClose);
return promise;
}
sendPromise(message, options) {
if (!this._tcpSocket) {
return Promise.reject();
}
this._tcpSocket.write(message);
return Promise.resolve({ msg: message });
}
disconnectPromise(options) {
if (!this._tcpSocket) {
return Promise.reject();
}
this._tcpSocket.destroy();
return Promise.resolve();
}
onMessage(data) {
let finishedData;
if (/^(\r\n)+$/.test(data)) {
// this.clearKeepAliveTimeout();
// if (this.configuration.traceSip === true) {
// this.logger.log(
// 'received WebSocket message with CRLF Keep Alive response'
// );
// }
return;
} else if (!data) {
this.logger.warn('received empty message, message discarded');
return;
} else if (typeof data !== 'string') {
// WebSocket binary message.
// try {
// // the UInt8Data was here prior to types, and doesn't check
// finishedData = String.fromCharCode.apply(null, (new Uint8Array(data) as unknown as Array<number>));
// } catch (err) {
// this.logger.warn("received WebSocket binary message failed to be converted into string, message discarded");
// return;
// }
// if (this.configuration.traceSip === true) {
// this.logger.log("received WebSocket binary message:\n\n" + data + "\n");
// }
} else {
// WebSocket text message.
// if (this.configuration.traceSip === true) {
// this.logger.log("received WebSocket text message:\n\n" + data + "\n");
// }
finishedData = data;
}
this.emit('message', finishedData);
}
onError(e) {
this.logger.warn('Transport error: ' + e);
this.emit('transportError');
}
onClose(e) {
this.logger.log(
'TCPSocket disconnected (code: ' +
e.code +
(e.reason ? '| reason: ' + e.reason : '') +
')'
);
this.status = TransportStatus.STATUS_CLOSED;
this.emit('disconnected', { code: e.code, reason: e.reason });
}
}
module.exports = SipTcpTransport;
const SIP = require('sip.js');
const SipTcpTransport = require('./sipTcpTransport');
let uri = 'xxxx@123.456.789.012'; // Update your sip uri
let authorizationUser = 'xxxx'; // Update your sip user
let password = 'yyyyyyy'; // Update your sip password
let ip = '123.456.789.012'; // Update your sip ip
var userAgent = new SIP.UA({
uri,
authorizationUser,
password,
hackViaTcp: true,
contactTransport: 'tcp',
transportConstructor: SipTcpTransport,
transportOptions: {
ip,
port: 5060,
},
});
userAgent.on('invite', (session) => session.accept());
@phanmn
Copy link
Author

phanmn commented Jun 6, 2023

hi @gvegaq86

Here is the version which I test

"sip": "0.0.5",
"sip.js": "^0.13.7",
"ws": "^6.2.1"

@giovegaq
Copy link

giovegaq commented Jun 8, 2023

@phanmn
This code is working well for me, but It seems I have problems closing the transport object at the end of my code, I'm using userAgent.stop() and the log shows "| sip.transport | TCPSocket disconnected (code: undefined)", it's like the transport object was never shut down, in the next execution I get: "| sip.ua | UA failed to parse incoming SIP message - discarding." and after 1 minute I'm able to register the UA correctly.

This is my code:

`var userAgent = new SIP.UA({
uri: uri,
authorizationUser: authorizationUser,
password: password,
hackViaTcp: true,
transportConstructor: SipTcpTransport,
transportOptions: {
ip,
port: 5060,
},
});

userAgent.on('invite', (session) => session.accept());
await userAgent.start();
await userAgent.register();

let i =0;
while(i<3){
console.log(userAgent.isRegistered())
if(userAgent.isRegistered()===true){
console.log("User agent is registered!!!")
break;
}
await page.waitForTimeout(1000);
i++;
}
userAgent.stop();`

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment