@wazo/sdk 0.37.0-rc.5 → 0.37.2

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 (149) hide show
  1. package/dist/wazo-sdk.js +5 -5
  2. package/esm/__tests__/api-client.test.js +93 -16
  3. package/esm/__tests__/web-rtc-client.test.js +153 -54
  4. package/esm/api/agentd.js +24 -3
  5. package/esm/api/amid.js +7 -1
  6. package/esm/api/application.js +24 -3
  7. package/esm/api/auth.js +24 -3
  8. package/esm/api/call-logd.js +78 -20
  9. package/esm/api/calld.js +24 -20
  10. package/esm/api/chatd.js +24 -3
  11. package/esm/api/confd.js +24 -3
  12. package/esm/api/ctid-ng.js +24 -3
  13. package/esm/api/dird.js +27 -6
  14. package/esm/api/webhookd.js +7 -1
  15. package/esm/api-client.js +93 -16
  16. package/esm/checker/Checker.js +156 -54
  17. package/esm/checker/checks/aor.js +95 -16
  18. package/esm/checker/checks/api.js +94 -16
  19. package/esm/checker/checks/index.js +156 -54
  20. package/esm/checker/checks/wazo-websocket.js +7 -1
  21. package/esm/checker/checks/webrtc-transport.js +153 -54
  22. package/esm/checker/checks/webrtc.js +153 -54
  23. package/esm/domain/AdHocAPIConference.js +1717 -1640
  24. package/esm/domain/CallLog.js +71 -19
  25. package/esm/domain/CallSession.js +1 -18
  26. package/esm/domain/Contact.js +3 -3
  27. package/esm/domain/Features.js +93 -16
  28. package/esm/domain/IndirectTransfer.js +0 -17
  29. package/esm/domain/Phone/CTIPhone.js +100 -19
  30. package/esm/domain/Phone/Phone.js +0 -17
  31. package/esm/domain/Phone/WebRTCPhone.js +51 -36
  32. package/esm/domain/Recording.js +51 -0
  33. package/esm/domain/Room.js +0 -17
  34. package/esm/domain/SwitchboardCall.js +0 -17
  35. package/esm/domain/__tests__/CallLog.test.js +89 -19
  36. package/esm/domain/__tests__/CallSession.test.js +1 -18
  37. package/esm/domain/__tests__/Contact.test.js +3 -3
  38. package/esm/domain/__tests__/IndirectTransfer.test.js +1 -18
  39. package/esm/domain/__tests__/Room.test.js +1 -18
  40. package/esm/domain/__tests__/Session.test.js +7 -0
  41. package/esm/index.js +3436 -2911
  42. package/esm/lib/WazoSessionDescriptionHandler.js +28 -10
  43. package/esm/service/CallApi.js +93 -16
  44. package/esm/service/IssueReporter.js +7 -1
  45. package/esm/service/__tests__/IssueReporter.test.js +26 -2
  46. package/esm/service/getApiClient.js +93 -16
  47. package/esm/simple/Auth.js +619 -97
  48. package/esm/simple/Configuration.js +619 -97
  49. package/esm/simple/Directory.js +93 -16
  50. package/esm/simple/Phone.js +3261 -2739
  51. package/esm/simple/Websocket.js +7 -1
  52. package/esm/simple/index.js +619 -97
  53. package/esm/simple/room/LocalParticipant.js +619 -97
  54. package/esm/simple/room/Participant.js +619 -97
  55. package/esm/simple/room/RemoteParticipant.js +619 -97
  56. package/esm/simple/room/Room.js +619 -97
  57. package/esm/simple/room/Stream.js +619 -97
  58. package/esm/simple/room/__tests__/RemoteParticipant.test.js +619 -97
  59. package/esm/simple/utils.js +619 -97
  60. package/esm/utils/__tests__/api-requester.test.js +32 -6
  61. package/esm/utils/api-requester.js +24 -3
  62. package/esm/web-rtc-client.js +153 -54
  63. package/esm/websocket-client.js +7 -1
  64. package/lib/__tests__/api-client.test.js +93 -16
  65. package/lib/__tests__/web-rtc-client.test.js +154 -55
  66. package/lib/api/agentd.js +24 -3
  67. package/lib/api/amid.js +7 -1
  68. package/lib/api/application.js +24 -3
  69. package/lib/api/auth.js +24 -3
  70. package/lib/api/call-logd.js +78 -20
  71. package/lib/api/calld.js +24 -20
  72. package/lib/api/chatd.js +24 -3
  73. package/lib/api/confd.js +24 -3
  74. package/lib/api/ctid-ng.js +24 -3
  75. package/lib/api/dird.js +27 -6
  76. package/lib/api/webhookd.js +7 -1
  77. package/lib/api-client.js +93 -16
  78. package/lib/checker/Checker.js +157 -55
  79. package/lib/checker/checks/aor.js +95 -16
  80. package/lib/checker/checks/api.js +94 -16
  81. package/lib/checker/checks/index.js +157 -55
  82. package/lib/checker/checks/wazo-websocket.js +7 -1
  83. package/lib/checker/checks/webrtc-transport.js +154 -55
  84. package/lib/checker/checks/webrtc.js +154 -55
  85. package/lib/domain/AdHocAPIConference.js +1717 -1640
  86. package/lib/domain/CallLog.js +71 -19
  87. package/lib/domain/CallSession.js +1 -18
  88. package/lib/domain/Contact.js +3 -3
  89. package/lib/domain/Features.js +93 -16
  90. package/lib/domain/IndirectTransfer.js +0 -17
  91. package/lib/domain/Phone/CTIPhone.js +100 -19
  92. package/lib/domain/Phone/Phone.js +0 -16
  93. package/lib/domain/Phone/WebRTCPhone.js +51 -36
  94. package/lib/domain/Recording.js +57 -0
  95. package/lib/domain/Room.js +0 -17
  96. package/lib/domain/SwitchboardCall.js +0 -17
  97. package/lib/domain/__tests__/CallLog.test.js +89 -19
  98. package/lib/domain/__tests__/CallSession.test.js +1 -18
  99. package/lib/domain/__tests__/Contact.test.js +3 -3
  100. package/lib/domain/__tests__/IndirectTransfer.test.js +1 -18
  101. package/lib/domain/__tests__/Room.test.js +1 -18
  102. package/lib/domain/__tests__/Session.test.js +7 -0
  103. package/lib/index.js +3437 -2912
  104. package/lib/lib/WazoSessionDescriptionHandler.js +28 -10
  105. package/lib/service/CallApi.js +93 -16
  106. package/lib/service/IssueReporter.js +7 -1
  107. package/lib/service/__tests__/IssueReporter.test.js +26 -2
  108. package/lib/service/getApiClient.js +93 -16
  109. package/lib/simple/Auth.js +620 -98
  110. package/lib/simple/Configuration.js +620 -98
  111. package/lib/simple/Directory.js +93 -16
  112. package/lib/simple/Phone.js +3262 -2740
  113. package/lib/simple/Websocket.js +7 -1
  114. package/lib/simple/index.js +620 -98
  115. package/lib/simple/room/LocalParticipant.js +620 -98
  116. package/lib/simple/room/Participant.js +620 -98
  117. package/lib/simple/room/RemoteParticipant.js +620 -98
  118. package/lib/simple/room/Room.js +620 -98
  119. package/lib/simple/room/Stream.js +620 -98
  120. package/lib/simple/room/__tests__/RemoteParticipant.test.js +620 -98
  121. package/lib/simple/utils.js +620 -98
  122. package/lib/utils/__tests__/api-requester.test.js +32 -6
  123. package/lib/utils/api-requester.js +24 -3
  124. package/lib/web-rtc-client.js +154 -55
  125. package/lib/websocket-client.js +7 -1
  126. package/package.json +1 -1
  127. package/src/api-client.js +4 -0
  128. package/src/checker/checks/aor.js +2 -0
  129. package/src/checker/checks/api.js +1 -0
  130. package/src/domain/CallLog.js +18 -11
  131. package/src/domain/CallSession.js +1 -2
  132. package/src/domain/Contact.js +3 -3
  133. package/src/domain/Phone/CTIPhone.js +6 -2
  134. package/src/domain/Phone/Phone.js +2 -0
  135. package/src/domain/Phone/WebRTCPhone.js +26 -16
  136. package/src/domain/Recording.js +48 -0
  137. package/src/domain/__tests__/CallLog.test.js +19 -0
  138. package/src/domain/__tests__/Session.test.js +7 -0
  139. package/src/index.js +6 -0
  140. package/src/lib/WazoSessionDescriptionHandler.js +21 -9
  141. package/src/service/IssueReporter.js +7 -1
  142. package/src/service/__tests__/IssueReporter.test.js +20 -1
  143. package/src/simple/Phone.js +5 -1
  144. package/src/simple/index.js +6 -0
  145. package/src/simple/room/Room.js +18 -15
  146. package/src/simple/room/Stream.js +1 -4
  147. package/src/utils/__tests__/api-requester.test.js +9 -4
  148. package/src/utils/api-requester.js +17 -2
  149. package/src/web-rtc-client.js +40 -13
