UNPKG

@stlite/browser

Version:
424 lines (423 loc) 15.1 kB
import { Cn as e, Ka as t, Ua as n, ln as r, ma as i } from "./index-Dl4ETd_L-D2oMd1k2.js"; //#region ../react/build/useWaveformController-rxqEhP00.js var a = /* @__PURE__ */ t(n(), 1), o = class { constructor() { this.wavesurfer = null, this.currentBlobUrl = null, this.events = {}, this.isPlaying = !1; } initialize(e) { this.wavesurfer = e, this.setupEventListeners(); } setupEventListeners() { this.wavesurfer && (this.teardownEventListeners(), this.handleTimeUpdate = (e) => { this.events.onTimeUpdate?.(e * 1e3); }, this.handlePause = () => { this.isPlaying = !1, this.events.onPause?.(); }, this.handlePlay = () => { this.isPlaying = !0, this.events.onPlay?.(); }, this.handleFinish = () => { this.isPlaying = !1, this.events.onFinish?.(); }, this.handleReady = () => { this.events.onReady?.(); }, this.handleError = (e) => { let t = e instanceof Error ? e : Error(String(e)); this.events.onError?.(t); }, this.wavesurfer.on("timeupdate", this.handleTimeUpdate), this.wavesurfer.on("pause", this.handlePause), this.wavesurfer.on("play", this.handlePlay), this.wavesurfer.on("finish", this.handleFinish), this.wavesurfer.on("ready", this.handleReady), this.wavesurfer.on("error", this.handleError)); } setEventHandlers(e) { this.events = e; } async load(e) { if (!this.wavesurfer) throw Error("WaveSurfer not initialized"); this.cleanupPreviousUrl(); let t, n = null; try { if (e instanceof Blob) n = URL.createObjectURL(e), t = n; else if (e instanceof ArrayBuffer) { let r = new Blob([e]); n = URL.createObjectURL(r), t = n; } else t = e; this.currentBlobUrl = n, await this.wavesurfer.load(t); } catch (e) { throw this.cleanupPreviousUrl(), e; } } async play() { if (!this.wavesurfer) throw Error("WaveSurfer not initialized"); await this.wavesurfer.play(); } pause() { this.wavesurfer && this.wavesurfer.pause(); } getDuration() { return this.wavesurfer ? this.wavesurfer.getDuration() * 1e3 : 0; } getCurrentTime() { return this.wavesurfer ? this.wavesurfer.getCurrentTime() * 1e3 : 0; } getIsPlaying() { return this.isPlaying; } seekToStart() { this.wavesurfer && this.wavesurfer.seekTo(0); } cleanupPreviousUrl() { this.currentBlobUrl &&= (URL.revokeObjectURL(this.currentBlobUrl), null); } destroy() { this.pause(), this.cleanupPreviousUrl(), this.wavesurfer &&= (this.teardownEventListeners(), this.wavesurfer.empty(), null), this.events = {}, this.isPlaying = !1, this.handleTimeUpdate = void 0, this.handlePause = void 0, this.handlePlay = void 0, this.handleFinish = void 0, this.handleReady = void 0, this.handleError = void 0; } teardownEventListeners() { this.wavesurfer && (this.handleTimeUpdate &&= (this.wavesurfer.un("timeupdate", this.handleTimeUpdate), void 0), this.handlePause &&= (this.wavesurfer.un("pause", this.handlePause), void 0), this.handlePlay &&= (this.wavesurfer.un("play", this.handlePlay), void 0), this.handleFinish &&= (this.wavesurfer.un("finish", this.handleFinish), void 0), this.handleReady &&= (this.wavesurfer.un("ready", this.handleReady), void 0), this.handleError &&= (this.wavesurfer.un("error", this.handleError), void 0)); } }; function s(e) { return e.name === "NotAllowedError" || e.name === "PermissionDeniedError" || e.message?.toLowerCase().includes("permission denied"); } var c = class { constructor(e = {}) { this.wavesurfer = null, this.recordPlugin = null, this.isRecording = !1, this.recordEndResolve = null, this.recordEndReject = null, this.events = {}, this.options = e; } initialize(e, t) { this.wavesurfer = e; try { let n = { renderRecordedAudio: !1, mimeType: "audio/webm" }; this.recordPlugin = e.registerPlugin(t.create(n)), this.setupEventListeners(); } catch (e) { let t = e instanceof Error ? e : Error(String(e)); throw s(t) ? (this.events.onPermissionDenied?.(), /* @__PURE__ */ Error("Microphone permission denied")) : (this.events.onError?.(t), t); } } setupEventListeners() { this.recordPlugin && (this.recordPlugin.on("record-start", () => { this.isRecording = !0, this.events.onRecordStart?.(); }), this.recordPlugin.on("record-end", (e) => { this.isRecording = !1, this.events.onRecordEnd?.(e), this.recordEndResolve && e && e.size > 0 ? (this.recordEndResolve(e), this.recordEndResolve = null, this.recordEndReject = null) : this.recordEndReject ? (this.recordEndReject(/* @__PURE__ */ Error("Invalid or empty recording")), this.recordEndResolve = null, this.recordEndReject = null) : (this.recordEndResolve = null, this.recordEndReject = null); }), this.recordPlugin.on("record-progress", (e) => { this.events.onRecordProgress?.(e); })); } setEventHandlers(e) { this.events = e; } async startRecording() { if (!this.recordPlugin) throw Error("Record plugin not initialized"); if (this.isRecording) return; let e = typeof this.options.sampleRate == "number" ? this.options.sampleRate : void 0, t = {}; e !== void 0 && (t.sampleRate = { ideal: e }), await this.startRecordingWithConstraints(t, e !== void 0); } async startRecordingWithConstraints(e, t) { if (!this.recordPlugin) throw Error("Record plugin not initialized"); try { let t = Object.keys(e).length ? e : void 0; await this.recordPlugin.startRecording(t); } catch (e) { let n = e instanceof Error ? e : Error(String(e)); if (s(n)) throw this.events.onPermissionDenied?.(), /* @__PURE__ */ Error("Microphone permission denied"); if (t && (n.name === "OverconstrainedError" || n.name === "NotReadableError")) { this.options.sampleRate = void 0, await this.startRecordingWithConstraints({}, !1); return; } throw this.events.onError?.(n), n; } } async stopRecording() { if (!this.recordPlugin || !this.isRecording) throw Error("Not currently recording"); try { return await new Promise((e, t) => { this.recordEndResolve = e, this.recordEndReject = t, this.recordPlugin?.stopRecording(); }); } catch (e) { let t = e instanceof Error ? e : Error(String(e)); throw this.events.onError?.(t), t; } } cancelRecording() { this.recordPlugin && this.isRecording && (this.recordPlugin.stopRecording(), this.isRecording = !1, this.recordEndResolve = null, this.recordEndReject = null); } destroy() { this.cancelRecording(), this.recordPlugin &&= (this.recordPlugin.destroy(), null), this.wavesurfer = null, this.events = {}; } }; async function l(e, t = 16e3) { if (!e || e.size === 0) throw Error("Invalid or empty blob provided"); if (!window.AudioContext) throw Error("AudioContext not supported in this browser"); let n = new AudioContext(); try { let r = await e.arrayBuffer(), i = await n.decodeAudioData(r), a = t ?? i.sampleRate; return d(await u(i, a), a); } finally { n.close(); } } async function u(e, t) { let { duration: n, numberOfChannels: r, sampleRate: i } = e, a = Math.ceil(n * t); if (!window.OfflineAudioContext) throw Error("OfflineAudioContext not supported"); let o = new OfflineAudioContext(1, a, t), s = o.createBufferSource(); if (s.buffer = e, r > 1) { let e = o.createChannelSplitter(r), t = o.createChannelMerger(1); s.connect(e); for (let n = 0; n < r; n++) { let i = o.createGain(); i.gain.value = 1 / r, e.connect(i, n), i.connect(t, 0, 0); } t.connect(o.destination); } else s.connect(o.destination); s.start(0); try { return await o.startRendering(); } catch (e) { throw Error(`Failed to resample audio from ${i}Hz to ${t}Hz: ${e instanceof Error ? e.message : String(e)}`); } } function d(e, t) { let n = e.length, r = n * 2 + 44, i = new ArrayBuffer(r), a = new DataView(i), o = e.getChannelData(0), s = (e, t) => { for (let n = 0; n < t.length; n++) a.setUint8(e + n, t.charCodeAt(n)); }; s(0, "RIFF"), a.setUint32(4, r - 8, !0), s(8, "WAVE"), s(12, "fmt "), a.setUint32(16, 16, !0), a.setUint16(20, 1, !0), a.setUint16(22, 1, !0), a.setUint32(24, t, !0), a.setUint32(28, t * 2, !0), a.setUint16(32, 2, !0), a.setUint16(34, 16, !0), s(36, "data"), a.setUint32(40, n * 2, !0); let c = 44; for (let e = 0; e < n; e++) { let t = Math.max(-1, Math.min(1, o[e])); a.setInt16(c, t * 32767, !0), c += 2; } return new Blob([i], { type: "audio/wav" }); } var f = 4, p = 4, m = 8, h = 0, g = 16e3; function _({ containerRef: t, sampleRate: n, events: s, waveformPadding: u = 0 }) { let d = i(), [_, v] = (0, a.useState)("idle"), [y, b] = (0, a.useState)(null), [x, S] = (0, a.useState)(!1), C = (0, a.useRef)(null), w = (0, a.useRef)(null), T = (0, a.useRef)(null), E = (0, a.useRef)(s), D = (0, a.useRef)(!1), O = (0, a.useRef)(!1), k = (0, a.useRef)(/* @__PURE__ */ new Set()), A = (0, a.useRef)(!1), j = n === void 0 ? g : n, M = (0, a.useCallback)(() => { k.current.clear(), S(!1), w.current &&= (w.current.destroy(), null), T.current &&= (T.current.destroy(), null), C.current &&= (C.current.destroy(), null), D.current = !1, A.current = !1, v("idle"), b(null); }, []), N = (0, a.useCallback)(() => { let e = Array.from(k.current); k.current.clear(), e.forEach((e) => { e.resolve(); }); }, []), P = (0, a.useCallback)((e) => { S(!1); let t = Array.from(k.current); k.current.clear(), t.forEach((t) => { t.reject(e); }); }, []), F = (0, a.useCallback)((e) => { e.setEventHandlers({ onPlay: () => { S(!0), E.current.onPlaybackPlay?.(); }, onPause: () => { S(!1), E.current.onPlaybackPause?.(); }, onFinish: () => { S(!1), E.current.onPlaybackFinish?.(); }, onReady: () => { N(); }, onError: (e) => { S(!1), P(e), E.current.onError?.(e); } }); }, [N, P]); (0, a.useEffect)(() => { E.current = s, T.current && F(T.current); }, [s, F]); let I = (0, a.useCallback)(async () => { if (!(D.current || O.current || !t.current)) { O.current = !0; try { let [n, r] = await Promise.all([import("./wavesurfer.esm-SpUmkfwo-BUVhZlGD.js"), import("./record-CvRL89xC-Djmz1rvI.js")]), i = n.default, a = r.default, s = i.create({ container: t.current, waveColor: d.colors.primary, progressColor: d.colors.bodyText, height: u > 0 ? e(d.sizes.largestElementHeight) - 2 * u : "auto", barWidth: f, barGap: p, barRadius: m, cursorWidth: h, interact: !0 }); C.current = s, A.current = !1; let l = new c({ sampleRate: j }); l.initialize(s, a), l.setEventHandlers({ onRecordProgress: (e) => { E.current.onProgressMs?.(e); }, onPermissionDenied: () => { E.current.onPermissionDenied(), v("idle"); }, onError: (e) => { E.current.onError(e), v("idle"); } }), w.current = l; let g = new o(); g.initialize(s), T.current = g, F(g), D.current = !0; } catch (e) { let t = e instanceof Error ? e : Error(String(e)); E.current.onError?.(t); } finally { O.current = !1; } } }, [ t, d, j, F, u ]); (0, a.useEffect)(() => (I(), () => { M(); }), [M, I]), (0, a.useEffect)(() => { let e = C.current; if (e) { if (_ === "recording") { e.setOptions({ waveColor: d.colors.primary, progressColor: d.colors.primary }); return; } if (A.current) { e.setOptions({ interact: !0, waveColor: r(d.colors.fadedText40, d.colors.secondaryBg), progressColor: d.colors.bodyText }); return; } e.setOptions({ waveColor: d.colors.primary, progressColor: d.colors.bodyText }); } }, [ _, d.colors.bodyText, d.colors.fadedText40, d.colors.primary, d.colors.secondaryBg ]); let L = (0, a.useCallback)(async () => { if (_ !== "recording") { if (D.current || await I(), !w.current) throw Error("Record backend not initialized"); C.current && C.current.setOptions({ waveColor: d.colors.primary, progressColor: d.colors.primary }), A.current = !1, await w.current.startRecording(), v("recording"), b(null), S(!1), E.current.onRecordStart?.(); } }, [ _, I, d.colors.primary ]), R = (0, a.useCallback)(() => { T.current && C.current && (T.current.destroy(), T.current = new o(), T.current.initialize(C.current), k.current.clear(), S(!1), F(T.current)), A.current = !1; }, [F]), z = (0, a.useCallback)(() => { T.current?.seekToStart(), S(!1), A.current = !0, C.current && C.current.setOptions({ interact: !0, waveColor: r(d.colors.fadedText40, d.colors.secondaryBg), progressColor: d.colors.bodyText }); }, [ d.colors.bodyText, d.colors.fadedText40, d.colors.secondaryBg ]), B = (0, a.useCallback)(async () => { if (_ !== "recording") throw Error("Not currently recording"); if (!w.current || !T.current) throw Error("Backends not initialized"); try { let e = await w.current.stopRecording(); b(e), await new Promise((t, n) => { if (!T.current) { n(/* @__PURE__ */ Error("Player not initialized")); return; } let r = { resolve: () => { k.current.delete(r), t(); }, reject: (e) => { k.current.delete(r), n(e); } }; k.current.add(r), T.current.load(e).catch((e) => { k.current.delete(r), n(e instanceof Error ? e : Error(String(e))); }); }), v("idle"), S(!1), z(); let t = { blob: e, meta: { durationMs: T.current?.getDuration() ?? 0, sampleRate: typeof j == "number" ? j : null, mimeType: e.type || "audio/webm", size: e.size } }; return E.current.onRecordReady?.(e), t; } catch (e) { let t = e instanceof Error ? e : Error(String(e)); return S(!1), v("idle"), E.current.onError(t), { blob: new Blob(), meta: { durationMs: 0, sampleRate: null, mimeType: "audio/webm", size: 0 } }; } }, [ _, z, j ]), V = (0, a.useCallback)(async (e) => { let t = e ?? y; if (!t) { let e = /* @__PURE__ */ Error("No recorded audio to approve"); E.current.onError(e); return; } try { let e = await l(t, j); await E.current.onApprove?.(e), b(null), v("idle"); } catch (e) { let t = e instanceof Error ? e : Error(String(e)); E.current.onError(t); } }, [y, j]), H = (0, a.useCallback)(() => { _ === "recording" && w.current?.cancelRecording(), R(), b(null), v("idle"), S(!1), A.current = !1, E.current.onCancel?.(); }, [_, R]), U = (0, a.useMemo)(() => ({ isPlaying: () => T.current?.getIsPlaying() ?? !1, play: async () => { if (!T.current) throw Error("Player not initialized"); await T.current.play(); }, pause: () => { T.current?.pause(); }, load: async (e) => { if (D.current || await I(), !T.current) throw Error("Player not initialized"); await T.current.load(e), z(); }, getCurrentTimeMs: () => T.current?.getCurrentTime() ?? 0, getDurationMs: () => T.current?.getDuration() ?? 0 }), [z, I]), W = (0, a.useCallback)((e) => { E.current = e; }, []); return (0, a.useEffect)(() => () => { M(); }, [M]), { state: _, isPlaybackPlaying: x, mountRef: t, start: L, stop: B, approve: V, cancel: H, destroy: M, playback: U, setEventHandlers: W }; } //#endregion export { _ as t }; //# sourceMappingURL=useWaveformController-rxqEhP00-DiSi28dC.js.map