@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stream-io/video-client",
3
- "version": "1.23.3",
3
+ "version": "1.23.4",
4
4
  "main": "dist/index.cjs.js",
5
5
  "module": "dist/index.es.js",
6
6
  "browser": "dist/index.browser.es.js",
@@ -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
- await this.selectTargetResolution(target_resolution);
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) {
@@ -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
- expect(layers[0].rid).toBe('q');
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
- expect(layers[0].rid).toBe('q');
132
- expect(layers[1].rid).toBe('h');
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
- expect(layers[0].rid).toBe('q');
149
- expect(layers[1].rid).toBe('h');
150
- expect(layers[2].rid).toBe('f');
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', () => {
@@ -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 (q), the one with the highest quality
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, 160x120 (q) and 640x480 (h)
194
- layers = optimalVideoLayers.filter((layer) => layer.rid !== 'h');
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,