@voicenter-team/opensips-js 1.0.20 → 1.0.22
Sign up to get free protection for your applications and to get access to all the features.
- package/build/enum/message.event.listener.type.d.ts +5 -0
- package/build/enum/message.event.listener.type.js +8 -0
- package/build/enum/session.direction.enum.d.ts +2 -0
- package/build/enum/session.direction.enum.js +5 -0
- package/build/helpers/UA/index.d.ts +38 -3
- package/build/helpers/UA/index.js +310 -1
- package/build/helpers/audio.helper.d.ts +7 -1
- package/build/helpers/audio.helper.js +39 -2
- package/build/helpers/jssip.d.ts +5 -0
- package/build/helpers/jssip.js +30 -0
- package/build/index.d.ts +58 -59
- package/build/index.js +395 -165
- package/build/lib/msrp/message.d.ts +12 -0
- package/build/lib/msrp/message.js +82 -0
- package/build/lib/msrp/session.d.ts +94 -0
- package/build/lib/msrp/session.js +621 -0
- package/package.json +2 -2
- package/src/types/Transactions.d.ts +9 -0
- package/src/types/UAExtended.d.ts +74 -0
- package/src/types/listeners.d.ts +17 -1
- package/src/types/msrp.d.ts +49 -0
- package/src/types/rtc.d.ts +9 -0
@@ -0,0 +1,621 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
19
|
+
if (mod && mod.__esModule) return mod;
|
20
|
+
var result = {};
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
22
|
+
__setModuleDefault(result, mod);
|
23
|
+
return result;
|
24
|
+
};
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
27
|
+
};
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
29
|
+
exports.MSRPSession = void 0;
|
30
|
+
const Utils = __importStar(require("jssip/lib/Utils"));
|
31
|
+
const RequestSender_1 = __importDefault(require("jssip/lib/RequestSender"));
|
32
|
+
const DigestAuthentication_1 = __importDefault(require("jssip/lib/DigestAuthentication"));
|
33
|
+
const message_1 = __importDefault(require("./message"));
|
34
|
+
const URI_1 = __importDefault(require("jssip/lib/URI"));
|
35
|
+
const SIPMessage = __importStar(require("jssip/lib/SIPMessage"));
|
36
|
+
const Constants_1 = __importDefault(require("jssip/lib/Constants"));
|
37
|
+
const events_1 = require("events");
|
38
|
+
const Dialog_1 = __importDefault(require("jssip/lib/Dialog"));
|
39
|
+
const Exceptions_1 = __importDefault(require("jssip/lib/Exceptions"));
|
40
|
+
const Transactions_1 = __importDefault(require("jssip/lib/Transactions"));
|
41
|
+
const C = {
|
42
|
+
// RTCSession states.
|
43
|
+
STATUS_NULL: 0,
|
44
|
+
STATUS_INVITE_SENT: 1,
|
45
|
+
STATUS_1XX_RECEIVED: 2,
|
46
|
+
STATUS_INVITE_RECEIVED: 3,
|
47
|
+
STATUS_WAITING_FOR_ANSWER: 4,
|
48
|
+
STATUS_ANSWERED: 5,
|
49
|
+
STATUS_WAITING_FOR_ACK: 6,
|
50
|
+
STATUS_CANCELED: 7,
|
51
|
+
STATUS_TERMINATED: 8,
|
52
|
+
STATUS_CONFIRMED: 9
|
53
|
+
};
|
54
|
+
class MSRPSession extends events_1.EventEmitter {
|
55
|
+
constructor(ua) {
|
56
|
+
super();
|
57
|
+
this._id = null;
|
58
|
+
this.my_ip = '127.0.0.1';
|
59
|
+
this._ua = ua;
|
60
|
+
console.log('session constructor configuration', ua.configuration);
|
61
|
+
console.log('session constructor uri ', ua.configuration.uri);
|
62
|
+
console.log('session constructor uri instanceof URI', ua.configuration.uri instanceof URI_1.default);
|
63
|
+
this.auth_id = Utils.createRandomToken(10);
|
64
|
+
this._status = C.STATUS_NULL;
|
65
|
+
this._dialog = null;
|
66
|
+
this._earlyDialogs = {};
|
67
|
+
this._contact = null;
|
68
|
+
this._from_tag = null;
|
69
|
+
this._to_tag = null;
|
70
|
+
this._msgHistory = [];
|
71
|
+
this.target_addr = [];
|
72
|
+
this.my_addr = [];
|
73
|
+
this.credentials = {
|
74
|
+
'username': ua._configuration.authorization_user,
|
75
|
+
'ha1': ua._configuration.ha1,
|
76
|
+
'realm': ua._configuration.realm
|
77
|
+
};
|
78
|
+
this._request = null;
|
79
|
+
this.status = 'new';
|
80
|
+
this.target = '';
|
81
|
+
this.message = '';
|
82
|
+
this._timers = {
|
83
|
+
ackTimer: null,
|
84
|
+
expiresTimer: null,
|
85
|
+
invite2xxTimer: null,
|
86
|
+
userNoAnswerTimer: null
|
87
|
+
};
|
88
|
+
this._direction = null;
|
89
|
+
this._local_identity = null;
|
90
|
+
this._remote_identity = null;
|
91
|
+
this._start_time = null;
|
92
|
+
this._end_time = null;
|
93
|
+
this._tones = null;
|
94
|
+
this._sessionTimers = {
|
95
|
+
enabled: this._ua.configuration.session_timers,
|
96
|
+
refreshMethod: this._ua.configuration.session_timers_refresh_method,
|
97
|
+
defaultExpires: Constants_1.default.SESSION_EXPIRES,
|
98
|
+
currentExpires: null,
|
99
|
+
running: false,
|
100
|
+
refresher: false,
|
101
|
+
timer: null // A setTimeout.
|
102
|
+
};
|
103
|
+
}
|
104
|
+
/**
|
105
|
+
* Expose C object.
|
106
|
+
*/
|
107
|
+
static get C() {
|
108
|
+
return C;
|
109
|
+
}
|
110
|
+
get direction() {
|
111
|
+
return this._direction;
|
112
|
+
}
|
113
|
+
get connection() {
|
114
|
+
return this._connection;
|
115
|
+
}
|
116
|
+
get id() {
|
117
|
+
return this._id;
|
118
|
+
}
|
119
|
+
connect(target = '') {
|
120
|
+
if (target !== '') {
|
121
|
+
this._direction = 'outgoing';
|
122
|
+
}
|
123
|
+
this.target = target;
|
124
|
+
this._connection = new WebSocket(`ws://${this._ua._configuration.realm}:2856`, 'msrp');
|
125
|
+
this._connection.binaryType = 'arraybuffer';
|
126
|
+
this._connection.onopen = (event) => {
|
127
|
+
console.log('open');
|
128
|
+
this.onopen();
|
129
|
+
};
|
130
|
+
this._connection.onclose = () => {
|
131
|
+
console.log('close');
|
132
|
+
this.onclose();
|
133
|
+
};
|
134
|
+
this._connection.onmessage = (msg) => {
|
135
|
+
console.log('msg', msg);
|
136
|
+
this.onmessage(msg);
|
137
|
+
};
|
138
|
+
this._connection.onerror = () => {
|
139
|
+
console.log('error');
|
140
|
+
this.onerror();
|
141
|
+
};
|
142
|
+
}
|
143
|
+
answer() {
|
144
|
+
this.connect();
|
145
|
+
}
|
146
|
+
acceptParty(msgObj) {
|
147
|
+
this._request.parseSDP(true);
|
148
|
+
// this.target_addr = this._request.sdp.media[0].invalid[1].value.replaceAll('path:', '');
|
149
|
+
this._request.reply(200, 'OK', [], 'v=0\n' +
|
150
|
+
`o=- 4232740119537112802 2 IN IP4 ${this.my_ip}\n` +
|
151
|
+
`c=IN IP4 ${this.my_ip}\n` +
|
152
|
+
't=0 0\n' +
|
153
|
+
'm=message 2856 TCP/TLS/MSRP *\n' +
|
154
|
+
'a=accept-types:text/plain text/html\n' +
|
155
|
+
`a=path: ${msgObj.getHeader('Use-Path')} msrp://${this._ua._configuration.authorization_user}.${this._ua._configuration.realm}:2856/${this.auth_id};ws\n`);
|
156
|
+
}
|
157
|
+
terminate(options = {}) {
|
158
|
+
const cause = options.cause || Constants_1.default.causes.BYE;
|
159
|
+
const extraHeaders = Utils.cloneArray(options.extraHeaders);
|
160
|
+
const body = options.body;
|
161
|
+
let cancel_reason;
|
162
|
+
let status_code = options.status_code;
|
163
|
+
let reason_phrase = options.reason_phrase;
|
164
|
+
// Check Session Status.
|
165
|
+
if (this._status === C.STATUS_TERMINATED) {
|
166
|
+
throw new Exceptions_1.default.InvalidStateError(this._status);
|
167
|
+
}
|
168
|
+
this.status = 'terminated';
|
169
|
+
switch (this._status) {
|
170
|
+
// - UAC -
|
171
|
+
case C.STATUS_NULL:
|
172
|
+
case C.STATUS_INVITE_SENT:
|
173
|
+
case C.STATUS_1XX_RECEIVED:
|
174
|
+
if (status_code && (status_code < 200 || status_code >= 700)) {
|
175
|
+
throw new TypeError(`Invalid status_code: ${status_code}`);
|
176
|
+
}
|
177
|
+
else if (status_code) {
|
178
|
+
reason_phrase = reason_phrase || Constants_1.default.REASON_PHRASE[status_code] || '';
|
179
|
+
cancel_reason = `SIP ;cause=${status_code} ;text="${reason_phrase}"`;
|
180
|
+
}
|
181
|
+
// Check Session Status.
|
182
|
+
if (this._status === C.STATUS_NULL || this._status === C.STATUS_INVITE_SENT) {
|
183
|
+
this._is_canceled = true;
|
184
|
+
this._cancel_reason = cancel_reason;
|
185
|
+
}
|
186
|
+
else if (this._status === C.STATUS_1XX_RECEIVED) {
|
187
|
+
this._request.cancel(cancel_reason);
|
188
|
+
}
|
189
|
+
this._status = C.STATUS_CANCELED;
|
190
|
+
this._failed('local', null, Constants_1.default.causes.CANCELED);
|
191
|
+
break;
|
192
|
+
// - UAS -
|
193
|
+
case C.STATUS_WAITING_FOR_ANSWER:
|
194
|
+
case C.STATUS_ANSWERED:
|
195
|
+
status_code = status_code || 480;
|
196
|
+
console.log('REPLY 480');
|
197
|
+
if (status_code < 300 || status_code >= 700) {
|
198
|
+
throw new TypeError(`Invalid status_code: ${status_code}`);
|
199
|
+
}
|
200
|
+
this._request.reply(status_code, reason_phrase, extraHeaders, body);
|
201
|
+
this._failed('local', null, Constants_1.default.causes.REJECTED);
|
202
|
+
break;
|
203
|
+
case C.STATUS_WAITING_FOR_ACK:
|
204
|
+
case C.STATUS_CONFIRMED:
|
205
|
+
reason_phrase = options.reason_phrase || Constants_1.default.REASON_PHRASE[status_code] || '';
|
206
|
+
if (status_code && (status_code < 200 || status_code >= 700)) {
|
207
|
+
throw new TypeError(`Invalid status_code: ${status_code}`);
|
208
|
+
}
|
209
|
+
else if (status_code) {
|
210
|
+
extraHeaders.push(`Reason: SIP ;cause=${status_code}; text="${reason_phrase}"`);
|
211
|
+
}
|
212
|
+
/* RFC 3261 section 15 (Terminating a session):
|
213
|
+
*
|
214
|
+
* "...the callee's UA MUST NOT send a BYE on a confirmed dialog
|
215
|
+
* until it has received an ACK for its 2xx response or until the server
|
216
|
+
* transaction times out."
|
217
|
+
*/
|
218
|
+
if (this._status === C.STATUS_WAITING_FOR_ACK &&
|
219
|
+
this._direction === 'incoming' &&
|
220
|
+
this._request.server_transaction.state !== Transactions_1.default.C.STATUS_TERMINATED) {
|
221
|
+
// Save the dialog for later restoration.
|
222
|
+
const dialog = this._dialog;
|
223
|
+
// Send the BYE as soon as the ACK is received...
|
224
|
+
this.receiveRequest = ({ method }) => {
|
225
|
+
if (method === Constants_1.default.ACK) {
|
226
|
+
this.sendRequest(Constants_1.default.BYE, {
|
227
|
+
extraHeaders,
|
228
|
+
body
|
229
|
+
});
|
230
|
+
dialog.terminate();
|
231
|
+
}
|
232
|
+
};
|
233
|
+
// .., or when the INVITE transaction times out
|
234
|
+
this._request.server_transaction.on('stateChanged', () => {
|
235
|
+
if (this._request.server_transaction.state ===
|
236
|
+
Transactions_1.default.C.STATUS_TERMINATED) {
|
237
|
+
this.sendRequest(Constants_1.default.BYE, {
|
238
|
+
extraHeaders,
|
239
|
+
body
|
240
|
+
});
|
241
|
+
dialog.terminate();
|
242
|
+
}
|
243
|
+
});
|
244
|
+
this._ended('local', null, cause);
|
245
|
+
// Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-).
|
246
|
+
this._dialog = dialog;
|
247
|
+
// Restore the dialog into 'ua' so the ACK can reach 'this' session.
|
248
|
+
this._ua.newDialog(dialog);
|
249
|
+
}
|
250
|
+
else {
|
251
|
+
this.sendRequest(Constants_1.default.BYE, {
|
252
|
+
extraHeaders,
|
253
|
+
body
|
254
|
+
});
|
255
|
+
this._ended('local', null, cause);
|
256
|
+
}
|
257
|
+
}
|
258
|
+
}
|
259
|
+
sendRequest(method, options) {
|
260
|
+
return this._dialog.sendRequest(method, options);
|
261
|
+
}
|
262
|
+
authenticate(auth) {
|
263
|
+
this.status = 'auth';
|
264
|
+
let msgObj = new message_1.default('');
|
265
|
+
msgObj.method = 'AUTH';
|
266
|
+
msgObj.addHeader('To-Path', `msrp://${this._ua._configuration.realm}:2856;ws`);
|
267
|
+
msgObj.addHeader('From-Path', `msrp://${this.credentials.username}.${this.credentials.realm}:2856/${this.auth_id};ws`);
|
268
|
+
if (auth) {
|
269
|
+
msgObj.addHeader('Authorization', auth.toString());
|
270
|
+
}
|
271
|
+
this._connection.send(msgObj.toString());
|
272
|
+
}
|
273
|
+
onmessage(msg) {
|
274
|
+
console.log('onmessage', msg);
|
275
|
+
const msgObj = new message_1.default(msg.data);
|
276
|
+
if (this.status === 'auth' && msgObj.code === 401) {
|
277
|
+
const _challenge = this.parseAuth(msgObj.getHeader('WWW-Authenticate'));
|
278
|
+
const digestAuthentication = new DigestAuthentication_1.default(this.credentials);
|
279
|
+
digestAuthentication.authenticate({ method: 'AUTH', ruri: `msrp://${this._ua._configuration.realm}:2856;ws`, body: null }, _challenge, Utils.createRandomToken(12));
|
280
|
+
this.authenticate(digestAuthentication);
|
281
|
+
}
|
282
|
+
if (this.status === 'auth' && msgObj.code === 200 && this._direction === 'outgoing') {
|
283
|
+
this.my_addr.push(msgObj.getHeader('To-Path'));
|
284
|
+
this.my_addr.push(msgObj.getHeader('Use-Path'));
|
285
|
+
this.status = 'active';
|
286
|
+
this.inviteParty(msgObj);
|
287
|
+
}
|
288
|
+
else if (this.status === 'auth' && msgObj.code === 200 && this._direction === 'incoming') {
|
289
|
+
this.my_addr.push(msgObj.getHeader('To-Path'));
|
290
|
+
this.my_addr.push(msgObj.getHeader('Use-Path'));
|
291
|
+
this.status = 'active';
|
292
|
+
this.acceptParty(msgObj);
|
293
|
+
}
|
294
|
+
else if (msgObj.method === 'SEND') {
|
295
|
+
this._sendOk(msgObj);
|
296
|
+
this._sendReport(msgObj);
|
297
|
+
msgObj.direction = 'incoming';
|
298
|
+
this.emit('newMessage', msgObj);
|
299
|
+
this._msgHistory.push(msgObj);
|
300
|
+
this.emit('msgHistoryUpdate', this._msgHistory);
|
301
|
+
console.log('======================================================================');
|
302
|
+
}
|
303
|
+
if (msgObj.code === 480) {
|
304
|
+
console.log('---------------------------------');
|
305
|
+
this._close();
|
306
|
+
}
|
307
|
+
}
|
308
|
+
onclose() {
|
309
|
+
console.log('close');
|
310
|
+
}
|
311
|
+
onopen() {
|
312
|
+
const pc = new RTCPeerConnection({ iceServers: [] });
|
313
|
+
pc.createDataChannel('');
|
314
|
+
pc.createOffer().then(pc.setLocalDescription.bind(pc));
|
315
|
+
pc.onicecandidate = (ice) => {
|
316
|
+
if (!ice || !ice.candidate || !ice.candidate.candidate)
|
317
|
+
return;
|
318
|
+
const ipRegex = /([0-9]{1,3}(\.[0-9]{1,3}){3})/;
|
319
|
+
const ipMatch = ice.candidate.candidate.match(ipRegex);
|
320
|
+
this.my_ip = ipMatch && ipMatch[1];
|
321
|
+
pc.onicecandidate = () => { };
|
322
|
+
this.authenticate(null);
|
323
|
+
};
|
324
|
+
}
|
325
|
+
onerror(e) {
|
326
|
+
console.log(e);
|
327
|
+
}
|
328
|
+
inviteParty(msgObj) {
|
329
|
+
const requestParams = {};
|
330
|
+
const extraHeaders = [];
|
331
|
+
requestParams.to_uri = new URI_1.default('sip', this.target, this._ua._configuration.realm);
|
332
|
+
requestParams.from_uri = new URI_1.default('sip', this._ua._configuration.uri.user, this._ua._configuration.uri.host);
|
333
|
+
// extraHeaders.push(`P-Preferred-Identity: ${this._ua._configuration.uri.toString()}`)
|
334
|
+
extraHeaders.push(`Contact: ${this._ua.contact.toString({
|
335
|
+
outbound: true
|
336
|
+
})}`);
|
337
|
+
extraHeaders.push('Content-Type: application/sdp');
|
338
|
+
this._request = new SIPMessage.InitialOutgoingInviteRequest(new URI_1.default('sip', this.target, this._ua._configuration.realm).clone(), this._ua, requestParams, extraHeaders, 'v=0\n' +
|
339
|
+
`o=- 4232740119537112802 2 IN IP4 ${this.my_ip}\n` +
|
340
|
+
`c=IN IP4 ${this.my_ip}\n` +
|
341
|
+
't=0 0\n' +
|
342
|
+
'm=message 2856 TCP/TLS/MSRP *\n' +
|
343
|
+
'a=accept-types:text/plain text/html\n' +
|
344
|
+
`a=path:${msgObj.getHeader('Use-Path')} msrp://${this._ua._configuration.authorization_user}.${this._ua._configuration.realm}:2856/${this.auth_id};ws\n`);
|
345
|
+
this._newMSRPSession('local', this._request);
|
346
|
+
this._id = this._request.call_id + this._from_tag;
|
347
|
+
const request_sender = new RequestSender_1.default(this._ua, this._request, {
|
348
|
+
onRequestTimeout: () => {
|
349
|
+
console.log('to');
|
350
|
+
},
|
351
|
+
onTransportError: (err) => {
|
352
|
+
console.log(err);
|
353
|
+
},
|
354
|
+
// Update the request on authentication.
|
355
|
+
onAuthenticated: (request) => {
|
356
|
+
this._request = request;
|
357
|
+
},
|
358
|
+
onReceiveResponse: (response) => {
|
359
|
+
if (response.status_code === 200) {
|
360
|
+
response.parseSDP(true);
|
361
|
+
this._status = C.STATUS_CONFIRMED;
|
362
|
+
this.target_addr = response.sdp.media[0].invalid[1].value.replaceAll('path:', '').split(' ').reverse();
|
363
|
+
this.status = 'active';
|
364
|
+
this.emit('active');
|
365
|
+
this.emit('confirmed');
|
366
|
+
}
|
367
|
+
}
|
368
|
+
});
|
369
|
+
request_sender.send();
|
370
|
+
}
|
371
|
+
sendMSRP(message) {
|
372
|
+
const msgObj = new message_1.default('');
|
373
|
+
msgObj.method = 'SEND';
|
374
|
+
msgObj.addHeader('To-Path', `${this.my_addr[1]} ${this.target_addr[1]} ${this.target_addr[0]}`);
|
375
|
+
msgObj.addHeader('From-Path', `${this.my_addr[0]}`);
|
376
|
+
msgObj.addHeader('Message-ID', Utils.createRandomToken(10));
|
377
|
+
msgObj.addHeader('Byte-Range', '1-25/25');
|
378
|
+
msgObj.addHeader('Content-Type', 'text/plain');
|
379
|
+
msgObj.addHeader('Success-Report', 'yes');
|
380
|
+
msgObj.addHeader('Failure-Report', 'yes');
|
381
|
+
// msgObj.addHeader('To', this._to_tag)
|
382
|
+
// msgObj.addHeader('From', this._from_tag)
|
383
|
+
msgObj.body = message;
|
384
|
+
this._connection.send(msgObj.toString());
|
385
|
+
msgObj.direction = 'outgoing';
|
386
|
+
this.emit('newMessage', msgObj);
|
387
|
+
this._msgHistory.push(msgObj);
|
388
|
+
this.emit('msgHistoryUpdate', this._msgHistory);
|
389
|
+
}
|
390
|
+
_sendOk(msgObj) {
|
391
|
+
let _i = msgObj.ident;
|
392
|
+
let _mId = msgObj.getHeader('Message-ID');
|
393
|
+
let _ok = new message_1.default('');
|
394
|
+
_ok.method = '200 OK';
|
395
|
+
_ok.addHeader('To-Path', `${this.my_addr[1]}`);
|
396
|
+
_ok.addHeader('From-Path', `${this.my_addr[0]}`);
|
397
|
+
_ok.addHeader('Message-ID', _mId);
|
398
|
+
_ok.ident = _i;
|
399
|
+
this._connection.send(_ok.toString());
|
400
|
+
}
|
401
|
+
_sendReport(msgObj) {
|
402
|
+
let _i = msgObj.ident;
|
403
|
+
let _mId = msgObj.getHeader('Message-ID');
|
404
|
+
let _report = new message_1.default('');
|
405
|
+
_report.method = 'REPORT';
|
406
|
+
_report.addHeader('To-Path', `${msgObj.getHeader('From-Path')}`);
|
407
|
+
_report.addHeader('From-Path', `${this.my_addr[0]}`);
|
408
|
+
_report.addHeader('Message-ID', _mId);
|
409
|
+
_report.addHeader('Byte-Range', '1-25/25');
|
410
|
+
_report.addHeader('Status', '000 200 OK');
|
411
|
+
_report.ident = _i;
|
412
|
+
this._connection.send(_report.toString());
|
413
|
+
}
|
414
|
+
parseAuth(content) {
|
415
|
+
const _challenge = {};
|
416
|
+
const _challengeArray = content.replace('Digest', '').split(',');
|
417
|
+
for (const _authItem of _challengeArray) {
|
418
|
+
const _itemArray = _authItem.trim().split('=');
|
419
|
+
_challenge[_itemArray[0]] = _itemArray[1].match('^"(.+)"$')[1];
|
420
|
+
}
|
421
|
+
return _challenge;
|
422
|
+
}
|
423
|
+
init_incoming(request, initCallback) {
|
424
|
+
let expires;
|
425
|
+
const contentType = request.hasHeader('Content-Type') ?
|
426
|
+
request.getHeader('Content-Type').toLowerCase() : undefined;
|
427
|
+
// Check body and content type.
|
428
|
+
if (request.body && (contentType !== 'application/sdp')) {
|
429
|
+
request.reply(415);
|
430
|
+
return;
|
431
|
+
}
|
432
|
+
// Session parameter initialization.
|
433
|
+
this._status = C.STATUS_INVITE_RECEIVED;
|
434
|
+
this._from_tag = request.from_tag;
|
435
|
+
this._id = request.call_id + this._from_tag;
|
436
|
+
this._request = request;
|
437
|
+
this._contact = this._ua.contact.toString();
|
438
|
+
// Get the Expires header value if exists.
|
439
|
+
if (request.hasHeader('expires')) {
|
440
|
+
expires = request.getHeader('expires') * 1000;
|
441
|
+
}
|
442
|
+
/* Set the to_tag before
|
443
|
+
* replying a response code that will create a dialog.
|
444
|
+
*/
|
445
|
+
request.to_tag = Utils.newTag();
|
446
|
+
// An error on dialog creation will fire 'failed' event.
|
447
|
+
if (!this._createDialog(request, 'UAS', true)) {
|
448
|
+
request.reply(500, 'Missing Contact header field');
|
449
|
+
return;
|
450
|
+
}
|
451
|
+
if (request.body) {
|
452
|
+
this._late_sdp = false;
|
453
|
+
}
|
454
|
+
else {
|
455
|
+
this._late_sdp = true;
|
456
|
+
}
|
457
|
+
this._status = C.STATUS_WAITING_FOR_ANSWER;
|
458
|
+
// Set userNoAnswerTimer.
|
459
|
+
this._timers.userNoAnswerTimer = setTimeout(() => {
|
460
|
+
request.reply(408);
|
461
|
+
this._failed('local', null, Constants_1.default.causes.NO_ANSWER);
|
462
|
+
}, this._ua.configuration.no_answer_timeout);
|
463
|
+
/* Set expiresTimer
|
464
|
+
* RFC3261 13.3.1
|
465
|
+
*/
|
466
|
+
if (expires) {
|
467
|
+
this._timers.expiresTimer = setTimeout(() => {
|
468
|
+
if (this._status === C.STATUS_WAITING_FOR_ANSWER) {
|
469
|
+
request.reply(487);
|
470
|
+
this._failed('system', null, Constants_1.default.causes.EXPIRES);
|
471
|
+
}
|
472
|
+
}, expires);
|
473
|
+
}
|
474
|
+
// Set internal properties.
|
475
|
+
this._direction = 'incoming';
|
476
|
+
this._local_identity = request.to;
|
477
|
+
this._remote_identity = request.from;
|
478
|
+
// A init callback was specifically defined.
|
479
|
+
if (initCallback) {
|
480
|
+
initCallback(this);
|
481
|
+
}
|
482
|
+
request.parseSDP(true);
|
483
|
+
this.target_addr = request.sdp.media[0].invalid[1].value.replaceAll('path:', '').split(' ').reverse();
|
484
|
+
// Fire 'newMSRPSession' event.
|
485
|
+
this._newMSRPSession('remote', request);
|
486
|
+
// The user may have rejected the call in the 'newRTCSession' event.
|
487
|
+
if (this._status === C.STATUS_TERMINATED) {
|
488
|
+
return;
|
489
|
+
}
|
490
|
+
// Reply 180.
|
491
|
+
request.reply(180, null, [`Contact: ${this._ua._contact}`]);
|
492
|
+
// Fire 'progress' event.
|
493
|
+
// TODO: Document that 'response' field in 'progress' event is null for incoming calls.
|
494
|
+
this._progress('local', null);
|
495
|
+
}
|
496
|
+
_failed(originator, message, cause) {
|
497
|
+
this.emit('_failed', {
|
498
|
+
originator,
|
499
|
+
message: message || null,
|
500
|
+
cause
|
501
|
+
});
|
502
|
+
this._close();
|
503
|
+
this.emit('failed', {
|
504
|
+
originator,
|
505
|
+
message: message || null,
|
506
|
+
cause
|
507
|
+
});
|
508
|
+
}
|
509
|
+
_close() {
|
510
|
+
if (this._status === C.STATUS_TERMINATED) {
|
511
|
+
return;
|
512
|
+
}
|
513
|
+
this._status = C.STATUS_TERMINATED;
|
514
|
+
// Terminate RTC.
|
515
|
+
if (this._connection) {
|
516
|
+
try {
|
517
|
+
this._connection.close();
|
518
|
+
}
|
519
|
+
catch (error) {
|
520
|
+
console.log('close() | error closing the RTCPeerConnection: %o', error);
|
521
|
+
}
|
522
|
+
}
|
523
|
+
// Terminate signaling.
|
524
|
+
// Clear SIP timers.
|
525
|
+
for (const timer in this._timers) {
|
526
|
+
if (Object.prototype.hasOwnProperty.call(this._timers, timer)) {
|
527
|
+
clearTimeout(this._timers[timer]);
|
528
|
+
}
|
529
|
+
}
|
530
|
+
// Clear Session Timers.
|
531
|
+
clearTimeout(this._sessionTimers.timer);
|
532
|
+
// Terminate confirmed dialog.
|
533
|
+
if (this._dialog) {
|
534
|
+
this._dialog.terminate();
|
535
|
+
delete this._dialog;
|
536
|
+
}
|
537
|
+
// Terminate early dialogs.
|
538
|
+
for (const dialog in this._earlyDialogs) {
|
539
|
+
if (Object.prototype.hasOwnProperty.call(this._earlyDialogs, dialog)) {
|
540
|
+
this._earlyDialogs[dialog].terminate();
|
541
|
+
delete this._earlyDialogs[dialog];
|
542
|
+
}
|
543
|
+
}
|
544
|
+
// Terminate REFER subscribers.
|
545
|
+
for (const subscriber in this._referSubscribers) {
|
546
|
+
if (Object.prototype.hasOwnProperty.call(this._referSubscribers, subscriber)) {
|
547
|
+
delete this._referSubscribers[subscriber];
|
548
|
+
}
|
549
|
+
}
|
550
|
+
this._ua.destroyMSRPSession(this);
|
551
|
+
}
|
552
|
+
_createDialog(message, type, early) {
|
553
|
+
const local_tag = (type === 'UAS') ? message.to_tag : message.from_tag;
|
554
|
+
const remote_tag = (type === 'UAS') ? message.from_tag : message.to_tag;
|
555
|
+
const id = message.call_id + local_tag + remote_tag;
|
556
|
+
let early_dialog = this._earlyDialogs[id];
|
557
|
+
// Early Dialog.
|
558
|
+
if (early) {
|
559
|
+
if (early_dialog) {
|
560
|
+
return true;
|
561
|
+
}
|
562
|
+
else {
|
563
|
+
early_dialog = new Dialog_1.default(this, message, type, Dialog_1.default.C.STATUS_EARLY);
|
564
|
+
// Dialog has been successfully created.
|
565
|
+
if (early_dialog.error) {
|
566
|
+
this._failed('remote', message, Constants_1.default.causes.INTERNAL_ERROR);
|
567
|
+
return false;
|
568
|
+
}
|
569
|
+
else {
|
570
|
+
this._earlyDialogs[id] = early_dialog;
|
571
|
+
return true;
|
572
|
+
}
|
573
|
+
}
|
574
|
+
}
|
575
|
+
// Confirmed Dialog.
|
576
|
+
else {
|
577
|
+
this._from_tag = message.from_tag;
|
578
|
+
this._to_tag = message.to_tag;
|
579
|
+
// In case the dialog is in _early_ state, update it.
|
580
|
+
if (early_dialog) {
|
581
|
+
early_dialog.update(message, type);
|
582
|
+
this._dialog = early_dialog;
|
583
|
+
delete this._earlyDialogs[id];
|
584
|
+
return true;
|
585
|
+
}
|
586
|
+
// Otherwise, create a _confirmed_ dialog.
|
587
|
+
const dialog = new Dialog_1.default(this, message, type);
|
588
|
+
if (dialog.error) {
|
589
|
+
this._failed('remote', message, Constants_1.default.causes.INTERNAL_ERROR);
|
590
|
+
return false;
|
591
|
+
}
|
592
|
+
else {
|
593
|
+
this._dialog = dialog;
|
594
|
+
return true;
|
595
|
+
}
|
596
|
+
}
|
597
|
+
}
|
598
|
+
_newMSRPSession(originator, request) {
|
599
|
+
this._ua.newMSRPSession(this, {
|
600
|
+
originator,
|
601
|
+
session: this,
|
602
|
+
request
|
603
|
+
});
|
604
|
+
}
|
605
|
+
_progress(originator, response) {
|
606
|
+
this.emit('progress', {
|
607
|
+
originator,
|
608
|
+
response: response || null
|
609
|
+
});
|
610
|
+
}
|
611
|
+
isEnded() {
|
612
|
+
switch (this._status) {
|
613
|
+
case C.STATUS_CANCELED:
|
614
|
+
case C.STATUS_TERMINATED:
|
615
|
+
return true;
|
616
|
+
default:
|
617
|
+
return false;
|
618
|
+
}
|
619
|
+
}
|
620
|
+
}
|
621
|
+
exports.MSRPSession = MSRPSession;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@voicenter-team/opensips-js",
|
3
|
-
"version": "1.0.
|
3
|
+
"version": "1.0.22",
|
4
4
|
"description": "The JS package for opensips",
|
5
5
|
"default": "src/index.ts",
|
6
6
|
"main": "build/index.js",
|
@@ -49,7 +49,7 @@
|
|
49
49
|
"dependencies": {
|
50
50
|
"@types/mime": "^3.0.1",
|
51
51
|
"generate-unique-id": "^2.0.1",
|
52
|
-
"jssip": "
|
52
|
+
"jssip": "3.10.0",
|
53
53
|
"loglevel": "^1.8.1",
|
54
54
|
"mime": "^3.0.0",
|
55
55
|
"p-iteration": "^1.1.8"
|