///
/**
* Type definitions for customHowler audio system
* @private
*/
interface HowlOptions {
src: string | string[];
/**
* Force use of HTML5 audio element instead of Web Audio API.
* Useful for testing or specific use cases where HTML5 is preferred.
* Default: auto-detect (use Web Audio API everywhere for non-blocking playback)
* Note: HTML5 audio blocks the main thread and should be avoided.
*/
html5?: boolean;
}
/**
* Lightweight Howl implementation using Web Audio API
*
* ## Features
*
* - **Web Audio API** (Desktop): Off-main-thread audio processing (smooth UI rendering)
* - **HTML5 Audio** (iOS): Reliable playback on iOS devices (avoids pitch shifting)
* - **HTML5 Sound pooling**: Maintains a pool of audio elements for efficient concurrent playback
* - **Caching**: Decoded AudioBuffers cached globally (efficient repeated playback)
* - **Overlapping playback**: Multiple source nodes allow simultaneous sounds
* - **Tree-shakable**: Side-effect free, lazy initialization
* - **Auto-unlock**: Automatically unlocks audio on first user interaction
* - **Auto-detect**: Automatically uses HTML5 on iOS, Web Audio API on desktop
*
* ## Usage
*
* ```typescript
* const beep = new Howl({ src: 'beep.mp3' });
* beep.play(); // First call unlocks audio, subsequent calls play immediately
* beep.play(); // Overlapping playback supported
* ```
*
* ## Performance Notes
*
* **Desktop (Web Audio API):**
* - Each play() call creates a new AudioBufferSourceNode (allows overlapping)
* - AudioBuffer is decoded once and shared (efficient repeated playback)
* - Audio runs on separate thread (doesn't block UI)
*
* **iOS (HTML5 Audio):**
* - Uses HTML5 audio pool for efficient concurrent playback
* - Main thread may block briefly during playback (unavoidable on iOS)
* - Reliable pitch and sample rate (avoids Web Audio API issues)
*
* ## Overlapping Playback
*
* Each call to play() creates a new AudioBufferSourceNode, allowing the same
* sound to play multiple times simultaneously (useful for rapid scanning feedback).
* The decoded AudioBuffer is shared, only the source nodes are created per play.
*/
declare class Howl {
/** Audio source URL (data URI, file path, or URL) */
private src;
/** Use HTML5 audio element (true) or Web Audio API (false) */
private html5;
/** Decoded audio buffer (cached after first load) - for Web Audio API only */
private audioBuffer;
/** Loading promise (prevents duplicate loads) */
private loadPromise;
/** Pool of HTML5 Sound objects (similar to Howler.js) */
private soundPool;
private soundPoolSize;
/** Track inactive (available) sounds for O(1) lookup instead of O(n) find */
private inactiveSounds;
constructor(options: HowlOptions);
/**
* Load and decode the audio file
*
* ## Caching Strategy
*
* This method implements three levels of caching:
*
* 1. **Instance cache**: Check if this Howl instance has already loaded the audio
* 2. **Instance promise cache**: Check if this Howl instance is currently loading
* 3. **Global cache**: Check if any Howl instance has loaded this URL
*
* Benefits:
* - Multiple Howl instances for the same sound share one AudioBuffer
* - Prevents duplicate network requests
* - Avoids redundant CPU-intensive audio decoding
* - Important for rapid scanning where same sound plays frequently
*
* ## Loading Process
*
* 1. Fetch audio file (supports data URIs, relative paths, full URLs)
* 2. Convert to ArrayBuffer
* 3. Decode using AudioContext.decodeAudioData() (async, CPU-intensive)
* 4. Cache the decoded AudioBuffer
*
* Note: decodeAudioData() runs in a separate thread and doesn't block the main thread
*
* @returns Promise - Decoded audio ready for playback
*/
private load;
/**
* Get or create a sound from the pool
* Follows Howler.js pattern: pool of Sound objects with state tracking
* Uses Set for O(1) lookup of inactive sounds instead of O(n) array find
* @private
*/
private getSoundFromPool;
/**
* Verify audio buffer contains actual data (debugging helper, no-op in production)
* @private
*/
private verifyAudioBuffer;
/**
* Handle playback errors for Web Audio API
* @private
*/
private handlePlaybackError;
/**
* Prepare AudioContext for playback
* @private
*/
private prepareAudioContext;
/**
* Play sound using HTML5 Sound pool (Howler.js style)
* Follows Howler.js pattern of Sound objects with state tracking
*
* ## Non-blocking Playback
*
* On iOS, the HTML5 audio play() call can block the main thread. To prevent
* this from blocking overlay rendering during continuous scanning, we defer
* the play() call to the next animation frame using requestAnimationFrame.
* This keeps the current frame free for UI rendering.
*
* @private
*/
private playHTML5;
/**
* Play the sound.
*
* This method is the public API - call it to play the sound.
* It's non-blocking (fire-and-forget) and supports overlapping playback.
*
* ## Behavior
*
* - Creates a new AudioBufferSourceNode for each call (allows overlapping)
* - Reuses cached AudioBuffer (efficient repeated playback)
* - Auto-unlocks audio on first play (if not already unlocked)
* - Uses iOS MediaStreamDestination workaround when needed
*
* ## Example
*
* ```typescript
* const beep = new Howl({ src: 'beep.mp3' });
* beep.play(); // First play
* beep.play(); // Overlapping play (both sounds play simultaneously)
* ```
*/
play(): void;
/**
* Internal async play method
*
* ## Playback Flow
*
* 1. **Unlock check**: Ensure audio is unlocked (iOS requirement)
* 2. **Load**: Load and decode audio if not already cached
* 3. **Create source**: Create new AudioBufferSourceNode for this playback
* 4. **Setup audio graph**: Source → Gain → Destination
* 5. **Start playback**: Call source.start(0) to play immediately
* 6. **Cleanup**: Disconnect source after playback completes
*
* ## Platform-specific playback
*
* **Desktop:**
* - Uses Web Audio API with standard AudioContext destination
*
* **iOS:**
* - Uses HTML5