react-native-nitro-player 0.7.0 → 0.7.1-alpha.1

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.
Files changed (110) hide show
  1. package/README.md +47 -46
  2. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrary.kt +9 -13
  3. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAudioDevices.kt +45 -90
  4. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridDownloadManager.kt +48 -182
  5. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridEqualizer.kt +21 -77
  6. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridPlayerQueue.kt +55 -104
  7. package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridTrackPlayer.kt +113 -123
  8. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/ExoPlayerCore.kt +82 -0
  9. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/ListenerRegistry.kt +48 -0
  10. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerAndroidAuto.kt +62 -0
  11. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +153 -1887
  12. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerListener.kt +122 -0
  13. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerNotify.kt +44 -0
  14. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerPlayback.kt +162 -0
  15. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueue.kt +179 -0
  16. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueueBuild.kt +170 -0
  17. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerSetup.kt +28 -0
  18. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerTempQueue.kt +121 -0
  19. package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerUrlLoader.kt +98 -0
  20. package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadDatabase.kt +27 -18
  21. package/android/src/main/java/com/margelo/nitro/nitroplayer/equalizer/EqualizerCore.kt +150 -135
  22. package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaSessionManager.kt +13 -30
  23. package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +102 -162
  24. package/ios/HybridDownloadManager.swift +32 -26
  25. package/ios/HybridEqualizer.swift +48 -35
  26. package/ios/HybridTrackPlayer.swift +127 -102
  27. package/ios/core/ListenerRegistry.swift +60 -0
  28. package/ios/core/TrackPlayerCore.swift +130 -2356
  29. package/ios/core/TrackPlayerListener.swift +395 -0
  30. package/ios/core/TrackPlayerNotify.swift +52 -0
  31. package/ios/core/TrackPlayerPlayback.swift +274 -0
  32. package/ios/core/TrackPlayerQueue.swift +221 -0
  33. package/ios/core/TrackPlayerQueueBuild.swift +493 -0
  34. package/ios/core/TrackPlayerTempQueue.swift +167 -0
  35. package/ios/core/TrackPlayerUrlLoader.swift +169 -0
  36. package/ios/equalizer/EqualizerCore.swift +63 -123
  37. package/ios/media/MediaSessionManager.swift +32 -49
  38. package/ios/playlist/PlaylistManager.swift +2 -9
  39. package/ios/queue/HybridPlayerQueue.swift +69 -66
  40. package/lib/hooks/useDownloadedTracks.js +16 -13
  41. package/lib/hooks/useEqualizer.d.ts +4 -4
  42. package/lib/hooks/useEqualizer.js +22 -17
  43. package/lib/hooks/useEqualizerPresets.d.ts +3 -3
  44. package/lib/hooks/useEqualizerPresets.js +12 -18
  45. package/lib/specs/AndroidAutoMediaLibrary.nitro.d.ts +2 -2
  46. package/lib/specs/AudioDevices.nitro.d.ts +2 -2
  47. package/lib/specs/DownloadManager.nitro.d.ts +10 -10
  48. package/lib/specs/Equalizer.nitro.d.ts +10 -10
  49. package/lib/specs/TrackPlayer.nitro.d.ts +38 -16
  50. package/lib/types/EqualizerTypes.d.ts +3 -3
  51. package/nitrogen/generated/android/NitroPlayerOnLoad.cpp +2 -0
  52. package/nitrogen/generated/android/c++/JFunc_void_std__vector_TrackItem__std__vector_TrackItem_.hpp +122 -0
  53. package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.cpp +31 -6
  54. package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.hpp +2 -2
  55. package/nitrogen/generated/android/c++/JHybridAudioDevicesSpec.cpp +16 -3
  56. package/nitrogen/generated/android/c++/JHybridAudioDevicesSpec.hpp +1 -1
  57. package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.cpp +154 -44
  58. package/nitrogen/generated/android/c++/JHybridDownloadManagerSpec.hpp +10 -10
  59. package/nitrogen/generated/android/c++/JHybridEqualizerSpec.cpp +130 -34
  60. package/nitrogen/generated/android/c++/JHybridEqualizerSpec.hpp +9 -9
  61. package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.cpp +115 -24
  62. package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.hpp +8 -8
  63. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +243 -24
  64. package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +16 -8
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__vector_TrackItem__std__vector_TrackItem_.kt +80 -0
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrarySpec.kt +3 -2
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridAudioDevicesSpec.kt +2 -1
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridDownloadManagerSpec.kt +10 -10
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridEqualizerSpec.kt +10 -9
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridPlayerQueueSpec.kt +9 -8
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridTrackPlayerSpec.kt +45 -8
  72. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.cpp +74 -18
  73. package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +380 -151
  74. package/nitrogen/generated/ios/c++/HybridDownloadManagerSpecSwift.hpp +10 -10
  75. package/nitrogen/generated/ios/c++/HybridEqualizerSpecSwift.hpp +12 -9
  76. package/nitrogen/generated/ios/c++/HybridPlayerQueueSpecSwift.hpp +23 -8
  77. package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +82 -8
  78. package/nitrogen/generated/ios/swift/Func_void_EqualizerState.swift +46 -0
  79. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__DownloadedPlaylist_.swift +58 -0
  80. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__DownloadedTrack_.swift +58 -0
  81. package/nitrogen/generated/ios/swift/Func_void_std__variant_nitro__NullType__std__string_.swift +58 -0
  82. package/nitrogen/generated/ios/swift/Func_void_std__vector_DownloadedPlaylist_.swift +46 -0
  83. package/nitrogen/generated/ios/swift/Func_void_std__vector_DownloadedTrack_.swift +46 -0
  84. package/nitrogen/generated/ios/swift/Func_void_std__vector_EqualizerBand_.swift +5 -5
  85. package/nitrogen/generated/ios/swift/Func_void_std__vector_TrackItem__std__vector_TrackItem_.swift +46 -0
  86. package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec.swift +10 -10
  87. package/nitrogen/generated/ios/swift/HybridDownloadManagerSpec_cxx.swift +141 -71
  88. package/nitrogen/generated/ios/swift/HybridEqualizerSpec.swift +9 -9
  89. package/nitrogen/generated/ios/swift/HybridEqualizerSpec_cxx.swift +105 -41
  90. package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec.swift +8 -8
  91. package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec_cxx.swift +95 -32
  92. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +16 -8
  93. package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +267 -32
  94. package/nitrogen/generated/shared/c++/HybridAndroidAutoMediaLibrarySpec.hpp +3 -2
  95. package/nitrogen/generated/shared/c++/HybridAudioDevicesSpec.hpp +2 -1
  96. package/nitrogen/generated/shared/c++/HybridDownloadManagerSpec.hpp +10 -10
  97. package/nitrogen/generated/shared/c++/HybridEqualizerSpec.hpp +10 -9
  98. package/nitrogen/generated/shared/c++/HybridPlayerQueueSpec.hpp +9 -8
  99. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.cpp +8 -0
  100. package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +16 -8
  101. package/package.json +5 -5
  102. package/src/hooks/useDownloadedTracks.ts +17 -13
  103. package/src/hooks/useEqualizer.ts +26 -21
  104. package/src/hooks/useEqualizerPresets.ts +15 -21
  105. package/src/specs/AndroidAutoMediaLibrary.nitro.ts +2 -2
  106. package/src/specs/AudioDevices.nitro.ts +2 -2
  107. package/src/specs/DownloadManager.nitro.ts +10 -10
  108. package/src/specs/Equalizer.nitro.ts +10 -10
  109. package/src/specs/TrackPlayer.nitro.ts +52 -16
  110. package/src/types/EqualizerTypes.ts +17 -13
