@stream-io/video-client 1.23.3 → 1.23.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 +7 -0
- package/dist/index.browser.es.js +30 -7
- package/dist/index.browser.es.js.map +1 -1
- package/dist/index.cjs.js +30 -7
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +30 -7
- package/dist/index.es.js.map +1 -1
- package/package.json +1 -1
- package/src/StreamSfuClient.ts +2 -0
- package/src/coordinator/connection/token_manager.ts +3 -1
- package/src/devices/CameraManager.ts +7 -1
- package/src/devices/devices.ts +14 -0
- package/src/rtc/__tests__/videoLayers.test.ts +21 -6
- package/src/rtc/videoLayers.ts +5 -3
package/package.json
CHANGED
package/src/StreamSfuClient.ts
CHANGED
|
@@ -237,6 +237,8 @@ export class StreamSfuClient {
|
|
|
237
237
|
const eventsToTrace: Partial<Record<SfuEventKinds, boolean>> = {
|
|
238
238
|
callEnded: true,
|
|
239
239
|
changePublishQuality: true,
|
|
240
|
+
changePublishOptions: true,
|
|
241
|
+
connectionQualityChanged: true,
|
|
240
242
|
error: true,
|
|
241
243
|
goAway: true,
|
|
242
244
|
};
|
|
@@ -113,7 +113,9 @@ export class TokenManager {
|
|
|
113
113
|
this.token = token;
|
|
114
114
|
} catch (e) {
|
|
115
115
|
return reject(
|
|
116
|
-
new Error(`Call to tokenProvider failed with message: ${e}
|
|
116
|
+
new Error(`Call to tokenProvider failed with message: ${e}`, {
|
|
117
|
+
cause: e,
|
|
118
|
+
}),
|
|
117
119
|
);
|
|
118
120
|
}
|
|
119
121
|
resolve(this.token);
|
|
@@ -123,7 +123,13 @@ export class CameraManager extends InputMediaDeviceManager<CameraManagerState> {
|
|
|
123
123
|
await this.statusChangeSettled();
|
|
124
124
|
|
|
125
125
|
const { target_resolution, camera_facing, camera_default_on } = settings;
|
|
126
|
-
|
|
126
|
+
// normalize target resolution to landscape format.
|
|
127
|
+
// on mobile devices, the device itself adjusts the resolution to portrait or landscape
|
|
128
|
+
// depending on the orientation of the device. using portrait resolution
|
|
129
|
+
// will result in falling back to the default resolution (640x480).
|
|
130
|
+
let { width, height } = target_resolution;
|
|
131
|
+
if (width < height) [width, height] = [height, width];
|
|
132
|
+
await this.selectTargetResolution({ width, height });
|
|
127
133
|
|
|
128
134
|
// Set camera direction if it's not yet set
|
|
129
135
|
if (!this.state.direction && !this.state.selectedDevice) {
|
package/src/devices/devices.ts
CHANGED
|
@@ -175,6 +175,20 @@ const getStream = async (
|
|
|
175
175
|
// every successful getUserMedia call.
|
|
176
176
|
navigator.mediaDevices.dispatchEvent(new Event('devicechange'));
|
|
177
177
|
}
|
|
178
|
+
if (constraints.video) {
|
|
179
|
+
const [videoTrack] = stream.getVideoTracks();
|
|
180
|
+
if (videoTrack) {
|
|
181
|
+
const { width, height } = videoTrack.getSettings();
|
|
182
|
+
const target = constraints.video as MediaTrackConstraints;
|
|
183
|
+
if (width !== target.width || height !== target.height) {
|
|
184
|
+
tracer?.trace(
|
|
185
|
+
`${tag}Warn`,
|
|
186
|
+
`Requested resolution ${target.width}x${target.height} but got ${width}x${height}`,
|
|
187
|
+
);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
178
192
|
return stream;
|
|
179
193
|
} catch (error) {
|
|
180
194
|
tracer?.trace(`${tag}OnFailure`, (error as Error).name);
|
|
@@ -112,7 +112,10 @@ describe('videoLayers', () => {
|
|
|
112
112
|
videoDimension: { width, height },
|
|
113
113
|
});
|
|
114
114
|
expect(layers.length).toBe(1);
|
|
115
|
-
|
|
115
|
+
const [q] = layers;
|
|
116
|
+
expect(q.rid).toBe('q');
|
|
117
|
+
expect(q.width).toBe(320);
|
|
118
|
+
expect(q.height).toBe(240);
|
|
116
119
|
});
|
|
117
120
|
|
|
118
121
|
it('should announce two simulcast layers for resolutions less than 640px wide', () => {
|
|
@@ -128,8 +131,13 @@ describe('videoLayers', () => {
|
|
|
128
131
|
videoDimension: { width, height },
|
|
129
132
|
});
|
|
130
133
|
expect(layers.length).toBe(2);
|
|
131
|
-
|
|
132
|
-
expect(
|
|
134
|
+
const [q, h] = layers;
|
|
135
|
+
expect(q.rid).toBe('q');
|
|
136
|
+
expect(q.width).toBe(320);
|
|
137
|
+
expect(q.height).toBe(240);
|
|
138
|
+
expect(h.rid).toBe('h');
|
|
139
|
+
expect(h.width).toBe(640);
|
|
140
|
+
expect(h.height).toBe(480);
|
|
133
141
|
});
|
|
134
142
|
|
|
135
143
|
it('should announce three simulcast layers for resolutions greater than 640px wide', () => {
|
|
@@ -145,9 +153,16 @@ describe('videoLayers', () => {
|
|
|
145
153
|
videoDimension: { width, height },
|
|
146
154
|
});
|
|
147
155
|
expect(layers.length).toBe(3);
|
|
148
|
-
|
|
149
|
-
expect(
|
|
150
|
-
expect(
|
|
156
|
+
const [q, h, f] = layers;
|
|
157
|
+
expect(q.rid).toBe('q');
|
|
158
|
+
expect(q.width).toBe(320);
|
|
159
|
+
expect(q.height).toBe(180);
|
|
160
|
+
expect(h.rid).toBe('h');
|
|
161
|
+
expect(h.width).toBe(640);
|
|
162
|
+
expect(h.height).toBe(360);
|
|
163
|
+
expect(f.rid).toBe('f');
|
|
164
|
+
expect(f.width).toBe(1280);
|
|
165
|
+
expect(f.height).toBe(720);
|
|
151
166
|
});
|
|
152
167
|
|
|
153
168
|
it('should announce only one layer for SVC codecs', () => {
|
package/src/rtc/videoLayers.ts
CHANGED
|
@@ -187,16 +187,18 @@ const withSimulcastConstraints = (
|
|
|
187
187
|
|
|
188
188
|
const size = Math.max(settings.width || 0, settings.height || 0);
|
|
189
189
|
if (size <= 320) {
|
|
190
|
-
// provide only one layer 320x240 (
|
|
190
|
+
// provide only one layer 320x240 (f), the one with the highest quality
|
|
191
191
|
layers = optimalVideoLayers.filter((layer) => layer.rid === 'f');
|
|
192
192
|
} else if (size <= 640) {
|
|
193
|
-
// provide two layers,
|
|
194
|
-
layers = optimalVideoLayers.filter((layer) => layer.rid !== '
|
|
193
|
+
// provide two layers, 320x240 (h) and 640x480 (f)
|
|
194
|
+
layers = optimalVideoLayers.filter((layer) => layer.rid !== 'q');
|
|
195
195
|
} else {
|
|
196
196
|
// provide three layers for sizes > 640x480
|
|
197
197
|
layers = optimalVideoLayers;
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
+
// we might have removed some layers, so we need to reassign the rid
|
|
201
|
+
// to match the expected order of [q, h, f] for simulcast
|
|
200
202
|
const ridMapping = ['q', 'h', 'f'];
|
|
201
203
|
return layers.map<OptimalVideoLayer>((layer, index, arr) => ({
|
|
202
204
|
...layer,
|