@capgo/native-audio
Advanced tools
@@ -83,3 +83,3 @@ ext { | ||
| implementation 'androidx.media3:media3-transformer:1.9.2' | ||
| implementation 'androidx.media3:media3-ui:1.9.2' | ||
| implementation 'androidx.media3:media3-ui:1.10.0' | ||
| implementation 'androidx.media3:media3-database:1.10.0' | ||
@@ -86,0 +86,0 @@ implementation 'androidx.media3:media3-common:1.10.0' |
+114
-0
@@ -617,2 +617,31 @@ { | ||
| { | ||
| "name": "addListener", | ||
| "signature": "(eventName: 'playbackState', listenerFunc: PlaybackStateListener) => Promise<PluginListenerHandle>", | ||
| "parameters": [ | ||
| { | ||
| "name": "eventName", | ||
| "docs": "", | ||
| "type": "'playbackState'" | ||
| }, | ||
| { | ||
| "name": "listenerFunc", | ||
| "docs": "", | ||
| "type": "PlaybackStateListener" | ||
| } | ||
| ], | ||
| "returns": "Promise<PluginListenerHandle>", | ||
| "tags": [ | ||
| { | ||
| "name": "since", | ||
| "text": "8.3.15\nreturn {@link PlaybackStateEvent}" | ||
| } | ||
| ], | ||
| "docs": "Listen for playback state changes, including notification and lock-screen transport controls.\nEmitted by Android and iOS. The current Web implementation does not emit this event.", | ||
| "complexTypes": [ | ||
| "PluginListenerHandle", | ||
| "PlaybackStateListener" | ||
| ], | ||
| "slug": "addlistenerplaybackstate-" | ||
| }, | ||
| { | ||
| "name": "clearCache", | ||
@@ -1311,2 +1340,55 @@ "signature": "() => Promise<void>", | ||
| ] | ||
| }, | ||
| { | ||
| "name": "PlaybackStateEvent", | ||
| "slug": "playbackstateevent", | ||
| "docs": "", | ||
| "tags": [], | ||
| "methods": [], | ||
| "properties": [ | ||
| { | ||
| "name": "assetId", | ||
| "tags": [], | ||
| "docs": "Asset Id of the audio", | ||
| "complexTypes": [], | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "state", | ||
| "tags": [], | ||
| "docs": "Resolved playback state after a local or remote transport action.", | ||
| "complexTypes": [ | ||
| "PlaybackStateValue" | ||
| ], | ||
| "type": "PlaybackStateValue" | ||
| }, | ||
| { | ||
| "name": "reason", | ||
| "tags": [], | ||
| "docs": "Reason for the state change, for example `play`, `pause`, `remotePlay`, or `complete`.", | ||
| "complexTypes": [], | ||
| "type": "string" | ||
| }, | ||
| { | ||
| "name": "isPlaying", | ||
| "tags": [], | ||
| "docs": "Whether the asset is currently playing.", | ||
| "complexTypes": [], | ||
| "type": "boolean" | ||
| }, | ||
| { | ||
| "name": "currentTime", | ||
| "tags": [], | ||
| "docs": "Current playback position in seconds when available.", | ||
| "complexTypes": [], | ||
| "type": "number | undefined" | ||
| }, | ||
| { | ||
| "name": "duration", | ||
| "tags": [], | ||
| "docs": "Total playback duration in seconds when available.", | ||
| "complexTypes": [], | ||
| "type": "number | undefined" | ||
| } | ||
| ] | ||
| } | ||
@@ -1355,2 +1437,34 @@ ], | ||
| ] | ||
| }, | ||
| { | ||
| "name": "PlaybackStateListener", | ||
| "slug": "playbackstatelistener", | ||
| "docs": "", | ||
| "types": [ | ||
| { | ||
| "text": "(state: PlaybackStateEvent): void", | ||
| "complexTypes": [ | ||
| "PlaybackStateEvent" | ||
| ] | ||
| } | ||
| ] | ||
| }, | ||
| { | ||
| "name": "PlaybackStateValue", | ||
| "slug": "playbackstatevalue", | ||
| "docs": "", | ||
| "types": [ | ||
| { | ||
| "text": "'playing'", | ||
| "complexTypes": [] | ||
| }, | ||
| { | ||
| "text": "'paused'", | ||
| "complexTypes": [] | ||
| }, | ||
| { | ||
| "text": "'stopped'", | ||
| "complexTypes": [] | ||
| } | ||
| ] | ||
| } | ||
@@ -1357,0 +1471,0 @@ ], |
@@ -349,2 +349,30 @@ import type { PluginListenerHandle } from '@capacitor/core'; | ||
| export type CurrentTimeListener = (state: CurrentTimeEvent) => void; | ||
| export type PlaybackStateValue = 'playing' | 'paused' | 'stopped'; | ||
| export interface PlaybackStateEvent { | ||
| /** | ||
| * Asset Id of the audio | ||
| */ | ||
| assetId: string; | ||
| /** | ||
| * Resolved playback state after a local or remote transport action. | ||
| */ | ||
| state: PlaybackStateValue; | ||
| /** | ||
| * Reason for the state change, for example `play`, `pause`, `remotePlay`, or `complete`. | ||
| */ | ||
| reason: string; | ||
| /** | ||
| * Whether the asset is currently playing. | ||
| */ | ||
| isPlaying: boolean; | ||
| /** | ||
| * Current playback position in seconds when available. | ||
| */ | ||
| currentTime?: number; | ||
| /** | ||
| * Total playback duration in seconds when available. | ||
| */ | ||
| duration?: number; | ||
| } | ||
| export type PlaybackStateListener = (state: PlaybackStateEvent) => void; | ||
| export interface NativeAudio { | ||
@@ -531,2 +559,10 @@ /** | ||
| /** | ||
| * Listen for playback state changes, including notification and lock-screen transport controls. | ||
| * Emitted by Android and iOS. The current Web implementation does not emit this event. | ||
| * | ||
| * @since 8.3.15 | ||
| * return {@link PlaybackStateEvent} | ||
| */ | ||
| addListener(eventName: 'playbackState', listenerFunc: PlaybackStateListener): Promise<PluginListenerHandle>; | ||
| /** | ||
| * Clear the audio cache for remote audio files | ||
@@ -533,0 +569,0 @@ * @since 6.5.0 |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\nexport interface CompletedEvent {\n /**\n * Emit when a play completes\n *\n * @since 5.0.0\n */\n assetId: string;\n}\n\nexport type CompletedListener = (state: CompletedEvent) => void;\n\nexport interface Assets {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n}\n\nexport interface AssetVolume {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Volume of the audio, between 0.1 and 1.0\n */\n volume: number;\n /**\n * Time over which to fade to the target volume, in seconds. Default is 0s (immediate).\n */\n duration?: number;\n}\n\nexport interface AssetRate {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Rate of the audio, between 0.1 and 1.0\n */\n rate: number;\n}\n\nexport interface AssetSetTime {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Time to set the audio, in seconds\n */\n time: number;\n}\n\nexport interface AssetPlayOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Time to start playing the audio, in seconds\n */\n time?: number;\n /**\n * Delay to start playing the audio, in seconds\n */\n delay?: number;\n\n /**\n * Volume of the audio, between 0.1 and 1.0\n */\n volume?: number;\n\n /**\n * Whether to fade in the audio\n */\n fadeIn?: boolean;\n\n /**\n * Whether to fade out the audio\n */\n fadeOut?: boolean;\n\n /**\n * Fade in duration in seconds.\n * Only used if fadeIn is true.\n * Default is 1s.\n */\n fadeInDuration?: number;\n\n /**\n * Fade out duration in seconds.\n * Only used if fadeOut is true.\n * Default is 1s.\n */\n fadeOutDuration?: number;\n\n /**\n * Time in seconds from the start of the audio to start fading out.\n * Only used if fadeOut is true.\n * Default is fadeOutDuration before end of audio.\n */\n fadeOutStartTime?: number;\n}\n\nexport interface AssetStopOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n\n /**\n * Whether to fade out the audio before stopping\n */\n fadeOut?: boolean;\n\n /**\n * Fade out duration in seconds.\n * Default is 1s.\n */\n fadeOutDuration?: number;\n}\n\nexport interface AssetPauseOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n\n /**\n * Whether to fade out the audio before pausing\n */\n fadeOut?: boolean;\n\n /**\n * Fade out duration in seconds.\n * Default is 1s.\n */\n fadeOutDuration?: number;\n}\n\nexport interface AssetResumeOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n\n /**\n * Whether to fade in the audio during resume\n */\n fadeIn?: boolean;\n\n /**\n * Fade in duration in seconds.\n * Default is 1s.\n */\n fadeInDuration?: number;\n}\n\nexport interface ConfigureOptions {\n /**\n * focus the audio with Audio Focus\n */\n focus?: boolean;\n /**\n * Play the audio in the background\n */\n background?: boolean;\n /**\n * Ignore silent mode, works only on iOS setting this will nuke other audio apps\n */\n ignoreSilent?: boolean;\n /**\n * Show audio playback in the notification center (iOS and Android)\n * When enabled, displays audio metadata (title, artist, album, artwork) in the system notification\n * and Control Center (iOS) or lock screen.\n *\n * **Important iOS Behavior:**\n * Enabling this option changes the audio session category to `.playback` with `.default` mode,\n * which means your app's audio will **interrupt** other apps' audio (like background music from\n * Spotify, Apple Music, etc.) instead of mixing with it. This is required for the Now Playing\n * info to appear in Control Center and on the lock screen.\n *\n * **Trade-offs:**\n * - `showNotification: true` → Shows Now Playing controls, but interrupts other audio\n * - `showNotification: false` → Audio mixes with other apps, but no Now Playing controls\n *\n * Use this when your app is the primary audio source (music players, podcast apps, etc.).\n * Disable this for secondary audio like sound effects or notification sounds where mixing\n * with background music is preferred.\n *\n * @see https://github.com/Cap-go/capacitor-native-audio/issues/202\n */\n showNotification?: boolean;\n /**\n * Enable background audio playback (Android only)\n *\n * When enabled, audio will continue playing when the app is backgrounded or the screen is locked.\n * The plugin will skip the automatic pause/resume logic that normally occurs when the app\n * enters the background or returns to the foreground.\n *\n * **Important Android Requirements:**\n * To use background playback on Android, your app must:\n * 1. Declare the required permissions in `AndroidManifest.xml`:\n * - `<uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />`\n * - `<uses-permission android:name=\"android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK\" />`\n * - `<uses-permission android:name=\"android.permission.WAKE_LOCK\" />`\n * 2. Start a Foreground Service with a media-style notification before backgrounding\n * (the plugin does not automatically create or manage the foreground service)\n * 3. Use `showNotification: true` to display playback controls in the notification\n *\n * **Usage Example:**\n * ```typescript\n * await NativeAudio.configure({\n * backgroundPlayback: true,\n * showNotification: true\n * });\n * // Start your foreground service here\n * // Then preload and play audio as normal\n * ```\n *\n * @default false\n * @platform Android\n * @since 8.2.0\n */\n backgroundPlayback?: boolean;\n}\n\n/**\n * Metadata to display in the notification center, Control Center (iOS), and lock screen\n * when `showNotification` is enabled in `configure()`.\n *\n * Note: This metadata will only be displayed if `showNotification: true` is set in the\n * `configure()` method. See {@link ConfigureOptions.showNotification} for important\n * behavior details about audio mixing on iOS.\n */\nexport interface NotificationMetadata {\n /**\n * The title to display in the notification center\n */\n title?: string;\n /**\n * The artist name to display in the notification center\n */\n artist?: string;\n /**\n * The album name to display in the notification center\n */\n album?: string;\n /**\n * URL or local path to the artwork/album art image\n */\n artworkUrl?: string;\n}\n\nexport interface PlayOnceOptions {\n /**\n * Path to the audio file, relative path of the file, absolute url (file://) or remote url (https://)\n * Supported formats:\n * - MP3, WAV (all platforms)\n * - M3U8/HLS streams (iOS and Android)\n */\n assetPath: string;\n /**\n * Volume of the audio, between 0.1 and 1.0\n * @default 1.0\n */\n volume?: number;\n /**\n * Is the audio file a URL, pass true if assetPath is a `file://` url\n * or a streaming URL (m3u8)\n * @default false\n */\n isUrl?: boolean;\n /**\n * Automatically start playback after loading\n * @default true\n */\n autoPlay?: boolean;\n /**\n * Delete the audio file from disk after playback completes\n * Only works for local files (file:// URLs), ignored for remote URLs\n * @default false\n * @since 7.11.0\n */\n deleteAfterPlay?: boolean;\n /**\n * Metadata to display in the notification center when audio is playing.\n * Only used when `showNotification: true` is set in `configure()`.\n *\n * See {@link ConfigureOptions.showNotification} for important details about\n * how this affects audio mixing behavior on iOS.\n *\n * @see NotificationMetadata\n * @since 7.10.0\n */\n notificationMetadata?: NotificationMetadata;\n /**\n * Custom HTTP headers to include when fetching remote audio files.\n * Only used when isUrl is true and assetPath is a remote URL (http/https).\n * Example: { 'x-api-key': 'abc123', 'Authorization': 'Bearer token' }\n *\n * @since 7.10.0\n */\n headers?: Record<string, string>;\n}\n\nexport interface PlayOnceResult {\n /**\n * The internally generated asset ID for this playback\n * Can be used to control playback (pause, stop, etc.) before completion\n */\n assetId: string;\n}\n\nexport interface PreloadOptions {\n /**\n * Path to the audio file, relative path of the file, absolute url (file://) or remote url (https://)\n * Supported formats:\n * - MP3, WAV (all platforms)\n * - M3U8/HLS streams (iOS and Android)\n */\n assetPath: string;\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Volume of the audio, between 0.1 and 1.0\n */\n volume?: number;\n /**\n * Audio channel number, default is 1\n */\n audioChannelNum?: number;\n /**\n * Is the audio file a URL, pass true if assetPath is a `file://` url\n * or a streaming URL (m3u8)\n */\n isUrl?: boolean;\n /**\n * Metadata to display in the notification center when audio is playing.\n * Only used when `showNotification: true` is set in `configure()`.\n *\n * See {@link ConfigureOptions.showNotification} for important details about\n * how this affects audio mixing behavior on iOS.\n *\n * @see NotificationMetadata\n */\n notificationMetadata?: NotificationMetadata;\n /**\n * Custom HTTP headers to include when fetching remote audio files.\n * Only used when isUrl is true and assetPath is a remote URL (http/https).\n * Example: { 'x-api-key': 'abc123', 'Authorization': 'Bearer token' }\n *\n * @since 7.10.0\n */\n headers?: Record<string, string>;\n}\n\nexport interface CurrentTimeEvent {\n /**\n * Current time of the audio in seconds\n * @since 6.5.0\n */\n currentTime: number;\n /**\n * Asset Id of the audio\n * @since 6.5.0\n */\n assetId: string;\n}\n\nexport type CurrentTimeListener = (state: CurrentTimeEvent) => void;\n\nexport interface NativeAudio {\n /**\n * Configure the audio player\n * @since 5.0.0\n * @param option {@link ConfigureOptions}\n * @returns\n */\n configure(options: ConfigureOptions): Promise<void>;\n\n /**\n * Load an audio file\n * @since 5.0.0\n * @param option {@link PreloadOptions}\n * @returns\n */\n preload(options: PreloadOptions): Promise<void>;\n /**\n * Play an audio file once with automatic cleanup\n *\n * Method designed for simple, single-shot audio playback,\n * such as notification sounds, UI feedback, or other short audio clips\n * that don't require manual state management.\n *\n * **Key Features:**\n * - **Fire-and-forget**: No need to manually preload, play, stop, or unload\n * - **Auto-cleanup**: Asset is automatically unloaded after playback completes\n * - **Optional file deletion**: Can delete local files after playback (useful for temp files)\n * - **Returns assetId**: Can still control playback if needed (pause, stop, etc.)\n *\n * **Use Cases:**\n * - Notification sounds\n * - UI sound effects (button clicks, alerts)\n * - Short audio clips that play once\n * - Temporary audio files that should be cleaned up\n *\n * **Comparison with regular play():**\n * - `play()`: Requires manual preload, play, and unload steps\n * - `playOnce()`: Handles everything automatically with a single call\n *\n * @example\n * ```typescript\n * // Simple one-shot playback\n * await NativeAudio.playOnce({ assetPath: 'audio/notification.mp3' });\n *\n * // Play and delete the file after completion\n * await NativeAudio.playOnce({\n * assetPath: 'file:///path/to/temp/audio.mp3',\n * isUrl: true,\n * deleteAfterPlay: true\n * });\n *\n * // Get the assetId to control playback\n * const { assetId } = await NativeAudio.playOnce({\n * assetPath: 'audio/long-track.mp3',\n * autoPlay: true\n * });\n * // Later, you can stop it manually if needed\n * await NativeAudio.stop({ assetId });\n * ```\n *\n * @since 7.11.0\n * @param options {@link PlayOnceOptions}\n * @returns {Promise<PlayOnceResult>} Object containing the generated assetId\n */\n playOnce(options: PlayOnceOptions): Promise<PlayOnceResult>;\n /**\n * Check if an audio file is preloaded\n *\n * @since 6.1.0\n * @param option {@link Assets}\n * @returns {Promise<boolean>}\n */\n isPreloaded(options: PreloadOptions): Promise<{ found: boolean }>;\n\n /**\n * Play an audio file\n * @since 5.0.0\n * @param option {@link AssetPlayOptions}\n * @returns\n */\n play(options: AssetPlayOptions): Promise<void>;\n\n /**\n * Pause an audio file\n * @since 5.0.0\n * @param option {@link AssetPauseOptions}\n * @returns\n */\n pause(options: AssetPauseOptions): Promise<void>;\n\n /**\n * Resume an audio file\n * @since 5.0.0\n * @param option {@link AssetResumeOptions}\n * @returns\n */\n resume(options: AssetResumeOptions): Promise<void>;\n\n /**\n * Stop an audio file\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns\n */\n loop(options: Assets): Promise<void>;\n\n /**\n * Stop an audio file\n * @since 5.0.0\n * @param option {@link AssetStopOptions}\n * @returns\n */\n stop(options: AssetStopOptions): Promise<void>;\n\n /**\n * Unload an audio file\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns\n */\n unload(options: Assets): Promise<void>;\n\n /**\n * Set the volume of an audio file\n * @since 5.0.0\n * @param option {@link AssetVolume}\n * @returns {Promise<void>}\n */\n setVolume(options: AssetVolume): Promise<void>;\n\n /**\n * Set the rate of an audio file\n * @since 5.0.0\n * @param option {@link AssetRate}\n * @returns {Promise<void>}\n */\n setRate(options: AssetRate): Promise<void>;\n\n /**\n * Set the current time of an audio file\n * @since 6.5.0\n * @param option {@link AssetSetTime}\n * @returns {Promise<void>}\n */\n setCurrentTime(options: AssetSetTime): Promise<void>;\n\n /**\n * Get the current time of an audio file\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns {Promise<{ currentTime: number }>}\n */\n getCurrentTime(options: Assets): Promise<{ currentTime: number }>;\n\n /**\n * Get the duration of an audio file in seconds\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns {Promise<{ duration: number }>}\n */\n getDuration(options: Assets): Promise<{ duration: number }>;\n\n /**\n * Check if an audio file is playing\n *\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns {Promise<boolean>}\n */\n isPlaying(options: Assets): Promise<{ isPlaying: boolean }>;\n\n /**\n * Listen for complete event\n *\n * @since 5.0.0\n * return {@link CompletedEvent}\n */\n addListener(eventName: 'complete', listenerFunc: CompletedListener): Promise<PluginListenerHandle>;\n\n /**\n * Listen for current time updates\n * Emits every 100ms while audio is playing\n *\n * @since 6.5.0\n * return {@link CurrentTimeEvent}\n */\n addListener(eventName: 'currentTime', listenerFunc: CurrentTimeListener): Promise<PluginListenerHandle>;\n /**\n * Clear the audio cache for remote audio files\n * @since 6.5.0\n * @returns {Promise<void>}\n */\n clearCache(): Promise<void>;\n\n /**\n * Set debug mode logging\n * @since 6.5.0\n * @param options - Options to enable or disable debug mode\n */\n setDebugMode(options: { enabled: boolean }): Promise<void>;\n\n /**\n * Get the native Capacitor plugin version\n *\n * @returns {Promise<{ id: string }>} an Promise with version for this device\n * @throws An error if the something went wrong\n */\n getPluginVersion(): Promise<{ version: string }>;\n\n /**\n * Deinitialize the plugin and restore original audio session settings\n * This method stops all playing audio and reverts any audio session changes made by the plugin\n * Use this when you need to ensure compatibility with other audio plugins\n *\n * @since 7.7.0\n * @returns {Promise<void>}\n */\n deinitPlugin(): Promise<void>;\n}\n"]} | ||
| {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\nexport interface CompletedEvent {\n /**\n * Emit when a play completes\n *\n * @since 5.0.0\n */\n assetId: string;\n}\n\nexport type CompletedListener = (state: CompletedEvent) => void;\n\nexport interface Assets {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n}\n\nexport interface AssetVolume {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Volume of the audio, between 0.1 and 1.0\n */\n volume: number;\n /**\n * Time over which to fade to the target volume, in seconds. Default is 0s (immediate).\n */\n duration?: number;\n}\n\nexport interface AssetRate {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Rate of the audio, between 0.1 and 1.0\n */\n rate: number;\n}\n\nexport interface AssetSetTime {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Time to set the audio, in seconds\n */\n time: number;\n}\n\nexport interface AssetPlayOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Time to start playing the audio, in seconds\n */\n time?: number;\n /**\n * Delay to start playing the audio, in seconds\n */\n delay?: number;\n\n /**\n * Volume of the audio, between 0.1 and 1.0\n */\n volume?: number;\n\n /**\n * Whether to fade in the audio\n */\n fadeIn?: boolean;\n\n /**\n * Whether to fade out the audio\n */\n fadeOut?: boolean;\n\n /**\n * Fade in duration in seconds.\n * Only used if fadeIn is true.\n * Default is 1s.\n */\n fadeInDuration?: number;\n\n /**\n * Fade out duration in seconds.\n * Only used if fadeOut is true.\n * Default is 1s.\n */\n fadeOutDuration?: number;\n\n /**\n * Time in seconds from the start of the audio to start fading out.\n * Only used if fadeOut is true.\n * Default is fadeOutDuration before end of audio.\n */\n fadeOutStartTime?: number;\n}\n\nexport interface AssetStopOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n\n /**\n * Whether to fade out the audio before stopping\n */\n fadeOut?: boolean;\n\n /**\n * Fade out duration in seconds.\n * Default is 1s.\n */\n fadeOutDuration?: number;\n}\n\nexport interface AssetPauseOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n\n /**\n * Whether to fade out the audio before pausing\n */\n fadeOut?: boolean;\n\n /**\n * Fade out duration in seconds.\n * Default is 1s.\n */\n fadeOutDuration?: number;\n}\n\nexport interface AssetResumeOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n\n /**\n * Whether to fade in the audio during resume\n */\n fadeIn?: boolean;\n\n /**\n * Fade in duration in seconds.\n * Default is 1s.\n */\n fadeInDuration?: number;\n}\n\nexport interface ConfigureOptions {\n /**\n * focus the audio with Audio Focus\n */\n focus?: boolean;\n /**\n * Play the audio in the background\n */\n background?: boolean;\n /**\n * Ignore silent mode, works only on iOS setting this will nuke other audio apps\n */\n ignoreSilent?: boolean;\n /**\n * Show audio playback in the notification center (iOS and Android)\n * When enabled, displays audio metadata (title, artist, album, artwork) in the system notification\n * and Control Center (iOS) or lock screen.\n *\n * **Important iOS Behavior:**\n * Enabling this option changes the audio session category to `.playback` with `.default` mode,\n * which means your app's audio will **interrupt** other apps' audio (like background music from\n * Spotify, Apple Music, etc.) instead of mixing with it. This is required for the Now Playing\n * info to appear in Control Center and on the lock screen.\n *\n * **Trade-offs:**\n * - `showNotification: true` → Shows Now Playing controls, but interrupts other audio\n * - `showNotification: false` → Audio mixes with other apps, but no Now Playing controls\n *\n * Use this when your app is the primary audio source (music players, podcast apps, etc.).\n * Disable this for secondary audio like sound effects or notification sounds where mixing\n * with background music is preferred.\n *\n * @see https://github.com/Cap-go/capacitor-native-audio/issues/202\n */\n showNotification?: boolean;\n /**\n * Enable background audio playback (Android only)\n *\n * When enabled, audio will continue playing when the app is backgrounded or the screen is locked.\n * The plugin will skip the automatic pause/resume logic that normally occurs when the app\n * enters the background or returns to the foreground.\n *\n * **Important Android Requirements:**\n * To use background playback on Android, your app must:\n * 1. Declare the required permissions in `AndroidManifest.xml`:\n * - `<uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />`\n * - `<uses-permission android:name=\"android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK\" />`\n * - `<uses-permission android:name=\"android.permission.WAKE_LOCK\" />`\n * 2. Start a Foreground Service with a media-style notification before backgrounding\n * (the plugin does not automatically create or manage the foreground service)\n * 3. Use `showNotification: true` to display playback controls in the notification\n *\n * **Usage Example:**\n * ```typescript\n * await NativeAudio.configure({\n * backgroundPlayback: true,\n * showNotification: true\n * });\n * // Start your foreground service here\n * // Then preload and play audio as normal\n * ```\n *\n * @default false\n * @platform Android\n * @since 8.2.0\n */\n backgroundPlayback?: boolean;\n}\n\n/**\n * Metadata to display in the notification center, Control Center (iOS), and lock screen\n * when `showNotification` is enabled in `configure()`.\n *\n * Note: This metadata will only be displayed if `showNotification: true` is set in the\n * `configure()` method. See {@link ConfigureOptions.showNotification} for important\n * behavior details about audio mixing on iOS.\n */\nexport interface NotificationMetadata {\n /**\n * The title to display in the notification center\n */\n title?: string;\n /**\n * The artist name to display in the notification center\n */\n artist?: string;\n /**\n * The album name to display in the notification center\n */\n album?: string;\n /**\n * URL or local path to the artwork/album art image\n */\n artworkUrl?: string;\n}\n\nexport interface PlayOnceOptions {\n /**\n * Path to the audio file, relative path of the file, absolute url (file://) or remote url (https://)\n * Supported formats:\n * - MP3, WAV (all platforms)\n * - M3U8/HLS streams (iOS and Android)\n */\n assetPath: string;\n /**\n * Volume of the audio, between 0.1 and 1.0\n * @default 1.0\n */\n volume?: number;\n /**\n * Is the audio file a URL, pass true if assetPath is a `file://` url\n * or a streaming URL (m3u8)\n * @default false\n */\n isUrl?: boolean;\n /**\n * Automatically start playback after loading\n * @default true\n */\n autoPlay?: boolean;\n /**\n * Delete the audio file from disk after playback completes\n * Only works for local files (file:// URLs), ignored for remote URLs\n * @default false\n * @since 7.11.0\n */\n deleteAfterPlay?: boolean;\n /**\n * Metadata to display in the notification center when audio is playing.\n * Only used when `showNotification: true` is set in `configure()`.\n *\n * See {@link ConfigureOptions.showNotification} for important details about\n * how this affects audio mixing behavior on iOS.\n *\n * @see NotificationMetadata\n * @since 7.10.0\n */\n notificationMetadata?: NotificationMetadata;\n /**\n * Custom HTTP headers to include when fetching remote audio files.\n * Only used when isUrl is true and assetPath is a remote URL (http/https).\n * Example: { 'x-api-key': 'abc123', 'Authorization': 'Bearer token' }\n *\n * @since 7.10.0\n */\n headers?: Record<string, string>;\n}\n\nexport interface PlayOnceResult {\n /**\n * The internally generated asset ID for this playback\n * Can be used to control playback (pause, stop, etc.) before completion\n */\n assetId: string;\n}\n\nexport interface PreloadOptions {\n /**\n * Path to the audio file, relative path of the file, absolute url (file://) or remote url (https://)\n * Supported formats:\n * - MP3, WAV (all platforms)\n * - M3U8/HLS streams (iOS and Android)\n */\n assetPath: string;\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Volume of the audio, between 0.1 and 1.0\n */\n volume?: number;\n /**\n * Audio channel number, default is 1\n */\n audioChannelNum?: number;\n /**\n * Is the audio file a URL, pass true if assetPath is a `file://` url\n * or a streaming URL (m3u8)\n */\n isUrl?: boolean;\n /**\n * Metadata to display in the notification center when audio is playing.\n * Only used when `showNotification: true` is set in `configure()`.\n *\n * See {@link ConfigureOptions.showNotification} for important details about\n * how this affects audio mixing behavior on iOS.\n *\n * @see NotificationMetadata\n */\n notificationMetadata?: NotificationMetadata;\n /**\n * Custom HTTP headers to include when fetching remote audio files.\n * Only used when isUrl is true and assetPath is a remote URL (http/https).\n * Example: { 'x-api-key': 'abc123', 'Authorization': 'Bearer token' }\n *\n * @since 7.10.0\n */\n headers?: Record<string, string>;\n}\n\nexport interface CurrentTimeEvent {\n /**\n * Current time of the audio in seconds\n * @since 6.5.0\n */\n currentTime: number;\n /**\n * Asset Id of the audio\n * @since 6.5.0\n */\n assetId: string;\n}\n\nexport type CurrentTimeListener = (state: CurrentTimeEvent) => void;\n\nexport type PlaybackStateValue = 'playing' | 'paused' | 'stopped';\n\nexport interface PlaybackStateEvent {\n /**\n * Asset Id of the audio\n */\n assetId: string;\n /**\n * Resolved playback state after a local or remote transport action.\n */\n state: PlaybackStateValue;\n /**\n * Reason for the state change, for example `play`, `pause`, `remotePlay`, or `complete`.\n */\n reason: string;\n /**\n * Whether the asset is currently playing.\n */\n isPlaying: boolean;\n /**\n * Current playback position in seconds when available.\n */\n currentTime?: number;\n /**\n * Total playback duration in seconds when available.\n */\n duration?: number;\n}\n\nexport type PlaybackStateListener = (state: PlaybackStateEvent) => void;\n\nexport interface NativeAudio {\n /**\n * Configure the audio player\n * @since 5.0.0\n * @param option {@link ConfigureOptions}\n * @returns\n */\n configure(options: ConfigureOptions): Promise<void>;\n\n /**\n * Load an audio file\n * @since 5.0.0\n * @param option {@link PreloadOptions}\n * @returns\n */\n preload(options: PreloadOptions): Promise<void>;\n /**\n * Play an audio file once with automatic cleanup\n *\n * Method designed for simple, single-shot audio playback,\n * such as notification sounds, UI feedback, or other short audio clips\n * that don't require manual state management.\n *\n * **Key Features:**\n * - **Fire-and-forget**: No need to manually preload, play, stop, or unload\n * - **Auto-cleanup**: Asset is automatically unloaded after playback completes\n * - **Optional file deletion**: Can delete local files after playback (useful for temp files)\n * - **Returns assetId**: Can still control playback if needed (pause, stop, etc.)\n *\n * **Use Cases:**\n * - Notification sounds\n * - UI sound effects (button clicks, alerts)\n * - Short audio clips that play once\n * - Temporary audio files that should be cleaned up\n *\n * **Comparison with regular play():**\n * - `play()`: Requires manual preload, play, and unload steps\n * - `playOnce()`: Handles everything automatically with a single call\n *\n * @example\n * ```typescript\n * // Simple one-shot playback\n * await NativeAudio.playOnce({ assetPath: 'audio/notification.mp3' });\n *\n * // Play and delete the file after completion\n * await NativeAudio.playOnce({\n * assetPath: 'file:///path/to/temp/audio.mp3',\n * isUrl: true,\n * deleteAfterPlay: true\n * });\n *\n * // Get the assetId to control playback\n * const { assetId } = await NativeAudio.playOnce({\n * assetPath: 'audio/long-track.mp3',\n * autoPlay: true\n * });\n * // Later, you can stop it manually if needed\n * await NativeAudio.stop({ assetId });\n * ```\n *\n * @since 7.11.0\n * @param options {@link PlayOnceOptions}\n * @returns {Promise<PlayOnceResult>} Object containing the generated assetId\n */\n playOnce(options: PlayOnceOptions): Promise<PlayOnceResult>;\n /**\n * Check if an audio file is preloaded\n *\n * @since 6.1.0\n * @param option {@link Assets}\n * @returns {Promise<boolean>}\n */\n isPreloaded(options: PreloadOptions): Promise<{ found: boolean }>;\n\n /**\n * Play an audio file\n * @since 5.0.0\n * @param option {@link AssetPlayOptions}\n * @returns\n */\n play(options: AssetPlayOptions): Promise<void>;\n\n /**\n * Pause an audio file\n * @since 5.0.0\n * @param option {@link AssetPauseOptions}\n * @returns\n */\n pause(options: AssetPauseOptions): Promise<void>;\n\n /**\n * Resume an audio file\n * @since 5.0.0\n * @param option {@link AssetResumeOptions}\n * @returns\n */\n resume(options: AssetResumeOptions): Promise<void>;\n\n /**\n * Stop an audio file\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns\n */\n loop(options: Assets): Promise<void>;\n\n /**\n * Stop an audio file\n * @since 5.0.0\n * @param option {@link AssetStopOptions}\n * @returns\n */\n stop(options: AssetStopOptions): Promise<void>;\n\n /**\n * Unload an audio file\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns\n */\n unload(options: Assets): Promise<void>;\n\n /**\n * Set the volume of an audio file\n * @since 5.0.0\n * @param option {@link AssetVolume}\n * @returns {Promise<void>}\n */\n setVolume(options: AssetVolume): Promise<void>;\n\n /**\n * Set the rate of an audio file\n * @since 5.0.0\n * @param option {@link AssetRate}\n * @returns {Promise<void>}\n */\n setRate(options: AssetRate): Promise<void>;\n\n /**\n * Set the current time of an audio file\n * @since 6.5.0\n * @param option {@link AssetSetTime}\n * @returns {Promise<void>}\n */\n setCurrentTime(options: AssetSetTime): Promise<void>;\n\n /**\n * Get the current time of an audio file\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns {Promise<{ currentTime: number }>}\n */\n getCurrentTime(options: Assets): Promise<{ currentTime: number }>;\n\n /**\n * Get the duration of an audio file in seconds\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns {Promise<{ duration: number }>}\n */\n getDuration(options: Assets): Promise<{ duration: number }>;\n\n /**\n * Check if an audio file is playing\n *\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns {Promise<boolean>}\n */\n isPlaying(options: Assets): Promise<{ isPlaying: boolean }>;\n\n /**\n * Listen for complete event\n *\n * @since 5.0.0\n * return {@link CompletedEvent}\n */\n addListener(eventName: 'complete', listenerFunc: CompletedListener): Promise<PluginListenerHandle>;\n\n /**\n * Listen for current time updates\n * Emits every 100ms while audio is playing\n *\n * @since 6.5.0\n * return {@link CurrentTimeEvent}\n */\n addListener(eventName: 'currentTime', listenerFunc: CurrentTimeListener): Promise<PluginListenerHandle>;\n /**\n * Listen for playback state changes, including notification and lock-screen transport controls.\n * Emitted by Android and iOS. The current Web implementation does not emit this event.\n *\n * @since 8.3.15\n * return {@link PlaybackStateEvent}\n */\n addListener(eventName: 'playbackState', listenerFunc: PlaybackStateListener): Promise<PluginListenerHandle>;\n /**\n * Clear the audio cache for remote audio files\n * @since 6.5.0\n * @returns {Promise<void>}\n */\n clearCache(): Promise<void>;\n\n /**\n * Set debug mode logging\n * @since 6.5.0\n * @param options - Options to enable or disable debug mode\n */\n setDebugMode(options: { enabled: boolean }): Promise<void>;\n\n /**\n * Get the native Capacitor plugin version\n *\n * @returns {Promise<{ id: string }>} an Promise with version for this device\n * @throws An error if the something went wrong\n */\n getPluginVersion(): Promise<{ version: string }>;\n\n /**\n * Deinitialize the plugin and restore original audio session settings\n * This method stops all playing audio and reverts any audio session changes made by the plugin\n * Use this when you need to ensure compatibility with other audio plugins\n *\n * @since 7.7.0\n * @returns {Promise<void>}\n */\n deinitPlugin(): Promise<void>;\n}\n"]} |
| @preconcurrency import AVFoundation | ||
| // swiftlint:disable file_length | ||
| // swiftlint:disable:next type_body_length | ||
@@ -92,2 +93,3 @@ public class RemoteAudioAsset: AudioAsset { | ||
| self.dispatchedCompleteMap[self.assetId] = true | ||
| self.owner?.handlePlaybackCompletion(assetId: self.assetId, audioAsset: self) | ||
| self.onComplete?() | ||
@@ -157,7 +159,7 @@ } | ||
| if let item = player.currentItem { | ||
| let d = item.duration | ||
| if d == .indefinite || !d.isValid { | ||
| let itemDuration = item.duration | ||
| if itemDuration == .indefinite || !itemDuration.isValid { | ||
| validTime = lowerBound | ||
| } else { | ||
| let durationSeconds = d.seconds | ||
| let durationSeconds = itemDuration.seconds | ||
| if durationSeconds.isFinite && durationSeconds > 0 { | ||
@@ -405,1 +407,2 @@ validTime = min(lowerBound, durationSeconds) | ||
| } | ||
| // swiftlint:enable file_length |
+14
-8
| { | ||
| "name": "@capgo/native-audio", | ||
| "version": "8.4.0", | ||
| "version": "8.4.1", | ||
| "description": "A native plugin for native audio engine", | ||
@@ -39,10 +39,10 @@ "license": "MPL-2.0", | ||
| "capacitor:sync:after": "node scripts/configure-dependencies.js", | ||
| "verify": "npm run verify:ios && npm run verify:android && npm run verify:web", | ||
| "verify": "bun run verify:ios && bun run verify:android && bun run verify:web", | ||
| "verify:ios": "xcodebuild -scheme CapgoNativeAudio -destination generic/platform=iOS", | ||
| "verify:android": "cd android && ./gradlew clean build test && cd ..", | ||
| "verify:web": "npm run build", | ||
| "test": "npm run test:ios", | ||
| "verify:web": "bun run build", | ||
| "test": "bun run test:ios", | ||
| "test:ios": "cd ios && xcodebuild test -workspace Plugin.xcworkspace -scheme Plugin -destination 'platform=iOS Simulator,name=iPhone 16' && cd ..", | ||
| "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint", | ||
| "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format", | ||
| "lint": "bun run eslint && bun run prettier -- --check && bun run swiftlint -- lint", | ||
| "fmt": "bun run eslint -- --fix && bun run prettier -- --write && bun run swiftlint -- --fix --format", | ||
| "eslint": "eslint . --ext .ts", | ||
@@ -52,7 +52,13 @@ "prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java", | ||
| "docgen": "docgen --api NativeAudio --output-readme README.md --output-json dist/docs.json", | ||
| "build": "npm run clean && npm run docgen && npm run build:scripts && tsc && rollup -c rollup.config.mjs", | ||
| "build": "bun run clean && bun run docgen && bun run build:scripts && tsc && rollup -c rollup.config.mjs", | ||
| "build:scripts": "tsc -p scripts/tsconfig.json", | ||
| "clean": "rimraf ./dist", | ||
| "watch": "tsc --watch", | ||
| "prepublishOnly": "npm run build" | ||
| "example:install": "cd example-app && bun install", | ||
| "example:build": "cd example-app && bun run build", | ||
| "example:sync:android": "cd example-app && bun run sync:android", | ||
| "example:sync:ios": "cd example-app && bun run sync:ios", | ||
| "test:e2e:android": "maestro test .maestro/android/basic-features.yaml", | ||
| "test:e2e:ios": "maestro test .maestro/ios/basic-features.yaml", | ||
| "prepublishOnly": "bun run build" | ||
| }, | ||
@@ -59,0 +65,0 @@ "devDependencies": { |
+63
-13
@@ -252,2 +252,6 @@ # Native audio | ||
| If you need to keep your app UI synchronized with Android notification or lock-screen controls, | ||
| listen for the `playbackState` event. It emits the `assetId`, resolved state, reason, and the latest | ||
| position/duration snapshot after remote transport actions. | ||
| **Android Notification Controls:** | ||
@@ -427,11 +431,11 @@ On Android, the notification displays three action buttons in this order: | ||
| This repository now ships with an interactive Capacitor project under `example/` that exercises the main APIs on web, iOS, and Android shells. | ||
| This repository now ships with an interactive Capacitor project under `example-app/` that exercises the main APIs on web, iOS, and Android shells. | ||
| ```bash | ||
| cd example | ||
| npm install | ||
| npm run dev # start the web playground | ||
| npm run sync # optional: generate iOS/Android platforms | ||
| npm run ios # open the iOS shell app | ||
| npm run android # open the Android shell app | ||
| cd example-app | ||
| bun install | ||
| bun run dev # start the web playground | ||
| bun run sync # optional: generate iOS/Android platforms | ||
| bun run ios # open the iOS shell app | ||
| bun run android # open the Android shell app | ||
| ``` | ||
@@ -926,2 +930,24 @@ | ||
| ### addListener('playbackState', ...) | ||
| ```typescript | ||
| addListener(eventName: 'playbackState', listenerFunc: PlaybackStateListener) => Promise<PluginListenerHandle> | ||
| ``` | ||
| Listen for playback state changes, including notification and lock-screen transport controls. | ||
| Emitted by Android and iOS. The current Web implementation does not emit this event. | ||
| | Param | Type | | ||
| | ------------------ | ----------------------------------------------------------------------- | | ||
| | **`eventName`** | <code>'playbackState'</code> | | ||
| | **`listenerFunc`** | <code><a href="#playbackstatelistener">PlaybackStateListener</a></code> | | ||
| **Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></code> | ||
| **Since:** 8.3.15 | ||
| return {@link PlaybackStateEvent} | ||
| -------------------- | ||
| ### clearCache() | ||
@@ -1145,2 +1171,14 @@ | ||
| #### PlaybackStateEvent | ||
| | Prop | Type | Description | | ||
| | ----------------- | ----------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | ||
| | **`assetId`** | <code>string</code> | Asset Id of the audio | | ||
| | **`state`** | <code><a href="#playbackstatevalue">PlaybackStateValue</a></code> | Resolved playback state after a local or remote transport action. | | ||
| | **`reason`** | <code>string</code> | Reason for the state change, for example `play`, `pause`, `remotePlay`, or `complete`. | | ||
| | **`isPlaying`** | <code>boolean</code> | Whether the asset is currently playing. | | ||
| | **`currentTime`** | <code>number</code> | Current playback position in seconds when available. | | ||
| | **`duration`** | <code>number</code> | Total playback duration in seconds when available. | | ||
| ### Type Aliases | ||
@@ -1165,2 +1203,12 @@ | ||
| #### PlaybackStateListener | ||
| <code>(state: <a href="#playbackstateevent">PlaybackStateEvent</a>): void</code> | ||
| #### PlaybackStateValue | ||
| <code>'playing' | 'paused' | 'stopped'</code> | ||
| </docgen-api> | ||
@@ -1173,3 +1221,3 @@ | ||
| ```bash | ||
| npm run build | ||
| bun run build | ||
| ``` | ||
@@ -1179,8 +1227,10 @@ | ||
| This plugin includes a comprehensive test suite for iOS: | ||
| This plugin includes native unit coverage plus Maestro smoke tests for the example app on iOS and Android: | ||
| 1. Open the iOS project in Xcode: `npx cap open ios` | ||
| 2. Navigate to the `PluginTests` directory | ||
| 3. Run tests using Product > Test (⌘+U) | ||
| 1. Run plugin verification with `bun run verify` | ||
| 2. Build and sync the example app from `example-app/` | ||
| 3. With a booted device and the shell app installed, run the Android smoke flow with `bun run test:e2e:android` | ||
| 4. With a booted simulator and the shell app installed, run the iOS smoke flow with `bun run test:e2e:ios` | ||
| 5. For native unit tests in Xcode, open the example app iOS project with `cd example-app && bunx cap open ios` and run Product > Test (⌘+U) | ||
| The tests cover core functionality including audio asset initialization, playback, volume control, fade effects, and more. See the [test documentation](ios/PluginTests/README.md) for more details. | ||
| The tests cover core functionality including audio asset initialization, playback, volume control, fade effects, and smoke-tested example app playback flows. See the [test documentation](ios/Tests/README.md) for more details. |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
721711
3.22%8239
4.16%1230
4.24%