react-native-nitro-player 0.7.1-alpha.0 → 0.7.1-alpha.2
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.
- package/README.md +47 -46
- package/android/src/main/AndroidManifest.xml +14 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrary.kt +5 -6
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAudioDevices.kt +68 -49
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridDownloadManager.kt +67 -21
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridEqualizer.kt +27 -5
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridPlayerQueue.kt +88 -49
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridTrackPlayer.kt +40 -10
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/ExoPlayerCore.kt +70 -29
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/ListenerRegistry.kt +4 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerAndroidAuto.kt +38 -32
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +70 -65
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerListener.kt +23 -12
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerNotify.kt +16 -4
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerPlayback.kt +101 -72
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueue.kt +64 -30
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueueBuild.kt +54 -28
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerSetup.kt +4 -3
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerTempQueue.kt +73 -62
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerUrlLoader.kt +51 -48
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadDatabase.kt +3 -3
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadManagerCore.kt +12 -3
- package/android/src/main/java/com/margelo/nitro/nitroplayer/equalizer/EqualizerCore.kt +169 -98
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaSessionManager.kt +30 -178
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/PlaybackService.kt +40 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +87 -85
- package/ios/core/TrackPlayerQueue.swift +27 -18
- package/ios/core/TrackPlayerQueueBuild.swift +16 -5
- package/ios/equalizer/EqualizerCore.swift +39 -34
- package/lib/hooks/useEqualizer.js +10 -5
- package/lib/specs/Equalizer.nitro.d.ts +1 -1
- package/lib/types/EqualizerTypes.d.ts +3 -3
- package/package.json +5 -5
- package/src/hooks/useEqualizer.ts +25 -17
- package/src/specs/AndroidAutoMediaLibrary.nitro.ts +3 -2
- package/src/specs/DownloadManager.nitro.ts +4 -2
- package/src/specs/Equalizer.nitro.ts +5 -3
- package/src/specs/TrackPlayer.nitro.ts +18 -6
- 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**.
|
|
60
|
-
| `getState()` | Both | **Async**.
|
|
61
|
-
| `skipToIndex(index)` | Both | **Async**. Skips to
|
|
62
|
-
| `configure(config)` | Both |
|
|
63
|
-
| `isAndroidAutoConnected()` | Both |
|
|
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
|
|
70
|
-
| `deletePlaylist(id)` | Both | Deletes a playlist by ID.
|
|
71
|
-
| `updatePlaylist(id, ...)` | Both | Updates
|
|
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
|
|
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
|
|
102
|
-
| `getAllDownloadedTracks()` | Both |
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
173
|
-
TrackPlayer.
|
|
174
|
-
TrackPlayer.
|
|
175
|
-
TrackPlayer.
|
|
176
|
-
TrackPlayer.
|
|
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
|
-
|
|
180
|
-
TrackPlayer.setRepeatMode('
|
|
181
|
-
TrackPlayer.setRepeatMode('
|
|
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
|
-
|
|
185
|
-
TrackPlayer.setVolume(
|
|
186
|
-
TrackPlayer.setVolume(
|
|
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
|
|
|
@@ -4,8 +4,21 @@
|
|
|
4
4
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
5
5
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
|
6
6
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
|
|
7
|
-
|
|
7
|
+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
|
|
8
|
+
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
9
|
+
|
|
8
10
|
<application>
|
|
11
|
+
<!-- PlaybackService keeps music alive when screen is locked / app backgrounded -->
|
|
12
|
+
<service
|
|
13
|
+
android:name="com.margelo.nitro.nitroplayer.media.NitroPlayerPlaybackService"
|
|
14
|
+
android:foregroundServiceType="mediaPlayback"
|
|
15
|
+
android:exported="true"
|
|
16
|
+
tools:node="merge">
|
|
17
|
+
<intent-filter>
|
|
18
|
+
<action android:name="androidx.media3.session.MediaSessionService" />
|
|
19
|
+
</intent-filter>
|
|
20
|
+
</service>
|
|
21
|
+
|
|
9
22
|
<!-- WorkManager's SystemForegroundService for download notifications -->
|
|
10
23
|
<service
|
|
11
24
|
android:name="androidx.work.impl.foreground.SystemForegroundService"
|
package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrary.kt
CHANGED
|
@@ -14,14 +14,13 @@ class HybridAndroidAutoMediaLibrary : HybridAndroidAutoMediaLibrarySpec() {
|
|
|
14
14
|
private val core: TrackPlayerCore
|
|
15
15
|
|
|
16
16
|
init {
|
|
17
|
-
val context =
|
|
18
|
-
|
|
17
|
+
val context =
|
|
18
|
+
NitroModules.applicationContext
|
|
19
|
+
?: throw IllegalStateException("React Context is not initialized")
|
|
19
20
|
core = TrackPlayerCore.getInstance(context)
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
override fun setMediaLibrary(libraryJson: String): Promise<Unit> =
|
|
23
|
-
Promise.async { core.setAndroidAutoMediaLibrary(libraryJson) }
|
|
23
|
+
override fun setMediaLibrary(libraryJson: String): Promise<Unit> = Promise.async { core.setAndroidAutoMediaLibrary(libraryJson) }
|
|
24
24
|
|
|
25
|
-
override fun clearMediaLibrary(): Promise<Unit> =
|
|
26
|
-
Promise.async { core.clearAndroidAutoMediaLibrary() }
|
|
25
|
+
override fun clearMediaLibrary(): Promise<Unit> = Promise.async { core.clearAndroidAutoMediaLibrary() }
|
|
27
26
|
}
|
|
@@ -19,12 +19,16 @@ class HybridAudioDevices : HybridAudioDevicesSpec() {
|
|
|
19
19
|
private val audioManager = applicationContext?.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
20
20
|
|
|
21
21
|
private val validCommunicationDeviceTypes: Set<Int> by lazy {
|
|
22
|
-
val types =
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
val types =
|
|
23
|
+
mutableSetOf(
|
|
24
|
+
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
|
|
25
|
+
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
|
|
26
|
+
AudioDeviceInfo.TYPE_WIRED_HEADSET,
|
|
27
|
+
AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
|
|
28
|
+
AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
|
|
29
|
+
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
|
|
30
|
+
AudioDeviceInfo.TYPE_USB_HEADSET,
|
|
31
|
+
)
|
|
28
32
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
29
33
|
types.add(AudioDeviceInfo.TYPE_BLE_HEADSET)
|
|
30
34
|
types.add(AudioDeviceInfo.TYPE_BLE_SPEAKER)
|
|
@@ -35,55 +39,70 @@ class HybridAudioDevices : HybridAudioDevicesSpec() {
|
|
|
35
39
|
override fun getAudioDevices(): Array<TAudioDevice> {
|
|
36
40
|
val devices = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
|
|
37
41
|
val activeDevice: AudioDeviceInfo? = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) audioManager.communicationDevice else null
|
|
38
|
-
return devices
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
return devices
|
|
43
|
+
.filter { validCommunicationDeviceTypes.contains(it.type) }
|
|
44
|
+
.map { device ->
|
|
45
|
+
TAudioDevice(
|
|
46
|
+
id = device.id.toDouble(),
|
|
47
|
+
name = device.productName?.toString() ?: getDeviceTypeName(device.type),
|
|
48
|
+
type = device.type.toDouble(),
|
|
49
|
+
isActive = device == activeDevice,
|
|
50
|
+
)
|
|
51
|
+
}.toTypedArray()
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
/** v2: setAudioDevice now returns Promise<Unit> instead of Boolean */
|
|
49
|
-
override fun setAudioDevice(deviceId: Double): Promise<Unit> =
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
55
|
+
override fun setAudioDevice(deviceId: Double): Promise<Unit> =
|
|
56
|
+
Promise.async {
|
|
57
|
+
val device =
|
|
58
|
+
audioManager
|
|
59
|
+
.getDevices(AudioManager.GET_DEVICES_OUTPUTS)
|
|
60
|
+
.firstOrNull { it.id == deviceId.toInt() }
|
|
61
|
+
?: throw IllegalArgumentException("Audio device $deviceId not found")
|
|
62
|
+
if (!validCommunicationDeviceTypes.contains(device.type)) {
|
|
63
|
+
throw IllegalArgumentException("Device type ${device.type} is not a valid communication device")
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
67
|
+
audioManager.setCommunicationDevice(device)
|
|
68
|
+
} else {
|
|
69
|
+
when (device.type) {
|
|
70
|
+
AudioDeviceInfo.TYPE_BLUETOOTH_SCO, AudioDeviceInfo.TYPE_BLUETOOTH_A2DP -> {
|
|
71
|
+
audioManager.startBluetoothSco()
|
|
72
|
+
audioManager.isBluetoothScoOn = true
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> {
|
|
76
|
+
audioManager.isSpeakerphoneOn = true
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
AudioDeviceInfo.TYPE_WIRED_HEADSET, AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> {
|
|
80
|
+
audioManager.isSpeakerphoneOn = false
|
|
81
|
+
audioManager.isBluetoothScoOn = false
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
else -> {
|
|
85
|
+
throw IllegalArgumentException("Unsupported device type for pre-Android 12: ${device.type}")
|
|
86
|
+
}
|
|
67
87
|
}
|
|
68
|
-
else -> throw IllegalArgumentException("Unsupported device type for pre-Android 12: ${device.type}")
|
|
69
88
|
}
|
|
89
|
+
} catch (e: Exception) {
|
|
90
|
+
NitroPlayerLogger.log("HybridAudioDevices", "Error setting audio device: ${e.message}")
|
|
91
|
+
throw e
|
|
70
92
|
}
|
|
71
|
-
} catch (e: Exception) {
|
|
72
|
-
NitroPlayerLogger.log("HybridAudioDevices", "Error setting audio device: ${e.message}")
|
|
73
|
-
throw e
|
|
74
93
|
}
|
|
75
|
-
}
|
|
76
94
|
|
|
77
|
-
private fun getDeviceTypeName(type: Int): String =
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
95
|
+
private fun getDeviceTypeName(type: Int): String =
|
|
96
|
+
when (type) {
|
|
97
|
+
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> "Built-in Earpiece"
|
|
98
|
+
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> "Built-in Speaker"
|
|
99
|
+
AudioDeviceInfo.TYPE_WIRED_HEADSET -> "Wired Headset"
|
|
100
|
+
AudioDeviceInfo.TYPE_WIRED_HEADPHONES -> "Wired Headphones"
|
|
101
|
+
AudioDeviceInfo.TYPE_BLUETOOTH_SCO -> "Bluetooth SCO"
|
|
102
|
+
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP -> "Bluetooth"
|
|
103
|
+
AudioDeviceInfo.TYPE_USB_HEADSET -> "USB Headset"
|
|
104
|
+
26 -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "BLE Headset" else "Type 26"
|
|
105
|
+
27 -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "BLE Speaker" else "Type 27"
|
|
106
|
+
else -> "Type $type"
|
|
107
|
+
}
|
|
89
108
|
}
|
|
@@ -15,77 +15,123 @@ class HybridDownloadManager : HybridDownloadManagerSpec() {
|
|
|
15
15
|
private val core: DownloadManagerCore
|
|
16
16
|
|
|
17
17
|
init {
|
|
18
|
-
val context =
|
|
19
|
-
|
|
18
|
+
val context =
|
|
19
|
+
NitroModules.applicationContext
|
|
20
|
+
?: throw IllegalStateException("React Context is not initialized")
|
|
20
21
|
core = DownloadManagerCore.getInstance(context)
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
// ── Configuration ─────────────────────────────────────────────────────────
|
|
24
25
|
override fun configure(config: DownloadConfig) = core.configure(config)
|
|
26
|
+
|
|
25
27
|
override fun getConfig(): DownloadConfig = core.getConfig()
|
|
26
28
|
|
|
27
29
|
// ── Download operations ───────────────────────────────────────────────────
|
|
28
|
-
override fun downloadTrack(
|
|
29
|
-
|
|
30
|
+
override fun downloadTrack(
|
|
31
|
+
track: TrackItem,
|
|
32
|
+
playlistId: String?,
|
|
33
|
+
): Promise<String> = Promise.async { core.downloadTrack(track, playlistId) }
|
|
34
|
+
|
|
35
|
+
override fun downloadPlaylist(
|
|
36
|
+
playlistId: String,
|
|
37
|
+
tracks: Array<TrackItem>,
|
|
38
|
+
): Promise<Array<String>> = Promise.async { core.downloadPlaylist(playlistId, tracks) }
|
|
39
|
+
|
|
30
40
|
override fun pauseDownload(downloadId: String): Promise<Unit> = Promise.async { core.pauseDownload(downloadId) }
|
|
41
|
+
|
|
31
42
|
override fun resumeDownload(downloadId: String): Promise<Unit> = Promise.async { core.resumeDownload(downloadId) }
|
|
43
|
+
|
|
32
44
|
override fun cancelDownload(downloadId: String): Promise<Unit> = Promise.async { core.cancelDownload(downloadId) }
|
|
45
|
+
|
|
33
46
|
override fun retryDownload(downloadId: String): Promise<Unit> = Promise.async { core.retryDownload(downloadId) }
|
|
47
|
+
|
|
34
48
|
override fun pauseAllDownloads(): Promise<Unit> = Promise.async { core.pauseAllDownloads() }
|
|
49
|
+
|
|
35
50
|
override fun resumeAllDownloads(): Promise<Unit> = Promise.async { core.resumeAllDownloads() }
|
|
51
|
+
|
|
36
52
|
override fun cancelAllDownloads(): Promise<Unit> = Promise.async { core.cancelAllDownloads() }
|
|
37
53
|
|
|
38
54
|
// ── Download status (sync) ────────────────────────────────────────────────
|
|
39
55
|
override fun getDownloadTask(downloadId: String): Variant_NullType_DownloadTask {
|
|
40
56
|
val task = core.getDownloadTask(downloadId)
|
|
41
|
-
return if (task != null)
|
|
42
|
-
|
|
57
|
+
return if (task != null) {
|
|
58
|
+
Variant_NullType_DownloadTask.create(task)
|
|
59
|
+
} else {
|
|
60
|
+
Variant_NullType_DownloadTask.create(NullType.NULL)
|
|
61
|
+
}
|
|
43
62
|
}
|
|
63
|
+
|
|
44
64
|
override fun getActiveDownloads(): Array<DownloadTask> = core.getActiveDownloads()
|
|
65
|
+
|
|
45
66
|
override fun getQueueStatus(): DownloadQueueStatus = core.getQueueStatus()
|
|
67
|
+
|
|
46
68
|
override fun isDownloading(trackId: String): Boolean = core.isDownloading(trackId)
|
|
69
|
+
|
|
47
70
|
override fun getDownloadState(trackId: String): DownloadState = core.getDownloadState(trackId)
|
|
48
71
|
|
|
49
72
|
// ── Downloaded content queries (now async per spec) ───────────────────────
|
|
50
73
|
override fun isTrackDownloaded(trackId: String): Promise<Boolean> = Promise.async { core.isTrackDownloaded(trackId) }
|
|
74
|
+
|
|
51
75
|
override fun isPlaylistDownloaded(playlistId: String): Promise<Boolean> = Promise.async { core.isPlaylistDownloaded(playlistId) }
|
|
76
|
+
|
|
52
77
|
override fun isPlaylistPartiallyDownloaded(playlistId: String): Promise<Boolean> = Promise.async { core.isPlaylistPartiallyDownloaded(playlistId) }
|
|
53
78
|
|
|
54
|
-
override fun getDownloadedTrack(trackId: String): Promise<Variant_NullType_DownloadedTrack> =
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
79
|
+
override fun getDownloadedTrack(trackId: String): Promise<Variant_NullType_DownloadedTrack> =
|
|
80
|
+
Promise.async {
|
|
81
|
+
val track = core.getDownloadedTrack(trackId)
|
|
82
|
+
if (track != null) {
|
|
83
|
+
Variant_NullType_DownloadedTrack.create(track)
|
|
84
|
+
} else {
|
|
85
|
+
Variant_NullType_DownloadedTrack.create(NullType.NULL)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
59
89
|
override fun getAllDownloadedTracks(): Promise<Array<DownloadedTrack>> = Promise.async { core.getAllDownloadedTracks() }
|
|
60
90
|
|
|
61
|
-
override fun getDownloadedPlaylist(playlistId: String): Promise<Variant_NullType_DownloadedPlaylist> =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
91
|
+
override fun getDownloadedPlaylist(playlistId: String): Promise<Variant_NullType_DownloadedPlaylist> =
|
|
92
|
+
Promise.async {
|
|
93
|
+
val playlist = core.getDownloadedPlaylist(playlistId)
|
|
94
|
+
if (playlist != null) {
|
|
95
|
+
Variant_NullType_DownloadedPlaylist.create(playlist)
|
|
96
|
+
} else {
|
|
97
|
+
Variant_NullType_DownloadedPlaylist.create(NullType.NULL)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
66
101
|
override fun getAllDownloadedPlaylists(): Promise<Array<DownloadedPlaylist>> = Promise.async { core.getAllDownloadedPlaylists() }
|
|
67
102
|
|
|
68
|
-
override fun getLocalPath(trackId: String): Promise<Variant_NullType_String> =
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
103
|
+
override fun getLocalPath(trackId: String): Promise<Variant_NullType_String> =
|
|
104
|
+
Promise.async {
|
|
105
|
+
val path = core.getLocalPath(trackId)
|
|
106
|
+
if (path != null) {
|
|
107
|
+
Variant_NullType_String.create(path)
|
|
108
|
+
} else {
|
|
109
|
+
Variant_NullType_String.create(NullType.NULL)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
73
112
|
|
|
74
113
|
override fun syncDownloads(): Promise<Double> = Promise.async { core.syncDownloads().toDouble() }
|
|
114
|
+
|
|
75
115
|
override fun getEffectiveUrl(track: TrackItem): Promise<String> = Promise.async { core.getEffectiveUrl(track) }
|
|
76
116
|
|
|
77
117
|
// ── Deletion ──────────────────────────────────────────────────────────────
|
|
78
118
|
override fun deleteDownloadedTrack(trackId: String): Promise<Unit> = Promise.async { core.deleteDownloadedTrack(trackId) }
|
|
119
|
+
|
|
79
120
|
override fun deleteDownloadedPlaylist(playlistId: String): Promise<Unit> = Promise.async { core.deleteDownloadedPlaylist(playlistId) }
|
|
121
|
+
|
|
80
122
|
override fun deleteAllDownloads(): Promise<Unit> = Promise.async { core.deleteAllDownloads() }
|
|
123
|
+
|
|
81
124
|
override fun getStorageInfo(): Promise<DownloadStorageInfo> = Promise.async { core.getStorageInfo() }
|
|
82
125
|
|
|
83
126
|
// ── Playback source ───────────────────────────────────────────────────────
|
|
84
127
|
override fun setPlaybackSourcePreference(preference: PlaybackSource) = core.setPlaybackSourcePreference(preference)
|
|
128
|
+
|
|
85
129
|
override fun getPlaybackSourcePreference(): PlaybackSource = core.getPlaybackSourcePreference()
|
|
86
130
|
|
|
87
131
|
// ── Events ────────────────────────────────────────────────────────────────
|
|
88
132
|
override fun onDownloadProgress(callback: (progress: DownloadProgress) -> Unit) = core.addProgressCallback(callback)
|
|
133
|
+
|
|
89
134
|
override fun onDownloadStateChange(callback: (downloadId: String, trackId: String, state: DownloadState, error: DownloadError?) -> Unit) = core.addStateChangeCallback(callback)
|
|
135
|
+
|
|
90
136
|
override fun onDownloadComplete(callback: (downloadedTrack: DownloadedTrack) -> Unit) = core.addCompleteCallback(callback)
|
|
91
137
|
}
|
|
@@ -13,37 +13,59 @@ class HybridEqualizer : HybridEqualizerSpec() {
|
|
|
13
13
|
private val core: EqualizerCore
|
|
14
14
|
|
|
15
15
|
init {
|
|
16
|
-
val context =
|
|
17
|
-
|
|
16
|
+
val context =
|
|
17
|
+
NitroModules.applicationContext
|
|
18
|
+
?: throw IllegalStateException("React Context is not initialized")
|
|
18
19
|
core = EqualizerCore.getInstance(context)
|
|
19
20
|
core.ensureInitialized()
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
// ── Sync reads ────────────────────────────────────────────────────────────
|
|
23
24
|
override fun isEnabled(): Boolean = core.isEnabled()
|
|
25
|
+
|
|
24
26
|
override fun getBandRange(): GainRange = core.getBandRange()
|
|
27
|
+
|
|
25
28
|
override fun getPresets(): Array<EqualizerPreset> = core.getPresets()
|
|
29
|
+
|
|
26
30
|
override fun getBuiltInPresets(): Array<EqualizerPreset> = core.getBuiltInPresets()
|
|
31
|
+
|
|
27
32
|
override fun getCustomPresets(): Array<EqualizerPreset> = core.getCustomPresets()
|
|
33
|
+
|
|
28
34
|
override fun getCurrentPresetName(): Variant_NullType_String {
|
|
29
35
|
val name = core.getCurrentPresetName()
|
|
30
|
-
return if (name != null)
|
|
31
|
-
|
|
36
|
+
return if (name != null) {
|
|
37
|
+
Variant_NullType_String.create(name)
|
|
38
|
+
} else {
|
|
39
|
+
Variant_NullType_String.create(NullType.NULL)
|
|
40
|
+
}
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
// ── Async mutations (per v2 spec) ─────────────────────────────────────────
|
|
35
44
|
override fun setEnabled(enabled: Boolean): Promise<Unit> = Promise.async { core.setEnabled(enabled) }
|
|
45
|
+
|
|
36
46
|
override fun getBands(): Promise<Array<EqualizerBand>> = Promise.async { core.getBands() }
|
|
37
|
-
|
|
47
|
+
|
|
48
|
+
override fun setBandGain(
|
|
49
|
+
bandIndex: Double,
|
|
50
|
+
gainDb: Double,
|
|
51
|
+
): Promise<Unit> = Promise.async { core.setBandGain(bandIndex.toInt(), gainDb) }
|
|
52
|
+
|
|
38
53
|
override fun setAllBandGains(gains: DoubleArray): Promise<Unit> = Promise.async { core.setAllBandGains(gains) }
|
|
54
|
+
|
|
39
55
|
override fun applyPreset(presetName: String): Promise<Unit> = Promise.async { core.applyPreset(presetName) }
|
|
56
|
+
|
|
40
57
|
override fun saveCustomPreset(name: String): Promise<Unit> = Promise.async { core.saveCustomPreset(name) }
|
|
58
|
+
|
|
41
59
|
override fun deleteCustomPreset(name: String): Promise<Unit> = Promise.async { core.deleteCustomPreset(name) }
|
|
60
|
+
|
|
42
61
|
override fun getState(): Promise<EqualizerState> = Promise.async { core.getState() }
|
|
62
|
+
|
|
43
63
|
override fun reset(): Promise<Unit> = Promise.async { core.reset() }
|
|
44
64
|
|
|
45
65
|
// ── Events ────────────────────────────────────────────────────────────────
|
|
46
66
|
override fun onEnabledChange(callback: (enabled: Boolean) -> Unit) = core.addOnEnabledChangeListener(callback)
|
|
67
|
+
|
|
47
68
|
override fun onBandChange(callback: (bands: Array<EqualizerBand>) -> Unit) = core.addOnBandChangeListener(callback)
|
|
69
|
+
|
|
48
70
|
override fun onPresetChange(callback: (presetName: Variant_NullType_String?) -> Unit) = core.addOnPresetChangeListener(callback)
|
|
49
71
|
}
|