@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.
Files changed (102) hide show
  1. package/README.md +1 -2
  2. package/audio/buffer.d.ts +8 -0
  3. package/audio/buffer.d.ts.map +1 -1
  4. package/audio/decoder.d.ts +25 -15
  5. package/audio/decoder.d.ts.map +1 -1
  6. package/audio/emitter.d.ts +13 -10
  7. package/audio/emitter.d.ts.map +1 -1
  8. package/audio/handover.d.ts +16 -0
  9. package/audio/handover.d.ts.map +1 -0
  10. package/audio/index.d.ts +0 -2
  11. package/audio/index.d.ts.map +1 -1
  12. package/audio/render.d.ts +10 -1
  13. package/audio/render.d.ts.map +1 -1
  14. package/audio/ring-buffer.d.ts +7 -0
  15. package/audio/ring-buffer.d.ts.map +1 -1
  16. package/audio/shared-ring-buffer.d.ts +30 -2
  17. package/audio/shared-ring-buffer.d.ts.map +1 -1
  18. package/audio/source.d.ts +21 -17
  19. package/audio/source.d.ts.map +1 -1
  20. package/audio/subscription.d.ts +10 -0
  21. package/audio/subscription.d.ts.map +1 -0
  22. package/audio/terminal.d.ts +36 -0
  23. package/audio/terminal.d.ts.map +1 -0
  24. package/audio/unlock.d.ts +20 -0
  25. package/audio/unlock.d.ts.map +1 -0
  26. package/audio/warmup.d.ts +9 -0
  27. package/audio/warmup.d.ts.map +1 -0
  28. package/broadcast.d.ts +21 -61
  29. package/broadcast.d.ts.map +1 -1
  30. package/element.d.ts +45 -12
  31. package/element.d.ts.map +1 -1
  32. package/element.js +190 -95
  33. package/element.js.map +1 -1
  34. package/index.d.ts +9 -6
  35. package/index.d.ts.map +1 -1
  36. package/index.js +24 -5
  37. package/index.js.map +1 -0
  38. package/msf.d.ts.map +1 -1
  39. package/package.json +5 -6
  40. package/source-lWNGIbmd.js +1722 -0
  41. package/source-lWNGIbmd.js.map +1 -0
  42. package/support/element.d.ts.map +1 -1
  43. package/support/element.js.map +1 -1
  44. package/support/index.d.ts +3 -3
  45. package/support/index.d.ts.map +1 -1
  46. package/support/index.js +18 -17
  47. package/support/index.js.map +1 -1
  48. package/sync-DNQkgnlX.js +132 -0
  49. package/sync-DNQkgnlX.js.map +1 -0
  50. package/sync.d.ts +42 -22
  51. package/sync.d.ts.map +1 -1
  52. package/ui/components/buffer-control.d.ts +1 -1
  53. package/ui/components/buffer-control.d.ts.map +1 -1
  54. package/ui/components/fullscreen-button.d.ts +1 -2
  55. package/ui/components/fullscreen-button.d.ts.map +1 -1
  56. package/ui/components/play-pause.d.ts +1 -1
  57. package/ui/components/play-pause.d.ts.map +1 -1
  58. package/ui/element.d.ts.map +1 -1
  59. package/ui/element.js +269 -265
  60. package/ui/element.js.map +1 -1
  61. package/ui/fullscreen.d.ts +1 -2
  62. package/ui/fullscreen.d.ts.map +1 -1
  63. package/video/config.d.ts +17 -0
  64. package/video/config.d.ts.map +1 -0
  65. package/video/decoder.d.ts +42 -16
  66. package/video/decoder.d.ts.map +1 -1
  67. package/video/index.d.ts +0 -2
  68. package/video/index.d.ts.map +1 -1
  69. package/video/playhead.d.ts +31 -0
  70. package/video/playhead.d.ts.map +1 -0
  71. package/video/presentation.d.ts +16 -0
  72. package/video/presentation.d.ts.map +1 -0
  73. package/video/renderer.d.ts +14 -17
  74. package/video/renderer.d.ts.map +1 -1
  75. package/video/source.d.ts +23 -20
  76. package/video/source.d.ts.map +1 -1
  77. package/audio/backend.d.ts +0 -26
  78. package/audio/backend.d.ts.map +0 -1
  79. package/audio/mse.d.ts +0 -22
  80. package/audio/mse.d.ts.map +0 -1
  81. package/audio/ring-buffer.test.d.ts +0 -2
  82. package/audio/ring-buffer.test.d.ts.map +0 -1
  83. package/audio/shared-ring-buffer.test.d.ts +0 -2
  84. package/audio/shared-ring-buffer.test.d.ts.map +0 -1
  85. package/backend.d.ts +0 -65
  86. package/backend.d.ts.map +0 -1
  87. package/broadcast-BY0pAaOe.js +0 -1706
  88. package/broadcast-BY0pAaOe.js.map +0 -1
  89. package/buffered.d.ts +0 -19
  90. package/buffered.d.ts.map +0 -1
  91. package/mse.d.ts +0 -19
  92. package/mse.d.ts.map +0 -1
  93. package/sync-D67IxmxJ.js +0 -128
  94. package/sync-D67IxmxJ.js.map +0 -1
  95. package/sync.test.d.ts +0 -2
  96. package/sync.test.d.ts.map +0 -1
  97. package/video/backend.d.ts +0 -25
  98. package/video/backend.d.ts.map +0 -1
  99. package/video/mse.d.ts +0 -23
  100. package/video/mse.d.ts.map +0 -1
  101. package/video/source.test.d.ts +0 -2
  102. 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. Defaults off for `mediaoverquic.com` relays until they support broadcast discovery. |
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
@@ -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,CAOb"}
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"}
@@ -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 { BufferedRanges } from "../buffered";
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 DecoderProps = {
6
- enabled?: boolean | Signal<boolean>;
7
+ export type DecoderInput = {
8
+ enabled: Getter<boolean>;
7
9
  };
8
- export interface AudioStats {
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
- source: Source;
20
- enabled: Signal<boolean>;
21
- readonly context: Getter<AudioContext | undefined>;
22
- readonly root: Getter<AudioNode | undefined>;
23
- readonly sampleRate: Getter<number | undefined>;
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
@@ -1 +1 @@
1
- {"version":3,"file":"decoder.d.ts","sourceRoot":"","sources":["../../src/audio/decoder.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAChC,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIlD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,MAAM,MAAM,YAAY,GAAG;IAE1B,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;CACpC,CAAC;AAEF,MAAM,WAAW,UAAU;IAC1B,wCAAwC;IACxC,aAAa,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,qBAAa,OAAO;;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAGzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,YAAY,GAAG,SAAS,CAAC,CAAiB;IAKnE,QAAQ,CAAC,IAAI,EAAoB,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAG/D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAoB;IAGnE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,UAAU,GAAG,SAAS,CAAC,CAAe;IAI7D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,CAAmB;IAIrE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAiB;IAOlD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,cAAc,CAAC,CAAkB;IAuB3D,YAAY,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,YAAY,EAc/C;IA+VD,KAAK,IAAI,IAAI,CAEZ;IAaD,KAAK,SAEJ;CACD"}
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"}
@@ -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 EmitterProps = {
4
- volume?: number | Signal<number>;
5
- muted?: boolean | Signal<boolean>;
6
- paused?: boolean | Signal<boolean>;
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
- volume: Signal<number>;
12
- muted: Signal<boolean>;
13
- paused: Signal<boolean>;
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
@@ -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;AAC9C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKzC,MAAM,MAAM,YAAY,GAAG;IAC1B,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;CACnC,CAAC;AAGF,qBAAa,OAAO;;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAIvB,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAUxB,YAAY,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,YAAY,EAkFhD;IAED,KAAK,SAEJ;CACD"}
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
@@ -1,6 +1,4 @@
1
- export type * from "./backend";
2
1
  export * from "./decoder";
3
2
  export * from "./emitter";
4
- export * from "./mse";
5
3
  export * from "./source";
6
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/audio/index.ts"],"names":[],"mappings":"AAAA,mBAAmB,WAAW,CAAC;AAC/B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,OAAO,CAAC;AACtB,cAAc,UAAU,CAAC"}
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
- export type Message = InitShared | InitPost | Data | Latency | Reset;
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";
@@ -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;AACrE,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,+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"}
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"}
@@ -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,CA6EvD;IAGD,KAAK,IAAI,IAAI,CAKZ;IAED,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,CAqBnC;CACD"}
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
- constructor(init: SharedRingBufferInit);
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
- /** Current playback timestamp derived from READ position. */
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;AAShC,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;IAE3B,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,qBAAqB,CACpC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,QAAQ,UAAQ,GACd,oBAAoB,CAatB;AA0BD,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;IAQpC,YAAY,IAAI,EAAE,oBAAoB,EAcrC;IAED;;;OAGG;IACH,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,IAAI,CAqExD;IAED;;;OAGG;IACH,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,CAiCnC;IAED,4CAA4C;IAC5C,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAEhC;IAED;;;OAGG;IACH,KAAK,IAAI,IAAI,CAKZ;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,CA6B5C;IAED,6DAA6D;IAC7D,IAAI,SAAS,IAAI,IAAI,CAAC,KAAK,CAG1B;IAED,uDAAuD;IACvD,IAAI,OAAO,IAAI,OAAO,CAErB;IAED;;;;;;OAMG;IACH,IAAI,MAAM,IAAI,MAAM,CAEnB;CACD"}
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 { type Getter, Signal } from "@norskvideo/moq-signals";
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 is supported by the backend.
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 SourceProps = {
13
- broadcast?: Broadcast | Signal<Broadcast | undefined>;
14
- target?: Target | Signal<Target | undefined>;
15
- supported?: 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. It is used by both MSE and Decoder backends.
28
+ * for audio playback. The Decoder consumes whichever rendition it picks.
20
29
  */
21
30
  export declare class Source {
22
31
  #private;
23
- broadcast: Signal<Broadcast | undefined>;
24
- target: Signal<Target | undefined>;
25
- readonly catalog: Getter<Catalog.Audio | undefined>;
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
@@ -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;AAElD,OAAO,EAAU,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAKpC,MAAM,MAAM,MAAM,GAAG;IAEpB,IAAI,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAE1E,MAAM,MAAM,WAAW,GAAG;IACzB,SAAS,CAAC,EAAE,SAAS,GAAG,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAGtD,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAG7C,SAAS,CAAC,EAAE,SAAS,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,qBAAa,MAAM;;IAClB,SAAS,EAAE,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IACzC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAEnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,CAAC;IAGpD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAmB;IAGlF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,GAAG,SAAS,CAAC,CAAe;IAGzD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,CAAgB;IAExE,SAAS,EAAE,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC,CAAC;IAGzC,IAAI,EAAE,IAAI,CAAC;IAIX,YAAY,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,WAAW,EAe1C;IAiFD,KAAK,IAAI,IAAI,CAEZ;CACD"}
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
- export interface BroadcastProps {
21
- connection?: Moq.Connection.Established | Signal<Moq.Connection.Established | undefined>;
22
- announced?: Getter<Set<Moq.Path.Valid>>;
23
- enabled?: boolean | Signal<boolean>;
24
- name?: Moq.Path.Valid | Signal<Moq.Path.Valid>;
25
- reload?: boolean | Signal<boolean>;
26
- catalogFormat?: CatalogFormat | Signal<CatalogFormat | undefined>;
27
- catalog?: Catalog.Root | Signal<Catalog.Root | undefined>;
28
- }
29
- /** A catalog source that optionally reloads automatically when live or offline. */
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
- connection: Signal<Moq.Connection.Established | undefined>;
33
- enabled: Signal<boolean>;
34
- name: Signal<Moq.Path.Valid>;
35
- status: Signal<"live" | "loading" | "offline">;
36
- reload: Signal<boolean>;
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
@@ -1 +1 @@
1
- {"version":3,"file":"broadcast.d.ts","sourceRoot":"","sources":["../src/broadcast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,OAAO,MAAM,mBAAmB,CAAC;AAE7C,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAC;AAErC,OAAO,EAAE,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAI3D,sFAAsF;AACtF,MAAM,MAAM,YAAY,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEtE;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,6CAAmD,CAAC;AAChF,0CAA0C;AAC1C,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,eAAe,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,+EAA+E;AAC/E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,aAAa,GAAG,SAAS,CAGlF;AAED,MAAM,WAAW,cAAc;IAC9B,UAAU,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAIzF,SAAS,CAAC,EAAE,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAIxC,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAGpC,IAAI,CAAC,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAI/C,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAOnC,aAAa,CAAC,EAAE,aAAa,GAAG,MAAM,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;IAOlE,OAAO,CAAC,EAAE,OAAO,CAAC,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;CAC1D;AAED,mFAAmF;AACnF,qBAAa,SAAS;;IACrB,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,GAAG,SAAS,CAAC,CAAC;IAE3D,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC7B,MAAM,yCAAyD;IAC/D,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAGxB,aAAa,EAAE,MAAM,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;IAGjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC,CAAgB;IAIlE,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC;IAU1C,OAAO,SAAgB;IAEvB,YAAY,KAAK,CAAC,EAAE,cAAc,EAajC;IAuGD;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,IAAI,CAahF;IAED,KAAK,SAEJ;CACD"}
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"}