@wazo/sdk 0.38.6 → 0.38.9

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 (118) hide show
  1. package/dist/wazo-sdk.js +2 -2
  2. package/esm/__tests__/api-client.test.js +142 -2
  3. package/esm/__tests__/web-rtc-client.test.js +249 -28
  4. package/esm/api/calld.js +8 -0
  5. package/esm/api/confd.js +134 -2
  6. package/esm/api-client.js +142 -2
  7. package/esm/checker/Checker.js +205 -25
  8. package/esm/checker/checks/aor.js +142 -2
  9. package/esm/checker/checks/api.js +142 -2
  10. package/esm/checker/checks/index.js +205 -25
  11. package/esm/checker/checks/wazo-websocket.js +2 -0
  12. package/esm/checker/checks/webrtc-transport.js +203 -25
  13. package/esm/checker/checks/webrtc.js +203 -25
  14. package/esm/domain/AdHocAPIConference.js +142 -2
  15. package/esm/domain/Features.js +142 -2
  16. package/esm/domain/Meeting.js +18 -0
  17. package/esm/domain/MeetingAuthorization.js +70 -0
  18. package/esm/domain/Phone/CTIPhone.js +142 -2
  19. package/esm/domain/Phone/WebRTCPhone.js +1 -3
  20. package/esm/domain/__tests__/Meeting.test.js +87 -1
  21. package/esm/domain/__tests__/MeetingAuthorization.test.js +109 -0
  22. package/esm/index.js +249 -31
  23. package/esm/lib/WazoSessionDescriptionHandler.js +22 -1
  24. package/esm/service/CallApi.js +142 -2
  25. package/esm/service/getApiClient.js +142 -2
  26. package/esm/simple/Auth.js +249 -31
  27. package/esm/simple/Configuration.js +249 -31
  28. package/esm/simple/Directory.js +142 -2
  29. package/esm/simple/Phone.js +249 -31
  30. package/esm/simple/Websocket.js +3 -0
  31. package/esm/simple/index.js +249 -31
  32. package/esm/simple/room/LocalParticipant.js +249 -31
  33. package/esm/simple/room/Participant.js +249 -31
  34. package/esm/simple/room/RemoteParticipant.js +249 -31
  35. package/esm/simple/room/Room.js +249 -31
  36. package/esm/simple/room/SipRoom.js +249 -31
  37. package/esm/simple/room/Stream.js +249 -31
  38. package/esm/simple/room/__tests__/Participant.test.js +14745 -0
  39. package/esm/simple/room/__tests__/RemoteParticipant.test.js +249 -31
  40. package/esm/simple/utils.js +249 -31
  41. package/esm/utils/__tests__/object.test.js +57 -0
  42. package/esm/utils/__tests__/sdp.test.js +50 -0
  43. package/esm/utils/__tests__/string.test.js +30 -0
  44. package/esm/utils/object.js +24 -0
  45. package/esm/utils/sdp.js +19 -1
  46. package/esm/utils/string.js +10 -0
  47. package/esm/web-rtc-client.js +203 -25
  48. package/esm/websocket-client.js +3 -1
  49. package/lib/__tests__/api-client.test.js +142 -2
  50. package/lib/__tests__/web-rtc-client.test.js +249 -28
  51. package/lib/api/calld.js +8 -0
  52. package/lib/api/confd.js +134 -2
  53. package/lib/api-client.js +142 -2
  54. package/lib/checker/Checker.js +205 -25
  55. package/lib/checker/checks/aor.js +142 -2
  56. package/lib/checker/checks/api.js +142 -2
  57. package/lib/checker/checks/index.js +205 -25
  58. package/lib/checker/checks/wazo-websocket.js +2 -0
  59. package/lib/checker/checks/webrtc-transport.js +203 -25
  60. package/lib/checker/checks/webrtc.js +203 -25
  61. package/lib/domain/AdHocAPIConference.js +142 -2
  62. package/lib/domain/Features.js +142 -2
  63. package/lib/domain/Meeting.js +18 -0
  64. package/lib/domain/MeetingAuthorization.js +79 -0
  65. package/lib/domain/Phone/CTIPhone.js +142 -2
  66. package/lib/domain/Phone/WebRTCPhone.js +1 -3
  67. package/lib/domain/__tests__/Meeting.test.js +87 -1
  68. package/lib/domain/__tests__/MeetingAuthorization.test.js +111 -0
  69. package/lib/index.js +249 -31
  70. package/lib/lib/WazoSessionDescriptionHandler.js +22 -1
  71. package/lib/service/CallApi.js +142 -2
  72. package/lib/service/getApiClient.js +142 -2
  73. package/lib/simple/Auth.js +249 -31
  74. package/lib/simple/Configuration.js +249 -31
  75. package/lib/simple/Directory.js +142 -2
  76. package/lib/simple/Phone.js +249 -31
  77. package/lib/simple/Websocket.js +3 -0
  78. package/lib/simple/index.js +249 -31
  79. package/lib/simple/room/LocalParticipant.js +249 -31
  80. package/lib/simple/room/Participant.js +249 -31
  81. package/lib/simple/room/RemoteParticipant.js +249 -31
  82. package/lib/simple/room/Room.js +249 -31
  83. package/lib/simple/room/SipRoom.js +249 -31
  84. package/lib/simple/room/Stream.js +249 -31
  85. package/lib/simple/room/__tests__/Participant.test.js +14755 -0
  86. package/lib/simple/room/__tests__/RemoteParticipant.test.js +249 -31
  87. package/lib/simple/utils.js +249 -31
  88. package/lib/utils/__tests__/object.test.js +59 -0
  89. package/lib/utils/__tests__/sdp.test.js +50 -0
  90. package/lib/utils/__tests__/string.test.js +32 -0
  91. package/lib/utils/object.js +28 -0
  92. package/lib/utils/sdp.js +19 -0
  93. package/lib/utils/string.js +14 -0
  94. package/lib/web-rtc-client.js +203 -25
  95. package/lib/websocket-client.js +3 -0
  96. package/package.json +2 -2
  97. package/src/__tests__/web-rtc-client.test.js +46 -3
  98. package/src/api/calld.js +8 -0
  99. package/src/api/confd.js +43 -2
  100. package/src/domain/Meeting.js +20 -0
  101. package/src/domain/MeetingAuthorization.js +67 -0
  102. package/src/domain/Phone/WebRTCPhone.js +1 -3
  103. package/src/domain/__tests__/Meeting.test.js +70 -1
  104. package/src/domain/__tests__/MeetingAuthorization.test.js +58 -0
  105. package/src/lib/WazoSessionDescriptionHandler.js +5 -2
  106. package/src/simple/room/Participant.js +40 -0
  107. package/src/simple/room/Room.js +2 -2
  108. package/src/simple/room/SipRoom.js +1 -1
  109. package/src/simple/room/__tests__/Participant.test.js +81 -0
  110. package/src/types/WebSocketMessage.js +7 -1
  111. package/src/utils/__tests__/object.test.js +35 -0
  112. package/src/utils/__tests__/sdp.test.js +33 -1
  113. package/src/utils/__tests__/string.test.js +23 -0
  114. package/src/utils/object.js +15 -0
  115. package/src/utils/sdp.js +18 -0
  116. package/src/utils/string.js +8 -0
  117. package/src/web-rtc-client.js +39 -22
  118. 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
  //
