sceyt-call 1.3.1 → 1.3.2

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 (4) hide show
  1. package/README.md +121 -4
  2. package/index.d.ts +57 -10
  3. package/index.js +1 -1
  4. package/package.json +2 -2
package/README.md CHANGED
@@ -13,6 +13,8 @@ JavaScript SDK for real-time voice and video calls with WebRTC. This SDK works a
13
13
  * [Call Events](#call-events)
14
14
  * [Client Events](#client-events)
15
15
  * [Call Management](#call-management)
16
+ * [Remote Participant Control](#remote-participant-control)
17
+ * [Call Permissions](#call-permissions)
16
18
  * [Call History (CDR)](#call-history-cdr)
17
19
  * [Participant States](#participant-states)
18
20
  * [Logging](#logging)
@@ -90,7 +92,7 @@ call.on('participantStateChanged', ({ participant, state }) => {
90
92
  ```typescript
91
93
  // Audio controls
92
94
  call.mute(true); // Mute microphone
93
- call.mute(false); // Unmute
95
+ call.mute(false); // Unmute (blocked if hard-muted by host or call audio is locked)
94
96
  call.hold(true); // Put on hold
95
97
 
96
98
  // Video controls
@@ -170,7 +172,7 @@ await call.switchToSFU(handleError);
170
172
  - `call.enableVideo(enabled, errorCallback?)` — camera/signal errors via callback
171
173
  - `call.startScreenShare(errorCallback?)` — screen share errors via callback
172
174
  - `call.stopScreenShare(errorCallback?)` — signal errors via callback
173
- - `call.mute(mute, errorCallback?)` — signal errors via callback
175
+ - `call.mute(mute, errorCallback?)` — signal errors via callback; returns error immediately if hard-muted
174
176
  - `call.switchToSFU(errorCallback?)` — signal errors via callback
175
177
  - `call.leave()` — no callback, check return value
176
178
 
@@ -206,8 +208,10 @@ call.on('videoTrackAdded', ({ participant, track }) => {
206
208
  videoElement.srcObject = new MediaStream([track]);
207
209
  });
208
210
 
209
- call.on('participantEvent', ({ participant, event }) => {
210
- // event: 'Mute' | 'Unmute' | 'Hold' | 'VideoEnabled' | etc.
211
+ call.on('participantEvent', ({ participant, event, changedBy }) => {
212
+ // event: 'Mute' | 'Unmute' | 'Hold' | 'VideoEnabled' | 'VideoDisabled' |
213
+ // 'ScreenSharingStarted' | 'ScreenSharingStopped' | etc.
214
+ // changedBy: userId of whoever triggered the change (e.g. a host muting a participant)
211
215
  });
212
216
 
213
217
  call.on('activeSpeakersChanged', ({ activeSpeakers }) => {
@@ -217,6 +221,18 @@ call.on('activeSpeakersChanged', ({ activeSpeakers }) => {
217
221
  call.on('sessionRenewed', ({ call, sessionId }) => {
218
222
  // Fired when the server assigns a new sessionId to an existing call
219
223
  });
224
+
225
+ call.on('callPermissionsUpdated', ({ call, permissions }) => {
226
+ // Fired when the host updates call-level audio/video permissions
227
+ console.log('Audio allowed:', permissions.allowPublishAudio);
228
+ console.log('Video allowed:', permissions.allowPublishVideo);
229
+ });
230
+
231
+ call.on('participantPermissionsUpdated', ({ call, participant, permissions }) => {
232
+ // Fired when a participant's individual permissions are updated by the host
233
+ console.log(`${participant.id} canPublishAudio: ${permissions.canPublishAudio}`);
234
+ console.log(`${participant.id} canPublishVideo: ${permissions.canPublishVideo}`);
235
+ });
220
236
  ```
221
237
 
222
238
  ## Client Events
@@ -266,6 +282,103 @@ const speakers = call?.activeSpeakers;
266
282
  const { data } = await callClient.fetchCall('call-id');
267
283
  ```
268
284
 
285
+ ## Remote Participant Control
286
+
287
+ Host participants can mute, disable video, or update permissions for other participants in the call. All methods return `CallClientResult<boolean>` and accept an optional error callback.
288
+
289
+ ### Mute / Unmute Remote Participants
290
+
291
+ ```typescript
292
+ // Mute a specific participant (soft-mute — they can unmute themselves)
293
+ call.muteRemoteParticipant('user1');
294
+
295
+ // Hard-mute: revoke publish-audio permission (they cannot unmute)
296
+ call.disableRemoteParticipantAudio('user1');
297
+
298
+ // Restore audio permission (allow them to unmute)
299
+ call.enableRemoteParticipantAudio('user1');
300
+ // or equivalently:
301
+ call.unmuteRemoteParticipant('user1');
302
+
303
+ // Mute all participants at once
304
+ call.muteAllRemoteParticipants();
305
+ ```
306
+
307
+ ### Disable Video for Remote Participants
308
+
309
+ ```typescript
310
+ // Turn off a specific participant's video
311
+ call.disableRemoteParticipantVideo('user1');
312
+ // or equivalently:
313
+ call.videoOffRemoteParticipant('user1');
314
+
315
+ // Turn off video for all participants
316
+ call.videoOffAllRemoteParticipants();
317
+ // or equivalently:
318
+ call.disableAllRemoteParticipantsVideo();
319
+ ```
320
+
321
+ ### Update Participant Permissions
322
+
323
+ ```typescript
324
+ import type { IParticipantPermissions } from 'sceyt-call';
325
+
326
+ // Grant or revoke individual publish permissions
327
+ call.updateParticipantPermissions('user1', {
328
+ canPublishAudio: true,
329
+ canPublishVideo: false,
330
+ });
331
+ ```
332
+
333
+ ## Call Permissions
334
+
335
+ The host can lock audio or video at the call level, preventing all participants from publishing.
336
+
337
+ ```typescript
338
+ import type { ICallPermissions } from 'sceyt-call';
339
+
340
+ // Lock audio for the entire call
341
+ call.disableCallAudio();
342
+
343
+ // Restore audio for the entire call
344
+ call.enableCallAudio();
345
+
346
+ // Lock video for the entire call
347
+ call.disableCallVideo();
348
+
349
+ // Restore video for the entire call
350
+ call.enableCallVideo();
351
+
352
+ // Update both at once
353
+ call.updateCallPermissions({ allowPublishAudio: false, allowPublishVideo: true });
354
+ ```
355
+
356
+ Current call-level permissions are exposed on the `call.permissions` property:
357
+
358
+ ```typescript
359
+ console.log(call.permissions?.allowPublishAudio); // boolean | undefined
360
+ console.log(call.permissions?.allowPublishVideo); // boolean | undefined
361
+ ```
362
+
363
+ ### Participant-level media state
364
+
365
+ Each participant now exposes a structured `mediaState` object instead of the old flat `muted`, `videoEnabled`, and `screenSharing` boolean fields:
366
+
367
+ ```typescript
368
+ const p = call.participants[0];
369
+
370
+ console.log(p.mediaState?.audio.enabled); // mic on/off
371
+ console.log(p.mediaState?.video.enabled); // camera on/off
372
+ console.log(p.mediaState?.screenShare.enabled); // screen share on/off
373
+
374
+ // changedBy tells you who last changed the state (e.g. a host action)
375
+ console.log(p.mediaState?.audio.changedBy);
376
+
377
+ // Individual publish permissions assigned by the host
378
+ console.log(p.permissions?.canPublishAudio);
379
+ console.log(p.permissions?.canPublishVideo);
380
+ ```
381
+
269
382
  ## Call History (CDR)
270
383
 
271
384
  ```typescript
@@ -318,6 +431,10 @@ import type {
318
431
  CallEventMap,
319
432
  CallClientEventMap,
320
433
  ICallDetailRecord,
434
+ ICallPermissions,
435
+ IParticipantPermissions,
436
+ IParticipantMediaState,
437
+ IMediaState,
321
438
  ParticipantState,
322
439
  CallState,
323
440
  MediaFlow
package/index.d.ts CHANGED
@@ -215,6 +215,8 @@ export interface CallSettings {
215
215
  maxParticipantsCount?: number;
216
216
  /** Type identifier for the call (e.g. 'audio', 'video', custom string) */
217
217
  callType?: string;
218
+ /** Call-level audio/video permissions set by the owner */
219
+ permissions: ICallPermissions;
218
220
  }
219
221
  /**
220
222
  * Options for creating a call.
@@ -276,11 +278,29 @@ interface SignalCallSettings {
276
278
  persistent?: boolean;
277
279
  notifyOnParticipantJoin?: boolean;
278
280
  maxParticipantsCount?: number;
281
+ permissions: ICallPermissions;
279
282
  }
280
283
  interface SignalCallOptions {
281
284
  settings?: SignalCallSettings;
282
285
  callType?: string;
283
286
  }
287
+ interface IMediaState {
288
+ enabled: boolean;
289
+ changedBy?: string;
290
+ }
291
+ interface IParticipantMediaState {
292
+ audio: IMediaState;
293
+ video: IMediaState;
294
+ screenShare: IMediaState;
295
+ }
296
+ interface IParticipantPermissions {
297
+ canPublishAudio: boolean;
298
+ canPublishVideo: boolean;
299
+ }
300
+ interface ICallPermissions {
301
+ allowPublishAudio: boolean;
302
+ allowPublishVideo: boolean;
303
+ }
284
304
  /**
285
305
  * Raw participant data as received from the server.
286
306
  * Use the `Participant` class for a richer API.
@@ -292,10 +312,6 @@ export interface IParticipant {
292
312
  clientId: string;
293
313
  /** Whether this participant is the presenter */
294
314
  presenter?: boolean;
295
- /** Whether the participant's camera is on */
296
- videoEnabled?: boolean;
297
- /** Whether the participant's microphone is muted */
298
- muted?: boolean;
299
315
  /** Whether the participant is on hold */
300
316
  onHold?: boolean;
301
317
  /** Whether the participant is sharing their screen */
@@ -306,6 +322,10 @@ export interface IParticipant {
306
322
  connectionState?: ParticipantConnectionState;
307
323
  /** Whether the call was silenced for this participant */
308
324
  isCallSilenced?: boolean;
325
+ /** Combined media track states */
326
+ mediaState?: IParticipantMediaState;
327
+ /** What this participant is allowed to publish */
328
+ permissions?: IParticipantPermissions;
309
329
  }
310
330
  type CallMetadata = {
311
331
  [key: string]: string | number;
@@ -461,14 +481,8 @@ export declare class Participant {
461
481
  id: string;
462
482
  /** Client identifier for multi-device support. Empty string if not applicable. */
463
483
  clientId: string;
464
- /** Whether the participant's microphone is muted */
465
- muted: boolean;
466
484
  /** Whether the participant is on hold */
467
485
  onHold: boolean;
468
- /** Whether the participant's camera is enabled */
469
- videoEnabled: boolean;
470
- /** Whether the participant is sharing their screen */
471
- screenSharing: boolean;
472
486
  /** Array of audio tracks from this participant. Use these to play participant's audio. */
473
487
  audioTracks: MediaStreamTrack[];
474
488
  /** Array of video tracks from this participant. Use these to display participant's video. */
@@ -477,6 +491,10 @@ export declare class Participant {
477
491
  state: ParticipantState;
478
492
  /** Current WebRTC connection state of the participant */
479
493
  connectionState: ParticipantConnectionState;
494
+ /** Combined media track states (audio, video, screenShare) */
495
+ mediaState?: IParticipantMediaState;
496
+ /** What this participant is allowed to publish */
497
+ permissions?: IParticipantPermissions;
480
498
  }
481
499
  interface ActiveSpeakerInfo {
482
500
  participant: Participant;
@@ -579,6 +597,7 @@ export interface CallEventMap {
579
597
  call: Call;
580
598
  participant: Participant;
581
599
  event: ParticipantEvent;
600
+ changedBy?: string;
582
601
  };
583
602
  /** Fired when participants are added to the call */
584
603
  participantsAdded: {
@@ -610,6 +629,17 @@ export interface CallEventMap {
610
629
  call: Call;
611
630
  sessionId: string;
612
631
  };
632
+ /** Fired when the owner updates call-level audio/video permissions */
633
+ callPermissionsUpdated: {
634
+ call: Call;
635
+ permissions: ICallPermissions;
636
+ };
637
+ /** Fired when a participant's individual permissions are updated by the owner */
638
+ participantPermissionsUpdated: {
639
+ call: Call;
640
+ participant: Participant;
641
+ permissions: IParticipantPermissions;
642
+ };
613
643
  }
614
644
  /**
615
645
  * Event map for SceytCallClient class.
@@ -681,6 +711,8 @@ export declare class Call extends TypedEventEmitter<CallEventMap> {
681
711
  callType?: string;
682
712
  /** Scheduling and broadcast settings for this call */
683
713
  settings?: CallSettings;
714
+ /** Current call-level audio/video permissions set by the owner */
715
+ permissions?: ICallPermissions;
684
716
  /** Current list of active speakers in the call */
685
717
  get activeSpeakers(): ActiveSpeakerInfo[];
686
718
  set activeSpeakers(speakers: ActiveSpeakerInfo[]);
@@ -793,6 +825,21 @@ export declare class Call extends TypedEventEmitter<CallEventMap> {
793
825
  * ```
794
826
  */
795
827
  mute(mute: boolean, errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
828
+ muteAllRemoteParticipants(errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
829
+ videoOffAllRemoteParticipants(errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
830
+ disableAllRemoteParticipantsVideo(errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
831
+ updateParticipantPermissions(id: string, permissions: IParticipantPermissions, errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
832
+ muteRemoteParticipant(id: string, errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
833
+ disableRemoteParticipantAudio(id: string, errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
834
+ enableRemoteParticipantAudio(id: string, errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
835
+ enableCallAudio(errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
836
+ disableCallAudio(errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
837
+ unmuteRemoteParticipant(id: string, errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
838
+ disableRemoteParticipantVideo(id: string, errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
839
+ videoOffRemoteParticipant(id: string, errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
840
+ disableCallVideo(errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
841
+ enableCallVideo(errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
842
+ updateCallPermissions(permissions: ICallPermissions, errorCallback?: (result: CallClientResult<boolean>) => void): CallClientResult<boolean>;
796
843
  /**
797
844
  * Put the call on hold or resume it.
798
845
  * When on hold, audio/video is paused but the call remains active.