@wazo/sdk 0.38.7 → 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 (106) 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 +227 -27
  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 +183 -24
  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 +183 -24
  11. package/esm/checker/checks/wazo-websocket.js +2 -0
  12. package/esm/checker/checks/webrtc-transport.js +181 -24
  13. package/esm/checker/checks/webrtc.js +181 -24
  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/__tests__/Meeting.test.js +87 -1
  20. package/esm/domain/__tests__/MeetingAuthorization.test.js +109 -0
  21. package/esm/index.js +226 -27
  22. package/esm/service/CallApi.js +142 -2
  23. package/esm/service/getApiClient.js +142 -2
  24. package/esm/simple/Auth.js +226 -27
  25. package/esm/simple/Configuration.js +226 -27
  26. package/esm/simple/Directory.js +142 -2
  27. package/esm/simple/Phone.js +226 -27
  28. package/esm/simple/Websocket.js +3 -0
  29. package/esm/simple/index.js +226 -27
  30. package/esm/simple/room/LocalParticipant.js +226 -27
  31. package/esm/simple/room/Participant.js +226 -27
  32. package/esm/simple/room/RemoteParticipant.js +226 -27
  33. package/esm/simple/room/Room.js +226 -27
  34. package/esm/simple/room/SipRoom.js +226 -27
  35. package/esm/simple/room/Stream.js +226 -27
  36. package/esm/simple/room/__tests__/Participant.test.js +14747 -0
  37. package/esm/simple/room/__tests__/RemoteParticipant.test.js +226 -27
  38. package/esm/simple/utils.js +226 -27
  39. package/esm/utils/__tests__/object.test.js +57 -0
  40. package/esm/utils/__tests__/string.test.js +30 -0
  41. package/esm/utils/object.js +24 -0
  42. package/esm/utils/string.js +10 -0
  43. package/esm/web-rtc-client.js +181 -24
  44. package/esm/websocket-client.js +3 -1
  45. package/lib/__tests__/api-client.test.js +142 -2
  46. package/lib/__tests__/web-rtc-client.test.js +227 -27
  47. package/lib/api/calld.js +8 -0
  48. package/lib/api/confd.js +134 -2
  49. package/lib/api-client.js +142 -2
  50. package/lib/checker/Checker.js +183 -24
  51. package/lib/checker/checks/aor.js +142 -2
  52. package/lib/checker/checks/api.js +142 -2
  53. package/lib/checker/checks/index.js +183 -24
  54. package/lib/checker/checks/wazo-websocket.js +2 -0
  55. package/lib/checker/checks/webrtc-transport.js +181 -24
  56. package/lib/checker/checks/webrtc.js +181 -24
  57. package/lib/domain/AdHocAPIConference.js +142 -2
  58. package/lib/domain/Features.js +142 -2
  59. package/lib/domain/Meeting.js +18 -0
  60. package/lib/domain/MeetingAuthorization.js +79 -0
  61. package/lib/domain/Phone/CTIPhone.js +142 -2
  62. package/lib/domain/__tests__/Meeting.test.js +87 -1
  63. package/lib/domain/__tests__/MeetingAuthorization.test.js +111 -0
  64. package/lib/index.js +226 -27
  65. package/lib/service/CallApi.js +142 -2
  66. package/lib/service/getApiClient.js +142 -2
  67. package/lib/simple/Auth.js +226 -27
  68. package/lib/simple/Configuration.js +226 -27
  69. package/lib/simple/Directory.js +142 -2
  70. package/lib/simple/Phone.js +226 -27
  71. package/lib/simple/Websocket.js +3 -0
  72. package/lib/simple/index.js +226 -27
  73. package/lib/simple/room/LocalParticipant.js +226 -27
  74. package/lib/simple/room/Participant.js +226 -27
  75. package/lib/simple/room/RemoteParticipant.js +226 -27
  76. package/lib/simple/room/Room.js +226 -27
  77. package/lib/simple/room/SipRoom.js +226 -27
  78. package/lib/simple/room/Stream.js +226 -27
  79. package/lib/simple/room/__tests__/Participant.test.js +14757 -0
  80. package/lib/simple/room/__tests__/RemoteParticipant.test.js +226 -27
  81. package/lib/simple/utils.js +226 -27
  82. package/lib/utils/__tests__/object.test.js +59 -0
  83. package/lib/utils/__tests__/string.test.js +32 -0
  84. package/lib/utils/object.js +28 -0
  85. package/lib/utils/string.js +14 -0
  86. package/lib/web-rtc-client.js +181 -24
  87. package/lib/websocket-client.js +3 -0
  88. package/package.json +2 -2
  89. package/src/__tests__/web-rtc-client.test.js +46 -3
  90. package/src/api/calld.js +8 -0
  91. package/src/api/confd.js +43 -2
  92. package/src/domain/Meeting.js +20 -0
  93. package/src/domain/MeetingAuthorization.js +67 -0
  94. package/src/domain/__tests__/Meeting.test.js +70 -1
  95. package/src/domain/__tests__/MeetingAuthorization.test.js +58 -0
  96. package/src/simple/room/Participant.js +40 -0
  97. package/src/simple/room/Room.js +2 -2
  98. package/src/simple/room/SipRoom.js +1 -1
  99. package/src/simple/room/__tests__/Participant.test.js +81 -0
  100. package/src/types/WebSocketMessage.js +7 -1
  101. package/src/utils/__tests__/object.test.js +35 -0
  102. package/src/utils/__tests__/string.test.js +23 -0
  103. package/src/utils/object.js +15 -0
  104. package/src/utils/string.js +8 -0
  105. package/src/web-rtc-client.js +39 -22
  106. package/src/websocket-client.js +2 -0