@@ -5068,6 +5200,14 @@ var calldMethods = (client , baseUrl ) => ({
5068
5200
  getMeetingParticipantsAsUser: async (meetingUuid ) =>
5069
5201
  client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
5070
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
+
5071
5211
  listTrunks: () => client.get(`${baseUrl}/trunks`),
5072
5212
 
5073
5213
  mute: (callId ) =>
@@ -6216,6 +6356,24 @@ const fixSdp = (sdp , candidates , forcePort = true)
6216
6356
  return fixed;
6217
6357
  };
6218
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
+
6219
6377
  /* global RTCSessionDescriptionInit, navigator */
6220
6378
 
6221
6379
  const wazoLogger = IssueReporter$1 ? IssueReporter$1.loggerFor('webrtc-sdh') : console;
@@ -6345,7 +6503,10 @@ class WazoSessionDescriptionHandler extends sessionDescriptionHandler.SessionDes
6345
6503
 
6346
6504
  // Check if we got ICEs
6347
6505
  if (sdp.indexOf('a=candidate') !== -1) {
6348
- return description;
6506
+ return {
6507
+ type: description.type,
6508
+ sdp: addIcesInAllBundles(sdp),
6509
+ };
6349
6510
  }
6350
6511
 
6351
6512
  wazoLogger.info('No ICE candidates found in SDP, fixing it with gathered ices', this.gatheredCandidates);
@@ -7805,7 +7966,7 @@ class WebRTCClient extends Emitter {
7805
7966
  });
