@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
@@ -9,7 +9,6 @@ var jsonToGraphQLQuery = require('json-to-graphql-query/lib/jsonToGraphQLQuery')
9
9
  var invitation = require('sip.js/lib/api/invitation');
10
10
  require('webrtc-adapter');
11
11
  var userAgentState = require('sip.js/lib/api/user-agent-state');
12
- require('sip.js/lib/api/message');
13
12
  var parser = require('sip.js/lib/core/messages/parser');
14
13
  var constants = require('sip.js/lib/core/messages/methods/constants');
15
14
  var uri = require('sip.js/lib/grammar/uri');
@@ -1013,7 +1012,7 @@ class Contact {
1013
1012
 
1014
1013
  return new Contact({
1015
1014
  sourceId: single.id || '',
1016
- name: single.displayName,
1015
+ name: single.displayName || '',
1017
1016
  number: numbers.length ? numbers[0].number : '',
1018
1017
  numbers,
1019
1018
  emails,
@@ -1044,7 +1043,7 @@ class Contact {
1044
1043
 
1045
1044
  return new Contact({
1046
1045
  sourceId: single.id || '',
1047
- name: single.name,
1046
+ name: single.name || '',
1048
1047
  number: numbers.length ? numbers[0].number : '',
1049
1048
  numbers,
1050
1049
  emails,
@@ -1145,7 +1144,7 @@ class Contact {
1145
1144
  } = {}) {
1146
1145
  this.id = id;
1147
1146
  this.uuid = uuid;
1148
- this.name = name;
1147
+ this.name = name || '';
1149
1148
  this.number = number;
1150
1149
  this.numbers = numbers;
1151
1150
  this.email = email;
@@ -1820,7 +1819,13 @@ class IssueReporter {
1820
1819
  }
1821
1820
 
1822
1821
  _isLevelAbove(level1 , level2 ) {
1823
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
1822
+ const index1 = LOG_LEVELS.indexOf(level1);
1823
+ const index2 = LOG_LEVELS.indexOf(level2);
1824
+ if (index1 === -1 || index2 === -1) {
1825
+ return false;
1826
+ }
1827
+
1828
+ return index1 > index2;
1824
1829
  }
1825
1830
 
1826
1831
  _makeCategory(category ) {
@@ -1843,7 +1848,7 @@ var IssueReporter$1 = new IssueReporter();
1843
1848
 
1844
1849
  const methods = ['head', 'get', 'post', 'put', 'delete'];
1845
1850
 
1846
- const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
1851
+ const logger$b = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
1847
1852
 
1848
1853
  // Use a function here to be able to mock it in tests
1849
1854
  const realFetch = () => {
@@ -1878,6 +1883,7 @@ class ApiRequester {
1878
1883
 
1879
1884
 
1880
1885
 
1886
+
1881
1887
 
1882
1888
 
1883
1889
 
@@ -1917,6 +1923,8 @@ class ApiRequester {
1917
1923
  this.token = token;
1918
1924
  }
1919
1925
 
1926
+ this.shouldLogErrors = true;
1927
+
1920
1928
  methods.forEach(method => {
1921
1929
  // $FlowFixMe
1922
1930
  ApiRequester.prototype[method] = function sugar(...args) {
@@ -1940,6 +1948,14 @@ class ApiRequester {
1940
1948
  this.fetchOptions = options;
1941
1949
  }
1942
1950
 
1951
+ disableErrorLogging() {
1952
+ this.shouldLogErrors = false;
1953
+ }
1954
+
1955
+ enableErrorLogging() {
1956
+ this.shouldLogErrors = true;
1957
+ }
1958
+
1943
1959
  async call(
1944
1960
  path ,
1945
1961
  method = 'get',
@@ -1971,7 +1987,7 @@ class ApiRequester {
1971
1987
  };
1972
1988
 
1973
1989
  if (this.refreshTokenPromise) {
1974
- logger$a.info('A token is already refreshing, waiting ...', { url });
1990
+ logger$b.info('A token is already refreshing, waiting ...', { url });
1975
1991
  await this.refreshTokenPromise;
1976
1992
  }
1977
1993
 
@@ -1991,7 +2007,7 @@ class ApiRequester {
1991
2007
  return promise.then(async (err ) => {
1992
2008
  // Check if the token is still valid
1993
2009
  if (firstCall && this._checkTokenExpired(response, err)) {
1994
- logger$a.warn('token expired', { error: err.reason });
2010
+ logger$b.warn('token expired', { error: err.reason });
1995
2011
  // Replay the call after refreshing the token
1996
2012
  return this._replayWithNewToken(err, path, method, body, headers, parse);
1997
2013
  }
@@ -2000,7 +2016,9 @@ class ApiRequester {
2000
2016
  ? exceptionClass.fromText(err, response.status)
2001
2017
  : exceptionClass.fromResponse(err, response.status);
2002
2018
 
2003
- logger$a.error('API error', error);
2019
+ if (this.shouldLogErrors) {
2020
+ logger$b.error('API error', error);
2021
+ }
2004
2022
 
2005
2023
  throw error;
2006
2024
  });
@@ -2008,7 +2026,9 @@ class ApiRequester {
2008
2026
 
2009
2027
  return newParse(response, isJson);
2010
2028
  }).catch(error => {
2011
- logger$a.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
2029
+ if (this.shouldLogErrors) {
2030
+ logger$b.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
2031
+ }
2012
2032
 
2013
2033
  throw error;
2014
2034
  });
@@ -2035,13 +2055,13 @@ class ApiRequester {
2035
2055
  ) {
2036
2056
  const isTokenNotFound = this._isTokenNotFound(err);
2037
2057
  let newPath = path;
2038
- logger$a.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
2058
+ logger$b.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
2039
2059
 
2040
2060
  this.refreshTokenPromise = this.refreshTokenPromise || this.refreshTokenCallback();
2041
2061
 
2042
2062
  return this.refreshTokenPromise.then(() => {
2043
2063
  this.refreshTokenPromise = null;
2044
- logger$a.info('token refreshed', { isTokenNotFound });
2064
+ logger$b.info('token refreshed', { isTokenNotFound });
2045
2065
  if (isTokenNotFound) {
2046
2066
  const pathParts = path.split('/');
2047
2067
  pathParts.pop();
@@ -3323,7 +3343,7 @@ class CallSession {
3323
3343
  return newFrom(callSession, CallSession);
3324
3344
  }
3325
3345
 
3326
- static parseCall(session , call ) {
3346
+ static parseCall(call ) {
3327
3347
  return new CallSession({
3328
3348
  callId: call.id,
3329
3349
  sipCallId: call.sipCallId,
@@ -3376,17 +3396,66 @@ class Emitter {
3376
3396
 
3377
3397
  //
3378
3398
 
3399
+
3400
+
3401
+
3402
+
3403
+
3404
+
3405
+
3406
+
3407
+
3408
+
3409
+
3410
+
3411
+
3412
+
3413
+
3414
+
3415
+ class Recording {
3416
+
3417
+
3418
+
3419
+
3420
+
3421
+
3422
+ static parseMany(recordings ) {
3423
+ return recordings.map(item => Recording.parse(item));
3424
+ }
3425
+
3426
+ static parse(plain ) {
3427
+ return new Recording({
3428
+ deleted: plain.deleted,
3429
+ fileName: plain.filename,
3430
+ end: plain.end_time ? moment__default['default'](plain.end_time).toDate() : null,
3431
+ start: moment__default['default'](plain.start_time).toDate(),
3432
+ uuid: plain.uuid,
3433
+ });
3434
+ }
3435
+
3436
+ constructor({ deleted, end, fileName, start, uuid } ) {
3437
+ this.deleted = deleted;
3438
+ this.end = end;
3439
+ this.fileName = fileName;
3440
+ this.start = start;
3441
+ this.uuid = uuid;
3442
+ }
3443
+ }
3444
+
3445
+ //
3446
+
3379
3447
 
3380
-
3448
+
3381
3449
 
3382
3450
 
3383
3451
 
3384
3452
 
3385
3453
 
3386
-
3454
+
3387
3455
 
3388
3456
 
3389
3457
 
3458
+
3390
3459
 
3391
3460
 
3392
3461
 
@@ -3399,7 +3468,7 @@ class Emitter {
3399
3468
 
3400
3469
 
3401
3470
 
3402
-
3471
+
3403
3472
 
3404
3473
 
3405
3474
 
@@ -3414,13 +3483,14 @@ class Emitter {
3414
3483
 
3415
3484
 
3416
3485
 
3417
-
3486
+
3487
+
3418
3488
 
3419
3489
 
3420
3490
  class CallLog {
3421
3491
 
3422
3492
 
3423
-
3493
+
3424
3494
 
3425
3495
 
3426
3496
 
@@ -3437,7 +3507,7 @@ class CallLog {
3437
3507
 
3438
3508
 
3439
3509
 
3440
-
3510
+
3441
3511
 
3442
3512
  static merge(current , toMerge ) {
3443
3513
  const onlyUnique = (value, index, self) => self.indexOf(value) === index;
@@ -3454,7 +3524,7 @@ class CallLog {
3454
3524
 
3455
3525
  static parse(plain ) {
3456
3526
  return new CallLog({
3457
- answer: moment__default['default'](plain.answer).toDate(),
3527
+ answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
3458
3528
  answered: plain.answered,
3459
3529
  callDirection: plain.call_direction,
3460
3530
  destination: {
@@ -3468,13 +3538,14 @@ class CallLog {
3468
3538
  id: plain.id,
3469
3539
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3470
3540
  start: moment__default['default'](plain.start).toDate(),
3471
- end: moment__default['default'](plain.end).toDate(),
3541
+ end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3542
+ recordings: Recording.parseMany(plain.recordings),
3472
3543
  });
3473
3544
  }
3474
3545
 
3475
3546
  static parseNew(plain , session ) {
3476
3547
  return new CallLog({
3477
- answer: moment__default['default'](plain.answer).toDate(),
3548
+ answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
3478
3549
  answered: plain.answered,
3479
3550
  callDirection: plain.call_direction,
3480
3551
  destination: {
@@ -3488,7 +3559,8 @@ class CallLog {
3488
3559
  id: plain.id,
3489
3560
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3490
3561
  start: moment__default['default'](plain.start).toDate(),
3491
- end: moment__default['default'](plain.end).toDate(),
3562
+ end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3563
+ recordings: Recording.parseMany(plain.recordings),
3492
3564
  // @TODO: FIXME add verification declined vs missed call
3493
3565
  newMissedCall: session
3494
3566
  && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
@@ -3670,11 +3742,414 @@ class IndirectTransfer {
3670
3742
  }
3671
3743
 
3672
3744
  //
3745
+
3746
+ class CallApi {
3747
+ static async fetchCallLogs(offset , limit ) {
3748
+ return getApiClient().callLogd.listCallLogs(offset, limit);
3749
+ }
3750
+
3751
+ static async fetchDistinctCallLogs(offset , limit , distinct = 'peer_exten') {
3752
+ return getApiClient().callLogd.listDistinctCallLogs(offset, limit, distinct);
3753
+ }
3754
+
3755
+ static async fetchActiveCalls() {
3756
+ return getApiClient().calld.listCalls();
3757
+ }
3758
+
3759
+ static async fetchCallLogsFromDate(from , number ) {
3760
+ return getApiClient().callLogd.listCallLogsFromDate(from, number);
3761
+ }
3762
+
3763
+ static async search(query , limit ) {
3764
+ return getApiClient().callLogd.search(query, limit);
3765
+ }
3766
+
3767
+ static async searchBy(field , value , limit ) {
3768
+ return getApiClient().callLogd.searchBy(field, value, limit);
3769
+ }
3770
+
3771
+ static async fetchSIP(session , line ) {
3772
+ const lineToUse = line || session.primaryLine();
3773
+ return getApiClient().confd.getUserLineSip(session.uuid, lineToUse ? lineToUse.id : null);
3774
+ }
3775
+
3776
+ static async cancelCall(callSession ) {
3777
+ return getApiClient().calld.cancelCall(callSession.callId);
3778
+ }
3779
+
3780
+ static async makeCall(callFromLine , extension , isMobile = false,
3781
+ callbackAllLines = false) {
3782
+ const lineId = callFromLine ? callFromLine.id : null;
3783
+
3784
+ const response = await getApiClient().calld.makeCall(extension, isMobile, lineId, callbackAllLines);
3785
+ return Call.parse(response);
3786
+ }
3787
+
3788
+ static async relocateCall(callId , line , contactIdentifier ) {
3789
+ return getApiClient().calld.relocateCall(callId, 'line', line, contactIdentifier);
3790
+ }
3791
+
3792
+ static async hold(callId ) {
3793
+ return getApiClient().calld.hold(callId);
3794
+ }
3795
+
3796
+ static async resume(callId ) {
3797
+ return getApiClient().calld.resume(callId);
3798
+ }
3799
+
3800
+ static async mute(callId ) {
3801
+ return getApiClient().calld.mute(callId);
3802
+ }
3803
+
3804
+ static async sendDTMF(callId , digits ) {
3805
+ return getApiClient().calld.sendDTMF(callId, digits);
3806
+ }
3807
+
3808
+ static async unmute(callId ) {
3809
+ return getApiClient().calld.unmute(callId);
3810
+ }
3811
+
3812
+ static async transferCall(callId , number , flow ) {
3813
+ return getApiClient().calld.transferCall(callId, number, flow);
3814
+ }
3815
+
3816
+ static async cancelCallTransfer(transferId ) {
3817
+ return getApiClient().calld.cancelCallTransfer(transferId);
3818
+ }
3819
+
3820
+ static async confirmCallTransfer(transferId ) {
3821
+ return getApiClient().calld.confirmCallTransfer(transferId);
3822
+ }
3823
+ }
3824
+
3825
+ //
3826
+
3827
+ const TRANSFER_FLOW_ATTENDED = 'attended';
3673
3828
  const TRANSFER_FLOW_BLIND = 'blind';
3674
3829
 
3675
3830
  // const MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD = '20.11';
3676
3831
 
3677
- IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3832
+ const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3833
+
3834
+ class CTIPhone extends Emitter {
3835
+
3836
+
3837
+
3838
+
3839
+
3840
+
3841
+
3842
+
3843
+ constructor(session , isMobile = false, callbackAllLines = false) {
3844
+ super();
3845
+ logger$a.info('CTI Phone created');
3846
+ this.session = session;
3847
+ this.isMobile = isMobile;
3848
+ this.callbackAllLines = callbackAllLines;
3849
+ }
3850
+
3851
+ getOptions() {
3852
+ // @FIXME: temporarily disabling this option
3853
+ // const hold = this.session.hasEngineVersionGte(MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD);
3854
+
3855
+ return {
3856
+ accept: false,
3857
+ decline: true,
3858
+ mute: true,
3859
+ hold: false,
3860
+ transfer: true,
3861
+ sendKey: true,
3862
+ addParticipant: false,
3863
+ record: true,
3864
+ merge: false,
3865
+ };
3866
+ }
3867
+
3868
+ hasAnActiveCall() {
3869
+ return !!this.currentCall;
3870
+ }
3871
+
3872
+ callCount() {
3873
+ return this.currentCall ? 1 : 0;
3874
+ }
3875
+
3876
+ isWebRTC() {
3877
+ return false;
3878
+ }
3879
+
3880
+ getUserAgent() {
3881
+ return 'cti-phone';
3882
+ }
3883
+
3884
+ startHeartbeat() {
3885
+ }
3886
+
3887
+ setOnHeartbeatTimeout() {
3888
+ }
3889
+
3890
+ setOnHeartbeatCallback() {
3891
+ }
3892
+
3893
+ stopHeartbeat() {
3894
+ }
3895
+
3896
+ bindClientEvents() {
3897
+ }
3898
+
3899
+ onConnect() {
3900
+ }
3901
+
3902
+ onDisconnect() {
3903
+ }
3904
+
3905
+ async makeCall(number , line ) {
3906
+ logger$a.info('make CTI call', { number });
3907
+
3908
+ if (!number) {
3909
+ return null;
3910
+ }
3911
+ try {
3912
+ this.currentCall = await CallApi.makeCall(line, number, this.isMobile, this.callbackAllLines);
3913
+ } catch (_) {
3914
+ // We have to deal with error like `User has no mobile phone number` error in the UI.
3915
+ }
3916
+ if (!this.currentCall) {
3917
+ return null;
3918
+ }
3919
+ const callSession = CallSession.parseCall(this.currentCall);
3920
+ this.eventEmitter.emit('onCallOutgoing', callSession);
3921
+
3922
+ return callSession;
3923
+ }
3924
+
3925
+ accept(callSession ) {
3926
+ if (!callSession) {
3927
+ return Promise.resolve(null);
3928
+ }
3929
+ logger$a.info('accept CTI call', { callId: callSession.getId(), number: callSession.number });
3930
+
3931
+ if (!this.currentCall) {
3932
+ this.currentCall = callSession.call;
3933
+ }
3934
+
3935
+ return Promise.resolve(callSession.getId());
3936
+ }
3937
+
3938
+ endCurrentCall(callSession ) {
3939
+ if (!callSession) {
3940
+ return;
3941
+ }
3942
+ logger$a.info('end current CTI call', { callId: callSession.getId(), number: callSession.number });
3943
+
3944
+ this.currentCall = undefined;
3945
+ this.eventEmitter.emit('onCallEnded', callSession);
3946
+ }
3947
+
3948
+ async hangup(callSession ) {
3949
+ if (!callSession) {
3950
+ return Promise.resolve(false);
3951
+ }
3952
+ logger$a.info('hangup CTI call', { callId: callSession.getId(), number: callSession.number });
3953
+
3954
+ try {
3955
+ await CallApi.cancelCall(callSession);
3956
+ if (this.currentCall && callSession.callId === this.currentCall.id) {
3957
+ this.endCurrentCall(callSession);
3958
+ }
3959
+
3960
+ this.eventEmitter.emit('onCallEnded', callSession);
3961
+ return true;
3962
+ } catch (e) {
3963
+ logger$a.error('hangup CTI call, error', e);
3964
+
3965
+ this.eventEmitter.emit('onCallFailed', callSession);
3966
+ return false;
3967
+ }
3968
+ }
3969
+
3970
+ ignore() {}
3971
+
3972
+ async reject(callSession ) {
3973
+ if (!callSession) {
3974
+ return;
3975
+ }
3976
+ logger$a.info('reject CTI call', { callId: callSession.getId(), number: callSession.number });
3977
+
3978
+ await CallApi.cancelCall(callSession);
3979
+ this.eventEmitter.emit('onCallEnded', callSession);
3980
+ }
3981
+
3982
+ async transfer(callSession , number ) {
3983
+ if (!callSession) {
3984
+ return;
3985
+ }
3986
+ logger$a.info('transfer CTI call', { callId: callSession.getId(), number: callSession.number, to: number });
3987
+
3988
+ await CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_BLIND);
3989
+ }
3990
+
3991
+ indirectTransfer() {}
3992
+
3993
+ async initiateCTIIndirectTransfer(callSession , number ) {
3994
+ if (!callSession) {
3995
+ return;
3996
+ }
3997
+ logger$a.info('indirect CTI transfer', { callId: callSession.getId(), number: callSession.number, to: number });
3998
+
3999
+ return CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_ATTENDED);
4000
+ }
4001
+
4002
+ async cancelCTIIndirectTransfer(transferId ) {
4003
+ logger$a.info('cancel CTI transfer', { transferId });
4004
+
4005
+ return CallApi.cancelCallTransfer(transferId);
4006
+ }
4007
+
4008
+ async confirmCTIIndirectTransfer(transferId ) {
4009
+ logger$a.info('confirm CTI transfer', { transferId });
4010
+
4011
+ return CallApi.confirmCallTransfer(transferId);
4012
+ }
4013
+
4014
+ sendKey(callSession , digits ) {
4015
+ if (!callSession) {
4016
+ return;
4017
+ }
4018
+ logger$a.info('send CTI key', { callId: callSession.getId(), number: callSession.number, digits });
4019
+
4020
+ return CallApi.sendDTMF(callSession.callId, digits);
4021
+ }
4022
+
4023
+ onConnectionMade() {
4024
+ logger$a.info('on CTI connection made');
4025
+
4026
+ this.eventEmitter.emit('onCallAccepted');
4027
+ }
4028
+
4029
+ async close() {
4030
+ logger$a.info('CTI close');
4031
+
4032
+ return Promise.resolve();
4033
+ }
4034
+
4035
+ async hold(callSession ) {
4036
+ if (!callSession) {
4037
+ return;
4038
+ }
4039
+ logger$a.info('CTI hold', { callId: callSession.getId(), number: callSession.number });
4040
+
4041
+ return CallApi.hold(callSession.callId);
4042
+ }
4043
+
4044
+ async resume(callSession ) {
4045
+ if (!callSession) {
4046
+ return;
4047
+ }
4048
+ logger$a.info('CTI resume', { callId: callSession.getId(), number: callSession.number });
4049
+
4050
+ return CallApi.resume(callSession.callId);
4051
+ }
4052
+
4053
+ async mute(callSession ) {
4054
+ if (!callSession) {
4055
+ return;
4056
+ }
4057
+ logger$a.info('CTI mute', { callId: callSession.getId(), number: callSession.number });
4058
+
4059
+ return CallApi.mute(callSession.callId);
4060
+ }
4061
+
4062
+ async unmute(callSession ) {
4063
+ if (!callSession) {
4064
+ return;
4065
+ }
4066
+ logger$a.info('CTI unmute', { callId: callSession.getId(), number: callSession.number });
4067
+
4068
+ return CallApi.unmute(callSession.callId);
4069
+ }
4070
+
4071
+ putOnSpeaker() {}
4072
+
4073
+ putOffSpeaker() {}
4074
+
4075
+ turnCameraOff() {}
4076
+
4077
+ turnCameraOn() {}
4078
+
4079
+ changeAudioInputDevice() {}
4080
+
4081
+ changeVideoInputDevice() {}
4082
+
4083
+ changeAudioDevice() {}
4084
+
4085
+ changeRingDevice() {}
4086
+
4087
+ changeAudioVolume() {}
4088
+
4089
+ changeRingVolume() {}
4090
+
4091
+ hasVideo() {
4092
+ return false;
4093
+ }
4094
+
4095
+ getLocalStreamForCall() {
4096
+ return null;
4097
+ }
4098
+
4099
+ getRemoteStreamForCall() {
4100
+ return null;
4101
+ }
4102
+
4103
+ getLocalVideoStream() {
4104
+ return null;
4105
+ }
4106
+
4107
+ setActiveSipSession() {}
4108
+
4109
+ isRegistered() {
4110
+ return true;
4111
+ }
4112
+
4113
+ hasIncomingCallSession() {
4114
+ return true;
4115
+ }
4116
+
4117
+ hasActiveRemoteVideoStream() {
4118
+ return false;
4119
+ }
4120
+
4121
+ getCurrentCallSession() {
4122
+ return this.currentCall ? CallSession.parseCall(this.currentCall) : null;
4123
+ }
4124
+
4125
+ enableRinging() {}
4126
+
4127
+ sendMessage() {}
4128
+
4129
+ disableRinging() {}
4130
+
4131
+ getLocalStream() {
4132
+ return null;
4133
+ }
4134
+
4135
+ getRemoteStream() {
4136
+ return null;
4137
+ }
4138
+
4139
+ getRemoteVideoStream() {
4140
+ return null;
4141
+ }
4142
+
4143
+ getRemoteAudioStream() {
4144
+ return null;
4145
+ }
4146
+
4147
+ hasLocalVideo() {
4148
+ return false;
4149
+ }
4150
+
4151
+ useLocalVideoElement() {}
4152
+ }
3678
4153
 
3679
4154
  /* */
3680
4155
 
@@ -4709,6 +5184,10 @@ class ApiClient {
4709
5184
  this.fetchOptions = fetchOptions;
4710
5185
  this.client.setFetchOptions(fetchOptions);
4711
5186
  }
5187
+
5188
+ disableErrorLogging() {
5189
+ this.client.disableErrorLogging();
5190
+ }
4712
5191
  }
4713
5192
 
4714
5193
  /* eslint-disable dot-notation */
@@ -5250,23 +5729,6 @@ const areCandidateValid = (candidates ) =>
5250
5729
  getSrflxOrRelay(candidates)
5251
5730
  .length > 0;
5252
5731
 
5253
- const toggleVideoDirection = (sdp , direction ) => {
5254
- const parsedSdp = sdpParser__default['default'].parse(sdp);
5255
- parsedSdp.media = parsedSdp.media.map(media => ({
5256
- ...media,
5257
- ...(media.type === 'video' ? { direction } : {}),
5258
- }));
5259
-
5260
- return sdpParser__default['default'].write(parsedSdp);
5261
- };
5262
-
5263
- const deactivateVideoModifier = (rawDescription ) => {
5264
- const description = rawDescription;
5265
- description.sdp = toggleVideoDirection(description.sdp, 'inactive');
5266
-
5267
- return Promise.resolve(description);
5268
- };
5269
-
5270
5732
  const hasAnActiveVideo = (sdp ) => {
5271
5733
  if (!sdp) {
5272
5734
  return false;
@@ -5378,6 +5840,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5378
5840
  const iceRestart = options.offerOptions ? options.offerOptions.iceRestart : false;
5379
5841
 
5380
5842
  const isConference = options ? !!options.conference : false;
5843
+ const audioOnly = options ? !!options.audioOnly : false;
5381
5844
 
5382
5845
  // We should wait for ice when iceRestart (reinvite) or for the first invite
5383
5846
  // We shouldn't wait for ice when holding or resuming the call
@@ -5404,16 +5867,16 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5404
5867
  };
5405
5868
 
5406
5869
  return this.getLocalMediaStream(options)
5407
- .then(() => this.updateDirection(options, isConference))
5870
+ .then(() => this.updateDirection(options, isConference, audioOnly))
5408
5871
  .then(() => this.createDataChannel(options))
5409
5872
  .then(() => {
5410
- if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options)) {
5873
+ if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
5411
5874
  // Add a video an empty bundle to be able to replaceTrack when joining a conference without video
5412
5875
  this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5413
5876
  }
5414
5877
  })
5415
5878
  .then(() => this.createLocalOfferOrAnswer(options))
5416
- .then((sessionDescription) => this.setLocalSessionDescription(sessionDescription))
5879
+ .then(sessionDescription => this.setLocalSessionDescription(sessionDescription))
5417
5880
  .then(() => this.waitForIceGatheringComplete(iceRestart, iceTimeout))
5418
5881
  .then(() => this.getLocalSessionDescription())
5419
5882
  .then(description => {
@@ -5536,7 +5999,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5536
5999
  }
5537
6000
 
5538
6001
  // Overridden to send `inactive` in conference
5539
- updateDirection(options , isConference = false) {
6002
+ updateDirection(options , isConference = false,
6003
+ audioOnly = false) {
5540
6004
  if (this._peerConnection === undefined) {
5541
6005
  return Promise.reject(new Error('Peer connection closed.'));
5542
6006
  }
@@ -5551,14 +6015,17 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5551
6015
  // if we are stable, assume we are creating a local offer
5552
6016
  this.logger.debug('SessionDescriptionHandler.updateDirection - setting offer direction');
5553
6017
  // determine the direction to offer given the current direction and hold state
5554
- const directionToOffer = (currentDirection ) => {
6018
+ const directionToOffer = (currentDirection , transceiver /* RTCRtpTransceiver */) => {
5555
6019
  if (isConference) {
6020
+ if (audioOnly && transceiver.receiver.track && transceiver.receiver.track.kind === 'video') {
6021
+ return 'sendonly';
6022
+ }
5556
6023
  return options && options.hold ? 'sendonly' : 'sendrecv';
5557
6024
  }
5558
6025
 
5559
6026
  switch (currentDirection) {
5560
6027
  case 'inactive':
5561
- return options && options.hold ? 'inactive' : 'recvonly';
6028
+ return options && options.hold ? 'inactive' : (isConference && !audioOnly ? 'sendrecv' : 'recvonly');
5562
6029
  case 'recvonly':
5563
6030
  return options && options.hold ? 'inactive' : 'recvonly';
5564
6031
  case 'sendonly':
@@ -5574,7 +6041,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5574
6041
  // set the transceiver direction to the offer direction
5575
6042
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5576
6043
  if (transceiver.direction /* guarding, but should always be true */) {
5577
- const offerDirection = directionToOffer(transceiver.direction);
6044
+ const offerDirection = directionToOffer(transceiver.direction, transceiver);
5578
6045
  if (transceiver.direction !== offerDirection) {
5579
6046
  // eslint-disable-next-line no-param-reassign
5580
6047
  transceiver.direction = offerDirection;
@@ -5633,6 +6100,13 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5633
6100
  // set the transceiver direction to the answer direction
5634
6101
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5635
6102
  if (transceiver.direction /* guarding, but should always be true */) {
6103
+ const { receiver } = transceiver;
6104
+ if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
6105
+ // eslint-disable-next-line no-param-reassign
6106
+ transceiver.direction = 'inactive';
6107
+ return;
6108
+ }
6109
+
5636
6110
  if (transceiver.direction !== 'stopped' && transceiver.direction !== answerDirection) {
5637
6111
  // eslint-disable-next-line no-param-reassign
5638
6112
  transceiver.direction = answerDirection;
@@ -5671,8 +6145,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5671
6145
  }
5672
6146
  const sender = pc.getSenders().find((otherSender) => otherSender.track && otherSender.track.kind === kind);
5673
6147
 
5674
- // Do not reuse sender tracks in SFU
5675
- if (sender && !sfu) {
6148
+ // Do not reuse sender video tracks in SFU
6149
+ if (sender && (!sfu || newTrack.kind === 'audio')) {
5676
6150
  trackUpdates.push(
5677
6151
  new Promise((resolve) => {
5678
6152
  this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
@@ -6224,9 +6698,15 @@ class WebRTCClient extends Emitter {
6224
6698
 
6225
6699
  call(number , enableVideo , audioOnly = false, conference = false) {
6226
6700
  logger$7.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
6227
- const inviterOptions = {};
6701
+ const inviterOptions = {
6702
+ sessionDescriptionHandlerOptionsReInvite: {
6703
+ conference,
6704
+ audioOnly,
6705
+ },
6706
+ };
6707
+
6228
6708
  if (audioOnly) {
6229
- inviterOptions.sessionDescriptionHandlerModifiersReInvite = [deactivateVideoModifier];
6709
+ inviterOptions.sessionDescriptionHandlerModifiersReInvite = [modifiers.stripVideo];
6230
6710
  }
6231
6711
 
6232
6712
  const session = new inviter.Inviter(this.userAgent, this._makeURI(number), inviterOptions);
@@ -6255,10 +6735,11 @@ class WebRTCClient extends Emitter {
6255
6735
  sessionDescriptionHandlerOptions: this.getMediaConfiguration(enableVideo || false, conference),
6256
6736
  };
6257
6737
 
6258
- inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6738
+ inviteOptions.sessionDescriptionHandlerOptions.audioOnly = audioOnly;
6259
6739
 
6740
+ inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6260
6741
  if (audioOnly) {
6261
- inviteOptions.sessionDescriptionHandlerModifiers.push(deactivateVideoModifier);
6742
+ inviteOptions.sessionDescriptionHandlerModifiers.push(modifiers.stripVideo);
6262
6743
  }
6263
6744
 
6264
6745
  // Do not await invite here or we'll miss the Establishing state transition
@@ -6472,6 +6953,9 @@ class WebRTCClient extends Emitter {
6472
6953
  if (!this._isWeb()) {
6473
6954
  options.sessionDescriptionHandlerModifiers = [modifiers.holdModifier];
6474
6955
  }
6956
+ options.sessionDescriptionHandlerOptions = {
6957
+ constraints: options.constraints,
6958
+ };
6475
6959
 
6476
6960
  // Send re-INVITE
6477
6961
  return session.invite(options);
@@ -6511,6 +6995,9 @@ class WebRTCClient extends Emitter {
6511
6995
  // (eg: holdModifier)
6512
6996
  options.sessionDescriptionHandlerModifiers = [];
6513
6997
  }
6998
+ options.sessionDescriptionHandlerOptions = {
6999
+ constraints: options.constraints,
7000
+ };
6514
7001
 
6515
7002
  // Send re-INVITE
6516
7003
  return session.invite(options);
@@ -6740,7 +7227,8 @@ class WebRTCClient extends Emitter {
6740
7227
  ? this.video.deviceId.exact : undefined;
6741
7228
  }
6742
7229
 
6743
- reinvite(sipSession , newConstraints = null, conference = false) {
7230
+ reinvite(sipSession , newConstraints = null, conference = false,
7231
+ audioOnly = false) {
6744
7232
  if (!sipSession) {
6745
7233
  return false;
6746
7234
  }
@@ -6750,16 +7238,17 @@ class WebRTCClient extends Emitter {
6750
7238
  }
6751
7239
 
6752
7240
  const wasMuted = this.isAudioMuted(sipSession);
6753
- // When upgrading to video, remove the `deactivateVideoModifier` modifiers
7241
+ // When upgrading to video, remove the `stripVideo` modifiers
6754
7242
  if (newConstraints && newConstraints.video) {
6755
- const modifiers = sipSession.sessionDescriptionHandlerModifiersReInvite;
6756
- sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers.filter(modifier =>
6757
- modifier !== deactivateVideoModifier);
7243
+ const modifiers$1 = sipSession.sessionDescriptionHandlerModifiersReInvite;
7244
+ sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers$1.filter(modifier =>
7245
+ modifier !== modifiers.stripVideo);
6758
7246
  }
6759
7247
 
6760
7248
  sipSession.sessionDescriptionHandlerOptionsReInvite = {
6761
7249
  ...sipSession.sessionDescriptionHandlerOptionsReInvite,
6762
7250
  conference,
7251
+ audioOnly,
6763
7252
  };
6764
7253
 
6765
7254
  const shouldDoVideo = newConstraints ? newConstraints.video : this.sessionWantsToDoVideo(sipSession);
@@ -6799,6 +7288,8 @@ class WebRTCClient extends Emitter {
6799
7288
  },
6800
7289
  sessionDescriptionHandlerOptions: {
6801
7290
  constraints,
7291
+ conference,
7292
+ audioOnly,
6802
7293
  offerOptions: {
6803
7294
  iceRestart: false,
6804
7295
  },
@@ -7258,6 +7749,8 @@ class WebRTCClient extends Emitter {
7258
7749
 
7259
7750
  // Invitation and Inviter extends Session
7260
7751
  _setupSession(session ) {
7752
+ const sipSessionId = this.getSipSessionId(session);
7753
+
7261
7754
  // When receiving an Invitation, the delegate is not defined.
7262
7755
  if (!session.delegate) {
7263
7756
  session.delegate = {};
@@ -7281,8 +7774,18 @@ class WebRTCClient extends Emitter {
7281
7774
  };
7282
7775
  };
7283
7776
 
7777
+ const oldInviteRequest = session.onInviteRequest.bind(session);
7778
+ let hadRemoteVideo = false;
7779
+
7780
+ // Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
7781
+ // Becase when `onInvite` is called we already got the video track
7782
+ session.onInviteRequest = (request) => {
7783
+ hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7784
+
7785
+ oldInviteRequest(request);
7786
+ };
7787
+
7284
7788
  session.delegate.onInvite = (request ) => {
7285
- const sipSessionId = this.getSipSessionId(session);
7286
7789
  let updatedCalleeName = null;
7287
7790
  let updatedNumber = null;
7288
7791
  if (session.assertedIdentity) {
@@ -7292,7 +7795,6 @@ class WebRTCClient extends Emitter {
7292
7795
  logger$7.info('re-invite received', { updatedCalleeName, updatedNumber });
7293
7796
 
7294
7797
  // Useful to know if it's a video upgrade or an unhold from a remote peer with a video stream
7295
- const hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7296
7798
 
7297
7799
  // Update SDP
7298
7800
  // Remote video is handled by the `track` event. Here we're dealing with video stream removal.
@@ -7342,7 +7844,7 @@ class WebRTCClient extends Emitter {
7342
7844
  }
7343
7845
 
7344
7846
  _isAudioOnly(session ) {
7345
- return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === deactivateVideoModifier);
7847
+ return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === modifiers.stripVideo);
7346
7848
  }
7347
7849
 
7348
7850
  _setupMedias(session , newStream ) {
@@ -7715,9 +8217,14 @@ class WebRTCPhone extends Emitter {
7715
8217
  return true;
7716
8218
  }
7717
8219
 
7718
- async sendReinvite(callSession , constraints = null, conference = false) {
8220
+ async sendReinvite(callSession , constraints = null, conference = false,
8221
+ audioOnly = false) {
7719
8222
  const sipSession = this.findSipSession(callSession);
7720
- logger$6.info('WebRTC phone - send reinvite', { sessionId: sipSession ? sipSession.id : null, constraints });
8223
+ logger$6.info('WebRTC phone - send reinvite', {
8224
+ sessionId: sipSession ? sipSession.id : null,
8225
+ constraints,
8226
+ audioOnly,
8227
+ });
7721
8228
 
7722
8229
  if (!sipSession) {
7723
8230
  return null;
@@ -7743,7 +8250,7 @@ class WebRTCPhone extends Emitter {
7743
8250
  // Force reinvite in SDH
7744
8251
  sipSession.sessionDescriptionHandler.localMediaStreamConstraints = null;
7745
8252
 
7746
- return this.client.reinvite(sipSession, constraints, conference);
8253
+ return this.client.reinvite(sipSession, constraints, conference, audioOnly);
7747
8254
  }
7748
8255
 
7749
8256
  getUserAgent() {
@@ -7819,9 +8326,9 @@ class WebRTCPhone extends Emitter {
7819
8326
  }
7820
8327
 
7821
8328
  // Release local video stream when downgrading to audio
7822
- const localVideoStream = sipSession.sessionDescriptionHandler.localMediaStream;
8329
+ const localStream = sipSession.sessionDescriptionHandler.localMediaStream;
7823
8330
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7824
- const videoTracks = localVideoStream.getVideoTracks();
8331
+ const videoTracks = localStream.getVideoTracks();
7825
8332
 
7826
8333
  // Remove video senders
7827
8334
  pc.getSenders().filter(sender => sender.track && sender.track.kind === 'video').forEach(videoSender => {
@@ -7836,7 +8343,7 @@ class WebRTCPhone extends Emitter {
7836
8343
  videoTracks.forEach(videoTrack => {
7837
8344
  videoTrack.enabled = false;
7838
8345
  videoTrack.stop();
7839
- localVideoStream.removeTrack(videoTrack);
8346
+ localStream.removeTrack(videoTrack);
7840
8347
  });
7841
8348
 
7842
8349
  this._sendReinviteMessage(callSession, false);
@@ -7853,12 +8360,14 @@ class WebRTCPhone extends Emitter {
7853
8360
 
7854
8361
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7855
8362
  const shouldScreenShare = constraints && constraints.screen;
8363
+ const options = sipSession.sessionDescriptionHandlerOptionsReInvite;
8364
+ const wasAudioOnly = options && options.audioOnly;
7856
8365
 
7857
8366
  // Check if a video sender already exists
7858
8367
  let videoSender;
7859
8368
  if (isConference) {
7860
8369
  const trans = pc.getTransceivers().find(transceiver => transceiver.mid === '1');
7861
- videoSender = trans.sender;
8370
+ videoSender = trans ? trans.sender : null;
7862
8371
  } else {
7863
8372
  videoSender = pc.getSenders().find(sender => sender.track === null);
7864
8373
  }
@@ -7895,6 +8404,11 @@ class WebRTCPhone extends Emitter {
7895
8404
  this._onScreenSharing(newStream, sipSession, callSession, false);
7896
8405
  }
7897
8406
 
8407
+ // We have to reinvite to change the direction on the bundle when upgrading from an audioOnly conference
8408
+ if (isConference && wasAudioOnly) {
8409
+ return true;
8410
+ }
8411
+
7898
8412
  // No reinvite needed here
7899
8413
  return false;
7900
8414
  }
@@ -7979,7 +8493,7 @@ class WebRTCPhone extends Emitter {
7979
8493
  event.track.enabled = false;
7980
8494
  }
7981
8495
 
7982
- return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event);
8496
+ return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event, sipSession);
7983
8497
  };
7984
8498
 
7985
8499
  peerConnection.onremovestream = event => {
@@ -8035,14 +8549,11 @@ class WebRTCPhone extends Emitter {
8035
8549
  const targetCallSession = callSession || this.currentCallSession;
8036
8550
  const conference = this.isConference(targetCallSession);
8037
8551
 
8038
- if (this.currentScreenShare.sender && this.currentScreenShare.hadVideo) {
8039
- // When stopping screenshare and we had video before that, we have to re-upgrade
8040
- await this.sendReinvite(targetCallSession, { audio: false, video: true }, conference);
8041
- } else {
8042
- // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8043
- // We have to downgrade to audio.
8044
- await this.sendReinvite(targetCallSession, { audio: false, video: false }, conference);
8045
- }
8552
+ // When stopping screenshare and we had video before that, we have to re-upgrade
8553
+ // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8554
+ // We have to downgrade to audio.
8555
+ const screenshareStopped = this.currentScreenShare.sender && this.currentScreenShare.hadVideo;
8556
+ await this.sendReinvite(targetCallSession, { audio: false, video: screenshareStopped }, conference);
8046
8557
  }
8047
8558
  } catch (e) {
8048
8559
  console.warn(e);
@@ -8379,6 +8890,7 @@ class WebRTCPhone extends Emitter {
8379
8890
  }
8380
8891
  }
8381
8892
 
8893
+ // @Deprecated
8382
8894
  unhold(callSession , withEvent = true, isConference = false) {
8383
8895
  logger$6.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
8384
8896
 
@@ -9376,6 +9888,7 @@ class Phone extends Emitter {
9376
9888
  return this.phone && this.phone.hasLocalVideo(callSession);
9377
9889
  }
9378
9890
 
9891
+ // @Deprecated
9379
9892
  getLocalMediaStream(callSession ) {
9380
9893
  logger$5.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
9381
9894
 
@@ -9394,17 +9907,20 @@ class Phone extends Emitter {
9394
9907
  return this.phone ? this.phone.getRemoteVideoStream(callSession) : null;
9395
9908
  }
9396
9909
 
9910
+ // @Deprecated
9397
9911
  getRemoteStreamForCall(callSession ) {
9398
9912
  logger$5.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
9399
9913
  return this.getRemoteStream(callSession);
9400
9914
  }
9401
9915
 
9402
9916
  // Returns remote streams directly from the peerConnection
9917
+ // @Deprecated
9403
9918
  getRemoteStreamsForCall(callSession ) {
9404
- logger$5.warn('Phone.getRe is deprecated, use Phone.getLocalStream instead');
9919
+ logger$5.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
9405
9920
  return this.getLocalStream(callSession);
9406
9921
  }
9407
9922
 
9923
+ // @Deprecated
9408
9924
  getRemoteVideoStreamForCall(callSession ) {
9409
9925
  logger$5.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
9410
9926
 
@@ -10767,13 +11283,15 @@ class Room$1 extends Emitter {
10767
11283
  }
10768
11284
  });
10769
11285
 
10770
- this.on(this.ON_VIDEO_STREAM, (stream, streamId) => {
11286
+ this.on(this.ON_VIDEO_STREAM, (stream, streamId, event, sipSession) => {
10771
11287
  logger$1.info('on room video stream', { streamId });
10772
11288
 
11289
+ this._mapMsid(sipSession.body.body);
11290
+
10773
11291
  // ON_VIDEO_STREAM is called before PARTICIPANT_JOINED, so we have to keep stream in `_unassociatedVideoStreams`.
10774
11292
  this._unassociatedVideoStreams[streamId] = stream;
10775
11293
 
10776
- const callId = this._getCallIdFromStreamId(streamId);
11294
+ const callId = this._getCallIdFromTrackId(streamId);
10777
11295
  const participant = callId ? this._getParticipantFromCallId(callId) : null;
10778
11296
  if (participant) {
10779
11297
  this.__associateStreams(participant);
@@ -10817,11 +11335,12 @@ class Room$1 extends Emitter {
10817
11335
  const sdp = sdpParser__default['default'].parse(rawSdp);
10818
11336
  const labelMsidArray = sdp.media.filter(media => !!media.label).map(({ label, msid }) => ({
10819
11337
  label: String(label),
10820
- msid: msid.split(' ')[1],
11338
+ streamId: msid.split(' ')[0],
11339
+ trackId: msid.split(' ')[1],
10821
11340
  }));
10822
11341
 
10823
- labelMsidArray.forEach(({ label, msid }) => {
10824
- this._callIdStreamIdMap[String(label)] = msid;
11342
+ labelMsidArray.forEach(({ label, streamId, trackId }) => {
11343
+ this._callIdStreamIdMap[String(label)] = { streamId, trackId };
10825
11344
 
10826
11345
  const callId = String(label);
10827
11346
  const participant = this._unassociatedParticipants[callId] || this._getParticipantFromCallId(callId);
@@ -11051,9 +11570,9 @@ class Room$1 extends Emitter {
11051
11570
  _onParticipantTrackUpdate(oldParticipant , update ) {
11052
11571
  const newParticipant = oldParticipant;
11053
11572
 
11054
- const label = this._callIdStreamIdMap[newParticipant.callId];
11573
+ const { trackId } = this._callIdStreamIdMap[newParticipant.callId] || {};
11055
11574
  const pc = Wazo.Phone.phone.currentSipSession.sessionDescriptionHandler.peerConnection;
11056
- const stream = pc.getRemoteStreams().find(otherStream => otherStream.getTracks().some(track => track.id === label));
11575
+ const stream = pc.getRemoteStreams().find(someStream => someStream.getTracks().some(track => track.id === trackId));
11057
11576
 
11058
11577
  if (update === 'downgrade') {
11059
11578
  newParticipant.streams = [];
@@ -11073,21 +11592,21 @@ class Room$1 extends Emitter {
11073
11592
 
11074
11593
  // Associate audio/video streams to the participant and triggers events on it
11075
11594
  __associateStreams(participant ) {
11076
- const streamId = this._callIdStreamIdMap[participant.callId];
11077
- if (!streamId) {
11595
+ const { trackId } = this._callIdStreamIdMap[participant.callId] || {};
11596
+ if (!trackId) {
11078
11597
  this._unassociatedParticipants[participant.callId] = participant;
11079
11598
 
11080
11599
  return;
11081
11600
  }
11082
- if (!streamId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
11601
+ if (!trackId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
11083
11602
  return;
11084
11603
  }
11085
11604
 
11086
- if (this._unassociatedVideoStreams[streamId]) {
11605
+ if (this._unassociatedVideoStreams[trackId]) {
11087
11606
  // Try to associate stream
11088
- this._associateStreamTo(this._unassociatedVideoStreams[streamId], participant);
11607
+ this._associateStreamTo(this._unassociatedVideoStreams[trackId], participant);
11089
11608
 
11090
- delete this._unassociatedVideoStreams[streamId];
11609
+ delete this._unassociatedVideoStreams[trackId];
11091
11610
  delete this._unassociatedParticipants[participant.callId];
11092
11611
  }
11093
11612
  }
@@ -11100,8 +11619,8 @@ class Room$1 extends Emitter {
11100
11619
  participant.onStreamSubscribed(stream);
11101
11620
  }
11102
11621
 
11103
- _getCallIdFromStreamId(streamId ) {
11104
- return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key] === streamId);
11622
+ _getCallIdFromTrackId(trackId ) {
11623
+ return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key].trackId === trackId);
11105
11624
  }
11106
11625
 
11107
11626
  _getParticipantFromCallId(callId ) {
@@ -11531,6 +12050,7 @@ var api = {
11531
12050
  check: async (server, session) => {
11532
12051
  const client = new ApiClient({ server });
11533
12052
  client.setToken(session.token);
12053
+ client.disableErrorLogging();
11534
12054
 
11535
12055
  const handleApiError = (apiName, error) => {
11536
12056
  const statusText = error instanceof ServerError ? 'server error' : 'api error';
@@ -11605,6 +12125,8 @@ var aor = {
11605
12125
  check: async (server, session) => {
11606
12126
  const apiClient = new ApiClient({ server });
11607
12127
  apiClient.setToken(session.token);
12128
+ apiClient.disableErrorLogging();
12129
+
11608
12130
  const line = session.primaryWebRtcLine();
11609
12131
  if (!line) {
11610
12132
  return 'No WebRTC line for this user';
@@ -12027,6 +12549,8 @@ const Wazo = {
12027
12549
  ServerError,
12028
12550
  Call,
12029
12551
  CallLog,
12552
+ CTIPhone,
12553
+ Recording,
12030
12554
  ChatMessage,
12031
12555
  ChatRoom,
12032
12556
  Contact,
@@ -12041,6 +12565,7 @@ const Wazo = {
12041
12565
  CallSession,
12042
12566
  IndirectTransfer,
12043
12567
  SwitchboardCall,
12568
+ WebRTCPhone,
12044
12569
  },
12045
12570
 
12046
12571
  // Api
@@ -12101,10 +12626,7 @@ class Stream {
12101
12626
  element.onloadedmetadata = () => {
12102
12627
  const tracks = this.htmlStream ? this.htmlStream.getVideoTracks() : [];
12103
12628
  tracks.forEach(track => {
12104
- // Do not re-enable the track if already mounted.
12105
- if (!track.loaded) {
12106
- track.enabled = true;
12107
- }
12629
+ track.enabled = true;
12108
12630
  // $FlowFixMe
12109
12631
  track.loaded = true;
12110
12632
  });