@wazo/sdk 0.37.30 → 0.37.34

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 (80) hide show
  1. package/dist/wazo-sdk.js +4 -4
  2. package/esm/__tests__/api-client.test.js +30 -0
  3. package/esm/__tests__/web-rtc-client.test.js +57 -6
  4. package/esm/api/calld.js +30 -0
  5. package/esm/api-client.js +30 -0
  6. package/esm/checker/Checker.js +57 -6
  7. package/esm/checker/checks/aor.js +30 -0
  8. package/esm/checker/checks/api.js +30 -0
  9. package/esm/checker/checks/index.js +57 -6
  10. package/esm/checker/checks/webrtc-transport.js +57 -6
  11. package/esm/checker/checks/webrtc.js +57 -6
  12. package/esm/domain/AdHocAPIConference.js +30 -0
  13. package/esm/domain/CallSession.js +9 -1
  14. package/esm/domain/Features.js +30 -0
  15. package/esm/domain/MeetingStatus.js +29 -0
  16. package/esm/domain/Phone/CTIPhone.js +39 -1
  17. package/esm/domain/Phone/WebRTCPhone.js +43 -8
  18. package/esm/domain/__tests__/CallSession.test.js +41 -5
  19. package/esm/domain/__tests__/IndirectTransfer.test.js +9 -1
  20. package/esm/domain/__tests__/Room.test.js +9 -1
  21. package/esm/index.js +100 -14
  22. package/esm/service/CallApi.js +30 -0
  23. package/esm/service/getApiClient.js +30 -0
  24. package/esm/simple/Auth.js +100 -14
  25. package/esm/simple/Configuration.js +100 -14
  26. package/esm/simple/Directory.js +30 -0
  27. package/esm/simple/Phone.js +100 -14
  28. package/esm/simple/index.js +100 -14
  29. package/esm/simple/room/LocalParticipant.js +100 -14
  30. package/esm/simple/room/Participant.js +100 -14
  31. package/esm/simple/room/RemoteParticipant.js +100 -14
  32. package/esm/simple/room/Room.js +100 -14
  33. package/esm/simple/room/SipRoom.js +100 -14
  34. package/esm/simple/room/Stream.js +100 -14
  35. package/esm/simple/room/__tests__/RemoteParticipant.test.js +100 -14
  36. package/esm/simple/utils.js +100 -14
  37. package/esm/web-rtc-client.js +57 -6
  38. package/lib/__tests__/api-client.test.js +30 -0
  39. package/lib/__tests__/web-rtc-client.test.js +57 -6
  40. package/lib/api/calld.js +30 -0
  41. package/lib/api-client.js +30 -0
  42. package/lib/checker/Checker.js +57 -6
  43. package/lib/checker/checks/aor.js +30 -0
  44. package/lib/checker/checks/api.js +30 -0
  45. package/lib/checker/checks/index.js +57 -6
  46. package/lib/checker/checks/webrtc-transport.js +57 -6
  47. package/lib/checker/checks/webrtc.js +57 -6
  48. package/lib/domain/AdHocAPIConference.js +30 -0
  49. package/lib/domain/CallSession.js +9 -1
  50. package/lib/domain/Features.js +30 -0
  51. package/lib/domain/MeetingStatus.js +31 -0
  52. package/lib/domain/Phone/CTIPhone.js +39 -1
  53. package/lib/domain/Phone/WebRTCPhone.js +43 -8
  54. package/lib/domain/__tests__/CallSession.test.js +41 -5
  55. package/lib/domain/__tests__/IndirectTransfer.test.js +9 -1
  56. package/lib/domain/__tests__/Room.test.js +9 -1
  57. package/lib/index.js +100 -14
  58. package/lib/service/CallApi.js +30 -0
  59. package/lib/service/getApiClient.js +30 -0
  60. package/lib/simple/Auth.js +100 -14
  61. package/lib/simple/Configuration.js +100 -14
  62. package/lib/simple/Directory.js +30 -0
  63. package/lib/simple/Phone.js +100 -14
  64. package/lib/simple/index.js +100 -14
  65. package/lib/simple/room/LocalParticipant.js +100 -14
  66. package/lib/simple/room/Participant.js +100 -14
  67. package/lib/simple/room/RemoteParticipant.js +100 -14
  68. package/lib/simple/room/Room.js +100 -14
  69. package/lib/simple/room/SipRoom.js +100 -14
  70. package/lib/simple/room/Stream.js +100 -14
  71. package/lib/simple/room/__tests__/RemoteParticipant.test.js +100 -14
  72. package/lib/simple/utils.js +100 -14
  73. package/lib/web-rtc-client.js +57 -6
  74. package/package.json +1 -1
  75. package/src/api/calld.js +3 -0
  76. package/src/domain/CallSession.js +9 -1
  77. package/src/domain/MeetingStatus.js +27 -0
  78. package/src/domain/Phone/WebRTCPhone.js +34 -7
  79. package/src/domain/__tests__/CallSession.test.js +32 -4
  80. package/src/web-rtc-client.js +27 -6
