react-native-audio-browser 0.2.0-next.27 → 0.2.0-next.29
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/android/src/main/java/com/audiobrowser/ServiceBinding.kt +8 -4
- package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +3 -4
- package/android/src/test/java/com/audiobrowser/ServiceBindingTest.kt +13 -0
- package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +2 -2
- package/ios/AVPlayerEngine.swift +334 -0
- package/ios/AVPlayerEngineCallbacks.swift +15 -0
- package/ios/Browser/BrowseGate.swift +58 -0
- package/ios/Browser/BrowserConfig.swift +31 -89
- package/ios/Browser/BrowserManager.swift +68 -487
- package/ios/Browser/NavigationErrorState.swift +41 -0
- package/ios/Browser/PageResolver.swift +227 -0
- package/ios/Browser/RequestLayer.swift +90 -0
- package/ios/Browser/{BrowserManager+URLResolution.swift → RequestPipeline.swift} +175 -107
- package/ios/CarPlay/CPInterfaceController+Safe.swift +11 -24
- package/ios/CarPlay/CarPlayArtworkResolver.swift +35 -83
- package/ios/CarPlay/CarPlayController.swift +42 -1442
- package/ios/CarPlay/CarPlayImageLoader.swift +42 -83
- package/ios/CarPlay/CarPlayListItemFactory.swift +9 -23
- package/ios/CarPlay/CarPlayNowPlayingManager.swift +119 -129
- package/ios/CarPlay/CarPlaySession+Navigator.swift +114 -0
- package/ios/CarPlay/CarPlaySession+PageLoader.swift +92 -0
- package/ios/CarPlay/CarPlaySession+Refresher.swift +43 -0
- package/ios/CarPlay/CarPlaySession+TabBar.swift +193 -0
- package/ios/CarPlay/CarPlaySession.swift +209 -0
- package/ios/CarPlay/CarPlayTemplates.swift +63 -0
- package/ios/CarPlay/HybridAudioBrowser+IntentFavorite.swift +20 -0
- package/ios/CarPlay/MediaIntentPlayback.swift +74 -0
- package/ios/CarPlay/RNABMediaAddHandler.swift +2 -18
- package/ios/CarPlay/RNABMediaAffinityHandler.swift +5 -21
- package/ios/CarPlay/RNABMediaIntentHandler.swift +2 -3
- package/ios/Extension/NavigationError+Conversion.swift +7 -4
- package/ios/Extension/UIImage+Adaptive.swift +12 -0
- package/ios/Extension/URLError+Connectivity.swift +15 -0
- package/ios/Http/HttpClient.swift +63 -145
- package/ios/HybridAudioBrowser+Browser.swift +153 -0
- package/ios/HybridAudioBrowser+Options.swift +144 -0
- package/ios/HybridAudioBrowser+Player.swift +397 -0
- package/ios/HybridAudioBrowser+PlayerCallbacks.swift +190 -0
- package/ios/HybridAudioBrowser+Stubs.swift +46 -0
- package/ios/HybridAudioBrowser.swift +74 -1687
- package/ios/Model/NitroTypeStubs.swift +18 -1
- package/ios/Model/PlayerUpdateOptions.swift +1 -1
- package/ios/NowPlayingInfo/NowPlayingInfoController.swift +18 -53
- package/ios/Observer/ItemObserver.swift +90 -0
- package/ios/Observer/PlayerObserver.swift +59 -0
- package/ios/Option/SessionCategories.swift +41 -92
- package/ios/Player/AudioSessionController.swift +177 -0
- package/ios/Player/DeferredSeek.swift +70 -0
- package/ios/Player/ErrorStatus.swift +27 -0
- package/ios/Player/MediaLoader.swift +24 -11
- package/ios/Player/NowPlayingUpdater.swift +157 -58
- package/ios/Player/PlaybackFailure.swift +125 -0
- package/ios/Player/PlaybackPersistence.swift +73 -0
- package/ios/Player/Player.swift +1083 -0
- package/ios/Player/{PlaybackCoordinatorCallbacks.swift → PlayerCallbacks.swift} +3 -4
- package/ios/Player/PlayerEngine.swift +89 -0
- package/ios/Player/PlayerStatusTypes.swift +2 -6
- package/ios/Player/QueueManager.swift +52 -59
- package/ios/Player/RetryLoop.swift +261 -0
- package/ios/Player/SleepTimerManager.swift +1 -1
- package/ios/RemoteCommand/RemoteCommandCallbacks.swift +2 -3
- package/ios/RemoteCommand/RemoteCommandController.swift +85 -367
- package/ios/Tests/CarPlayArtworkResolverTests.swift +60 -356
- package/ios/Tests/DeferredSeekTests.swift +70 -0
- package/ios/Tests/EmitterTests.swift +29 -0
- package/ios/Tests/GenerationMemoTests.swift +121 -0
- package/ios/Tests/LRUCacheTests.swift +4 -5
- package/ios/Tests/MediaLoaderTests.swift +12 -33
- package/ios/Tests/ObserverTests.swift +88 -0
- package/ios/Tests/PlaybackErrorTests.swift +76 -0
- package/ios/Tests/PlaybackFailureTests.swift +189 -0
- package/ios/Tests/PlaybackPersistenceTests.swift +93 -0
- package/ios/Tests/PlayerPolicyTests.swift +405 -0
- package/ios/Tests/{PlaybackCoordinatorTests.swift → PlayerTests.swift} +298 -248
- package/ios/Tests/PlayingStateTests.swift +42 -0
- package/ios/Tests/QueueManagerTests.swift +76 -107
- package/ios/Tests/ReadyValueTests.swift +73 -0
- package/ios/Tests/RemoteCommandControllerTests.swift +10 -30
- package/ios/Tests/RemoteCommandTests.swift +2 -4
- package/ios/Tests/RequestLayerTests.swift +112 -0
- package/ios/Tests/RetryLoopTests.swift +270 -0
- package/ios/Tests/Support/TestTypes.swift +111 -112
- package/ios/Tests/TrackIdTemplateTests.swift +1 -1
- package/ios/Tests/URLErrorConnectivityTests.swift +20 -0
- package/ios/TrackSelector.swift +1 -1
- package/ios/Util/ArtworkImageFetcher.swift +42 -0
- package/ios/Util/Emitter.swift +42 -0
- package/ios/Util/GenerationMemo.swift +36 -0
- package/ios/Util/LRUCache.swift +23 -162
- package/ios/Util/NetworkMonitor.swift +1 -1
- package/ios/Util/ReadyValue.swift +56 -0
- package/ios/Util/SFSymbolRenderer.swift +35 -29
- package/ios/Util/SVGProcessor.swift +0 -10
- package/lib/commonjs/web/NativeAudioBrowser.js +1 -1
- package/lib/commonjs/web/TrackPlayer/PlayingStateFactory.js +1 -1
- package/lib/module/web/NativeAudioBrowser.js +1 -1
- package/lib/module/web/TrackPlayer/PlayingStateFactory.js +1 -1
- package/lib/typescript/src/types/browser.d.ts +3 -3
- package/package.json +1 -1
- package/src/types/browser.ts +3 -3
- package/src/web/NativeAudioBrowser.ts +1 -1
- package/src/web/TrackPlayer/PlayingStateFactory.test.ts +1 -1
- package/src/web/TrackPlayer/PlayingStateFactory.ts +1 -1
- package/ios/Bridge.h +0 -8
- package/ios/Browser/MediaResolveComposer.swift +0 -114
- package/ios/NowPlayingInfo/MediaItemProperty.swift +0 -78
- package/ios/NowPlayingInfo/NowPlayingInfoKeyValue.swift +0 -6
- package/ios/NowPlayingInfo/NowPlayingInfoProperty.swift +0 -220
- package/ios/Observer/PlayerItemNotificationObserver.swift +0 -119
- package/ios/Observer/PlayerItemPropertyObserver.swift +0 -133
- package/ios/Observer/PlayerStateObserver.swift +0 -50
- package/ios/Observer/PlayerTimeObserver.swift +0 -55
- package/ios/Option/PitchAlgorithms.swift +0 -17
- package/ios/Option/TimeEventFrequency.swift +0 -18
- package/ios/Player/LoadSeekCoordinator.swift +0 -99
- package/ios/Player/MediaLoaderDelegate.swift +0 -11
- package/ios/Player/PlaybackCoordinator.swift +0 -761
- package/ios/Player/PlaybackEffectHandler.swift +0 -54
- package/ios/Player/PlaybackErrorHandler.swift +0 -175
- package/ios/Player/PlaybackStateStore.swift +0 -27
- package/ios/Player/PlayingStateManager.swift +0 -33
- package/ios/Player/RetryManager.swift +0 -384
- package/ios/Player/SeekCompletionHandler.swift +0 -5
- package/ios/Player/SleepTimerHandling.swift +0 -28
- package/ios/Support/RNTrackPlayer-Bridging-Header.h +0 -7
- package/ios/Tests/LoadSeekCoordinatorTests.swift +0 -327
- package/ios/Tests/MediaResolveTests.swift +0 -126
- package/ios/Tests/OnceValueTests.swift +0 -79
- package/ios/Tests/PlaybackErrorHandlerTests.swift +0 -549
- package/ios/Tests/PlaybackStateStoreTests.swift +0 -49
- package/ios/Tests/PlayerTimeObserverTests.swift +0 -37
- package/ios/Tests/PlayingStateManagerTests.swift +0 -57
- package/ios/Tests/RetryManagerTests.swift +0 -178
- package/ios/TrackPlayer.swift +0 -1042
- package/ios/TrackPlayerCallbacks.swift +0 -53
- package/ios/Util/MetadataAdapter.swift +0 -131
- package/ios/Util/OnceValue.swift +0 -104
- /package/ios/{Player → CarPlay}/MediaIntentCriteria.swift +0 -0
- /package/ios/{Browser → CarPlay}/SectionPresentation.swift +0 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import AVFoundation
|
|
2
|
+
import AVKit
|
|
3
|
+
import Foundation
|
|
4
|
+
import MediaPlayer
|
|
5
|
+
import NitroModules
|
|
6
|
+
import os.log
|
|
7
|
+
|
|
8
|
+
// MARK: - PlayerCallbacks, AVPlayerEngineCallbacks
|
|
9
|
+
|
|
10
|
+
extension HybridAudioBrowser: PlayerCallbacks, AVPlayerEngineCallbacks {
|
|
11
|
+
public func playerDidChangePlayback(_ playback: Playback) {
|
|
12
|
+
onPlaybackChanged(playback)
|
|
13
|
+
// The Player sets the error before this fires, so the error line renders.
|
|
14
|
+
engine?.nowPlayingUpdater.render()
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public func playerDidChangeActiveTrack(_ event: PlaybackActiveTrackChangedEvent) {
|
|
18
|
+
// Hydrate the active track's `favorited` from the authoritative set so JS
|
|
19
|
+
// consumers (useActiveTrack) match getActiveTrack()'s hydrated value — the
|
|
20
|
+
// Player emits the raw queue track, whose flag isn't kept in sync.
|
|
21
|
+
let hydrated = PlaybackActiveTrackChangedEvent(
|
|
22
|
+
lastIndex: event.lastIndex,
|
|
23
|
+
lastTrack: event.lastTrack,
|
|
24
|
+
lastPosition: event.lastPosition,
|
|
25
|
+
index: event.index,
|
|
26
|
+
track: event.track.map(browserManager.hydrateFavorite),
|
|
27
|
+
)
|
|
28
|
+
activeTrackChangedEmitter.emit(hydrated)
|
|
29
|
+
engine?.nowPlayingUpdater.trackChanged()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
public func playerDidUpdateProgress(_ event: PlaybackProgressUpdatedEvent) {
|
|
33
|
+
onPlaybackProgressUpdated(event)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
public func playerDidFirePlaybackInterval() {
|
|
37
|
+
onPlaybackInterval()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public func playerDidChangePlayWhenReady(_ playWhenReady: Bool) {
|
|
41
|
+
// Intent to play again is the earliest cancel signal for a pending session release.
|
|
42
|
+
if playWhenReady { audioSession.cancelRelease() }
|
|
43
|
+
onPlaybackPlayWhenReadyChanged(PlaybackPlayWhenReadyChangedEvent(playWhenReady: playWhenReady))
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
public func playerDidChangePlayingState(_ state: PlayingState) {
|
|
47
|
+
onPlaybackPlayingState(state)
|
|
48
|
+
// Lazily activate the audio session the moment playback actually produces — or is buffering to
|
|
49
|
+
// produce — output. This (not setup) is where we grab the session, so launching the app never
|
|
50
|
+
// interrupts other apps' audio; the interruption only happens when the user truly starts
|
|
51
|
+
// playback, which is correct. Keyed off play *state*, not `playWhenReady`, because the intent
|
|
52
|
+
// can be set at setup (before any track) while output only begins here. Idempotent:
|
|
53
|
+
// `setActive(true)` is a no-op when the session is already active.
|
|
54
|
+
if state.playing || state.buffering {
|
|
55
|
+
audioSession.activate()
|
|
56
|
+
// The now-playing session's activation request at link time predates this
|
|
57
|
+
// (the audio session was still inactive, and the system may have declined);
|
|
58
|
+
// re-request now so the surface can appear even if playback never produces
|
|
59
|
+
// audio (first-ever load failing on a dead stream).
|
|
60
|
+
engine?.reactivateNowPlayingSession()
|
|
61
|
+
}
|
|
62
|
+
// A stall starting or recovering may not change the Player state.
|
|
63
|
+
engine?.nowPlayingUpdater.render()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
public func playerShouldReleaseSession() {
|
|
67
|
+
audioSession.scheduleRelease()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
public func playerDidEndQueue(_ event: PlaybackQueueEndedEvent) {
|
|
71
|
+
onPlaybackQueueEnded(event)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
public func playerDidChangeQueue(_ tracks: [Track]) {
|
|
75
|
+
queueChangedEmitter.emit(tracks)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
public func playerDidChangeRepeatMode(_ event: RepeatModeChangedEvent) {
|
|
79
|
+
repeatModeChangedEmitter.emit(event)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
public func playerDidChangeShuffleEnabled(_ enabled: Bool) {
|
|
83
|
+
shuffleChangedEmitter.emit(enabled)
|
|
84
|
+
onPlaybackShuffleModeChanged(enabled)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
public func playerDidError(_ event: PlaybackErrorEvent) {
|
|
88
|
+
onPlaybackError(event)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
public func playerDidChangeSleepTimer(_ state: SleepTimer?) {
|
|
92
|
+
onSleepTimerChanged(state)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
public func playerDidChangeNowPlaying(_ metadata: NowPlayingMetadata) {
|
|
96
|
+
onNowPlayingChanged(metadata)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
public func playerDidReceiveCommonMetadata(_ items: [AVMetadataItem]) {
|
|
100
|
+
let metadata = TrackMetadata.from(items: items)
|
|
101
|
+
onTrackMetadata(metadata)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public func playerDidReceiveTimedMetadata(_ groups: [AVTimedMetadataGroup]) {
|
|
105
|
+
for group in groups {
|
|
106
|
+
if let metadata = TimedMetadata.from(items: group.items, icyCharset: player?.currentTrack?.icyCharset) {
|
|
107
|
+
onTimedMetadata(metadata)
|
|
108
|
+
engine?.nowPlayingUpdater.receivedTimedMetadata(metadata)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public func playerDidReceiveChapterMetadata(_ groups: [AVTimedMetadataGroup]) {
|
|
114
|
+
let chapters = ChapterMetadata.from(groups: groups)
|
|
115
|
+
onChapterMetadata(chapters)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public func remotePlay() {
|
|
119
|
+
dispatchRemote(handler: handleRemotePlay, report: onRemotePlay) { player?.play() }
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public func remotePause() {
|
|
123
|
+
dispatchRemote(handler: handleRemotePause, report: onRemotePause) { player?.pause() }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public func remoteStop() {
|
|
127
|
+
dispatchRemote(handler: handleRemoteStop, report: onRemoteStop) { player?.stop() }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
public func remotePlayPause() {
|
|
131
|
+
if player?.playWhenReady == true { remotePause() } else { remotePlay() }
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
public func remoteNext() {
|
|
135
|
+
dispatchRemote(handler: handleRemoteNext, report: onRemoteNext) { player?.next() }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public func remotePrevious() {
|
|
139
|
+
dispatchRemote(handler: handleRemotePrevious, report: onRemotePrevious) { player?.previous() }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public func remoteJumpForward(interval: Double) {
|
|
143
|
+
dispatchRemote(
|
|
144
|
+
RemoteJumpForwardEvent(interval: interval), handler: handleRemoteJumpForward, report: onRemoteJumpForward,
|
|
145
|
+
) { player?.seek(by: interval) }
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public func remoteJumpBackward(interval: Double) {
|
|
149
|
+
dispatchRemote(
|
|
150
|
+
RemoteJumpBackwardEvent(interval: interval), handler: handleRemoteJumpBackward, report: onRemoteJumpBackward,
|
|
151
|
+
) { player?.seek(by: -interval) }
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
public func remoteSeek(position: Double) {
|
|
155
|
+
dispatchRemote(RemoteSeekEvent(position: position), handler: handleRemoteSeek, report: onRemoteSeek) {
|
|
156
|
+
player?.seek(to: position)
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/// Runs JS's override for a remote command when it set one, else `fallback`, then reports
|
|
161
|
+
/// the command to JS.
|
|
162
|
+
private func dispatchRemote(handler: (() -> Void)?, report: () -> Void, fallback: () -> Void) {
|
|
163
|
+
if let handler { handler() } else { fallback() }
|
|
164
|
+
report()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private func dispatchRemote<Event>(
|
|
168
|
+
_ event: Event,
|
|
169
|
+
handler: ((Event) -> Void)?,
|
|
170
|
+
report: (Event) -> Void,
|
|
171
|
+
fallback: () -> Void,
|
|
172
|
+
) {
|
|
173
|
+
if let handler { handler(event) } else { fallback() }
|
|
174
|
+
report(event)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public func remoteChangeRepeatMode(mode: RepeatMode) {
|
|
178
|
+
// Apply the repeat mode change from CarPlay/lock screen
|
|
179
|
+
try? setRepeatMode(mode: mode)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
public func remoteChangeShuffleMode(enabled: Bool) {
|
|
183
|
+
// Apply the shuffle mode change from CarPlay/lock screen
|
|
184
|
+
try? setShuffleEnabled(enabled: enabled)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
public func remoteChangePlaybackRate(rate: Float) {
|
|
188
|
+
player?.rate = rate
|
|
189
|
+
}
|
|
190
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import AVFoundation
|
|
2
|
+
import AVKit
|
|
3
|
+
import Foundation
|
|
4
|
+
import MediaPlayer
|
|
5
|
+
import NitroModules
|
|
6
|
+
import os.log
|
|
7
|
+
|
|
8
|
+
public extension HybridAudioBrowser {
|
|
9
|
+
// MARK: - Equalizer (unsupported on iOS)
|
|
10
|
+
|
|
11
|
+
func getEqualizerSettings() throws -> EqualizerSettings? {
|
|
12
|
+
// No-op: equalizer unsupported on iOS
|
|
13
|
+
nil
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
func setEqualizerEnabled(enabled _: Bool) throws {
|
|
17
|
+
// No-op: equalizer unsupported on iOS
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
func setEqualizerPreset(preset _: String) throws {
|
|
21
|
+
// No-op: equalizer unsupported on iOS
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
func setEqualizerLevels(levels _: [Double]) throws {
|
|
25
|
+
// No-op: equalizer unsupported on iOS
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// MARK: - Battery (Android-only, stub implementations)
|
|
29
|
+
|
|
30
|
+
func getBatteryWarningPending() throws -> Bool {
|
|
31
|
+
false
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
func getBatteryOptimizationStatus() throws -> BatteryOptimizationStatus {
|
|
35
|
+
// iOS doesn't have battery optimization restrictions like Android
|
|
36
|
+
.unrestricted
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
func dismissBatteryWarning() throws {
|
|
40
|
+
// No-op on iOS
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
func openBatterySettings() throws {
|
|
44
|
+
// No-op on iOS
|
|
45
|
+
}
|
|
46
|
+
}
|