@@ -2671,6 +2671,70 @@ class ExternalApp {
2671
2671
 
2672
2672
  //
2673
2673
 
2674
+ class MeetingAuthorization {
2675
+
2676
+
2677
+
2678
+
2679
+
2680
+
2681
+ constructor({
2682
+ meetingUuid,
2683
+ uuid,
2684
+ userUuid,
2685
+ userName,
2686
+ } = {}) {
2687
+ this.meetingUuid = meetingUuid;
2688
+ this.uuid = uuid;
2689
+ this.userUuid = userUuid;
2690
+ this.userName = userName;
2691
+ }
2692
+
2693
+ setStatus(status ) {
2694
+ this.status = status;
2695
+ }
2696
+
2697
+ getStatus() {
2698
+ return this.status;
2699
+ }
2700
+
2701
+ static parse(plain ) {
2702
+ const {
2703
+ meeting_uuid: meetingUuid,
2704
+ uuid,
2705
+ guest_uuid: userUuid,
2706
+ guest_name: userName,
2707
+ } = plain;
2708
+
2709
+ return new MeetingAuthorization({
2710
+ meetingUuid,
2711
+ uuid,
2712
+ userUuid,
2713
+ userName,
2714
+ });
2715
+ }
2716
+
2717
+ static parseMany(items ) {
2718
+ if (!items) {
2719
+ return [];
2720
+ }
2721
+ return items.map(MeetingAuthorization.parse);
2722
+ }
2723
+ }
2724
+
2725
+ //
2726
+
2727
+
2728
+
2729
+
2730
+
2731
+
2732
+
2733
+
2734
+
2735
+
2736
+
2737
+
2674
2738
 
2675
2739
 
2676
2740
 
@@ -2681,6 +2745,7 @@ class ExternalApp {
2681
2745
 
2682
2746
 
2683
2747
 
2748
+
2684
2749
 
2685
2750
 
2686
2751
  class Meeting {
@@ -2695,6 +2760,8 @@ class Meeting {
2695
2760
 
2696
2761
 
2697
2762
 
2763
+
2764
+
2698
2765
 
2699
2766
  static parse(plain ) {
2700
2767
  return new Meeting({
@@ -2707,6 +2774,7 @@ class Meeting {
2707
2774
  extension: plain.exten,
2708
2775
  persistent: plain.persistent,
2709
2776
  creationTime: moment(plain.creation_time).toDate(),
2777
+ requireAuthorization: plain.require_authorization,
2710
2778
  });
2711
2779
  }
2712
2780
 
@@ -2731,6 +2799,7 @@ class Meeting {
2731
2799
  extension,
2732
2800
  persistent,
2733
2801
  creationTime,
2802
+ requireAuthorization,
2734
2803
  } = {}) {
2735
2804
  this.guestSipAuthorization = guestSipAuthorization;
2736
2805
  this.uri = uri;
@@ -2741,6 +2810,7 @@ class Meeting {
2741
2810
  this.extension = extension;
2742
2811
  this.persistent = persistent;
2743
2812
  this.creationTime = creationTime;
2813
+ this.requireAuthorization = requireAuthorization;
2744
2814
 
2745
2815
  // Useful to compare instead of instanceof with minified code
2746
2816
  this.type = 'Meeting';
@@ -2751,8 +2821,32 @@ class Meeting {
2751
2821
  const [username, secret] = atob(this.guestSipAuthorization).split(':');
2752
2822
  return { username, secret };
2753
2823
  }
2824
+
2754
2825
  }
2755
2826
 
2827
+ //
2828
+
2829
+ const camelToUnderscore = (key ) => {
2830
+ if (typeof key !== 'string') {
2831
+ throw new Error('Input is not a string');
2832
+ }
2833
+ return key.charAt(0).toLowerCase() + key.substring(1).replace(/([A-Z])/g, '_$1').toLowerCase();
2834
+ };
2835
+
2836
+ //
2837
+
2838
+ const convertKeysFromCamelToUnderscore = (args ) => {
2839
+ if (!args || typeof args !== 'object' || Array.isArray(args)) {
2840
+ throw new Error('Input is not an object');
2841
+ }
2842
+
2843
+ return Object.keys(args).reduce((acc, key) => {
2844
+ acc[camelToUnderscore(key)] = typeof args[key] === 'object' && !Array.isArray(args[key])
2845
+ ? convertKeysFromCamelToUnderscore(args[key]) : args[key];
2846
+ return acc;
2847
+ }, {});
2848
+ };
2849
+
2756
2850
  /* */
2757
2851
 
2758
2852
  var confdMethods = (client , baseUrl ) => ({
@@ -2821,8 +2915,18 @@ var confdMethods = (client , baseUrl ) => ({
2821
2915
  getMyMeetings: () =>
2822
2916
  client.get(`${baseUrl}/users/me/meetings`).then(response => Meeting.parseMany(response.items)),
2823
2917
 
2824
- createMyMeeting: (name , persistent ) =>
2825
- client.post(`${baseUrl}/users/me/meetings`, { name, persistent }).then(Meeting.parse),
2918
+ createMyMeeting: (args ) =>
2919
+ client
2920
+ .post(`${baseUrl}/users/me/meetings`, convertKeysFromCamelToUnderscore(args))
2921
+ .then(Meeting.parse),
2922
+
2923
+ updateMyMeeting: (meetingUuid , data ) =>
2924
+ client.put(
2925
+ `${baseUrl}/users/me/meetings/${meetingUuid}`,
2926
+ convertKeysFromCamelToUnderscore(data),
2927
+ null,
2928
+ ApiRequester.successResponseParser,
2929
+ ),
2826
2930
 
2827
2931
  deleteMyMeeting: (meetingUuid ) =>
2828
2932
  client.delete(`${baseUrl}/users/me/meetings/${meetingUuid}`, null),
@@ -2830,8 +2934,36 @@ var confdMethods = (client , baseUrl ) => ({
2830
2934
  getMeeting: (meetingUuid ) =>
2831
2935
  client.get(`${baseUrl}/meetings/${meetingUuid}`, null).then(Meeting.parse),
2832
2936
 
2937
+ meetingAuthorizations: (meetingUuid ) =>
2938
+ client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/authorizations`, null).then(MeetingAuthorization.parseMany),
2939
+
2940
+ meetingAuthorizationReject: (meetingUuid , authorizationUuid ) =>
2941
+ client.put(
2942
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/reject`,
2943
+ {},
2944
+ null,
2945
+ ApiRequester.successResponseParser,
2946
+ ),
2947
+
2948
+ meetingAuthorizationAccept: (meetingUuid , authorizationUuid ) =>
2949
+ client.put(
2950
+ `${baseUrl}/users/me/meetings/${meetingUuid}/authorizations/${authorizationUuid}/accept`,
2951
+ {},
2952
+ null,
2953
+ ApiRequester.successResponseParser,
2954
+ ),
2955
+
2833
2956
  guestGetMeeting: (meetingUuid ) =>
2834
2957
  client.get(`${baseUrl}/guests/me/meetings/${meetingUuid}`, null).then(Meeting.parse),
2958
+
2959
+ guestAuthorizationRequest: (userUuid , meetingUuid , username ) =>
2960
+ client
2961
+ .post(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations`, { guest_name: username })
2962
+ .then(MeetingAuthorization.parse),
2963
+
2964
+ guestAuthorizationCheck: (userUuid , meetingUuid , authorizationUuid ) =>
2965
+ client.get(`${baseUrl}/guests/${userUuid}/meetings/${meetingUuid}/authorizations/${authorizationUuid}`, null),
2966
+
2835
2967
  });
2836
2968
 
2837
2969
  //
@@ -5056,6 +5188,14 @@ var calldMethods = (client , baseUrl ) => ({
5056
5188
  getMeetingParticipantsAsUser: async (meetingUuid ) =>
5057
5189
  client.get(`${baseUrl}/users/me/meetings/${meetingUuid}/participants`),
5058
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
+
5059
5199
  listTrunks: () => client.get(`${baseUrl}/trunks`),
5060
5200
 
5061
5201
  mute: (callId ) =>
@@ -7814,7 +7954,7 @@ class WebRTCClient extends Emitter {
7814
7954
  });
7815
7955
  }
7816
7956
 
7817
- changeAudioInputDevice(id , session , force ) {
7957
+ async changeAudioInputDevice(id , session , force ) {
7818
7958
  const currentId = this.getAudioDeviceId();
7819
7959
  logger$8.info('setting audio input device', { id, currentId, session: !!session });
7820
7960
 
@@ -7822,33 +7962,50 @@ class WebRTCClient extends Emitter {
7822
7962
  return null;
7823
7963
  }
7824
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
+
7825
7983
  // let's update the local audio value
7826
7984
  if (this.audio) {
7827
7985
  this.audio = {
7828
7986
  deviceId: {
7829
- exact: id,
7987
+ exact: deviceId,
7830
7988
  },
7831
7989
  };
7832
7990
  }
7833
7991
 
7834
- if (session) {
7992
+ if (session && navigator.mediaDevices) {
7835
7993
  const sdh = session.sessionDescriptionHandler;
7836
7994
  const pc = sdh.peerConnection;
7837
7995
 
7838
- // $FlowFixMe
7839
- return navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: id } } }).then(async stream => {
7840
- const audioTrack = stream.getAudioTracks()[0];
7841
- 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);
7842
8000
 
7843
- if (sender) {
7844
- if (sender.track) {
7845
- audioTrack.enabled = sender.track.enabled;
7846
- }
7847
- sender.replaceTrack(audioTrack);
8001
+ if (sender) {
8002
+ if (sender.track) {
8003
+ audioTrack.enabled = sender.track.enabled;
7848
8004
  }
8005
+ sender.replaceTrack(audioTrack);
8006
+ }
7849
8007
 
7850
- return stream;
7851
- });
8008
+ return stream;
7852
8009
  }
7853
8010
  }
7854
8011
 
@@ -7868,14 +8025,14 @@ class WebRTCClient extends Emitter {
7868
8025
  return null;
7869
8026
  }
7870
8027
 
7871
- // let's update the local video value
7872
- if (this.video) {
7873
- this.video = {
7874
- deviceId: {
7875
- exact: id,
7876
- },
7877
- };
7878
- }
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
+ };
7879
8036
  }
7880
8037
 
7881
8038
  changeSessionVideoInputDevice(id , session ) {
@@ -11270,6 +11427,7 @@ const AGENT_UNPAUSED = 'agent_unpaused';
11270
11427
  const CONFERENCE_ADHOC_PARTICIPANT_LEFT = 'conference_adhoc_participant_left';
11271
11428
  const CONFERENCE_ADHOC_DELETED = 'conference_adhoc_deleted';
11272
11429
  const MEETING_USER_PROGRESS = 'meeting_user_progress';
11430
+ const MEETING_USER_GUEST_AUTHORIZATION_CREATED = 'meeting_user_guest_authorization_created';
11273
11431
 
11274
11432
  const BLACKLIST_EVENTS = [
11275
11433
  CHAT_MESSAGE_SENT,
@@ -11621,6 +11779,7 @@ WebSocketClient.eventLists = [
11621
11779
  CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11622
11780
  CONFERENCE_ADHOC_DELETED,
11623
11781
  MEETING_USER_PROGRESS,
11782
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11624
11783
  ];
11625
11784
 
11626
11785
  var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
@@ -11692,6 +11851,7 @@ var WebSocketClient$1 = /*#__PURE__*/Object.freeze({
11692
11851
  CONFERENCE_ADHOC_PARTICIPANT_LEFT: CONFERENCE_ADHOC_PARTICIPANT_LEFT,
11693
11852
  CONFERENCE_ADHOC_DELETED: CONFERENCE_ADHOC_DELETED,
11694
11853
  MEETING_USER_PROGRESS: MEETING_USER_PROGRESS,
11854
+ MEETING_USER_GUEST_AUTHORIZATION_CREATED: MEETING_USER_GUEST_AUTHORIZATION_CREATED,
11695
11855
  HEARTBEAT_ENGINE_VERSION: HEARTBEAT_ENGINE_VERSION,
11696
11856
  'default': WebSocketClient
11697
11857
  });
@@ -11789,7 +11949,7 @@ class SipRoom extends Room {
11789
11949
  logger$3.info('connecting to sip room', { extension, audioOnly, room: !!room });
11790
11950
 
11791
11951
  if (!room) {
11792
- await Wazo.Phone.connect();
11952
+ await Wazo.Phone.connect({ media: constraints });
11793
11953
 
11794
11954
  const withCamera = constraints && !!constraints.video;
11795
11955
 
@@ -13476,7 +13636,7 @@ class Room extends Emitter {
13476
13636
  logger$1.info('connecting to room', { extension, audioOnly, room: !!room });
13477
13637
 
13478
13638
  if (!room) {
13479
- await Wazo.Phone.connect();
13639
+ await Wazo.Phone.connect({ media: constraints });
13480
13640
 
13481
13641
  const withCamera = constraints && !!constraints.video;
13482
13642
 
@@ -13921,7 +14081,7 @@ class Room extends Emitter {
13921
14081
  const participant = this._getParticipantFromCallId(status.callId);
13922
14082
 
13923
14083
  if (participant) {
13924
- // we're received, so no need to broadcast, hence the input false arg
14084
+ // we're receiving, so no need to broadcast
13925
14085
  participant.updateStatus(status, false);
13926
14086
  }
13927
14087
  break;
@@ -14195,6 +14355,7 @@ class Participant extends Emitter {
14195
14355
 
14196
14356
 
14197
14357
 
14358
+
14198
14359
 
14199
14360
 
14200
14361
 
@@ -14212,6 +14373,7 @@ class Participant extends Emitter {
14212
14373
 
14213
14374
 
14214
14375
 
14376
+
14215
14377
 
14216
14378
  /**
14217
14379
  * @param room Room The room where the participant is
@@ -14235,6 +14397,7 @@ class Participant extends Emitter {
14235
14397
  this.screensharing = false;
14236
14398
  this.isOnHold = false;
14237
14399
  this.extra = extra;
14400
+ this.banned = false;
14238
14401
 
14239
14402
  this.ON_UPDATED = 'participant/ON_UPDATED';
14240
14403
  this.ON_START_TALKING = 'participant/ON_START_TALKING';
@@ -14251,6 +14414,7 @@ class Participant extends Emitter {
14251
14414
  this.ON_EXTRA_CHANGE = 'participant/ON_EXTRA_CHANGE';
14252
14415
  this.ON_HOLD = 'participant/ON_HOLD';
14253
14416
  this.ON_RESUME = 'participant/ON_RESUME';
14417
+ this.ON_BAN = 'participant/ON_BAN';
14254
14418
  }
14255
14419
 
14256
14420
  triggerEvent(name , ...args ) {
@@ -14291,6 +14455,10 @@ class Participant extends Emitter {
14291
14455
  status.extra = this.extra;
14292
14456
  break;
14293
14457
  }
14458
+ case this.ON_BAN: {
14459
+ status.banned = true;
14460
+ break;
14461
+ }
14294
14462
  }
14295
14463
 
14296
14464
  if (broadcast) {
@@ -14393,6 +14561,11 @@ class Participant extends Emitter {
14393
14561
  this.triggerUpdate(this.ON_RESUME, broadcast);
14394
14562
  }
14395
14563
 
14564
+ onBan(broadcast = true) {
14565
+ this.banned = true;
14566
+ this.triggerUpdate(this.ON_BAN, broadcast);
14567
+ }
14568
+
14396
14569
  getStatus() {
14397
14570
  return {
14398
14571
  callId: this.callId,
@@ -14439,6 +14612,10 @@ class Participant extends Emitter {
14439
14612
  }
14440
14613
  }
14441
14614
 
14615
+ if (status.banned) {
14616
+ this.onBan(false);
14617
+ }
14618
+
14442
14619
  // Poor man's object comparison
14443
14620
  if (typeof status.extra !== 'undefined' && JSON.stringify(this.extra) !== JSON.stringify(status.extra)) {
14444
14621
  this.extra = { ...this.extra, ...status.extra };
@@ -14466,6 +14643,28 @@ class Participant extends Emitter {
14466
14643
  this.streams = streams;
14467
14644
  this.videoStreams = streams;
14468
14645
  }
14646
+
14647
+ async ban(apiRequestDelay = null) {
14648
+ const { meetingUuid } = this.room;
14649
+ if (!meetingUuid) {
14650
+ throw new Error('Attempting to ban a participant without a `meetingUuid`');
14651
+ }
14652
+
14653
+ // this notifies all that someone is being banned
14654
+ this.onBan(true);
14655
+
14656
+ // this allows to delay the actual ban, in order for the banned participant as well as others to react to the situation
14657
+ if (apiRequestDelay) {
14658
+ await this.delay(apiRequestDelay);
14659
+ }
14660
+
14661
+ // proceed with the actual kick
14662
+ return getApiClient().calld.banMeetingParticipant(meetingUuid, this.callId);
14663
+ }
14664
+
14665
+ async delay(ms ) {
14666
+ return new Promise(resolve => setTimeout(resolve, ms));
14667
+ }
14469
14668
  }
14470
14669
 
14471
14670
  export default Participant;