react-native-nitro-player 0.0.1 → 0.3.0-alpha.10
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 +282 -2
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAudioDevices.kt +37 -29
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridTrackPlayer.kt +24 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +408 -16
- package/ios/HybridAudioRoutePicker.swift +47 -46
- package/ios/HybridTrackPlayer.swift +22 -0
- package/ios/core/TrackPlayerCore.swift +538 -48
- package/lib/hooks/callbackManager.d.ts +28 -0
- package/lib/hooks/callbackManager.js +76 -0
- package/lib/hooks/index.d.ts +7 -0
- package/lib/hooks/index.js +3 -0
- package/lib/hooks/useActualQueue.d.ts +48 -0
- package/lib/hooks/useActualQueue.js +98 -0
- package/lib/hooks/useNowPlaying.d.ts +36 -0
- package/lib/hooks/useNowPlaying.js +87 -0
- package/lib/hooks/useOnChangeTrack.d.ts +33 -6
- package/lib/hooks/useOnChangeTrack.js +65 -9
- package/lib/hooks/useOnPlaybackStateChange.d.ts +32 -6
- package/lib/hooks/useOnPlaybackStateChange.js +65 -9
- package/lib/hooks/usePlaylist.d.ts +48 -0
- package/lib/hooks/usePlaylist.js +136 -0
- package/lib/index.d.ts +1 -0
- package/lib/specs/TrackPlayer.nitro.d.ts +6 -0
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +46 -9
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +5 -0
- package/nitrogen/generated/android/c++/JRepeatMode.hpp +62 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridTrackPlayerSpec.kt +20 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/RepeatMode.kt +22 -0
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +9 -0
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Umbrella.hpp +3 -0
- package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +44 -4
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +5 -0
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +64 -0
- package/nitrogen/generated/ios/swift/RepeatMode.swift +44 -0
- package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.cpp +5 -0
- package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +12 -3
- package/nitrogen/generated/shared/c++/RepeatMode.hpp +80 -0
- package/package.json +13 -12
- package/src/hooks/callbackManager.ts +96 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useActualQueue.ts +116 -0
- package/src/hooks/useNowPlaying.ts +97 -0
- package/src/hooks/useOnChangeTrack.ts +77 -13
- package/src/hooks/useOnPlaybackStateChange.ts +83 -13
- package/src/hooks/usePlaylist.ts +161 -0
- package/src/index.ts +1 -1
- package/src/specs/TrackPlayer.nitro.ts +7 -0
package/README.md
CHANGED
|
@@ -80,8 +80,116 @@ TrackPlayer.pause()
|
|
|
80
80
|
TrackPlayer.skipToNext()
|
|
81
81
|
TrackPlayer.skipToPrevious()
|
|
82
82
|
TrackPlayer.seek(30) // Seek to 30 seconds
|
|
83
|
+
|
|
84
|
+
// Set repeat mode
|
|
85
|
+
TrackPlayer.setRepeatMode('off') // No repeat
|
|
86
|
+
TrackPlayer.setRepeatMode('Playlist') // Repeat entire playlist
|
|
87
|
+
TrackPlayer.setRepeatMode('track') // Repeat current track
|
|
88
|
+
|
|
89
|
+
// Set volume (0-100)
|
|
90
|
+
TrackPlayer.setVolume(50) // Set volume to 50%
|
|
91
|
+
TrackPlayer.setVolume(0) // Mute
|
|
92
|
+
TrackPlayer.setVolume(100) // Maximum volume
|
|
93
|
+
|
|
94
|
+
// Add temporary tracks to queue
|
|
95
|
+
TrackPlayer.addToUpNext('song-id') // Add to up-next queue (FIFO)
|
|
96
|
+
TrackPlayer.playNext('song-id') // Add to play-next stack (LIFO)
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Temporary Queue Management
|
|
100
|
+
|
|
101
|
+
The player supports adding temporary tracks to the queue without modifying the original playlist. These tracks are automatically removed after playing.
|
|
102
|
+
|
|
103
|
+
### `addToUpNext(trackId: string)`
|
|
104
|
+
|
|
105
|
+
Adds a track to the **up-next queue** (FIFO - First In, First Out). Tracks play in the order they were added.
|
|
106
|
+
|
|
107
|
+
**Behavior:**
|
|
108
|
+
|
|
109
|
+
- Track is inserted after the current track and any "play next" tracks
|
|
110
|
+
- Multiple tracks can be added - they play in the order added
|
|
111
|
+
- Track is automatically removed after playing
|
|
112
|
+
- Does not modify the original playlist
|
|
113
|
+
|
|
114
|
+
**Example:**
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// Add tracks to up-next queue
|
|
118
|
+
TrackPlayer.addToUpNext('song-1') // Will play 3rd
|
|
119
|
+
TrackPlayer.addToUpNext('song-2') // Will play 4th
|
|
120
|
+
TrackPlayer.addToUpNext('song-3') // Will play 5th
|
|
121
|
+
// Order: [current] → [song-1] → [song-2] → [song-3]
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `playNext(trackId: string)`
|
|
125
|
+
|
|
126
|
+
Adds a track to the **play-next stack** (LIFO - Last In, First Out). The most recently added track plays first.
|
|
127
|
+
|
|
128
|
+
**Behavior:**
|
|
129
|
+
|
|
130
|
+
- Track is inserted immediately after the current track
|
|
131
|
+
- Multiple tracks can be added - the last added plays first
|
|
132
|
+
- Track is automatically removed after playing
|
|
133
|
+
- Does not modify the original playlist
|
|
134
|
+
|
|
135
|
+
**Example:**
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// Add tracks to play-next stack
|
|
139
|
+
TrackPlayer.playNext('song-1') // Will play 3rd
|
|
140
|
+
TrackPlayer.playNext('song-2') // Will play 2nd (most recent)
|
|
141
|
+
TrackPlayer.playNext('song-3') // Will play 1st (most recent)
|
|
142
|
+
// Order: [current] → [song-3] → [song-2] → [song-1]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Queue Order
|
|
146
|
+
|
|
147
|
+
The actual playback order is:
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
[original tracks before current]
|
|
151
|
+
+ [CURRENT TRACK]
|
|
152
|
+
+ [playNext stack (LIFO)]
|
|
153
|
+
+ [upNext queue (FIFO)]
|
|
154
|
+
+ [original tracks after current]
|
|
83
155
|
```
|
|
84
156
|
|
|
157
|
+
### Clearing Temporary Tracks
|
|
158
|
+
|
|
159
|
+
Temporary tracks are automatically cleared when:
|
|
160
|
+
|
|
161
|
+
- `TrackPlayer.playSong()` is called
|
|
162
|
+
- `PlayerQueue.loadPlaylist()` is called
|
|
163
|
+
- `TrackPlayer.playFromIndex()` is called
|
|
164
|
+
|
|
165
|
+
### Getting the Actual Queue
|
|
166
|
+
|
|
167
|
+
Use `useActualQueue()` hook to see the complete queue including temporary tracks:
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
import { useActualQueue } from 'react-native-nitro-player'
|
|
171
|
+
|
|
172
|
+
function QueueView() {
|
|
173
|
+
const { queue, refreshQueue, isLoading } = useActualQueue()
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<ScrollView>
|
|
177
|
+
{queue.map((track, index) => (
|
|
178
|
+
<View key={track.id}>
|
|
179
|
+
<Text>{index + 1}. {track.title}</Text>
|
|
180
|
+
</View>
|
|
181
|
+
))}
|
|
182
|
+
</ScrollView>
|
|
183
|
+
)
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**Returns:**
|
|
188
|
+
|
|
189
|
+
- `queue: TrackItem[]` - Complete queue in playback order
|
|
190
|
+
- `refreshQueue: () => void` - Manually refresh the queue
|
|
191
|
+
- `isLoading: boolean` - Whether the queue is currently loading
|
|
192
|
+
|
|
85
193
|
## Core Concepts
|
|
86
194
|
|
|
87
195
|
### PlayerQueue
|
|
@@ -99,6 +207,9 @@ Controls playback. Use it to:
|
|
|
99
207
|
|
|
100
208
|
- Play, pause, and seek
|
|
101
209
|
- Skip tracks
|
|
210
|
+
- Control repeat mode
|
|
211
|
+
- Control volume
|
|
212
|
+
- Add temporary tracks to queue (`addToUpNext`, `playNext`)
|
|
102
213
|
- Get current player state
|
|
103
214
|
- Listen to playback events
|
|
104
215
|
|
|
@@ -159,6 +270,93 @@ Automatically polls for audio device changes every 2 seconds.
|
|
|
159
270
|
|
|
160
271
|
- `devices: TAudioDevice[]` - Array of available audio devices
|
|
161
272
|
|
|
273
|
+
### `useNowPlaying()`
|
|
274
|
+
|
|
275
|
+
Returns the complete current player state (same as `TrackPlayer.getState()`). This hook provides all player information in a single object and automatically updates when the player state changes.
|
|
276
|
+
|
|
277
|
+
**Returns:**
|
|
278
|
+
|
|
279
|
+
- `PlayerState` object containing:
|
|
280
|
+
- `currentTrack: TrackItem | null` - The current track being played, or `null` if no track is playing
|
|
281
|
+
- `totalDuration: number` - Total duration of the current track in seconds
|
|
282
|
+
- `currentState: TrackPlayerState` - Current playback state (`'playing'`, `'paused'`, or `'stopped'`)
|
|
283
|
+
- `currentPlaylistId: string | null` - ID of the currently loaded playlist, or `null` if no playlist is loaded
|
|
284
|
+
- `currentIndex: number` - Index of the current track in the playlist (-1 if no track is playing)
|
|
285
|
+
|
|
286
|
+
**Note:** This hook is equivalent to calling `TrackPlayer.getState()` but provides reactive updates. It listens to track changes and playback state changes to update automatically. Also dont rely on progress from this hook
|
|
287
|
+
|
|
288
|
+
### `useActualQueue()`
|
|
289
|
+
|
|
290
|
+
Returns the actual playback queue including temporary tracks (from `addToUpNext` and `playNext`).
|
|
291
|
+
|
|
292
|
+
**Returns:**
|
|
293
|
+
|
|
294
|
+
- `queue: TrackItem[]` - Complete queue in playback order: `[tracks_before_current] + [current] + [playNext_stack] + [upNext_queue] + [remaining_tracks]`
|
|
295
|
+
- `refreshQueue: () => void` - Manually refresh the queue (useful after adding tracks)
|
|
296
|
+
- `isLoading: boolean` - Whether the queue is currently loading
|
|
297
|
+
|
|
298
|
+
**Auto-updates when:**
|
|
299
|
+
|
|
300
|
+
- Track changes
|
|
301
|
+
- Temporary tracks are added (`playNext`/`addToUpNext`)
|
|
302
|
+
- Playback state changes
|
|
303
|
+
|
|
304
|
+
**Example:**
|
|
305
|
+
|
|
306
|
+
```typescript
|
|
307
|
+
import { useActualQueue } from 'react-native-nitro-player'
|
|
308
|
+
|
|
309
|
+
function QueueView() {
|
|
310
|
+
const { queue, refreshQueue, isLoading } = useActualQueue()
|
|
311
|
+
|
|
312
|
+
const handleAddToUpNext = (trackId: string) => {
|
|
313
|
+
TrackPlayer.addToUpNext(trackId)
|
|
314
|
+
// Refresh queue after adding track
|
|
315
|
+
setTimeout(refreshQueue, 100)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
return (
|
|
319
|
+
<ScrollView>
|
|
320
|
+
{queue.map((track, index) => (
|
|
321
|
+
<View key={track.id}>
|
|
322
|
+
<Text>{index + 1}. {track.title}</Text>
|
|
323
|
+
</View>
|
|
324
|
+
))}
|
|
325
|
+
</ScrollView>
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### `usePlaylist()`
|
|
331
|
+
|
|
332
|
+
Manages playlist-related state and provides access to all playlists and tracks.
|
|
333
|
+
|
|
334
|
+
**Returns:**
|
|
335
|
+
|
|
336
|
+
- `currentPlaylist: Playlist | null` - The currently loaded playlist
|
|
337
|
+
- `currentPlaylistId: string | null` - ID of the currently loaded playlist
|
|
338
|
+
- `allPlaylists: Playlist[]` - Array of all playlists
|
|
339
|
+
- `allTracks: TrackItem[]` - Array of all tracks from all playlists
|
|
340
|
+
- `isLoading: boolean` - Whether playlists are currently loading
|
|
341
|
+
- `refreshPlaylists: () => void` - Manually refresh playlist data
|
|
342
|
+
|
|
343
|
+
**Example:**
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import { usePlaylist } from 'react-native-nitro-player'
|
|
347
|
+
|
|
348
|
+
function PlaylistView() {
|
|
349
|
+
const { allPlaylists, allTracks, refreshPlaylists } = usePlaylist()
|
|
350
|
+
|
|
351
|
+
return (
|
|
352
|
+
<View>
|
|
353
|
+
<Text>Playlists: {allPlaylists.length}</Text>
|
|
354
|
+
<Text>Total Tracks: {allTracks.length}</Text>
|
|
355
|
+
</View>
|
|
356
|
+
)
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
162
360
|
## Audio Device APIs
|
|
163
361
|
|
|
164
362
|
### `AudioDevices` (Android only)
|
|
@@ -183,7 +381,7 @@ import { AudioDevices } from 'react-native-nitro-player'
|
|
|
183
381
|
|
|
184
382
|
if (AudioDevices) {
|
|
185
383
|
const devices = AudioDevices.getAudioDevices()
|
|
186
|
-
devices.forEach(
|
|
384
|
+
devices.forEach(device => {
|
|
187
385
|
console.log(`${device.name} - Active: ${device.isActive}`)
|
|
188
386
|
})
|
|
189
387
|
}
|
|
@@ -228,6 +426,82 @@ if (AudioRoutePicker) {
|
|
|
228
426
|
}
|
|
229
427
|
```
|
|
230
428
|
|
|
429
|
+
## Repeat Mode
|
|
430
|
+
|
|
431
|
+
Control how tracks repeat during playback.
|
|
432
|
+
|
|
433
|
+
### `setRepeatMode(mode: RepeatMode): boolean`
|
|
434
|
+
|
|
435
|
+
Sets the repeat mode for the player.
|
|
436
|
+
|
|
437
|
+
**Parameters:**
|
|
438
|
+
|
|
439
|
+
- `mode: 'off' | 'Playlist' | 'track'` - The repeat mode to set
|
|
440
|
+
- `'off'` - No repeat, playlist stops at the end
|
|
441
|
+
- `'Playlist'` - Repeat the entire playlist
|
|
442
|
+
- `'track'` - Repeat the current track only
|
|
443
|
+
|
|
444
|
+
**Returns:** `true` if successful, `false` otherwise
|
|
445
|
+
|
|
446
|
+
**Example:**
|
|
447
|
+
|
|
448
|
+
```typescript
|
|
449
|
+
import { TrackPlayer } from 'react-native-nitro-player'
|
|
450
|
+
|
|
451
|
+
// Turn off repeat
|
|
452
|
+
TrackPlayer.setRepeatMode('off')
|
|
453
|
+
|
|
454
|
+
// Repeat entire playlist
|
|
455
|
+
TrackPlayer.setRepeatMode('Playlist')
|
|
456
|
+
|
|
457
|
+
// Repeat current track
|
|
458
|
+
TrackPlayer.setRepeatMode('track')
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
## Volume Control
|
|
462
|
+
|
|
463
|
+
Control the playback volume level.
|
|
464
|
+
|
|
465
|
+
### `setVolume(volume: number): boolean`
|
|
466
|
+
|
|
467
|
+
Sets the playback volume level.
|
|
468
|
+
|
|
469
|
+
**Parameters:**
|
|
470
|
+
|
|
471
|
+
- `volume: number` - Volume level between 0 and 100
|
|
472
|
+
- `0` - Mute (no sound)
|
|
473
|
+
- `50` - Half volume
|
|
474
|
+
- `100` - Maximum volume
|
|
475
|
+
|
|
476
|
+
**Returns:** `true` if successful, `false` otherwise (e.g., if player is not initialized)
|
|
477
|
+
|
|
478
|
+
**Example:**
|
|
479
|
+
|
|
480
|
+
```typescript
|
|
481
|
+
import { TrackPlayer } from 'react-native-nitro-player'
|
|
482
|
+
|
|
483
|
+
// Set volume to 50%
|
|
484
|
+
const success = TrackPlayer.setVolume(50)
|
|
485
|
+
if (success) {
|
|
486
|
+
console.log('Volume set successfully')
|
|
487
|
+
} else {
|
|
488
|
+
console.warn('Failed to set volume')
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Mute the player
|
|
492
|
+
TrackPlayer.setVolume(0)
|
|
493
|
+
|
|
494
|
+
// Set to maximum volume
|
|
495
|
+
TrackPlayer.setVolume(100)
|
|
496
|
+
|
|
497
|
+
// Incremental volume control
|
|
498
|
+
const currentVolume = 50
|
|
499
|
+
TrackPlayer.setVolume(currentVolume + 10) // Increase by 10%
|
|
500
|
+
TrackPlayer.setVolume(currentVolume - 10) // Decrease by 10%
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
**Note:** The volume value is automatically clamped to the 0-100 range. Values outside this range will be clamped to the nearest valid value.
|
|
504
|
+
|
|
231
505
|
## Usage Examples
|
|
232
506
|
|
|
233
507
|
### Using React Hooks
|
|
@@ -259,6 +533,9 @@ function PlayerComponent() {
|
|
|
259
533
|
// Check Android Auto connection
|
|
260
534
|
const { isConnected } = useAndroidAutoConnection()
|
|
261
535
|
|
|
536
|
+
// Get complete player state (alternative to individual hooks)
|
|
537
|
+
const nowPlaying = useNowPlaying()
|
|
538
|
+
|
|
262
539
|
return (
|
|
263
540
|
<View>
|
|
264
541
|
{track && (
|
|
@@ -266,6 +543,8 @@ function PlayerComponent() {
|
|
|
266
543
|
)}
|
|
267
544
|
<Text>State: {state}</Text>
|
|
268
545
|
<Text>Progress: {position} / {totalDuration}</Text>
|
|
546
|
+
{/* Or use useNowPlaying for all state at once */}
|
|
547
|
+
<Text>Now Playing State: {nowPlaying.currentState}</Text>
|
|
269
548
|
</View>
|
|
270
549
|
)
|
|
271
550
|
}
|
|
@@ -349,7 +628,7 @@ TrackPlayer.onPlaybackProgressChange(
|
|
|
349
628
|
)
|
|
350
629
|
|
|
351
630
|
// Listen to Android Auto connection changes
|
|
352
|
-
TrackPlayer.onAndroidAutoConnectionChange(
|
|
631
|
+
TrackPlayer.onAndroidAutoConnectionChange(connected => {
|
|
353
632
|
console.log('Android Auto:', connected ? 'Connected' : 'Disconnected')
|
|
354
633
|
})
|
|
355
634
|
```
|
|
@@ -572,6 +851,7 @@ AndroidAutoMediaLibraryHelper.set({
|
|
|
572
851
|
|
|
573
852
|
- ✅ **Playlist Management**: Create, update, and manage multiple playlists
|
|
574
853
|
- ✅ **Playback Controls**: Play, pause, seek, skip tracks
|
|
854
|
+
- ✅ **Volume Control**: Adjust playback volume (0-100)
|
|
575
855
|
- ✅ **React Hooks**: Built-in hooks for reactive state management
|
|
576
856
|
- ✅ **Event Listeners**: Listen to track changes, state changes, and more
|
|
577
857
|
- ✅ **Android Auto Support**: Control playback from Android Auto with customizable UI
|
|
@@ -7,21 +7,21 @@ import android.os.Build
|
|
|
7
7
|
import com.margelo.nitro.NitroModules
|
|
8
8
|
|
|
9
9
|
class HybridAudioDevices : HybridAudioDevicesSpec() {
|
|
10
|
-
|
|
11
|
-
val applicationContext = NitroModules.applicationContext;
|
|
10
|
+
val applicationContext = NitroModules.applicationContext
|
|
12
11
|
private val audioManager = applicationContext?.getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
|
13
|
-
|
|
12
|
+
|
|
14
13
|
// Device types that can be set as communication devices
|
|
15
14
|
private val validCommunicationDeviceTypes: Set<Int> by lazy {
|
|
16
|
-
val types =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
15
|
+
val types =
|
|
16
|
+
mutableSetOf(
|
|
17
|
+
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE,
|
|
18
|
+
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER,
|
|
19
|
+
AudioDeviceInfo.TYPE_WIRED_HEADSET,
|
|
20
|
+
AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
|
|
21
|
+
AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
|
|
22
|
+
AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
|
|
23
|
+
AudioDeviceInfo.TYPE_USB_HEADSET,
|
|
24
|
+
)
|
|
25
25
|
// BLE types are only available on Android S (API 31) and above
|
|
26
26
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
27
27
|
types.add(AudioDeviceInfo.TYPE_BLE_HEADSET)
|
|
@@ -29,7 +29,7 @@ class HybridAudioDevices : HybridAudioDevicesSpec() {
|
|
|
29
29
|
}
|
|
30
30
|
types
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
override fun getAudioDevices(): Array<TAudioDevice> {
|
|
34
34
|
val devices = audioManager.getDevices(android.media.AudioManager.GET_DEVICES_OUTPUTS)
|
|
35
35
|
var activeDevice: AudioDeviceInfo? = null
|
|
@@ -37,20 +37,23 @@ class HybridAudioDevices : HybridAudioDevicesSpec() {
|
|
|
37
37
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
38
38
|
activeDevice = audioManager.communicationDevice
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
// Filter to only include valid communication devices
|
|
42
|
-
return devices
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
return devices
|
|
43
|
+
.filter { device ->
|
|
44
|
+
validCommunicationDeviceTypes.contains(device.type)
|
|
45
|
+
}.map { device ->
|
|
46
|
+
TAudioDevice(
|
|
47
|
+
id = device.id.toDouble(),
|
|
48
|
+
name = device.productName?.toString() ?: getDeviceTypeName(device.type),
|
|
49
|
+
type = device.type.toDouble(),
|
|
50
|
+
isActive = device == activeDevice,
|
|
51
|
+
)
|
|
52
|
+
}.toTypedArray()
|
|
50
53
|
}
|
|
51
|
-
|
|
52
|
-
private fun getDeviceTypeName(type: Int): String
|
|
53
|
-
|
|
54
|
+
|
|
55
|
+
private fun getDeviceTypeName(type: Int): String =
|
|
56
|
+
when (type) {
|
|
54
57
|
AudioDeviceInfo.TYPE_BUILTIN_EARPIECE -> "Built-in Earpiece"
|
|
55
58
|
AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> "Built-in Speaker"
|
|
56
59
|
AudioDeviceInfo.TYPE_WIRED_HEADSET -> "Wired Headset"
|
|
@@ -62,11 +65,11 @@ class HybridAudioDevices : HybridAudioDevicesSpec() {
|
|
|
62
65
|
27 -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) "BLE Speaker" else "Type 27"
|
|
63
66
|
else -> "Type $type"
|
|
64
67
|
}
|
|
65
|
-
}
|
|
66
68
|
|
|
67
69
|
override fun setAudioDevice(deviceId: Double): Boolean {
|
|
68
70
|
val device =
|
|
69
|
-
audioManager
|
|
71
|
+
audioManager
|
|
72
|
+
.getDevices(android.media.AudioManager.GET_DEVICES_OUTPUTS)
|
|
70
73
|
.firstOrNull { it.id == deviceId.toInt() }
|
|
71
74
|
?: return false
|
|
72
75
|
|
|
@@ -83,21 +86,26 @@ class HybridAudioDevices : HybridAudioDevicesSpec() {
|
|
|
83
86
|
// Pre-Android 12 fallback (best-effort)
|
|
84
87
|
when (device.type) {
|
|
85
88
|
android.media.AudioDeviceInfo.TYPE_BLUETOOTH_SCO,
|
|
86
|
-
android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP
|
|
89
|
+
android.media.AudioDeviceInfo.TYPE_BLUETOOTH_A2DP,
|
|
90
|
+
-> {
|
|
87
91
|
audioManager.startBluetoothSco()
|
|
88
92
|
audioManager.isBluetoothScoOn = true
|
|
89
93
|
true
|
|
90
94
|
}
|
|
95
|
+
|
|
91
96
|
android.media.AudioDeviceInfo.TYPE_BUILTIN_SPEAKER -> {
|
|
92
97
|
audioManager.isSpeakerphoneOn = true
|
|
93
98
|
true
|
|
94
99
|
}
|
|
100
|
+
|
|
95
101
|
android.media.AudioDeviceInfo.TYPE_WIRED_HEADSET,
|
|
96
|
-
android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES
|
|
102
|
+
android.media.AudioDeviceInfo.TYPE_WIRED_HEADPHONES,
|
|
103
|
+
-> {
|
|
97
104
|
audioManager.isSpeakerphoneOn = false
|
|
98
105
|
audioManager.isBluetoothScoOn = false
|
|
99
106
|
true
|
|
100
107
|
}
|
|
108
|
+
|
|
101
109
|
else -> {
|
|
102
110
|
android.util.Log.w(TAG, "Unsupported device type for pre-Android 12: ${device.type}")
|
|
103
111
|
false
|
|
@@ -53,10 +53,30 @@ class HybridTrackPlayer : HybridTrackPlayerSpec() {
|
|
|
53
53
|
core.seek(position)
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
@DoNotStrip
|
|
57
|
+
@Keep
|
|
58
|
+
override fun addToUpNext(trackId: String) {
|
|
59
|
+
core.addToUpNext(trackId)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@DoNotStrip
|
|
63
|
+
@Keep
|
|
64
|
+
override fun playNext(trackId: String) {
|
|
65
|
+
core.playNext(trackId)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@DoNotStrip
|
|
69
|
+
@Keep
|
|
70
|
+
override fun getActualQueue(): Array<TrackItem> = core.getActualQueue().toTypedArray()
|
|
71
|
+
|
|
56
72
|
@DoNotStrip
|
|
57
73
|
@Keep
|
|
58
74
|
override fun getState(): PlayerState = core.getState()
|
|
59
75
|
|
|
76
|
+
@DoNotStrip
|
|
77
|
+
@Keep
|
|
78
|
+
override fun setRepeatMode(mode: RepeatMode): Boolean = core.setRepeatMode(mode)
|
|
79
|
+
|
|
60
80
|
override fun onChangeTrack(callback: (track: TrackItem, reason: Reason?) -> Unit) {
|
|
61
81
|
core.onChangeTrack = callback
|
|
62
82
|
}
|
|
@@ -90,4 +110,8 @@ class HybridTrackPlayer : HybridTrackPlayerSpec() {
|
|
|
90
110
|
|
|
91
111
|
@Keep
|
|
92
112
|
override fun isAndroidAutoConnected(): Boolean = core.isAndroidAutoConnected()
|
|
113
|
+
|
|
114
|
+
@DoNotStrip
|
|
115
|
+
@Keep
|
|
116
|
+
override fun setVolume(volume: Double): Boolean = core.setVolume(volume)
|
|
93
117
|
}
|