@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
@@ -11,7 +11,6 @@ var jsonToGraphQLQuery = require('json-to-graphql-query/lib/jsonToGraphQLQuery')
11
11
  var invitation = require('sip.js/lib/api/invitation');
12
12
  require('webrtc-adapter');
13
13
  var userAgentState = require('sip.js/lib/api/user-agent-state');
14
- require('sip.js/lib/api/message');
15
14
  var parser = require('sip.js/lib/core/messages/parser');
16
15
  var constants = require('sip.js/lib/core/messages/methods/constants');
17
16
  var uri = require('sip.js/lib/grammar/uri');
@@ -1015,7 +1014,7 @@ class Contact {
1015
1014
 
1016
1015
  return new Contact({
1017
1016
  sourceId: single.id || '',
1018
- name: single.displayName,
1017
+ name: single.displayName || '',
1019
1018
  number: numbers.length ? numbers[0].number : '',
1020
1019
  numbers,
1021
1020
  emails,
@@ -1046,7 +1045,7 @@ class Contact {
1046
1045
 
1047
1046
  return new Contact({
1048
1047
  sourceId: single.id || '',
1049
- name: single.name,
1048
+ name: single.name || '',
1050
1049
  number: numbers.length ? numbers[0].number : '',
1051
1050
  numbers,
1052
1051
  emails,
@@ -1147,7 +1146,7 @@ class Contact {
1147
1146
  } = {}) {
1148
1147
  this.id = id;
1149
1148
  this.uuid = uuid;
1150
- this.name = name;
1149
+ this.name = name || '';
1151
1150
  this.number = number;
1152
1151
  this.numbers = numbers;
1153
1152
  this.email = email;
@@ -1822,7 +1821,13 @@ class IssueReporter {
1822
1821
  }
1823
1822
 
1824
1823
  _isLevelAbove(level1 , level2 ) {
1825
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
1824
+ const index1 = LOG_LEVELS.indexOf(level1);
1825
+ const index2 = LOG_LEVELS.indexOf(level2);
1826
+ if (index1 === -1 || index2 === -1) {
1827
+ return false;
1828
+ }
1829
+
1830
+ return index1 > index2;
1826
1831
  }
1827
1832
 
1828
1833
  _makeCategory(category ) {
@@ -1845,7 +1850,7 @@ var IssueReporter$1 = new IssueReporter();
1845
1850
 
1846
1851
  const methods = ['head', 'get', 'post', 'put', 'delete'];
1847
1852
 
1848
- const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
1853
+ const logger$b = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
1849
1854
 
1850
1855
  // Use a function here to be able to mock it in tests
1851
1856
  const realFetch = () => {
@@ -1880,6 +1885,7 @@ class ApiRequester {
1880
1885
 
1881
1886
 
1882
1887
 
1888
+
1883
1889
 
1884
1890
 
1885
1891
 
@@ -1919,6 +1925,8 @@ class ApiRequester {
1919
1925
  this.token = token;
1920
1926
  }
1921
1927
 
1928
+ this.shouldLogErrors = true;
1929
+
1922
1930
  methods.forEach(method => {
1923
1931
  // $FlowFixMe
1924
1932
  ApiRequester.prototype[method] = function sugar(...args) {
@@ -1942,6 +1950,14 @@ class ApiRequester {
1942
1950
  this.fetchOptions = options;
1943
1951
  }
1944
1952
 
1953
+ disableErrorLogging() {
1954
+ this.shouldLogErrors = false;
1955
+ }
1956
+
1957
+ enableErrorLogging() {
1958
+ this.shouldLogErrors = true;
1959
+ }
1960
+
1945
1961
  async call(
1946
1962
  path ,
1947
1963
  method = 'get',
@@ -1973,7 +1989,7 @@ class ApiRequester {
1973
1989
  };
1974
1990
 
1975
1991
  if (this.refreshTokenPromise) {
1976
- logger$a.info('A token is already refreshing, waiting ...', { url });
1992
+ logger$b.info('A token is already refreshing, waiting ...', { url });
1977
1993
  await this.refreshTokenPromise;
1978
1994
  }
1979
1995
 
@@ -1993,7 +2009,7 @@ class ApiRequester {
1993
2009
  return promise.then(async (err ) => {
1994
2010
  // Check if the token is still valid
1995
2011
  if (firstCall && this._checkTokenExpired(response, err)) {
1996
- logger$a.warn('token expired', { error: err.reason });
2012
+ logger$b.warn('token expired', { error: err.reason });
1997
2013
  // Replay the call after refreshing the token
1998
2014
  return this._replayWithNewToken(err, path, method, body, headers, parse);
1999
2015
  }
@@ -2002,7 +2018,9 @@ class ApiRequester {
2002
2018
  ? exceptionClass.fromText(err, response.status)
2003
2019
  : exceptionClass.fromResponse(err, response.status);
2004
2020
 
2005
- logger$a.error('API error', error);
2021
+ if (this.shouldLogErrors) {
2022
+ logger$b.error('API error', error);
2023
+ }
2006
2024
 
2007
2025
  throw error;
2008
2026
  });
@@ -2010,7 +2028,9 @@ class ApiRequester {
2010
2028
 
2011
2029
  return newParse(response, isJson);
2012
2030
  }).catch(error => {
2013
- logger$a.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
2031
+ if (this.shouldLogErrors) {
2032
+ logger$b.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
2033
+ }
2014
2034
 
2015
2035
  throw error;
2016
2036
  });
@@ -2037,13 +2057,13 @@ class ApiRequester {
2037
2057
  ) {
2038
2058
  const isTokenNotFound = this._isTokenNotFound(err);
2039
2059
  let newPath = path;
2040
- logger$a.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
2060
+ logger$b.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
2041
2061
 
2042
2062
  this.refreshTokenPromise = this.refreshTokenPromise || this.refreshTokenCallback();
2043
2063
 
2044
2064
  return this.refreshTokenPromise.then(() => {
2045
2065
  this.refreshTokenPromise = null;
2046
- logger$a.info('token refreshed', { isTokenNotFound });
2066
+ logger$b.info('token refreshed', { isTokenNotFound });
2047
2067
  if (isTokenNotFound) {
2048
2068
  const pathParts = path.split('/');
2049
2069
  pathParts.pop();
@@ -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 */
@@ -4990,23 +5469,6 @@ const areCandidateValid = (candidates ) =>
4990
5469
  getSrflxOrRelay(candidates)
4991
5470
  .length > 0;
4992
5471
 
4993
- const toggleVideoDirection = (sdp , direction ) => {
4994
- const parsedSdp = sdpParser__default['default'].parse(sdp);
4995
- parsedSdp.media = parsedSdp.media.map(media => ({
4996
- ...media,
4997
- ...(media.type === 'video' ? { direction } : {}),
4998
- }));
4999
-
5000
- return sdpParser__default['default'].write(parsedSdp);
5001
- };
5002
-
5003
- const deactivateVideoModifier = (rawDescription ) => {
5004
- const description = rawDescription;
5005
- description.sdp = toggleVideoDirection(description.sdp, 'inactive');
5006
-
5007
- return Promise.resolve(description);
5008
- };
5009
-
5010
5472
  const hasAnActiveVideo = (sdp ) => {
5011
5473
  if (!sdp) {
5012
5474
  return false;
@@ -5118,6 +5580,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5118
5580
  const iceRestart = options.offerOptions ? options.offerOptions.iceRestart : false;
5119
5581
 
5120
5582
  const isConference = options ? !!options.conference : false;
5583
+ const audioOnly = options ? !!options.audioOnly : false;
5121
5584
 
5122
5585
  // We should wait for ice when iceRestart (reinvite) or for the first invite
5123
5586
  // We shouldn't wait for ice when holding or resuming the call
@@ -5144,16 +5607,16 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5144
5607
  };
5145
5608
 
5146
5609
  return this.getLocalMediaStream(options)
5147
- .then(() => this.updateDirection(options, isConference))
5610
+ .then(() => this.updateDirection(options, isConference, audioOnly))
5148
5611
  .then(() => this.createDataChannel(options))
5149
5612
  .then(() => {
5150
- if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options)) {
5613
+ if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
5151
5614
  // Add a video an empty bundle to be able to replaceTrack when joining a conference without video
5152
5615
  this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5153
5616
  }
5154
5617
  })
5155
5618
  .then(() => this.createLocalOfferOrAnswer(options))
5156
- .then((sessionDescription) => this.setLocalSessionDescription(sessionDescription))
5619
+ .then(sessionDescription => this.setLocalSessionDescription(sessionDescription))
5157
5620
  .then(() => this.waitForIceGatheringComplete(iceRestart, iceTimeout))
5158
5621
  .then(() => this.getLocalSessionDescription())
5159
5622
  .then(description => {
@@ -5276,7 +5739,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5276
5739
  }
5277
5740
 
5278
5741
  // Overridden to send `inactive` in conference
5279
- updateDirection(options , isConference = false) {
5742
+ updateDirection(options , isConference = false,
5743
+ audioOnly = false) {
5280
5744
  if (this._peerConnection === undefined) {
5281
5745
  return Promise.reject(new Error('Peer connection closed.'));
5282
5746
  }
@@ -5291,14 +5755,17 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5291
5755
  // if we are stable, assume we are creating a local offer
5292
5756
  this.logger.debug('SessionDescriptionHandler.updateDirection - setting offer direction');
5293
5757
  // determine the direction to offer given the current direction and hold state
5294
- const directionToOffer = (currentDirection ) => {
5758
+ const directionToOffer = (currentDirection , transceiver /* RTCRtpTransceiver */) => {
5295
5759
  if (isConference) {
5760
+ if (audioOnly && transceiver.receiver.track && transceiver.receiver.track.kind === 'video') {
5761
+ return 'sendonly';
5762
+ }
5296
5763
  return options && options.hold ? 'sendonly' : 'sendrecv';
5297
5764
  }
5298
5765
 
5299
5766
  switch (currentDirection) {
5300
5767
  case 'inactive':
5301
- return options && options.hold ? 'inactive' : 'recvonly';
5768
+ return options && options.hold ? 'inactive' : (isConference && !audioOnly ? 'sendrecv' : 'recvonly');
5302
5769
  case 'recvonly':
5303
5770
  return options && options.hold ? 'inactive' : 'recvonly';
5304
5771
  case 'sendonly':
@@ -5314,7 +5781,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5314
5781
  // set the transceiver direction to the offer direction
5315
5782
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5316
5783
  if (transceiver.direction /* guarding, but should always be true */) {
5317
- const offerDirection = directionToOffer(transceiver.direction);
5784
+ const offerDirection = directionToOffer(transceiver.direction, transceiver);
5318
5785
  if (transceiver.direction !== offerDirection) {
5319
5786
  // eslint-disable-next-line no-param-reassign
5320
5787
  transceiver.direction = offerDirection;
@@ -5373,6 +5840,13 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5373
5840
  // set the transceiver direction to the answer direction
5374
5841
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5375
5842
  if (transceiver.direction /* guarding, but should always be true */) {
5843
+ const { receiver } = transceiver;
5844
+ if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
5845
+ // eslint-disable-next-line no-param-reassign
5846
+ transceiver.direction = 'inactive';
5847
+ return;
5848
+ }
5849
+
5376
5850
  if (transceiver.direction !== 'stopped' && transceiver.direction !== answerDirection) {
5377
5851
  // eslint-disable-next-line no-param-reassign
5378
5852
  transceiver.direction = answerDirection;
@@ -5411,8 +5885,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5411
5885
  }
5412
5886
  const sender = pc.getSenders().find((otherSender) => otherSender.track && otherSender.track.kind === kind);
5413
5887
 
5414
- // Do not reuse sender tracks in SFU
5415
- if (sender && !sfu) {
5888
+ // Do not reuse sender video tracks in SFU
5889
+ if (sender && (!sfu || newTrack.kind === 'audio')) {
5416
5890
  trackUpdates.push(
5417
5891
  new Promise((resolve) => {
5418
5892
  this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
@@ -5964,9 +6438,15 @@ class WebRTCClient extends Emitter {
5964
6438
 
5965
6439
  call(number , enableVideo , audioOnly = false, conference = false) {
5966
6440
  logger$8.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
5967
- const inviterOptions = {};
6441
+ const inviterOptions = {
6442
+ sessionDescriptionHandlerOptionsReInvite: {
6443
+ conference,
6444
+ audioOnly,
6445
+ },
6446
+ };
6447
+
5968
6448
  if (audioOnly) {
5969
- inviterOptions.sessionDescriptionHandlerModifiersReInvite = [deactivateVideoModifier];
6449
+ inviterOptions.sessionDescriptionHandlerModifiersReInvite = [modifiers.stripVideo];
5970
6450
  }
5971
6451
 
5972
6452
  const session = new inviter.Inviter(this.userAgent, this._makeURI(number), inviterOptions);
@@ -5995,10 +6475,11 @@ class WebRTCClient extends Emitter {
5995
6475
  sessionDescriptionHandlerOptions: this.getMediaConfiguration(enableVideo || false, conference),
5996
6476
  };
5997
6477
 
5998
- inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6478
+ inviteOptions.sessionDescriptionHandlerOptions.audioOnly = audioOnly;
5999
6479
 
6480
+ inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6000
6481
  if (audioOnly) {
6001
- inviteOptions.sessionDescriptionHandlerModifiers.push(deactivateVideoModifier);
6482
+ inviteOptions.sessionDescriptionHandlerModifiers.push(modifiers.stripVideo);
6002
6483
  }
6003
6484
 
6004
6485
  // Do not await invite here or we'll miss the Establishing state transition
@@ -6212,6 +6693,9 @@ class WebRTCClient extends Emitter {
6212
6693
  if (!this._isWeb()) {
6213
6694
  options.sessionDescriptionHandlerModifiers = [modifiers.holdModifier];
6214
6695
  }
6696
+ options.sessionDescriptionHandlerOptions = {
6697
+ constraints: options.constraints,
6698
+ };
6215
6699
 
6216
6700
  // Send re-INVITE
6217
6701
  return session.invite(options);
@@ -6251,6 +6735,9 @@ class WebRTCClient extends Emitter {
6251
6735
  // (eg: holdModifier)
6252
6736
  options.sessionDescriptionHandlerModifiers = [];
6253
6737
  }
6738
+ options.sessionDescriptionHandlerOptions = {
6739
+ constraints: options.constraints,
6740
+ };
6254
6741
 
6255
6742
  // Send re-INVITE
6256
6743
  return session.invite(options);
@@ -6480,7 +6967,8 @@ class WebRTCClient extends Emitter {
6480
6967
  ? this.video.deviceId.exact : undefined;
6481
6968
  }
6482
6969
 
6483
- reinvite(sipSession , newConstraints = null, conference = false) {
6970
+ reinvite(sipSession , newConstraints = null, conference = false,
6971
+ audioOnly = false) {
6484
6972
  if (!sipSession) {
6485
6973
  return false;
6486
6974
  }
@@ -6490,16 +6978,17 @@ class WebRTCClient extends Emitter {
6490
6978
  }
6491
6979
 
6492
6980
  const wasMuted = this.isAudioMuted(sipSession);
6493
- // When upgrading to video, remove the `deactivateVideoModifier` modifiers
6981
+ // When upgrading to video, remove the `stripVideo` modifiers
6494
6982
  if (newConstraints && newConstraints.video) {
6495
- const modifiers = sipSession.sessionDescriptionHandlerModifiersReInvite;
6496
- sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers.filter(modifier =>
6497
- modifier !== deactivateVideoModifier);
6983
+ const modifiers$1 = sipSession.sessionDescriptionHandlerModifiersReInvite;
6984
+ sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers$1.filter(modifier =>
6985
+ modifier !== modifiers.stripVideo);
6498
6986
  }
6499
6987
 
6500
6988
  sipSession.sessionDescriptionHandlerOptionsReInvite = {
6501
6989
  ...sipSession.sessionDescriptionHandlerOptionsReInvite,
6502
6990
  conference,
6991
+ audioOnly,
6503
6992
  };
6504
6993
 
6505
6994
  const shouldDoVideo = newConstraints ? newConstraints.video : this.sessionWantsToDoVideo(sipSession);
@@ -6539,6 +7028,8 @@ class WebRTCClient extends Emitter {
6539
7028
  },
6540
7029
  sessionDescriptionHandlerOptions: {
6541
7030
  constraints,
7031
+ conference,
7032
+ audioOnly,
6542
7033
  offerOptions: {
6543
7034
  iceRestart: false,
6544
7035
  },
@@ -6998,6 +7489,8 @@ class WebRTCClient extends Emitter {
6998
7489
 
6999
7490
  // Invitation and Inviter extends Session
7000
7491
  _setupSession(session ) {
7492
+ const sipSessionId = this.getSipSessionId(session);
7493
+
7001
7494
  // When receiving an Invitation, the delegate is not defined.
7002
7495
  if (!session.delegate) {
7003
7496
  session.delegate = {};
@@ -7021,8 +7514,18 @@ class WebRTCClient extends Emitter {
7021
7514
  };
7022
7515
  };
7023
7516
 
7517
+ const oldInviteRequest = session.onInviteRequest.bind(session);
7518
+ let hadRemoteVideo = false;
7519
+
7520
+ // Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
7521
+ // Becase when `onInvite` is called we already got the video track
7522
+ session.onInviteRequest = (request) => {
7523
+ hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7524
+
7525
+ oldInviteRequest(request);
7526
+ };
7527
+
7024
7528
  session.delegate.onInvite = (request ) => {
7025
- const sipSessionId = this.getSipSessionId(session);
7026
7529
  let updatedCalleeName = null;
7027
7530
  let updatedNumber = null;
7028
7531
  if (session.assertedIdentity) {
@@ -7032,7 +7535,6 @@ class WebRTCClient extends Emitter {
7032
7535
  logger$8.info('re-invite received', { updatedCalleeName, updatedNumber });
7033
7536
 
7034
7537
  // Useful to know if it's a video upgrade or an unhold from a remote peer with a video stream
7035
- const hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7036
7538
 
7037
7539
  // Update SDP
7038
7540
  // Remote video is handled by the `track` event. Here we're dealing with video stream removal.
@@ -7082,7 +7584,7 @@ class WebRTCClient extends Emitter {
7082
7584
  }
7083
7585
 
7084
7586
  _isAudioOnly(session ) {
7085
- return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === deactivateVideoModifier);
7587
+ return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === modifiers.stripVideo);
7086
7588
  }
7087
7589
 
7088
7590
  _setupMedias(session , newStream ) {
@@ -7455,9 +7957,14 @@ class WebRTCPhone extends Emitter {
7455
7957
  return true;
7456
7958
  }
7457
7959
 
7458
- async sendReinvite(callSession , constraints = null, conference = false) {
7960
+ async sendReinvite(callSession , constraints = null, conference = false,
7961
+ audioOnly = false) {
7459
7962
  const sipSession = this.findSipSession(callSession);
7460
- logger$7.info('WebRTC phone - send reinvite', { sessionId: sipSession ? sipSession.id : null, constraints });
7963
+ logger$7.info('WebRTC phone - send reinvite', {
7964
+ sessionId: sipSession ? sipSession.id : null,
7965
+ constraints,
7966
+ audioOnly,
7967
+ });
7461
7968
 
7462
7969
  if (!sipSession) {
7463
7970
  return null;
@@ -7483,7 +7990,7 @@ class WebRTCPhone extends Emitter {
7483
7990
  // Force reinvite in SDH
7484
7991
  sipSession.sessionDescriptionHandler.localMediaStreamConstraints = null;
7485
7992
 
7486
- return this.client.reinvite(sipSession, constraints, conference);
7993
+ return this.client.reinvite(sipSession, constraints, conference, audioOnly);
7487
7994
  }
7488
7995
 
7489
7996
  getUserAgent() {
@@ -7559,9 +8066,9 @@ class WebRTCPhone extends Emitter {
7559
8066
  }
7560
8067
 
7561
8068
  // Release local video stream when downgrading to audio
7562
- const localVideoStream = sipSession.sessionDescriptionHandler.localMediaStream;
8069
+ const localStream = sipSession.sessionDescriptionHandler.localMediaStream;
7563
8070
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7564
- const videoTracks = localVideoStream.getVideoTracks();
8071
+ const videoTracks = localStream.getVideoTracks();
7565
8072
 
7566
8073
  // Remove video senders
7567
8074
  pc.getSenders().filter(sender => sender.track && sender.track.kind === 'video').forEach(videoSender => {
@@ -7576,7 +8083,7 @@ class WebRTCPhone extends Emitter {
7576
8083
  videoTracks.forEach(videoTrack => {
7577
8084
  videoTrack.enabled = false;
7578
8085
  videoTrack.stop();
7579
- localVideoStream.removeTrack(videoTrack);
8086
+ localStream.removeTrack(videoTrack);
7580
8087
  });
7581
8088
 
7582
8089
  this._sendReinviteMessage(callSession, false);
@@ -7593,12 +8100,14 @@ class WebRTCPhone extends Emitter {
7593
8100
 
7594
8101
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7595
8102
  const shouldScreenShare = constraints && constraints.screen;
8103
+ const options = sipSession.sessionDescriptionHandlerOptionsReInvite;
8104
+ const wasAudioOnly = options && options.audioOnly;
7596
8105
 
7597
8106
  // Check if a video sender already exists
7598
8107
  let videoSender;
7599
8108
  if (isConference) {
7600
8109
  const trans = pc.getTransceivers().find(transceiver => transceiver.mid === '1');
7601
- videoSender = trans.sender;
8110
+ videoSender = trans ? trans.sender : null;
7602
8111
  } else {
7603
8112
  videoSender = pc.getSenders().find(sender => sender.track === null);
7604
8113
  }
@@ -7635,6 +8144,11 @@ class WebRTCPhone extends Emitter {
7635
8144
  this._onScreenSharing(newStream, sipSession, callSession, false);
7636
8145
  }
7637
8146
 
8147
+ // We have to reinvite to change the direction on the bundle when upgrading from an audioOnly conference
8148
+ if (isConference && wasAudioOnly) {
8149
+ return true;
8150
+ }
8151
+
7638
8152
  // No reinvite needed here
7639
8153
  return false;
7640
8154
  }
@@ -7719,7 +8233,7 @@ class WebRTCPhone extends Emitter {
7719
8233
  event.track.enabled = false;
7720
8234
  }
7721
8235
 
7722
- return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event);
8236
+ return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event, sipSession);
7723
8237
  };
7724
8238
 
7725
8239
  peerConnection.onremovestream = event => {
@@ -7775,14 +8289,11 @@ class WebRTCPhone extends Emitter {
7775
8289
  const targetCallSession = callSession || this.currentCallSession;
7776
8290
  const conference = this.isConference(targetCallSession);
7777
8291
 
7778
- if (this.currentScreenShare.sender && this.currentScreenShare.hadVideo) {
7779
- // When stopping screenshare and we had video before that, we have to re-upgrade
7780
- await this.sendReinvite(targetCallSession, { audio: false, video: true }, conference);
7781
- } else {
7782
- // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
7783
- // We have to downgrade to audio.
7784
- await this.sendReinvite(targetCallSession, { audio: false, video: false }, conference);
7785
- }
8292
+ // When stopping screenshare and we had video before that, we have to re-upgrade
8293
+ // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8294
+ // We have to downgrade to audio.
8295
+ const screenshareStopped = this.currentScreenShare.sender && this.currentScreenShare.hadVideo;
8296
+ await this.sendReinvite(targetCallSession, { audio: false, video: screenshareStopped }, conference);
7786
8297
  }
7787
8298
  } catch (e) {
7788
8299
  console.warn(e);
@@ -8119,6 +8630,7 @@ class WebRTCPhone extends Emitter {
8119
8630
  }
8120
8631
  }
8121
8632
 
8633
+ // @Deprecated
8122
8634
  unhold(callSession , withEvent = true, isConference = false) {
8123
8635
  logger$7.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
8124
8636
 
@@ -9116,6 +9628,7 @@ class Phone extends Emitter {
9116
9628
  return this.phone && this.phone.hasLocalVideo(callSession);
9117
9629
  }
9118
9630
 
9631
+ // @Deprecated
9119
9632
  getLocalMediaStream(callSession ) {
9120
9633
  logger$6.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
9121
9634
 
@@ -9134,17 +9647,20 @@ class Phone extends Emitter {
9134
9647
  return this.phone ? this.phone.getRemoteVideoStream(callSession) : null;
9135
9648
  }
9136
9649
 
9650
+ // @Deprecated
9137
9651
  getRemoteStreamForCall(callSession ) {
9138
9652
  logger$6.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
9139
9653
  return this.getRemoteStream(callSession);
9140
9654
  }
9141
9655
 
9142
9656
  // Returns remote streams directly from the peerConnection
9657
+ // @Deprecated
9143
9658
  getRemoteStreamsForCall(callSession ) {
9144
- logger$6.warn('Phone.getRe is deprecated, use Phone.getLocalStream instead');
9659
+ logger$6.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
9145
9660
  return this.getLocalStream(callSession);
9146
9661
  }
9147
9662
 
9663
+ // @Deprecated
9148
9664
  getRemoteVideoStreamForCall(callSession ) {
9149
9665
  logger$6.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
9150
9666
 
@@ -10507,13 +11023,15 @@ class Room$1 extends Emitter {
10507
11023
  }
10508
11024
  });
10509
11025
 
10510
- this.on(this.ON_VIDEO_STREAM, (stream, streamId) => {
11026
+ this.on(this.ON_VIDEO_STREAM, (stream, streamId, event, sipSession) => {
10511
11027
  logger$2.info('on room video stream', { streamId });
10512
11028
 
11029
+ this._mapMsid(sipSession.body.body);
11030
+
10513
11031
  // ON_VIDEO_STREAM is called before PARTICIPANT_JOINED, so we have to keep stream in `_unassociatedVideoStreams`.
10514
11032
  this._unassociatedVideoStreams[streamId] = stream;
10515
11033
 
10516
- const callId = this._getCallIdFromStreamId(streamId);
11034
+ const callId = this._getCallIdFromTrackId(streamId);
10517
11035
  const participant = callId ? this._getParticipantFromCallId(callId) : null;
10518
11036
  if (participant) {
10519
11037
  this.__associateStreams(participant);
@@ -10557,11 +11075,12 @@ class Room$1 extends Emitter {
10557
11075
  const sdp = sdpParser__default['default'].parse(rawSdp);
10558
11076
  const labelMsidArray = sdp.media.filter(media => !!media.label).map(({ label, msid }) => ({
10559
11077
  label: String(label),
10560
- msid: msid.split(' ')[1],
11078
+ streamId: msid.split(' ')[0],
11079
+ trackId: msid.split(' ')[1],
10561
11080
  }));
10562
11081
 
10563
- labelMsidArray.forEach(({ label, msid }) => {
10564
- this._callIdStreamIdMap[String(label)] = msid;
11082
+ labelMsidArray.forEach(({ label, streamId, trackId }) => {
11083
+ this._callIdStreamIdMap[String(label)] = { streamId, trackId };
10565
11084
 
10566
11085
  const callId = String(label);
10567
11086
  const participant = this._unassociatedParticipants[callId] || this._getParticipantFromCallId(callId);
@@ -10791,9 +11310,9 @@ class Room$1 extends Emitter {
10791
11310
  _onParticipantTrackUpdate(oldParticipant , update ) {
10792
11311
  const newParticipant = oldParticipant;
10793
11312
 
10794
- const label = this._callIdStreamIdMap[newParticipant.callId];
11313
+ const { trackId } = this._callIdStreamIdMap[newParticipant.callId] || {};
10795
11314
  const pc = Wazo.Phone.phone.currentSipSession.sessionDescriptionHandler.peerConnection;
10796
- const stream = pc.getRemoteStreams().find(otherStream => otherStream.getTracks().some(track => track.id === label));
11315
+ const stream = pc.getRemoteStreams().find(someStream => someStream.getTracks().some(track => track.id === trackId));
10797
11316
 
10798
11317
  if (update === 'downgrade') {
10799
11318
  newParticipant.streams = [];
@@ -10813,21 +11332,21 @@ class Room$1 extends Emitter {
10813
11332
 
10814
11333
  // Associate audio/video streams to the participant and triggers events on it
10815
11334
  __associateStreams(participant ) {
10816
- const streamId = this._callIdStreamIdMap[participant.callId];
10817
- if (!streamId) {
11335
+ const { trackId } = this._callIdStreamIdMap[participant.callId] || {};
11336
+ if (!trackId) {
10818
11337
  this._unassociatedParticipants[participant.callId] = participant;
10819
11338
 
10820
11339
  return;
10821
11340
  }
10822
- if (!streamId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
11341
+ if (!trackId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
10823
11342
  return;
10824
11343
  }
10825
11344
 
10826
- if (this._unassociatedVideoStreams[streamId]) {
11345
+ if (this._unassociatedVideoStreams[trackId]) {
10827
11346
  // Try to associate stream
10828
- this._associateStreamTo(this._unassociatedVideoStreams[streamId], participant);
11347
+ this._associateStreamTo(this._unassociatedVideoStreams[trackId], participant);
10829
11348
 
10830
- delete this._unassociatedVideoStreams[streamId];
11349
+ delete this._unassociatedVideoStreams[trackId];
10831
11350
  delete this._unassociatedParticipants[participant.callId];
10832
11351
  }
10833
11352
  }
@@ -10840,8 +11359,8 @@ class Room$1 extends Emitter {
10840
11359
  participant.onStreamSubscribed(stream);
10841
11360
  }
10842
11361
 
10843
- _getCallIdFromStreamId(streamId ) {
10844
- return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key] === streamId);
11362
+ _getCallIdFromTrackId(trackId ) {
11363
+ return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key].trackId === trackId);
10845
11364
  }
10846
11365
 
10847
11366
  _getParticipantFromCallId(callId ) {
@@ -10890,10 +11409,7 @@ class Stream {
10890
11409
  element.onloadedmetadata = () => {
10891
11410
  const tracks = this.htmlStream ? this.htmlStream.getVideoTracks() : [];
10892
11411
  tracks.forEach(track => {
10893
- // Do not re-enable the track if already mounted.
10894
- if (!track.loaded) {
10895
- track.enabled = true;
10896
- }
11412
+ track.enabled = true;
10897
11413
  // $FlowFixMe
10898
11414
  track.loaded = true;
10899
11415
  });
@@ -11334,6 +11850,7 @@ var api = {
11334
11850
  check: async (server, session) => {
11335
11851
  const client = new ApiClient({ server });
11336
11852
  client.setToken(session.token);
11853
+ client.disableErrorLogging();
11337
11854
 
11338
11855
  const handleApiError = (apiName, error) => {
11339
11856
  const statusText = error instanceof ServerError ? 'server error' : 'api error';
@@ -11408,6 +11925,8 @@ var aor = {
11408
11925
  check: async (server, session) => {
11409
11926
  const apiClient = new ApiClient({ server });
11410
11927
  apiClient.setToken(session.token);
11928
+ apiClient.disableErrorLogging();
11929
+
11411
11930
  const line = session.primaryWebRtcLine();
11412
11931
  if (!line) {
11413
11932
  return 'No WebRTC line for this user';
@@ -11830,6 +12349,8 @@ const Wazo = {
11830
12349
  ServerError,
11831
12350
  Call,
11832
12351
  CallLog,
12352
+ CTIPhone,
12353
+ Recording,
11833
12354
  ChatMessage,
11834
12355
  ChatRoom,
11835
12356
  Contact,
@@ -11844,6 +12365,7 @@ const Wazo = {
11844
12365
  CallSession,
11845
12366
  IndirectTransfer,
11846
12367
  SwitchboardCall,
12368
+ WebRTCPhone,
11847
12369
  },
11848
12370
 
11849
12371
  // Api