@norskvideo/moq-watch 0.1.2 → 0.1.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/README.md +1 -2
- package/audio/buffer.d.ts +8 -0
- package/audio/buffer.d.ts.map +1 -1
- package/audio/decoder.d.ts +25 -15
- package/audio/decoder.d.ts.map +1 -1
- package/audio/emitter.d.ts +13 -10
- package/audio/emitter.d.ts.map +1 -1
- package/audio/handover.d.ts +16 -0
- package/audio/handover.d.ts.map +1 -0
- package/audio/index.d.ts +0 -2
- package/audio/index.d.ts.map +1 -1
- package/audio/render.d.ts +10 -1
- package/audio/render.d.ts.map +1 -1
- package/audio/ring-buffer.d.ts +7 -0
- package/audio/ring-buffer.d.ts.map +1 -1
- package/audio/shared-ring-buffer.d.ts +30 -2
- package/audio/shared-ring-buffer.d.ts.map +1 -1
- package/audio/source.d.ts +21 -17
- package/audio/source.d.ts.map +1 -1
- package/audio/subscription.d.ts +10 -0
- package/audio/subscription.d.ts.map +1 -0
- package/audio/terminal.d.ts +36 -0
- package/audio/terminal.d.ts.map +1 -0
- package/audio/unlock.d.ts +20 -0
- package/audio/unlock.d.ts.map +1 -0
- package/audio/warmup.d.ts +9 -0
- package/audio/warmup.d.ts.map +1 -0
- package/broadcast.d.ts +21 -61
- package/broadcast.d.ts.map +1 -1
- package/element.d.ts +45 -12
- package/element.d.ts.map +1 -1
- package/element.js +190 -95
- package/element.js.map +1 -1
- package/index.d.ts +9 -6
- package/index.d.ts.map +1 -1
- package/index.js +24 -5
- package/index.js.map +1 -0
- package/msf.d.ts.map +1 -1
- package/package.json +5 -6
- package/source-lWNGIbmd.js +1722 -0
- package/source-lWNGIbmd.js.map +1 -0
- package/support/element.d.ts.map +1 -1
- package/support/element.js.map +1 -1
- package/support/index.d.ts +3 -3
- package/support/index.d.ts.map +1 -1
- package/support/index.js +18 -17
- package/support/index.js.map +1 -1
- package/sync-DNQkgnlX.js +132 -0
- package/sync-DNQkgnlX.js.map +1 -0
- package/sync.d.ts +42 -22
- package/sync.d.ts.map +1 -1
- package/ui/components/buffer-control.d.ts +1 -1
- package/ui/components/buffer-control.d.ts.map +1 -1
- package/ui/components/fullscreen-button.d.ts +1 -2
- package/ui/components/fullscreen-button.d.ts.map +1 -1
- package/ui/components/play-pause.d.ts +1 -1
- package/ui/components/play-pause.d.ts.map +1 -1
- package/ui/element.d.ts.map +1 -1
- package/ui/element.js +269 -265
- package/ui/element.js.map +1 -1
- package/ui/fullscreen.d.ts +1 -2
- package/ui/fullscreen.d.ts.map +1 -1
- package/video/config.d.ts +17 -0
- package/video/config.d.ts.map +1 -0
- package/video/decoder.d.ts +42 -16
- package/video/decoder.d.ts.map +1 -1
- package/video/index.d.ts +0 -2
- package/video/index.d.ts.map +1 -1
- package/video/playhead.d.ts +31 -0
- package/video/playhead.d.ts.map +1 -0
- package/video/presentation.d.ts +16 -0
- package/video/presentation.d.ts.map +1 -0
- package/video/renderer.d.ts +14 -17
- package/video/renderer.d.ts.map +1 -1
- package/video/source.d.ts +23 -20
- package/video/source.d.ts.map +1 -1
- package/audio/backend.d.ts +0 -26
- package/audio/backend.d.ts.map +0 -1
- package/audio/mse.d.ts +0 -22
- package/audio/mse.d.ts.map +0 -1
- package/audio/ring-buffer.test.d.ts +0 -2
- package/audio/ring-buffer.test.d.ts.map +0 -1
- package/audio/shared-ring-buffer.test.d.ts +0 -2
- package/audio/shared-ring-buffer.test.d.ts.map +0 -1
- package/backend.d.ts +0 -65
- package/backend.d.ts.map +0 -1
- package/broadcast-BY0pAaOe.js +0 -1706
- package/broadcast-BY0pAaOe.js.map +0 -1
- package/buffered.d.ts +0 -19
- package/buffered.d.ts.map +0 -1
- package/mse.d.ts +0 -19
- package/mse.d.ts.map +0 -1
- package/sync-D67IxmxJ.js +0 -128
- package/sync-D67IxmxJ.js.map +0 -1
- package/sync.test.d.ts +0 -2
- package/sync.test.d.ts.map +0 -1
- package/video/backend.d.ts +0 -25
- package/video/backend.d.ts.map +0 -1
- package/video/mse.d.ts +0 -23
- package/video/mse.d.ts.map +0 -1
- package/video/source.test.d.ts +0 -2
- package/video/source.test.d.ts.map +0 -1
package/README.md
CHANGED
|
@@ -72,7 +72,7 @@ The simplest way to watch a stream:
|
|
|
72
72
|
| `muted` | boolean | false | Mute audio |
|
|
73
73
|
| `visible` | never, distance, or always | `20%` | When to download video (see below) |
|
|
74
74
|
| `volume` | number | 0.5 | Audio volume (0-1) |
|
|
75
|
-
| `reload` | boolean | true | Wait for (re)announcement before subscribing.
|
|
75
|
+
| `reload` | boolean | true | Wait for (re)announcement before subscribing. Ignored when the relay does not support broadcast discovery. |
|
|
76
76
|
|
|
77
77
|
The `visible` attribute controls when the video track is downloaded, based on the canvas
|
|
78
78
|
position relative to the viewport:
|
|
@@ -129,7 +129,6 @@ The `<moq-watch-ui>` element automatically discovers the nested `<moq-watch>` el
|
|
|
129
129
|
## Features
|
|
130
130
|
|
|
131
131
|
- **WebCodecs decoding** — Hardware-accelerated video and audio decoding
|
|
132
|
-
- **MSE fallback** — Media Source Extensions for broader codec support
|
|
133
132
|
- **Reactive state** — All properties are signals from `@moq/signals`
|
|
134
133
|
- **Chat** — Subscribe to text chat channels
|
|
135
134
|
- **Location** — Peer location and window tracking
|
package/audio/buffer.d.ts
CHANGED
|
@@ -18,6 +18,14 @@ export interface AudioBuffer {
|
|
|
18
18
|
setLatency(samples: number): void;
|
|
19
19
|
/** Flush buffered samples and re-stall, ready to anchor the next utterance (buffered mode). */
|
|
20
20
|
reset(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Drop buffered samples at or after `timestamp`, keeping what is already due.
|
|
23
|
+
*
|
|
24
|
+
* Used when a new track takes over the timeline: its samples overwrite the slots they land on,
|
|
25
|
+
* but the previous track's write-ahead tail would otherwise play once the new audio runs out.
|
|
26
|
+
* Unlike `reset()` this keeps playing, so there's no gap at the handover.
|
|
27
|
+
*/
|
|
28
|
+
truncate(timestamp: Time.Micro): void;
|
|
21
29
|
/**
|
|
22
30
|
* Resolve once the playhead is near enough to decode a frame at `timestamp`. In buffered mode this
|
|
23
31
|
* applies backpressure: it stays pending while decoding `timestamp` would run more than the latency
|
package/audio/buffer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../../src/audio/buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAU,KAAK,MAAM,EAAU,MAAM,cAAc,CAAC;AAwD3D;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,gFAAgF;IAChF,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAE1D,4CAA4C;IAC5C,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,+FAA+F;IAC/F,KAAK,IAAI,IAAI,CAAC;IAEd;;;;;OAKG;IACH,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAEvC,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAElC,gEAAgE;IAChE,KAAK,IAAI,IAAI,CAAC;CACd;AAED,0FAA0F;AAC1F,wBAAgB,yBAAyB,IAAI,OAAO,CAMnD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,QAAQ,UAAQ,GACd,WAAW,
|
|
1
|
+
{"version":3,"file":"buffer.d.ts","sourceRoot":"","sources":["../../src/audio/buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAU,KAAK,MAAM,EAAU,MAAM,cAAc,CAAC;AAwD3D;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,gFAAgF;IAChF,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAE1D,4CAA4C;IAC5C,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IAElC,+FAA+F;IAC/F,KAAK,IAAI,IAAI,CAAC;IAEd;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IAEtC;;;;;OAKG;IACH,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE3C,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAEvC,uDAAuD;IACvD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAElC,gEAAgE;IAChE,KAAK,IAAI,IAAI,CAAC;CACd;AAED,0FAA0F;AAC1F,wBAAgB,yBAAyB,IAAI,OAAO,CAMnD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,gBAAgB,EACzB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,cAAc,EAAE,MAAM,EACtB,QAAQ,UAAQ,GACd,WAAW,CAUb"}
|
package/audio/decoder.d.ts
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
|
+
import * as Catalog from "@norskvideo/moq-hang/catalog";
|
|
2
|
+
import * as Container from "@norskvideo/moq-hang/container";
|
|
1
3
|
import { Time } from "@norskvideo/moq-net";
|
|
2
|
-
import { type Getter, Signal } from "@norskvideo/moq-signals";
|
|
3
|
-
import type
|
|
4
|
+
import { type Getter, type Inputs, type Readonlys, Signal } from "@norskvideo/moq-signals";
|
|
5
|
+
import { type Sync } from "../sync";
|
|
4
6
|
import type { Source } from "./source";
|
|
5
|
-
export type
|
|
6
|
-
enabled
|
|
7
|
+
export type DecoderInput = {
|
|
8
|
+
enabled: Getter<boolean>;
|
|
7
9
|
};
|
|
8
|
-
|
|
10
|
+
type DecoderOutput = {
|
|
11
|
+
context: Signal<AudioContext | undefined>;
|
|
12
|
+
root: Signal<AudioNode | undefined>;
|
|
13
|
+
sampleRate: Signal<number | undefined>;
|
|
14
|
+
stats: Signal<Stats | undefined>;
|
|
15
|
+
timestamp: Signal<Time.Milli | undefined>;
|
|
16
|
+
stalled: Signal<boolean>;
|
|
17
|
+
buffered: Signal<Container.BufferedRanges>;
|
|
18
|
+
};
|
|
19
|
+
/** Cumulative audio statistics since the decoder started. */
|
|
20
|
+
export interface Stats {
|
|
9
21
|
/** Number of encoded bytes received. */
|
|
10
22
|
bytesReceived: number;
|
|
11
23
|
}
|
|
@@ -16,17 +28,15 @@ export interface AudioStats {
|
|
|
16
28
|
*/
|
|
17
29
|
export declare class Decoder {
|
|
18
30
|
#private;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
readonly
|
|
22
|
-
readonly
|
|
23
|
-
|
|
24
|
-
readonly stats: Getter<AudioStats | undefined>;
|
|
25
|
-
readonly timestamp: Getter<Time.Milli | undefined>;
|
|
26
|
-
readonly stalled: Getter<boolean>;
|
|
27
|
-
readonly buffered: Getter<BufferedRanges>;
|
|
28
|
-
constructor(source: Source, props?: DecoderProps);
|
|
31
|
+
readonly in: Readonlys<DecoderInput>;
|
|
32
|
+
readonly source: Source;
|
|
33
|
+
readonly sync: Sync;
|
|
34
|
+
readonly out: Readonlys<DecoderOutput>;
|
|
35
|
+
constructor(source: Source, sync: Sync, props?: Inputs<DecoderInput>);
|
|
29
36
|
reset(): void;
|
|
30
37
|
close(): void;
|
|
38
|
+
static supported: typeof supported;
|
|
31
39
|
}
|
|
40
|
+
declare function supported(config: Catalog.AudioConfig): Promise<boolean>;
|
|
41
|
+
export {};
|
|
32
42
|
//# sourceMappingURL=decoder.d.ts.map
|
package/audio/decoder.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../src/audio/decoder.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../src/audio/decoder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAC7C,OAAO,KAAK,SAAS,MAAM,qBAAqB,CAAC;AAGjD,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAU,KAAK,MAAM,EAAU,KAAK,MAAM,EAAE,KAAK,SAAS,EAAa,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3G,OAAO,EAA6B,KAAK,IAAI,EAAE,MAAM,SAAS,CAAC;AAK/D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAWvC,MAAM,MAAM,YAAY,GAAG;IAE1B,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;CACzB,CAAC;AAEF,KAAK,aAAa,GAAG;IACpB,OAAO,EAAE,MAAM,CAAC,YAAY,GAAG,SAAS,CAAC,CAAC;IAI1C,IAAI,EAAE,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAEpC,UAAU,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACvC,KAAK,EAAE,MAAM,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IAGjC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IAG1C,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAGzB,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;CAC3C,CAAC;AAEF,6DAA6D;AAC7D,MAAM,WAAW,KAAK;IACrB,wCAAwC;IACxC,aAAa,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAAa,OAAO;;IACnB,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAWpB,QAAQ,CAAC,GAAG,2BAAwB;IA0BpC,YAAY,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC,EAanE;IA8bD,KAAK,IAAI,IAAI,CAEZ;IAWD,KAAK,SAEJ;IAGD,MAAM,CAAC,SAAS,mBAAa;CAC7B;AAED,iBAAe,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAsCtE"}
|
package/audio/emitter.d.ts
CHANGED
|
@@ -1,17 +1,20 @@
|
|
|
1
|
-
import { Signal } from "@norskvideo/moq-signals";
|
|
1
|
+
import { type Getter, type Inputs, type Readonlys, Signal } from "@norskvideo/moq-signals";
|
|
2
2
|
import type { Decoder } from "./decoder";
|
|
3
|
-
export type
|
|
4
|
-
volume
|
|
5
|
-
muted
|
|
6
|
-
paused
|
|
3
|
+
export type EmitterInput = {
|
|
4
|
+
volume: Getter<number>;
|
|
5
|
+
muted: Getter<boolean>;
|
|
6
|
+
paused: Getter<boolean>;
|
|
7
|
+
};
|
|
8
|
+
type EmitterOutput = {
|
|
9
|
+
enabled: Signal<boolean>;
|
|
7
10
|
};
|
|
8
11
|
export declare class Emitter {
|
|
9
12
|
#private;
|
|
10
|
-
source: Decoder;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
constructor(source: Decoder, props?: EmitterProps);
|
|
13
|
+
readonly source: Decoder;
|
|
14
|
+
readonly in: Readonlys<EmitterInput>;
|
|
15
|
+
readonly out: Readonlys<EmitterOutput>;
|
|
16
|
+
constructor(source: Decoder, props?: Inputs<EmitterInput>);
|
|
15
17
|
close(): void;
|
|
16
18
|
}
|
|
19
|
+
export {};
|
|
17
20
|
//# sourceMappingURL=emitter.d.ts.map
|
package/audio/emitter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../../src/audio/emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,MAAM,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"emitter.d.ts","sourceRoot":"","sources":["../../src/audio/emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,MAAM,EAAU,KAAK,MAAM,EAAE,KAAK,SAAS,EAAa,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3G,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,MAAM,MAAM,YAAY,GAAG;IAC1B,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAIvB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAGvB,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;CACxB,CAAC;AAEF,KAAK,aAAa,GAAG;IAEpB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;CACzB,CAAC;AAGF,qBAAa,OAAO;;IACnB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IAEzB,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC,YAAY,CAAC,CAAC;IAKrC,QAAQ,CAAC,GAAG,2BAAwB;IAOpC,YAAY,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,YAAY,CAAC,EAoExD;IAED,KAAK,SAEJ;CACD"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tracks whether the audio ring still holds samples from a superseded subscription.
|
|
3
|
+
*
|
|
4
|
+
* The ring outlives the subscription that fills it, so reopening one (a rendition swap, a
|
|
5
|
+
* republished broadcast, a reconnect) leaves the previous subscription's decoded audio buffered.
|
|
6
|
+
* The replacement is the authority from its first frame onwards, so everything the ring holds past
|
|
7
|
+
* that timestamp is stale and has to go.
|
|
8
|
+
*/
|
|
9
|
+
export declare class Handover {
|
|
10
|
+
#private;
|
|
11
|
+
/** Record a subscription opening on the current ring. */
|
|
12
|
+
opened(): void;
|
|
13
|
+
/** Consume one decoded frame and report whether it is the first of a replacement subscription. */
|
|
14
|
+
takeover(): boolean;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=handover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handover.d.ts","sourceRoot":"","sources":["../../src/audio/handover.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,qBAAa,QAAQ;;IAIpB,yDAAyD;IACzD,MAAM,IAAI,IAAI,CAGb;IAED,kGAAkG;IAClG,QAAQ,IAAI,OAAO,CAIlB;CACD"}
|
package/audio/index.d.ts
CHANGED
package/audio/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC"}
|
package/audio/render.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Time } from "@norskvideo/moq-net";
|
|
2
2
|
import type { SharedRingBufferInit } from "./shared-ring-buffer";
|
|
3
|
-
|
|
3
|
+
/** Everything the main thread sends the render worklet over its port. */
|
|
4
|
+
export type Message = InitShared | InitPost | Data | Latency | Reset | Truncate;
|
|
4
5
|
export type ToMain = State;
|
|
5
6
|
/** Init message when SharedArrayBuffer is available. */
|
|
6
7
|
export interface InitShared extends SharedRingBufferInit {
|
|
@@ -18,6 +19,14 @@ export interface InitPost {
|
|
|
18
19
|
export interface Reset {
|
|
19
20
|
type: "reset";
|
|
20
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Drop buffered samples at or after `timestamp`, keeping what is already due (fallback path only;
|
|
24
|
+
* the shared path truncates via Atomics).
|
|
25
|
+
*/
|
|
26
|
+
export interface Truncate {
|
|
27
|
+
type: "truncate";
|
|
28
|
+
timestamp: Time.Micro;
|
|
29
|
+
}
|
|
21
30
|
/** Audio samples sent via postMessage (fallback path only). */
|
|
22
31
|
export interface Data {
|
|
23
32
|
type: "data";
|
package/audio/render.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/audio/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,IAAI,GAAG,OAAO,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/audio/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAEjE,yEAAyE;AACzE,MAAM,MAAM,OAAO,GAAG,UAAU,GAAG,QAAQ,GAAG,IAAI,GAAG,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAC;AAChF,MAAM,MAAM,MAAM,GAAG,KAAK,CAAC;AAE3B,wDAAwD;AACxD,MAAM,WAAW,UAAW,SAAQ,oBAAoB;IACvD,IAAI,EAAE,aAAa,CAAC;CACpB;AAED,sDAAsD;AACtD,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;IAGpB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,0FAA0F;AAC1F,MAAM,WAAW,KAAK;IACrB,IAAI,EAAE,OAAO,CAAC;CACd;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACxB,IAAI,EAAE,UAAU,CAAC;IACjB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC;CACtB;AAED,+DAA+D;AAC/D,MAAM,WAAW,IAAI;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC;CACtB;AAED,gEAAgE;AAChE,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;CACpB;AAED,8EAA8E;AAC9E,MAAM,WAAW,KAAK;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;CACjB"}
|
package/audio/ring-buffer.d.ts
CHANGED
|
@@ -15,6 +15,13 @@ export declare class AudioRingBuffer {
|
|
|
15
15
|
get capacity(): number;
|
|
16
16
|
resize(latency: Time.Milli): void;
|
|
17
17
|
write(timestamp: Time.Micro, data: Float32Array[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Drop buffered samples at or after `timestamp`, keeping whatever is already due.
|
|
20
|
+
*
|
|
21
|
+
* A successor track overwrites the slots its own samples land on, but anything the previous
|
|
22
|
+
* track wrote beyond them would otherwise still play once the successor runs out.
|
|
23
|
+
*/
|
|
24
|
+
truncate(timestamp: Time.Micro): void;
|
|
18
25
|
reset(): void;
|
|
19
26
|
read(output: Float32Array[]): number;
|
|
20
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ring-buffer.d.ts","sourceRoot":"","sources":["../../src/audio/ring-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,qBAAa,eAAe;;IAK3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAU1B,YAAY,KAAK,EAAE;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;QACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACnB,EAqBA;IAMD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,SAAS,IAAI,IAAI,CAAC,KAAK,CAE1B;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAgChC;IAED,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"ring-buffer.d.ts","sourceRoot":"","sources":["../../src/audio/ring-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAEhC,qBAAa,eAAe;;IAK3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAU1B,YAAY,KAAK,EAAE;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC;QACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACnB,EAqBA;IAMD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,IAAI,SAAS,IAAI,IAAI,CAAC,KAAK,CAE1B;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,QAAQ,IAAI,MAAM,CAErB;IAED,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAgChC;IAED,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,CA8EvD;IAED;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAKpC;IAGD,KAAK,IAAI,IAAI,CAKZ;IAED,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,CAqBnC;CACD"}
|
|
@@ -5,8 +5,15 @@ export interface SharedRingBufferInit {
|
|
|
5
5
|
rate: number;
|
|
6
6
|
samples: SharedArrayBuffer;
|
|
7
7
|
control: SharedArrayBuffer;
|
|
8
|
+
state: SharedArrayBuffer;
|
|
8
9
|
buffered: boolean;
|
|
9
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Allocate the shared memory for a ring holding at least `capacity` samples per channel.
|
|
13
|
+
*
|
|
14
|
+
* The capacity is rounded up to a power of two so `slot` can mask instead of taking a
|
|
15
|
+
* remainder; read `init.capacity` back rather than assuming the requested value.
|
|
16
|
+
*/
|
|
10
17
|
export declare function allocSharedRingBuffer(channels: number, capacity: number, rate: number, buffered?: boolean): SharedRingBufferInit;
|
|
11
18
|
export declare class SharedRingBuffer {
|
|
12
19
|
#private;
|
|
@@ -15,7 +22,15 @@ export declare class SharedRingBuffer {
|
|
|
15
22
|
readonly rate: number;
|
|
16
23
|
readonly buffered: boolean;
|
|
17
24
|
readonly init: SharedRingBufferInit;
|
|
18
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Wrap the shared memory described by `init`.
|
|
27
|
+
*
|
|
28
|
+
* Pass `previous` in the worklet when this ring replaces one already being read. `resize`
|
|
29
|
+
* snapshots the playhead on the main thread and hands the replacement over by message, so the
|
|
30
|
+
* reader keeps draining the old ring in the meantime. Carrying its cursor across means those
|
|
31
|
+
* samples are not played twice.
|
|
32
|
+
*/
|
|
33
|
+
constructor(init: SharedRingBufferInit, previous?: SharedRingBuffer);
|
|
19
34
|
/**
|
|
20
35
|
* Insert audio samples at the given timestamp.
|
|
21
36
|
* Main thread only. Handles out-of-order writes, gap filling, and overflow.
|
|
@@ -28,6 +43,14 @@ export declare class SharedRingBuffer {
|
|
|
28
43
|
read(output: Float32Array[]): number;
|
|
29
44
|
/** Update the target latency in samples. */
|
|
30
45
|
setLatency(samples: number): void;
|
|
46
|
+
/**
|
|
47
|
+
* Drop buffered samples at or after `timestamp`, keeping whatever is already due.
|
|
48
|
+
* Main thread only.
|
|
49
|
+
*
|
|
50
|
+
* A successor track overwrites the slots its own samples land on, but anything the previous
|
|
51
|
+
* track wrote beyond them would otherwise still play once the successor runs out.
|
|
52
|
+
*/
|
|
53
|
+
truncate(timestamp: Time.Micro): void;
|
|
31
54
|
/**
|
|
32
55
|
* Flush buffered samples and re-stall, ready to anchor the next utterance (buffered mode).
|
|
33
56
|
* Main thread only. The worklet reader sees STALLED and stops until the next insert.
|
|
@@ -46,7 +69,12 @@ export declare class SharedRingBuffer {
|
|
|
46
69
|
* by READ/WRITE elsewhere.
|
|
47
70
|
*/
|
|
48
71
|
resize(newCapacity: number): SharedRingBuffer;
|
|
49
|
-
/**
|
|
72
|
+
/**
|
|
73
|
+
* Current playback timestamp derived from READ position.
|
|
74
|
+
*
|
|
75
|
+
* Main thread only, and stateful: it advances the unwrapped read position, so it has to be
|
|
76
|
+
* polled rather than sampled once. See `#position`.
|
|
77
|
+
*/
|
|
50
78
|
get timestamp(): Time.Micro;
|
|
51
79
|
/** Whether the buffer is stalled (waiting to fill). */
|
|
52
80
|
get stalled(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared-ring-buffer.d.ts","sourceRoot":"","sources":["../../src/audio/shared-ring-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"shared-ring-buffer.d.ts","sourceRoot":"","sources":["../../src/audio/shared-ring-buffer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAmChC,MAAM,WAAW,oBAAoB;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,iBAAiB,CAAC;IAC3B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,KAAK,EAAE,iBAAiB,CAAC;IAEzB,QAAQ,EAAE,OAAO,CAAC;CAClB;AAOD;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,UAAQ,GACd,oBAAoB,CAgBtB;AAkBD,qBAAa,gBAAgB;;IAC5B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;IAuBpC;;;;;;;OAOG;IACH,YAAY,IAAI,EAAE,oBAAoB,EAAE,QAAQ,CAAC,EAAE,gBAAgB,EAiBlE;IA0CD;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,CAmFxD;IAED;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,CAqDnC;IAED,4CAA4C;IAC5C,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhC;IAED;;;;;;OAMG;IACH,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,GAAG,IAAI,CAcpC;IAED;;;OAGG;IACH,KAAK,IAAI,IAAI,CAMZ;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAqC5C;IAiBD;;;;;OAKG;IACH,IAAI,SAAS,IAAI,IAAI,CAAC,KAAK,CAE1B;IAED,uDAAuD;IACvD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;;;OAMG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;CACD"}
|
package/audio/source.d.ts
CHANGED
|
@@ -1,34 +1,38 @@
|
|
|
1
1
|
import type * as Catalog from "@norskvideo/moq-hang/catalog";
|
|
2
|
-
import
|
|
2
|
+
import type * as Moq from "@norskvideo/moq-net";
|
|
3
|
+
import { type Getter, type Inputs, type Readonlys, Signal } from "@norskvideo/moq-signals";
|
|
3
4
|
import type { Broadcast } from "../broadcast";
|
|
4
|
-
import type { Sync } from "../sync";
|
|
5
5
|
export type Target = {
|
|
6
6
|
name?: string;
|
|
7
7
|
};
|
|
8
8
|
/**
|
|
9
|
-
* A function that checks if an audio configuration
|
|
9
|
+
* A function that checks if an audio configuration can be played.
|
|
10
|
+
*
|
|
11
|
+
* `Decoder.supported` is the WebCodecs probe used by `<moq-watch>`.
|
|
10
12
|
*/
|
|
11
13
|
export type Supported = (config: Catalog.AudioConfig) => Promise<boolean>;
|
|
12
|
-
export type
|
|
13
|
-
broadcast
|
|
14
|
-
target
|
|
15
|
-
supported
|
|
14
|
+
export type SourceInput = {
|
|
15
|
+
broadcast: Getter<Broadcast | undefined>;
|
|
16
|
+
target: Getter<Target | undefined>;
|
|
17
|
+
supported: Getter<Supported | undefined>;
|
|
18
|
+
};
|
|
19
|
+
type SourceOutput = {
|
|
20
|
+
catalog: Signal<Catalog.Audio | undefined>;
|
|
21
|
+
available: Signal<Record<string, Catalog.AudioConfig>>;
|
|
22
|
+
track: Signal<string | undefined>;
|
|
23
|
+
config: Signal<Catalog.AudioConfig | undefined>;
|
|
24
|
+
jitter: Signal<Moq.Time.Milli | undefined>;
|
|
16
25
|
};
|
|
17
26
|
/**
|
|
18
27
|
* Source handles catalog extraction, support checking, and rendition selection
|
|
19
|
-
* for audio playback.
|
|
28
|
+
* for audio playback. The Decoder consumes whichever rendition it picks.
|
|
20
29
|
*/
|
|
21
30
|
export declare class Source {
|
|
22
31
|
#private;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
readonly available: Getter<Record<string, Catalog.AudioConfig>>;
|
|
27
|
-
readonly track: Signal<string | undefined>;
|
|
28
|
-
readonly config: Getter<Catalog.AudioConfig | undefined>;
|
|
29
|
-
supported: Signal<Supported | undefined>;
|
|
30
|
-
sync: Sync;
|
|
31
|
-
constructor(sync: Sync, props?: SourceProps);
|
|
32
|
+
readonly in: Readonlys<SourceInput>;
|
|
33
|
+
readonly out: Readonlys<SourceOutput>;
|
|
34
|
+
constructor(props?: Inputs<SourceInput>);
|
|
32
35
|
close(): void;
|
|
33
36
|
}
|
|
37
|
+
export {};
|
|
34
38
|
//# sourceMappingURL=source.d.ts.map
|
package/audio/source.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/audio/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,OAAO,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/audio/source.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAC;AAErC,OAAO,EAAU,KAAK,MAAM,EAAU,KAAK,MAAM,EAAE,KAAK,SAAS,EAAa,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3G,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAK9C,MAAM,MAAM,MAAM,GAAG;IAEpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE1E,MAAM,MAAM,WAAW,GAAG;IACzB,SAAS,EAAE,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAGzC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAInC,SAAS,EAAE,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;CACzC,CAAC;AAEF,KAAK,YAAY,GAAG;IACnB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IAC3C,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACvD,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAGhD,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;CAC3C,CAAC;AAEF;;;GAGG;AACH,qBAAa,MAAM;;IAClB,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC;IASpC,QAAQ,CAAC,GAAG,0BAAwB;IAIpC,YAAY,KAAK,CAAC,EAAE,MAAM,CAAC,WAAW,CAAC,EAUtC;IAoGD,KAAK,IAAI,IAAI,CAEZ;CACD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type * as Moq from "@norskvideo/moq-net";
|
|
2
|
+
import type { Time } from "@norskvideo/moq-net";
|
|
3
|
+
import type { Effect, Getter } from "@norskvideo/moq-signals";
|
|
4
|
+
/** Opens a live-edge audio subscription and keeps its expiry budget aligned with playback. @internal */
|
|
5
|
+
export declare function subscribe(effect: Effect, { broadcast, track, maxLatency, }: {
|
|
6
|
+
broadcast: Moq.Broadcast.Consumer;
|
|
7
|
+
track: string;
|
|
8
|
+
maxLatency: Getter<Time.Milli>;
|
|
9
|
+
}): Moq.Track.Subscriber;
|
|
10
|
+
//# sourceMappingURL=subscription.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../src/audio/subscription.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAC;AACrC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAEnD,wGAAwG;AACxG,wBAAgB,SAAS,CACxB,MAAM,EAAE,MAAM,EACd,EACC,SAAS,EACT,KAAK,EACL,UAAU,GACV,EAAE;IACF,SAAS,EAAE,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;CAC/B,GACC,GAAG,CAAC,KAAK,CAAC,UAAU,CActB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Time } from "@norskvideo/moq-net";
|
|
2
|
+
interface SampleSpan {
|
|
3
|
+
readonly timestamp: number;
|
|
4
|
+
readonly sampleRate: number;
|
|
5
|
+
readonly numberOfFrames: number;
|
|
6
|
+
}
|
|
7
|
+
interface Update {
|
|
8
|
+
readonly discontinuity: number;
|
|
9
|
+
readonly end?: Time.Micro;
|
|
10
|
+
readonly frame?: {
|
|
11
|
+
readonly timestamp: Time.Micro;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/** The portion of decoded audio that belongs to the source timeline. */
|
|
15
|
+
export interface DecodedSpan {
|
|
16
|
+
/** Source timestamp of the first retained frame. */
|
|
17
|
+
readonly timestamp: Time.Micro;
|
|
18
|
+
/** Decoded frames to skip before copying. */
|
|
19
|
+
readonly frameOffset: number;
|
|
20
|
+
/** Decoded frames to retain after the offset. */
|
|
21
|
+
readonly frames: number;
|
|
22
|
+
}
|
|
23
|
+
/** Track codec epochs and map decoded output onto the source timeline. */
|
|
24
|
+
export declare class Terminal {
|
|
25
|
+
#private;
|
|
26
|
+
/** The exclusive source endpoint most recently received. */
|
|
27
|
+
get end(): Time.Micro | undefined;
|
|
28
|
+
/** Reset state for a new container consumer with Opus pre-skip in 48 kHz frames. */
|
|
29
|
+
clear(preSkip?: number): void;
|
|
30
|
+
/** Apply one ordered consumer result and report whether its codec epoch changed. */
|
|
31
|
+
update(next: Update): boolean;
|
|
32
|
+
/** Remove codec pre-skip and terminal padding from one decoded sample. */
|
|
33
|
+
span(sample: SampleSpan): DecodedSpan;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
36
|
+
//# sourceMappingURL=terminal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/audio/terminal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAErC,UAAU,UAAU;IACnB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CAChC;AAED,UAAU,MAAM;IACf,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAA;KAAE,CAAC;CACpD;AAED,wEAAwE;AACxE,MAAM,WAAW,WAAW;IAC3B,oDAAoD;IACpD,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED,0EAA0E;AAC1E,qBAAa,QAAQ;;IAOpB,4DAA4D;IAC5D,IAAI,GAAG,IAAI,IAAI,CAAC,KAAK,GAAG,SAAS,CAEhC;IAED,oFAAoF;IACpF,KAAK,CAAC,OAAO,SAAI,GAAG,IAAI,CAKvB;IAED,oFAAoF;IACpF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAU5B;IAED,0EAA0E;IAC1E,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,WAAW,CAuBpC;CAMD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Effect } from "@norskvideo/moq-signals";
|
|
2
|
+
/**
|
|
3
|
+
* Resume a suspended {@link AudioContext} from a real user gesture.
|
|
4
|
+
*
|
|
5
|
+
* The context is built at page load, before any user activation can exist, so browsers that
|
|
6
|
+
* gate audio on a gesture reject a `resume()` made then. A single unconditional attempt would
|
|
7
|
+
* fire once, be rejected, and never retry, leaving audio silent. This instead attempts
|
|
8
|
+
* `resume()` immediately (for autoplay-permissive browsers like Chrome with prior engagement),
|
|
9
|
+
* then retries on every `pointerdown`/`keydown` until the context is actually running, dropping
|
|
10
|
+
* the gesture listeners once it is. `pointerdown` and `keydown` cover mouse, touch, pen, and
|
|
11
|
+
* keyboard, and each carries a user activation.
|
|
12
|
+
*
|
|
13
|
+
* Safari also reports an "interrupted" state (a WebKit-only value outside the
|
|
14
|
+
* suspended/running/closed set) and can leave it on its own; mirroring `statechange` into a
|
|
15
|
+
* signal picks that up so the listeners are re-armed or dropped as the state moves.
|
|
16
|
+
*
|
|
17
|
+
* Scoped to `effect`: the listeners are removed when the effect reruns or closes.
|
|
18
|
+
*/
|
|
19
|
+
export declare function unlockOnGesture(effect: Effect, context: AudioContext): void;
|
|
20
|
+
//# sourceMappingURL=unlock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unlock.d.ts","sourceRoot":"","sources":["../../src/audio/unlock.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,MAAM,EAAU,MAAM,cAAc,CAAC;AAEnD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,IAAI,CAe3E"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/** Tracks decoder callbacks discarded during initial playback setup. */
|
|
2
|
+
export declare class Warmup {
|
|
3
|
+
#private;
|
|
4
|
+
/** Create a warm-up window containing `callbacks` decoder callbacks. */
|
|
5
|
+
constructor(callbacks: number);
|
|
6
|
+
/** Consume one callback and report whether it belongs to the warm-up window. */
|
|
7
|
+
drop(): boolean;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=warmup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"warmup.d.ts","sourceRoot":"","sources":["../../src/audio/warmup.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,qBAAa,MAAM;;IAGlB,wEAAwE;IACxE,YAAY,SAAS,EAAE,MAAM,EAE5B;IAED,gFAAgF;IAChF,IAAI,IAAI,OAAO,CAId;CACD"}
|
package/broadcast.d.ts
CHANGED
|
@@ -1,71 +1,31 @@
|
|
|
1
1
|
import * as Catalog from "@norskvideo/moq-hang/catalog";
|
|
2
2
|
import type * as Moq from "@norskvideo/moq-net";
|
|
3
|
-
import { Effect, type Getter, Signal } from "@norskvideo/moq-signals";
|
|
4
|
-
/** Consumes a custom track once subscribed, scoped to the subscription's lifetime. */
|
|
5
|
-
export type ConsumeTrack = (track: Moq.Track, effect: Effect) => void;
|
|
6
|
-
/**
|
|
7
|
-
* Catalog formats accepted by Watch.
|
|
8
|
-
*
|
|
9
|
-
* Watch supports the on-the-wire catalog formats from `@norskvideo/moq-hang`, plus
|
|
10
|
-
* `"hangz"` (the DEFLATE-compressed `catalog.json.z` track) and `"manual"`, where
|
|
11
|
-
* the user supplies the catalog directly without fetching. `"hangz"` is opt-in
|
|
12
|
-
* only: it shares the `.hang` broadcast suffix and is never auto-detected, so set
|
|
13
|
-
* it explicitly via `catalogFormat`.
|
|
14
|
-
*/
|
|
3
|
+
import { Effect, type Getter, type Inputs, type Readonlys, Signal } from "@norskvideo/moq-signals";
|
|
15
4
|
export declare const CATALOG_FORMATS: readonly ["hang", "msf", "hangz", "manual"];
|
|
16
|
-
/** A catalog format accepted by Watch. */
|
|
17
5
|
export type CatalogFormat = (typeof CATALOG_FORMATS)[number];
|
|
18
|
-
/** Parse a catalog format string, returning `undefined` for unknown values. */
|
|
19
6
|
export declare function parseCatalogFormat(value: string | null): CatalogFormat | undefined;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
enabled
|
|
24
|
-
name
|
|
25
|
-
reload
|
|
26
|
-
catalogFormat
|
|
27
|
-
catalog
|
|
28
|
-
}
|
|
29
|
-
|
|
7
|
+
type Status = "offline" | "loading" | "live";
|
|
8
|
+
export type BroadcastInput = {
|
|
9
|
+
connection: Getter<Moq.Connection.Established | undefined>;
|
|
10
|
+
enabled: Getter<boolean>;
|
|
11
|
+
name: Getter<Moq.Path.Valid>;
|
|
12
|
+
reload: Getter<boolean>;
|
|
13
|
+
catalogFormat: Getter<CatalogFormat | undefined>;
|
|
14
|
+
catalog: Getter<Catalog.Root | undefined>;
|
|
15
|
+
};
|
|
16
|
+
type BroadcastOutput = {
|
|
17
|
+
status: Signal<Status>;
|
|
18
|
+
active: Signal<Moq.Broadcast.Consumer | undefined>;
|
|
19
|
+
catalog: Signal<Catalog.Root | undefined>;
|
|
20
|
+
};
|
|
30
21
|
export declare class Broadcast {
|
|
31
22
|
#private;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
catalogFormat: Signal<CatalogFormat | undefined>;
|
|
38
|
-
readonly active: Getter<Moq.Broadcast | undefined>;
|
|
39
|
-
catalog: Signal<Catalog.Root | undefined>;
|
|
40
|
-
signals: Effect;
|
|
41
|
-
constructor(props?: BroadcastProps);
|
|
42
|
-
/**
|
|
43
|
-
* Subscribe to a custom track within this broadcast, following the active broadcast across
|
|
44
|
-
* reconnects. `consume` runs with a freshly-subscribed track and a subscription-scoped effect
|
|
45
|
-
* each time a broadcast becomes active (re-running on reconnect).
|
|
46
|
-
*
|
|
47
|
-
* For a JSON track, wrap the track with a `@norskvideo/moq-json` `Consumer` and read it in a spawned loop
|
|
48
|
-
* (e.g. into a Signal). An application advertises the track in its own catalog section, which it
|
|
49
|
-
* reads back from {@link catalog} (unknown sections pass through the loose schema):
|
|
50
|
-
*
|
|
51
|
-
* ```ts
|
|
52
|
-
* import * as Json from "@norskvideo/moq-json";
|
|
53
|
-
* const scte35 = new Signal<{ splices: number[] } | undefined>(undefined);
|
|
54
|
-
* broadcast.subscribeTrack("scte35.json", Catalog.PRIORITY.catalog, (track, effect) => {
|
|
55
|
-
* const consumer = new Json.Snapshot.Consumer<{ splices: number[] }>(track);
|
|
56
|
-
* effect.spawn(async () => {
|
|
57
|
-
* for (;;) {
|
|
58
|
-
* const next = await Promise.race([effect.cancel, consumer.next()]);
|
|
59
|
-
* if (next === undefined) break;
|
|
60
|
-
* scte35.set(next);
|
|
61
|
-
* }
|
|
62
|
-
* });
|
|
63
|
-
* });
|
|
64
|
-
* ```
|
|
65
|
-
*
|
|
66
|
-
* Returns a function to stop subscribing; also stopped when this broadcast closes.
|
|
67
|
-
*/
|
|
68
|
-
subscribeTrack(name: string, priority: number, consume: ConsumeTrack): () => void;
|
|
23
|
+
readonly in: Readonlys<BroadcastInput>;
|
|
24
|
+
readonly out: Readonlys<BroadcastOutput>;
|
|
25
|
+
constructor(props?: Inputs<BroadcastInput>);
|
|
26
|
+
/** Resolve a rendition's `broadcast` reference to a consumer, or `undefined` if unreachable. */
|
|
27
|
+
relativeBroadcast(effect: Effect, rel: string | undefined): Moq.Broadcast.Consumer | undefined;
|
|
69
28
|
close(): void;
|
|
70
29
|
}
|
|
30
|
+
export {};
|
|
71
31
|
//# sourceMappingURL=broadcast.d.ts.map
|
package/broadcast.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../src/broadcast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../src/broadcast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAG7C,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAU,KAAK,MAAM,EAAE,KAAK,SAAS,EAAa,MAAM,EAAE,MAAM,cAAc,CAAC;AAmD3G,eAAO,MAAM,eAAe,6CAAmD,CAAC;AAChF,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,GAAG,SAAS,CAGlF;AAED,KAAK,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;AAI7C,MAAM,MAAM,cAAc,GAAG;IAC5B,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAI3D,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAGzB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAI7B,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAOxB,aAAa,EAAE,MAAM,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;IAIjD,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;CAC1C,CAAC;AAEF,KAAK,eAAe,GAAG;IACtB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAC;IAKnD,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;CAC1C,CAAC;AAGF,qBAAa,SAAS;;IACrB,QAAQ,CAAC,EAAE,EAAE,SAAS,CAAC,cAAc,CAAC,CAAC;IAOvC,QAAQ,CAAC,GAAG,6BAAwB;IAsBpC,YAAY,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC,EAczC;IAuLD,gGAAgG;IAChG,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC,QAAQ,GAAG,SAAS,CAa7F;IAED,KAAK,SAEJ;CACD"}
|