diff --git a/lib/RTCSession.d.ts b/lib/RTCSession.d.ts index b4398202f..73a09be4a 100644 --- a/lib/RTCSession.d.ts +++ b/lib/RTCSession.d.ts @@ -43,6 +43,7 @@ export interface AnswerOptions extends ExtraHeaders { rtcAnswerConstraints?: RTCOfferOptions; rtcOfferConstraints?: RTCOfferOptions; sessionTimersExpires?: number; + allowEvents?: string[]; } export interface RejectOptions extends ExtraHeaders { @@ -136,6 +137,12 @@ export interface OutgoingInfoEvent { request: OutgoingRequest; } +export interface NotifyEvent { + originator: Originator.REMOTE; + type: string; + request: IncomingRequest; +} + export interface HoldEvent { originator: Originator } @@ -183,6 +190,7 @@ export type DTMFListener = IncomingDTMFListener | OutgoingDTMFListener; export type IncomingInfoListener = (event: IncomingInfoEvent) => void; export type OutgoingInfoListener = (event: OutgoingInfoEvent) => void; export type InfoListener = IncomingInfoListener | OutgoingInfoListener; +export type NotifyListener = (event: NotifyEvent) => void export type HoldListener = (event: HoldEvent) => void; export type MuteListener = (event: MediaConstraints) => void; export type ReInviteListener = (event: ReInviteEvent) => void; @@ -202,6 +210,7 @@ export interface RTCSessionEventMap { 'failed': EndListener; 'newDTMF': DTMFListener; 'newInfo': InfoListener; + 'newNotify': NotifyListener; 'hold': HoldListener; 'unhold': HoldListener; 'muted': MuteListener; @@ -244,6 +253,8 @@ export class RTCSession extends EventEmitter { set data(_data: any); get data(): any; + set allow_events(events: string[]); + get connection(): RTCPeerConnectionDeprecated; get contact(): string; diff --git a/lib/RTCSession.js b/lib/RTCSession.js index df9e50a56..fe9acdf68 100644 --- a/lib/RTCSession.js +++ b/lib/RTCSession.js @@ -134,6 +134,9 @@ module.exports = class RTCSession extends EventEmitter // Custom session empty object for high level use. this._data = {}; + + // List of allowed NOTIFY events for the Allow-Events header. + this._allowEvents = []; } /** @@ -202,6 +205,11 @@ module.exports = class RTCSession extends EventEmitter this._data = _data; } + set allow_events(events) + { + this._allowEvents = events; + } + get status() { return this._status; @@ -283,6 +291,7 @@ module.exports = class RTCSession extends EventEmitter this._rtcAnswerConstraints = options.rtcAnswerConstraints || null; this._data = options.data || this._data; + this._allowEvents = options.allowEvents || this._allowEvents; // Check target. if (target === undefined) @@ -374,6 +383,12 @@ module.exports = class RTCSession extends EventEmitter extraHeaders.push(`Session-Expires: ${this._sessionTimers.defaultExpires}${this._ua.configuration.session_timers_force_refresher ? ';refresher=uac' : ''}`); } + // If in-dialog NOTIFY events are allowed the Allow-Events header gets set. + if (this._allowEvents.length > 0) + { + extraHeaders.push(`Allow-Events: ${this._allowEvents.join()}`); + } + this._request = new SIPMessage.InitialOutgoingInviteRequest( target, this._ua, requestParams, extraHeaders); @@ -495,8 +510,16 @@ module.exports = class RTCSession extends EventEmitter return; } + const extraHeaders = [ `Contact: ${this._contact}` ]; + + // If in-dialog NOTIFY events are allowed the Allow-Events header gets set. + if (this._allowEvents.length > 0) + { + extraHeaders.push(`Allow-Events: ${this._allowEvents.join()}`); + } + // Reply 180. - request.reply(180, null, [ `Contact: ${this._contact}` ]); + request.reply(180, null, extraHeaders); // Fire 'progress' event. // TODO: Document that 'response' field in 'progress' event is null for incoming calls. @@ -529,6 +552,7 @@ module.exports = class RTCSession extends EventEmitter this._rtcOfferConstraints = options.rtcOfferConstraints || null; this._data = options.data || this._data; + this._allowEvents = options.allowEvents || this._allowEvents; // Check Session Direction and Status. if (this._direction !== 'incoming') @@ -572,6 +596,12 @@ module.exports = class RTCSession extends EventEmitter extraHeaders.unshift(`Contact: ${this._contact}`); + // If in-dialog NOTIFY events are allowed the Allow-Events header gets set. + if (this._allowEvents.length > 0) + { + extraHeaders.push(`Allow-Events: ${this._allowEvents.join()}`); + } + // Determine incoming media from incoming SDP offer (if any). const sdp = request.parseSDP(); @@ -1598,7 +1628,11 @@ module.exports = class RTCSession extends EventEmitter } break; case JsSIP_C.NOTIFY: - if (this._status === C.STATUS_CONFIRMED) + if (this._status === C.STATUS_1XX_RECEIVED || + this._status === C.STATUS_WAITING_FOR_ANSWER || + this._status === C.STATUS_ANSWERED || + this._status === C.STATUS_WAITING_FOR_ACK || + this._status === C.STATUS_CONFIRMED) { this._receiveNotify(request); } @@ -2505,9 +2539,10 @@ module.exports = class RTCSession extends EventEmitter request.reply(400); } - switch (request.event.event) + if (request.event.event === 'refer') { - case 'refer': { + if (this._status === C.STATUS_CONFIRMED) + { let id; let referSubscriber; @@ -2537,14 +2572,26 @@ module.exports = class RTCSession extends EventEmitter referSubscriber.receiveNotify(request); request.reply(200); - - break; } - - default: { - request.reply(489); + else + { + request.reply(403, 'Wrong Status'); } } + else if (this._allowEvents.indexOf(request.event.event) !== -1) + { + this.emit('newNotify', { + originator : 'remote', + type : request.event.event, + request : request + }); + + request.reply(200); + } + else + { + request.reply(489); + } } /**