@mentra/miniapp 3.2.1-beta.319 → 3.2.1-beta.355
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/README.md +16 -0
- package/dist/background/index.d.ts +5 -3
- package/dist/background/index.d.ts.map +1 -1
- package/dist/background/index.js +1 -0
- package/dist/background/index.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/display.d.ts +33 -0
- package/dist/modules/display.d.ts.map +1 -1
- package/dist/modules/display.js +2 -0
- package/dist/modules/display.js.map +1 -1
- package/dist/modules/meeting.d.ts +66 -6
- package/dist/modules/meeting.d.ts.map +1 -1
- package/dist/modules/meeting.js +72 -19
- package/dist/modules/meeting.js.map +1 -1
- package/dist/modules/stream.d.ts +46 -0
- package/dist/modules/stream.d.ts.map +1 -1
- package/dist/modules/stream.js +107 -0
- package/dist/modules/stream.js.map +1 -1
- package/dist/protocol.d.ts +39 -0
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +36 -0
- package/dist/protocol.js.map +1 -1
- package/dist/react/StreamPreview.d.ts +41 -0
- package/dist/react/StreamPreview.d.ts.map +1 -0
- package/dist/react/StreamPreview.js +144 -0
- package/dist/react/StreamPreview.js.map +1 -0
- package/dist/react/index.d.ts +2 -0
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js +1 -0
- package/dist/react/index.js.map +1 -1
- package/dist/react/stream-preview/PreviewConnection.d.ts +139 -0
- package/dist/react/stream-preview/PreviewConnection.d.ts.map +1 -0
- package/dist/react/stream-preview/PreviewConnection.js +462 -0
- package/dist/react/stream-preview/PreviewConnection.js.map +1 -0
- package/dist/react/stream-preview/controlChannel.d.ts +75 -0
- package/dist/react/stream-preview/controlChannel.d.ts.map +1 -0
- package/dist/react/stream-preview/controlChannel.js +55 -0
- package/dist/react/stream-preview/controlChannel.js.map +1 -0
- package/dist/react/stream-preview/creditLoop.d.ts +81 -0
- package/dist/react/stream-preview/creditLoop.d.ts.map +1 -0
- package/dist/react/stream-preview/creditLoop.js +146 -0
- package/dist/react/stream-preview/creditLoop.js.map +1 -0
- package/dist/react/stream-preview/protocol.d.ts +113 -0
- package/dist/react/stream-preview/protocol.d.ts.map +1 -0
- package/dist/react/stream-preview/protocol.js +148 -0
- package/dist/react/stream-preview/protocol.js.map +1 -0
- package/dist/react/stream-preview/resizeCoalescer.d.ts +38 -0
- package/dist/react/stream-preview/resizeCoalescer.d.ts.map +1 -0
- package/dist/react/stream-preview/resizeCoalescer.js +71 -0
- package/dist/react/stream-preview/resizeCoalescer.js.map +1 -0
- package/dist/react/stream-preview/testFrames.d.ts +38 -0
- package/dist/react/stream-preview/testFrames.d.ts.map +1 -0
- package/dist/react/stream-preview/testFrames.js +50 -0
- package/dist/react/stream-preview/testFrames.js.map +1 -0
- package/dist/react/stream-preview/tiers.d.ts +21 -0
- package/dist/react/stream-preview/tiers.d.ts.map +1 -0
- package/dist/react/stream-preview/tiers.js +33 -0
- package/dist/react/stream-preview/tiers.js.map +1 -0
- package/dist/react/stream-preview/trace.d.ts +23 -0
- package/dist/react/stream-preview/trace.d.ts.map +1 -0
- package/dist/react/stream-preview/trace.js +71 -0
- package/dist/react/stream-preview/trace.js.map +1 -0
- package/dist/react/stream-preview/transport.d.ts +79 -0
- package/dist/react/stream-preview/transport.d.ts.map +1 -0
- package/dist/react/stream-preview/transport.js +209 -0
- package/dist/react/stream-preview/transport.js.map +1 -0
- package/dist/react/stream-preview/yuvRenderer.d.ts +31 -0
- package/dist/react/stream-preview/yuvRenderer.d.ts.map +1 -0
- package/dist/react/stream-preview/yuvRenderer.js +398 -0
- package/dist/react/stream-preview/yuvRenderer.js.map +1 -0
- package/dist/session.d.ts +5 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +5 -0
- package/dist/session.js.map +1 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +1 -0
- package/dist/ui/index.js.map +1 -1
- package/package.json +8 -3
- package/src/background/index.ts +14 -1
- package/src/index.ts +15 -0
- package/src/modules/display.ts +37 -0
- package/src/modules/meeting.ts +133 -23
- package/src/modules/stream.ts +153 -1
- package/src/protocol.ts +75 -0
- package/src/react/StreamPreview.tsx +187 -0
- package/src/react/index.ts +2 -0
- package/src/react/stream-preview/PreviewConnection.ts +552 -0
- package/src/react/stream-preview/controlChannel.ts +119 -0
- package/src/react/stream-preview/creditLoop.ts +189 -0
- package/src/react/stream-preview/protocol.ts +227 -0
- package/src/react/stream-preview/resizeCoalescer.ts +88 -0
- package/src/react/stream-preview/testFrames.ts +86 -0
- package/src/react/stream-preview/tiers.ts +37 -0
- package/src/react/stream-preview/trace.ts +81 -0
- package/src/react/stream-preview/transport.ts +242 -0
- package/src/react/stream-preview/yuvRenderer.ts +453 -0
- package/src/session.ts +8 -0
- package/src/ui/index.ts +2 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapse a stream of box measurements into the few that matter.
|
|
3
|
+
*
|
|
4
|
+
* A layout animation fires ResizeObserver every frame. Bursts inside one frame are merged with
|
|
5
|
+
* `requestAnimationFrame`, and a size is only applied once it has held still for the settle
|
|
6
|
+
* window. Hiding (a zero box) and the first measurement apply at once: the first so the preview
|
|
7
|
+
* starts without a delay, hiding so production stops as soon as nobody can see it.
|
|
8
|
+
*/
|
|
9
|
+
export interface PreviewBox {
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}
|
|
13
|
+
export interface ResizeCoalescerOptions {
|
|
14
|
+
apply: (box: PreviewBox) => void;
|
|
15
|
+
settleMs?: number;
|
|
16
|
+
requestFrame?: (cb: () => void) => unknown;
|
|
17
|
+
setTimer?: (cb: () => void, ms: number) => unknown;
|
|
18
|
+
clearTimer?: (handle: unknown) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const RESIZE_SETTLE_MS = 250;
|
|
21
|
+
export declare class ResizeCoalescer {
|
|
22
|
+
private readonly options;
|
|
23
|
+
private latest;
|
|
24
|
+
private lastApplied;
|
|
25
|
+
private framePending;
|
|
26
|
+
private timer;
|
|
27
|
+
private cancelled;
|
|
28
|
+
private readonly settleMs;
|
|
29
|
+
private readonly requestFrame;
|
|
30
|
+
private readonly setTimer;
|
|
31
|
+
private readonly clearTimer;
|
|
32
|
+
constructor(options: ResizeCoalescerOptions);
|
|
33
|
+
push(box: PreviewBox): void;
|
|
34
|
+
cancel(): void;
|
|
35
|
+
private applyLatest;
|
|
36
|
+
private clearSettle;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=resizeCoalescer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizeCoalescer.d.ts","sourceRoot":"","sources":["../../../src/react/stream-preview/resizeCoalescer.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAA;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,OAAO,CAAA;IAC1C,QAAQ,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAA;IAClD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;CACvC;AAED,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAMnC,qBAAa,eAAe;IAWd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAVpC,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,WAAW,CAA0B;IAC7C,OAAO,CAAC,YAAY,CAAQ;IAC5B,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAC1D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyC;IAClE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA2B;gBAEzB,OAAO,EAAE,sBAAsB;IAS5D,IAAI,CAAC,GAAG,EAAE,UAAU,GAAG,IAAI;IAqB3B,MAAM,IAAI,IAAI;IAKd,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,WAAW;CAKpB"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapse a stream of box measurements into the few that matter.
|
|
3
|
+
*
|
|
4
|
+
* A layout animation fires ResizeObserver every frame. Bursts inside one frame are merged with
|
|
5
|
+
* `requestAnimationFrame`, and a size is only applied once it has held still for the settle
|
|
6
|
+
* window. Hiding (a zero box) and the first measurement apply at once: the first so the preview
|
|
7
|
+
* starts without a delay, hiding so production stops as soon as nobody can see it.
|
|
8
|
+
*/
|
|
9
|
+
export const RESIZE_SETTLE_MS = 250;
|
|
10
|
+
function isZero(box) {
|
|
11
|
+
return !(box.width > 0) || !(box.height > 0);
|
|
12
|
+
}
|
|
13
|
+
export class ResizeCoalescer {
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.options = options;
|
|
16
|
+
this.latest = null;
|
|
17
|
+
this.lastApplied = null;
|
|
18
|
+
this.framePending = false;
|
|
19
|
+
this.timer = null;
|
|
20
|
+
this.cancelled = false;
|
|
21
|
+
this.settleMs = options.settleMs ?? RESIZE_SETTLE_MS;
|
|
22
|
+
this.requestFrame =
|
|
23
|
+
options.requestFrame ??
|
|
24
|
+
((cb) => (typeof requestAnimationFrame === "function" ? requestAnimationFrame(() => cb()) : setTimeout(cb, 16)));
|
|
25
|
+
this.setTimer = options.setTimer ?? ((cb, ms) => setTimeout(cb, ms));
|
|
26
|
+
this.clearTimer = options.clearTimer ?? ((handle) => clearTimeout(handle));
|
|
27
|
+
}
|
|
28
|
+
push(box) {
|
|
29
|
+
if (this.cancelled)
|
|
30
|
+
return;
|
|
31
|
+
this.latest = box;
|
|
32
|
+
if (!this.lastApplied || isZero(box) || isZero(this.lastApplied)) {
|
|
33
|
+
this.clearSettle();
|
|
34
|
+
this.applyLatest();
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
if (this.framePending)
|
|
38
|
+
return;
|
|
39
|
+
this.framePending = true;
|
|
40
|
+
this.requestFrame(() => {
|
|
41
|
+
this.framePending = false;
|
|
42
|
+
if (this.cancelled)
|
|
43
|
+
return;
|
|
44
|
+
this.clearSettle();
|
|
45
|
+
this.timer = this.setTimer(() => {
|
|
46
|
+
this.timer = null;
|
|
47
|
+
this.applyLatest();
|
|
48
|
+
}, this.settleMs);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
cancel() {
|
|
52
|
+
this.cancelled = true;
|
|
53
|
+
this.clearSettle();
|
|
54
|
+
}
|
|
55
|
+
applyLatest() {
|
|
56
|
+
const box = this.latest;
|
|
57
|
+
if (!box || this.cancelled)
|
|
58
|
+
return;
|
|
59
|
+
if (this.lastApplied && this.lastApplied.width === box.width && this.lastApplied.height === box.height)
|
|
60
|
+
return;
|
|
61
|
+
this.lastApplied = box;
|
|
62
|
+
this.options.apply(box);
|
|
63
|
+
}
|
|
64
|
+
clearSettle() {
|
|
65
|
+
if (this.timer === null)
|
|
66
|
+
return;
|
|
67
|
+
this.clearTimer(this.timer);
|
|
68
|
+
this.timer = null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=resizeCoalescer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resizeCoalescer.js","sourceRoot":"","sources":["../../../src/react/stream-preview/resizeCoalescer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build `MFPV` frames for tests. Lives beside the parser so the golden-bytes test and the parser
|
|
3
|
+
* cannot drift apart silently. Not exported from the package entry.
|
|
4
|
+
*/
|
|
5
|
+
import { type PreviewPixelFormat } from "./protocol";
|
|
6
|
+
export interface BuildPreviewFrameOptions {
|
|
7
|
+
width?: number;
|
|
8
|
+
height?: number;
|
|
9
|
+
pixelFormat?: PreviewPixelFormat;
|
|
10
|
+
sessionGen?: number;
|
|
11
|
+
frameSeq?: number;
|
|
12
|
+
rotationQuarters?: number;
|
|
13
|
+
/** Raw header codes so a test can send "unknown" (0) and check the fallback. */
|
|
14
|
+
colorMatrixCode?: number;
|
|
15
|
+
colorRangeCode?: number;
|
|
16
|
+
flags?: number;
|
|
17
|
+
timestampNs?: bigint;
|
|
18
|
+
sentAtNs?: bigint;
|
|
19
|
+
/** Byte written into every sample of each plane, so plane views can be told apart. */
|
|
20
|
+
fill?: {
|
|
21
|
+
y?: number;
|
|
22
|
+
u?: number;
|
|
23
|
+
v?: number;
|
|
24
|
+
};
|
|
25
|
+
/** Deliberate corruption, for the rejection tests. Every field overrides what would be written. */
|
|
26
|
+
corrupt?: {
|
|
27
|
+
magic?: readonly number[];
|
|
28
|
+
version?: number;
|
|
29
|
+
headerLen?: number;
|
|
30
|
+
payloadLen?: number;
|
|
31
|
+
/** Payload bytes actually appended, independent of the declared `payloadLen`. */
|
|
32
|
+
payloadBytes?: number;
|
|
33
|
+
pixelFormatCode?: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/** Build a wire-format frame. */
|
|
37
|
+
export declare function buildPreviewFrame(options?: BuildPreviewFrameOptions): ArrayBuffer;
|
|
38
|
+
//# sourceMappingURL=testFrames.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testFrames.d.ts","sourceRoot":"","sources":["../../../src/react/stream-preview/testFrames.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAQL,KAAK,kBAAkB,EACxB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,wBAAwB;IACvC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,kBAAkB,CAAA;IAChC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,gFAAgF;IAChF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,sFAAsF;IACtF,IAAI,CAAC,EAAE;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,CAAC,EAAE,MAAM,CAAA;KAAC,CAAA;IAC3C,mGAAmG;IACnG,OAAO,CAAC,EAAE;QACR,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;QACzB,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,iFAAiF;QACjF,YAAY,CAAC,EAAE,MAAM,CAAA;QACrB,eAAe,CAAC,EAAE,MAAM,CAAA;KACzB,CAAA;CACF;AAED,iCAAiC;AACjC,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,wBAA6B,GAAG,WAAW,CAyCrF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build `MFPV` frames for tests. Lives beside the parser so the golden-bytes test and the parser
|
|
3
|
+
* cannot drift apart silently. Not exported from the package entry.
|
|
4
|
+
*/
|
|
5
|
+
import { chromaDimensions, packedPayloadBytes, PIXEL_FORMAT_I420, PIXEL_FORMAT_NV12, PREVIEW_FRAME_HEADER_BYTES, PREVIEW_FRAME_MAGIC, PREVIEW_FRAME_VERSION, } from "./protocol";
|
|
6
|
+
/** Build a wire-format frame. */
|
|
7
|
+
export function buildPreviewFrame(options = {}) {
|
|
8
|
+
const width = options.width ?? 1280;
|
|
9
|
+
const height = options.height ?? 720;
|
|
10
|
+
const pixelFormat = options.pixelFormat ?? "i420";
|
|
11
|
+
const corrupt = options.corrupt ?? {};
|
|
12
|
+
const chroma = chromaDimensions(width, height);
|
|
13
|
+
const declaredPayload = corrupt.payloadLen ?? packedPayloadBytes(width, height);
|
|
14
|
+
const actualPayload = corrupt.payloadBytes ?? packedPayloadBytes(width, height);
|
|
15
|
+
const buffer = new ArrayBuffer(PREVIEW_FRAME_HEADER_BYTES + actualPayload);
|
|
16
|
+
const header = new DataView(buffer, 0, PREVIEW_FRAME_HEADER_BYTES);
|
|
17
|
+
const magic = corrupt.magic ?? PREVIEW_FRAME_MAGIC;
|
|
18
|
+
for (let index = 0; index < 4; index += 1)
|
|
19
|
+
header.setUint8(index, magic[index] ?? 0);
|
|
20
|
+
header.setUint16(4, corrupt.version ?? PREVIEW_FRAME_VERSION, true);
|
|
21
|
+
header.setUint16(6, corrupt.headerLen ?? PREVIEW_FRAME_HEADER_BYTES, true);
|
|
22
|
+
header.setUint32(8, declaredPayload, true);
|
|
23
|
+
header.setUint32(12, options.sessionGen ?? 1, true);
|
|
24
|
+
header.setUint32(16, options.frameSeq ?? 1, true);
|
|
25
|
+
header.setUint16(20, width, true);
|
|
26
|
+
header.setUint16(22, height, true);
|
|
27
|
+
header.setUint8(24, corrupt.pixelFormatCode ?? (pixelFormat === "nv12" ? PIXEL_FORMAT_NV12 : PIXEL_FORMAT_I420));
|
|
28
|
+
header.setUint8(25, options.rotationQuarters ?? 0);
|
|
29
|
+
header.setUint8(26, options.colorMatrixCode ?? 1);
|
|
30
|
+
header.setUint8(27, options.colorRangeCode ?? 1);
|
|
31
|
+
header.setUint16(28, options.flags ?? 0, true);
|
|
32
|
+
header.setBigInt64(32, options.timestampNs ?? 0n, true);
|
|
33
|
+
header.setBigInt64(40, options.sentAtNs ?? 0n, true);
|
|
34
|
+
const payload = new Uint8Array(buffer, PREVIEW_FRAME_HEADER_BYTES);
|
|
35
|
+
const luma = Math.min(width * height, payload.length);
|
|
36
|
+
const chromaPlane = chroma.width * chroma.height;
|
|
37
|
+
payload.fill(options.fill?.y ?? 0x80, 0, luma);
|
|
38
|
+
if (pixelFormat === "nv12") {
|
|
39
|
+
for (let index = luma; index + 1 < payload.length; index += 2) {
|
|
40
|
+
payload[index] = options.fill?.u ?? 0x40;
|
|
41
|
+
payload[index + 1] = options.fill?.v ?? 0xc0;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
payload.fill(options.fill?.u ?? 0x40, luma, Math.min(luma + chromaPlane, payload.length));
|
|
46
|
+
payload.fill(options.fill?.v ?? 0xc0, Math.min(luma + chromaPlane, payload.length));
|
|
47
|
+
}
|
|
48
|
+
return buffer;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=testFrames.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testFrames.js","sourceRoot":"","sources":["../../../src/react/stream-preview/testFrames.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preview sizing tiers.
|
|
3
|
+
*
|
|
4
|
+
* The page measures its box (CSS pixels × devicePixelRatio, after rotation) and only tells the
|
|
5
|
+
* host when the quantized tier changes, so a resize storm costs at most one reconfigure per tier.
|
|
6
|
+
* The host quantizes again with the same table and is the authority; native never upscales.
|
|
7
|
+
*/
|
|
8
|
+
export interface PreviewTier {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
maxFps: number;
|
|
12
|
+
}
|
|
13
|
+
/** Smallest first. The last entry is the ceiling until measurements justify raising it. */
|
|
14
|
+
export declare const PREVIEW_TIERS: readonly PreviewTier[];
|
|
15
|
+
/**
|
|
16
|
+
* The smallest tier that covers the box, capped at the ceiling. A zero-area box means the preview
|
|
17
|
+
* is hidden and returns null.
|
|
18
|
+
*/
|
|
19
|
+
export declare function quantizePreviewTier(boxWidth: number, boxHeight: number): PreviewTier | null;
|
|
20
|
+
export declare function sameTier(a: PreviewTier | null, b: PreviewTier | null): boolean;
|
|
21
|
+
//# sourceMappingURL=tiers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiers.d.ts","sourceRoot":"","sources":["../../../src/react/stream-preview/tiers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;CACf;AAED,2FAA2F;AAC3F,eAAO,MAAM,aAAa,EAAE,SAAS,WAAW,EAG/C,CAAA;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAM3F;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,WAAW,GAAG,IAAI,EAAE,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAI9E"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preview sizing tiers.
|
|
3
|
+
*
|
|
4
|
+
* The page measures its box (CSS pixels × devicePixelRatio, after rotation) and only tells the
|
|
5
|
+
* host when the quantized tier changes, so a resize storm costs at most one reconfigure per tier.
|
|
6
|
+
* The host quantizes again with the same table and is the authority; native never upscales.
|
|
7
|
+
*/
|
|
8
|
+
/** Smallest first. The last entry is the ceiling until measurements justify raising it. */
|
|
9
|
+
export const PREVIEW_TIERS = [
|
|
10
|
+
{ width: 320, height: 180, maxFps: 15 },
|
|
11
|
+
{ width: 640, height: 360, maxFps: 15 },
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* The smallest tier that covers the box, capped at the ceiling. A zero-area box means the preview
|
|
15
|
+
* is hidden and returns null.
|
|
16
|
+
*/
|
|
17
|
+
export function quantizePreviewTier(boxWidth, boxHeight) {
|
|
18
|
+
if (!(boxWidth > 0) || !(boxHeight > 0))
|
|
19
|
+
return null;
|
|
20
|
+
for (const tier of PREVIEW_TIERS) {
|
|
21
|
+
if (tier.width >= boxWidth && tier.height >= boxHeight)
|
|
22
|
+
return tier;
|
|
23
|
+
}
|
|
24
|
+
return PREVIEW_TIERS[PREVIEW_TIERS.length - 1];
|
|
25
|
+
}
|
|
26
|
+
export function sameTier(a, b) {
|
|
27
|
+
if (a === b)
|
|
28
|
+
return true;
|
|
29
|
+
if (!a || !b)
|
|
30
|
+
return false;
|
|
31
|
+
return a.width === b.width && a.height === b.height && a.maxFps === b.maxFps;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=tiers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tiers.js","sourceRoot":"","sources":["../../../src/react/stream-preview/tiers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,2FAA2F;AAC3F,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,EAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAC;IACrC,EAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE,EAAC;CACtC,CAAA;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,QAAgB,EAAE,SAAiB;IACrE,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACpD,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,KAAK,IAAI,QAAQ,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;YAAE,OAAO,IAAI,CAAA;IACrE,CAAC;IACD,OAAO,aAAa,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAE,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,CAAqB,EAAE,CAAqB;IACnE,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAA;IACxB,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAA;IAC1B,OAAO,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,CAAA;AAC9E,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page-side `PREVIEW_TRACE` lines.
|
|
3
|
+
*
|
|
4
|
+
* Same shape as the host and native layers: a literal grep marker, `phase=`, then `key=value`
|
|
5
|
+
* pairs. The WebView console is forwarded to the host as `dev_log`, so these lines land in the
|
|
6
|
+
* Mentra App log buffer next to the host's and ship with bug reports.
|
|
7
|
+
*
|
|
8
|
+
* Nothing here runs per frame. Per-frame facts are counters.
|
|
9
|
+
*/
|
|
10
|
+
/** Grep marker. Never build this by concatenation — a single grep must be exhaustive. */
|
|
11
|
+
export declare const PREVIEW_TRACE_MARKER = "PREVIEW_TRACE";
|
|
12
|
+
export type PreviewTraceFields = Record<string, string | number | boolean | null | undefined>;
|
|
13
|
+
type Sink = (line: string, level: "log" | "warn") => void;
|
|
14
|
+
/** Render one line. Exported for tests. */
|
|
15
|
+
export declare function formatPreviewTrace(phase: string, fields?: PreviewTraceFields): string;
|
|
16
|
+
export declare function previewTrace(phase: string, fields?: PreviewTraceFields): void;
|
|
17
|
+
export declare function previewTraceWarn(phase: string, fields?: PreviewTraceFields): void;
|
|
18
|
+
/** Warn once per key, then report how many were suppressed at most every 10 s. */
|
|
19
|
+
export declare function previewTraceWarnLimited(key: string, phase: string, fields?: PreviewTraceFields): void;
|
|
20
|
+
/** Test seam: capture lines and drive the clock. Pass nothing to restore the defaults. */
|
|
21
|
+
export declare function setPreviewTraceSinkForTests(next?: Sink, clock?: () => number): void;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=trace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../../src/react/stream-preview/trace.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,yFAAyF;AACzF,eAAO,MAAM,oBAAoB,kBAAkB,CAAA;AAOnD,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAE7F,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,GAAG,MAAM,KAAK,IAAI,CAAA;AAgBzD,2CAA2C;AAC3C,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,kBAAuB,GAAG,MAAM,CASzF;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAE7E;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAEjF;AAID,kFAAkF;AAClF,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAcrG;AAED,0FAA0F;AAC1F,wBAAgB,2BAA2B,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAInF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Page-side `PREVIEW_TRACE` lines.
|
|
3
|
+
*
|
|
4
|
+
* Same shape as the host and native layers: a literal grep marker, `phase=`, then `key=value`
|
|
5
|
+
* pairs. The WebView console is forwarded to the host as `dev_log`, so these lines land in the
|
|
6
|
+
* Mentra App log buffer next to the host's and ship with bug reports.
|
|
7
|
+
*
|
|
8
|
+
* Nothing here runs per frame. Per-frame facts are counters.
|
|
9
|
+
*/
|
|
10
|
+
/** Grep marker. Never build this by concatenation — a single grep must be exhaustive. */
|
|
11
|
+
export const PREVIEW_TRACE_MARKER = "PREVIEW_TRACE";
|
|
12
|
+
const REDACTED = "<redacted>";
|
|
13
|
+
const SENSITIVE_KEYS = ["token", "secret", "password", "authorization", "url", "meetingurl"];
|
|
14
|
+
/** Repeated identical warnings: log the first, then a count at most this often. */
|
|
15
|
+
const RATE_LIMIT_WINDOW_MS = 10000;
|
|
16
|
+
function defaultSink(line, level) {
|
|
17
|
+
if (typeof console === "undefined")
|
|
18
|
+
return;
|
|
19
|
+
if (level === "warn")
|
|
20
|
+
console.warn(line);
|
|
21
|
+
else
|
|
22
|
+
console.log(line);
|
|
23
|
+
}
|
|
24
|
+
let sink = defaultSink;
|
|
25
|
+
let now = () => (typeof performance !== "undefined" ? performance.now() : Date.now());
|
|
26
|
+
function isSensitive(key) {
|
|
27
|
+
const lower = key.toLowerCase();
|
|
28
|
+
return SENSITIVE_KEYS.some((sensitive) => lower.includes(sensitive));
|
|
29
|
+
}
|
|
30
|
+
/** Render one line. Exported for tests. */
|
|
31
|
+
export function formatPreviewTrace(phase, fields = {}) {
|
|
32
|
+
const parts = [`[${PREVIEW_TRACE_MARKER}]`, `layer=page`, `phase=${phase}`];
|
|
33
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
34
|
+
if (value === undefined)
|
|
35
|
+
continue;
|
|
36
|
+
const rendered = isSensitive(key) ? REDACTED : String(value).replace(/\s+/g, "_");
|
|
37
|
+
parts.push(`${key}=${rendered}`);
|
|
38
|
+
}
|
|
39
|
+
parts.push(`t=${Math.round(now())}`);
|
|
40
|
+
return parts.join(" ");
|
|
41
|
+
}
|
|
42
|
+
export function previewTrace(phase, fields) {
|
|
43
|
+
sink(formatPreviewTrace(phase, fields), "log");
|
|
44
|
+
}
|
|
45
|
+
export function previewTraceWarn(phase, fields) {
|
|
46
|
+
sink(formatPreviewTrace(phase, fields), "warn");
|
|
47
|
+
}
|
|
48
|
+
const rateLimited = new Map();
|
|
49
|
+
/** Warn once per key, then report how many were suppressed at most every 10 s. */
|
|
50
|
+
export function previewTraceWarnLimited(key, phase, fields) {
|
|
51
|
+
const at = now();
|
|
52
|
+
const entry = rateLimited.get(key);
|
|
53
|
+
if (!entry) {
|
|
54
|
+
rateLimited.set(key, { firstAt: at, suppressed: 0 });
|
|
55
|
+
previewTraceWarn(phase, fields);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
entry.suppressed += 1;
|
|
59
|
+
if (at - entry.firstAt >= RATE_LIMIT_WINDOW_MS) {
|
|
60
|
+
previewTraceWarn(phase, { ...fields, repeated: entry.suppressed });
|
|
61
|
+
entry.firstAt = at;
|
|
62
|
+
entry.suppressed = 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** Test seam: capture lines and drive the clock. Pass nothing to restore the defaults. */
|
|
66
|
+
export function setPreviewTraceSinkForTests(next, clock) {
|
|
67
|
+
sink = next ?? defaultSink;
|
|
68
|
+
now = clock ?? (() => (typeof performance !== "undefined" ? performance.now() : Date.now()));
|
|
69
|
+
rateLimited.clear();
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=trace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace.js","sourceRoot":"","sources":["../../../src/react/stream-preview/trace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The two ways raw frames reach this WebView, behind one interface.
|
|
3
|
+
*
|
|
4
|
+
* iOS has no way to hand a WebView binary without a copy through JavaScriptCore, so it gets a
|
|
5
|
+
* loopback WebSocket. Android has `WebViewCompat.addWebMessageListener`, which delivers an
|
|
6
|
+
* ArrayBuffer to a JS object the native side installs on `window`. Which one is in use is decided
|
|
7
|
+
* by the host's config, never by the page.
|
|
8
|
+
*
|
|
9
|
+
* Reconnection is not here. Every failure is surfaced with its own reason and `PreviewConnection`
|
|
10
|
+
* decides whether to handshake again.
|
|
11
|
+
*/
|
|
12
|
+
export interface PreviewTransport {
|
|
13
|
+
connect(): Promise<void>;
|
|
14
|
+
onBinary(cb: (buf: ArrayBuffer) => void): void;
|
|
15
|
+
onError(cb: (reason: string) => void): void;
|
|
16
|
+
sendText(json: string): void;
|
|
17
|
+
close(): void;
|
|
18
|
+
}
|
|
19
|
+
/** Carries the machine-readable reason so a caller does not have to match on message text. */
|
|
20
|
+
export declare class PreviewTransportError extends Error {
|
|
21
|
+
readonly reason: string;
|
|
22
|
+
constructor(reason: string);
|
|
23
|
+
}
|
|
24
|
+
/** The Android-side object installed by `WebViewCompat.addWebMessageListener`. */
|
|
25
|
+
export interface PreviewWebMessagePort {
|
|
26
|
+
postMessage(message: string): void;
|
|
27
|
+
addEventListener(type: "message", handler: (event: {
|
|
28
|
+
data: unknown;
|
|
29
|
+
}) => void): void;
|
|
30
|
+
removeEventListener?(type: "message", handler: (event: {
|
|
31
|
+
data: unknown;
|
|
32
|
+
}) => void): void;
|
|
33
|
+
}
|
|
34
|
+
/** Used when an older host config omits `portName`. */
|
|
35
|
+
export declare const DEFAULT_PREVIEW_PORT_NAME = "MentraFramePreviewPort";
|
|
36
|
+
/** `{t:"ack",gen,seq}` — the one message the consumer sends per frame. */
|
|
37
|
+
export declare function ackMessage(gen: number, seq: number): string;
|
|
38
|
+
/** iOS: a loopback WebSocket from the native host. */
|
|
39
|
+
export declare class WebSocketTransport implements PreviewTransport {
|
|
40
|
+
private readonly url;
|
|
41
|
+
private readonly token;
|
|
42
|
+
private socket;
|
|
43
|
+
private binaryHandler;
|
|
44
|
+
private errorHandler;
|
|
45
|
+
private opened;
|
|
46
|
+
private closed;
|
|
47
|
+
constructor(url: string, token: string);
|
|
48
|
+
connect(): Promise<void>;
|
|
49
|
+
onBinary(cb: (buf: ArrayBuffer) => void): void;
|
|
50
|
+
onError(cb: (reason: string) => void): void;
|
|
51
|
+
sendText(json: string): void;
|
|
52
|
+
close(): void;
|
|
53
|
+
private fail;
|
|
54
|
+
}
|
|
55
|
+
/** Android: the JS object native installs with `WebViewCompat.addWebMessageListener`. */
|
|
56
|
+
export declare class WebMessagePortTransport implements PreviewTransport {
|
|
57
|
+
private readonly token;
|
|
58
|
+
private readonly portName;
|
|
59
|
+
private port;
|
|
60
|
+
private binaryHandler;
|
|
61
|
+
private errorHandler;
|
|
62
|
+
private closed;
|
|
63
|
+
private readonly listener;
|
|
64
|
+
constructor(token: string, portName?: string);
|
|
65
|
+
connect(): Promise<void>;
|
|
66
|
+
onBinary(cb: (buf: ArrayBuffer) => void): void;
|
|
67
|
+
onError(cb: (reason: string) => void): void;
|
|
68
|
+
sendText(json: string): void;
|
|
69
|
+
close(): void;
|
|
70
|
+
private report;
|
|
71
|
+
}
|
|
72
|
+
export interface PreviewTransportOptions {
|
|
73
|
+
url?: string;
|
|
74
|
+
portName?: string;
|
|
75
|
+
token: string;
|
|
76
|
+
}
|
|
77
|
+
/** Build the transport the host asked for. The page never picks on its own. */
|
|
78
|
+
export declare function createPreviewTransport(transport: "websocket" | "webmessage", options: PreviewTransportOptions): PreviewTransport;
|
|
79
|
+
//# sourceMappingURL=transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../../src/react/stream-preview/transport.ts"],"names":[],"mappings":"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"}
|