@stream-io/video-client 0.3.20 → 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.
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const version = "0.3.20";
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.20",
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",
@@ -120,9 +120,9 @@ describe('call API', () => {
120
120
  response = await call.update({
121
121
  settings_override: {
122
122
  recording: {
123
- mode: RecordSettingsRequestModeEnum.AVAILABLE,
124
123
  audio_only: false,
125
124
  quality: RecordSettingsRequestQualityEnum._1080P,
125
+ mode: RecordSettingsRequestModeEnum.AUTO_ON,
126
126
  },
127
127
  },
128
128
  });
@@ -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
  });