@wazo/sdk 0.37.2 → 0.37.6

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 (99) hide show
  1. package/dist/wazo-sdk.js +5 -5
  2. package/esm/__tests__/api-client.test.js +84 -22
  3. package/esm/__tests__/web-rtc-client.test.js +156 -55
  4. package/esm/api/call-logd.js +10 -22
  5. package/esm/api/calld.js +3 -0
  6. package/esm/api/confd.js +71 -0
  7. package/esm/api-client.js +84 -22
  8. package/esm/checker/Checker.js +160 -55
  9. package/esm/checker/checks/aor.js +84 -22
  10. package/esm/checker/checks/api.js +84 -22
  11. package/esm/checker/checks/index.js +160 -55
  12. package/esm/checker/checks/wazo-websocket.js +4 -0
  13. package/esm/checker/checks/webrtc-transport.js +156 -55
  14. package/esm/checker/checks/webrtc.js +156 -55
  15. package/esm/domain/AdHocAPIConference.js +84 -22
  16. package/esm/domain/CallLog.js +10 -22
  17. package/esm/domain/Features.js +84 -22
  18. package/esm/domain/Meeting.js +71 -0
  19. package/esm/domain/Phone/CTIPhone.js +84 -22
  20. package/esm/domain/Phone/WebRTCPhone.js +22 -8
  21. package/esm/domain/__tests__/CallLog.test.js +10 -22
  22. package/esm/index.js +726 -371
  23. package/esm/lib/WazoSessionDescriptionHandler.js +17 -9
  24. package/esm/service/CallApi.js +84 -22
  25. package/esm/service/getApiClient.js +84 -22
  26. package/esm/simple/Auth.js +717 -363
  27. package/esm/simple/Configuration.js +717 -363
  28. package/esm/simple/Directory.js +84 -22
  29. package/esm/simple/Phone.js +709 -355
  30. package/esm/simple/Websocket.js +6 -0
  31. package/esm/simple/index.js +719 -365
  32. package/esm/simple/room/LocalParticipant.js +689 -335
  33. package/esm/simple/room/Participant.js +689 -335
  34. package/esm/simple/room/RemoteParticipant.js +689 -335
  35. package/esm/simple/room/Room.js +689 -335
  36. package/esm/simple/room/SipRoom.js +13001 -0
  37. package/esm/simple/room/Stream.js +719 -365
  38. package/esm/simple/room/__tests__/RemoteParticipant.test.js +4130 -3774
  39. package/esm/simple/utils.js +719 -365
  40. package/esm/web-rtc-client.js +156 -55
  41. package/esm/websocket-client.js +5 -1
  42. package/lib/__tests__/api-client.test.js +84 -22
  43. package/lib/__tests__/web-rtc-client.test.js +156 -55
  44. package/lib/api/call-logd.js +10 -22
  45. package/lib/api/calld.js +3 -0
  46. package/lib/api/confd.js +71 -0
  47. package/lib/api-client.js +84 -22
  48. package/lib/checker/Checker.js +160 -55
  49. package/lib/checker/checks/aor.js +84 -22
  50. package/lib/checker/checks/api.js +84 -22
  51. package/lib/checker/checks/index.js +160 -55
  52. package/lib/checker/checks/wazo-websocket.js +4 -0
  53. package/lib/checker/checks/webrtc-transport.js +156 -55
  54. package/lib/checker/checks/webrtc.js +156 -55
  55. package/lib/domain/AdHocAPIConference.js +84 -22
  56. package/lib/domain/CallLog.js +10 -22
  57. package/lib/domain/Features.js +84 -22
  58. package/lib/domain/Meeting.js +73 -0
  59. package/lib/domain/Phone/CTIPhone.js +84 -22
  60. package/lib/domain/Phone/WebRTCPhone.js +22 -8
  61. package/lib/domain/__tests__/CallLog.test.js +10 -22
  62. package/lib/index.js +726 -371
  63. package/lib/lib/WazoSessionDescriptionHandler.js +17 -9
  64. package/lib/service/CallApi.js +84 -22
  65. package/lib/service/getApiClient.js +84 -22
  66. package/lib/simple/Auth.js +717 -363
  67. package/lib/simple/Configuration.js +717 -363
  68. package/lib/simple/Directory.js +84 -22
  69. package/lib/simple/Phone.js +709 -355
  70. package/lib/simple/Websocket.js +6 -0
  71. package/lib/simple/index.js +719 -365
  72. package/lib/simple/room/LocalParticipant.js +689 -335
  73. package/lib/simple/room/Participant.js +689 -335
  74. package/lib/simple/room/RemoteParticipant.js +689 -335
  75. package/lib/simple/room/Room.js +689 -335
  76. package/lib/simple/room/SipRoom.js +13011 -0
  77. package/lib/simple/room/Stream.js +719 -365
  78. package/lib/simple/room/__tests__/RemoteParticipant.test.js +4131 -3775
  79. package/lib/simple/utils.js +719 -365
  80. package/lib/web-rtc-client.js +156 -55
  81. package/lib/websocket-client.js +6 -0
  82. package/package.json +1 -1
  83. package/src/api/calld.js +3 -0
  84. package/src/api/confd.js +13 -0
  85. package/src/domain/CallLog.js +10 -22
  86. package/src/domain/Meeting.js +59 -0
  87. package/src/domain/Phone/WebRTCPhone.js +22 -8
  88. package/src/index.js +2 -0
  89. package/src/lib/WazoSessionDescriptionHandler.js +17 -9
  90. package/src/simple/Phone.js +13 -4
  91. package/src/simple/index.js +4 -0
  92. package/src/simple/room/Participant.js +7 -0
  93. package/src/simple/room/Room.js +158 -79
  94. package/src/simple/room/SipRoom.js +147 -0
  95. package/src/simple/room/Stream.js +1 -3
  96. package/src/simple/room/__tests__/RemoteParticipant.test.js +3 -2
  97. package/src/types/WebSocketMessage.js +21 -0
  98. package/src/web-rtc-client.js +55 -24
  99. package/src/websocket-client.js +4 -0
@@ -369,7 +369,7 @@ var IssueReporter$1 = new IssueReporter();
369
369
 
370
370
  const methods = ['head', 'get', 'post', 'put', 'delete'];
371
371
 
372
- const logger$b = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
372
+ const logger$c = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
373
373
 
374
374
  // Use a function here to be able to mock it in tests
