@voltkit-rtc/client 0.9.1 → 0.9.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.
- package/CHANGELOG.md +13 -0
- package/README.md +9 -5
- package/dist/cjs/adaptive.d.ts +9 -5
- package/dist/cjs/adaptive.d.ts.map +1 -1
- package/dist/cjs/adaptive.js +10 -6
- package/dist/cjs/adaptive.js.map +1 -1
- package/dist/cjs/diagnostics.d.ts +1 -1
- package/dist/cjs/diagnostics.js +1 -1
- package/dist/cjs/index.d.ts +19 -7
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +20 -8
- package/dist/cjs/index.js.map +1 -1
- package/dist/esm/adaptive.d.ts +9 -5
- package/dist/esm/adaptive.d.ts.map +1 -1
- package/dist/esm/adaptive.js +10 -6
- package/dist/esm/adaptive.js.map +1 -1
- package/dist/esm/diagnostics.d.ts +1 -1
- package/dist/esm/diagnostics.js +1 -1
- package/dist/esm/index.d.ts +19 -7
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +20 -8
- package/dist/esm/index.js.map +1 -1
- package/package.json +1 -1
- package/src/adaptive.ts +10 -6
- package/src/diagnostics.ts +1 -1
- package/src/index.ts +20 -8
package/package.json
CHANGED
package/src/adaptive.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* The app attaches the element that shows a video (`attachVideo`). From that
|
|
6
6
|
* element's size on screen (CSS pixels × devicePixelRatio, at most 2) the
|
|
7
|
-
* smallest simulcast layer that fills it
|
|
7
|
+
* smallest simulcast layer that fills it without being stretched is chosen; while no attached
|
|
8
8
|
* element is visible (scrolled away, `display: none`, the tab in the
|
|
9
9
|
* background) the video is paused at the media server, so it costs no
|
|
10
10
|
* bandwidth and no decoding. This is what LiveKit calls adaptiveStream and
|
|
@@ -27,12 +27,16 @@ export interface ViewBox {
|
|
|
27
27
|
|
|
28
28
|
/** Never ask for more than twice the CSS size: a 3× phone screen gains nothing visible from it. */
|
|
29
29
|
export const MAX_PIXEL_RATIO = 2;
|
|
30
|
-
/**
|
|
31
|
-
|
|
30
|
+
/**
|
|
31
|
+
* A layer is never stretched on screen: a box bigger than a layer gets the next one up. Up to 0.9.1 a layer could be
|
|
32
|
+
* shown 15% bigger than it is, which looks soft on a face (owner, 2026-10-20: "quality should look good"). The 2% is
|
|
33
|
+
* for rounding only, so a box a pixel or two bigger than a layer keeps it.
|
|
34
|
+
*/
|
|
35
|
+
export const MAX_UPSCALE = 1.02;
|
|
32
36
|
|
|
33
37
|
/**
|
|
34
|
-
* The smallest layer that fills `box`
|
|
35
|
-
* not known (an older publisher): then the server chooses, as before.
|
|
38
|
+
* The smallest layer that fills `box` without being stretched, or null when
|
|
39
|
+
* the layers are not known (an older publisher): then the server chooses, as before.
|
|
36
40
|
*
|
|
37
41
|
* With `cover` the picture is scaled until it fills the box (a part is
|
|
38
42
|
* cropped), with `contain` until it fits. Either way the scale is measured
|
|
@@ -46,7 +50,7 @@ export function layerForBox(layers: readonly VideoLayer[], box: ViewBox, pixelRa
|
|
|
46
50
|
const h = box.height * ratio;
|
|
47
51
|
for (const layer of usable) {
|
|
48
52
|
const scale = box.fit === 'cover' ? Math.max(w / layer.width, h / layer.height) : Math.min(w / layer.width, h / layer.height);
|
|
49
|
-
// The layer is
|
|
53
|
+
// The layer is not stretched on screen (see MAX_UPSCALE).
|
|
50
54
|
if (scale <= MAX_UPSCALE) return layer.spatialLayer;
|
|
51
55
|
}
|
|
52
56
|
return usable[usable.length - 1]!.spatialLayer;
|
package/src/diagnostics.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -2337,7 +2337,14 @@ export class StreamClient {
|
|
|
2337
2337
|
return parseSendStats(report.values(), { quality: this.videoQuality, baseline, keyPrefix: prefix });
|
|
2338
2338
|
}
|
|
2339
2339
|
|
|
2340
|
-
/**
|
|
2340
|
+
/**
|
|
2341
|
+
* The quality this viewer gets of one remote video. '1080p', '720p' and '480p' pick the publisher's biggest layer
|
|
2342
|
+
* at or below that size (a 720p camera cannot give 1080p), and the viewer gets it while the video is shown, however
|
|
2343
|
+
* big it is on screen: someone who picks 1080p expects 1080p, not the smaller copy that fits the tile. A connection
|
|
2344
|
+
* that cannot carry it still gets less until it recovers, and a video shown through attachVideo is still paused
|
|
2345
|
+
* while nobody can see it. 'auto' (the default) goes back to the size it is shown at, or the server's choice.
|
|
2346
|
+
* Kept across reconnects.
|
|
2347
|
+
*/
|
|
2341
2348
|
async setReceiveQuality(producerId: string, quality: ReceiveQuality): Promise<void> {
|
|
2342
2349
|
if (!['auto', '1080p', '720p', '480p'].includes(quality)) throw new RangeError('setReceiveQuality: unsupported quality');
|
|
2343
2350
|
const consumer = this.consumers.get(producerId);
|
|
@@ -3089,26 +3096,31 @@ export class StreamClient {
|
|
|
3089
3096
|
* Adaptive stream (like LiveKit's adaptiveStream and Tencent TRTC's small
|
|
3090
3097
|
* stream with receiveWhenViewVisible): tell the SDK which element shows a
|
|
3091
3098
|
* remote video. It then receives the smallest layer that fills that element
|
|
3092
|
-
*
|
|
3099
|
+
* without stretching it (its size on screen × devicePixelRatio, at most 2) and pauses the
|
|
3093
3100
|
* video at the server while the element is not visible (scrolled away,
|
|
3094
3101
|
* `display: none`, or the tab in the background), so a grid of small tiles
|
|
3095
3102
|
* stops decoding full-size video. Attach the same video to several elements
|
|
3096
3103
|
* and the largest visible one decides. Returns the function that detaches
|
|
3097
|
-
* it; detach when the element goes away. A
|
|
3098
|
-
* `setReceiveQuality`
|
|
3099
|
-
*
|
|
3100
|
-
*
|
|
3104
|
+
* it; detach when the element goes away. A quality chosen with
|
|
3105
|
+
* `setReceiveQuality` replaces the size it is shown at (the video is still
|
|
3106
|
+
* paused while hidden), and a ceiling set with `setPreferredLayers` still
|
|
3107
|
+
* applies. Works with any server; one without `pauseConsumer` gets the
|
|
3108
|
+
* smallest layer instead of a pause.
|
|
3101
3109
|
*/
|
|
3102
3110
|
attachVideo(producerId: string, element: Element): () => void {
|
|
3103
3111
|
return this.adaptive.attach(producerId, element);
|
|
3104
3112
|
}
|
|
3105
3113
|
|
|
3106
|
-
/**
|
|
3114
|
+
/**
|
|
3115
|
+
* The layers to ask for. A quality chosen with setReceiveQuality is the layer, whatever the size on screen (owner,
|
|
3116
|
+
* 2026-10-20: viewers who picked 1080p got 540p, because it was only a ceiling). A ceiling set with
|
|
3117
|
+
* setPreferredLayers and adaptive stream's size: the lower of the two.
|
|
3118
|
+
*/
|
|
3107
3119
|
private effectiveLayers(producerId: string, want: AdaptiveWant | null): PreferredLayers {
|
|
3108
3120
|
let manual: PreferredLayers | undefined = this.preferredLayers.get(producerId);
|
|
3109
3121
|
const quality = this.receiveQualities.get(producerId);
|
|
3110
3122
|
if (quality && quality !== 'auto') {
|
|
3111
|
-
try {
|
|
3123
|
+
try { return { spatialLayer: receiveSpatialLayer(this.remoteVideoLayers.get(producerId) ?? [], quality) }; } catch { manual = undefined; }
|
|
3112
3124
|
}
|
|
3113
3125
|
const adaptive = want?.visible ? want.spatialLayer : null;
|
|
3114
3126
|
if (adaptive === null || adaptive === undefined) return manual ?? { spatialLayer: -1, temporalLayer: -1 };
|