@stream-io/video-client 0.3.19 → 0.3.21

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.
@@ -810,7 +810,7 @@ export interface CallReactionEvent {
810
810
  type: string;
811
811
  }
812
812
  /**
813
- *
813
+ * CallRecording represents a recording of a call.
814
814
  * @export
815
815
  * @interface CallRecording
816
816
  */
@@ -840,6 +840,62 @@ export interface CallRecording {
840
840
  */
841
841
  url: string;
842
842
  }
843
+ /**
844
+ * This event is sent when call recording has failed
845
+ * @export
846
+ * @interface CallRecordingFailedEvent
847
+ */
848
+ export interface CallRecordingFailedEvent {
849
+ /**
850
+ *
851
+ * @type {string}
852
+ * @memberof CallRecordingFailedEvent
853
+ */
854
+ call_cid: string;
855
+ /**
856
+ *
857
+ * @type {string}
858
+ * @memberof CallRecordingFailedEvent
859
+ */
860
+ created_at: string;
861
+ /**
862
+ * The type of event: "call.recording_failed" in this case
863
+ * @type {string}
864
+ * @memberof CallRecordingFailedEvent
865
+ */
866
+ type: string;
867
+ }
868
+ /**
869
+ * This event is sent when call recording is ready
870
+ * @export
871
+ * @interface CallRecordingReadyEvent
872
+ */
873
+ export interface CallRecordingReadyEvent {
874
+ /**
875
+ *
876
+ * @type {string}
877
+ * @memberof CallRecordingReadyEvent
878
+ */
879
+ call_cid: string;
880
+ /**
881
+ *
882
+ * @type {CallRecording}
883
+ * @memberof CallRecordingReadyEvent
884
+ */
885
+ call_recording: CallRecording;
886
+ /**
887
+ *
888
+ * @type {string}
889
+ * @memberof CallRecordingReadyEvent
890
+ */
891
+ created_at: string;
892
+ /**
893
+ * The type of event: "call.recording_ready" in this case
894
+ * @type {string}
895
+ * @memberof CallRecordingReadyEvent
896
+ */
897
+ type: string;
898
+ }
843
899
  /**
844
900
  * This event is sent when call recording has started
845
901
  * @export
@@ -1493,12 +1549,6 @@ export interface CallSettingsResponse {
1493
1549
  * @interface CallStateResponseFields
1494
1550
  */
