@voicenter-team/opensips-js 1.0.21 → 1.0.42

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/index.d.ts +737 -0
  2. package/dist/opensips-js.cjs.js +155 -0
  3. package/dist/opensips-js.es.js +21363 -0
  4. package/dist/opensips-js.iife.js +155 -0
  5. package/dist/opensips-js.umd.js +155 -0
  6. package/package.json +15 -9
  7. package/src/types/Dialog.d.ts +7 -0
  8. package/src/types/Socket.d.ts +8 -0
  9. package/src/types/Transactions.d.ts +9 -0
  10. package/src/types/UAExtended.d.ts +86 -0
  11. package/src/types/listeners.d.ts +26 -2
  12. package/src/types/msrp.d.ts +55 -0
  13. package/src/types/rtc.d.ts +23 -4
  14. package/src/types/timer.d.ts +7 -0
  15. package/build/enum/call.event.listener.type.d.ts +0 -7
  16. package/build/enum/call.event.listener.type.js +0 -10
  17. package/build/enum/metric.keys.to.include.d.ts +0 -2
  18. package/build/enum/metric.keys.to.include.js +0 -4
  19. package/build/helpers/UA/index.d.ts +0 -6
  20. package/build/helpers/UA/index.js +0 -9
  21. package/build/helpers/audio.helper.d.ts +0 -9
  22. package/build/helpers/audio.helper.js +0 -61
  23. package/build/helpers/filter.helper.d.ts +0 -2
  24. package/build/helpers/filter.helper.js +0 -14
  25. package/build/helpers/time.helper.d.ts +0 -16
  26. package/build/helpers/time.helper.js +0 -28
  27. package/build/helpers/volume.helper.d.ts +0 -2
  28. package/build/helpers/volume.helper.js +0 -76
  29. package/build/helpers/webrtcmetrics/collector.d.ts +0 -32
  30. package/build/helpers/webrtcmetrics/collector.js +0 -282
  31. package/build/helpers/webrtcmetrics/engine.d.ts +0 -20
  32. package/build/helpers/webrtcmetrics/engine.js +0 -164
  33. package/build/helpers/webrtcmetrics/exporter.d.ts +0 -116
  34. package/build/helpers/webrtcmetrics/exporter.js +0 -528
  35. package/build/helpers/webrtcmetrics/extractor.d.ts +0 -1
  36. package/build/helpers/webrtcmetrics/extractor.js +0 -976
  37. package/build/helpers/webrtcmetrics/index.d.ts +0 -63
  38. package/build/helpers/webrtcmetrics/index.js +0 -93
  39. package/build/helpers/webrtcmetrics/metrics.d.ts +0 -2
  40. package/build/helpers/webrtcmetrics/metrics.js +0 -8
  41. package/build/helpers/webrtcmetrics/probe.d.ts +0 -76
  42. package/build/helpers/webrtcmetrics/probe.js +0 -153
  43. package/build/helpers/webrtcmetrics/utils/config.d.ts +0 -12
  44. package/build/helpers/webrtcmetrics/utils/config.js +0 -28
  45. package/build/helpers/webrtcmetrics/utils/helper.d.ts +0 -13
  46. package/build/helpers/webrtcmetrics/utils/helper.js +0 -134
  47. package/build/helpers/webrtcmetrics/utils/log.d.ts +0 -7
  48. package/build/helpers/webrtcmetrics/utils/log.js +0 -71
  49. package/build/helpers/webrtcmetrics/utils/models.d.ts +0 -309
  50. package/build/helpers/webrtcmetrics/utils/models.js +0 -298
  51. package/build/helpers/webrtcmetrics/utils/score.d.ts +0 -4
  52. package/build/helpers/webrtcmetrics/utils/score.js +0 -235
  53. package/build/helpers/webrtcmetrics/utils/shortUUId.d.ts +0 -1
  54. package/build/helpers/webrtcmetrics/utils/shortUUId.js +0 -7
  55. package/build/index.d.ts +0 -181
  56. package/build/index.js +0 -911