@@ -4024,6 +4024,34 @@ var chatdMethods = (client , baseUrl ) => ({
4024
4024
  client.get(`${baseUrl}/users/me/rooms/messages`, options),
4025
4025
  });
4026
4026
 
4027
+ //
4028
+
4029
+
4030
+
4031
+
4032
+
4033
+ class MeetingStatus {
4034
+
4035
+
4036
+
4037
+
4038
+ constructor({
4039
+ full,
4040
+ } = {}) {
4041
+ this.full = full;
4042
+
4043
+ // Useful to compare instead of instanceof with minified code
4044
+ this.type = 'MeetingStatus';
4045
+ }
4046
+
4047
+ static parse(plain ) {
4048
+ return new MeetingStatus({
4049
+ full: plain.full,
4050
+ });
4051
+ }
4052
+
4053
+ }
4054
+
4027
4055
  /* */
4028
4056
 
4029
4057
 
@@ -4218,6 +4246,8 @@ var calldMethods = (client , baseUrl ) => ({
4218
4246
  client.put(`${baseUrl}/users/me/calls/${callId}/record/resume`, null, null,
4219
4247
  ApiRequester.successResponseParser),
4220
4248
 
4249
+ guestGetMeetingStatus: (meetingUuid ) =>
4250
+ client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}/status`).then(MeetingStatus.parse),
4221
4251
  });
4222
4252
 
4223
4253
  //
@@ -0,0 +1,31 @@
1
+ 'use strict';
2
+
3
+ //
4
+
5
+
6
+
7
+
8
+
9
+ class MeetingStatus {
10
+
11
+
12
+
13
+
14
+ constructor({
15
+ full,
16
+ } = {}) {
17
+ this.full = full;
18
+
19
+ // Useful to compare instead of instanceof with minified code
20
+ this.type = 'MeetingStatus';
21
+ }
22
+
23
+ static parse(plain ) {
24
+ return new MeetingStatus({
25
+ full: plain.full,
26
+ });
27
+ }
28
+
29
+ }
30
+
31
+ module.exports = MeetingStatus;
@@ -2051,13 +2051,21 @@ class CallSession {
2051
2051
 
2052
2052
  // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
2053
2053
  set answered(value ) {
2054
- this.answerTime = value ? new Date() : null;
2054
+ this.answerTime = value ? this.answerTime || new Date() : null;
2055
2055
  }
2056
2056
 
2057
2057
  get answered() {
2058
2058
  return !!this.answerTime;
2059
2059
  }
2060
2060
 
2061
+ toJSON() {
2062
+ const jsonObj = { ...this };
2063
+ // $FlowFixMe
2064
+ jsonObj.answered = this.answered;
2065
+
2066
+ return jsonObj;
2067
+ }
2068
+
2061
2069
  static parseCall(call ) {
2062
2070
  return new CallSession({
2063
2071
  callId: call.id,
@@ -4416,6 +4424,34 @@ class IndirectTransfer {
4416
4424
  }
4417
4425
  }
4418
4426
 
4427
+ //
4428
+
4429
+
4430
+
4431
+
4432
+
4433
+ class MeetingStatus {
4434
+
4435
+
4436
+
4437
+
4438
+ constructor({
4439
+ full,
4440
+ } = {}) {
4441
+ this.full = full;
4442
+
4443
+ // Useful to compare instead of instanceof with minified code
4444
+ this.type = 'MeetingStatus';
4445
+ }
4446
+
4447
+ static parse(plain ) {
4448
+ return new MeetingStatus({
4449
+ full: plain.full,
4450
+ });
4451
+ }
4452
+
4453
+ }
4454
+
4419
4455
  /* */
4420
4456
 
4421
4457
 
@@ -4610,6 +4646,8 @@ var calldMethods = (client , baseUrl ) => ({
4610
4646
  client.put(`${baseUrl}/users/me/calls/${callId}/record/resume`, null, null,
4611
4647
  ApiRequester.successResponseParser),
4612
4648
 
4649
+ guestGetMeetingStatus: (meetingUuid ) =>
4650
+ client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}/status`).then(MeetingStatus.parse),
4613
4651
  });
