@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 */
@@ -4988,23 +5467,6 @@ const areCandidateValid = (candidates ) =>
4988
5467
  getSrflxOrRelay(candidates)
4989
5468
  .length > 0;
4990
5469
 
4991
- const toggleVideoDirection = (sdp , direction ) => {
4992
- const parsedSdp = sdpParser__default['default'].parse(sdp);
4993
- parsedSdp.media = parsedSdp.media.map(media => ({
4994
- ...media,
4995
- ...(media.type === 'video' ? { direction } : {}),
4996
- }));
4997
-
4998
- return sdpParser__default['default'].write(parsedSdp);
4999
- };
5000
-
5001
- const deactivateVideoModifier = (rawDescription ) => {
5002
- const description = rawDescription;
5003
- description.sdp = toggleVideoDirection(description.sdp, 'inactive');
5004
-
5005
- return Promise.resolve(description);
5006
- };
5007
-
5008
5470
  const hasAnActiveVideo = (sdp ) => {
5009
5471
  if (!sdp) {
5010
5472
  return false;
@@ -5116,6 +5578,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5116
5578
  const iceRestart = options.offerOptions ? options.offerOptions.iceRestart : false;
5117
5579
 
5118
5580
  const isConference = options ? !!options.conference : false;
5581
+ const audioOnly = options ? !!options.audioOnly : false;
5119
5582
 
5120
5583
  // We should wait for ice when iceRestart (reinvite) or for the first invite
5121
5584
  // We shouldn't wait for ice when holding or resuming the call
@@ -5142,16 +5605,16 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5142
5605
  };
5143
5606
 
5144
5607
  return this.getLocalMediaStream(options)
5145
- .then(() => this.updateDirection(options, isConference))
5608
+ .then(() => this.updateDirection(options, isConference, audioOnly))
5146
5609
  .then(() => this.createDataChannel(options))
5147
5610
  .then(() => {
5148
- if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options)) {
5611
+ if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
5149
5612
  // Add a video an empty bundle to be able to replaceTrack when joining a conference without video
5150
5613
  this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5151
5614
  }
5152
5615
  })
5153
5616
  .then(() => this.createLocalOfferOrAnswer(options))
5154
- .then((sessionDescription) => this.setLocalSessionDescription(sessionDescription))
5617
+ .then(sessionDescription => this.setLocalSessionDescription(sessionDescription))
5155
5618
  .then(() => this.waitForIceGatheringComplete(iceRestart, iceTimeout))
5156
5619
  .then(() => this.getLocalSessionDescription())