7806
7967
  }
7807
7968
 
7808
- changeAudioInputDevice(id , session , force ) {
7969
+ async changeAudioInputDevice(id , session , force ) {
7809
7970
  const currentId = this.getAudioDeviceId();
7810
7971
  logger$8.info('setting audio input device', { id, currentId, session: !!session });
7811
7972
 
@@ -7813,33 +7974,50 @@ class WebRTCClient extends Emitter {
7813
7974
  return null;
7814
7975
  }
7815
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
+
7816
7995
  // let's update the local audio value
7817
7996
  if (this.audio) {
7818
7997
  this.audio = {
7819
7998
  deviceId: {
7820
- exact: id,
7999
+ exact: deviceId,
7821
8000
  },
7822
8001
  };
7823
8002
  }
7824
8003
 
7825
- if (session) {
8004
+ if (session && navigator.mediaDevices) {
7826
8005
  const sdh = session.sessionDescriptionHandler;
7827
8006
  const pc = sdh.peerConnection;
7828
8007
 
7829
- // $FlowFixMe
7830
- return navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: id } } }).then(async stream => {
7831
- const audioTrack = stream.getAudioTracks()[0];
7832
- 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);
7833
8012
 
7834
- if (sender) {
7835
- if (sender.track) {
7836
- audioTrack.enabled = sender.track.enabled;
7837
- }
7838
- sender.replaceTrack(audioTrack);
8013
+ if (sender) {
8014
+ if (sender.track) {
8015
+ audioTrack.enabled = sender.track.enabled;
7839
8016
  }
8017
+ sender.replaceTrack(audioTrack);
8018
+ }
7840
8019
 
7841
- return stream;
7842
- });
8020
+ return stream;
7843
8021
  }
7844
8022
  }
7845
8023
 
@@ -7859,14 +8037,14 @@ class WebRTCClient extends Emitter {
7859
8037
  return null;
7860
8038
  }
7861
8039
 
7862
- // let's update the local video value
7863
- if (this.video) {
7864
- this.video = {
7865
- deviceId: {
7866
- exact: id,
7867
- },
7868
- };
7869
- }
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
+ };
7870
8048
  }
7871
8049
 