@@ -12,7 +12,6 @@ var jsonToGraphQLQuery = require('json-to-graphql-query/lib/jsonToGraphQLQuery')
12
12
  var invitation = require('sip.js/lib/api/invitation');
13
13
  require('webrtc-adapter');
14
14
  var userAgentState = require('sip.js/lib/api/user-agent-state');
15
- require('sip.js/lib/api/message');
16
15
  var parser = require('sip.js/lib/core/messages/parser');
17
16
  var constants = require('sip.js/lib/core/messages/methods/constants');
18
17
  var uri = require('sip.js/lib/grammar/uri');
@@ -341,7 +340,13 @@ class IssueReporter {
341
340
  }
342
341
 
343
342
  _isLevelAbove(level1 , level2 ) {
344
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
343
+ const index1 = LOG_LEVELS.indexOf(level1);
344
+ const index2 = LOG_LEVELS.indexOf(level2);
345
+ if (index1 === -1 || index2 === -1) {
346
+ return false;
347
+ }
348
+
349
+ return index1 > index2;
345
350
  }
346
351
 
347
352
  _makeCategory(category ) {
@@ -364,7 +369,7 @@ var IssueReporter$1 = new IssueReporter();
364
369
 
365
370
  const methods = ['head', 'get', 'post', 'put', 'delete'];
366
371
 
367
- const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
372
+ const logger$b = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
368
373
 
369
374
  // Use a function here to be able to mock it in tests
370
375
  const realFetch = () => {
@@ -399,6 +404,7 @@ class ApiRequester {
399
404
 
400
405
 
401
406
 
407
+
402
408
 
403
409
 
404
410
 
@@ -438,6 +444,8 @@ class ApiRequester {
438
444
  this.token = token;
439
445
  }
440
446
 
447
+ this.shouldLogErrors = true;
448
+
441
449
  methods.forEach(method => {
442
450
  // $FlowFixMe
443
451
  ApiRequester.prototype[method] = function sugar(...args) {
@@ -461,6 +469,14 @@ class ApiRequester {
461
469
  this.fetchOptions = options;
462
470
  }
463
471
 
472
+ disableErrorLogging() {
473
+ this.shouldLogErrors = false;
474
+ }
475
+
476
+ enableErrorLogging() {
477
+ this.shouldLogErrors = true;
478
+ }
479
+
464
480
  async call(
465
481
  path ,
466
482
  method = 'get',
@@ -492,7 +508,7 @@ class ApiRequester {
492
508
  };
493
509
 
494
510
  if (this.refreshTokenPromise) {
495
- logger$a.info('A token is already refreshing, waiting ...', { url });
511
+ logger$b.info('A token is already refreshing, waiting ...', { url });
496
512
  await this.refreshTokenPromise;
497
513
  }
498
514
 
@@ -512,7 +528,7 @@ class ApiRequester {
512
528
  return promise.then(async (err ) => {
513
529
  // Check if the token is still valid
514
530
  if (firstCall && this._checkTokenExpired(response, err)) {
515
- logger$a.warn('token expired', { error: err.reason });
531
+ logger$b.warn('token expired', { error: err.reason });
516
532
  // Replay the call after refreshing the token
517
533
  return this._replayWithNewToken(err, path, method, body, headers, parse);
518
534
  }
@@ -521,7 +537,9 @@ class ApiRequester {
521
537
  ? exceptionClass.fromText(err, response.status)
522
538
  : exceptionClass.fromResponse(err, response.status);
523
539
 
524
- logger$a.error('API error', error);
540
+ if (this.shouldLogErrors) {
541
+ logger$b.error('API error', error);
542
+ }
525
543
 
526
544
  throw error;
527
545
  });
@@ -529,7 +547,9 @@ class ApiRequester {
529
547
 
530
548
  return newParse(response, isJson);
531
549
  }).catch(error => {
532
- logger$a.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
550
+ if (this.shouldLogErrors) {
551
+ logger$b.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
552
+ }
533
553
 
534
554
  throw error;
535
555
  });
@@ -556,13 +576,13 @@ class ApiRequester {
556
576
  ) {
557
577
  const isTokenNotFound = this._isTokenNotFound(err);
558
578
  let newPath = path;
559
- logger$a.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
579
+ logger$b.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
560
580
 
561
581
  this.refreshTokenPromise = this.refreshTokenPromise || this.refreshTokenCallback();
562
582
 
563
583
  return this.refreshTokenPromise.then(() => {
564
584
  this.refreshTokenPromise = null;
565
- logger$a.info('token refreshed', { isTokenNotFound });
585
+ logger$b.info('token refreshed', { isTokenNotFound });
566
586
  if (isTokenNotFound) {
567
587
  const pathParts = path.split('/');
568
588
  pathParts.pop();
@@ -1579,7 +1599,7 @@ class Contact {
1579
1599
 
1580
1600
  return new Contact({
1581
1601
  sourceId: single.id || '',
1582
- name: single.displayName,
1602
+ name: single.displayName || '',
1583
1603
  number: numbers.length ? numbers[0].number : '',
1584
1604
  numbers,
1585
1605
  emails,
@@ -1610,7 +1630,7 @@ class Contact {
1610
1630
 
1611
1631
  return new Contact({
1612
1632
  sourceId: single.id || '',
1613
- name: single.name,
1633
+ name: single.name || '',
1614
1634
  number: numbers.length ? numbers[0].number : '',
1615
1635
  numbers,
1616
1636
  emails,
@@ -1711,7 +1731,7 @@ class Contact {
1711
1731
  } = {}) {
1712
1732
  this.id = id;
1713
1733
  this.uuid = uuid;
1714
- this.name = name;
1734
+ this.name = name || '';
1715
1735
  this.number = number;
1716
1736
  this.numbers = numbers;
1717
1737
  this.email = email;
@@ -3325,7 +3345,7 @@ class CallSession {
3325
3345
  return newFrom(callSession, CallSession);
3326
3346
  }
3327
3347
 
3328
- static parseCall(session , call ) {
3348
+ static parseCall(call ) {
3329
3349
  return new CallSession({
3330
3350
  callId: call.id,
3331
3351
  sipCallId: call.sipCallId,
@@ -3378,17 +3398,66 @@ class Emitter {
3378
3398
 
3379
3399
  //
3380
3400
 
3401
+
3402
+
3403
+
3404
+
3405
+
3406
+
3407
+
3408
+
3409
+
3410
+
3411
+
3412
+
3413
+
3414
+
3415
+
3416
+
3417
+ class Recording {
3418
+
3419
+
3420
+
3421
+
3422
+
3423
+
3424
+ static parseMany(recordings ) {
3425
+ return recordings.map(item => Recording.parse(item));
3426
+ }
3427
+
3428
+ static parse(plain ) {
3429
+ return new Recording({
3430
+ deleted: plain.deleted,
3431
+ fileName: plain.filename,
3432
+ end: plain.end_time ? moment__default['default'](plain.end_time).toDate() : null,
3433
+ start: moment__default['default'](plain.start_time).toDate(),
3434
+ uuid: plain.uuid,
3435
+ });
3436
+ }
3437
+
3438
+ constructor({ deleted, end, fileName, start, uuid } ) {
3439
+ this.deleted = deleted;
3440
+ this.end = end;
3441
+ this.fileName = fileName;
3442
+ this.start = start;
3443
+ this.uuid = uuid;
3444
+ }
3445
+ }
3446
+
3447
+ //
3448
+
3381
3449
 
3382
-
3450
+
3383
3451
 
3384
3452
 
3385
3453
 
3386
3454
 
3387
3455
 
3388
-
3456
+
3389
3457
 
3390
3458
 
3391
3459
 
3460
+
3392
3461
 
3393
3462
 
3394
3463
 
@@ -3401,7 +3470,7 @@ class Emitter {
3401
3470
 
3402
3471
 
3403
3472
 
3404
-
3473
+
3405
3474
 
3406
3475
 
3407
3476
 
@@ -3416,13 +3485,14 @@ class Emitter {
3416
3485
 
3417
3486
 
3418
3487
 
3419
-
3488
+
3489
+
3420
3490
 
3421
3491
 
3422
3492
  class CallLog {
3423
3493
 
3424
3494
 
3425
-
3495
+
3426
3496
 
3427
3497
 
3428
3498
 
@@ -3439,7 +3509,7 @@ class CallLog {
3439
3509
 
3440
3510
 
3441
3511
 
3442
-
3512
+
3443
3513
 
3444
3514
  static merge(current , toMerge ) {
3445
3515
  const onlyUnique = (value, index, self) => self.indexOf(value) === index;
@@ -3456,7 +3526,7 @@ class CallLog {
3456
3526
 
3457
3527
  static parse(plain ) {
3458
3528
  return new CallLog({
3459
- answer: moment__default['default'](plain.answer).toDate(),
3529
+ answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
3460
3530
  answered: plain.answered,
3461
3531
  callDirection: plain.call_direction,
3462
3532
  destination: {
@@ -3470,13 +3540,14 @@ class CallLog {
3470
3540
  id: plain.id,
3471
3541
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3472
3542
  start: moment__default['default'](plain.start).toDate(),
3473
- end: moment__default['default'](plain.end).toDate(),
3543
+ end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3544
+ recordings: Recording.parseMany(plain.recordings),
3474
3545
  });
3475
3546
  }
3476
3547
 
3477
3548
  static parseNew(plain , session ) {
3478
3549
  return new CallLog({
3479
- answer: moment__default['default'](plain.answer).toDate(),
3550
+ answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
3480
3551
  answered: plain.answered,
3481
3552
  callDirection: plain.call_direction,
3482
3553
  destination: {
@@ -3490,7 +3561,8 @@ class CallLog {
3490
3561
  id: plain.id,
3491
3562
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3492
3563
  start: moment__default['default'](plain.start).toDate(),
3493
- end: moment__default['default'](plain.end).toDate(),
3564
+ end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3565
+ recordings: Recording.parseMany(plain.recordings),
3494
3566
  // @TODO: FIXME add verification declined vs missed call
3495
3567
  newMissedCall: session
3496
3568
  && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
@@ -3672,11 +3744,414 @@ class IndirectTransfer {
3672
3744
  }
3673
3745
 
3674
3746
  //
3747
+
3748
+ class CallApi {
3749
+ static async fetchCallLogs(offset , limit ) {
3750
+ return getApiClient().callLogd.listCallLogs(offset, limit);
3751
+ }
3752
+
3753
+ static async fetchDistinctCallLogs(offset , limit , distinct = 'peer_exten') {
3754
+ return getApiClient().callLogd.listDistinctCallLogs(offset, limit, distinct);
3755
+ }
3756
+
3757
+ static async fetchActiveCalls() {
3758
+ return getApiClient().calld.listCalls();
3759
+ }
3760
+
3761
+ static async fetchCallLogsFromDate(from , number ) {
3762
+ return getApiClient().callLogd.listCallLogsFromDate(from, number);
3763
+ }
3764
+
3765
+ static async search(query , limit ) {
3766
+ return getApiClient().callLogd.search(query, limit);
3767
+ }
3768
+
3769
+ static async searchBy(field , value , limit ) {
3770
+ return getApiClient().callLogd.searchBy(field, value, limit);
3771
+ }
3772
+
3773
+ static async fetchSIP(session , line ) {
3774
+ const lineToUse = line || session.primaryLine();
3775
+ return getApiClient().confd.getUserLineSip(session.uuid, lineToUse ? lineToUse.id : null);
3776
+ }
3777
+
3778
+ static async cancelCall(callSession ) {
3779
+ return getApiClient().calld.cancelCall(callSession.callId);
3780
+ }
3781
+
3782
+ static async makeCall(callFromLine , extension , isMobile = false,
3783
+ callbackAllLines = false) {
3784
+ const lineId = callFromLine ? callFromLine.id : null;
3785
+
3786
+ const response = await getApiClient().calld.makeCall(extension, isMobile, lineId, callbackAllLines);
3787
+ return Call.parse(response);
3788
+ }
3789
+
3790
+ static async relocateCall(callId , line , contactIdentifier ) {
3791
+ return getApiClient().calld.relocateCall(callId, 'line', line, contactIdentifier);
3792
+ }
3793
+
3794
+ static async hold(callId ) {
3795
+ return getApiClient().calld.hold(callId);
3796
+ }
3797
+
3798
+ static async resume(callId ) {
3799
+ return getApiClient().calld.resume(callId);
3800
+ }
3801
+
3802
+ static async mute(callId ) {
3803
+ return getApiClient().calld.mute(callId);
3804
+ }
3805
+
3806
+ static async sendDTMF(callId , digits ) {
3807
+ return getApiClient().calld.sendDTMF(callId, digits);
3808
+ }
3809
+
3810
+ static async unmute(callId ) {
3811
+ return getApiClient().calld.unmute(callId);
3812
+ }
3813
+
3814
+ static async transferCall(callId , number , flow ) {
3815
+ return getApiClient().calld.transferCall(callId, number, flow);
3816
+ }
3817
+
3818
+ static async cancelCallTransfer(transferId ) {
3819
+ return getApiClient().calld.cancelCallTransfer(transferId);
3820
+ }
3821
+
3822
+ static async confirmCallTransfer(transferId ) {
3823
+ return getApiClient().calld.confirmCallTransfer(transferId);
3824
+ }
3825
+ }
3826
+
3827
+ //
3828
+
3829
+ const TRANSFER_FLOW_ATTENDED = 'attended';
3675
3830
  const TRANSFER_FLOW_BLIND = 'blind';
3676
3831
 
3677
3832
  // const MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD = '20.11';
3678
3833
 
3679
- IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3834
+ const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3835
+
3836
+ class CTIPhone extends Emitter {
3837
+
3838
+
3839
+
3840
+
3841
+
3842
+
3843
+
3844
+
3845
+ constructor(session , isMobile = false, callbackAllLines = false) {
3846
+ super();
3847
+ logger$a.info('CTI Phone created');
3848
+ this.session = session;
3849
+ this.isMobile = isMobile;
3850
+ this.callbackAllLines = callbackAllLines;
3851
+ }
3852
+
3853
+ getOptions() {
3854
+ // @FIXME: temporarily disabling this option
3855
+ // const hold = this.session.hasEngineVersionGte(MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD);
3856
+
3857
+ return {
3858
+ accept: false,
3859
+ decline: true,
3860
+ mute: true,
3861
+ hold: false,
3862
+ transfer: true,
3863
+ sendKey: true,
3864
+ addParticipant: false,
3865
+ record: true,
3866
+ merge: false,
3867
+ };
3868
+ }
3869
+
3870
+ hasAnActiveCall() {
3871
+ return !!this.currentCall;
3872
+ }
3873
+
3874
+ callCount() {
3875
+ return this.currentCall ? 1 : 0;
3876
+ }
3877
+
3878
+ isWebRTC() {
3879
+ return false;
3880
+ }
3881
+
3882
+ getUserAgent() {
3883
+ return 'cti-phone';
3884
+ }
3885
+
3886
+ startHeartbeat() {
3887
+ }
3888
+
3889
+ setOnHeartbeatTimeout() {
3890
+ }
3891
+
3892
+ setOnHeartbeatCallback() {
3893
+ }
3894
+
3895
+ stopHeartbeat() {
3896
+ }
3897
+
3898
+ bindClientEvents() {
3899
+ }
3900
+
3901
+ onConnect() {
3902
+ }
3903
+
3904
+ onDisconnect() {
3905
+ }
3906
+
3907
+ async makeCall(number , line ) {
3908
+ logger$a.info('make CTI call', { number });
3909
+
3910
+ if (!number) {
3911
+ return null;
3912
+ }
3913
+ try {
3914
+ this.currentCall = await CallApi.makeCall(line, number, this.isMobile, this.callbackAllLines);
3915
+ } catch (_) {
3916
+ // We have to deal with error like `User has no mobile phone number` error in the UI.
3917
+ }
3918
+ if (!this.currentCall) {
3919
+ return null;
3920
+ }
3921
+ const callSession = CallSession.parseCall(this.currentCall);
3922
+ this.eventEmitter.emit('onCallOutgoing', callSession);
3923
+
3924
+ return callSession;
3925
+ }
3926
+
3927
+ accept(callSession ) {
3928
+ if (!callSession) {
3929
+ return Promise.resolve(null);
3930
+ }
3931
+ logger$a.info('accept CTI call', { callId: callSession.getId(), number: callSession.number });
3932
+
3933
+ if (!this.currentCall) {
3934
+ this.currentCall = callSession.call;
3935
+ }
3936
+
3937
+ return Promise.resolve(callSession.getId());
3938
+ }
3939
+
3940
+ endCurrentCall(callSession ) {
3941
+ if (!callSession) {
3942
+ return;
3943
+ }
3944
+ logger$a.info('end current CTI call', { callId: callSession.getId(), number: callSession.number });
3945
+
3946
+ this.currentCall = undefined;
3947
+ this.eventEmitter.emit('onCallEnded', callSession);
3948
+ }
3949
+
3950
+ async hangup(callSession ) {
3951
+ if (!callSession) {
3952
+ return Promise.resolve(false);
3953
+ }
3954
+ logger$a.info('hangup CTI call', { callId: callSession.getId(), number: callSession.number });
3955
+
3956
+ try {
3957
+ await CallApi.cancelCall(callSession);
3958
+ if (this.currentCall && callSession.callId === this.currentCall.id) {
3959
+ this.endCurrentCall(callSession);
3960
+ }
3961
+
3962
+ this.eventEmitter.emit('onCallEnded', callSession);
3963
+ return true;
3964
+ } catch (e) {
3965
+ logger$a.error('hangup CTI call, error', e);
3966
+
3967
+ this.eventEmitter.emit('onCallFailed', callSession);
3968
+ return false;
3969
+ }
3970
+ }
3971
+
3972
+ ignore() {}
3973
+
3974
+ async reject(callSession ) {
3975
+ if (!callSession) {
3976
+ return;
3977
+ }
3978
+ logger$a.info('reject CTI call', { callId: callSession.getId(), number: callSession.number });
3979
+
3980
+ await CallApi.cancelCall(callSession);
3981
+ this.eventEmitter.emit('onCallEnded', callSession);
3982
+ }
3983
+
3984
+ async transfer(callSession , number ) {
3985
+ if (!callSession) {
3986
+ return;
3987
+ }
3988
+ logger$a.info('transfer CTI call', { callId: callSession.getId(), number: callSession.number, to: number });
3989
+
3990
+ await CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_BLIND);
3991
+ }
3992
+
3993
+ indirectTransfer() {}
3994
+
3995
+ async initiateCTIIndirectTransfer(callSession , number ) {
3996
+ if (!callSession) {
3997
+ return;
3998
+ }
3999
+ logger$a.info('indirect CTI transfer', { callId: callSession.getId(), number: callSession.number, to: number });
4000
+
4001
+ return CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_ATTENDED);
4002
+ }
4003
+
4004
+ async cancelCTIIndirectTransfer(transferId ) {
4005
+ logger$a.info('cancel CTI transfer', { transferId });
4006
+
4007
+ return CallApi.cancelCallTransfer(transferId);
4008
+ }
4009
+
4010
+ async confirmCTIIndirectTransfer(transferId ) {
4011
+ logger$a.info('confirm CTI transfer', { transferId });
4012
+
4013
+ return CallApi.confirmCallTransfer(transferId);
4014
+ }
4015
+
4016
+ sendKey(callSession , digits ) {
4017
+ if (!callSession) {
4018
+ return;
4019
+ }
4020
+ logger$a.info('send CTI key', { callId: callSession.getId(), number: callSession.number, digits });
4021
+
4022
+ return CallApi.sendDTMF(callSession.callId, digits);
4023
+ }
4024
+
4025
+ onConnectionMade() {
4026
+ logger$a.info('on CTI connection made');
4027
+
4028
+ this.eventEmitter.emit('onCallAccepted');
4029
+ }
4030
+
4031
+ async close() {
4032
+ logger$a.info('CTI close');
4033
+
4034
+ return Promise.resolve();
4035
+ }
4036
+
4037
+ async hold(callSession ) {
4038
+ if (!callSession) {
4039
+ return;
4040
+ }
4041
+ logger$a.info('CTI hold', { callId: callSession.getId(), number: callSession.number });
4042
+
4043
+ return CallApi.hold(callSession.callId);
4044
+ }
4045
+
4046
+ async resume(callSession ) {
4047
+ if (!callSession) {
4048
+ return;
4049
+ }
4050
+ logger$a.info('CTI resume', { callId: callSession.getId(), number: callSession.number });
4051
+
4052
+ return CallApi.resume(callSession.callId);
4053
+ }
4054
+
4055
+ async mute(callSession ) {
4056
+ if (!callSession) {
4057
+ return;
4058
+ }
4059
+ logger$a.info('CTI mute', { callId: callSession.getId(), number: callSession.number });
4060
+
4061
+ return CallApi.mute(callSession.callId);
4062
+ }
4063
+
4064
+ async unmute(callSession ) {
4065
+ if (!callSession) {
4066
+ return;
4067
+ }
4068
+ logger$a.info('CTI unmute', { callId: callSession.getId(), number: callSession.number });
4069
+
4070
+ return CallApi.unmute(callSession.callId);
4071
+ }
4072
+
4073
+ putOnSpeaker() {}
4074
+
4075
+ putOffSpeaker() {}
4076
+
4077
+ turnCameraOff() {}
4078
+
4079
+ turnCameraOn() {}
4080
+
4081
+ changeAudioInputDevice() {}
4082
+
4083
+ changeVideoInputDevice() {}
4084
+
4085
+ changeAudioDevice() {}
4086
+
4087
+ changeRingDevice() {}
4088
+
4089
+ changeAudioVolume() {}
4090
+
4091
+ changeRingVolume() {}
4092
+
4093
+ hasVideo() {
4094
+ return false;
4095
+ }
4096
+
4097
+ getLocalStreamForCall() {
4098
+ return null;
4099
+ }
4100
+
4101
+ getRemoteStreamForCall() {
4102
+ return null;
4103
+ }
4104
+
4105
+ getLocalVideoStream() {
4106
+ return null;
4107
+ }
4108
+
4109
+ setActiveSipSession() {}
4110
+
4111
+ isRegistered() {
4112
+ return true;
4113
+ }
4114
+
4115
+ hasIncomingCallSession() {
4116
+ return true;
4117
+ }
4118
+
4119
+ hasActiveRemoteVideoStream() {
4120
+ return false;
4121
+ }
4122
+
4123
+ getCurrentCallSession() {
4124
+ return this.currentCall ? CallSession.parseCall(this.currentCall) : null;
4125
+ }
4126
+
4127
+ enableRinging() {}
4128
+
4129
+ sendMessage() {}
4130
+
4131
+ disableRinging() {}
4132
+
4133
+ getLocalStream() {
4134
+ return null;
4135
+ }
4136
+
4137
+ getRemoteStream() {
4138
+ return null;
4139
+ }
4140
+
4141
+ getRemoteVideoStream() {
4142
+ return null;
4143
+ }
4144
+
4145
+ getRemoteAudioStream() {
4146
+ return null;
4147
+ }
4148
+
4149
+ hasLocalVideo() {
4150
+ return false;
4151
+ }
4152
+
4153
+ useLocalVideoElement() {}
4154
+ }
3680
4155
 
3681
4156
  /* */
3682
4157
 
@@ -4711,6 +5186,10 @@ class ApiClient {
4711
5186
  this.fetchOptions = fetchOptions;
4712
5187
  this.client.setFetchOptions(fetchOptions);
4713
5188
  }
5189
+
5190
+ disableErrorLogging() {
5191
+ this.client.disableErrorLogging();
5192
+ }
4714
5193
  }
4715
5194
 
4716
5195
  /* eslint-disable dot-notation */
@@ -5252,23 +5731,6 @@ const areCandidateValid = (candidates ) =>
5252
5731
  getSrflxOrRelay(candidates)
5253
5732
  .length > 0;
5254
5733
 
5255
- const toggleVideoDirection = (sdp , direction ) => {
5256
- const parsedSdp = sdpParser__default['default'].parse(sdp);
5257
- parsedSdp.media = parsedSdp.media.map(media => ({
5258
- ...media,
5259
- ...(media.type === 'video' ? { direction } : {}),
5260
- }));
5261
-
5262
- return sdpParser__default['default'].write(parsedSdp);
5263
- };
5264
-
5265
- const deactivateVideoModifier = (rawDescription ) => {
5266
- const description = rawDescription;
5267
- description.sdp = toggleVideoDirection(description.sdp, 'inactive');
5268
-
5269
- return Promise.resolve(description);
5270
- };
5271
-
5272
5734
  const hasAnActiveVideo = (sdp ) => {
5273
5735
  if (!sdp) {
5274
5736
  return false;
@@ -5380,6 +5842,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5380
5842
  const iceRestart = options.offerOptions ? options.offerOptions.iceRestart : false;
5381
5843
 
5382
5844
  const isConference = options ? !!options.conference : false;
5845
+ const audioOnly = options ? !!options.audioOnly : false;
5383
5846
 
5384
5847
  // We should wait for ice when iceRestart (reinvite) or for the first invite
5385
5848
  // We shouldn't wait for ice when holding or resuming the call
@@ -5406,16 +5869,16 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5406
5869
  };
5407
5870
 
5408
5871
  return this.getLocalMediaStream(options)
5409
- .then(() => this.updateDirection(options, isConference))
5872
+ .then(() => this.updateDirection(options, isConference, audioOnly))
5410
5873
  .then(() => this.createDataChannel(options))
5411
5874
  .then(() => {
5412
- if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options)) {
5875
+ if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
5413
5876
  // Add a video an empty bundle to be able to replaceTrack when joining a conference without video
5414
5877
  this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5415
5878
  }
5416
5879
  })
5417
5880
  .then(() => this.createLocalOfferOrAnswer(options))
5418
- .then((sessionDescription) => this.setLocalSessionDescription(sessionDescription))
5881
+ .then(sessionDescription => this.setLocalSessionDescription(sessionDescription))
5419
5882
  .then(() => this.waitForIceGatheringComplete(iceRestart, iceTimeout))
5420
5883
  .then(() => this.getLocalSessionDescription())
5421
5884
  .then(description => {
@@ -5538,7 +6001,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5538
6001
  }
5539
6002
 
5540
6003
  // Overridden to send `inactive` in conference
5541
- updateDirection(options , isConference = false) {
6004
+ updateDirection(options , isConference = false,
6005
+ audioOnly = false) {
5542
6006
  if (this._peerConnection === undefined) {
5543
6007
  return Promise.reject(new Error('Peer connection closed.'));
5544
6008
  }
@@ -5553,14 +6017,17 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5553
6017
  // if we are stable, assume we are creating a local offer
5554
6018
  this.logger.debug('SessionDescriptionHandler.updateDirection - setting offer direction');
5555
6019
  // determine the direction to offer given the current direction and hold state
5556
- const directionToOffer = (currentDirection ) => {
6020
+ const directionToOffer = (currentDirection , transceiver /* RTCRtpTransceiver */) => {
5557
6021
  if (isConference) {
6022
+ if (audioOnly && transceiver.receiver.track && transceiver.receiver.track.kind === 'video') {
6023
+ return 'sendonly';
6024
+ }
5558
6025
  return options && options.hold ? 'sendonly' : 'sendrecv';
5559
6026
  }
5560
6027
 
5561
6028
  switch (currentDirection) {
5562
6029
  case 'inactive':
5563
- return options && options.hold ? 'inactive' : 'recvonly';
6030
+ return options && options.hold ? 'inactive' : (isConference && !audioOnly ? 'sendrecv' : 'recvonly');
5564
6031
  case 'recvonly':
5565
6032
  return options && options.hold ? 'inactive' : 'recvonly';
5566
6033
  case 'sendonly':
@@ -5576,7 +6043,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5576
6043
  // set the transceiver direction to the offer direction
5577
6044
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5578
6045
  if (transceiver.direction /* guarding, but should always be true */) {
5579
- const offerDirection = directionToOffer(transceiver.direction);
6046
+ const offerDirection = directionToOffer(transceiver.direction, transceiver);
5580
6047
  if (transceiver.direction !== offerDirection) {
5581
6048
  // eslint-disable-next-line no-param-reassign
5582
6049
  transceiver.direction = offerDirection;
@@ -5635,6 +6102,13 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5635
6102
  // set the transceiver direction to the answer direction
5636
6103
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5637
6104
  if (transceiver.direction /* guarding, but should always be true */) {
6105
+ const { receiver } = transceiver;
6106
+ if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
6107
+ // eslint-disable-next-line no-param-reassign
6108
+ transceiver.direction = 'inactive';
6109
+ return;
6110
+ }
6111
+
5638
6112
  if (transceiver.direction !== 'stopped' && transceiver.direction !== answerDirection) {
5639
6113
  // eslint-disable-next-line no-param-reassign
5640
6114
  transceiver.direction = answerDirection;
@@ -5673,8 +6147,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5673
6147
  }
5674
6148
  const sender = pc.getSenders().find((otherSender) => otherSender.track && otherSender.track.kind === kind);
5675
6149
 
5676
- // Do not reuse sender tracks in SFU
5677
- if (sender && !sfu) {
6150
+ // Do not reuse sender video tracks in SFU
6151
+ if (sender && (!sfu || newTrack.kind === 'audio')) {
5678
6152
  trackUpdates.push(
5679
6153
  new Promise((resolve) => {
5680
6154
  this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
@@ -6226,9 +6700,15 @@ class WebRTCClient extends Emitter {
6226
6700
 
6227
6701
  call(number , enableVideo , audioOnly = false, conference = false) {
6228
6702
  logger$7.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
6229
- const inviterOptions = {};
6703
+ const inviterOptions = {
6704
+ sessionDescriptionHandlerOptionsReInvite: {
6705
+ conference,
6706
+ audioOnly,
6707
+ },
6708
+ };
6709
+
6230
6710
  if (audioOnly) {
6231
- inviterOptions.sessionDescriptionHandlerModifiersReInvite = [deactivateVideoModifier];
6711
+ inviterOptions.sessionDescriptionHandlerModifiersReInvite = [modifiers.stripVideo];
6232
6712
  }
6233
6713
 
6234
6714
  const session = new inviter.Inviter(this.userAgent, this._makeURI(number), inviterOptions);
@@ -6257,10 +6737,11 @@ class WebRTCClient extends Emitter {
6257
6737
  sessionDescriptionHandlerOptions: this.getMediaConfiguration(enableVideo || false, conference),
6258
6738
  };
6259
6739
 
6260
- inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6740
+ inviteOptions.sessionDescriptionHandlerOptions.audioOnly = audioOnly;
6261
6741
 
6742
+ inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6262
6743
  if (audioOnly) {
6263
- inviteOptions.sessionDescriptionHandlerModifiers.push(deactivateVideoModifier);
6744
+ inviteOptions.sessionDescriptionHandlerModifiers.push(modifiers.stripVideo);
6264
6745
  }
6265
6746
 
6266
6747
  // Do not await invite here or we'll miss the Establishing state transition
@@ -6474,6 +6955,9 @@ class WebRTCClient extends Emitter {
6474
6955
  if (!this._isWeb()) {
6475
6956
  options.sessionDescriptionHandlerModifiers = [modifiers.holdModifier];
6476
6957
  }
6958
+ options.sessionDescriptionHandlerOptions = {
6959
+ constraints: options.constraints,
6960
+ };
6477
6961
 
6478
6962
  // Send re-INVITE
6479
6963
  return session.invite(options);
@@ -6513,6 +6997,9 @@ class WebRTCClient extends Emitter {
6513
6997
  // (eg: holdModifier)
6514
6998
  options.sessionDescriptionHandlerModifiers = [];
6515
6999
  }
7000
+ options.sessionDescriptionHandlerOptions = {
7001
+ constraints: options.constraints,
7002
+ };
6516
7003
 
6517
7004
  // Send re-INVITE
6518
7005
  return session.invite(options);
@@ -6742,7 +7229,8 @@ class WebRTCClient extends Emitter {
6742
7229
  ? this.video.deviceId.exact : undefined;
6743
7230
  }
6744
7231
 
6745
- reinvite(sipSession , newConstraints = null, conference = false) {
7232
+ reinvite(sipSession , newConstraints = null, conference = false,
7233
+ audioOnly = false) {
6746
7234
  if (!sipSession) {
6747
7235
  return false;
6748
7236
  }
@@ -6752,16 +7240,17 @@ class WebRTCClient extends Emitter {
6752
7240
  }
6753
7241
 
6754
7242
  const wasMuted = this.isAudioMuted(sipSession);
6755
- // When upgrading to video, remove the `deactivateVideoModifier` modifiers
7243
+ // When upgrading to video, remove the `stripVideo` modifiers
6756
7244
  if (newConstraints && newConstraints.video) {
6757
- const modifiers = sipSession.sessionDescriptionHandlerModifiersReInvite;
6758
- sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers.filter(modifier =>
6759
- modifier !== deactivateVideoModifier);
7245
+ const modifiers$1 = sipSession.sessionDescriptionHandlerModifiersReInvite;
7246
+ sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers$1.filter(modifier =>
7247
+ modifier !== modifiers.stripVideo);
6760
7248
  }
6761
7249
 
6762
7250
  sipSession.sessionDescriptionHandlerOptionsReInvite = {
6763
7251
  ...sipSession.sessionDescriptionHandlerOptionsReInvite,
6764
7252
  conference,
7253
+ audioOnly,
6765
7254
  };
6766
7255
 
6767
7256
  const shouldDoVideo = newConstraints ? newConstraints.video : this.sessionWantsToDoVideo(sipSession);
@@ -6801,6 +7290,8 @@ class WebRTCClient extends Emitter {
6801
7290
  },
6802
7291
  sessionDescriptionHandlerOptions: {
6803
7292
  constraints,
7293
+ conference,
7294
+ audioOnly,
6804
7295
  offerOptions: {
6805
7296
  iceRestart: false,
6806
7297
  },
@@ -7260,6 +7751,8 @@ class WebRTCClient extends Emitter {
7260
7751
 
7261
7752
  // Invitation and Inviter extends Session
7262
7753
  _setupSession(session ) {
7754
+ const sipSessionId = this.getSipSessionId(session);
7755
+
7263
7756
  // When receiving an Invitation, the delegate is not defined.
7264
7757
  if (!session.delegate) {
7265
7758
  session.delegate = {};
@@ -7283,8 +7776,18 @@ class WebRTCClient extends Emitter {
7283
7776
  };
7284
7777
  };
7285
7778
 
7779
+ const oldInviteRequest = session.onInviteRequest.bind(session);
7780
+ let hadRemoteVideo = false;
7781
+
7782
+ // Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
7783
+ // Becase when `onInvite` is called we already got the video track
7784
+ session.onInviteRequest = (request) => {
7785
+ hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7786
+
7787
+ oldInviteRequest(request);
7788
+ };
7789
+
7286
7790
  session.delegate.onInvite = (request ) => {
7287
- const sipSessionId = this.getSipSessionId(session);
7288
7791
  let updatedCalleeName = null;
7289
7792
  let updatedNumber = null;
7290
7793
  if (session.assertedIdentity) {
@@ -7294,7 +7797,6 @@ class WebRTCClient extends Emitter {
7294
7797
  logger$7.info('re-invite received', { updatedCalleeName, updatedNumber });
7295
7798
 
7296
7799
  // Useful to know if it's a video upgrade or an unhold from a remote peer with a video stream
7297
- const hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7298
7800
 
7299
7801
  // Update SDP
7300
7802
  // Remote video is handled by the `track` event. Here we're dealing with video stream removal.
@@ -7344,7 +7846,7 @@ class WebRTCClient extends Emitter {
7344
7846
  }
7345
7847
 
7346
7848
  _isAudioOnly(session ) {
7347
- return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === deactivateVideoModifier);
7849
+ return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === modifiers.stripVideo);
7348
7850
  }
7349
7851
 
7350
7852
  _setupMedias(session , newStream ) {
@@ -7717,9 +8219,14 @@ class WebRTCPhone extends Emitter {
7717
8219
  return true;
7718
8220
  }
7719
8221
 
7720
- async sendReinvite(callSession , constraints = null, conference = false) {
8222
+ async sendReinvite(callSession , constraints = null, conference = false,
8223
+ audioOnly = false) {
7721
8224
  const sipSession = this.findSipSession(callSession);
7722
- logger$6.info('WebRTC phone - send reinvite', { sessionId: sipSession ? sipSession.id : null, constraints });
8225
+ logger$6.info('WebRTC phone - send reinvite', {
8226
+ sessionId: sipSession ? sipSession.id : null,
8227
+ constraints,
8228
+ audioOnly,
8229
+ });
7723
8230
 
7724
8231
  if (!sipSession) {
7725
8232
  return null;
@@ -7745,7 +8252,7 @@ class WebRTCPhone extends Emitter {
7745
8252
  // Force reinvite in SDH
7746
8253
  sipSession.sessionDescriptionHandler.localMediaStreamConstraints = null;
7747
8254
 
7748
- return this.client.reinvite(sipSession, constraints, conference);
8255
+ return this.client.reinvite(sipSession, constraints, conference, audioOnly);
7749
8256
  }
7750
8257
 
7751
8258
  getUserAgent() {
@@ -7821,9 +8328,9 @@ class WebRTCPhone extends Emitter {
7821
8328
  }
7822
8329
 
7823
8330
  // Release local video stream when downgrading to audio
7824
- const localVideoStream = sipSession.sessionDescriptionHandler.localMediaStream;
8331
+ const localStream = sipSession.sessionDescriptionHandler.localMediaStream;
7825
8332
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7826
- const videoTracks = localVideoStream.getVideoTracks();
8333
+ const videoTracks = localStream.getVideoTracks();
7827
8334
 
7828
8335
  // Remove video senders
7829
8336
  pc.getSenders().filter(sender => sender.track && sender.track.kind === 'video').forEach(videoSender => {
@@ -7838,7 +8345,7 @@ class WebRTCPhone extends Emitter {
7838
8345
  videoTracks.forEach(videoTrack => {
7839
8346
  videoTrack.enabled = false;
7840
8347
  videoTrack.stop();
7841
- localVideoStream.removeTrack(videoTrack);
8348
+ localStream.removeTrack(videoTrack);
7842
8349
  });
7843
8350
 
7844
8351
  this._sendReinviteMessage(callSession, false);
@@ -7855,12 +8362,14 @@ class WebRTCPhone extends Emitter {
7855
8362
 
7856
8363
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7857
8364
  const shouldScreenShare = constraints && constraints.screen;
8365
+ const options = sipSession.sessionDescriptionHandlerOptionsReInvite;
8366
+ const wasAudioOnly = options && options.audioOnly;
7858
8367
 
7859
8368
  // Check if a video sender already exists
7860
8369
  let videoSender;
7861
8370
  if (isConference) {
7862
8371
  const trans = pc.getTransceivers().find(transceiver => transceiver.mid === '1');
7863
- videoSender = trans.sender;
8372
+ videoSender = trans ? trans.sender : null;
7864
8373
  } else {
7865
8374
  videoSender = pc.getSenders().find(sender => sender.track === null);
7866
8375
  }
@@ -7897,6 +8406,11 @@ class WebRTCPhone extends Emitter {
7897
8406
  this._onScreenSharing(newStream, sipSession, callSession, false);
7898
8407
  }
7899
8408
 
8409
+ // We have to reinvite to change the direction on the bundle when upgrading from an audioOnly conference
8410
+ if (isConference && wasAudioOnly) {
8411
+ return true;
8412
+ }
8413
+
7900
8414
  // No reinvite needed here
7901
8415
  return false;
7902
8416
  }
@@ -7981,7 +8495,7 @@ class WebRTCPhone extends Emitter {
7981
8495
  event.track.enabled = false;
7982
8496
  }
7983
8497
 
7984
- return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event);
8498
+ return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event, sipSession);
7985
8499
  };
7986
8500
 
7987
8501
  peerConnection.onremovestream = event => {
@@ -8037,14 +8551,11 @@ class WebRTCPhone extends Emitter {
8037
8551
  const targetCallSession = callSession || this.currentCallSession;
8038
8552
  const conference = this.isConference(targetCallSession);
8039
8553
 
8040
- if (this.currentScreenShare.sender && this.currentScreenShare.hadVideo) {
8041
- // When stopping screenshare and we had video before that, we have to re-upgrade
8042
- await this.sendReinvite(targetCallSession, { audio: false, video: true }, conference);
8043
- } else {
8044
- // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8045
- // We have to downgrade to audio.
8046
- await this.sendReinvite(targetCallSession, { audio: false, video: false }, conference);
8047
- }
8554
+ // When stopping screenshare and we had video before that, we have to re-upgrade
8555
+ // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8556
+ // We have to downgrade to audio.
8557
+ const screenshareStopped = this.currentScreenShare.sender && this.currentScreenShare.hadVideo;
8558
+ await this.sendReinvite(targetCallSession, { audio: false, video: screenshareStopped }, conference);
8048
8559
  }
8049
8560
  } catch (e) {
8050
8561
  console.warn(e);
@@ -8381,6 +8892,7 @@ class WebRTCPhone extends Emitter {
8381
8892
  }
8382
8893
  }
8383
8894
 
8895
+ // @Deprecated
8384
8896
  unhold(callSession , withEvent = true, isConference = false) {
8385
8897
  logger$6.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
8386
8898
 
@@ -9378,6 +9890,7 @@ class Phone extends Emitter {
9378
9890
  return this.phone && this.phone.hasLocalVideo(callSession);
9379
9891
  }
9380
9892
 
9893
+ // @Deprecated
9381
9894
  getLocalMediaStream(callSession ) {
9382
9895
  logger$5.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
9383
9896
 
@@ -9396,17 +9909,20 @@ class Phone extends Emitter {
9396
9909
  return this.phone ? this.phone.getRemoteVideoStream(callSession) : null;
9397
9910
  }
9398
9911
 
9912
+ // @Deprecated
9399
9913
  getRemoteStreamForCall(callSession ) {
9400
9914
  logger$5.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
9401
9915
  return this.getRemoteStream(callSession);
9402
9916
  }
9403
9917
 
9404
9918
  // Returns remote streams directly from the peerConnection
9919
+ // @Deprecated
9405
9920
  getRemoteStreamsForCall(callSession ) {
9406
- logger$5.warn('Phone.getRe is deprecated, use Phone.getLocalStream instead');
9921
+ logger$5.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
9407
9922
  return this.getLocalStream(callSession);
9408
9923
  }
9409
9924
 
9925
+ // @Deprecated
9410
9926
  getRemoteVideoStreamForCall(callSession ) {
9411
9927
  logger$5.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
9412
9928
 
@@ -10400,10 +10916,7 @@ class Stream {
10400
10916
  element.onloadedmetadata = () => {
10401
10917
  const tracks = this.htmlStream ? this.htmlStream.getVideoTracks() : [];
10402
10918
  tracks.forEach(track => {
10403
- // Do not re-enable the track if already mounted.
10404
- if (!track.loaded) {
10405
- track.enabled = true;
10406
- }
10919
+ track.enabled = true;
10407
10920
  // $FlowFixMe
10408
10921
  track.loaded = true;
10409
10922
  });
@@ -10844,6 +11357,7 @@ var api = {
10844
11357
  check: async (server, session) => {
10845
11358
  const client = new ApiClient({ server });
10846
11359
  client.setToken(session.token);
11360
+ client.disableErrorLogging();
10847
11361
 
10848
11362
  const handleApiError = (apiName, error) => {
10849
11363
  const statusText = error instanceof ServerError ? 'server error' : 'api error';
@@ -10918,6 +11432,8 @@ var aor = {
10918
11432
  check: async (server, session) => {
10919
11433
  const apiClient = new ApiClient({ server });
10920
11434
  apiClient.setToken(session.token);
11435
+ apiClient.disableErrorLogging();
11436
+
10921
11437
  const line = session.primaryWebRtcLine();
10922
11438
  if (!line) {
10923
11439
  return 'No WebRTC line for this user';
@@ -11340,6 +11856,8 @@ const Wazo = {
11340
11856
  ServerError,
11341
11857
  Call,
11342
11858
  CallLog,
11859
+ CTIPhone,
11860
+ Recording,
11343
11861
  ChatMessage,
11344
11862
  ChatRoom,
11345
11863
  Contact,
@@ -11354,6 +11872,7 @@ const Wazo = {
11354
11872
  CallSession,
11355
11873
  IndirectTransfer,
11356
11874
  SwitchboardCall,
11875
+ WebRTCPhone,
11357
11876
  },
11358
11877
 
11359
11878
  // Api
@@ -11788,13 +12307,15 @@ class Room extends Emitter {
11788
12307
  }
11789
12308
  });
11790
12309
 
11791
- this.on(this.ON_VIDEO_STREAM, (stream, streamId) => {
12310
+ this.on(this.ON_VIDEO_STREAM, (stream, streamId, event, sipSession) => {
11792
12311
  logger.info('on room video stream', { streamId });
11793
12312
 
12313
+ this._mapMsid(sipSession.body.body);
12314
+
11794
12315
  // ON_VIDEO_STREAM is called before PARTICIPANT_JOINED, so we have to keep stream in `_unassociatedVideoStreams`.
11795
12316
  this._unassociatedVideoStreams[streamId] = stream;
11796
12317
 
11797
- const callId = this._getCallIdFromStreamId(streamId);
12318
+ const callId = this._getCallIdFromTrackId(streamId);
11798
12319
  const participant = callId ? this._getParticipantFromCallId(callId) : null;
11799
12320
  if (participant) {
11800
12321
  this.__associateStreams(participant);
@@ -11838,11 +12359,12 @@ class Room extends Emitter {
11838
12359
  const sdp = sdpParser__default['default'].parse(rawSdp);
11839
12360
  const labelMsidArray = sdp.media.filter(media => !!media.label).map(({ label, msid }) => ({
11840
12361
  label: String(label),
11841
- msid: msid.split(' ')[1],
12362
+ streamId: msid.split(' ')[0],
12363
+ trackId: msid.split(' ')[1],
11842
12364
  }));
11843
12365
 
11844
- labelMsidArray.forEach(({ label, msid }) => {
11845
- this._callIdStreamIdMap[String(label)] = msid;
12366
+ labelMsidArray.forEach(({ label, streamId, trackId }) => {
12367
+ this._callIdStreamIdMap[String(label)] = { streamId, trackId };
11846
12368
 
11847
12369
  const callId = String(label);
11848
12370
  const participant = this._unassociatedParticipants[callId] || this._getParticipantFromCallId(callId);
@@ -12072,9 +12594,9 @@ class Room extends Emitter {
12072
12594
  _onParticipantTrackUpdate(oldParticipant , update ) {
12073
12595
  const newParticipant = oldParticipant;
12074
12596
 
12075
- const label = this._callIdStreamIdMap[newParticipant.callId];
12597
+ const { trackId } = this._callIdStreamIdMap[newParticipant.callId] || {};
12076
12598
  const pc = Wazo.Phone.phone.currentSipSession.sessionDescriptionHandler.peerConnection;
12077
- const stream = pc.getRemoteStreams().find(otherStream => otherStream.getTracks().some(track => track.id === label));
12599
+ const stream = pc.getRemoteStreams().find(someStream => someStream.getTracks().some(track => track.id === trackId));
12078
12600
 
12079
12601
  if (update === 'downgrade') {
12080
12602
  newParticipant.streams = [];
@@ -12094,21 +12616,21 @@ class Room extends Emitter {
12094
12616
 
12095
12617
  // Associate audio/video streams to the participant and triggers events on it
12096
12618
  __associateStreams(participant ) {
12097
- const streamId = this._callIdStreamIdMap[participant.callId];
12098
- if (!streamId) {
12619
+ const { trackId } = this._callIdStreamIdMap[participant.callId] || {};
12620
+ if (!trackId) {
12099
12621
  this._unassociatedParticipants[participant.callId] = participant;
12100
12622
 
12101
12623
  return;
12102
12624
  }
12103
- if (!streamId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
12625
+ if (!trackId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
12104
12626
  return;
12105
12627
  }
12106
12628
 
12107
- if (this._unassociatedVideoStreams[streamId]) {
12629
+ if (this._unassociatedVideoStreams[trackId]) {
12108
12630
  // Try to associate stream
12109
- this._associateStreamTo(this._unassociatedVideoStreams[streamId], participant);
12631
+ this._associateStreamTo(this._unassociatedVideoStreams[trackId], participant);
12110
12632
 
12111
- delete this._unassociatedVideoStreams[streamId];
12633
+ delete this._unassociatedVideoStreams[trackId];
12112
12634
  delete this._unassociatedParticipants[participant.callId];
12113
12635
  }
12114
12636
  }
@@ -12121,8 +12643,8 @@ class Room extends Emitter {
12121
12643
  participant.onStreamSubscribed(stream);
12122
12644
  }
12123
12645
 
12124
- _getCallIdFromStreamId(streamId ) {
12125
- return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key] === streamId);
12646
+ _getCallIdFromTrackId(trackId ) {
12647
+ return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key].trackId === trackId);
12126
12648
  }
12127
12649
 
12128
12650
  _getParticipantFromCallId(callId ) {