{"version":3,"file":"audio-player.cjs","names":[],"sources":["../../src/audio/audio-player.ts"],"sourcesContent":["import { setAudioOutput } from \"./audio-output\";\n\nexport interface PlayAudioOptions {\n    /** Volume between 0 and 1. Default: 1. */\n    volume?: number;\n    /** Loop the clip. Default: false. */\n    loop?: boolean;\n    /** Begin playback immediately. Default: true. */\n    autoplay?: boolean;\n    /** Stop the previous clip managed by this player. Default: false. */\n    stopPrevious?: boolean;\n    /**\n     * Output device to play on, from `useMediaDevices().audioOutputs`.\n     *\n     * Ignored where the browser has no output routing (everything but Chromium) —\n     * the clip still plays, on the system default. Useful for a chime that must land\n     * on a headset while the call audio stays on the speakers.\n     */\n    sinkId?: string;\n    /** Fired when playback ends naturally. */\n    onEnded?: () => void;\n    /** Fired on playback error. */\n    onError?: (error: unknown) => void;\n}\n\n/**\n * Imperative handle over one \"current\" clip.\n *\n * Named `*Handle` like the SDK's other imperative handles (`ChatComposerHandle`,\n * `SignaturePadHandle`) — it is a control surface, not the `<AudioPlayer>` component.\n */\nexport interface AudioPlayerHandle {\n    /** Play `src`. Returns the underlying element, or `null` when the browser blocked autoplay. */\n    play: (src: string, options?: PlayAudioOptions) => Promise<HTMLAudioElement | null>;\n    /** Stop the currently-playing clip and rewind it. */\n    stop: () => void;\n    /** Currently playing audio element, or `null`. */\n    current: () => HTMLAudioElement | null;\n}\n\n/**\n * Create an isolated audio player that tracks a single \"current\" clip.\n * Multiple players coexist independently; use this when several layers of UI\n * need their own playback state.\n */\nexport function createAudioPlayer(): AudioPlayerHandle {\n    let current: HTMLAudioElement | null = null;\n\n    async function play(\n        src: string,\n        {\n            volume = 1,\n            loop = false,\n            autoplay = true,\n            stopPrevious = false,\n            sinkId,\n            onEnded,\n            onError,\n        }: PlayAudioOptions = {},\n    ): Promise<HTMLAudioElement | null> {\n        try {\n            if (stopPrevious && current) {\n                current.pause();\n                current.currentTime = 0;\n            }\n            const audio = new Audio(src);\n            audio.volume = Math.max(0, Math.min(1, volume));\n            audio.loop = loop;\n            audio.preload = \"auto\";\n            if (onEnded) audio.onended = onEnded;\n            if (onError) audio.onerror = (event) => onError(event);\n            current = audio;\n            // Routed before `play()`: applying a sink to an element that is already\n            // playing restarts its audio pipeline and clips the first few ms.\n            if (sinkId !== undefined) await setAudioOutput(audio, sinkId);\n            if (autoplay) await audio.play();\n            return audio;\n        } catch (error) {\n            onError?.(error);\n            return null;\n        }\n    }\n\n    function stop(): void {\n        if (!current) return;\n        current.pause();\n        current.currentTime = 0;\n    }\n\n    return { play, stop, current: () => current };\n}\n\nlet defaultPlayer: AudioPlayerHandle | null = null;\n\nfunction getDefaultPlayer(): AudioPlayerHandle {\n    if (!defaultPlayer) defaultPlayer = createAudioPlayer();\n    return defaultPlayer;\n}\n\n/**\n * Convenience wrapper around a shared {@link AudioPlayerHandle}. Use this for\n * one-off notification sounds. For more complex flows (e.g. several\n * simultaneous channels), build a dedicated player with {@link createAudioPlayer}.\n */\nexport async function playAudio(\n    src: string,\n    options?: PlayAudioOptions,\n): Promise<HTMLAudioElement | null> {\n    return getDefaultPlayer().play(src, options);\n}\n\n/** Stop the clip currently playing on the shared default player. */\nexport function stopAudio(): void {\n    getDefaultPlayer().stop();\n}\n"],"mappings":"sCA6CA,SAAgB,GAAuC,CACnD,IAAI,EAAmC,KAEvC,eAAe,EACX,EACA,CACI,SAAS,EACT,OAAO,GACP,WAAW,GACX,eAAe,GACf,SACA,UACA,WACkB,CAAC,EACS,CAChC,GAAI,CACI,GAAgB,IAChB,EAAQ,MAAM,EACd,EAAQ,YAAc,GAE1B,IAAM,EAAQ,IAAI,MAAM,CAAG,EAW3B,MAVA,GAAM,OAAS,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,CAAM,CAAC,EAC9C,EAAM,KAAO,EACb,EAAM,QAAU,OACZ,IAAS,EAAM,QAAU,GACzB,IAAS,EAAM,QAAW,GAAU,EAAQ,CAAK,GACrD,EAAU,EAGN,IAAW,IAAA,IAAW,MAAM,EAAA,eAAe,EAAO,CAAM,EACxD,GAAU,MAAM,EAAM,KAAK,EACxB,CACX,OAAS,EAAO,CAEZ,OADA,IAAU,CAAK,EACR,IACX,CACJ,CAEA,SAAS,GAAa,CACb,IACL,EAAQ,MAAM,EACd,EAAQ,YAAc,EAC1B,CAEA,MAAO,CAAE,OAAM,OAAM,YAAe,CAAQ,CAChD,CAEA,IAAI,EAA0C,KAE9C,SAAS,GAAsC,CAE3C,MADA,CAAoB,IAAgB,EAAkB,EAC/C,CACX,CAOA,eAAsB,EAClB,EACA,EACgC,CAChC,OAAO,EAAiB,CAAC,CAAC,KAAK,EAAK,CAAO,CAC/C,CAGA,SAAgB,GAAkB,CAC9B,EAAiB,CAAC,CAAC,KAAK,CAC5B"}