7872
8050
  changeSessionVideoInputDevice(id , session ) {
@@ -9468,9 +9646,7 @@ class WebRTCPhone extends Emitter {
9468
9646
 
9469
9647
  try {
9470
9648
  if (this.currentScreenShare.stream) {
9471
- this.currentScreenShare.stream.getTracks()
9472
- .filter(track => track.kind === 'video')
9473
- .forEach(track => track.stop());
9649
+ this.currentScreenShare.stream.getTracks().forEach(track => track.stop());
9474
9650
  }
9475
9651
 
9476
9652
  if (restoreLocalStream) {
@@ -11261,6 +11437,7 @@ const AGENT_UNPAUSED = 'agent_unpaused';
11261
11437
  const CONFERENCE_ADHOC_PARTICIPANT_LEFT = 'conference_adhoc_participant_left';
11262
11438
  const CONFERENCE_ADHOC_DELETED = 'conference_adhoc_deleted';
11263
11439
  const MEETING_USER_PROGRESS = 'meeting_user_progress';
11440
+ const MEETING_USER_GUEST_AUTHORIZATION_CREATED = 'meeting_user_guest_authorization_created';
11264
11441
 
11265
11442
  const BLACKLIST_EVENTS = [
11266
11443
  CHAT_MESSAGE_SENT,
@@ -11612,6 +11789,7 @@ WebSocketClient.eventLists = [
11612
11789
  CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11613
11790
  CONFERENCE_ADHOC_DELETED,
11614
11791
  MEETING_USER_PROGRESS,
11792
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11615
11793
  ];
11616
11794
 
11617
11795
  var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
@@ -11683,6 +11861,7 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
11683
11861
  CONFERENCE_ADHOC_PARTICIPANT_LEFT: CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11684
11862
  CONFERENCE_ADHOC_DELETED: CONFERENCE_ADHOC_DELETED,
11685
11863
  MEETING_USER_PROGRESS: MEETING_USER_PROGRESS,
11864
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED: MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11686
11865
  HEARTBEAT_ENGINE_VERSION: HEARTBEAT_ENGINE_VERSION,
11687
11866
  'default': WebSocketClient
11688
11867
  });
@@ -11787,6 +11966,7 @@ class Participant extends Emitter {
11787
11966
 
11788
11967
 
11789
11968
 
11969
+
11790
11970
 
11791
11971
 
11792
11972
 
@@ -11804,6 +11984,7 @@ class Participant extends Emitter {
11804
11984
 
11805
11985
 
11806
11986
 
11987
+
11807
11988
 
11808
11989
  /**
11809
11990
  * @param room Room The room where the participant is
@@ -11827,6 +12008,7 @@ class Participant extends Emitter {
11827
12008
  this.screensharing = false;
11828
12009
  this.isOnHold = false;
11829
12010
  this.extra = extra;
12011
+ this.banned = false;
11830
12012
 
11831
12013
  this.ON_UPDATED = 'participant/ON_UPDATED';
11832
12014
  this.ON_START_TALKING = 'participant/ON_START_TALKING';
@@ -11843,6 +12025,7 @@ class Participant extends Emitter {
11843
12025
  this.ON_EXTRA_CHANGE = 'participant/ON_EXTRA_CHANGE';
11844
12026
  this.ON_HOLD = 'participant/ON_HOLD';
11845
12027
  this.ON_RESUME = 'participant/ON_RESUME';
12028
+ this.ON_BAN = 'participant/ON_BAN';
11846
12029
  }
11847
12030
 
11848
12031
  triggerEvent(name , ...args ) {
@@ -11883,6 +12066,10 @@ class Participant extends Emitter {
11883
12066
  status.extra = this.extra;
11884
12067
  break;
11885
12068
  }
12069
+ case this.ON_BAN: {
12070
+ status.banned = true;
12071
+ break;
12072
+ }
11886
12073
  }
11887
12074
 
11888
12075
  if (broadcast) {
@@ -11985,6 +12172,11 @@ class Participant extends Emitter {
11985
12172
  this.triggerUpdate(this.ON_RESUME, broadcast);
11986
12173
  }
11987
12174
 
12175
+ onBan(broadcast = true) {
12176
+ this.banned = true;
12177
+ this.triggerUpdate(this.ON_BAN, broadcast);
12178
+ }
12179
+
11988
12180
  getStatus() {
11989
12181
  return {
11990
12182
  callId: this.callId,
@@ -12031,6 +12223,10 @@ class Participant extends Emitter {
12031
12223
  }
12032
12224
  }
12033
12225
 
12226
+ if (status.banned) {
12227
+ this.onBan(false);
12228
+ }
12229
+
12034
12230
  // Poor man's object comparison
12035
12231
  if (typeof status.extra !== 'undefined' && JSON.stringify(this.extra) !== JSON.stringify(status.extra)) {
12036
12232
  this.extra = { ...this.extra, ...status.extra };
@@ -12058,6 +12254,28 @@ class Participant extends Emitter {
12058
12254
  this.streams = streams;
12059
12255
  this.videoStreams = streams;
12060
12256
  }
12257
+
12258
+ async ban(apiRequestDelay = null) {
12259
+ const { meetingUuid } = this.room;
12260
+ if (!meetingUuid) {
12261
+ throw new Error('Attempting to ban a participant without a `meetingUuid`');
12262
+ }
12263
+
12264
+ // this notifies all that someone is being banned
12265
+ this.onBan(true);
12266
+
12267
+ // this allows to delay the actual ban, in order for the banned participant as well as others to react to the situation
12268
+ if (apiRequestDelay) {
12269
+ await this.delay(apiRequestDelay);
12270
+ }
12271
+
12272
+ // proceed with the actual kick
12273
+ return getApiClient().calld.banMeetingParticipant(meetingUuid, this.callId);
12274
+ }
12275
+
12276
+ async delay(ms ) {
12277
+ return new Promise(resolve => setTimeout(resolve, ms));
12278
+ }
12061
12279
  }
12062
12280
 
12063
12281
  //
@@ -12210,7 +12428,7 @@ class Room$1 extends Emitter {
12210
12428
  logger$2.info('connecting to room', { extension, audioOnly, room: !!room });
12211
12429
 
12212
12430
  if (!room) {
12213
- await Wazo.Phone.connect();
12431
+ await Wazo.Phone.connect({ media: constraints });
12214
12432
 
12215
12433
  const withCamera = constraints && !!constraints.video;
12216
12434
 
@@ -12655,7 +12873,7 @@ class Room$1 extends Emitter {
12655
12873
  const participant = this._getParticipantFromCallId(status.callId);
12656
12874
 
12657
12875
  if (participant) {
12658
- // we're received, so no need to broadcast, hence the input false arg
12876
+ // we're receiving, so no need to broadcast
12659
12877
  participant.updateStatus(status, false);
12660
12878
  }
12661
12879
  break;
@@ -12922,7 +13140,7 @@ class SipRoom extends Room$1 {
12922
13140
  logger$1.info('connecting to sip room', { extension, audioOnly, room: !!room });
12923
13141
 
12924
13142
  if (!room) {
12925
- await Wazo.Phone.connect();
13143
+ await Wazo.Phone.connect({ media: constraints });
12926
13144
 
12927
13145
  const withCamera = constraints && !!constraints.video;
12928
13146
 
@@ -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
  });
@@ -0,0 +1,32 @@
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
+ describe('string utils', () => {
13
+ describe('camelToUnderscore', () => {
14
+ it('', () => {
15
+ expect(() => camelToUnderscore(null)).toThrow('Input is not a string');
16
+ expect(() => camelToUnderscore(undefined)).toThrow('Input is not a string');
17
+ expect(() => camelToUnderscore({})).toThrow('Input is not a string');
18
+ expect(() => camelToUnderscore([])).toThrow('Input is not a string');
19
+ });
20
+
21
+ it('should convert camel-cased string to underscore', () => {
22
+ expect(camelToUnderscore('loremIpsum')).toEqual('lorem_ipsum');
23
+ expect(camelToUnderscore('lorem-ipsum')).toEqual('lorem-ipsum');
24
+ expect(camelToUnderscore('')).toEqual('');
25
+ });
26
+
27
+ it('should not prefix string with an underscore', () => {
28
+ expect(camelToUnderscore('LoremIpsum')).toEqual('lorem_ipsum');
29
+ expect(camelToUnderscore('L123')).toEqual('l123');
30
+ });
31
+ });
32
+ });
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ //
6
+
7
+ const camelToUnderscore = (key ) => {
8
+ if (typeof key !== 'string') {
9
+ throw new Error('Input is not a string');
10
+ }
11
+ return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
12
+ };
13
+
14
+ //
15
+
16
+ const convertKeysFromCamelToUnderscore = (args ) => {
17
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
18
+ throw new Error('Input is not an object');
19
+ }
20
+
21
+ return Object.keys(args).reduce((acc, key) => {
22
+ acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
23
+ ? convertKeysFromCamelToUnderscore(args[key]) : args[key];
24
+ return acc;
25
+ }, {});
26
+ };
27
+
28
+ exports.convertKeysFromCamelToUnderscore = convertKeysFromCamelToUnderscore;