@capgo/native-audio 7.9.11 → 7.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1 +1 @@
|
|
|
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}\nexport type CompletedListener = (state: CompletedEvent) => void;\nexport interface Assets {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\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\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 AssetPlayOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Time to start playing the audio, in milliseconds\n */\n time?: number;\n /**\n * Delay to start playing the audio, in milliseconds\n */\n delay?: number;\n}\n\nexport interface ConfigureOptions {\n /**\n * Play the audio with Fade effect, only available for IOS\n */\n fade?: boolean;\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
|
|
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}\nexport type CompletedListener = (state: CompletedEvent) => void;\nexport interface Assets {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\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\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 AssetPlayOptions {\n /**\n * Asset Id, unique identifier of the file\n */\n assetId: string;\n /**\n * Time to start playing the audio, in milliseconds\n */\n time?: number;\n /**\n * Delay to start playing the audio, in milliseconds\n */\n delay?: number;\n}\n\nexport interface ConfigureOptions {\n /**\n * Play the audio with Fade effect, only available for IOS\n */\n fade?: boolean;\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\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 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}\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 * 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 * 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 * Play an audio file\n * @since 5.0.0\n * @param option {@link PlayOptions}\n * @returns\n */\n play(options: { assetId: string; time?: number; delay?: number }): Promise<void>;\n /**\n * Pause an audio file\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns\n */\n pause(options: Assets): Promise<void>;\n /**\n * Resume an audio file\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns\n */\n resume(options: Assets): Promise<void>;\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 * Stop an audio file\n * @since 5.0.0\n * @param option {@link Assets}\n * @returns\n */\n stop(options: Assets): Promise<void>;\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 * 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: { assetId: string; volume: number }): Promise<void>;\n /**\n * Set the rate of an audio file\n * @since 5.0.0\n * @param option {@link AssetPlayOptions}\n * @returns {Promise<void>}\n */\n setRate(options: { assetId: string; rate: number }): Promise<void>;\n /**\n * Set the current time of an audio file\n * @since 6.5.0\n * @param option {@link AssetPlayOptions}\n * @returns {Promise<void>}\n */\n setCurrentTime(options: { assetId: string; time: number }): Promise<void>;\n /**\n * Get the current time of an audio file\n * @since 5.0.0\n * @param option {@link AssetPlayOptions}\n * @returns {Promise<{ currentTime: number }>}\n */\n getCurrentTime(options: { assetId: string }): Promise<{ currentTime: number }>;\n /**\n * Get the duration of an audio file\n * @since 5.0.0\n * @param option {@link AssetPlayOptions}\n * @returns {Promise<{ duration: number }>}\n */\n getDuration(options: Assets): Promise<{ duration: number }>;\n /**\n * Check if an audio file is playing\n *\n * @since 5.0.0\n * @param option {@link AssetPlayOptions}\n * @returns {Promise<boolean>}\n */\n isPlaying(options: Assets): Promise<{ isPlaying: boolean }>;\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 * 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 * 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"]}
|
|
@@ -28,6 +28,7 @@ public class AudioAsset: NSObject, AVAudioPlayerDelegate {
|
|
|
28
28
|
// Maximum number of channels to prevent excessive resource usage
|
|
29
29
|
private let maxChannels = Constant.MaxChannels
|
|
30
30
|
|
|
31
|
+
// Timers - must only be accessed from main thread
|
|
31
32
|
private var currentTimeTimer: Timer?
|
|
32
33
|
internal var fadeTimer: Timer?
|
|
33
34
|
|
|
@@ -87,11 +88,19 @@ public class AudioAsset: NSObject, AVAudioPlayerDelegate {
|
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
deinit {
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
// Invalidate timers - must be done on main thread
|
|
92
|
+
let currentTimer = currentTimeTimer
|
|
93
|
+
let fadeTimerRef = fadeTimer
|
|
92
94
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
if Thread.isMainThread {
|
|
96
|
+
currentTimer?.invalidate()
|
|
97
|
+
fadeTimerRef?.invalidate()
|
|
98
|
+
} else {
|
|
99
|
+
DispatchQueue.main.async {
|
|
100
|
+
currentTimer?.invalidate()
|
|
101
|
+
fadeTimerRef?.invalidate()
|
|
102
|
+
}
|
|
103
|
+
}
|
|
95
104
|
|
|
96
105
|
// Clean up any players that might still be playing
|
|
97
106
|
for player in channels {
|
|
@@ -269,11 +278,7 @@ public class AudioAsset: NSObject, AVAudioPlayerDelegate {
|
|
|
269
278
|
strongPlayer.volume = endVolume
|
|
270
279
|
}
|
|
271
280
|
timer.invalidate()
|
|
272
|
-
|
|
273
|
-
// Update timer reference on main thread
|
|
274
|
-
DispatchQueue.main.async {
|
|
275
|
-
strongSelf.fadeTimer = nil
|
|
276
|
-
}
|
|
281
|
+
strongSelf.fadeTimer = nil
|
|
277
282
|
}
|
|
278
283
|
}
|
|
279
284
|
|
|
@@ -283,12 +288,13 @@ public class AudioAsset: NSObject, AVAudioPlayerDelegate {
|
|
|
283
288
|
}
|
|
284
289
|
|
|
285
290
|
internal func stopFadeTimer() {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
self
|
|
291
|
+
if Thread.isMainThread {
|
|
292
|
+
fadeTimer?.invalidate()
|
|
293
|
+
fadeTimer = nil
|
|
294
|
+
} else {
|
|
295
|
+
DispatchQueue.main.async { [weak self] in
|
|
296
|
+
self?.fadeTimer?.invalidate()
|
|
297
|
+
self?.fadeTimer = nil
|
|
292
298
|
}
|
|
293
299
|
}
|
|
294
300
|
}
|
|
@@ -469,9 +475,11 @@ public class AudioAsset: NSObject, AVAudioPlayerDelegate {
|
|
|
469
475
|
DispatchQueue.main.async { [weak self] in
|
|
470
476
|
guard let strongSelf = self else { return }
|
|
471
477
|
|
|
472
|
-
|
|
478
|
+
// Stop existing timer first (we're on main thread now)
|
|
479
|
+
strongSelf.currentTimeTimer?.invalidate()
|
|
480
|
+
strongSelf.currentTimeTimer = nil
|
|
473
481
|
|
|
474
|
-
|
|
482
|
+
let timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { [weak self] _ in
|
|
475
483
|
guard let strongSelf = self, let strongOwner = strongSelf.owner else {
|
|
476
484
|
self?.stopCurrentTimeUpdates()
|
|
477
485
|
return
|
|
@@ -483,18 +491,21 @@ public class AudioAsset: NSObject, AVAudioPlayerDelegate {
|
|
|
483
491
|
strongSelf.stopCurrentTimeUpdates()
|
|
484
492
|
}
|
|
485
493
|
}
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
494
|
+
|
|
495
|
+
strongSelf.currentTimeTimer = timer
|
|
496
|
+
RunLoop.current.add(timer, forMode: .common)
|
|
489
497
|
}
|
|
490
498
|
}
|
|
491
499
|
|
|
492
500
|
internal func stopCurrentTimeUpdates() {
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
501
|
+
if Thread.isMainThread {
|
|
502
|
+
currentTimeTimer?.invalidate()
|
|
503
|
+
currentTimeTimer = nil
|
|
504
|
+
} else {
|
|
505
|
+
DispatchQueue.main.async { [weak self] in
|
|
506
|
+
self?.currentTimeTimer?.invalidate()
|
|
507
|
+
self?.currentTimeTimer = nil
|
|
508
|
+
}
|
|
498
509
|
}
|
|
499
510
|
}
|
|
500
511
|
}
|
|
@@ -13,7 +13,7 @@ enum MyError: Error {
|
|
|
13
13
|
// swiftlint:disable type_body_length file_length
|
|
14
14
|
@objc(NativeAudio)
|
|
15
15
|
public class NativeAudio: CAPPlugin, AVAudioPlayerDelegate, CAPBridgedPlugin {
|
|
16
|
-
private let pluginVersion: String = "7.
|
|
16
|
+
private let pluginVersion: String = "7.10.0"
|
|
17
17
|
public let identifier = "NativeAudio"
|
|
18
18
|
public let jsName = "NativeAudio"
|
|
19
19
|
public let pluginMethods: [CAPPluginMethod] = [
|