@stream-io/video-client 1.6.2 → 1.6.4
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/CHANGELOG.md +14 -0
- package/dist/index.browser.es.js +124 -101
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +124 -101
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +124 -101
- package/dist/index.es.js.map +1 -1
- package/dist/src/devices/CameraManager.d.ts +20 -0
- package/dist/src/rtc/codecs.d.ts +4 -0
- package/dist/src/rtc/videoLayers.d.ts +4 -2
- package/dist/src/types.d.ts +1 -0
- package/package.json +1 -1
- package/src/Call.ts +8 -6
- package/src/StreamVideoClient.ts +2 -1
- package/src/devices/CameraManager.ts +31 -3
- package/src/rtc/Publisher.ts +15 -19
- package/src/rtc/__tests__/videoLayers.test.ts +36 -6
- package/src/rtc/codecs.ts +15 -0
- package/src/rtc/videoLayers.ts +18 -4
- package/src/types.ts +1 -0
|
@@ -2,6 +2,7 @@ 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';
|
|
5
6
|
type PreferredCodec = 'vp8' | 'h264' | string;
|
|
6
7
|
export declare class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
7
8
|
private targetResolution;
|
|
@@ -11,7 +12,19 @@ export declare class CameraManager extends InputMediaDeviceManager<CameraManager
|
|
|
11
12
|
* @internal internal use only, not part of the public API.
|
|
12
13
|
*/
|
|
13
14
|
preferredCodec: PreferredCodec | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* The preferred bitrate for encoding the video.
|
|
17
|
+
*
|
|
18
|
+
* @internal internal use only, not part of the public API.
|
|
19
|
+
*/
|
|
20
|
+
preferredBitrate: number | undefined;
|
|
14
21
|
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;
|
|
15
28
|
/**
|
|
16
29
|
* Select the camera direction.
|
|
17
30
|
*
|
|
@@ -39,6 +52,13 @@ export declare class CameraManager extends InputMediaDeviceManager<CameraManager
|
|
|
39
52
|
* @param codec the codec to use for encoding the video.
|
|
40
53
|
*/
|
|
41
54
|
setPreferredCodec(codec: 'vp8' | 'h264' | string | undefined): void;
|
|
55
|
+
/**
|
|
56
|
+
* Sets the preferred bitrate for encoding the video.
|
|
57
|
+
*
|
|
58
|
+
* @internal internal use only, not part of the public API.
|
|
59
|
+
* @param bitrate the bitrate to use for encoding the video.
|
|
60
|
+
*/
|
|
61
|
+
setPreferredBitrate(bitrate: number | undefined): void;
|
|
42
62
|
protected getDevices(): Observable<MediaDeviceInfo[]>;
|
|
43
63
|
protected getStream(constraints: MediaTrackConstraints): Promise<MediaStream>;
|
|
44
64
|
protected publishStream(stream: MediaStream): Promise<void>;
|
package/dist/src/rtc/codecs.d.ts
CHANGED
|
@@ -14,3 +14,7 @@ export declare const getPreferredCodecs: (kind: "audio" | "video", preferredCode
|
|
|
14
14
|
* @param direction the direction of the transceiver.
|
|
15
15
|
*/
|
|
16
16
|
export declare const getGenericSdp: (direction: RTCRtpTransceiverDirection) => Promise<string>;
|
|
17
|
+
/**
|
|
18
|
+
* Returns the optimal codec for RN.
|
|
19
|
+
*/
|
|
20
|
+
export declare const getRNOptimalCodec: () => "h264" | "vp8" | undefined;
|
|
@@ -10,8 +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
14
|
*/
|
|
14
|
-
export declare const findOptimalVideoLayers: (videoTrack: MediaStreamTrack, targetResolution
|
|
15
|
+
export declare const findOptimalVideoLayers: (videoTrack: MediaStreamTrack, targetResolution: TargetResolutionResponse | undefined, preferredBitrate: number | undefined) => OptimalVideoLayer[];
|
|
15
16
|
/**
|
|
16
17
|
* Computes the maximum bitrate for a given resolution.
|
|
17
18
|
* If the current resolution is lower than the target resolution,
|
|
@@ -22,6 +23,7 @@ export declare const findOptimalVideoLayers: (videoTrack: MediaStreamTrack, targ
|
|
|
22
23
|
* @param targetResolution the target resolution.
|
|
23
24
|
* @param currentWidth the current width of the track.
|
|
24
25
|
* @param currentHeight the current height of the track.
|
|
26
|
+
* @param preferredBitrate the preferred bitrate for the track.
|
|
25
27
|
*/
|
|
26
|
-
export declare const getComputedMaxBitrate: (targetResolution: TargetResolutionResponse, currentWidth: number, currentHeight: number) => number;
|
|
28
|
+
export declare const getComputedMaxBitrate: (targetResolution: TargetResolutionResponse, currentWidth: number, currentHeight: number, preferredBitrate: number | undefined) => number;
|
|
27
29
|
export declare const findOptimalScreenSharingLayers: (videoTrack: MediaStreamTrack, preferences?: ScreenShareSettings, defaultMaxBitrate?: number) => OptimalVideoLayer[];
|
package/dist/src/types.d.ts
CHANGED
package/package.json
CHANGED
package/src/Call.ts
CHANGED
|
@@ -1324,9 +1324,10 @@ export class Call {
|
|
|
1324
1324
|
case TrackType.VIDEO:
|
|
1325
1325
|
const videoStream = this.camera.state.mediaStream;
|
|
1326
1326
|
if (videoStream) {
|
|
1327
|
-
await this.publishVideoStream(
|
|
1328
|
-
|
|
1329
|
-
|
|
1327
|
+
await this.publishVideoStream(
|
|
1328
|
+
videoStream,
|
|
1329
|
+
this.camera.publishOptions,
|
|
1330
|
+
);
|
|
1330
1331
|
}
|
|
1331
1332
|
break;
|
|
1332
1333
|
case TrackType.SCREEN_SHARE:
|
|
@@ -2209,9 +2210,10 @@ export class Call {
|
|
|
2209
2210
|
this.camera.state.mediaStream &&
|
|
2210
2211
|
!this.publisher?.isPublishing(TrackType.VIDEO)
|
|
2211
2212
|
) {
|
|
2212
|
-
await this.publishVideoStream(
|
|
2213
|
-
|
|
2214
|
-
|
|
2213
|
+
await this.publishVideoStream(
|
|
2214
|
+
this.camera.state.mediaStream,
|
|
2215
|
+
this.camera.publishOptions,
|
|
2216
|
+
);
|
|
2215
2217
|
}
|
|
2216
2218
|
|
|
2217
2219
|
// Start camera if backend config specifies, and there is no local setting
|
package/src/StreamVideoClient.ts
CHANGED
|
@@ -320,6 +320,7 @@ export class StreamVideoClient {
|
|
|
320
320
|
return;
|
|
321
321
|
}
|
|
322
322
|
const userId = this.streamClient.user?.id;
|
|
323
|
+
const apiKey = this.streamClient.key;
|
|
323
324
|
const disconnectUser = () => this.streamClient.disconnectUser(timeout);
|
|
324
325
|
this.disconnectionPromise = this.connectionPromise
|
|
325
326
|
? this.connectionPromise.then(() => disconnectUser())
|
|
@@ -329,7 +330,7 @@ export class StreamVideoClient {
|
|
|
329
330
|
);
|
|
330
331
|
await this.disconnectionPromise;
|
|
331
332
|
if (userId) {
|
|
332
|
-
StreamVideoClient._instanceMap.delete(userId);
|
|
333
|
+
StreamVideoClient._instanceMap.delete(apiKey + userId);
|
|
333
334
|
}
|
|
334
335
|
this.eventHandlersToUnregister.forEach((unregister) => unregister());
|
|
335
336
|
this.eventHandlersToUnregister = [];
|
|
@@ -4,6 +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';
|
|
7
8
|
|
|
8
9
|
type PreferredCodec = 'vp8' | 'h264' | string;
|
|
9
10
|
|
|
@@ -20,10 +21,29 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
20
21
|
*/
|
|
21
22
|
preferredCodec: PreferredCodec | undefined;
|
|
22
23
|
|
|
24
|
+
/**
|
|
25
|
+
* The preferred bitrate for encoding the video.
|
|
26
|
+
*
|
|
27
|
+
* @internal internal use only, not part of the public API.
|
|
28
|
+
*/
|
|
29
|
+
preferredBitrate: number | undefined;
|
|
30
|
+
|
|
23
31
|
constructor(call: Call) {
|
|
24
32
|
super(call, new CameraManagerState(), TrackType.VIDEO);
|
|
25
33
|
}
|
|
26
34
|
|
|
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
|
+
|
|
27
47
|
/**
|
|
28
48
|
* Select the camera direction.
|
|
29
49
|
*
|
|
@@ -88,6 +108,16 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
88
108
|
this.preferredCodec = codec;
|
|
89
109
|
}
|
|
90
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Sets the preferred bitrate for encoding the video.
|
|
113
|
+
*
|
|
114
|
+
* @internal internal use only, not part of the public API.
|
|
115
|
+
* @param bitrate the bitrate to use for encoding the video.
|
|
116
|
+
*/
|
|
117
|
+
setPreferredBitrate(bitrate: number | undefined) {
|
|
118
|
+
this.preferredBitrate = bitrate;
|
|
119
|
+
}
|
|
120
|
+
|
|
91
121
|
protected getDevices(): Observable<MediaDeviceInfo[]> {
|
|
92
122
|
return getVideoDevices();
|
|
93
123
|
}
|
|
@@ -107,9 +137,7 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
107
137
|
}
|
|
108
138
|
|
|
109
139
|
protected publishStream(stream: MediaStream): Promise<void> {
|
|
110
|
-
return this.call.publishVideoStream(stream,
|
|
111
|
-
preferredCodec: this.preferredCodec,
|
|
112
|
-
});
|
|
140
|
+
return this.call.publishVideoStream(stream, this.publishOptions);
|
|
113
141
|
}
|
|
114
142
|
|
|
115
143
|
protected stopPublishStream(stopTracks: boolean): Promise<void> {
|
package/src/rtc/Publisher.ts
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
findOptimalVideoLayers,
|
|
14
14
|
OptimalVideoLayer,
|
|
15
15
|
} from './videoLayers';
|
|
16
|
-
import { getPreferredCodecs } from './codecs';
|
|
16
|
+
import { getPreferredCodecs, getRNOptimalCodec } from './codecs';
|
|
17
17
|
import { trackTypeToParticipantStreamKey } from './helpers/tracks';
|
|
18
18
|
import { CallingState, CallState } from '../store';
|
|
19
19
|
import { PublishOptions } from '../types';
|
|
@@ -22,7 +22,6 @@ import { enableHighQualityAudio, toggleDtx } from '../helpers/sdp-munging';
|
|
|
22
22
|
import { Logger } from '../coordinator/connection/types';
|
|
23
23
|
import { getLogger } from '../logger';
|
|
24
24
|
import { Dispatcher } from './Dispatcher';
|
|
25
|
-
import { getOSInfo } from '../client-details';
|
|
26
25
|
import { VideoLayerSetting } from '../gen/video/sfu/event/events';
|
|
27
26
|
import { TargetResolutionResponse } from '../gen/shims';
|
|
28
27
|
|
|
@@ -260,30 +259,18 @@ export class Publisher {
|
|
|
260
259
|
const screenShareBitrate =
|
|
261
260
|
settings?.screensharing.target_resolution?.bitrate;
|
|
262
261
|
|
|
262
|
+
const { preferredBitrate, preferredCodec, screenShareSettings } = opts;
|
|
263
263
|
const videoEncodings =
|
|
264
264
|
trackType === TrackType.VIDEO
|
|
265
|
-
? findOptimalVideoLayers(track, targetResolution)
|
|
265
|
+
? findOptimalVideoLayers(track, targetResolution, preferredBitrate)
|
|
266
266
|
: trackType === TrackType.SCREEN_SHARE
|
|
267
267
|
? findOptimalScreenSharingLayers(
|
|
268
268
|
track,
|
|
269
|
-
|
|
269
|
+
screenShareSettings,
|
|
270
270
|
screenShareBitrate,
|
|
271
271
|
)
|
|
272
272
|
: undefined;
|
|
273
273
|
|
|
274
|
-
let preferredCodec = opts.preferredCodec;
|
|
275
|
-
if (!preferredCodec && trackType === TrackType.VIDEO && isReactNative()) {
|
|
276
|
-
const osName = getOSInfo()?.name.toLowerCase();
|
|
277
|
-
if (osName === 'ipados') {
|
|
278
|
-
// in ipads it was noticed that if vp8 codec is used
|
|
279
|
-
// then the bytes sent is 0 in the outbound-rtp
|
|
280
|
-
// so we are forcing h264 codec for ipads
|
|
281
|
-
preferredCodec = 'H264';
|
|
282
|
-
} else if (osName === 'android') {
|
|
283
|
-
preferredCodec = 'VP8';
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
274
|
// listen for 'ended' event on the track as it might be ended abruptly
|
|
288
275
|
// by an external factor as permission revokes, device disconnected, etc.
|
|
289
276
|
// keep in mind that `track.stop()` doesn't trigger this event.
|
|
@@ -306,9 +293,14 @@ export class Publisher {
|
|
|
306
293
|
this.transceiverRegistry[trackType] = transceiver;
|
|
307
294
|
this.publishOptionsPerTrackType.set(trackType, opts);
|
|
308
295
|
|
|
296
|
+
const codec =
|
|
297
|
+
isReactNative() && trackType === TrackType.VIDEO && !preferredCodec
|
|
298
|
+
? getRNOptimalCodec()
|
|
299
|
+
: preferredCodec;
|
|
300
|
+
|
|
309
301
|
const codecPreferences =
|
|
310
302
|
'setCodecPreferences' in transceiver
|
|
311
|
-
? this.getCodecPreferences(trackType,
|
|
303
|
+
? this.getCodecPreferences(trackType, codec)
|
|
312
304
|
: undefined;
|
|
313
305
|
if (codecPreferences) {
|
|
314
306
|
this.logger(
|
|
@@ -721,7 +713,11 @@ export class Publisher {
|
|
|
721
713
|
const publishOpts = this.publishOptionsPerTrackType.get(trackType);
|
|
722
714
|
optimalLayers =
|
|
723
715
|
trackType === TrackType.VIDEO
|
|
724
|
-
? findOptimalVideoLayers(
|
|
716
|
+
? findOptimalVideoLayers(
|
|
717
|
+
track,
|
|
718
|
+
targetResolution,
|
|
719
|
+
publishOpts?.preferredBitrate,
|
|
720
|
+
)
|
|
725
721
|
: trackType === TrackType.SCREEN_SHARE
|
|
726
722
|
? findOptimalScreenSharingLayers(
|
|
727
723
|
track,
|
|
@@ -138,7 +138,12 @@ describe('videoLayers', () => {
|
|
|
138
138
|
describe('getComputedMaxBitrate', () => {
|
|
139
139
|
it('should scale target bitrate down if resolution is smaller than target resolution', () => {
|
|
140
140
|
const targetResolution = { width: 1920, height: 1080, bitrate: 3000000 };
|
|
141
|
-
const scaledBitrate = getComputedMaxBitrate(
|
|
141
|
+
const scaledBitrate = getComputedMaxBitrate(
|
|
142
|
+
targetResolution,
|
|
143
|
+
1280,
|
|
144
|
+
720,
|
|
145
|
+
undefined,
|
|
146
|
+
);
|
|
142
147
|
expect(scaledBitrate).toBe(1333333);
|
|
143
148
|
});
|
|
144
149
|
|
|
@@ -148,7 +153,12 @@ describe('videoLayers', () => {
|
|
|
148
153
|
const targetBitrates = ['f', 'h', 'q'].map((rid) => {
|
|
149
154
|
const width = targetResolution.width / downscaleFactor;
|
|
150
155
|
const height = targetResolution.height / downscaleFactor;
|
|
151
|
-
const bitrate = getComputedMaxBitrate(
|
|
156
|
+
const bitrate = getComputedMaxBitrate(
|
|
157
|
+
targetResolution,
|
|
158
|
+
width,
|
|
159
|
+
height,
|
|
160
|
+
undefined,
|
|
161
|
+
);
|
|
152
162
|
downscaleFactor *= 2;
|
|
153
163
|
return {
|
|
154
164
|
rid,
|
|
@@ -166,25 +176,45 @@ describe('videoLayers', () => {
|
|
|
166
176
|
|
|
167
177
|
it('should not scale target bitrate if resolution is larger than target resolution', () => {
|
|
168
178
|
const targetResolution = { width: 1280, height: 720, bitrate: 1000000 };
|
|
169
|
-
const scaledBitrate = getComputedMaxBitrate(
|
|
179
|
+
const scaledBitrate = getComputedMaxBitrate(
|
|
180
|
+
targetResolution,
|
|
181
|
+
2560,
|
|
182
|
+
1440,
|
|
183
|
+
undefined,
|
|
184
|
+
);
|
|
170
185
|
expect(scaledBitrate).toBe(1000000);
|
|
171
186
|
});
|
|
172
187
|
|
|
173
188
|
it('should not scale target bitrate if resolution is equal to target resolution', () => {
|
|
174
189
|
const targetResolution = { width: 1280, height: 720, bitrate: 1000000 };
|
|
175
|
-
const scaledBitrate = getComputedMaxBitrate(
|
|
190
|
+
const scaledBitrate = getComputedMaxBitrate(
|
|
191
|
+
targetResolution,
|
|
192
|
+
1280,
|
|
193
|
+
720,
|
|
194
|
+
undefined,
|
|
195
|
+
);
|
|
176
196
|
expect(scaledBitrate).toBe(1000000);
|
|
177
197
|
});
|
|
178
198
|
|
|
179
199
|
it('should handle 0 width and height', () => {
|
|
180
200
|
const targetResolution = { width: 1280, height: 720, bitrate: 1000000 };
|
|
181
|
-
const scaledBitrate = getComputedMaxBitrate(
|
|
201
|
+
const scaledBitrate = getComputedMaxBitrate(
|
|
202
|
+
targetResolution,
|
|
203
|
+
0,
|
|
204
|
+
0,
|
|
205
|
+
undefined,
|
|
206
|
+
);
|
|
182
207
|
expect(scaledBitrate).toBe(0);
|
|
183
208
|
});
|
|
184
209
|
|
|
185
210
|
it('should handle 4k target resolution', () => {
|
|
186
211
|
const targetResolution = { width: 3840, height: 2160, bitrate: 15000000 };
|
|
187
|
-
const scaledBitrate = getComputedMaxBitrate(
|
|
212
|
+
const scaledBitrate = getComputedMaxBitrate(
|
|
213
|
+
targetResolution,
|
|
214
|
+
1280,
|
|
215
|
+
720,
|
|
216
|
+
undefined,
|
|
217
|
+
);
|
|
188
218
|
expect(scaledBitrate).toBe(1666667);
|
|
189
219
|
});
|
|
190
220
|
});
|
package/src/rtc/codecs.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { getOSInfo } from '../client-details';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Returns back a list of sorted codecs, with the preferred codec first.
|
|
3
5
|
*
|
|
@@ -88,3 +90,16 @@ export const getGenericSdp = async (direction: RTCRtpTransceiverDirection) => {
|
|
|
88
90
|
tempPc.close();
|
|
89
91
|
return sdp;
|
|
90
92
|
};
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Returns the optimal codec for RN.
|
|
96
|
+
*/
|
|
97
|
+
export const getRNOptimalCodec = () => {
|
|
98
|
+
const osName = getOSInfo()?.name.toLowerCase();
|
|
99
|
+
// in ipads it was noticed that if vp8 codec is used
|
|
100
|
+
// then the bytes sent is 0 in the outbound-rtp
|
|
101
|
+
// so we are forcing h264 codec for ipads
|
|
102
|
+
if (osName === 'ipados') return 'h264';
|
|
103
|
+
if (osName === 'android') return 'vp8';
|
|
104
|
+
return undefined;
|
|
105
|
+
};
|
package/src/rtc/videoLayers.ts
CHANGED
|
@@ -25,16 +25,23 @@ 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
29
|
*/
|
|
29
30
|
export const findOptimalVideoLayers = (
|
|
30
31
|
videoTrack: MediaStreamTrack,
|
|
31
32
|
targetResolution: TargetResolutionResponse = defaultTargetResolution,
|
|
33
|
+
preferredBitrate: number | undefined,
|
|
32
34
|
) => {
|
|
33
35
|
const optimalVideoLayers: OptimalVideoLayer[] = [];
|
|
34
36
|
const settings = videoTrack.getSettings();
|
|
35
37
|
const { width: w = 0, height: h = 0 } = settings;
|
|
36
38
|
|
|
37
|
-
const maxBitrate = getComputedMaxBitrate(
|
|
39
|
+
const maxBitrate = getComputedMaxBitrate(
|
|
40
|
+
targetResolution,
|
|
41
|
+
w,
|
|
42
|
+
h,
|
|
43
|
+
preferredBitrate,
|
|
44
|
+
);
|
|
38
45
|
let downscaleFactor = 1;
|
|
39
46
|
['f', 'h', 'q'].forEach((rid) => {
|
|
40
47
|
// Reversing the order [f, h, q] to [q, h, f] as Chrome uses encoding index
|
|
@@ -68,22 +75,29 @@ export const findOptimalVideoLayers = (
|
|
|
68
75
|
* @param targetResolution the target resolution.
|
|
69
76
|
* @param currentWidth the current width of the track.
|
|
70
77
|
* @param currentHeight the current height of the track.
|
|
78
|
+
* @param preferredBitrate the preferred bitrate for the track.
|
|
71
79
|
*/
|
|
72
80
|
export const getComputedMaxBitrate = (
|
|
73
81
|
targetResolution: TargetResolutionResponse,
|
|
74
82
|
currentWidth: number,
|
|
75
83
|
currentHeight: number,
|
|
84
|
+
preferredBitrate: number | undefined,
|
|
76
85
|
): number => {
|
|
77
86
|
// if the current resolution is lower than the target resolution,
|
|
78
87
|
// we want to proportionally reduce the target bitrate
|
|
79
|
-
const {
|
|
88
|
+
const {
|
|
89
|
+
width: targetWidth,
|
|
90
|
+
height: targetHeight,
|
|
91
|
+
bitrate: targetBitrate,
|
|
92
|
+
} = targetResolution;
|
|
93
|
+
const bitrate = preferredBitrate || targetBitrate;
|
|
80
94
|
if (currentWidth < targetWidth || currentHeight < targetHeight) {
|
|
81
95
|
const currentPixels = currentWidth * currentHeight;
|
|
82
96
|
const targetPixels = targetWidth * targetHeight;
|
|
83
97
|
const reductionFactor = currentPixels / targetPixels;
|
|
84
|
-
return Math.round(
|
|
98
|
+
return Math.round(bitrate * reductionFactor);
|
|
85
99
|
}
|
|
86
|
-
return
|
|
100
|
+
return bitrate;
|
|
87
101
|
};
|
|
88
102
|
|
|
89
103
|
/**
|