375
375
  const realFetch = () => {
@@ -508,7 +508,7 @@ class ApiRequester {
508
508
  };
509
509
 
510
510
  if (this.refreshTokenPromise) {
511
- logger$b.info('A token is already refreshing, waiting ...', { url });
511
+ logger$c.info('A token is already refreshing, waiting ...', { url });
512
512
  await this.refreshTokenPromise;
513
513
  }
514
514
 
@@ -528,7 +528,7 @@ class ApiRequester {
528
528
  return promise.then(async (err ) => {
529
529
  // Check if the token is still valid
530
530
  if (firstCall && this._checkTokenExpired(response, err)) {
531
- logger$b.warn('token expired', { error: err.reason });
531
+ logger$c.warn('token expired', { error: err.reason });
532
532
  // Replay the call after refreshing the token
533
533
  return this._replayWithNewToken(err, path, method, body, headers, parse);
534
534
  }
@@ -538,7 +538,7 @@ class ApiRequester {
538
538
  : exceptionClass.fromResponse(err, response.status);
539
539
 
540
540
  if (this.shouldLogErrors) {
541
- logger$b.error('API error', error);
541
+ logger$c.error('API error', error);
542
542
  }
543
543
 
544
544
  throw error;
@@ -548,7 +548,7 @@ class ApiRequester {
548
548
  return newParse(response, isJson);
549
549
  }).catch(error => {
550
550
  if (this.shouldLogErrors) {
551
- logger$b.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
551
+ logger$c.error('Fetch failed', { url, options, message: error.message, stack: error.stack });
552
552
  }
553
553
 
554
554
  throw error;
@@ -576,13 +576,13 @@ class ApiRequester {
576
576
  ) {
577
577
  const isTokenNotFound = this._isTokenNotFound(err);
578
578
  let newPath = path;
579
- logger$b.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
579
+ logger$c.info('refreshing token', { inProgress: !!this.refreshTokenPromise });
580
580
 
581
581
  this.refreshTokenPromise = this.refreshTokenPromise || this.refreshTokenCallback();
582
582
 
583
583
  return this.refreshTokenPromise.then(() => {
584
584
  this.refreshTokenPromise = null;
585
- logger$b.info('token refreshed', { isTokenNotFound });
585
+ logger$c.info('token refreshed', { isTokenNotFound });
586
586
  if (isTokenNotFound) {
587
587
  const pathParts = path.split('/');
588
588
  pathParts.pop();
@@ -2524,6 +2524,65 @@ class ExternalApp {
2524
2524
  }
2525
2525
  }
2526
2526
 
2527
+ //
2528
+
2529
+
2530
+
2531
+
2532
+
2533
+
2534
+
2535
+
2536
+
2537
+
2538
+
2539
+ class Meeting {
2540
+
2541
+
2542
+
2543
+
2544
+
2545
+
2546
+
2547
+
2548
+
2549
+
2550
+ static parse(plain ) {
2551
+ return new Meeting({
2552
+ guestSipAuthorization: plain.guest_sip_authorization,
2553
+ hostname: plain.hostname,
2554
+ name: plain.name,
2555
+ ownerUuids: plain.owner_uuids,
2556
+ port: plain.port,
2557
+ uuid: plain.uuid,
2558
+ number: plain.number,
2559
+ });
2560
+ }
2561
+
2562
+ static newFrom(meeting ) {
2563
+ return newFrom(meeting, Meeting);
2564
+ }
2565
+
2566
+ constructor({ uuid, name, guestSipAuthorization, ownerUuids, port, hostname, number } = {}) {
2567
+ this.guestSipAuthorization = guestSipAuthorization;
2568
+ this.hostname = hostname;
2569
+ this.name = name;
2570
+ this.ownerUuids = ownerUuids;
2571
+ this.port = port;
2572
+ this.uuid = uuid;
2573
+ this.number = number;
2574
+
2575
+ // Useful to compare instead of instanceof with minified code
2576
+ this.type = 'Meeting';
2577
+ }
2578
+
2579
+ getGuestSipCredentials() {
2580
+ // eslint-disable-next-line no-undef
2581
+ const [username, secret] = atob(this.guestSipAuthorization).split(':');
2582
+ return { username, secret };
2583
+ }
2584
+ }
2585
+
2527
2586
  /* */
2528
2587
 
2529
2588
  var confdMethods = (client , baseUrl ) => ({
@@ -2588,6 +2647,18 @@ var confdMethods = (client , baseUrl ) => ({
2588
2647
  return null;
2589
2648
  }
2590
2649
  },
2650
+
2651
+ createMyMeeting: (name ) =>
2652
+ client.post(`${baseUrl}/users/me/meetings`, { name }).then(Meeting.parse),
2653
+
2654
+ deleteMyMeeting: (meetingUuid ) =>
2655
+ client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
2656
+
2657
+ getMeeting: (meetingUuid ) =>
2658
+ client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
2659
+
2660
+ guestGetMeeting: (meetingUuid ) =>
2661
+ client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
2591
2662
  });
2592
2663
 
2593
2664
  //
@@ -3530,7 +3601,11 @@ class CallLog {
3530
3601
  answered: plain.answered,
3531
3602
  callDirection: plain.call_direction,
3532
3603
  destination: {
3533
- extension: plain.requested_extension || plain.destination_extension,
3604
+ // @TEMP: Temporarily assuming empty numbers are meetings
3605
+ // which is admittedly a very dangerous assumption. Did i mention it was temporary?
3606
+ extension: plain.requested_extension
3607
+ || plain.destination_extension
3608
+ || `meeting-${plain.requested_name || plain.destination_name || ''}`,
3534
3609
  name: plain.requested_name || plain.destination_name || '',
3535
3610
  },
3536
3611
  source: {
@@ -3546,27 +3621,11 @@ class CallLog {
3546
3621
  }
3547
3622
 
3548
3623
  static parseNew(plain , session ) {
3549
- return new CallLog({
3550
- answer: plain.answer ? moment__default['default'](plain.answer).toDate() : null,
3551
- answered: plain.answered,
3552
- callDirection: plain.call_direction,
3553
- destination: {
3554
- extension: plain.requested_extension || plain.destination_extension,
3555
- name: plain.requested_name || plain.destination_name || '',
3556
- },
3557
- source: {
3558
- extension: plain.source_extension,
3559
- name: plain.source_name,
3560
- },
3561
- id: plain.id,
3562
- duration: (plain.duration || 0) * 1000, // duration is in seconds
3563
- start: moment__default['default'](plain.start).toDate(),
3564
- end: plain.end ? moment__default['default'](plain.end).toDate() : null,
3565
- recordings: Recording.parseMany(plain.recordings),
3566
- // @TODO: FIXME add verification declined vs missed call
3567
- newMissedCall: session
3568
- && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered,
3569
- });
3624
+ const callLog = CallLog.parse(plain);
3625
+ // @TODO: FIXME add verification declined vs missed call
3626
+ callLog.newMissedCall = session
3627
+ && session.hasExtension(plain.requested_extension || plain.destination_extension) && !plain.answered;
3628
+ return callLog;
3570
3629
  }
3571
3630
 
3572
3631
  static newFrom(profile ) {
@@ -3831,7 +3890,7 @@ const TRANSFER_FLOW_BLIND = 'blind';
3831
3890
 
3832
3891
  // const MINIMUM_WAZO_ENGINE_VERSION_FOR_CTI_HOLD = '20.11';
3833
3892
 
3834
- const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3893
+ const logger$b = IssueReporter$1 ? IssueReporter$1.loggerFor('cti-phone') : console;
3835
3894
 
3836
3895
  class CTIPhone extends Emitter {
3837
3896
 
@@ -3844,7 +3903,7 @@ class CTIPhone extends Emitter {
3844
3903
 
3845
3904
  constructor(session , isMobile = false, callbackAllLines = false) {
3846
3905
  super();
3847
- logger$a.info('CTI Phone created');
3906
+ logger$b.info('CTI Phone created');
3848
3907
  this.session = session;
3849
3908
  this.isMobile = isMobile;
3850
3909
  this.callbackAllLines = callbackAllLines;
@@ -3905,7 +3964,7 @@ class CTIPhone extends Emitter {
3905
3964
  }
3906
3965
 
3907
3966
  async makeCall(number , line ) {
3908
- logger$a.info('make CTI call', { number });
3967
+ logger$b.info('make CTI call', { number });
3909
3968
 
3910
3969
  if (!number) {
3911
3970
  return null;
@@ -3928,7 +3987,7 @@ class CTIPhone extends Emitter {
3928
3987
  if (!callSession) {
3929
3988
  return Promise.resolve(null);
3930
3989
  }
3931
- logger$a.info('accept CTI call', { callId: callSession.getId(), number: callSession.number });
3990
+ logger$b.info('accept CTI call', { callId: callSession.getId(), number: callSession.number });
3932
3991
 
3933
3992
  if (!this.currentCall) {
3934
3993
  this.currentCall = callSession.call;
@@ -3941,7 +4000,7 @@ class CTIPhone extends Emitter {
3941
4000
  if (!callSession) {
3942
4001
  return;
3943
4002
  }
3944
- logger$a.info('end current CTI call', { callId: callSession.getId(), number: callSession.number });
4003
+ logger$b.info('end current CTI call', { callId: callSession.getId(), number: callSession.number });
3945
4004
 
3946
4005
  this.currentCall = undefined;
3947
4006
  this.eventEmitter.emit('onCallEnded', callSession);
@@ -3951,7 +4010,7 @@ class CTIPhone extends Emitter {
3951
4010
  if (!callSession) {
3952
4011
  return Promise.resolve(false);
3953
4012
  }
3954
- logger$a.info('hangup CTI call', { callId: callSession.getId(), number: callSession.number });
4013
+ logger$b.info('hangup CTI call', { callId: callSession.getId(), number: callSession.number });
3955
4014
 
3956
4015
  try {
3957
4016
  await CallApi.cancelCall(callSession);
@@ -3962,7 +4021,7 @@ class CTIPhone extends Emitter {
3962
4021
  this.eventEmitter.emit('onCallEnded', callSession);
3963
4022
  return true;
3964
4023
  } catch (e) {
3965
- logger$a.error('hangup CTI call, error', e);
4024
+ logger$b.error('hangup CTI call, error', e);
3966
4025
 
3967
4026
  this.eventEmitter.emit('onCallFailed', callSession);
3968
4027
  return false;
@@ -3975,7 +4034,7 @@ class CTIPhone extends Emitter {
3975
4034
  if (!callSession) {
3976
4035
  return;
3977
4036
  }
3978
- logger$a.info('reject CTI call', { callId: callSession.getId(), number: callSession.number });
4037
+ logger$b.info('reject CTI call', { callId: callSession.getId(), number: callSession.number });
3979
4038
 
3980
4039
  await CallApi.cancelCall(callSession);
3981
4040
  this.eventEmitter.emit('onCallEnded', callSession);
@@ -3985,7 +4044,7 @@ class CTIPhone extends Emitter {
3985
4044
  if (!callSession) {
3986
4045
  return;
3987
4046
  }
3988
- logger$a.info('transfer CTI call', { callId: callSession.getId(), number: callSession.number, to: number });
4047
+ logger$b.info('transfer CTI call', { callId: callSession.getId(), number: callSession.number, to: number });
3989
4048
 
3990
4049
  await CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_BLIND);
3991
4050
  }
@@ -3996,19 +4055,19 @@ class CTIPhone extends Emitter {
3996
4055
  if (!callSession) {
3997
4056
  return;
3998
4057
  }
3999
- logger$a.info('indirect CTI transfer', { callId: callSession.getId(), number: callSession.number, to: number });
4058
+ logger$b.info('indirect CTI transfer', { callId: callSession.getId(), number: callSession.number, to: number });
4000
4059
 
4001
4060
  return CallApi.transferCall(callSession.callId, number, TRANSFER_FLOW_ATTENDED);
4002
4061
  }
4003
4062
 
4004
4063
  async cancelCTIIndirectTransfer(transferId ) {
4005
- logger$a.info('cancel CTI transfer', { transferId });
4064
+ logger$b.info('cancel CTI transfer', { transferId });
4006
4065
 
4007
4066
  return CallApi.cancelCallTransfer(transferId);
4008
4067
  }
4009
4068
 
4010
4069
  async confirmCTIIndirectTransfer(transferId ) {
4011
- logger$a.info('confirm CTI transfer', { transferId });
4070
+ logger$b.info('confirm CTI transfer', { transferId });
4012
4071
 
4013
4072
  return CallApi.confirmCallTransfer(transferId);
4014
4073
  }
@@ -4017,19 +4076,19 @@ class CTIPhone extends Emitter {
4017
4076
  if (!callSession) {
4018
4077
  return;
4019
4078
  }
4020
- logger$a.info('send CTI key', { callId: callSession.getId(), number: callSession.number, digits });
4079
+ logger$b.info('send CTI key', { callId: callSession.getId(), number: callSession.number, digits });
4021
4080
 
4022
4081
  return CallApi.sendDTMF(callSession.callId, digits);
4023
4082
  }
4024
4083
 
4025
4084
  onConnectionMade() {
4026
- logger$a.info('on CTI connection made');
4085
+ logger$b.info('on CTI connection made');
4027
4086
 
4028
4087
  this.eventEmitter.emit('onCallAccepted');
4029
4088
  }
4030
4089
 
4031
4090
  async close() {
4032
- logger$a.info('CTI close');
4091
+ logger$b.info('CTI close');
4033
4092
 
4034
4093
  return Promise.resolve();
4035
4094
  }
@@ -4038,7 +4097,7 @@ class CTIPhone extends Emitter {
4038
4097
  if (!callSession) {
4039
4098
  return;
4040
4099
  }
4041
- logger$a.info('CTI hold', { callId: callSession.getId(), number: callSession.number });
4100
+ logger$b.info('CTI hold', { callId: callSession.getId(), number: callSession.number });
4042
4101
 
4043
4102
  return CallApi.hold(callSession.callId);
4044
4103
  }
@@ -4047,7 +4106,7 @@ class CTIPhone extends Emitter {
4047
4106
  if (!callSession) {
4048
4107
  return;
4049
4108
  }
4050
- logger$a.info('CTI resume', { callId: callSession.getId(), number: callSession.number });
4109
+ logger$b.info('CTI resume', { callId: callSession.getId(), number: callSession.number });
4051
4110
 
4052
4111
  return CallApi.resume(callSession.callId);
4053
4112
  }
@@ -4056,7 +4115,7 @@ class CTIPhone extends Emitter {
4056
4115
  if (!callSession) {
4057
4116
  return;
4058
4117
  }
4059
- logger$a.info('CTI mute', { callId: callSession.getId(), number: callSession.number });
4118
+ logger$b.info('CTI mute', { callId: callSession.getId(), number: callSession.number });
4060
4119
 
4061
4120
  return CallApi.mute(callSession.callId);
4062
4121
  }
@@ -4065,7 +4124,7 @@ class CTIPhone extends Emitter {
4065
4124
  if (!callSession) {
4066
4125
  return;
4067
4126
  }
4068
- logger$a.info('CTI unmute', { callId: callSession.getId(), number: callSession.number });
4127
+ logger$b.info('CTI unmute', { callId: callSession.getId(), number: callSession.number });
4069
4128
 
4070
4129
  return CallApi.unmute(callSession.callId);
4071
4130
  }
@@ -4711,6 +4770,9 @@ var calldMethods = (client , baseUrl ) => ({
4711
4770
  getConferenceParticipantsAsUser: async (conferenceId ) =>
4712
4771
  client.get(`${baseUrl}/users/me/conferences/${conferenceId}/participants`),
4713
4772
 
4773
+ getMeetingParticipantsAsUser: async (meetingUuid ) =>
4774
+ client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
4775
+
4714
4776
  listTrunks: () => client.get(`${baseUrl}/trunks`),
4715
4777
 
4716
4778
  mute: (callId ) =>
@@ -5064,7 +5126,7 @@ const AGENTD_VERSION = '1.0';
5064
5126
  const WEBHOOKD_VERSION = '1.0';
5065
5127
  const AMID_VERSION = '1.0';
5066
5128
 
5067
- const logger$9 = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
5129
+ const logger$a = IssueReporter$1 ? IssueReporter$1.loggerFor('api') : console;
5068
5130
 
5069
5131
  class ApiClient {
5070
5132
 
@@ -5116,12 +5178,12 @@ class ApiClient {
5116
5178
  }
5117
5179
 
5118
5180
  async forceRefreshToken() {
5119
- logger$9.info('forcing refresh token, calling callback');
5181
+ logger$a.info('forcing refresh token, calling callback');
5120
5182
  return this.refreshTokenCallback();
5121
5183
  }
5122
5184
 
5123
5185
  async refreshTokenCallback() {
5124
- logger$9.info('refresh token callback called', {
5186
+ logger$a.info('refresh token callback called', {
5125
5187
  refreshToken: this.refreshToken,
5126
5188
  refreshBackend: this.refreshBackend,
5127
5189
  refreshExpiration: this.refreshExpiration,
@@ -5139,7 +5201,7 @@ class ApiClient {
5139
5201
  this.isMobile,
5140
5202
  );
5141
5203
 
5142
- logger$9.info('token refreshed', { token: session.token });
5204
+ logger$a.info('token refreshed', { token: session.token });
5143
5205
 
5144
5206
  if (this.onRefreshToken) {
5145
5207
  this.onRefreshToken(session.token, session);
@@ -5280,7 +5342,7 @@ var getApiClient = (forServer ) => {
5280
5342
  class InvalidSubscription extends Error {}
5281
5343
  class InvalidAuthorization extends Error {}
5282
5344
 
5283
- const logger$8 = IssueReporter$1.loggerFor('simple-auth');
5345
+ const logger$9 = IssueReporter$1.loggerFor('simple-auth');
5284
5346
 
5285
5347
  class Auth {
5286
5348
 
@@ -5315,7 +5377,7 @@ class Auth {
5315
5377
  setApiClientId(this.clientId);
5316
5378
  setRefreshExpiration(this.expiration);
5317
5379
  setOnRefreshToken((token , session ) => {
5318
- logger$8.info('on refresh token done', { token });
5380
+ logger$9.info('on refresh token done', { token });
5319
5381
  setApiToken(token);
5320
5382
  Wazo.Websocket.updateToken(token);
5321
5383
 
@@ -5874,7 +5936,9 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5874
5936
  .then(() => {
5875
5937
  if (isConference && (options.constraints && !options.constraints.video) && !('hold' in options) && !audioOnly) {
5876
5938
  // Add a video an empty bundle to be able to replaceTrack when joining a conference without video
5877
- this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5939
+ if (this.peerConnection.addTransceiver) {
5940
+ this.peerConnection.addTransceiver('video', { streams: [this._localMediaStream], direction: 'sendrecv' });
5941
+ }
5878
5942
  }
5879
5943
  })
5880
5944
  .then(() => this.createLocalOfferOrAnswer(options))
@@ -5901,12 +5965,6 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
5901
5965
  };
5902
5966
  })
5903
5967
  .then((sessionDescription) => this.applyModifiers(sessionDescription, modifiers))
5904
- .then((sessionDescription) => {
5905
- // Set new constraints to avoid the constraints check issue in `sdh.getLocalMediaStream` later.
5906
- this.localMediaStreamConstraints = options.constraints;
5907
-
5908
- return sessionDescription;
5909
- })
5910
5968
  .then((sessionDescription) => ({ body: sessionDescription.sdp, contentType: 'application/sdp' }))
5911
5969
  .catch((error) => {
5912
5970
  wazoLogger.error('error when creating media', error);
@@ -6101,6 +6159,9 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
6101
6159
 
6102
6160
  // set the transceiver direction to the answer direction
6103
6161
  this._peerConnection.getTransceivers().forEach((transceiver) => {
6162
+ if (transceiver.stopped) {
6163
+ return;
6164
+ }
6104
6165
  if (transceiver.direction /* guarding, but should always be true */) {
6105
6166
  const { receiver } = transceiver;
6106
6167
  if (isConference && audioOnly && receiver.track && receiver.track.kind === 'video') {
@@ -6145,10 +6206,15 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
6145
6206
  if (kind !== 'audio' && kind !== 'video') {
6146
6207
  throw new Error(`Unknown new track kind ${kind}.`);
6147
6208
  }
6148
- const sender = pc.getSenders().find((otherSender) => otherSender.track && otherSender.track.kind === kind);
6209
+ const sender = pc.getSenders && pc.getSenders().find((otherSender) =>
6210
+ otherSender.track && otherSender.track.kind === kind);
6149
6211
 
6150
6212
  // Do not reuse sender video tracks in SFU
6151
6213
  if (sender && (!sfu || newTrack.kind === 'audio')) {
6214
+ if (sender.track) {
6215
+ // eslint-disable-next-line no-param-reassign
6216
+ newTrack.enabled = sender.track.enabled;
6217
+ }
6152
6218
  trackUpdates.push(
6153
6219
  new Promise((resolve) => {
6154
6220
  this.logger.debug(`SessionDescriptionHandler.setLocalMediaStream - replacing sender ${kind} track`);
@@ -6182,7 +6248,11 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
6182
6248
  // Review: could make streamless tracks a configurable option?
6183
6249
  // https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/addTrack#Usage_notes
6184
6250
  try {
6185
- pc.addTrack(newTrack, localStream);
6251
+ if (pc.addTrack) {
6252
+ pc.addTrack(newTrack, localStream);
6253
+ } else {
6254
+ pc.addStream(localStream);
6255
+ }
6186
6256
  } catch (error) {
6187
6257
  this.logger.error(`SessionDescriptionHandler.setLocalMediaStream - failed to add sender ${kind} track`);
6188
6258
  throw error;
@@ -6318,7 +6388,7 @@ const DEFAULT_ICE_TIMEOUT = 3000;
6318
6388
  const SEND_STATS_DELAY = 5000;
6319
6389
 
6320
6390
  const states = ['STATUS_NULL', 'STATUS_NEW', 'STATUS_CONNECTING', 'STATUS_CONNECTED', 'STATUS_COMPLETED'];
6321
- const logger$7 = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-client') : console;
6391
+ const logger$8 = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-client') : console;
6322
6392
  const statsLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-stats') : console;
6323
6393
 
6324
6394
  // events
@@ -6364,6 +6434,7 @@ const MAX_REGISTER_TRIES = 10;
6364
6434
 
6365
6435
 
6366
6436
 
6437
+
6367
6438
 
6368
6439
 
6369
6440
 
@@ -6390,6 +6461,7 @@ class WebRTCClient extends Emitter {
6390
6461
 
6391
6462
 
6392
6463
 
6464
+
6393
6465
 
6394
6466
  // sugar
6395
6467
 
@@ -6428,6 +6500,8 @@ class WebRTCClient extends Emitter {
6428
6500
  super();
6429
6501
  this.uaConfigOverrides = uaConfigOverrides;
6430
6502
  this.config = config;
6503
+ this.skipRegister = config.skipRegister;
6504
+
6431
6505
  this._buildConfig(config, session).then((newConfig ) => {
6432
6506
  this.config = newConfig;
6433
6507
  this.userAgent = this.createUserAgent(uaConfigOverrides);
@@ -6483,13 +6557,13 @@ class WebRTCClient extends Emitter {
6483
6557
 
6484
6558
  createUserAgent(configOverrides ) {
6485
6559
  const webRTCConfiguration = this._createWebRTCConfiguration(configOverrides);
6486
- logger$7.info('sdk webrtc, creating UA', { webRTCConfiguration });
6560
+ logger$8.info('sdk webrtc, creating UA', { webRTCConfiguration });
6487
6561
 
6488
6562
  webRTCConfiguration.delegate = {
6489
6563
  onConnect: this.onConnect.bind(this),
6490
6564
  onDisconnect: this.onDisconnect.bind(this),
6491
6565
  onInvite: (invitation ) => {
6492
- logger$7.info('sdk webrtc on invite', {
6566
+ logger$8.info('sdk webrtc on invite', {
6493
6567
  method: 'delegate.onInvite',
6494
6568
  id: invitation.id,
6495
6569
  remoteURI: invitation.remoteURI,
@@ -6532,7 +6606,7 @@ class WebRTCClient extends Emitter {
6532
6606
  }
6533
6607
 
6534
6608
  onConnect() {
6535
- logger$7.info('sdk webrtc connected', { method: 'delegate.onConnect' });
6609
+ logger$8.info('sdk webrtc connected', { method: 'delegate.onConnect' });
6536
6610
  this.eventEmitter.emit(CONNECTED);
6537
6611
  if (!this.isRegistered() && this.registerer && this.registerer.waiting) {
6538
6612
  this.registerer.waitingToggle(false);
@@ -6541,7 +6615,7 @@ class WebRTCClient extends Emitter {
6541
6615
  }
6542
6616
 
6543
6617
  async onDisconnect(error ) {
6544
- logger$7.info('sdk webrtc disconnected', { method: 'delegate.onConnect', error });
6618
+ logger$8.info('sdk webrtc disconnected', { method: 'delegate.onConnect', error });
6545
6619
  this.connectionPromise = null;
6546
6620
  // The UA will attempt to reconnect automatically when an error occurred
6547
6621
  this.eventEmitter.emit(DISCONNECTED, error);
@@ -6555,40 +6629,48 @@ class WebRTCClient extends Emitter {
6555
6629
  }
6556
6630
 
6557
6631
  register(tries = 0) {
6558
- logger$7.info('sdk webrtc registering...', {
6632
+ const logInfo = {
6559
6633
  userAgent: !!this.userAgent,
6560
6634
  registered: this.isRegistered(),
6561
6635
  connectionPromise: !!this.connectionPromise,
6562
6636
  registerer: !!this.registerer,
6563
6637
  waiting: this.registerer && this.registerer.waiting,
6564
6638
  tries,
6565
- });
6639
+ skipRegister: this.skipRegister,
6640
+ };
6641
+
6642
+ if (this.skipRegister) {
6643
+ logger$8.info('sdk webrtc skip register...', logInfo);
6644
+ return Promise.resolve();
6645
+ }
6646
+
6647
+ logger$8.info('sdk webrtc registering...', logInfo);
6566
6648
 
6567
6649
  if (!this.userAgent) {
6568
- logger$7.info('sdk webrtc recreating User Agent');
6650
+ logger$8.info('sdk webrtc recreating User Agent');
6569
6651
  this.userAgent = this.createUserAgent(this.uaConfigOverrides);
6570
6652
  }
6571
6653
  if (!this.userAgent || this.isRegistered()) {
6572
- logger$7.info('sdk webrtc registering aborted, already registered or no UA can be created');
6654
+ logger$8.info('sdk webrtc registering aborted, already registered or no UA can be created');
6573
6655
  return Promise.resolve();
6574
6656
  }
6575
6657
 
6576
6658
  if (this.connectionPromise || (this.registerer && this.registerer.waiting)) {
6577
- logger$7.info('sdk webrtc registering aborted due to a registration in progress.');
6659
+ logger$8.info('sdk webrtc registering aborted due to a registration in progress.');
6578
6660
  return Promise.resolve();
6579
6661
  }
6580
6662
 
6581
6663
  const registerOptions = this._isWeb() ? {} : { extraContactHeaderParams: ['mobility=mobile'] };
6582
6664
 
6583
6665
  const onRegisterFailed = () => {
6584
- logger$7.info('sdk webrtc registering failed', { tries, registerer: !!this.registerer });
6666
+ logger$8.info('sdk webrtc registering failed', { tries, registerer: !!this.registerer });
6585
6667
  this.connectionPromise = null;
6586
6668
  if (this.registerer && this.registerer.waiting) {
6587
6669
  this.registerer.waitingToggle(false);
6588
6670
  }
6589
6671
 
6590
6672
  if (tries <= MAX_REGISTER_TRIES) {
6591
- logger$7.info('sdk webrtc registering, retrying...', { tries });
6673
+ logger$8.info('sdk webrtc registering, retrying...', { tries });
6592
6674
  setTimeout(() => this.register(tries + 1), 300);
6593
6675
  }
6594
6676
  };
@@ -6597,18 +6679,18 @@ class WebRTCClient extends Emitter {
6597
6679
  // Avoid race condition with the close method called just before register and setting userAgent to null
6598
6680
  // during the resolution of the primise.
6599
6681
  if (!this.userAgent) {
6600
- logger$7.info('sdk webrtc recreating User Agent after connection');
6682
+ logger$8.info('sdk webrtc recreating User Agent after connection');
6601
6683
  this.userAgent = this.createUserAgent(this.uaConfigOverrides);
6602
6684
  }
6603
6685
 
6604
- logger$7.info('sdk webrtc registering, transport connected', { registerOptions, ua: !!this.userAgent });
6686
+ logger$8.info('sdk webrtc registering, transport connected', { registerOptions, ua: !!this.userAgent });
6605
6687
  this.registerer = new registerer.Registerer(this.userAgent, registerOptions);
6606
6688
  this.connectionPromise = null;
6607
6689
  this._monkeyPatchRegisterer(this.registerer);
6608
6690
 
6609
6691
  // Bind registerer events
6610
6692
  this.registerer.stateChange.addListener(newState => {
6611
- logger$7.info('sdk webrtc registering, state changed', { newState });
6693
+ logger$8.info('sdk webrtc registering, state changed', { newState });
6612
6694
 
6613
6695
  if (newState === registererState.RegistererState.Registered && this.registerer
6614
6696
  && this.registerer.state === registererState.RegistererState.Registered) {
@@ -6621,7 +6703,7 @@ class WebRTCClient extends Emitter {
6621
6703
  const options = {
6622
6704
  requestDelegate: {
6623
6705
  onReject: response => {
6624
- logger$7.error('sdk webrtc registering, rejected', { response });
6706
+ logger$8.error('sdk webrtc registering, rejected', { response });
6625
6707
 
6626
6708
  onRegisterFailed();
6627
6709
  },
@@ -6629,13 +6711,13 @@ class WebRTCClient extends Emitter {
6629
6711
  };
6630
6712
 
6631
6713
  return this.registerer.register(options).catch((e) => {
6632
- logger$7.error('sdk webrtc registering, error', e);
6714
+ logger$8.error('sdk webrtc registering, error', e);
6633
6715
 
6634
6716
  this.eventEmitter.emit(REGISTRATION_FAILED);
6635
6717
  return e;
6636
6718
  });
6637
6719
  }).catch(error => {
6638
- logger$7.error('sdk webrtc registering, transport error', error);
6720
+ logger$8.error('sdk webrtc registering, transport error', error);
6639
6721
  onRegisterFailed();
6640
6722
  });
6641
6723
  }
@@ -6664,21 +6746,21 @@ class WebRTCClient extends Emitter {
6664
6746
  }
6665
6747
 
6666
6748
  unregister() {
6667
- logger$7.info('sdk webrtc unregistering..', { userAgent: !!this.userAgent, registerer: !!this.registerer });
6749
+ logger$8.info('sdk webrtc unregistering..', { userAgent: !!this.userAgent, registerer: !!this.registerer });
6668
6750
  if (!this.registerer) {
6669
6751
  return Promise.resolve();
6670
6752
  }
6671
6753
 
6672
6754
  try {
6673
6755
  return this.registerer.unregister().then(() => {
6674
- logger$7.info('sdk webrtc unregistered');
6756
+ logger$8.info('sdk webrtc unregistered');
6675
6757
  this._cleanupRegister();
6676
6758
  }).catch(e => {
6677
- logger$7.error('sdk webrtc unregistering, promise error', e);
6759
+ logger$8.error('sdk webrtc unregistering, promise error', e);
6678
6760
  this._cleanupRegister();
6679
6761
  });
6680
6762
  } catch (e) {
6681
- logger$7.error('sdk webrtc unregistering, error', e);
6763
+ logger$8.error('sdk webrtc unregistering, error', e);
6682
6764
  // Avoid issue with `undefined is not an object (evaluating 'new.target.prototype')` when triggering a new
6683
6765
  // error when the registerer is in a bad state
6684
6766
  this._cleanupRegister();
@@ -6686,7 +6768,7 @@ class WebRTCClient extends Emitter {
6686
6768
  }
6687
6769
 
6688
6770
  stop() {
6689
- logger$7.info('sdk webrtc stop', { userAgent: !!this.userAgent });
6771
+ logger$8.info('sdk webrtc stop', { userAgent: !!this.userAgent });
6690
6772
  if (!this.userAgent) {
6691
6773
  return Promise.resolve();
6692
6774
  }
@@ -6694,12 +6776,12 @@ class WebRTCClient extends Emitter {
6694
6776
  return this.userAgent.stop().then(() => {
6695
6777
  return this._cleanupRegister();
6696
6778
  }).catch(e => {
6697
- logger$7.warn('sdk webrtc stop, error', { message: e.message, stack: e.stack });
6779
+ logger$8.warn('sdk webrtc stop, error', { message: e.message, stack: e.stack });
6698
6780
  });
6699
6781
  }
6700
6782
 
6701
6783
  call(number , enableVideo , audioOnly = false, conference = false) {
6702
- logger$7.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
6784
+ logger$8.info('sdk webrtc creating call', { number, enableVideo, audioOnly });
6703
6785
  const inviterOptions = {
6704
6786
  sessionDescriptionHandlerOptionsReInvite: {
6705
6787
  conference,
@@ -6728,7 +6810,7 @@ class WebRTCClient extends Emitter {
6728
6810
  this._onAccepted(session, response.session, true);
6729
6811
  },
6730
6812
  onReject: (response ) => {
6731
- logger$7.info('on call rejected', { id: session.id, fromTag: session.fromTag });
6813
+ logger$8.info('on call rejected', { id: session.id, fromTag: session.fromTag });
6732
6814
  this._stopSendingStats(session);
6733
6815
 
6734
6816
  this.eventEmitter.emit(REJECTED, session, response);
@@ -6750,11 +6832,11 @@ class WebRTCClient extends Emitter {
6750
6832
  }
6751
6833
 
6752
6834
  answer(session , enableVideo ) {
6753
- logger$7.info('sdk webrtc answer call', { id: session.id, enableVideo });
6835
+ logger$8.info('sdk webrtc answer call', { id: session.id, enableVideo });
6754
6836
 
6755
6837
  if (!session || !session.accept) {
6756
6838
  const error = 'No session to answer, or not an invitation';
6757
- logger$7.warn(error);
6839
+ logger$8.warn(error);
6758
6840
  return Promise.reject(new Error(error));
6759
6841
  }
6760
6842
  const options = {
@@ -6764,15 +6846,15 @@ class WebRTCClient extends Emitter {
6764
6846
  return session.accept(options).then(() => {
6765
6847
  if (session.isCanceled) {
6766
6848
  const message = 'accepted a canceled session (or was canceled during the accept phase).';
6767
- logger$7.error(message, { id: session.id });
6849
+ logger$8.error(message, { id: session.id });
6768
6850
  this.onCallEnded(session);
6769
6851
 
6770
6852
  throw new CanceledCallError(message);
6771
6853
  }
6772
- logger$7.info('sdk webrtc answer, accepted.');
6854
+ logger$8.info('sdk webrtc answer, accepted.');
6773
6855
  this._onAccepted(session);
6774
6856
  }).catch(e => {
6775
- logger$7.error(`answer call error for ${session ? session.id : 'n/a'}`, e);
6857
+ logger$8.error(`answer call error for ${session ? session.id : 'n/a'}`, e);
6776
6858
 
6777
6859
  throw e;
6778
6860
  });
@@ -6780,7 +6862,7 @@ class WebRTCClient extends Emitter {
6780
6862
 
6781
6863
  hangup(session ) {
6782
6864
  const { state, id } = session;
6783
- logger$7.info('sdk webrtc hangup call', { id, state });
6865
+ logger$8.info('sdk webrtc hangup call', { id, state });
6784
6866
 
6785
6867
  try {
6786
6868
  this._stopSendingStats(session);
@@ -6809,24 +6891,24 @@ class WebRTCClient extends Emitter {
6809
6891
 
6810
6892
  return bye();
6811
6893
  } catch (error) {
6812
- logger$7.warn('sdk webrtc hangup, error', error);
6894
+ logger$8.warn('sdk webrtc hangup, error', error);
6813
6895
  }
6814
6896
 
6815
6897
  return null;
6816
6898
  }
6817
6899
 
6818
6900
  reject(session ) {
6819
- logger$7.info('sdk webrtc reject call', { id: session.id });
6901
+ logger$8.info('sdk webrtc reject call', { id: session.id });
6820
6902
 
6821
6903
  try {
6822
6904
  return session.reject ? session.reject() : session.cancel();
6823
6905
  } catch (e) {
6824
- logger$7.warn('Error when rejecting call', e.message, e.stack);
6906
+ logger$8.warn('Error when rejecting call', e.message, e.stack);
6825
6907
  }
6826
6908
  }
6827
6909
 
6828
6910
  async close() {
6829
- logger$7.info('sdk webrtc closing client', { userAgent: !!this.userAgent });
6911
+ logger$8.info('sdk webrtc closing client', { userAgent: !!this.userAgent });
6830
6912
  this._cleanupMedia();
6831
6913
  this.connectionPromise = null;
6832
6914
 
@@ -6857,7 +6939,7 @@ class WebRTCClient extends Emitter {
6857
6939
  // eg: "INVITE not rejectable in state Completed"
6858
6940
  }
6859
6941
  this.userAgent = null;
6860
- logger$7.info('sdk webrtc client closed');
6942
+ logger$8.info('sdk webrtc client closed');
6861
6943
  }
6862
6944
 
6863
6945
  getNumber(session ) {
@@ -6870,13 +6952,13 @@ class WebRTCClient extends Emitter {
6870
6952
  }
6871
6953
 
6872
6954
  mute(session ) {
6873
- logger$7.info('sdk webrtc mute', { id: session.id });
6955
+ logger$8.info('sdk webrtc mute', { id: session.id });
6874
6956
 
6875
6957
  this._toggleAudio(session, true);
6876
6958
  }
6877
6959
 
6878
6960
  unmute(session ) {
6879
- logger$7.info('sdk webrtc unmute', { id: session.id });
6961
+ logger$8.info('sdk webrtc unmute', { id: session.id });
6880
6962
 
6881
6963
  this._toggleAudio(session, false);
6882
6964
  }
@@ -6893,12 +6975,18 @@ class WebRTCClient extends Emitter {
6893
6975
  }
6894
6976
 
6895
6977
  if (pc.getSenders) {
6978
+ if (!pc.getSenders().length) {
6979
+ return false;
6980
+ }
6896
6981
  pc.getSenders().forEach(sender => {
6897
6982
  if (sender && sender.track && sender.track.kind === 'audio') {
6898
6983
  muted = muted && !sender.track.enabled;
6899
6984
  }
6900
6985
  });
6901
6986
  } else {
6987
+ if (!pc.getLocalStreams().length) {
6988
+ return false;
6989
+ }
6902
6990
  pc.getLocalStreams().forEach(stream => {
6903
6991
  stream.getAudioTracks().forEach(track => {
6904
6992
  muted = muted && !track.enabled;
@@ -6910,20 +6998,20 @@ class WebRTCClient extends Emitter {
6910
6998
  }
6911
6999
 
6912
7000
  toggleCameraOn(session ) {
6913
- logger$7.info('sdk webrtc toggle camera on', { id: session.id });
7001
+ logger$8.info('sdk webrtc toggle camera on', { id: session.id });
6914
7002
 
6915
7003
  this._toggleVideo(session, false);
6916
7004
  }
6917
7005
 
6918
7006
  toggleCameraOff(session ) {
6919
- logger$7.info('sdk webrtc toggle camera off', { id: session.id });
7007
+ logger$8.info('sdk webrtc toggle camera off', { id: session.id });
6920
7008
 
6921
7009
  this._toggleVideo(session, true);
6922
7010
  }
6923
7011
 
6924
7012
  hold(session , isConference = false) {
6925
7013
  const sessionId = this.getSipSessionId(session);
6926
- logger$7.info('sdk webrtc hold', {
7014
+ logger$8.info('sdk webrtc hold', {
6927
7015
  sessionId,
6928
7016
  keys: Object.keys(this.heldSessions),
6929
7017
  pendingReinvite: !!session.pendingReinvite,
@@ -6957,6 +7045,8 @@ class WebRTCClient extends Emitter {
6957
7045
  }
6958
7046
  options.sessionDescriptionHandlerOptions = {
6959
7047
  constraints: options.constraints,
7048
+ hold: true,
7049
+ conference: isConference,
6960
7050
  };
6961
7051
 
6962
7052
  // Send re-INVITE
@@ -6966,7 +7056,7 @@ class WebRTCClient extends Emitter {
6966
7056
  unhold(session , isConference = false) {
6967
7057
  const sessionId = this.getSipSessionId(session);
6968
7058
 
6969
- logger$7.info('sdk webrtc unhold', {
7059
+ logger$8.info('sdk webrtc unhold', {
6970
7060
  sessionId,
6971
7061
  keys: Object.keys(this.heldSessions),
6972
7062
  pendingReinvite: !!session.pendingReinvite,
@@ -6999,6 +7089,8 @@ class WebRTCClient extends Emitter {
6999
7089
  }
7000
7090
  options.sessionDescriptionHandlerOptions = {
7001
7091
  constraints: options.constraints,
7092
+ hold: false,
7093
+ conference: isConference,
7002
7094
  };
7003
7095
 
7004
7096
  // Send re-INVITE
@@ -7057,7 +7149,7 @@ class WebRTCClient extends Emitter {
7057
7149
  return;
7058
7150
  }
7059
7151
 
7060
- logger$7.info('send WebRTC message', { sipId: sipSession.id, contentType });
7152
+ logger$8.info('send WebRTC message', { sipId: sipSession.id, contentType });
7061
7153
 
7062
7154
  try {
7063
7155
  sipSession.message({
@@ -7182,7 +7274,8 @@ class WebRTCClient extends Emitter {
7182
7274
  }
7183
7275
  const sdh = session.sessionDescriptionHandler;
7184
7276
  const pc = sdh.peerConnection;
7185
- const localStream = this.getLocalStream(this.getSipSessionId(session));
7277
+ const sessionId = this.getSipSessionId(session);
7278
+ const localStream = this.getLocalStream(sessionId);
7186
7279
 
7187
7280
  // Release old video stream
7188
7281
  if (localStream) {
@@ -7208,11 +7301,8 @@ class WebRTCClient extends Emitter {
7208
7301
 
7209
7302
  // let's update the local stream
7210
7303
  this.eventEmitter.emit('onVideoInputChange', stream);
7211
- try {
7212
- await sdh.setLocalMediaStream(stream);
7213
- } catch (_) {
7214
- // Nothing to do
7215
- }
7304
+ this.setLocalMediaStream(sessionId, stream);
7305
+
7216
7306
  return stream;
7217
7307
  });
7218
7308
  }
@@ -7424,7 +7514,7 @@ class WebRTCClient extends Emitter {
7424
7514
  }
7425
7515
 
7426
7516
  startHeartbeat() {
7427
- logger$7.info('sdk webrtc start heartbeat', { userAgent: !!this.userAgent });
7517
+ logger$8.info('sdk webrtc start heartbeat', { userAgent: !!this.userAgent });
7428
7518
  if (!this.userAgent) {
7429
7519
  this.heartbeat.stop();
7430
7520
  return;
@@ -7437,7 +7527,7 @@ class WebRTCClient extends Emitter {
7437
7527
  }
7438
7528
 
7439
7529
  stopHeartbeat() {
7440
- logger$7.info('sdk webrtc stop heartbeat');
7530
+ logger$8.info('sdk webrtc stop heartbeat');
7441
7531
  this.heartbeat.stop();
7442
7532
  }
7443
7533
 
@@ -7457,7 +7547,7 @@ class WebRTCClient extends Emitter {
7457
7547
  }
7458
7548
 
7459
7549
  attemptReconnection() {
7460
- logger$7.info('attempt reconnection', { userAgent: !!this.userAgent });
7550
+ logger$8.info('attempt reconnection', { userAgent: !!this.userAgent });
7461
7551
  if (!this.userAgent) {
7462
7552
  return;
7463
7553
  }
@@ -7514,9 +7604,11 @@ class WebRTCClient extends Emitter {
7514
7604
  remoteStream.removeTrack(track);
7515
7605
  });
7516
7606
 
7517
- pc.getReceivers().forEach(receiver => {
7518
- remoteStream.addTrack(receiver.track);
7519
- });
7607
+ if (pc.getReceivers) {
7608
+ pc.getReceivers().forEach(receiver => {
7609
+ remoteStream.addTrack(receiver.track);
7610
+ });
7611
+ }
7520
7612
  }
7521
7613
 
7522
7614
  getMediaConfiguration(enableVideo , conference = false, constraints = null) {
@@ -7551,6 +7643,25 @@ class WebRTCClient extends Emitter {
7551
7643
  return sessionId in this.conferences;
7552
7644
  }
7553
7645
 
7646
+ createAudioElementFor(sessionId ) {
7647
+ const audio = document.createElement('audio');
7648
+ audio.setAttribute('id', `audio-${sessionId}`);
7649
+
7650
+ if (audio.setSinkId && this.audioOutputDeviceId) {
7651
+ audio.setSinkId(this.audioOutputDeviceId);
7652
+ }
7653
+
7654
+ if (document.body) {
7655
+ document.body.appendChild(audio);
7656
+ }
7657
+ this.audioElements[sessionId] = audio;
7658
+
7659
+ audio.volume = this.audioOutputVolume;
7660
+ audio.autoplay = true;
7661
+
7662
+ return audio;
7663
+ }
7664
+
7554
7665
  _onTransportError() {
7555
7666
  this.eventEmitter.emit(TRANSPORT_ERROR);
7556
7667
  this.attemptReconnection();
@@ -7560,7 +7671,7 @@ class WebRTCClient extends Emitter {
7560
7671
  const body = message && typeof message === 'object' ? message.data : message;
7561
7672
  if (body && body.indexOf('200 OK') !== -1) {
7562
7673
  if (this.hasHeartbeat()) {
7563
- logger$7.info('on heartbeat received from Asterisk', { hasHeartbeat: this.hasHeartbeat() });
7674
+ logger$8.info('on heartbeat received from Asterisk', { hasHeartbeat: this.hasHeartbeat() });
7564
7675
 
7565
7676
  this.heartbeat.onHeartbeat();
7566
7677
  if (this.heartbeatCb) {
@@ -7571,7 +7682,7 @@ class WebRTCClient extends Emitter {
7571
7682
  }
7572
7683
 
7573
7684
  async _onHeartbeatTimeout() {
7574
- logger$7.info('sdk webrtc heartbeat timed out', { userAgent: !!this.userAgent, cb: !!this.heartbeatTimeoutCb });
7685
+ logger$8.info('sdk webrtc heartbeat timed out', { userAgent: !!this.userAgent, cb: !!this.heartbeatTimeoutCb });
7575
7686
 
7576
7687
  if (this.heartbeatTimeoutCb) {
7577
7688
  this.heartbeatTimeoutCb();
@@ -7583,7 +7694,7 @@ class WebRTCClient extends Emitter {
7583
7694
  try {
7584
7695
  await this.userAgent.transport.disconnect();
7585
7696
  } catch (e) {
7586
- logger$7.error('Transport disconnection after heartbeat timeout, error', e);
7697
+ logger$8.error('Transport disconnection after heartbeat timeout, error', e);
7587
7698
  }
7588
7699
  }
7589
7700
 
@@ -7616,31 +7727,31 @@ class WebRTCClient extends Emitter {
7616
7727
  }
7617
7728
 
7618
7729
  _connectIfNeeded() {
7619
- logger$7.info('connect if needed, checking', { connected: this.isConnected() });
7730
+ logger$8.info('connect if needed, checking', { connected: this.isConnected() });
7620
7731
  if (!this.userAgent) {
7621
- logger$7.info('need to recreate User Agent');
7732
+ logger$8.info('need to recreate User Agent');
7622
7733
  this.userAgent = this.createUserAgent(this.uaConfigOverrides);
7623
7734
  }
7624
7735
 
7625
7736
  if (this.isConnected()) {
7626
- logger$7.info('webrtc sdk, already connected');
7737
+ logger$8.info('webrtc sdk, already connected');
7627
7738
  return Promise.resolve();
7628
7739
  }
7629
7740
 
7630
7741
  if (this.isConnecting()) {
7631
- logger$7.info('webrtc sdk, already connecting...');
7742
+ logger$8.info('webrtc sdk, already connecting...');
7632
7743
 
7633
7744
  this.connectionPromise = this.userAgent.transport.connectPromise;
7634
7745
  return this.connectionPromise;
7635
7746
  }
7636
7747
 
7637
7748
  if (this.connectionPromise) {
7638
- logger$7.info('webrtc sdk, connection promise connecting...');
7749
+ logger$8.info('webrtc sdk, connection promise connecting...');
7639
7750
  // $FlowFixMe
7640
7751
  return this.connectionPromise;
7641
7752
  }
7642
7753
 
7643
- logger$7.info('WebRTC UA needs to connect');
7754
+ logger$8.info('WebRTC UA needs to connect');
7644
7755
 
7645
7756
  // Force UA to reconnect
7646
7757
  if (this.userAgent && this.userAgent.state !== userAgentState.UserAgentState.Stopped) {
@@ -7765,7 +7876,7 @@ class WebRTCClient extends Emitter {
7765
7876
 
7766
7877
  sdh.peerConnectionDelegate = {
7767
7878
  onicecandidateerror: (error ) => {
7768
- logger$7.error('on icecandidate error', {
7879
+ logger$8.error('on icecandidate error', {
7769
7880
  address: error.address,
7770
7881
  port: error.port,
7771
7882
  errorCode: error.errorCode,
@@ -7780,7 +7891,7 @@ class WebRTCClient extends Emitter {
7780
7891
  let hadRemoteVideo = false;
7781
7892
 
7782
7893
  // Monkey patch `onInviteRequest` to be able to know if there was a remote video stream before `onInvite` is called
7783
- // Becase when `onInvite` is called we already got the video track
7894
+ // Because when `onInvite` is called we already got the video track
7784
7895
  session.onInviteRequest = (request) => {
7785
7896
  hadRemoteVideo = this.hasARemoteVideoTrack(sipSessionId);
7786
7897
 
@@ -7794,7 +7905,7 @@ class WebRTCClient extends Emitter {
7794
7905
  updatedNumber = session.assertedIdentity.uri.normal.user;
7795
7906
  updatedCalleeName = session.assertedIdentity.displayName || updatedNumber;
7796
7907
  }
7797
- logger$7.info('re-invite received', { updatedCalleeName, updatedNumber });
7908
+ logger$8.info('re-invite received', { updatedCalleeName, updatedNumber });
7798
7909
 
7799
7910
  // Useful to know if it's a video upgrade or an unhold from a remote peer with a video stream
7800
7911
 
@@ -7815,7 +7926,7 @@ class WebRTCClient extends Emitter {
7815
7926
  }
7816
7927
 
7817
7928
  _onAccepted(session , sessionDialog , withEvent = true) {
7818
- logger$7.info('on call accepted', { id: session.id, remoteTag: session.remoteTag });
7929
+ logger$8.info('on call accepted', { id: session.id, remoteTag: session.remoteTag });
7819
7930
 
7820
7931
  this.storeSipSession(session);
7821
7932
 
@@ -7855,20 +7966,10 @@ class WebRTCClient extends Emitter {
7855
7966
  const isConference = this.isConference(sessionId);
7856
7967
 
7857
7968
  if (this._hasAudio() && this._isWeb() && !(sessionId in this.audioElements)) {
7858
- const audio = document.createElement('audio');
7859
- audio.setAttribute('id', `audio-${sessionId}`);
7860
-
7861
- if (audio.setSinkId && this.audioOutputDeviceId) {
7862
- audio.setSinkId(this.audioOutputDeviceId);
7863
- }
7864
-
7865
- if (document.body) {
7866
- document.body.appendChild(audio);
7867
- }
7868
- this.audioElements[sessionId] = audio;
7969
+ this.createAudioElementFor(sessionId);
7869
7970
  }
7870
7971
 
7871
- const audioElement = this.audioElements[this.getSipSessionId(session)];
7972
+ const audioElement = this.audioElements[sessionId];
7872
7973
  const stream = newStream || this.getRemoteStream(sessionId);
7873
7974
 
7874
7975
  if (!this._isWeb() || !stream) {
@@ -8015,10 +8116,10 @@ class WebRTCClient extends Emitter {
8015
8116
 
8016
8117
  _stopSendingStats(session ) {
8017
8118
  const sessionId = this.getSipSessionId(session);
8018
- logger$7.trace('Check for stopping stats', { sessionId, ids: Object.keys(this.statsIntervals) });
8119
+ logger$8.trace('Check for stopping stats', { sessionId, ids: Object.keys(this.statsIntervals) });
8019
8120
 
8020
8121
  if (sessionId in this.statsIntervals) {
8021
- logger$7.trace('Stop sending stats for call', { sessionId });
8122
+ logger$8.trace('Stop sending stats for call', { sessionId });
8022
8123
  this.statsIntervals[sessionId]();
8023
8124
  delete this.statsIntervals[sessionId];
8024
8125
  }
@@ -8034,7 +8135,7 @@ class WebRTCClient extends Emitter {
8034
8135
  try {
8035
8136
  await this.userAgent.transport.disconnect();
8036
8137
  } catch (e) {
8037
- logger$7.error('WebRTC transport disconnect, error', e);
8138
+ logger$8.error('WebRTC transport disconnect, error', e);
8038
8139
  }
8039
8140
  }
8040
8141
  }
@@ -8121,7 +8222,7 @@ const events = [
8121
8222
  ON_SIGNAL,
8122
8223
  ];
8123
8224
 
8124
- const logger$6 = IssueReporter$1.loggerFor('webrtc-phone');
8225
+ const logger$7 = IssueReporter$1.loggerFor('webrtc-phone');
8125
8226
 
8126
8227
  class WebRTCPhone extends Emitter {
8127
8228
 
@@ -8192,7 +8293,7 @@ class WebRTCPhone extends Emitter {
8192
8293
  }).catch(error => {
8193
8294
  // Avoid exception on `t.server.scheme` in sip transport when losing the webrtc socket connection
8194
8295
  console.error('register error', error, error.message, error.stack);
8195
- logger$6.error('WebRTC register error', { message: error.message, stack: error.stack });
8296
+ logger$7.error('WebRTC register error', { message: error.message, stack: error.stack });
8196
8297
  });
8197
8298
  }
8198
8299
 
@@ -8207,7 +8308,7 @@ class WebRTCPhone extends Emitter {
8207
8308
  if (!this.client) {
8208
8309
  return;
8209
8310
  }
8210
- logger$6.info('WebRTC phone stop');
8311
+ logger$7.info('WebRTC phone stop');
8211
8312
  this.client.stop();
8212
8313
  }
8213
8314
 
@@ -8222,14 +8323,14 @@ class WebRTCPhone extends Emitter {
8222
8323
  async sendReinvite(callSession , constraints = null, conference = false,
8223
8324
  audioOnly = false) {
8224
8325
  const sipSession = this.findSipSession(callSession);
8225
- logger$6.info('WebRTC phone - send reinvite', {
8326
+ logger$7.info('WebRTC phone - send reinvite', {
8226
8327
  sessionId: sipSession ? sipSession.id : null,
8227
8328
  constraints,
8228
8329
  audioOnly,
8229
8330
  });
8230
8331
 
8231
8332
  if (!sipSession) {
8232
- return null;
8333
+ return false;
8233
8334
  }
8234
8335
 
8235
8336
  // $FlowFixMe
@@ -8239,19 +8340,17 @@ class WebRTCPhone extends Emitter {
8239
8340
  // Downgrade
8240
8341
  if (constraints && !isUpgrade) {
8241
8342
  // No reinvite needed
8242
- return this._downgradeToAudio(callSession);
8343
+ this._downgradeToAudio(callSession);
8344
+ return false;
8243
8345
  }
8244
8346
 
8245
8347
  if (isUpgrade) {
8246
8348
  const shouldReinvite = await this._upgradeToVideo(callSession, constraints, conference);
8247
8349
  if (!shouldReinvite) {
8248
- return;
8350
+ return false;
8249
8351
  }
8250
8352
  }
8251
8353
 
8252
- // Force reinvite in SDH
8253
- sipSession.sessionDescriptionHandler.localMediaStreamConstraints = null;
8254
-
8255
8354
  return this.client.reinvite(sipSession, constraints, conference, audioOnly);
8256
8355
  }
8257
8356
 
@@ -8260,7 +8359,7 @@ class WebRTCPhone extends Emitter {
8260
8359
  }
8261
8360
 
8262
8361
  startHeartbeat() {
8263
- logger$6.info('WebRTC phone - start heartbeat', { client: !!this.client, hasHeartbeat: this.client.hasHeartbeat() });
8362
+ logger$7.info('WebRTC phone - start heartbeat', { client: !!this.client, hasHeartbeat: this.client.hasHeartbeat() });
8264
8363
  if (!this.client || this.client.hasHeartbeat()) {
8265
8364
  return;
8266
8365
  }
@@ -8269,7 +8368,7 @@ class WebRTCPhone extends Emitter {
8269
8368
  }
8270
8369
 
8271
8370
  stopHeartbeat() {
8272
- logger$6.info('WebRTC phone - stopHeartbeat', { client: !!this.client });
8371
+ logger$7.info('WebRTC phone - stopHeartbeat', { client: !!this.client });
8273
8372
  if (!this.client) {
8274
8373
  return;
8275
8374
  }
@@ -8286,7 +8385,7 @@ class WebRTCPhone extends Emitter {
8286
8385
  }
8287
8386
 
8288
8387
  reconnect() {
8289
- logger$6.info('WebRTC phone - reconnect', { client: !!this.client });
8388
+ logger$7.info('WebRTC phone - reconnect', { client: !!this.client });
8290
8389
  if (!this.client) {
8291
8390
  return;
8292
8391
  }
@@ -8324,7 +8423,7 @@ class WebRTCPhone extends Emitter {
8324
8423
  _downgradeToAudio(callSession ) {
8325
8424
  const sipSession = this.findSipSession(callSession);
8326
8425
  if (!sipSession) {
8327
- return;
8426
+ return false;
8328
8427
  }
8329
8428
 
8330
8429
  // Release local video stream when downgrading to audio
@@ -8437,7 +8536,7 @@ class WebRTCPhone extends Emitter {
8437
8536
  // Monkey patch to know when canceled with the CANCEL message
8438
8537
  const onCancel = sipSession._onCancel.bind(sipSession);
8439
8538
  sipSession._onCancel = (message ) => {
8440
- logger$6.trace('on sip session canceled', { callId: message.callId });
8539
+ logger$7.trace('on sip session canceled', { callId: message.callId });
8441
8540
 
8442
8541
  onCancel(message);
8443
8542
  const elsewhere = message.data.indexOf('cause=26') !== -1 && message.data.indexOf('completed elsewhere') !== -1;
@@ -8462,13 +8561,13 @@ class WebRTCPhone extends Emitter {
8462
8561
  this.audioOutputVolume,
8463
8562
  );
8464
8563
  case sessionState.SessionState.Terminating:
8465
- logger$6.info('WebRTC phone - call terminating', { sipId: sipSession.id });
8564
+ logger$7.info('WebRTC phone - call terminating', { sipId: sipSession.id });
8466
8565
 
8467
8566
  this.eventEmitter.emit(ON_CALL_ENDING, this._createCallSession(sipSession));
8468
8567
 
8469
8568
  break;
8470
8569
  case sessionState.SessionState.Terminated:
8471
- logger$6.info('WebRTC phone - call terminated', { sipId: sipSession.id });
8570
+ logger$7.info('WebRTC phone - call terminated', { sipId: sipSession.id });
8472
8571
 
8473
8572
  this._onCallTerminated(sipSession);
8474
8573
 
@@ -8504,7 +8603,7 @@ class WebRTCPhone extends Emitter {
8504
8603
  }
8505
8604
 
8506
8605
  async startScreenSharing(constraints , callSession ) {
8507
- logger$6.info('WebRTC - start screen sharing', { constraints, id: callSession ? callSession.getId() : null });
8606
+ logger$7.info('WebRTC - start screen sharing', { constraints, id: callSession ? callSession.getId() : null });
8508
8607
 
8509
8608
  const screenShareStream = await this._getStreamFromConstraints(constraints);
8510
8609
  if (!screenShareStream) {
@@ -8526,6 +8625,10 @@ class WebRTCPhone extends Emitter {
8526
8625
  localStream.removeTrack(videoTrack);
8527
8626
  }
8528
8627
 
8628
+ if (localStream) {
8629
+ localStream.addTrack(screenTrack);
8630
+ }
8631
+
8529
8632
  if (sender) {
8530
8633
  sender.replaceTrack(screenTrack);
8531
8634
  }
@@ -8540,7 +8643,8 @@ class WebRTCPhone extends Emitter {
8540
8643
  return;
8541
8644
  }
8542
8645
 
8543
- logger$6.info('WebRTC phone - stop screen sharing');
8646
+ logger$7.info('WebRTC phone - stop screen sharing');
8647
+ let reinvited = false;
8544
8648
 
8545
8649
  try {
8546
8650
  if (this.currentScreenShare.stream) {
@@ -8555,7 +8659,8 @@ class WebRTCPhone extends Emitter {
8555
8659
  // When upgrading directly to screenshare (eg: we don't have a videoLocalStream to replace)
8556
8660
  // We have to downgrade to audio.
8557
8661
  const screenshareStopped = this.currentScreenShare.sender && this.currentScreenShare.hadVideo;
8558
- await this.sendReinvite(targetCallSession, { audio: false, video: screenshareStopped }, conference);
8662
+ const constraints = { audio: false, video: screenshareStopped };
8663
+ reinvited = await this.sendReinvite(targetCallSession, constraints, conference);
8559
8664
  }
8560
8665
  } catch (e) {
8561
8666
  console.warn(e);
@@ -8569,6 +8674,8 @@ class WebRTCPhone extends Emitter {
8569
8674
  );
8570
8675
 
8571
8676
  this.currentScreenShare = null;
8677
+
8678
+ return reinvited;
8572
8679
  }
8573
8680
 
8574
8681
  async _getStreamFromConstraints(constraints , conference = false) {
@@ -8606,7 +8713,7 @@ class WebRTCPhone extends Emitter {
8606
8713
  }
8607
8714
 
8608
8715
  _onCallAccepted(sipSession , cameraEnabled ) {
8609
- logger$6.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
8716
+ logger$7.info('WebRTC phone - on call accepted', { sipId: sipSession.id, cameraEnabled });
8610
8717
 
8611
8718
  const callSession = this._createAcceptedCallSession(sipSession, cameraEnabled);
8612
8719
  this.currentSipSession = sipSession;
@@ -8624,11 +8731,15 @@ class WebRTCPhone extends Emitter {
8624
8731
  }
8625
8732
 
8626
8733
  changeAudioDevice(id ) {
8627
- logger$6.info('WebRTC phone - change audio device', { deviceId: id });
8734
+ logger$7.info('WebRTC phone - change audio device', { deviceId: id });
8628
8735
  this.audioOutputDeviceId = id;
8629
8736
  this.client.changeAudioOutputDevice(id);
8630
8737
  }
8631
8738
 
8739
+ createAudioElementFor(sessionId ) {
8740
+ return this.client.createAudioElementFor(sessionId);
8741
+ }
8742
+
8632
8743
  changeRingDevice(id ) {
8633
8744
  this.audioRingDeviceId = id;
8634
8745
  }
@@ -8645,25 +8756,25 @@ class WebRTCPhone extends Emitter {
8645
8756
  }
8646
8757
 
8647
8758
  changeAudioInputDevice(id ) {
8648
- logger$6.info('WebRTC phone - changeAudio input device', { deviceId: id });
8759
+ logger$7.info('WebRTC phone - changeAudio input device', { deviceId: id });
8649
8760
 
8650
8761
  return this.client.changeAudioInputDevice(id, this.currentSipSession);
8651
8762
  }
8652
8763
 
8653
8764
  changeVideoInputDevice(id ) {
8654
- logger$6.info('WebRTC phone - change video input device', { deviceId: id });
8765
+ logger$7.info('WebRTC phone - change video input device', { deviceId: id });
8655
8766
 
8656
8767
  return this.client.changeVideoInputDevice(id, this.currentSipSession);
8657
8768
  }
8658
8769
 
8659
8770
  changeSessionVideoInputDevice(id ) {
8660
- logger$6.info('WebRTC phone - change session video input device', { deviceId: id });
8771
+ logger$7.info('WebRTC phone - change session video input device', { deviceId: id });
8661
8772
 
8662
8773
  return this.client.changeSessionVideoInputDevice(id, this.currentSipSession);
8663
8774
  }
8664
8775
 
8665
8776
  _onCallTerminated(sipSession ) {
8666
- logger$6.info('WebRTC phone - on call terminated', { sipId: sipSession.id });
8777
+ logger$7.info('WebRTC phone - on call terminated', { sipId: sipSession.id });
8667
8778
 
8668
8779
  const callSession = this._createCallSession(sipSession);
8669
8780
  const isCurrentSession = this.isCurrentCallSipSession(callSession);
@@ -8697,7 +8808,7 @@ class WebRTCPhone extends Emitter {
8697
8808
  const hasIncomingCallSession = this.hasIncomingCallSession();
8698
8809
 
8699
8810
  // Re-trigger incoming call event for remaining incoming calls
8700
- logger$6.info('WebRTC phone - check to re-trigger incoming call', {
8811
+ logger$7.info('WebRTC phone - check to re-trigger incoming call', {
8701
8812
  sipId: sipSession.id,
8702
8813
  shouldRetrigger,
8703
8814
  hasIncomingCallSession,
@@ -8786,37 +8897,37 @@ class WebRTCPhone extends Emitter {
8786
8897
 
8787
8898
  // Deprecated
8788
8899
  getLocalStreamForCall(callSession ) {
8789
- logger$6.warn('WebRTCPhone.getLocalStreamForCall is deprecated, use WebRTCPhone.getLocalStream instead');
8900
+ logger$7.warn('WebRTCPhone.getLocalStreamForCall is deprecated, use WebRTCPhone.getLocalStream instead');
8790
8901
 
8791
8902
  return this.getLocalStream(callSession);
8792
8903
  }
8793
8904
 
8794
8905
  // Deprecated
8795
8906
  getRemoteStreamForCall(callSession ) {
8796
- logger$6.warn('WebRTCPhone.getRemoteStreamForCall is deprecated, use WebRTCPhone.getRemoteStream instead');
8907
+ logger$7.warn('WebRTCPhone.getRemoteStreamForCall is deprecated, use WebRTCPhone.getRemoteStream instead');
8797
8908
 
8798
8909
  return this.getRemoteVideoStream(callSession);
8799
8910
  }
8800
8911
 
8801
8912
  getRemoteStreamsForCall(callSession ) {
8802
- logger$6.warn('WebRTCPhone.getRemoteStreamsForCall is deprecated, use WebRTCPhone.getRemoteStreams instead');
8913
+ logger$7.warn('WebRTCPhone.getRemoteStreamsForCall is deprecated, use WebRTCPhone.getRemoteStreams instead');
8803
8914
 
8804
8915
  return this.getRemoteStream(callSession);
8805
8916
  }
8806
8917
 
8807
8918
  accept(callSession , cameraEnabled ) {
8808
- logger$6.info('WebRTC phone - accept call', { id: callSession ? callSession.getId() : 'n/a', cameraEnabled });
8919
+ logger$7.info('WebRTC phone - accept call', { id: callSession ? callSession.getId() : 'n/a', cameraEnabled });
8809
8920
  if (this.currentSipSession) {
8810
8921
  this.holdSipSession(this.currentSipSession, this.currentCallSession, true);
8811
8922
  }
8812
8923
 
8813
8924
  if (!callSession) {
8814
- logger$6.warn('no CallSession to accept.');
8925
+ logger$7.warn('no CallSession to accept.');
8815
8926
  return Promise.resolve(null);
8816
8927
  }
8817
8928
 
8818
8929
  if (callSession.getId() in this.acceptedSessions) {
8819
- logger$6.warn('CallSession already accepted.', { id: callSession ? callSession.getId() : 'n/a' });
8930
+ logger$7.warn('CallSession already accepted.', { id: callSession ? callSession.getId() : 'n/a' });
8820
8931
  return Promise.resolve(callSession.sipCallId);
8821
8932
  }
8822
8933
 
@@ -8828,24 +8939,24 @@ class WebRTCPhone extends Emitter {
8828
8939
  const sipSession = this.client.getSipSession(callSession.getId());
8829
8940
  if (sipSession) {
8830
8941
  if (sipSession.state === sessionState.SessionState.Terminated || sipSession.state === sessionState.SessionState.Terminating) {
8831
- logger$6.warn('Trying to answer a terminated sipSession.');
8942
+ logger$7.warn('Trying to answer a terminated sipSession.');
8832
8943
 
8833
8944
  return Promise.resolve(null);
8834
8945
  }
8835
8946
 
8836
- logger$6.info('accept call, session found', { sipId: sipSession.id });
8947
+ logger$7.info('accept call, session found', { sipId: sipSession.id });
8837
8948
 
8838
8949
  // $FlowFixMe
8839
8950
  return this.client.answer(sipSession, this.allowVideo ? cameraEnabled : false).then(() => {
8840
8951
  return callSession.sipCallId;
8841
8952
  }).catch(e => {
8842
- logger$6.error(e);
8953
+ logger$7.error(e);
8843
8954
  this.endCurrentCall(callSession);
8844
8955
  throw e;
8845
8956
  });
8846
8957
  }
8847
8958
 
8848
- logger$6.warn('no CallSession found to accept.', { id: callSession ? callSession.getId() : 'n/a' });
8959
+ logger$7.warn('no CallSession found to accept.', { id: callSession ? callSession.getId() : 'n/a' });
8849
8960
 
8850
8961
  return Promise.resolve(null);
8851
8962
  }
@@ -8855,7 +8966,7 @@ class WebRTCPhone extends Emitter {
8855
8966
  }
8856
8967
 
8857
8968
  async reject(callSession ) {
8858
- logger$6.info('reject WebRTC called', { id: callSession.getId() });
8969
+ logger$7.info('reject WebRTC called', { id: callSession.getId() });
8859
8970
 
8860
8971
  this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'call rejected locally');
8861
8972
  if (!callSession || callSession.getId() in this.rejectedSessions) {
@@ -8867,14 +8978,14 @@ class WebRTCPhone extends Emitter {
8867
8978
 
8868
8979
  const sipSession = this.findSipSession(callSession);
8869
8980
  if (sipSession) {
8870
- logger$6.info('WebRTC rejecting', { sipId: sipSession.id });
8981
+ logger$7.info('WebRTC rejecting', { sipId: sipSession.id });
8871
8982
 
8872
8983
  this.client.hangup(sipSession);
8873
8984
  }
8874
8985
  }
8875
8986
 
8876
8987
  async ignore(callSession ) {
8877
- logger$6.info('WebRTC ignore', { id: callSession.getId() });
8988
+ logger$7.info('WebRTC ignore', { id: callSession.getId() });
8878
8989
 
8879
8990
  // kill the ring
8880
8991
  this.eventEmitter.emit(ON_TERMINATE_SOUND, callSession, 'ignoring call');
@@ -8883,7 +8994,7 @@ class WebRTCPhone extends Emitter {
8883
8994
  }
8884
8995
 
8885
8996
  hold(callSession , withEvent = true, isConference = false) {
8886
- logger$6.info('WebRTC hold', { id: callSession.getId() });
8997
+ logger$7.info('WebRTC hold', { id: callSession.getId() });
8887
8998
 
8888
8999
  const sipSession = this.findSipSession(callSession);
8889
9000
 
@@ -8894,7 +9005,7 @@ class WebRTCPhone extends Emitter {
8894
9005
 
8895
9006
  // @Deprecated
8896
9007
  unhold(callSession , withEvent = true, isConference = false) {
8897
- logger$6.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
9008
+ logger$7.info('WebRTC unhold', { id: callSession ? callSession.getId() : null });
8898
9009
 
8899
9010
  console.warn('Please note that `phone.unhold()` is being deprecated; `phone.resume()` is the preferred method');
8900
9011
 
@@ -8909,7 +9020,7 @@ class WebRTCPhone extends Emitter {
8909
9020
  const sipSession = this.findSipSession(callSession);
8910
9021
 
8911
9022
  if (sipSession) {
8912
- logger$6.info('WebRTC atxfer', { sipId: sipSession.id });
9023
+ logger$7.info('WebRTC atxfer', { sipId: sipSession.id });
8913
9024
 
8914
9025
  return this.client.atxfer(sipSession);
8915
9026
  }
@@ -8924,7 +9035,7 @@ class WebRTCPhone extends Emitter {
8924
9035
  if (!sipSession) {
8925
9036
  return new Promise((resolve, reject) => reject(new Error('No session to hold')));
8926
9037
  }
8927
- logger$6.info('WebRTC hold sip session', { sipId: sipSession.id });
9038
+ logger$7.info('WebRTC hold sip session', { sipId: sipSession.id });
8928
9039
 
8929
9040
  const promise = this.client.hold(sipSession, isConference);
8930
9041
  if (withEvent) {
@@ -8943,7 +9054,7 @@ class WebRTCPhone extends Emitter {
8943
9054
  if (!sipSession) {
8944
9055
  return new Promise((resolve, reject) => reject(new Error('No session to unhold')));
8945
9056
  }
8946
- logger$6.info('WebRTC unhold', { sipId: sipSession.id });
9057
+ logger$7.info('WebRTC unhold', { sipId: sipSession.id });
8947
9058
 
8948
9059
  const promise = this.client.unhold(sipSession, isConference);
8949
9060
  if (withEvent) {
@@ -8954,18 +9065,18 @@ class WebRTCPhone extends Emitter {
8954
9065
  }
8955
9066
 
8956
9067
  resume(callSession , isConference = false) {
8957
- logger$6.info('WebRTC resume called', { id: callSession ? callSession.getId() : null });
9068
+ logger$7.info('WebRTC resume called', { id: callSession ? callSession.getId() : null });
8958
9069
 
8959
9070
  const sipSession = this.findSipSession(callSession);
8960
9071
  if (!sipSession) {
8961
9072
  return new Promise((resolve, reject) => reject(new Error('No session to resume')));
8962
9073
  }
8963
9074
 
8964
- logger$6.info('WebRTC resuming', { sipId: sipSession.id });
9075
+ logger$7.info('WebRTC resuming', { sipId: sipSession.id });
8965
9076
 
8966
9077
  // Hold current session if different from the current one (we don't want 2 sessions active at the same time).
8967
9078
  if (this.currentSipSession && this.currentSipSession.id !== sipSession.id) {
8968
- logger$6.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
9079
+ logger$7.info('WebRTC hold call after resume', { id: this.currentSipSession.id });
8969
9080
  this.holdSipSession(this.currentSipSession, callSession);
8970
9081
  }
8971
9082
 
@@ -8980,14 +9091,14 @@ class WebRTCPhone extends Emitter {
8980
9091
  }
8981
9092
 
8982
9093
  mute(callSession , withEvent = true) {
8983
- logger$6.info('WebRTC mute called', { id: callSession ? callSession.getId() : null });
9094
+ logger$7.info('WebRTC mute called', { id: callSession ? callSession.getId() : null });
8984
9095
 
8985
9096
  const sipSession = this.findSipSession(callSession);
8986
9097
  if (!sipSession) {
8987
9098
  return;
8988
9099
  }
8989
9100
 
8990
- logger$6.info('WebRTC muting', { sipId: sipSession.id });
9101
+ logger$7.info('WebRTC muting', { sipId: sipSession.id });
8991
9102
  this.client.mute(sipSession);
8992
9103
  const newCallSession = this._createCallSession(sipSession, callSession, { muted: true });
8993
9104
 
@@ -9001,14 +9112,14 @@ class WebRTCPhone extends Emitter {
9001
9112
  }
9002
9113
 
9003
9114
  unmute(callSession , withEvent = true) {
9004
- logger$6.info('WebRTC unmute called', { id: callSession ? callSession.getId() : null });
9115
+ logger$7.info('WebRTC unmute called', { id: callSession ? callSession.getId() : null });
9005
9116
 
9006
9117
  const sipSession = this.findSipSession(callSession);
9007
9118
  if (!sipSession) {
9008
9119
  return;
9009
9120
  }
9010
9121
 
9011
- logger$6.info('WebRTC unmuting', { sipId: sipSession.id });
9122
+ logger$7.info('WebRTC unmuting', { sipId: sipSession.id });
9012
9123
  this.client.unmute(sipSession);
9013
9124
  const newCallSession = this._createCallSession(sipSession, callSession, { muted: false });
9014
9125
 
@@ -9035,7 +9146,7 @@ class WebRTCPhone extends Emitter {
9035
9146
  if (!sipSession) {
9036
9147
  return;
9037
9148
  }
9038
- logger$6.info('WebRTC turn camera on', { sipId: sipSession.id });
9149
+ logger$7.info('WebRTC turn camera on', { sipId: sipSession.id });
9039
9150
 
9040
9151
  this.client.toggleCameraOn(sipSession);
9041
9152
 
@@ -9047,7 +9158,7 @@ class WebRTCPhone extends Emitter {
9047
9158
  if (!sipSession) {
9048
9159
  return;
9049
9160
  }
9050
- logger$6.info('WebRTC turn camera off', { sipId: sipSession.id });
9161
+ logger$7.info('WebRTC turn camera off', { sipId: sipSession.id });
9051
9162
 
9052
9163
  this.client.toggleCameraOff(sipSession);
9053
9164
  this.eventEmitter.emit(ON_CAMERA_DISABLED, this._createCameraDisabledCallSession(sipSession, callSession));
@@ -9059,7 +9170,7 @@ class WebRTCPhone extends Emitter {
9059
9170
  return;
9060
9171
  }
9061
9172
 
9062
- logger$6.info('WebRTC send key', { sipId: sipSession.id, tone });
9173
+ logger$7.info('WebRTC send key', { sipId: sipSession.id, tone });
9063
9174
  this.client.sendDTMF(sipSession, tone);
9064
9175
  }
9065
9176
 
@@ -9067,7 +9178,7 @@ class WebRTCPhone extends Emitter {
9067
9178
  // @TODO: line is not used here
9068
9179
  async makeCall(number , line , cameraEnabled ,
9069
9180
  audioOnly = false, conference = false) {
9070
- logger$6.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled });
9181
+ logger$7.info('make WebRTC call', { number, lineId: line ? line.id : null, cameraEnabled });
9071
9182
  if (!number) {
9072
9183
  return Promise.resolve(null);
9073
9184
  }
@@ -9077,7 +9188,7 @@ class WebRTCPhone extends Emitter {
9077
9188
  }
9078
9189
  if (this.currentSipSession) {
9079
9190
  this.holdSipSession(this.currentSipSession, this.currentCallSession, true).catch(e => {
9080
- logger$6.warn('Unable to hold current session when making another call', e);
9191
+ logger$7.warn('Unable to hold current session when making another call', e);
9081
9192
  });
9082
9193
  }
9083
9194
 
@@ -9087,7 +9198,7 @@ class WebRTCPhone extends Emitter {
9087
9198
  this._bindEvents(sipSession);
9088
9199
  } catch (error) {
9089
9200
  console.warn(error);
9090
- logger$6.warn('make WebRTC call, error', { message: error.message, stack: error.stack });
9201
+ logger$7.warn('make WebRTC call, error', { message: error.message, stack: error.stack });
9091
9202
  return Promise.resolve(null);
9092
9203
  }
9093
9204
  const callSession = this._createOutgoingCallSession(sipSession, cameraEnabled || false);
@@ -9115,7 +9226,7 @@ class WebRTCPhone extends Emitter {
9115
9226
  return;
9116
9227
  }
9117
9228
 
9118
- logger$6.info('WebRTC transfer', { sipId: sipSession.id, target });
9229
+ logger$7.info('WebRTC transfer', { sipId: sipSession.id, target });
9119
9230
 
9120
9231
  this.client.transfer(sipSession, target);
9121
9232
  }
@@ -9124,7 +9235,7 @@ class WebRTCPhone extends Emitter {
9124
9235
  const sipSession = this.client.getSipSession(source.sipCallId);
9125
9236
  const sipSessionTarget = this.client.getSipSession(destination.sipCallId);
9126
9237
 
9127
- logger$6.info('WebRTC indirect transfer', {
9238
+ logger$7.info('WebRTC indirect transfer', {
9128
9239
  sipId: sipSession ? sipSession.id : null,
9129
9240
  target: sipSessionTarget ? sipSessionTarget.id : null,
9130
9241
  });
@@ -9152,7 +9263,7 @@ class WebRTCPhone extends Emitter {
9152
9263
  return false;
9153
9264
  }
9154
9265
 
9155
- logger$6.info('WebRTC hangup', { sipId: sipSession.id });
9266
+ logger$7.info('WebRTC hangup', { sipId: sipSession.id });
9156
9267
 
9157
9268
  const sipSessionId = this.getSipSessionId(sipSession);
9158
9269
 
@@ -9197,7 +9308,7 @@ class WebRTCPhone extends Emitter {
9197
9308
  }
9198
9309
 
9199
9310
  async close() {
9200
- logger$6.info('WebRTC close');
9311
+ logger$7.info('WebRTC close');
9201
9312
 
9202
9313
  try {
9203
9314
  await Promise.race([
@@ -9205,7 +9316,7 @@ class WebRTCPhone extends Emitter {
9205
9316
  new Promise((resolve, reject) => setTimeout(() => reject(new Error('Unregister, timed out')), 3000)),
9206
9317
  ]);
9207
9318
  } catch (e) {
9208
- logger$6.error('WebRTC close, unregister error', e);
9319
+ logger$7.error('WebRTC close, unregister error', e);
9209
9320
  }
9210
9321
 
9211
9322
  this.client.close();
@@ -9223,12 +9334,12 @@ class WebRTCPhone extends Emitter {
9223
9334
  }
9224
9335
 
9225
9336
  enableRinging() {
9226
- logger$6.info('WebRTC enable ringing');
9337
+ logger$7.info('WebRTC enable ringing');
9227
9338
  this.ringingEnabled = true;
9228
9339
  }
9229
9340
 
9230
9341
  disableRinging() {
9231
- logger$6.info('WebRTC disable ringing');
9342
+ logger$7.info('WebRTC disable ringing');
9232
9343
  this.ringingEnabled = false;
9233
9344
  }
9234
9345
 
@@ -9268,7 +9379,7 @@ class WebRTCPhone extends Emitter {
9268
9379
 
9269
9380
  // Deprecated
9270
9381
  getLocalMediaStream(callSession ) {
9271
- logger$6.warn('WebRTCPhone.getLocalMediaStream is deprecated, use WebRTCPhone.getLocalStream instead');
9382
+ logger$7.warn('WebRTCPhone.getLocalMediaStream is deprecated, use WebRTCPhone.getLocalStream instead');
9272
9383
  return this.getLocalStream(callSession);
9273
9384
  }
9274
9385
 
@@ -9276,6 +9387,10 @@ class WebRTCPhone extends Emitter {
9276
9387
  return callSession ? this.client.hasLocalVideo(callSession.sipCallId) : null;
9277
9388
  }
9278
9389
 
9390
+ hasALocalVideoTrack(callSession ) {
9391
+ return callSession ? this.client.hasALocalVideoTrack(callSession.sipCallId) : null;
9392
+ }
9393
+
9279
9394
  getRemoteStream(callSession ) {
9280
9395
  return callSession ? this.client.getRemoteStream(callSession.sipCallId) : null;
9281
9396
  }
@@ -9298,7 +9413,7 @@ class WebRTCPhone extends Emitter {
9298
9413
  this.client.on(this.client.INVITE, (sipSession , wantsToDoVideo ) => {
9299
9414
  const autoAnswer = sipSession.request.getHeader('Answer-Mode') === 'Auto';
9300
9415
  const withVideo = this.allowVideo ? wantsToDoVideo : false;
9301
- logger$6.info('WebRTC invite received', { sipId: sipSession.id, withVideo, autoAnswer });
9416
+ logger$7.info('WebRTC invite received', { sipId: sipSession.id, withVideo, autoAnswer });
9302
9417
 
9303
9418
  const callSession = this._createIncomingCallSession(sipSession, withVideo, null, autoAnswer);
9304
9419
  this.incomingSessions.push(callSession.getId());
@@ -9321,7 +9436,7 @@ class WebRTCPhone extends Emitter {
9321
9436
  });
9322
9437
 
9323
9438
  this.client.on(this.client.ON_REINVITE, (...args) => {
9324
- logger$6.info('WebRTC on reinvite', {
9439
+ logger$7.info('WebRTC on reinvite', {
9325
9440
  sessionId: args[0].id,
9326
9441
  inviteId: args[1].id,
9327
9442
  updatedCalleeName: args[2],
@@ -9341,7 +9456,7 @@ class WebRTCPhone extends Emitter {
9341
9456
  });
9342
9457
 
9343
9458
  this.client.on(this.client.ACCEPTED, (sipSession ) => {
9344
- logger$6.info('WebRTC call accepted', { sipId: sipSession.id });
9459
+ logger$7.info('WebRTC call accepted', { sipId: sipSession.id });
9345
9460
 
9346
9461
  this._onCallAccepted(sipSession, this.client.hasVideo(this.getSipSessionId(sipSession)));
9347
9462
 
@@ -9352,17 +9467,17 @@ class WebRTCPhone extends Emitter {
9352
9467
  this.client.on('ended', () => {});
9353
9468
 
9354
9469
  this.client.on(this.client.ON_ERROR, e => {
9355
- logger$6.error('WebRTC error', e);
9470
+ logger$7.error('WebRTC error', e);
9356
9471
  this.eventEmitter.emit(ON_CALL_ERROR, e);
9357
9472
  });
9358
9473
 
9359
9474
  this.client.on(this.client.UNREGISTERED, () => {
9360
- logger$6.info('WebRTC unregistered');
9475
+ logger$7.info('WebRTC unregistered');
9361
9476
  this.eventEmitter.emit(ON_UNREGISTERED);
9362
9477
  });
9363
9478
 
9364
9479
  this.client.on(this.client.REGISTERED, () => {
9365
- logger$6.info('WebRTC registered', {
9480
+ logger$7.info('WebRTC registered', {
9366
9481
  shouldSendReinvite: this.shouldSendReinvite,
9367
9482
  state: this.currentSipSession ? this.currentSipSession.state : null,
9368
9483
  currentSipSession: !!this.currentSipSession,
@@ -9378,19 +9493,19 @@ class WebRTCPhone extends Emitter {
9378
9493
  try {
9379
9494
  this.sendReinvite(this.currentCallSession);
9380
9495
  } catch (e) {
9381
- logger$6.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
9496
+ logger$7.error('WebRTC reinvite after register, error', { message: e.message, stack: e.stack });
9382
9497
  }
9383
9498
  }
9384
9499
  });
9385
9500
 
9386
9501
  this.client.on(this.client.CONNECTED, () => {
9387
- logger$6.info('WebRTC client connected');
9502
+ logger$7.info('WebRTC client connected');
9388
9503
 
9389
9504
  this.stopHeartbeat();
9390
9505
  });
9391
9506
 
9392
9507
  this.client.on(this.client.DISCONNECTED, () => {
9393
- logger$6.info('WebRTC client disconnected');
9508
+ logger$7.info('WebRTC client disconnected');
9394
9509
 
9395
9510
  this.eventEmitter.emit(ON_UNREGISTERED);
9396
9511
 
@@ -9622,7 +9737,7 @@ var PHONE_EVENTS = /*#__PURE__*/Object.freeze({
9622
9737
 
9623
9738
  //
9624
9739
 
9625
- const logger$5 = IssueReporter$1.loggerFor('simple-phone');
9740
+ const logger$6 = IssueReporter$1.loggerFor('simple-phone');
9626
9741
  const sipLogger = IssueReporter$1.loggerFor('sip.js');
9627
9742
  const protocolLogger = IssueReporter$1.loggerFor('sip');
9628
9743
 
@@ -9729,7 +9844,7 @@ class Phone extends Emitter {
9729
9844
  async disconnect() {
9730
9845
  if (this.phone) {
9731
9846
  if (this.phone.hasAnActiveCall()) {
9732
- logger$5.info('hangup call on disconnect');
9847
+ logger$6.info('hangup call on disconnect');
9733
9848
  // $FlowFixMe
9734
9849
  await this.phone.hangup();
9735
9850
  }
@@ -9752,13 +9867,13 @@ class Phone extends Emitter {
9752
9867
  }
9753
9868
 
9754
9869
  async hangup(callSession ) {
9755
- logger$5.info('hangup via simple phone', { callId: callSession.getId() });
9870
+ logger$6.info('hangup via simple phone', { callId: callSession.getId() });
9756
9871
 
9757
9872
  return this.phone && this.phone.hangup(callSession);
9758
9873
  }
9759
9874
 
9760
9875
  async accept(callSession , cameraEnabled ) {
9761
- logger$5.info('accept via simple phone', { callId: callSession.getId(), cameraEnabled });
9876
+ logger$6.info('accept via simple phone', { callId: callSession.getId(), cameraEnabled });
9762
9877
 
9763
9878
  return this.phone && this.phone.accept(callSession, cameraEnabled);
9764
9879
  }
@@ -9778,13 +9893,18 @@ class Phone extends Emitter {
9778
9893
  return adHocConference.start();
9779
9894
  }
9780
9895
 
9781
- mute(callSession ) {
9782
- this.muteViaAPI(callSession);
9896
+ mute(callSession , withApi = true) {
9897
+ if (withApi) {
9898
+ this.muteViaAPI(callSession);
9899
+ }
9900
+
9783
9901
  return this.phone && this.phone.mute(callSession);
9784
9902
  }
9785
9903
 
9786
- unmute(callSession ) {
9787
- this.unmuteViaAPI(callSession);
9904
+ unmute(callSession , withApi = true) {
9905
+ if (withApi) {
9906
+ this.unmuteViaAPI(callSession);
9907
+ }
9788
9908
 
9789
9909
  return this.phone && this.phone.unmute(callSession);
9790
9910
  }
@@ -9792,7 +9912,7 @@ class Phone extends Emitter {
9792
9912
  muteViaAPI(callSession ) {
9793
9913
  if (callSession && callSession.callId) {
9794
9914
  Wazo.getApiClient().calld.mute(callSession.callId).catch(e => {
9795
- logger$5.error('Mute via API, error', e);
9915
+ logger$6.error('Mute via API, error', e);
9796
9916
  });
9797
9917
  }
9798
9918
  }
@@ -9800,7 +9920,7 @@ class Phone extends Emitter {
9800
9920
  unmuteViaAPI(callSession ) {
9801
9921
  if (callSession && callSession.callId) {
9802
9922
  Wazo.getApiClient().calld.unmute(callSession.callId).catch(e => {
9803
- logger$5.error('Unmute via API, error', e);
9923
+ logger$6.error('Unmute via API, error', e);
9804
9924
  });
9805
9925
  }
9806
9926
  }
@@ -9890,9 +10010,13 @@ class Phone extends Emitter {
9890
10010
  return this.phone && this.phone.hasLocalVideo(callSession);
9891
10011
  }
9892
10012
 
10013
+ hasALocalVideoTrack(callSession ) {
10014
+ return this.phone && this.phone.hasALocalVideoTrack(callSession);
10015
+ }
10016
+
9893
10017
  // @Deprecated
9894
10018
  getLocalMediaStream(callSession ) {
9895
- logger$5.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
10019
+ logger$6.warn('Phone.getLocalMediaStream is deprecated, use Phone.getLocalStream instead');
9896
10020
 
9897
10021
  return this.phone && this.phone.getLocalStream(callSession);
9898
10022
  }
@@ -9911,20 +10035,20 @@ class Phone extends Emitter {
9911
10035
 
9912
10036
  // @Deprecated
9913
10037
  getRemoteStreamForCall(callSession ) {
9914
- logger$5.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
10038
+ logger$6.warn('Phone.getRemoteStreamForCall is deprecated, use Phone.getRemoteStream instead');
9915
10039
  return this.getRemoteStream(callSession);
9916
10040
  }
9917
10041
 
9918
10042
  // Returns remote streams directly from the peerConnection
9919
10043
  // @Deprecated
9920
10044
  getRemoteStreamsForCall(callSession ) {
9921
- logger$5.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
10045
+ logger$6.warn('Phone.getRemoteStreamsForCall is deprecated, use Phone.getLocalStream instead');
9922
10046
  return this.getLocalStream(callSession);
9923
10047
  }
9924
10048
 
9925
10049
  // @Deprecated
9926
10050
  getRemoteVideoStreamForCall(callSession ) {
9927
- logger$5.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
10051
+ logger$6.warn('Phone.getRemoteVideoStreamForCall is deprecated, use Phone.getRemoteVideoStream instead');
9928
10052
 
9929
10053
  return this.getRemoteVideoStream(callSession);
9930
10054
  }
@@ -10054,6 +10178,8 @@ const CONFERENCE_USER_PARTICIPANT_JOINED = 'conference_user_participant_joined';
10054
10178
  const CONFERENCE_USER_PARTICIPANT_LEFT = 'conference_user_participant_left';
10055
10179
  const CONFERENCE_USER_PARTICIPANT_TALK_STARTED = 'conference_user_participant_talk_started';
10056
10180
  const CONFERENCE_USER_PARTICIPANT_TALK_STOPPED = 'conference_user_participant_talk_stopped';
10181
+ const MEETING_USER_PARTICIPANT_JOINED = 'meeting_user_participant_joined';
10182
+ const MEETING_USER_PARTICIPANT_LEFT = 'meeting_user_participant_left';
10057
10183
  const SWITCHBOARD_QUEUED_CALLS_UPDATED = 'switchboard_queued_calls_updated';
10058
10184
  const SWITCHBOARD_QUEUED_CALL_ANSWERED = 'switchboard_queued_call_answered';
10059
10185
  const SWITCHBOARD_HELD_CALLS_UPDATED = 'switchboard_held_calls_updated';
@@ -10095,7 +10221,7 @@ const BLACKLIST_EVENTS = [
10095
10221
  ];
10096
10222
 
10097
10223
  const HEARTBEAT_ENGINE_VERSION = '20.09';
10098
- const logger$4 = IssueReporter$1.loggerFor('wazo-ws');
10224
+ const logger$5 = IssueReporter$1.loggerFor('wazo-ws');
10099
10225
  const messageLogger = IssueReporter$1.loggerFor('wazo-ws-message');
10100
10226
 
10101
10227
  class WebSocketClient extends Emitter {
@@ -10144,19 +10270,19 @@ class WebSocketClient extends Emitter {
10144
10270
  }
10145
10271
 
10146
10272
  connect() {
10147
- logger$4.info('connect method started', { host: this.host, token: this.token });
10273
+ logger$5.info('connect method started', { host: this.host, token: this.token });
10148
10274
  this.socket = new ReconnectingWebSocket__default['default'](this._getUrl.bind(this), [], this.options);
10149
10275
  if (this.options.binaryType) {
10150
10276
  this.socket.binaryType = this.options.binaryType;
10151
10277
  }
10152
10278
 
10153
10279
  this.socket.onopen = () => {
10154
- logger$4.info('on Wazo WS open', { method: 'connect', host: this.host });
10280
+ logger$5.info('on Wazo WS open', { method: 'connect', host: this.host });
10155
10281
  this.eventEmitter.emit(SOCKET_EVENTS$1.ON_OPEN);
10156
10282
  };
10157
10283
 
10158
10284
  this.socket.onerror = event => {
10159
- logger$4.error('on Wazo WS error', event.target);
10285
+ logger$5.error('on Wazo WS error', event.target);
10160
10286
  this.eventEmitter.emit(SOCKET_EVENTS$1.ON_ERROR, event);
10161
10287
  };
10162
10288
 
@@ -10186,7 +10312,7 @@ class WebSocketClient extends Emitter {
10186
10312
 
10187
10313
  this.socket.onclose = event => {
10188
10314
  // Can't be converted to JSON (circular structure)
10189
- logger$4.info('on Wazo WS close', {
10315
+ logger$5.info('on Wazo WS close', {
10190
10316
  reason: event.reason,
10191
10317
  code: event.code,
10192
10318
  readyState: event.target.readyState,
@@ -10204,12 +10330,12 @@ class WebSocketClient extends Emitter {
10204
10330
  };
10205
10331
 
10206
10332
  this.socket.onerror = event => {
10207
- logger$4.info('Wazo WS error', { message: event.message, code: event.code, readyState: event.target.readyState });
10333
+ logger$5.info('Wazo WS error', { message: event.message, code: event.code, readyState: event.target.readyState });
10208
10334
  };
10209
10335
  }
10210
10336
 
10211
10337
  close(force = false) {
10212
- logger$4.info('Wazo WS close', { socket: !!this.socket, host: this.host, token: this.token });
10338
+ logger$5.info('Wazo WS close', { socket: !!this.socket, host: this.host, token: this.token });
10213
10339
 
10214
10340
  if (!this.socket) {
10215
10341
  return;
@@ -10227,7 +10353,7 @@ class WebSocketClient extends Emitter {
10227
10353
 
10228
10354
  updateToken(token ) {
10229
10355
  this.token = token;
10230
- logger$4.info('Wazo WS updating token', { url: this._getUrl(), token, socket: !!this.socket });
10356
+ logger$5.info('Wazo WS updating token', { url: this._getUrl(), token, socket: !!this.socket });
10231
10357
 
10232
10358
  if (this.socket) {
10233
10359
  // If still connected, send the token to the WS
@@ -10245,7 +10371,7 @@ class WebSocketClient extends Emitter {
10245
10371
  }
10246
10372
 
10247
10373
  startHeartbeat() {
10248
- logger$4.info('Wazo WS start heartbeat', { host: this.host, token: this.token });
10374
+ logger$5.info('Wazo WS start heartbeat', { host: this.host, token: this.token });
10249
10375
 
10250
10376
  if (!this.socket) {
10251
10377
  this.heartbeat.stop();
@@ -10259,7 +10385,7 @@ class WebSocketClient extends Emitter {
10259
10385
  }
10260
10386
 
10261
10387
  stopHeartbeat() {
10262
- logger$4.info('Wazo WS stop heartbeat', { host: this.host, token: this.token });
10388
+ logger$5.info('Wazo WS stop heartbeat', { host: this.host, token: this.token });
10263
10389
 
10264
10390
  this.heartbeat.stop();
10265
10391
  }
@@ -10289,7 +10415,7 @@ class WebSocketClient extends Emitter {
10289
10415
  }
10290
10416
 
10291
10417
  reconnect(reason ) {
10292
- logger$4.info('Wazo WS reconnect', { reason, socket: !!this.socket, host: this.host, token: this.token });
10418
+ logger$5.info('Wazo WS reconnect', { reason, socket: !!this.socket, host: this.host, token: this.token });
10293
10419
  if (!this.socket) {
10294
10420
  return;
10295
10421
  }
@@ -10345,7 +10471,7 @@ class WebSocketClient extends Emitter {
10345
10471
  this.close();
10346
10472
  }
10347
10473
  const url = `wss://${this.host || ''}/api/websocketd/?token=${this.token || ''}&version=${this.version}`;
10348
- logger$4.log('Wazo WS url computed to reconnect', { url });
10474
+ logger$5.log('Wazo WS url computed to reconnect', { url });
10349
10475
 
10350
10476
  return url;
10351
10477
  }
@@ -10353,12 +10479,12 @@ class WebSocketClient extends Emitter {
10353
10479
  _onHeartbeat(message ) {
10354
10480
  if (message.payload === 'pong') {
10355
10481
  this.heartbeat.onHeartbeat();
10356
- logger$4.log('on heartbeat received from Wazo WS');
10482
+ logger$5.log('on heartbeat received from Wazo WS');
10357
10483
  }
10358
10484
  }
10359
10485
 
10360
10486
  async _onHeartbeatTimeout() {
10361
- logger$4.log('heartbeat timed out', { host: this.host, token: this.token });
10487
+ logger$5.log('heartbeat timed out', { host: this.host, token: this.token });
10362
10488
 
10363
10489
  this.close();
10364
10490
  this.eventEmitter.emit(SOCKET_EVENTS$1.ON_CLOSE, new Error('Websocket ping failure.'));
@@ -10400,6 +10526,8 @@ WebSocketClient.eventLists = [
10400
10526
  CHATD_USER_ROOM_CREATED,
10401
10527
  CONFERENCE_USER_PARTICIPANT_JOINED,
10402
10528
  CONFERENCE_USER_PARTICIPANT_LEFT,
10529
+ MEETING_USER_PARTICIPANT_JOINED,
10530
+ MEETING_USER_PARTICIPANT_LEFT,
10403
10531
  CONFERENCE_USER_PARTICIPANT_TALK_STARTED,
10404
10532
  CONFERENCE_USER_PARTICIPANT_TALK_STOPPED,
10405
10533
  SWITCHBOARD_QUEUED_CALLS_UPDATED,
@@ -10470,6 +10598,8 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
10470
10598
  CONFERENCE_USER_PARTICIPANT_LEFT: CONFERENCE_USER_PARTICIPANT_LEFT,
10471
10599
  CONFERENCE_USER_PARTICIPANT_TALK_STARTED: CONFERENCE_USER_PARTICIPANT_TALK_STARTED,
10472
10600
  CONFERENCE_USER_PARTICIPANT_TALK_STOPPED: CONFERENCE_USER_PARTICIPANT_TALK_STOPPED,
10601
+ MEETING_USER_PARTICIPANT_JOINED: MEETING_USER_PARTICIPANT_JOINED,
10602
+ MEETING_USER_PARTICIPANT_LEFT: MEETING_USER_PARTICIPANT_LEFT,
10473
10603
  SWITCHBOARD_QUEUED_CALLS_UPDATED: SWITCHBOARD_QUEUED_CALLS_UPDATED,
10474
10604
  SWITCHBOARD_QUEUED_CALL_ANSWERED: SWITCHBOARD_QUEUED_CALL_ANSWERED,
10475
10605
  SWITCHBOARD_HELD_CALLS_UPDATED: SWITCHBOARD_HELD_CALLS_UPDATED,
@@ -10511,7 +10641,7 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
10511
10641
  const { SOCKET_EVENTS, ...OTHER_EVENTS } = WebSocketClient$1;
10512
10642
  const ALL_EVENTS = [...Object.values(SOCKET_EVENTS), ...Object.values(OTHER_EVENTS)];
10513
10643
 
10514
- const logger$3 = IssueReporter$1.loggerFor('simple-ws-client');
10644
+ const logger$4 = IssueReporter$1.loggerFor('simple-ws-client');
10515
10645
 
10516
10646
  class Websocket extends Emitter {
10517
10647
 
@@ -10535,7 +10665,7 @@ class Websocket extends Emitter {
10535
10665
  }
10536
10666
 
10537
10667
  open(host , session ) {
10538
- logger$3.info('open simple WebSocket', { host, token: session.token });
10668
+ logger$4.info('open simple WebSocket', { host, token: session.token });
10539
10669
  this.ws = new WebSocketClient(
10540
10670
  {
10541
10671
  host,
@@ -10563,7 +10693,7 @@ class Websocket extends Emitter {
10563
10693
  }
10564
10694
 
10565
10695
  updateToken(token ) {
10566
- logger$3.info('update token via simple Websocket', { token, ws: !!this.ws });
10696
+ logger$4.info('update token via simple Websocket', { token, ws: !!this.ws });
10567
10697
 
10568
10698
  if (!this.ws) {
10569
10699
  return;
@@ -10591,6 +10721,145 @@ var Websocket$1 = global.wazoWebsocketInstance;
10591
10721
 
10592
10722
  //
10593
10723
 
10724
+ const logger$3 = IssueReporter$1.loggerFor('sdk-sip-room');
10725
+
10726
+ class SipRoom extends Room {
10727
+
10728
+ static async connect({ extension, constraints, audioOnly = false, extra, room } ) {
10729
+ logger$3.info('connecting to sip room', { extension, audioOnly, room: !!room });
10730
+
10731
+ if (!room) {
10732
+ await Wazo.Phone.connect();
10733
+
10734
+ const withCamera = constraints && !!constraints.video;
10735
+
10736
+ const callSession = await Wazo.Phone.call(extension, withCamera, null, audioOnly, true);
10737
+ // eslint-disable-next-line no-param-reassign
10738
+ room = new SipRoom(callSession, extension, null, null, extra);
10739
+ }
10740
+
10741
+ if (room && room.callSession && room.callSession.call) {
10742
+ room.setCallId(room.callSession.call.id);
10743
+ }
10744
+
10745
+ logger$3.info('connected to room', {
10746
+ extension: room.extension,
10747
+ });
10748
+
10749
+ return room;
10750
+ }
10751
+
10752
+ mute() {
10753
+ logger$3.info('mute sip room');
10754
+
10755
+ Wazo.Phone.mute(this.callSession, false);
10756
+
10757
+ this.sendMuteStatus();
10758
+ }
10759
+
10760
+ unmute() {
10761
+ logger$3.info('unmute sip room');
10762
+
10763
+ Wazo.Phone.unmute(this.callSession, false);
10764
+
10765
+ this.sendUnMuteStatus();
10766
+ }
10767
+
10768
+ getLocalGuestName() {
10769
+ return Wazo.Phone.phone.client.userAgent.options.displayName;
10770
+ }
10771
+
10772
+ // Overridden to not listen to websocket messages
10773
+ _transferEvents() {
10774
+ // Phone events
10775
+ Wazo.Phone.on(this.ON_MESSAGE, this._boundOnMessage);
10776
+ Wazo.Phone.on(this.ON_CHAT, this._boundOnChat);
10777
+ Wazo.Phone.on(this.ON_SIGNAL, this._boundOnSignal);
10778
+ Wazo.Phone.on(this.ON_VIDEO_INPUT_CHANGE, this._boundSaveLocalVideoStream);
10779
+
10780
+ [this.ON_AUDIO_STREAM, this.ON_VIDEO_STREAM, this.ON_REMOVE_STREAM].forEach(event =>
10781
+ Wazo.Phone.on(event, (...args) => this.eventEmitter.emit.apply(this.eventEmitter, [event, ...args])));
10782
+ }
10783
+
10784
+ _onMessage(message ) {
10785
+ // eslint-disable-next-line no-underscore-dangle
10786
+ const body = super._onMessage(message);
10787
+ if (!body) {
10788
+ return;
10789
+ }
10790
+
10791
+ const getChannel = () => body.channels[0];
10792
+
10793
+ switch (body.type) {
10794
+ case 'ConfbridgeWelcome':
10795
+ body.channels.forEach(channel => {
10796
+ this._onParticipantJoined(channel);
10797
+ });
10798
+
10799
+ break;
10800
+ case 'ConfbridgeJoin': {
10801
+ const channel = getChannel();
10802
+ this._onParticipantJoined(channel);
10803
+ break;
10804
+ }
10805
+ case 'ConfbridgeLeave': {
10806
+ const channel = getChannel();
10807
+ this._onParticipantLeft({
10808
+ data: {
10809
+ call_id: channel.id,
10810
+ },
10811
+ });
10812
+ break;
10813
+ }
10814
+ }
10815
+ }
10816
+
10817
+ async _onParticipantJoined(channel ) {
10818
+ const isLocal = channel.channelvars.WAZO_SIP_CALL_ID === this._getCurrentSipCallIs();
10819
+ const callId = channel.id;
10820
+ const ParticipantClass = isLocal ? Wazo.LocalParticipant : Wazo.RemoteParticipant;
10821
+ const name = channel.caller ? channel.caller.name : null;
10822
+ const extra = isLocal ? { guestName: this.getLocalGuestName() } : {};
10823
+ const participant = new ParticipantClass(this, {
10824
+ caller_id_name: name,
10825
+ call_id: callId,
10826
+ }, extra);
10827
+
10828
+ const participantIdx = this.participants.findIndex(other => other.callId === participant.callId);
10829
+ if (participantIdx !== -1 && name) {
10830
+ this.participants[participantIdx].name = name;
10831
+ return;
10832
+ }
10833
+
10834
+ if (isLocal) {
10835
+ // Should be updated by the Wazo WS but we don't have it for now
10836
+ if (this.callSession) {
10837
+ this.callSession.ringing = false;
10838
+ }
10839
+
10840
+ this._onLocalParticipantJoined(participant);
10841
+
10842
+ // Give some time for the stream to be updated
10843
+ setTimeout(() => {
10844
+ this.eventEmitter.emit(this.ON_JOINED, participant, this.participants);
10845
+ }, 1000);
10846
+ }
10847
+
10848
+ this.participants.push(participant);
10849
+
10850
+ this._isParticipantJoining(participant);
10851
+
10852
+ return participant;
10853
+ }
10854
+
10855
+ _getCurrentSipCallIs() {
10856
+ return Wazo.Phone.getSipSessionId(Wazo.Phone.phone.currentSipSession);
10857
+ }
10858
+
10859
+ }
10860
+
10861
+ //
10862
+
10594
10863
  const logger$2 = IssueReporter$1.loggerFor('room');
10595
10864
 
10596
10865
  class Participant extends Emitter {
@@ -10625,6 +10894,7 @@ class Participant extends Emitter {
10625
10894
 
10626
10895
 
10627
10896
  /**
10897
+ * @param room Room The room where the participant is
10628
10898
  * @param rawParticipant string Participant sent via the Wazo WS
10629
10899
  * @param extra Object extra status of the participant
10630
10900
  */
@@ -10852,6 +11122,11 @@ class Participant extends Emitter {
10852
11122
  // Poor man's object comparison
10853
11123
  if (typeof status.extra !== 'undefined' && JSON.stringify(this.extra) !== JSON.stringify(status.extra)) {
10854
11124
  this.extra = { ...this.extra, ...status.extra };
11125
+
11126
+ if (this.extra.contact && !(this.extra.contact instanceof Contact)) {
11127
+ this.extra.contact = new Contact(this.extra.contact);
11128
+ }
11129
+
10855
11130
  this.triggerUpdate(this.ON_EXTRA_CHANGE, broadcast);
10856
11131
  }
10857
11132
  }
@@ -10934,9 +11209,7 @@ class Stream {
10934
11209
  return false;
10935
11210
  }
10936
11211
 
10937
- // With canvas track (used to fake upgrade in conference), we don't have a width
10938
- return this.htmlStream.getTracks().find(track => track.kind === 'video'
10939
- && track.readyState !== 'ended' && 'width' in track.getSettings());
11212
+ return this.htmlStream.getTracks().some(track => track.kind === 'video' && track.readyState !== 'ended');
10940
11213
  }
10941
11214
 
10942
11215
  get id() {
@@ -11837,6 +12110,7 @@ const Wazo = {
11837
12110
  Phone: Phone$1,
11838
12111
  Websocket: Websocket$1,
11839
12112
  Room,
12113
+ SipRoom,
11840
12114
  RemoteParticipant,
11841
12115
  LocalParticipant,
11842
12116
  Stream,
@@ -11873,6 +12147,7 @@ const Wazo = {
11873
12147
  IndirectTransfer,
11874
12148
  SwitchboardCall,
11875
12149
  WebRTCPhone,
12150
+ Meeting,
11876
12151
  },
11877
12152
 
11878
12153
  // Api
@@ -11901,7 +12176,7 @@ if (global) {
11901
12176
  global.Wazo = Wazo;
11902
12177
  }
11903
12178
 
11904
- /* global document */
12179
+ //
11905
12180
 
11906
12181
  const SIGNAL_TYPE_PARTICIPANT_UPDATE = 'signal/PARTICIPANT_UPDATE';
11907
12182
  const SIGNAL_TYPE_PARTICIPANT_REQUEST = 'signal/PARTICIPANT_REQUEST';
@@ -11913,6 +12188,7 @@ class Room extends Emitter {
11913
12188
 
11914
12189
 
11915
12190
 
12191
+
11916
12192
 
11917
12193
 
11918
12194
 
@@ -11934,6 +12210,8 @@ class Room extends Emitter {
11934
12210
 
11935
12211
 
11936
12212
 
12213
+
12214
+
11937
12215
 
11938
12216
 
11939
12217
 
@@ -11951,6 +12229,7 @@ class Room extends Emitter {
11951
12229
  * @param extension string
11952
12230
  * @param sourceId number
11953
12231
  * @param callId string
12232
+ * @param meetingUuid string
11954
12233
  * @param extra Object
11955
12234
  */
11956
12235
  constructor(
@@ -11958,15 +12237,17 @@ class Room extends Emitter {
11958
12237
  extension ,
11959
12238
  sourceId ,
11960
12239
  callId ,
12240
+ meetingUuid ,
11961
12241
  extra = {},
11962
12242
  ) {
11963
12243
  super();
11964
- logger.info('room initialized', { callId, extension, sourceId });
12244
+ logger.info('room initialized', { callId, extension, sourceId, meetingUuid });
11965
12245
 
11966
12246
  // Represents the room callSession
11967
12247
  this.callSession = callSession;
11968
12248
  this.extension = extension;
11969
12249
  this.sourceId = sourceId;
12250
+ this.meetingUuid = meetingUuid;
11970
12251
  this.callId = callId;
11971
12252
  this.participants = [];
11972
12253
  this.connected = false;
@@ -11986,6 +12267,8 @@ class Room extends Emitter {
11986
12267
  // Sugar syntax for `room.EVENT_NAME`
11987
12268
  this.CONFERENCE_USER_PARTICIPANT_JOINED = Wazo.Websocket.CONFERENCE_USER_PARTICIPANT_JOINED;
11988
12269
  this.CONFERENCE_USER_PARTICIPANT_LEFT = Wazo.Websocket.CONFERENCE_USER_PARTICIPANT_LEFT;
12270
+ this.MEETING_USER_PARTICIPANT_JOINED = Wazo.Websocket.MEETING_USER_PARTICIPANT_JOINED;
12271
+ this.MEETING_USER_PARTICIPANT_LEFT = Wazo.Websocket.MEETING_USER_PARTICIPANT_LEFT;
11989
12272
  this.ON_SHARE_SCREEN_ENDED = Wazo.Phone.ON_SHARE_SCREEN_ENDED;
11990
12273
  this.ON_MESSAGE = Wazo.Phone.ON_MESSAGE;
11991
12274
  this.ON_CHAT = Wazo.Phone.ON_CHAT;
@@ -12020,9 +12303,10 @@ class Room extends Emitter {
12020
12303
  * @param audioOnly boolean
12021
12304
  * @param extra Object
12022
12305
  * @param room ?Room
12306
+ * @param meeting ?Meeting
12023
12307
  * @returns {Promise<Room>}
12024
12308
  */
12025
- static async connect({ extension, constraints, audioOnly = false, extra, room } ) {
12309
+ static async connect({ extension, constraints, audioOnly = false, extra, room, meeting } ) {
12026
12310
  logger.info('connecting to room', { extension, audioOnly, room: !!room });
12027
12311
 
12028
12312
  if (!room) {
@@ -12057,21 +12341,31 @@ class Room extends Emitter {
12057
12341
  room.setCallId(room.callSession.call.id);
12058
12342
  }
12059
12343
 
12060
- // Fetch conference source
12061
- const sources = await getApiClient().dird.fetchConferenceSource('default');
12062
- // Retrieve conference sources
12063
- const contacts = await getApiClient().dird.fetchConferenceContacts(sources.items[0]);
12064
- // Retrieve conference
12065
- const conference = contacts.find(contact => contact.numbers.find(number => number.number === extension));
12344
+ if (!meeting) {
12345
+ // Fetch conference source
12346
+ const sources = await getApiClient().dird.fetchConferenceSource('default');
12347
+ // Retrieve conference sources
12348
+ const contacts = await getApiClient().dird.fetchConferenceContacts(sources.items[0]);
12349
+ // Retrieve conference
12350
+ const conference = contacts.find(contact => contact.numbers.find(number => number.number === extension));
12066
12351
 
12067
- logger.info('connected to room', {
12068
- sourceId: conference ? conference.sourceId : null,
12069
- name: conference ? conference.name : null,
12070
- });
12352
+ logger.info('connected to room', {
12353
+ sourceId: conference ? conference.sourceId : null,
12354
+ name: conference ? conference.name : null,
12355
+ });
12071
12356
 
12072
- if (conference) {
12073
- room.setSourceId(conference.sourceId);
12074
- room.setName(conference.name);
12357
+ if (conference) {
12358
+ room.setSourceId(conference.sourceId);
12359
+ room.setName(conference.name);
12360
+ }
12361
+ } else if (meeting) {
12362
+ logger.info('Already connected to meeting', {
12363
+ uuid: meeting.uuid,
12364
+ name: meeting.name,
12365
+ });
12366
+
12367
+ room.setMeetingUuid(meeting.uuid);
12368
+ room.setName(meeting.name);
12075
12369
  }
12076
12370
 
12077
12371
  return room;
@@ -12099,10 +12393,8 @@ class Room extends Emitter {
12099
12393
  Wazo.Phone.phone.off(Wazo.Phone.phone.client.ON_REINVITE, this._boundOnReinvite);
12100
12394
  Wazo.Websocket.off(this.CONFERENCE_USER_PARTICIPANT_JOINED, this._boundOnParticipantJoined);
12101
12395
  Wazo.Websocket.off(this.CONFERENCE_USER_PARTICIPANT_LEFT, this._boundOnParticipantLeft);
12102
-
12103
- if (this.roomAudioElement && document.body) {
12104
- document.body.removeChild(this.roomAudioElement);
12105
- }
12396
+ Wazo.Websocket.off(this.MEETING_USER_PARTICIPANT_JOINED, this._boundOnParticipantJoined);
12397
+ Wazo.Websocket.off(this.MEETING_USER_PARTICIPANT_LEFT, this._boundOnParticipantLeft);
12106
12398
  }
12107
12399
 
12108
12400
  setSourceId(sourceId ) {
@@ -12111,6 +12403,12 @@ class Room extends Emitter {
12111
12403
  this.sourceId = sourceId;
12112
12404
  }
12113
12405
 
12406
+ setMeetingUuid(meetingUuid ) {
12407
+ logger.info('set meeting uuid', { meetingUuid });
12408
+
12409
+ this.meetingUuid = meetingUuid;
12410
+ }
12411
+
12114
12412
  setCallId(callId ) {
12115
12413
  logger.info('set room call id', { callId });
12116
12414
 
@@ -12152,14 +12450,22 @@ class Room extends Emitter {
12152
12450
  return screensharingStream;
12153
12451
  }
12154
12452
 
12155
- stopScreenSharing(restoreLocalStream = true) {
12453
+ async stopScreenSharing(restoreLocalStream = true) {
12156
12454
  logger.info('stop room screen sharing');
12157
12455
 
12158
- Wazo.Phone.stopScreenSharing(this.callSession, restoreLocalStream);
12456
+ const reinvited = await Wazo.Phone.stopScreenSharing(this.callSession, restoreLocalStream);
12159
12457
 
12160
12458
  if (this.localParticipant) {
12161
12459
  this.localParticipant.onStopScreensharing();
12162
12460
  }
12461
+
12462
+ if (!reinvited && this.localParticipant) {
12463
+ // When we had video and we made a screenshare we don't reinvite when stopping the screensahre
12464
+ // So not REINVITE even is fired, we have to restore the video stream manually
12465
+ const localVideoStream = Wazo.Phone.getLocalVideoStream(this.callSession);
12466
+ // $FlowFixMe
12467
+ this._associateStreamTo(localVideoStream, this.localParticipant);
12468
+ }
12163
12469
  }
12164
12470
 
12165
12471
  turnCameraOff() {
@@ -12262,6 +12568,22 @@ class Room extends Emitter {
12262
12568
  return response;
12263
12569
  }
12264
12570
 
12571
+ hasALocalVideoTrack() {
12572
+ return Wazo.Phone.hasALocalVideoTrack(this.callSession);
12573
+ }
12574
+
12575
+ getLocalStream() {
12576
+ return Wazo.Phone.getLocalStream(this.callSession);
12577
+ }
12578
+
12579
+ getRemoteStream() {
12580
+ return Wazo.Phone.getRemoteStream(this.callSession);
12581
+ }
12582
+
12583
+ getRemoteVideoStream() {
12584
+ return Wazo.Phone.getRemoteVideoStream(this.callSession);
12585
+ }
12586
+
12265
12587
  _bindEvents() {
12266
12588
  if (!Wazo.Phone.phone || !Wazo.Phone.phone.currentSipSession) {
12267
12589
  return;
@@ -12283,27 +12605,10 @@ class Room extends Emitter {
12283
12605
  logger.info('on room audio stream');
12284
12606
 
12285
12607
  this.audioStream = stream;
12286
- if (document.createElement) {
12287
- // $FlowFixMe
12288
- let roomAudioElement = document.getElementById('audio-room');
12289
- if (!this.roomAudioElement) {
12290
- roomAudioElement = document.createElement('audio');
12291
- // $FlowFixMe
12292
- document.body.appendChild(roomAudioElement);
12293
- }
12294
- if (!roomAudioElement) {
12295
- return;
12296
- }
12297
- this.roomAudioElement = roomAudioElement;
12608
+ if (!this.roomAudioElement) {
12609
+ const sessionId = Wazo.Phone.phone.getSipSessionId(Wazo.Phone.phone.currentSipSession);
12610
+ this.roomAudioElement = Wazo.Phone.phone.createAudioElementFor(sessionId);
12298
12611
  this.roomAudioElement.srcObject = stream;
12299
- this.roomAudioElement.autoplay = true;
12300
- this.roomAudioElement.id = 'audio-room';
12301
-
12302
- // $FlowFixMe
12303
- if (this.roomAudioElement.setSinkId) {
12304
- // $FlowFixMe
12305
- this.roomAudioElement.setSinkId(Wazo.Phone.getOutputDevice());
12306
- }
12307
12612
  }
12308
12613
  });
12309
12614
 
@@ -12378,6 +12683,9 @@ class Room extends Emitter {
12378
12683
  Wazo.Websocket.on(this.CONFERENCE_USER_PARTICIPANT_JOINED, this._boundOnParticipantJoined);
12379
12684
  Wazo.Websocket.on(this.CONFERENCE_USER_PARTICIPANT_LEFT, this._boundOnParticipantLeft);
12380
12685
 
12686
+ Wazo.Websocket.on(this.MEETING_USER_PARTICIPANT_JOINED, this._boundOnParticipantJoined);
12687
+ Wazo.Websocket.on(this.MEETING_USER_PARTICIPANT_LEFT, this._boundOnParticipantLeft);
12688
+
12381
12689
  // Phone events
12382
12690
  Wazo.Phone.on(this.ON_MESSAGE, this._boundOnMessage);
12383
12691
  Wazo.Phone.on(this.ON_CHAT, this._boundOnChat);
@@ -12388,15 +12696,15 @@ class Room extends Emitter {
12388
12696
  Wazo.Phone.on(event, (...args) => this.eventEmitter.emit.apply(this.eventEmitter, [event, ...args])));
12389
12697
  }
12390
12698
 
12391
- _onMessage(message ) {
12699
+ _onMessage(message ) {
12392
12700
  if (message.method !== 'MESSAGE') {
12393
- return;
12701
+ return null;
12394
12702
  }
12395
12703
  let body;
12396
12704
  try {
12397
12705
  body = JSON.parse(message.body);
12398
12706
  } catch (e) {
12399
- return;
12707
+ return null;
12400
12708
  }
12401
12709
 
12402
12710
  switch (body.type) {
@@ -12415,6 +12723,8 @@ class Room extends Emitter {
12415
12723
  }
12416
12724
 
12417
12725
  this.eventEmitter.emit(this.ON_MESSAGE, body);
12726
+
12727
+ return body;
12418
12728
  }
12419
12729
 
12420
12730
  _onChat(content ) {
@@ -12479,23 +12789,24 @@ class Room extends Emitter {
12479
12789
  const session = Wazo.Auth.getSession();
12480
12790
  let participants = [];
12481
12791
 
12482
- // @TODO: we could use a better function name here
12483
- const isJoining = part => {
12484
- this.__associateStreams(part);
12485
- // @VALIDATE: no need to publicize ourselves, no?
12486
- if (part instanceof RemoteParticipant) {
12487
- this.eventEmitter.emit(this.CONFERENCE_USER_PARTICIPANT_JOINED, part);
12488
- }
12489
- };
12490
-
12491
12792
  // When we join the room, we can call `getConferenceParticipantsAsUser`, not before.
12492
12793
  if (participant.user_uuid === session.uuid) {
12493
12794
  logger.info('room current user joined');
12494
12795
 
12495
12796
  // Retrieve participants via an API calls
12496
12797
  const conferenceId = this.sourceId || payload.data.conference_id;
12497
- const response = await getApiClient().calld.getConferenceParticipantsAsUser(conferenceId);
12498
- logger.info('fetching conference participants', { conferenceId });
12798
+ let response;
12799
+ try {
12800
+ if (this.meetingUuid) {
12801
+ logger.info('fetching meeting participants', { meetingUuid: this.meetingUuid });
12802
+ response = await getApiClient().calld.getMeetingParticipantsAsUser(this.meetingUuid);
12803
+ } else {
12804
+ logger.info('fetching conference participants', { conferenceId });
12805
+ response = await getApiClient().calld.getConferenceParticipantsAsUser(conferenceId);
12806
+ }
12807
+ } catch (e) {
12808
+ logger.error('room participants fetching, error', e);
12809
+ }
12499
12810
  if (response) {
12500
12811
  logger.info('conference participants fetched', { nb: response.items.length });
12501
12812
  participants = response.items.map(item => {
@@ -12510,25 +12821,10 @@ class Room extends Emitter {
12510
12821
 
12511
12822
  const localParticipant = participants.find(someParticipant => someParticipant instanceof Wazo.LocalParticipant);
12512
12823
  if (!this.localParticipant && localParticipant) {
12513
- this.localParticipant = localParticipant;
12514
-
12515
- const localVideoStream = this._getLocalVideoStream();
12516
- if (localVideoStream) {
12517
- this._saveLocalVideoStream(localVideoStream);
12518
- }
12519
-
12520
- this.connected = true;
12521
-
12522
- // we're in the room, now let's request everyone's status
12523
- if (this.localParticipant) {
12524
- this.sendSignal({
12525
- type: SIGNAL_TYPE_PARTICIPANT_REQUEST,
12526
- origin: this.localParticipant.getStatus(),
12527
- });
12528
- }
12824
+ this._onLocalParticipantJoined(localParticipant);
12529
12825
  }
12530
12826
 
12531
- participants.forEach(someParticipant => isJoining(someParticipant));
12827
+ participants.forEach(someParticipant => this._isParticipantJoining(someParticipant));
12532
12828
  this.eventEmitter.emit(this.ON_JOINED, localParticipant, participants);
12533
12829
  }
12534
12830
 
@@ -12543,12 +12839,41 @@ class Room extends Emitter {
12543
12839
 
12544
12840
  if (remoteParticipant) {
12545
12841
  this.participants.push(remoteParticipant);
12546
- isJoining(remoteParticipant);
12842
+ this._isParticipantJoining(remoteParticipant);
12547
12843
  }
12548
12844
 
12549
12845
  return remoteParticipant;
12550
12846
  }
12551
12847
 
12848
+ _onLocalParticipantJoined(localParticipant ) {
12849
+ this.localParticipant = localParticipant;
12850
+
12851
+ const localVideoStream = this._getLocalVideoStream();
12852
+ if (localVideoStream) {
12853
+ this._saveLocalVideoStream(localVideoStream);
12854
+ }
12855
+
12856
+ this.connected = true;
12857
+
12858
+ localParticipant.broadcastStatus();
12859
+
12860
+ // we're in the room, now let's request everyone's status
12861
+ if (this.localParticipant) {
12862
+ this.sendSignal({
12863
+ type: SIGNAL_TYPE_PARTICIPANT_REQUEST,
12864
+ origin: this.localParticipant.getStatus(),
12865
+ });
12866
+ }
12867
+ }
12868
+
12869
+ _isParticipantJoining(participant ) {
12870
+ this.__associateStreams(participant);
12871
+ // @VALIDATE: no need to publicize ourselves, no?
12872
+ if (participant instanceof RemoteParticipant) {
12873
+ this.eventEmitter.emit(this.CONFERENCE_USER_PARTICIPANT_JOINED, participant);
12874
+ }
12875
+ }
12876
+
12552
12877
  _saveLocalVideoStream(stream ) {
12553
12878
  const { localParticipant } = this;
12554
12879
 
@@ -12594,9 +12919,11 @@ class Room extends Emitter {
12594
12919
  _onParticipantTrackUpdate(oldParticipant , update ) {
12595
12920
  const newParticipant = oldParticipant;
12596
12921
 
12597
- const { trackId } = this._callIdStreamIdMap[newParticipant.callId] || {};
12922
+ const { trackId, streamId } = this._callIdStreamIdMap[newParticipant.callId] || {};
12598
12923
  const pc = Wazo.Phone.phone.currentSipSession.sessionDescriptionHandler.peerConnection;
12599
- const stream = pc.getRemoteStreams().find(someStream => someStream.getTracks().some(track => track.id === trackId));
12924
+ // Can't use `getReceivers` here because on FF we make the mapping based on the streamId
12925
+ const stream = pc.getRemoteStreams().find(someStream =>
12926
+ someStream.id === streamId || someStream.getTracks().some(track => track.id === trackId));
12600
12927
 
12601
12928
  if (update === 'downgrade') {
12602
12929
  newParticipant.streams = [];
@@ -12626,15 +12953,42 @@ class Room extends Emitter {
12626
12953
  return;
12627
12954
  }
12628
12955
 
12629
- if (this._unassociatedVideoStreams[trackId]) {
12956
+ const streamId = this._getStreamIdFrTrackId(trackId);
12957
+ const key = this._getUnassociatedMapIdFromTrackIdOrStreamId(trackId, streamId);
12958
+ const stream = this._unassociatedVideoStreams[key];
12959
+
12960
+ if (stream) {
12630
12961
  // Try to associate stream
12631
- this._associateStreamTo(this._unassociatedVideoStreams[trackId], participant);
12962
+ this._associateStreamTo(stream, participant);
12632
12963
 
12633
- delete this._unassociatedVideoStreams[trackId];
12964
+ delete this._unassociatedVideoStreams[key];
12634
12965
  delete this._unassociatedParticipants[participant.callId];
12635
12966
  }
12636
12967
  }
12637
12968
 
12969
+ _getUnassociatedMapIdFromTrackIdOrStreamId(trackId , streamId ) {
12970
+ // Find by trackId
12971
+ if (trackId in this._unassociatedVideoStreams) {
12972
+ return trackId;
12973
+ }
12974
+
12975
+ // Find by streamId
12976
+ if (streamId && streamId in this._unassociatedVideoStreams) {
12977
+ return streamId;
12978
+ }
12979
+
12980
+ // Find in all the streams by streamId (used on FF where we can't map by trackId)
12981
+ const idx = Object.values(this._unassociatedVideoStreams).findIndex((stream ) =>
12982
+ stream && stream.id === streamId);
12983
+ return idx === -1 ? null : Object.keys(this._unassociatedVideoStreams)[idx];
12984
+ }
12985
+
12986
+ _getStreamIdFrTrackId(trackId ) {
12987
+ const mapping = Object.values(this._callIdStreamIdMap).find((map ) => map.trackId === trackId);
12988
+
12989
+ return mapping ? mapping.streamId : null;
12990
+ }
12991
+
12638
12992
  _associateStreamTo(rawStream , participant ) {
12639
12993
  const stream = new Wazo.Stream(rawStream, participant);
12640
12994
  participant.streams.push(stream);