🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@capgo/native-audio

Package Overview
Dependencies
Maintainers
1
Versions
256
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@capgo/native-audio - npm Package Compare versions

Comparing version
8.4.0
to
8.4.1
+1
-1
android/build.gradle

@@ -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'

@@ -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
{
"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&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</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