package/README.md CHANGED
@@ -42,41 +42,46 @@ npm install react-native-nitro-modules
42
42
 
43
43
  ### TrackPlayer Methods
44
44
 
45
+ Command-style methods return **`Promise<void>`** (or another **`Promise`**) and **reject** on failure; **`getRepeatMode()`** and **`isAndroidAutoConnected()`** are synchronous reads.
46
+
45
47
  | Name | Platform | Description |
46
48
  | --------------------------- | -------- | ------------------------------------------------------------------- |
47
- | `play()` | Both | Resumes playback. |
48
- | `pause()` | Both | Pauses playback. |
49
+ | `play()` | Both | **Async**. Resumes playback. |
50
+ | `pause()` | Both | **Async**. Pauses playback. |
49
51
  | `playSong(id, playlistId?)` | Both | **Async**. Plays a specific song, optionally from a playlist. |
50
- | `skipToNext()` | Both | Skips to the next track in the queue. |
51
- | `skipToPrevious()` | Both | Skips to the previous track. |
52
- | `seek(position)` | Both | Seeks to a specific time position in seconds. |
52
+ | `skipToNext()` | Both | **Async**. Skips to the next track in the queue. |
53
+ | `skipToPrevious()` | Both | **Async**. Skips to the previous track. |
54
+ | `seek(position)` | Both | **Async**. Seeks to a specific time position in seconds. |
53
55
  | `setPlaybackSpeed(speed)` | Both | **Async**. Sets playback speed (e.g. 0.5x, 1x, 1.5x, 2x). |
54
56
  | `getPlaybackSpeed()` | Both | **Async**. Gets the current playback speed. |
55
- | `setVolume(0-100)` | Both | Sets playback volume (0-100). |
56
- | `setRepeatMode(mode)` | Both | Sets repeat mode (`off`, `track`, `Playlist`). |
57
+ | `setVolume(0-100)` | Both | **Async**. Sets playback volume (0-100). |
58
+ | `setRepeatMode(mode)` | Both | **Async**. Sets repeat mode (`off`, `track`, `Playlist`). |
59
+ | `getRepeatMode()` | Both | **Sync**. Current repeat mode. |
57
60
  | `addToUpNext(id)` | Both | **Async**. Adds a track to the "up next" queue (FIFO). |
58
61
  | `playNext(id)` | Both | **Async**. Adds a track to the "play next" stack (LIFO). |
59
- | `getActualQueue()` | Both | **Async**. Gets the full playback queue including temporary tracks. |
60
- | `getState()` | Both | **Async**. Gets the current player state immediately. |
61
- | `skipToIndex(index)` | Both | **Async**. Skips to a specific index in the actual queue. |
62
- | `configure(config)` | Both | Configures player settings (Android Auto, etc.). |
63
- | `isAndroidAutoConnected()` | Both | Checks if Android Auto is currently connected. |
62
+ | `getActualQueue()` | Both | **Async**. Full playback queue including temporary tracks. |
63
+ | `getState()` | Both | **Async**. Snapshot of player state. |
64
+ | `skipToIndex(index)` | Both | **Async**. Skips to an index in the actual queue (`Promise<boolean>`). |
65
+ | `configure(config)` | Both | **Async**. Player settings (Android Auto, CarPlay, notification). |
66
+ | `isAndroidAutoConnected()` | Both | **Sync**. Android Auto connection. |
64
67
 
