{"version":3,"file":"audio.cjs","names":[],"sources":["../src/macros/env.ts","../src/std/audio/web_audio.ts"],"sourcesContent":["/**\n * @internal\n * 小游戏环境宏模块。\n */\n\n/**\n * 小游戏环境宏。\n *\n * 可通过打包工具在 build 时修改，如 esbuild webpack vite 等。\n */\ndeclare const __MINIGAME_STD_MINA__: boolean;\n\n/**\n * 如果在小游戏环境中返回 true，否则返回 false。\n */\nexport const IS_MINA = __MINIGAME_STD_MINA__;\n","/**\n * Web/小游戏 平台的音频播放实现。\n */\n\nimport { Once, tryAsyncResult, type AsyncIOResult, type AsyncVoidIOResult } from 'happy-rusty';\nimport { IS_MINA } from '../../macros/env.ts';\nimport { fetchT } from '../fetch/mod.ts';\nimport { readFile } from '../fs/mod.ts';\nimport { ASYNC_RESULT_VOID, bufferSourceToAb } from '../internal/mod.ts';\nimport type { PlayOptions } from './audio_defines.ts';\n\n// #region Internal Variables\n\n/**\n * 缓存的 AudioContext。\n */\nconst audioContext = /*#__PURE__*/ Once<AudioContext>();\n\n// #endregion\n\n/**\n * 获取缓存的 AudioContext。\n * @returns 返回缓存的 AudioContext。\n * @since 1.5.0\n * @example\n * ```ts\n * const context = audio.getGlobalAudioContext();\n * ```\n */\nexport function getGlobalAudioContext(): AudioContext {\n    return audioContext.getOrInit(createWebAudioContext);\n}\n\n/**\n * 关闭缓存的 AudioContext。\n * @returns 返回一个 AsyncVoidIOResult。\n * @since 1.5.0\n * @example\n * ```ts\n * await audio.closeGlobalAudioContext();\n * ```\n */\nexport function closeGlobalAudioContext(): AsyncVoidIOResult {\n    if (!audioContext.isInitialized()) {\n        return ASYNC_RESULT_VOID;\n    }\n\n    // 重置 Once 以便下次重新创建\n    return tryAsyncResult(audioContext.take().unwrap().close());\n}\n\n/**\n * 创建一个 AudioContext。\n * 如果要获取缓存的实例，请使用 `getGlobalAudioContext`。\n * @returns 返回一个 AudioContext实例。\n * @since 1.5.0\n * @example\n * ```ts\n * const context = audio.createWebAudioContext();\n * ```\n */\nexport function createWebAudioContext(): AudioContext {\n    return IS_MINA\n        // 两者 API 基本兼容\n        ? (wx.createWebAudioContext() as unknown as AudioContext)\n        : new AudioContext();\n}\n\n/**\n * 播放一个 AudioBuffer。\n * @param buffer - 解码后的 AudioBuffer。\n * @param options - 播放选项。\n * @returns 正在播放的 AudioBufferSourceNode。\n * @since 1.5.0\n * @example\n * ```ts\n * const source = audio.playWebAudioFromAudioBuffer(audioBuffer, { loop: true });\n * ```\n */\nexport function playWebAudioFromAudioBuffer(buffer: AudioBuffer, options?: PlayOptions): AudioBufferSourceNode {\n    const {\n        loop = false,\n        autoDisconnect = true,\n    } = options ?? {};\n\n    const context = getGlobalAudioContext();\n    const source = context.createBufferSource();\n\n    source.buffer = buffer;\n    source.loop = loop;\n    source.connect(context.destination);\n\n    if (autoDisconnect) {\n        source.onended = () => {\n            source.disconnect();\n        };\n    }\n\n    source.start();\n\n    return source;\n}\n\n/**\n * 使用 Buffer 进行解码播放。\n * @param buffer - 需要解码的 Buffer。\n * @param options - 播放选项。\n * @returns 正在播放的 AudioBufferSourceNode。\n * @since 1.5.0\n * @example\n * ```ts\n * const result = await audio.playWebAudioFromBufferSource(buffer);\n * if (result.isOk()) {\n *     const source = result.unwrap();\n * }\n * ```\n */\nexport async function playWebAudioFromBufferSource(buffer: BufferSource, options?: PlayOptions): AsyncIOResult<AudioBufferSourceNode> {\n    const context = getGlobalAudioContext();\n    const audioBufferRes = await tryAsyncResult(() => context.decodeAudioData(bufferSourceToAb(buffer)));\n\n    return audioBufferRes.map(audioBuffer => playWebAudioFromAudioBuffer(audioBuffer, options));\n}\n\n/**\n * 读取文件并播放。\n * @param filePath - 文件路径。\n * @param options - 播放选项。\n * @returns 正在播放的 AudioBufferSourceNode。\n * @since 1.5.0\n * @example\n * ```ts\n * const result = await audio.playWebAudioFromFile('/path/to/audio.mp3');\n * if (result.isOk()) {\n *     const source = result.unwrap();\n * }\n * ```\n */\nexport async function playWebAudioFromFile(filePath: string, options?: PlayOptions): AsyncIOResult<AudioBufferSourceNode> {\n    const bufferRes = await readFile(filePath);\n\n    return bufferRes.andThenAsync(bytes => playWebAudioFromBufferSource(bytes.buffer, options));\n}\n\n/**\n * 从远程 URL 下载音频并解码播放。\n * 会先完整下载音频数据再调用 `decodeAudioData`，适合短音效，不适合长音频或流式播放。\n * @param url - 音频资源 URL。\n * @param options - 播放选项。\n * @returns 正在播放的 AudioBufferSourceNode。\n * @since 2.2.0\n * @example\n * ```ts\n * const result = await audio.playWebAudioFromUrl('https://example.com/audio.mp3');\n * if (result.isOk()) {\n *     const source = result.unwrap();\n * }\n * ```\n */\nexport async function playWebAudioFromUrl(url: string, options?: PlayOptions): AsyncIOResult<AudioBufferSourceNode> {\n    const bufferRes = await fetchT(url, { responseType: 'arraybuffer' }).result;\n\n    return bufferRes.andThenAsync(ab => playWebAudioFromBufferSource(ab, options));\n}\n"],"mappings":";;;;;;;;;AAeA,MAAa,UAAU;;;;;;;;;ACCvB,MAAM,eAA6B,eAAA,GAAA,YAAA,KAAA,CAAmB;;;;;;;;;;AAatD,SAAgB,wBAAsC;CAClD,OAAO,aAAa,UAAU,qBAAqB;AACvD;;;;;;;;;;AAWA,SAAgB,0BAA6C;CACzD,IAAI,CAAC,aAAa,cAAc,GAC5B,OAAO,wBAAA;CAIX,QAAA,GAAA,YAAA,eAAA,CAAsB,aAAa,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AAC9D;;;;;;;;;;;AAYA,SAAgB,wBAAsC;CAClD,OAAO,UAEA,GAAG,sBAAsB,IAC1B,IAAI,aAAa;AAC3B;;;;;;;;;;;;AAaA,SAAgB,4BAA4B,QAAqB,SAA8C;CAC3G,MAAM,EACF,OAAO,OACP,iBAAiB,SACjB,WAAW,CAAC;CAEhB,MAAM,UAAU,sBAAsB;CACtC,MAAM,SAAS,QAAQ,mBAAmB;CAE1C,OAAO,SAAS;CAChB,OAAO,OAAO;CACd,OAAO,QAAQ,QAAQ,WAAW;CAElC,IAAI,gBACA,OAAO,gBAAgB;EACnB,OAAO,WAAW;CACtB;CAGJ,OAAO,MAAM;CAEb,OAAO;AACX;;;;;;;;;;;;;;;AAgBA,eAAsB,6BAA6B,QAAsB,SAA6D;CAClI,MAAM,UAAU,sBAAsB;CAGtC,QAAO,OAAA,GAAA,YAAA,eAAA,OAF2C,QAAQ,iBAAA,GAAA,wBAAA,iBAAA,CAAiC,MAAM,CAAC,CAAC,EAAA,CAE7E,KAAI,gBAAe,4BAA4B,aAAa,OAAO,CAAC;AAC9F;;;;;;;;;;;;;;;AAgBA,eAAsB,qBAAqB,UAAkB,SAA6D;CAGtH,QAAO,OAAA,GAAA,kBAAA,SAAA,CAF0B,QAAQ,EAAA,CAExB,cAAa,UAAS,6BAA6B,MAAM,QAAQ,OAAO,CAAC;AAC9F;;;;;;;;;;;;;;;;AAiBA,eAAsB,oBAAoB,KAAa,SAA6D;CAGhH,QAAO,OAAA,GAAA,qBAAA,OAAA,CAFwB,KAAK,EAAE,cAAc,cAAc,CAAC,CAAC,CAAC,OAAA,CAEpD,cAAa,OAAM,6BAA6B,IAAI,OAAO,CAAC;AACjF"}