package/build/index.js DELETED
@@ -1,911 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- const jssip_1 = __importDefault(require("jssip"));
16
- const UA_1 = __importDefault(require("./helpers/UA"));
17
- const p_iteration_1 = require("p-iteration");
18
- const time_helper_1 = require("./helpers/time.helper");
19
- const filter_helper_1 = require("./helpers/filter.helper");
20
- const audio_helper_1 = require("./helpers/audio.helper");
21
- const metrics_1 = __importDefault(require("./helpers/webrtcmetrics/metrics"));
22
- const metric_keys_to_include_1 = require("./enum/metric.keys.to.include");
23
- const call_event_listener_type_1 = require("./enum/call.event.listener.type");
24
- const CALL_STATUS_UNANSWERED = 0;
25
- const STORAGE_KEYS = {
26
- SELECTED_INPUT_DEVICE: 'selectedInputDevice',
27
- SELECTED_OUTPUT_DEVICE: 'selectedOutputDevice'
28
- };
29
- class OpenSIPSJS extends UA_1.default {
30
- constructor(options) {
31
- const configuration = Object.assign(Object.assign({}, options.configuration), { sockets: options.socketInterfaces.map(sock => new jssip_1.default.WebSocketInterface(sock)) });
32
- super(configuration);
33
- this.initialized = false;
34
- this.newRTCSessionEventName = 'newRTCSession';
35
- this.registeredEventName = 'registered';
36
- this.unregisteredEventName = 'unregistered';
37
- this.activeCalls = {};
38
- this.extendedCalls = {};
39
- this.state = {
40
- isMuted: false,
41
- isAutoAnswer: false,
42
- activeCalls: {},
43
- extendedCalls: {},
44
- availableMediaDevices: [],
45
- selectedMediaDevices: {
46
- input: 'default',
47
- output: 'default' //localStorage.getItem(STORAGE_KEYS.SELECTED_OUTPUT_DEVICE) || 'default'
48
- },
49
- microphoneInputLevel: 2,
50
- speakerVolume: 1,
51
- muteWhenJoin: false,
52
- originalStream: null,
53
- isDND: false,
54
- listeners: {},
55
- activeRooms: {},
56
- callStatus: {},
57
- callTime: {},
58
- timeIntervals: {},
59
- callMetrics: {},
60
- metricConfig: {
61
- refreshEvery: 1000,
62
- }
63
- };
64
- this.options = options;
65
- }
66
- on(type, listener) {
67
- return super.on(type, listener);
68
- }
69
- off(type, listener) {
70
- return super.off(type, listener);
71
- }
72
- emit(type, args) {
73
- return super.emit(type, args);
74
- }
75
- get sipDomain() {
76
- return this.options.sipDomain;
77
- }
78
- get sipOptions() {
79
- const options = Object.assign(Object.assign({}, this.options.sipOptions), { mediaConstraints: this.getUserMediaConstraints });
80
- return options;
81
- }
82
- get currentActiveRoomId() {
83
- return this._currentActiveRoomId;
84
- }
85
- set currentActiveRoomId(roomId) {
86
- this._currentActiveRoomId = roomId;
87
- this.emit('currentActiveRoomChanged', roomId);
88
- }
89
- get autoAnswer() {
90
- return this.state.isAutoAnswer;
91
- }
92
- set autoAnswer(value) {
93
- this.state.isAutoAnswer = value;
94
- }
95
- get callAddingInProgress() {
96
- return this._callAddingInProgress;
97
- }
98
- set callAddingInProgress(value) {
99
- this._callAddingInProgress = value;
100
- this.emit('callAddingInProgressChanged', value);
101
- }
102
- get muteWhenJoin() {
103
- return this.state.muteWhenJoin;
104
- }
105
- set muteWhenJoin(value) {
106
- this.state.muteWhenJoin = value;
107
- this.emit('changeMuteWhenJoin', value);
108
- }
109
- get isDND() {
110
- return this.state.isDND;
111
- }
112
- set isDND(value) {
113
- this.state.isDND = value;
114
- this.emit('changeIsDND', value);
115
- }
116
- get speakerVolume() {
117
- return this.state.speakerVolume;
118
- }
119
- set speakerVolume(value) {
120
- this.state.speakerVolume = value;
121
- Object.values(this.state.extendedCalls).forEach((call) => {
122
- if (call.audioTag) {
123
- call.audioTag.volume = value;
124
- }
125
- });
126
- }
127
- get microphoneInputLevel() {
128
- return this.state.microphoneInputLevel;
129
- }
130
- set microphoneInputLevel(value) {
131
- this.state.microphoneInputLevel = value;
132
- this.roomReconfigure(this.currentActiveRoomId);
133
- }
134
- get getActiveCalls() {
135
- return this.state.activeCalls;
136
- }
137
- get hasActiveCalls() {
138
- return Object.values(this.state.extendedCalls).length > 0;
139
- }
140
- get getActiveRooms() {
141
- return this.state.activeRooms;
142
- }
143
- get isMuted() {
144
- return this.state.isMuted;
145
- }
146
- set isMuted(value) {
147
- this.state.isMuted = value;
148
- this.emit('changeIsMuted', value);
149
- }
150
- get getInputDeviceList() {
151
- return this.state.availableMediaDevices.filter(device => device.kind === 'audioinput');
152
- }
153
- get getOutputDeviceList() {
154
- return this.state.availableMediaDevices.filter(device => device.kind === 'audiooutput');
155
- }
156
- /*getInputDeviceList: (state) => {
157
- return state.availableMediaDevices.filter(device => device.kind === 'audioinput');
158
- },
159
- getOutputDeviceList: (state) => {
160
- return state.availableMediaDevices.filter(device => device.kind === 'audiooutput');
161
- }*/
162
- get getUserMediaConstraints() {
163
- return {
164
- audio: {
165
- deviceId: {
166
- exact: this.state.selectedMediaDevices.input
167
- }
168
- },
169
- video: false
170
- };
171
- }
172
- get getInputDefaultDevice() {
173
- return this.getInputDeviceList.find(device => device.deviceId === 'default');
174
- }
175
- get getOutputDefaultDevice() {
176
- return this.getOutputDeviceList.find(device => device.deviceId === 'default');
177
- }
178
- get selectedInputDevice() {
179
- return this.state.selectedMediaDevices.input;
180
- }
181
- set selectedInputDevice(deviceId) {
182
- localStorage.setItem(STORAGE_KEYS.SELECTED_INPUT_DEVICE, deviceId);
183
- this.state.selectedMediaDevices.input = deviceId;
184
- this.emit('changeActiveInputMediaDevice', deviceId);
185
- }
186
- get selectedOutputDevice() {
187
- return this.state.selectedMediaDevices.output;
188
- }
189
- set selectedOutputDevice(deviceId) {
190
- localStorage.setItem(STORAGE_KEYS.SELECTED_OUTPUT_DEVICE, deviceId);
191
- this.state.selectedMediaDevices.output = deviceId;
192
- this.emit('changeActiveOutputMediaDevice', deviceId);
193
- }
194
- get originalStream() {
195
- return this.state.originalStream;
196
- }
197
- setAvailableMediaDevices(devices) {
198
- this.state.availableMediaDevices = devices;
199
- this.emit('changeAvailableDeviceList', devices);
200
- }
201
- updateDeviceList() {
202
- return __awaiter(this, void 0, void 0, function* () {
203
- yield navigator.mediaDevices.getUserMedia(this.getUserMediaConstraints);
204
- const devices = yield navigator.mediaDevices.enumerateDevices();
205
- this.setAvailableMediaDevices(devices);
206
- });
207
- }
208
- setMediaDevices(setDefaults = false) {
209
- var _a, _b;
210
- return __awaiter(this, void 0, void 0, function* () {
211
- this.state.selectedMediaDevices.input = localStorage.getItem(STORAGE_KEYS.SELECTED_INPUT_DEVICE) || 'default';
212
- this.state.selectedMediaDevices.output = localStorage.getItem(STORAGE_KEYS.SELECTED_OUTPUT_DEVICE) || 'default';
213
- yield navigator.mediaDevices.getUserMedia(this.getUserMediaConstraints);
214
- const devices = yield navigator.mediaDevices.enumerateDevices();
215
- this.setAvailableMediaDevices(devices);
216
- const defaultMicrophone = setDefaults
217
- ? ((_a = this.getInputDefaultDevice) === null || _a === void 0 ? void 0 : _a.deviceId) || ''
218
- : '';
219
- const defaultSpeaker = setDefaults
220
- ? ((_b = this.getOutputDefaultDevice) === null || _b === void 0 ? void 0 : _b.deviceId) || ''
221
- : '';
222
- yield this.setMicrophone(defaultMicrophone);
223
- yield this.setSpeaker(defaultSpeaker);
224
- });
225
- }
226
- setCallTime(value) {
227
- const time = Object.assign({}, value);
228
- delete time.callId;
229
- this.state.callTime = Object.assign(Object.assign({}, this.state.callTime), { [value.callId]: time });
230
- }
231
- removeCallTime(callId) {
232
- const callTimeCopy = Object.assign({}, this.state.callTime);
233
- delete callTimeCopy[callId];
234
- this.state.callTime = Object.assign({}, callTimeCopy);
235
- }
236
- setTimeInterval(callId, interval) {
237
- this.state.timeIntervals = Object.assign(Object.assign({}, this.state.timeIntervals), { [callId]: interval });
238
- }
239
- removeTimeInterval(callId) {
240
- const timeIntervalsCopy = Object.assign({}, this.state.timeIntervals);
241
- clearInterval(timeIntervalsCopy[callId]);
242
- delete timeIntervalsCopy[callId];
243
- this.state.timeIntervals = Object.assign({}, timeIntervalsCopy);
244
- }
245
- _stopCallTimer(callId) {
246
- this.removeTimeInterval(callId);
247
- this.removeCallTime(callId);
248
- }
249
- setMetricsConfig(config) {
250
- this.state.metricConfig = Object.assign(Object.assign({}, this.state.metricConfig), config);
251
- }
252
- sendDTMF(callId, value) {
253
- const validation_regex = /^[A-D0-9]+$/g;
254
- if (!validation_regex.test(value)) {
255
- throw new Error('Not allowed character in DTMF input');
256
- }
257
- const call = this.state.extendedCalls[callId];
258
- call.sendDTMF(value);
259
- }
260
- doMute(value) {
261
- const activeRoomId = this.currentActiveRoomId;
262
- this.isMuted = value;
263
- this.roomReconfigure(activeRoomId);
264
- }
265
- sendMessage(target, body, options) {
266
- return super.sendMessage(`sip:${target}@${this.sipDomain}`, body, options);
267
- }
268
- doCallHold({ callId, toHold, automatic }) {
269
- const call = this.state.extendedCalls[callId];
270
- call._automaticHold = automatic !== null && automatic !== void 0 ? automatic : false;
271
- if (toHold) {
272
- call.hold();
273
- }
274
- else {
275
- call.unhold();
276
- }
277
- }
278
- _cancelAllOutgoingUnanswered() {
279
- Object.values(this.getActiveCalls).filter(call => {
280
- return call.direction === 'outgoing'
281
- && call.status === CALL_STATUS_UNANSWERED;
282
- }).forEach(call => this.callTerminate(call._id));
283
- }
284
- callAnswer(callId) {
285
- const call = this.state.extendedCalls[callId];
286
- this._cancelAllOutgoingUnanswered();
287
- call.answer(this.sipOptions);
288
- this.updateCall(call);
289
- // TODO: maybe would be better to move to the top
290
- this.setCurrentActiveRoomId(call.roomId);
291
- call.connection.addEventListener('addstream', (event) => __awaiter(this, void 0, void 0, function* () {
292
- this._triggerAddStream(event, call);
293
- }));
294
- }
295
- callMove(callId, roomId) {
296
- return __awaiter(this, void 0, void 0, function* () {
297
- this._updateCallStatus({ callId, isMoving: true });
298
- yield this.callChangeRoom({ callId, roomId });
299
- this._updateCallStatus({ callId, isMoving: false });
300
- });
301
- }
302
- updateCall(value) {
303
- this.state.activeCalls[value._id] = (0, audio_helper_1.simplifyCallObject)(value);
304
- this.emit('changeActiveCalls', this.state.activeCalls);
305
- }
306
- updateRoom(value) {
307
- const room = this.state.activeRooms[value.roomId];
308
- const newRoomData = Object.assign(Object.assign({}, room), value);
309
- this.state.activeRooms = Object.assign(Object.assign({}, this.state.activeRooms), { [value.roomId]: Object.assign({}, newRoomData) });
310
- this.emit('updateRoom', { room: newRoomData, roomList: this.state.activeRooms });
311
- }
312
- hasAutoAnswerHeaders(event) {
313
- const regex = /answer-after=0/;
314
- const request = event.request;
315
- const callInfoHeader = request.getHeader('Call-Info');
316
- return callInfoHeader && regex.test(callInfoHeader);
317
- }
318
- _addCall(value, emitEvent = true) {
319
- this.state.activeCalls = Object.assign(Object.assign({}, this.state.activeCalls), { [value._id]: (0, audio_helper_1.simplifyCallObject)(value) });
320
- /*this.state.extendedCalls = {
321
- ...this.state.extendedCalls,
322
- [value._id]: value
323
- }*/
324
- this.state.extendedCalls[value._id] = value;
325
- if (emitEvent) {
326
- this.emit('changeActiveCalls', this.state.activeCalls);
327
- }
328
- }
329
- _addCallStatus(callId) {
330
- this.state.callStatus = Object.assign(Object.assign({}, this.state.callStatus), { [callId]: {
331
- isMoving: false,
332
- isTransferring: false,
333
- isMerging: false
334
- } });
335
- this.emit('changeCallStatus', this.state.callStatus);
336
- }
337
- _updateCallStatus(value) {
338
- const prevStatus = Object.assign({}, this.state.callStatus[value.callId]);
339
- const newStatus = Object.assign({}, prevStatus);
340
- if (value.isMoving !== undefined) {
341
- newStatus.isMoving = value.isMoving;
342
- }
343
- if (value.isTransferring !== undefined) {
344
- newStatus.isTransferring = value.isTransferring;
345
- }
346
- if (value.isMerging !== undefined) {
347
- newStatus.isMerging = value.isMerging;
348
- }
349
- this.state.callStatus = Object.assign(Object.assign({}, this.state.callStatus), { [value.callId]: Object.assign({}, newStatus) });
350
- this.emit('changeCallStatus', this.state.callStatus);
351
- }
352
- _removeCallStatus(callId) {
353
- const callStatusCopy = Object.assign({}, this.state.callStatus);
354
- delete callStatusCopy[callId];
355
- this.state.callStatus = Object.assign({}, callStatusCopy);
356
- this.emit('changeCallStatus', this.state.callStatus);
357
- }
358
- _addRoom(value) {
359
- this.state.activeRooms = Object.assign(Object.assign({}, this.state.activeRooms), { [value.roomId]: value });
360
- this.emit('addRoom', { room: value, roomList: this.state.activeRooms });
361
- }
362
- setMicrophone(dId) {
363
- return __awaiter(this, void 0, void 0, function* () {
364
- if (!this.getInputDeviceList.find(({ deviceId }) => deviceId === dId)) {
365
- return;
366
- }
367
- this.selectedInputDevice = dId;
368
- let stream; // = null
369
- try {
370
- stream = yield navigator.mediaDevices.getUserMedia(this.getUserMediaConstraints);
371
- }
372
- catch (err) {
373
- console.error(err);
374
- }
375
- if (Object.keys(this.getActiveCalls).length === 0) {
376
- return;
377
- }
378
- const callsInCurrentRoom = Object.values(this.state.extendedCalls).filter(call => call.roomId === this.currentActiveRoomId);
379
- if (callsInCurrentRoom.length === 1) {
380
- Object.values(callsInCurrentRoom).forEach(call => {
381
- const processedStream = (0, audio_helper_1.processAudioVolume)(stream, this.microphoneInputLevel);
382
- processedStream.getTracks().forEach(track => track.enabled = !this.isMuted);
383
- this._setOriginalStream(processedStream);
384
- call.connection.getSenders()[0].replaceTrack(processedStream.getTracks()[0]);
385
- this.updateCall(call);
386
- });
387
- }
388
- else {
389
- yield this._doConference(callsInCurrentRoom);
390
- }
391
- });
392
- }
393
- _setOriginalStream(value) {
394
- this.state.originalStream = value;
395
- this.emit('changeOriginalStream', value);
396
- }
397
- setSpeaker(dId) {
398
- return __awaiter(this, void 0, void 0, function* () {
399
- if (!this.getOutputDeviceList.find(({ deviceId }) => deviceId === dId)) {
400
- return;
401
- }
402
- this.selectedOutputDevice = dId;
403
- const activeCallList = Object.values(this.state.extendedCalls);
404
- if (activeCallList.length === 0) {
405
- return;
406
- }
407
- const callsInCurrentRoom = activeCallList.filter(call => call.roomId === this.currentActiveRoomId);
408
- if (callsInCurrentRoom.length === 1) {
409
- activeCallList.forEach(call => {
410
- var _a;
411
- (_a = call.audioTag) === null || _a === void 0 ? void 0 : _a.setSinkId(dId);
412
- this.updateCall(call);
413
- });
414
- }
415
- else {
416
- yield this._doConference(callsInCurrentRoom);
417
- }
418
- });
419
- }
420
- removeRoom(roomId) {
421
- const activeRoomsCopy = Object.assign({}, this.state.activeRooms);
422
- const roomToRemove = Object.assign({}, activeRoomsCopy[roomId]);
423
- delete activeRoomsCopy[roomId];
424
- this.state.activeRooms = Object.assign({}, activeRoomsCopy);
425
- this.emit('removeRoom', { room: roomToRemove, roomList: this.state.activeRooms });
426
- }
427
- deleteRoomIfEmpty(roomId) {
428
- if (roomId === undefined) {
429
- return;
430
- }
431
- if (Object.values(this.state.extendedCalls).filter(call => call.roomId === roomId).length === 0) {
432
- this.removeRoom(roomId);
433
- if (this.currentActiveRoomId === roomId) {
434
- this.currentActiveRoomId = undefined;
435
- }
436
- }
437
- }
438
- checkInitialized() {
439
- if (!this.initialized) {
440
- throw new Error('[OpenSIPSJS] You must call `start` method first!');
441
- }
442
- }
443
- muteReconfigure(call) {
444
- if (this.state.isMuted) {
445
- call.mute({ audio: true });
446
- }
447
- else {
448
- call.unmute({ audio: true });
449
- }
450
- }
451
- roomReconfigure(roomId) {
452
- return __awaiter(this, void 0, void 0, function* () {
453
- if (roomId === undefined) {
454
- return;
455
- }
456
- const callsInRoom = Object.values(this.state.extendedCalls).filter(call => call.roomId === roomId);
457
- // Let`s take care on the audio output first and check if passed room is our selected room
458
- if (this.currentActiveRoomId === roomId) {
459
- callsInRoom.forEach(call => {
460
- if (call.audioTag) {
461
- this.muteReconfigure(call);
462
- call.audioTag.muted = false;
463
- this.updateCall(call);
464
- }
465
- });
466
- }
467
- else {
468
- callsInRoom.forEach(call => {
469
- if (call.audioTag) {
470
- call.audioTag.muted = true;
471
- this.updateCall(call);
472
- }
473
- });
474
- }
475
- // Now let`s configure the sound we are sending for each active call on this room
476
- if (callsInRoom.length === 0) {
477
- this.deleteRoomIfEmpty(roomId);
478
- }
479
- else if (callsInRoom.length === 1 && this.currentActiveRoomId !== roomId) {
480
- if (!callsInRoom[0].isOnHold().local) {
481
- this.doCallHold({ callId: callsInRoom[0].id, toHold: true, automatic: true });
482
- }
483
- }
484
- else if (callsInRoom.length === 1 && this.currentActiveRoomId === roomId) {
485
- if (callsInRoom[0].isOnHold().local && callsInRoom[0]._automaticHold) {
486
- this.doCallHold({ callId: callsInRoom[0].id, toHold: false });
487
- }
488
- let stream;
489
- try {
490
- stream = yield navigator.mediaDevices.getUserMedia(this.getUserMediaConstraints);
491
- }
492
- catch (err) {
493
- console.error(err);
494
- }
495
- if (stream && callsInRoom[0].connection && callsInRoom[0].connection.getSenders()[0]) {
496
- const processedStream = (0, audio_helper_1.processAudioVolume)(stream, this.microphoneInputLevel);
497
- processedStream.getTracks().forEach(track => track.enabled = !this.state.isMuted);
498
- this._setOriginalStream(processedStream);
499
- yield callsInRoom[0].connection.getSenders()[0].replaceTrack(processedStream.getTracks()[0]);
500
- this.muteReconfigure(callsInRoom[0]);
501
- }
502
- }
503
- else if (callsInRoom.length > 1) {
504
- yield this._doConference(callsInRoom);
505
- }
506
- });
507
- }
508
- _doConference(sessions) {
509
- return __awaiter(this, void 0, void 0, function* () {
510
- sessions.forEach(call => {
511
- if (call._localHold) {
512
- this.doCallHold({ callId: call._id, toHold: false });
513
- }
514
- });
515
- // Take all received tracks from the sessions you want to merge
516
- const receivedTracks = [];
517
- sessions.forEach(session => {
518
- if (session !== null && session !== undefined) {
519
- session.connection.getReceivers().forEach((receiver) => {
520
- receivedTracks.push(receiver.track);
521
- });
522
- }
523
- });
524
- // Use the Web Audio API to mix the received tracks
525
- const audioContext = new AudioContext();
526
- const allReceivedMediaStreams = new MediaStream();
527
- // For each call we will build dedicated mix for all other calls
528
- yield (0, p_iteration_1.forEach)(sessions, (session) => __awaiter(this, void 0, void 0, function* () {
529
- if (session === null || session === undefined) {
530
- return;
531
- }
532
- const mixedOutput = audioContext.createMediaStreamDestination();
533
- session.connection.getReceivers().forEach((receiver) => {
534
- receivedTracks.forEach(track => {
535
- allReceivedMediaStreams.addTrack(receiver.track);
536
- if (receiver.track.id !== track.id) {
537
- const sourceStream = audioContext.createMediaStreamSource(new MediaStream([track]));
538
- sourceStream.connect(mixedOutput);
539
- }
540
- });
541
- });
542
- if (sessions[0].roomId === this.currentActiveRoomId) {
543
- // Mixing your voice with all the received audio
544
- const stream = yield navigator.mediaDevices.getUserMedia(this.getUserMediaConstraints);
545
- const processedStream = (0, audio_helper_1.processAudioVolume)(stream, this.microphoneInputLevel);
546
- processedStream.getTracks().forEach(track => track.enabled = !this.isMuted);
547
- this._setOriginalStream(processedStream);
548
- const sourceStream = audioContext.createMediaStreamSource(processedStream);
549
- // stream.getTracks().forEach(track => track.enabled = !getters.isMuted) // TODO: Fix this
550
- sourceStream.connect(mixedOutput);
551
- }
552
- if (session.connection.getSenders()[0]) {
553
- //mixedOutput.stream.getTracks().forEach(track => track.enabled = !getters.isMuted) // Uncomment to mute all callers on mute
554
- yield session.connection.getSenders()[0].replaceTrack(mixedOutput.stream.getTracks()[0]);
555
- this._muteReconfigure(session);
556
- }
557
- }));
558
- });
559
- }
560
- _muteReconfigure(call) {
561
- if (this.isMuted) {
562
- call.mute({ audio: true });
563
- }
564
- else {
565
- call.unmute({ audio: true });
566
- }
567
- }
568
- muteCaller(callId, value) {
569
- const call = this.state.extendedCalls[callId];
570
- if (call && call.connection.getReceivers().length) {
571
- call.localMuted = value;
572
- call.connection.getReceivers().forEach((receiver) => {
573
- receiver.track.enabled = !value;
574
- });
575
- this.updateCall(call);
576
- this.roomReconfigure(call.roomId);
577
- }
578
- }
579
- callTerminate(callId) {
580
- const call = this.state.extendedCalls[callId];
581
- if (call._status !== 8) {
582
- call.terminate();
583
- }
584
- }
585
- callTransfer(callId, target) {
586
- if (target.toString().length === 0) {
587
- return console.error('Target must be passed');
588
- }
589
- const call = this.state.extendedCalls[callId];
590
- if (!call._is_confirmed && !call._is_canceled) {
591
- const redirectTarget = `sip:${target}@${this.sipDomain}`;
592
- call.terminate({
593
- status_code: 302,
594
- reason_phrase: 'Moved Temporarily',
595
- extraHeaders: [`Contact: ${redirectTarget}`]
596
- });
597
- return;
598
- }
599
- this._updateCallStatus({ callId, isTransferring: true });
600
- call.refer(`sip:${target}@${this.sipDomain}`);
601
- this.updateCall(call);
602
- }
603
- callMerge(roomId) {
604
- const callsInRoom = Object.values(this.state.extendedCalls).filter((call) => call.roomId === roomId);
605
- if (callsInRoom.length !== 2)
606
- return;
607
- const firstCall = callsInRoom[0];
608
- const secondCall = callsInRoom[1];
609
- if (!firstCall || !secondCall) {
610
- return;
611
- }
612
- // TODO: Check all call.id for working in the same way as call._id
613
- this._updateCallStatus({ callId: firstCall._id, isMerging: true });
614
- this._updateCallStatus({ callId: secondCall._id, isMerging: true });
615
- firstCall.refer(secondCall.remote_identity.uri.toString(), { 'replaces': secondCall });
616
- this.updateCall(firstCall);
617
- }
618
- // TODO: Use this method in demo
619
- setDND(value) {
620
- this.isDND = value;
621
- }
622
- _startCallTimer(callId) {
623
- const timeData = {
624
- callId,
625
- hours: 0,
626
- minutes: 0,
627
- seconds: 0,
628
- formatted: ''
629
- };
630
- this.setCallTime(timeData);
631
- const interval = setInterval(() => {
632
- const callTime = Object.assign({}, this.state.callTime[callId]);
633
- const updatedTime = (0, time_helper_1.setupTime)(callTime);
634
- this.setCallTime(Object.assign({ callId }, updatedTime));
635
- }, 1000);
636
- this.setTimeInterval(callId, interval);
637
- }
638
- setCurrentActiveRoomId(roomId) {
639
- return __awaiter(this, void 0, void 0, function* () {
640
- const oldRoomId = this.currentActiveRoomId;
641
- if (roomId === oldRoomId) {
642
- return;
643
- }
644
- this.currentActiveRoomId = roomId;
645
- yield this.roomReconfigure(oldRoomId);
646
- yield this.roomReconfigure(roomId);
647
- });
648
- }
649
- getNewRoomId() {
650
- const roomIdList = Object.keys(this.state.activeRooms);
651
- if (roomIdList.length === 0) {
652
- return 1;
653
- }
654
- return (parseInt(roomIdList.sort()[roomIdList.length - 1]) + 1);
655
- }
656
- subscribe(type, listener) {
657
- const isListenerEmpty = !this.state.listeners[type] || !this.state.listeners[type].length;
658
- const newListeners = isListenerEmpty ? [listener] : [...this.state.listeners[type], listener];
659
- this.state.listeners = Object.assign(Object.assign({}, this.state.listeners), { [type]: newListeners });
660
- }
661
- removeIListener(value) {
662
- const listenersCopy = Object.assign({}, this.state.listeners);
663
- delete listenersCopy[value];
664
- this.state.listeners = Object.assign({}, listenersCopy);
665
- }
666
- addCall(event) {
667
- return __awaiter(this, void 0, void 0, function* () {
668
- const session = event.session;
669
- const sessionAlreadyInActiveCalls = this.getActiveCalls[session.id];
670
- if (sessionAlreadyInActiveCalls !== undefined) {
671
- return;
672
- }
673
- const roomId = this.getNewRoomId();
674
- const newRoomInfo = {
675
- started: new Date(),
676
- incomingInProgress: false,
677
- roomId
678
- };
679
- if (session.direction === 'incoming') {
680
- newRoomInfo.incomingInProgress = true;
681
- this.subscribe(call_event_listener_type_1.CALL_EVENT_LISTENER_TYPE.CALL_CONFIRMED, (call) => {
682
- if (session.id === call.id) {
683
- this.updateRoom({
684
- incomingInProgress: false,
685
- roomId
686
- });
687
- this._startCallTimer(session.id);
688
- }
689
- });
690
- this.subscribe(call_event_listener_type_1.CALL_EVENT_LISTENER_TYPE.CALL_FAILED, (call) => {
691
- if (session.id === call.id) {
692
- this.updateRoom({
693
- incomingInProgress: false,
694
- roomId
695
- });
696
- this.deleteRoomIfEmpty(roomId);
697
- }
698
- });
699
- }
700
- else if (session.direction === 'outgoing') {
701
- this._startCallTimer(session.id);
702
- }
703
- const call = session;
704
- const autoAnswerByHeaders = this.hasAutoAnswerHeaders(event);
705
- const doAutoAnswer = call.direction === 'incoming' && !this.hasActiveCalls && (autoAnswerByHeaders || this.autoAnswer);
706
- call.roomId = roomId;
707
- call.localMuted = false;
708
- call.autoAnswer = doAutoAnswer;
709
- if (doAutoAnswer) {
710
- this._addCall(call, false);
711
- }
712
- else {
713
- this._addCall(call);
714
- }
715
- // this._addCall(call)
716
- this._addCallStatus(session.id);
717
- this._addRoom(newRoomInfo);
718
- if (doAutoAnswer) {
719
- this.callAnswer(call._id);
720
- }
721
- });
722
- }
723
- _triggerListener({ listenerType, session, event }) {
724
- const listeners = this.state.listeners[listenerType];
725
- if (!listeners || !listeners.length) {
726
- return;
727
- }
728
- listeners.forEach((listener) => {
729
- listener(session, event);
730
- });
731
- }
732
- _removeCall(value) {
733
- const stateActiveCallsCopy = Object.assign({}, this.state.activeCalls);
734
- delete stateActiveCallsCopy[value];
735
- // delete activeCalls[value]
736
- this.state.activeCalls = Object.assign({}, stateActiveCallsCopy);
737
- const stateExtendedCallsCopy = Object.assign({}, this.state.extendedCalls);
738
- delete stateExtendedCallsCopy[value];
739
- this.state.extendedCalls = Object.assign({}, stateExtendedCallsCopy);
740
- this.emit('changeActiveCalls', this.state.activeCalls);
741
- }
742
- _activeCallListRemove(call) {
743
- const callRoomIdToConfigure = this.state.extendedCalls[call._id].roomId;
744
- this._removeCall(call._id);
745
- this.roomReconfigure(callRoomIdToConfigure);
746
- }
747
- newRTCSessionCallback(event) {
748
- const session = event.session;
749
- if (this.isDND) {
750
- session.terminate({ status_code: 486, reason_phrase: 'Do Not Disturb' });
751
- return;
752
- }
753
- // stop timers on ended and failed
754
- session.on('ended', (event) => {
755
- this._triggerListener({ listenerType: call_event_listener_type_1.CALL_EVENT_LISTENER_TYPE.CALL_ENDED, session, event });
756
- const s = this.getActiveCalls[session.id];
757
- if (s) {
758
- this._activeCallListRemove(s);
759
- }
760
- this._stopCallTimer(session.id);
761
- this._removeCallStatus(session.id);
762
- this._removeCallMetrics(session.id);
763
- if (!Object.keys(this.state.extendedCalls).length) {
764
- this.isMuted = false;
765
- }
766
- });
767
- session.on('progress', (event) => {
768
- this._triggerListener({ listenerType: call_event_listener_type_1.CALL_EVENT_LISTENER_TYPE.CALL_PROGRESS, session, event });
769
- });
770
- session.on('failed', (event) => {
771
- this._triggerListener({ listenerType: call_event_listener_type_1.CALL_EVENT_LISTENER_TYPE.CALL_FAILED, session, event });
772
- if (session.id === this.callAddingInProgress) {
773
- this.callAddingInProgress = undefined;
774
- }
775
- const s = this.getActiveCalls[session.id];
776
- if (s) {
777
- this._activeCallListRemove(s);
778
- }
779
- this._stopCallTimer(session.id);
780
- this._removeCallStatus(session.id);
781
- this._removeCallMetrics(session.id);
782
- if (!Object.keys(this.state.extendedCalls).length) {
783
- this.isMuted = false;
784
- }
785
- });
786
- session.on('confirmed', (event) => {
787
- this._triggerListener({ listenerType: call_event_listener_type_1.CALL_EVENT_LISTENER_TYPE.CALL_CONFIRMED, session, event });
788
- this.updateCall(session);
789
- if (session.id === this.callAddingInProgress) {
790
- this.callAddingInProgress = undefined;
791
- }
792
- });
793
- this.addCall(event);
794
- if (session.direction === 'outgoing') {
795
- const roomId = this.getActiveCalls[session.id].roomId;
796
- this.setCurrentActiveRoomId(roomId);
797
- }
798
- }
799
- setInitialized(value) {
800
- this.initialized = value;
801
- this.emit('ready', value);
802
- }
803
- start() {
804
- this.on(this.registeredEventName, () => {
805
- this.setInitialized(true);
806
- });
807
- this.on(this.unregisteredEventName, () => {
808
- this.setInitialized(false);
809
- });
810
- this.on(this.newRTCSessionEventName, this.newRTCSessionCallback.bind(this));
811
- super.start();
812
- this.setMediaDevices(true);
813
- return this;
814
- }
815
- setMuteWhenJoin(value) {
816
- this.muteWhenJoin = value;
817
- }
818
- _setCallMetrics(value) {
819
- const metrics = Object.assign({}, value);
820
- delete metrics['callId'];
821
- this.state.callMetrics = Object.assign(Object.assign({}, this.state.callMetrics), { [value.callId]: metrics });
822
- }
823
- _removeCallMetrics(callId) {
824
- const callMetricsCopy = Object.assign({}, this.state.callMetrics);
825
- delete callMetricsCopy[callId];
826
- this.state.callMetrics = Object.assign({}, callMetricsCopy);
827
- }
828
- _getCallQuality(call) {
829
- const metrics = new metrics_1.default(this.state.metricConfig);
830
- const probe = metrics.createProbe(call.connection, {
831
- cid: call._id
832
- });
833
- const inboundKeys = [];
834
- let inboundAudio;
835
- probe.onreport = (probe) => {
836
- //console.log('probe', probe)
837
- /*const inboundMetrics = Object.entries(probe.audio).filter(([ key, value ]) => {
838
- return value.direction === 'inbound'
839
- })*/
840
- //const ioo = Object.entries(probe.audio).
841
- Object.entries(probe.audio).forEach(([key, value]) => {
842
- if (value.direction === 'inbound' && !inboundKeys.includes(key)) {
843
- inboundKeys.push(key);
844
- inboundAudio = key;
845
- }
846
- });
847
- /*inboundMetrics.forEach(([ key, value ]) => {
848
- if (!inboundKeys.includes(key)) {
849
- inboundKeys.push(key)
850
- inboundAudio = key
851
- }
852
- })*/
853
- const inboundAudioMetric = probe.audio[inboundAudio];
854
- const metric = (0, filter_helper_1.filterObjectKeys)(inboundAudioMetric, metric_keys_to_include_1.METRIC_KEYS_TO_INCLUDE);
855
- metric.callId = call._id;
856
- this._setCallMetrics(metrics);
857
- };
858
- this.subscribe(call_event_listener_type_1.CALL_EVENT_LISTENER_TYPE.CALL_ENDED, (session) => {
859
- if (session._id === call._id) {
860
- metrics.stopAllProbes();
861
- }
862
- });
863
- metrics.startAllProbes();
864
- }
865
- _triggerAddStream(event, call) {
866
- return __awaiter(this, void 0, void 0, function* () {
867
- this.isMuted = this.muteWhenJoin;
868
- const stream = yield navigator.mediaDevices.getUserMedia(this.getUserMediaConstraints);
869
- const processedStream = (0, audio_helper_1.processAudioVolume)(stream, this.microphoneInputLevel);
870
- const muteMicro = this.isMuted || this.muteWhenJoin;
871
- processedStream.getTracks().forEach(track => track.enabled = !muteMicro);
872
- this._setOriginalStream(processedStream);
873
- yield call.connection.getSenders()[0].replaceTrack(processedStream.getTracks()[0]);
874
- (0, audio_helper_1.syncStream)(event, call, this.selectedOutputDevice, this.speakerVolume);
875
- this._getCallQuality(call);
876
- this.updateCall(call);
877
- });
878
- }
879
- doCall({ target, addToCurrentRoom }) {
880
- this.checkInitialized();
881
- if (target.length === 0) {
882
- return console.error('Target must be a valid string');
883
- }
884
- const call = this.call(`sip:${target}@${this.sipDomain}`, this.sipOptions);
885
- this.callAddingInProgress = call.id;
886
- if (addToCurrentRoom && this.currentActiveRoomId !== undefined) {
887
- this.callChangeRoom({
888
- callId: call.id,
889
- roomId: this.currentActiveRoomId
890
- });
891
- }
892
- call.connection.addEventListener('addstream', (event) => {
893
- this._triggerAddStream(event, call);
894
- });
895
- }
896
- callChangeRoom({ callId, roomId }) {
897
- return __awaiter(this, void 0, void 0, function* () {
898
- const oldRoomId = this.state.extendedCalls[callId].roomId;
899
- this.state.extendedCalls[callId].roomId = roomId;
900
- yield this.setCurrentActiveRoomId(roomId);
901
- return Promise.all([
902
- this.roomReconfigure(oldRoomId),
903
- this.roomReconfigure(roomId)
904
- ]).then(() => {
905
- this.deleteRoomIfEmpty(oldRoomId);
906
- this.deleteRoomIfEmpty(roomId);
907
- });
908
- });
909
- }
910
- }
911
- exports.default = OpenSIPSJS;