65
68
  ### PlayerQueue Methods
66
69
 
70
+ Mutations return **`Promise<void>`** (or **`Promise<string>`** for `createPlaylist`). **`getPlaylist`** / **`getAllPlaylists`** / **`getCurrentPlaylistId`** are synchronous reads.
71
+
67
72
  | Name | Platform | Description |
68
73
  | --------------------------------------- | -------- | ------------------------------------------------------- |
69
- | `createPlaylist(name, ...)` | Both | Creates a new playlist. Returns ID. |
70
- | `deletePlaylist(id)` | Both | Deletes a playlist by ID. |
71
- | `updatePlaylist(id, ...)` | Both | Updates playlist metadata (name, description, artwork). |
74
+ | `createPlaylist(name, ...)` | Both | **Async**. Creates a playlist; resolves to playlist ID. |
75
+ | `deletePlaylist(id)` | Both | **Async**. Deletes a playlist by ID. |
76
+ | `updatePlaylist(id, ...)` | Both | **Async**. Updates metadata (name, description, artwork). |
72
77
  | `getPlaylist(id)` | Both | Gets a specific playlist object. |
73
78
  | `getAllPlaylists()` | Both | Gets all available playlists. |
74
- | `loadPlaylist(id)` | Both | Loads a playlist for playback. |
79
+ | `loadPlaylist(id)` | Both | **Async**. Loads a playlist for playback. |
75
80
  | `getCurrentPlaylistId()` | Both | Gets the ID of the currently playing playlist. |
76
- | `addTrackToPlaylist(pid, track)` | Both | Adds a track to a playlist. |
77
- | `addTracksToPlaylist(pid, tracks)` | Both | Adds multiple tracks to a playlist. |
78
- | `removeTrackFromPlaylist(pid, tid)` | Both | Removes a track from a playlist. |
79
- | `reorderTrackInPlaylist(pid, tid, idx)` | Both | Moves a track to a new position in the playlist. |
81
+ | `addTrackToPlaylist(pid, track)` | Both | **Async**. Adds a track to a playlist. |
82
+ | `addTracksToPlaylist(pid, tracks)` | Both | **Async**. Adds multiple tracks to a playlist. |
83
+ | `removeTrackFromPlaylist(pid, tid)` | Both | **Async**. Removes a track from a playlist. |
84
+ | `reorderTrackInPlaylist(pid, tid, idx)` | Both | **Async**. Moves a track to a new position. |
80
85
 
81
86
  ### Platform-Specific APIs
82
87
 
@@ -98,8 +103,10 @@ npm install react-native-nitro-modules
98
103
  | `pauseDownload(downloadId)` | Both | **Async**. Pauses an active download. |
99
104
  | `resumeDownload(downloadId)` | Both | **Async**. Resumes a paused download. |
100
105
  | `cancelDownload(downloadId)` | Both | **Async**. Cancels a download. |
101
- | `isTrackDownloaded(trackId)` | Both | Checks if a track is downloaded. |
102
- | `getAllDownloadedTracks()` | Both | Gets all downloaded tracks. |
106
+ | `isTrackDownloaded(trackId)` | Both | **Async**. Checks on-disk download state. |
107
+ | `getAllDownloadedTracks()` | Both | **Async**. Lists persisted downloaded tracks. |
108
+ | `getEffectiveUrl(track)` | Both | **Async**. Local or remote URL from preference + downloads. |
109
+ | `syncDownloads()` | Both | **Async**. Reconcile DB with files; returns cleanup count. |
103
110
  | `deleteDownloadedTrack(trackId)` | Both | **Async**. Deletes a downloaded track. |
104
111
  | `getStorageInfo()` | Both | **Async**. Gets download storage usage information. |
105
112
  | `setPlaybackSourcePreference(pref)` | Both | Sets playback source: `'auto'`, `'download'`, or `'network'`. |
@@ -109,6 +116,8 @@ npm install react-native-nitro-modules
109
116
 
110
117
  ## Quick Start
111
118
 
119
+ `TrackPlayer` / `PlayerQueue` commands return **Promises**. The snippets use `await`—run them inside an `async` function, or use `.then()` / `void` / `.catch()` as appropriate.
120
+
112
121
  ### 1. Configure the Player
113
122
 
114
123
  Configure the player before using it in your app:
@@ -116,7 +125,7 @@ Configure the player before using it in your app:
116
125
  ```typescript
117
126
  import { TrackPlayer } from 'react-native-nitro-player'
118
127
 
119
- TrackPlayer.configure({
128
+ await TrackPlayer.configure({
120
129
  androidAutoEnabled: true,
121
130
  carPlayEnabled: false,
122
131
  showInNotification: true,
@@ -147,15 +156,13 @@ const tracks: TrackItem[] = [
147
156
  },
148
157
  ]
149
158
 
150
- // Create a playlist
151
- const playlistId = PlayerQueue.createPlaylist(
159
+ const playlistId = await PlayerQueue.createPlaylist(
152
160
  'My Playlist',
153
161
  'Playlist description',
154
162
  'https://example.com/playlist-artwork.jpg'
155
163
  )
156
164
 
157
- // Add tracks to the playlist
158
- PlayerQueue.addTracksToPlaylist(playlistId, tracks)
165
+ await PlayerQueue.addTracksToPlaylist(playlistId, tracks)
159
166
  ```
