react-native-nitro-player 1.7.0-alpha.3 → 1.7.0-alpha.5
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 +9 -0
- package/android/src/main/AndroidManifest.xml +8 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrary.kt +51 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/HybridPlayerQueue.kt +45 -7
- package/android/src/main/java/com/margelo/nitro/nitroplayer/connection/AndroidAutoConnectionDetector.kt +2 -2
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/ExoPlayerCore.kt +17 -2
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/NitroPlayerLogger.kt +2 -2
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerAndroidAuto.kt +41 -31
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerAudioFocus.kt +65 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCast.kt +1 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerCore.kt +92 -15
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerListener.kt +12 -17
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerNotify.kt +5 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerPlayback.kt +39 -13
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueue.kt +1 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerQueueBuild.kt +25 -4
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerRecovery.kt +97 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerSetup.kt +0 -5
- package/android/src/main/java/com/margelo/nitro/nitroplayer/core/TrackPlayerUrlLoader.kt +22 -5
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/DownloadDatabase.kt +3 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/download/TrackItemJson.kt +6 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/AudioFocusController.kt +87 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/CastSessionController.kt +2 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/ExoPlayerBuilder.kt +3 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaBrowserService.kt +96 -45
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaLibrary.kt +2 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaLibraryManager.kt +147 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaLibraryParser.kt +3 -0
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaSessionCallbackFactory.kt +102 -24
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/MediaSessionManager.kt +51 -3
- package/android/src/main/java/com/margelo/nitro/nitroplayer/media/PlaybackService.kt +82 -1
- package/android/src/main/java/com/margelo/nitro/nitroplayer/playlist/PlaylistManager.kt +75 -0
- package/ios/cast/CastQueueDiff.swift +58 -0
- package/ios/cast/CastQueueReconciler.swift +228 -0
- package/ios/core/CastSessionManager.swift +215 -31
- package/ios/core/TrackPlayerCast.swift +96 -65
- package/ios/core/TrackPlayerCore.swift +31 -0
- package/ios/core/TrackPlayerListener.swift +19 -3
- package/ios/core/TrackPlayerPlayback.swift +12 -10
- package/ios/core/TrackPlayerQueue.swift +10 -2
- package/ios/core/TrackPlayerQueueBuild.swift +21 -9
- package/ios/core/TrackPlayerTempQueue.swift +27 -15
- package/ios/core/TrackPlayerUrlLoader.swift +6 -2
- package/ios/playlist/PlaylistManager.swift +60 -1
- package/ios/queue/HybridPlayerQueue.swift +40 -13
- package/lib/hooks/callbackManager.d.ts +2 -0
- package/lib/hooks/callbackManager.js +23 -8
- package/lib/index.js +5 -1
- package/lib/specs/AndroidAutoMediaLibrary.nitro.d.ts +12 -0
- package/lib/specs/TrackPlayer.nitro.d.ts +5 -1
- package/lib/types/AndroidAutoMediaLibrary.d.ts +11 -0
- package/lib/types/PlayerQueue.d.ts +14 -0
- package/lib/utils/androidAutoMediaLibrary.d.ts +13 -1
- package/lib/utils/androidAutoMediaLibrary.js +23 -0
- package/nitrogen/generated/android/NitroPlayerOnLoad.cpp +6 -0
- package/nitrogen/generated/android/c++/JAndroidAudioFocusMode.hpp +61 -0
- package/nitrogen/generated/android/c++/JFunc_void.hpp +75 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +76 -0
- package/nitrogen/generated/android/c++/JFunc_void_std__string_std__string.hpp +76 -0
- package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.cpp +29 -0
- package/nitrogen/generated/android/c++/JHybridAndroidAutoMediaLibrarySpec.hpp +6 -0
- package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.cpp +43 -0
- package/nitrogen/generated/android/c++/JHybridPlayerQueueSpec.hpp +2 -0
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +4 -0
- package/nitrogen/generated/android/c++/JPlayerConfig.hpp +9 -3
- package/nitrogen/generated/android/c++/JShufflePlaylistOptions.hpp +57 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/AndroidAudioFocusMode.kt +24 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__string.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/Func_void_std__string_std__string.kt +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridAndroidAutoMediaLibrarySpec.kt +44 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/HybridPlayerQueueSpec.kt +8 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/PlayerConfig.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitroplayer/ShufflePlaylistOptions.kt +38 -0
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Bridge.hpp +36 -0
- package/nitrogen/generated/ios/NitroPlayer-Swift-Cxx-Umbrella.hpp +6 -0
- package/nitrogen/generated/ios/c++/HybridPlayerQueueSpecSwift.hpp +19 -0
- package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +3 -0
- package/nitrogen/generated/ios/swift/AndroidAudioFocusMode.swift +44 -0
- package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec.swift +2 -0
- package/nitrogen/generated/ios/swift/HybridPlayerQueueSpec_cxx.swift +38 -0
- package/nitrogen/generated/ios/swift/PlayerConfig.swift +12 -1
- package/nitrogen/generated/ios/swift/ShufflePlaylistOptions.swift +42 -0
- package/nitrogen/generated/shared/c++/AndroidAudioFocusMode.hpp +80 -0
- package/nitrogen/generated/shared/c++/HybridAndroidAutoMediaLibrarySpec.cpp +6 -0
- package/nitrogen/generated/shared/c++/HybridAndroidAutoMediaLibrarySpec.hpp +7 -0
- package/nitrogen/generated/shared/c++/HybridPlayerQueueSpec.cpp +2 -0
- package/nitrogen/generated/shared/c++/HybridPlayerQueueSpec.hpp +5 -0
- package/nitrogen/generated/shared/c++/PlayerConfig.hpp +9 -3
- package/nitrogen/generated/shared/c++/ShufflePlaylistOptions.hpp +83 -0
- package/package.json +1 -1
- package/src/hooks/callbackManager.ts +25 -10
- package/src/index.ts +9 -1
- package/src/specs/AndroidAutoMediaLibrary.nitro.ts +18 -0
- package/src/specs/TrackPlayer.nitro.ts +11 -0
- package/src/types/AndroidAutoMediaLibrary.ts +24 -0
- package/src/types/PlayerQueue.ts +17 -0
- package/src/utils/androidAutoMediaLibrary.ts +48 -1
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
///
|
|
2
|
+
/// ShufflePlaylistOptions.hpp
|
|
3
|
+
/// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
|
|
4
|
+
/// https://github.com/mrousavy/nitro
|
|
5
|
+
/// Copyright © Marc Rousavy @ Margelo
|
|
6
|
+
///
|
|
7
|
+
|
|
8
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#if __has_include(<NitroModules/JSIConverter.hpp>)
|
|
11
|
+
#include <NitroModules/JSIConverter.hpp>
|
|
12
|
+
#else
|
|
13
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
14
|
+
#endif
|
|
15
|
+
#if __has_include(<NitroModules/NitroDefines.hpp>)
|
|
16
|
+
#include <NitroModules/NitroDefines.hpp>
|
|
17
|
+
#else
|
|
18
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
19
|
+
#endif
|
|
20
|
+
#if __has_include(<NitroModules/JSIHelpers.hpp>)
|
|
21
|
+
#include <NitroModules/JSIHelpers.hpp>
|
|
22
|
+
#else
|
|
23
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
24
|
+
#endif
|
|
25
|
+
#if __has_include(<NitroModules/PropNameIDCache.hpp>)
|
|
26
|
+
#include <NitroModules/PropNameIDCache.hpp>
|
|
27
|
+
#else
|
|
28
|
+
#error NitroModules cannot be found! Are you sure you installed NitroModules properly?
|
|
29
|
+
#endif
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
#include <optional>
|
|
34
|
+
|
|
35
|
+
namespace margelo::nitro::nitroplayer {
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A struct which can be represented as a JavaScript object (ShufflePlaylistOptions).
|
|
39
|
+
*/
|
|
40
|
+
struct ShufflePlaylistOptions final {
|
|
41
|
+
public:
|
|
42
|
+
std::optional<bool> keepCurrentTrackFirst SWIFT_PRIVATE;
|
|
43
|
+
|
|
44
|
+
public:
|
|
45
|
+
ShufflePlaylistOptions() = default;
|
|
46
|
+
explicit ShufflePlaylistOptions(std::optional<bool> keepCurrentTrackFirst): keepCurrentTrackFirst(keepCurrentTrackFirst) {}
|
|
47
|
+
|
|
48
|
+
public:
|
|
49
|
+
friend bool operator==(const ShufflePlaylistOptions& lhs, const ShufflePlaylistOptions& rhs) = default;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
} // namespace margelo::nitro::nitroplayer
|
|
53
|
+
|
|
54
|
+
namespace margelo::nitro {
|
|
55
|
+
|
|
56
|
+
// C++ ShufflePlaylistOptions <> JS ShufflePlaylistOptions (object)
|
|
57
|
+
template <>
|
|
58
|
+
struct JSIConverter<margelo::nitro::nitroplayer::ShufflePlaylistOptions> final {
|
|
59
|
+
static inline margelo::nitro::nitroplayer::ShufflePlaylistOptions fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
|
|
60
|
+
jsi::Object obj = arg.asObject(runtime);
|
|
61
|
+
return margelo::nitro::nitroplayer::ShufflePlaylistOptions(
|
|
62
|
+
JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "keepCurrentTrackFirst")))
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::nitroplayer::ShufflePlaylistOptions& arg) {
|
|
66
|
+
jsi::Object obj(runtime);
|
|
67
|
+
obj.setProperty(runtime, PropNameIDCache::get(runtime, "keepCurrentTrackFirst"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.keepCurrentTrackFirst));
|
|
68
|
+
return obj;
|
|
69
|
+
}
|
|
70
|
+
static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
|
|
71
|
+
if (!value.isObject()) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
jsi::Object obj = value.getObject(runtime);
|
|
75
|
+
if (!nitro::isPlainObject(runtime, obj)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "keepCurrentTrackFirst")))) return false;
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
} // namespace margelo::nitro
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-nitro-player",
|
|
3
|
-
"version": "1.7.0-alpha.
|
|
3
|
+
"version": "1.7.0-alpha.5",
|
|
4
4
|
"description": "A powerful audio player library for React Native with playlist management, playback controls, and support for Android Auto and CarPlay",
|
|
5
5
|
"main": "lib/index",
|
|
6
6
|
"module": "lib/index",
|
|
@@ -37,6 +37,7 @@ class CallbackSubscriptionManager {
|
|
|
37
37
|
private androidAutoConnectionSubscribers =
|
|
38
38
|
new Set<AndroidAutoConnectionCallback>()
|
|
39
39
|
private isPlaylistsChangedRegistered = false
|
|
40
|
+
private playlistsChangedFanOutScheduled = false
|
|
40
41
|
private isAndroidAutoConnectionRegistered = false
|
|
41
42
|
private isPlaybackStateRegistered = false
|
|
42
43
|
private isTrackChangeRegistered = false
|
|
@@ -204,21 +205,35 @@ class CallbackSubscriptionManager {
|
|
|
204
205
|
}
|
|
205
206
|
}
|
|
206
207
|
|
|
208
|
+
// Task-level, not a microtask: native callbacks arrive as separate JS tasks.
|
|
209
|
+
private schedulePlaylistsChangedFanOut(): void {
|
|
210
|
+
if (this.playlistsChangedFanOutScheduled) return
|
|
211
|
+
this.playlistsChangedFanOutScheduled = true
|
|
212
|
+
setTimeout(() => {
|
|
213
|
+
this.playlistsChangedFanOutScheduled = false
|
|
214
|
+
this.playlistsChangedSubscribers.forEach((subscriber) => {
|
|
215
|
+
try {
|
|
216
|
+
subscriber()
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.error(
|
|
219
|
+
'[CallbackManager] Error in playlists changed subscriber:',
|
|
220
|
+
error
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
})
|
|
224
|
+
}, 0)
|
|
225
|
+
}
|
|
226
|
+
|
|
207
227
|
private ensurePlaylistsChangedRegistered(): void {
|
|
208
228
|
if (this.isPlaylistsChangedRegistered) return
|
|
209
229
|
|
|
210
230
|
try {
|
|
211
231
|
PlayerQueue.onPlaylistsChanged(() => {
|
|
212
|
-
this.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
'[CallbackManager] Error in playlists changed subscriber:',
|
|
218
|
-
error
|
|
219
|
-
)
|
|
220
|
-
}
|
|
221
|
-
})
|
|
232
|
+
this.schedulePlaylistsChangedFanOut()
|
|
233
|
+
})
|
|
234
|
+
// Track-level mutations only fire the per-playlist event.
|
|
235
|
+
PlayerQueue.onPlaylistChanged(() => {
|
|
236
|
+
this.schedulePlaylistsChangedFanOut()
|
|
222
237
|
})
|
|
223
238
|
this.isPlaylistsChangedRegistered = true
|
|
224
239
|
} catch (error) {
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// TODO: Export all HybridObjects here for the user
|
|
2
2
|
|
|
3
3
|
import { NitroModules } from 'react-native-nitro-modules'
|
|
4
|
-
import { Platform } from 'react-native'
|
|
4
|
+
import { AppRegistry, Platform } from 'react-native'
|
|
5
5
|
import type {
|
|
6
6
|
PlayerQueue as PlayerQueueType,
|
|
7
7
|
TrackPlayer as TrackPlayerType,
|
|
@@ -13,6 +13,14 @@ import type { Cast as CastType } from './specs/Cast.nitro'
|
|
|
13
13
|
import type { DownloadManager as DownloadManagerType } from './specs/DownloadManager.nitro'
|
|
14
14
|
import type { Equalizer as EqualizerType } from './specs/Equalizer.nitro'
|
|
15
15
|
|
|
16
|
+
// Native runs this while it needs JS without a resumed activity (car, screen off): it keeps JS timers ticking
|
|
17
|
+
if (Platform.OS === 'android') {
|
|
18
|
+
AppRegistry.registerHeadlessTask(
|
|
19
|
+
'NitroPlayerKeepAlive',
|
|
20
|
+
() => () => new Promise<void>(() => {})
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
export const PlayerQueue =
|
|
17
25
|
NitroModules.createHybridObject<PlayerQueueType>('PlayerQueue')
|
|
18
26
|
export const TrackPlayer =
|
|
@@ -20,4 +20,22 @@ export interface AndroidAutoMediaLibrary extends HybridObject<{
|
|
|
20
20
|
* Falls back to showing all playlists
|
|
21
21
|
*/
|
|
22
22
|
clearMediaLibrary(): Promise<void>
|
|
23
|
+
|
|
24
|
+
/** Android Auto opened a folder published with `children: []`; answer with {@link resolveRequest}. */
|
|
25
|
+
onLoadChildren(callback: (requestId: string, parentId: string) => void): void
|
|
26
|
+
|
|
27
|
+
/** A car search, or a voice request the loaded playlists cannot match; answer with {@link resolveRequest}. */
|
|
28
|
+
onSearch(callback: (requestId: string, query: string) => void): void
|
|
29
|
+
|
|
30
|
+
/** Answers {@link onLoadChildren} / {@link onSearch} with a JSON array of MediaItem. */
|
|
31
|
+
resolveRequest(requestId: string, itemsJson: string): void
|
|
32
|
+
|
|
33
|
+
/** Replaces the session buttons with a JSON array of SessionButton. */
|
|
34
|
+
setSessionButtons(buttonsJson: string): void
|
|
35
|
+
|
|
36
|
+
/** Called with the button's `action` when a session button is pressed. */
|
|
37
|
+
onSessionButtonPress(callback: (action: string) => void): void
|
|
38
|
+
|
|
39
|
+
/** A controller asked to play with nothing loaded (car auto-play, play on connect); load the last queue now. */
|
|
40
|
+
onPlaybackResumption(callback: () => void): void
|
|
23
41
|
}
|
|
@@ -8,6 +8,7 @@ import type {
|
|
|
8
8
|
PlayerConfig,
|
|
9
9
|
Playlist,
|
|
10
10
|
TimedMetadata,
|
|
11
|
+
ShufflePlaylistOptions,
|
|
11
12
|
} from '../types/PlayerQueue'
|
|
12
13
|
|
|
13
14
|
export interface PlayerQueue extends HybridObject<{
|
|
@@ -47,6 +48,16 @@ export interface PlayerQueue extends HybridObject<{
|
|
|
47
48
|
trackId: string,
|
|
48
49
|
newIndex: number
|
|
49
50
|
): Promise<void>
|
|
51
|
+
/** One native pass. Unknown ids are skipped; rejects only if the playlist does not exist. */
|
|
52
|
+
removeTracksFromPlaylist(
|
|
53
|
+
playlistId: string,
|
|
54
|
+
trackIds: string[]
|
|
55
|
+
): Promise<void>
|
|
56
|
+
/** Fisher-Yates shuffle of the stored playlist, persisted. Never interrupts the playing item. */
|
|
57
|
+
shufflePlaylist(
|
|
58
|
+
playlistId: string,
|
|
59
|
+
options?: ShufflePlaylistOptions
|
|
60
|
+
): Promise<void>
|
|
50
61
|
|
|
51
62
|
// Playback control
|
|
52
63
|
loadPlaylist(playlistId: string, index?: number): Promise<void>
|
|
@@ -38,6 +38,9 @@ export interface MediaItem {
|
|
|
38
38
|
|
|
39
39
|
/** Layout type for folder items (overrides library default) */
|
|
40
40
|
layoutType?: LayoutType
|
|
41
|
+
|
|
42
|
+
/** Group header; contiguous items sharing one are listed under it */
|
|
43
|
+
groupTitle?: string
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
/**
|
|
@@ -56,3 +59,24 @@ export interface MediaLibrary {
|
|
|
56
59
|
/** Optional app icon URL */
|
|
57
60
|
appIconUrl?: string
|
|
58
61
|
}
|
|
62
|
+
|
|
63
|
+
export type SessionButtonIcon =
|
|
64
|
+
| 'heart'
|
|
65
|
+
| 'heart_filled'
|
|
66
|
+
| 'star'
|
|
67
|
+
| 'star_filled'
|
|
68
|
+
| 'thumb_up'
|
|
69
|
+
| 'thumb_up_filled'
|
|
70
|
+
| 'plus'
|
|
71
|
+
| 'check'
|
|
72
|
+
|
|
73
|
+
/** App-defined button beside the transport controls in Android Auto and the notification */
|
|
74
|
+
export interface SessionButton {
|
|
75
|
+
/** Passed to the press callback */
|
|
76
|
+
action: string
|
|
77
|
+
|
|
78
|
+
/** Accessibility label */
|
|
79
|
+
title: string
|
|
80
|
+
|
|
81
|
+
icon: SessionButtonIcon
|
|
82
|
+
}
|
package/src/types/PlayerQueue.ts
CHANGED
|
@@ -26,6 +26,11 @@ export interface Playlist {
|
|
|
26
26
|
|
|
27
27
|
export type QueueOperation = 'add' | 'remove' | 'clear' | 'update'
|
|
28
28
|
|
|
29
|
+
export interface ShufflePlaylistOptions {
|
|
30
|
+
/** Move the playing track to index 0 and shuffle the rest behind it (default: true). */
|
|
31
|
+
keepCurrentTrackFirst?: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
export type TrackPlayerState = 'playing' | 'paused' | 'stopped' | 'buffering'
|
|
30
35
|
|
|
31
36
|
export type Reason = 'user_action' | 'skip' | 'end' | 'error' | 'repeat'
|
|
@@ -56,6 +61,15 @@ export interface TimedMetadata {
|
|
|
56
61
|
artworkUrl?: string
|
|
57
62
|
}
|
|
58
63
|
|
|
64
|
+
/**
|
|
65
|
+
* How Android reacts when another app takes audio focus.
|
|
66
|
+
* - 'pause': pause for any interruption and resume after it (default, today's behaviour)
|
|
67
|
+
* - 'duck': keep playing at a reduced volume through transient interruptions
|
|
68
|
+
* - 'ignore': never react to audio focus at all
|
|
69
|
+
* iOS ignores this option.
|
|
70
|
+
*/
|
|
71
|
+
export type AndroidAudioFocusMode = 'pause' | 'duck' | 'ignore'
|
|
72
|
+
|
|
59
73
|
export interface PlayerConfig {
|
|
60
74
|
androidAutoEnabled?: boolean
|
|
61
75
|
carPlayEnabled?: boolean
|
|
@@ -75,4 +89,7 @@ export interface PlayerConfig {
|
|
|
75
89
|
lookaheadCount?: number
|
|
76
90
|
|
|
77
91
|
androidNotificationIcon?: string
|
|
92
|
+
|
|
93
|
+
/** How Android reacts when another app takes audio focus (default: 'pause'). */
|
|
94
|
+
androidAudioFocus?: AndroidAudioFocusMode
|
|
78
95
|
}
|
|
@@ -1,6 +1,24 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type {
|
|
2
|
+
MediaItem,
|
|
3
|
+
MediaLibrary,
|
|
4
|
+
SessionButton,
|
|
5
|
+
} from '../types/AndroidAutoMediaLibrary'
|
|
2
6
|
import { AndroidAutoMediaLibrary as AndroidAutoMediaLibraryModule } from '../index'
|
|
3
7
|
|
|
8
|
+
type ItemsProvider = (
|
|
9
|
+
argument: string
|
|
10
|
+
) => Promise<MediaItem[] | null | undefined>
|
|
11
|
+
|
|
12
|
+
const answer = (requestId: string, provide: () => ReturnType<ItemsProvider>) =>
|
|
13
|
+
provide()
|
|
14
|
+
.catch(() => null)
|
|
15
|
+
.then((items) =>
|
|
16
|
+
AndroidAutoMediaLibraryModule?.resolveRequest(
|
|
17
|
+
requestId,
|
|
18
|
+
JSON.stringify(items ?? [])
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
|
|
4
22
|
/**
|
|
5
23
|
* Helper utilities for Android Auto Media Library
|
|
6
24
|
* Android-only functionality
|
|
@@ -57,6 +75,35 @@ export const AndroidAutoMediaLibraryHelper = {
|
|
|
57
75
|
AndroidAutoMediaLibraryModule.clearMediaLibrary()
|
|
58
76
|
},
|
|
59
77
|
|
|
78
|
+
/** Children of folders published with `children: []`; playable ids are `${playlistId}:${trackId}`, empty after 10s. Register at module scope: the car can start the app without UI. */
|
|
79
|
+
setChildrenLoader: (loader: ItemsProvider): void => {
|
|
80
|
+
AndroidAutoMediaLibraryModule?.onLoadChildren((requestId, parentId) =>
|
|
81
|
+
answer(requestId, () => loader(parentId))
|
|
82
|
+
)
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/** Answers car searches and unmatched voice requests (first playable result plays); search shows from the next connection. */
|
|
86
|
+
setSearchHandler: (handler: ItemsProvider): void => {
|
|
87
|
+
AndroidAutoMediaLibraryModule?.onSearch((requestId, query) =>
|
|
88
|
+
answer(requestId, () => handler(query))
|
|
89
|
+
)
|
|
90
|
+
},
|
|
91
|
+
|
|
92
|
+
/** Buttons beside the transport controls in Android Auto and the notification; call again to change their state. */
|
|
93
|
+
setSessionButtons: (buttons: SessionButton[]): void => {
|
|
94
|
+
AndroidAutoMediaLibraryModule?.setSessionButtons(JSON.stringify(buttons))
|
|
95
|
+
},
|
|
96
|
+
|
|
97
|
+
/** Called with the pressed button's `action`. */
|
|
98
|
+
onSessionButtonPress: (callback: (action: string) => void): void => {
|
|
99
|
+
AndroidAutoMediaLibraryModule?.onSessionButtonPress(callback)
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
/** Car auto-play or play-on-connect found nothing loaded: restore your last queue (playback starts once it is loaded). */
|
|
103
|
+
onPlaybackResumption: (callback: () => void): void => {
|
|
104
|
+
AndroidAutoMediaLibraryModule?.onPlaybackResumption(callback)
|
|
105
|
+
},
|
|
106
|
+
|
|
60
107
|
/**
|
|
61
108
|
* Check if Android Auto Media Library is available (Android only)
|
|
62
109
|
*/
|