@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 */
@@ -4978,23 +5457,6 @@ const areCandidateValid = (candidates ) =>
4978
5457
  getSrflxOrRelay(candidates)
4979
5458
  .length > 0;
4980
5459
 
4981
- const toggleVideoDirection = (sdp , direction ) => {
4982
- const parsedSdp = sdpParser.parse(sdp);
4983
- parsedSdp.media = parsedSdp.media.map(media => ({
4984
- ...media,
4985
- ...(media.type === 'video' ? { direction } : {}),
4986
- }));
4987
-
4988
- return sdpParser.write(parsedSdp);
4989
- };
4990
-
4991
- const deactivateVideoModifier = (rawDescription ) => {
4992
- const description = rawDescription;
4993
- description.sdp = toggleVideoDirection(description.sdp, 'inactive');
4994
-
4995
- return Promise.resolve(description);
4996
- };
4997
-
4998
5460
  const hasAnActiveVideo = (sdp ) => {
4999
5461
  if (!sdp) {
5000
5462
  return false;
@@ -5106,6 +5568,7 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5106
5568
  const iceRestart = options.offerOptions ? options.offerOptions.iceRestart : false;
5107
5569
 
5108
5570
  const isConference = options ? !!options.conference : false;
5571
+ const audioOnly = options ? !!options.audioOnly : false;
5109
5572
 
5110
5573
  // We should wait for ice when iceRestart (reinvite) or for the first invite
5111
5574
  // We shouldn't wait for ice when holding or resuming the call
@@ -5132,16 +5595,16 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5132
5595
  };
5133
5596
 
5134
5597
  return this.getLocalMediaStream(options)
5135
- .then(() => this.updateDirection(options, isConference))
5598
+ .then(() => this.updateDirection(options, isConference, audioOnly))
5136
5599
  .then(() => this.createDataChannel(options))
5137
5600
  .then(() => {
5138
- if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options)) {
5601
+ if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
5139
5602
  // Add a video an empty bundle to be able to replaceTrack when joining a conference without video
5140
5603
  this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5141
5604
  }
5142
5605
  })
5143
5606
  .then(() => this.createLocalOfferOrAnswer(options))
5144
- .then((sessionDescription) => this.setLocalSessionDescription(sessionDescription))
5607
+ .then(sessionDescription => this.setLocalSessionDescription(sessionDescription))
5145
5608
  .then(() => this.waitForIceGatheringComplete(iceRestart, iceTimeout))
5146
5609
  .then(() => this.getLocalSessionDescription())