160
167
 
161
168
  ### 3. Play Music
@@ -163,28 +170,23 @@ PlayerQueue.addTracksToPlaylist(playlistId, tracks)
163
170
  ```typescript
164
171
  import { TrackPlayer, PlayerQueue } from 'react-native-nitro-player'
165
172
 
166
- // Load and play a playlist
167
- PlayerQueue.loadPlaylist(playlistId)
173
+ await PlayerQueue.loadPlaylist(playlistId)
168
174
 
169
- // Or play a specific song
170
175
  await TrackPlayer.playSong('song-id', playlistId)
171
176
 
172
- // Basic controls
173
- TrackPlayer.play()
174
- TrackPlayer.pause()
175
- TrackPlayer.skipToNext()
176
- TrackPlayer.skipToPrevious()
177
- TrackPlayer.seek(30) // Seek to 30 seconds
177
+ await TrackPlayer.play()
178
+ await TrackPlayer.pause()
179
+ await TrackPlayer.skipToNext()
180
+ await TrackPlayer.skipToPrevious()
181
+ await TrackPlayer.seek(30)
178
182
 
179
- // Set repeat mode
180
- TrackPlayer.setRepeatMode('off') // No repeat
181
- TrackPlayer.setRepeatMode('Playlist') // Repeat entire playlist
182
- TrackPlayer.setRepeatMode('track') // Repeat current track
183
+ await TrackPlayer.setRepeatMode('off')
184
+ await TrackPlayer.setRepeatMode('Playlist')
185
+ await TrackPlayer.setRepeatMode('track')
183
186
 
184
- // Set volume (0-100)
185
- TrackPlayer.setVolume(50) // Set volume to 50%
186
- TrackPlayer.setVolume(0) // Mute
187
- TrackPlayer.setVolume(100) // Maximum volume
187
+ await TrackPlayer.setVolume(50)
188
+ await TrackPlayer.setVolume(0)
189
+ await TrackPlayer.setVolume(100)
188
190
 
189
191
  // Add temporary tracks to queue
190
192
  await TrackPlayer.addToUpNext('song-id') // Add to up-next queue (FIFO)
@@ -280,8 +282,7 @@ The actual playback order is:
280
282
  Temporary tracks are automatically cleared when:
281
283
 
282
284
  - `await TrackPlayer.playSong()` is called
283
- - `PlayerQueue.loadPlaylist()` is called
284
- - `TrackPlayer.playFromIndex()` is called
285
+ - `await PlayerQueue.loadPlaylist()` is called
285
286
 
286
287
  ### `skipToIndex(index: number): Promise<boolean>`
287
288
 
@@ -3,7 +3,10 @@ package com.margelo.nitro.nitroplayer
3
3
  import androidx.annotation.Keep
4
4
  import com.facebook.proguard.annotations.DoNotStrip
5
5
  import com.margelo.nitro.NitroModules
6
+ import com.margelo.nitro.core.Promise
6
7
  import com.margelo.nitro.nitroplayer.core.TrackPlayerCore
8
+ import com.margelo.nitro.nitroplayer.core.clearAndroidAutoMediaLibrary
9
+ import com.margelo.nitro.nitroplayer.core.setAndroidAutoMediaLibrary
7
10
 
8
11
  @DoNotStrip
9
12
  @Keep
@@ -11,21 +14,14 @@ class HybridAndroidAutoMediaLibrary : HybridAndroidAutoMediaLibrarySpec() {
11
14
  private val core: TrackPlayerCore
12
15
 
13
16
  init {
14
- val context =
15
- NitroModules.applicationContext
16
- ?: throw IllegalStateException("React Context is not initialized")
17
+ val context = NitroModules.applicationContext
18
+ ?: throw IllegalStateException("React Context is not initialized")
17
19
  core = TrackPlayerCore.getInstance(context)
18
20
  }
19
21
 
20
- @DoNotStrip
21
- @Keep
22
- override fun setMediaLibrary(libraryJson: String) {
23
- core.setAndroidAutoMediaLibrary(libraryJson)
24
- }
22
+ override fun setMediaLibrary(libraryJson: String): Promise<Unit> =
23
+ Promise.async { core.setAndroidAutoMediaLibrary(libraryJson) }
25
24
 
26
- @DoNotStrip
27
- @Keep
28
- override fun clearMediaLibrary() {
29
- core.clearAndroidAutoMediaLibrary()
30
- }
25
+ override fun clearMediaLibrary(): Promise<Unit> =
26
+ Promise.async { core.clearAndroidAutoMediaLibrary() }
31
27
  }
@@ -1,3 +1,5 @@
1
+ @file:Suppress("ktlint:standard:max-line-length")
2
+
1
3
  package com.margelo.nitro.nitroplayer
2
4
 
3
5
  import android.content.Context
@@ -7,6 +9,7 @@ import android.os.Build
7
9
  import androidx.annotation.Keep
8
10
  import com.facebook.proguard.annotations.DoNotStrip
9
11
  import com.margelo.nitro.NitroModules
12
+ import com.margelo.nitro.core.Promise
10
13
  import com.margelo.nitro.nitroplayer.core.NitroPlayerLogger
11
14
 
12
15
  @DoNotStrip
@@ -15,19 +18,13 @@ class HybridAudioDevices : HybridAudioDevicesSpec() {
15
18
  val applicationContext = NitroModules.applicationContext
16
19
  private val audioManager = applicationContext?.getSystemService(Context.AUDIO_SERVICE) as AudioManager
17
20
 
18
- // Device types that can be set as communication devices
19
21
  private val validCommunicationDeviceTypes: Set<Int> by lazy {
20
- val types =
21
- mutableSetOf(
22
- AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
23
- AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
24
- AudioDeviceInfo.TYPE_WIRED_HEADSET,
25
- AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
26
- AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
27
- AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
28
- AudioDeviceInfo.TYPE_USB_HEADSET,
29
- )
30
- // BLE types are only available on Android S (API 31) and above
22
+ val types = mutableSetOf(
23
+ AudioDeviceInfo.TYPE_BUILTIN_EARPIECE, AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
24
+ AudioDeviceInfo.TYPE_WIRED_HEADSET, AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
25
+ AudioDeviceInfo.TYPE_BLUETOOTH_SCO, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
26
+ AudioDeviceInfo.TYPE_USB_HEADSET,
27
+ )
31
28
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
32
29
  types.add(AudioDeviceInfo.TYPE_BLE_HEADSET)
33
30
  types.add(AudioDeviceInfo.TYPE_BLE_SPEAKER)
@@ -35,100 +32,58 @@ class HybridAudioDevices : HybridAudioDevicesSpec() {
35
32
  types
36
33
  }
37
34
 
38
- @DoNotStrip
39
- @Keep
40
35
  override fun getAudioDevices(): Array<TAudioDevice> {
41
- val devices = audioManager.getDevices(android.media.AudioManager.GET_DEVICES_OUTPUTS)
42
- var activeDevice: AudioDeviceInfo? = null
43
-
44
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
45
- activeDevice = audioManager.communicationDevice
46
- }
47
-
48
- // Filter to only include valid communication devices
49
- return devices
50
- .filter { device ->
51
- validCommunicationDeviceTypes.contains(device.type)
52
- }.map { device ->
53
- TAudioDevice(
54
- id = device.id.toDouble(),
55
- name = device.productName?.toString() ?: getDeviceTypeName(device.type),
56
- type = device.type.toDouble(),
57
- isActive = device == activeDevice,
58
- )
59
- }.toTypedArray()
36
+ val devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
37
+ val activeDevice: AudioDeviceInfo? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) audioManager.communicationDevice else null
38
+ return devices.filter { validCommunicationDeviceTypes.contains(it.type) }.map { device ->
39
+ TAudioDevice(
40
+ id = device.id.toDouble(),
41
+ name = device.productName?.toString() ?: getDeviceTypeName(device.type),
42
+ type = device.type.toDouble(),
43
+ isActive = device == activeDevice,
44
+ )
45
+ }.toTypedArray()
60
46
  }
61
47
 
62
- private fun getDeviceTypeName(type: Int): String =
63
- when (type) {
64
- AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> "Built-in Earpiece"
65
- AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> "Built-in Speaker"
66
- AudioDeviceInfo.TYPE_WIRED_HEADSET -> "Wired Headset"
67
- AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> "Wired Headphones"
68
- AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> "Bluetooth SCO"
69
- AudioDeviceInfo.TYPE_BLUETOOTH_A2DP -> "Bluetooth"
70
- AudioDeviceInfo.TYPE_USB_HEADSET -> "USB Headset"
71
- 26 -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "BLE Headset" else "Type 26"
72
- 27 -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "BLE Speaker" else "Type 27"
73
- else -> "Type $type"
74
- }
75
-
76
- @DoNotStrip
77
- @Keep
78
- override fun setAudioDevice(deviceId: Double): Boolean {
79
- val device =
80
- audioManager
81
- .getDevices(android.media.AudioManager.GET_DEVICES_OUTPUTS)
82
- .firstOrNull { it.id == deviceId.toInt() }
83
- ?: return false
84
-
85
- // Check if device type is valid for communication
48
+ /** v2: setAudioDevice now returns Promise<Unit> instead of Boolean */
49
+ override fun setAudioDevice(deviceId: Double): Promise<Unit> = Promise.async {
50
+ val device = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
51
+ .firstOrNull { it.id == deviceId.toInt() }
52
+ ?: throw IllegalArgumentException("Audio device $deviceId not found")
86
53
  if (!validCommunicationDeviceTypes.contains(device.type)) {
87
- NitroPlayerLogger.log("HybridAudioDevices", "Device type ${device.type} is not a valid communication device")
88
- return false
54
+ throw IllegalArgumentException("Device type ${device.type} is not a valid communication device")
89
55
  }
90
-
91
- return try {
92
- if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
56
+ try {
57
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
93
58
  audioManager.setCommunicationDevice(device)
94
59
  } else {
95
- // Pre-Android 12 fallback (best-effort)
96
60
  when (device.type) {
97
- android.media.AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
98
- android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
99
- -> {
100
- audioManager.startBluetoothSco()
101
- audioManager.isBluetoothScoOn = true
102
- true
103
- }
104
-
105
- android.media.AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> {
106
- audioManager.isSpeakerphoneOn = true
107
- true
108
- }
109
-
110
- android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET,
111
- android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
112
- -> {
113
- audioManager.isSpeakerphoneOn = false
114
- audioManager.isBluetoothScoOn = false
115
- true
61
+ AudioDeviceInfo.TYPE_BLUETOOTH_SCO, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP -> {
62
+ audioManager.startBluetoothSco(); audioManager.isBluetoothScoOn = true
116
63
  }
117
-
118
- else -> {
119
- NitroPlayerLogger.log("HybridAudioDevices", "Unsupported device type for pre-Android 12: ${device.type}")
120
- false
64
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> audioManager.isSpeakerphoneOn = true
65
+ AudioDeviceInfo.TYPE_WIRED_HEADSET, AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> {
66
+ audioManager.isSpeakerphoneOn = false; audioManager.isBluetoothScoOn = false
121
67
  }
68
+ else -> throw IllegalArgumentException("Unsupported device type for pre-Android 12: ${device.type}")
122
69
  }
123
70
  }
124
71
  } catch (e: Exception) {
125
72
  NitroPlayerLogger.log("HybridAudioDevices", "Error setting audio device: ${e.message}")
126
- e.printStackTrace()
127
- false
73
+ throw e
128
74
  }
129
75
  }
130
76
 
131
- companion object {
132
- private const val TAG = "HybridAudioDevices"
77
+ private fun getDeviceTypeName(type: Int): String = when (type) {
78
+ AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> "Built-in Earpiece"
79
+ AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> "Built-in Speaker"
80
+ AudioDeviceInfo.TYPE_WIRED_HEADSET -> "Wired Headset"
81
+ AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> "Wired Headphones"
82
+ AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> "Bluetooth SCO"
83
+ AudioDeviceInfo.TYPE_BLUETOOTH_A2DP -> "Bluetooth"
84
+ AudioDeviceInfo.TYPE_USB_HEADSET -> "USB Headset"
85
+ 26 -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "BLE Headset" else "Type 26"
86
+ 27 -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "BLE Speaker" else "Type 27"
87
+ else -> "Type $type"
133
88
  }
134
89
  }
@@ -1,3 +1,5 @@
1
+ @file:Suppress("ktlint:standard:max-line-length")
2
+
1
3
  package com.margelo.nitro.nitroplayer
2
4
 
3
5
  import androidx.annotation.Keep
@@ -7,219 +9,83 @@ import com.margelo.nitro.core.NullType
7
9
  import com.margelo.nitro.core.Promise
8
10
  import com.margelo.nitro.nitroplayer.download.DownloadManagerCore
9
11
 
10
- /**
11
- * Hybrid implementation of DownloadManagerSpec for Android
12
- * Bridges Nitro modules with the native DownloadManagerCore implementation
13
- */
14
12
  @DoNotStrip
15
13
  @Keep
16
14
  class HybridDownloadManager : HybridDownloadManagerSpec() {
17
15
  private val core: DownloadManagerCore
18
16
 
19
17
  init {
20
- val context =
21
- NitroModules.applicationContext
22
- ?: throw IllegalStateException("React Context is not initialized")
18
+ val context = NitroModules.applicationContext
19
+ ?: throw IllegalStateException("React Context is not initialized")
23
20
  core = DownloadManagerCore.getInstance(context)
24
21
  }
25
22
 
26
- // Configuration
27
- @DoNotStrip
28
- @Keep
29
- override fun configure(config: DownloadConfig) {
30
- core.configure(config)
31
- }
32
-
33
- @DoNotStrip
34
- @Keep
23
+ // ── Configuration ─────────────────────────────────────────────────────────
24
+ override fun configure(config: DownloadConfig) = core.configure(config)
35
25
  override fun getConfig(): DownloadConfig = core.getConfig()
36
26
 
37
- // Download Operations
38
- override fun downloadTrack(
39
- track: TrackItem,
40
- playlistId: String?,
41
- ): Promise<String> =
42
- Promise.async {
43
- core.downloadTrack(track, playlistId)
44
- }
45
-
46
- override fun downloadPlaylist(
47
- playlistId: String,
48
- tracks: Array<TrackItem>,
49
- ): Promise<Array<String>> =
50
- Promise.async {
51
- core.downloadPlaylist(playlistId, tracks)
52
- }
53
-
54
- // Download Control
55
- override fun pauseDownload(downloadId: String): Promise<Unit> =
56
- Promise.async {
57
- core.pauseDownload(downloadId)
58
- }
59
-
60
- override fun resumeDownload(downloadId: String): Promise<Unit> =
61
- Promise.async {
62
- core.resumeDownload(downloadId)
63
- }
64
-
65
- override fun cancelDownload(downloadId: String): Promise<Unit> =
66
- Promise.async {
67
- core.cancelDownload(downloadId)
68
- }
69
-
70
- override fun retryDownload(downloadId: String): Promise<Unit> =
71
- Promise.async {
72
- core.retryDownload(downloadId)
73
- }
74
-
75
- override fun pauseAllDownloads(): Promise<Unit> =
76
- Promise.async {
77
- core.pauseAllDownloads()
78
- }
79
-
80
- override fun resumeAllDownloads(): Promise<Unit> =
81
- Promise.async {
82
- core.resumeAllDownloads()
83
- }
84
-
85
- override fun cancelAllDownloads(): Promise<Unit> =
86
- Promise.async {
87
- core.cancelAllDownloads()
88
- }
89
-
90
- // Download Status
91
- @DoNotStrip
92
- @Keep
27
+ // ── Download operations ───────────────────────────────────────────────────
28
+ override fun downloadTrack(track: TrackItem, playlistId: String?): Promise<String> = Promise.async { core.downloadTrack(track, playlistId) }
29
+ override fun downloadPlaylist(playlistId: String, tracks: Array<TrackItem>): Promise<Array<String>> = Promise.async { core.downloadPlaylist(playlistId, tracks) }
30
+ override fun pauseDownload(downloadId: String): Promise<Unit> = Promise.async { core.pauseDownload(downloadId) }
31
+ override fun resumeDownload(downloadId: String): Promise<Unit> = Promise.async { core.resumeDownload(downloadId) }
32
+ override fun cancelDownload(downloadId: String): Promise<Unit> = Promise.async { core.cancelDownload(downloadId) }
33
+ override fun retryDownload(downloadId: String): Promise<Unit> = Promise.async { core.retryDownload(downloadId) }
34
+ override fun pauseAllDownloads(): Promise<Unit> = Promise.async { core.pauseAllDownloads() }
35
+ override fun resumeAllDownloads(): Promise<Unit> = Promise.async { core.resumeAllDownloads() }
36
+ override fun cancelAllDownloads(): Promise<Unit> = Promise.async { core.cancelAllDownloads() }
37
+
38
+ // ── Download status (sync) ────────────────────────────────────────────────
93
39
  override fun getDownloadTask(downloadId: String): Variant_NullType_DownloadTask {
94
40
  val task = core.getDownloadTask(downloadId)
95
- return if (task != null) {
96
- Variant_NullType_DownloadTask.create(task)
97
- } else {
98
- Variant_NullType_DownloadTask.create(NullType.NULL)
99
- }
41
+ return if (task != null) Variant_NullType_DownloadTask.create(task)
42
+ else Variant_NullType_DownloadTask.create(NullType.NULL)
100
43
  }
101
-
102
- @DoNotStrip
103
- @Keep
104
44
  override fun getActiveDownloads(): Array<DownloadTask> = core.getActiveDownloads()
105
-
106
- @DoNotStrip
107
- @Keep
108
45
  override fun getQueueStatus(): DownloadQueueStatus = core.getQueueStatus()
109
-
110
- @DoNotStrip
111
- @Keep
112
46
  override fun isDownloading(trackId: String): Boolean = core.isDownloading(trackId)
113
-
114
- @DoNotStrip
115
- @Keep
116
47
  override fun getDownloadState(trackId: String): DownloadState = core.getDownloadState(trackId)
117
48
 
118
- // Downloaded Content Queries
119
- @DoNotStrip
120
- @Keep
121
- override fun isTrackDownloaded(trackId: String): Boolean = core.isTrackDownloaded(trackId)
49
+ // ── Downloaded content queries (now async per spec) ───────────────────────
50
+ override fun isTrackDownloaded(trackId: String): Promise<Boolean> = Promise.async { core.isTrackDownloaded(trackId) }
51
+ override fun isPlaylistDownloaded(playlistId: String): Promise<Boolean> = Promise.async { core.isPlaylistDownloaded(playlistId) }
52
+ override fun isPlaylistPartiallyDownloaded(playlistId: String): Promise<Boolean> = Promise.async { core.isPlaylistPartiallyDownloaded(playlistId) }
122
53
 
123
- @DoNotStrip
124
- @Keep
125
- override fun isPlaylistDownloaded(playlistId: String): Boolean = core.isPlaylistDownloaded(playlistId)
126
-
127
- @DoNotStrip
128
- @Keep
129
- override fun isPlaylistPartiallyDownloaded(playlistId: String): Boolean = core.isPlaylistPartiallyDownloaded(playlistId)
130
-
131
- @DoNotStrip
132
- @Keep
133
- override fun getDownloadedTrack(trackId: String): Variant_NullType_DownloadedTrack {
54
+ override fun getDownloadedTrack(trackId: String): Promise<Variant_NullType_DownloadedTrack> = Promise.async {
134
55
  val track = core.getDownloadedTrack(trackId)
135
- return if (track != null) {
136
- Variant_NullType_DownloadedTrack.create(track)
137
- } else {
138
- Variant_NullType_DownloadedTrack.create(NullType.NULL)
139
- }
56
+ if (track != null) Variant_NullType_DownloadedTrack.create(track)
57
+ else Variant_NullType_DownloadedTrack.create(NullType.NULL)
140
58
  }
59
+ override fun getAllDownloadedTracks(): Promise<Array<DownloadedTrack>> = Promise.async { core.getAllDownloadedTracks() }
141
60
 
142
- @DoNotStrip
143
- @Keep
144
- override fun getAllDownloadedTracks(): Array<DownloadedTrack> = core.getAllDownloadedTracks()
145
-
146
- @DoNotStrip
147
- @Keep
148
- override fun getDownloadedPlaylist(playlistId: String): Variant_NullType_DownloadedPlaylist {
61
+ override fun getDownloadedPlaylist(playlistId: String): Promise<Variant_NullType_DownloadedPlaylist> = Promise.async {
149
62
  val playlist = core.getDownloadedPlaylist(playlistId)
150
- return if (playlist != null) {
151
- Variant_NullType_DownloadedPlaylist.create(playlist)
152
- } else {
153
- Variant_NullType_DownloadedPlaylist.create(NullType.NULL)
154
- }
63
+ if (playlist != null) Variant_NullType_DownloadedPlaylist.create(playlist)
64
+ else Variant_NullType_DownloadedPlaylist.create(NullType.NULL)
155
65
  }
66
+ override fun getAllDownloadedPlaylists(): Promise<Array<DownloadedPlaylist>> = Promise.async { core.getAllDownloadedPlaylists() }
156
67
 
157
- @DoNotStrip
158
- @Keep
159
- override fun getAllDownloadedPlaylists(): Array<DownloadedPlaylist> = core.getAllDownloadedPlaylists()
160
-
161
- @DoNotStrip
162
- @Keep
163
- override fun getLocalPath(trackId: String): Variant_NullType_String {
68
+ override fun getLocalPath(trackId: String): Promise<Variant_NullType_String> = Promise.async {
164
69
  val path = core.getLocalPath(trackId)
165
- return if (path != null) {
166
- Variant_NullType_String.create(path)
167
- } else {
168
- Variant_NullType_String.create(NullType.NULL)
169
- }
70
+ if (path != null) Variant_NullType_String.create(path)
71
+ else Variant_NullType_String.create(NullType.NULL)
170
72
  }
171
73
 
172
- // Deletion
173
- override fun deleteDownloadedTrack(trackId: String): Promise<Unit> =
174
- Promise.async {
175
- core.deleteDownloadedTrack(trackId)
176
- }
74
+ override fun syncDownloads(): Promise<Double> = Promise.async { core.syncDownloads().toDouble() }
75
+ override fun getEffectiveUrl(track: TrackItem): Promise<String> = Promise.async { core.getEffectiveUrl(track) }
177
76
 
178
- override fun deleteDownloadedPlaylist(playlistId: String): Promise<Unit> =
179
- Promise.async {
180
- core.deleteDownloadedPlaylist(playlistId)
181
- }
77
+ // ── Deletion ──────────────────────────────────────────────────────────────
78
+ override fun deleteDownloadedTrack(trackId: String): Promise<Unit> = Promise.async { core.deleteDownloadedTrack(trackId) }
79
+ override fun deleteDownloadedPlaylist(playlistId: String): Promise<Unit> = Promise.async { core.deleteDownloadedPlaylist(playlistId) }
80
+ override fun deleteAllDownloads(): Promise<Unit> = Promise.async { core.deleteAllDownloads() }
81
+ override fun getStorageInfo(): Promise<DownloadStorageInfo> = Promise.async { core.getStorageInfo() }
182
82
 
183
- override fun deleteAllDownloads(): Promise<Unit> =
184
- Promise.async {
185
- core.deleteAllDownloads()
186
- }
187
-
188
- // Storage Management
189
- override fun getStorageInfo(): Promise<DownloadStorageInfo> =
190
- Promise.async {
191
- core.getStorageInfo()
192
- }
193
-
194
- @DoNotStrip
195
- @Keep
196
- override fun syncDownloads(): Double = core.syncDownloads().toDouble()
197
-
198
- // Playback Source Preference
199
- @DoNotStrip
200
- @Keep
201
- override fun setPlaybackSourcePreference(preference: PlaybackSource) {
202
- core.setPlaybackSourcePreference(preference)
203
- }
204
-
205
- @DoNotStrip
206
- @Keep
83
+ // ── Playback source ───────────────────────────────────────────────────────
84
+ override fun setPlaybackSourcePreference(preference: PlaybackSource) = core.setPlaybackSourcePreference(preference)
207
85
  override fun getPlaybackSourcePreference(): PlaybackSource = core.getPlaybackSourcePreference()
208
86
 
209
- @DoNotStrip
210
- @Keep
211
- override fun getEffectiveUrl(track: TrackItem): String = core.getEffectiveUrl(track)
212
-
213
- // Event Callbacks
214
- override fun onDownloadProgress(callback: (progress: DownloadProgress) -> Unit) {
215
- core.addProgressCallback(callback)
216
- }
217
-
218
- override fun onDownloadStateChange(callback: (downloadId: String, trackId: String, state: DownloadState, error: DownloadError?) -> Unit) {
219
- core.addStateChangeCallback(callback)
220
- }
221
-
222
- override fun onDownloadComplete(callback: (downloadedTrack: DownloadedTrack) -> Unit) {
223
- core.addCompleteCallback(callback)
224
- }
87
+ // ── Events ────────────────────────────────────────────────────────────────
88
+ override fun onDownloadProgress(callback: (progress: DownloadProgress) -> Unit) = core.addProgressCallback(callback)
89
+ override fun onDownloadStateChange(callback: (downloadId: String, trackId: String, state: DownloadState, error: DownloadError?) -> Unit) = core.addStateChangeCallback(callback)
90
+ override fun onDownloadComplete(callback: (downloadedTrack: DownloadedTrack) -> Unit) = core.addCompleteCallback(callback)
225
91
  }