UNPKG

jssip

Version:

The Javascript SIP library

139 lines (138 loc) 4.54 kB
"use strict"; const EventEmitter = require('events').EventEmitter; const Logger = require('../Logger'); const JsSIP_C = require('../Constants'); const Exceptions = require('../Exceptions'); const Utils = require('../Utils'); const logger = new Logger('RTCSession:DTMF'); const C = { MIN_DURATION: 70, MAX_DURATION: 6000, DEFAULT_DURATION: 100, MIN_INTER_TONE_GAP: 50, DEFAULT_INTER_TONE_GAP: 500, }; module.exports = class DTMF extends EventEmitter { constructor(session) { super(); this._session = session; this._direction = null; this._tone = null; this._duration = null; this._request = null; } get tone() { return this._tone; } get duration() { return this._duration; } send(tone, options = {}) { if (tone === undefined) { throw new TypeError('Not enough arguments'); } 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 && this._session.status !== this._session.C.STATUS_1XX_RECEIVED) { throw new Exceptions.InvalidStateError(this._session.status); } const extraHeaders = Utils.cloneArray(options.extraHeaders); this.eventHandlers = Utils.cloneObject(options.eventHandlers); // Check tone type. if (typeof tone === 'string') { tone = tone.toUpperCase(); } else if (typeof tone === 'number') { tone = tone.toString(); } else { throw new TypeError(`Invalid tone: ${tone}`); } // Check tone value. if (!tone.match(/^[0-9A-DR#*]$/)) { throw new TypeError(`Invalid tone: ${tone}`); } else { this._tone = tone; } // Duration is checked/corrected in RTCSession. this._duration = options.duration; extraHeaders.push('Content-Type: application/dtmf-relay'); let body = `Signal=${this._tone}\r\n`; body += `Duration=${this._duration}`; this._session.newDTMF({ originator: 'local', dtmf: this, request: this._request, }); this._session.sendRequest(JsSIP_C.INFO, { extraHeaders, eventHandlers: { onSuccessResponse: response => { this.emit('succeeded', { originator: 'remote', response, }); }, onErrorResponse: response => { if (this.eventHandlers.onFailed) { this.eventHandlers.onFailed(); } this.emit('failed', { originator: 'remote', response, }); }, onRequestTimeout: () => { this._session.onRequestTimeout(); }, onTransportError: () => { this._session.onTransportError(); }, onDialogError: () => { this._session.onDialogError(); }, }, body, }); } init_incoming(request) { const reg_tone = /^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/; const reg_duration = /^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/; this._direction = 'incoming'; this._request = request; request.reply(200); if (request.body) { const body = request.body.split('\n'); if (body.length >= 1) { if (reg_tone.test(body[0])) { this._tone = body[0].replace(reg_tone, '$2'); } } if (body.length >= 2) { if (reg_duration.test(body[1])) { this._duration = parseInt(body[1].replace(reg_duration, '$2'), 10); } } } if (!this._duration) { this._duration = C.DEFAULT_DURATION; } if (!this._tone) { logger.debug('invalid INFO DTMF received, discarded'); } else { this._session.newDTMF({ originator: 'remote', dtmf: this, request, }); } } }; /** * Expose C object. */ module.exports.C = C;