5147
5610
  .then(description => {
@@ -5264,7 +5727,8 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5264
5727
  }
5265
5728
 
5266
5729
  // Overridden to send `inactive` in conference
5267
- updateDirection(options , isConference = false) {
5730
+ updateDirection(options , isConference = false,
5731
+ audioOnly = false) {
5268
5732
  if (this._peerConnection === undefined) {
5269
5733
  return Promise.reject(new Error('Peer connection closed.'));
5270
5734
  }
@@ -5279,14 +5743,17 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5279
5743
  // if we are stable, assume we are creating a local offer
5280
5744
  this.logger.debug('SessionDescriptionHandler.updateDirection - setting offer direction');
5281
5745
  // determine the direction to offer given the current direction and hold state
5282
- const directionToOffer = (currentDirection ) => {
5746
+ const directionToOffer = (currentDirection , transceiver /* RTCRtpTransceiver */) => {
5283
5747
  if (isConference) {
5748
+ if (audioOnly && transceiver.receiver.track && transceiver.receiver.track.kind === 'video') {
5749
+ return 'sendonly';
5750
+ }
5284
5751
  return options && options.hold ? 'sendonly' : 'sendrecv';
5285
5752
  }
5286
5753
 
5287
5754
  switch (currentDirection) {
5288
5755
  case 'inactive':
5289
- return options && options.hold ? 'inactive' : 'recvonly';
5756
+ return options && options.hold ? 'inactive' : (isConference && !audioOnly ? 'sendrecv' : 'recvonly');
5290
5757
  case 'recvonly':
5291
5758
  return options && options.hold ? 'inactive' : 'recvonly';
5292
5759
  case 'sendonly':
@@ -5302,7 +5769,7 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5302
5769
  // set the transceiver direction to the offer direction
5303
5770
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5304
5771
  if (transceiver.direction /* guarding, but should always be true */) {
5305
- const offerDirection = directionToOffer(transceiver.direction);
5772
+ const offerDirection = directionToOffer(transceiver.direction, transceiver);
5306
5773
  if (transceiver.direction !== offerDirection) {
5307
5774
  // eslint-disable-next-line no-param-reassign
5308
5775
  transceiver.direction = offerDirection;
@@ -5361,6 +5828,13 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5361
5828
  // set the transceiver direction to the answer direction
5362
5829
  this._peerConnection.getTransceivers().forEach((transceiver) => {
5363
5830
  if (transceiver.direction /* guarding, but should always be true */) {
5831
+ const { receiver } = transceiver;
5832
+ if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
5833
+ // eslint-disable-next-line no-param-reassign
5834
+ transceiver.direction = 'inactive';
5835
+ return;
5836
+ }
5837
+
5364
5838
  if (transceiver.direction !== 'stopped' && transceiver.direction !== answerDirection) {
5365
5839
  // eslint-disable-next-line no-param-reassign
5366
5840
  transceiver.direction = answerDirection;
@@ -5399,8 +5873,8 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
5399
5873
  }
5400
5874
  const sender = pc.getSenders().find((otherSender) => otherSender.track && otherSender.track.kind === kind);
5401
5875
 
5402
- // Do not reuse sender tracks in SFU
5403
- if (sender && !sfu) {
5876
+ // Do not reuse sender video tracks in SFU
5877
+ if (sender && (!sfu || newTrack.kind === 'audio')) {
5404
5878
  trackUpdates.push(
5405
5879
  new Promise((resolve) => {
5406
5880
  this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
@@ -5952,9 +6426,15 @@ class WebRTCClient extends Emitter {
5952
6426
 
5953
6427
  call(number , enableVideo , audioOnly = false, conference = false) {
5954
6428
  logger$8.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
5955
- const inviterOptions = {};
6429
+ const inviterOptions = {
6430
+ sessionDescriptionHandlerOptionsReInvite: {
6431
+ conference,
6432
+ audioOnly,
6433
+ },
6434
+ };
6435
+
5956
6436
  if (audioOnly) {
5957
- inviterOptions.sessionDescriptionHandlerModifiersReInvite = [deactivateVideoModifier];
6437
+ inviterOptions.sessionDescriptionHandlerModifiersReInvite = [stripVideo];
5958
6438
  }
5959
6439
 
5960
6440
  const session = new Inviter(this.userAgent, this._makeURI(number), inviterOptions);
@@ -5983,10 +6463,11 @@ class WebRTCClient extends Emitter {
5983
6463
  sessionDescriptionHandlerOptions: this.getMediaConfiguration(enableVideo || false, conference),
5984
6464
  };
5985
6465
 
5986
- inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
6466
+ inviteOptions.sessionDescriptionHandlerOptions.audioOnly = audioOnly;
5987
6467
 
6468
+ inviteOptions.sessionDescriptionHandlerModifiers = [replaceLocalIpModifier];
5988
6469
  if (audioOnly) {
5989
- inviteOptions.sessionDescriptionHandlerModifiers.push(deactivateVideoModifier);
6470
+ inviteOptions.sessionDescriptionHandlerModifiers.push(stripVideo);
5990
6471
  }
5991
6472
 
5992
6473
  // Do not await invite here or we'll miss the Establishing state transition
@@ -6200,6 +6681,9 @@ class WebRTCClient extends Emitter {
6200
6681
  if (!this._isWeb()) {
6201
6682
  options.sessionDescriptionHandlerModifiers = [holdModifier];
6202
6683
  }
6684
+ options.sessionDescriptionHandlerOptions = {
6685
+ constraints: options.constraints,
6686
+ };
6203
6687
 
6204
6688
  // Send re-INVITE
6205
6689
  return session.invite(options);
@@ -6239,6 +6723,9 @@ class WebRTCClient extends Emitter {
6239
6723
  // (eg: holdModifier)
6240
6724
  options.sessionDescriptionHandlerModifiers = [];
6241
6725
  }
6726
+ options.sessionDescriptionHandlerOptions = {
6727
+ constraints: options.constraints,
6728
+ };
6242
6729
 
6243
6730
  // Send re-INVITE
6244
6731
  return session.invite(options);
@@ -6468,7 +6955,8 @@ class WebRTCClient extends Emitter {
6468
6955
  ? this.video.deviceId.exact : undefined;
6469
6956
  }
6470
6957
 
6471
- reinvite(sipSession , newConstraints = null, conference = false) {
6958
+ reinvite(sipSession , newConstraints = null, conference = false,
6959
+ audioOnly = false) {
6472
6960
  if (!sipSession) {
6473
6961
  return false;
6474
6962
  }
@@ -6478,16 +6966,17 @@ class WebRTCClient extends Emitter {
6478
6966
  }
6479
6967
 
6480
6968
  const wasMuted = this.isAudioMuted(sipSession);
6481
- // When upgrading to video, remove the `deactivateVideoModifier` modifiers
6969
+ // When upgrading to video, remove the `stripVideo` modifiers
6482
6970
  if (newConstraints && newConstraints.video) {
6483
6971
  const modifiers = sipSession.sessionDescriptionHandlerModifiersReInvite;
6484
6972
  sipSession.sessionDescriptionHandlerModifiersReInvite = modifiers.filter(modifier =>
6485
- modifier !== deactivateVideoModifier);
6973
+ modifier !== stripVideo);
6486
6974
  }
6487
6975
 
6488
6976
  sipSession.sessionDescriptionHandlerOptionsReInvite = {
6489
6977
  ...sipSession.sessionDescriptionHandlerOptionsReInvite,
6490
6978
  conference,
6979
+ audioOnly,
6491
6980
  };
6492
6981
 
6493
6982
  const shouldDoVideo = newConstraints ? newConstraints.video : this.sessionWantsToDoVideo(sipSession);
@@ -6527,6 +7016,8 @@ class WebRTCClient extends Emitter {
6527
7016
  },
6528
7017
  sessionDescriptionHandlerOptions: {
6529
7018
  constraints,
7019
+ conference,
7020
+ audioOnly,
6530
7021
  offerOptions: {
6531
7022
  iceRestart: false,
6532
7023
  },
@@ -6986,6 +7477,8 @@ class WebRTCClient extends Emitter {
6986
7477
 
6987
7478
  // Invitation and Inviter extends Session
6988
7479
  _setupSession(session ) {
7480
+ const sipSessionId = this.getSipSessionId(session);
7481
+
6989
7482
  // When receiving an Invitation, the delegate is not defined.
6990
7483
  if (!session.delegate) {
6991
7484
  session.delegate = {};
@@ -7009,8 +7502,18 @@ class WebRTCClient extends Emitter {
7009
7502
  };
7010
7503
  };
7011
7504
 
7505
+ const oldInviteRequest = session.onInviteRequest.bind(session);
7506
+ let hadRemoteVideo = false;
7507
+
7508
+ // Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
7509
+ // Becase when `onInvite` is called we already got the video track
7510
+ session.onInviteRequest = (request) => {
7511
+ hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7512
+
7513
+ oldInviteRequest(request);
7514
+ };
7515
+
7012
7516
  session.delegate.onInvite = (request ) => {
7013
- const sipSessionId = this.getSipSessionId(session);
7014
7517
  let updatedCalleeName = null;
7015
7518
  let updatedNumber = null;
7016
7519
  if (session.assertedIdentity) {
@@ -7020,7 +7523,6 @@ class WebRTCClient extends Emitter {
7020
7523
  logger$8.info('re-invite received', { updatedCalleeName, updatedNumber });
7021
7524
 
7022
7525
  // Useful to know if it's a video upgrade or an unhold from a remote peer with a video stream
7023
- const hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7024
7526
 
7025
7527
  // Update SDP
7026
7528
  // Remote video is handled by the `track` event. Here we're dealing with video stream removal.
@@ -7070,7 +7572,7 @@ class WebRTCClient extends Emitter {
7070
7572
  }
7071
7573
 
7072
7574
  _isAudioOnly(session ) {
7073
- return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === deactivateVideoModifier);
7575
+ return session.sessionDescriptionHandlerModifiersReInvite.find(modifier => modifier === stripVideo);
7074
7576
  }
7075
7577
 
7076
7578
  _setupMedias(session , newStream ) {
@@ -7443,9 +7945,14 @@ class WebRTCPhone extends Emitter {
7443
7945
  return true;
7444
7946
  }
7445
7947
 
7446
- async sendReinvite(callSession , constraints = null, conference = false) {
7948
+ async sendReinvite(callSession , constraints = null, conference = false,
7949
+ audioOnly = false) {
7447
7950
  const sipSession = this.findSipSession(callSession);
7448
- logger$7.info('WebRTC phone - send reinvite', { sessionId: sipSession ? sipSession.id : null, constraints });
7951
+ logger$7.info('WebRTC phone - send reinvite', {
7952
+ sessionId: sipSession ? sipSession.id : null,
7953
+ constraints,
7954
+ audioOnly,
7955
+ });
7449
7956
 
7450
7957
  if (!sipSession) {
7451
7958
  return null;
@@ -7471,7 +7978,7 @@ class WebRTCPhone extends Emitter {
7471
7978
  // Force reinvite in SDH
7472
7979
  sipSession.sessionDescriptionHandler.localMediaStreamConstraints = null;
7473
7980
 
7474
- return this.client.reinvite(sipSession, constraints, conference);
7981
+ return this.client.reinvite(sipSession, constraints, conference, audioOnly);
7475
7982
  }
7476
7983
 
7477
7984
  getUserAgent() {
@@ -7547,9 +8054,9 @@ class WebRTCPhone extends Emitter {
7547
8054
  }
7548
8055
 
7549
8056
  // Release local video stream when downgrading to audio
7550
- const localVideoStream = sipSession.sessionDescriptionHandler.localMediaStream;
8057
+ const localStream = sipSession.sessionDescriptionHandler.localMediaStream;
7551
8058
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7552
- const videoTracks = localVideoStream.getVideoTracks();
8059
+ const videoTracks = localStream.getVideoTracks();
7553
8060
 
7554
8061
  // Remove video senders
7555
8062
  pc.getSenders().filter(sender => sender.track && sender.track.kind === 'video').forEach(videoSender => {
@@ -7564,7 +8071,7 @@ class WebRTCPhone extends Emitter {
7564
8071
  videoTracks.forEach(videoTrack => {
7565
8072
  videoTrack.enabled = false;
7566
8073
  videoTrack.stop();
7567
- localVideoStream.removeTrack(videoTrack);
8074
+ localStream.removeTrack(videoTrack);
7568
8075
  });
7569
8076
 
7570
8077
  this._sendReinviteMessage(callSession, false);
@@ -7581,12 +8088,14 @@ class WebRTCPhone extends Emitter {
7581
8088
 
7582
8089
  const pc = sipSession.sessionDescriptionHandler.peerConnection;
7583
8090
  const shouldScreenShare = constraints && constraints.screen;
8091
+ const options = sipSession.sessionDescriptionHandlerOptionsReInvite;
8092
+ const wasAudioOnly = options && options.audioOnly;
7584
8093
 
7585
8094
  // Check if a video sender already exists
7586
8095
  let videoSender;
7587
8096
  if (isConference) {
7588
8097
  const trans = pc.getTransceivers().find(transceiver => transceiver.mid === '1');
7589
- videoSender = trans.sender;
8098
+ videoSender = trans ? trans.sender : null;
7590
8099
  } else {
7591
8100
  videoSender = pc.getSenders().find(sender => sender.track === null);
7592
8101
  }
@@ -7623,6 +8132,11 @@ class WebRTCPhone extends Emitter {
7623
8132
  this._onScreenSharing(newStream, sipSession, callSession, false);
7624
8133
  }
7625
8134
 
8135
+ // We have to reinvite to change the direction on the bundle when upgrading from an audioOnly conference
8136
+ if (isConference && wasAudioOnly) {
8137
+ return true;
8138
+ }
8139
+
7626
8140
  // No reinvite needed here
7627
8141
  return false;
7628
8142
  }
@@ -7707,7 +8221,7 @@ class WebRTCPhone extends Emitter {
7707
8221
  event.track.enabled = false;
7708
8222
  }
7709
8223
 
7710
- return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event);
8224
+ return this.eventEmitter.emit(ON_VIDEO_STREAM, stream, event.track.id, event, sipSession);
7711
8225
  };
7712
8226
 
7713
8227
  peerConnection.onremovestream = event => {
@@ -7763,14 +8277,11 @@ class WebRTCPhone extends Emitter {
7763
8277
  const targetCallSession = callSession || this.currentCallSession;
7764
8278
  const conference = this.isConference(targetCallSession);
7765
8279
 
7766
- if (this.currentScreenShare.sender && this.currentScreenShare.hadVideo) {
7767
- // When stopping screenshare and we had video before that, we have to re-upgrade
7768
- await this.sendReinvite(targetCallSession, { audio: false, video: true }, conference);
7769
- } else {
7770
- // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
7771
- // We have to downgrade to audio.
7772
- await this.sendReinvite(targetCallSession, { audio: false, video: false }, conference);
7773
- }
8280
+ // When stopping screenshare and we had video before that, we have to re-upgrade
8281
+ // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8282
+ // We have to downgrade to audio.
8283
+ const screenshareStopped = this.currentScreenShare.sender && this.currentScreenShare.hadVideo;
8284
+ await this.sendReinvite(targetCallSession, { audio: false, video: screenshareStopped }, conference);
7774
8285
  }
7775
8286
  } catch (e) {
7776
8287
  console.warn(e);
@@ -8107,6 +8618,7 @@ class WebRTCPhone extends Emitter {
8107
8618
  }
8108
8619
  }
8109
8620
 
8621
+ // @Deprecated
8110
8622
  unhold(callSession , withEvent = true, isConference = false) {
8111
8623
  logger$7.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
8112
8624
 
@@ -9104,6 +9616,7 @@ class Phone extends Emitter {
9104
9616
  return this.phone && this.phone.hasLocalVideo(callSession);
9105
9617
  }
9106
9618
 
9619
+ // @Deprecated
9107
9620
  getLocalMediaStream(callSession ) {
9108
9621
  logger$6.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
9109
9622
 
@@ -9122,17 +9635,20 @@ class Phone extends Emitter {
9122
9635
  return this.phone ? this.phone.getRemoteVideoStream(callSession) : null;
9123
9636
  }
9124
9637
 
9638
+ // @Deprecated
9125
9639
  getRemoteStreamForCall(callSession ) {
9126
9640
  logger$6.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
9127
9641
  return this.getRemoteStream(callSession);
9128
9642
  }
9129
9643
 
9130
9644
  // Returns remote streams directly from the peerConnection
9645
+ // @Deprecated
9131
9646
  getRemoteStreamsForCall(callSession ) {
9132
- logger$6.warn('Phone.getRe is deprecated, use Phone.getLocalStream instead');
9647
+ logger$6.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
9133
9648
  return this.getLocalStream(callSession);
9134
9649
  }
9135
9650
 
9651
+ // @Deprecated
9136
9652
  getRemoteVideoStreamForCall(callSession ) {
9137
9653
  logger$6.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
9138
9654
 
@@ -10495,13 +11011,15 @@ class Room$1 extends Emitter {
10495
11011
  }
10496
11012
  });
10497
11013
 
10498
- this.on(this.ON_VIDEO_STREAM, (stream, streamId) => {
11014
+ this.on(this.ON_VIDEO_STREAM, (stream, streamId, event, sipSession) => {
10499
11015
  logger$2.info('on room video stream', { streamId });
10500
11016
 
11017
+ this._mapMsid(sipSession.body.body);
11018
+
10501
11019
  // ON_VIDEO_STREAM is called before PARTICIPANT_JOINED, so we have to keep stream in `_unassociatedVideoStreams`.
10502
11020
  this._unassociatedVideoStreams[streamId] = stream;
10503
11021
 
10504
- const callId = this._getCallIdFromStreamId(streamId);
11022
+ const callId = this._getCallIdFromTrackId(streamId);
10505
11023
  const participant = callId ? this._getParticipantFromCallId(callId) : null;
10506
11024
  if (participant) {
10507
11025
  this.__associateStreams(participant);
@@ -10545,11 +11063,12 @@ class Room$1 extends Emitter {
10545
11063
  const sdp = sdpParser.parse(rawSdp);
10546
11064
  const labelMsidArray = sdp.media.filter(media => !!media.label).map(({ label, msid }) => ({
10547
11065
  label: String(label),
10548
- msid: msid.split(' ')[1],
11066
+ streamId: msid.split(' ')[0],
11067
+ trackId: msid.split(' ')[1],
10549
11068
  }));
10550
11069
 
10551
- labelMsidArray.forEach(({ label, msid }) => {
10552
- this._callIdStreamIdMap[String(label)] = msid;
11070
+ labelMsidArray.forEach(({ label, streamId, trackId }) => {
11071
+ this._callIdStreamIdMap[String(label)] = { streamId, trackId };
10553
11072
 
10554
11073
  const callId = String(label);
10555
11074
  const participant = this._unassociatedParticipants[callId] || this._getParticipantFromCallId(callId);
@@ -10779,9 +11298,9 @@ class Room$1 extends Emitter {
10779
11298
  _onParticipantTrackUpdate(oldParticipant , update ) {
10780
11299
  const newParticipant = oldParticipant;
10781
11300
 
10782
- const label = this._callIdStreamIdMap[newParticipant.callId];
11301
+ const { trackId } = this._callIdStreamIdMap[newParticipant.callId] || {};
10783
11302
  const pc = Wazo.Phone.phone.currentSipSession.sessionDescriptionHandler.peerConnection;
10784
- const stream = pc.getRemoteStreams().find(otherStream => otherStream.getTracks().some(track => track.id === label));
11303
+ const stream = pc.getRemoteStreams().find(someStream => someStream.getTracks().some(track => track.id === trackId));
10785
11304
 
10786
11305
  if (update === 'downgrade') {
10787
11306
  newParticipant.streams = [];
@@ -10801,21 +11320,21 @@ class Room$1 extends Emitter {
10801
11320
 
10802
11321
  // Associate audio/video streams to the participant and triggers events on it
10803
11322
  __associateStreams(participant ) {
10804
- const streamId = this._callIdStreamIdMap[participant.callId];
10805
- if (!streamId) {
11323
+ const { trackId } = this._callIdStreamIdMap[participant.callId] || {};
11324
+ if (!trackId) {
10806
11325
  this._unassociatedParticipants[participant.callId] = participant;
10807
11326
 
10808
11327
  return;
10809
11328
  }
10810
- if (!streamId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
11329
+ if (!trackId || !participant || !this.localParticipant || participant.callId === this.localParticipant.callId) {
10811
11330
  return;
10812
11331
  }
10813
11332
 
10814
- if (this._unassociatedVideoStreams[streamId]) {
11333
+ if (this._unassociatedVideoStreams[trackId]) {
10815
11334
  // Try to associate stream
10816
- this._associateStreamTo(this._unassociatedVideoStreams[streamId], participant);
11335
+ this._associateStreamTo(this._unassociatedVideoStreams[trackId], participant);
10817
11336
 
10818
- delete this._unassociatedVideoStreams[streamId];
11337
+ delete this._unassociatedVideoStreams[trackId];
10819
11338
  delete this._unassociatedParticipants[participant.callId];
10820
11339
  }
10821
11340
  }
@@ -10828,8 +11347,8 @@ class Room$1 extends Emitter {
10828
11347
  participant.onStreamSubscribed(stream);
10829
11348
  }
10830
11349
 
10831
- _getCallIdFromStreamId(streamId ) {
10832
- return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key] === streamId);
11350
+ _getCallIdFromTrackId(trackId ) {
11351
+ return Object.keys(this._callIdStreamIdMap).find(key => this._callIdStreamIdMap[key].trackId === trackId);
10833
11352
  }
10834
11353
 
10835
11354
  _getParticipantFromCallId(callId ) {
@@ -10878,10 +11397,7 @@ class Stream {
10878
11397
  element.onloadedmetadata = () => {
10879
11398
  const tracks = this.htmlStream ? this.htmlStream.getVideoTracks() : [];
10880
11399
  tracks.forEach(track => {
10881
- // Do not re-enable the track if already mounted.
10882
- if (!track.loaded) {
10883
- track.enabled = true;
10884
- }
11400
+ track.enabled = true;
10885
11401
  // $FlowFixMe
10886
11402
  track.loaded = true;
10887
11403
  });
@@ -11305,6 +11821,7 @@ var api = {
11305
11821
  check: async (server, session) => {
11306
11822
  const client = new ApiClient({ server });
11307
11823
  client.setToken(session.token);
11824
+ client.disableErrorLogging();
11308
11825
 
11309
11826
  const handleApiError = (apiName, error) => {
11310
11827
  const statusText = error instanceof ServerError ? 'server error' : 'api error';
@@ -11379,6 +11896,8 @@ var aor = {
11379
11896
  check: async (server, session) => {
11380
11897
  const apiClient = new ApiClient({ server });
11381
11898
  apiClient.setToken(session.token);
11899
+ apiClient.disableErrorLogging();
11900
+
11382
11901
  const line = session.primaryWebRtcLine();
11383
11902
  if (!line) {
11384
11903
  return 'No WebRTC line for this user';
@@ -11801,6 +12320,8 @@ const Wazo = {
11801
12320
  ServerError,
11802
12321
  Call,
11803
12322
  CallLog,
12323
+ CTIPhone,
12324
+ Recording,
11804
12325
  ChatMessage,
11805
12326
  ChatRoom,
11806
12327
  Contact,
@@ -11815,6 +12336,7 @@ const Wazo = {
11815
12336
  CallSession,
11816
12337
  IndirectTransfer,
11817
12338
  SwitchboardCall,
12339
+ WebRTCPhone,
11818
12340
  },
11819
12341
 
11820
12342
  // Api