@wazo/sdk 0.37.0 → 0.37.4

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 (144) hide show
  1. package/dist/wazo-sdk.js +5 -5
  2. package/esm/__tests__/api-client.test.js +91 -23
  3. package/esm/__tests__/web-rtc-client.test.js +165 -56
  4. package/esm/api/agentd.js +7 -1
  5. package/esm/api/amid.js +7 -1
  6. package/esm/api/application.js +7 -1
  7. package/esm/api/auth.js +7 -1
  8. package/esm/api/call-logd.js +17 -23
  9. package/esm/api/calld.js +10 -18
  10. package/esm/api/chatd.js +7 -1
  11. package/esm/api/confd.js +78 -1
  12. package/esm/api/ctid-ng.js +7 -1
  13. package/esm/api/dird.js +7 -1
  14. package/esm/api/webhookd.js +7 -1
  15. package/esm/api-client.js +91 -23
  16. package/esm/checker/Checker.js +169 -56
  17. package/esm/checker/checks/aor.js +91 -23
  18. package/esm/checker/checks/api.js +91 -23
  19. package/esm/checker/checks/index.js +169 -56
  20. package/esm/checker/checks/wazo-websocket.js +11 -1
  21. package/esm/checker/checks/webrtc-transport.js +165 -56
  22. package/esm/checker/checks/webrtc.js +165 -56
  23. package/esm/domain/AdHocAPIConference.js +1722 -1654
  24. package/esm/domain/CallLog.js +10 -22
  25. package/esm/domain/CallSession.js +1 -18
  26. package/esm/domain/Features.js +91 -23
  27. package/esm/domain/IndirectTransfer.js +0 -17
  28. package/esm/domain/Meeting.js +71 -0
  29. package/esm/domain/Phone/CTIPhone.js +98 -26
  30. package/esm/domain/Phone/Phone.js +0 -17
  31. package/esm/domain/Phone/WebRTCPhone.js +47 -27
  32. package/esm/domain/Room.js +0 -17
  33. package/esm/domain/SwitchboardCall.js +0 -17
  34. package/esm/domain/__tests__/CallLog.test.js +10 -22
  35. package/esm/domain/__tests__/CallSession.test.js +1 -18
  36. package/esm/domain/__tests__/IndirectTransfer.test.js +1 -18
  37. package/esm/domain/__tests__/Room.test.js +1 -18
  38. package/esm/index.js +3880 -3111
  39. package/esm/lib/WazoSessionDescriptionHandler.js +24 -10
  40. package/esm/service/CallApi.js +91 -23
  41. package/esm/service/IssueReporter.js +7 -1
  42. package/esm/service/__tests__/IssueReporter.test.js +9 -1
  43. package/esm/service/getApiClient.js +91 -23
  44. package/esm/simple/Auth.js +1126 -360
  45. package/esm/simple/Configuration.js +1126 -360
  46. package/esm/simple/Directory.js +91 -23
  47. package/esm/simple/Phone.js +3724 -2958
  48. package/esm/simple/Websocket.js +13 -1
  49. package/esm/simple/index.js +1128 -362
  50. package/esm/simple/room/LocalParticipant.js +1097 -331
  51. package/esm/simple/room/Participant.js +1097 -331
  52. package/esm/simple/room/RemoteParticipant.js +1097 -331
  53. package/esm/simple/room/Room.js +1097 -331
  54. package/esm/simple/room/SipRoom.js +12996 -0
  55. package/esm/simple/room/Stream.js +1128 -362
  56. package/esm/simple/room/__tests__/RemoteParticipant.test.js +5157 -4389
  57. package/esm/simple/utils.js +1128 -362
  58. package/esm/utils/__tests__/api-requester.test.js +7 -1
  59. package/esm/utils/api-requester.js +7 -1
  60. package/esm/web-rtc-client.js +165 -56
  61. package/esm/websocket-client.js +12 -2
  62. package/lib/__tests__/api-client.test.js +91 -23
  63. package/lib/__tests__/web-rtc-client.test.js +165 -56
  64. package/lib/api/agentd.js +7 -1
  65. package/lib/api/amid.js +7 -1
  66. package/lib/api/application.js +7 -1
  67. package/lib/api/auth.js +7 -1
  68. package/lib/api/call-logd.js +17 -23
  69. package/lib/api/calld.js +10 -18
  70. package/lib/api/chatd.js +7 -1
  71. package/lib/api/confd.js +78 -1
  72. package/lib/api/ctid-ng.js +7 -1
  73. package/lib/api/dird.js +7 -1
  74. package/lib/api/webhookd.js +7 -1
  75. package/lib/api-client.js +91 -23
  76. package/lib/checker/Checker.js +169 -56
  77. package/lib/checker/checks/aor.js +91 -23
  78. package/lib/checker/checks/api.js +91 -23
  79. package/lib/checker/checks/index.js +169 -56
  80. package/lib/checker/checks/wazo-websocket.js +11 -1
  81. package/lib/checker/checks/webrtc-transport.js +165 -56
  82. package/lib/checker/checks/webrtc.js +165 -56
  83. package/lib/domain/AdHocAPIConference.js +1722 -1654
  84. package/lib/domain/CallLog.js +10 -22
  85. package/lib/domain/CallSession.js +1 -18
  86. package/lib/domain/Features.js +91 -23
  87. package/lib/domain/IndirectTransfer.js +0 -17
  88. package/lib/domain/Meeting.js +73 -0
  89. package/lib/domain/Phone/CTIPhone.js +98 -26
  90. package/lib/domain/Phone/Phone.js +0 -16
  91. package/lib/domain/Phone/WebRTCPhone.js +47 -27
  92. package/lib/domain/Room.js +0 -17
  93. package/lib/domain/SwitchboardCall.js +0 -17
  94. package/lib/domain/__tests__/CallLog.test.js +10 -22
  95. package/lib/domain/__tests__/CallSession.test.js +1 -18
  96. package/lib/domain/__tests__/IndirectTransfer.test.js +1 -18
  97. package/lib/domain/__tests__/Room.test.js +1 -18
  98. package/lib/index.js +3880 -3111
  99. package/lib/lib/WazoSessionDescriptionHandler.js +24 -10
  100. package/lib/service/CallApi.js +91 -23
  101. package/lib/service/IssueReporter.js +7 -1
  102. package/lib/service/__tests__/IssueReporter.test.js +9 -1
  103. package/lib/service/getApiClient.js +91 -23
  104. package/lib/simple/Auth.js +1126 -360
  105. package/lib/simple/Configuration.js +1126 -360
  106. package/lib/simple/Directory.js +91 -23
  107. package/lib/simple/Phone.js +3724 -2958
  108. package/lib/simple/Websocket.js +13 -1
  109. package/lib/simple/index.js +1128 -362
  110. package/lib/simple/room/LocalParticipant.js +1097 -331
  111. package/lib/simple/room/Participant.js +1097 -331
  112. package/lib/simple/room/RemoteParticipant.js +1097 -331
  113. package/lib/simple/room/Room.js +1097 -331
  114. package/lib/simple/room/SipRoom.js +13006 -0
  115. package/lib/simple/room/Stream.js +1128 -362
  116. package/lib/simple/room/__tests__/RemoteParticipant.test.js +5157 -4389
  117. package/lib/simple/utils.js +1128 -362
  118. package/lib/utils/__tests__/api-requester.test.js +7 -1
  119. package/lib/utils/api-requester.js +7 -1
  120. package/lib/web-rtc-client.js +165 -56
  121. package/lib/websocket-client.js +13 -1
  122. package/package.json +1 -1
  123. package/src/api/calld.js +3 -0
  124. package/src/api/confd.js +13 -0
  125. package/src/domain/CallLog.js +10 -22
  126. package/src/domain/CallSession.js +1 -2
  127. package/src/domain/Meeting.js +59 -0
  128. package/src/domain/Phone/CTIPhone.js +6 -2
  129. package/src/domain/Phone/Phone.js +2 -0
  130. package/src/domain/Phone/WebRTCPhone.js +22 -8
  131. package/src/index.js +6 -0
  132. package/src/lib/WazoSessionDescriptionHandler.js +17 -9
  133. package/src/service/IssueReporter.js +7 -1
  134. package/src/service/__tests__/IssueReporter.test.js +2 -0
  135. package/src/simple/Phone.js +13 -4
  136. package/src/simple/index.js +8 -0
  137. package/src/simple/room/Participant.js +7 -0
  138. package/src/simple/room/Room.js +157 -79
  139. package/src/simple/room/SipRoom.js +147 -0
  140. package/src/simple/room/Stream.js +1 -3
  141. package/src/simple/room/__tests__/RemoteParticipant.test.js +3 -2
  142. package/src/types/WebSocketMessage.js +21 -0
  143. package/src/web-rtc-client.js +57 -24
  144. package/src/websocket-client.js +4 -0
@@ -138,7 +138,7 @@ const isMobile = () => typeof navigator !== 'undefined' && navigator.product ===
138
138
 
139
139
  const methods = ['head', 'get', 'post', 'put', 'delete'];
140
140
 
141
- const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
141
+ const logger$c = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
142
142
 
143
143
  // Use a function here to be able to mock it in tests
