@wazo/sdk 0.38.5 → 0.38.8

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 (135) hide show
  1. package/README.md +1 -1
  2. package/dist/wazo-sdk.js +2 -2
  3. package/esm/__tests__/api-client.test.js +148 -2
  4. package/esm/__tests__/web-rtc-client.test.js +303 -26
  5. package/esm/api/calld.js +14 -0
  6. package/esm/api/confd.js +134 -2
  7. package/esm/api/ctid-ng.js +6 -0
  8. package/esm/api-client.js +148 -2
  9. package/esm/checker/Checker.js +212 -26
  10. package/esm/checker/checks/aor.js +148 -2
  11. package/esm/checker/checks/api.js +148 -2
  12. package/esm/checker/checks/index.js +212 -26
  13. package/esm/checker/checks/wazo-websocket.js +2 -0
  14. package/esm/checker/checks/webrtc-transport.js +210 -26
  15. package/esm/checker/checks/webrtc.js +210 -26
  16. package/esm/domain/AdHocAPIConference.js +148 -2
  17. package/esm/domain/Call.js +6 -0
  18. package/esm/domain/CallSession.js +1 -1
  19. package/esm/domain/Features.js +148 -2
  20. package/esm/domain/Meeting.js +18 -0
  21. package/esm/domain/MeetingAuthorization.js +70 -0
  22. package/esm/domain/Phone/CTIPhone.js +149 -3
  23. package/esm/domain/Phone/WebRTCPhone.js +3 -3
  24. package/esm/domain/__tests__/Call.test.js +6 -0
  25. package/esm/domain/__tests__/CallSession.test.js +1 -1
  26. package/esm/domain/__tests__/IndirectTransfer.test.js +1 -1
  27. package/esm/domain/__tests__/Meeting.test.js +87 -1
  28. package/esm/domain/__tests__/MeetingAuthorization.test.js +109 -0
  29. package/esm/domain/__tests__/Room.test.js +1 -1
  30. package/esm/index.js +258 -32
  31. package/esm/lib/WazoSessionDescriptionHandler.js +22 -1
  32. package/esm/service/CallApi.js +148 -2
  33. package/esm/service/getApiClient.js +148 -2
  34. package/esm/simple/Auth.js +258 -32
  35. package/esm/simple/Configuration.js +258 -32
  36. package/esm/simple/Directory.js +148 -2
  37. package/esm/simple/Phone.js +258 -32
  38. package/esm/simple/Websocket.js +3 -0
  39. package/esm/simple/index.js +258 -32
  40. package/esm/simple/room/LocalParticipant.js +258 -32
  41. package/esm/simple/room/Participant.js +258 -32
  42. package/esm/simple/room/RemoteParticipant.js +258 -32
  43. package/esm/simple/room/Room.js +258 -32
  44. package/esm/simple/room/SipRoom.js +258 -32
  45. package/esm/simple/room/Stream.js +258 -32
  46. package/esm/simple/room/__tests__/Participant.test.js +14747 -0
  47. package/esm/simple/room/__tests__/RemoteParticipant.test.js +258 -32
  48. package/esm/simple/utils.js +258 -32
  49. package/esm/utils/__tests__/object.test.js +57 -0
  50. package/esm/utils/__tests__/sdp.test.js +50 -0
  51. package/esm/utils/__tests__/string.test.js +30 -0
  52. package/esm/utils/object.js +24 -0
  53. package/esm/utils/sdp.js +19 -1
  54. package/esm/utils/string.js +10 -0
  55. package/esm/web-rtc-client.js +210 -26
  56. package/esm/websocket-client.js +3 -1
  57. package/lib/__tests__/api-client.test.js +148 -2
  58. package/lib/__tests__/web-rtc-client.test.js +303 -26
  59. package/lib/api/calld.js +14 -0
  60. package/lib/api/confd.js +134 -2
  61. package/lib/api/ctid-ng.js +6 -0
  62. package/lib/api-client.js +148 -2
  63. package/lib/checker/Checker.js +212 -26
  64. package/lib/checker/checks/aor.js +148 -2
  65. package/lib/checker/checks/api.js +148 -2
  66. package/lib/checker/checks/index.js +212 -26
  67. package/lib/checker/checks/wazo-websocket.js +2 -0
  68. package/lib/checker/checks/webrtc-transport.js +210 -26
  69. package/lib/checker/checks/webrtc.js +210 -26
  70. package/lib/domain/AdHocAPIConference.js +148 -2
  71. package/lib/domain/Call.js +6 -0
  72. package/lib/domain/CallSession.js +1 -1
  73. package/lib/domain/Features.js +148 -2
  74. package/lib/domain/Meeting.js +18 -0
  75. package/lib/domain/MeetingAuthorization.js +79 -0
  76. package/lib/domain/Phone/CTIPhone.js +149 -3
  77. package/lib/domain/Phone/WebRTCPhone.js +3 -3
  78. package/lib/domain/__tests__/Call.test.js +6 -0
  79. package/lib/domain/__tests__/CallSession.test.js +1 -1
  80. package/lib/domain/__tests__/IndirectTransfer.test.js +1 -1
  81. package/lib/domain/__tests__/Meeting.test.js +87 -1
  82. package/lib/domain/__tests__/MeetingAuthorization.test.js +111 -0
  83. package/lib/domain/__tests__/Room.test.js +1 -1
  84. package/lib/index.js +258 -32
  85. package/lib/lib/WazoSessionDescriptionHandler.js +22 -1
  86. package/lib/service/CallApi.js +148 -2
  87. package/lib/service/getApiClient.js +148 -2
  88. package/lib/simple/Auth.js +258 -32
  89. package/lib/simple/Configuration.js +258 -32
  90. package/lib/simple/Directory.js +148 -2
  91. package/lib/simple/Phone.js +258 -32
  92. package/lib/simple/Websocket.js +3 -0
  93. package/lib/simple/index.js +258 -32
  94. package/lib/simple/room/LocalParticipant.js +258 -32
  95. package/lib/simple/room/Participant.js +258 -32
  96. package/lib/simple/room/RemoteParticipant.js +258 -32
  97. package/lib/simple/room/Room.js +258 -32
  98. package/lib/simple/room/SipRoom.js +258 -32
  99. package/lib/simple/room/Stream.js +258 -32
  100. package/lib/simple/room/__tests__/Participant.test.js +14757 -0
  101. package/lib/simple/room/__tests__/RemoteParticipant.test.js +258 -32
  102. package/lib/simple/utils.js +258 -32
  103. package/lib/utils/__tests__/object.test.js +59 -0
  104. package/lib/utils/__tests__/sdp.test.js +50 -0
  105. package/lib/utils/__tests__/string.test.js +32 -0
  106. package/lib/utils/object.js +28 -0
  107. package/lib/utils/sdp.js +19 -0
  108. package/lib/utils/string.js +14 -0
  109. package/lib/web-rtc-client.js +210 -26
  110. package/lib/websocket-client.js +3 -0
  111. package/package.json +2 -2
  112. package/src/__tests__/web-rtc-client.test.js +93 -0
  113. package/src/api/calld.js +8 -0
  114. package/src/api/confd.js +43 -2
  115. package/src/domain/Call.js +6 -0
  116. package/src/domain/CallSession.js +1 -1
  117. package/src/domain/Meeting.js +20 -0
  118. package/src/domain/MeetingAuthorization.js +67 -0
  119. package/src/domain/Phone/WebRTCPhone.js +2 -2
  120. package/src/domain/__tests__/Meeting.test.js +70 -1
  121. package/src/domain/__tests__/MeetingAuthorization.test.js +58 -0
  122. package/src/lib/WazoSessionDescriptionHandler.js +5 -2
  123. package/src/simple/room/Participant.js +40 -0
  124. package/src/simple/room/Room.js +2 -2
  125. package/src/simple/room/SipRoom.js +1 -1
  126. package/src/simple/room/__tests__/Participant.test.js +81 -0
  127. package/src/types/WebSocketMessage.js +7 -1
  128. package/src/utils/__tests__/object.test.js +35 -0
  129. package/src/utils/__tests__/sdp.test.js +33 -1
  130. package/src/utils/__tests__/string.test.js +23 -0
  131. package/src/utils/object.js +15 -0
  132. package/src/utils/sdp.js +18 -0
  133. package/src/utils/string.js +8 -0
  134. package/src/web-rtc-client.js +40 -23
  135. package/src/websocket-client.js +2 -0