1495
1551
  export interface CallStateResponseFields {
1496
- /**
1497
- *
1498
- * @type {Array<UserResponse>}
1499
- * @memberof CallStateResponseFields
1500
- */
1501
- blocked_users: Array<UserResponse>;
1502
1552
  /**
1503
1553
  *
1504
1554
  * @type {CallResponse}
@@ -2242,12 +2292,6 @@ export interface GeofenceSettingsRequest {
2242
2292
  * @interface GetCallResponse
2243
2293
  */
2244
2294
  export interface GetCallResponse {
2245
- /**
2246
- *
2247
- * @type {Array<UserResponse>}
2248
- * @memberof GetCallResponse
2249
- */
2250
- blocked_users: Array<UserResponse>;
2251
2295
  /**
2252
2296
  *
2253
2297
  * @type {CallResponse}
@@ -2386,12 +2430,6 @@ export interface GetOrCreateCallRequest {
2386
2430
  * @interface GetOrCreateCallResponse
2387
2431
  */
2388
2432
  export interface GetOrCreateCallResponse {
2389
- /**
2390
- *
2391
- * @type {Array<UserResponse>}
2392
- * @memberof GetOrCreateCallResponse
2393
- */
2394
- blocked_users: Array<UserResponse>;
2395
2433
  /**
2396
2434
  *
2397
2435
  * @type {CallResponse}
@@ -2628,12 +2666,6 @@ export interface JoinCallRequest {
2628
2666
  * @interface JoinCallResponse
2629
2667
  */
2630
2668
  export interface JoinCallResponse {
2631
- /**
2632
- *
2633
- * @type {Array<UserResponse>}
2634
- * @memberof JoinCallResponse
2635
- */
2636
- blocked_users: Array<UserResponse>;
2637
2669
  /**
2638
2670
  *
2639
2671
  * @type {CallResponse}
@@ -4020,12 +4052,6 @@ export interface UpdateCallRequest {
4020
4052
  * @interface UpdateCallResponse
4021
4053
  */
4022
4054
  export interface UpdateCallResponse {
4023
- /**
4024
- *
4025
- * @type {Array<UserResponse>}
4026
- * @memberof UpdateCallResponse
4027
- */
4028
- blocked_users: Array<UserResponse>;
4029
4055
  /**
4030
4056
  *
4031
4057
  * @type {CallResponse}
@@ -4354,6 +4380,10 @@ export type VideoEvent = ({
4354
4380
  } & UpdatedCallPermissionsEvent) | ({
4355
4381
  type: 'call.reaction_new';
4356
4382
  } & CallReactionEvent) | ({
4383
+ type: 'call.recording_failed';
4384
+ } & CallRecordingFailedEvent) | ({
4385
+ type: 'call.recording_ready';
4386
+ } & CallRecordingReadyEvent) | ({
4357
4387
  type: 'call.recording_started';
4358
4388
  } & CallRecordingStartedEvent) | ({
4359
4389
  type: 'call.recording_stopped';
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "0.3.19";
1
+ export declare const version = "0.3.21";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "0.3.19",
3
+ "version": "0.3.21",
4
4
  "packageManager": "yarn@3.2.4",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
@@ -3,7 +3,11 @@ import { beforeAll, describe, expect, it } from 'vitest';
3
3
  import { StreamVideoServerClient } from '../../StreamVideoServerClient';
4
4
  import { generateUUIDv4 } from '../../coordinator/connection/utils';
5
5
  import { LogLevel } from '../../coordinator/connection/types';
6
- import { OwnCapability, RecordSettingsModeEnum } from '../../gen/coordinator';
6
+ import {
7
+ OwnCapability,
8
+ RecordSettingsModeEnum,
9
+ RecordSettingsQualityEnum,
10
+ } from '../../gen/coordinator';
7
11
 
8
12
  const apiKey = process.env.STREAM_API_KEY!;
9
13
  const secret = process.env.STREAM_SECRET!;
@@ -95,6 +99,9 @@ describe('call types CRUD API', () => {
95
99
  audio: { mic_default_on: false, default_device: 'earpiece' },
96
100
  recording: {
97
101
  mode: RecordSettingsModeEnum.DISABLED,
102
+ // FIXME OL: these props shouldn't be required to be set when recording is disabled
103
+ audio_only: false,
104
+ quality: RecordSettingsQualityEnum._1080P,
98
105
  },
99
106
  },
100
107
  });
@@ -122,6 +122,7 @@ describe('call API', () => {
122
122
  recording: {
123
123
  audio_only: false,
124
124
  quality: RecordSettingsRequestQualityEnum._1080P,
125
+ mode: RecordSettingsRequestModeEnum.AUTO_ON,
125
126
  },
126
127
  },
127
128
  });
@@ -814,7 +814,7 @@ export interface CallReactionEvent {
814
814
  type: string;
815
815
  }
816
816
  /**
817
- *
817
+ * CallRecording represents a recording of a call.
818
818
  * @export
819
819
  * @interface CallRecording
820
820
  */
@@ -844,6 +844,62 @@ export interface CallRecording {
844
844
  */
845
845
  url: string;
846
846
  }
847
+ /**
848
+ * This event is sent when call recording has failed
849
+ * @export
850
+ * @interface CallRecordingFailedEvent
851
+ */
852
+ export interface CallRecordingFailedEvent {
853
+ /**
854
+ *
855
+ * @type {string}
856
+ * @memberof CallRecordingFailedEvent
857
+ */
858
+ call_cid: string;
859
+ /**
860
+ *
861
+ * @type {string}
862
+ * @memberof CallRecordingFailedEvent
863
+ */
864
+ created_at: string;
865
+ /**
866
+ * The type of event: "call.recording_failed" in this case
867
+ * @type {string}
868
+ * @memberof CallRecordingFailedEvent
869
+ */
870
+ type: string;
871
+ }
872
+ /**
873
+ * This event is sent when call recording is ready
874
+ * @export
875
+ * @interface CallRecordingReadyEvent
876
+ */
877
+ export interface CallRecordingReadyEvent {
878
+ /**
879
+ *
880
+ * @type {string}
881
+ * @memberof CallRecordingReadyEvent
882
+ */
883
+ call_cid: string;
884
+ /**
885
+ *
886
+ * @type {CallRecording}
887
+ * @memberof CallRecordingReadyEvent
888
+ */
889
+ call_recording: CallRecording;
890
+ /**
891
+ *
892
+ * @type {string}
893
+ * @memberof CallRecordingReadyEvent
894
+ */
895
+ created_at: string;
896
+ /**
897
+ * The type of event: "call.recording_ready" in this case
898
+ * @type {string}
899
+ * @memberof CallRecordingReadyEvent
900
+ */
901
+ type: string;
902
+ }
847
903
  /**
848
904
  * This event is sent when call recording has started
849
905
  * @export
@@ -1487,12 +1543,6 @@ export interface CallSettingsResponse {
1487
1543
  * @interface CallStateResponseFields
1488
1544
  */
1489
1545
  export interface CallStateResponseFields {
1490
- /**
1491
- *
1492
- * @type {Array<UserResponse>}
1493
- * @memberof CallStateResponseFields
1494
- */
1495
- blocked_users: Array<UserResponse>;
1496
1546
  /**
1497
1547
  *
1498
1548
  * @type {CallResponse}
@@ -2227,12 +2277,6 @@ export interface GeofenceSettingsRequest {
2227
2277
  * @interface GetCallResponse
2228
2278
  */
2229
2279
  export interface GetCallResponse {
2230
- /**
2231
- *
2232
- * @type {Array<UserResponse>}
2233
- * @memberof GetCallResponse
2234
- */
2235
- blocked_users: Array<UserResponse>;
2236
2280
  /**
2237
2281
  *
2238
2282
  * @type {CallResponse}
@@ -2369,12 +2413,6 @@ export interface GetOrCreateCallRequest {
2369
2413
  * @interface GetOrCreateCallResponse
2370
2414
  */
2371
2415
  export interface GetOrCreateCallResponse {
2372
- /**
2373
- *
2374
- * @type {Array<UserResponse>}
2375
- * @memberof GetOrCreateCallResponse
2376
- */
2377
- blocked_users: Array<UserResponse>;
2378
2416
  /**
2379
2417
  *
2380
2418
  * @type {CallResponse}
@@ -2611,12 +2649,6 @@ export interface JoinCallRequest {
2611
2649
  * @interface JoinCallResponse
2612
2650
  */
2613
2651
  export interface JoinCallResponse {
2614
- /**
2615
- *
2616
- * @type {Array<UserResponse>}
2617
- * @memberof JoinCallResponse
2618
- */
2619
- blocked_users: Array<UserResponse>;
2620
2652
  /**
2621
2653
  *
2622
2654
  * @type {CallResponse}
@@ -4001,12 +4033,6 @@ export interface UpdateCallRequest {
4001
4033
  * @interface UpdateCallResponse
4002
4034
  */
4003
4035
  export interface UpdateCallResponse {
4004
- /**
4005
- *
4006
- * @type {Array<UserResponse>}
4007
- * @memberof UpdateCallResponse
4008
- */
4009
- blocked_users: Array<UserResponse>;
4010
4036
  /**
4011
4037
  *
4012
4038
  * @type {CallResponse}
@@ -4314,6 +4340,8 @@ export type VideoEvent =
4314
4340
  | ({ type: 'call.permission_request' } & PermissionRequestEvent)
4315
4341
  | ({ type: 'call.permissions_updated' } & UpdatedCallPermissionsEvent)
4316
4342
  | ({ type: 'call.reaction_new' } & CallReactionEvent)
4343
+ | ({ type: 'call.recording_failed' } & CallRecordingFailedEvent)
4344
+ | ({ type: 'call.recording_ready' } & CallRecordingReadyEvent)
4317
4345
  | ({ type: 'call.recording_started' } & CallRecordingStartedEvent)
4318
4346
  | ({ type: 'call.recording_stopped' } & CallRecordingStoppedEvent)
4319
4347
  | ({ type: 'call.rejected' } & CallRejectedEvent)
@@ -152,6 +152,14 @@ export class DynascaleManager {
152
152
  debounceType: DebounceType,
153
153
  dimension: VideoDimension | undefined,
154
154
  ) => {
155
+ if (dimension && (dimension.width === 0 || dimension.height === 0)) {
156
+ // ignore 0x0 dimensions. this can happen when the video element
157
+ // is not visible (e.g., has display: none).
158
+ // we treat this as "unsubscription" as we don't want to keep
159
+ // consuming bandwidth for a video that is not visible on the screen.
160
+ this.logger('debug', `Ignoring 0x0 dimension`, boundParticipant);
161
+ dimension = undefined;
162
+ }
155
163
  this.call.updateSubscriptionsPartial(
156
164
  trackType,
157
165
  { [sessionId]: { dimension } },
@@ -171,6 +179,12 @@ export class DynascaleManager {
171
179
  shareReplay(1),
172
180
  );
173
181
 
182
+ /**
183
+ * Since the video elements are now being removed from the DOM (React SDK) upon
184
+ * visibility change, this subscription is not in use an stays here only for the
185
+ * plain JS integrations where integrators might choose not to remove the video
186
+ * elements from the DOM.
187
+ */
174
188
  // keep copy for resize observer handler
175
189
  let viewportVisibilityState: VisibilityState | undefined;
176
190
  const viewportVisibilityStateSubscription =
@@ -231,6 +245,8 @@ export class DynascaleManager {
231
245
  });
232
246
  resizeObserver?.observe(videoElement);
233
247
 
248
+ // element renders and gets bound - track subscription gets
249
+ // triggered first other ones get skipped on initial subscriptions
234
250
  const publishedTracksSubscription = boundParticipant.isLocalParticipant
235
251
  ? null
236
252
  : participant$
@@ -248,13 +264,13 @@ export class DynascaleManager {
248
264
  .subscribe((isPublishing) => {
249
265
  if (isPublishing) {
250
266
  // the participant just started to publish a track
251
- requestTrackWithDimensions(DebounceType.IMMEDIATE, {
267
+ requestTrackWithDimensions(DebounceType.FAST, {
252
268
  width: videoElement.clientWidth,
253
269
  height: videoElement.clientHeight,
254
270
  });
255
271
  } else {
256
272
  // the participant just stopped publishing a track
257
- requestTrackWithDimensions(DebounceType.IMMEDIATE, undefined);
273
+ requestTrackWithDimensions(DebounceType.FAST, undefined);
258
274
  }
259
275
  });
260
276
 
@@ -286,7 +302,7 @@ export class DynascaleManager {
286
302
  videoElement.muted = true;
287
303
 
288
304
  return () => {
289
- requestTrackWithDimensions(DebounceType.IMMEDIATE, undefined);
305
+ requestTrackWithDimensions(DebounceType.FAST, undefined);
290
306
  viewportVisibilityStateSubscription?.unsubscribe();
291
307
  publishedTracksSubscription?.unsubscribe();
292
308
  streamSubscription.unsubscribe();
@@ -4,7 +4,7 @@
4
4
 
5
5
  import '../../rtc/__tests__/mocks/webrtc.mocks';
6
6
 
7
- import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
7
+ import { afterEach, beforeEach, describe, expect, it, Mock, vi } from 'vitest';
8
8
  import { DynascaleManager } from '../DynascaleManager';
9
9
  import { Call } from '../../Call';
10
10
  import { StreamClient } from '../../coordinator/connection/client';
@@ -195,7 +195,7 @@ describe('DynascaleManager', () => {
195
195
  expect(updateSubscription).toHaveBeenCalledWith(
196
196
  'videoTrack',
197
197
  { 'session-id': { dimension: undefined } },
198
- DebounceType.IMMEDIATE,
198
+ DebounceType.FAST,
199
199
  );
200
200
 
201
201
  call.state.updateParticipant('session-id', {
@@ -212,7 +212,7 @@ describe('DynascaleManager', () => {
212
212
  },
213
213
  },
214
214
  },
215
- DebounceType.IMMEDIATE,
215
+ DebounceType.FAST,
216
216
  );
217
217
 
218
218
  call.state.updateParticipant('session-id', {
@@ -222,7 +222,7 @@ describe('DynascaleManager', () => {
222
222
  expect(updateSubscription).toHaveBeenCalledWith(
223
223
  'videoTrack',
224
224
  { 'session-id': { dimension: undefined } },
225
- DebounceType.IMMEDIATE,
225
+ DebounceType.FAST,
226
226
  );
227
227
 
228
228
  cleanup?.();
@@ -230,7 +230,7 @@ describe('DynascaleManager', () => {
230
230
  expect(updateSubscription).toHaveBeenCalledWith(
231
231
  'videoTrack',
232
232
  { 'session-id': { dimension: undefined } },
233
- DebounceType.IMMEDIATE,
233
+ DebounceType.FAST,
234
234
  );
235
235
  });
236
236
 
@@ -271,7 +271,7 @@ describe('DynascaleManager', () => {
271
271
  },
272
272
  },
273
273
  },
274
- DebounceType.IMMEDIATE,
274
+ DebounceType.FAST,
275
275
  );
276
276
  expect(play).toHaveBeenCalled();
277
277
  expect(videoElement.srcObject).toBe(mediaStream);
@@ -281,7 +281,7 @@ describe('DynascaleManager', () => {
281
281
  expect(updateSubscription).toHaveBeenCalledWith(
282
282
  'videoTrack',
283
283
  { 'session-id': { dimension: undefined } },
284
- DebounceType.IMMEDIATE,
284
+ DebounceType.FAST,
285
285
  );
286
286
  });
287
287
 
@@ -308,7 +308,7 @@ describe('DynascaleManager', () => {
308
308
  expect(updateSubscription).toHaveBeenCalledWith(
309
309
  'videoTrack',
310
310
  { 'session-id': { dimension: undefined } },
311
- DebounceType.IMMEDIATE,
311
+ DebounceType.FAST,
312
312
  );
313
313
 
314
314
  call.state.updateParticipant('session-id', {
@@ -369,7 +369,7 @@ describe('DynascaleManager', () => {
369
369
  expect(updateSubscription).toHaveBeenCalledWith(
370
370
  'videoTrack',
371
371
  { 'session-id': { dimension: undefined } },
372
- DebounceType.IMMEDIATE,
372
+ DebounceType.FAST,
373
373
  );
374
374
  });
375
375
 
@@ -417,7 +417,7 @@ describe('DynascaleManager', () => {
417
417
  },
418
418
  },
419
419
  },
420
- DebounceType.IMMEDIATE,
420
+ DebounceType.FAST,
421
421
  );
422
422
 
423
423
  // @ts-ignore simulate resize
@@ -439,7 +439,47 @@ describe('DynascaleManager', () => {
439
439
  expect(updateSubscription).toHaveBeenCalledWith(
440
440
  'videoTrack',
441
441
  { 'session-id': { dimension: undefined } },
442
- DebounceType.IMMEDIATE,
442
+ DebounceType.FAST,
443
+ );
444
+ });
445
+
446
+ it('video: should unsubscribe when element dimensions are zero', () => {
447
+ // @ts-ignore
448
+ call.state.updateOrAddParticipant('session-id', {
449
+ userId: 'user-id',
450
+ sessionId: 'session-id',
451
+ publishedTracks: [TrackType.VIDEO],
452
+ viewportVisibilityState: {
453
+ videoTrack: VisibilityState.VISIBLE,
454
+ screenShareTrack: VisibilityState.UNKNOWN,
455
+ },
456
+ });
457
+
458
+ let updateSubscription = vi.spyOn(call, 'updateSubscriptionsPartial');
459
+
460
+ // @ts-ignore simulate resize
461
+ videoElement.clientHeight = 0;
462
+ // @ts-ignore simulate resize
463
+ videoElement.clientWidth = 0;
464
+
465
+ const cleanup = dynascaleManager.bindVideoElement(
466
+ videoElement,
467
+ 'session-id',
468
+ 'videoTrack',
469
+ );
470
+
471
+ expect(updateSubscription).toHaveBeenCalledWith(
472
+ 'videoTrack',
473
+ { 'session-id': { dimension: undefined } },
474
+ DebounceType.FAST,
475
+ );
476
+
477
+ cleanup?.();
478
+
479
+ expect(updateSubscription).toHaveBeenLastCalledWith(
480
+ 'videoTrack',
481
+ { 'session-id': { dimension: undefined } },
482
+ DebounceType.FAST,
443
483
  );
444
484
  });
445
485
  });
@@ -382,6 +382,8 @@ export class CallState {
382
382
  'connection.error': undefined,
383
383
  'connection.ok': undefined,
384
384
  'health.check': undefined,
385
+ 'call.recording_failed': undefined,
386
+ 'call.recording_ready': undefined,
385
387
  custom: undefined,
386
388
 
387
389
  // events that update call state: