@stream-io/video-client 1.7.1 → 1.7.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.
@@ -2,29 +2,21 @@ import { Observable } from 'rxjs';
2
2
  import { Call } from '../Call';
3
3
  import { CameraDirection, CameraManagerState } from './CameraManagerState';
4
4
  import { InputMediaDeviceManager } from './InputMediaDeviceManager';
5
- import { PublishOptions } from '../types';
6
- type PreferredCodec = 'vp8' | 'h264' | string;
5
+ import { PreferredCodec, PublishOptions } from '../types';
7
6
  export declare class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
8
7
  private targetResolution;
9
8
  /**
10
- * The preferred codec for encoding the video.
9
+ * The options to use when publishing the video stream.
11
10
  *
12
- * @internal internal use only, not part of the public API.
11
+ * @internal
13
12
  */
14
- preferredCodec: PreferredCodec | undefined;
13
+ publishOptions: PublishOptions | undefined;
15
14
  /**
16
- * The preferred bitrate for encoding the video.
15
+ * Constructs a new CameraManager.
17
16
  *
18
- * @internal internal use only, not part of the public API.
17
+ * @param call the call instance.
19
18
  */
20
- preferredBitrate: number | undefined;
21
19
  constructor(call: Call);
22
- /**
23
- * The publish options for the camera.
24
- *
25
- * @internal internal use only, not part of the public API.
26
- */
27
- get publishOptions(): PublishOptions;
28
20
  /**
29
21
  * Select the camera direction.
30
22
  *
@@ -51,17 +43,24 @@ export declare class CameraManager extends InputMediaDeviceManager<CameraManager
51
43
  * @internal internal use only, not part of the public API.
52
44
  * @param codec the codec to use for encoding the video.
53
45
  */
54
- setPreferredCodec(codec: 'vp8' | 'h264' | string | undefined): void;
46
+ setPreferredCodec(codec: PreferredCodec | undefined): void;
55
47
  /**
56
- * Sets the preferred bitrate for encoding the video.
48
+ * Updates the preferred publish options for the video stream.
57
49
  *
58
- * @internal internal use only, not part of the public API.
59
- * @param bitrate the bitrate to use for encoding the video.
50
+ * @internal
51
+ * @param options the options to use.
52
+ */
53
+ updatePublishOptions(options: PublishOptions): void;
54
+ /**
55
+ * Returns the capture resolution of the camera.
60
56
  */
61
- setPreferredBitrate(bitrate: number | undefined): void;
57
+ getCaptureResolution(): {
58
+ width: number | undefined;
59
+ height: number | undefined;
60
+ frameRate: number | undefined;
61
+ } | undefined;
62
62
  protected getDevices(): Observable<MediaDeviceInfo[]>;
63
63
  protected getStream(constraints: MediaTrackConstraints): Promise<MediaStream>;
64
64
  protected publishStream(stream: MediaStream): Promise<void>;
65
65
  protected stopPublishStream(stopTracks: boolean): Promise<void>;
66
66
  }
67
- export {};
@@ -1,4 +1,4 @@
1
- import { ScreenShareSettings } from '../types';
1
+ import { PublishOptions } from '../types';
2
2
  import { TargetResolutionResponse } from '../gen/shims';
