@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
@@ -7,12 +7,11 @@ import { jsonToGraphQLQuery } from 'json-to-graphql-query/lib/jsonToGraphQLQuery
7
7
  import { Invitation } from 'sip.js/lib/api/invitation';
8
8
  import 'webrtc-adapter';
9
9
  import { UserAgentState } from 'sip.js/lib/api/user-agent-state';
10
- import 'sip.js/lib/api/message';
11
10
  import { Parser } from 'sip.js/lib/core/messages/parser';
12
11
  import { C } from 'sip.js/lib/core/messages/methods/constants';
13
12
  import { URI } from 'sip.js/lib/grammar/uri';
14
13
  import { UserAgent } from 'sip.js/lib/api/user-agent';
15
- import { holdModifier } from 'sip.js/lib/platform/web/modifiers/modifiers';
14
+ import { stripVideo, holdModifier } from 'sip.js/lib/platform/web/modifiers/modifiers';
16
15
  import { Registerer } from 'sip.js/lib/api/registerer';
17
16
  import { Inviter } from 'sip.js/lib/api/inviter';
18
17
  import { Messager } from 'sip.js/lib/api/messager';
@@ -1003,7 +1002,7 @@ class Contact {
1003
1002
 
1004
1003
  return new Contact({
1005
1004
  sourceId: single.id || '',
1006
- name: single.displayName,
1005
+ name: single.displayName || '',
1007
1006
  number: numbers.length ? numbers[0].number : '',
1008
1007
  numbers,
1009
1008
  emails,
@@ -1034,7 +1033,7 @@ class Contact {
1034
1033
 
1035
1034
  return new Contact({
1036
1035
  sourceId: single.id || '',
1037
- name: single.name,
1036
+ name: single.name || '',
1038
1037
  number: numbers.length ? numbers[0].number : '',
1039
1038
  numbers,
1040
1039
  emails,
@@ -1135,7 +1134,7 @@ class Contact {
1135
1134
  } = {}) {
1136
1135
  this.id = id;
1137
1136
  this.uuid = uuid;
1138
- this.name = name;
1137
+ this.name = name || '';
1139
1138
  this.number = number;
1140
1139
  this.numbers = numbers;
1141
1140
  this.email = email;
@@ -1810,7 +1809,13 @@ class IssueReporter {
1810
1809
  }
1811
1810
 
1812
1811
  _isLevelAbove(level1 , level2 ) {
1813
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
1812
+ const index1 = LOG_LEVELS.indexOf(level1);
1813
+ const index2 = LOG_LEVELS.indexOf(level2);
1814
+ if (index1 === -1 || index2 === -1) {
1815
+ return false;
1816
+ }
1817
+
1818
+ return index1 > index2;
1814
1819
  }
1815
1820
 
1816
1821
  _makeCategory(category ) {
@@ -1833,7 +1838,7 @@ var IssueReporter$1 = new IssueReporter();
1833
1838
 
1834
1839
  const methods = ['head', 'get', 'post', 'put', 'delete'];
1835
1840
 
1836
- const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
1841
+ const logger$b = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
1837
1842
 
1838
1843
  // Use a function here to be able to mock it in tests
1839
1844
  const realFetch = () => {
@@ -1868,6 +1873,7 @@ class ApiRequester {
1868
1873
 
1869
1874
 
1870
1875
 
1876
+
1871
1877
 
1872
1878
 
1873
1879
 
@@ -1907,6 +1913,8 @@ class ApiRequester {
1907
1913
  this.token = token;
1908
1914
  }
1909
1915
 
1916
+ this.shouldLogErrors = true;
1917
+
1910
1918
  methods.forEach(method => {
1911
1919
  // $FlowFixMe
1912
1920
  ApiRequester.prototype[method] = function sugar(...args) {
@@ -1930,6 +1938,14 @@ class ApiRequester {
1930
1938
  this.fetchOptions = options;
1931
1939
  }
1932
1940
 
1941
+ disableErrorLogging() {
1942
+ this.shouldLogErrors = false;
1943
+ }
1944
+
1945
+ enableErrorLogging() {
1946
+ this.shouldLogErrors = true;
1947
+ }
1948
+
1933
1949
  async call(
1934
1950
  path ,
1935
1951
  method = 'get',
@@ -1961,7 +1977,7 @@ class ApiRequester {
1961
1977
  };
1962
1978
 
1963
1979
  if (this.refreshTokenPromise) {
1964
- logger$a.info('A token is already refreshing, waiting ...', { url });
1980
+ logger$b.info('A token is already refreshing, waiting ...', { url });
1965
1981
  await this.refreshTokenPromise;
1966
1982
  }
1967
1983
 
@@ -1981,7 +1997,7 @@ class ApiRequester {
1981
1997
  return promise.then(async (err ) => {
1982
1998
  // Check if the token is still valid
1983
1999
  if (firstCall && this._checkTokenExpired(response, err)) {
1984
- logger$a.warn('token expired', { error: err.reason });
2000
+ logger$b.warn('token expired', { error: err.reason });
1985
2001
  // Replay the call after refreshing the token
1986
2002
  return this._replayWithNewToken(err, path, method, body, headers, parse);
1987
2003
  }
@@ -1990,7 +2006,9 @@ class ApiRequester {
1990
2006
  ? exceptionClass.fromText(err, response.status)
1991
2007
  : exceptionClass.fromResponse(err, response.status);
1992
2008
 
1993
- logger$a.error('API error', error);
2009
+ if (this.shouldLogErrors) {
2010
+ logger$b.error('API error', error);
2011
+ }
1994
2012
 
1995
2013
  throw error;
1996
2014
  });
@@ -1998,7 +2016,9 @@ class ApiRequester {
1998
2016
 
1999
2017
  return newParse(response, isJson);
2000
2018
  }).catch(error => {
2001
- logger$a.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
2019
+ if (this.shouldLogErrors) {
2020
+ logger$b.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
2021
+ }
2002
2022
 
2003
2023
  throw error;
2004
2024
  });
@@ -2025,13 +2045,13 @@ class ApiRequester {
2025
2045
  ) {
2026
2046
  const isTokenNotFound = this._isTokenNotFound(err);
2027
2047
  let newPath = path;
2028
- logger$a.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
2048
+ logger$b.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
2029
2049
 
2030
2050
  this.refreshTokenPromise = this.refreshTokenPromise || this.refreshTokenCallback();
2031
2051
 
2032
2052
  return this.refreshTokenPromise.then(() => {
2033
2053
  this.refreshTokenPromise = null;
2034
- logger$a.info('token refreshed', { isTokenNotFound });
2054
+ logger$b.info('token refreshed', { isTokenNotFound });
2035
2055
  if (isTokenNotFound) {
2036
2056
  const pathParts = path.split('/');
2037
2057
  pathParts.pop();
@@ -3313,7 +3333,7 @@ class CallSession {
3313
3333
  return newFrom(callSession, CallSession);
3314
3334
  }
3315
3335
 
3316
- static parseCall(session , call ) {
3336
+ static parseCall(call ) {
3317
3337
  return new CallSession({
3318
3338
  callId: call.id,
3319
3339
  sipCallId: call.sipCallId,
@@ -3366,17 +3386,66 @@ class Emitter {
3366
3386
 
3367
3387
  //
3368
3388
 
3389
+
3390
+
3391
+
3392
+
3393
+
3394
+
3395
+
3396
+
3397
+
3398
+
3399
+
3400
+
3401
+
3402
+
3403
+
3404
+
3405
+ class Recording {
3406
+
3407
+
3408
+
3409
+
3410
+
3411
+
3412
+ static parseMany(recordings ) {
3413
+ return recordings.map(item => Recording.parse(item));
3414
+ }
3415
+
3416
+ static parse(plain ) {
3417
+ return new Recording({
3418
+ deleted: plain.deleted,
3419
+ fileName: plain.filename,
3420
+ end: plain.end_time ? moment(plain.end_time).toDate() : null,
3421
+ start: moment(plain.start_time).toDate(),
3422
+ uuid: plain.uuid,
3423
+ });
3424
+ }
3425
+
3426
+ constructor({ deleted, end, fileName, start, uuid } ) {
3427
+ this.deleted = deleted;
3428
+ this.end = end;
3429
+ this.fileName = fileName;
3430
+ this.start = start;
3431
+ this.uuid = uuid;
3432
+ }
3433
+ }
3434
+
3435
+ //
3436
+
3369
3437
 
3370
-
3438
+
3371
3439
 
3372
3440
 
3373
3441
 
3374
3442
 
3375
3443
 
3376
-
3444
+
3377
3445
 
3378
3446
 
3379
3447
 
3448
+
3380
3449
 
3381
3450
 
3382
3451
 
@@ -3389,7 +3458,7 @@ class Emitter {
3389
3458
 
3390
3459
 
3391
3460
 
3392
-
3461
+
3393
3462
 
3394
3463
 
3395
3464
 
@@ -3404,13 +3473,14 @@ class Emitter {
3404
3473
 
3405
3474
 
3406
3475
 
3407
-
3476
+
3477
+
3408
3478
 
3409
3479
 
3410
3480
  class CallLog {
3411
3481
 
3412
3482
 
3413
-
3483
+
3414
3484
 
3415
3485
 
3416
3486
 
@@ -3427,7 +3497,7 @@ class CallLog {
3427
3497
 
3428
3498
 
3429
3499
 
3430
-
3500
+
3431
3501
 
3432
3502
  static merge(current , toMerge ) {
3433
3503
  const onlyUnique = (value, index, self) => self.indexOf(value) === index;
@@ -3444,7 +3514,7 @@ class CallLog {
3444
3514
 
3445
3515
  static parse(plain ) {
3446
3516
  return new CallLog({
3447
- answer: moment(plain.answer).toDate(),
3517
+ answer: plain.answer ? moment(plain.answer).toDate() : null,
3448
3518
  answered: plain.answered,
3449
3519
  callDirection: plain.call_direction,
3450
3520
  destination: {
@@ -3458,13 +3528,14 @@ class CallLog {
3458
3528
  id: plain.id,
3459
3529
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3460
3530
  start: moment(plain.start).toDate(),
3461
- end: moment(plain.end).toDate(),
3531
+ end: plain.end ? moment(plain.end).toDate() : null,
3532
+ recordings: Recording.parseMany(plain.recordings),
3462
3533
  });
3463
3534
  }
3464
3535
 
3465
3536
  static parseNew(plain , session ) {
3466
3537
  return new CallLog({
3467
- answer: moment(plain.answer).toDate(),
3538
+ answer: plain.answer ? moment(plain.answer).toDate() : null,
3468
3539
  answered: plain.answered,
3469
3540
  callDirection: plain.call_direction,
3470
3541
  destination: {
@@ -3478,7 +3549,8 @@ class CallLog {
3478
3549
  id: plain.id,
3479
3550
  duration: (plain.duration || 0) * 1000, // duration is in seconds
3480
3551
  start: moment(plain.start).toDate(),
3481
- end: moment(plain.end).toDate(),
3552
+ end: plain.end ? moment(plain.end).toDate() : null,
3553
+ recordings: Recording.parseMany(plain.recordings),
3482
3554
  // @TODO: FIXME add verification declined vs missed call
3483
3555
  newMissedCall: session
3484
3556
  && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
@@ -3660,11 +3732,414 @@ class IndirectTransfer {
3660
3732
  }
3661
3733
 
3662
3734
  //
3735
+
3736
+ class CallApi {
3737
+ static async fetchCallLogs(offset , limit ) {
3738
+ return getApiClient().callLogd.listCallLogs(offset, limit);
3739
+ }
3740
+
3741
+ static async fetchDistinctCallLogs(offset , limit , distinct = 'peer_exten') {
3742
+ return getApiClient().callLogd.listDistinctCallLogs(offset, limit, distinct);
3743
+ }
3744
+
3745
+ static async fetchActiveCalls() {
3746
+ return getApiClient().calld.listCalls();
3747
+ }
3748
+
3749
+ static async fetchCallLogsFromDate(from , number ) {
3750
+ return getApiClient().callLogd.listCallLogsFromDate(from, number);
3751
+ }
3752
+
3753
+ static async search(query , limit ) {
3754
+ return getApiClient().callLogd.search(query, limit);
3755
+ }
3756
+
3757
+ static async searchBy(field , value , limit ) {
3758
+ return getApiClient().callLogd.searchBy(field, value, limit);
3759
+ }
3760
+
3761
+ static async fetchSIP(session , line ) {
3762
+ const lineToUse = line || session.primaryLine();
3763
+ return getApiClient().confd.getUserLineSip(session.uuid, lineToUse ? lineToUse.id : null);
3764
+ }
3765
+
3766
+ static async cancelCall(callSession ) {
3767
+ return getApiClient().calld.cancelCall(callSession.callId);
3768
+ }
3769
+
3770
+ static async makeCall(callFromLine , extension , isMobile = false,
3771
+ callbackAllLines = false) {
3772
+ const lineId = callFromLine ? callFromLine.id : null;
3773
+
3774
+ const response = await getApiClient().calld.makeCall(extension, isMobile, lineId, callbackAllLines);
3775
+ return Call.parse(response);
3776
+ }
3777
+
3778
+ static async relocateCall(callId , line , contactIdentifier ) {
3779
+ return getApiClient().calld.relocateCall(callId, 'line', line, contactIdentifier);
3780
+ }
3781
+
3782
+ static async hold(callId ) {
3783
+ return getApiClient().calld.hold(callId);
3784
+ }
3785
+
3786
+ static async resume(callId ) {
3787
+ return getApiClient().calld.resume(callId);
3788
+ }
3789
+
3790
+ static async mute(callId ) {
3791
+ return getApiClient().calld.mute(callId);
3792
+ }
3793
+
3794
+ static async sendDTMF(callId , digits ) {
3795
+ return getApiClient().calld.sendDTMF(callId, digits);
3796
+ }
3797
+
3798
+ static async unmute(callId ) {
3799
+ return getApiClient().calld.unmute(callId);
3800
+ }
3801
+
3802
+ static async transferCall(callId , number , flow ) {
3803
+ return getApiClient().calld.transferCall(callId, number, flow);
3804
+ }
3805
+
3806
+ static async cancelCallTransfer(transferId ) {
3807
+ return getApiClient().calld.cancelCallTransfer(transferId);
3808
+ }
3809
+
3810
+ static async confirmCallTransfer(transferId ) {
3811
+ return getApiClient().calld.confirmCallTransfer(transferId);
3812
+ }
3813
+ }
3814
+
3815
+ //
3816
+
3817
+ const TRANSFER_FLOW_ATTENDED = 'attended';
3663
3818
  const TRANSFER_FLOW_BLIND = 'blind';
3664
3819
 
3665
3820
  // const MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD = '20.11';
3666
3821
 
3667
- IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3822
+ const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3823
+
3824
+ class CTIPhone extends Emitter {
3825
+
3826
+
3827
+
3828
+
3829
+
3830
+
3831
+
3832
+
3833
+ constructor(session , isMobile = false, callbackAllLines = false) {
3834
+ super();
3835
+ logger$a.info('CTI Phone created');
3836
+ this.session = session;
3837
+ this.isMobile = isMobile;
3838
+ this.callbackAllLines = callbackAllLines;
3839
+ }
3840
+
3841
+ getOptions() {
3842
+ // @FIXME: temporarily disabling this option
3843
+ // const hold = this.session.hasEngineVersionGte(MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD);
3844
+
3845
+ return {
3846
+ accept: false,
3847
+ decline: true,
3848
+ mute: true,
3849
+ hold: false,
3850
+ transfer: true,
3851
+ sendKey: true,
3852
+ addParticipant: false,
3853
+ record: true,
3854
+ merge: false,
3855
+ };
3856
+ }
3857
+
3858
+ hasAnActiveCall() {
3859
+ return !!this.currentCall;
3860
+ }
3861
+
3862
+ callCount() {
3863
+ return this.currentCall ? 1 : 0;
3864
+ }
3865
+
3866
+ isWebRTC() {
3867
+ return false;
3868
+ }
3869
+
3870
+ getUserAgent() {
3871
+ return 'cti-phone';
3872
+ }
3873
+
3874
+ startHeartbeat() {
3875
+ }
3876
+
3877
+ setOnHeartbeatTimeout() {
3878
+ }
3879
+
3880
+ setOnHeartbeatCallback() {
3881
+ }
3882
+
3883
+ stopHeartbeat() {
3884
+ }
3885
+
3886
+ bindClientEvents() {
3887
+ }
3888
+
3889
+ onConnect() {
3890
+ }
3891
+
3892
+ onDisconnect() {
3893
+ }
3894
+
3895
+ async makeCall(number , line ) {
3896
+ logger$a.info('make CTI call', { number });
3897
+
3898
+ if (!number) {
3899
+ return null;
3900
+ }
3901
+ try {
3902
+ this.currentCall = await CallApi.makeCall(line, number, this.isMobile, this.callbackAllLines);
3903
+ } catch (_) {
3904
+ // We have to deal with error like `User has no mobile phone number` error in the UI.
3905
+ }
3906
+ if (!this.currentCall) {
3907
+ return null;
3908
+ }
3909
+ const callSession = CallSession.parseCall(this.currentCall);
3910
+ this.eventEmitter.emit('onCallOutgoing', callSession);
3911
+
3912
+ return callSession;
3913
+ }
3914
+
3915
+ accept(callSession ) {
3916
+ if (!callSession) {
3917
+ return Promise.resolve(null);
3918
+ }
3919
+ logger$a.info('accept CTI call', { callId: callSession.getId(), number: callSession.number });
3920
+
3921
+ if (!this.currentCall) {
3922
+ this.currentCall = callSession.call;
3923
+ }
3924
+
3925
+ return Promise.resolve(callSession.getId());
3926
+ }
3927
+
3928
+ endCurrentCall(callSession ) {
3929
+ if (!callSession) {
3930
+ return;
3931
+ }
3932
+ logger$a.info('end current CTI call', { callId: callSession.getId(), number: callSession.number });
3933
+
3934
+ this.currentCall = undefined;
3935
+ this.eventEmitter.emit('onCallEnded', callSession);
3936
+ }
3937
+
3938
+ async hangup(callSession ) {
3939
+ if (!callSession) {
3940
+ return Promise.resolve(false);
3941
+ }
3942
+ logger$a.info('hangup CTI call', { callId: callSession.getId(), number: callSession.number });
3943
+
3944
+ try {
3945
+ await CallApi.cancelCall(callSession);
3946
+ if (this.currentCall && callSession.callId === this.currentCall.id) {
3947
+ this.endCurrentCall(callSession);
3948
+ }
3949
+
3950
+ this.eventEmitter.emit('onCallEnded', callSession);
3951
+ return true;
3952
+ } catch (e) {
3953
+ logger$a.error('hangup CTI call, error', e);
3954
+
3955
+ this.eventEmitter.emit('onCallFailed', callSession);
3956
+ return false;
3957
+ }
3958
+ }
3959
+
3960
+ ignore() {}
3961
+
3962
+ async reject(callSession ) {
3963
+ if (!callSession) {
3964
+ return;
3965
+ }
3966
+ logger$a.info('reject CTI call', { callId: callSession.getId(), number: callSession.number });
3967
+
3968
+ await CallApi.cancelCall(callSession);
3969
+ this.eventEmitter.emit('onCallEnded', callSession);
3970
+ }
3971
+
3972
+ async transfer(callSession , number ) {
3973
+ if (!callSession) {
3974
+ return;
3975
+ }
3976
+ logger$a.info('transfer CTI call', { callId: callSession.getId(), number: callSession.number, to: number });
3977
+
3978
+ await CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_BLIND);
3979
+ }
3980
+
3981
+ indirectTransfer() {}
3982
+
3983
+ async initiateCTIIndirectTransfer(callSession , number ) {
3984
+ if (!callSession) {
3985
+ return;
3986
+ }
3987
+ logger$a.info('indirect CTI transfer', { callId: callSession.getId(), number: callSession.number, to: number });
3988
+
3989
+ return CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_ATTENDED);
3990
+ }
3991
+
3992
+ async cancelCTIIndirectTransfer(transferId ) {
3993
+ logger$a.info('cancel CTI transfer', { transferId });
3994
+
3995
+ return CallApi.cancelCallTransfer(transferId);
3996
+ }
3997
+
3998
+ async confirmCTIIndirectTransfer(transferId ) {
3999
+ logger$a.info('confirm CTI transfer', { transferId });
4000
+
4001
+ return CallApi.confirmCallTransfer(transferId);
4002
+ }
4003
+
4004
+ sendKey(callSession , digits ) {
4005
+ if (!callSession) {
4006
+ return;
4007
+ }
4008
+ logger$a.info('send CTI key', { callId: callSession.getId(), number: callSession.number, digits });
4009
+
4010
+ return CallApi.sendDTMF(callSession.callId, digits);
4011
+ }
4012
+
4013
+ onConnectionMade() {
4014
+ logger$a.info('on CTI connection made');
4015
+
4016
+ this.eventEmitter.emit('onCallAccepted');
4017
+ }
4018
+
4019
+ async close() {
4020
+ logger$a.info('CTI close');
4021
+
4022
+ return Promise.resolve();
4023
+ }
4024
+
4025
+ async hold(callSession ) {
4026
+ if (!callSession) {
4027
+ return;
4028
+ }
4029
+ logger$a.info('CTI hold', { callId: callSession.getId(), number: callSession.number });
4030
+
4031
+ return CallApi.hold(callSession.callId);
4032
+ }
4033
+
4034
+ async resume(callSession ) {
4035
+ if (!callSession) {
4036
+ return;
4037
+ }
4038
+ logger$a.info('CTI resume', { callId: callSession.getId(), number: callSession.number });
4039
+
4040
+ return CallApi.resume(callSession.callId);
4041
+ }
4042
+
4043
+ async mute(callSession ) {
4044
+ if (!callSession) {
4045
+ return;
4046
+ }
4047
+ logger$a.info('CTI mute', { callId: callSession.getId(), number: callSession.number });
4048
+
4049
+ return CallApi.mute(callSession.callId);
4050
+ }
4051
+
4052
+ async unmute(callSession ) {
4053
+ if (!callSession) {
4054
+ return;
4055
+ }
4056
+ logger$a.info('CTI unmute', { callId: callSession.getId(), number: callSession.number });
4057
+
4058
+ return CallApi.unmute(callSession.callId);
4059
+ }
4060
+
4061
+ putOnSpeaker() {}
4062
+
4063
+ putOffSpeaker() {}
4064
+
4065
+ turnCameraOff() {}
4066
+
4067
+ turnCameraOn() {}
4068
+
4069
+ changeAudioInputDevice() {}
4070
+
4071
+ changeVideoInputDevice() {}
4072
+
4073
+ changeAudioDevice() {}
4074
+
4075
+ changeRingDevice() {}
4076
+
4077
+ changeAudioVolume() {}
4078
+
4079
+ changeRingVolume() {}
4080
+
4081
+ hasVideo() {
4082
+ return false;
4083
+ }
4084
+
4085
+ getLocalStreamForCall() {
4086
+ return null;
4087
+ }
4088
+
4089
+ getRemoteStreamForCall() {
4090
+ return null;
4091
+ }
4092
+
4093
+ getLocalVideoStream() {
4094
+ return null;
4095
+ }
4096
+
4097
+ setActiveSipSession() {}
4098
+
4099
+ isRegistered() {
4100
+ return true;
4101
+ }
4102
+
4103
+ hasIncomingCallSession() {
4104
+ return true;
4105
+ }
4106
+
4107
+ hasActiveRemoteVideoStream() {
4108
+ return false;
4109
+ }
4110
+
4111
+ getCurrentCallSession() {
4112
+ return this.currentCall ? CallSession.parseCall(this.currentCall) : null;
4113
+ }
4114
+
4115
+ enableRinging() {}
4116
+
4117
+ sendMessage() {}
4118
+
4119
+ disableRinging() {}
4120
+
4121
+ getLocalStream() {
4122
+ return null;
4123
+ }
4124
+
4125
+ getRemoteStream() {
4126
+ return null;
4127
+ }
4128
+
4129
+ getRemoteVideoStream() {
4130
+ return null;
4131
+ }
4132
+
4133
+ getRemoteAudioStream() {
4134
+ return null;
4135
+ }
4136
+
4137
+ hasLocalVideo() {
4138
+ return false;
4139
+ }
4140
+
4141
+ useLocalVideoElement() {}
4142
+ }
3668
4143
 
3669
4144
  /* */
3670
4145
 
@@ -4699,6 +5174,10 @@ class ApiClient {
4699
5174
  this.fetchOptions = fetchOptions;
4700
5175
  this.client.setFetchOptions(fetchOptions);
4701
5176
  }
5177
+
5178
+ disableErrorLogging() {
5179
+ this.client.disableErrorLogging();
5180
+ }
4702
5181
  }
4703
5182
 
4704
5183
  /* eslint-disable dot-notation */
@@ -5240,23 +5719,6 @@ const areCandidateValid = (candidates ) =>
5240
5719
  getSrflxOrRelay(candidates)
5241
5720
  .length > 0;
5242
5721
 
5243
- const toggleVideoDirection = (sdp , direction ) => {
5244
- const parsedSdp = sdpParser.parse(sdp);
5245
- parsedSdp.media = parsedSdp.media.map(media => ({
5246
- ...media,
5247
- ...(media.type === 'video' ? { direction } : {}),
5248
- }));
5249
-
5250
- return sdpParser.write(parsedSdp);
5251
- };
5252
-
5253
- const deactivateVideoModifier = (rawDescription ) => {
5254
- const description = rawDescription;
5255
- description.sdp = toggleVideoDirection(description.sdp, 'inactive');
5256
-
5257
- return Promise.resolve(description);
5258
- };
5259
-
5260
5722
  const hasAnActiveVideo = (sdp ) => {
5261
5723
  if (!sdp) {
5262
5724
  return false;
@@ -5368,6 +5830,7 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5368
5830
  const iceRestart = options.offerOptions ? options.offerOptions.iceRestart : false;
5369
5831
 
5370
5832
  const isConference = options ? !!options.conference : false;
5833
+ const audioOnly = options ? !!options.audioOnly : false;
5371
5834
 
5372
5835
  // We should wait for ice when iceRestart (reinvite) or for the first invite
5373
5836
  // We shouldn't wait for ice when holding or resuming the call
@@ -5394,16 +5857,16 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5394
5857
  };
5395
5858
 
5396
5859
  return this.getLocalMediaStream(options)
5397
- .then(() => this.updateDirection(options, isConference))
5860
+ .then(() => this.updateDirection(options, isConference, audioOnly))
5398
5861
  .then(() => this.createDataChannel(options))
5399
5862
  .then(() => {
5400
- if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options)) {
5863
+ if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
5401
5864
  // Add a video an empty bundle to be able to replaceTrack when joining a conference without video
5402
5865
  this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5403
5866
  }
5404
5867
  })
5405
5868
  .then(() => this.createLocalOfferOrAnswer(options))
5406
- .then((sessionDescription) => this.setLocalSessionDescription(sessionDescription))
5869
+ .then(sessionDescription => this.setLocalSessionDescription(sessionDescription))
5407
5870
  .then(() => this.waitForIceGatheringComplete(iceRestart, iceTimeout))
5408
5871
  .then(() => this.getLocalSessionDescription())
5409
5872
  .then(description => {
@@ -5526,7 +5989,8 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5526
5989
  }
5527
5990
 
5528
5991
  // Overridden to send `inactive` in conference
5529
- updateDirection(options , isConference = false) {
5992
+ updateDirection(options , isConference = false,
5993
+ audioOnly = false) {
5530
5994
  if (this._peerConnection === undefined) {
5531
5995
  return Promise.reject(new Error('Peer connection closed.'));
5532
5996
  }
@@ -5541,14 +6005,17 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5541
6005
  // if we are stable, assume we are creating a local offer
5542
6006
  this.logger.debug('SessionDescriptionHandler.updateDirection - setting offer direction');
5543
6007
  // determine the direction to offer given the current direction and hold state
5544
- const directionToOffer = (currentDirection ) => {
6008
+ const directionToOffer = (currentDirection , transceiver /* RTCRtpTransceiver */) => {
5545
6009
  if (isConference) {
6010
+ if (audioOnly && transceiver.receiver.track && transceiver.receiver.track.kind === 'video') {
6011
+ return 'sendonly';
6012
+ }
5546
6013
  return options && options.hold ? 'sendonly' : 'sendrecv';
5547
6014
  }
5548
6015
 
5549
6016
  switch (currentDirection) {
5550
6017
  case 'inactive':
5551
- return options && options.hold ? 'inactive' : 'recvonly';
6018
+ return options && options.hold ? 'inactive' : (isConference && !audioOnly ? 'sendrecv' : 'recvonly');
5552
6019
  case 'recvonly':
5553
6020
  return options && options.hold ? 'inactive' : 'recvonly';
5554
6021
  case 'sendonly':
@@ -5564,7 +6031,7 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5564
6031
  // set the transceiver direction to the offer direction
5565
6032
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5566
6033
  if (transceiver.direction /* guarding, but should always be true */) {
5567
- const offerDirection = directionToOffer(transceiver.direction);
6034
+ const offerDirection = directionToOffer(transceiver.direction, transceiver);
5568
6035
  if (transceiver.direction !== offerDirection) {
5569
6036
  // eslint-disable-next-line no-param-reassign
5570
6037
  transceiver.direction = offerDirection;
@@ -5623,6 +6090,13 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5623
6090
  // set the transceiver direction to the answer direction
5624
6091
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5625
6092
  if (transceiver.direction /* guarding, but should always be true */) {
6093
+ const { receiver } = transceiver;
6094
+ if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
6095
+ // eslint-disable-next-line no-param-reassign
6096
+ transceiver.direction = 'inactive';
6097
+ return;
6098
+ }
6099
+
5626
6100
  if (transceiver.direction !== 'stopped' && transceiver.direction !== answerDirection) {
5627
6101
  // eslint-disable-next-line no-param-reassign
5628
6102
  transceiver.direction = answerDirection;
@@ -5661,8 +6135,8 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5661
6135
  }
5662
6136
  const sender = pc.getSenders().find((otherSender) => otherSender.track && otherSender.track.kind === kind);
5663
6137
 
5664
- // Do not reuse sender tracks in SFU
5665
- if (sender && !sfu) {
6138
+ // Do not reuse sender video tracks in SFU
6139
+ if (sender && (!sfu || newTrack.kind === 'audio')) {
5666
6140
  trackUpdates.push(
5667
6141
  new Promise((resolve) => {
5668
6142
  this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
@@ -6214,9 +6688,15 @@ class WebRTCClient extends Emitter {
6214
6688
 
6215
6689
  call(number , enableVideo , audioOnly = false, conference = false) {
6216
6690
  logger$7.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
6217
- const inviterOptions = {};
6691
+ const inviterOptions = {
6692
+ sessionDescriptionHandlerOptionsReInvite: {
6693
+ conference,
6694
+ audioOnly,
6695
+ },
6696
+ };
6697
+
6218
6698
  if (audioOnly) {
6219
- inviterOptions.sessionDescriptionHandlerModifiersReInvite = [deactivateVideoModifier];
6699
+ inviterOptions.sessionDescriptionHandlerModifiersReInvite = [stripVideo];
6220
6700
  }
6221
6701
 
6222
6702
  const session = new Inviter(this.userAgent, this._makeURI(number), inviterOptions);
@@ -6245,10 +6725,11 @@ class WebRTCClient extends Emitter {
6245
6725
  sessionDescriptionHandlerOptions: this.getMediaConfiguration(enableVideo || false, conference),
6246
6726
  };
6247
6727
 
6248
- inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6728
+ inviteOptions.sessionDescriptionHandlerOptions.audioOnly = audioOnly;
6249
6729
 
6730
+ inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6250
6731
  if (audioOnly) {
6251
- inviteOptions.sessionDescriptionHandlerModifiers.push(deactivateVideoModifier);
6732
+ inviteOptions.sessionDescriptionHandlerModifiers.push(stripVideo);
6252
6733
  }
6253
6734
 
6254
6735
  // Do not await invite here or we'll miss the Establishing state transition
@@ -6462,6 +6943,9 @@ class WebRTCClient extends Emitter {
6462
6943
  if (!this._isWeb()) {
6463
6944
  options.sessionDescriptionHandlerModifiers = [holdModifier];
6464
6945
  }
6946
+ options.sessionDescriptionHandlerOptions = {
6947
+ constraints: options.constraints,
6948
+ };
6465
6949
 
6466
6950
  // Send re-INVITE
6467
6951
  return session.invite(options);
@@ -6501,6 +6985,9 @@ class WebRTCClient extends Emitter {
6501
6985
  // (eg: holdModifier)
6502
6986
  options.sessionDescriptionHandlerModifiers = [];
6503
6987
  }
6988
+ options.sessionDescriptionHandlerOptions = {
6989
+ constraints: options.constraints,
6990
+ };
6504
6991
 
6505
6992
  // Send re-INVITE
6506
6993
  return session.invite(options);
@@ -6730,7 +7217,8 @@ class WebRTCClient extends Emitter {
6730
7217
  ? this.video.deviceId.exact : undefined;
6731
7218
  }
6732
7219
 
6733
- reinvite(sipSession , newConstraints = null, conference = false) {
7220
+ reinvite(sipSession , newConstraints = null, conference = false,
7221
+ audioOnly = false) {
6734
7222
  if (!sipSession) {
6735
7223
  return false;
6736
7224
  }
@@ -6740,16 +7228,17 @@ class WebRTCClient extends Emitter {
6740
7228
  }
6741
7229
 
6742
7230
  const wasMuted = this.isAudioMuted(sipSession);
6743
- // When upgrading to video, remove the `deactivateVideoModifier` modifiers
7231
+ // When upgrading to video, remove the `stripVideo` modifiers
6744
7232
  if (newConstraints && newConstraints.video) {
6745
7233
  const modifiers = sipSession.sessionDescriptionHandlerModifiersReInvite;
6746
7234
  sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers.filter(modifier =>
6747
- modifier !== deactivateVideoModifier);
7235
+ modifier !== stripVideo);
6748
7236
  }
6749
7237
 
6750
7238
  sipSession.sessionDescriptionHandlerOptionsReInvite = {
6751
7239
  ...sipSession.sessionDescriptionHandlerOptionsReInvite,
6752
7240
  conference,
7241
+ audioOnly,
6753
7242
  };
6754
7243
 
6755
7244
  const shouldDoVideo = newConstraints ? newConstraints.video : this.sessionWantsToDoVideo(sipSession);
@@ -6789,6 +7278,8 @@ class WebRTCClient extends Emitter {
6789
7278
  },
6790
7279
  sessionDescriptionHandlerOptions: {
6791
7280
  constraints,
7281
+ conference,
7282
+ audioOnly,
6792
7283
  offerOptions: {
6793
7284
  iceRestart: false,
6794
7285
  },
@@ -7248,6 +7739,8 @@ class WebRTCClient extends Emitter {
7248
7739
 
7249
7740
  // Invitation and Inviter extends Session
7250
7741
  _setupSession(session ) {
7742
+ const sipSessionId = this.getSipSessionId(session);
7743
+
7251
7744
  // When receiving an Invitation, the delegate is not defined.
7252
7745
  if (!session.delegate) {
7253
7746
  session.delegate = {};
@@ -7271,8 +7764,18 @@ class WebRTCClient extends Emitter {
7271
7764
  };
7272
7765
  };
7273
7766
 
7767
+ const oldInviteRequest = session.onInviteRequest.bind(session);
7768
+ let hadRemoteVideo = false;
7769
+
7770
+ // Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
7771
+ // Becase when `onInvite` is called we already got the video track
7772
+ session.onInviteRequest = (request) => {
7773
+ hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7774
+
7775
+ oldInviteRequest(request);
7776
+ };
7777
+
7274
7778
  session.delegate.onInvite = (request ) => {
7275
- const sipSessionId = this.getSipSessionId(session);
7276
7779
  let updatedCalleeName = null;
7277
7780
  let updatedNumber = null;
7278
7781
  if (session.assertedIdentity) {
@@ -7282,7 +7785,6 @@ class WebRTCClient extends Emitter {
7282
7785
  logger$7.info('re-invite received', { updatedCalleeName, updatedNumber });
7283
7786
 
7284
7787
  // Useful to know if it's a video upgrade or an unhold from a remote peer with a video stream
7285
- const hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7286
7788
 
7287
7789
  // Update SDP
7288
7790
  // Remote video is handled by the `track` event. Here we're dealing with video stream removal.
@@ -7332,7 +7834,7 @@ class WebRTCClient extends Emitter {
7332
7834
  }
7333
7835
 
7334
7836
  _isAudioOnly(session ) {
7335
- return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === deactivateVideoModifier);
7837
+ return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === stripVideo);
7336
7838
  }
7337
7839
 
7338
7840
  _setupMedias(session , newStream ) {
@@ -7705,9 +8207,14 @@ class WebRTCPhone extends Emitter {
7705
8207
  return true;
7706
8208
  }
7707
8209
 
7708
- async sendReinvite(callSession , constraints = null, conference = false) {
8210
+ async sendReinvite(callSession , constraints = null, conference = false,
8211
+ audioOnly = false) {
7709
8212
  const sipSession = this.findSipSession(callSession);
7710
- logger$6.info('WebRTC phone - send reinvite', { sessionId: sipSession ? sipSession.id : null, constraints });
8213
+ logger$6.info('WebRTC phone - send reinvite', {
8214
+ sessionId: sipSession ? sipSession.id : null,
8215
+ constraints,
8216
+ audioOnly,
8217
+ });
7711
8218
 
7712
8219
  if (!sipSession) {
7713
8220
  return null;
@@ -7733,7 +8240,7 @@ class WebRTCPhone extends Emitter {
7733
8240
  // Force reinvite in SDH
7734
8241
  sipSession.sessionDescriptionHandler.localMediaStreamConstraints = null;
7735
8242
 
7736
- return this.client.reinvite(sipSession, constraints, conference);
8243
+ return this.client.reinvite(sipSession, constraints, conference, audioOnly);
7737
8244
  }
7738
8245
 
7739
8246
  getUserAgent() {
@@ -7809,9 +8316,9 @@ class WebRTCPhone extends Emitter {
7809
8316
  }
7810
8317
 
7811
8318
  // Release local video stream when downgrading to audio
7812
- const localVideoStream = sipSession.sessionDescriptionHandler.localMediaStream;
8319
+ const localStream = sipSession.sessionDescriptionHandler.localMediaStream;
7813
8320
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7814
- const videoTracks = localVideoStream.getVideoTracks();
8321
+ const videoTracks = localStream.getVideoTracks();
7815
8322
 
7816
8323
  // Remove video senders
7817
8324
  pc.getSenders().filter(sender => sender.track && sender.track.kind === 'video').forEach(videoSender => {
@@ -7826,7 +8333,7 @@ class WebRTCPhone extends Emitter {
7826
8333
  videoTracks.forEach(videoTrack => {
7827
8334
  videoTrack.enabled = false;
7828
8335
  videoTrack.stop();
7829
- localVideoStream.removeTrack(videoTrack);
8336
+ localStream.removeTrack(videoTrack);
7830
8337
  });
7831
8338
 
7832
8339
  this._sendReinviteMessage(callSession, false);
@@ -7843,12 +8350,14 @@ class WebRTCPhone extends Emitter {
7843
8350
 
7844
8351
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7845
8352
  const shouldScreenShare = constraints && constraints.screen;
8353
+ const options = sipSession.sessionDescriptionHandlerOptionsReInvite;
8354
+ const wasAudioOnly = options && options.audioOnly;
7846
8355
 
7847
8356
  // Check if a video sender already exists
7848
8357
  let videoSender;
7849
8358
  if (isConference) {
7850
8359
  const trans = pc.getTransceivers().find(transceiver => transceiver.mid === '1');
7851
- videoSender = trans.sender;
8360
+ videoSender = trans ? trans.sender : null;
7852
8361
  } else {
7853
8362
  videoSender = pc.getSenders().find(sender => sender.track === null);
7854
8363
  }
@@ -7885,6 +8394,11 @@ class WebRTCPhone extends Emitter {
7885
8394
  this._onScreenSharing(newStream, sipSession, callSession, false);
7886
8395
  }
7887
8396
 
8397
+ // We have to reinvite to change the direction on the bundle when upgrading from an audioOnly conference
8398
+ if (isConference && wasAudioOnly) {
8399
+ return true;
8400
+ }
8401
+
7888
8402
  // No reinvite needed here
7889
8403
  return false;
7890
8404
  }
@@ -7969,7 +8483,7 @@ class WebRTCPhone extends Emitter {
7969
8483
  event.track.enabled = false;
7970
8484
  }
7971
8485
 
7972
- return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event);
8486
+ return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event, sipSession);
7973
8487
  };
7974
8488
 
7975
8489
  peerConnection.onremovestream = event => {
@@ -8025,14 +8539,11 @@ class WebRTCPhone extends Emitter {
8025
8539
  const targetCallSession = callSession || this.currentCallSession;
8026
8540
  const conference = this.isConference(targetCallSession);
8027
8541
 
8028
- if (this.currentScreenShare.sender && this.currentScreenShare.hadVideo) {
8029
- // When stopping screenshare and we had video before that, we have to re-upgrade
8030
- await this.sendReinvite(targetCallSession, { audio: false, video: true }, conference);
8031
- } else {
8032
- // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8033
- // We have to downgrade to audio.
8034
- await this.sendReinvite(targetCallSession, { audio: false, video: false }, conference);
8035
- }
8542
+ // When stopping screenshare and we had video before that, we have to re-upgrade
8543
+ // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8544
+ // We have to downgrade to audio.
8545
+ const screenshareStopped = this.currentScreenShare.sender && this.currentScreenShare.hadVideo;
8546
+ await this.sendReinvite(targetCallSession, { audio: false, video: screenshareStopped }, conference);
8036
8547
  }
8037
8548
  } catch (e) {
8038
8549
  console.warn(e);
@@ -8369,6 +8880,7 @@ class WebRTCPhone extends Emitter {
8369
8880
  }
8370
8881
  }
8371
8882
 
8883
+ // @Deprecated
8372
8884
  unhold(callSession , withEvent = true, isConference = false) {
8373
8885
  logger$6.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
8374
8886
 
@@ -9366,6 +9878,7 @@ class Phone extends Emitter {
9366
9878
  return this.phone && this.phone.hasLocalVideo(callSession);
9367
9879
  }
9368
9880
 
9881
+ // @Deprecated
9369
9882
  getLocalMediaStream(callSession ) {
9370
9883
  logger$5.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
9371
9884
 
@@ -9384,17 +9897,20 @@ class Phone extends Emitter {
9384
9897
  return this.phone ? this.phone.getRemoteVideoStream(callSession) : null;
9385
9898
  }
9386
9899
 
9900
+ // @Deprecated
9387
9901
  getRemoteStreamForCall(callSession ) {
9388
9902
  logger$5.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
9389
9903
  return this.getRemoteStream(callSession);
9390
9904
  }
9391
9905
 
9392
9906
  // Returns remote streams directly from the peerConnection
9907
+ // @Deprecated
9393
9908
  getRemoteStreamsForCall(callSession ) {
9394
- logger$5.warn('Phone.getRe is deprecated, use Phone.getLocalStream instead');
9909
+ logger$5.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
9395
9910
  return this.getLocalStream(callSession);
9396
9911
  }
9397
9912
 
9913
+ // @Deprecated
9398
9914
  getRemoteVideoStreamForCall(callSession ) {
9399
9915
  logger$5.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
9400
9916
 
@@ -10757,13 +11273,15 @@ class Room$1 extends Emitter {
10757
11273
  }
10758
11274
  });
10759
11275
 
10760
- this.on(this.ON_VIDEO_STREAM, (stream, streamId) => {
11276
+ this.on(this.ON_VIDEO_STREAM, (stream, streamId, event, sipSession) => {
10761
11277
  logger$1.info('on room video stream', { streamId });
10762
11278
 
11279
+ this._mapMsid(sipSession.body.body);
11280
+
10763
11281
  // ON_VIDEO_STREAM is called before PARTICIPANT_JOINED, so we have to keep stream in `_unassociatedVideoStreams`.
10764
11282
  this._unassociatedVideoStreams[streamId] = stream;
10765
11283
 
10766
- const callId = this._getCallIdFromStreamId(streamId);
11284
+ const callId = this._getCallIdFromTrackId(streamId);
10767
11285
  const participant = callId ? this._getParticipantFromCallId(callId) : null;
10768
11286
  if (participant) {
10769
11287
  this.__associateStreams(participant);
@@ -10807,11 +11325,12 @@ class Room$1 extends Emitter {
10807
11325
  const sdp = sdpParser.parse(rawSdp);
10808
11326
  const labelMsidArray = sdp.media.filter(media => !!media.label).map(({ label, msid }) => ({
10809
11327
  label: String(label),
10810
- msid: msid.split(' ')[1],
11328
+ streamId: msid.split(' ')[0],
11329
+ trackId: msid.split(' ')[1],
10811
11330
  }));
10812
11331
 
10813
- labelMsidArray.forEach(({ label, msid }) => {
10814
- this._callIdStreamIdMap[String(label)] = msid;
11332
+ labelMsidArray.forEach(({ label, streamId, trackId }) => {
11333
+ this._callIdStreamIdMap[String(label)] = { streamId, trackId };
10815
11334
 
10816
11335
  const callId = String(label);
10817
11336
  const participant = this._unassociatedParticipants[callId] || this._getParticipantFromCallId(callId);
@@ -11041,9 +11560,9 @@ class Room$1 extends Emitter {
11041
11560
  _onParticipantTrackUpdate(oldParticipant , update ) {
11042
11561
  const newParticipant = oldParticipant;
11043
11562
 
11044
- const label = this._callIdStreamIdMap[newParticipant.callId];
11563
+ const { trackId } = this._callIdStreamIdMap[newParticipant.callId] || {};
11045
11564
  const pc = Wazo.Phone.phone.currentSipSession.sessionDescriptionHandler.peerConnection;
11046
- const stream = pc.getRemoteStreams().find(otherStream => otherStream.getTracks().some(track => track.id === label));
11565
+ const stream = pc.getRemoteStreams().find(someStream => someStream.getTracks().some(track => track.id === trackId));
11047
11566
 
11048
11567
  if (update === 'downgrade') {
11049
11568
  newParticipant.streams = [];
@@ -11063,21 +11582,21 @@ class Room$1 extends Emitter {
11063
11582
 
11064
11583
  // Associate audio/video streams to the participant and triggers events on it
11065
11584
  __associateStreams(participant ) {
11066
- const streamId = this._callIdStreamIdMap[participant.callId];
11067
- if (!streamId) {
11585
+ const { trackId } = this._callIdStreamIdMap[participant.callId] || {};
11586
+ if (!trackId) {
11068
11587
  this._unassociatedParticipants[participant.callId] = participant;
11069
11588
 
11070
11589
  return;
11071
11590
  }
11072
- if (!streamId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
11591
+ if (!trackId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
11073
11592
  return;
11074
11593
  }
11075
11594
 
11076
- if (this._unassociatedVideoStreams[streamId]) {
11595
+ if (this._unassociatedVideoStreams[trackId]) {
11077
11596
  // Try to associate stream
11078
- this._associateStreamTo(this._unassociatedVideoStreams[streamId], participant);
11597
+ this._associateStreamTo(this._unassociatedVideoStreams[trackId], participant);
11079
11598
 
11080
- delete this._unassociatedVideoStreams[streamId];
11599
+ delete this._unassociatedVideoStreams[trackId];
11081
11600
  delete this._unassociatedParticipants[participant.callId];
11082
11601
  }
11083
11602
  }
@@ -11090,8 +11609,8 @@ class Room$1 extends Emitter {
11090
11609
  participant.onStreamSubscribed(stream);
11091
11610
  }
11092
11611
 
11093
- _getCallIdFromStreamId(streamId ) {
11094
- return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key] === streamId);
11612
+ _getCallIdFromTrackId(trackId ) {
11613
+ return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key].trackId === trackId);
11095
11614
  }
11096
11615
 
11097
11616
  _getParticipantFromCallId(callId ) {
@@ -11140,10 +11659,7 @@ class Stream {
11140
11659
  element.onloadedmetadata = () => {
11141
11660
  const tracks = this.htmlStream ? this.htmlStream.getVideoTracks() : [];
11142
11661
  tracks.forEach(track => {
11143
- // Do not re-enable the track if already mounted.
11144
- if (!track.loaded) {
11145
- track.enabled = true;
11146
- }
11662
+ track.enabled = true;
11147
11663
  // $FlowFixMe
11148
11664
  track.loaded = true;
11149
11665
  });
@@ -11584,6 +12100,7 @@ var api = {
11584
12100
  check: async (server, session) => {
11585
12101
  const client = new ApiClient({ server });
11586
12102
  client.setToken(session.token);
12103
+ client.disableErrorLogging();
11587
12104
 
11588
12105
  const handleApiError = (apiName, error) => {
11589
12106
  const statusText = error instanceof ServerError ? 'server error' : 'api error';
@@ -11658,6 +12175,8 @@ var aor = {
11658
12175
  check: async (server, session) => {
11659
12176
  const apiClient = new ApiClient({ server });
11660
12177
  apiClient.setToken(session.token);
12178
+ apiClient.disableErrorLogging();
12179
+
11661
12180
  const line = session.primaryWebRtcLine();
11662
12181
  if (!line) {
11663
12182
  return 'No WebRTC line for this user';
@@ -12080,6 +12599,8 @@ const Wazo = {
12080
12599
  ServerError,
12081
12600
  Call,
12082
12601
  CallLog,
12602
+ CTIPhone,
12603
+ Recording,
12083
12604
  ChatMessage,
12084
12605
  ChatRoom,
12085
12606
  Contact,
@@ -12094,6 +12615,7 @@ const Wazo = {
12094
12615
  CallSession,
12095
12616
  IndirectTransfer,
12096
12617
  SwitchboardCall,
12618
+ WebRTCPhone,
12097
12619
  },
12098
12620
 
12099
12621
  // Api