@langchain/svelte 0.4.7 → 1.0.1

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 (74) hide show
  1. package/README.md +37 -443
  2. package/dist/context.cjs +72 -0
  3. package/dist/context.cjs.map +1 -0
  4. package/dist/context.d.cts +72 -0
  5. package/dist/context.d.cts.map +1 -0
  6. package/dist/context.d.ts +72 -0
  7. package/dist/context.d.ts.map +1 -0
  8. package/dist/context.js +70 -0
  9. package/dist/context.js.map +1 -0
  10. package/dist/index.cjs +32 -316
  11. package/dist/index.d.cts +11 -97
  12. package/dist/index.d.ts +11 -97
  13. package/dist/index.js +10 -290
  14. package/dist/selectors.svelte.cjs +214 -0
  15. package/dist/selectors.svelte.cjs.map +1 -0
  16. package/dist/selectors.svelte.d.cts +146 -0
  17. package/dist/selectors.svelte.d.cts.map +1 -0
  18. package/dist/selectors.svelte.d.ts +146 -0
  19. package/dist/selectors.svelte.d.ts.map +1 -0
  20. package/dist/selectors.svelte.js +204 -0
  21. package/dist/selectors.svelte.js.map +1 -0
  22. package/dist/use-audio-player.svelte.cjs +608 -0
  23. package/dist/use-audio-player.svelte.cjs.map +1 -0
  24. package/dist/use-audio-player.svelte.d.cts +70 -0
  25. package/dist/use-audio-player.svelte.d.cts.map +1 -0
  26. package/dist/use-audio-player.svelte.d.ts +70 -0
  27. package/dist/use-audio-player.svelte.d.ts.map +1 -0
  28. package/dist/use-audio-player.svelte.js +608 -0
  29. package/dist/use-audio-player.svelte.js.map +1 -0
  30. package/dist/use-media-url.svelte.cjs +54 -0
  31. package/dist/use-media-url.svelte.cjs.map +1 -0
  32. package/dist/use-media-url.svelte.d.cts +29 -0
  33. package/dist/use-media-url.svelte.d.cts.map +1 -0
  34. package/dist/use-media-url.svelte.d.ts +29 -0
  35. package/dist/use-media-url.svelte.d.ts.map +1 -0
  36. package/dist/use-media-url.svelte.js +54 -0
  37. package/dist/use-media-url.svelte.js.map +1 -0
  38. package/dist/use-projection.svelte.cjs +62 -0
  39. package/dist/use-projection.svelte.cjs.map +1 -0
  40. package/dist/use-projection.svelte.d.cts +65 -0
  41. package/dist/use-projection.svelte.d.cts.map +1 -0
  42. package/dist/use-projection.svelte.d.ts +65 -0
  43. package/dist/use-projection.svelte.d.ts.map +1 -0
  44. package/dist/use-projection.svelte.js +62 -0
  45. package/dist/use-projection.svelte.js.map +1 -0
  46. package/dist/use-stream.svelte.cjs +193 -0
  47. package/dist/use-stream.svelte.cjs.map +1 -0
  48. package/dist/use-stream.svelte.d.cts +116 -0
  49. package/dist/use-stream.svelte.d.cts.map +1 -0
  50. package/dist/use-stream.svelte.d.ts +116 -0
  51. package/dist/use-stream.svelte.d.ts.map +1 -0
  52. package/dist/use-stream.svelte.js +191 -0
  53. package/dist/use-stream.svelte.js.map +1 -0
  54. package/dist/use-video-player.svelte.cjs +233 -0
  55. package/dist/use-video-player.svelte.cjs.map +1 -0
  56. package/dist/use-video-player.svelte.d.cts +66 -0
  57. package/dist/use-video-player.svelte.d.cts.map +1 -0
  58. package/dist/use-video-player.svelte.d.ts +66 -0
  59. package/dist/use-video-player.svelte.d.ts.map +1 -0
  60. package/dist/use-video-player.svelte.js +233 -0
  61. package/dist/use-video-player.svelte.js.map +1 -0
  62. package/package.json +9 -8
  63. package/dist/index.cjs.map +0 -1
  64. package/dist/index.d.cts.map +0 -1
  65. package/dist/index.d.ts.map +0 -1
  66. package/dist/index.js.map +0 -1
  67. package/dist/stream.custom.cjs +0 -122
  68. package/dist/stream.custom.cjs.map +0 -1
  69. package/dist/stream.custom.js +0 -122
  70. package/dist/stream.custom.js.map +0 -1
  71. package/dist/subagents.cjs +0 -81
  72. package/dist/subagents.cjs.map +0 -1
  73. package/dist/subagents.js +0 -81
  74. package/dist/subagents.js.map +0 -1