3
3
  export type OptimalVideoLayer = RTCRtpEncodingParameters & {
4
4
  width: number;
@@ -10,9 +10,9 @@ export type OptimalVideoLayer = RTCRtpEncodingParameters & {
10
10
  *
11
11
  * @param videoTrack the video track to find optimal layers for.
12
12
  * @param targetResolution the expected target resolution.
13
- * @param preferredBitrate the preferred bitrate for the video track.
13
+ * @param publishOptions the publish options for the track.
14
14
  */
15
- export declare const findOptimalVideoLayers: (videoTrack: MediaStreamTrack, targetResolution: TargetResolutionResponse | undefined, preferredBitrate: number | undefined) => OptimalVideoLayer[];
15
+ export declare const findOptimalVideoLayers: (videoTrack: MediaStreamTrack, targetResolution?: TargetResolutionResponse, publishOptions?: PublishOptions) => OptimalVideoLayer[];
16
16
  /**
17
17
  * Computes the maximum bitrate for a given resolution.
18
18
  * If the current resolution is lower than the target resolution,
@@ -26,4 +26,4 @@ export declare const findOptimalVideoLayers: (videoTrack: MediaStreamTrack, targ
26
26
  * @param preferredBitrate the preferred bitrate for the track.
27
27
  */
28
28
  export declare const getComputedMaxBitrate: (targetResolution: TargetResolutionResponse, currentWidth: number, currentHeight: number, preferredBitrate: number | undefined) => number;
29
- export declare const findOptimalScreenSharingLayers: (videoTrack: MediaStreamTrack, preferences?: ScreenShareSettings, defaultMaxBitrate?: number) => OptimalVideoLayer[];
29
+ export declare const findOptimalScreenSharingLayers: (videoTrack: MediaStreamTrack, publishOptions?: PublishOptions, defaultMaxBitrate?: number) => OptimalVideoLayer[];
@@ -109,9 +109,15 @@ export type SubscriptionChange = {
109
109
  export type SubscriptionChanges = {
110
110
  [sessionId: string]: SubscriptionChange;
111
111
  };
112
+ /**
113
+ * A preferred codec to use when publishing a video track.
114
+ * @internal
115
+ */
116
+ export type PreferredCodec = 'vp8' | 'h264' | string;
112
117
  export type PublishOptions = {
113
- preferredCodec?: string | null;
118
+ preferredCodec?: PreferredCodec | null;
114
119
  preferredBitrate?: number;
120
+ bitrateDownscaleFactor?: number;
115
121
  screenShareSettings?: ScreenShareSettings;
116
122
  };
117
123
  export type ScreenShareSettings = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "1.7.1",
3
+ "version": "1.7.2",
4
4
  "packageManager": "yarn@3.2.4",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.es.js",
@@ -4,9 +4,7 @@ import { CameraDirection, CameraManagerState } from './CameraManagerState';
4
4
  import { InputMediaDeviceManager } from './InputMediaDeviceManager';
5
5
  import { getVideoDevices, getVideoStream } from './devices';
6
6
  import { TrackType } from '../gen/video/sfu/models/models';
7
- import { PublishOptions } from '../types';
8
-
9
- type PreferredCodec = 'vp8' | 'h264' | string;
7
+ import { PreferredCodec, PublishOptions } from '../types';
10
8
 
11
9
  export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
12
10
  private targetResolution = {
@@ -15,35 +13,21 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
15
13
  };
16
14
 
17
15
  /**
18
- * The preferred codec for encoding the video.
16
+ * The options to use when publishing the video stream.
19
17
  *
20
- * @internal internal use only, not part of the public API.
18
+ * @internal
21
19
  */
22
- preferredCodec: PreferredCodec | undefined;
20
+ publishOptions: PublishOptions | undefined;
23
21
 
24
22
  /**
25
- * The preferred bitrate for encoding the video.
23
+ * Constructs a new CameraManager.
26
24
  *
27
- * @internal internal use only, not part of the public API.
25
+ * @param call the call instance.
28
26
  */
29
- preferredBitrate: number | undefined;
30
-
31
27
  constructor(call: Call) {
32
28
  super(call, new CameraManagerState(), TrackType.VIDEO);
33
29
  }
34
30
 
35
- /**
36
- * The publish options for the camera.
37
- *
38
- * @internal internal use only, not part of the public API.
39
- */
40
- get publishOptions(): PublishOptions {
41
- return {
42
- preferredCodec: this.preferredCodec,
43
- preferredBitrate: this.preferredBitrate,
44
- };
45
- }
46
-
47
31
  /**
48
32
  * Select the camera direction.
49
33
  *
@@ -104,18 +88,36 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
104
88
  * @internal internal use only, not part of the public API.
105
89
  * @param codec the codec to use for encoding the video.
106
90
  */
107
- setPreferredCodec(codec: 'vp8' | 'h264' | string | undefined) {
108
- this.preferredCodec = codec;
91
+ setPreferredCodec(codec: PreferredCodec | undefined) {
92
+ this.updatePublishOptions({ preferredCodec: codec });
109
93
  }
110
94
 
111
95
  /**
112
- * Sets the preferred bitrate for encoding the video.
96
+ * Updates the preferred publish options for the video stream.
113
97
  *
114
- * @internal internal use only, not part of the public API.
115
- * @param bitrate the bitrate to use for encoding the video.
98
+ * @internal
99
+ * @param options the options to use.
116
100
  */
117
- setPreferredBitrate(bitrate: number | undefined) {
118
- this.preferredBitrate = bitrate;
101
+ updatePublishOptions(options: PublishOptions) {
102
+ this.publishOptions = { ...this.publishOptions, ...options };
103
+ }
104
+
105
+ /**
106
+ * Returns the capture resolution of the camera.
107
+ */
108
+ getCaptureResolution() {
109
+ const { mediaStream } = this.state;
110
+ if (!mediaStream) return;
111
+
112
+ const [videoTrack] = mediaStream.getVideoTracks();
113
+ if (!videoTrack) return;
114
+
115
+ const settings = videoTrack.getSettings();
116
+ return {
117
+ width: settings.width,
118
+ height: settings.height,
119
+ frameRate: settings.frameRate,
120
+ };
119
121
  }
120
122
 
121
123
  protected getDevices(): Observable<MediaDeviceInfo[]> {
@@ -82,9 +82,7 @@ describe('CameraManager', () => {
82
82
 
83
83
  expect(manager['call'].publishVideoStream).toHaveBeenCalledWith(
84
84
  manager.state.mediaStream,
85
- {
86
- preferredCodec: undefined,
87
- },
85
+ undefined,
88
86
  );
89
87
  });
90
88
 
@@ -259,16 +259,11 @@ export class Publisher {
259
259
  const screenShareBitrate =
260
260
  settings?.screensharing.target_resolution?.bitrate;
261
261
 
262
- const { preferredBitrate, preferredCodec, screenShareSettings } = opts;
263
262
  const videoEncodings =
264
263
  trackType === TrackType.VIDEO
265
- ? findOptimalVideoLayers(track, targetResolution, preferredBitrate)
264
+ ? findOptimalVideoLayers(track, targetResolution, opts)
266
265
  : trackType === TrackType.SCREEN_SHARE
267
- ? findOptimalScreenSharingLayers(
268
- track,
269
- screenShareSettings,
270
- screenShareBitrate,
271
- )
266
+ ? findOptimalScreenSharingLayers(track, opts, screenShareBitrate)
272
267
  : undefined;
273
268
 
274
269
  // listen for 'ended' event on the track as it might be ended abruptly
@@ -293,6 +288,7 @@ export class Publisher {
293
288
  this.transceiverRegistry[trackType] = transceiver;
294
289
  this.publishOptionsPerTrackType.set(trackType, opts);
295
290
 
291
+ const { preferredCodec } = opts;
296
292
  const codec =
297
293
  isReactNative() && trackType === TrackType.VIDEO && !preferredCodec
298
294
  ? getRNOptimalCodec()
@@ -713,16 +709,9 @@ export class Publisher {
713
709
  const publishOpts = this.publishOptionsPerTrackType.get(trackType);
714
710
  optimalLayers =
715
711
  trackType === TrackType.VIDEO
716
- ? findOptimalVideoLayers(
717
- track,
718
- targetResolution,
719
- publishOpts?.preferredBitrate,
720
- )
712
+ ? findOptimalVideoLayers(track, targetResolution, publishOpts)
721
713
  : trackType === TrackType.SCREEN_SHARE
722
- ? findOptimalScreenSharingLayers(
723
- track,
724
- publishOpts?.screenShareSettings,
725
- )
714
+ ? findOptimalScreenSharingLayers(track, publishOpts)
726
715
  : [];
727
716
  this.trackLayersCache[trackType] = optimalLayers;
728
717
  } else {
@@ -1,4 +1,4 @@
1
- import { ScreenShareSettings } from '../types';
1
+ import { PublishOptions } from '../types';
2
2
  import { TargetResolutionResponse } from '../gen/shims';
3
3
 
4
4
  export type OptimalVideoLayer = RTCRtpEncodingParameters & {
@@ -25,17 +25,17 @@ const defaultBitratePerRid: Record<string, number> = {
25
25
  *
26
26
  * @param videoTrack the video track to find optimal layers for.
27
27
  * @param targetResolution the expected target resolution.
28
- * @param preferredBitrate the preferred bitrate for the video track.
28
+ * @param publishOptions the publish options for the track.
29
29
  */
30
30
  export const findOptimalVideoLayers = (
31
31
  videoTrack: MediaStreamTrack,
32
32
  targetResolution: TargetResolutionResponse = defaultTargetResolution,
33
- preferredBitrate: number | undefined,
33
+ publishOptions?: PublishOptions,
34
34
  ) => {
35
35
  const optimalVideoLayers: OptimalVideoLayer[] = [];
36
36
  const settings = videoTrack.getSettings();
37
37
  const { width: w = 0, height: h = 0 } = settings;
38
-
38
+ const { preferredBitrate, bitrateDownscaleFactor = 2 } = publishOptions || {};
39
39
  const maxBitrate = getComputedMaxBitrate(
40
40
  targetResolution,
41
41
  w,
@@ -43,6 +43,7 @@ export const findOptimalVideoLayers = (
43
43
  preferredBitrate,
44
44
  );
45
45
  let downscaleFactor = 1;
46
+ let bitrateFactor = 1;
46
47
  ['f', 'h', 'q'].forEach((rid) => {
47
48
  // Reversing the order [f, h, q] to [q, h, f] as Chrome uses encoding index
48
49
  // when deciding which layer to disable when CPU or bandwidth is constrained.
@@ -53,11 +54,12 @@ export const findOptimalVideoLayers = (
53
54
  width: Math.round(w / downscaleFactor),
54
55
  height: Math.round(h / downscaleFactor),
55
56
  maxBitrate:
56
- Math.round(maxBitrate / downscaleFactor) || defaultBitratePerRid[rid],
57
+ Math.round(maxBitrate / bitrateFactor) || defaultBitratePerRid[rid],
57
58
  scaleResolutionDownBy: downscaleFactor,
58
59
  maxFramerate: 30,
59
60
  });
60
61
  downscaleFactor *= 2;
62
+ bitrateFactor *= bitrateDownscaleFactor;
61
63
  });
62
64
 
63
65
  // for simplicity, we start with all layers enabled, then this function
@@ -135,9 +137,10 @@ const withSimulcastConstraints = (
135
137
 
136
138
  export const findOptimalScreenSharingLayers = (
137
139
  videoTrack: MediaStreamTrack,
138
- preferences?: ScreenShareSettings,
140
+ publishOptions?: PublishOptions,
139
141
  defaultMaxBitrate = 3000000,
140
142
  ): OptimalVideoLayer[] => {
143
+ const { screenShareSettings: preferences } = publishOptions || {};
141
144
  const settings = videoTrack.getSettings();
142
145
  return [
143
146
  {
package/src/types.ts CHANGED
@@ -146,9 +146,16 @@ export type SubscriptionChanges = {
146
146
  [sessionId: string]: SubscriptionChange;
147
147
  };
148
148
 
149
+ /**
150
+ * A preferred codec to use when publishing a video track.
151
+ * @internal
152
+ */
153
+ export type PreferredCodec = 'vp8' | 'h264' | string;
154
+
149
155
  export type PublishOptions = {
150
- preferredCodec?: string | null;
156
+ preferredCodec?: PreferredCodec | null;
151
157
  preferredBitrate?: number;
158
+ bitrateDownscaleFactor?: number;
152
159
  screenShareSettings?: ScreenShareSettings;
153
160
  };
154
161