144
144
  const realFetch = () => {
@@ -277,7 +277,7 @@ class ApiRequester {
277
277
  };
278
278
 
279
279
  if (this.refreshTokenPromise) {
280
- logger$a.info('A token is already refreshing, waiting ...', { url });
280
+ logger$c.info('A token is already refreshing, waiting ...', { url });
281
281
  await this.refreshTokenPromise;
282
282
  }
283
283
 
@@ -297,7 +297,7 @@ class ApiRequester {
297
297
  return promise.then(async (err ) => {
298
298
  // Check if the token is still valid
299
299
  if (firstCall && this._checkTokenExpired(response, err)) {
300
- logger$a.warn('token expired', { error: err.reason });
300
+ logger$c.warn('token expired', { error: err.reason });
301
301
  // Replay the call after refreshing the token
302
302
  return this._replayWithNewToken(err, path, method, body, headers, parse);
303
303
  }
@@ -307,7 +307,7 @@ class ApiRequester {
307
307
  : exceptionClass.fromResponse(err, response.status);
308
308
 
309
309
  if (this.shouldLogErrors) {
310
- logger$a.error('API error', error);
310
+ logger$c.error('API error', error);
311
311
  }
312
312
 
313
313
  throw error;
@@ -317,7 +317,7 @@ class ApiRequester {
317
317
  return newParse(response, isJson);
318
318
  }).catch(error => {
319
319
  if (this.shouldLogErrors) {
320
- logger$a.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
320
+ logger$c.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
321
321
  }
322
322
 
323
323
  throw error;
@@ -345,13 +345,13 @@ class ApiRequester {
345
345
  ) {
346
346
  const isTokenNotFound = this._isTokenNotFound(err);
347
347
  let newPath = path;
348
- logger$a.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
348
+ logger$c.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
349
349
 
350
350
  this.refreshTokenPromise = this.refreshTokenPromise || this.refreshTokenCallback();
351
351
 
352
352
  return this.refreshTokenPromise.then(() => {
353
353
  this.refreshTokenPromise = null;
354
- logger$a.info('token refreshed', { isTokenNotFound });
354
+ logger$c.info('token refreshed', { isTokenNotFound });
355
355
  if (isTokenNotFound) {
356
356
  const pathParts = path.split('/');
357
357
  pathParts.pop();
@@ -629,7 +629,13 @@ class IssueReporter {
629
629
  }
630
630
 
631
631
  _isLevelAbove(level1 , level2 ) {
632
- return LOG_LEVELS.indexOf(level1) > LOG_LEVELS.indexOf(level2);
632
+ const index1 = LOG_LEVELS.indexOf(level1);
633
+ const index2 = LOG_LEVELS.indexOf(level2);
634
+ if (index1 === -1 || index2 === -1) {
635
+ return false;
636
+ }
637
+
638
+ return index1 > index2;
633
639
  }
634
640
 
635
641
  _makeCategory(category ) {
@@ -2542,6 +2548,65 @@ class ExternalApp {
2542
2548
  }
2543
2549
  }
2544
2550
 
2551
+ //
2552
+
2553
+
2554
+
2555
+
2556
+
2557
+
2558
+
2559
+
2560
+
2561
+
2562
+
2563
+ class Meeting {
2564
+
2565
+
2566
+
2567
+
2568
+
2569
+
2570
+
2571
+
2572
+
2573
+
2574
+ static parse(plain ) {
2575
+ return new Meeting({
2576
+ guestSipAuthorization: plain.guest_sip_authorization,
2577
+ hostname: plain.hostname,
2578
+ name: plain.name,
2579
+ ownerUuids: plain.owner_uuids,
2580
+ port: plain.port,
2581
+ uuid: plain.uuid,
2582
+ number: plain.number,
2583
+ });
2584
+ }
2585
+
2586
+ static newFrom(meeting ) {
2587
+ return newFrom(meeting, Meeting);
2588
+ }
2589
+
2590
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, hostname, number } = {}) {
2591
+ this.guestSipAuthorization = guestSipAuthorization;
2592
+ this.hostname = hostname;
2593
+ this.name = name;
2594
+ this.ownerUuids = ownerUuids;
2595
+ this.port = port;
2596
+ this.uuid = uuid;
2597
+ this.number = number;
2598
+
2599
+ // Useful to compare instead of instanceof with minified code
2600
+ this.type = 'Meeting';
2601
+ }
2602
+
2603
+ getGuestSipCredentials() {
2604
+ // eslint-disable-next-line no-undef
2605
+ const [username, secret] = atob(this.guestSipAuthorization).split(':');
2606
+ return { username, secret };
2607
+ }
2608
+ }
2609
+
2545
2610
  /* */
2546
2611
 
2547
2612
  var confdMethods = (client , baseUrl ) => ({
@@ -2606,6 +2671,18 @@ var confdMethods = (client , baseUrl ) => ({
2606
2671
  return null;
2607
2672
  }
2608
2673
  },
2674
+
2675
+ createMyMeeting: (name ) =>
2676
+ client.post(`${baseUrl}/users/me/meetings`, { name }).then(Meeting.parse),
2677
+
2678
+ deleteMyMeeting: (meetingUuid ) =>
2679
+ client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
2680
+
2681
+ getMeeting: (meetingUuid ) =>
2682
+ client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
2683
+
2684
+ guestGetMeeting: (meetingUuid ) =>
2685
+ client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
2609
2686
  });
2610
2687
 
2611
2688
  //
@@ -3363,7 +3440,7 @@ class CallSession {
3363
3440
  return newFrom(callSession, CallSession);
3364
3441
  }
3365
3442
 
3366
- static parseCall(session , call ) {
3443
+ static parseCall(call ) {
3367
3444
  return new CallSession({
3368
3445
  callId: call.id,
3369
3446
  sipCallId: call.sipCallId,
@@ -3522,7 +3599,11 @@ class CallLog {
3522
3599
  answered: plain.answered,
3523
3600
  callDirection: plain.call_direction,
3524
3601
  destination: {
3525
- extension: plain.requested_extension || plain.destination_extension,
3602
+ // @TEMP: Temporarily assuming empty numbers are meetings
3603
+ // which is admittedly a very dangerous assumption. Did i mention it was temporary?
3604
+ extension: plain.requested_extension
3605
+ || plain.destination_extension
3606
+ || `meeting-${plain.requested_name || plain.destination_name || ''}`,
3526
3607
  name: plain.requested_name || plain.destination_name || '',
3527
3608
  },
3528
3609
  source: {
@@ -3538,27 +3619,11 @@ class CallLog {
3538
3619
  }
3539
3620
 
3540
3621
  static parseNew(plain , session ) {
3541
- return new CallLog({
3542
- answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
3543
- answered: plain.answered,
3544
- callDirection: plain.call_direction,
3545
- destination: {
3546
- extension: plain.requested_extension || plain.destination_extension,
3547
- name: plain.requested_name || plain.destination_name || '',
3548
- },
3549
- source: {
3550
- extension: plain.source_extension,
3551
- name: plain.source_name,
3552
- },
3553
- id: plain.id,
3554
- duration: (plain.duration || 0) * 1000, // duration is in seconds
3555
- start: moment__default['default'](plain.start).toDate(),
3556
- end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3557
- recordings: Recording.parseMany(plain.recordings),
3558
- // @TODO: FIXME add verification declined vs missed call
3559
- newMissedCall: session
3560
- && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
3561
- });
3622
+ const callLog = CallLog.parse(plain);
3623
+ // @TODO: FIXME add verification declined vs missed call
3624
+ callLog.newMissedCall = session
3625
+ && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered;
3626
+ return callLog;
3562
3627
  }
3563
3628
 
3564
3629
  static newFrom(profile ) {
@@ -3718,29 +3783,432 @@ class IndirectTransfer {
3718
3783
  });
3719
3784
  }
3720
3785
 
3721
- destinationIs(callSession ) {
3722
- return callSession.isId(this.destinationId);
3786
+ destinationIs(callSession ) {
3787
+ return callSession.isId(this.destinationId);
3788
+ }
3789
+
3790
+ sourceIs(callSession ) {
3791
+ return callSession.isId(this.sourceId);
3792
+ }
3793
+
3794
+ updateFrom(indirectTransfer ) {
3795
+ updateFrom(this, indirectTransfer);
3796
+ }
3797
+
3798
+ static newFrom(indirectTransfer ) {
3799
+ return newFrom(indirectTransfer, IndirectTransfer);
3800
+ }
3801
+ }
3802
+
3803
+ //
3804
+
3805
+ class CallApi {
3806
+ static async fetchCallLogs(offset , limit ) {
3807
+ return getApiClient().callLogd.listCallLogs(offset, limit);
3808
+ }
3809
+
3810
+ static async fetchDistinctCallLogs(offset , limit , distinct = 'peer_exten') {
3811
+ return getApiClient().callLogd.listDistinctCallLogs(offset, limit, distinct);
3812
+ }
3813
+
3814
+ static async fetchActiveCalls() {
3815
+ return getApiClient().calld.listCalls();
3816
+ }
3817
+
3818
+ static async fetchCallLogsFromDate(from , number ) {
3819
+ return getApiClient().callLogd.listCallLogsFromDate(from, number);
3820
+ }
3821
+
3822
+ static async search(query , limit ) {
3823
+ return getApiClient().callLogd.search(query, limit);
3824
+ }
3825
+
3826
+ static async searchBy(field , value , limit ) {
3827
+ return getApiClient().callLogd.searchBy(field, value, limit);
3828
+ }
3829
+
3830
+ static async fetchSIP(session , line ) {
3831
+ const lineToUse = line || session.primaryLine();
3832
+ return getApiClient().confd.getUserLineSip(session.uuid, lineToUse ? lineToUse.id : null);
3833
+ }
3834
+
3835
+ static async cancelCall(callSession ) {
3836
+ return getApiClient().calld.cancelCall(callSession.callId);
3837
+ }
3838
+
3839
+ static async makeCall(callFromLine , extension , isMobile = false,
3840
+ callbackAllLines = false) {
3841
+ const lineId = callFromLine ? callFromLine.id : null;
3842
+
3843
+ const response = await getApiClient().calld.makeCall(extension, isMobile, lineId, callbackAllLines);
3844
+ return Call.parse(response);
3845
+ }
3846
+
3847
+ static async relocateCall(callId , line , contactIdentifier ) {
3848
+ return getApiClient().calld.relocateCall(callId, 'line', line, contactIdentifier);
3849
+ }
3850
+
3851
+ static async hold(callId ) {
3852
+ return getApiClient().calld.hold(callId);
3853
+ }
3854
+
3855
+ static async resume(callId ) {
3856
+ return getApiClient().calld.resume(callId);
3857
+ }
3858
+
3859
+ static async mute(callId ) {
3860
+ return getApiClient().calld.mute(callId);
3861
+ }
3862
+
3863
+ static async sendDTMF(callId , digits ) {
3864
+ return getApiClient().calld.sendDTMF(callId, digits);
3865
+ }
3866
+
3867
+ static async unmute(callId ) {
3868
+ return getApiClient().calld.unmute(callId);
3869
+ }
3870
+
3871
+ static async transferCall(callId , number , flow ) {
3872
+ return getApiClient().calld.transferCall(callId, number, flow);
3873
+ }
3874
+
3875
+ static async cancelCallTransfer(transferId ) {
3876
+ return getApiClient().calld.cancelCallTransfer(transferId);
3877
+ }
3878
+
3879
+ static async confirmCallTransfer(transferId ) {
3880
+ return getApiClient().calld.confirmCallTransfer(transferId);
3881
+ }
3882
+ }
3883
+
3884
+ //
3885
+
3886
+ const TRANSFER_FLOW_ATTENDED = 'attended';
3887
+ const TRANSFER_FLOW_BLIND = 'blind';
3888
+
3889
+ // const MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD = '20.11';
3890
+
3891
+ const logger$b = IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3892
+
3893
+ class CTIPhone extends Emitter {
3894
+
3895
+
3896
+
3897
+
3898
+
3899
+
3900
+
3901
+
3902
+ constructor(session , isMobile = false, callbackAllLines = false) {
3903
+ super();
3904
+ logger$b.info('CTI Phone created');
3905
+ this.session = session;
3906
+ this.isMobile = isMobile;
3907
+ this.callbackAllLines = callbackAllLines;
3908
+ }
3909
+
3910
+ getOptions() {
3911
+ // @FIXME: temporarily disabling this option
3912
+ // const hold = this.session.hasEngineVersionGte(MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD);
3913
+
3914
+ return {
3915
+ accept: false,
3916
+ decline: true,
3917
+ mute: true,
3918
+ hold: false,
3919
+ transfer: true,
3920
+ sendKey: true,
3921
+ addParticipant: false,
3922
+ record: true,
3923
+ merge: false,
3924
+ };
3925
+ }
3926
+
3927
+ hasAnActiveCall() {
3928
+ return !!this.currentCall;
3929
+ }
3930
+
3931
+ callCount() {
3932
+ return this.currentCall ? 1 : 0;
3933
+ }
3934
+
3935
+ isWebRTC() {
3936
+ return false;
3937
+ }
3938
+
3939
+ getUserAgent() {
3940
+ return 'cti-phone';
3941
+ }
3942
+
3943
+ startHeartbeat() {
3944
+ }
3945
+
3946
+ setOnHeartbeatTimeout() {
3947
+ }
3948
+
3949
+ setOnHeartbeatCallback() {
3950
+ }
3951
+
3952
+ stopHeartbeat() {
3953
+ }
3954
+
3955
+ bindClientEvents() {
3956
+ }
3957
+
3958
+ onConnect() {
3959
+ }
3960
+
3961
+ onDisconnect() {
3962
+ }
3963
+
3964
+ async makeCall(number , line ) {
3965
+ logger$b.info('make CTI call', { number });
3966
+
3967
+ if (!number) {
3968
+ return null;
3969
+ }
3970
+ try {
3971
+ this.currentCall = await CallApi.makeCall(line, number, this.isMobile, this.callbackAllLines);
3972
+ } catch (_) {
3973
+ // We have to deal with error like `User has no mobile phone number` error in the UI.
3974
+ }
3975
+ if (!this.currentCall) {
3976
+ return null;
3977
+ }
3978
+ const callSession = CallSession.parseCall(this.currentCall);
3979
+ this.eventEmitter.emit('onCallOutgoing', callSession);
3980
+
3981
+ return callSession;
3982
+ }
3983
+
3984
+ accept(callSession ) {
3985
+ if (!callSession) {
3986
+ return Promise.resolve(null);
3987
+ }
3988
+ logger$b.info('accept CTI call', { callId: callSession.getId(), number: callSession.number });
3989
+
3990
+ if (!this.currentCall) {
3991
+ this.currentCall = callSession.call;
3992
+ }
3993
+
3994
+ return Promise.resolve(callSession.getId());
3995
+ }
3996
+
3997
+ endCurrentCall(callSession ) {
3998
+ if (!callSession) {
3999
+ return;
4000
+ }
4001
+ logger$b.info('end current CTI call', { callId: callSession.getId(), number: callSession.number });
4002
+
4003
+ this.currentCall = undefined;
4004
+ this.eventEmitter.emit('onCallEnded', callSession);
4005
+ }
4006
+
4007
+ async hangup(callSession ) {
4008
+ if (!callSession) {
4009
+ return Promise.resolve(false);
4010
+ }
4011
+ logger$b.info('hangup CTI call', { callId: callSession.getId(), number: callSession.number });
4012
+
4013
+ try {
4014
+ await CallApi.cancelCall(callSession);
4015
+ if (this.currentCall && callSession.callId === this.currentCall.id) {
4016
+ this.endCurrentCall(callSession);
4017
+ }
4018
+
4019
+ this.eventEmitter.emit('onCallEnded', callSession);
4020
+ return true;
4021
+ } catch (e) {
4022
+ logger$b.error('hangup CTI call, error', e);
4023
+
4024
+ this.eventEmitter.emit('onCallFailed', callSession);
4025
+ return false;
4026
+ }
4027
+ }
4028
+
4029
+ ignore() {}
4030
+
4031
+ async reject(callSession ) {
4032
+ if (!callSession) {
4033
+ return;
4034
+ }
4035
+ logger$b.info('reject CTI call', { callId: callSession.getId(), number: callSession.number });
4036
+
4037
+ await CallApi.cancelCall(callSession);
4038
+ this.eventEmitter.emit('onCallEnded', callSession);
4039
+ }
4040
+
4041
+ async transfer(callSession , number ) {
4042
+ if (!callSession) {
4043
+ return;
4044
+ }
4045
+ logger$b.info('transfer CTI call', { callId: callSession.getId(), number: callSession.number, to: number });
4046
+
4047
+ await CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_BLIND);
4048
+ }
4049
+
4050
+ indirectTransfer() {}
4051
+
4052
+ async initiateCTIIndirectTransfer(callSession , number ) {
4053
+ if (!callSession) {
4054
+ return;
4055
+ }
4056
+ logger$b.info('indirect CTI transfer', { callId: callSession.getId(), number: callSession.number, to: number });
4057
+
4058
+ return CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_ATTENDED);
4059
+ }
4060
+
4061
+ async cancelCTIIndirectTransfer(transferId ) {
4062
+ logger$b.info('cancel CTI transfer', { transferId });
4063
+
4064
+ return CallApi.cancelCallTransfer(transferId);
4065
+ }
4066
+
4067
+ async confirmCTIIndirectTransfer(transferId ) {
4068
+ logger$b.info('confirm CTI transfer', { transferId });
4069
+
4070
+ return CallApi.confirmCallTransfer(transferId);
4071
+ }
4072
+
4073
+ sendKey(callSession , digits ) {
4074
+ if (!callSession) {
4075
+ return;
4076
+ }
4077
+ logger$b.info('send CTI key', { callId: callSession.getId(), number: callSession.number, digits });
4078
+
4079
+ return CallApi.sendDTMF(callSession.callId, digits);
4080
+ }
4081
+
4082
+ onConnectionMade() {
4083
+ logger$b.info('on CTI connection made');
4084
+
4085
+ this.eventEmitter.emit('onCallAccepted');
4086
+ }
4087
+
4088
+ async close() {
4089
+ logger$b.info('CTI close');
4090
+
4091
+ return Promise.resolve();
4092
+ }
4093
+
4094
+ async hold(callSession ) {
4095
+ if (!callSession) {
4096
+ return;
4097
+ }
4098
+ logger$b.info('CTI hold', { callId: callSession.getId(), number: callSession.number });
4099
+
4100
+ return CallApi.hold(callSession.callId);
4101
+ }
4102
+
4103
+ async resume(callSession ) {
4104
+ if (!callSession) {
4105
+ return;
4106
+ }
4107
+ logger$b.info('CTI resume', { callId: callSession.getId(), number: callSession.number });
4108
+
4109
+ return CallApi.resume(callSession.callId);
4110
+ }
4111
+
4112
+ async mute(callSession ) {
4113
+ if (!callSession) {
4114
+ return;
4115
+ }
4116
+ logger$b.info('CTI mute', { callId: callSession.getId(), number: callSession.number });
4117
+
4118
+ return CallApi.mute(callSession.callId);
4119
+ }
4120
+
4121
+ async unmute(callSession ) {
4122
+ if (!callSession) {
4123
+ return;
4124
+ }
4125
+ logger$b.info('CTI unmute', { callId: callSession.getId(), number: callSession.number });
4126
+
4127
+ return CallApi.unmute(callSession.callId);
4128
+ }
4129
+
4130
+ putOnSpeaker() {}
4131
+
4132
+ putOffSpeaker() {}
4133
+
4134
+ turnCameraOff() {}
4135
+
4136
+ turnCameraOn() {}
4137
+
4138
+ changeAudioInputDevice() {}
4139
+
4140
+ changeVideoInputDevice() {}
4141
+
4142
+ changeAudioDevice() {}
4143
+
4144
+ changeRingDevice() {}
4145
+
4146
+ changeAudioVolume() {}
4147
+
4148
+ changeRingVolume() {}
4149
+
4150
+ hasVideo() {
4151
+ return false;
4152
+ }
4153
+
4154
+ getLocalStreamForCall() {
4155
+ return null;
4156
+ }
4157
+
4158
+ getRemoteStreamForCall() {
4159
+ return null;
4160
+ }
4161
+
4162
+ getLocalVideoStream() {
4163
+ return null;
4164
+ }
4165
+
4166
+ setActiveSipSession() {}
4167
+
4168
+ isRegistered() {
4169
+ return true;
4170
+ }
4171
+
4172
+ hasIncomingCallSession() {
4173
+ return true;
4174
+ }
4175
+
4176
+ hasActiveRemoteVideoStream() {
4177
+ return false;
4178
+ }
4179
+
4180
+ getCurrentCallSession() {
4181
+ return this.currentCall ? CallSession.parseCall(this.currentCall) : null;
3723
4182
  }
3724
4183
 
3725
- sourceIs(callSession ) {
3726
- return callSession.isId(this.sourceId);
4184
+ enableRinging() {}
4185
+
4186
+ sendMessage() {}
4187
+
4188
+ disableRinging() {}
4189
+
4190
+ getLocalStream() {
4191
+ return null;
3727
4192
  }
3728
4193
 
3729
- updateFrom(indirectTransfer ) {
3730
- updateFrom(this, indirectTransfer);
4194
+ getRemoteStream() {
4195
+ return null;
3731
4196
  }
3732
4197
 
3733
- static newFrom(indirectTransfer ) {
3734
- return newFrom(indirectTransfer, IndirectTransfer);
4198
+ getRemoteVideoStream() {
4199
+ return null;
3735
4200
  }
3736
- }
3737
4201
 
3738
- //
3739
- const TRANSFER_FLOW_BLIND = 'blind';
4202
+ getRemoteAudioStream() {
4203
+ return null;
4204
+ }
3740
4205
 
3741
- // const MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD = '20.11';
4206
+ hasLocalVideo() {
4207
+ return false;
4208
+ }
3742
4209
 
3743
- IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
4210
+ useLocalVideoElement() {}
4211
+ }
3744
4212
 
3745
4213
  /* */
3746
4214
 
@@ -4300,6 +4768,9 @@ var calldMethods = (client , baseUrl ) => ({
4300
4768
  getConferenceParticipantsAsUser: async (conferenceId ) =>
4301
4769
  client.get(`${baseUrl}/users/me/conferences/${conferenceId}/participants`),
4302
4770
 
4771
+ getMeetingParticipantsAsUser: async (meetingUuid ) =>
4772
+ client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
4773
+
4303
4774
  listTrunks: () => client.get(`${baseUrl}/trunks`),
4304
4775
 
4305
4776
  mute: (callId ) =>
@@ -4653,7 +5124,7 @@ const AGENTD_VERSION = '1.0';
4653
5124
  const WEBHOOKD_VERSION = '1.0';
4654
5125
  const AMID_VERSION = '1.0';
4655
5126
 
4656
- const logger$9 = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
5127
+ const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
4657
5128
 
4658
5129
  class ApiClient {
4659
5130
 
@@ -4705,12 +5176,12 @@ class ApiClient {
4705
5176
  }
4706
5177
 
4707
5178
  async forceRefreshToken() {
4708
- logger$9.info('forcing refresh token, calling callback');
5179
+ logger$a.info('forcing refresh token, calling callback');
4709
5180
  return this.refreshTokenCallback();
4710
5181
  }
4711
5182
 
4712
5183
  async refreshTokenCallback() {
4713
- logger$9.info('refresh token callback called', {
5184
+ logger$a.info('refresh token callback called', {
4714
5185
  refreshToken: this.refreshToken,
4715
5186
  refreshBackend: this.refreshBackend,
4716
5187
  refreshExpiration: this.refreshExpiration,
@@ -4728,7 +5199,7 @@ class ApiClient {
4728
5199
  this.isMobile,
4729
5200
  );
4730
5201
 
4731
- logger$9.info('token refreshed', { token: session.token });
5202
+ logger$a.info('token refreshed', { token: session.token });
4732
5203
 
4733
5204
  if (this.onRefreshToken) {
4734
5205
  this.onRefreshToken(session.token, session);
@@ -4869,7 +5340,7 @@ var getApiClient = (forServer ) => {
4869
5340
  class InvalidSubscription extends Error {}
4870
5341
  class InvalidAuthorization extends Error {}
4871
5342
 
4872
- const logger$8 = IssueReporter$1.loggerFor('simple-auth');
5343
+ const logger$9 = IssueReporter$1.loggerFor('simple-auth');
4873
5344
 
4874
5345
  class Auth {
4875
5346
 
@@ -4904,7 +5375,7 @@ class Auth {
4904
5375
  setApiClientId(this.clientId);
4905
5376
  setRefreshExpiration(this.expiration);
4906
5377
  setOnRefreshToken((token , session ) => {
4907
- logger$8.info('on refresh token done', { token });
5378
+ logger$9.info('on refresh token done', { token });
4908
5379
  setApiToken(token);
4909
5380
  Wazo.Websocket.updateToken(token);
4910
5381
 
@@ -5463,7 +5934,9 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5463
5934
  .then(() => {
5464
5935
  if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
5465
5936
  // Add a video an empty bundle to be able to replaceTrack when joining a conference without video
5466
- this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5937
+ if (this.peerConnection.addTransceiver) {
5938
+ this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5939
+ }
5467
5940
  }
5468
5941
  })
5469
5942
  .then(() => this.createLocalOfferOrAnswer(options))
@@ -5490,12 +5963,6 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5490
5963
  };
5491
5964
  })
5492
5965
  .then((sessionDescription) => this.applyModifiers(sessionDescription, modifiers))
5493
- .then((sessionDescription) => {
5494
- // Set new constraints to avoid the constraints check issue in `sdh.getLocalMediaStream` later.
5495
- this.localMediaStreamConstraints = options.constraints;
5496
-
5497
- return sessionDescription;
5498
- })
5499
5966
  .then((sessionDescription) => ({ body: sessionDescription.sdp, contentType: 'application/sdp' }))
5500
5967
  .catch((error) => {
5501
5968
  wazoLogger.error('error when creating media', error);
@@ -5690,6 +6157,9 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5690
6157
 
5691
6158
  // set the transceiver direction to the answer direction
5692
6159
  this._peerConnection.getTransceivers().forEach((transceiver) => {
6160
+ if (transceiver.stopped) {
6161
+ return;
6162
+ }
5693
6163
  if (transceiver.direction /* guarding, but should always be true */) {
5694
6164
  const { receiver } = transceiver;
5695
6165
  if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
@@ -5734,10 +6204,15 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5734
6204
  if (kind !== 'audio' && kind !== 'video') {
5735
6205
  throw new Error(`Unknown new track kind ${kind}.`);
5736
6206
  }
5737
- const sender = pc.getSenders().find((otherSender) => otherSender.track && otherSender.track.kind === kind);
6207
+ const sender = pc.getSenders && pc.getSenders().find((otherSender) =>
6208
+ otherSender.track && otherSender.track.kind === kind);
5738
6209
 
5739
6210
  // Do not reuse sender video tracks in SFU
5740
6211
  if (sender && (!sfu || newTrack.kind === 'audio')) {
6212
+ if (sender.track) {
6213
+ // eslint-disable-next-line no-param-reassign
6214
+ newTrack.enabled = sender.track.enabled;
6215
+ }
5741
6216
  trackUpdates.push(
5742
6217
  new Promise((resolve) => {
5743
6218
  this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
@@ -5771,7 +6246,11 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5771
6246
  // Review: could make streamless tracks a configurable option?
5772
6247
  // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addTrack#Usage_notes
5773
6248
  try {
5774
- pc.addTrack(newTrack, localStream);
6249
+ if (pc.addTrack) {
6250
+ pc.addTrack(newTrack, localStream);
6251
+ } else {
6252
+ pc.addStream(localStream);
6253
+ }
5775
6254
  } catch (error) {
5776
6255
  this.logger.error(`SessionDescriptionHandler.setLocalMediaStream - failed to add sender ${kind} track`);
5777
6256
  throw error;
@@ -5907,7 +6386,7 @@ const DEFAULT_ICE_TIMEOUT = 3000;
5907
6386
  const SEND_STATS_DELAY = 5000;
5908
6387
 
5909
6388
  const states = ['STATUS_NULL', 'STATUS_NEW', 'STATUS_CONNECTING', 'STATUS_CONNECTED', 'STATUS_COMPLETED'];
5910
- const logger$7 = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-client') : console;
6389
+ const logger$8 = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-client') : console;
5911
6390
  const statsLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-stats') : console;
5912
6391
 
5913
6392
  // events
@@ -5953,6 +6432,7 @@ const MAX_REGISTER_TRIES = 10;
5953
6432
 
5954
6433
 
5955
6434
 
6435
+
5956
6436
 
5957
6437
 
5958
6438
 
@@ -5979,6 +6459,7 @@ class WebRTCClient extends Emitter {
5979
6459
 
5980
6460
 
5981
6461
 
6462
+
5982
6463
 
5983
6464
  // sugar
5984
6465
 
@@ -6017,6 +6498,8 @@ class WebRTCClient extends Emitter {
6017
6498
  super();
6018
6499
  this.uaConfigOverrides = uaConfigOverrides;
6019
6500
  this.config = config;
6501
+ this.skipRegister = config.skipRegister;
6502
+
6020
6503
  this._buildConfig(config, session).then((newConfig ) => {
6021
6504
  this.config = newConfig;
6022
6505
  this.userAgent = this.createUserAgent(uaConfigOverrides);
@@ -6072,13 +6555,13 @@ class WebRTCClient extends Emitter {
6072
6555
 
6073
6556
  createUserAgent(configOverrides ) {
6074
6557
  const webRTCConfiguration = this._createWebRTCConfiguration(configOverrides);
6075
- logger$7.info('sdk webrtc, creating UA', { webRTCConfiguration });
6558
+ logger$8.info('sdk webrtc, creating UA', { webRTCConfiguration });
6076
6559
 
6077
6560
  webRTCConfiguration.delegate = {
6078
6561
  onConnect: this.onConnect.bind(this),
6079
6562
  onDisconnect: this.onDisconnect.bind(this),
6080
6563
  onInvite: (invitation ) => {
6081
- logger$7.info('sdk webrtc on invite', {
6564
+ logger$8.info('sdk webrtc on invite', {
6082
6565
  method: 'delegate.onInvite',
6083
6566
  id: invitation.id,
6084
6567
  remoteURI: invitation.remoteURI,
@@ -6121,7 +6604,7 @@ class WebRTCClient extends Emitter {
6121
6604
  }
6122
6605
 
6123
6606
  onConnect() {
6124
- logger$7.info('sdk webrtc connected', { method: 'delegate.onConnect' });
6607
+ logger$8.info('sdk webrtc connected', { method: 'delegate.onConnect' });
6125
6608
  this.eventEmitter.emit(CONNECTED);
6126
6609
  if (!this.isRegistered() && this.registerer && this.registerer.waiting) {
6127
6610
  this.registerer.waitingToggle(false);
@@ -6130,7 +6613,7 @@ class WebRTCClient extends Emitter {
6130
6613
  }
6131
6614
 
6132
6615
  async onDisconnect(error ) {
6133
- logger$7.info('sdk webrtc disconnected', { method: 'delegate.onConnect', error });
6616
+ logger$8.info('sdk webrtc disconnected', { method: 'delegate.onConnect', error });
6134
6617
  this.connectionPromise = null;
6135
6618
  // The UA will attempt to reconnect automatically when an error occurred
6136
6619
  this.eventEmitter.emit(DISCONNECTED, error);
@@ -6144,40 +6627,48 @@ class WebRTCClient extends Emitter {
6144
6627
  }
6145
6628
 
6146
6629
  register(tries = 0) {
6147
- logger$7.info('sdk webrtc registering...', {
6630
+ const logInfo = {
6148
6631
  userAgent: !!this.userAgent,
6149
6632
  registered: this.isRegistered(),
6150
6633
  connectionPromise: !!this.connectionPromise,
6151
6634
  registerer: !!this.registerer,
6152
6635
  waiting: this.registerer && this.registerer.waiting,
6153
6636
  tries,
6154
- });
6637
+ skipRegister: this.skipRegister,
6638
+ };
6639
+
6640
+ if (this.skipRegister) {
6641
+ logger$8.info('sdk webrtc skip register...', logInfo);
6642
+ return Promise.resolve();
6643
+ }
6644
+
6645
+ logger$8.info('sdk webrtc registering...', logInfo);
6155
6646
 
6156
6647
  if (!this.userAgent) {
6157
- logger$7.info('sdk webrtc recreating User Agent');
6648
+ logger$8.info('sdk webrtc recreating User Agent');
6158
6649
  this.userAgent = this.createUserAgent(this.uaConfigOverrides);
6159
6650
  }
6160
6651
  if (!this.userAgent || this.isRegistered()) {
6161
- logger$7.info('sdk webrtc registering aborted, already registered or no UA can be created');
6652
+ logger$8.info('sdk webrtc registering aborted, already registered or no UA can be created');
6162
6653
  return Promise.resolve();
6163
6654
  }
6164
6655
 
6165
6656
  if (this.connectionPromise || (this.registerer && this.registerer.waiting)) {
6166
- logger$7.info('sdk webrtc registering aborted due to a registration in progress.');
6657
+ logger$8.info('sdk webrtc registering aborted due to a registration in progress.');
6167
6658
  return Promise.resolve();
6168
6659
  }
6169
6660
 
6170
6661
  const registerOptions = this._isWeb() ? {} : { extraContactHeaderParams: ['mobility=mobile'] };
6171
6662
 
6172
6663
  const onRegisterFailed = () => {
6173
- logger$7.info('sdk webrtc registering failed', { tries, registerer: !!this.registerer });
6664
+ logger$8.info('sdk webrtc registering failed', { tries, registerer: !!this.registerer });
6174
6665
  this.connectionPromise = null;
6175
6666
  if (this.registerer && this.registerer.waiting) {
6176
6667
  this.registerer.waitingToggle(false);
6177
6668
  }
6178
6669
 
6179
6670
  if (tries <= MAX_REGISTER_TRIES) {
6180
- logger$7.info('sdk webrtc registering, retrying...', { tries });
6671
+ logger$8.info('sdk webrtc registering, retrying...', { tries });
6181
6672
  setTimeout(() => this.register(tries + 1), 300);
6182
6673
  }
6183
6674
  };
@@ -6186,18 +6677,18 @@ class WebRTCClient extends Emitter {
6186
6677
  // Avoid race condition with the close method called just before register and setting userAgent to null
6187
6678
  // during the resolution of the primise.
6188
6679
  if (!this.userAgent) {
6189
- logger$7.info('sdk webrtc recreating User Agent after connection');
6680
+ logger$8.info('sdk webrtc recreating User Agent after connection');
6190
6681
  this.userAgent = this.createUserAgent(this.uaConfigOverrides);
6191
6682
  }
6192
6683
 
6193
- logger$7.info('sdk webrtc registering, transport connected', { registerOptions, ua: !!this.userAgent });
6684
+ logger$8.info('sdk webrtc registering, transport connected', { registerOptions, ua: !!this.userAgent });
6194
6685
  this.registerer = new registerer.Registerer(this.userAgent, registerOptions);
6195
6686
  this.connectionPromise = null;
6196
6687
  this._monkeyPatchRegisterer(this.registerer);
6197
6688
 
6198
6689
  // Bind registerer events
6199
6690
  this.registerer.stateChange.addListener(newState => {
6200
- logger$7.info('sdk webrtc registering, state changed', { newState });
6691
+ logger$8.info('sdk webrtc registering, state changed', { newState });
6201
6692
 
6202
6693
  if (newState === registererState.RegistererState.Registered && this.registerer
6203
6694
  && this.registerer.state === registererState.RegistererState.Registered) {
@@ -6210,7 +6701,7 @@ class WebRTCClient extends Emitter {
6210
6701
  const options = {
6211
6702
  requestDelegate: {
6212
6703
  onReject: response => {
6213
- logger$7.error('sdk webrtc registering, rejected', { response });
6704
+ logger$8.error('sdk webrtc registering, rejected', { response });
6214
6705
 
6215
6706
  onRegisterFailed();
6216
6707
  },
@@ -6218,13 +6709,13 @@ class WebRTCClient extends Emitter {
6218
6709
  };
6219
6710
 
6220
6711
  return this.registerer.register(options).catch((e) => {
6221
- logger$7.error('sdk webrtc registering, error', e);
6712
+ logger$8.error('sdk webrtc registering, error', e);
6222
6713
 
6223
6714
  this.eventEmitter.emit(REGISTRATION_FAILED);
6224
6715
  return e;
6225
6716
  });
6226
6717
  }).catch(error => {
6227
- logger$7.error('sdk webrtc registering, transport error', error);
6718
+ logger$8.error('sdk webrtc registering, transport error', error);
6228
6719
  onRegisterFailed();
6229
6720
  });
6230
6721
  }
@@ -6253,21 +6744,21 @@ class WebRTCClient extends Emitter {
6253
6744
  }
6254
6745
 
6255
6746
  unregister() {
6256
- logger$7.info('sdk webrtc unregistering..', { userAgent: !!this.userAgent, registerer: !!this.registerer });
6747
+ logger$8.info('sdk webrtc unregistering..', { userAgent: !!this.userAgent, registerer: !!this.registerer });
6257
6748
  if (!this.registerer) {
6258
6749
  return Promise.resolve();
6259
6750
  }
6260
6751
 
6261
6752
  try {
6262
6753
  return this.registerer.unregister().then(() => {
6263
- logger$7.info('sdk webrtc unregistered');
6754
+ logger$8.info('sdk webrtc unregistered');
6264
6755
  this._cleanupRegister();
6265
6756
  }).catch(e => {
6266
- logger$7.error('sdk webrtc unregistering, promise error', e);
6757
+ logger$8.error('sdk webrtc unregistering, promise error', e);
6267
6758
  this._cleanupRegister();
6268
6759
  });
6269
6760
  } catch (e) {
6270
- logger$7.error('sdk webrtc unregistering, error', e);
6761
+ logger$8.error('sdk webrtc unregistering, error', e);
6271
6762
  // Avoid issue with `undefined is not an object (evaluating 'new.target.prototype')` when triggering a new
6272
6763
  // error when the registerer is in a bad state
6273
6764
  this._cleanupRegister();
@@ -6275,7 +6766,7 @@ class WebRTCClient extends Emitter {
6275
6766
  }
6276
6767
 
6277
6768
  stop() {
6278
- logger$7.info('sdk webrtc stop', { userAgent: !!this.userAgent });
6769
+ logger$8.info('sdk webrtc stop', { userAgent: !!this.userAgent });
6279
6770
  if (!this.userAgent) {
6280
6771
  return Promise.resolve();
6281
6772
  }
@@ -6283,12 +6774,12 @@ class WebRTCClient extends Emitter {
6283
6774
  return this.userAgent.stop().then(() => {
6284
6775
  return this._cleanupRegister();
6285
6776
  }).catch(e => {
6286
- logger$7.warn('sdk webrtc stop, error', { message: e.message, stack: e.stack });
6777
+ logger$8.warn('sdk webrtc stop, error', { message: e.message, stack: e.stack });
6287
6778
  });
6288
6779
  }
6289
6780
 
6290
6781
  call(number , enableVideo , audioOnly = false, conference = false) {
6291
- logger$7.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
6782
+ logger$8.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
6292
6783
  const inviterOptions = {
6293
6784
  sessionDescriptionHandlerOptionsReInvite: {
6294
6785
  conference,
@@ -6317,7 +6808,7 @@ class WebRTCClient extends Emitter {
6317
6808
  this._onAccepted(session, response.session, true);
6318
6809
  },
6319
6810
  onReject: (response ) => {
6320
- logger$7.info('on call rejected', { id: session.id, fromTag: session.fromTag });
6811
+ logger$8.info('on call rejected', { id: session.id, fromTag: session.fromTag });
6321
6812
  this._stopSendingStats(session);
6322
6813
 
6323
6814
  this.eventEmitter.emit(REJECTED, session, response);
@@ -6339,11 +6830,11 @@ class WebRTCClient extends Emitter {
6339
6830
  }
6340
6831
 
6341
6832
  answer(session , enableVideo ) {
6342
- logger$7.info('sdk webrtc answer call', { id: session.id, enableVideo });
6833
+ logger$8.info('sdk webrtc answer call', { id: session.id, enableVideo });
6343
6834
 
6344
6835
  if (!session || !session.accept) {
6345
6836
  const error = 'No session to answer, or not an invitation';
6346
- logger$7.warn(error);
6837
+ logger$8.warn(error);
6347
6838
  return Promise.reject(new Error(error));
6348
6839
  }
6349
6840
  const options = {
@@ -6353,15 +6844,15 @@ class WebRTCClient extends Emitter {
6353
6844
  return session.accept(options).then(() => {
6354
6845
  if (session.isCanceled) {
6355
6846
  const message = 'accepted a canceled session (or was canceled during the accept phase).';
6356
- logger$7.error(message, { id: session.id });
6847
+ logger$8.error(message, { id: session.id });
6357
6848
  this.onCallEnded(session);
6358
6849
 
6359
6850
  throw new CanceledCallError(message);
6360
6851
  }
6361
- logger$7.info('sdk webrtc answer, accepted.');
6852
+ logger$8.info('sdk webrtc answer, accepted.');
6362
6853
  this._onAccepted(session);
6363
6854
  }).catch(e => {
6364
- logger$7.error(`answer call error for ${session ? session.id : 'n/a'}`, e);
6855
+ logger$8.error(`answer call error for ${session ? session.id : 'n/a'}`, e);
6365
6856
 
6366
6857
  throw e;
6367
6858
  });
@@ -6369,7 +6860,7 @@ class WebRTCClient extends Emitter {
6369
6860
 
6370
6861
  hangup(session ) {
6371
6862
  const { state, id } = session;
6372
- logger$7.info('sdk webrtc hangup call', { id, state });
6863
+ logger$8.info('sdk webrtc hangup call', { id, state });
6373
6864
 
6374
6865
  try {
6375
6866
  this._stopSendingStats(session);
@@ -6398,24 +6889,24 @@ class WebRTCClient extends Emitter {
6398
6889
 
6399
6890
  return bye();
6400
6891
  } catch (error) {
6401
- logger$7.warn('sdk webrtc hangup, error', error);
6892
+ logger$8.warn('sdk webrtc hangup, error', error);
6402
6893
  }
6403
6894
 
6404
6895
  return null;
6405
6896
  }
6406
6897
 
6407
6898
  reject(session ) {
6408
- logger$7.info('sdk webrtc reject call', { id: session.id });
6899
+ logger$8.info('sdk webrtc reject call', { id: session.id });
6409
6900
 
6410
6901
  try {
6411
6902
  return session.reject ? session.reject() : session.cancel();
6412
6903
  } catch (e) {
6413
- logger$7.warn('Error when rejecting call', e.message, e.stack);
6904
+ logger$8.warn('Error when rejecting call', e.message, e.stack);
6414
6905
  }
6415
6906
  }
6416
6907
 
6417
6908
  async close() {
6418
- logger$7.info('sdk webrtc closing client', { userAgent: !!this.userAgent });
6909
+ logger$8.info('sdk webrtc closing client', { userAgent: !!this.userAgent });
6419
6910
  this._cleanupMedia();
6420
6911
  this.connectionPromise = null;
6421
6912
 
@@ -6446,7 +6937,7 @@ class WebRTCClient extends Emitter {
6446
6937
  // eg: "INVITE not rejectable in state Completed"
6447
6938
  }
6448
6939
  this.userAgent = null;
6449
- logger$7.info('sdk webrtc client closed');
6940
+ logger$8.info('sdk webrtc client closed');
6450
6941
  }
6451
6942
 
6452
6943
  getNumber(session ) {
@@ -6459,13 +6950,13 @@ class WebRTCClient extends Emitter {
6459
6950
  }
6460
6951
 
6461
6952
  mute(session ) {
6462
- logger$7.info('sdk webrtc mute', { id: session.id });
6953
+ logger$8.info('sdk webrtc mute', { id: session.id });
6463
6954
 
6464
6955
  this._toggleAudio(session, true);
6465
6956
  }
6466
6957
 
6467
6958
  unmute(session ) {
6468
- logger$7.info('sdk webrtc unmute', { id: session.id });
6959
+ logger$8.info('sdk webrtc unmute', { id: session.id });
6469
6960
 
6470
6961
  this._toggleAudio(session, false);
6471
6962
  }
@@ -6482,12 +6973,18 @@ class WebRTCClient extends Emitter {
6482
6973
  }
6483
6974
 
6484
6975
  if (pc.getSenders) {
6976
+ if (!pc.getSenders().length) {
6977
+ return false;
6978
+ }
6485
6979
  pc.getSenders().forEach(sender => {
6486
6980
  if (sender && sender.track && sender.track.kind === 'audio') {
6487
6981
  muted = muted && !sender.track.enabled;
6488
6982
  }
6489
6983
  });
6490
6984
  } else {
6985
+ if (!pc.getLocalStreams().length) {
6986
+ return false;
6987
+ }
6491
6988
  pc.getLocalStreams().forEach(stream => {
6492
6989
  stream.getAudioTracks().forEach(track => {
6493
6990
  muted = muted && !track.enabled;
@@ -6499,20 +6996,20 @@ class WebRTCClient extends Emitter {
6499
6996
  }
6500
6997
 
6501
6998
  toggleCameraOn(session ) {
6502
- logger$7.info('sdk webrtc toggle camera on', { id: session.id });
6999
+ logger$8.info('sdk webrtc toggle camera on', { id: session.id });
6503
7000
 
6504
7001
  this._toggleVideo(session, false);
6505
7002
  }
6506
7003
 
6507
7004
  toggleCameraOff(session ) {
6508
- logger$7.info('sdk webrtc toggle camera off', { id: session.id });
7005
+ logger$8.info('sdk webrtc toggle camera off', { id: session.id });
6509
7006
 
6510
7007
  this._toggleVideo(session, true);
6511
7008
  }
6512
7009
 
6513
7010
  hold(session , isConference = false) {
6514
7011
  const sessionId = this.getSipSessionId(session);
6515
- logger$7.info('sdk webrtc hold', {
7012
+ logger$8.info('sdk webrtc hold', {
6516
7013
  sessionId,
6517
7014
  keys: Object.keys(this.heldSessions),
6518
7015
  pendingReinvite: !!session.pendingReinvite,
@@ -6544,6 +7041,9 @@ class WebRTCClient extends Emitter {
6544
7041
  if (!this._isWeb()) {
6545
7042
  options.sessionDescriptionHandlerModifiers = [modifiers.holdModifier];
6546
7043
  }
7044
+ options.sessionDescriptionHandlerOptions = {
7045
+ constraints: options.constraints,
7046
+ };
6547
7047
 
6548
7048
  // Send re-INVITE
6549
7049
  return session.invite(options);
@@ -6552,7 +7052,7 @@ class WebRTCClient extends Emitter {
6552
7052
  unhold(session , isConference = false) {
6553
7053
  const sessionId = this.getSipSessionId(session);
6554
7054
 
6555
- logger$7.info('sdk webrtc unhold', {
7055
+ logger$8.info('sdk webrtc unhold', {
6556
7056
  sessionId,
6557
7057
  keys: Object.keys(this.heldSessions),
6558
7058
  pendingReinvite: !!session.pendingReinvite,
@@ -6583,6 +7083,9 @@ class WebRTCClient extends Emitter {
6583
7083
  // (eg: holdModifier)
6584
7084
  options.sessionDescriptionHandlerModifiers = [];
6585
7085
  }
7086
+ options.sessionDescriptionHandlerOptions = {
7087
+ constraints: options.constraints,
7088
+ };
6586
7089
 
6587
7090
  // Send re-INVITE
6588
7091
  return session.invite(options);
@@ -6640,7 +7143,7 @@ class WebRTCClient extends Emitter {
6640
7143
  return;
6641
7144
  }
6642
7145
 
6643
- logger$7.info('send WebRTC message', { sipId: sipSession.id, contentType });
7146
+ logger$8.info('send WebRTC message', { sipId: sipSession.id, contentType });
6644
7147
 
6645
7148
  try {
6646
7149
  sipSession.message({
@@ -6765,7 +7268,8 @@ class WebRTCClient extends Emitter {
6765
7268
  }
6766
7269
  const sdh = session.sessionDescriptionHandler;
6767
7270
  const pc = sdh.peerConnection;
6768
- const localStream = this.getLocalStream(this.getSipSessionId(session));
7271
+ const sessionId = this.getSipSessionId(session);
7272
+ const localStream = this.getLocalStream(sessionId);
6769
7273
 
6770
7274
  // Release old video stream
6771
7275
  if (localStream) {
@@ -6791,11 +7295,8 @@ class WebRTCClient extends Emitter {
6791
7295
 
6792
7296
  // let's update the local stream
6793
7297
  this.eventEmitter.emit('onVideoInputChange', stream);
6794
- try {
6795
- await sdh.setLocalMediaStream(stream);
6796
- } catch (_) {
6797
- // Nothing to do
6798
- }
7298
+ this.setLocalMediaStream(sessionId, stream);
7299
+
6799
7300
  return stream;
6800
7301
  });
6801
7302
  }
@@ -7007,7 +7508,7 @@ class WebRTCClient extends Emitter {
7007
7508
  }
7008
7509
 
7009
7510
  startHeartbeat() {
7010
- logger$7.info('sdk webrtc start heartbeat', { userAgent: !!this.userAgent });
7511
+ logger$8.info('sdk webrtc start heartbeat', { userAgent: !!this.userAgent });
7011
7512
  if (!this.userAgent) {
7012
7513
  this.heartbeat.stop();
7013
7514
  return;
@@ -7020,7 +7521,7 @@ class WebRTCClient extends Emitter {
7020
7521
  }
7021
7522
 
7022
7523
  stopHeartbeat() {
7023
- logger$7.info('sdk webrtc stop heartbeat');
7524
+ logger$8.info('sdk webrtc stop heartbeat');
7024
7525
  this.heartbeat.stop();
7025
7526
  }
7026
7527
 
@@ -7040,7 +7541,7 @@ class WebRTCClient extends Emitter {
7040
7541
  }
7041
7542
 
7042
7543
  attemptReconnection() {
7043
- logger$7.info('attempt reconnection', { userAgent: !!this.userAgent });
7544
+ logger$8.info('attempt reconnection', { userAgent: !!this.userAgent });
7044
7545
  if (!this.userAgent) {
7045
7546
  return;
7046
7547
  }
@@ -7097,9 +7598,11 @@ class WebRTCClient extends Emitter {
7097
7598
  remoteStream.removeTrack(track);
7098
7599
  });
7099
7600
 
7100
- pc.getReceivers().forEach(receiver => {
7101
- remoteStream.addTrack(receiver.track);
7102
- });
7601
+ if (pc.getReceivers) {
7602
+ pc.getReceivers().forEach(receiver => {
7603
+ remoteStream.addTrack(receiver.track);
7604
+ });
7605
+ }
7103
7606
  }
7104
7607
 
7105
7608
  getMediaConfiguration(enableVideo , conference = false, constraints = null) {
@@ -7134,6 +7637,25 @@ class WebRTCClient extends Emitter {
7134
7637
  return sessionId in this.conferences;
7135
7638
  }
7136
7639
 
7640
+ createAudioElementFor(sessionId ) {
7641
+ const audio = document.createElement('audio');
7642
+ audio.setAttribute('id', `audio-${sessionId}`);
7643
+
7644
+ if (audio.setSinkId && this.audioOutputDeviceId) {
7645
+ audio.setSinkId(this.audioOutputDeviceId);
7646
+ }
7647
+
7648
+ if (document.body) {
7649
+ document.body.appendChild(audio);
7650
+ }
7651
+ this.audioElements[sessionId] = audio;
7652
+
7653
+ audio.volume = this.audioOutputVolume;
7654
+ audio.autoplay = true;
7655
+
7656
+ return audio;
7657
+ }
7658
+
7137
7659
  _onTransportError() {
7138
7660
  this.eventEmitter.emit(TRANSPORT_ERROR);
7139
7661
  this.attemptReconnection();
@@ -7143,7 +7665,7 @@ class WebRTCClient extends Emitter {
7143
7665
  const body = message && typeof message === 'object' ? message.data : message;
7144
7666
  if (body && body.indexOf('200 OK') !== -1) {
7145
7667
  if (this.hasHeartbeat()) {
7146
- logger$7.info('on heartbeat received from Asterisk', { hasHeartbeat: this.hasHeartbeat() });
7668
+ logger$8.info('on heartbeat received from Asterisk', { hasHeartbeat: this.hasHeartbeat() });
7147
7669
 
7148
7670
  this.heartbeat.onHeartbeat();
7149
7671
  if (this.heartbeatCb) {
@@ -7154,7 +7676,7 @@ class WebRTCClient extends Emitter {
7154
7676
  }
7155
7677
 
7156
7678
  async _onHeartbeatTimeout() {
7157
- logger$7.info('sdk webrtc heartbeat timed out', { userAgent: !!this.userAgent, cb: !!this.heartbeatTimeoutCb });
7679
+ logger$8.info('sdk webrtc heartbeat timed out', { userAgent: !!this.userAgent, cb: !!this.heartbeatTimeoutCb });
7158
7680
 
7159
7681
  if (this.heartbeatTimeoutCb) {
7160
7682
  this.heartbeatTimeoutCb();
@@ -7166,7 +7688,7 @@ class WebRTCClient extends Emitter {
7166
7688
  try {
7167
7689
  await this.userAgent.transport.disconnect();
7168
7690
  } catch (e) {
7169
- logger$7.error('Transport disconnection after heartbeat timeout, error', e);
7691
+ logger$8.error('Transport disconnection after heartbeat timeout, error', e);
7170
7692
  }
7171
7693
  }
7172
7694
 
@@ -7199,31 +7721,31 @@ class WebRTCClient extends Emitter {
7199
7721
  }
7200
7722
 
7201
7723
  _connectIfNeeded() {
7202
- logger$7.info('connect if needed, checking', { connected: this.isConnected() });
7724
+ logger$8.info('connect if needed, checking', { connected: this.isConnected() });
7203
7725
  if (!this.userAgent) {
7204
- logger$7.info('need to recreate User Agent');
7726
+ logger$8.info('need to recreate User Agent');
7205
7727
  this.userAgent = this.createUserAgent(this.uaConfigOverrides);
7206
7728
  }
7207
7729
 
7208
7730
  if (this.isConnected()) {
7209
- logger$7.info('webrtc sdk, already connected');
7731
+ logger$8.info('webrtc sdk, already connected');
7210
7732
  return Promise.resolve();
7211
7733
  }
7212
7734
 
7213
7735
  if (this.isConnecting()) {
7214
- logger$7.info('webrtc sdk, already connecting...');
7736
+ logger$8.info('webrtc sdk, already connecting...');
7215
7737
 
7216
7738
  this.connectionPromise = this.userAgent.transport.connectPromise;
7217
7739
  return this.connectionPromise;
7218
7740
  }
7219
7741
 
7220
7742
  if (this.connectionPromise) {
7221
- logger$7.info('webrtc sdk, connection promise connecting...');
7743
+ logger$8.info('webrtc sdk, connection promise connecting...');
7222
7744
  // $FlowFixMe
7223
7745
  return this.connectionPromise;
7224
7746
  }
7225
7747
 
7226
- logger$7.info('WebRTC UA needs to connect');
7748
+ logger$8.info('WebRTC UA needs to connect');
7227
7749
 
7228
7750
  // Force UA to reconnect
7229
7751
  if (this.userAgent && this.userAgent.state !== userAgentState.UserAgentState.Stopped) {
@@ -7348,7 +7870,7 @@ class WebRTCClient extends Emitter {
7348
7870
 
7349
7871
  sdh.peerConnectionDelegate = {
7350
7872
  onicecandidateerror: (error ) => {
7351
- logger$7.error('on icecandidate error', {
7873
+ logger$8.error('on icecandidate error', {
7352
7874
  address: error.address,
7353
7875
  port: error.port,
7354
7876
  errorCode: error.errorCode,
@@ -7363,7 +7885,7 @@ class WebRTCClient extends Emitter {
7363
7885
  let hadRemoteVideo = false;
7364
7886
 
7365
7887
  // Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
7366
- // Becase when `onInvite` is called we already got the video track
7888
+ // Because when `onInvite` is called we already got the video track
7367
7889
  session.onInviteRequest = (request) => {
7368
7890
  hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7369
7891
 
@@ -7377,7 +7899,7 @@ class WebRTCClient extends Emitter {
7377
7899
  updatedNumber = session.assertedIdentity.uri.normal.user;
7378
7900
  updatedCalleeName = session.assertedIdentity.displayName || updatedNumber;
7379
7901
  }
7380
- logger$7.info('re-invite received', { updatedCalleeName, updatedNumber });
7902
+ logger$8.info('re-invite received', { updatedCalleeName, updatedNumber });
7381
7903
 
7382
7904
  // Useful to know if it's a video upgrade or an unhold from a remote peer with a video stream
7383
7905
 
@@ -7398,7 +7920,7 @@ class WebRTCClient extends Emitter {
7398
7920
  }
7399
7921
 
7400
7922
  _onAccepted(session , sessionDialog , withEvent = true) {
7401
- logger$7.info('on call accepted', { id: session.id, remoteTag: session.remoteTag });
7923
+ logger$8.info('on call accepted', { id: session.id, remoteTag: session.remoteTag });
7402
7924
 
7403
7925
  this.storeSipSession(session);
7404
7926
 
@@ -7438,20 +7960,10 @@ class WebRTCClient extends Emitter {
7438
7960
  const isConference = this.isConference(sessionId);
7439
7961
 
7440
7962
  if (this._hasAudio() && this._isWeb() && !(sessionId in this.audioElements)) {
7441
- const audio = document.createElement('audio');
7442
- audio.setAttribute('id', `audio-${sessionId}`);
7443
-
7444
- if (audio.setSinkId && this.audioOutputDeviceId) {
7445
- audio.setSinkId(this.audioOutputDeviceId);
7446
- }
7447
-
7448
- if (document.body) {
7449
- document.body.appendChild(audio);
7450
- }
7451
- this.audioElements[sessionId] = audio;
7963
+ this.createAudioElementFor(sessionId);
7452
7964
  }
7453
7965
 
7454
- const audioElement = this.audioElements[this.getSipSessionId(session)];
7966
+ const audioElement = this.audioElements[sessionId];
7455
7967
  const stream = newStream || this.getRemoteStream(sessionId);
7456
7968
 
7457
7969
  if (!this._isWeb() || !stream) {
@@ -7598,10 +8110,10 @@ class WebRTCClient extends Emitter {
7598
8110
 
7599
8111
  _stopSendingStats(session ) {
7600
8112
  const sessionId = this.getSipSessionId(session);
7601
- logger$7.trace('Check for stopping stats', { sessionId, ids: Object.keys(this.statsIntervals) });
8113
+ logger$8.trace('Check for stopping stats', { sessionId, ids: Object.keys(this.statsIntervals) });
7602
8114
 
7603
8115
  if (sessionId in this.statsIntervals) {
7604
- logger$7.trace('Stop sending stats for call', { sessionId });
8116
+ logger$8.trace('Stop sending stats for call', { sessionId });
7605
8117
  this.statsIntervals[sessionId]();
7606
8118
  delete this.statsIntervals[sessionId];
7607
8119
  }
@@ -7617,7 +8129,7 @@ class WebRTCClient extends Emitter {
7617
8129
  try {
7618
8130
  await this.userAgent.transport.disconnect();
7619
8131
  } catch (e) {
7620
- logger$7.error('WebRTC transport disconnect, error', e);
8132
+ logger$8.error('WebRTC transport disconnect, error', e);
7621
8133
  }
7622
8134
  }
7623
8135
  }
@@ -7704,7 +8216,7 @@ const events = [
7704
8216
  ON_SIGNAL,
7705
8217
  ];
7706
8218
 
7707
- const logger$6 = IssueReporter$1.loggerFor('webrtc-phone');
8219
+ const logger$7 = IssueReporter$1.loggerFor('webrtc-phone');
7708
8220
 
7709
8221
  class WebRTCPhone extends Emitter {
7710
8222
 
@@ -7775,7 +8287,7 @@ class WebRTCPhone extends Emitter {
7775
8287
  }).catch(error => {
7776
8288
  // Avoid exception on `t.server.scheme` in sip transport when losing the webrtc socket connection
7777
8289
  console.error('register error', error, error.message, error.stack);
7778
- logger$6.error('WebRTC register error', { message: error.message, stack: error.stack });
8290
+ logger$7.error('WebRTC register error', { message: error.message, stack: error.stack });
7779
8291
  });
7780
8292
  }
7781
8293
 
@@ -7790,7 +8302,7 @@ class WebRTCPhone extends Emitter {
7790
8302
  if (!this.client) {
7791
8303
  return;
7792
8304
  }
7793
- logger$6.info('WebRTC phone stop');
8305
+ logger$7.info('WebRTC phone stop');
7794
8306
  this.client.stop();
7795
8307
  }
7796
8308
 
@@ -7805,14 +8317,14 @@ class WebRTCPhone extends Emitter {
7805
8317
  async sendReinvite(callSession , constraints = null, conference = false,
7806
8318
  audioOnly = false) {
7807
8319
  const sipSession = this.findSipSession(callSession);
7808
- logger$6.info('WebRTC phone - send reinvite', {
8320
+ logger$7.info('WebRTC phone - send reinvite', {
7809
8321
  sessionId: sipSession ? sipSession.id : null,
7810
8322
  constraints,
7811
8323
  audioOnly,
7812
8324
  });
7813
8325
 
7814
8326
  if (!sipSession) {
7815
- return null;
8327
+ return false;
7816
8328
  }
7817
8329
 
7818
8330
  // $FlowFixMe
@@ -7822,19 +8334,17 @@ class WebRTCPhone extends Emitter {
7822
8334
  // Downgrade
7823
8335
  if (constraints && !isUpgrade) {
7824
8336
  // No reinvite needed
7825
- return this._downgradeToAudio(callSession);
8337
+ this._downgradeToAudio(callSession);
8338
+ return false;
7826
8339
  }
7827
8340
 
7828
8341
  if (isUpgrade) {
7829
8342
  const shouldReinvite = await this._upgradeToVideo(callSession, constraints, conference);
7830
8343
  if (!shouldReinvite) {
7831
- return;
8344
+ return false;
7832
8345
  }
7833
8346
  }
7834
8347
 
7835
- // Force reinvite in SDH
7836
- sipSession.sessionDescriptionHandler.localMediaStreamConstraints = null;
7837
-
7838
8348
  return this.client.reinvite(sipSession, constraints, conference, audioOnly);
7839
8349
  }
7840
8350
 
@@ -7843,7 +8353,7 @@ class WebRTCPhone extends Emitter {
7843
8353
  }
7844
8354
 
7845
8355
  startHeartbeat() {
7846
- logger$6.info('WebRTC phone - start heartbeat', { client: !!this.client, hasHeartbeat: this.client.hasHeartbeat() });
8356
+ logger$7.info('WebRTC phone - start heartbeat', { client: !!this.client, hasHeartbeat: this.client.hasHeartbeat() });
7847
8357
  if (!this.client || this.client.hasHeartbeat()) {
7848
8358
  return;
7849
8359
  }
@@ -7852,7 +8362,7 @@ class WebRTCPhone extends Emitter {
7852
8362
  }
7853
8363
 
7854
8364
  stopHeartbeat() {
7855
- logger$6.info('WebRTC phone - stopHeartbeat', { client: !!this.client });
8365
+ logger$7.info('WebRTC phone - stopHeartbeat', { client: !!this.client });
7856
8366
  if (!this.client) {
7857
8367
  return;
7858
8368
  }
@@ -7869,7 +8379,7 @@ class WebRTCPhone extends Emitter {
7869
8379
  }
7870
8380
 
7871
8381
  reconnect() {
7872
- logger$6.info('WebRTC phone - reconnect', { client: !!this.client });
8382
+ logger$7.info('WebRTC phone - reconnect', { client: !!this.client });
7873
8383
  if (!this.client) {
7874
8384
  return;
7875
8385
  }
@@ -7907,7 +8417,7 @@ class WebRTCPhone extends Emitter {
7907
8417
  _downgradeToAudio(callSession ) {
7908
8418
  const sipSession = this.findSipSession(callSession);
7909
8419
  if (!sipSession) {
7910
- return;
8420
+ return false;
7911
8421
  }
7912
8422
 
7913
8423
  // Release local video stream when downgrading to audio
@@ -8020,7 +8530,7 @@ class WebRTCPhone extends Emitter {
8020
8530
  // Monkey patch to know when canceled with the CANCEL message
8021
8531
  const onCancel = sipSession._onCancel.bind(sipSession);
8022
8532
  sipSession._onCancel = (message ) => {
8023
- logger$6.trace('on sip session canceled', { callId: message.callId });
8533
+ logger$7.trace('on sip session canceled', { callId: message.callId });
8024
8534
 
8025
8535
  onCancel(message);
8026
8536
  const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
@@ -8045,13 +8555,13 @@ class WebRTCPhone extends Emitter {
8045
8555
  this.audioOutputVolume,
8046
8556
  );
8047
8557
  case sessionState.SessionState.Terminating:
8048
- logger$6.info('WebRTC phone - call terminating', { sipId: sipSession.id });
8558
+ logger$7.info('WebRTC phone - call terminating', { sipId: sipSession.id });
8049
8559
 
8050
8560
  this.eventEmitter.emit(ON_CALL_ENDING, this._createCallSession(sipSession));
8051
8561
 
8052
8562
  break;
8053
8563
  case sessionState.SessionState.Terminated:
8054
- logger$6.info('WebRTC phone - call terminated', { sipId: sipSession.id });
8564
+ logger$7.info('WebRTC phone - call terminated', { sipId: sipSession.id });
8055
8565
 
8056
8566
  this._onCallTerminated(sipSession);
8057
8567
 
@@ -8087,7 +8597,7 @@ class WebRTCPhone extends Emitter {
8087
8597
  }
8088
8598
 
8089
8599
  async startScreenSharing(constraints , callSession ) {
8090
- logger$6.info('WebRTC - start screen sharing', { constraints, id: callSession ? callSession.getId() : null });
8600
+ logger$7.info('WebRTC - start screen sharing', { constraints, id: callSession ? callSession.getId() : null });
8091
8601
 
8092
8602
  const screenShareStream = await this._getStreamFromConstraints(constraints);
8093
8603
  if (!screenShareStream) {
@@ -8109,6 +8619,10 @@ class WebRTCPhone extends Emitter {
8109
8619
  localStream.removeTrack(videoTrack);
8110
8620
  }
8111
8621
 
8622
+ if (localStream) {
8623
+ localStream.addTrack(screenTrack);
8624
+ }
8625
+
8112
8626
  if (sender) {
8113
8627
  sender.replaceTrack(screenTrack);
8114
8628
  }
@@ -8123,7 +8637,8 @@ class WebRTCPhone extends Emitter {
8123
8637
  return;
8124
8638
  }
8125
8639
 
8126
- logger$6.info('WebRTC phone - stop screen sharing');
8640
+ logger$7.info('WebRTC phone - stop screen sharing');
8641
+ let reinvited = false;
8127
8642
 
8128
8643
  try {
8129
8644
  if (this.currentScreenShare.stream) {
@@ -8138,7 +8653,8 @@ class WebRTCPhone extends Emitter {
8138
8653
  // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8139
8654
  // We have to downgrade to audio.
8140
8655
  const screenshareStopped = this.currentScreenShare.sender && this.currentScreenShare.hadVideo;
8141
- await this.sendReinvite(targetCallSession, { audio: false, video: screenshareStopped }, conference);
8656
+ const constraints = { audio: false, video: screenshareStopped };
8657
+ reinvited = await this.sendReinvite(targetCallSession, constraints, conference);
8142
8658
  }
8143
8659
  } catch (e) {
8144
8660
  console.warn(e);
@@ -8152,6 +8668,8 @@ class WebRTCPhone extends Emitter {
8152
8668
  );
8153
8669
 
8154
8670
  this.currentScreenShare = null;
8671
+
8672
+ return reinvited;
8155
8673
  }
8156
8674
 
8157
8675
  async _getStreamFromConstraints(constraints , conference = false) {
@@ -8189,7 +8707,7 @@ class WebRTCPhone extends Emitter {
8189
8707
  }
8190
8708
 
8191
8709
  _onCallAccepted(sipSession , cameraEnabled ) {
8192
- logger$6.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
8710
+ logger$7.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
8193
8711
 
8194
8712
  const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
8195
8713
  this.currentSipSession = sipSession;
@@ -8207,11 +8725,15 @@ class WebRTCPhone extends Emitter {
8207
8725
  }
8208
8726
 
8209
8727
  changeAudioDevice(id ) {
8210
- logger$6.info('WebRTC phone - change audio device', { deviceId: id });
8728
+ logger$7.info('WebRTC phone - change audio device', { deviceId: id });
8211
8729
  this.audioOutputDeviceId = id;
8212
8730
  this.client.changeAudioOutputDevice(id);
8213
8731
  }
8214
8732
 
8733
+ createAudioElementFor(sessionId ) {
8734
+ return this.client.createAudioElementFor(sessionId);
8735
+ }
8736
+
8215
8737
  changeRingDevice(id ) {
8216
8738
  this.audioRingDeviceId = id;
8217
8739
  }
@@ -8228,25 +8750,25 @@ class WebRTCPhone extends Emitter {
8228
8750
  }
8229
8751
 
8230
8752
  changeAudioInputDevice(id ) {
8231
- logger$6.info('WebRTC phone - changeAudio input device', { deviceId: id });
8753
+ logger$7.info('WebRTC phone - changeAudio input device', { deviceId: id });
8232
8754
 
8233
8755
  return this.client.changeAudioInputDevice(id, this.currentSipSession);
8234
8756
  }
8235
8757
 
8236
8758
  changeVideoInputDevice(id ) {
8237
- logger$6.info('WebRTC phone - change video input device', { deviceId: id });
8759
+ logger$7.info('WebRTC phone - change video input device', { deviceId: id });
8238
8760
 
8239
8761
  return this.client.changeVideoInputDevice(id, this.currentSipSession);
8240
8762
  }
8241
8763
 
8242
8764
  changeSessionVideoInputDevice(id ) {
8243
- logger$6.info('WebRTC phone - change session video input device', { deviceId: id });
8765
+ logger$7.info('WebRTC phone - change session video input device', { deviceId: id });
8244
8766
 
8245
8767
  return this.client.changeSessionVideoInputDevice(id, this.currentSipSession);
8246
8768
  }
8247
8769
 
8248
8770
  _onCallTerminated(sipSession ) {
8249
- logger$6.info('WebRTC phone - on call terminated', { sipId: sipSession.id });
8771
+ logger$7.info('WebRTC phone - on call terminated', { sipId: sipSession.id });
8250
8772
 
8251
8773
  const callSession = this._createCallSession(sipSession);
8252
8774
  const isCurrentSession = this.isCurrentCallSipSession(callSession);
@@ -8280,7 +8802,7 @@ class WebRTCPhone extends Emitter {
8280
8802
  const hasIncomingCallSession = this.hasIncomingCallSession();
8281
8803
 
8282
8804
  // Re-trigger incoming call event for remaining incoming calls
8283
- logger$6.info('WebRTC phone - check to re-trigger incoming call', {
8805
+ logger$7.info('WebRTC phone - check to re-trigger incoming call', {
8284
8806
  sipId: sipSession.id,
8285
8807
  shouldRetrigger,
8286
8808
  hasIncomingCallSession,
@@ -8369,37 +8891,37 @@ class WebRTCPhone extends Emitter {
8369
8891
 
8370
8892
  // Deprecated
8371
8893
  getLocalStreamForCall(callSession ) {
8372
- logger$6.warn('WebRTCPhone.getLocalStreamForCall is deprecated, use WebRTCPhone.getLocalStream instead');
8894
+ logger$7.warn('WebRTCPhone.getLocalStreamForCall is deprecated, use WebRTCPhone.getLocalStream instead');
8373
8895
 
8374
8896
  return this.getLocalStream(callSession);
8375
8897
  }
8376
8898
 
8377
8899
  // Deprecated
8378
8900
  getRemoteStreamForCall(callSession ) {
8379
- logger$6.warn('WebRTCPhone.getRemoteStreamForCall is deprecated, use WebRTCPhone.getRemoteStream instead');
8901
+ logger$7.warn('WebRTCPhone.getRemoteStreamForCall is deprecated, use WebRTCPhone.getRemoteStream instead');
8380
8902
 
8381
8903
  return this.getRemoteVideoStream(callSession);
8382
8904
  }
8383
8905
 
8384
8906
  getRemoteStreamsForCall(callSession ) {
8385
- logger$6.warn('WebRTCPhone.getRemoteStreamsForCall is deprecated, use WebRTCPhone.getRemoteStreams instead');
8907
+ logger$7.warn('WebRTCPhone.getRemoteStreamsForCall is deprecated, use WebRTCPhone.getRemoteStreams instead');
8386
8908
 
8387
8909
  return this.getRemoteStream(callSession);
8388
8910
  }
8389
8911
 
8390
8912
  accept(callSession , cameraEnabled ) {
8391
- logger$6.info('WebRTC phone - accept call', { id: callSession ? callSession.getId() : 'n/a', cameraEnabled });
8913
+ logger$7.info('WebRTC phone - accept call', { id: callSession ? callSession.getId() : 'n/a', cameraEnabled });
8392
8914
  if (this.currentSipSession) {
8393
8915
  this.holdSipSession(this.currentSipSession, this.currentCallSession, true);
8394
8916
  }
8395
8917
 
8396
8918
  if (!callSession) {
8397
- logger$6.warn('no CallSession to accept.');
8919
+ logger$7.warn('no CallSession to accept.');
8398
8920
  return Promise.resolve(null);
8399
8921
  }
8400
8922
 
8401
8923
  if (callSession.getId() in this.acceptedSessions) {
8402
- logger$6.warn('CallSession already accepted.', { id: callSession ? callSession.getId() : 'n/a' });
8924
+ logger$7.warn('CallSession already accepted.', { id: callSession ? callSession.getId() : 'n/a' });
8403
8925
  return Promise.resolve(callSession.sipCallId);
8404
8926
  }
8405
8927
 
@@ -8411,24 +8933,24 @@ class WebRTCPhone extends Emitter {
8411
8933
  const sipSession = this.client.getSipSession(callSession.getId());
8412
8934
  if (sipSession) {
8413
8935
  if (sipSession.state === sessionState.SessionState.Terminated || sipSession.state === sessionState.SessionState.Terminating) {
8414
- logger$6.warn('Trying to answer a terminated sipSession.');
8936
+ logger$7.warn('Trying to answer a terminated sipSession.');
8415
8937
 
8416
8938
  return Promise.resolve(null);
8417
8939
  }
8418
8940
 
8419
- logger$6.info('accept call, session found', { sipId: sipSession.id });
8941
+ logger$7.info('accept call, session found', { sipId: sipSession.id });
8420
8942
 
8421
8943
  // $FlowFixMe
8422
8944
  return this.client.answer(sipSession, this.allowVideo ? cameraEnabled : false).then(() => {
8423
8945
  return callSession.sipCallId;
8424
8946
  }).catch(e => {
8425
- logger$6.error(e);
8947
+ logger$7.error(e);
8426
8948
  this.endCurrentCall(callSession);
8427
8949
  throw e;
8428
8950
  });
8429
8951
  }
8430
8952
 
8431
- logger$6.warn('no CallSession found to accept.', { id: callSession ? callSession.getId() : 'n/a' });
8953
+ logger$7.warn('no CallSession found to accept.', { id: callSession ? callSession.getId() : 'n/a' });
8432
8954
 
8433
8955
  return Promise.resolve(null);
8434
8956
  }
@@ -8438,7 +8960,7 @@ class WebRTCPhone extends Emitter {
8438
8960
  }
8439
8961
 
8440
8962
  async reject(callSession ) {
8441
- logger$6.info('reject WebRTC called', { id: callSession.getId() });
8963
+ logger$7.info('reject WebRTC called', { id: callSession.getId() });
8442
8964
 
8443
8965
  this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'call rejected locally');
8444
8966
  if (!callSession || callSession.getId() in this.rejectedSessions) {
@@ -8450,14 +8972,14 @@ class WebRTCPhone extends Emitter {
8450
8972
 
8451
8973
  const sipSession = this.findSipSession(callSession);
8452
8974
  if (sipSession) {
8453
- logger$6.info('WebRTC rejecting', { sipId: sipSession.id });
8975
+ logger$7.info('WebRTC rejecting', { sipId: sipSession.id });
8454
8976
 
8455
8977
  this.client.hangup(sipSession);
8456
8978
  }
8457
8979
  }
8458
8980
 
8459
8981
  async ignore(callSession ) {
8460
- logger$6.info('WebRTC ignore', { id: callSession.getId() });
8982
+ logger$7.info('WebRTC ignore', { id: callSession.getId() });
8461
8983
 
8462
8984
  // kill the ring
8463
8985
  this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'ignoring call');
@@ -8466,7 +8988,7 @@ class WebRTCPhone extends Emitter {
8466
8988
  }
8467
8989
 
8468
8990
  hold(callSession , withEvent = true, isConference = false) {
8469
- logger$6.info('WebRTC hold', { id: callSession.getId() });
8991
+ logger$7.info('WebRTC hold', { id: callSession.getId() });
8470
8992
 
8471
8993
  const sipSession = this.findSipSession(callSession);
8472
8994
 
@@ -8477,7 +8999,7 @@ class WebRTCPhone extends Emitter {
8477
8999
 
8478
9000
  // @Deprecated
8479
9001
  unhold(callSession , withEvent = true, isConference = false) {
8480
- logger$6.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
9002
+ logger$7.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
8481
9003
 
8482
9004
  console.warn('Please note that `phone.unhold()` is being deprecated; `phone.resume()` is the preferred method');
8483
9005
 
@@ -8492,7 +9014,7 @@ class WebRTCPhone extends Emitter {
8492
9014
  const sipSession = this.findSipSession(callSession);
8493
9015
 
8494
9016
  if (sipSession) {
8495
- logger$6.info('WebRTC atxfer', { sipId: sipSession.id });
9017
+ logger$7.info('WebRTC atxfer', { sipId: sipSession.id });
8496
9018
 
8497
9019
  return this.client.atxfer(sipSession);
8498
9020
  }
@@ -8507,7 +9029,7 @@ class WebRTCPhone extends Emitter {
8507
9029
  if (!sipSession) {
8508
9030
  return new Promise((resolve, reject) => reject(new Error('No session to hold')));
8509
9031
  }
8510
- logger$6.info('WebRTC hold sip session', { sipId: sipSession.id });
9032
+ logger$7.info('WebRTC hold sip session', { sipId: sipSession.id });
8511
9033
 
8512
9034
  const promise = this.client.hold(sipSession, isConference);
8513
9035
  if (withEvent) {
@@ -8526,7 +9048,7 @@ class WebRTCPhone extends Emitter {
8526
9048
  if (!sipSession) {
8527
9049
  return new Promise((resolve, reject) => reject(new Error('No session to unhold')));
8528
9050
  }
8529
- logger$6.info('WebRTC unhold', { sipId: sipSession.id });
9051
+ logger$7.info('WebRTC unhold', { sipId: sipSession.id });
8530
9052
 
8531
9053
  const promise = this.client.unhold(sipSession, isConference);
8532
9054
  if (withEvent) {
@@ -8537,18 +9059,18 @@ class WebRTCPhone extends Emitter {
8537
9059
  }
8538
9060
 
8539
9061
  resume(callSession , isConference = false) {
8540
- logger$6.info('WebRTC resume called', { id: callSession ? callSession.getId() : null });
9062
+ logger$7.info('WebRTC resume called', { id: callSession ? callSession.getId() : null });
8541
9063
 
8542
9064
  const sipSession = this.findSipSession(callSession);
8543
9065
  if (!sipSession) {
8544
9066
  return new Promise((resolve, reject) => reject(new Error('No session to resume')));
8545
9067
  }
8546
9068
 
8547
- logger$6.info('WebRTC resuming', { sipId: sipSession.id });
9069
+ logger$7.info('WebRTC resuming', { sipId: sipSession.id });
8548
9070
 
8549
9071
  // Hold current session if different from the current one (we don't want 2 sessions active at the same time).
8550
9072
  if (this.currentSipSession && this.currentSipSession.id !== sipSession.id) {
8551
- logger$6.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
9073
+ logger$7.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
8552
9074
  this.holdSipSession(this.currentSipSession, callSession);
8553
9075
  }
8554
9076
 
@@ -8563,14 +9085,14 @@ class WebRTCPhone extends Emitter {
8563
9085
  }
8564
9086
 
8565
9087
  mute(callSession , withEvent = true) {
8566
- logger$6.info('WebRTC mute called', { id: callSession ? callSession.getId() : null });
9088
+ logger$7.info('WebRTC mute called', { id: callSession ? callSession.getId() : null });
8567
9089
 
8568
9090
  const sipSession = this.findSipSession(callSession);
8569
9091
  if (!sipSession) {
8570
9092
  return;
8571
9093
  }
8572
9094
 
8573
- logger$6.info('WebRTC muting', { sipId: sipSession.id });
9095
+ logger$7.info('WebRTC muting', { sipId: sipSession.id });
8574
9096
  this.client.mute(sipSession);
8575
9097
  const newCallSession = this._createCallSession(sipSession, callSession, { muted: true });
8576
9098
 
@@ -8584,14 +9106,14 @@ class WebRTCPhone extends Emitter {
8584
9106
  }
8585
9107
 
8586
9108
  unmute(callSession , withEvent = true) {
8587
- logger$6.info('WebRTC unmute called', { id: callSession ? callSession.getId() : null });
9109
+ logger$7.info('WebRTC unmute called', { id: callSession ? callSession.getId() : null });
8588
9110
 
8589
9111
  const sipSession = this.findSipSession(callSession);
8590
9112
  if (!sipSession) {
8591
9113
  return;
8592
9114
  }
8593
9115
 
8594
- logger$6.info('WebRTC unmuting', { sipId: sipSession.id });
9116
+ logger$7.info('WebRTC unmuting', { sipId: sipSession.id });
8595
9117
  this.client.unmute(sipSession);
8596
9118
  const newCallSession = this._createCallSession(sipSession, callSession, { muted: false });
8597
9119
 
@@ -8618,7 +9140,7 @@ class WebRTCPhone extends Emitter {
8618
9140
  if (!sipSession) {
8619
9141
  return;
8620
9142
  }
8621
- logger$6.info('WebRTC turn camera on', { sipId: sipSession.id });
9143
+ logger$7.info('WebRTC turn camera on', { sipId: sipSession.id });
8622
9144
 
8623
9145
  this.client.toggleCameraOn(sipSession);
8624
9146
 
@@ -8630,7 +9152,7 @@ class WebRTCPhone extends Emitter {
8630
9152
  if (!sipSession) {
8631
9153
  return;
8632
9154
  }
8633
- logger$6.info('WebRTC turn camera off', { sipId: sipSession.id });
9155
+ logger$7.info('WebRTC turn camera off', { sipId: sipSession.id });
8634
9156
 
8635
9157
  this.client.toggleCameraOff(sipSession);
8636
9158
  this.eventEmitter.emit(ON_CAMERA_DISABLED, this._createCameraDisabledCallSession(sipSession, callSession));
@@ -8642,7 +9164,7 @@ class WebRTCPhone extends Emitter {
8642
9164
  return;
8643
9165
  }
8644
9166
 
8645
- logger$6.info('WebRTC send key', { sipId: sipSession.id, tone });
9167
+ logger$7.info('WebRTC send key', { sipId: sipSession.id, tone });
8646
9168
  this.client.sendDTMF(sipSession, tone);
8647
9169
  }
8648
9170
 
@@ -8650,7 +9172,7 @@ class WebRTCPhone extends Emitter {
8650
9172
  // @TODO: line is not used here
8651
9173
  async makeCall(number , line , cameraEnabled ,
8652
9174
  audioOnly = false, conference = false) {
8653
- logger$6.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled });
9175
+ logger$7.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled });
8654
9176
  if (!number) {
8655
9177
  return Promise.resolve(null);
8656
9178
  }
@@ -8660,7 +9182,7 @@ class WebRTCPhone extends Emitter {
8660
9182
  }
8661
9183
  if (this.currentSipSession) {
8662
9184
  this.holdSipSession(this.currentSipSession, this.currentCallSession, true).catch(e => {
8663
- logger$6.warn('Unable to hold current session when making another call', e);
9185
+ logger$7.warn('Unable to hold current session when making another call', e);
8664
9186
  });
8665
9187
  }
8666
9188
 
@@ -8670,7 +9192,7 @@ class WebRTCPhone extends Emitter {
8670
9192
  this._bindEvents(sipSession);
8671
9193
  } catch (error) {
8672
9194
  console.warn(error);
8673
- logger$6.warn('make WebRTC call, error', { message: error.message, stack: error.stack });
9195
+ logger$7.warn('make WebRTC call, error', { message: error.message, stack: error.stack });
8674
9196
  return Promise.resolve(null);
8675
9197
  }
8676
9198
  const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
@@ -8698,7 +9220,7 @@ class WebRTCPhone extends Emitter {
8698
9220
  return;
8699
9221
  }
8700
9222
 
8701
- logger$6.info('WebRTC transfer', { sipId: sipSession.id, target });
9223
+ logger$7.info('WebRTC transfer', { sipId: sipSession.id, target });
8702
9224
 
8703
9225
  this.client.transfer(sipSession, target);
8704
9226
  }
@@ -8707,7 +9229,7 @@ class WebRTCPhone extends Emitter {
8707
9229
  const sipSession = this.client.getSipSession(source.sipCallId);
8708
9230
  const sipSessionTarget = this.client.getSipSession(destination.sipCallId);
8709
9231
 
8710
- logger$6.info('WebRTC indirect transfer', {
9232
+ logger$7.info('WebRTC indirect transfer', {
8711
9233
  sipId: sipSession ? sipSession.id : null,
8712
9234
  target: sipSessionTarget ? sipSessionTarget.id : null,
8713
9235
  });
@@ -8735,7 +9257,7 @@ class WebRTCPhone extends Emitter {
8735
9257
  return false;
8736
9258
  }
8737
9259
 
8738
- logger$6.info('WebRTC hangup', { sipId: sipSession.id });
9260
+ logger$7.info('WebRTC hangup', { sipId: sipSession.id });
8739
9261
 
8740
9262
  const sipSessionId = this.getSipSessionId(sipSession);
8741
9263
 
@@ -8780,7 +9302,7 @@ class WebRTCPhone extends Emitter {
8780
9302
  }
8781
9303
 
8782
9304
  async close() {
8783
- logger$6.info('WebRTC close');
9305
+ logger$7.info('WebRTC close');
8784
9306
 
8785
9307
  try {
8786
9308
  await Promise.race([
@@ -8788,7 +9310,7 @@ class WebRTCPhone extends Emitter {
8788
9310
  new Promise((resolve, reject) => setTimeout(() => reject(new Error('Unregister, timed out')), 3000)),
8789
9311
  ]);
8790
9312
  } catch (e) {
8791
- logger$6.error('WebRTC close, unregister error', e);
9313
+ logger$7.error('WebRTC close, unregister error', e);
8792
9314
  }
8793
9315
 
8794
9316
  this.client.close();
@@ -8806,12 +9328,12 @@ class WebRTCPhone extends Emitter {
8806
9328
  }
8807
9329
 
8808
9330
  enableRinging() {
8809
- logger$6.info('WebRTC enable ringing');
9331
+ logger$7.info('WebRTC enable ringing');
8810
9332
  this.ringingEnabled = true;
8811
9333
  }
8812
9334
 
8813
9335
  disableRinging() {
8814
- logger$6.info('WebRTC disable ringing');
9336
+ logger$7.info('WebRTC disable ringing');
8815
9337
  this.ringingEnabled = false;
8816
9338
  }
8817
9339
 
@@ -8851,7 +9373,7 @@ class WebRTCPhone extends Emitter {
8851
9373
 
8852
9374
  // Deprecated
8853
9375
  getLocalMediaStream(callSession ) {
8854
- logger$6.warn('WebRTCPhone.getLocalMediaStream is deprecated, use WebRTCPhone.getLocalStream instead');
9376
+ logger$7.warn('WebRTCPhone.getLocalMediaStream is deprecated, use WebRTCPhone.getLocalStream instead');
8855
9377
  return this.getLocalStream(callSession);
8856
9378
  }
8857
9379
 
@@ -8859,6 +9381,10 @@ class WebRTCPhone extends Emitter {
8859
9381
  return callSession ? this.client.hasLocalVideo(callSession.sipCallId) : null;
8860
9382
  }
8861
9383
 
9384
+ hasALocalVideoTrack(callSession ) {
9385
+ return callSession ? this.client.hasALocalVideoTrack(callSession.sipCallId) : null;
9386
+ }
9387
+
8862
9388
  getRemoteStream(callSession ) {
8863
9389
  return callSession ? this.client.getRemoteStream(callSession.sipCallId) : null;
8864
9390
  }
@@ -8881,7 +9407,7 @@ class WebRTCPhone extends Emitter {
8881
9407
  this.client.on(this.client.INVITE, (sipSession , wantsToDoVideo ) => {
8882
9408
  const autoAnswer = sipSession.request.getHeader('Answer-Mode') === 'Auto';
8883
9409
  const withVideo = this.allowVideo ? wantsToDoVideo : false;
8884
- logger$6.info('WebRTC invite received', { sipId: sipSession.id, withVideo, autoAnswer });
9410
+ logger$7.info('WebRTC invite received', { sipId: sipSession.id, withVideo, autoAnswer });
8885
9411
 
8886
9412
  const callSession = this._createIncomingCallSession(sipSession, withVideo, null, autoAnswer);
8887
9413
  this.incomingSessions.push(callSession.getId());
@@ -8904,7 +9430,7 @@ class WebRTCPhone extends Emitter {
8904
9430
  });
8905
9431
 
8906
9432
  this.client.on(this.client.ON_REINVITE, (...args) => {
8907
- logger$6.info('WebRTC on reinvite', {
9433
+ logger$7.info('WebRTC on reinvite', {
8908
9434
  sessionId: args[0].id,
8909
9435
  inviteId: args[1].id,
8910
9436
  updatedCalleeName: args[2],
@@ -8924,7 +9450,7 @@ class WebRTCPhone extends Emitter {
8924
9450
  });
8925
9451
 
8926
9452
  this.client.on(this.client.ACCEPTED, (sipSession ) => {
8927
- logger$6.info('WebRTC call accepted', { sipId: sipSession.id });
9453
+ logger$7.info('WebRTC call accepted', { sipId: sipSession.id });
8928
9454
 
8929
9455
  this._onCallAccepted(sipSession, this.client.hasVideo(this.getSipSessionId(sipSession)));
8930
9456
 
@@ -8935,17 +9461,17 @@ class WebRTCPhone extends Emitter {
8935
9461
  this.client.on('ended', () => {});
8936
9462
 
8937
9463
  this.client.on(this.client.ON_ERROR, e => {
8938
- logger$6.error('WebRTC error', e);
9464
+ logger$7.error('WebRTC error', e);
8939
9465
  this.eventEmitter.emit(ON_CALL_ERROR, e);
8940
9466
  });
8941
9467
 
8942
9468
  this.client.on(this.client.UNREGISTERED, () => {
8943
- logger$6.info('WebRTC unregistered');
9469
+ logger$7.info('WebRTC unregistered');
8944
9470
  this.eventEmitter.emit(ON_UNREGISTERED);
8945
9471
  });
8946
9472
 
8947
9473
  this.client.on(this.client.REGISTERED, () => {
8948
- logger$6.info('WebRTC registered', {
9474
+ logger$7.info('WebRTC registered', {
8949
9475
  shouldSendReinvite: this.shouldSendReinvite,
8950
9476
  state: this.currentSipSession ? this.currentSipSession.state : null,
8951
9477
  currentSipSession: !!this.currentSipSession,
@@ -8961,19 +9487,19 @@ class WebRTCPhone extends Emitter {
8961
9487
  try {
8962
9488
  this.sendReinvite(this.currentCallSession);
8963
9489
  } catch (e) {
8964
- logger$6.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
9490
+ logger$7.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
8965
9491
  }
8966
9492
  }
8967
9493
  });
8968
9494
 
8969
9495
  this.client.on(this.client.CONNECTED, () => {
8970
- logger$6.info('WebRTC client connected');
9496
+ logger$7.info('WebRTC client connected');
8971
9497
 
8972
9498
  this.stopHeartbeat();
8973
9499
  });
8974
9500
 
8975
9501
  this.client.on(this.client.DISCONNECTED, () => {
8976
- logger$6.info('WebRTC client disconnected');
9502
+ logger$7.info('WebRTC client disconnected');
8977
9503
 
8978
9504
  this.eventEmitter.emit(ON_UNREGISTERED);
8979
9505
 
@@ -9205,7 +9731,7 @@ var PHONE_EVENTS = /*#__PURE__*/Object.freeze({
9205
9731
 
9206
9732
  //
9207
9733
 
9208
- const logger$5 = IssueReporter$1.loggerFor('simple-phone');
9734
+ const logger$6 = IssueReporter$1.loggerFor('simple-phone');
9209
9735
  const sipLogger = IssueReporter$1.loggerFor('sip.js');
9210
9736
  const protocolLogger = IssueReporter$1.loggerFor('sip');
9211
9737
 
@@ -9312,7 +9838,7 @@ class Phone extends Emitter {
9312
9838
  async disconnect() {
9313
9839
  if (this.phone) {
9314
9840
  if (this.phone.hasAnActiveCall()) {
9315
- logger$5.info('hangup call on disconnect');
9841
+ logger$6.info('hangup call on disconnect');
9316
9842
  // $FlowFixMe
9317
9843
  await this.phone.hangup();
9318
9844
  }
@@ -9335,13 +9861,13 @@ class Phone extends Emitter {
9335
9861
  }
9336
9862
 
9337
9863
  async hangup(callSession ) {
9338
- logger$5.info('hangup via simple phone', { callId: callSession.getId() });
9864
+ logger$6.info('hangup via simple phone', { callId: callSession.getId() });
9339
9865
 
9340
9866
  return this.phone && this.phone.hangup(callSession);
9341
9867
  }
9342
9868
 
9343
9869
  async accept(callSession , cameraEnabled ) {
9344
- logger$5.info('accept via simple phone', { callId: callSession.getId(), cameraEnabled });
9870
+ logger$6.info('accept via simple phone', { callId: callSession.getId(), cameraEnabled });
9345
9871
 
9346
9872
  return this.phone && this.phone.accept(callSession, cameraEnabled);
9347
9873
  }
@@ -9361,13 +9887,18 @@ class Phone extends Emitter {
9361
9887
  return adHocConference.start();
9362
9888
  }
9363
9889
 
9364
- mute(callSession ) {
9365
- this.muteViaAPI(callSession);
9890
+ mute(callSession , withApi = true) {
9891
+ if (withApi) {
9892
+ this.muteViaAPI(callSession);
9893
+ }
9894
+
9366
9895
  return this.phone && this.phone.mute(callSession);
9367
9896
  }
9368
9897
 
9369
- unmute(callSession ) {
9370
- this.unmuteViaAPI(callSession);
9898
+ unmute(callSession , withApi = true) {
9899
+ if (withApi) {
9900
+ this.unmuteViaAPI(callSession);
9901
+ }
9371
9902
 
9372
9903
  return this.phone && this.phone.unmute(callSession);
9373
9904
  }
@@ -9375,7 +9906,7 @@ class Phone extends Emitter {
9375
9906
  muteViaAPI(callSession ) {
9376
9907
  if (callSession && callSession.callId) {
9377
9908
  Wazo.getApiClient().calld.mute(callSession.callId).catch(e => {
9378
- logger$5.error('Mute via API, error', e);
9909
+ logger$6.error('Mute via API, error', e);
9379
9910
  });
9380
9911
  }
9381
9912
  }
@@ -9383,7 +9914,7 @@ class Phone extends Emitter {
9383
9914
  unmuteViaAPI(callSession ) {
9384
9915
  if (callSession && callSession.callId) {
9385
9916
  Wazo.getApiClient().calld.unmute(callSession.callId).catch(e => {
9386
- logger$5.error('Unmute via API, error', e);
9917
+ logger$6.error('Unmute via API, error', e);
9387
9918
  });
9388
9919
  }
9389
9920
  }
@@ -9473,9 +10004,13 @@ class Phone extends Emitter {
9473
10004
  return this.phone && this.phone.hasLocalVideo(callSession);
9474
10005
  }
9475
10006
 
10007
+ hasALocalVideoTrack(callSession ) {
10008
+ return this.phone && this.phone.hasALocalVideoTrack(callSession);
10009
+ }
10010
+
9476
10011
  // @Deprecated
9477
10012
  getLocalMediaStream(callSession ) {
9478
- logger$5.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
10013
+ logger$6.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
9479
10014
 
9480
10015
  return this.phone && this.phone.getLocalStream(callSession);
9481
10016
  }
@@ -9494,20 +10029,20 @@ class Phone extends Emitter {
9494
10029
 
9495
10030
  // @Deprecated
9496
10031
  getRemoteStreamForCall(callSession ) {
9497
- logger$5.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
10032
+ logger$6.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
9498
10033
  return this.getRemoteStream(callSession);
9499
10034
  }
9500
10035
 
9501
10036
  // Returns remote streams directly from the peerConnection
9502
10037
  // @Deprecated
9503
10038
  getRemoteStreamsForCall(callSession ) {
9504
- logger$5.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
10039
+ logger$6.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
9505
10040
  return this.getLocalStream(callSession);
9506
10041
  }
9507
10042
 
9508
10043
  // @Deprecated
9509
10044
  getRemoteVideoStreamForCall(callSession ) {
9510
- logger$5.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
10045
+ logger$6.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
9511
10046
 
9512
10047
  return this.getRemoteVideoStream(callSession);
9513
10048
  }
@@ -9637,6 +10172,8 @@ const CONFERENCE_USER_PARTICIPANT_JOINED = 'conference_user_participant_joined';
9637
10172
  const CONFERENCE_USER_PARTICIPANT_LEFT = 'conference_user_participant_left';
9638
10173
  const CONFERENCE_USER_PARTICIPANT_TALK_STARTED = 'conference_user_participant_talk_started';
9639
10174
  const CONFERENCE_USER_PARTICIPANT_TALK_STOPPED = 'conference_user_participant_talk_stopped';
10175
+ const MEETING_USER_PARTICIPANT_JOINED = 'meeting_user_participant_joined';
10176
+ const MEETING_USER_PARTICIPANT_LEFT = 'meeting_user_participant_left';
9640
10177
  const SWITCHBOARD_QUEUED_CALLS_UPDATED = 'switchboard_queued_calls_updated';
9641
10178
  const SWITCHBOARD_QUEUED_CALL_ANSWERED = 'switchboard_queued_call_answered';
9642
10179
  const SWITCHBOARD_HELD_CALLS_UPDATED = 'switchboard_held_calls_updated';
@@ -9678,7 +10215,7 @@ const BLACKLIST_EVENTS = [
9678
10215
  ];
9679
10216
 
9680
10217
  const HEARTBEAT_ENGINE_VERSION = '20.09';
9681
- const logger$4 = IssueReporter$1.loggerFor('wazo-ws');
10218
+ const logger$5 = IssueReporter$1.loggerFor('wazo-ws');
9682
10219
  const messageLogger = IssueReporter$1.loggerFor('wazo-ws-message');
9683
10220
 
9684
10221
  class WebSocketClient extends Emitter {
@@ -9727,19 +10264,19 @@ class WebSocketClient extends Emitter {
9727
10264
  }
9728
10265
 
9729
10266
  connect() {
9730
- logger$4.info('connect method started', { host: this.host, token: this.token });
10267
+ logger$5.info('connect method started', { host: this.host, token: this.token });
9731
10268
  this.socket = new ReconnectingWebSocket__default['default'](this._getUrl.bind(this), [], this.options);
9732
10269
  if (this.options.binaryType) {
9733
10270
  this.socket.binaryType = this.options.binaryType;
9734
10271
  }
9735
10272
 
9736
10273
  this.socket.onopen = () => {
9737
- logger$4.info('on Wazo WS open', { method: 'connect', host: this.host });
10274
+ logger$5.info('on Wazo WS open', { method: 'connect', host: this.host });
9738
10275
  this.eventEmitter.emit(SOCKET_EVENTS$1.ON_OPEN);
9739
10276
  };
9740
10277
 
9741
10278
  this.socket.onerror = event => {
9742
- logger$4.error('on Wazo WS error', event.target);
10279
+ logger$5.error('on Wazo WS error', event.target);
9743
10280
  this.eventEmitter.emit(SOCKET_EVENTS$1.ON_ERROR, event);
9744
10281
  };
9745
10282
 
@@ -9769,7 +10306,7 @@ class WebSocketClient extends Emitter {
9769
10306
 
9770
10307
  this.socket.onclose = event => {
9771
10308
  // Can't be converted to JSON (circular structure)
9772
- logger$4.info('on Wazo WS close', {
10309
+ logger$5.info('on Wazo WS close', {
9773
10310
  reason: event.reason,
9774
10311
  code: event.code,
9775
10312
  readyState: event.target.readyState,
@@ -9787,12 +10324,12 @@ class WebSocketClient extends Emitter {
9787
10324
  };
9788
10325
 
9789
10326
  this.socket.onerror = event => {
9790
- logger$4.info('Wazo WS error', { message: event.message, code: event.code, readyState: event.target.readyState });
10327
+ logger$5.info('Wazo WS error', { message: event.message, code: event.code, readyState: event.target.readyState });
9791
10328
  };
9792
10329
  }
9793
10330
 
9794
10331
  close(force = false) {
9795
- logger$4.info('Wazo WS close', { socket: !!this.socket, host: this.host, token: this.token });
10332
+ logger$5.info('Wazo WS close', { socket: !!this.socket, host: this.host, token: this.token });
9796
10333
 
9797
10334
  if (!this.socket) {
9798
10335
  return;
@@ -9810,7 +10347,7 @@ class WebSocketClient extends Emitter {
9810
10347
 
9811
10348
  updateToken(token ) {
9812
10349
  this.token = token;
9813
- logger$4.info('Wazo WS updating token', { url: this._getUrl(), token, socket: !!this.socket });
10350
+ logger$5.info('Wazo WS updating token', { url: this._getUrl(), token, socket: !!this.socket });
9814
10351
 
9815
10352
  if (this.socket) {
9816
10353
  // If still connected, send the token to the WS
@@ -9828,7 +10365,7 @@ class WebSocketClient extends Emitter {
9828
10365
  }
9829
10366
 
9830
10367
  startHeartbeat() {
9831
- logger$4.info('Wazo WS start heartbeat', { host: this.host, token: this.token });
10368
+ logger$5.info('Wazo WS start heartbeat', { host: this.host, token: this.token });
9832
10369
 
9833
10370
  if (!this.socket) {
9834
10371
  this.heartbeat.stop();
@@ -9842,7 +10379,7 @@ class WebSocketClient extends Emitter {
9842
10379
  }
9843
10380
 
9844
10381
  stopHeartbeat() {
9845
- logger$4.info('Wazo WS stop heartbeat', { host: this.host, token: this.token });
10382
+ logger$5.info('Wazo WS stop heartbeat', { host: this.host, token: this.token });
9846
10383
 
9847
10384
  this.heartbeat.stop();
9848
10385
  }
@@ -9872,7 +10409,7 @@ class WebSocketClient extends Emitter {
9872
10409
  }
9873
10410
 
9874
10411
  reconnect(reason ) {
9875
- logger$4.info('Wazo WS reconnect', { reason, socket: !!this.socket, host: this.host, token: this.token });
10412
+ logger$5.info('Wazo WS reconnect', { reason, socket: !!this.socket, host: this.host, token: this.token });
9876
10413
  if (!this.socket) {
9877
10414
  return;
9878
10415
  }
@@ -9928,7 +10465,7 @@ class WebSocketClient extends Emitter {
9928
10465
  this.close();
9929
10466
  }
9930
10467
  const url = `wss://${this.host || ''}/api/websocketd/?token=${this.token || ''}&version=${this.version}`;
9931
- logger$4.log('Wazo WS url computed to reconnect', { url });
10468
+ logger$5.log('Wazo WS url computed to reconnect', { url });
9932
10469
 
9933
10470
  return url;
9934
10471
  }
@@ -9936,12 +10473,12 @@ class WebSocketClient extends Emitter {
9936
10473
  _onHeartbeat(message ) {
9937
10474
  if (message.payload === 'pong') {
9938
10475
  this.heartbeat.onHeartbeat();
9939
- logger$4.log('on heartbeat received from Wazo WS');
10476
+ logger$5.log('on heartbeat received from Wazo WS');
9940
10477
  }
9941
10478
  }
9942
10479
 
9943
10480
  async _onHeartbeatTimeout() {
9944
- logger$4.log('heartbeat timed out', { host: this.host, token: this.token });
10481
+ logger$5.log('heartbeat timed out', { host: this.host, token: this.token });
9945
10482
 
9946
10483
  this.close();
9947
10484
  this.eventEmitter.emit(SOCKET_EVENTS$1.ON_CLOSE, new Error('Websocket ping failure.'));
@@ -9983,6 +10520,8 @@ WebSocketClient.eventLists = [
9983
10520
  CHATD_USER_ROOM_CREATED,
9984
10521
  CONFERENCE_USER_PARTICIPANT_JOINED,
9985
10522
  CONFERENCE_USER_PARTICIPANT_LEFT,
10523
+ MEETING_USER_PARTICIPANT_JOINED,
10524
+ MEETING_USER_PARTICIPANT_LEFT,
9986
10525
  CONFERENCE_USER_PARTICIPANT_TALK_STARTED,
9987
10526
  CONFERENCE_USER_PARTICIPANT_TALK_STOPPED,
9988
10527
  SWITCHBOARD_QUEUED_CALLS_UPDATED,
@@ -10053,6 +10592,8 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
10053
10592
  CONFERENCE_USER_PARTICIPANT_LEFT: CONFERENCE_USER_PARTICIPANT_LEFT,
10054
10593
  CONFERENCE_USER_PARTICIPANT_TALK_STARTED: CONFERENCE_USER_PARTICIPANT_TALK_STARTED,
10055
10594
  CONFERENCE_USER_PARTICIPANT_TALK_STOPPED: CONFERENCE_USER_PARTICIPANT_TALK_STOPPED,
10595
+ MEETING_USER_PARTICIPANT_JOINED: MEETING_USER_PARTICIPANT_JOINED,
10596
+ MEETING_USER_PARTICIPANT_LEFT: MEETING_USER_PARTICIPANT_LEFT,
10056
10597
  SWITCHBOARD_QUEUED_CALLS_UPDATED: SWITCHBOARD_QUEUED_CALLS_UPDATED,
10057
10598
  SWITCHBOARD_QUEUED_CALL_ANSWERED: SWITCHBOARD_QUEUED_CALL_ANSWERED,
10058
10599
  SWITCHBOARD_HELD_CALLS_UPDATED: SWITCHBOARD_HELD_CALLS_UPDATED,
@@ -10094,7 +10635,7 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
10094
10635
  const { SOCKET_EVENTS, ...OTHER_EVENTS } = WebSocketClient$1;
10095
10636
  const ALL_EVENTS = [...Object.values(SOCKET_EVENTS), ...Object.values(OTHER_EVENTS)];
10096
10637
 
10097
- const logger$3 = IssueReporter$1.loggerFor('simple-ws-client');
10638
+ const logger$4 = IssueReporter$1.loggerFor('simple-ws-client');
10098
10639
 
10099
10640
  class Websocket extends Emitter {
10100
10641
 
@@ -10118,7 +10659,7 @@ class Websocket extends Emitter {
10118
10659
  }
10119
10660
 
10120
10661
  open(host , session ) {
10121
- logger$3.info('open simple WebSocket', { host, token: session.token });
10662
+ logger$4.info('open simple WebSocket', { host, token: session.token });
10122
10663
  this.ws = new WebSocketClient(
10123
10664
  {
10124
10665
  host,
@@ -10146,7 +10687,7 @@ class Websocket extends Emitter {
10146
10687
  }
10147
10688
 
10148
10689
  updateToken(token ) {
10149
- logger$3.info('update token via simple Websocket', { token, ws: !!this.ws });
10690
+ logger$4.info('update token via simple Websocket', { token, ws: !!this.ws });
10150
10691
 
10151
10692
  if (!this.ws) {
10152
10693
  return;
@@ -10174,6 +10715,145 @@ var Websocket$1 = global.wazoWebsocketInstance;
10174
10715
 
10175
10716
  //
10176
10717
 
10718
+ const logger$3 = IssueReporter$1.loggerFor('sdk-sip-room');
10719
+
10720
+ class SipRoom extends Room {
10721
+
10722
+ static async connect({ extension, constraints, audioOnly = false, extra, room } ) {
10723
+ logger$3.info('connecting to sip room', { extension, audioOnly, room: !!room });
10724
+
10725
+ if (!room) {
10726
+ await Wazo.Phone.connect();
10727
+
10728
+ const withCamera = constraints && !!constraints.video;
10729
+
10730
+ const callSession = await Wazo.Phone.call(extension, withCamera, null, audioOnly, true);
10731
+ // eslint-disable-next-line no-param-reassign
10732
+ room = new SipRoom(callSession, extension, null, null, extra);
10733
+ }
10734
+
10735
+ if (room && room.callSession && room.callSession.call) {
10736
+ room.setCallId(room.callSession.call.id);
10737
+ }
10738
+
10739
+ logger$3.info('connected to room', {
10740
+ extension: room.extension,
10741
+ });
10742
+
10743
+ return room;
10744
+ }
10745
+
10746
+ mute() {
10747
+ logger$3.info('mute sip room');
10748
+
10749
+ Wazo.Phone.mute(this.callSession, false);
10750
+
10751
+ this.sendMuteStatus();
10752
+ }
10753
+
10754
+ unmute() {
10755
+ logger$3.info('unmute sip room');
10756
+
10757
+ Wazo.Phone.unmute(this.callSession, false);
10758
+
10759
+ this.sendUnMuteStatus();
10760
+ }
10761
+
10762
+ getLocalGuestName() {
10763
+ return Wazo.Phone.phone.client.userAgent.options.displayName;
10764
+ }
10765
+
10766
+ // Overridden to not listen to websocket messages
10767
+ _transferEvents() {
10768
+ // Phone events
10769
+ Wazo.Phone.on(this.ON_MESSAGE, this._boundOnMessage);
10770
+ Wazo.Phone.on(this.ON_CHAT, this._boundOnChat);
10771
+ Wazo.Phone.on(this.ON_SIGNAL, this._boundOnSignal);
10772
+ Wazo.Phone.on(this.ON_VIDEO_INPUT_CHANGE, this._boundSaveLocalVideoStream);
10773
+
10774
+ [this.ON_AUDIO_STREAM, this.ON_VIDEO_STREAM, this.ON_REMOVE_STREAM].forEach(event =>
10775
+ Wazo.Phone.on(event, (...args) => this.eventEmitter.emit.apply(this.eventEmitter, [event, ...args])));
10776
+ }
10777
+
10778
+ _onMessage(message ) {
10779
+ // eslint-disable-next-line no-underscore-dangle
10780
+ const body = super._onMessage(message);
10781
+ if (!body) {
10782
+ return;
10783
+ }
10784
+
10785
+ const getChannel = () => body.channels[0];
10786
+
10787
+ switch (body.type) {
10788
+ case 'ConfbridgeWelcome':
10789
+ body.channels.forEach(channel => {
10790
+ this._onParticipantJoined(channel);
10791
+ });
10792
+
10793
+ break;
10794
+ case 'ConfbridgeJoin': {
10795
+ const channel = getChannel();
10796
+ this._onParticipantJoined(channel);
10797
+ break;
10798
+ }
10799
+ case 'ConfbridgeLeave': {
10800
+ const channel = getChannel();
10801
+ this._onParticipantLeft({
10802
+ data: {
10803
+ call_id: channel.id,
10804
+ },
10805
+ });
10806
+ break;
10807
+ }
10808
+ }
10809
+ }
10810
+
10811
+ async _onParticipantJoined(channel ) {
10812
+ const isLocal = channel.channelvars.WAZO_SIP_CALL_ID === this._getCurrentSipCallIs();
10813
+ const callId = channel.id;
10814
+ const ParticipantClass = isLocal ? Wazo.LocalParticipant : Wazo.RemoteParticipant;
10815
+ const name = channel.caller ? channel.caller.name : null;
10816
+ const extra = isLocal ? { guestName: this.getLocalGuestName() } : {};
10817
+ const participant = new ParticipantClass(this, {
10818
+ caller_id_name: name,
10819
+ call_id: callId,
10820
+ }, extra);
10821
+
10822
+ const participantIdx = this.participants.findIndex(other => other.callId === participant.callId);
10823
+ if (participantIdx !== -1 && name) {
10824
+ this.participants[participantIdx].name = name;
10825
+ return;
10826
+ }
10827
+
10828
+ if (isLocal) {
10829
+ // Should be updated by the Wazo WS but we don't have it for now
10830
+ if (this.callSession) {
10831
+ this.callSession.ringing = false;
10832
+ }
10833
+
10834
+ this._onLocalParticipantJoined(participant);
10835
+
10836
+ // Give some time for the stream to be updated
10837
+ setTimeout(() => {
10838
+ this.eventEmitter.emit(this.ON_JOINED, participant, this.participants);
10839
+ }, 1000);
10840
+ }
10841
+
10842
+ this.participants.push(participant);
10843
+
10844
+ this._isParticipantJoining(participant);
10845
+
10846
+ return participant;
10847
+ }
10848
+
10849
+ _getCurrentSipCallIs() {
10850
+ return Wazo.Phone.getSipSessionId(Wazo.Phone.phone.currentSipSession);
10851
+ }
10852
+
10853
+ }
10854
+
10855
+ //
10856
+
10177
10857
  class RemoteParticipant extends Participant {
10178
10858
  constructor(room , rawParticipant = {}, extra = {}) {
10179
10859
  super(room, rawParticipant, extra);
@@ -10238,9 +10918,7 @@ class Stream {
10238
10918
  return false;
10239
10919
  }
10240
10920
 
10241
- // With canvas track (used to fake upgrade in conference), we don't have a width
10242
- return this.htmlStream.getTracks().find(track => track.kind === 'video'
10243
- && track.readyState !== 'ended' && 'width' in track.getSettings());
10921
+ return this.htmlStream.getTracks().some(track => track.kind === 'video' && track.readyState !== 'ended');
10244
10922
  }
10245
10923
 
10246
10924
  get id() {
@@ -11141,6 +11819,7 @@ const Wazo = {
11141
11819
  Phone: Phone$1,
11142
11820
  Websocket: Websocket$1,
11143
11821
  Room,
11822
+ SipRoom,
11144
11823
  RemoteParticipant,
11145
11824
  LocalParticipant,
11146
11825
  Stream,
@@ -11160,6 +11839,7 @@ const Wazo = {
11160
11839
  ServerError,
11161
11840
  Call,
11162
11841
  CallLog,
11842
+ CTIPhone,
11163
11843
  Recording,
11164
11844
  ChatMessage,
11165
11845
  ChatRoom,
@@ -11175,6 +11855,8 @@ const Wazo = {
11175
11855
  CallSession,
11176
11856
  IndirectTransfer,
11177
11857
  SwitchboardCall,
11858
+ WebRTCPhone,
11859
+ Meeting,
11178
11860
  },
11179
11861
 
11180
11862
  // Api
@@ -11203,7 +11885,7 @@ if (global) {
11203
11885
  global.Wazo = Wazo;
11204
11886
  }
11205
11887
 
11206
- /* global document */
11888
+ //
11207
11889
 
11208
11890
  const SIGNAL_TYPE_PARTICIPANT_UPDATE = 'signal/PARTICIPANT_UPDATE';
11209
11891
  const SIGNAL_TYPE_PARTICIPANT_REQUEST = 'signal/PARTICIPANT_REQUEST';
@@ -11215,6 +11897,7 @@ class Room extends Emitter {
11215
11897
 
11216
11898
 
11217
11899
 
11900
+
11218
11901
 
11219
11902
 
11220
11903
 
@@ -11236,6 +11919,8 @@ class Room extends Emitter {
11236
11919
 
11237
11920
 
11238
11921
 
11922
+
11923
+
11239
11924
 
11240
11925
 
11241
11926
 
@@ -11253,6 +11938,7 @@ class Room extends Emitter {
11253
11938
  * @param extension string
11254
11939
  * @param sourceId number
11255
11940
  * @param callId string
11941
+ * @param meetingUuid string
11256
11942
  * @param extra Object
11257
11943
  */
11258
11944
  constructor(
@@ -11260,15 +11946,17 @@ class Room extends Emitter {
11260
11946
  extension ,
11261
11947
  sourceId ,
11262
11948
  callId ,
11949
+ meetingUuid ,
11263
11950
  extra = {},
11264
11951
  ) {
11265
11952
  super();
11266
- logger$1.info('room initialized', { callId, extension, sourceId });
11953
+ logger$1.info('room initialized', { callId, extension, sourceId, meetingUuid });
11267
11954
 
11268
11955
  // Represents the room callSession
11269
11956
  this.callSession = callSession;
11270
11957
  this.extension = extension;
11271
11958
  this.sourceId = sourceId;
11959
+ this.meetingUuid = meetingUuid;
11272
11960
  this.callId = callId;
11273
11961
  this.participants = [];
11274
11962
  this.connected = false;
@@ -11288,6 +11976,8 @@ class Room extends Emitter {
11288
11976
  // Sugar syntax for `room.EVENT_NAME`
11289
11977
  this.CONFERENCE_USER_PARTICIPANT_JOINED = Wazo.Websocket.CONFERENCE_USER_PARTICIPANT_JOINED;
11290
11978
  this.CONFERENCE_USER_PARTICIPANT_LEFT = Wazo.Websocket.CONFERENCE_USER_PARTICIPANT_LEFT;
11979
+ this.MEETING_USER_PARTICIPANT_JOINED = Wazo.Websocket.MEETING_USER_PARTICIPANT_JOINED;
11980
+ this.MEETING_USER_PARTICIPANT_LEFT = Wazo.Websocket.MEETING_USER_PARTICIPANT_LEFT;
11291
11981
  this.ON_SHARE_SCREEN_ENDED = Wazo.Phone.ON_SHARE_SCREEN_ENDED;
11292
11982
  this.ON_MESSAGE = Wazo.Phone.ON_MESSAGE;
11293
11983
  this.ON_CHAT = Wazo.Phone.ON_CHAT;
@@ -11322,9 +12012,10 @@ class Room extends Emitter {
11322
12012
  * @param audioOnly boolean
11323
12013
  * @param extra Object
11324
12014
  * @param room ?Room
12015
+ * @param meeting ?Meeting
11325
12016
  * @returns {Promise<Room>}
11326
12017
  */
11327
- static async connect({ extension, constraints, audioOnly = false, extra, room } ) {
12018
+ static async connect({ extension, constraints, audioOnly = false, extra, room, meeting } ) {
11328
12019
  logger$1.info('connecting to room', { extension, audioOnly, room: !!room });
11329
12020
 
11330
12021
  if (!room) {
@@ -11359,21 +12050,31 @@ class Room extends Emitter {
11359
12050
  room.setCallId(room.callSession.call.id);
11360
12051
  }
11361
12052
 
11362
- // Fetch conference source
11363
- const sources = await getApiClient().dird.fetchConferenceSource('default');
11364
- // Retrieve conference sources
11365
- const contacts = await getApiClient().dird.fetchConferenceContacts(sources.items[0]);
11366
- // Retrieve conference
11367
- const conference = contacts.find(contact => contact.numbers.find(number => number.number === extension));
12053
+ if (!meeting) {
12054
+ // Fetch conference source
12055
+ const sources = await getApiClient().dird.fetchConferenceSource('default');
12056
+ // Retrieve conference sources
12057
+ const contacts = await getApiClient().dird.fetchConferenceContacts(sources.items[0]);
12058
+ // Retrieve conference
12059
+ const conference = contacts.find(contact => contact.numbers.find(number => number.number === extension));
11368
12060
 
11369
- logger$1.info('connected to room', {
11370
- sourceId: conference ? conference.sourceId : null,
11371
- name: conference ? conference.name : null,
11372
- });
12061
+ logger$1.info('connected to room', {
12062
+ sourceId: conference ? conference.sourceId : null,
12063
+ name: conference ? conference.name : null,
12064
+ });
11373
12065
 
11374
- if (conference) {
11375
- room.setSourceId(conference.sourceId);
11376
- room.setName(conference.name);
12066
+ if (conference) {
12067
+ room.setSourceId(conference.sourceId);
12068
+ room.setName(conference.name);
12069
+ }
12070
+ } else if (meeting) {
12071
+ logger$1.info('Already connected to meeting', {
12072
+ uuid: meeting.uuid,
12073
+ name: meeting.name,
12074
+ });
12075
+
12076
+ room.setMeetingUuid(meeting.uuid);
12077
+ room.setName(meeting.name);
11377
12078
  }
11378
12079
 
11379
12080
  return room;
@@ -11401,10 +12102,8 @@ class Room extends Emitter {
11401
12102
  Wazo.Phone.phone.off(Wazo.Phone.phone.client.ON_REINVITE, this._boundOnReinvite);
11402
12103
  Wazo.Websocket.off(this.CONFERENCE_USER_PARTICIPANT_JOINED, this._boundOnParticipantJoined);
11403
12104
  Wazo.Websocket.off(this.CONFERENCE_USER_PARTICIPANT_LEFT, this._boundOnParticipantLeft);
11404
-
11405
- if (this.roomAudioElement && document.body) {
11406
- document.body.removeChild(this.roomAudioElement);
11407
- }
12105
+ Wazo.Websocket.off(this.MEETING_USER_PARTICIPANT_JOINED, this._boundOnParticipantJoined);
12106
+ Wazo.Websocket.off(this.MEETING_USER_PARTICIPANT_LEFT, this._boundOnParticipantLeft);
11408
12107
  }
11409
12108
 
11410
12109
  setSourceId(sourceId ) {
@@ -11413,6 +12112,12 @@ class Room extends Emitter {
11413
12112
  this.sourceId = sourceId;
11414
12113
  }
11415
12114
 
12115
+ setMeetingUuid(meetingUuid ) {
12116
+ logger$1.info('set meeting uuid', { meetingUuid });
12117
+
12118
+ this.meetingUuid = meetingUuid;
12119
+ }
12120
+
11416
12121
  setCallId(callId ) {
11417
12122
  logger$1.info('set room call id', { callId });
11418
12123
 
@@ -11454,14 +12159,22 @@ class Room extends Emitter {
11454
12159
  return screensharingStream;
11455
12160
  }
11456
12161
 
11457
- stopScreenSharing(restoreLocalStream = true) {
12162
+ async stopScreenSharing(restoreLocalStream = true) {
11458
12163
  logger$1.info('stop room screen sharing');
11459
12164
 
11460
- Wazo.Phone.stopScreenSharing(this.callSession, restoreLocalStream);
12165
+ const reinvited = await Wazo.Phone.stopScreenSharing(this.callSession, restoreLocalStream);
11461
12166
 
11462
12167
  if (this.localParticipant) {
11463
12168
  this.localParticipant.onStopScreensharing();
11464
12169
  }
12170
+
12171
+ if (!reinvited && this.localParticipant) {
12172
+ // When we had video and we made a screenshare we don't reinvite when stopping the screensahre
12173
+ // So not REINVITE even is fired, we have to restore the video stream manually
12174
+ const localVideoStream = Wazo.Phone.getLocalVideoStream(this.callSession);
12175
+ // $FlowFixMe
12176
+ this._associateStreamTo(localVideoStream, this.localParticipant);
12177
+ }
11465
12178
  }
11466
12179
 
11467
12180
  turnCameraOff() {
@@ -11564,6 +12277,22 @@ class Room extends Emitter {
11564
12277
  return response;
11565
12278
  }
11566
12279
 
12280
+ hasALocalVideoTrack() {
12281
+ return Wazo.Phone.hasALocalVideoTrack(this.callSession);
12282
+ }
12283
+
12284
+ getLocalStream() {
12285
+ return Wazo.Phone.getLocalStream(this.callSession);
12286
+ }
12287
+
12288
+ getRemoteStream() {
12289
+ return Wazo.Phone.getRemoteStream(this.callSession);
12290
+ }
12291
+
12292
+ getRemoteVideoStream() {
12293
+ return Wazo.Phone.getRemoteVideoStream(this.callSession);
12294
+ }
12295
+
11567
12296
  _bindEvents() {
11568
12297
  if (!Wazo.Phone.phone || !Wazo.Phone.phone.currentSipSession) {
11569
12298
  return;
@@ -11585,27 +12314,10 @@ class Room extends Emitter {
11585
12314
  logger$1.info('on room audio stream');
11586
12315
 
11587
12316
  this.audioStream = stream;
11588
- if (document.createElement) {
11589
- // $FlowFixMe
11590
- let roomAudioElement = document.getElementById('audio-room');
11591
- if (!this.roomAudioElement) {
11592
- roomAudioElement = document.createElement('audio');
11593
- // $FlowFixMe
11594
- document.body.appendChild(roomAudioElement);
11595
- }
11596
- if (!roomAudioElement) {
11597
- return;
11598
- }
11599
- this.roomAudioElement = roomAudioElement;
12317
+ if (!this.roomAudioElement) {
12318
+ const sessionId = Wazo.Phone.phone.getSipSessionId(Wazo.Phone.phone.currentSipSession);
12319
+ this.roomAudioElement = Wazo.Phone.phone.createAudioElementFor(sessionId);
11600
12320
  this.roomAudioElement.srcObject = stream;
11601
- this.roomAudioElement.autoplay = true;
11602
- this.roomAudioElement.id = 'audio-room';
11603
-
11604
- // $FlowFixMe
11605
- if (this.roomAudioElement.setSinkId) {
11606
- // $FlowFixMe
11607
- this.roomAudioElement.setSinkId(Wazo.Phone.getOutputDevice());
11608
- }
11609
12321
  }
11610
12322
  });
11611
12323
 
@@ -11680,6 +12392,9 @@ class Room extends Emitter {
11680
12392
  Wazo.Websocket.on(this.CONFERENCE_USER_PARTICIPANT_JOINED, this._boundOnParticipantJoined);
11681
12393
  Wazo.Websocket.on(this.CONFERENCE_USER_PARTICIPANT_LEFT, this._boundOnParticipantLeft);
11682
12394
 
12395
+ Wazo.Websocket.on(this.MEETING_USER_PARTICIPANT_JOINED, this._boundOnParticipantJoined);
12396
+ Wazo.Websocket.on(this.MEETING_USER_PARTICIPANT_LEFT, this._boundOnParticipantLeft);
12397
+
11683
12398
  // Phone events
11684
12399
  Wazo.Phone.on(this.ON_MESSAGE, this._boundOnMessage);
11685
12400
  Wazo.Phone.on(this.ON_CHAT, this._boundOnChat);
@@ -11690,15 +12405,15 @@ class Room extends Emitter {
11690
12405
  Wazo.Phone.on(event, (...args) => this.eventEmitter.emit.apply(this.eventEmitter, [event, ...args])));
11691
12406
  }
11692
12407
 
11693
- _onMessage(message ) {
12408
+ _onMessage(message ) {
11694
12409
  if (message.method !== 'MESSAGE') {
11695
- return;
12410
+ return null;
11696
12411
  }
11697
12412
  let body;
11698
12413
  try {
11699
12414
  body = JSON.parse(message.body);
11700
12415
  } catch (e) {
11701
- return;
12416
+ return null;
11702
12417
  }
11703
12418
 
11704
12419
  switch (body.type) {
@@ -11717,6 +12432,8 @@ class Room extends Emitter {
11717
12432
  }
11718
12433
 
11719
12434
  this.eventEmitter.emit(this.ON_MESSAGE, body);
12435
+
12436
+ return body;
11720
12437
  }
11721
12438
 
11722
12439
  _onChat(content ) {
@@ -11781,23 +12498,24 @@ class Room extends Emitter {
11781
12498
  const session = Wazo.Auth.getSession();
11782
12499
  let participants = [];
11783
12500
 
11784
- // @TODO: we could use a better function name here
11785
- const isJoining = part => {
11786
- this.__associateStreams(part);
11787
- // @VALIDATE: no need to publicize ourselves, no?
11788
- if (part instanceof RemoteParticipant) {
11789
- this.eventEmitter.emit(this.CONFERENCE_USER_PARTICIPANT_JOINED, part);
11790
- }
11791
- };
11792
-
11793
12501
  // When we join the room, we can call `getConferenceParticipantsAsUser`, not before.
11794
12502
  if (participant.user_uuid === session.uuid) {
11795
12503
  logger$1.info('room current user joined');
11796
12504
 
11797
12505
  // Retrieve participants via an API calls
11798
12506
  const conferenceId = this.sourceId || payload.data.conference_id;
11799
- const response = await getApiClient().calld.getConferenceParticipantsAsUser(conferenceId);
11800
- logger$1.info('fetching conference participants', { conferenceId });
12507
+ let response;
12508
+ try {
12509
+ if (this.meetingUuid) {
12510
+ logger$1.info('fetching meeting participants', { meetingUuid: this.meetingUuid });
12511
+ response = await getApiClient().calld.getMeetingParticipantsAsUser(this.meetingUuid);
12512
+ } else {
12513
+ logger$1.info('fetching conference participants', { conferenceId });
12514
+ response = await getApiClient().calld.getConferenceParticipantsAsUser(conferenceId);
12515
+ }
12516
+ } catch (e) {
12517
+ logger$1.error('room participants fetching, error', e);
12518
+ }
11801
12519
  if (response) {
11802
12520
  logger$1.info('conference participants fetched', { nb: response.items.length });
11803
12521
  participants = response.items.map(item => {
@@ -11812,25 +12530,10 @@ class Room extends Emitter {
11812
12530
 
11813
12531
  const localParticipant = participants.find(someParticipant => someParticipant instanceof Wazo.LocalParticipant);
11814
12532
  if (!this.localParticipant && localParticipant) {
11815
- this.localParticipant = localParticipant;
11816
-
11817
- const localVideoStream = this._getLocalVideoStream();
11818
- if (localVideoStream) {
11819
- this._saveLocalVideoStream(localVideoStream);
11820
- }
11821
-
11822
- this.connected = true;
11823
-
11824
- // we're in the room, now let's request everyone's status
11825
- if (this.localParticipant) {
11826
- this.sendSignal({
11827
- type: SIGNAL_TYPE_PARTICIPANT_REQUEST,
11828
- origin: this.localParticipant.getStatus(),
11829
- });
11830
- }
12533
+ this._onLocalParticipantJoined(localParticipant);
11831
12534
  }
11832
12535
 
11833
- participants.forEach(someParticipant => isJoining(someParticipant));
12536
+ participants.forEach(someParticipant => this._isParticipantJoining(someParticipant));
11834
12537
  this.eventEmitter.emit(this.ON_JOINED, localParticipant, participants);
11835
12538
  }
11836
12539
 
@@ -11845,12 +12548,41 @@ class Room extends Emitter {
11845
12548
 
11846
12549
  if (remoteParticipant) {
11847
12550
  this.participants.push(remoteParticipant);
11848
- isJoining(remoteParticipant);
12551
+ this._isParticipantJoining(remoteParticipant);
11849
12552
  }
11850
12553
 
11851
12554
  return remoteParticipant;
11852
12555
  }
11853
12556
 
12557
+ _onLocalParticipantJoined(localParticipant ) {
12558
+ this.localParticipant = localParticipant;
12559
+
12560
+ const localVideoStream = this._getLocalVideoStream();
12561
+ if (localVideoStream) {
12562
+ this._saveLocalVideoStream(localVideoStream);
12563
+ }
12564
+
12565
+ this.connected = true;
12566
+
12567
+ localParticipant.broadcastStatus();
12568
+
12569
+ // we're in the room, now let's request everyone's status
12570
+ if (this.localParticipant) {
12571
+ this.sendSignal({
12572
+ type: SIGNAL_TYPE_PARTICIPANT_REQUEST,
12573
+ origin: this.localParticipant.getStatus(),
12574
+ });
12575
+ }
12576
+ }
12577
+
12578
+ _isParticipantJoining(participant ) {
12579
+ this.__associateStreams(participant);
12580
+ // @VALIDATE: no need to publicize ourselves, no?
12581
+ if (participant instanceof RemoteParticipant) {
12582
+ this.eventEmitter.emit(this.CONFERENCE_USER_PARTICIPANT_JOINED, participant);
12583
+ }
12584
+ }
12585
+
11854
12586
  _saveLocalVideoStream(stream ) {
11855
12587
  const { localParticipant } = this;
11856
12588
 
@@ -11896,9 +12628,11 @@ class Room extends Emitter {
11896
12628
  _onParticipantTrackUpdate(oldParticipant , update ) {
11897
12629
  const newParticipant = oldParticipant;
11898
12630
 
11899
- const { trackId } = this._callIdStreamIdMap[newParticipant.callId] || {};
12631
+ const { trackId, streamId } = this._callIdStreamIdMap[newParticipant.callId] || {};
11900
12632
  const pc = Wazo.Phone.phone.currentSipSession.sessionDescriptionHandler.peerConnection;
11901
- const stream = pc.getRemoteStreams().find(someStream => someStream.getTracks().some(track => track.id === trackId));
12633
+ // Can't use `getReceivers` here because on FF we make the mapping based on the streamId
12634
+ const stream = pc.getRemoteStreams().find(someStream =>
12635
+ someStream.id === streamId || someStream.getTracks().some(track => track.id === trackId));
11902
12636
 
11903
12637
  if (update === 'downgrade') {
11904
12638
  newParticipant.streams = [];
@@ -11928,15 +12662,41 @@ class Room extends Emitter {
11928
12662
  return;
11929
12663
  }
11930
12664
 
11931
- if (this._unassociatedVideoStreams[trackId]) {
12665
+ const streamId = this._getStreamIdFrTrackId(trackId);
12666
+ const key = this._getUnassociatedMapIdFromTrackIdOrStreamId(trackId, streamId);
12667
+ const stream = this._unassociatedVideoStreams[key];
12668
+
12669
+ if (stream) {
11932
12670
  // Try to associate stream
11933
- this._associateStreamTo(this._unassociatedVideoStreams[trackId], participant);
12671
+ this._associateStreamTo(stream, participant);
11934
12672
 
11935
- delete this._unassociatedVideoStreams[trackId];
12673
+ delete this._unassociatedVideoStreams[key];
11936
12674
  delete this._unassociatedParticipants[participant.callId];
11937
12675
  }
11938
12676
  }
11939
12677
 
12678
+ _getUnassociatedMapIdFromTrackIdOrStreamId(trackId , streamId ) {
12679
+ // Find by trackId
12680
+ if (trackId in this._unassociatedVideoStreams) {
12681
+ return trackId;
12682
+ }
12683
+
12684
+ // Find by streamId
12685
+ if (streamId && streamId in this._unassociatedVideoStreams) {
12686
+ return streamId;
12687
+ }
12688
+
12689
+ // Find in all the streams by streamId (used on FF where we can't map by trackId)
12690
+ const idx = Object.values(this._unassociatedVideoStreams).findIndex((stream ) => stream.id === streamId);
12691
+ return idx === -1 ? null : Object.keys(this._unassociatedVideoStreams)[idx];
12692
+ }
12693
+
12694
+ _getStreamIdFrTrackId(trackId ) {
12695
+ const mapping = Object.values(this._callIdStreamIdMap).find((map ) => map.trackId === trackId);
12696
+
12697
+ return mapping ? mapping.streamId : null;
12698
+ }
12699
+
11940
12700
  _associateStreamTo(rawStream , participant ) {
11941
12701
  const stream = new Wazo.Stream(rawStream, participant);
11942
12702
  participant.streams.push(stream);
@@ -11994,6 +12754,7 @@ class Participant extends Emitter {
11994
12754
 
11995
12755
 
11996
12756
  /**
12757
+ * @param room Room The room where the participant is
11997
12758
  * @param rawParticipant string Participant sent via the Wazo WS
11998
12759
  * @param extra Object extra status of the participant
11999
12760
  */
@@ -12221,6 +12982,11 @@ class Participant extends Emitter {
12221
12982
  // Poor man's object comparison
12222
12983
  if (typeof status.extra !== 'undefined' && JSON.stringify(this.extra) !== JSON.stringify(status.extra)) {
12223
12984
  this.extra = { ...this.extra, ...status.extra };
12985
+
12986
+ if (this.extra.contact && !(this.extra.contact instanceof Contact)) {
12987
+ this.extra.contact = new Contact(this.extra.contact);
12988
+ }
12989
+
12224
12990
  this.triggerUpdate(this.ON_EXTRA_CHANGE, broadcast);
12225
12991
  }
12226
12992
  }