@@ -0,0 +1,608 @@
1
+ import { onDestroy } from "svelte";
2
+ //#region src/use-audio-player.svelte.ts
3
+ const DEFAULT_SAMPLE_RATE = 24e3;
4
+ const DEFAULT_CHANNELS = 1;
5
+ const ANALYSER_FFT_SIZE = 512;
6
+ /**
7
+ * Module-level registry of shared readers keyed by {@link MediaBase}
8
+ * identity. Keying on identity (WeakMap) keeps the pump stable
9
+ * across remounts and simultaneous consumers while letting GC
10
+ * reclaim entries alongside their media handles.
11
+ */
12
+ const pumpRegistry = /* @__PURE__ */ new WeakMap();
13
+ function attachToPump(media, listener) {
14
+ let controller = pumpRegistry.get(media);
15
+ if (controller == null) {
16
+ const reader = media.stream.getReader();
17
+ controller = {
18
+ chunks: [],
19
+ finished: false,
20
+ error: void 0,
21
+ listeners: /* @__PURE__ */ new Set()
22
+ };
23
+ pumpRegistry.set(media, controller);
24
+ const owned = controller;
25
+ (async () => {
26
+ try {
27
+ while (true) {
28
+ const { value, done } = await reader.read();
29
+ if (done) break;
30
+ if (value == null || value.byteLength === 0) continue;
31
+ owned.chunks.push(value);
32
+ for (const l of owned.listeners) try {
33
+ l({
34
+ type: "chunk",
35
+ bytes: value
36
+ });
37
+ } catch {}
38
+ }
39
+ owned.finished = true;
40
+ for (const l of owned.listeners) try {
41
+ l({ type: "finished" });
42
+ } catch {}
43
+ } catch (err) {
44
+ owned.error = err;
45
+ for (const l of owned.listeners) try {
46
+ l({
47
+ type: "error",
48
+ error: err
49
+ });
50
+ } catch {}
51
+ } finally {
52
+ try {
53
+ reader.releaseLock();
54
+ } catch {}
55
+ }
56
+ })();
57
+ }
58
+ for (const chunk of controller.chunks) listener({
59
+ type: "chunk",
60
+ bytes: chunk
61
+ });
62
+ if (controller.finished) listener({ type: "finished" });
63
+ if (controller.error != null) listener({
64
+ type: "error",
65
+ error: controller.error
66
+ });
67
+ controller.listeners.add(listener);
68
+ return () => {
69
+ controller.listeners.delete(listener);
70
+ };
71
+ }
72
+ function tryParseWavHeader(bytes) {
73
+ if (bytes.byteLength < 12) return { status: "need-more" };
74
+ if (bytes[0] !== 82 || bytes[1] !== 73 || bytes[2] !== 70 || bytes[3] !== 70 || bytes[8] !== 87 || bytes[9] !== 65 || bytes[10] !== 86 || bytes[11] !== 69) return {
75
+ status: "invalid",
76
+ reason: "not a RIFF/WAVE stream"
77
+ };
78
+ const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
79
+ let fmt = null;
80
+ let offset = 12;
81
+ while (offset + 8 <= bytes.byteLength) {
82
+ const id = String.fromCharCode(bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3]);
83
+ const size = view.getUint32(offset + 4, true);
84
+ const payloadStart = offset + 8;
85
+ if (id === "fmt ") {
86
+ if (payloadStart + 16 > bytes.byteLength) return { status: "need-more" };
87
+ fmt = {
88
+ audioFormat: view.getUint16(payloadStart, true),
89
+ channels: view.getUint16(payloadStart + 2, true),
90
+ sampleRate: view.getUint32(payloadStart + 4, true),
91
+ bitsPerSample: view.getUint16(payloadStart + 14, true)
92
+ };
93
+ if (fmt.audioFormat !== 1) return {
94
+ status: "invalid",
95
+ reason: `unsupported WAV audioFormat=${fmt.audioFormat} (expected 1, linear PCM)`
96
+ };
97
+ if (fmt.bitsPerSample !== 16) return {
98
+ status: "invalid",
99
+ reason: `unsupported WAV bitsPerSample=${fmt.bitsPerSample} (expected 16)`
100
+ };
101
+ } else if (id === "data") {
102
+ if (fmt == null) return {
103
+ status: "invalid",
104
+ reason: "data chunk preceded fmt chunk"
105
+ };
106
+ return {
107
+ status: "parsed",
108
+ format: {
109
+ sampleRate: fmt.sampleRate,
110
+ channels: fmt.channels,
111
+ bitsPerSample: fmt.bitsPerSample
112
+ },
113
+ dataOffset: payloadStart
114
+ };
115
+ }
116
+ offset = payloadStart + size + (size & 1);
117
+ }
118
+ return { status: "need-more" };
119
+ }
120
+ function concatChunks(chunks) {
121
+ if (chunks.length === 1) return chunks[0];
122
+ let total = 0;
123
+ for (const c of chunks) total += c.byteLength;
124
+ const out = new Uint8Array(total);
125
+ let at = 0;
126
+ for (const c of chunks) {
127
+ out.set(c, at);
128
+ at += c.byteLength;
129
+ }
130
+ return out;
131
+ }
132
+ function resolveAudioContextCtor() {
133
+ if (typeof window === "undefined") return void 0;
134
+ return window.AudioContext ?? window.webkitAudioContext;
135
+ }
136
+ function detectStrategy(mimeType, override, pcmPrefixes) {
137
+ if (override === "pcm" || override === "element") return override;
138
+ const m = mimeType ?? "";
139
+ return m === "audio/pcm" || m === "audio/L16" || m.startsWith("audio/pcm;") || m.startsWith("audio/L16;") || m === "audio/wav" || m === "audio/wave" || m === "audio/x-wav" || m === "audio/vnd.wave" || (pcmPrefixes?.some((p) => m.startsWith(p)) ?? false) ? "pcm" : "element";
140
+ }
141
+ function unwrap(input) {
142
+ if (typeof input === "function") return input();
143
+ return input;
144
+ }
145
+ /**
146
+ * Progressive audio playback for {@link AudioMedia} handles with a
147
+ * uniform surface across PCM (streamed) and container
148
+ * (`HTMLAudioElement`) strategies.
149
+ *
150
+ * The Svelte binding mirrors the React / Vue equivalents: reactive
151
+ * state is exposed as getters on the returned handle and templates
152
+ * read `player.status` / `player.currentTime` directly.
153
+ *
154
+ * @param media - Audio handle from `useAudio` (plain value or getter).
155
+ * @param options - Strategy overrides and PCM format hints.
156
+ */
157
+ function useAudioPlayer(media, options) {
158
+ const sampleRate = options?.pcm?.sampleRate ?? DEFAULT_SAMPLE_RATE;
159
+ const channels = options?.pcm?.channels ?? DEFAULT_CHANNELS;
160
+ const pcmPrefixes = options?.pcmMimePrefixes;
161
+ const strategyOverride = options?.strategy ?? "auto";
162
+ const autoPlay = options?.autoPlay ?? false;
163
+ let status = $state("idle");
164
+ let error = $state(void 0);
165
+ let currentTime = $state(0);
166
+ let duration = $state(void 0);
167
+ let level = $state(0);
168
+ let strategyState = $state("element");
169
+ let ctx = null;
170
+ let analyser = null;
171
+ let freqBuf = null;
172
+ let timeBuf = null;
173
+ let rafHandle = null;
174
+ let playStartCtxTime = 0;
175
+ let nextStartTime = 0;
176
+ let shouldPlay = false;
177
+ let pendingChunks = [];
178
+ const activeSources = /* @__PURE__ */ new Set();
179
+ let format = null;
180
+ let upstreamFinished = false;
181
+ let audioEl = null;
182
+ let elementSource = null;
183
+ let pendingResolve = null;
184
+ let pendingReject = null;
185
+ const resolvePending = () => {
186
+ const resolve = pendingResolve;
187
+ pendingResolve = null;
188
+ pendingReject = null;
189
+ resolve?.();
190
+ };
191
+ const rejectPending = (err) => {
192
+ const reject = pendingReject;
193
+ pendingResolve = null;
194
+ pendingReject = null;
195
+ reject?.(err);
196
+ };
197
+ $effect(() => {
198
+ const s = status;
199
+ if (s === "finished" || s === "paused" || s === "idle") resolvePending();
200
+ else if (s === "error") rejectPending(error ?? /* @__PURE__ */ new Error("playback error"));
201
+ });
202
+ const tickAnalyser = () => {
203
+ if (analyser == null) {
204
+ rafHandle = null;
205
+ return;
206
+ }
207
+ if (timeBuf != null) {
208
+ analyser.getByteTimeDomainData(timeBuf);
209
+ let sum = 0;
210
+ for (let i = 0; i < timeBuf.length; i += 1) {
211
+ const v = (timeBuf[i] - 128) / 128;
212
+ sum += v * v;
213
+ }
214
+ level = Math.sqrt(sum / timeBuf.length);
215
+ }
216
+ if (ctx != null && status === "playing") currentTime = ctx.currentTime - playStartCtxTime;
217
+ if (typeof window !== "undefined") rafHandle = window.requestAnimationFrame(tickAnalyser);
218
+ };
219
+ const startAnalyserLoop = () => {
220
+ if (rafHandle != null) return;
221
+ if (typeof window === "undefined") return;
222
+ rafHandle = window.requestAnimationFrame(tickAnalyser);
223
+ };
224
+ const stopAnalyserLoop = () => {
225
+ if (rafHandle == null) return;
226
+ if (typeof window !== "undefined") window.cancelAnimationFrame(rafHandle);
227
+ rafHandle = null;
228
+ level = 0;
229
+ };
230
+ const ensureAnalyser = (context) => {
231
+ if (analyser != null) return analyser;
232
+ const node = context.createAnalyser();
233
+ node.fftSize = ANALYSER_FFT_SIZE;
234
+ node.connect(context.destination);
235
+ analyser = node;
236
+ freqBuf = new Uint8Array(node.frequencyBinCount);
237
+ timeBuf = new Uint8Array(node.fftSize);
238
+ return node;
239
+ };
240
+ const ensureContextForPcm = () => {
241
+ if (ctx != null) return ctx;
242
+ if (format == null) return null;
243
+ const AudioCtx = resolveAudioContextCtor();
244
+ if (AudioCtx == null) {
245
+ error = /* @__PURE__ */ new Error("Web Audio API is not available in this environment");
246
+ status = "error";
247
+ return null;
248
+ }
249
+ const context = new AudioCtx({ sampleRate: format.sampleRate });
250
+ ctx = context;
251
+ nextStartTime = context.currentTime;
252
+ ensureAnalyser(context);
253
+ return context;
254
+ };
255
+ const ensureContextForElement = () => {
256
+ if (ctx != null) return ctx;
257
+ const AudioCtx = resolveAudioContextCtor();
258
+ if (AudioCtx == null) return null;
259
+ const context = new AudioCtx();
260
+ ctx = context;
261
+ ensureAnalyser(context);
262
+ return context;
263
+ };
264
+ const scheduleChunk = (context, bytes) => {
265
+ if (format == null || analyser == null) return;
266
+ const { sampleRate: bufSampleRate, channels: bufChannels } = format;
267
+ const sampleCount = Math.floor(bytes.byteLength / 2);
268
+ if (sampleCount === 0) return;
269
+ const framesPerChannel = Math.floor(sampleCount / bufChannels);
270
+ if (framesPerChannel === 0) return;
271
+ const buffer = context.createBuffer(bufChannels, framesPerChannel, bufSampleRate);
272
+ const view = new DataView(bytes.buffer, bytes.byteOffset, framesPerChannel * bufChannels * 2);
273
+ for (let channel = 0; channel < bufChannels; channel += 1) {
274
+ const channelData = buffer.getChannelData(channel);
275
+ for (let frame = 0; frame < framesPerChannel; frame += 1) {
276
+ const sampleOffset = (frame * bufChannels + channel) * 2;
277
+ const int = view.getInt16(sampleOffset, true);
278
+ channelData[frame] = int < 0 ? int / 32768 : int / 32767;
279
+ }
280
+ }
281
+ const source = context.createBufferSource();
282
+ source.buffer = buffer;
283
+ source.connect(analyser);
284
+ const now = context.currentTime;
285
+ const startAt = Math.max(now, nextStartTime);
286
+ source.start(startAt);
287
+ nextStartTime = startAt + buffer.duration;
288
+ activeSources.add(source);
289
+ source.onended = () => {
290
+ activeSources.delete(source);
291
+ if (activeSources.size === 0 && upstreamFinished && pendingChunks.length === 0) status = "finished";
292
+ };
293
+ };
294
+ const flushPendingPcm = () => {
295
+ if (!shouldPlay) return;
296
+ const context = ensureContextForPcm();
297
+ if (context == null) return;
298
+ if (context.state === "suspended") context.resume();
299
+ const chunks = pendingChunks;
300
+ pendingChunks = [];
301
+ for (const bytes of chunks) scheduleChunk(context, bytes);
302
+ if (chunks.length > 0 && status !== "playing") {
303
+ playStartCtxTime = context.currentTime;
304
+ currentTime = 0;
305
+ status = "playing";
306
+ startAnalyserLoop();
307
+ }
308
+ };
309
+ const play = () => {
310
+ if (unwrap(media) == null) return;
311
+ if (status === "error") return;
312
+ if (strategyState === "pcm") {
313
+ shouldPlay = true;
314
+ if (status !== "playing") status = "buffering";
315
+ const context = ensureContextForPcm();
316
+ if (context != null && context.state === "suspended") context.resume();
317
+ flushPendingPcm();
318
+ return;
319
+ }
320
+ if (audioEl == null) {
321
+ shouldPlay = true;
322
+ status = "buffering";
323
+ return;
324
+ }
325
+ shouldPlay = true;
326
+ const context = ensureContextForElement();
327
+ if (context != null && context.state === "suspended") context.resume();
328
+ audioEl.play().catch((err) => {
329
+ error = err;
330
+ status = "error";
331
+ });
332
+ };
333
+ const pause = () => {
334
+ shouldPlay = false;
335
+ if (strategyState === "pcm") {
336
+ if (ctx != null && ctx.state === "running") ctx.suspend();
337
+ } else audioEl?.pause();
338
+ if (status === "playing" || status === "buffering") status = "paused";
339
+ };
340
+ const stop = () => {
341
+ shouldPlay = false;
342
+ stopAnalyserLoop();
343
+ if (strategyState === "pcm") {
344
+ for (const source of activeSources) try {
345
+ source.stop();
346
+ } catch {}
347
+ activeSources.clear();
348
+ pendingChunks = [];
349
+ nextStartTime = 0;
350
+ } else if (audioEl != null) {
351
+ audioEl.pause();
352
+ audioEl.currentTime = 0;
353
+ }
354
+ const context = ctx;
355
+ ctx = null;
356
+ analyser = null;
357
+ freqBuf = null;
358
+ timeBuf = null;
359
+ elementSource = null;
360
+ if (context != null) context.close();
361
+ currentTime = 0;
362
+ status = unwrap(media) == null ? "idle" : "paused";
363
+ };
364
+ const reset = () => {
365
+ stop();
366
+ error = void 0;
367
+ duration = void 0;
368
+ upstreamFinished = false;
369
+ status = "idle";
370
+ };
371
+ const toggle = () => {
372
+ if (status === "playing") pause();
373
+ else play();
374
+ };
375
+ const playToEnd = () => {
376
+ pendingResolve?.();
377
+ pendingResolve = null;
378
+ pendingReject = null;
379
+ return new Promise((resolve, reject) => {
380
+ pendingResolve = resolve;
381
+ pendingReject = reject;
382
+ play();
383
+ });
384
+ };
385
+ const seek = (seconds) => {
386
+ if (strategyState !== "element") return;
387
+ if (audioEl == null) return;
388
+ audioEl.currentTime = seconds;
389
+ currentTime = seconds;
390
+ };
391
+ const getFrequencyData = () => {
392
+ if (analyser == null || freqBuf == null) return void 0;
393
+ analyser.getByteFrequencyData(freqBuf);
394
+ return freqBuf;
395
+ };
396
+ const getTimeDomainData = () => {
397
+ if (analyser == null || timeBuf == null) return void 0;
398
+ analyser.getByteTimeDomainData(timeBuf);
399
+ return timeBuf;
400
+ };
401
+ let detachPcm = null;
402
+ let detachElement = null;
403
+ const teardownBinding = () => {
404
+ detachPcm?.();
405
+ detachPcm = null;
406
+ detachElement?.();
407
+ detachElement = null;
408
+ const el = audioEl;
409
+ audioEl = null;
410
+ elementSource = null;
411
+ if (el != null) try {
412
+ el.pause();
413
+ el.removeAttribute("src");
414
+ el.load();
415
+ } catch {}
416
+ };
417
+ const bindPcm = (m) => {
418
+ error = void 0;
419
+ status = "buffering";
420
+ currentTime = 0;
421
+ duration = void 0;
422
+ upstreamFinished = false;
423
+ pendingChunks = [];
424
+ const mimeType = m.mimeType ?? "";
425
+ const isRawPcm = mimeType === "audio/pcm" || mimeType === "audio/L16" || mimeType.startsWith("audio/pcm;") || mimeType.startsWith("audio/L16;") || pcmPrefixes != null && pcmPrefixes.some((prefix) => mimeType.startsWith(prefix));
426
+ const isWav = mimeType === "audio/wav" || mimeType === "audio/wave" || mimeType === "audio/x-wav" || mimeType === "audio/vnd.wave";
427
+ if (isRawPcm) format = {
428
+ sampleRate,
429
+ channels,
430
+ bitsPerSample: 16
431
+ };
432
+ else if (isWav) format = null;
433
+ else {
434
+ error = /* @__PURE__ */ new Error(`useAudioPlayer: forced PCM strategy for unsupported mime ${JSON.stringify(mimeType)}`);
435
+ status = "error";
436
+ return () => {};
437
+ }
438
+ const wavHeaderChunks = [];
439
+ let wavHeaderParsed = !isWav;
440
+ let wavHeaderFailed = false;
441
+ const routeChunk = (bytes) => {
442
+ if (wavHeaderFailed) return;
443
+ if (wavHeaderParsed) {
444
+ pendingChunks.push(bytes);
445
+ if (shouldPlay) flushPendingPcm();
446
+ return;
447
+ }
448
+ wavHeaderChunks.push(bytes);
449
+ const combined = concatChunks(wavHeaderChunks);
450
+ const result = tryParseWavHeader(combined);
451
+ if (result.status === "need-more") return;
452
+ if (result.status === "invalid") {
453
+ wavHeaderFailed = true;
454
+ error = /* @__PURE__ */ new Error(`useAudioPlayer: invalid WAV stream: ${result.reason}`);
455
+ status = "error";
456
+ return;
457
+ }
458
+ format = result.format;
459
+ wavHeaderParsed = true;
460
+ wavHeaderChunks.length = 0;
461
+ const tail = combined.subarray(result.dataOffset);
462
+ if (tail.byteLength > 0) {
463
+ pendingChunks.push(tail);
464
+ if (shouldPlay) flushPendingPcm();
465
+ }
466
+ };
467
+ if (autoPlay) shouldPlay = true;
468
+ return attachToPump(m, (event) => {
469
+ switch (event.type) {
470
+ case "chunk":
471
+ routeChunk(event.bytes);
472
+ break;
473
+ case "finished":
474
+ upstreamFinished = true;
475
+ if (pendingChunks.length === 0 && activeSources.size === 0) status = "finished";
476
+ break;
477
+ case "error":
478
+ error = event.error;
479
+ status = "error";
480
+ break;
481
+ }
482
+ });
483
+ };
484
+ const bindElement = (m) => {
485
+ if (typeof window === "undefined") return () => {};
486
+ error = void 0;
487
+ status = "buffering";
488
+ currentTime = 0;
489
+ duration = void 0;
490
+ let cancelled = false;
491
+ m.objectURL.then((resolved) => {
492
+ if (cancelled) return;
493
+ audioEl = new Audio(resolved);
494
+ audioEl.preload = "auto";
495
+ const el = audioEl;
496
+ const onPlay = () => {
497
+ if (status === "error") return;
498
+ const context = ensureContextForElement();
499
+ if (context != null && elementSource == null && el != null) try {
500
+ const src = context.createMediaElementSource(el);
501
+ src.connect(analyser);
502
+ elementSource = src;
503
+ } catch {}
504
+ playStartCtxTime = 0;
505
+ currentTime = el?.currentTime ?? 0;
506
+ status = "playing";
507
+ startAnalyserLoop();
508
+ };
509
+ const onPause = () => {
510
+ if (el != null && el.ended) return;
511
+ if (status === "playing") status = "paused";
512
+ };
513
+ const onEnded = () => {
514
+ status = "finished";
515
+ };
516
+ const onTimeUpdate = () => {
517
+ if (el != null) currentTime = el.currentTime;
518
+ };
519
+ const onLoadedMetadata = () => {
520
+ if (el != null && Number.isFinite(el.duration)) duration = el.duration;
521
+ };
522
+ const onError = () => {
523
+ error = /* @__PURE__ */ new Error("HTMLAudioElement error");
524
+ status = "error";
525
+ };
526
+ el.addEventListener("play", onPlay);
527
+ el.addEventListener("pause", onPause);
528
+ el.addEventListener("ended", onEnded);
529
+ el.addEventListener("timeupdate", onTimeUpdate);
530
+ el.addEventListener("loadedmetadata", onLoadedMetadata);
531
+ el.addEventListener("error", onError);
532
+ if (shouldPlay || autoPlay) el.play().catch((err) => {
533
+ error = err;
534
+ status = "error";
535
+ });
536
+ else status = "paused";
537
+ }, () => {
538
+ if (!cancelled) {
539
+ error = /* @__PURE__ */ new Error("media failed to materialise");
540
+ status = "error";
541
+ }
542
+ });
543
+ return () => {
544
+ cancelled = true;
545
+ try {
546
+ m.revoke();
547
+ } catch {}
548
+ };
549
+ };
550
+ $effect(() => {
551
+ const m = unwrap(media);
552
+ teardownBinding();
553
+ if (m == null) {
554
+ status = "idle";
555
+ error = void 0;
556
+ currentTime = 0;
557
+ duration = void 0;
558
+ level = 0;
559
+ upstreamFinished = false;
560
+ return;
561
+ }
562
+ strategyState = detectStrategy(m.mimeType, strategyOverride, pcmPrefixes);
563
+ if (m.error != null) {
564
+ error = new Error(m.error.message);
565
+ status = "error";
566
+ return;
567
+ }
568
+ if (strategyState === "pcm") detachPcm = bindPcm(m) ?? null;
569
+ else detachElement = bindElement(m);
570
+ });
571
+ onDestroy(() => {
572
+ teardownBinding();
573
+ stop();
574
+ });
575
+ return {
576
+ get status() {
577
+ return status;
578
+ },
579
+ get strategy() {
580
+ return strategyState;
581
+ },
582
+ play,
583
+ pause,
584
+ stop,
585
+ toggle,
586
+ reset,
587
+ playToEnd,
588
+ get currentTime() {
589
+ return currentTime;
590
+ },
591
+ get duration() {
592
+ return duration;
593
+ },
594
+ seek,
595
+ get level() {
596
+ return level;
597
+ },
598
+ getFrequencyData,
599
+ getTimeDomainData,
600
+ get error() {
601
+ return error;
602
+ }
603
+ };
604
+ }
605
+ //#endregion
606
+ export { useAudioPlayer };
607
+
608
+ //# sourceMappingURL=use-audio-player.svelte.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-audio-player.svelte.js","names":[],"sources":["../src/use-audio-player.svelte.ts"],"sourcesContent":["import { onDestroy } from \"svelte\";\nimport type { AudioMedia, MediaBase } from \"@langchain/langgraph-sdk/stream\";\nimport type { ValueOrGetter } from \"./use-projection.svelte.js\";\n\n/**\n * Lifecycle state of an audio or video player returned by\n * {@link useAudioPlayer} and `useVideoPlayer`.\n */\nexport type PlayerStatus =\n | \"idle\"\n | \"buffering\"\n | \"playing\"\n | \"paused\"\n | \"finished\"\n | \"error\";\n\n/** Options for {@link useAudioPlayer}. */\nexport interface UseAudioPlayerOptions {\n /**\n * Begin playback as soon as the first byte arrives (PCM strategy)\n * or the blob settles (`element` strategy). Subject to browser\n * autoplay policies — on sites without a prior user gesture the\n * underlying `play()` may be rejected and the hook transitions to\n * `\"error\"`.\n */\n autoPlay?: boolean;\n /** Overrides for the PCM strategy. Ignored by `element` / WAV. */\n pcm?: {\n /** Sample rate in Hz. Defaults to `24000`. */\n sampleRate?: number;\n /** Channel count. Defaults to `1` (mono). */\n channels?: number;\n };\n /** Additional mime prefixes treated as raw PCM16. */\n pcmMimePrefixes?: readonly string[];\n /** Force a specific playback strategy. Default `\"auto\"`. */\n strategy?: \"auto\" | \"pcm\" | \"element\";\n}\n\n/**\n * Player controls + live state returned by {@link useAudioPlayer}.\n *\n * Live state is exposed via getters on a stable object so templates\n * can read `player.status` / `player.currentTime` without a `.value`\n * hop. Imperative controls are plain functions.\n */\nexport interface AudioPlayerHandle {\n readonly status: PlayerStatus;\n readonly strategy: \"pcm\" | \"element\";\n play(): void;\n pause(): void;\n stop(): void;\n toggle(): void;\n reset(): void;\n playToEnd(): Promise<void>;\n readonly currentTime: number;\n readonly duration: number | undefined;\n seek(seconds: number): void;\n /** RMS level of the last analysed frame, `[0, 1]`. */\n readonly level: number;\n getFrequencyData(): Uint8Array | undefined;\n getTimeDomainData(): Uint8Array | undefined;\n readonly error: Error | undefined;\n}\n\nconst DEFAULT_SAMPLE_RATE = 24_000;\nconst DEFAULT_CHANNELS = 1;\nconst ANALYSER_FFT_SIZE = 512;\n\ninterface AudioFormat {\n readonly sampleRate: number;\n readonly channels: number;\n readonly bitsPerSample: number;\n}\n\ntype PumpEvent =\n | { readonly type: \"chunk\"; readonly bytes: Uint8Array }\n | { readonly type: \"finished\" }\n | { readonly type: \"error\"; readonly error: Error };\n\ntype PumpListener = (event: PumpEvent) => void;\n\ninterface PumpController {\n readonly chunks: Uint8Array[];\n finished: boolean;\n error: Error | undefined;\n readonly listeners: Set<PumpListener>;\n}\n\n/**\n * Module-level registry of shared readers keyed by {@link MediaBase}\n * identity. Keying on identity (WeakMap) keeps the pump stable\n * across remounts and simultaneous consumers while letting GC\n * reclaim entries alongside their media handles.\n */\nconst pumpRegistry = new WeakMap<MediaBase, PumpController>();\n\nfunction attachToPump(media: MediaBase, listener: PumpListener): () => void {\n let controller = pumpRegistry.get(media);\n if (controller == null) {\n const reader = media.stream.getReader();\n controller = {\n chunks: [],\n finished: false,\n error: undefined,\n listeners: new Set<PumpListener>(),\n };\n pumpRegistry.set(media, controller);\n const owned = controller;\n void (async () => {\n try {\n // oxlint-disable-next-line no-constant-condition\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n if (value == null || value.byteLength === 0) continue;\n owned.chunks.push(value);\n for (const l of owned.listeners) {\n try {\n l({ type: \"chunk\", bytes: value });\n } catch {\n // A misbehaving listener must not take down the pump.\n }\n }\n }\n owned.finished = true;\n for (const l of owned.listeners) {\n try {\n l({ type: \"finished\" });\n } catch {\n // Swallow — see above.\n }\n }\n } catch (err) {\n owned.error = err as Error;\n for (const l of owned.listeners) {\n try {\n l({ type: \"error\", error: err as Error });\n } catch {\n // Swallow — see above.\n }\n }\n } finally {\n try {\n reader.releaseLock();\n } catch {\n // best-effort\n }\n }\n })();\n }\n\n for (const chunk of controller.chunks) {\n listener({ type: \"chunk\", bytes: chunk });\n }\n if (controller.finished) listener({ type: \"finished\" });\n if (controller.error != null) {\n listener({ type: \"error\", error: controller.error });\n }\n\n controller.listeners.add(listener);\n\n return () => {\n controller!.listeners.delete(listener);\n };\n}\n\ntype WavHeaderResult =\n | { readonly status: \"need-more\" }\n | { readonly status: \"invalid\"; readonly reason: string }\n | {\n readonly status: \"parsed\";\n readonly format: AudioFormat;\n readonly dataOffset: number;\n };\n\nfunction tryParseWavHeader(bytes: Uint8Array): WavHeaderResult {\n if (bytes.byteLength < 12) return { status: \"need-more\" };\n\n if (\n bytes[0] !== 0x52 ||\n bytes[1] !== 0x49 ||\n bytes[2] !== 0x46 ||\n bytes[3] !== 0x46 ||\n bytes[8] !== 0x57 ||\n bytes[9] !== 0x41 ||\n bytes[10] !== 0x56 ||\n bytes[11] !== 0x45\n ) {\n return { status: \"invalid\", reason: \"not a RIFF/WAVE stream\" };\n }\n\n const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n let fmt: {\n audioFormat: number;\n sampleRate: number;\n channels: number;\n bitsPerSample: number;\n } | null = null;\n\n let offset = 12;\n while (offset + 8 <= bytes.byteLength) {\n const id = String.fromCharCode(\n bytes[offset]!,\n bytes[offset + 1]!,\n bytes[offset + 2]!,\n bytes[offset + 3]!\n );\n const size = view.getUint32(offset + 4, true);\n const payloadStart = offset + 8;\n\n if (id === \"fmt \") {\n if (payloadStart + 16 > bytes.byteLength) return { status: \"need-more\" };\n fmt = {\n audioFormat: view.getUint16(payloadStart, true),\n channels: view.getUint16(payloadStart + 2, true),\n sampleRate: view.getUint32(payloadStart + 4, true),\n bitsPerSample: view.getUint16(payloadStart + 14, true),\n };\n if (fmt.audioFormat !== 1) {\n return {\n status: \"invalid\",\n reason: `unsupported WAV audioFormat=${fmt.audioFormat} (expected 1, linear PCM)`,\n };\n }\n if (fmt.bitsPerSample !== 16) {\n return {\n status: \"invalid\",\n reason: `unsupported WAV bitsPerSample=${fmt.bitsPerSample} (expected 16)`,\n };\n }\n } else if (id === \"data\") {\n if (fmt == null) {\n return { status: \"invalid\", reason: \"data chunk preceded fmt chunk\" };\n }\n return {\n status: \"parsed\",\n format: {\n sampleRate: fmt.sampleRate,\n channels: fmt.channels,\n bitsPerSample: fmt.bitsPerSample,\n },\n dataOffset: payloadStart,\n };\n }\n\n offset = payloadStart + size + (size & 1);\n }\n\n return { status: \"need-more\" };\n}\n\nfunction concatChunks(chunks: readonly Uint8Array[]): Uint8Array {\n if (chunks.length === 1) return chunks[0]!;\n let total = 0;\n for (const c of chunks) total += c.byteLength;\n const out = new Uint8Array(total);\n let at = 0;\n for (const c of chunks) {\n out.set(c, at);\n at += c.byteLength;\n }\n return out;\n}\n\nfunction resolveAudioContextCtor(): typeof AudioContext | undefined {\n if (typeof window === \"undefined\") return undefined;\n return (\n (window as unknown as { AudioContext?: typeof AudioContext })\n .AudioContext ??\n (window as unknown as { webkitAudioContext?: typeof AudioContext })\n .webkitAudioContext\n );\n}\n\nfunction detectStrategy(\n mimeType: string | undefined,\n override: UseAudioPlayerOptions[\"strategy\"],\n pcmPrefixes: readonly string[] | undefined\n): \"pcm\" | \"element\" {\n if (override === \"pcm\" || override === \"element\") return override;\n const m = mimeType ?? \"\";\n const isPcm =\n m === \"audio/pcm\" ||\n m === \"audio/L16\" ||\n m.startsWith(\"audio/pcm;\") ||\n m.startsWith(\"audio/L16;\") ||\n m === \"audio/wav\" ||\n m === \"audio/wave\" ||\n m === \"audio/x-wav\" ||\n m === \"audio/vnd.wave\" ||\n (pcmPrefixes?.some((p) => m.startsWith(p)) ?? false);\n return isPcm ? \"pcm\" : \"element\";\n}\n\nfunction unwrap<T>(input: ValueOrGetter<T>): T {\n if (typeof input === \"function\") return (input as () => T)();\n return input;\n}\n\n/**\n * Progressive audio playback for {@link AudioMedia} handles with a\n * uniform surface across PCM (streamed) and container\n * (`HTMLAudioElement`) strategies.\n *\n * The Svelte binding mirrors the React / Vue equivalents: reactive\n * state is exposed as getters on the returned handle and templates\n * read `player.status` / `player.currentTime` directly.\n *\n * @param media - Audio handle from `useAudio` (plain value or getter).\n * @param options - Strategy overrides and PCM format hints.\n */\nexport function useAudioPlayer(\n media: ValueOrGetter<AudioMedia | undefined>,\n options?: UseAudioPlayerOptions\n): AudioPlayerHandle {\n const sampleRate = options?.pcm?.sampleRate ?? DEFAULT_SAMPLE_RATE;\n const channels = options?.pcm?.channels ?? DEFAULT_CHANNELS;\n const pcmPrefixes = options?.pcmMimePrefixes;\n const strategyOverride = options?.strategy ?? \"auto\";\n const autoPlay = options?.autoPlay ?? false;\n\n let status = $state<PlayerStatus>(\"idle\");\n let error = $state<Error | undefined>(undefined);\n let currentTime = $state(0);\n let duration = $state<number | undefined>(undefined);\n let level = $state(0);\n let strategyState = $state<\"pcm\" | \"element\">(\"element\");\n\n // ── Shared state (not reactive) ─────────────────────────────────────\n let ctx: AudioContext | null = null;\n let analyser: AnalyserNode | null = null;\n let freqBuf: Uint8Array<ArrayBuffer> | null = null;\n let timeBuf: Uint8Array<ArrayBuffer> | null = null;\n let rafHandle: number | null = null;\n let playStartCtxTime = 0;\n\n // ── PCM strategy state ──────────────────────────────────────────────\n let nextStartTime = 0;\n let shouldPlay = false;\n let pendingChunks: Uint8Array[] = [];\n const activeSources = new Set<AudioBufferSourceNode>();\n let format: AudioFormat | null = null;\n let upstreamFinished = false;\n\n // ── Element strategy state ──────────────────────────────────────────\n let audioEl: HTMLAudioElement | null = null;\n let elementSource: MediaElementAudioSourceNode | null = null;\n\n // ── `playToEnd` bookkeeping ─────────────────────────────────────────\n let pendingResolve: (() => void) | null = null;\n let pendingReject: ((err: Error) => void) | null = null;\n\n const resolvePending = () => {\n const resolve = pendingResolve;\n pendingResolve = null;\n pendingReject = null;\n resolve?.();\n };\n const rejectPending = (err: Error) => {\n const reject = pendingReject;\n pendingResolve = null;\n pendingReject = null;\n reject?.(err);\n };\n\n // Fire pending resolvers whenever status enters a terminal state.\n $effect(() => {\n const s = status;\n if (s === \"finished\" || s === \"paused\" || s === \"idle\") {\n resolvePending();\n } else if (s === \"error\") {\n rejectPending(error ?? new Error(\"playback error\"));\n }\n });\n\n // ── Analyser loop ───────────────────────────────────────────────────\n const tickAnalyser = () => {\n if (analyser == null) {\n rafHandle = null;\n return;\n }\n if (timeBuf != null) {\n analyser.getByteTimeDomainData(timeBuf);\n let sum = 0;\n for (let i = 0; i < timeBuf.length; i += 1) {\n const v = (timeBuf[i]! - 128) / 128;\n sum += v * v;\n }\n level = Math.sqrt(sum / timeBuf.length);\n }\n if (ctx != null && status === \"playing\") {\n currentTime = ctx.currentTime - playStartCtxTime;\n }\n if (typeof window !== \"undefined\") {\n rafHandle = window.requestAnimationFrame(tickAnalyser);\n }\n };\n\n const startAnalyserLoop = () => {\n if (rafHandle != null) return;\n if (typeof window === \"undefined\") return;\n rafHandle = window.requestAnimationFrame(tickAnalyser);\n };\n\n const stopAnalyserLoop = () => {\n if (rafHandle == null) return;\n if (typeof window !== \"undefined\") {\n window.cancelAnimationFrame(rafHandle);\n }\n rafHandle = null;\n level = 0;\n };\n\n // ── AudioContext / AnalyserNode ─────────────────────────────────────\n const ensureAnalyser = (context: AudioContext): AnalyserNode => {\n if (analyser != null) return analyser;\n const node = context.createAnalyser();\n node.fftSize = ANALYSER_FFT_SIZE;\n node.connect(context.destination);\n analyser = node;\n freqBuf = new Uint8Array(node.frequencyBinCount);\n timeBuf = new Uint8Array(node.fftSize);\n return node;\n };\n\n const ensureContextForPcm = (): AudioContext | null => {\n if (ctx != null) return ctx;\n if (format == null) return null;\n const AudioCtx = resolveAudioContextCtor();\n if (AudioCtx == null) {\n error = new Error(\"Web Audio API is not available in this environment\");\n status = \"error\";\n return null;\n }\n const context = new AudioCtx({ sampleRate: format.sampleRate });\n ctx = context;\n nextStartTime = context.currentTime;\n ensureAnalyser(context);\n return context;\n };\n\n const ensureContextForElement = (): AudioContext | null => {\n if (ctx != null) return ctx;\n const AudioCtx = resolveAudioContextCtor();\n if (AudioCtx == null) return null;\n const context = new AudioCtx();\n ctx = context;\n ensureAnalyser(context);\n return context;\n };\n\n // ── PCM scheduling ──────────────────────────────────────────────────\n const scheduleChunk = (context: AudioContext, bytes: Uint8Array) => {\n if (format == null || analyser == null) return;\n const { sampleRate: bufSampleRate, channels: bufChannels } = format;\n\n const sampleCount = Math.floor(bytes.byteLength / 2);\n if (sampleCount === 0) return;\n const framesPerChannel = Math.floor(sampleCount / bufChannels);\n if (framesPerChannel === 0) return;\n\n const buffer = context.createBuffer(\n bufChannels,\n framesPerChannel,\n bufSampleRate\n );\n const view = new DataView(\n bytes.buffer,\n bytes.byteOffset,\n framesPerChannel * bufChannels * 2\n );\n for (let channel = 0; channel < bufChannels; channel += 1) {\n const channelData = buffer.getChannelData(channel);\n for (let frame = 0; frame < framesPerChannel; frame += 1) {\n const sampleOffset = (frame * bufChannels + channel) * 2;\n const int = view.getInt16(sampleOffset, true);\n channelData[frame] = int < 0 ? int / 0x8000 : int / 0x7fff;\n }\n }\n\n const source = context.createBufferSource();\n source.buffer = buffer;\n source.connect(analyser);\n const now = context.currentTime;\n const startAt = Math.max(now, nextStartTime);\n source.start(startAt);\n nextStartTime = startAt + buffer.duration;\n activeSources.add(source);\n source.onended = () => {\n activeSources.delete(source);\n if (\n activeSources.size === 0 &&\n upstreamFinished &&\n pendingChunks.length === 0\n ) {\n status = \"finished\";\n }\n };\n };\n\n const flushPendingPcm = () => {\n if (!shouldPlay) return;\n const context = ensureContextForPcm();\n if (context == null) return;\n if (context.state === \"suspended\") void context.resume();\n const chunks = pendingChunks;\n pendingChunks = [];\n for (const bytes of chunks) scheduleChunk(context, bytes);\n if (chunks.length > 0 && status !== \"playing\") {\n playStartCtxTime = context.currentTime;\n currentTime = 0;\n status = \"playing\";\n startAnalyserLoop();\n }\n };\n\n // ── Public controls ─────────────────────────────────────────────────\n const play = () => {\n const m = unwrap(media);\n if (m == null) return;\n if (status === \"error\") return;\n\n if (strategyState === \"pcm\") {\n shouldPlay = true;\n if (status !== \"playing\") status = \"buffering\";\n const context = ensureContextForPcm();\n if (context != null && context.state === \"suspended\") {\n void context.resume();\n }\n flushPendingPcm();\n return;\n }\n\n if (audioEl == null) {\n shouldPlay = true;\n status = \"buffering\";\n return;\n }\n shouldPlay = true;\n const context = ensureContextForElement();\n if (context != null && context.state === \"suspended\") {\n void context.resume();\n }\n audioEl.play().catch((err) => {\n error = err as Error;\n status = \"error\";\n });\n };\n\n const pause = () => {\n shouldPlay = false;\n if (strategyState === \"pcm\") {\n if (ctx != null && ctx.state === \"running\") void ctx.suspend();\n } else {\n audioEl?.pause();\n }\n if (status === \"playing\" || status === \"buffering\") {\n status = \"paused\";\n }\n };\n\n const stop = () => {\n shouldPlay = false;\n stopAnalyserLoop();\n\n if (strategyState === \"pcm\") {\n for (const source of activeSources) {\n try {\n source.stop();\n } catch {\n // Already stopped\n }\n }\n activeSources.clear();\n pendingChunks = [];\n nextStartTime = 0;\n } else if (audioEl != null) {\n audioEl.pause();\n audioEl.currentTime = 0;\n }\n\n const context = ctx;\n ctx = null;\n analyser = null;\n freqBuf = null;\n timeBuf = null;\n elementSource = null;\n if (context != null) void context.close();\n\n currentTime = 0;\n status = unwrap(media) == null ? \"idle\" : \"paused\";\n };\n\n const reset = () => {\n stop();\n error = undefined;\n duration = undefined;\n upstreamFinished = false;\n status = \"idle\";\n };\n\n const toggle = () => {\n if (status === \"playing\") pause();\n else play();\n };\n\n const playToEnd = (): Promise<void> => {\n pendingResolve?.();\n pendingResolve = null;\n pendingReject = null;\n return new Promise<void>((resolve, reject) => {\n pendingResolve = resolve;\n pendingReject = reject;\n play();\n });\n };\n\n const seek = (seconds: number) => {\n if (strategyState !== \"element\") return;\n if (audioEl == null) return;\n audioEl.currentTime = seconds;\n currentTime = seconds;\n };\n\n const getFrequencyData = (): Uint8Array | undefined => {\n if (analyser == null || freqBuf == null) return undefined;\n analyser.getByteFrequencyData(freqBuf);\n return freqBuf;\n };\n\n const getTimeDomainData = (): Uint8Array | undefined => {\n if (analyser == null || timeBuf == null) return undefined;\n analyser.getByteTimeDomainData(timeBuf);\n return timeBuf;\n };\n\n // ── Media binding ───────────────────────────────────────────────────\n let detachPcm: (() => void) | null = null;\n let detachElement: (() => void) | null = null;\n\n const teardownBinding = () => {\n detachPcm?.();\n detachPcm = null;\n detachElement?.();\n detachElement = null;\n const el = audioEl;\n audioEl = null;\n elementSource = null;\n if (el != null) {\n try {\n el.pause();\n el.removeAttribute(\"src\");\n el.load();\n } catch {\n // best-effort teardown\n }\n }\n };\n\n const bindPcm = (m: AudioMedia) => {\n error = undefined;\n status = \"buffering\";\n currentTime = 0;\n duration = undefined;\n upstreamFinished = false;\n pendingChunks = [];\n\n const mimeType = m.mimeType ?? \"\";\n const isRawPcm =\n mimeType === \"audio/pcm\" ||\n mimeType === \"audio/L16\" ||\n mimeType.startsWith(\"audio/pcm;\") ||\n mimeType.startsWith(\"audio/L16;\") ||\n (pcmPrefixes != null &&\n pcmPrefixes.some((prefix) => mimeType.startsWith(prefix)));\n const isWav =\n mimeType === \"audio/wav\" ||\n mimeType === \"audio/wave\" ||\n mimeType === \"audio/x-wav\" ||\n mimeType === \"audio/vnd.wave\";\n\n if (isRawPcm) {\n format = { sampleRate, channels, bitsPerSample: 16 };\n } else if (isWav) {\n format = null;\n } else {\n error = new Error(\n `useAudioPlayer: forced PCM strategy for unsupported mime ${JSON.stringify(mimeType)}`\n );\n status = \"error\";\n return () => {};\n }\n\n const wavHeaderChunks: Uint8Array[] = [];\n let wavHeaderParsed = !isWav;\n let wavHeaderFailed = false;\n\n const routeChunk = (bytes: Uint8Array) => {\n if (wavHeaderFailed) return;\n\n if (wavHeaderParsed) {\n pendingChunks.push(bytes);\n if (shouldPlay) flushPendingPcm();\n return;\n }\n\n wavHeaderChunks.push(bytes);\n const combined = concatChunks(wavHeaderChunks);\n const result = tryParseWavHeader(combined);\n if (result.status === \"need-more\") return;\n if (result.status === \"invalid\") {\n wavHeaderFailed = true;\n error = new Error(\n `useAudioPlayer: invalid WAV stream: ${result.reason}`\n );\n status = \"error\";\n return;\n }\n\n format = result.format;\n wavHeaderParsed = true;\n wavHeaderChunks.length = 0;\n\n const tail = combined.subarray(result.dataOffset);\n if (tail.byteLength > 0) {\n pendingChunks.push(tail);\n if (shouldPlay) flushPendingPcm();\n }\n };\n\n if (autoPlay) shouldPlay = true;\n\n return attachToPump(m, (event) => {\n switch (event.type) {\n case \"chunk\":\n routeChunk(event.bytes);\n break;\n case \"finished\":\n upstreamFinished = true;\n if (pendingChunks.length === 0 && activeSources.size === 0) {\n status = \"finished\";\n }\n break;\n case \"error\":\n error = event.error;\n status = \"error\";\n break;\n }\n });\n };\n\n const bindElement = (m: AudioMedia): (() => void) => {\n if (typeof window === \"undefined\") return () => {};\n error = undefined;\n status = \"buffering\";\n currentTime = 0;\n duration = undefined;\n\n let cancelled = false;\n\n m.objectURL.then(\n (resolved) => {\n if (cancelled) return;\n audioEl = new Audio(resolved);\n audioEl.preload = \"auto\";\n\n const el = audioEl;\n const onPlay = () => {\n if (status === \"error\") return;\n const context = ensureContextForElement();\n if (context != null && elementSource == null && el != null) {\n try {\n const src = context.createMediaElementSource(el);\n src.connect(analyser!);\n elementSource = src;\n } catch {\n // Some browsers reject a second createMediaElementSource\n // on the same element; fall through without visualization.\n }\n }\n playStartCtxTime = 0;\n currentTime = el?.currentTime ?? 0;\n status = \"playing\";\n startAnalyserLoop();\n };\n const onPause = () => {\n if (el != null && el.ended) return;\n if (status === \"playing\") status = \"paused\";\n };\n const onEnded = () => {\n status = \"finished\";\n };\n const onTimeUpdate = () => {\n if (el != null) currentTime = el.currentTime;\n };\n const onLoadedMetadata = () => {\n if (el != null && Number.isFinite(el.duration)) {\n duration = el.duration;\n }\n };\n const onError = () => {\n error = new Error(\"HTMLAudioElement error\");\n status = \"error\";\n };\n\n el.addEventListener(\"play\", onPlay);\n el.addEventListener(\"pause\", onPause);\n el.addEventListener(\"ended\", onEnded);\n el.addEventListener(\"timeupdate\", onTimeUpdate);\n el.addEventListener(\"loadedmetadata\", onLoadedMetadata);\n el.addEventListener(\"error\", onError);\n\n if (shouldPlay || autoPlay) {\n el.play().catch((err) => {\n error = err as Error;\n status = \"error\";\n });\n } else {\n status = \"paused\";\n }\n },\n () => {\n if (!cancelled) {\n error = new Error(\"media failed to materialise\");\n status = \"error\";\n }\n }\n );\n\n return () => {\n cancelled = true;\n try {\n m.revoke();\n } catch {\n // best-effort\n }\n };\n };\n\n // React to media changes + re-establish bindings.\n $effect(() => {\n const m = unwrap(media);\n teardownBinding();\n\n if (m == null) {\n status = \"idle\";\n error = undefined;\n currentTime = 0;\n duration = undefined;\n level = 0;\n upstreamFinished = false;\n return;\n }\n\n strategyState = detectStrategy(m.mimeType, strategyOverride, pcmPrefixes);\n\n if (m.error != null) {\n error = new Error(m.error.message);\n status = \"error\";\n return;\n }\n\n if (strategyState === \"pcm\") {\n detachPcm = bindPcm(m) ?? null;\n } else {\n detachElement = bindElement(m);\n }\n });\n\n onDestroy(() => {\n teardownBinding();\n stop();\n });\n\n return {\n get status() {\n return status;\n },\n get strategy() {\n return strategyState;\n },\n play,\n pause,\n stop,\n toggle,\n reset,\n playToEnd,\n get currentTime() {\n return currentTime;\n },\n get duration() {\n return duration;\n },\n seek,\n get level() {\n return level;\n },\n getFrequencyData,\n getTimeDomainData,\n get error() {\n return error;\n },\n };\n}\n"],"mappings":"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"}