react-native-audio-browser 0.2.0-next.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AudioBrowser.podspec +1 -1
- package/README.md +2 -180
- package/android/build.gradle +1 -17
- package/android/gradle.properties +1 -1
- package/android/src/main/AndroidManifest.xml +0 -15
- package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +141 -401
- package/android/src/main/java/com/audiobrowser/Callbacks.kt +6 -4
- package/android/src/main/java/com/audiobrowser/Service.kt +18 -67
- package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +178 -442
- package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +4 -41
- package/android/src/main/java/com/audiobrowser/browser/TrackLoadHandler.kt +4 -4
- package/android/src/main/java/com/audiobrowser/http/RequestConfigBuilder.kt +97 -109
- package/android/src/main/java/com/audiobrowser/model/PlaybackMetadata.kt +10 -6
- package/android/src/main/java/com/audiobrowser/model/PlayerSetupOptions.kt +8 -40
- package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +46 -40
- package/android/src/main/java/com/audiobrowser/player/AutomaticBufferManager.kt +1 -4
- package/android/src/main/java/com/audiobrowser/player/DynamicLoadControl.kt +1 -18
- package/android/src/main/java/com/audiobrowser/player/MediaFactory.kt +3 -15
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +134 -422
- package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +404 -248
- package/android/src/main/java/com/audiobrowser/player/PlaybackProgressUpdateManager.kt +59 -0
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +5 -25
- package/android/src/main/java/com/audiobrowser/player/Player.kt +582 -469
- package/android/src/main/java/com/audiobrowser/player/PlayerListener.kt +67 -190
- package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +53 -118
- package/android/src/main/java/com/audiobrowser/player/SleepTimer.kt +3 -37
- package/android/src/main/java/com/audiobrowser/player/TransformingDataSource.kt +40 -85
- package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +0 -24
- package/android/src/main/java/com/audiobrowser/util/CoilBitmapLoader.kt +300 -23
- package/android/src/main/java/com/audiobrowser/util/EqualizerManager.kt +23 -13
- package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +2 -2
- package/android/src/main/java/com/audiobrowser/util/MetadataAdapter.kt +3 -4
- package/android/src/main/java/com/audiobrowser/util/PlayingStateFactory.kt +1 -2
- package/android/src/main/java/com/audiobrowser/util/RatingFactory.kt +72 -0
- package/android/src/main/java/com/audiobrowser/util/ResolvedTrackFactory.kt +36 -0
- package/android/src/main/java/com/audiobrowser/util/SvgArtworkRenderer.kt +111 -6
- package/android/src/main/java/com/audiobrowser/util/SystemVolumeMonitor.kt +8 -22
- package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +80 -112
- package/android/src/main/res/values/strings.xml +0 -4
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +0 -4
- package/android/src/test/java/com/audiobrowser/browser/SimpleRouterTest.kt +2 -1
- package/android/src/test/java/com/audiobrowser/http/RequestConfigBuilderTest.kt +0 -72
- package/android/src/test/java/com/audiobrowser/player/PlaybackProgressUpdateManagerTest.kt +146 -0
- package/ios/Browser/BrowserConfig.swift +11 -41
- package/ios/Browser/BrowserManager+URLResolution.swift +93 -213
- package/ios/Browser/BrowserManager.swift +110 -303
- package/ios/Browser/BrowserPathHelper.swift +3 -32
- package/ios/Browser/JsonModels.swift +66 -287
- package/ios/CarPlay/CarPlayArtworkResolver.swift +6 -6
- package/ios/CarPlay/CarPlayController.swift +149 -739
- package/ios/CarPlay/CarPlayImageLoader.swift +8 -57
- package/ios/CarPlay/CarPlayListItemFactory.swift +35 -44
- package/ios/CarPlay/CarPlayNowPlayingManager.swift +36 -180
- package/ios/CarPlay/RNABAudioBrowser.h +10 -15
- package/ios/CarPlay/RNABAudioBrowser.m +14 -15
- package/ios/CarPlay/RNABCarPlaySceneDelegate.m +0 -2
- package/ios/CarPlay/RNABMediaIntentHandler.swift +43 -53
- package/ios/CarPlay/Track+CarPlay.swift +63 -0
- package/ios/Extension/Capability+RemoteCommand.swift +9 -7
- package/ios/Extension/ChapterMetadata+AVFoundation.swift +1 -1
- package/ios/Extension/NavigationError+Conversion.swift +1 -8
- package/ios/Extension/ResolvedTrack+Copying.swift +4 -10
- package/ios/Extension/TimedMetadata+AVFoundation.swift +1 -1
- package/ios/Extension/Track+AVPlayer.swift +4 -4
- package/ios/Extension/Track+Copying.swift +3 -9
- package/ios/Extension/TrackMetadata+AVFoundation.swift +1 -1
- package/ios/HybridAudioBrowser.swift +173 -751
- package/ios/Model/NitroTypeStubs.swift +224 -299
- package/ios/Model/PlayerUpdateOptions.swift +23 -23
- package/ios/Model/RemoteCommand.swift +6 -24
- package/ios/Model/TrackPlayerError.swift +18 -82
- package/ios/NowPlayingInfo/NowPlayingInfoCenter.swift +9 -0
- package/ios/NowPlayingInfo/NowPlayingInfoController.swift +121 -99
- package/ios/Observer/PlayerItemNotificationObserver.swift +5 -45
- package/ios/Observer/PlayerItemPropertyObserver.swift +4 -27
- package/ios/Observer/PlayerTimeObserver.swift +53 -3
- package/ios/Option/SessionCategories.swift +11 -34
- package/ios/Player/LoadSeekCoordinator.swift +1 -16
- package/ios/Player/MediaLoader.swift +11 -31
- package/ios/Player/NowPlayingUpdater.swift +26 -119
- package/ios/Player/PlaybackCoordinator.swift +51 -285
- package/ios/Player/PlaybackCoordinatorCallbacks.swift +1 -6
- package/ios/Player/PlaybackEffectHandler.swift +9 -19
- package/ios/Player/PlaybackErrorHandler.swift +13 -97
- package/ios/Player/PlaybackProgressUpdateManager.swift +68 -0
- package/ios/Player/PlaybackStateMachine.swift +13 -18
- package/ios/Player/PlayingStateManager.swift +2 -3
- package/ios/Player/QueueManager.swift +61 -67
- package/ios/Player/RetryManager.swift +21 -98
- package/ios/Player/SleepTimerHandling.swift +0 -8
- package/ios/Player/SleepTimerManager.swift +11 -72
- package/ios/RemoteCommand/RemoteCommandController.swift +21 -40
- package/ios/Tests/BrowserPathHelperTests.swift +0 -28
- package/ios/Tests/CarPlayArtworkResolverTests.swift +39 -39
- package/ios/Tests/ChapterMetadataAVFoundationTests.swift +2 -2
- package/ios/Tests/LoadSeekCoordinatorTests.swift +7 -40
- package/ios/Tests/MediaLoaderTests.swift +20 -32
- package/ios/Tests/PlaybackCoordinatorTests.swift +13 -787
- package/ios/Tests/PlaybackErrorHandlerTests.swift +46 -380
- package/ios/Tests/PlaybackProgressUpdateManagerTests.swift +166 -0
- package/ios/Tests/PlaybackStateMachineTests.swift +8 -33
- package/ios/Tests/QueueManagerTests.swift +18 -149
- package/ios/Tests/ResolvedTrackCopyingTests.swift +8 -15
- package/ios/Tests/Support/TestTypes.swift +20 -61
- package/ios/Tests/TrackSelectorTests.swift +15 -15
- package/ios/TrackPlayer.swift +58 -380
- package/ios/TrackPlayerCallbacks.swift +44 -5
- package/ios/TrackSelector.swift +5 -5
- package/ios/Util/ArtworkImageFetcher.swift +2 -4
- package/ios/Util/NetworkMonitor.swift +3 -7
- package/ios/Util/OnceValue.swift +0 -34
- package/lib/commonjs/AudioBrowser.js +11 -0
- package/lib/commonjs/AudioBrowser.js.map +1 -1
- package/lib/commonjs/features/browser.js +158 -59
- package/lib/commonjs/features/browser.js.map +1 -1
- package/lib/commonjs/features/equalizer.js +1 -1
- package/lib/commonjs/features/errors.js +5 -37
- package/lib/commonjs/features/errors.js.map +1 -1
- package/lib/commonjs/features/favorites.js +1 -1
- package/lib/commonjs/features/index.js +0 -22
- package/lib/commonjs/features/index.js.map +1 -1
- package/lib/commonjs/features/metadata.js +3 -3
- package/lib/commonjs/features/metadata.js.map +1 -1
- package/lib/commonjs/features/network.js +1 -1
- package/lib/commonjs/features/nowPlaying.js +1 -36
- package/lib/commonjs/features/nowPlaying.js.map +1 -1
- package/lib/commonjs/features/output.js +23 -37
- package/lib/commonjs/features/output.js.map +1 -1
- package/lib/commonjs/features/playback/controls.js +0 -9
- package/lib/commonjs/features/playback/controls.js.map +1 -1
- package/lib/commonjs/features/playback/index.js +0 -11
- package/lib/commonjs/features/playback/index.js.map +1 -1
- package/lib/commonjs/features/playback/playWhenReady.js +1 -1
- package/lib/commonjs/features/playback/playing.js +1 -1
- package/lib/commonjs/features/playback/progress.js +13 -29
- package/lib/commonjs/features/playback/progress.js.map +1 -1
- package/lib/commonjs/features/playback/state.js +1 -1
- package/lib/commonjs/features/playback/volume.js +2 -2
- package/lib/commonjs/features/player/options.js +29 -79
- package/lib/commonjs/features/player/options.js.map +1 -1
- package/lib/commonjs/features/player/setup.js +3 -256
- package/lib/commonjs/features/player/setup.js.map +1 -1
- package/lib/commonjs/features/queue/activeTrack.js +1 -1
- package/lib/commonjs/features/queue/queue.js +5 -12
- package/lib/commonjs/features/queue/queue.js.map +1 -1
- package/lib/commonjs/features/queue/repeatMode.js +1 -1
- package/lib/commonjs/features/queue/shuffle.js +1 -1
- package/lib/commonjs/features/rating.js +2 -0
- package/lib/commonjs/features/rating.js.map +1 -0
- package/lib/commonjs/features/remoteControls.js +104 -14
- package/lib/commonjs/features/remoteControls.js.map +1 -1
- package/lib/commonjs/features/sleepTimer.js +5 -10
- package/lib/commonjs/features/sleepTimer.js.map +1 -1
- package/lib/commonjs/native.js +0 -5
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/native.web.js +1 -4
- package/lib/commonjs/native.web.js.map +1 -1
- package/lib/commonjs/types/player.js +2 -0
- package/lib/commonjs/types/player.js.map +1 -0
- package/lib/commonjs/utils/LazyNativeEmitter.js +8 -8
- package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/commonjs/utils/NativeUpdatedValue.js +3 -0
- package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/commonjs/web/NativeAudioBrowser.js +124 -301
- package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
- package/lib/commonjs/web/SimpleRouter.test.js +174 -0
- package/lib/commonjs/web/SimpleRouter.test.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/Player.js +26 -90
- package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js +293 -0
- package/lib/commonjs/web/TrackPlayer/PlaylistPlayer.js.map +1 -0
- package/lib/commonjs/web/TrackPlayer/RepeatMode.js +1 -1
- package/lib/commonjs/web/TrackPlayer/RepeatMode.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/SleepTimer.js +3 -34
- package/lib/commonjs/web/TrackPlayer/SleepTimer.js.map +1 -1
- package/lib/commonjs/web/TrackPlayer/index.js +5 -13
- package/lib/commonjs/web/TrackPlayer/index.js.map +1 -1
- package/lib/commonjs/web/browser/BrowserManager.js +50 -176
- package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
- package/lib/commonjs/web/browser/NavigationErrorManager.js +1 -3
- package/lib/commonjs/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/commonjs/web/browser/SearchManager.js +9 -11
- package/lib/commonjs/web/browser/SearchManager.js.map +1 -1
- package/lib/commonjs/web/http/HttpClient.js +23 -4
- package/lib/commonjs/web/http/HttpClient.js.map +1 -1
- package/lib/commonjs/web/http/RequestConfigBuilder.js +58 -107
- package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/commonjs/web/player/NowPlayingManager.js +5 -6
- package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
- package/lib/commonjs/web/player/OptionsManager.js +17 -9
- package/lib/commonjs/web/player/OptionsManager.js.map +1 -1
- package/lib/module/AudioBrowser.js +1 -4
- package/lib/module/AudioBrowser.js.map +1 -1
- package/lib/module/features/browser.js +156 -53
- package/lib/module/features/browser.js.map +1 -1
- package/lib/module/features/equalizer.js +1 -1
- package/lib/module/features/errors.js +5 -37
- package/lib/module/features/errors.js.map +1 -1
- package/lib/module/features/favorites.js +1 -1
- package/lib/module/features/index.js +0 -2
- package/lib/module/features/index.js.map +1 -1
- package/lib/module/features/metadata.js +3 -3
- package/lib/module/features/metadata.js.map +1 -1
- package/lib/module/features/network.js +1 -1
- package/lib/module/features/nowPlaying.js +1 -34
- package/lib/module/features/nowPlaying.js.map +1 -1
- package/lib/module/features/output.js +19 -32
- package/lib/module/features/output.js.map +1 -1
- package/lib/module/features/playback/controls.js +0 -8
- package/lib/module/features/playback/controls.js.map +1 -1
- package/lib/module/features/playback/index.js +0 -1
- package/lib/module/features/playback/index.js.map +1 -1
- package/lib/module/features/playback/playWhenReady.js +1 -1
- package/lib/module/features/playback/playing.js +1 -1
- package/lib/module/features/playback/progress.js +13 -29
- package/lib/module/features/playback/progress.js.map +1 -1
- package/lib/module/features/playback/state.js +1 -1
- package/lib/module/features/playback/volume.js +2 -2
- package/lib/module/features/player/options.js +29 -79
- package/lib/module/features/player/options.js.map +1 -1
- package/lib/module/features/player/setup.js +3 -256
- package/lib/module/features/player/setup.js.map +1 -1
- package/lib/module/features/queue/activeTrack.js +1 -1
- package/lib/module/features/queue/queue.js +5 -12
- package/lib/module/features/queue/queue.js.map +1 -1
- package/lib/module/features/queue/repeatMode.js +1 -1
- package/lib/module/features/queue/shuffle.js +1 -1
- package/lib/module/features/rating.js +2 -0
- package/lib/module/features/rating.js.map +1 -0
- package/lib/module/features/remoteControls.js +103 -13
- package/lib/module/features/remoteControls.js.map +1 -1
- package/lib/module/features/sleepTimer.js +5 -10
- package/lib/module/features/sleepTimer.js.map +1 -1
- package/lib/module/native.js +0 -5
- package/lib/module/native.js.map +1 -1
- package/lib/module/native.web.js +1 -4
- package/lib/module/native.web.js.map +1 -1
- package/lib/module/types/player.js +2 -0
- package/lib/module/types/player.js.map +1 -0
- package/lib/module/utils/LazyNativeEmitter.js +8 -8
- package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
- package/lib/module/utils/NativeUpdatedValue.js +3 -0
- package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
- package/lib/module/web/NativeAudioBrowser.js +125 -302
- package/lib/module/web/NativeAudioBrowser.js.map +1 -1
- package/lib/module/web/SimpleRouter.test.js +174 -0
- package/lib/module/web/SimpleRouter.test.js.map +1 -0
- package/lib/module/web/TrackPlayer/Player.js +26 -90
- package/lib/module/web/TrackPlayer/Player.js.map +1 -1
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js +288 -0
- package/lib/module/web/TrackPlayer/PlaylistPlayer.js.map +1 -0
- package/lib/module/web/TrackPlayer/RepeatMode.js +1 -1
- package/lib/module/web/TrackPlayer/RepeatMode.js.map +1 -1
- package/lib/module/web/TrackPlayer/SleepTimer.js +3 -34
- package/lib/module/web/TrackPlayer/SleepTimer.js.map +1 -1
- package/lib/module/web/TrackPlayer/index.js +1 -2
- package/lib/module/web/TrackPlayer/index.js.map +1 -1
- package/lib/module/web/browser/BrowserManager.js +50 -176
- package/lib/module/web/browser/BrowserManager.js.map +1 -1
- package/lib/module/web/browser/NavigationErrorManager.js +1 -3
- package/lib/module/web/browser/NavigationErrorManager.js.map +1 -1
- package/lib/module/web/browser/SearchManager.js +9 -11
- package/lib/module/web/browser/SearchManager.js.map +1 -1
- package/lib/module/web/http/HttpClient.js +23 -4
- package/lib/module/web/http/HttpClient.js.map +1 -1
- package/lib/module/web/http/RequestConfigBuilder.js +58 -107
- package/lib/module/web/http/RequestConfigBuilder.js.map +1 -1
- package/lib/module/web/player/NowPlayingManager.js +5 -7
- package/lib/module/web/player/NowPlayingManager.js.map +1 -1
- package/lib/module/web/player/OptionsManager.js +17 -9
- package/lib/module/web/player/OptionsManager.js.map +1 -1
- package/lib/typescript/src/AudioBrowser.d.ts +1 -0
- package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
- package/lib/typescript/src/features/browser.d.ts +1 -40
- package/lib/typescript/src/features/browser.d.ts.map +1 -1
- package/lib/typescript/src/features/equalizer.d.ts +1 -1
- package/lib/typescript/src/features/errors.d.ts +6 -61
- package/lib/typescript/src/features/errors.d.ts.map +1 -1
- package/lib/typescript/src/features/favorites.d.ts +1 -1
- package/lib/typescript/src/features/index.d.ts +0 -2
- package/lib/typescript/src/features/index.d.ts.map +1 -1
- package/lib/typescript/src/features/metadata.d.ts +7 -9
- package/lib/typescript/src/features/metadata.d.ts.map +1 -1
- package/lib/typescript/src/features/network.d.ts +1 -1
- package/lib/typescript/src/features/nowPlaying.d.ts +1 -28
- package/lib/typescript/src/features/nowPlaying.d.ts.map +1 -1
- package/lib/typescript/src/features/output.d.ts +18 -28
- package/lib/typescript/src/features/output.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/controls.d.ts +0 -5
- package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/index.d.ts +0 -1
- package/lib/typescript/src/features/playback/index.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/playWhenReady.d.ts +1 -1
- package/lib/typescript/src/features/playback/playing.d.ts +1 -1
- package/lib/typescript/src/features/playback/progress.d.ts +1 -4
- package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
- package/lib/typescript/src/features/playback/state.d.ts +1 -1
- package/lib/typescript/src/features/playback/volume.d.ts +2 -2
- package/lib/typescript/src/features/player/options.d.ts +127 -176
- package/lib/typescript/src/features/player/options.d.ts.map +1 -1
- package/lib/typescript/src/features/player/setup.d.ts +167 -213
- package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/activeTrack.d.ts +1 -1
- package/lib/typescript/src/features/queue/queue.d.ts +4 -11
- package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
- package/lib/typescript/src/features/queue/repeatMode.d.ts +1 -1
- package/lib/typescript/src/features/queue/shuffle.d.ts +1 -1
- package/lib/typescript/src/features/rating.d.ts +14 -0
- package/lib/typescript/src/features/rating.d.ts.map +1 -0
- package/lib/typescript/src/features/remoteControls.d.ts +35 -23
- package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
- package/lib/typescript/src/features/sleepTimer.d.ts +4 -19
- package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/native.d.ts +2 -1
- package/lib/typescript/src/native.d.ts.map +1 -1
- package/lib/typescript/src/native.web.d.ts +3 -0
- package/lib/typescript/src/native.web.d.ts.map +1 -0
- package/lib/typescript/src/specs/audio-browser.nitro.d.ts +225 -17
- package/lib/typescript/src/specs/audio-browser.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-native.d.ts +3 -9
- package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
- package/lib/typescript/src/types/browser-nodes.d.ts +13 -145
- package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
- package/lib/typescript/src/types/browser.d.ts +85 -349
- package/lib/typescript/src/types/browser.d.ts.map +1 -1
- package/lib/typescript/src/types/player.d.ts +64 -0
- package/lib/typescript/src/types/player.d.ts.map +1 -0
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +6 -8
- package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +2 -0
- package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
- package/lib/typescript/src/utils/resolveAssetSource.d.ts.map +1 -1
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts +188 -0
- package/lib/typescript/src/web/NativeAudioBrowser.d.ts.map +1 -0
- package/lib/typescript/src/web/SimpleRouter.d.ts +40 -0
- package/lib/typescript/src/web/SimpleRouter.d.ts.map +1 -0
- package/lib/typescript/src/web/SimpleRouter.test.d.ts +2 -0
- package/lib/typescript/src/web/SimpleRouter.test.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/Event.d.ts +11 -0
- package/lib/typescript/src/web/TrackPlayer/Event.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts +59 -0
- package/lib/typescript/src/web/TrackPlayer/Player.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts +39 -0
- package/lib/typescript/src/web/TrackPlayer/PlaylistPlayer.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts +6 -0
- package/lib/typescript/src/web/TrackPlayer/RepeatMode.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts +4 -0
- package/lib/typescript/src/web/TrackPlayer/SetupNotCalledError.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts +34 -0
- package/lib/typescript/src/web/TrackPlayer/SleepTimer.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/State.d.ts +13 -0
- package/lib/typescript/src/web/TrackPlayer/State.d.ts.map +1 -0
- package/lib/typescript/src/web/TrackPlayer/index.d.ts +5 -0
- package/lib/typescript/src/web/TrackPlayer/index.d.ts.map +1 -0
- package/lib/typescript/src/web/browser/BrowserManager.d.ts +154 -0
- package/lib/typescript/src/web/browser/BrowserManager.d.ts.map +1 -0
- package/lib/typescript/src/web/browser/FavoriteManager.d.ts +42 -0
- package/lib/typescript/src/web/browser/FavoriteManager.d.ts.map +1 -0
- package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts +40 -0
- package/lib/typescript/src/web/browser/NavigationErrorManager.d.ts.map +1 -0
- package/lib/typescript/src/web/browser/SearchManager.d.ts +22 -0
- package/lib/typescript/src/web/browser/SearchManager.d.ts.map +1 -0
- package/lib/typescript/src/web/http/HttpClient.d.ts +25 -0
- package/lib/typescript/src/web/http/HttpClient.d.ts.map +1 -0
- package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts +98 -0
- package/lib/typescript/src/web/http/RequestConfigBuilder.d.ts.map +1 -0
- package/lib/typescript/src/web/player/NowPlayingManager.d.ts +34 -0
- package/lib/typescript/src/web/player/NowPlayingManager.d.ts.map +1 -0
- package/lib/typescript/src/web/player/OptionsManager.d.ts +32 -0
- package/lib/typescript/src/web/player/OptionsManager.d.ts.map +1 -0
- package/lib/typescript/src/web/util/BrowserPathHelper.d.ts +69 -0
- package/lib/typescript/src/web/util/BrowserPathHelper.d.ts.map +1 -0
- package/lib/typescript/src/web/util/shuffle.d.ts +8 -0
- package/lib/typescript/src/web/util/shuffle.d.ts.map +1 -0
- package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +2 -4
- package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +10 -24
- package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +6 -6
- package/nitrogen/generated/android/c++/JAndroidOptions.hpp +20 -10
- package/nitrogen/generated/android/c++/JAndroidUpdateOptions.hpp +86 -0
- package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +1 -33
- package/nitrogen/generated/android/c++/JBrowseResult.hpp +0 -5
- package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +3 -3
- package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +0 -6
- package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +2 -3
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +0 -6
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.hpp +147 -0
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +0 -8
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +0 -6
- package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +0 -6
- package/nitrogen/generated/android/c++/JFunc_void_IosOutput.hpp +80 -0
- package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +10 -0
- package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +9 -14
- package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +0 -2
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +0 -6
- package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +0 -2
- package/nitrogen/generated/android/c++/JFunc_void_RemoteSetRatingEvent.hpp +87 -0
- package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +10 -10
- package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +0 -6
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +0 -6
- package/nitrogen/generated/android/c++/JHeartRating.hpp +57 -0
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +221 -245
- package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +22 -25
- package/nitrogen/generated/android/c++/JImageRowItem.hpp +3 -33
- package/nitrogen/generated/android/c++/{JOutput.hpp → JIosOutput.hpp} +15 -15
- package/nitrogen/generated/android/c++/JIosOutputType.hpp +85 -0
- package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +1 -33
- package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +28 -61
- package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +9 -20
- package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +24 -21
- package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +0 -6
- package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +20 -10
- package/nitrogen/generated/android/c++/{JRemoteButton.hpp → JNotificationButton.hpp} +20 -20
- package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +94 -0
- package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +17 -3
- package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +3 -7
- package/nitrogen/generated/android/c++/JOptions.hpp +14 -19
- package/nitrogen/generated/android/c++/{JNativeAndroidSetupOptions.hpp → JPartialAndroidSetupPlayerOptions.hpp} +10 -10
- package/nitrogen/generated/android/c++/{JNativeIOSSetupOptions.hpp → JPartialIOSSetupPlayerOptions.hpp} +10 -10
- package/nitrogen/generated/android/c++/JPartialSetupPlayerOptions.hpp +96 -0
- package/nitrogen/generated/android/c++/JPercentageRating.hpp +57 -0
- package/nitrogen/generated/android/c++/JPlayback.hpp +0 -2
- package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +0 -6
- package/nitrogen/generated/android/c++/JPlaybackError.hpp +3 -18
- package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +0 -2
- package/nitrogen/generated/android/c++/JPlaybackState.hpp +3 -3
- package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
- package/nitrogen/generated/android/c++/JRatingType.hpp +73 -0
- package/nitrogen/generated/android/c++/JRemoteSetRatingEvent.hpp +66 -0
- package/nitrogen/generated/android/c++/JResolvedTrack.hpp +5 -23
- package/nitrogen/generated/android/c++/JRetryConfig.hpp +7 -11
- package/nitrogen/generated/android/c++/JSearchMode.hpp +9 -27
- package/nitrogen/generated/android/c++/JSearchParams.hpp +3 -9
- package/nitrogen/generated/android/c++/JStarRating.hpp +57 -0
- package/nitrogen/generated/android/c++/{JGateEvent.hpp → JThumbsRating.hpp} +15 -16
- package/nitrogen/generated/android/c++/JTrack.hpp +5 -23
- package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +0 -6
- package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +1 -14
- package/nitrogen/generated/android/c++/JUpdateOptions.hpp +105 -0
- package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.cpp +34 -0
- package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.hpp +105 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +75 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioContentType.kt +4 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +9 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidUpdateOptions.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +4 -10
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayNowPlayingButton.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.kt → Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.kt} +12 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_void_Output.kt → Func_void_IosOutput.kt} +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Func_void_GateEvent.kt → Func_void_RemoteSetRatingEvent.kt} +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +9 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Gate.kt → HeartRating.kt} +6 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +109 -103
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +3 -24
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Output.kt → IosOutput.kt} +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutputType.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +4 -10
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +6 -18
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +4 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorType.kt +1 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +9 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → NotificationButton.kt} +8 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +50 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +6 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +3 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +3 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NativeAndroidSetupOptions.kt → PartialAndroidSetupPlayerOptions.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NativeIOSSetupOptions.kt → PartialIOSSetupPlayerOptions.kt} +5 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialSetupPlayerOptions.kt +47 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{GateDecision.kt → PercentageRating.kt} +6 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +3 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackState.kt +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{GateReason.kt → RatingType.kt} +10 -5
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{ArtworkVariants.kt → RemoteSetRatingEvent.kt} +6 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +3 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +4 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchMode.kt +6 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +3 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{GateEvent.kt → StarRating.kt} +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → ThumbsRating.kt} +6 -6
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +3 -12
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +4 -7
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/UpdateOptions.kt +53 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.kt +77 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Variant_NullType_RemoteButtonLayout.kt → Variant_NullType_NotificationButtonLayout.kt} +9 -9
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +28 -139
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +489 -1125
- package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +45 -66
- package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +118 -176
- package/nitrogen/generated/ios/swift/AndroidAudioContentType.swift +8 -8
- package/nitrogen/generated/ios/swift/AndroidOptions.swift +22 -12
- package/nitrogen/generated/ios/swift/AndroidUpdateOptions.swift +119 -0
- package/nitrogen/generated/ios/swift/ArtworkRequestConfig.swift +1 -95
- package/nitrogen/generated/ios/swift/CarPlayNowPlayingButton.swift +4 -4
- package/nitrogen/generated/ios/swift/FormattedNavigationError.swift +4 -17
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.swift +68 -0
- package/nitrogen/generated/ios/swift/{Func_void_Output.swift → Func_void_IosOutput.swift} +10 -10
- package/nitrogen/generated/ios/swift/{Func_void_GateEvent.swift → Func_void_RemoteSetRatingEvent.swift} +10 -10
- package/nitrogen/generated/ios/swift/Func_void_bool.swift +5 -5
- package/nitrogen/generated/ios/swift/{Func_void_std__shared_ptr_Promise_GateDecision__.swift → Func_void_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError___.swift} +17 -17
- package/nitrogen/generated/ios/swift/HeartRating.swift +29 -0
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +14 -20
- package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +197 -230
- package/nitrogen/generated/ios/swift/ImageRowItem.swift +2 -121
- package/nitrogen/generated/ios/swift/{Output.swift → IosOutput.swift} +7 -7
- package/nitrogen/generated/ios/swift/IosOutputType.swift +76 -0
- package/nitrogen/generated/ios/swift/MediaRequestConfig.swift +1 -107
- package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +22 -161
- package/nitrogen/generated/ios/swift/NativeRouteEntry.swift +19 -19
- package/nitrogen/generated/ios/swift/NativeUpdateOptions.swift +25 -12
- package/nitrogen/generated/ios/swift/NavigationErrorType.swift +0 -8
- package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +41 -12
- package/nitrogen/generated/ios/swift/{RemoteButton.swift → NotificationButton.swift} +10 -10
- package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +92 -0
- package/nitrogen/generated/ios/swift/NowPlayingMetadata.swift +48 -1
- package/nitrogen/generated/ios/swift/NowPlayingUpdate.swift +1 -19
- package/nitrogen/generated/ios/swift/Options.swift +4 -10
- package/nitrogen/generated/ios/swift/{NativeAndroidSetupOptions.swift → PartialAndroidSetupPlayerOptions.swift} +5 -5
- package/nitrogen/generated/ios/swift/{NativeIOSSetupOptions.swift → PartialIOSSetupPlayerOptions.swift} +5 -5
- package/nitrogen/generated/ios/swift/PartialSetupPlayerOptions.swift +101 -0
- package/nitrogen/generated/ios/swift/PercentageRating.swift +29 -0
- package/nitrogen/generated/ios/swift/PlaybackError.swift +2 -43
- package/nitrogen/generated/ios/swift/PlaybackState.swift +4 -4
- package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
- package/nitrogen/generated/ios/swift/RatingType.swift +60 -0
- package/nitrogen/generated/ios/swift/RemoteSetRatingEvent.swift +58 -0
- package/nitrogen/generated/ios/swift/ResolvedTrack.swift +8 -74
- package/nitrogen/generated/ios/swift/RetryConfig.swift +4 -35
- package/nitrogen/generated/ios/swift/SearchMode.swift +12 -36
- package/nitrogen/generated/ios/swift/SearchParams.swift +2 -7
- package/nitrogen/generated/ios/swift/StarRating.swift +29 -0
- package/nitrogen/generated/ios/swift/ThumbsRating.swift +29 -0
- package/nitrogen/generated/ios/swift/Track.swift +8 -74
- package/nitrogen/generated/ios/swift/TransformableRequestConfig.swift +1 -60
- package/nitrogen/generated/ios/swift/UpdateOptions.swift +143 -0
- package/nitrogen/generated/ios/swift/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.swift +20 -0
- package/nitrogen/generated/ios/swift/{Variant_NullType_RemoteButtonLayout.swift → Variant_NullType_NotificationButtonLayout.swift} +3 -3
- package/nitrogen/generated/shared/c++/AndroidAudioContentType.hpp +10 -10
- package/nitrogen/generated/shared/c++/AndroidOptions.hpp +19 -8
- package/nitrogen/generated/shared/c++/AndroidUpdateOptions.hpp +109 -0
- package/nitrogen/generated/shared/c++/ArtworkRequestConfig.hpp +2 -10
- package/nitrogen/generated/shared/c++/CarPlayNowPlayingButton.hpp +6 -6
- package/nitrogen/generated/shared/c++/EqualizerSettings.hpp +2 -0
- package/nitrogen/generated/shared/c++/FormattedNavigationError.hpp +5 -6
- package/nitrogen/generated/shared/c++/{GateEvent.hpp → HeartRating.hpp} +17 -18
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +18 -21
- package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +35 -44
- package/nitrogen/generated/shared/c++/ImageRowItem.hpp +2 -33
- package/nitrogen/generated/shared/c++/{Output.hpp → IosOutput.hpp} +18 -18
- package/nitrogen/generated/shared/c++/IosOutputType.hpp +112 -0
- package/nitrogen/generated/shared/c++/MediaRequestConfig.hpp +2 -10
- package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +15 -31
- package/nitrogen/generated/shared/c++/NativeRouteEntry.hpp +5 -5
- package/nitrogen/generated/shared/c++/NativeUpdateOptions.hpp +7 -9
- package/nitrogen/generated/shared/c++/NavigationErrorType.hpp +0 -8
- package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +19 -8
- package/nitrogen/generated/shared/c++/{RemoteButton.hpp → NotificationButton.hpp} +25 -25
- package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +102 -0
- package/nitrogen/generated/shared/c++/NowPlayingMetadata.hpp +19 -3
- package/nitrogen/generated/shared/c++/NowPlayingUpdate.hpp +2 -6
- package/nitrogen/generated/shared/c++/Options.hpp +8 -8
- package/nitrogen/generated/shared/c++/{NativeAndroidSetupOptions.hpp → PartialAndroidSetupPlayerOptions.hpp} +11 -11
- package/nitrogen/generated/shared/c++/{NativeIOSSetupOptions.hpp → PartialIOSSetupPlayerOptions.hpp} +11 -11
- package/nitrogen/generated/shared/c++/PartialSetupPlayerOptions.hpp +104 -0
- package/nitrogen/generated/shared/c++/{FavoriteConfig.hpp → PercentageRating.hpp} +17 -18
- package/nitrogen/generated/shared/c++/PlaybackError.hpp +3 -18
- package/nitrogen/generated/shared/c++/PlaybackState.hpp +9 -9
- package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
- package/nitrogen/generated/shared/c++/RatingType.hpp +96 -0
- package/nitrogen/generated/shared/c++/RemoteSetRatingEvent.hpp +94 -0
- package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +5 -24
- package/nitrogen/generated/shared/c++/RetryConfig.hpp +6 -10
- package/nitrogen/generated/shared/c++/SearchMode.hpp +15 -39
- package/nitrogen/generated/shared/c++/SearchParams.hpp +2 -9
- package/nitrogen/generated/shared/c++/{Gate.hpp → StarRating.hpp} +16 -21
- package/nitrogen/generated/shared/c++/{GateDecision.hpp → ThumbsRating.hpp} +17 -23
- package/nitrogen/generated/shared/c++/Track.hpp +5 -24
- package/nitrogen/generated/shared/c++/TransformableRequestConfig.hpp +2 -6
- package/nitrogen/generated/shared/c++/UpdateOptions.hpp +111 -0
- package/package.json +5 -12
- package/src/AudioBrowser.ts +1 -4
- package/src/features/browser.ts +201 -58
- package/src/features/equalizer.ts +1 -1
- package/src/features/errors.ts +5 -71
- package/src/features/favorites.ts +1 -1
- package/src/features/index.ts +0 -2
- package/src/features/metadata.ts +15 -9
- package/src/features/network.ts +1 -1
- package/src/features/nowPlaying.ts +1 -37
- package/src/features/output.ts +22 -35
- package/src/features/playback/controls.ts +0 -8
- package/src/features/playback/index.ts +0 -1
- package/src/features/playback/playWhenReady.ts +1 -1
- package/src/features/playback/playing.ts +1 -1
- package/src/features/playback/progress.ts +13 -32
- package/src/features/playback/state.ts +1 -1
- package/src/features/playback/volume.ts +2 -2
- package/src/features/player/options.ts +110 -217
- package/src/features/player/setup.ts +175 -397
- package/src/features/queue/activeTrack.ts +1 -1
- package/src/features/queue/queue.ts +6 -17
- package/src/features/queue/repeatMode.ts +1 -1
- package/src/features/queue/shuffle.ts +1 -1
- package/src/features/rating.ts +17 -0
- package/src/features/remoteControls.ts +115 -13
- package/src/features/sleepTimer.ts +5 -24
- package/src/native.ts +0 -5
- package/src/native.web.ts +1 -4
- package/src/specs/audio-browser.nitro.ts +41 -131
- package/src/types/browser-native.ts +6 -19
- package/src/types/browser-nodes.ts +13 -160
- package/src/types/browser.ts +89 -377
- package/src/types/player.ts +69 -0
- package/src/utils/LazyNativeEmitter.ts +8 -9
- package/src/utils/NativeUpdatedValue.ts +2 -0
- package/src/web/NativeAudioBrowser.ts +158 -365
- package/src/web/TrackPlayer/Player.ts +39 -113
- package/src/web/TrackPlayer/PlaylistPlayer.ts +346 -0
- package/src/web/TrackPlayer/RepeatMode.ts +1 -1
- package/src/web/TrackPlayer/SleepTimer.ts +3 -38
- package/src/web/TrackPlayer/index.ts +1 -2
- package/src/web/browser/BrowserManager.ts +62 -231
- package/src/web/browser/NavigationErrorManager.ts +1 -3
- package/src/web/browser/SearchManager.ts +15 -11
- package/src/web/http/HttpClient.ts +35 -5
- package/src/web/http/RequestConfigBuilder.ts +63 -120
- package/src/web/player/NowPlayingManager.ts +5 -6
- package/src/web/player/OptionsManager.ts +18 -12
- package/android/src/main/java/com/audiobrowser/browser/ArtworkResolutionRegistry.kt +0 -37
- package/android/src/main/java/com/audiobrowser/browser/BrowseArtworkRegistry.kt +0 -34
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +0 -299
- package/android/src/main/java/com/audiobrowser/browser/JsonArtwork.kt +0 -79
- package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +0 -42
- package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +0 -35
- package/android/src/main/java/com/audiobrowser/player/CapabilityControls.kt +0 -172
- package/android/src/main/java/com/audiobrowser/player/EqualizerController.kt +0 -153
- package/android/src/main/java/com/audiobrowser/player/InterceptingPlayer.kt +0 -141
- package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +0 -347
- package/android/src/main/java/com/audiobrowser/player/PlaybackErrorClassifier.kt +0 -129
- package/android/src/main/java/com/audiobrowser/player/PlaybackStateMachine.kt +0 -85
- package/android/src/main/java/com/audiobrowser/player/PlaybackTimer.kt +0 -56
- package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +0 -20
- package/android/src/main/java/com/audiobrowser/player/PlayerEngineFactory.kt +0 -130
- package/android/src/main/java/com/audiobrowser/player/SleepTimerManager.kt +0 -80
- package/android/src/main/java/com/audiobrowser/player/StuckRecoveryPolicy.kt +0 -50
- package/android/src/main/java/com/audiobrowser/player/VolumeFader.kt +0 -81
- package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +0 -141
- package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +0 -37
- package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +0 -41
- package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +0 -209
- package/android/src/main/java/com/audiobrowser/util/ArtworkContentProvider.kt +0 -161
- package/android/src/main/java/com/audiobrowser/util/ArtworkUris.kt +0 -28
- package/android/src/main/java/com/audiobrowser/util/ArtworkVariant.kt +0 -24
- package/android/src/main/java/com/audiobrowser/util/CoilArtworkLoader.kt +0 -49
- package/android/src/main/java/com/audiobrowser/util/CoilArtworkLoaderHolder.kt +0 -36
- package/android/src/main/java/com/audiobrowser/util/OutputMonitor.kt +0 -211
- package/android/src/main/java/com/audiobrowser/util/OutputSwitcher.kt +0 -58
- package/android/src/main/java/com/audiobrowser/util/RatingFavorites.kt +0 -14
- package/android/src/test/java/com/audiobrowser/TestFixtures.kt +0 -165
- package/android/src/test/java/com/audiobrowser/browser/ArtworkResolutionRegistryTest.kt +0 -46
- package/android/src/test/java/com/audiobrowser/browser/BrowseArtworkRegistryTest.kt +0 -39
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerBuildApiRequestTest.kt +0 -114
- package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +0 -141
- package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +0 -177
- package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +0 -55
- package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +0 -94
- package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +0 -203
- package/android/src/test/java/com/audiobrowser/player/DynamicLoadControlTest.kt +0 -56
- package/android/src/test/java/com/audiobrowser/player/EqualizerControllerTest.kt +0 -216
- package/android/src/test/java/com/audiobrowser/player/MediaSessionSlotMappingTest.kt +0 -45
- package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +0 -442
- package/android/src/test/java/com/audiobrowser/player/PlaybackErrorClassifierTest.kt +0 -190
- package/android/src/test/java/com/audiobrowser/player/PlaybackStateMachineTest.kt +0 -198
- package/android/src/test/java/com/audiobrowser/player/PlaybackTimerTest.kt +0 -137
- package/android/src/test/java/com/audiobrowser/player/PlayerEngineFactoryTest.kt +0 -36
- package/android/src/test/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicyTest.kt +0 -268
- package/android/src/test/java/com/audiobrowser/player/SessionErrorMaskTest.kt +0 -68
- package/android/src/test/java/com/audiobrowser/player/StuckRecoveryPolicyTest.kt +0 -40
- package/android/src/test/java/com/audiobrowser/player/TransformingDataSourceTest.kt +0 -193
- package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +0 -107
- package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +0 -73
- package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherTest.kt +0 -75
- package/android/src/test/java/com/audiobrowser/tls/CertFixtures.kt +0 -18
- package/android/src/test/java/com/audiobrowser/util/ArtworkContentProviderTest.kt +0 -163
- package/android/src/test/java/com/audiobrowser/util/ArtworkUrisTest.kt +0 -34
- package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +0 -28
- package/android/src/test/java/com/audiobrowser/util/CoilArtworkLoaderHolderTest.kt +0 -53
- package/android/src/test/java/com/audiobrowser/util/CoilArtworkLoaderTest.kt +0 -58
- package/android/src/test/java/com/audiobrowser/util/FakeImageLoader.kt +0 -57
- package/android/src/test/java/com/audiobrowser/util/PlayingStateFactoryTest.kt +0 -40
- package/android/src/test/java/com/audiobrowser/util/RatingFavoritesTest.kt +0 -34
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryBrowseTest.kt +0 -50
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +0 -63
- package/android/src/test/java/com/audiobrowser/util/TrackFactoryRatingTest.kt +0 -35
- package/android/src/test/resources/certs/isrg-root-x1.pem +0 -31
- package/android/src/test/resources/certs/letsencrypt-r13.der +0 -0
- package/android/src/test/resources/certs/letsencrypt-r13.pem +0 -29
- package/android/src/test/resources/certs/stationplaylist-leaf.pem +0 -34
- package/ios/Browser/MediaResolveComposer.swift +0 -114
- package/ios/Browser/SearchDrillIn.swift +0 -44
- package/ios/Browser/SectionScope.swift +0 -35
- package/ios/Browser/TabBarEntries.swift +0 -15
- package/ios/CarPlay/CPInterfaceController+Safe.swift +0 -126
- package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
- package/ios/CarPlay/RNABMediaAddHandler.swift +0 -75
- package/ios/CarPlay/RNABMediaAffinityHandler.swift +0 -69
- package/ios/Extension/PlayerCapabilities+Favorite.swift +0 -20
- package/ios/Extension/RequestConfig+Copying.swift +0 -31
- package/ios/Extension/Variant+Artwork.swift +0 -49
- package/ios/NowPlayingInfo/SilentAudioPrimer.swift +0 -73
- package/ios/Player/AirPlayStallJudgement.swift +0 -25
- package/ios/Player/EndOfTrackJudgement.swift +0 -32
- package/ios/Player/MediaIntentCriteria.swift +0 -139
- package/ios/Player/PersistedPlaybackState.swift +0 -11
- package/ios/Player/PlaybackStateStore.swift +0 -27
- package/ios/Player/PlaybackTimer.swift +0 -61
- package/ios/Player/VolumeFader.swift +0 -77
- package/ios/RemoteCommand/RemoteCommandCallbacks.swift +0 -47
- package/ios/Tests/AirPlayStallJudgementTests.swift +0 -52
- package/ios/Tests/EndOfTrackJudgementTests.swift +0 -35
- package/ios/Tests/JsonModelsTests.swift +0 -58
- package/ios/Tests/MediaIntentCriteriaTests.swift +0 -170
- package/ios/Tests/MediaLoaderAssetOptionsTests.swift +0 -46
- package/ios/Tests/MediaResolveTests.swift +0 -126
- package/ios/Tests/OnceValueTests.swift +0 -79
- package/ios/Tests/PlaybackStateStoreTests.swift +0 -48
- package/ios/Tests/PlaybackTimerTests.swift +0 -55
- package/ios/Tests/PlayingStateManagerTests.swift +0 -57
- package/ios/Tests/RemoteCommandControllerTests.swift +0 -156
- package/ios/Tests/RemoteCommandTests.swift +0 -67
- package/ios/Tests/RetryManagerTests.swift +0 -89
- package/ios/Tests/SearchDrillInTests.swift +0 -63
- package/ios/Tests/SectionScopeTests.swift +0 -82
- package/ios/Tests/SleepTimerManagerTests.swift +0 -107
- package/ios/Tests/Support/ManualSleepTimerScheduler.swift +0 -47
- package/ios/Tests/TabBarEntriesTests.swift +0 -71
- package/lib/commonjs/features/browser-config.js +0 -227
- package/lib/commonjs/features/browser-config.js.map +0 -1
- package/lib/commonjs/features/carConnection.js +0 -42
- package/lib/commonjs/features/carConnection.js.map +0 -1
- package/lib/commonjs/features/gate.js +0 -149
- package/lib/commonjs/features/gate.js.map +0 -1
- package/lib/commonjs/features/playback/trackPlaybackTime.js +0 -86
- package/lib/commonjs/features/playback/trackPlaybackTime.js.map +0 -1
- package/lib/commonjs/features/player/validateOptions.js +0 -24
- package/lib/commonjs/features/player/validateOptions.js.map +0 -1
- package/lib/commonjs/utils/artwork.js +0 -31
- package/lib/commonjs/utils/artwork.js.map +0 -1
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js +0 -71
- package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js.map +0 -1
- package/lib/commonjs/web/TrackPlayer/PlaybackTimer.js +0 -34
- package/lib/commonjs/web/TrackPlayer/PlaybackTimer.js.map +0 -1
- package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js +0 -21
- package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js.map +0 -1
- package/lib/commonjs/web/TrackPlayer/QueueManager.js +0 -273
- package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +0 -1
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js +0 -158
- package/lib/commonjs/web/TrackPlayer/QueuePlayer.js.map +0 -1
- package/lib/commonjs/web/TrackPlayer/VolumeFader.js +0 -75
- package/lib/commonjs/web/TrackPlayer/VolumeFader.js.map +0 -1
- package/lib/commonjs/web/browser/assertBrowsePageShape.js +0 -22
- package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +0 -1
- package/lib/commonjs/web/browser/classifyTrackNavigation.js +0 -41
- package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +0 -1
- package/lib/commonjs/web/browser/parseSearchResponse.js +0 -20
- package/lib/commonjs/web/browser/parseSearchResponse.js.map +0 -1
- package/lib/commonjs/web/playbackErrorKind.js +0 -57
- package/lib/commonjs/web/playbackErrorKind.js.map +0 -1
- package/lib/commonjs/web/player/MediaSessionManager.js +0 -121
- package/lib/commonjs/web/player/MediaSessionManager.js.map +0 -1
- package/lib/commonjs/web/player/RemoteCommandController.js +0 -96
- package/lib/commonjs/web/player/RemoteCommandController.js.map +0 -1
- package/lib/module/features/browser-config.js +0 -221
- package/lib/module/features/browser-config.js.map +0 -1
- package/lib/module/features/carConnection.js +0 -37
- package/lib/module/features/carConnection.js.map +0 -1
- package/lib/module/features/gate.js +0 -144
- package/lib/module/features/gate.js.map +0 -1
- package/lib/module/features/playback/trackPlaybackTime.js +0 -83
- package/lib/module/features/playback/trackPlaybackTime.js.map +0 -1
- package/lib/module/features/player/validateOptions.js +0 -20
- package/lib/module/features/player/validateOptions.js.map +0 -1
- package/lib/module/utils/artwork.js +0 -26
- package/lib/module/utils/artwork.js.map +0 -1
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js +0 -67
- package/lib/module/web/TrackPlayer/PlaybackStateMachine.js.map +0 -1
- package/lib/module/web/TrackPlayer/PlaybackTimer.js +0 -29
- package/lib/module/web/TrackPlayer/PlaybackTimer.js.map +0 -1
- package/lib/module/web/TrackPlayer/PlayingStateFactory.js +0 -17
- package/lib/module/web/TrackPlayer/PlayingStateFactory.js.map +0 -1
- package/lib/module/web/TrackPlayer/QueueManager.js +0 -269
- package/lib/module/web/TrackPlayer/QueueManager.js.map +0 -1
- package/lib/module/web/TrackPlayer/QueuePlayer.js +0 -154
- package/lib/module/web/TrackPlayer/QueuePlayer.js.map +0 -1
- package/lib/module/web/TrackPlayer/VolumeFader.js +0 -70
- package/lib/module/web/TrackPlayer/VolumeFader.js.map +0 -1
- package/lib/module/web/browser/assertBrowsePageShape.js +0 -18
- package/lib/module/web/browser/assertBrowsePageShape.js.map +0 -1
- package/lib/module/web/browser/classifyTrackNavigation.js +0 -38
- package/lib/module/web/browser/classifyTrackNavigation.js.map +0 -1
- package/lib/module/web/browser/parseSearchResponse.js +0 -16
- package/lib/module/web/browser/parseSearchResponse.js.map +0 -1
- package/lib/module/web/playbackErrorKind.js +0 -52
- package/lib/module/web/playbackErrorKind.js.map +0 -1
- package/lib/module/web/player/MediaSessionManager.js +0 -116
- package/lib/module/web/player/MediaSessionManager.js.map +0 -1
- package/lib/module/web/player/RemoteCommandController.js +0 -92
- package/lib/module/web/player/RemoteCommandController.js.map +0 -1
- package/lib/typescript/src/features/browser-config.d.ts +0 -12
- package/lib/typescript/src/features/browser-config.d.ts.map +0 -1
- package/lib/typescript/src/features/carConnection.d.ts +0 -20
- package/lib/typescript/src/features/carConnection.d.ts.map +0 -1
- package/lib/typescript/src/features/gate.d.ts +0 -78
- package/lib/typescript/src/features/gate.d.ts.map +0 -1
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +0 -34
- package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +0 -1
- package/lib/typescript/src/features/player/validateOptions.d.ts +0 -2
- package/lib/typescript/src/features/player/validateOptions.d.ts.map +0 -1
- package/lib/typescript/src/utils/artwork.d.ts +0 -19
- package/lib/typescript/src/utils/artwork.d.ts.map +0 -1
- package/nitrogen/generated/android/c++/JArtworkVariants.hpp +0 -61
- package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
- package/nitrogen/generated/android/c++/JFavoritesMatchMode.hpp +0 -58
- package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +0 -100
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.hpp +0 -112
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +0 -121
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +0 -123
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +0 -133
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +0 -121
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.hpp +0 -139
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.hpp +0 -134
- package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +0 -131
- package/nitrogen/generated/android/c++/JFunc_void_GateEvent.hpp +0 -79
- package/nitrogen/generated/android/c++/JFunc_void_Output.hpp +0 -80
- package/nitrogen/generated/android/c++/JGate.hpp +0 -62
- package/nitrogen/generated/android/c++/JGateDecision.hpp +0 -64
- package/nitrogen/generated/android/c++/JGateReason.hpp +0 -58
- package/nitrogen/generated/android/c++/JIOSOptions.hpp +0 -95
- package/nitrogen/generated/android/c++/JMediaReference.hpp +0 -58
- package/nitrogen/generated/android/c++/JNativeGateRequest.hpp +0 -74
- package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +0 -182
- package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +0 -96
- package/nitrogen/generated/android/c++/JOutputType.hpp +0 -82
- package/nitrogen/generated/android/c++/JPlaybackErrorKind.hpp +0 -76
- package/nitrogen/generated/android/c++/JRemoteButtonLayout.hpp +0 -86
- package/nitrogen/generated/android/c++/JStallReason.hpp +0 -58
- package/nitrogen/generated/android/c++/JTrackRequest.hpp +0 -93
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
- package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
- package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.cpp +0 -26
- package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.hpp +0 -75
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.cpp +0 -41
- package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +0 -121
- package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.cpp +0 -26
- package/nitrogen/generated/android/c++/JVariant_String_ArtworkVariants.hpp +0 -70
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNowPlayingParams.kt +0 -50
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.kt +0 -80
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +0 -80
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_RequestConfig___Track.kt +0 -80
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.kt +0 -80
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_std__string____Track.kt +0 -80
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.kt +0 -80
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.kt +0 -80
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +0 -44
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaReference.kt +0 -23
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeGateRequest.kt +0 -44
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeSetupPlayerOptions.kt +0 -66
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +0 -44
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/OutputType.kt +0 -31
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorKind.kt +0 -29
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButton.kt +0 -26
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButtonLayout.kt +0 -44
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StallReason.kt +0 -23
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackRequest.kt +0 -44
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.kt +0 -65
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_String_ArtworkVariants.kt +0 -53
- package/nitrogen/generated/ios/swift/ArtworkVariants.swift +0 -34
- package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
- package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
- package/nitrogen/generated/ios/swift/FormatNowPlayingParams.swift +0 -67
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___MediaTransformParams.swift +0 -54
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___RequestConfig_std__optional_std__unordered_map_std__string__std__string__.swift +0 -69
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_RequestConfig___Track.swift +0 -54
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.swift +0 -60
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_std__string____Track.swift +0 -60
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_GateDecision_____NativeGateRequest.swift +0 -61
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_TransformableRequestConfig____.swift +0 -61
- package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.swift +0 -77
- package/nitrogen/generated/ios/swift/Func_void_GateDecision.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_TransformableRequestConfig.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_std__optional_NowPlayingUpdate_.swift +0 -46
- package/nitrogen/generated/ios/swift/Func_void_std__optional_std__string_.swift +0 -53
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_TransformableRequestConfig__.swift +0 -66
- package/nitrogen/generated/ios/swift/Func_void_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError____.swift +0 -81
- package/nitrogen/generated/ios/swift/Gate.swift +0 -47
- package/nitrogen/generated/ios/swift/GateDecision.swift +0 -40
- package/nitrogen/generated/ios/swift/GateEvent.swift +0 -29
- package/nitrogen/generated/ios/swift/GateReason.swift +0 -40
- package/nitrogen/generated/ios/swift/IOSOptions.swift +0 -51
- package/nitrogen/generated/ios/swift/MediaReference.swift +0 -40
- package/nitrogen/generated/ios/swift/NativeGateRequest.swift +0 -58
- package/nitrogen/generated/ios/swift/NativeSetupPlayerOptions.swift +0 -206
- package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +0 -90
- package/nitrogen/generated/ios/swift/OutputType.swift +0 -72
- package/nitrogen/generated/ios/swift/PlaybackErrorKind.swift +0 -64
- package/nitrogen/generated/ios/swift/RemoteButtonLayout.swift +0 -57
- package/nitrogen/generated/ios/swift/StallReason.swift +0 -40
- package/nitrogen/generated/ios/swift/TrackRequest.swift +0 -106
- package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
- package/nitrogen/generated/ios/swift/Variant_ResolvedTrack_BrowseError_Promise_BrowseResult_.swift +0 -19
- package/nitrogen/generated/ios/swift/Variant_String_ArtworkVariants.swift +0 -18
- package/nitrogen/generated/shared/c++/ArtworkVariants.hpp +0 -87
- package/nitrogen/generated/shared/c++/FavoritesMatchMode.hpp +0 -76
- package/nitrogen/generated/shared/c++/FormatNowPlayingParams.hpp +0 -110
- package/nitrogen/generated/shared/c++/GateReason.hpp +0 -76
- package/nitrogen/generated/shared/c++/IOSOptions.hpp +0 -91
- package/nitrogen/generated/shared/c++/MediaReference.hpp +0 -76
- package/nitrogen/generated/shared/c++/NativeGateRequest.hpp +0 -97
- package/nitrogen/generated/shared/c++/NativeSetupPlayerOptions.hpp +0 -138
- package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +0 -92
- package/nitrogen/generated/shared/c++/OutputType.hpp +0 -108
- package/nitrogen/generated/shared/c++/PlaybackErrorKind.hpp +0 -100
- package/nitrogen/generated/shared/c++/RemoteButtonLayout.hpp +0 -94
- package/nitrogen/generated/shared/c++/StallReason.hpp +0 -76
- package/nitrogen/generated/shared/c++/TrackRequest.hpp +0 -93
- package/src/codegen-no-config-variant.test.ts +0 -70
- package/src/features/browser-config.test.ts +0 -110
- package/src/features/browser-config.ts +0 -293
- package/src/features/browser.test.ts +0 -19
- package/src/features/carConnection.ts +0 -36
- package/src/features/gate.test.ts +0 -72
- package/src/features/gate.ts +0 -155
- package/src/features/playback/trackPlaybackTime.test.ts +0 -80
- package/src/features/playback/trackPlaybackTime.ts +0 -101
- package/src/features/player/options.test.ts +0 -38
- package/src/features/player/setup.test.ts +0 -125
- package/src/features/player/validateOptions.ts +0 -22
- package/src/features/queue/queue.test.ts +0 -36
- package/src/public-surface.test.ts +0 -116
- package/src/utils/artwork.ts +0 -30
- package/src/web/NativeAudioBrowser.playWhenReady.test.ts +0 -301
- package/src/web/TrackPlayer/PlaybackStateMachine.test.ts +0 -139
- package/src/web/TrackPlayer/PlaybackStateMachine.ts +0 -82
- package/src/web/TrackPlayer/PlaybackTimer.test.ts +0 -67
- package/src/web/TrackPlayer/PlaybackTimer.ts +0 -33
- package/src/web/TrackPlayer/Player.dispatch.test.ts +0 -229
- package/src/web/TrackPlayer/Player.load.test.ts +0 -86
- package/src/web/TrackPlayer/PlayingStateFactory.test.ts +0 -51
- package/src/web/TrackPlayer/PlayingStateFactory.ts +0 -24
- package/src/web/TrackPlayer/QueueManager.test.ts +0 -289
- package/src/web/TrackPlayer/QueueManager.ts +0 -302
- package/src/web/TrackPlayer/QueuePlayer.ts +0 -188
- package/src/web/TrackPlayer/VolumeFader.ts +0 -74
- package/src/web/browser/__tests__/layer-resolver.test.ts +0 -69
- package/src/web/browser/assertBrowsePageShape.test.ts +0 -27
- package/src/web/browser/assertBrowsePageShape.ts +0 -27
- package/src/web/browser/classifyTrackNavigation.test.ts +0 -41
- package/src/web/browser/classifyTrackNavigation.ts +0 -35
- package/src/web/browser/parseSearchResponse.test.ts +0 -25
- package/src/web/browser/parseSearchResponse.ts +0 -15
- package/src/web/http/RequestConfigBuilder.test.ts +0 -59
- package/src/web/playbackErrorKind.test.ts +0 -55
- package/src/web/playbackErrorKind.ts +0 -56
- package/src/web/player/MediaSessionManager.test.ts +0 -220
- package/src/web/player/MediaSessionManager.ts +0 -151
- package/src/web/player/NowPlayingManager.test.ts +0 -46
- package/src/web/player/RemoteCommandController.test.ts +0 -171
- package/src/web/player/RemoteCommandController.ts +0 -166
|
@@ -2,59 +2,61 @@ package com.audiobrowser.player
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.content.Context
|
|
5
|
-
import
|
|
6
|
-
import android.os.Looper
|
|
7
|
-
import androidx.core.net.toUri
|
|
5
|
+
import androidx.media3.common.AudioAttributes
|
|
8
6
|
import androidx.media3.common.C
|
|
7
|
+
import androidx.media3.common.ForwardingPlayer
|
|
9
8
|
import androidx.media3.common.HeartRating
|
|
10
|
-
import androidx.media3.common.
|
|
9
|
+
import androidx.media3.common.MediaItem
|
|
10
|
+
import androidx.media3.common.TrackSelectionParameters
|
|
11
11
|
import androidx.media3.database.StandaloneDatabaseProvider
|
|
12
12
|
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
|
|
13
13
|
import androidx.media3.datasource.cache.SimpleCache
|
|
14
|
+
import androidx.media3.exoplayer.DefaultRenderersFactory
|
|
14
15
|
import androidx.media3.exoplayer.ExoPlayer
|
|
16
|
+
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter
|
|
15
17
|
import androidx.media3.session.MediaLibraryService
|
|
16
18
|
import androidx.media3.session.MediaSession
|
|
17
19
|
import com.audiobrowser.AudioBrowser
|
|
18
20
|
import com.audiobrowser.Callbacks
|
|
19
|
-
import com.audiobrowser.browser.displayArtworkSource
|
|
20
|
-
import com.audiobrowser.browser.resolveArtworkUrl
|
|
21
|
-
import com.audiobrowser.browser.unattributedArtworkSource
|
|
22
21
|
import com.audiobrowser.extension.NumberExt.Companion.toSeconds
|
|
22
|
+
import com.margelo.nitro.audiobrowser.ImageContext
|
|
23
23
|
import com.audiobrowser.model.PlayerSetupOptions
|
|
24
24
|
import com.audiobrowser.model.PlayerUpdateOptions
|
|
25
|
+
import com.audiobrowser.util.AndroidAudioContentTypeFactory
|
|
25
26
|
import com.audiobrowser.util.CoilBitmapLoader
|
|
27
|
+
import com.audiobrowser.util.EqualizerManager
|
|
26
28
|
import com.audiobrowser.util.NetworkConnectivityMonitor
|
|
27
29
|
import com.audiobrowser.util.PlayingStateFactory
|
|
28
30
|
import com.audiobrowser.util.RepeatModeFactory
|
|
29
31
|
import com.audiobrowser.util.TrackFactory
|
|
32
|
+
import com.margelo.nitro.audiobrowser.AndroidPlayerWakeMode
|
|
30
33
|
import com.margelo.nitro.audiobrowser.AppKilledPlaybackBehavior
|
|
31
34
|
import com.margelo.nitro.audiobrowser.FavoriteChangedEvent
|
|
32
|
-
import com.margelo.nitro.audiobrowser.GateEvent
|
|
33
|
-
import com.margelo.nitro.audiobrowser.GateReason
|
|
34
|
-
import com.margelo.nitro.audiobrowser.ImageContext
|
|
35
|
-
import com.margelo.nitro.audiobrowser.ImageSource
|
|
36
|
-
import com.margelo.nitro.audiobrowser.NativeGateRequest
|
|
37
35
|
import com.margelo.nitro.audiobrowser.NowPlayingMetadata
|
|
36
|
+
import com.margelo.nitro.audiobrowser.NowPlayingUpdate
|
|
38
37
|
import com.margelo.nitro.audiobrowser.Playback
|
|
39
38
|
import com.margelo.nitro.audiobrowser.PlaybackActiveTrackChangedEvent
|
|
40
39
|
import com.margelo.nitro.audiobrowser.PlaybackError
|
|
41
|
-
import com.margelo.nitro.audiobrowser.PlaybackPlayWhenReadyChangedEvent
|
|
42
40
|
import com.margelo.nitro.audiobrowser.PlaybackProgressUpdatedEvent
|
|
43
41
|
import com.margelo.nitro.audiobrowser.PlaybackQueueEndedEvent
|
|
44
42
|
import com.margelo.nitro.audiobrowser.PlaybackState
|
|
45
43
|
import com.margelo.nitro.audiobrowser.PlayingState
|
|
44
|
+
import com.margelo.nitro.audiobrowser.RatingType
|
|
45
|
+
import com.margelo.nitro.audiobrowser.RemoteJumpBackwardEvent
|
|
46
|
+
import com.margelo.nitro.audiobrowser.RemoteJumpForwardEvent
|
|
47
|
+
import com.margelo.nitro.audiobrowser.RemoteSeekEvent
|
|
46
48
|
import com.margelo.nitro.audiobrowser.RepeatMode
|
|
47
49
|
import com.margelo.nitro.audiobrowser.SearchParams
|
|
50
|
+
import com.margelo.nitro.audiobrowser.SleepTimer as NitroSleepTimer
|
|
51
|
+
import com.margelo.nitro.audiobrowser.SleepTimerEndOfTrack
|
|
52
|
+
import com.margelo.nitro.audiobrowser.SleepTimerTime
|
|
48
53
|
import com.margelo.nitro.audiobrowser.Track
|
|
54
|
+
import com.margelo.nitro.core.NullType
|
|
49
55
|
import java.io.File
|
|
50
|
-
import java.io.IOException
|
|
51
56
|
import java.util.concurrent.TimeUnit
|
|
52
57
|
import kotlin.time.Duration.Companion.seconds
|
|
53
58
|
import kotlinx.coroutines.CompletableDeferred
|
|
54
|
-
import kotlinx.coroutines.Dispatchers
|
|
55
|
-
import kotlinx.coroutines.MainScope
|
|
56
59
|
import kotlinx.coroutines.TimeoutCancellationException
|
|
57
|
-
import kotlinx.coroutines.withContext
|
|
58
60
|
import kotlinx.coroutines.withTimeout
|
|
59
61
|
import timber.log.Timber
|
|
60
62
|
|
|
@@ -64,50 +66,25 @@ class Player(internal val context: Context) {
|
|
|
64
66
|
get() = options.appKilledPlaybackBehavior
|
|
65
67
|
|
|
66
68
|
private var options = PlayerUpdateOptions()
|
|
67
|
-
private val mainHandler = Handler(Looper.getMainLooper())
|
|
68
69
|
internal var callbacks: Callbacks? = null
|
|
69
70
|
private lateinit var mediaSession: MediaSession
|
|
70
71
|
val networkMonitor: NetworkConnectivityMonitor = NetworkConnectivityMonitor(context)
|
|
71
|
-
|
|
72
|
-
EqualizerController(onSettingsChanged = { settings -> callbacks?.onEqualizerChanged(settings) })
|
|
72
|
+
private var equalizerManager: EqualizerManager? = null
|
|
73
73
|
private val mediaSessionCallback = MediaSessionCallback(this)
|
|
74
74
|
internal val playbackStateStore = PlaybackStateStore(this)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
private val sleepTimer =
|
|
76
|
+
object : SleepTimer() {
|
|
77
|
+
override fun onComplete() {
|
|
78
|
+
Timber.d("Sleep timer completed, stopping playback")
|
|
79
|
+
stop()
|
|
80
|
+
callbacks?.onSleepTimerChanged(NitroSleepTimer.create(NullType.NULL))
|
|
81
|
+
}
|
|
82
|
+
}
|
|
82
83
|
|
|
83
84
|
lateinit var exoPlayer: ExoPlayer
|
|
84
85
|
lateinit var forwardingPlayer: androidx.media3.common.Player
|
|
85
86
|
/** Thread-safe cache of playWhenReady for access from non-main threads (e.g., retry policy) */
|
|
86
87
|
@Volatile internal var playWhenReadyCache = false
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Whether the current load has ever produced audio — selects between the retry policy's
|
|
90
|
-
* first-connect and recovery budgets. Volatile: read from ExoPlayer's loader thread. Set when
|
|
91
|
-
* playback starts, cleared on media-item transition (a new load starts unproven); retry reloads
|
|
92
|
-
* of the same load keep it.
|
|
93
|
-
*/
|
|
94
|
-
@Volatile internal var hasPlayedCache = false
|
|
95
|
-
|
|
96
|
-
/** Last playWhenReady value emitted to JS — see [emitPlayWhenReadyChanged]. */
|
|
97
|
-
private var lastEmittedPlayWhenReady: Boolean? = null
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Emits the playWhenReady change to JS exactly once per value. Two producers exist: the
|
|
101
|
-
* synchronous clear at ENDED in [setPlaybackState] (ordered before the state / queue-ended
|
|
102
|
-
* callbacks, matching iOS) and the async media3 listener (authoritative for changes ExoPlayer
|
|
103
|
-
* makes on its own, e.g. audio focus); the guard deduplicates their overlap.
|
|
104
|
-
*/
|
|
105
|
-
internal fun emitPlayWhenReadyChanged(value: Boolean) {
|
|
106
|
-
if (lastEmittedPlayWhenReady == value) return
|
|
107
|
-
lastEmittedPlayWhenReady = value
|
|
108
|
-
callbacks?.onPlaybackPlayWhenReadyChanged(PlaybackPlayWhenReadyChangedEvent(value))
|
|
109
|
-
}
|
|
110
|
-
|
|
111
88
|
private lateinit var mediaFactory: MediaFactory
|
|
112
89
|
private lateinit var loadControl: DynamicLoadControl
|
|
113
90
|
private var automaticBufferManager: AutomaticBufferManager? = null
|
|
@@ -118,39 +95,49 @@ class Player(internal val context: Context) {
|
|
|
118
95
|
*/
|
|
119
96
|
@Volatile private var pendingNetworkRetry = false
|
|
120
97
|
|
|
98
|
+
private var _browser: AudioBrowser? = null
|
|
121
99
|
private var browserRegistered = CompletableDeferred<AudioBrowser>()
|
|
122
100
|
private var _coilBitmapLoader: CoilBitmapLoader? = null
|
|
123
101
|
|
|
124
102
|
/**
|
|
125
|
-
* Coil ImageLoader for SVG pre-rendering in Android Auto browse items.
|
|
126
|
-
* creation.
|
|
103
|
+
* Coil ImageLoader for SVG pre-rendering in Android Auto browse items.
|
|
104
|
+
* Set by Service after creation.
|
|
127
105
|
*/
|
|
128
106
|
var imageLoader: coil3.ImageLoader? = null
|
|
129
107
|
|
|
130
|
-
/** Registry that maps content:// tokens to artwork URLs for the browse content provider. */
|
|
131
|
-
val browseArtworkRegistry = com.audiobrowser.browser.BrowseArtworkRegistry()
|
|
132
|
-
|
|
133
108
|
/**
|
|
134
|
-
* Set the CoilBitmapLoader for
|
|
109
|
+
* Set the CoilBitmapLoader for artwork URL transformation. Called from Service after creation.
|
|
135
110
|
*/
|
|
136
111
|
var coilBitmapLoader: CoilBitmapLoader?
|
|
137
112
|
get() = _coilBitmapLoader
|
|
138
113
|
set(value) {
|
|
139
114
|
_coilBitmapLoader = value
|
|
115
|
+
// If browser is already set, wire up the resolver
|
|
116
|
+
_browser?.let { audioBrowser -> wireUpArtworkResolver(audioBrowser, value) }
|
|
140
117
|
}
|
|
141
118
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
119
|
+
var browser: AudioBrowser?
|
|
120
|
+
get() = _browser
|
|
121
|
+
set(value) {
|
|
122
|
+
_browser = value
|
|
123
|
+
value?.let { audioBrowser ->
|
|
124
|
+
// Wire up artwork URL resolver
|
|
125
|
+
// This ensures the resolver is available when onGetChildren resumes
|
|
126
|
+
wireUpArtworkResolver(audioBrowser, _coilBitmapLoader)
|
|
127
|
+
|
|
128
|
+
// NOTE: We do NOT complete browserRegistered here.
|
|
129
|
+
// Configuration (routes/tabs) must be set before Android Auto can browse.
|
|
130
|
+
// Call notifyBrowserConfigurationReady() after configuration is set.
|
|
131
|
+
}
|
|
132
|
+
}
|
|
146
133
|
|
|
147
134
|
/**
|
|
148
|
-
* Notifies that the browser configuration is ready (routes/tabs are configured).
|
|
149
|
-
* called after setting the browser AND its configuration.
|
|
150
|
-
* browse content.
|
|
135
|
+
* Notifies that the browser configuration is ready (routes/tabs are configured).
|
|
136
|
+
* This should be called after setting the browser AND its configuration.
|
|
137
|
+
* Only then will Android Auto be able to browse content.
|
|
151
138
|
*/
|
|
152
139
|
fun notifyBrowserConfigurationReady() {
|
|
153
|
-
val audioBrowser =
|
|
140
|
+
val audioBrowser = _browser ?: return
|
|
154
141
|
|
|
155
142
|
if (!browserRegistered.isCompleted) {
|
|
156
143
|
Timber.d("Browser configuration ready - completing deferred")
|
|
@@ -168,15 +155,34 @@ class Player(internal val context: Context) {
|
|
|
168
155
|
mediaSessionCallback.updateMediaSession(
|
|
169
156
|
mediaSession,
|
|
170
157
|
options.capabilities,
|
|
171
|
-
options.
|
|
158
|
+
options.notificationButtons,
|
|
172
159
|
searchAvailable,
|
|
173
|
-
options.forwardJumpInterval,
|
|
174
|
-
options.backwardJumpInterval,
|
|
175
160
|
)
|
|
176
161
|
}
|
|
177
162
|
}
|
|
178
163
|
}
|
|
179
164
|
|
|
165
|
+
/**
|
|
166
|
+
* Wires up the artwork URL resolver between BrowserManager and CoilBitmapLoader. This enables
|
|
167
|
+
* artwork URL transformation during browse-time (Phase 2).
|
|
168
|
+
*/
|
|
169
|
+
private fun wireUpArtworkResolver(audioBrowser: AudioBrowser, loader: CoilBitmapLoader?) {
|
|
170
|
+
val browserManager = audioBrowser.browserManager
|
|
171
|
+
if (loader != null) {
|
|
172
|
+
Timber.d("Wiring up artwork URL resolver")
|
|
173
|
+
browserManager.artworkUrlResolver = { track, perRouteConfig, imageContext ->
|
|
174
|
+
loader.transformArtworkUrlForTrack(track, perRouteConfig, imageContext)
|
|
175
|
+
}
|
|
176
|
+
// Clear content cache so that content resolved before the resolver was wired up
|
|
177
|
+
// will be re-fetched with artwork transformation applied
|
|
178
|
+
browserManager.clearContentCache()
|
|
179
|
+
Timber.d("Cleared content cache after wiring artwork resolver")
|
|
180
|
+
} else {
|
|
181
|
+
Timber.d("CoilBitmapLoader not available - artwork URL transformation disabled")
|
|
182
|
+
browserManager.artworkUrlResolver = null
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
180
186
|
/**
|
|
181
187
|
* Suspends until the browser is registered, with a timeout.
|
|
182
188
|
*
|
|
@@ -194,16 +200,133 @@ class Player(internal val context: Context) {
|
|
|
194
200
|
throw e
|
|
195
201
|
}
|
|
196
202
|
|
|
203
|
+
/**
|
|
204
|
+
* ForwardingPlayer that intercepts external player actions and dispatches them to callbacks.
|
|
205
|
+
*
|
|
206
|
+
* This class blocks all external media item modifications to delegate control to RNAB. These
|
|
207
|
+
* overrides prevent media controllers (like Android Auto, notifications) from directly modifying
|
|
208
|
+
* the queue, ensuring all queue changes go through the RNAB API for proper state management and
|
|
209
|
+
* event handling.
|
|
210
|
+
*/
|
|
211
|
+
private inner class InterceptingPlayer(player: ExoPlayer) : ForwardingPlayer(player) {
|
|
212
|
+
|
|
213
|
+
override fun setMediaItems(mediaItems: MutableList<MediaItem>, resetPosition: Boolean) {
|
|
214
|
+
return super.setMediaItems(mediaItems, resetPosition)
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
override fun addMediaItems(mediaItems: MutableList<MediaItem>) {
|
|
218
|
+
return super.addMediaItems(mediaItems)
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
override fun addMediaItems(index: Int, mediaItems: MutableList<MediaItem>) {
|
|
222
|
+
return super.addMediaItems(index, mediaItems)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
override fun setMediaItems(
|
|
226
|
+
mediaItems: MutableList<MediaItem>,
|
|
227
|
+
startIndex: Int,
|
|
228
|
+
startPositionMs: Long,
|
|
229
|
+
) {
|
|
230
|
+
return super.setMediaItems(mediaItems, startIndex, startPositionMs)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
override fun setMediaItems(mediaItems: MutableList<MediaItem>) {
|
|
234
|
+
return super.setMediaItems(mediaItems)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Intercept playback controls and dispatch to callbacks or fall back to default behavior
|
|
238
|
+
override fun play() {
|
|
239
|
+
if (callbacks?.handleRemotePlay() != true) {
|
|
240
|
+
super.play()
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
override fun pause() {
|
|
245
|
+
if (callbacks?.handleRemotePause() != true) {
|
|
246
|
+
super.pause()
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
override fun seekToNext() {
|
|
251
|
+
Timber.Forest.d("InterceptingPlayer.seekToNext() called")
|
|
252
|
+
if (callbacks?.handleRemoteNext() != true) {
|
|
253
|
+
super.seekToNext()
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
override fun seekToNextMediaItem() {
|
|
258
|
+
Timber.Forest.d("InterceptingPlayer.seekToNextMediaItem() called")
|
|
259
|
+
if (callbacks?.handleRemoteNext() != true) {
|
|
260
|
+
super.seekToNextMediaItem()
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
override fun seekToPrevious() {
|
|
265
|
+
Timber.Forest.d("InterceptingPlayer.seekToPrevious() called")
|
|
266
|
+
if (callbacks?.handleRemotePrevious() != true) {
|
|
267
|
+
super.seekToPrevious()
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
override fun seekToPreviousMediaItem() {
|
|
272
|
+
Timber.Forest.d("InterceptingPlayer.seekToPreviousMediaItem() called")
|
|
273
|
+
if (callbacks?.handleRemotePrevious() != true) {
|
|
274
|
+
super.seekToPreviousMediaItem()
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
override fun seekForward() {
|
|
279
|
+
Timber.Forest.d("InterceptingPlayer.seekForward() called")
|
|
280
|
+
if (
|
|
281
|
+
callbacks?.handleRemoteJumpForward(
|
|
282
|
+
RemoteJumpForwardEvent(interval = options.forwardJumpInterval)
|
|
283
|
+
) != true
|
|
284
|
+
) {
|
|
285
|
+
super.seekForward()
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
override fun seekBack() {
|
|
290
|
+
if (
|
|
291
|
+
callbacks?.handleRemoteJumpBackward(
|
|
292
|
+
RemoteJumpBackwardEvent(interval = options.backwardJumpInterval)
|
|
293
|
+
) != true
|
|
294
|
+
) {
|
|
295
|
+
super.seekBack()
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
override fun stop() {
|
|
300
|
+
if (callbacks?.handleRemoteStop() != true) {
|
|
301
|
+
super.stop()
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
override fun seekTo(mediaItemIndex: Int, positionMs: Long) {
|
|
306
|
+
if (
|
|
307
|
+
callbacks?.handleRemoteSeek(RemoteSeekEvent(position = positionMs.toDouble() / 1000.0)) !=
|
|
308
|
+
true
|
|
309
|
+
) {
|
|
310
|
+
super.seekTo(mediaItemIndex, positionMs)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
override fun seekTo(positionMs: Long) {
|
|
315
|
+
if (
|
|
316
|
+
callbacks?.handleRemoteSeek(RemoteSeekEvent(position = positionMs.toDouble() / 1000.0)) !=
|
|
317
|
+
true
|
|
318
|
+
) {
|
|
319
|
+
super.seekTo(positionMs)
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
197
324
|
private lateinit var playerListener: PlayerListener
|
|
198
325
|
private var cache: SimpleCache? = null
|
|
199
326
|
|
|
200
|
-
private val
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
it == PlaybackState.LOADING || it == PlaybackState.BUFFERING || it == PlaybackState.PLAYING
|
|
204
|
-
}
|
|
205
|
-
) {
|
|
206
|
-
val index = currentIndex ?: return@PlaybackTimer
|
|
327
|
+
private val progressUpdateManager: PlaybackProgressUpdateManager by lazy {
|
|
328
|
+
PlaybackProgressUpdateManager {
|
|
329
|
+
val index = currentIndex ?: return@PlaybackProgressUpdateManager
|
|
207
330
|
val event =
|
|
208
331
|
PlaybackProgressUpdatedEvent(
|
|
209
332
|
position = position.toSeconds(),
|
|
@@ -215,12 +338,7 @@ class Player(internal val context: Context) {
|
|
|
215
338
|
}
|
|
216
339
|
}
|
|
217
340
|
|
|
218
|
-
private val intervalTimer: PlaybackTimer by lazy {
|
|
219
|
-
PlaybackTimer(isActive = { it == PlaybackState.PLAYING }) { callbacks?.onPlaybackInterval() }
|
|
220
|
-
}
|
|
221
|
-
|
|
222
341
|
internal var playingState: PlayingState = PlayingState(false, false)
|
|
223
|
-
private set
|
|
224
342
|
|
|
225
343
|
val currentTrack: Track?
|
|
226
344
|
get() = exoPlayer.currentMediaItem?.let { TrackFactory.fromMedia3(it) }
|
|
@@ -234,6 +352,9 @@ class Player(internal val context: Context) {
|
|
|
234
352
|
internal var playbackState: PlaybackState = PlaybackState.NONE
|
|
235
353
|
private set
|
|
236
354
|
|
|
355
|
+
/** Current now playing metadata override (null = use track metadata) */
|
|
356
|
+
private var nowPlayingOverride: NowPlayingUpdate? = null
|
|
357
|
+
|
|
237
358
|
fun getPlayback(): Playback {
|
|
238
359
|
return Playback(playbackState, playbackError)
|
|
239
360
|
}
|
|
@@ -242,33 +363,9 @@ class Player(internal val context: Context) {
|
|
|
242
363
|
return playingState
|
|
243
364
|
}
|
|
244
365
|
|
|
245
|
-
/**
|
|
246
|
-
* Re-derives [playingState] from the current `playWhenReady` + [playbackState] and emits
|
|
247
|
-
* `onPlaybackPlayingState` when it changed. The only writer of [playingState] — called from the
|
|
248
|
-
* state machine ([setPlaybackState]) and from [PlayerListener.onPlayWhenReadyChanged], the change
|
|
249
|
-
* points of its two inputs.
|
|
250
|
-
*/
|
|
251
|
-
internal fun refreshPlayingState() {
|
|
252
|
-
val newPlayingState = PlayingStateFactory.derive(playWhenReady, playbackState)
|
|
253
|
-
if (newPlayingState == playingState) return
|
|
254
|
-
Timber.d(
|
|
255
|
-
"PlayingState changed: playing=${newPlayingState.playing}, buffering=${newPlayingState.buffering}"
|
|
256
|
-
)
|
|
257
|
-
playingState = newPlayingState
|
|
258
|
-
callbacks?.onPlaybackPlayingState(playingState)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
366
|
var playWhenReady: Boolean
|
|
262
367
|
get() = exoPlayer.playWhenReady
|
|
263
368
|
set(value) {
|
|
264
|
-
// Raising the intent at STATE_ENDED must replay, not silently no-op:
|
|
265
|
-
// ExoPlayer's setPlayWhenReady(true) never restarts an ended player (the
|
|
266
|
-
// ENDED→seekToDefaultPosition replay lives in media3's media-button
|
|
267
|
-
// path, not the Player API). In the setter so every writer gets it —
|
|
268
|
-
// play(), togglePlayback() and JS setPlayWhenReady alike.
|
|
269
|
-
if (value && exoPlayer.playbackState == ExoPlayer.STATE_ENDED) {
|
|
270
|
-
exoPlayer.seekToDefaultPosition()
|
|
271
|
-
}
|
|
272
369
|
playWhenReadyCache = value
|
|
273
370
|
exoPlayer.playWhenReady = value
|
|
274
371
|
}
|
|
@@ -301,6 +398,8 @@ class Player(internal val context: Context) {
|
|
|
301
398
|
val isPlaying
|
|
302
399
|
get() = exoPlayer.isPlaying
|
|
303
400
|
|
|
401
|
+
var ratingType: RatingType = RatingType.NONE
|
|
402
|
+
|
|
304
403
|
var repeatMode: RepeatMode
|
|
305
404
|
get() = RepeatModeFactory.fromMedia3(exoPlayer.repeatMode)
|
|
306
405
|
internal set(value) {
|
|
@@ -330,14 +429,8 @@ class Player(internal val context: Context) {
|
|
|
330
429
|
.map { index -> TrackFactory.fromMedia3(exoPlayer.getMediaItemAt(index)) }
|
|
331
430
|
.toTypedArray()
|
|
332
431
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
* media3's own order computation (the linear `currentMediaItemIndex == count - 1` check missed a
|
|
336
|
-
* shuffled queue whose playback order ends on a different linear index). Matches iOS's
|
|
337
|
-
* `isLastInPlaybackOrder`.
|
|
338
|
-
*/
|
|
339
|
-
val isLastInPlaybackOrder: Boolean
|
|
340
|
-
get() = exoPlayer.nextMediaItemIndex == C.INDEX_UNSET
|
|
432
|
+
val isLastTrack: Boolean
|
|
433
|
+
get() = exoPlayer.currentMediaItemIndex == exoPlayer.mediaItemCount - 1
|
|
341
434
|
|
|
342
435
|
/**
|
|
343
436
|
* The source path from which the current queue was expanded (e.g., from a contextual URL). Used
|
|
@@ -374,12 +467,6 @@ class Player(internal val context: Context) {
|
|
|
374
467
|
fun setup(setupOptions: PlayerSetupOptions) {
|
|
375
468
|
Timber.Forest.d("Setting up player with new options")
|
|
376
469
|
|
|
377
|
-
nowPlaying.enabled = setupOptions.autoUpdateNowPlayingMetadata
|
|
378
|
-
// Wrap the Nitro Func into a plain suspend call so the updater (and its tests) never touch
|
|
379
|
-
// bridge types; the double-await depth is unchanged (invoke -> bridge Promise -> JS promise).
|
|
380
|
-
nowPlaying.formatter =
|
|
381
|
-
setupOptions.nowPlayingMetadataFormatter?.let { f -> { params -> f.invoke(params).await() } }
|
|
382
|
-
|
|
383
470
|
val isInitialSetup = !::exoPlayer.isInitialized
|
|
384
471
|
|
|
385
472
|
if (!isInitialSetup) {
|
|
@@ -389,9 +476,6 @@ class Player(internal val context: Context) {
|
|
|
389
476
|
}
|
|
390
477
|
|
|
391
478
|
if (setupOptions.maxCacheSize > 0) {
|
|
392
|
-
// SimpleCache locks its folder — re-setup must release the previous
|
|
393
|
-
// instance first or the constructor throws.
|
|
394
|
-
cache?.release()
|
|
395
479
|
cache =
|
|
396
480
|
SimpleCache(
|
|
397
481
|
File(context.cacheDir, "RNAB"),
|
|
@@ -405,46 +489,94 @@ class Player(internal val context: Context) {
|
|
|
405
489
|
cache = null
|
|
406
490
|
}
|
|
407
491
|
|
|
408
|
-
//
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
492
|
+
// Recreate ExoPlayer with new setup options
|
|
493
|
+
val renderer = DefaultRenderersFactory(context)
|
|
494
|
+
renderer.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER)
|
|
495
|
+
|
|
496
|
+
// Create bandwidth meter for adaptive bitrate selection in HLS/DASH
|
|
497
|
+
val bandwidthMeter = DefaultBandwidthMeter.Builder(context).build()
|
|
498
|
+
|
|
499
|
+
loadControl = run {
|
|
500
|
+
val minBuffer = setupOptions.minBuffer.toInt()
|
|
501
|
+
val maxBuffer = setupOptions.maxBuffer.toInt()
|
|
502
|
+
val playBuffer = setupOptions.playBuffer.toInt()
|
|
503
|
+
// When automatic (rebufferBuffer is null), start at playBuffer and let AutomaticBufferManager
|
|
504
|
+
// adjust
|
|
505
|
+
// When fixed (rebufferBuffer is set), use that value
|
|
506
|
+
val playAfterRebuffer = setupOptions.rebufferBuffer?.toInt() ?: playBuffer
|
|
507
|
+
val backBuffer = setupOptions.backBuffer.toInt()
|
|
508
|
+
val config =
|
|
509
|
+
BufferConfig(
|
|
510
|
+
minBufferMs = minBuffer,
|
|
511
|
+
maxBufferMs = maxBuffer,
|
|
512
|
+
bufferForPlaybackMs = playBuffer,
|
|
513
|
+
bufferForPlaybackAfterRebufferMs = playAfterRebuffer,
|
|
514
|
+
backBufferMs = backBuffer,
|
|
515
|
+
)
|
|
516
|
+
DynamicLoadControl(initialConfig = config)
|
|
517
|
+
}
|
|
518
|
+
// Create MediaFactory with reference to browser for media URL transformation
|
|
519
|
+
// shouldRetry checks playWhenReady to avoid retrying when paused (e.g., another app took audio
|
|
520
|
+
// focus). Uses thread-safe cache since this is called from ExoPlayer's playback thread.
|
|
521
|
+
// isOnline and onRetryPending enable network-aware retry acceleration.
|
|
522
|
+
mediaFactory =
|
|
523
|
+
MediaFactory(
|
|
412
524
|
context,
|
|
413
|
-
setupOptions,
|
|
414
525
|
cache,
|
|
526
|
+
setupOptions.retryPolicy,
|
|
415
527
|
shouldRetry = { playWhenReadyCache },
|
|
416
528
|
isOnline = { networkMonitor.getOnline() },
|
|
417
|
-
|
|
418
|
-
onRetryPending = { exception, isNetworkError ->
|
|
529
|
+
onRetryPending = { isNetworkError ->
|
|
419
530
|
// Track pending network retries for acceleration when connectivity returns
|
|
420
531
|
pendingNetworkRetry = isNetworkError
|
|
421
532
|
if (isNetworkError) {
|
|
422
533
|
Timber.d("Network retry pending, will accelerate on connectivity restoration")
|
|
423
534
|
}
|
|
424
|
-
reportRetryingError(exception)
|
|
425
535
|
},
|
|
426
|
-
|
|
427
|
-
)
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
exoPlayer = engine.exoPlayer
|
|
536
|
+
transferListener = bandwidthMeter,
|
|
537
|
+
) { url ->
|
|
538
|
+
browser?.getMediaRequestConfig(url)
|
|
539
|
+
}
|
|
431
540
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
541
|
+
exoPlayer =
|
|
542
|
+
ExoPlayer.Builder(context)
|
|
543
|
+
.setRenderersFactory(renderer)
|
|
544
|
+
.setBandwidthMeter(bandwidthMeter)
|
|
545
|
+
.setHandleAudioBecomingNoisy(setupOptions.handleAudioBecomingNoisy)
|
|
546
|
+
.setMediaSourceFactory(mediaFactory)
|
|
547
|
+
.setWakeMode(
|
|
548
|
+
when (setupOptions.wakeMode) {
|
|
549
|
+
AndroidPlayerWakeMode.NONE -> C.WAKE_MODE_NONE
|
|
550
|
+
AndroidPlayerWakeMode.LOCAL -> C.WAKE_MODE_LOCAL
|
|
551
|
+
AndroidPlayerWakeMode.NETWORK -> C.WAKE_MODE_NETWORK
|
|
552
|
+
}
|
|
553
|
+
)
|
|
554
|
+
.setLoadControl(loadControl)
|
|
555
|
+
.setName("AudioBrowser")
|
|
556
|
+
.build()
|
|
557
|
+
exoPlayer.setAudioAttributes(
|
|
558
|
+
AudioAttributes.Builder()
|
|
559
|
+
.setUsage(C.USAGE_MEDIA)
|
|
560
|
+
.setContentType(AndroidAudioContentTypeFactory.toMedia3(setupOptions.audioContentType))
|
|
561
|
+
.build(),
|
|
562
|
+
true, // handle audio focus
|
|
563
|
+
)
|
|
564
|
+
|
|
565
|
+
// Apply setup-specific options
|
|
566
|
+
setupOptions.audioOffload?.let {
|
|
567
|
+
val audioOffloadPreferences =
|
|
568
|
+
TrackSelectionParameters.AudioOffloadPreferences.Builder()
|
|
569
|
+
.setAudioOffloadMode(
|
|
570
|
+
TrackSelectionParameters.AudioOffloadPreferences.AUDIO_OFFLOAD_MODE_ENABLED
|
|
571
|
+
)
|
|
572
|
+
.setIsGaplessSupportRequired(it.gaplessSupportRequired)
|
|
573
|
+
.setIsSpeedChangeSupportRequired(it.rateChangeSupportRequired)
|
|
574
|
+
.build()
|
|
575
|
+
exoPlayer.trackSelectionParameters.audioOffloadPreferences = audioOffloadPreferences
|
|
438
576
|
}
|
|
439
577
|
|
|
440
578
|
// Recreate forwarding player with new ExoPlayer
|
|
441
|
-
forwardingPlayer =
|
|
442
|
-
InterceptingPlayer(
|
|
443
|
-
exoPlayer,
|
|
444
|
-
{ callbacks },
|
|
445
|
-
{ options },
|
|
446
|
-
keepSessionAliveOnError = setupOptions.keepSessionAliveOnError,
|
|
447
|
-
)
|
|
579
|
+
forwardingPlayer = InterceptingPlayer(exoPlayer)
|
|
448
580
|
|
|
449
581
|
if (isInitialSetup) {
|
|
450
582
|
// Initial setup - create player listener and emit initial state
|
|
@@ -453,7 +585,7 @@ class Player(internal val context: Context) {
|
|
|
453
585
|
callbacks?.onPlaybackChanged(Playback(PlaybackState.NONE, null))
|
|
454
586
|
|
|
455
587
|
// Initialize equalizer with audio session ID
|
|
456
|
-
|
|
588
|
+
initializeEqualizer()
|
|
457
589
|
} else {
|
|
458
590
|
// Re-setup - re-add listener and update MediaSession
|
|
459
591
|
forwardingPlayer.addListener(playerListener)
|
|
@@ -488,8 +620,8 @@ class Player(internal val context: Context) {
|
|
|
488
620
|
}
|
|
489
621
|
|
|
490
622
|
/**
|
|
491
|
-
* Starts observing network connectivity changes and invokes the callback when state changes.
|
|
492
|
-
* handles accelerating pending network retries when connectivity is restored.
|
|
623
|
+
* Starts observing network connectivity changes and invokes the callback when state changes.
|
|
624
|
+
* Also handles accelerating pending network retries when connectivity is restored.
|
|
493
625
|
*
|
|
494
626
|
* @param scope The coroutine scope to use for observation
|
|
495
627
|
*/
|
|
@@ -497,10 +629,6 @@ class Player(internal val context: Context) {
|
|
|
497
629
|
networkMonitor.observeOnline(scope) { isOnline ->
|
|
498
630
|
callbacks?.onOnlineChanged(isOnline)
|
|
499
631
|
|
|
500
|
-
// Re-render now-playing so the formatter's stall classification (buffering vs offline) tracks
|
|
501
|
-
// connectivity immediately, not only on the next playback transition.
|
|
502
|
-
nowPlaying.render()
|
|
503
|
-
|
|
504
632
|
// Accelerate pending network retry when connectivity is restored
|
|
505
633
|
if (isOnline && pendingNetworkRetry) {
|
|
506
634
|
Timber.d("Network restored with pending retry, triggering immediate retry")
|
|
@@ -676,18 +804,36 @@ class Player(internal val context: Context) {
|
|
|
676
804
|
* controllers without interrupting playback.
|
|
677
805
|
*/
|
|
678
806
|
fun setActiveTrackFavorited(favorited: Boolean) {
|
|
807
|
+
val index = exoPlayer.currentMediaItemIndex
|
|
808
|
+
if (index == C.INDEX_UNSET) return
|
|
809
|
+
|
|
679
810
|
val currentTrack = this.currentTrack ?: return
|
|
680
811
|
|
|
681
|
-
//
|
|
682
|
-
// user's gesture is durable even when there's no active media item to
|
|
683
|
-
// update (queue tear-down, between-track gaps, etc.).
|
|
812
|
+
// Update native favorites cache (only tracks with src can be favorited)
|
|
684
813
|
currentTrack.src?.let { src -> browser?.browserManager?.updateFavorite(src, favorited) }
|
|
685
814
|
|
|
686
|
-
val index = exoPlayer.currentMediaItemIndex
|
|
687
|
-
if (index == C.INDEX_UNSET) return
|
|
688
|
-
|
|
689
815
|
// Create updated Track with new favorited state
|
|
690
|
-
val updatedTrack =
|
|
816
|
+
val updatedTrack =
|
|
817
|
+
Track(
|
|
818
|
+
url = currentTrack.url,
|
|
819
|
+
src = currentTrack.src,
|
|
820
|
+
artwork = currentTrack.artwork,
|
|
821
|
+
artworkSource = currentTrack.artworkSource,
|
|
822
|
+
artworkCarPlayTinted = currentTrack.artworkCarPlayTinted,
|
|
823
|
+
title = currentTrack.title,
|
|
824
|
+
subtitle = currentTrack.subtitle,
|
|
825
|
+
artist = currentTrack.artist,
|
|
826
|
+
album = currentTrack.album,
|
|
827
|
+
description = currentTrack.description,
|
|
828
|
+
genre = currentTrack.genre,
|
|
829
|
+
duration = currentTrack.duration,
|
|
830
|
+
style = currentTrack.style,
|
|
831
|
+
childrenStyle = currentTrack.childrenStyle,
|
|
832
|
+
favorited = favorited,
|
|
833
|
+
groupTitle = currentTrack.groupTitle,
|
|
834
|
+
live = currentTrack.live,
|
|
835
|
+
imageRow = currentTrack.imageRow,
|
|
836
|
+
)
|
|
691
837
|
|
|
692
838
|
// Use buildUpon() on the existing MediaItem to update only the metadata
|
|
693
839
|
// This preserves internal references and avoids playback interruption
|
|
@@ -735,152 +881,78 @@ class Player(internal val context: Context) {
|
|
|
735
881
|
// MARK: - Now Playing Metadata
|
|
736
882
|
|
|
737
883
|
/**
|
|
738
|
-
*
|
|
739
|
-
*
|
|
740
|
-
* reads plus MediaItem stamping via [replaceMediaItem], and artwork resolution via the browser.
|
|
884
|
+
* Updates the now playing notification metadata. Pass null to clear overrides and revert to track
|
|
885
|
+
* metadata.
|
|
741
886
|
*/
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
get() = this@Player.currentIndex
|
|
747
|
-
|
|
748
|
-
override val currentTrack
|
|
749
|
-
get() = this@Player.currentTrack
|
|
750
|
-
|
|
751
|
-
override val playbackState
|
|
752
|
-
get() = this@Player.playbackState
|
|
753
|
-
|
|
754
|
-
override val playbackError
|
|
755
|
-
get() = this@Player.playbackError
|
|
756
|
-
|
|
757
|
-
override val playWhenReady
|
|
758
|
-
get() = exoPlayer.playWhenReady
|
|
759
|
-
|
|
760
|
-
override val isRebuffering
|
|
761
|
-
get() = loadControl.isRebuffering
|
|
762
|
-
|
|
763
|
-
override val isOnline
|
|
764
|
-
get() = networkMonitor.getOnline()
|
|
765
|
-
|
|
766
|
-
override val hasNowPlayingArtworkConfig
|
|
767
|
-
get() = browser?.browserManager?.config?.nowPlayingArtwork != null
|
|
768
|
-
|
|
769
|
-
override fun stampFields(
|
|
770
|
-
index: Int,
|
|
771
|
-
track: Track,
|
|
772
|
-
title: String?,
|
|
773
|
-
secondaryLine: String?,
|
|
774
|
-
album: String?,
|
|
775
|
-
) =
|
|
776
|
-
restampMediaItem(index, track) {
|
|
777
|
-
setTitle(title)
|
|
778
|
-
.setDisplayTitle(title)
|
|
779
|
-
.setArtist(secondaryLine)
|
|
780
|
-
// Android Auto reads DISPLAY_SUBTITLE (not ARTIST) once DISPLAY_TITLE is set, so
|
|
781
|
-
// mirror the line into `subtitle`; `artist` still drives the lock screen /
|
|
782
|
-
// notification.
|
|
783
|
-
.setSubtitle(secondaryLine)
|
|
784
|
-
.setAlbumTitle(album)
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
override fun stampArtwork(index: Int, track: Track, uri: String) =
|
|
788
|
-
restampMediaItem(index, track) { setArtworkUri(uri.toUri()) }
|
|
789
|
-
|
|
790
|
-
override suspend fun resolveNowPlayingArtwork(track: Track, sizePx: Double): String? {
|
|
791
|
-
val browserManager = browser?.browserManager ?: return null
|
|
792
|
-
val config = browserManager.config.nowPlayingArtwork ?: return null
|
|
793
|
-
val resolved =
|
|
794
|
-
try {
|
|
795
|
-
browserManager.resolveArtworkUrl(track, config, ImageContext(sizePx, sizePx))
|
|
796
|
-
} catch (e: Exception) {
|
|
797
|
-
Timber.e(e, "Failed to resolve now-playing artwork for track id=${track.id}")
|
|
798
|
-
null
|
|
799
|
-
}
|
|
800
|
-
val uri = resolved?.uri?.takeIf { it.isNotEmpty() } ?: return null
|
|
801
|
-
// Remember how this URI was produced: Media3 hands it back to the bitmap loader, which
|
|
802
|
-
// re-resolves Track-first (with the nowPlayingArtwork kind, not the global artwork
|
|
803
|
-
// config).
|
|
804
|
-
browserManager.artworkResolutions.register(uri, track, config)
|
|
805
|
-
return uri
|
|
806
|
-
}
|
|
887
|
+
fun updateNowPlaying(update: NowPlayingUpdate?) {
|
|
888
|
+
nowPlayingOverride = update
|
|
889
|
+
applyNowPlayingMetadata()
|
|
890
|
+
}
|
|
807
891
|
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
892
|
+
/** Gets the current now playing metadata (override if set, else track metadata). */
|
|
893
|
+
fun getNowPlaying(): NowPlayingMetadata? {
|
|
894
|
+
val track = currentTrack ?: return null
|
|
895
|
+
val override = nowPlayingOverride
|
|
896
|
+
|
|
897
|
+
return NowPlayingMetadata(
|
|
898
|
+
elapsedTime = null,
|
|
899
|
+
title = override?.title ?: track.title,
|
|
900
|
+
album = track.album,
|
|
901
|
+
artist = override?.artist ?: track.artist,
|
|
902
|
+
duration = track.duration,
|
|
903
|
+
artwork = track.artwork,
|
|
904
|
+
description = track.description,
|
|
905
|
+
mediaId = track.src ?: track.url,
|
|
906
|
+
genre = track.genre,
|
|
907
|
+
rating = null, // TODO: map track.favorited to rating if needed
|
|
813
908
|
)
|
|
814
|
-
|
|
815
|
-
/** Republishes the item at [index] with mutated metadata, preserving uri and Track tag. */
|
|
816
|
-
private fun restampMediaItem(
|
|
817
|
-
index: Int,
|
|
818
|
-
track: Track,
|
|
819
|
-
mutate: MediaMetadata.Builder.() -> MediaMetadata.Builder,
|
|
820
|
-
) {
|
|
821
|
-
val currentMediaItem = exoPlayer.getMediaItemAt(index)
|
|
822
|
-
val updatedMediaItem =
|
|
823
|
-
currentMediaItem
|
|
824
|
-
.buildUpon()
|
|
825
|
-
.setUri(currentMediaItem.localConfiguration?.uri)
|
|
826
|
-
.setMediaMetadata(currentMediaItem.mediaMetadata.buildUpon().mutate().build())
|
|
827
|
-
.setTag(track)
|
|
828
|
-
.build()
|
|
829
|
-
exoPlayer.replaceMediaItem(index, updatedMediaItem)
|
|
830
909
|
}
|
|
831
910
|
|
|
832
911
|
/**
|
|
833
|
-
*
|
|
834
|
-
|
|
835
|
-
/**
|
|
836
|
-
* A restart from a terminal error begins a new load of the same track: fresh retry budgets and
|
|
837
|
-
* unproven playback, so the user's tap yields a visible first-connect retry window instead of a
|
|
838
|
-
* single silent attempt — the same behavior as re-selecting the track (ADR 0004). Hooked off the
|
|
839
|
-
* player error clearing: every recovery path (retry(), play(), the transport controls' idle-error
|
|
840
|
-
* recovery) goes through exoPlayer.prepare(), which clears the error.
|
|
912
|
+
* Clears the now playing override when track changes. Called from
|
|
913
|
+
* PlayerListener.onMediaItemTransition.
|
|
841
914
|
*/
|
|
842
|
-
internal fun
|
|
843
|
-
|
|
844
|
-
hasPlayedCache = false
|
|
915
|
+
internal fun clearNowPlayingOverride() {
|
|
916
|
+
nowPlayingOverride = null
|
|
845
917
|
}
|
|
846
918
|
|
|
919
|
+
/**
|
|
920
|
+
* Resets the retry timer when track changes. Called from PlayerListener.onMediaItemTransition.
|
|
921
|
+
*/
|
|
847
922
|
internal fun resetRetryTimer() {
|
|
848
923
|
mediaFactory.resetRetryTimer()
|
|
849
924
|
}
|
|
850
925
|
|
|
851
926
|
/**
|
|
852
|
-
*
|
|
853
|
-
*
|
|
854
|
-
* resolution registry). Must run on the main thread (ExoPlayer access).
|
|
927
|
+
* Applies the current now playing metadata to the media notification. Uses the override if set,
|
|
928
|
+
* otherwise uses track metadata.
|
|
855
929
|
*/
|
|
856
|
-
private fun
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
return item.localConfiguration?.tag as? Track
|
|
861
|
-
}
|
|
862
|
-
}
|
|
863
|
-
return null
|
|
864
|
-
}
|
|
930
|
+
private fun applyNowPlayingMetadata() {
|
|
931
|
+
val index = currentIndex ?: return
|
|
932
|
+
val track = currentTrack ?: return
|
|
933
|
+
val override = nowPlayingOverride
|
|
865
934
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
935
|
+
val currentMediaItem = exoPlayer.getMediaItemAt(index)
|
|
936
|
+
val updatedMetadata =
|
|
937
|
+
currentMediaItem.mediaMetadata
|
|
938
|
+
.buildUpon()
|
|
939
|
+
.setTitle(override?.title ?: track.title)
|
|
940
|
+
.setDisplayTitle(override?.title ?: track.title)
|
|
941
|
+
.setArtist(override?.artist ?: track.artist)
|
|
942
|
+
.build()
|
|
943
|
+
|
|
944
|
+
val updatedMediaItem =
|
|
945
|
+
currentMediaItem
|
|
946
|
+
.buildUpon()
|
|
947
|
+
.setUri(currentMediaItem.localConfiguration?.uri)
|
|
948
|
+
.setMediaMetadata(updatedMetadata)
|
|
949
|
+
.setTag(track)
|
|
950
|
+
.build()
|
|
951
|
+
|
|
952
|
+
exoPlayer.replaceMediaItem(index, updatedMediaItem)
|
|
953
|
+
|
|
954
|
+
// Notify JS of the now playing metadata change
|
|
955
|
+
getNowPlaying()?.let { callbacks?.onNowPlayingChanged(it) }
|
|
884
956
|
}
|
|
885
957
|
|
|
886
958
|
/**
|
|
@@ -903,25 +975,12 @@ class Player(internal val context: Context) {
|
|
|
903
975
|
}
|
|
904
976
|
|
|
905
977
|
fun play() {
|
|
906
|
-
|
|
907
|
-
// (ExoPlayer.play() is only setPlayWhenReady(true)).
|
|
908
|
-
playWhenReady = true
|
|
978
|
+
exoPlayer.play()
|
|
909
979
|
if (currentTrack != null) {
|
|
910
|
-
// No-op unless the player is STATE_IDLE (ExoPlayer.prepare early-returns
|
|
911
|
-
// otherwise), so this only reconnects after a stop() or error and never
|
|
912
|
-
// re-buffers a healthy stream. Reconnecting is also how live streams
|
|
913
|
-
// rejoin the live edge on resume.
|
|
914
980
|
exoPlayer.prepare()
|
|
915
981
|
}
|
|
916
982
|
}
|
|
917
983
|
|
|
918
|
-
/** Jump to the live edge (default position) of a live item; no-op otherwise. */
|
|
919
|
-
fun seekToLiveEdge() {
|
|
920
|
-
if (exoPlayer.isCurrentMediaItemLive) {
|
|
921
|
-
exoPlayer.seekToDefaultPosition()
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
|
|
925
984
|
/**
|
|
926
985
|
* Executes a search and plays the results. Used for voice commands with structured search
|
|
927
986
|
* parameters.
|
|
@@ -931,20 +990,7 @@ class Player(internal val context: Context) {
|
|
|
931
990
|
*/
|
|
932
991
|
suspend fun playFromSearch(params: SearchParams): Boolean {
|
|
933
992
|
return try {
|
|
934
|
-
val
|
|
935
|
-
// A gate blocks external-surface "play" search too — otherwise voice search is a way around
|
|
936
|
-
// the gate (mirrors the iOS play-media intent guard). Resolved per request; a gated decision
|
|
937
|
-
// fires onGate(search) and refuses.
|
|
938
|
-
val gateOutcome =
|
|
939
|
-
audioBrowser.gateDecision(
|
|
940
|
-
NativeGateRequest(reason = GateReason.SEARCH, path = null, search = params)
|
|
941
|
-
)
|
|
942
|
-
if (gateOutcome.gated) {
|
|
943
|
-
Timber.i("playFromSearch refused — request is gated")
|
|
944
|
-
audioBrowser.onGate(GateEvent(GateReason.SEARCH))
|
|
945
|
-
return false
|
|
946
|
-
}
|
|
947
|
-
val browserManager = audioBrowser.browserManager
|
|
993
|
+
val browserManager = awaitBrowser().browserManager
|
|
948
994
|
|
|
949
995
|
Timber.d(
|
|
950
996
|
"Executing voice search: mode=${params.mode}, query='${params.query}', artist='${params.artist}', album='${params.album}'"
|
|
@@ -973,10 +1019,7 @@ class Player(internal val context: Context) {
|
|
|
973
1019
|
}
|
|
974
1020
|
|
|
975
1021
|
fun pause() {
|
|
976
|
-
|
|
977
|
-
// drop direction too — the retry policy reads it off-main before
|
|
978
|
-
// ExoPlayer's listener round-trip syncs it.
|
|
979
|
-
playWhenReady = false
|
|
1022
|
+
exoPlayer.pause()
|
|
980
1023
|
}
|
|
981
1024
|
|
|
982
1025
|
fun togglePlayback() {
|
|
@@ -993,11 +1036,8 @@ class Player(internal val context: Context) {
|
|
|
993
1036
|
* required for playback.
|
|
994
1037
|
*/
|
|
995
1038
|
fun stop() {
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
// is emitted (direct field assignment bypasses events — see its docstring).
|
|
999
|
-
setPlaybackState(PlaybackState.STOPPED)
|
|
1000
|
-
playWhenReady = false
|
|
1039
|
+
playbackState = PlaybackState.STOPPED
|
|
1040
|
+
exoPlayer.playWhenReady = false
|
|
1001
1041
|
exoPlayer.stop()
|
|
1002
1042
|
}
|
|
1003
1043
|
|
|
@@ -1011,15 +1051,7 @@ class Player(internal val context: Context) {
|
|
|
1011
1051
|
* use [pause].
|
|
1012
1052
|
*/
|
|
1013
1053
|
fun destroy() {
|
|
1014
|
-
// Cancel without a final save: the loop would tick against the released
|
|
1015
|
-
// player and persist position 0 over the real resumption position.
|
|
1016
|
-
playbackStateStore.cancelPeriodicSave()
|
|
1017
|
-
// An armed timer's Runnable would outlive the release and fire pause() into the
|
|
1018
|
-
// released player. Cleared here, while a mid-ramp fade can still restore volume.
|
|
1019
|
-
sleepTimer.clear()
|
|
1020
1054
|
stop()
|
|
1021
|
-
nowPlaying.destroy()
|
|
1022
|
-
mediaSessionCallback.destroy()
|
|
1023
1055
|
forwardingPlayer.removeListener(playerListener)
|
|
1024
1056
|
automaticBufferManager?.detach()
|
|
1025
1057
|
automaticBufferManager = null
|
|
@@ -1027,7 +1059,8 @@ class Player(internal val context: Context) {
|
|
|
1027
1059
|
cache?.release()
|
|
1028
1060
|
cache = null
|
|
1029
1061
|
networkMonitor.destroy()
|
|
1030
|
-
|
|
1062
|
+
equalizerManager?.release()
|
|
1063
|
+
equalizerManager = null
|
|
1031
1064
|
}
|
|
1032
1065
|
|
|
1033
1066
|
fun seekTo(duration: Long, unit: TimeUnit) {
|
|
@@ -1040,57 +1073,6 @@ class Player(internal val context: Context) {
|
|
|
1040
1073
|
exoPlayer.seekTo(positionMs)
|
|
1041
1074
|
}
|
|
1042
1075
|
|
|
1043
|
-
/**
|
|
1044
|
-
* Invalidates in-flight [reportRetryingError] posts: bumped on track change so a report
|
|
1045
|
-
* classified for the outgoing track can't land on the incoming one's spinner. Written on main,
|
|
1046
|
-
* read on ExoPlayer's loader thread.
|
|
1047
|
-
*/
|
|
1048
|
-
@Volatile private var retryingErrorGeneration = 0
|
|
1049
|
-
|
|
1050
|
-
/**
|
|
1051
|
-
* Surfaces a load failure the retry policy is still working on: attached to the current
|
|
1052
|
-
* (non-terminal) state via [Callbacks.onPlaybackChanged], so UIs can show the cause over the
|
|
1053
|
-
* spinner. Not an ERROR transition, and not a [Callbacks.onPlaybackError] — that event stays
|
|
1054
|
-
* reserved for terminal errors. Called from ExoPlayer's loader thread, hence the main hop.
|
|
1055
|
-
*/
|
|
1056
|
-
private fun reportRetryingError(exception: IOException) {
|
|
1057
|
-
val error = PlaybackErrorClassifier.retryingLoadError(exception, networkMonitor.getOnline())
|
|
1058
|
-
val generation = retryingErrorGeneration
|
|
1059
|
-
mainHandler.post {
|
|
1060
|
-
// The track changed while this post was in flight — the error belongs to the old one.
|
|
1061
|
-
if (generation != retryingErrorGeneration) return@post
|
|
1062
|
-
// Only attach while the failure is what the listener is looking at. During PLAYING/READY
|
|
1063
|
-
// buffered audio is still audibly fine, and ExoPlayer's in-place retry can succeed without
|
|
1064
|
-
// any state change — an advisory attached there would never clear.
|
|
1065
|
-
if (
|
|
1066
|
-
playbackState != PlaybackState.LOADING &&
|
|
1067
|
-
playbackState != PlaybackState.BUFFERING &&
|
|
1068
|
-
playbackState != PlaybackState.PAUSED
|
|
1069
|
-
) {
|
|
1070
|
-
return@post
|
|
1071
|
-
}
|
|
1072
|
-
// Each failed attempt re-reports; identical repeats add nothing (and would
|
|
1073
|
-
// re-render now-playing every backoff tick).
|
|
1074
|
-
if (playbackError == error) return@post
|
|
1075
|
-
playbackError = error
|
|
1076
|
-
callbacks?.onPlaybackChanged(Playback(playbackState, error))
|
|
1077
|
-
nowPlaying.render()
|
|
1078
|
-
}
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
/**
|
|
1082
|
-
* Drops a retrying error whose track is gone. The new track may keep the state on
|
|
1083
|
-
* LOADING/BUFFERING — no state-change emit — so the clear is emitted here, or the old track's
|
|
1084
|
-
* error would linger over the new one's spinner.
|
|
1085
|
-
*/
|
|
1086
|
-
internal fun clearRetryingError() {
|
|
1087
|
-
retryingErrorGeneration++
|
|
1088
|
-
if (playbackError?.retrying != true) return
|
|
1089
|
-
playbackError = null
|
|
1090
|
-
callbacks?.onPlaybackChanged(Playback(playbackState, null))
|
|
1091
|
-
nowPlaying.render()
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
1076
|
/**
|
|
1095
1077
|
* Updates the player state and emits a state change event if the state has changed. Only emits an
|
|
1096
1078
|
* event if the new state differs from the current state.
|
|
@@ -1106,78 +1088,39 @@ class Player(internal val context: Context) {
|
|
|
1106
1088
|
val oldState = playbackState
|
|
1107
1089
|
playbackState = state
|
|
1108
1090
|
|
|
1109
|
-
// Audio rendered: this load has proven itself — retries from here on get
|
|
1110
|
-
// the retry policy's full recovery budget, not the short first-connect one.
|
|
1111
|
-
if (state == PlaybackState.PLAYING) {
|
|
1112
|
-
hasPlayedCache = true
|
|
1113
|
-
}
|
|
1114
|
-
|
|
1115
|
-
// A natural end exhausts the play intent — nothing is left to play. Keeping
|
|
1116
|
-
// playWhenReady true inverted the play/pause toggle, held audio focus forever
|
|
1117
|
-
// (ExoPlayer abandons it only at IDLE or on the intent dropping), and kept the
|
|
1118
|
-
// periodic position save running. Cleared and emitted before the state /
|
|
1119
|
-
// queue-ended callbacks so JS observes the native order (intent → state →
|
|
1120
|
-
// queueEnded); the media3 listener's later echo is deduplicated by
|
|
1121
|
-
// emitPlayWhenReadyChanged. The state machine's ENDED guard keeps the drop
|
|
1122
|
-
// from re-reporting the state as PAUSED.
|
|
1123
|
-
if (state == PlaybackState.ENDED && playWhenReady) {
|
|
1124
|
-
playWhenReady = false
|
|
1125
|
-
emitPlayWhenReadyChanged(false)
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
// The last track fires no AUTO media-item transition, so an armed
|
|
1129
|
-
// end-of-track sleep timer would stay set forever and pause the next
|
|
1130
|
-
// track played instead.
|
|
1131
|
-
if (state == PlaybackState.ENDED) {
|
|
1132
|
-
sleepTimer.onTrackEnd()
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
1091
|
// Clear error when transitioning away from error state
|
|
1136
1092
|
if (oldState == PlaybackState.ERROR) {
|
|
1137
1093
|
playbackError = null
|
|
1138
1094
|
callbacks?.onPlaybackError(null)
|
|
1139
1095
|
}
|
|
1140
1096
|
|
|
1141
|
-
// A retrying error rides along through LOADING/BUFFERING/PAUSED; a state that
|
|
1142
|
-
// proves recovery (READY/PLAYING — data flowed) or abandons the attempt clears
|
|
1143
|
-
// it, before the Playback below is built so the emitted event is already clean.
|
|
1144
|
-
if (
|
|
1145
|
-
playbackError?.retrying == true &&
|
|
1146
|
-
state != PlaybackState.LOADING &&
|
|
1147
|
-
state != PlaybackState.BUFFERING &&
|
|
1148
|
-
state != PlaybackState.PAUSED
|
|
1149
|
-
) {
|
|
1150
|
-
playbackError = null
|
|
1151
|
-
}
|
|
1152
|
-
|
|
1153
1097
|
val playback = Playback(state, playbackError)
|
|
1154
1098
|
callbacks?.onPlaybackChanged(playback)
|
|
1155
1099
|
|
|
1156
|
-
//
|
|
1157
|
-
// `playbackState` (plus isRebuffering / isOnline / error), so any transition can change its
|
|
1158
|
-
// output — the live song while paused, a "Reconnecting…" line on a rebuffer, an offline/error
|
|
1159
|
-
// line. The publish-dedupe in applyNowPlayingFields drops redundant updates, so re-running
|
|
1160
|
-
// through the rapid startup sequence (none→loading→buffering→ready→playing) is cheap.
|
|
1161
|
-
nowPlaying.render()
|
|
1162
|
-
|
|
1163
|
-
// Emit queue ended event when playback ends on the last track. Repeat modes never
|
|
1164
|
-
// conceptually end the queue (matches web's endsQueue()): an ENDED that surfaces while
|
|
1165
|
-
// repeating (e.g. a seek to the end) must not read as "playlist over".
|
|
1100
|
+
// Emit queue ended event when playback ends on the last track
|
|
1166
1101
|
// This coupling ensures queue ended events are always triggered consistently with state
|
|
1167
1102
|
// changes
|
|
1168
|
-
if (state == PlaybackState.ENDED &&
|
|
1103
|
+
if (state == PlaybackState.ENDED && isLastTrack) {
|
|
1169
1104
|
currentIndex?.let { index ->
|
|
1170
1105
|
val event =
|
|
1171
1106
|
PlaybackQueueEndedEvent(track = index.toDouble(), position = position.toSeconds())
|
|
1172
1107
|
callbacks?.onPlaybackQueueEnded(event)
|
|
1173
1108
|
}
|
|
1174
|
-
// Reset saved position to 0 so resumption starts from beginning
|
|
1175
|
-
|
|
1109
|
+
// Reset saved position to 0 so resumption starts from beginning (only when not repeating)
|
|
1110
|
+
if (repeatMode == RepeatMode.OFF) {
|
|
1111
|
+
playbackStateStore.savePositionZero()
|
|
1112
|
+
}
|
|
1176
1113
|
}
|
|
1177
1114
|
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1115
|
+
progressUpdateManager.onPlaybackStateChanged(state)
|
|
1116
|
+
val newPlayingState = PlayingStateFactory.derive(playWhenReady, state)
|
|
1117
|
+
if (newPlayingState != playingState) {
|
|
1118
|
+
Timber.d(
|
|
1119
|
+
"PlayingState changed: playing=${newPlayingState.playing}, buffering=${newPlayingState.buffering}"
|
|
1120
|
+
)
|
|
1121
|
+
playingState = newPlayingState
|
|
1122
|
+
callbacks?.onPlaybackPlayingState(playingState)
|
|
1123
|
+
}
|
|
1181
1124
|
}
|
|
1182
1125
|
}
|
|
1183
1126
|
|
|
@@ -1187,11 +1130,7 @@ class Player(internal val context: Context) {
|
|
|
1187
1130
|
* @param interval The interval in seconds, or null to disable progress updates
|
|
1188
1131
|
*/
|
|
1189
1132
|
fun setProgressUpdateInterval(interval: Double?) {
|
|
1190
|
-
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
fun setPlaybackIntervalEnabled(enabled: Boolean) {
|
|
1194
|
-
intervalTimer.setInterval(if (enabled) 1.0 else null)
|
|
1133
|
+
progressUpdateManager.setUpdateInterval(interval)
|
|
1195
1134
|
}
|
|
1196
1135
|
|
|
1197
1136
|
/**
|
|
@@ -1210,6 +1149,8 @@ class Player(internal val context: Context) {
|
|
|
1210
1149
|
|
|
1211
1150
|
// Check what changed
|
|
1212
1151
|
val skipSilenceChanged = previousOptions.skipSilence != options.skipSilence
|
|
1152
|
+
val ratingTypeChanged = previousOptions.ratingType != options.ratingType
|
|
1153
|
+
val shuffleChanged = previousOptions.shuffle != options.shuffle
|
|
1213
1154
|
val progressUpdateEventIntervalChanged =
|
|
1214
1155
|
previousOptions.progressUpdateEventInterval != options.progressUpdateEventInterval
|
|
1215
1156
|
val forwardJumpIntervalChanged =
|
|
@@ -1217,18 +1158,20 @@ class Player(internal val context: Context) {
|
|
|
1217
1158
|
val backwardJumpIntervalChanged =
|
|
1218
1159
|
previousOptions.backwardJumpInterval != options.backwardJumpInterval
|
|
1219
1160
|
val capabilitiesChanged = previousOptions.capabilities != options.capabilities
|
|
1220
|
-
val
|
|
1221
|
-
|
|
1161
|
+
val notificationButtonsChanged =
|
|
1162
|
+
previousOptions.notificationButtons != options.notificationButtons
|
|
1222
1163
|
val appKilledPlaybackBehaviorChanged =
|
|
1223
1164
|
previousOptions.appKilledPlaybackBehavior != options.appKilledPlaybackBehavior
|
|
1224
1165
|
|
|
1225
1166
|
val hasChanged =
|
|
1226
1167
|
skipSilenceChanged ||
|
|
1168
|
+
ratingTypeChanged ||
|
|
1169
|
+
shuffleChanged ||
|
|
1227
1170
|
progressUpdateEventIntervalChanged ||
|
|
1228
1171
|
forwardJumpIntervalChanged ||
|
|
1229
1172
|
backwardJumpIntervalChanged ||
|
|
1230
1173
|
capabilitiesChanged ||
|
|
1231
|
-
|
|
1174
|
+
notificationButtonsChanged ||
|
|
1232
1175
|
appKilledPlaybackBehaviorChanged
|
|
1233
1176
|
|
|
1234
1177
|
// Apply only changed properties
|
|
@@ -1236,32 +1179,25 @@ class Player(internal val context: Context) {
|
|
|
1236
1179
|
skipSilence = options.skipSilence
|
|
1237
1180
|
}
|
|
1238
1181
|
|
|
1239
|
-
if (
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1182
|
+
if (ratingTypeChanged) {
|
|
1183
|
+
options.ratingType?.let { ratingType = it }
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
if (shuffleChanged) {
|
|
1187
|
+
shuffleMode = options.shuffle
|
|
1243
1188
|
}
|
|
1244
1189
|
|
|
1245
1190
|
if (progressUpdateEventIntervalChanged) {
|
|
1246
1191
|
setProgressUpdateInterval(options.progressUpdateEventInterval)
|
|
1247
1192
|
}
|
|
1248
1193
|
|
|
1249
|
-
|
|
1250
|
-
// interval has to rebuild the layout even when capabilities and placement are untouched.
|
|
1251
|
-
if (
|
|
1252
|
-
capabilitiesChanged ||
|
|
1253
|
-
remoteButtonLayoutChanged ||
|
|
1254
|
-
forwardJumpIntervalChanged ||
|
|
1255
|
-
backwardJumpIntervalChanged
|
|
1256
|
-
) {
|
|
1194
|
+
if (capabilitiesChanged || notificationButtonsChanged) {
|
|
1257
1195
|
val searchAvailable = browser?.browserManager?.config?.hasSearch ?: false
|
|
1258
1196
|
mediaSessionCallback.updateMediaSession(
|
|
1259
1197
|
mediaSession,
|
|
1260
1198
|
options.capabilities,
|
|
1261
|
-
options.
|
|
1199
|
+
options.notificationButtons,
|
|
1262
1200
|
searchAvailable,
|
|
1263
|
-
options.forwardJumpInterval,
|
|
1264
|
-
options.backwardJumpInterval,
|
|
1265
1201
|
)
|
|
1266
1202
|
}
|
|
1267
1203
|
|
|
@@ -1305,6 +1241,187 @@ class Player(internal val context: Context) {
|
|
|
1305
1241
|
return networkMonitor.getOnline()
|
|
1306
1242
|
}
|
|
1307
1243
|
|
|
1244
|
+
/** Initializes the equalizer with the player's audio session ID. */
|
|
1245
|
+
private fun initializeEqualizer() {
|
|
1246
|
+
val audioSessionId = exoPlayer.audioSessionId
|
|
1247
|
+
if (audioSessionId == C.AUDIO_SESSION_ID_UNSET) {
|
|
1248
|
+
Timber.d("Skipping equalizer init - no audio session yet, will init on first playback")
|
|
1249
|
+
return
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
try {
|
|
1253
|
+
equalizerManager =
|
|
1254
|
+
EqualizerManager(audioSessionId).apply {
|
|
1255
|
+
setOnSettingsChanged { settings -> callbacks?.onEqualizerChanged(settings) }
|
|
1256
|
+
}
|
|
1257
|
+
Timber.d("Equalizer initialized with session ID: $audioSessionId")
|
|
1258
|
+
} catch (e: Exception) {
|
|
1259
|
+
Timber.e(e, "Failed to initialize equalizer")
|
|
1260
|
+
equalizerManager = null
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
/**
|
|
1265
|
+
* Reinitializes the equalizer when the audio session ID changes. Preserves current settings
|
|
1266
|
+
* (enabled state, preset, or custom levels). Also handles first-time initialization when the
|
|
1267
|
+
* equalizer was skipped at startup due to unset audio session ID.
|
|
1268
|
+
*/
|
|
1269
|
+
internal fun reinitializeEqualizer(newAudioSessionId: Int) {
|
|
1270
|
+
val oldManager = equalizerManager
|
|
1271
|
+
|
|
1272
|
+
// First-time initialization (skipped at startup because session was unset)
|
|
1273
|
+
if (oldManager == null) {
|
|
1274
|
+
Timber.d("First-time equalizer initialization with session ID: $newAudioSessionId")
|
|
1275
|
+
try {
|
|
1276
|
+
equalizerManager =
|
|
1277
|
+
EqualizerManager(newAudioSessionId).apply {
|
|
1278
|
+
setOnSettingsChanged { settings -> callbacks?.onEqualizerChanged(settings) }
|
|
1279
|
+
}
|
|
1280
|
+
Timber.d("Equalizer initialized with session ID: $newAudioSessionId")
|
|
1281
|
+
} catch (e: Exception) {
|
|
1282
|
+
Timber.e(e, "Failed to initialize equalizer")
|
|
1283
|
+
equalizerManager = null
|
|
1284
|
+
}
|
|
1285
|
+
return
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
// Same session ID, no need to reinitialize
|
|
1289
|
+
if (oldManager.audioSessionId == newAudioSessionId) {
|
|
1290
|
+
return
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
try {
|
|
1294
|
+
// Capture current settings before releasing old equalizer
|
|
1295
|
+
val currentSettings = oldManager.getSettings()
|
|
1296
|
+
|
|
1297
|
+
// Release old equalizer
|
|
1298
|
+
oldManager.release()
|
|
1299
|
+
|
|
1300
|
+
// Create new equalizer with new session ID
|
|
1301
|
+
equalizerManager =
|
|
1302
|
+
EqualizerManager(newAudioSessionId).apply {
|
|
1303
|
+
setOnSettingsChanged { settings -> callbacks?.onEqualizerChanged(settings) }
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
// Restore previous settings if available
|
|
1307
|
+
currentSettings?.let { settings ->
|
|
1308
|
+
if (settings.activePreset != null) {
|
|
1309
|
+
// Restore preset
|
|
1310
|
+
equalizerManager?.setPreset(settings.activePreset)
|
|
1311
|
+
} else if (settings.enabled) {
|
|
1312
|
+
// Restore custom levels
|
|
1313
|
+
equalizerManager?.setLevels(settings.bandLevels)
|
|
1314
|
+
}
|
|
1315
|
+
// Restore enabled state
|
|
1316
|
+
equalizerManager?.setEnabled(settings.enabled)
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
Timber.d("Equalizer reinitialized for new session ID: $newAudioSessionId")
|
|
1320
|
+
} catch (e: Exception) {
|
|
1321
|
+
Timber.e(e, "Failed to reinitialize equalizer")
|
|
1322
|
+
equalizerManager = null
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
/**
|
|
1327
|
+
* Gets the current equalizer settings.
|
|
1328
|
+
*
|
|
1329
|
+
* @return Current equalizer settings or null if not available
|
|
1330
|
+
*/
|
|
1331
|
+
fun getEqualizerSettings(): com.margelo.nitro.audiobrowser.EqualizerSettings? {
|
|
1332
|
+
return equalizerManager?.getSettings()
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
/**
|
|
1336
|
+
* Enables or disables the equalizer.
|
|
1337
|
+
*
|
|
1338
|
+
* @param enabled true to enable, false to disable
|
|
1339
|
+
*/
|
|
1340
|
+
fun setEqualizerEnabled(enabled: Boolean) {
|
|
1341
|
+
equalizerManager?.setEnabled(enabled)
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* Applies a preset to the equalizer.
|
|
1346
|
+
*
|
|
1347
|
+
* @param preset Name of the preset to apply
|
|
1348
|
+
*/
|
|
1349
|
+
fun setEqualizerPreset(preset: String) {
|
|
1350
|
+
equalizerManager?.setPreset(preset)
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
/**
|
|
1354
|
+
* Sets custom band levels for the equalizer.
|
|
1355
|
+
*
|
|
1356
|
+
* @param levels Array of level values in millibels for each band
|
|
1357
|
+
*/
|
|
1358
|
+
fun setEqualizerLevels(levels: DoubleArray) {
|
|
1359
|
+
equalizerManager?.setLevels(levels)
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
// MARK: - Sleep Timer
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* Gets the current sleep timer state.
|
|
1366
|
+
*
|
|
1367
|
+
* @return Sleep timer state or null if no timer is active
|
|
1368
|
+
*/
|
|
1369
|
+
fun getSleepTimer(): NitroSleepTimer {
|
|
1370
|
+
return when {
|
|
1371
|
+
sleepTimer.time != null -> {
|
|
1372
|
+
NitroSleepTimer.create(SleepTimerTime(sleepTimer.time!!))
|
|
1373
|
+
}
|
|
1374
|
+
sleepTimer.sleepWhenPlayedToEnd -> {
|
|
1375
|
+
NitroSleepTimer.create(SleepTimerEndOfTrack(true))
|
|
1376
|
+
}
|
|
1377
|
+
else -> {
|
|
1378
|
+
NitroSleepTimer.create(NullType.NULL)
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
|
|
1383
|
+
/**
|
|
1384
|
+
* Sets a sleep timer to stop playback after the specified duration.
|
|
1385
|
+
*
|
|
1386
|
+
* @param seconds Number of seconds until playback stops
|
|
1387
|
+
*/
|
|
1388
|
+
fun setSleepTimer(seconds: Double) {
|
|
1389
|
+
sleepTimer.sleepAfter(seconds)
|
|
1390
|
+
callbacks?.onSleepTimerChanged(getSleepTimer())
|
|
1391
|
+
}
|
|
1392
|
+
|
|
1393
|
+
/** Sets a sleep timer to stop playback when the current track finishes playing. */
|
|
1394
|
+
fun setSleepTimerToEndOfTrack() {
|
|
1395
|
+
sleepTimer.sleepWhenPlayedToEnd()
|
|
1396
|
+
callbacks?.onSleepTimerChanged(getSleepTimer())
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Clears the active sleep timer.
|
|
1401
|
+
*
|
|
1402
|
+
* @return true if a timer was cleared, false if no timer was active
|
|
1403
|
+
*/
|
|
1404
|
+
fun clearSleepTimer(): Boolean {
|
|
1405
|
+
val wasRunning = sleepTimer.clear()
|
|
1406
|
+
if (wasRunning) {
|
|
1407
|
+
callbacks?.onSleepTimerChanged(NitroSleepTimer.create(NullType.NULL))
|
|
1408
|
+
}
|
|
1409
|
+
return wasRunning
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
/**
|
|
1413
|
+
* Checks if the sleep timer is set to end on track completion and stops playback if so. Called
|
|
1414
|
+
* when a track naturally finishes playing.
|
|
1415
|
+
*/
|
|
1416
|
+
internal fun checkSleepTimerOnTrackEnd() {
|
|
1417
|
+
if (sleepTimer.sleepWhenPlayedToEnd) {
|
|
1418
|
+
Timber.d("Sleep timer triggered on track end, stopping playback")
|
|
1419
|
+
sleepTimer.clear()
|
|
1420
|
+
stop()
|
|
1421
|
+
callbacks?.onSleepTimerChanged(NitroSleepTimer.create(NullType.NULL))
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1308
1425
|
/**
|
|
1309
1426
|
* Validates that an index is within bounds [0, trackCount).
|
|
1310
1427
|
*
|
|
@@ -1352,10 +1469,6 @@ class Player(internal val context: Context) {
|
|
|
1352
1469
|
mediaSessionCallback.notifyContentChanged(path)
|
|
1353
1470
|
}
|
|
1354
1471
|
|
|
1355
|
-
fun invalidateAllContent() {
|
|
1356
|
-
mediaSessionCallback.invalidateAllContent()
|
|
1357
|
-
}
|
|
1358
|
-
|
|
1359
1472
|
/**
|
|
1360
1473
|
* Returns the recommended artwork size in pixels from the connected media browser (e.g., Android
|
|
1361
1474
|
* Auto), or null if not provided.
|