5157
5620
  .then(description => {
@@ -5274,7 +5737,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5274
5737
  }
5275
5738
 
5276
5739
  // Overridden to send `inactive` in conference
5277
- updateDirection(options , isConference = false) {
5740
+ updateDirection(options , isConference = false,
5741
+ audioOnly = false) {
5278
5742
  if (this._peerConnection === undefined) {
5279
5743
  return Promise.reject(new Error('Peer connection closed.'));
5280
5744
  }
@@ -5289,14 +5753,17 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5289
5753
  // if we are stable, assume we are creating a local offer
5290
5754
  this.logger.debug('SessionDescriptionHandler.updateDirection - setting offer direction');
5291
5755
  // determine the direction to offer given the current direction and hold state
5292
- const directionToOffer = (currentDirection ) => {
5756
+ const directionToOffer = (currentDirection , transceiver /* RTCRtpTransceiver */) => {
5293
5757
  if (isConference) {
5758
+ if (audioOnly && transceiver.receiver.track && transceiver.receiver.track.kind === 'video') {
5759
+ return 'sendonly';
5760
+ }
5294
5761
  return options && options.hold ? 'sendonly' : 'sendrecv';
5295
5762
  }
5296
5763
 
5297
5764
  switch (currentDirection) {
5298
5765
  case 'inactive':
5299
- return options && options.hold ? 'inactive' : 'recvonly';
5766
+ return options && options.hold ? 'inactive' : (isConference && !audioOnly ? 'sendrecv' : 'recvonly');
5300
5767
  case 'recvonly':
5301
5768
  return options && options.hold ? 'inactive' : 'recvonly';
5302
5769
  case 'sendonly':
@@ -5312,7 +5779,7 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5312
5779
  // set the transceiver direction to the offer direction
5313
5780
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5314
5781
  if (transceiver.direction /* guarding, but should always be true */) {
5315
- const offerDirection = directionToOffer(transceiver.direction);
5782
+ const offerDirection = directionToOffer(transceiver.direction, transceiver);
5316
5783
  if (transceiver.direction !== offerDirection) {
5317
5784
  // eslint-disable-next-line no-param-reassign
5318
5785
  transceiver.direction = offerDirection;
@@ -5371,6 +5838,13 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5371
5838
  // set the transceiver direction to the answer direction
5372
5839
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5373
5840
  if (transceiver.direction /* guarding, but should always be true */) {
5841
+ const { receiver } = transceiver;
5842
+ if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
5843
+ // eslint-disable-next-line no-param-reassign
5844
+ transceiver.direction = 'inactive';
5845
+ return;
5846
+ }
5847
+
5374
5848
  if (transceiver.direction !== 'stopped' && transceiver.direction !== answerDirection) {
5375
5849
  // eslint-disable-next-line no-param-reassign
5376
5850
  transceiver.direction = answerDirection;
@@ -5409,8 +5883,8 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5409
5883
  }
5410
5884
  const sender = pc.getSenders().find((otherSender) => otherSender.track && otherSender.track.kind === kind);
5411
5885
 
5412
- // Do not reuse sender tracks in SFU
5413
- if (sender && !sfu) {
5886
+ // Do not reuse sender video tracks in SFU
5887
+ if (sender && (!sfu || newTrack.kind === 'audio')) {
5414
5888
  trackUpdates.push(
5415
5889
  new Promise((resolve) => {
5416
5890
  this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
@@ -5962,9 +6436,15 @@ class WebRTCClient extends Emitter {
5962
6436
 
5963
6437
  call(number , enableVideo , audioOnly = false, conference = false) {
5964
6438
  logger$8.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
5965
- const inviterOptions = {};
6439
+ const inviterOptions = {
6440
+ sessionDescriptionHandlerOptionsReInvite: {
6441
+ conference,
6442
+ audioOnly,
6443
+ },
6444
+ };
6445
+
5966
6446
  if (audioOnly) {
5967
- inviterOptions.sessionDescriptionHandlerModifiersReInvite = [deactivateVideoModifier];
6447
+ inviterOptions.sessionDescriptionHandlerModifiersReInvite = [modifiers.stripVideo];
5968
6448
  }
5969
6449
 
5970
6450
  const session = new inviter.Inviter(this.userAgent, this._makeURI(number), inviterOptions);
@@ -5993,10 +6473,11 @@ class WebRTCClient extends Emitter {
5993
6473
  sessionDescriptionHandlerOptions: this.getMediaConfiguration(enableVideo || false, conference),
5994
6474
  };
5995
6475
 
5996
- inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6476
+ inviteOptions.sessionDescriptionHandlerOptions.audioOnly = audioOnly;
5997
6477
 
6478
+ inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
5998
6479
  if (audioOnly) {
5999
- inviteOptions.sessionDescriptionHandlerModifiers.push(deactivateVideoModifier);
6480
+ inviteOptions.sessionDescriptionHandlerModifiers.push(modifiers.stripVideo);
6000
6481
  }
6001
6482
 
6002
6483
  // Do not await invite here or we'll miss the Establishing state transition
@@ -6210,6 +6691,9 @@ class WebRTCClient extends Emitter {
6210
6691
  if (!this._isWeb()) {
6211
6692
  options.sessionDescriptionHandlerModifiers = [modifiers.holdModifier];
6212
6693
  }
6694
+ options.sessionDescriptionHandlerOptions = {
6695
+ constraints: options.constraints,
6696
+ };
6213
6697
 
6214
6698
  // Send re-INVITE
6215
6699
  return session.invite(options);
@@ -6249,6 +6733,9 @@ class WebRTCClient extends Emitter {
6249
6733
  // (eg: holdModifier)
6250
6734
  options.sessionDescriptionHandlerModifiers = [];
6251
6735
  }
6736
+ options.sessionDescriptionHandlerOptions = {
6737
+ constraints: options.constraints,
6738
+ };
6252
6739
 
6253
6740
  // Send re-INVITE
6254
6741
  return session.invite(options);
@@ -6478,7 +6965,8 @@ class WebRTCClient extends Emitter {
6478
6965
  ? this.video.deviceId.exact : undefined;
6479
6966
  }
6480
6967
 
6481
- reinvite(sipSession , newConstraints = null, conference = false) {
6968
+ reinvite(sipSession , newConstraints = null, conference = false,
6969
+ audioOnly = false) {
6482
6970
  if (!sipSession) {
6483
6971
  return false;
6484
6972
  }
@@ -6488,16 +6976,17 @@ class WebRTCClient extends Emitter {
6488
6976
  }
6489
6977
 
6490
6978
  const wasMuted = this.isAudioMuted(sipSession);
6491
- // When upgrading to video, remove the `deactivateVideoModifier` modifiers
6979
+ // When upgrading to video, remove the `stripVideo` modifiers
6492
6980
  if (newConstraints && newConstraints.video) {
6493
- const modifiers = sipSession.sessionDescriptionHandlerModifiersReInvite;
6494
- sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers.filter(modifier =>
6495
- modifier !== deactivateVideoModifier);
6981
+ const modifiers$1 = sipSession.sessionDescriptionHandlerModifiersReInvite;
6982
+ sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers$1.filter(modifier =>
6983
+ modifier !== modifiers.stripVideo);
6496
6984
  }
6497
6985
 
6498
6986
  sipSession.sessionDescriptionHandlerOptionsReInvite = {
6499
6987
  ...sipSession.sessionDescriptionHandlerOptionsReInvite,
6500
6988
  conference,
6989
+ audioOnly,
6501
6990
  };
6502
6991
 
6503
6992
  const shouldDoVideo = newConstraints ? newConstraints.video : this.sessionWantsToDoVideo(sipSession);
@@ -6537,6 +7026,8 @@ class WebRTCClient extends Emitter {
6537
7026
  },
6538
7027
  sessionDescriptionHandlerOptions: {
6539
7028
  constraints,
7029
+ conference,
7030
+ audioOnly,
6540
7031
  offerOptions: {
6541
7032
  iceRestart: false,
6542
7033
  },
@@ -6996,6 +7487,8 @@ class WebRTCClient extends Emitter {
6996
7487
 
6997
7488
  // Invitation and Inviter extends Session
6998
7489
  _setupSession(session ) {
7490
+ const sipSessionId = this.getSipSessionId(session);
7491
+
6999
7492
  // When receiving an Invitation, the delegate is not defined.
7000
7493
  if (!session.delegate) {
7001
7494
  session.delegate = {};
@@ -7019,8 +7512,18 @@ class WebRTCClient extends Emitter {
7019
7512
  };
7020
7513
  };
7021
7514
 
7515
+ const oldInviteRequest = session.onInviteRequest.bind(session);
7516
+ let hadRemoteVideo = false;
7517
+
7518
+ // Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
7519
+ // Becase when `onInvite` is called we already got the video track
7520
+ session.onInviteRequest = (request) => {
7521
+ hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7522
+
7523
+ oldInviteRequest(request);
7524
+ };
7525
+
7022
7526
  session.delegate.onInvite = (request ) => {
7023
- const sipSessionId = this.getSipSessionId(session);
7024
7527
  let updatedCalleeName = null;
7025
7528
  let updatedNumber = null;
7026
7529
  if (session.assertedIdentity) {
@@ -7030,7 +7533,6 @@ class WebRTCClient extends Emitter {
7030
7533
  logger$8.info('re-invite received', { updatedCalleeName, updatedNumber });
7031
7534
 
7032
7535
  // Useful to know if it's a video upgrade or an unhold from a remote peer with a video stream
7033
- const hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7034
7536
 
7035
7537
  // Update SDP
7036
7538
  // Remote video is handled by the `track` event. Here we're dealing with video stream removal.
@@ -7080,7 +7582,7 @@ class WebRTCClient extends Emitter {
7080
7582
  }
7081
7583
 
7082
7584
  _isAudioOnly(session ) {
7083
- return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === deactivateVideoModifier);
7585
+ return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === modifiers.stripVideo);
7084
7586
  }
7085
7587
 
7086
7588
  _setupMedias(session , newStream ) {
@@ -7453,9 +7955,14 @@ class WebRTCPhone extends Emitter {
7453
7955
  return true;
7454
7956
  }
7455
7957
 
7456
- async sendReinvite(callSession , constraints = null, conference = false) {
7958
+ async sendReinvite(callSession , constraints = null, conference = false,
7959
+ audioOnly = false) {
7457
7960
  const sipSession = this.findSipSession(callSession);
7458
- logger$7.info('WebRTC phone - send reinvite', { sessionId: sipSession ? sipSession.id : null, constraints });
7961
+ logger$7.info('WebRTC phone - send reinvite', {
7962
+ sessionId: sipSession ? sipSession.id : null,
7963
+ constraints,
7964
+ audioOnly,
7965
+ });
7459
7966
 
7460
7967
  if (!sipSession) {
7461
7968
  return null;
@@ -7481,7 +7988,7 @@ class WebRTCPhone extends Emitter {
7481
7988
  // Force reinvite in SDH
7482
7989
  sipSession.sessionDescriptionHandler.localMediaStreamConstraints = null;
7483
7990
 
7484
- return this.client.reinvite(sipSession, constraints, conference);
7991
+ return this.client.reinvite(sipSession, constraints, conference, audioOnly);
7485
7992
  }
7486
7993
 
7487
7994
  getUserAgent() {
@@ -7557,9 +8064,9 @@ class WebRTCPhone extends Emitter {
7557
8064
  }
7558
8065
 
7559
8066
  // Release local video stream when downgrading to audio
7560
- const localVideoStream = sipSession.sessionDescriptionHandler.localMediaStream;
8067
+ const localStream = sipSession.sessionDescriptionHandler.localMediaStream;
7561
8068
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7562
- const videoTracks = localVideoStream.getVideoTracks();
8069
+ const videoTracks = localStream.getVideoTracks();
7563
8070
 
7564
8071
  // Remove video senders
7565
8072
  pc.getSenders().filter(sender => sender.track && sender.track.kind === 'video').forEach(videoSender => {
@@ -7574,7 +8081,7 @@ class WebRTCPhone extends Emitter {
7574
8081
  videoTracks.forEach(videoTrack => {
7575
8082
  videoTrack.enabled = false;
7576
8083
  videoTrack.stop();
7577
- localVideoStream.removeTrack(videoTrack);
8084
+ localStream.removeTrack(videoTrack);
7578
8085
  });
7579
8086
 
7580
8087
  this._sendReinviteMessage(callSession, false);
@@ -7591,12 +8098,14 @@ class WebRTCPhone extends Emitter {
7591
8098
 
7592
8099
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7593
8100
  const shouldScreenShare = constraints && constraints.screen;
8101
+ const options = sipSession.sessionDescriptionHandlerOptionsReInvite;
8102
+ const wasAudioOnly = options && options.audioOnly;
7594
8103
 
7595
8104
  // Check if a video sender already exists
7596
8105
  let videoSender;
7597
8106
  if (isConference) {
7598
8107
  const trans = pc.getTransceivers().find(transceiver => transceiver.mid === '1');
7599
- videoSender = trans.sender;
8108
+ videoSender = trans ? trans.sender : null;
7600
8109
  } else {
7601
8110
  videoSender = pc.getSenders().find(sender => sender.track === null);
7602
8111
  }
@@ -7633,6 +8142,11 @@ class WebRTCPhone extends Emitter {
7633
8142
  this._onScreenSharing(newStream, sipSession, callSession, false);
7634
8143
  }
7635
8144
 
8145
+ // We have to reinvite to change the direction on the bundle when upgrading from an audioOnly conference
8146
+ if (isConference && wasAudioOnly) {
8147
+ return true;
8148
+ }
8149
+
7636
8150
  // No reinvite needed here
7637
8151
  return false;
7638
8152
  }
@@ -7717,7 +8231,7 @@ class WebRTCPhone extends Emitter {
7717
8231
  event.track.enabled = false;
7718
8232
  }
7719
8233
 
7720
- return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event);
8234
+ return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event, sipSession);
7721
8235
  };
7722
8236
 
7723
8237
  peerConnection.onremovestream = event => {
@@ -7773,14 +8287,11 @@ class WebRTCPhone extends Emitter {
7773
8287
  const targetCallSession = callSession || this.currentCallSession;
7774
8288
  const conference = this.isConference(targetCallSession);
7775
8289
 
7776
- if (this.currentScreenShare.sender && this.currentScreenShare.hadVideo) {
7777
- // When stopping screenshare and we had video before that, we have to re-upgrade
7778
- await this.sendReinvite(targetCallSession, { audio: false, video: true }, conference);
7779
- } else {
7780
- // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
7781
- // We have to downgrade to audio.
7782
- await this.sendReinvite(targetCallSession, { audio: false, video: false }, conference);
7783
- }
8290
+ // When stopping screenshare and we had video before that, we have to re-upgrade
8291
+ // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8292
+ // We have to downgrade to audio.
8293
+ const screenshareStopped = this.currentScreenShare.sender && this.currentScreenShare.hadVideo;
8294
+ await this.sendReinvite(targetCallSession, { audio: false, video: screenshareStopped }, conference);
7784
8295
  }
7785
8296
  } catch (e) {
7786
8297
  console.warn(e);
@@ -8117,6 +8628,7 @@ class WebRTCPhone extends Emitter {
8117
8628
  }
8118
8629
  }
8119
8630
 
8631
+ // @Deprecated
8120
8632
  unhold(callSession , withEvent = true, isConference = false) {
8121
8633
  logger$7.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
8122
8634
 
@@ -9114,6 +9626,7 @@ class Phone extends Emitter {
9114
9626
  return this.phone && this.phone.hasLocalVideo(callSession);
9115
9627
  }
9116
9628
 
9629
+ // @Deprecated
9117
9630
  getLocalMediaStream(callSession ) {
9118
9631
  logger$6.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
9119
9632
 
@@ -9132,17 +9645,20 @@ class Phone extends Emitter {
9132
9645
  return this.phone ? this.phone.getRemoteVideoStream(callSession) : null;
9133
9646
  }
9134
9647
 
9648
+ // @Deprecated
9135
9649
  getRemoteStreamForCall(callSession ) {
9136
9650
  logger$6.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
9137
9651
  return this.getRemoteStream(callSession);
9138
9652
  }
9139
9653
 
9140
9654
  // Returns remote streams directly from the peerConnection
9655
+ // @Deprecated
9141
9656
  getRemoteStreamsForCall(callSession ) {
9142
- logger$6.warn('Phone.getRe is deprecated, use Phone.getLocalStream instead');
9657
+ logger$6.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
9143
9658
  return this.getLocalStream(callSession);
9144
9659
  }
9145
9660
 
9661
+ // @Deprecated
9146
9662
  getRemoteVideoStreamForCall(callSession ) {
9147
9663
  logger$6.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
9148
9664
 
@@ -10505,13 +11021,15 @@ class Room$1 extends Emitter {
10505
11021
  }
10506
11022
  });
10507
11023
 
10508
- this.on(this.ON_VIDEO_STREAM, (stream, streamId) => {
11024
+ this.on(this.ON_VIDEO_STREAM, (stream, streamId, event, sipSession) => {
10509
11025
  logger$2.info('on room video stream', { streamId });
10510
11026
 
11027
+ this._mapMsid(sipSession.body.body);
11028
+
10511
11029
  // ON_VIDEO_STREAM is called before PARTICIPANT_JOINED, so we have to keep stream in `_unassociatedVideoStreams`.
10512
11030
  this._unassociatedVideoStreams[streamId] = stream;
10513
11031
 
10514
- const callId = this._getCallIdFromStreamId(streamId);
11032
+ const callId = this._getCallIdFromTrackId(streamId);
10515
11033
  const participant = callId ? this._getParticipantFromCallId(callId) : null;
10516
11034
  if (participant) {
10517
11035
  this.__associateStreams(participant);
@@ -10555,11 +11073,12 @@ class Room$1 extends Emitter {
10555
11073
  const sdp = sdpParser__default['default'].parse(rawSdp);
10556
11074
  const labelMsidArray = sdp.media.filter(media => !!media.label).map(({ label, msid }) => ({
10557
11075
  label: String(label),
10558
- msid: msid.split(' ')[1],
11076
+ streamId: msid.split(' ')[0],
11077
+ trackId: msid.split(' ')[1],
10559
11078
  }));
10560
11079
 
10561
- labelMsidArray.forEach(({ label, msid }) => {
10562
- this._callIdStreamIdMap[String(label)] = msid;
11080
+ labelMsidArray.forEach(({ label, streamId, trackId }) => {
11081
+ this._callIdStreamIdMap[String(label)] = { streamId, trackId };
10563
11082
 
10564
11083
  const callId = String(label);
10565
11084
  const participant = this._unassociatedParticipants[callId] || this._getParticipantFromCallId(callId);
@@ -10789,9 +11308,9 @@ class Room$1 extends Emitter {
10789
11308
  _onParticipantTrackUpdate(oldParticipant , update ) {
10790
11309
  const newParticipant = oldParticipant;
10791
11310
 
10792
- const label = this._callIdStreamIdMap[newParticipant.callId];
11311
+ const { trackId } = this._callIdStreamIdMap[newParticipant.callId] || {};
10793
11312
  const pc = Wazo.Phone.phone.currentSipSession.sessionDescriptionHandler.peerConnection;
10794
- const stream = pc.getRemoteStreams().find(otherStream => otherStream.getTracks().some(track => track.id === label));
11313
+ const stream = pc.getRemoteStreams().find(someStream => someStream.getTracks().some(track => track.id === trackId));
10795
11314
 
10796
11315
  if (update === 'downgrade') {
10797
11316
  newParticipant.streams = [];
@@ -10811,21 +11330,21 @@ class Room$1 extends Emitter {
10811
11330
 
10812
11331
  // Associate audio/video streams to the participant and triggers events on it
10813
11332
  __associateStreams(participant ) {
10814
- const streamId = this._callIdStreamIdMap[participant.callId];
10815
- if (!streamId) {
11333
+ const { trackId } = this._callIdStreamIdMap[participant.callId] || {};
11334
+ if (!trackId) {
10816
11335
  this._unassociatedParticipants[participant.callId] = participant;
10817
11336
 
10818
11337
  return;
10819
11338
  }
10820
- if (!streamId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
11339
+ if (!trackId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
10821
11340
  return;
10822
11341
  }
10823
11342
 
10824
- if (this._unassociatedVideoStreams[streamId]) {
11343
+ if (this._unassociatedVideoStreams[trackId]) {
10825
11344
  // Try to associate stream
10826
- this._associateStreamTo(this._unassociatedVideoStreams[streamId], participant);
11345
+ this._associateStreamTo(this._unassociatedVideoStreams[trackId], participant);
10827
11346
 
10828
- delete this._unassociatedVideoStreams[streamId];
11347
+ delete this._unassociatedVideoStreams[trackId];
10829
11348
  delete this._unassociatedParticipants[participant.callId];
10830
11349
  }
10831
11350
  }
@@ -10838,8 +11357,8 @@ class Room$1 extends Emitter {
10838
11357
  participant.onStreamSubscribed(stream);
10839
11358
  }
10840
11359
 
10841
- _getCallIdFromStreamId(streamId ) {
10842
- return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key] === streamId);
11360
+ _getCallIdFromTrackId(trackId ) {
11361
+ return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key].trackId === trackId);
10843
11362
  }
10844
11363
 
10845
11364
  _getParticipantFromCallId(callId ) {
@@ -10888,10 +11407,7 @@ class Stream {
10888
11407
  element.onloadedmetadata = () => {
10889
11408
  const tracks = this.htmlStream ? this.htmlStream.getVideoTracks() : [];
10890
11409
  tracks.forEach(track => {
10891
- // Do not re-enable the track if already mounted.
10892
- if (!track.loaded) {
10893
- track.enabled = true;
10894
- }
11410
+ track.enabled = true;
10895
11411
  // $FlowFixMe
10896
11412
  track.loaded = true;
10897
11413
  });
@@ -11315,6 +11831,7 @@ var api = {
11315
11831
  check: async (server, session) => {
11316
11832
  const client = new ApiClient({ server });
11317
11833
  client.setToken(session.token);
11834
+ client.disableErrorLogging();
11318
11835
 
11319
11836
  const handleApiError = (apiName, error) => {
11320
11837
  const statusText = error instanceof ServerError ? 'server error' : 'api error';
@@ -11389,6 +11906,8 @@ var aor = {
11389
11906
  check: async (server, session) => {
11390
11907
  const apiClient = new ApiClient({ server });
11391
11908
  apiClient.setToken(session.token);
11909
+ apiClient.disableErrorLogging();
11910
+
11392
11911
  const line = session.primaryWebRtcLine();
11393
11912
  if (!line) {
11394
11913
  return 'No WebRTC line for this user';
@@ -11811,6 +12330,8 @@ const Wazo = {
11811
12330
  ServerError,
11812
12331
  Call,
11813
12332
  CallLog,
12333
+ CTIPhone,
12334
+ Recording,
11814
12335
  ChatMessage,
11815
12336
  ChatRoom,
11816
12337
  Contact,
@@ -11825,6 +12346,7 @@ const Wazo = {
11825
12346
  CallSession,
11826
12347
  IndirectTransfer,
11827
12348
  SwitchboardCall,
12349
+ WebRTCPhone,
11828
12350
  },
11829
12351
 
11830
12352
  // Api