@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
@@ -2657,6 +2657,70 @@ class ExternalApp {
2657
2657
 
2658
2658
  //
2659
2659
 
2660
+ class MeetingAuthorization {
2661
+
2662
+
2663
+
2664
+
2665
+
2666
+
2667
+ constructor({
2668
+ meetingUuid,
2669
+ uuid,
2670
+ userUuid,
2671
+ userName,
2672
+ } = {}) {
2673
+ this.meetingUuid = meetingUuid;
2674
+ this.uuid = uuid;
2675
+ this.userUuid = userUuid;
2676
+ this.userName = userName;
2677
+ }
2678
+
2679
+ setStatus(status ) {
2680
+ this.status = status;
2681
+ }
2682
+
2683
+ getStatus() {
2684
+ return this.status;
2685
+ }
2686
+
2687
+ static parse(plain ) {
2688
+ const {
2689
+ meeting_uuid: meetingUuid,
2690
+ uuid,
2691
+ guest_uuid: userUuid,
2692
+ guest_name: userName,
2693
+ } = plain;
2694
+
2695
+ return new MeetingAuthorization({
2696
+ meetingUuid,
2697
+ uuid,
2698
+ userUuid,
2699
+ userName,
2700
+ });
2701
+ }
2702
+
2703
+ static parseMany(items ) {
2704
+ if (!items) {
2705
+ return [];
2706
+ }
2707
+ return items.map(MeetingAuthorization.parse);
2708
+ }
2709
+ }
2710
+
2711
+ //
2712
+
2713
+
2714
+
2715
+
2716
+
2717
+
2718
+
2719
+
2720
+
2721
+
2722
+
2723
+
2660
2724
 
2661
2725
 
2662
2726
 
@@ -2667,6 +2731,7 @@ class ExternalApp {
2667
2731
 
2668
2732
 
2669
2733
 
2734
+
2670
2735
 
2671
2736
 
2672
2737
  class Meeting {
@@ -2681,6 +2746,8 @@ class Meeting {
2681
2746
 
2682
2747
 
2683
2748
 
2749
+
2750
+
2684
2751
 
2685
2752
  static parse(plain ) {
2686
2753
  return new Meeting({
@@ -2693,6 +2760,7 @@ class Meeting {
2693
2760
  extension: plain.exten,
2694
2761
  persistent: plain.persistent,
2695
2762
  creationTime: moment__default['default'](plain.creation_time).toDate(),
2763
+ requireAuthorization: plain.require_authorization,
2696
2764
  });
2697
2765
  }
2698
2766
 
@@ -2717,6 +2785,7 @@ class Meeting {
2717
2785
  extension,
2718
2786
  persistent,
2719
2787
  creationTime,
2788
+ requireAuthorization,
2720
2789
  } = {}) {
2721
2790
  this.guestSipAuthorization = guestSipAuthorization;
2722
2791
  this.uri = uri;
@@ -2727,6 +2796,7 @@ class Meeting {
2727
2796
  this.extension = extension;
2728
2797
  this.persistent = persistent;
2729
2798
  this.creationTime = creationTime;
2799
+ this.requireAuthorization = requireAuthorization;
2730
2800
 
2731
2801
  // Useful to compare instead of instanceof with minified code
2732
2802
  this.type = 'Meeting';
@@ -2737,8 +2807,32 @@ class Meeting {
2737
2807
  const [username, secret] = atob(this.guestSipAuthorization).split(':');
2738
2808
  return { username, secret };
2739
2809
  }
2810
+
2740
2811
  }
2741
2812
 
2813
+ //
2814
+
2815
+ const camelToUnderscore = (key ) => {
2816
+ if (typeof key !== 'string') {
2817
+ throw new Error('Input is not a string');
2818
+ }
2819
+ return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
2820
+ };
2821
+
2822
+ //
2823
+
2824
+ const convertKeysFromCamelToUnderscore = (args ) => {
2825
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
2826
+ throw new Error('Input is not an object');
2827
+ }
2828
+
2829
+ return Object.keys(args).reduce((acc, key) => {
2830
+ acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
2831
+ ? convertKeysFromCamelToUnderscore(args[key]) : args[key];
2832
+ return acc;
2833
+ }, {});
2834
+ };
2835
+
2742
2836
  /* */
2743
2837
 
2744
2838
  var confdMethods = (client , baseUrl ) => ({
@@ -2807,8 +2901,18 @@ var confdMethods = (client , baseUrl ) => ({
2807
2901
  getMyMeetings: () =>
2808
2902
  client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
2809
2903
 
2810
- createMyMeeting: (name , persistent ) =>
2811
- client.post(`${baseUrl}/users/me/meetings`, { name, persistent }).then(Meeting.parse),
2904
+ createMyMeeting: (args ) =>
2905
+ client
2906
+ .post(`${baseUrl}/users/me/meetings`, convertKeysFromCamelToUnderscore(args))
2907
+ .then(Meeting.parse),
2908
+
2909
+ updateMyMeeting: (meetingUuid , data ) =>
2910
+ client.put(
2911
+ `${baseUrl}/users/me/meetings/${meetingUuid}`,
2912
+ convertKeysFromCamelToUnderscore(data),
2913
+ null,
2914
+ ApiRequester.successResponseParser,
2915
+ ),
2812
2916
 
2813
2917
  deleteMyMeeting: (meetingUuid ) =>
2814
2918
  client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
@@ -2816,8 +2920,36 @@ var confdMethods = (client , baseUrl ) => ({
2816
2920
  getMeeting: (meetingUuid ) =>
2817
2921
  client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
2818
2922
 
2923
+ meetingAuthorizations: (meetingUuid ) =>
2924
+ client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations`, null).then(MeetingAuthorization.parseMany),
2925
+
2926
+ meetingAuthorizationReject: (meetingUuid , authorizationUuid ) =>
2927
+ client.put(
2928
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/reject`,
2929
+ {},
2930
+ null,
2931
+ ApiRequester.successResponseParser,
2932
+ ),
2933
+
2934
+ meetingAuthorizationAccept: (meetingUuid , authorizationUuid ) =>
2935
+ client.put(
2936
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/accept`,
2937
+ {},
2938
+ null,
2939
+ ApiRequester.successResponseParser,
2940
+ ),
2941
+
2819
2942
  guestGetMeeting: (meetingUuid ) =>
2820
2943
  client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
2944
+
2945
+ guestAuthorizationRequest: (userUuid , meetingUuid , username ) =>
2946
+ client
2947
+ .post(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations`, { guest_name: username })
2948
+ .then(MeetingAuthorization.parse),
2949
+
2950
+ guestAuthorizationCheck: (userUuid , meetingUuid , authorizationUuid ) =>
2951
+ client.get(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations/${authorizationUuid}`, null),
2952
+
2821
2953
  });
2822
2954
 
2823
2955
  //
@@ -3083,6 +3215,7 @@ const RECORD_STATE_ACTIVE = 'active';
3083
3215
 
3084
3216
 
3085
3217
 
3218
+
3086
3219
 
3087
3220
 
3088
3221
 
@@ -3093,6 +3226,7 @@ const RECORD_STATE_ACTIVE = 'active';
3093
3226
 
3094
3227
 
3095
3228
 
3229
+
3096
3230
 
3097
3231
 
3098
3232
 
@@ -3121,6 +3255,7 @@ class Call {
3121
3255
 
3122
3256
 
3123
3257
 
3258
+
3124
3259
 
3125
3260
 
3126
3261
 
@@ -3145,6 +3280,7 @@ class Call {
3145
3280
  calleeNumber: plain.peer_caller_id_number,
3146
3281
  dialedExtension: plain.dialed_extension,
3147
3282
  isCaller: plain.is_caller,
3283
+ isVideo: plain.is_video,
3148
3284
  muted: plain.muted,
3149
3285
  onHold: plain.on_hold,
3150
3286
  status: plain.status,
@@ -3168,6 +3304,7 @@ class Call {
3168
3304
  calleeNumber,
3169
3305
  dialedExtension,
3170
3306
  isCaller,
3307
+ isVideo,
3171
3308
  lineId,
3172
3309
  muted,
3173
3310
  onHold,
@@ -3191,6 +3328,7 @@ class Call {
3191
3328
  this.startingTime = startingTime;
3192
3329
  this.talkingToIds = talkingToIds || [];
3193
3330
  this.recording = recording;
3331
+ this.isVideo = !!isVideo;
3194
3332
 
3195
3333
  // Useful to compare instead of instanceof with minified code
3196
3334
  this.type = 'Call';
@@ -3664,7 +3802,7 @@ class CallSession {
3664
3802
  ringing: call.isRinging(),
3665
3803
  answered: call.isUp(),
3666
3804
  answeredBySystem: call.isUp() && call.talkingToIds.length === 0,
3667
- cameraEnabled: false,
3805
+ cameraEnabled: call.isVideo,
3668
3806
  dialedExtension: call.dialedExtension,
3669
3807
  call,
3670
3808
  conference: false, // @FIXME?
@@ -5062,6 +5200,14 @@ var calldMethods = (client , baseUrl ) => ({
5062
5200
  getMeetingParticipantsAsUser: async (meetingUuid ) =>
5063
5201
  client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
5064
5202
 
5203
+ banMeetingParticipant: (meetingUuid , participantUuid ) =>
5204
+ client.delete(
5205
+ `${baseUrl}/users/me/meetings/${meetingUuid}/participants/${participantUuid}`,
5206
+ null,
5207
+ null,
5208
+ ApiRequester.successResponseParser,
5209
+ ),
5210
+
5065
5211
  listTrunks: () => client.get(`${baseUrl}/trunks`),
5066
5212
 
5067
5213
  mute: (callId ) =>
@@ -6210,6 +6356,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
6210
6356
  return fixed;
6211
6357
  };
6212
6358
 
6359
+ const addIcesInAllBundles = (sdp ) => {
6360
+ const parsedSdp = sdpParser__default['default'].parse(sdp);
6361
+
6362
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
6363
+ if (!mediaWithCandidate) {
6364
+ return sdp;
6365
+ }
6366
+
6367
+ const { candidates } = mediaWithCandidate;
6368
+
6369
+ parsedSdp.media = parsedSdp.media.map(media => ({
6370
+ ...media,
6371
+ candidates: media.candidates || candidates,
6372
+ }));
6373
+
6374
+ return sdpParser__default['default'].write(parsedSdp);
6375
+ };
6376
+
6213
6377
  /* global RTCSessionDescriptionInit, navigator */
6214
6378
 
6215
6379
  const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
@@ -6339,7 +6503,10 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
6339
6503
 
6340
6504
  // Check if we got ICEs
6341
6505
  if (sdp.indexOf('a=candidate') !== -1) {
6342
- return description;
6506
+ return {
6507
+ type: description.type,
6508
+ sdp: addIcesInAllBundles(sdp),
6509
+ };
6343
6510
  }
6344
6511
 
6345
6512
  wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
@@ -7799,41 +7966,58 @@ class WebRTCClient extends Emitter {
7799
7966
  });
7800
7967
  }
7801
7968
 
7802
- changeAudioInputDevice(id , session ) {
7969
+ async changeAudioInputDevice(id , session , force ) {
7803
7970
  const currentId = this.getAudioDeviceId();
7804
7971
  logger$8.info('setting audio input device', { id, currentId, session: !!session });
7805
7972
 
7806
- if (id === currentId) {
7973
+ if (!force && id === currentId) {
7807
7974
  return null;
7808
7975
  }
7809
7976
 
7977
+ // in order to handle an audio track change for default devices
7978
+ // we need the actual id of the device (not 'default')
7979
+ let deviceId = id;
7980
+ if (id === 'default' && navigator.mediaDevices) {
7981
+ const devices = await navigator.mediaDevices.enumerateDevices();
7982
+ const defaultDevice = devices.find(device => device.deviceId === 'default');
7983
+ if (defaultDevice) {
7984
+ const deviceLabel = defaultDevice.label.replace('Default - ', '');
7985
+ const targetDevice = devices.find(device => device.label === deviceLabel);
7986
+ if (targetDevice) {
7987
+ deviceId = targetDevice.deviceId;
7988
+ if (!force && deviceId === currentId) {
7989
+ return null;
7990
+ }
7991
+ }
7992
+ }
7993
+ }
7994
+
7810
7995
  // let's update the local audio value
7811
7996
  if (this.audio) {
7812
7997
  this.audio = {
7813
7998
  deviceId: {
7814
- exact: id,
7999
+ exact: deviceId,
7815
8000
  },
7816
8001
  };
7817
8002
  }
7818
8003
 
7819
- if (session) {
8004
+ if (session && navigator.mediaDevices) {
7820
8005
  const sdh = session.sessionDescriptionHandler;
7821
8006
  const pc = sdh.peerConnection;
7822
8007
 
7823
- // $FlowFixMe
7824
- return navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: id } } }).then(async stream => {
7825
- const audioTrack = stream.getAudioTracks()[0];
7826
- const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
8008
+ const constraints = { audio: { deviceId: { exact: deviceId } } };
8009
+ const stream = await navigator.mediaDevices.getUserMedia(constraints);
8010
+ const audioTrack = stream.getAudioTracks()[0];
8011
+ const sender = pc && pc.getSenders().find(s => audioTrack && s && s.track && s.track.kind === audioTrack.kind);
7827
8012
 
7828
- if (sender) {
7829
- if (sender.track) {
7830
- audioTrack.enabled = sender.track.enabled;
7831
- }
7832
- sender.replaceTrack(audioTrack);
8013
+ if (sender) {
8014
+ if (sender.track) {
8015
+ audioTrack.enabled = sender.track.enabled;
7833
8016
  }
8017
+ sender.replaceTrack(audioTrack);
8018
+ }
7834
8019
 
7835
- return stream;
7836
- });
8020
+ return stream;
7837
8021
  }
7838
8022
  }
7839
8023
 
@@ -7853,14 +8037,14 @@ class WebRTCClient extends Emitter {
7853
8037
  return null;
7854
8038
  }
7855
8039
 
7856
- // let's update the local video value
7857
- if (this.video) {
7858
- this.video = {
7859
- deviceId: {
7860
- exact: id,
7861
- },
7862
- };
7863
- }
8040
+ // let's make sure we don't lose other video constraints settings -- width, height, frameRate...
8041
+ const videoObject = typeof this.video === 'object' ? this.video : {};
8042
+ this.video = {
8043
+ ...videoObject,
8044
+ deviceId: {
8045
+ exact: id,
8046
+ },
8047
+ };
7864
8048
  }
7865
8049
 
7866
8050
  changeSessionVideoInputDevice(id , session ) {
@@ -9599,10 +9783,10 @@ class WebRTCPhone extends Emitter {
9599
9783
  this.audioRingVolume = volume;
9600
9784
  }
9601
9785
 
9602
- changeAudioInputDevice(id ) {
9786
+ changeAudioInputDevice(id , force ) {
9603
9787
  logger$7.info('WebRTC phone - changeAudio input device', { deviceId: id });
9604
9788
 
9605
- return this.client.changeAudioInputDevice(id, this.currentSipSession);
9789
+ return this.client.changeAudioInputDevice(id, this.currentSipSession, force);
9606
9790
  }
9607
9791
 
9608
9792
  changeVideoInputDevice(id ) {
@@ -11255,6 +11439,7 @@ const AGENT_UNPAUSED = 'agent_unpaused';
11255
11439
  const CONFERENCE_ADHOC_PARTICIPANT_LEFT = 'conference_adhoc_participant_left';
11256
11440
  const CONFERENCE_ADHOC_DELETED = 'conference_adhoc_deleted';
11257
11441
  const MEETING_USER_PROGRESS = 'meeting_user_progress';
11442
+ const MEETING_USER_GUEST_AUTHORIZATION_CREATED = 'meeting_user_guest_authorization_created';
11258
11443
 
11259
11444
  const BLACKLIST_EVENTS = [
11260
11445
  CHAT_MESSAGE_SENT,
@@ -11606,6 +11791,7 @@ WebSocketClient.eventLists = [
11606
11791
  CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11607
11792
  CONFERENCE_ADHOC_DELETED,
11608
11793
  MEETING_USER_PROGRESS,
11794
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11609
11795
  ];
11610
11796
 
11611
11797
  var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
@@ -11677,6 +11863,7 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
11677
11863
  CONFERENCE_ADHOC_PARTICIPANT_LEFT: CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11678
11864
  CONFERENCE_ADHOC_DELETED: CONFERENCE_ADHOC_DELETED,
11679
11865
  MEETING_USER_PROGRESS: MEETING_USER_PROGRESS,
11866
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED: MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11680
11867
  HEARTBEAT_ENGINE_VERSION: HEARTBEAT_ENGINE_VERSION,
11681
11868
  'default': WebSocketClient
11682
11869
  });
@@ -11781,6 +11968,7 @@ class Participant extends Emitter {
11781
11968
 
11782
11969
 
11783
11970
 
11971
+
11784
11972
 
11785
11973
 
11786
11974
 
@@ -11798,6 +11986,7 @@ class Participant extends Emitter {
11798
11986
 
11799
11987
 
11800
11988
 
11989
+
11801
11990
 
11802
11991
  /**
11803
11992
  * @param room Room The room where the participant is
@@ -11821,6 +12010,7 @@ class Participant extends Emitter {
11821
12010
  this.screensharing = false;
11822
12011
  this.isOnHold = false;
11823
12012
  this.extra = extra;
12013
+ this.banned = false;
11824
12014
 
11825
12015
  this.ON_UPDATED = 'participant/ON_UPDATED';
11826
12016
  this.ON_START_TALKING = 'participant/ON_START_TALKING';
@@ -11837,6 +12027,7 @@ class Participant extends Emitter {
11837
12027
  this.ON_EXTRA_CHANGE = 'participant/ON_EXTRA_CHANGE';
11838
12028
  this.ON_HOLD = 'participant/ON_HOLD';
11839
12029
  this.ON_RESUME = 'participant/ON_RESUME';
12030
+ this.ON_BAN = 'participant/ON_BAN';
11840
12031
  }
11841
12032
 
11842
12033
  triggerEvent(name , ...args ) {
@@ -11877,6 +12068,10 @@ class Participant extends Emitter {
11877
12068
  status.extra = this.extra;
11878
12069
  break;
11879
12070
  }
12071
+ case this.ON_BAN: {
12072
+ status.banned = true;
12073
+ break;
12074
+ }
11880
12075
  }
11881
12076
 
11882
12077
  if (broadcast) {
@@ -11979,6 +12174,11 @@ class Participant extends Emitter {
11979
12174
  this.triggerUpdate(this.ON_RESUME, broadcast);
11980
12175
  }
11981
12176
 
12177
+ onBan(broadcast = true) {
12178
+ this.banned = true;
12179
+ this.triggerUpdate(this.ON_BAN, broadcast);
12180
+ }
12181
+
11982
12182
  getStatus() {
11983
12183
  return {
11984
12184
  callId: this.callId,
@@ -12025,6 +12225,10 @@ class Participant extends Emitter {
12025
12225
  }
12026
12226
  }
12027
12227
 
12228
+ if (status.banned) {
12229
+ this.onBan(false);
12230
+ }
12231
+
12028
12232
  // Poor man's object comparison
12029
12233
  if (typeof status.extra !== 'undefined' && JSON.stringify(this.extra) !== JSON.stringify(status.extra)) {
12030
12234
  this.extra = { ...this.extra, ...status.extra };
@@ -12052,6 +12256,28 @@ class Participant extends Emitter {
12052
12256
  this.streams = streams;
12053
12257
  this.videoStreams = streams;
12054
12258
  }
12259
+
12260
+ async ban(apiRequestDelay = null) {
12261
+ const { meetingUuid } = this.room;
12262
+ if (!meetingUuid) {
12263
+ throw new Error('Attempting to ban a participant without a `meetingUuid`');
12264
+ }
12265
+
12266
+ // this notifies all that someone is being banned
12267
+ this.onBan(true);
12268
+
12269
+ // this allows to delay the actual ban, in order for the banned participant as well as others to react to the situation
12270
+ if (apiRequestDelay) {
12271
+ await this.delay(apiRequestDelay);
12272
+ }
12273
+
12274
+ // proceed with the actual kick
12275
+ return getApiClient().calld.banMeetingParticipant(meetingUuid, this.callId);
12276
+ }
12277
+
12278
+ async delay(ms ) {
12279
+ return new Promise(resolve => setTimeout(resolve, ms));
12280
+ }
12055
12281
  }
12056
12282
 
12057
12283
  //
@@ -12204,7 +12430,7 @@ class Room$1 extends Emitter {
12204
12430
  logger$2.info('connecting to room', { extension, audioOnly, room: !!room });
12205
12431
 
12206
12432
  if (!room) {
12207
- await Wazo.Phone.connect();
12433
+ await Wazo.Phone.connect({ media: constraints });
12208
12434
 
12209
12435
  const withCamera = constraints && !!constraints.video;
12210
12436
 
@@ -12649,7 +12875,7 @@ class Room$1 extends Emitter {
12649
12875
  const participant = this._getParticipantFromCallId(status.callId);
12650
12876
 
12651
12877
  if (participant) {
12652
- // we're received, so no need to broadcast, hence the input false arg
12878
+ // we're receiving, so no need to broadcast
12653
12879
  participant.updateStatus(status, false);
12654
12880
  }
12655
12881
  break;
@@ -12916,7 +13142,7 @@ class SipRoom extends Room$1 {
12916
13142
  logger$1.info('connecting to sip room', { extension, audioOnly, room: !!room });
12917
13143
 
12918
13144
  if (!room) {
12919
- await Wazo.Phone.connect();
13145
+ await Wazo.Phone.connect({ media: constraints });
12920
13146
 
12921
13147
  const withCamera = constraints && !!constraints.video;
12922
13148
 
@@ -0,0 +1,59 @@
1
+ 'use strict';
2
+
3
+ //
4
+
5
+ const camelToUnderscore = (key ) => {
6
+ if (typeof key !== 'string') {
7
+ throw new Error('Input is not a string');
8
+ }
9
+ return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
10
+ };
11
+
12
+ //
13
+
14
+ const convertKeysFromCamelToUnderscore = (args ) => {
15
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
16
+ throw new Error('Input is not an object');
17
+ }
18
+
19
+ return Object.keys(args).reduce((acc, key) => {
20
+ acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
21
+ ? convertKeysFromCamelToUnderscore(args[key]) : args[key];
22
+ return acc;
23
+ }, {});
24
+ };
25
+
26
+ //
27
+
28
+ describe('object utils', () => {
29
+ describe('convertKeysFromCamelToUnderscore', () => {
30
+ it('should throw an error when input is not an object', () => {
31
+ const msg = 'Input is not an object';
32
+ expect(() => convertKeysFromCamelToUnderscore(true)).toThrow(msg);
33
+ expect(() => convertKeysFromCamelToUnderscore(null)).toThrow(msg);
34
+ expect(() => convertKeysFromCamelToUnderscore(undefined)).toThrow(msg);
35
+ expect(() => convertKeysFromCamelToUnderscore([])).toThrow(msg);
36
+ expect(() => convertKeysFromCamelToUnderscore('some-string')).toThrow(msg);
37
+ });
38
+
39
+ it('should convert camel-cased keys to underscore', () => {
40
+ let value = Math.random();
41
+ expect(convertKeysFromCamelToUnderscore({ LoremIpsum: value })).toEqual({ lorem_ipsum: value });
42
+ value = Math.random();
43
+ expect(convertKeysFromCamelToUnderscore({ loremIpsum: value })).toEqual({ lorem_ipsum: value });
44
+ value = Math.random();
45
+ expect(convertKeysFromCamelToUnderscore({ 'lorem-ipsum': value })).toEqual({ 'lorem-ipsum': value });
46
+ value = Math.random();
47
+ expect(convertKeysFromCamelToUnderscore({ L123: value })).toEqual({ l123: value });
48
+ });
49
+
50
+ it('should handle multi-leveled object', () => {
51
+ const value = Math.random();
52
+ expect(convertKeysFromCamelToUnderscore({ LoremIpsum: { DoloreSit: { Amet: value }, regular: 'reg' } }))
53
+ .toEqual({ lorem_ipsum: { dolore_sit: { amet: value }, regular: 'reg' } });
54
+
55
+ expect(convertKeysFromCamelToUnderscore({ LoremIpsum: { DoloreSit: { Amet: [value] }, regular: ['something'] } }))
56
+ .toEqual({ lorem_ipsum: { dolore_sit: { amet: [value] }, regular: ['something'] } });
57
+ });
58
+ });
59
+ });
@@ -104,6 +104,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
104
104
  return fixed;
105
105
  };
106
106
 
107
+ const addIcesInAllBundles = (sdp ) => {
108
+ const parsedSdp = sdpParser__default['default'].parse(sdp);
109
+
110
+ const mediaWithCandidate = parsedSdp.media.find(media => !!media.candidates);
111
+ if (!mediaWithCandidate) {
112
+ return sdp;
113
+ }
114
+
115
+ const { candidates } = mediaWithCandidate;
116
+
117
+ parsedSdp.media = parsedSdp.media.map(media => ({
118
+ ...media,
119
+ candidates: media.candidates || candidates,
120
+ }));
121
+
122
+ return sdpParser__default['default'].write(parsedSdp);
123
+ };
124
+
107
125
  /* eslint-disable max-len */
108
126
 
109
127
  const goodSdp = `
@@ -268,4 +286,36 @@ describe('SDP utils', () => {
268
286
  expect(hasAnActiveVideo(inactiveVideo)).toBeFalsy();
269
287
  });
270
288
  });
289
+
290
+ describe('Adding candidate in all bundles ', () => {
291
+ it('should add candidate everywhere', async () => {
292
+ const audioWithoutCandidate = `
293
+ c=IN IP4 203.0.113.1
294
+ m=audio 54400 RTP/SAVPF 0 96
295
+ m=video 54400 RTP/SAVPF 0 96
296
+ a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
297
+ 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
298
+ `;
299
+ const fixedAudioWithoutCandidate = sdpParser__default['default'].parse(addIcesInAllBundles(audioWithoutCandidate));
300
+
301
+ expect(fixedAudioWithoutCandidate.media[0].candidates[0].type).toBe('host');
302
+ expect(fixedAudioWithoutCandidate.media[0].candidates[1].type).toBe('relay');
303
+ expect(fixedAudioWithoutCandidate.media[1].candidates[0].type).toBe('host');
304
+ expect(fixedAudioWithoutCandidate.media[1].candidates[1].type).toBe('relay');
305
+
306
+ // It should not add candidate if already present
307
+ const audioWithCandidate = `
308
+ c=IN IP4 203.0.113.1
309
+ m=audio 54400 RTP/SAVPF 0 96
310
+ a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ srflx
311
+
312
+ m=video 54400 RTP/SAVPF 0 96
313
+ a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
314
+ `;
315
+ const fixedAudioWithCandidate = sdpParser__default['default'].parse(addIcesInAllBundles(audioWithCandidate));
316
+
317
+ expect(fixedAudioWithCandidate.media[0].candidates[0].type).toBe('srflx');
318
+ expect(fixedAudioWithCandidate.media[1].candidates[0].type).toBe('host');
319
+ });
320
+ });
271
321
  });