4614
4652
 
4615
4653
  //
@@ -399,13 +399,21 @@ class CallSession {
399
399
 
400
400
  // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
401
401
  set answered(value ) {
402
- this.answerTime = value ? new Date() : null;
402
+ this.answerTime = value ? this.answerTime || new Date() : null;
403
403
  }
404
404
 
405
405
  get answered() {
406
406
  return !!this.answerTime;
407
407
  }
408
408
 
409
+ toJSON() {
410
+ const jsonObj = { ...this };
411
+ // $FlowFixMe
412
+ jsonObj.answered = this.answered;
413
+
414
+ return jsonObj;
415
+ }
416
+
409
417
  static parseCall(call ) {
410
418
  return new CallSession({
411
419
  callId: call.id,
@@ -1513,6 +1521,7 @@ class WebRTCPhone extends Emitter {
1513
1521
  }
1514
1522
 
1515
1523
  callSession.answerTime = new Date();
1524
+ this._updateCallSession(callSession);
1516
1525
  this.eventEmitter.emit(ON_CALL_ACCEPTED, callSession, cameraEnabled);
1517
1526
 
1518
1527
  return callSession;
@@ -1722,6 +1731,12 @@ class WebRTCPhone extends Emitter {
1722
1731
  return Promise.resolve(null);
1723
1732
  }
1724
1733
 
1734
+ const sipSessionId = this.getSipSessionIdFromCallSession(callSession);
1735
+ if (sipSessionId && !(sipSessionId in this.callSessions)) {
1736
+ logger.warn('Call session already ended or not found, can\'t accept it.', { sipSessionId });
1737
+ return Promise.resolve(null);
1738
+ }
1739
+
1725
1740
  if (callSession.getId() in this.acceptedSessions) {
1726
1741
  logger.warn('CallSession already accepted.', { id: callSession ? callSession.getId() : 'n/a' });
1727
1742
  return Promise.resolve(callSession.sipCallId);
@@ -1729,6 +1744,7 @@ class WebRTCPhone extends Emitter {
1729
1744
 
1730
1745
  this.shouldSendReinvite = false;
1731
1746
  callSession.answerTime = new Date();
1747
+ this._updateCallSession(callSession);
1732
1748
  this.acceptedSessions[callSession.getId()] = true;
1733
1749
 
1734
1750
  this.eventEmitter.emit(ON_CALL_ANSWERED, callSession);
@@ -1828,7 +1844,7 @@ class WebRTCPhone extends Emitter {
1828
1844
  // Hold current session if different from the current one (we don't want 2 sessions active at the same time).
1829
1845
  if (this.currentSipSession && this.currentSipSession.id !== sipSession.id) {
1830
1846
  logger.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
1831
- this.holdSipSession(this.currentSipSession, callSession);
1847
+ this.holdSipSession(this.currentSipSession, this.currentCallSession);
1832
1848
  }
1833
1849
 
1834
1850
  const promise = this.unholdSipSession(sipSession, callSession, withEvent, isConference);
@@ -2039,6 +2055,7 @@ class WebRTCPhone extends Emitter {
2039
2055
  }
2040
2056
  const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
2041
2057
  callSession.creationTime = new Date();
2058
+ this._updateCallSession(callSession);
2042
2059
 
2043
2060
  this.eventEmitter.emit(ON_PLAY_PROGRESS_SOUND, this.audioOutputDeviceId, this.audioOutputVolume);
2044
2061
 
@@ -2180,7 +2197,7 @@ class WebRTCPhone extends Emitter {
2180
2197
  return this.client && this.client.isConference(callSession.sipCallId);
2181
2198
  }
2182
2199
 
2183
- async close() {
2200
+ async close(force = false) {
2184
2201
  logger.info('WebRTC close');
2185
2202
 
2186
2203
  try {
@@ -2192,7 +2209,7 @@ class WebRTCPhone extends Emitter {
2192
2209
  logger.error('WebRTC close, unregister error', e);
2193
2210
  }
2194
2211
 
2195
- this.client.close();
2212
+ this.client.close(force);
2196
2213
  this.unbind();
2197
2214
 
2198
2215
  this.incomingSessions = [];
@@ -2318,6 +2335,8 @@ class WebRTCPhone extends Emitter {
2318
2335
  }
2319
2336
 
2320
2337
  callSession.creationTime = new Date();
2338
+ this._updateCallSession(callSession);
2339
+
2321
2340
  this.eventEmitter.emit(ON_CALL_INCOMING, callSession, wantsToDoVideo);
2322
2341
  });
2323
2342
 
@@ -2342,9 +2361,17 @@ class WebRTCPhone extends Emitter {
2342
2361
  });
2343
2362
 
2344
2363
  this.client.on(this.client.ACCEPTED, (sipSession ) => {
2345
- logger.info('WebRTC call accepted', { sipId: sipSession.id });
2364
+ const sessionId = this.getSipSessionId(sipSession);
2365
+ const hasSession = sessionId in this.callSessions;
2346
2366
 
2347
- this._onCallAccepted(sipSession, this.client.hasVideo(this.getSipSessionId(sipSession)));
2367
+ logger.info('WebRTC call accepted', { sipId: sessionId, hasSession });
2368
+
2369
+ if (!hasSession) {
2370
+ logger.warn('Call accepted ignored, session is no longer present in the WebRtcPhone', { sessionId });
2371
+ return;
2372
+ }
2373
+
2374
+ this._onCallAccepted(sipSession, this.client.hasVideo(sessionId));
2348
2375
 
2349
2376
  if (this.audioOutputDeviceId) {
2350
2377
  this.client.changeAudioOutputDevice(this.audioOutputDeviceId);
@@ -2361,6 +2388,8 @@ class WebRTCPhone extends Emitter {
2361
2388
  logger.info('WebRTC call rejected', session.id);
2362
2389
  const callSession = this._createCallSession(session);
2363
2390
  callSession.endTime = new Date();
2391
+ this._updateCallSession(callSession);
2392
+
2364
2393
  this.eventEmitter.emit(ON_CALL_REJECTED, callSession);
2365
2394
  });
2366
2395
 
@@ -2478,9 +2507,14 @@ class WebRTCPhone extends Emitter {
2478
2507
  return this.client.getSipSessionId(sipSession);
2479
2508
  }
2480
2509
 
2481
- _updateCallSession(callSession ) {
2510
+ getSipSessionIdFromCallSession(callSession ) {
2482
2511
  const sipSession = this.findSipSession(callSession);
2483
- const sipSessionId = sipSession ? this.getSipSessionId(sipSession) : null;
2512
+
2513
+ return sipSession ? this.getSipSessionId(sipSession) : null;
2514
+ }
2515
+
2516
+ _updateCallSession(callSession ) {
2517
+ const sipSessionId = this.getSipSessionIdFromCallSession(callSession);
2484
2518
 
2485
2519
  if (sipSessionId) {
2486
2520
  this.callSessions[sipSessionId] = callSession;
@@ -2585,6 +2619,7 @@ class WebRTCPhone extends Emitter {
2585
2619
  displayName: identity ? identity.displayName || number : number,
2586
2620
  startTime: fromSession ? fromSession.startTime : new Date(),
2587
2621
  creationTime: fromSession ? fromSession.creationTime : null,
2622
+ answerTime: fromSession ? fromSession.answerTime : null,
2588
2623
  endTime: fromSession ? fromSession.endTime : null,
2589
2624
  answered: state === sessionState.SessionState.Established,
2590
2625
  paused: this.client.isCallHeld(sipSession),
@@ -370,13 +370,21 @@ class CallSession {
370
370
 
371
371
  // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
372
372
  set answered(value ) {
373
- this.answerTime = value ? new Date() : null;
373
+ this.answerTime = value ? this.answerTime || new Date() : null;
374
374
  }
375
375
 
376
376
  get answered() {
377
377
  return !!this.answerTime;
378
378
  }
379
379
 
380
+ toJSON() {
381
+ const jsonObj = { ...this };
382
+ // $FlowFixMe
383
+ jsonObj.answered = this.answered;
384
+
385
+ return jsonObj;
386
+ }
387
+
380
388
  static parseCall(call ) {
381
389
  return new CallSession({
382
390
  callId: call.id,
@@ -402,6 +410,8 @@ class CallSession {
402
410
  }
403
411
  }
404
412
 
413
+ const stringify = cs => JSON.parse(JSON.stringify(cs));
414
+
405
415
  describe('CallSession domain', () => {
406
416
  it('should update from another CallSession without data loss', () => {
407
417
  const callSession = new CallSession({
@@ -440,7 +450,7 @@ describe('CallSession domain', () => {
440
450
  expect(cs2.is(cs1)).toBeTruthy();
441
451
  });
442
452
 
443
- it('should set answerTime when setting answered', () => {
453
+ it('should set answerTime when setting answered to true', () => {
444
454
  const cs1 = new CallSession({});
445
455
  cs1.answered = true;
446
456
 
@@ -449,11 +459,37 @@ describe('CallSession domain', () => {
449
459
 
450
460
  const cs3 = new CallSession({ answered: true });
451
461
 
452
- expect(cs1.answered).toBeTruthy();
462
+ expect(cs1.answered).toEqual(true);
453
463
  expect(cs1.answerTime).not.toBeNull();
454
- expect(cs2.answered).toBeTruthy();
464
+ expect(cs2.answered).toEqual(true);
455
465
  expect(cs2.answerTime).not.toBeNull();
456
- expect(cs3.answered).toBeTruthy();
466
+ expect(cs3.answered).toEqual(true);
457
467
  expect(cs3.answerTime).not.toBeNull();
468
+
469
+ const cs4 = stringify(cs1);
470
+ const cs5 = stringify(cs2);
471
+ const cs6 = stringify(cs3);
472
+
473
+ expect(cs4.answered).toEqual(true);
474
+ expect(cs5.answered).toEqual(true);
475
+ expect(cs6.answered).toEqual(true);
476
+ });
477
+
478
+ it('should reset answerTime when setting answered to false', () => {
479
+ const cs1 = new CallSession({});
480
+ cs1.answered = false;
481
+
482
+ const cs2 = new CallSession({ answered: false });
483
+
484
+ expect(cs1.answered).toEqual(false);
485
+ expect(cs1.answerTime).toBeNull();
486
+ expect(cs2.answered).toEqual(false);
487
+ expect(cs2.answerTime).toBeNull();
488
+
489
+ const cs4 = stringify(cs1);
490
+ const cs5 = stringify(cs2);
491
+
492
+ expect(cs4.answered).toEqual(false);
493
+ expect(cs5.answered).toEqual(false);
458
494
  });
459
495
  });
@@ -370,13 +370,21 @@ class CallSession {
370
370
 
371
371
  // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
372
372
  set answered(value ) {
373
- this.answerTime = value ? new Date() : null;
373
+ this.answerTime = value ? this.answerTime || new Date() : null;
374
374
  }
375
375
 
376
376
  get answered() {
377
377
  return !!this.answerTime;
378
378
  }
379
379
 
380
+ toJSON() {
381
+ const jsonObj = { ...this };
382
+ // $FlowFixMe
383
+ jsonObj.answered = this.answered;
384
+
385
+ return jsonObj;
386
+ }
387
+
380
388
  static parseCall(call ) {
381
389
  return new CallSession({
382
390
  callId: call.id,
@@ -370,13 +370,21 @@ class CallSession {
370
370
 
371
371
  // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
372
372
  set answered(value ) {
373
- this.answerTime = value ? new Date() : null;
373
+ this.answerTime = value ? this.answerTime || new Date() : null;
374
374
  }
375
375
 
376
376
  get answered() {
377
377
  return !!this.answerTime;
378
378
  }
379
379
 
380
+ toJSON() {
381
+ const jsonObj = { ...this };
382
+ // $FlowFixMe
383
+ jsonObj.answered = this.answered;
384
+
385
+ return jsonObj;
386
+ }
387
+
380
388
  static parseCall(call ) {
381
389
  return new CallSession({
382
390
  callId: call.id,
package/lib/index.js CHANGED
@@ -3596,13 +3596,21 @@ class CallSession {
3596
3596
 
3597
3597
  // Retro-compatibility: `answered` was a boolean before. We can reproduce the behaviour with a getter/setter
3598
3598
  set answered(value ) {
3599
- this.answerTime = value ? new Date() : null;
3599
+ this.answerTime = value ? this.answerTime || new Date() : null;
3600
3600
  }
3601
3601
 
3602
3602
  get answered() {
3603
3603
  return !!this.answerTime;
3604
3604
  }
3605
3605
 
3606
+ toJSON() {
3607
+ const jsonObj = { ...this };
3608
+ // $FlowFixMe
3609
+ jsonObj.answered = this.answered;
3610
+
3611
+ return jsonObj;
3612
+ }
3613
+
3606
3614
  static parseCall(call ) {
3607
3615
  return new CallSession({
3608
3616
  callId: call.id,
@@ -4937,6 +4945,34 @@ var chatdMethods = (client , baseUrl ) => ({
4937
4945
  client.get(`${baseUrl}/users/me/rooms/messages`, options),
4938
4946
  });
4939
4947
 
4948
+ //
4949
+
4950
+
4951
+
4952
+
4953
+
4954
+ class MeetingStatus {
4955
+
4956
+
4957
+
4958
+
4959
+ constructor({
4960
+ full,
4961
+ } = {}) {
4962
+ this.full = full;
4963
+
4964
+ // Useful to compare instead of instanceof with minified code
4965
+ this.type = 'MeetingStatus';
4966
+ }
4967
+
4968
+ static parse(plain ) {
4969
+ return new MeetingStatus({
4970
+ full: plain.full,
4971
+ });
4972
+ }
4973
+
4974
+ }
4975
+
4940
4976
  /* */
4941
4977
 
4942
4978
 
@@ -5131,6 +5167,8 @@ var calldMethods = (client , baseUrl ) => ({
5131
5167
  client.put(`${baseUrl}/users/me/calls/${callId}/record/resume`, null, null,
5132
5168
  ApiRequester.successResponseParser),
5133
5169
 
5170
+ guestGetMeetingStatus: (meetingUuid ) =>
5171
+ client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}/status`).then(MeetingStatus.parse),
5134
5172
  });
5135
5173
 
5136
5174
  //
@@ -6198,7 +6236,7 @@ const events$1 = [REGISTERED, UNREGISTERED, REGISTRATION_FAILED, INVITE];
6198
6236
  const transportEvents = [CONNECTED, DISCONNECTED, TRANSPORT_ERROR, MESSAGE];
6199
6237
  class CanceledCallError extends Error {}
6200
6238
 
6201
- const MAX_REGISTER_TRIES = 10;
6239
+ const MAX_REGISTER_TRIES = 5;
6202
6240
 
6203
6241
 
6204
6242
 
@@ -6252,6 +6290,7 @@ class WebRTCClient extends Emitter {
6252
6290
 
6253
6291
 
6254
6292
 
6293
+
6255
6294
 
6256
6295
  // sugar
6257
6296
 
@@ -6314,6 +6353,7 @@ class WebRTCClient extends Emitter {
6314
6353
  this.conferences = {};
6315
6354
  this.networkMonitoringInterval = {};
6316
6355
  this.sessionNetworkStats = {};
6356
+ this.forceClosed = false;
6317
6357
 
6318
6358
  this._boundOnHeartbeat = this._onHeartbeat.bind(this);
6319
6359
  this.heartbeat = new Heartbeat(config.heartbeatDelay, config.heartbeatTimeout, config.maxHeartbeats);
@@ -6435,6 +6475,8 @@ class WebRTCClient extends Emitter {
6435
6475
  skipRegister: this.skipRegister,
6436
6476
  };
6437
6477
 
6478
+ this.forceClosed = false;
6479
+
6438
6480
  if (this.skipRegister) {
6439
6481
  logger$9.info('sdk webrtc skip register...', logInfo);
6440
6482
  return Promise.resolve();
@@ -6459,7 +6501,15 @@ class WebRTCClient extends Emitter {
6459
6501
  const registerOptions = this._isWeb() ? {} : { extraContactHeaderParams: ['mobility=mobile'] };
6460
6502
 
6461
6503
  const onRegisterFailed = () => {
6462
- logger$9.info('sdk webrtc registering failed', { tries, registerer: !!this.registerer });
6504
+ logger$9.info('sdk webrtc registering failed', {
6505
+ tries,
6506
+ registerer: !!this.registerer,
6507
+ forceClosed: this.forceClosed,
6508
+ });
6509
+ if (this.forceClosed) {
6510
+ return;
6511
+ }
6512
+
6463
6513
  this.connectionPromise = null;
6464
6514
  if (this.registerer && this.registerer.waiting) {
6465
6515
  this.registerer.waitingToggle(false);
@@ -6737,8 +6787,9 @@ class WebRTCClient extends Emitter {
6737
6787
  }
6738
6788
  }
6739
6789
 
6740
- async close() {
6741
- logger$9.info('sdk webrtc closing client', { userAgent: !!this.userAgent });
6790
+ async close(force = false) {
6791
+ logger$9.info('sdk webrtc closing client', { userAgent: !!this.userAgent, force });
6792
+ this.forceClosed = force;
6742
6793
  this._cleanupMedia();
6743
6794
  this.connectionPromise = null;
6744
6795
 
@@ -6757,7 +6808,7 @@ class WebRTCClient extends Emitter {
6757
6808
  this.userAgent.delegate = null;
6758
6809
  this.userAgent.stateChange.removeAllListeners();
6759
6810
 
6760
- await this._disconnectTransport();
6811
+ await this._disconnectTransport(force);
6761
6812
 
6762
6813
  this._cleanupRegister();
6763
6814
 
@@ -8193,7 +8244,15 @@ class WebRTCClient extends Emitter {
8193
8244
  return userAgent.UserAgent.makeURI(`sip:${target}@${this.config.host}`);
8194
8245
  }
8195
8246
 
8196
- async _disconnectTransport() {
8247
+ async _disconnectTransport(force = false) {
8248
+ if (force) {
8249
+ // Bypass sip.js state machine that prevent to close WS with the state `Connecting`
8250
+ this.userAgent.transport.disconnectResolve = () => {};
8251
+ // eslint-disable-next-line
8252
+ this.userAgent.transport._ws.close(1000);
8253
+ return;
8254
+ }
8255
+
8197
8256
  // Check if `disconnectPromise` is not present to avoid `Disconnect promise must not be defined` errors.
8198
8257
  if (this.userAgent && this.userAgent.transport && !this.userAgent.transport.disconnectPromise) {
8199
8258
  try {
@@ -9831,6 +9890,7 @@ class WebRTCPhone extends Emitter {
9831
9890
  }
9832
9891
 
9833
9892
  callSession.answerTime = new Date();
9893
+ this._updateCallSession(callSession);
9834
9894
  this.eventEmitter.emit(ON_CALL_ACCEPTED, callSession, cameraEnabled);
9835
9895
 
9836
9896
  return callSession;
@@ -10040,6 +10100,12 @@ class WebRTCPhone extends Emitter {
10040
10100
  return Promise.resolve(null);
10041
10101
  }
10042
10102
 
10103
+ const sipSessionId = this.getSipSessionIdFromCallSession(callSession);
10104
+ if (sipSessionId && !(sipSessionId in this.callSessions)) {
10105
+ logger$7.warn('Call session already ended or not found, can\'t accept it.', { sipSessionId });
10106
+ return Promise.resolve(null);
10107
+ }
10108
+
10043
10109
  if (callSession.getId() in this.acceptedSessions) {
10044
10110
  logger$7.warn('CallSession already accepted.', { id: callSession ? callSession.getId() : 'n/a' });
10045
10111
  return Promise.resolve(callSession.sipCallId);
@@ -10047,6 +10113,7 @@ class WebRTCPhone extends Emitter {
10047
10113
 
10048
10114
  this.shouldSendReinvite = false;
10049
10115
  callSession.answerTime = new Date();
10116
+ this._updateCallSession(callSession);
10050
10117
  this.acceptedSessions[callSession.getId()] = true;
10051
10118
 
10052
10119
  this.eventEmitter.emit(ON_CALL_ANSWERED, callSession);
@@ -10146,7 +10213,7 @@ class WebRTCPhone extends Emitter {
10146
10213
  // Hold current session if different from the current one (we don't want 2 sessions active at the same time).
10147
10214
  if (this.currentSipSession && this.currentSipSession.id !== sipSession.id) {
10148
10215
  logger$7.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
10149
- this.holdSipSession(this.currentSipSession, callSession);
10216
+ this.holdSipSession(this.currentSipSession, this.currentCallSession);
10150
10217
  }
10151
10218
 
10152
10219
  const promise = this.unholdSipSession(sipSession, callSession, withEvent, isConference);
@@ -10357,6 +10424,7 @@ class WebRTCPhone extends Emitter {
10357
10424
  }
10358
10425
  const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
10359
10426
  callSession.creationTime = new Date();
10427
+ this._updateCallSession(callSession);
10360
10428
 
10361
10429
  this.eventEmitter.emit(ON_PLAY_PROGRESS_SOUND, this.audioOutputDeviceId, this.audioOutputVolume);
10362
10430
 
@@ -10498,7 +10566,7 @@ class WebRTCPhone extends Emitter {
10498
10566
  return this.client && this.client.isConference(callSession.sipCallId);
10499
10567
  }
10500
10568
 
10501
- async close() {
10569
+ async close(force = false) {
10502
10570
  logger$7.info('WebRTC close');
10503
10571
 
10504
10572
  try {
@@ -10510,7 +10578,7 @@ class WebRTCPhone extends Emitter {
10510
10578
  logger$7.error('WebRTC close, unregister error', e);
10511
10579
  }
10512
10580
 
10513
- this.client.close();
10581
+ this.client.close(force);
10514
10582
  this.unbind();
10515
10583
 
10516
10584
  this.incomingSessions = [];
@@ -10636,6 +10704,8 @@ class WebRTCPhone extends Emitter {
10636
10704
  }
10637
10705
 
10638
10706
  callSession.creationTime = new Date();
10707
+ this._updateCallSession(callSession);
10708
+
10639
10709
  this.eventEmitter.emit(ON_CALL_INCOMING, callSession, wantsToDoVideo);
10640
10710
  });
10641
10711
 
@@ -10660,9 +10730,17 @@ class WebRTCPhone extends Emitter {
10660
10730
  });
10661
10731
 
10662
10732
  this.client.on(this.client.ACCEPTED, (sipSession ) => {
10663
- logger$7.info('WebRTC call accepted', { sipId: sipSession.id });
10733
+ const sessionId = this.getSipSessionId(sipSession);
10734
+ const hasSession = sessionId in this.callSessions;
10664
10735
 
10665
- this._onCallAccepted(sipSession, this.client.hasVideo(this.getSipSessionId(sipSession)));
10736
+ logger$7.info('WebRTC call accepted', { sipId: sessionId, hasSession });
10737
+
10738
+ if (!hasSession) {
10739
+ logger$7.warn('Call accepted ignored, session is no longer present in the WebRtcPhone', { sessionId });
10740
+ return;
10741
+ }
10742
+
10743
+ this._onCallAccepted(sipSession, this.client.hasVideo(sessionId));
10666
10744
 
10667
10745
  if (this.audioOutputDeviceId) {
10668
10746
  this.client.changeAudioOutputDevice(this.audioOutputDeviceId);
@@ -10679,6 +10757,8 @@ class WebRTCPhone extends Emitter {
10679
10757
  logger$7.info('WebRTC call rejected', session.id);
10680
10758
  const callSession = this._createCallSession(session);
10681
10759
  callSession.endTime = new Date();
10760
+ this._updateCallSession(callSession);
10761
+
10682
10762
  this.eventEmitter.emit(ON_CALL_REJECTED, callSession);
10683
10763
  });
10684
10764
 
@@ -10796,9 +10876,14 @@ class WebRTCPhone extends Emitter {
10796
10876
  return this.client.getSipSessionId(sipSession);
10797
10877
  }
10798
10878
 
10799
- _updateCallSession(callSession ) {
10879
+ getSipSessionIdFromCallSession(callSession ) {
10800
10880
  const sipSession = this.findSipSession(callSession);
10801
- const sipSessionId = sipSession ? this.getSipSessionId(sipSession) : null;
10881
+
10882
+ return sipSession ? this.getSipSessionId(sipSession) : null;
10883
+ }
10884
+
10885
+ _updateCallSession(callSession ) {
10886
+ const sipSessionId = this.getSipSessionIdFromCallSession(callSession);
10802
10887
 
10803
10888
  if (sipSessionId) {
10804
10889
  this.callSessions[sipSessionId] = callSession;
@@ -10903,6 +10988,7 @@ class WebRTCPhone extends Emitter {
10903
10988
  displayName: identity ? identity.displayName || number : number,
10904
10989
  startTime: fromSession ? fromSession.startTime : new Date(),
10905
10990
  creationTime: fromSession ? fromSession.creationTime : null,
10991
+ answerTime: fromSession ? fromSession.answerTime : null,
10906
10992
  endTime: fromSession ? fromSession.endTime : null,
10907
10993
  answered: state === sessionState.SessionState.Established,
10908
10994
  paused: this.client.isCallHeld(sipSession),