@@ -2645,6 +2645,70 @@ class ExternalApp {
2645
2645
 
2646
2646
  //
2647
2647
 
2648
+ class MeetingAuthorization {
2649
+
2650
+
2651
+
2652
+
2653
+
2654
+
2655
+ constructor({
2656
+ meetingUuid,
2657
+ uuid,
2658
+ userUuid,
2659
+ userName,
2660
+ } = {}) {
2661
+ this.meetingUuid = meetingUuid;
2662
+ this.uuid = uuid;
2663
+ this.userUuid = userUuid;
2664
+ this.userName = userName;
2665
+ }
2666
+
2667
+ setStatus(status ) {
2668
+ this.status = status;
2669
+ }
2670
+
2671
+ getStatus() {
2672
+ return this.status;
2673
+ }
2674
+
2675
+ static parse(plain ) {
2676
+ const {
2677
+ meeting_uuid: meetingUuid,
2678
+ uuid,
2679
+ guest_uuid: userUuid,
2680
+ guest_name: userName,
2681
+ } = plain;
2682
+
2683
+ return new MeetingAuthorization({
2684
+ meetingUuid,
2685
+ uuid,
2686
+ userUuid,
2687
+ userName,
2688
+ });
2689
+ }
2690
+
2691
+ static parseMany(items ) {
2692
+ if (!items) {
2693
+ return [];
2694
+ }
2695
+ return items.map(MeetingAuthorization.parse);
2696
+ }
2697
+ }
2698
+
2699
+ //
2700
+
2701
+
2702
+
2703
+
2704
+
2705
+
2706
+
2707
+
2708
+
2709
+
2710
+
2711
+
2648
2712
 
2649
2713
 
2650
2714
 
@@ -2655,6 +2719,7 @@ class ExternalApp {
2655
2719
 
2656
2720
 
2657
2721
 
2722
+
2658
2723
 
2659
2724
 
2660
2725
  class Meeting {
@@ -2669,6 +2734,8 @@ class Meeting {
2669
2734
 
2670
2735
 
2671
2736
 
2737
+
2738
+
2672
2739
 
2673
2740
  static parse(plain ) {
2674
2741
  return new Meeting({
@@ -2681,6 +2748,7 @@ class Meeting {
2681
2748
  extension: plain.exten,
2682
2749
  persistent: plain.persistent,
2683
2750
  creationTime: moment(plain.creation_time).toDate(),
2751
+ requireAuthorization: plain.require_authorization,
2684
2752
  });
2685
2753
  }
2686
2754
 
@@ -2705,6 +2773,7 @@ class Meeting {
2705
2773
  extension,
2706
2774
  persistent,
2707
2775
  creationTime,
2776
+ requireAuthorization,
2708
2777
  } = {}) {
2709
2778
  this.guestSipAuthorization = guestSipAuthorization;
2710
2779
  this.uri = uri;
@@ -2715,6 +2784,7 @@ class Meeting {
2715
2784
  this.extension = extension;
2716
2785
  this.persistent = persistent;
2717
2786
  this.creationTime = creationTime;
2787
+ this.requireAuthorization = requireAuthorization;
2718
2788
 
2719
2789
  // Useful to compare instead of instanceof with minified code
2720
2790
  this.type = 'Meeting';
@@ -2725,8 +2795,32 @@ class Meeting {
2725
2795
  const [username, secret] = atob(this.guestSipAuthorization).split(':');
2726
2796
  return { username, secret };
2727
2797
  }
2798
+
2728
2799
  }
2729
2800
 
2801
+ //
2802
+
2803
+ const camelToUnderscore = (key ) => {
2804
+ if (typeof key !== 'string') {
2805
+ throw new Error('Input is not a string');
2806
+ }
2807
+ return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
2808
+ };
2809
+
2810
+ //
2811
+
2812
+ const convertKeysFromCamelToUnderscore = (args ) => {
2813
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
2814
+ throw new Error('Input is not an object');
2815
+ }
2816
+
2817
+ return Object.keys(args).reduce((acc, key) => {
2818
+ acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
2819
+ ? convertKeysFromCamelToUnderscore(args[key]) : args[key];
2820
+ return acc;
2821
+ }, {});
2822
+ };
2823
+
2730
2824
  /* */
2731
2825
 
2732
2826
  var confdMethods = (client , baseUrl ) => ({
@@ -2795,8 +2889,18 @@ var confdMethods = (client , baseUrl ) => ({
2795
2889
  getMyMeetings: () =>
2796
2890
  client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
2797
2891
 
2798
- createMyMeeting: (name , persistent ) =>
2799
- client.post(`${baseUrl}/users/me/meetings`, { name, persistent }).then(Meeting.parse),
2892
+ createMyMeeting: (args ) =>
2893
+ client
2894
+ .post(`${baseUrl}/users/me/meetings`, convertKeysFromCamelToUnderscore(args))
2895
+ .then(Meeting.parse),
2896
+
2897
+ updateMyMeeting: (meetingUuid , data ) =>
2898
+ client.put(
2899
+ `${baseUrl}/users/me/meetings/${meetingUuid}`,
2900
+ convertKeysFromCamelToUnderscore(data),
2901
+ null,
2902
+ ApiRequester.successResponseParser,
2903
+ ),
2800
2904
 
2801
2905
  deleteMyMeeting: (meetingUuid ) =>
2802
2906
  client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
@@ -2804,8 +2908,36 @@ var confdMethods = (client , baseUrl ) => ({
2804
2908
  getMeeting: (meetingUuid ) =>
2805
2909
  client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
2806
2910
 
2911
+ meetingAuthorizations: (meetingUuid ) =>
2912
+ client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations`, null).then(MeetingAuthorization.parseMany),
2913
+
2914
+ meetingAuthorizationReject: (meetingUuid , authorizationUuid ) =>
2915
+ client.put(
2916
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/reject`,
2917
+ {},
2918
+ null,
2919
+ ApiRequester.successResponseParser,
2920
+ ),
2921
+
2922
+ meetingAuthorizationAccept: (meetingUuid , authorizationUuid ) =>
2923
+ client.put(
2924
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/accept`,
2925
+ {},
2926
+ null,
2927
+ ApiRequester.successResponseParser,
2928
+ ),
2929
+
2807
2930
  guestGetMeeting: (meetingUuid ) =>
2808
2931
  client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
2932
+
2933
+ guestAuthorizationRequest: (userUuid , meetingUuid , username ) =>
2934
+ client
2935
+ .post(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations`, { guest_name: username })
2936
+ .then(MeetingAuthorization.parse),
2937
+
2938
+ guestAuthorizationCheck: (userUuid , meetingUuid , authorizationUuid ) =>
2939
+ client.get(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations/${authorizationUuid}`, null),
2940
+
2809
2941
  });
2810
2942
 
2811
2943
  //
@@ -3071,6 +3203,7 @@ const RECORD_STATE_ACTIVE = 'active';
3071
3203
 
3072
3204
 
3073
3205
 
3206
+
3074
3207
 
3075
3208
 
3076
3209
 
@@ -3081,6 +3214,7 @@ const RECORD_STATE_ACTIVE = 'active';
3081
3214
 
3082
3215
 
3083
3216
 
3217
+
3084
3218
 
3085
3219
 
3086
3220
 
@@ -3109,6 +3243,7 @@ class Call {
3109
3243
 
3110
3244
 
3111
3245
 
3246
+
3112
3247
 
3113
3248
 
3114
3249
 
@@ -3133,6 +3268,7 @@ class Call {
3133
3268
  calleeNumber: plain.peer_caller_id_number,
3134
3269
  dialedExtension: plain.dialed_extension,
3135
3270
  isCaller: plain.is_caller,
3271
+ isVideo: plain.is_video,
3136
3272
  muted: plain.muted,
3137
3273
  onHold: plain.on_hold,
3138
3274
  status: plain.status,
@@ -3156,6 +3292,7 @@ class Call {
3156
3292
  calleeNumber,
3157
3293
  dialedExtension,
3158
3294
  isCaller,
3295
+ isVideo,
3159
3296
  lineId,
3160
3297
  muted,
3161
3298
  onHold,
@@ -3179,6 +3316,7 @@ class Call {
3179
3316
  this.startingTime = startingTime;
3180
3317
  this.talkingToIds = talkingToIds || [];
3181
3318
  this.recording = recording;
3319
+ this.isVideo = !!isVideo;
3182
3320
 
3183
3321
  // Useful to compare instead of instanceof with minified code
3184
3322
  this.type = 'Call';
@@ -3652,7 +3790,7 @@ class CallSession {
3652
3790
  ringing: call.isRinging(),
3653
3791
  answered: call.isUp(),
3654
3792
  answeredBySystem: call.isUp() && call.talkingToIds.length === 0,
3655
- cameraEnabled: false,
3793
+ cameraEnabled: call.isVideo,
3656
3794
  dialedExtension: call.dialedExtension,
3657
3795
  call,
3658
3796
  conference: false, // @FIXME?
@@ -5050,6 +5188,14 @@ var calldMethods = (client , baseUrl ) => ({
5050
5188
  getMeetingParticipantsAsUser: async (meetingUuid ) =>
5051
5189
  client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
5052
5190
 
5191
+ banMeetingParticipant: (meetingUuid , participantUuid ) =>
5192
+ client.delete(
5193
+ `${baseUrl}/users/me/meetings/${meetingUuid}/participants/${participantUuid}`,
5194
+ null,
5195
+ null,
5196
+ ApiRequester.successResponseParser,
5197
+ ),
5198
+
5053
5199
  listTrunks: () => client.get(`${baseUrl}/trunks`),
5054
5200
 
5055
5201
  mute: (callId ) =>
@@ -6198,6 +6344,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
6198
6344
  return fixed;
6199
6345
  };
6200
6346
 
6347
+ const addIcesInAllBundles = (sdp ) => {
6348
+ const parsedSdp = sdpParser.parse(sdp);
6349
+
6350
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
6351
+ if (!mediaWithCandidate) {
6352
+ return sdp;
6353
+ }
6354
+
6355
+ const { candidates } = mediaWithCandidate;
6356
+
6357
+ parsedSdp.media = parsedSdp.media.map(media => ({
6358
+ ...media,
6359
+ candidates: media.candidates || candidates,
6360
+ }));
6361
+
6362
+ return sdpParser.write(parsedSdp);
6363
+ };
6364
+
6201
6365
  /* global RTCSessionDescriptionInit, navigator */
6202
6366
 
6203
6367
  const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
@@ -6327,7 +6491,10 @@ class WazoSessionDescriptionHandler extends SessionDescriptionHandler {
6327
6491
 
6328
6492
  // Check if we got ICEs
6329
6493
  if (sdp.indexOf('a=candidate') !== -1) {
6330
- return description;
6494
+ return {
6495
+ type: description.type,
6496
+ sdp: addIcesInAllBundles(sdp),
6497
+ };
6331
6498
  }
6332
6499
 
6333
6500
  wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
@@ -7787,41 +7954,58 @@ class WebRTCClient extends Emitter {
7787
7954
  });
7788
7955
  }
7789
7956
 
7790
- changeAudioInputDevice(id , session ) {
7957
+ async changeAudioInputDevice(id , session , force ) {
7791
7958
  const currentId = this.getAudioDeviceId();
7792
7959
  logger$8.info('setting audio input device', { id, currentId, session: !!session });
7793
7960
 
7794
- if (id === currentId) {
7961
+ if (!force && id === currentId) {
7795
7962
  return null;
7796
7963
  }
7797
7964
 
7965
+ // in order to handle an audio track change for default devices
7966
+ // we need the actual id of the device (not 'default')
7967
+ let deviceId = id;
7968
+ if (id === 'default' && navigator.mediaDevices) {
7969
+ const devices = await navigator.mediaDevices.enumerateDevices();
7970
+ const defaultDevice = devices.find(device => device.deviceId === 'default');
7971
+ if (defaultDevice) {
7972
+ const deviceLabel = defaultDevice.label.replace('Default - ', '');
7973
+ const targetDevice = devices.find(device => device.label === deviceLabel);
7974
+ if (targetDevice) {
7975
+ deviceId = targetDevice.deviceId;
7976
+ if (!force && deviceId === currentId) {
7977
+ return null;
7978
+ }
7979
+ }
7980
+ }
7981
+ }
7982
+
7798
7983
  // let's update the local audio value
7799
7984
  if (this.audio) {
7800
7985
  this.audio = {
7801
7986
  deviceId: {
7802
- exact: id,
7987
+ exact: deviceId,
7803
7988
  },
7804
7989
  };
7805
7990
  }
7806
7991
 
7807
- if (session) {
7992
+ if (session && navigator.mediaDevices) {
7808
7993
  const sdh = session.sessionDescriptionHandler;
7809
7994
  const pc = sdh.peerConnection;
7810
7995
 
7811
- // $FlowFixMe
7812
- return navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: id } } }).then(async stream => {
7813
- const audioTrack = stream.getAudioTracks()[0];
7814
- const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
7996
+ const constraints = { audio: { deviceId: { exact: deviceId } } };
7997
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
7998
+ const audioTrack = stream.getAudioTracks()[0];
7999
+ const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
7815
8000
 
7816
- if (sender) {
7817
- if (sender.track) {
7818
- audioTrack.enabled = sender.track.enabled;
7819
- }
7820
- sender.replaceTrack(audioTrack);
8001
+ if (sender) {
8002
+ if (sender.track) {
8003
+ audioTrack.enabled = sender.track.enabled;
7821
8004
  }
8005
+ sender.replaceTrack(audioTrack);
8006
+ }
7822
8007
 
7823
- return stream;
7824
- });
8008
+ return stream;
7825
8009
  }
7826
8010
  }
7827
8011
 
@@ -7841,14 +8025,14 @@ class WebRTCClient extends Emitter {
7841
8025
  return null;
7842
8026
  }
7843
8027
 
7844
- // let's update the local video value
7845
- if (this.video) {
7846
- this.video = {
7847
- deviceId: {
7848
- exact: id,
7849
- },
7850
- };
7851
- }
8028
+ // let's make sure we don't lose other video constraints settings -- width, height, frameRate...
8029
+ const videoObject = typeof this.video === 'object' ? this.video : {};
8030
+ this.video = {
8031
+ ...videoObject,
8032
+ deviceId: {
8033
+ exact: id,
8034
+ },
8035
+ };
7852
8036
  }
7853
8037
 
7854
8038
  changeSessionVideoInputDevice(id , session ) {
@@ -9587,10 +9771,10 @@ class WebRTCPhone extends Emitter {
9587
9771
  this.audioRingVolume = volume;
9588
9772
  }
9589
9773
 
9590
- changeAudioInputDevice(id ) {
9774
+ changeAudioInputDevice(id , force ) {
9591
9775
  logger$7.info('WebRTC phone - changeAudio input device', { deviceId: id });
9592
9776
 
9593
- return this.client.changeAudioInputDevice(id, this.currentSipSession);
9777
+ return this.client.changeAudioInputDevice(id, this.currentSipSession, force);
9594
9778
  }
9595
9779
 
9596
9780
  changeVideoInputDevice(id ) {
@@ -11243,6 +11427,7 @@ const AGENT_UNPAUSED = 'agent_unpaused';
11243
11427
  const CONFERENCE_ADHOC_PARTICIPANT_LEFT = 'conference_adhoc_participant_left';
11244
11428
  const CONFERENCE_ADHOC_DELETED = 'conference_adhoc_deleted';
11245
11429
  const MEETING_USER_PROGRESS = 'meeting_user_progress';
11430
+ const MEETING_USER_GUEST_AUTHORIZATION_CREATED = 'meeting_user_guest_authorization_created';
11246
11431
 
11247
11432
  const BLACKLIST_EVENTS = [
11248
11433
  CHAT_MESSAGE_SENT,
@@ -11594,6 +11779,7 @@ WebSocketClient.eventLists = [
11594
11779
  CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11595
11780
  CONFERENCE_ADHOC_DELETED,
11596
11781
  MEETING_USER_PROGRESS,
11782
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11597
11783
  ];
11598
11784
 
11599
11785
  var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
@@ -11665,6 +11851,7 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
11665
11851
  CONFERENCE_ADHOC_PARTICIPANT_LEFT: CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11666
11852
  CONFERENCE_ADHOC_DELETED: CONFERENCE_ADHOC_DELETED,
11667
11853
  MEETING_USER_PROGRESS: MEETING_USER_PROGRESS,
11854
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED: MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11668
11855
  HEARTBEAT_ENGINE_VERSION: HEARTBEAT_ENGINE_VERSION,
11669
11856
  'default': WebSocketClient
11670
11857
  });
@@ -11769,6 +11956,7 @@ class Participant extends Emitter {
11769
11956
 
11770
11957
 
11771
11958
 
11959
+
11772
11960
 
11773
11961
 
11774
11962
 
@@ -11786,6 +11974,7 @@ class Participant extends Emitter {
11786
11974
 
11787
11975
 
11788
11976
 
11977
+
11789
11978
 
11790
11979
  /**
11791
11980
  * @param room Room The room where the participant is
@@ -11809,6 +11998,7 @@ class Participant extends Emitter {
11809
11998
  this.screensharing = false;
11810
11999
  this.isOnHold = false;
11811
12000
  this.extra = extra;
12001
+ this.banned = false;
11812
12002
 
11813
12003
  this.ON_UPDATED = 'participant/ON_UPDATED';
11814
12004
  this.ON_START_TALKING = 'participant/ON_START_TALKING';
@@ -11825,6 +12015,7 @@ class Participant extends Emitter {
11825
12015
  this.ON_EXTRA_CHANGE = 'participant/ON_EXTRA_CHANGE';
11826
12016
  this.ON_HOLD = 'participant/ON_HOLD';
11827
12017
  this.ON_RESUME = 'participant/ON_RESUME';
12018
+ this.ON_BAN = 'participant/ON_BAN';
11828
12019
  }
11829
12020
 
11830
12021
  triggerEvent(name , ...args ) {
@@ -11865,6 +12056,10 @@ class Participant extends Emitter {
11865
12056
  status.extra = this.extra;
11866
12057
  break;
11867
12058
  }
12059
+ case this.ON_BAN: {
12060
+ status.banned = true;
12061
+ break;
12062
+ }
11868
12063
  }
11869
12064
 
11870
12065
  if (broadcast) {
@@ -11967,6 +12162,11 @@ class Participant extends Emitter {
11967
12162
  this.triggerUpdate(this.ON_RESUME, broadcast);
11968
12163
  }
11969
12164
 
12165
+ onBan(broadcast = true) {
12166
+ this.banned = true;
12167
+ this.triggerUpdate(this.ON_BAN, broadcast);
12168
+ }
12169
+
11970
12170
  getStatus() {
11971
12171
  return {
11972
12172
  callId: this.callId,
@@ -12013,6 +12213,10 @@ class Participant extends Emitter {
12013
12213
  }
12014
12214
  }
12015
12215
 
12216
+ if (status.banned) {
12217
+ this.onBan(false);
12218
+ }
12219
+
12016
12220
  // Poor man's object comparison
12017
12221
  if (typeof status.extra !== 'undefined' && JSON.stringify(this.extra) !== JSON.stringify(status.extra)) {
12018
12222
  this.extra = { ...this.extra, ...status.extra };
@@ -12040,6 +12244,28 @@ class Participant extends Emitter {
12040
12244
  this.streams = streams;
12041
12245
  this.videoStreams = streams;
12042
12246
  }
12247
+
12248
+ async ban(apiRequestDelay = null) {
12249
+ const { meetingUuid } = this.room;
12250
+ if (!meetingUuid) {
12251
+ throw new Error('Attempting to ban a participant without a `meetingUuid`');
12252
+ }
12253
+
12254
+ // this notifies all that someone is being banned
12255
+ this.onBan(true);
12256
+
12257
+ // this allows to delay the actual ban, in order for the banned participant as well as others to react to the situation
12258
+ if (apiRequestDelay) {
12259
+ await this.delay(apiRequestDelay);
12260
+ }
12261
+
12262
+ // proceed with the actual kick
12263
+ return getApiClient().calld.banMeetingParticipant(meetingUuid, this.callId);
12264
+ }
12265
+
12266
+ async delay(ms ) {
12267
+ return new Promise(resolve => setTimeout(resolve, ms));
12268
+ }
12043
12269
  }
12044
12270
 
12045
12271
  //
@@ -12192,7 +12418,7 @@ class Room$1 extends Emitter {
12192
12418
  logger$2.info('connecting to room', { extension, audioOnly, room: !!room });
12193
12419
 
12194
12420
  if (!room) {
12195
- await Wazo.Phone.connect();
12421
+ await Wazo.Phone.connect({ media: constraints });
12196
12422
 
12197
12423
  const withCamera = constraints && !!constraints.video;
12198
12424
 
@@ -12637,7 +12863,7 @@ class Room$1 extends Emitter {
12637
12863
  const participant = this._getParticipantFromCallId(status.callId);
12638
12864
 
12639
12865
  if (participant) {
12640
- // we're received, so no need to broadcast, hence the input false arg
12866
+ // we're receiving, so no need to broadcast
12641
12867
  participant.updateStatus(status, false);
12642
12868
  }
12643
12869
  break;
@@ -12904,7 +13130,7 @@ class SipRoom extends Room$1 {
12904
13130
  logger$1.info('connecting to sip room', { extension, audioOnly, room: !!room });
12905
13131
 
12906
13132
  if (!room) {
12907
- await Wazo.Phone.connect();
13133
+ await Wazo.Phone.connect({ media: constraints });
12908
13134
 
12909
13135
  const withCamera = constraints && !!constraints.video;
12910
13136
 
@@ -0,0 +1,57 @@
1
+ //
2
+
3
+ const camelToUnderscore = (key ) => {
4
+ if (typeof key !== 'string') {
5
+ throw new Error('Input is not a string');
6
+ }
7
+ return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
8
+ };
9
+
10
+ //
11
+
12
+ const convertKeysFromCamelToUnderscore = (args ) => {
13
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
14
+ throw new Error('Input is not an object');
15
+ }
16
+
17
+ return Object.keys(args).reduce((acc, key) => {
18
+ acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
19
+ ? convertKeysFromCamelToUnderscore(args[key]) : args[key];
20
+ return acc;
21
+ }, {});
22
+ };
23
+
24
+ //
25
+
26
+ describe('object utils', () => {
27
+ describe('convertKeysFromCamelToUnderscore', () => {
28
+ it('should throw an error when input is not an object', () => {
29
+ const msg = 'Input is not an object';
30
+ expect(() => convertKeysFromCamelToUnderscore(true)).toThrow(msg);
31
+ expect(() => convertKeysFromCamelToUnderscore(null)).toThrow(msg);
32
+ expect(() => convertKeysFromCamelToUnderscore(undefined)).toThrow(msg);
33
+ expect(() => convertKeysFromCamelToUnderscore([])).toThrow(msg);
34
+ expect(() => convertKeysFromCamelToUnderscore('some-string')).toThrow(msg);
35
+ });
36
+
37
+ it('should convert camel-cased keys to underscore', () => {
38
+ let value = Math.random();
39
+ expect(convertKeysFromCamelToUnderscore({ LoremIpsum: value })).toEqual({ lorem_ipsum: value });
40
+ value = Math.random();
41
+ expect(convertKeysFromCamelToUnderscore({ loremIpsum: value })).toEqual({ lorem_ipsum: value });
42
+ value = Math.random();
43
+ expect(convertKeysFromCamelToUnderscore({ 'lorem-ipsum': value })).toEqual({ 'lorem-ipsum': value });
44
+ value = Math.random();
45
+ expect(convertKeysFromCamelToUnderscore({ L123: value })).toEqual({ l123: value });
46
+ });
47
+
48
+ it('should handle multi-leveled object', () => {
49
+ const value = Math.random();
50
+ expect(convertKeysFromCamelToUnderscore({ LoremIpsum: { DoloreSit: { Amet: value }, regular: 'reg' } }))
51
+ .toEqual({ lorem_ipsum: { dolore_sit: { amet: value }, regular: 'reg' } });
52
+
53
+ expect(convertKeysFromCamelToUnderscore({ LoremIpsum: { DoloreSit: { Amet: [value] }, regular: ['something'] } }))
54
+ .toEqual({ lorem_ipsum: { dolore_sit: { amet: [value] }, regular: ['something'] } });
55
+ });
56
+ });
57
+ });
@@ -98,6 +98,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
98
98
  return fixed;
99
99
  };
100
100
 
101
+ const addIcesInAllBundles = (sdp ) => {
102
+ const parsedSdp = sdpParser.parse(sdp);
103
+
104
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
105
+ if (!mediaWithCandidate) {
106
+ return sdp;
107
+ }
108
+
109
+ const { candidates } = mediaWithCandidate;
110
+
111
+ parsedSdp.media = parsedSdp.media.map(media => ({
112
+ ...media,
113
+ candidates: media.candidates || candidates,
114
+ }));
115
+
116
+ return sdpParser.write(parsedSdp);
117
+ };
118
+
101
119
  /* eslint-disable max-len */
102
120
 
103
121
  const goodSdp = `
@@ -262,4 +280,36 @@ describe('SDP utils', () => {
262
280
  expect(hasAnActiveVideo(inactiveVideo)).toBeFalsy();
263
281
  });
264
282
  });
283
+
284
+ describe('Adding candidate in all bundles ', () => {
285
+ it('should add candidate everywhere', async () => {
286
+ const audioWithoutCandidate = `
287
+ c=IN IP4 203.0.113.1
288
+ m=audio 54400 RTP/SAVPF 0 96
289
+ m=video 54400 RTP/SAVPF 0 96
290
+ a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
291
+ a=candidate:3996450952 1 udp 41819903 14.72.21.2 65092 typ relay raddr 0.0.0.0 rport 0 generation 0 network-id 3 network-cost 10
292
+ `;
293
+ const fixedAudioWithoutCandidate = sdpParser.parse(addIcesInAllBundles(audioWithoutCandidate));
294
+
295
+ expect(fixedAudioWithoutCandidate.media[0].candidates[0].type).toBe('host');
296
+ expect(fixedAudioWithoutCandidate.media[0].candidates[1].type).toBe('relay');
297
+ expect(fixedAudioWithoutCandidate.media[1].candidates[0].type).toBe('host');
298
+ expect(fixedAudioWithoutCandidate.media[1].candidates[1].type).toBe('relay');
299
+
300
+ // It should not add candidate if already present
301
+ const audioWithCandidate = `
302
+ c=IN IP4 203.0.113.1
303
+ m=audio 54400 RTP/SAVPF 0 96
304
+ a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ srflx
305
+
306
+ m=video 54400 RTP/SAVPF 0 96
307
+ a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
308
+ `;
309
+ const fixedAudioWithCandidate = sdpParser.parse(addIcesInAllBundles(audioWithCandidate));
310
+
311
+ expect(fixedAudioWithCandidate.media[0].candidates[0].type).toBe('srflx');
312
+ expect(fixedAudioWithCandidate.media[1].candidates[0].type).toBe('host');
313
+ });
314
+ });
265
315
  });