react-native-queue-player 1.2.0 → 2.0.1
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/QueuePlayer.podspec +14 -9
- package/README.md +3 -3
- package/android/consumer-rules.pro +1 -1
- package/android/src/main/cpp/airplay2_control.c +4 -4
- package/android/src/main/cpp/airplay2_control.h +4 -4
- package/android/src/main/cpp/airplay2_jni.cpp +3 -19
- package/android/src/main/cpp/airplay2_pair.c +7 -7
- package/android/src/main/cpp/airplay2_pair.h +2 -2
- package/android/src/main/cpp/airplay2_rtsp.c +8 -8
- package/android/src/main/cpp/airplay2_session.c +2 -2
- package/android/src/main/cpp/airplay_jni.cpp +8 -69
- package/android/src/main/java/com/margelo/nitro/queueplayer/AirPlayEngine.kt +7 -16
- package/android/src/main/java/com/margelo/nitro/queueplayer/CacheMimeTypes.kt +1 -1
- package/android/src/main/java/com/margelo/nitro/queueplayer/CastManager.kt +2 -14
- package/android/src/main/java/com/margelo/nitro/queueplayer/CellularTransportMonitor.kt +77 -0
- package/android/src/main/java/com/margelo/nitro/queueplayer/CrossfadeEngine.kt +187 -52
- package/android/src/main/java/com/margelo/nitro/queueplayer/Equalizer.kt +27 -7
- package/android/src/main/java/com/margelo/nitro/queueplayer/EqualizerEngine.kt +33 -12
- package/android/src/main/java/com/margelo/nitro/queueplayer/EqualizerLegacyEngine.kt +31 -8
- package/android/src/main/java/com/margelo/nitro/queueplayer/FFTProcessorTee.kt +45 -30
- package/android/src/main/java/com/margelo/nitro/queueplayer/FifoCacheEvictor.kt +111 -15
- package/android/src/main/java/com/margelo/nitro/queueplayer/GaplessEngine.kt +60 -33
- package/android/src/main/java/com/margelo/nitro/queueplayer/HeadlessJsMediaService.kt +1 -1
- package/android/src/main/java/com/margelo/nitro/queueplayer/IEqualizerEngine.kt +3 -1
- package/android/src/main/java/com/margelo/nitro/queueplayer/LookaheadCache.kt +111 -29
- package/android/src/main/java/com/margelo/nitro/queueplayer/LookaheadCacheWriter.kt +78 -30
- package/android/src/main/java/com/margelo/nitro/queueplayer/MediaItemBuilder.kt +6 -6
- package/android/src/main/java/com/margelo/nitro/queueplayer/MediaResponseCheck.kt +156 -0
- package/android/src/main/java/com/margelo/nitro/queueplayer/MediaValidatingDataSource.kt +165 -0
- package/android/src/main/java/com/margelo/nitro/queueplayer/MimeCapturingDataSource.kt +18 -9
- package/android/src/main/java/com/margelo/nitro/queueplayer/NowPlayingFormatExtractor.kt +48 -1
- package/android/src/main/java/com/margelo/nitro/queueplayer/PitchCorrection.kt +3 -2
- package/android/src/main/java/com/margelo/nitro/queueplayer/PlaybackEngine.kt +71 -76
- package/android/src/main/java/com/margelo/nitro/queueplayer/PlaybackErrorMapping.kt +13 -5
- package/android/src/main/java/com/margelo/nitro/queueplayer/PlaybackModeStateMachine.kt +2 -2
- package/android/src/main/java/com/margelo/nitro/queueplayer/PlaybackService.kt +68 -46
- package/android/src/main/java/com/margelo/nitro/queueplayer/PlaybackServiceCallback.kt +6 -5
- package/android/src/main/java/com/margelo/nitro/queueplayer/QueueMutationArithmetic.kt +5 -6
- package/android/src/main/java/com/margelo/nitro/queueplayer/QueueSkipArithmetic.kt +11 -8
- package/android/src/main/java/com/margelo/nitro/queueplayer/ReplayGainAudioProcessor.kt +26 -6
- package/android/src/main/java/com/margelo/nitro/queueplayer/ReplayGainData.kt +22 -3
- package/android/src/main/java/com/margelo/nitro/queueplayer/ReplayGainExtractor.kt +38 -12
- package/android/src/main/java/com/margelo/nitro/queueplayer/ReplayGainGain.kt +17 -13
- package/android/src/main/java/com/margelo/nitro/queueplayer/SuppliedReplayGain.kt +66 -0
- package/android/src/main/java/com/margelo/nitro/queueplayer/TrackPlayer.kt +985 -276
- package/android/src/main/java/com/margelo/nitro/queueplayer/Visualizer.kt +4 -8
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/CastBackend.kt +4 -3
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/CastSession.kt +5 -4
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/airplay/AirPlay2JNI.kt +0 -2
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/airplay/AirPlay2Session.kt +4 -2
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/airplay/AirPlayBackend.kt +16 -9
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/airplay/AirPlayMetadataSync.kt +1 -1
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/airplay/AirPlayRenderersFactory.kt +6 -14
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/airplay/AirplayJNI.kt +1 -13
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/airplay/MulticastLockHolder.kt +1 -1
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/chromecast/ChromecastBackend.kt +3 -3
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/http/LocalMediaServer.kt +11 -35
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/http/MediaServerHandle.kt +0 -5
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/http/MediaTokenRegistry.kt +0 -6
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/net/LocalAddressMonitor.kt +32 -33
- package/android/src/test/java/androidx/media3/session/{MediaSessionControllerRequestTestSeam.kt → MediaSessionControllerRequestTestSupport.kt} +1 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/AvrcpMetadataTest.kt +12 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/CrossfadeEngineFocusLossTest.kt +115 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/CrossfadeEngineLifecycleTest.kt +45 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/EngineEndSignalOrderTest.kt +70 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/EqualizerEngineTest.kt +17 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/EqualizerKtTest.kt +0 -6
- package/android/src/test/java/com/margelo/nitro/queueplayer/EqualizerLegacyEngineTest.kt +17 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/FFTProcessorTeeTest.kt +15 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/FifoCacheEvictorTest.kt +135 -4
- package/android/src/test/java/com/margelo/nitro/queueplayer/GaplessEngineLifecycleTest.kt +1 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/GaplessEngineReplayGainTest.kt +36 -2
- package/android/src/test/java/com/margelo/nitro/queueplayer/LookaheadCacheTest.kt +84 -18
- package/android/src/test/java/com/margelo/nitro/queueplayer/LookaheadCacheWriterCancelTest.kt +85 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/LookaheadCacheWriterTest.kt +112 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/MediaItemBuilderTest.kt +5 -3
- package/android/src/test/java/com/margelo/nitro/queueplayer/MediaResponseCheckTest.kt +163 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/MediaValidatingDataSourceTest.kt +189 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/NowPlayingFormatExtractorTest.kt +45 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/PitchAwareAudioProcessorChainTest.kt +1 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/PlaybackServiceCallbackSearchTest.kt +47 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/PlaybackServiceCallbackTest.kt +53 -29
- package/android/src/test/java/com/margelo/nitro/queueplayer/PlaybackServiceLifecycleTest.kt +8 -8
- package/android/src/test/java/com/margelo/nitro/queueplayer/QueueSkipArithmeticTest.kt +33 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/ReplayGainAudioProcessorTest.kt +128 -5
- package/android/src/test/java/com/margelo/nitro/queueplayer/ReplayGainExtractorTest.kt +209 -14
- package/android/src/test/java/com/margelo/nitro/queueplayer/ReplayGainGainTest.kt +150 -10
- package/android/src/test/java/com/margelo/nitro/queueplayer/ReplayGainMergeTest.kt +258 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/RobolectricServiceBindHelper.kt +2 -2
- package/android/src/test/java/com/margelo/nitro/queueplayer/SessionCommandForwardingPlayerTest.kt +2 -2
- package/android/src/test/java/com/margelo/nitro/queueplayer/ShadowDynamicsProcessingRejectingEnable.kt +19 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/ShadowEqualizer.kt +1 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/ShadowEqualizerRejectingBandWrites.kt +27 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/SuppliedReplayGainTest.kt +61 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerAirPlayMetadataWiringTest.kt +4 -4
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerAudioFocusTest.kt +1 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerCastCommandRoutingTest.kt +2 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerCastStateTest.kt +2 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerEventsTest.kt +122 -38
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerLifecycleTest.kt +291 -27
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerLookaheadConfigTest.kt +277 -38
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerMutationTest.kt +5 -3
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerProgressThrottleTest.kt +2 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerQueueChangeTest.kt +85 -3
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerQueueTest.kt +11 -7
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerReadersTest.kt +2 -1
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerSkipCapabilityTest.kt +90 -4
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerSkipTest.kt +8 -26
- package/android/src/test/java/com/margelo/nitro/queueplayer/TrackPlayerTransportTest.kt +3 -3
- package/android/src/test/java/com/margelo/nitro/queueplayer/VisualizerKtTest.kt +0 -4
- package/android/src/test/java/com/margelo/nitro/queueplayer/cast/FakeRemotePlayer.kt +2 -2
- package/android/src/test/java/com/margelo/nitro/queueplayer/cast/net/LocalAddressMonitorTest.kt +173 -0
- package/android/src/test/java/com/margelo/nitro/queueplayer/cast/net/ShadowConnectivityManagerRecordingRequests.kt +27 -0
- package/app.plugin.js +17 -1
- package/ios/AVPlayerItemQueueItemId.swift +26 -12
- package/ios/AVQueueBuilder.swift +120 -85
- package/ios/ArtworkLoader.swift +0 -7
- package/ios/ArtworkResolver.swift +22 -4
- package/ios/AssetReplayGainReader.swift +118 -0
- package/ios/AudioSession.swift +67 -16
- package/ios/AudioTapProvider.swift +284 -149
- package/ios/CarPlayBridge.swift +0 -12
- package/ios/CarPlayCoordinator.swift +18 -2
- package/ios/CarPlaySceneDelegate.swift +2 -2
- package/ios/Cast/AirPlayRouteState.swift +9 -8
- package/ios/Cast/Core/CastEventBridge.swift +66 -26
- package/ios/Cast/Core/CastNowPlayingController.swift +38 -16
- package/ios/Cast/Core/CastSession.swift +2 -2
- package/ios/Cast/Core/CastTransportRouter.swift +21 -9
- package/ios/Cast/Core/LocalMediaServer.swift +41 -52
- package/ios/Cast/Core/LocalNetworkPermissionProbe.swift +32 -11
- package/ios/Cast/Core/MediaServerHandle.swift +0 -4
- package/ios/Cast/Core/MediaTokenRegistry.swift +0 -6
- package/ios/CastManager.swift +1 -1
- package/ios/CrossfadeEngine.swift +672 -226
- package/ios/EQTap.swift +20 -17
- package/ios/Equalizer.swift +1 -1
- package/ios/FLACStreamInfo.swift +65 -0
- package/ios/GaplessEngine.swift +57 -30
- package/ios/InputGuards.swift +35 -5
- package/ios/LookaheadCache.swift +229 -58
- package/ios/LookaheadCachePrefetcher.swift +48 -36
- package/ios/MediaResponseCheck.swift +122 -0
- package/ios/MediaServer/MediaHTTPConnection.swift +691 -0
- package/ios/NetworkRecoveryPolicy.swift +32 -0
- package/ios/NowPlayingFormatExtractor.swift +25 -18
- package/ios/NowPlayingInfo.swift +84 -48
- package/ios/OutputRouteMonitor.swift +16 -3
- package/ios/PendingBrowseRequests.swift +1 -1
- package/ios/PlaceholderArtwork.swift +9 -5
- package/ios/PlaybackEngine.swift +165 -76
- package/ios/PlaybackErrorMapping.swift +3 -3
- package/ios/PlaybackModeStateMachine.swift +2 -2
- package/ios/PlaybackNetworkMonitor.swift +73 -0
- package/ios/PlayerStateDerivation.swift +6 -6
- package/ios/QueueMutationArithmetic.swift +25 -0
- package/ios/QueueSkipArithmetic.swift +5 -3
- package/ios/QueueWindowArithmetic.swift +152 -0
- package/ios/ReadThroughServer.swift +283 -0
- package/ios/RemoteCommands.swift +44 -4
- package/ios/ReplayGainData.swift +22 -3
- package/ios/ReplayGainExtractor.swift +70 -27
- package/ios/Siri/VoiceDonation.swift +14 -9
- package/ios/StreamingBitrateProbe.swift +22 -68
- package/ios/SuppliedReplayGain.swift +83 -0
- package/ios/Tests/AVQueueBuilderTests.swift +158 -221
- package/ios/Tests/ActiveItemEngineStub.swift +44 -0
- package/ios/Tests/AssetReplayGainReaderTests.swift +228 -0
- package/ios/Tests/AudioTapProviderDispatchTargetTests.swift +158 -0
- package/ios/Tests/AudioTapProviderReplayGainTests.swift +122 -10
- package/ios/Tests/BitrateReresolveBudgetTests.swift +71 -0
- package/ios/Tests/CastMediaItemTranslationTests.swift +72 -0
- package/ios/Tests/CastNowPlayingControllerTests.swift +1 -1
- package/ios/Tests/CrossfadeAdvanceWithoutFadeTests.swift +120 -0
- package/ios/Tests/CrossfadeEngineIncomingMixTests.swift +122 -0
- package/ios/Tests/CrossfadeEngineTests.swift +164 -0
- package/ios/Tests/CrossfadeMixReapplyTests.swift +66 -0
- package/ios/Tests/CrossfadePlaybackIntentTests.swift +81 -0
- package/ios/Tests/EngineSwapTests.swift +91 -0
- package/ios/Tests/EqualizerAudioMixProviderTests.swift +46 -0
- package/ios/Tests/EqualizerHybridTests.swift +5 -2
- package/ios/Tests/FLACStreamInfoTests.swift +88 -0
- package/ios/Tests/GaplessEngineLifecycleTests.swift +4 -4
- package/ios/Tests/InputGuardsTests.swift +41 -0
- package/ios/Tests/InterruptionIntentTests.swift +77 -0
- package/ios/Tests/LookaheadCacheCellularAccessTests.swift +185 -0
- package/ios/Tests/LookaheadCachePrefetcherTests.swift +53 -30
- package/ios/Tests/LookaheadCacheRuntimeConfigTests.swift +160 -1
- package/ios/Tests/LookaheadCacheTests.swift +44 -18
- package/ios/Tests/MediaHTTPConnectionTests.swift +79 -0
- package/ios/Tests/MediaResponseCheckTests.swift +128 -0
- package/ios/Tests/MutationDeferralTests.swift +220 -0
- package/ios/Tests/NowPlayingInfoTests.swift +86 -99
- package/ios/Tests/NowPlayingSnapshotTests.swift +127 -0
- package/ios/Tests/OriginRestartStitcherTests.swift +60 -0
- package/ios/Tests/PlaybackNetworkMonitorTests.swift +95 -0
- package/ios/Tests/PlayerFixtures.swift +48 -0
- package/ios/Tests/PlayerStateDerivationTests.swift +10 -10
- package/ios/Tests/QueueMutationGenerationTests.swift +141 -0
- package/ios/Tests/QueueRebuildPrefixTests.swift +317 -0
- package/ios/Tests/QueueStateTests.swift +3 -1
- package/ios/Tests/QueueWindowArithmeticTests.swift +56 -0
- package/ios/Tests/QueueWindowSliceTests.swift +162 -0
- package/ios/Tests/ReadThroughRoutingLifecycleTests.swift +63 -0
- package/ios/Tests/ReadThroughServerTests.swift +345 -0
- package/ios/Tests/RemoteCommandsTests.swift +28 -0
- package/ios/Tests/ReplayGainExtractorTests.swift +216 -6
- package/ios/Tests/ReplayGainMergeTests.swift +230 -0
- package/ios/Tests/RetryRecoveryTests.swift +418 -0
- package/ios/Tests/SkipCapabilityTests.swift +233 -8
- package/ios/Tests/SkipIndexTests.swift +32 -2
- package/ios/Tests/SleepTimerPauseIntentTests.swift +43 -0
- package/ios/Tests/StallRecoveryTests.swift +97 -0
- package/ios/Tests/StreamingBitrateProbeTests.swift +17 -20
- package/ios/Tests/TopUpWindowGateTests.swift +441 -0
- package/ios/Tests/TrackPlayer+TestHops.swift +14 -0
- package/ios/Tests/TrackPlayerCallOrderTests.swift +93 -0
- package/ios/Tests/TrackPlayerConfigureTeardownTests.swift +86 -0
- package/ios/Tests/TrackPlayerEndVerdictTests.swift +206 -0
- package/ios/Tests/TrackPlayerSeekTests.swift +137 -0
- package/ios/Tests/TrackPlayerThreadingTests.swift +127 -0
- package/ios/Tests/TrackSourceClassifierTests.swift +33 -7
- package/ios/Tests/VoiceVocabularyOptInTests.swift +38 -0
- package/ios/TrackPlayer+Automotive.swift +101 -0
- package/ios/TrackPlayer+Cache.swift +232 -0
- package/ios/TrackPlayer+Config.swift +291 -0
- package/ios/TrackPlayer+EngineDelegate.swift +209 -0
- package/ios/TrackPlayer+EventsAPI.swift +111 -0
- package/ios/TrackPlayer+EventsDispatch.swift +1042 -0
- package/ios/TrackPlayer+EventsWiring.swift +173 -0
- package/ios/TrackPlayer+Lifecycle.swift +982 -0
- package/ios/TrackPlayer+NowPlayingFormat.swift +258 -0
- package/ios/TrackPlayer+Queue.swift +951 -0
- package/ios/TrackPlayer+Recovery.swift +213 -0
- package/ios/TrackPlayer+Skip.swift +465 -0
- package/ios/TrackPlayer+SleepTimer.swift +175 -0
- package/ios/TrackPlayer+State.swift +108 -0
- package/ios/TrackPlayer+Threading.swift +135 -0
- package/ios/TrackPlayer+Transport.swift +272 -0
- package/ios/TrackPlayer+Window.swift +227 -0
- package/ios/TrackPlayer.swift +331 -4619
- package/ios/Visualizer.swift +6 -5
- package/ios/tests-harness/Podfile +1 -1
- package/ios/tests-harness/TestHost.xcodeproj/project.pbxproj +19 -11
- package/ios/tests-harness/scripts/seed-xcodeproj.rb +2 -2
- package/lib/module/hooks/useActiveTrack.js +29 -22
- package/lib/module/hooks/useActiveTrack.js.map +1 -1
- package/lib/module/hooks/useCast.js +8 -26
- package/lib/module/hooks/useCast.js.map +1 -1
- package/lib/module/hooks/useEqualizer.js +19 -12
- package/lib/module/hooks/useEqualizer.js.map +1 -1
- package/lib/module/hooks/useLookaheadCache.js +3 -7
- package/lib/module/hooks/useLookaheadCache.js.map +1 -1
- package/lib/module/hooks/useQueue.js +66 -19
- package/lib/module/hooks/useQueue.js.map +1 -1
- package/lib/module/index.js +6 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/queueDelta.js +41 -0
- package/lib/module/queueDelta.js.map +1 -0
- package/lib/module/types.js +28 -5
- package/lib/module/types.js.map +1 -1
- package/lib/typescript/TrackPlayer.nitro.d.ts +53 -28
- package/lib/typescript/TrackPlayer.nitro.d.ts.map +1 -1
- package/lib/typescript/hooks/useActiveTrack.d.ts +5 -7
- package/lib/typescript/hooks/useActiveTrack.d.ts.map +1 -1
- package/lib/typescript/hooks/useCast.d.ts +6 -1
- package/lib/typescript/hooks/useCast.d.ts.map +1 -1
- package/lib/typescript/hooks/useEqualizer.d.ts +2 -1
- package/lib/typescript/hooks/useEqualizer.d.ts.map +1 -1
- package/lib/typescript/hooks/useLookaheadCache.d.ts.map +1 -1
- package/lib/typescript/hooks/useQueue.d.ts +4 -4
- package/lib/typescript/hooks/useQueue.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -1
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/queueDelta.d.ts +10 -0
- package/lib/typescript/queueDelta.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +168 -12
- package/lib/typescript/types.d.ts.map +1 -1
- package/nitrogen/generated/android/c++/JFunc_void_QueueChangeDelta_double_QueueChangeReason.hpp +85 -0
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.cpp +45 -19
- package/nitrogen/generated/android/c++/JHybridTrackPlayerSpec.hpp +3 -3
- package/nitrogen/generated/android/c++/JLookaheadCacheConfig.hpp +8 -4
- package/nitrogen/generated/android/c++/JPlayerConfig.hpp +5 -1
- package/nitrogen/generated/android/c++/JQueueChangeDelta.hpp +128 -0
- package/nitrogen/generated/android/c++/JTrackItem.hpp +19 -3
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_BrowseItem______std__string.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_TrackItem______MediaSearchRequest.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_TrackItem______std__string.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_AudioRoute.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_BufferState.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_CacheStatus.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_CastDiscoveryState.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_CastLocalNetworkPermissionEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_CastRoute.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_CastSessionDiedEvent.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_PlaybackError.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_PlayerProgress.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_PlayerState_StateChangeReason.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/{Func_void_std__vector_TrackItem__double_QueueChangeReason.kt → Func_void_QueueChangeDelta_double_QueueChangeReason.kt} +14 -16
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_ServiceReadyReason.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_SkipCapability.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_SleepTimerState.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_VisualizerErrorReason.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_VisualizerFrame.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_bool.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_double_double.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_std__optional_TrackItem__double_TrackChangeReason_std__optional_double_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_std__optional_std__variant_nitro__NullType__NowPlayingFormat__.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_std__vector_CastReceiver_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/Func_void_std__vector_EqualizerBand_.kt +0 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/HybridCastManagerSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/HybridEqualizerSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/HybridTrackPlayerSpec.kt +6 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/HybridVisualizerSpec.kt +2 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/LookaheadCacheConfig.kt +9 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/PlayerConfig.kt +7 -2
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/QueueChangeDelta.kt +86 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/queueplayer/TrackItem.kt +24 -4
- package/nitrogen/generated/android/queueplayerOnLoad.cpp +2 -2
- package/nitrogen/generated/ios/QueuePlayer-Swift-Cxx-Bridge.cpp +16 -16
- package/nitrogen/generated/ios/QueuePlayer-Swift-Cxx-Bridge.hpp +80 -65
- package/nitrogen/generated/ios/QueuePlayer-Swift-Cxx-Umbrella.hpp +3 -0
- package/nitrogen/generated/ios/c++/HybridTrackPlayerSpecSwift.hpp +6 -3
- package/nitrogen/generated/ios/swift/Func_void_CacheStatus.swift +5 -5
- package/nitrogen/generated/ios/swift/Func_void_QueueChangeDelta_double_QueueChangeReason.swift +46 -0
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec.swift +3 -3
- package/nitrogen/generated/ios/swift/HybridTrackPlayerSpec_cxx.swift +32 -24
- package/nitrogen/generated/ios/swift/LookaheadCacheConfig.swift +20 -2
- package/nitrogen/generated/ios/swift/PlayerConfig.swift +19 -1
- package/nitrogen/generated/ios/swift/QueueChangeDelta.swift +82 -0
- package/nitrogen/generated/ios/swift/TrackItem.swift +73 -1
- package/nitrogen/generated/shared/c++/HybridTrackPlayerSpec.hpp +6 -3
- package/nitrogen/generated/shared/c++/LookaheadCacheConfig.hpp +7 -3
- package/nitrogen/generated/shared/c++/PlayerConfig.hpp +5 -1
- package/nitrogen/generated/shared/c++/QueueChangeDelta.hpp +113 -0
- package/nitrogen/generated/shared/c++/TrackItem.hpp +18 -2
- package/package.json +8 -8
- package/src/TrackPlayer.nitro.ts +53 -27
- package/src/hooks/useActiveTrack.ts +29 -22
- package/src/hooks/useCast.ts +14 -15
- package/src/hooks/useEqualizer.ts +19 -12
- package/src/hooks/useLookaheadCache.ts +3 -7
- package/src/hooks/useQueue.ts +66 -17
- package/src/index.ts +13 -3
- package/src/queueDelta.ts +41 -0
- package/src/types.ts +169 -12
- package/android/src/main/java/com/margelo/nitro/queueplayer/PendingIntentBuffer.kt +0 -82
- package/android/src/main/java/com/margelo/nitro/queueplayer/cast/http/LocalMediaServerLifecycle.kt +0 -15
- package/android/src/test/java/com/margelo/nitro/queueplayer/PendingIntentBufferTest.kt +0 -192
- package/android/src/test/java/com/margelo/nitro/queueplayer/PlaybackEngineInterfaceTest.kt +0 -135
- package/android/src/test/java/com/margelo/nitro/queueplayer/SmokeTest.kt +0 -27
- package/ios/Cast/Core/LocalAddressMonitor.swift +0 -110
- package/ios/Cast/Core/MediaHTTPConnection.swift +0 -349
- package/ios/MetadataReader.swift +0 -555
- package/ios/Tests/CrossfadeEngineStubTests.swift +0 -43
- package/ios/Tests/MetadataReaderTests.swift +0 -603
- package/ios/Tests/PlaybackEngineProtocolTests.swift +0 -92
- package/ios/Tests/VoiceDonationTests.swift +0 -26
- package/nitrogen/generated/android/c++/JFunc_void_std__vector_TrackItem__double_QueueChangeReason.hpp +0 -101
- package/nitrogen/generated/ios/swift/Func_void_std__vector_TrackItem__double_QueueChangeReason.swift +0 -46
- /package/ios/{Cast/Core → MediaServer}/MimeTypes.swift +0 -0
|
@@ -36,6 +36,32 @@ final class ReplayGainExtractorTests: XCTestCase {
|
|
|
36
36
|
XCTAssertEqual(actual, expected, accuracy: accuracy, file: file, line: line)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
private func assertAcceptedGain(
|
|
40
|
+
_ value: Double,
|
|
41
|
+
expected: Double,
|
|
42
|
+
accuracy: Double = 0.001,
|
|
43
|
+
file: StaticString = #file, line: UInt = #line
|
|
44
|
+
) {
|
|
45
|
+
guard let actual = ReplayGainExtractor.acceptGainDb(value) else {
|
|
46
|
+
XCTFail("expected acceptGainDb(\(value)) to succeed", file: file, line: line)
|
|
47
|
+
return
|
|
48
|
+
}
|
|
49
|
+
XCTAssertEqual(actual, expected, accuracy: accuracy, file: file, line: line)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private func assertAcceptedPeak(
|
|
53
|
+
_ value: Double,
|
|
54
|
+
expected: Double,
|
|
55
|
+
accuracy: Double = 0.0001,
|
|
56
|
+
file: StaticString = #file, line: UInt = #line
|
|
57
|
+
) {
|
|
58
|
+
guard let actual = ReplayGainExtractor.acceptPeak(value) else {
|
|
59
|
+
XCTFail("expected acceptPeak(\(value)) to succeed", file: file, line: line)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
XCTAssertEqual(actual, expected, accuracy: accuracy, file: file, line: line)
|
|
63
|
+
}
|
|
64
|
+
|
|
39
65
|
// MARK: - parseGainDb tolerance
|
|
40
66
|
|
|
41
67
|
func testParseGainDbStandardFormat() {
|
|
@@ -94,7 +120,7 @@ final class ReplayGainExtractorTests: XCTestCase {
|
|
|
94
120
|
XCTAssertNil(ReplayGainExtractor.parseGainDb("-inf"))
|
|
95
121
|
}
|
|
96
122
|
|
|
97
|
-
// MARK: - parsePeak tolerance +
|
|
123
|
+
// MARK: - parsePeak tolerance + plausible-range guards
|
|
98
124
|
|
|
99
125
|
func testParsePeakStandardLinear() {
|
|
100
126
|
assertPeak("0.987654", expected: 0.987654)
|
|
@@ -102,17 +128,47 @@ final class ReplayGainExtractorTests: XCTestCase {
|
|
|
102
128
|
assertPeak("1.234567", expected: 1.234567)
|
|
103
129
|
}
|
|
104
130
|
|
|
105
|
-
func
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
131
|
+
func testPeakAtFullScaleIsAccepted() {
|
|
132
|
+
// 1.000000 is the spec's encoding of digital full scale — a real
|
|
133
|
+
// measurement for a modern master, and the one most in need of the
|
|
134
|
+
// 1/peak clip cap.
|
|
135
|
+
assertPeak("1.000000", expected: 1.0)
|
|
136
|
+
assertPeak("1", expected: 1.0)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
func testParsePeakRejectsEncoderZero() {
|
|
110
140
|
XCTAssertNil(ReplayGainExtractor.parsePeak("0.0001"),
|
|
111
141
|
"peak < 0.001 means encoder zero / no analysis")
|
|
112
142
|
XCTAssertNil(ReplayGainExtractor.parsePeak("0"),
|
|
113
143
|
"peak == 0 means encoder zero")
|
|
114
144
|
}
|
|
115
145
|
|
|
146
|
+
func testParsePeakAcceptsRealMeasurementsEitherSideOfUnity() {
|
|
147
|
+
assertPeak("0.923366", expected: 0.923366)
|
|
148
|
+
assertPeak("1.160082", expected: 1.160082)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
func testParsePeakAcceptsTheLowerBoundary() {
|
|
152
|
+
assertPeak("0.001", expected: 0.001, accuracy: 0.000001)
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
func testParsePeakRejectsJustBelowTheLowerBoundary() {
|
|
156
|
+
XCTAssertNil(ReplayGainExtractor.parsePeak("0.000999"))
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
func testParsePeakAcceptsTheUpperBoundary() {
|
|
160
|
+
assertPeak("2.0", expected: 2.0)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
func testParsePeakRejectsJustAboveTheUpperBoundary() {
|
|
164
|
+
XCTAssertNil(ReplayGainExtractor.parsePeak("2.000001"))
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
func testParsePeakRejectsCommaDecimal() {
|
|
168
|
+
// RG2 is period-decimal, same as the gain path.
|
|
169
|
+
XCTAssertNil(ReplayGainExtractor.parsePeak("0,5"))
|
|
170
|
+
}
|
|
171
|
+
|
|
116
172
|
func testParsePeakRejectsOutOfRange() {
|
|
117
173
|
XCTAssertNil(ReplayGainExtractor.parsePeak("-0.5"))
|
|
118
174
|
XCTAssertNil(ReplayGainExtractor.parsePeak("3.0"))
|
|
@@ -189,4 +245,158 @@ final class ReplayGainExtractorTests: XCTestCase {
|
|
|
189
245
|
}
|
|
190
246
|
}
|
|
191
247
|
|
|
248
|
+
// MARK: - acceptPeak — the numeric half of the same rule
|
|
249
|
+
|
|
250
|
+
func testAcceptPeakAcceptsFullScale() {
|
|
251
|
+
assertAcceptedPeak(1.0, expected: 1.0)
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
func testAcceptPeakAcceptsTheBoundaries() {
|
|
255
|
+
assertAcceptedPeak(0.001, expected: 0.001, accuracy: 0.000001)
|
|
256
|
+
assertAcceptedPeak(2.0, expected: 2.0)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
func testAcceptPeakAcceptsRealMeasurementsEitherSideOfUnity() {
|
|
260
|
+
assertAcceptedPeak(0.923366, expected: 0.923366)
|
|
261
|
+
assertAcceptedPeak(1.160082, expected: 1.160082)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
func testAcceptPeakRejectsValuesOutsideTheBoundaries() {
|
|
265
|
+
// Paired with an accepted value so the test still fails against an
|
|
266
|
+
// acceptor that rejects everything.
|
|
267
|
+
assertAcceptedPeak(0.5, expected: 0.5)
|
|
268
|
+
XCTAssertNil(ReplayGainExtractor.acceptPeak(0.000999))
|
|
269
|
+
XCTAssertNil(ReplayGainExtractor.acceptPeak(2.000001))
|
|
270
|
+
XCTAssertNil(ReplayGainExtractor.acceptPeak(0.0))
|
|
271
|
+
XCTAssertNil(ReplayGainExtractor.acceptPeak(-0.5))
|
|
272
|
+
XCTAssertNil(ReplayGainExtractor.acceptPeak(3.0))
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
func testAcceptPeakRejectsNonFinite() {
|
|
276
|
+
assertAcceptedPeak(1.0, expected: 1.0)
|
|
277
|
+
XCTAssertNil(ReplayGainExtractor.acceptPeak(.nan))
|
|
278
|
+
XCTAssertNil(ReplayGainExtractor.acceptPeak(.infinity))
|
|
279
|
+
XCTAssertNil(ReplayGainExtractor.acceptPeak(-.infinity))
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// MARK: - acceptGainDb — the numeric half of the same rule
|
|
283
|
+
|
|
284
|
+
func testAcceptGainDbAcceptsAnyFiniteValue() {
|
|
285
|
+
assertAcceptedGain(-20.0, expected: -20.0)
|
|
286
|
+
assertAcceptedGain(-6.54, expected: -6.54)
|
|
287
|
+
assertAcceptedGain(0.0, expected: 0.0)
|
|
288
|
+
assertAcceptedGain(3.21, expected: 3.21)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
func testAcceptGainDbAppliesNoRangeGuard() {
|
|
292
|
+
// Unlike a peak, a gain has no plausible-value window — the only
|
|
293
|
+
// rejection is non-finite.
|
|
294
|
+
assertAcceptedGain(100.0, expected: 100.0)
|
|
295
|
+
assertAcceptedGain(-100.0, expected: -100.0)
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
func testAcceptGainDbRejectsNonFinite() {
|
|
299
|
+
assertAcceptedGain(-6.0, expected: -6.0)
|
|
300
|
+
XCTAssertNil(ReplayGainExtractor.acceptGainDb(.nan))
|
|
301
|
+
XCTAssertNil(ReplayGainExtractor.acceptGainDb(.infinity))
|
|
302
|
+
XCTAssertNil(ReplayGainExtractor.acceptGainDb(-.infinity))
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// MARK: - One rule, two entry points
|
|
306
|
+
|
|
307
|
+
func testPeakStringAndNumericPathsAgree() {
|
|
308
|
+
// The string parser is the numeric acceptor plus text handling, so
|
|
309
|
+
// every value that has both representations must land identically.
|
|
310
|
+
let cases: [(String, Double)] = [
|
|
311
|
+
("1.000000", 1.0),
|
|
312
|
+
("1", 1.0),
|
|
313
|
+
("0.923366", 0.923366),
|
|
314
|
+
("1.160082", 1.160082),
|
|
315
|
+
("0.5", 0.5),
|
|
316
|
+
("2.0", 2.0),
|
|
317
|
+
("2.000001", 2.000001),
|
|
318
|
+
("0.001", 0.001),
|
|
319
|
+
("0.000999", 0.000999),
|
|
320
|
+
("0", 0.0),
|
|
321
|
+
("-0.5", -0.5),
|
|
322
|
+
("3.0", 3.0),
|
|
323
|
+
("nan", Double.nan),
|
|
324
|
+
("inf", Double.infinity),
|
|
325
|
+
("-inf", -Double.infinity),
|
|
326
|
+
]
|
|
327
|
+
for (raw, value) in cases {
|
|
328
|
+
XCTAssertEqual(
|
|
329
|
+
ReplayGainExtractor.parsePeak(raw),
|
|
330
|
+
ReplayGainExtractor.acceptPeak(value),
|
|
331
|
+
"parsePeak(\"\(raw)\") and acceptPeak(\(value)) must agree"
|
|
332
|
+
)
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
func testGainDbStringAndNumericPathsAgree() {
|
|
337
|
+
let cases: [(String, Double)] = [
|
|
338
|
+
("-20.00 dB", -20.0),
|
|
339
|
+
("-6.54", -6.54),
|
|
340
|
+
("+3.21 dB", 3.21),
|
|
341
|
+
("0.00 dB", 0.0),
|
|
342
|
+
("100.0", 100.0),
|
|
343
|
+
("-100.0", -100.0),
|
|
344
|
+
("nan dB", Double.nan),
|
|
345
|
+
("inf", Double.infinity),
|
|
346
|
+
("-inf", -Double.infinity),
|
|
347
|
+
]
|
|
348
|
+
for (raw, value) in cases {
|
|
349
|
+
XCTAssertEqual(
|
|
350
|
+
ReplayGainExtractor.parseGainDb(raw),
|
|
351
|
+
ReplayGainExtractor.acceptGainDb(value),
|
|
352
|
+
"parseGainDb(\"\(raw)\") and acceptGainDb(\(value)) must agree"
|
|
353
|
+
)
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// MARK: - Tag-set acceptance
|
|
358
|
+
|
|
359
|
+
// MARK: - Tag-set acceptance
|
|
360
|
+
|
|
361
|
+
func testRgDataFromTagsParsesAllFourFields() throws {
|
|
362
|
+
let data = try XCTUnwrap(ReplayGainExtractor.rgDataFromTags([
|
|
363
|
+
"REPLAYGAIN_TRACK_GAIN": "-12.0 dB",
|
|
364
|
+
"REPLAYGAIN_TRACK_PEAK": "0.95",
|
|
365
|
+
"REPLAYGAIN_ALBUM_GAIN": "-8.0 dB",
|
|
366
|
+
"REPLAYGAIN_ALBUM_PEAK": "0.90",
|
|
367
|
+
]))
|
|
368
|
+
XCTAssertEqual(try XCTUnwrap(data.trackGainDb), -12.0, accuracy: 0.001)
|
|
369
|
+
XCTAssertEqual(try XCTUnwrap(data.trackPeak), 0.95, accuracy: 0.001)
|
|
370
|
+
XCTAssertEqual(try XCTUnwrap(data.albumGainDb), -8.0, accuracy: 0.001)
|
|
371
|
+
XCTAssertEqual(try XCTUnwrap(data.albumPeak), 0.90, accuracy: 0.001)
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
func testRgDataFromTagsAcceptsLowercaseKeys() throws {
|
|
375
|
+
let data = try XCTUnwrap(ReplayGainExtractor.rgDataFromTags([
|
|
376
|
+
"replaygain_track_gain": "-6.5 dB",
|
|
377
|
+
]))
|
|
378
|
+
XCTAssertEqual(try XCTUnwrap(data.trackGainDb), -6.5, accuracy: 0.001)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
func testRgDataFromTagsReturnsNilForEmptyDict() {
|
|
382
|
+
XCTAssertNil(ReplayGainExtractor.rgDataFromTags([:]))
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
func testRgDataFromTagsReturnsNilWhenAllValuesUnparseable() {
|
|
386
|
+
XCTAssertNil(ReplayGainExtractor.rgDataFromTags([
|
|
387
|
+
"REPLAYGAIN_TRACK_GAIN": "garbage",
|
|
388
|
+
"REPLAYGAIN_TRACK_PEAK": "3.0", // above the plausible range → rejected
|
|
389
|
+
]))
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
func testRgDataFromTagsAcceptsAFullScalePeak() throws {
|
|
393
|
+
// 1.000000 is digital full scale — a measurement, so the tag set is
|
|
394
|
+
// usable even when it carries nothing else.
|
|
395
|
+
let data = try XCTUnwrap(ReplayGainExtractor.rgDataFromTags([
|
|
396
|
+
"REPLAYGAIN_TRACK_PEAK": "1.000000",
|
|
397
|
+
]))
|
|
398
|
+
XCTAssertEqual(try XCTUnwrap(data.trackPeak), 1.0, accuracy: 0.0001)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// MARK: - Opus container guard
|
|
192
402
|
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
@testable import QueuePlayer
|
|
3
|
+
|
|
4
|
+
/// Unit tests for `ReplayGainData.merge(suppliedClaimed:supplied:detected:)`
|
|
5
|
+
/// — the all-or-nothing, per-item choice between consumer-supplied
|
|
6
|
+
/// ReplayGain and values detected from the file.
|
|
7
|
+
///
|
|
8
|
+
/// The rule is one predicate on the item, not two pair decisions and not
|
|
9
|
+
/// four field decisions: if the consumer supplied *any* of the four
|
|
10
|
+
/// fields, that track's ReplayGain comes solely from the consumer and
|
|
11
|
+
/// detection is discarded in full — including for the mode the consumer
|
|
12
|
+
/// said nothing about. Supplying a value is itself the statement of
|
|
13
|
+
/// intent; a consumer who wanted the file's own tags supplies nothing.
|
|
14
|
+
///
|
|
15
|
+
/// `suppliedClaimed` is captured before validation, so
|
|
16
|
+
/// `suppliedClaimed == true` with `supplied == nil` is a real state
|
|
17
|
+
/// meaning "the consumer owns this track and gave nothing usable".
|
|
18
|
+
/// Ownership is triggered by field *presence*, not validity.
|
|
19
|
+
///
|
|
20
|
+
/// Supplied and detected fixtures deliberately carry different values in
|
|
21
|
+
/// every field, so a row that returned the wrong source cannot pass.
|
|
22
|
+
final class ReplayGainMergeTests: XCTestCase {
|
|
23
|
+
|
|
24
|
+
// MARK: - Fixtures
|
|
25
|
+
|
|
26
|
+
private let detectedAll = ReplayGainData(
|
|
27
|
+
trackGainDb: -20.0, trackPeak: 0.5,
|
|
28
|
+
albumGainDb: -6.0, albumPeak: 0.6
|
|
29
|
+
)
|
|
30
|
+
private let detectedTrackOnly = ReplayGainData(
|
|
31
|
+
trackGainDb: -20.0, trackPeak: 0.5,
|
|
32
|
+
albumGainDb: nil, albumPeak: nil
|
|
33
|
+
)
|
|
34
|
+
private let detectedAlbumOnly = ReplayGainData(
|
|
35
|
+
trackGainDb: nil, trackPeak: nil,
|
|
36
|
+
albumGainDb: -6.0, albumPeak: 0.6
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
private let suppliedAll = ReplayGainData(
|
|
40
|
+
trackGainDb: -3.0, trackPeak: 0.25,
|
|
41
|
+
albumGainDb: -9.0, albumPeak: 0.3
|
|
42
|
+
)
|
|
43
|
+
private let suppliedTrackGain = ReplayGainData(
|
|
44
|
+
trackGainDb: -3.0, trackPeak: nil,
|
|
45
|
+
albumGainDb: nil, albumPeak: nil
|
|
46
|
+
)
|
|
47
|
+
private let suppliedAlbumGain = ReplayGainData(
|
|
48
|
+
trackGainDb: nil, trackPeak: nil,
|
|
49
|
+
albumGainDb: -9.0, albumPeak: nil
|
|
50
|
+
)
|
|
51
|
+
private let suppliedTrackPeak = ReplayGainData(
|
|
52
|
+
trackGainDb: nil, trackPeak: 0.25,
|
|
53
|
+
albumGainDb: nil, albumPeak: nil
|
|
54
|
+
)
|
|
55
|
+
private let suppliedAlbumPeak = ReplayGainData(
|
|
56
|
+
trackGainDb: nil, trackPeak: nil,
|
|
57
|
+
albumGainDb: nil, albumPeak: 0.3
|
|
58
|
+
)
|
|
59
|
+
private let suppliedTrackPair = ReplayGainData(
|
|
60
|
+
trackGainDb: -3.0, trackPeak: 0.25,
|
|
61
|
+
albumGainDb: nil, albumPeak: nil
|
|
62
|
+
)
|
|
63
|
+
private let suppliedAlbumPair = ReplayGainData(
|
|
64
|
+
trackGainDb: nil, trackPeak: nil,
|
|
65
|
+
albumGainDb: -9.0, albumPeak: 0.3
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
// MARK: - Helper
|
|
69
|
+
|
|
70
|
+
private func assertMerge(
|
|
71
|
+
claimed: Bool,
|
|
72
|
+
supplied: ReplayGainData?,
|
|
73
|
+
detected: ReplayGainData?,
|
|
74
|
+
equals expected: ReplayGainData?,
|
|
75
|
+
_ message: String,
|
|
76
|
+
file: StaticString = #file, line: UInt = #line
|
|
77
|
+
) {
|
|
78
|
+
let actual = ReplayGainData.merge(
|
|
79
|
+
suppliedClaimed: claimed, supplied: supplied, detected: detected
|
|
80
|
+
)
|
|
81
|
+
XCTAssertEqual(actual, expected, message, file: file, line: line)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// MARK: - No claim — detection is used verbatim
|
|
85
|
+
|
|
86
|
+
func testAnUnclaimedTrackUsesEveryDetectedField() {
|
|
87
|
+
assertMerge(
|
|
88
|
+
claimed: false, supplied: nil, detected: detectedAll,
|
|
89
|
+
equals: detectedAll,
|
|
90
|
+
"no supplied field means detection is used, all four"
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
func testAnUnclaimedTrackWithNoDetectionHasNoReplayGain() {
|
|
95
|
+
assertMerge(
|
|
96
|
+
claimed: false, supplied: nil, detected: nil,
|
|
97
|
+
equals: nil,
|
|
98
|
+
"nothing supplied and nothing detected is no ReplayGain"
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
func testAnUnclaimedTrackKeepsATrackOnlyDetection() {
|
|
103
|
+
assertMerge(
|
|
104
|
+
claimed: false, supplied: nil, detected: detectedTrackOnly,
|
|
105
|
+
equals: detectedTrackOnly,
|
|
106
|
+
"a partial detection is used as-is, not padded"
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
func testAnUnclaimedTrackKeepsAnAlbumOnlyDetection() {
|
|
111
|
+
assertMerge(
|
|
112
|
+
claimed: false, supplied: nil, detected: detectedAlbumOnly,
|
|
113
|
+
equals: detectedAlbumOnly,
|
|
114
|
+
"the mirrored partial-detection case"
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// MARK: - Claimed — one supplied field discards all detection
|
|
119
|
+
|
|
120
|
+
func testASuppliedTrackGainDiscardsEveryDetectedField() {
|
|
121
|
+
assertMerge(
|
|
122
|
+
claimed: true, supplied: suppliedTrackGain, detected: detectedAll,
|
|
123
|
+
equals: suppliedTrackGain,
|
|
124
|
+
"supplied trackGain applies; detected peak and album pair are dropped"
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
func testASuppliedAlbumGainDiscardsEveryDetectedField() {
|
|
129
|
+
assertMerge(
|
|
130
|
+
claimed: true, supplied: suppliedAlbumGain, detected: detectedAll,
|
|
131
|
+
equals: suppliedAlbumGain,
|
|
132
|
+
"supplied albumGain applies; detected track pair and album peak are dropped"
|
|
133
|
+
)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
func testASuppliedTrackPeakAloneLeavesNoGainAnywhere() {
|
|
137
|
+
assertMerge(
|
|
138
|
+
claimed: true, supplied: suppliedTrackPeak, detected: detectedAll,
|
|
139
|
+
equals: suppliedTrackPeak,
|
|
140
|
+
"a peak with no gain is ownership with nothing to apply"
|
|
141
|
+
)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
func testASuppliedAlbumPeakAloneLeavesNoGainAnywhere() {
|
|
145
|
+
assertMerge(
|
|
146
|
+
claimed: true, supplied: suppliedAlbumPeak, detected: detectedAll,
|
|
147
|
+
equals: suppliedAlbumPeak,
|
|
148
|
+
"the mirrored peak-only case"
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
func testASuppliedTrackPairDiscardsTheDetectedAlbumPair() {
|
|
153
|
+
assertMerge(
|
|
154
|
+
claimed: true, supplied: suppliedTrackPair, detected: detectedAll,
|
|
155
|
+
equals: suppliedTrackPair,
|
|
156
|
+
"album mode plays at unity even though the file carries album tags"
|
|
157
|
+
)
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
func testASuppliedAlbumPairDiscardsTheDetectedTrackPair() {
|
|
161
|
+
assertMerge(
|
|
162
|
+
claimed: true, supplied: suppliedAlbumPair, detected: detectedAll,
|
|
163
|
+
equals: suppliedAlbumPair,
|
|
164
|
+
"track mode plays at unity even though the file carries track tags"
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
func testAFullySuppliedSetReplacesAFullyDetectedSet() {
|
|
169
|
+
assertMerge(
|
|
170
|
+
claimed: true, supplied: suppliedAll, detected: detectedAll,
|
|
171
|
+
equals: suppliedAll,
|
|
172
|
+
"all four supplied values win over all four detected values"
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
func testASuppliedTrackGainDiscardsAnAlbumOnlyDetection() {
|
|
177
|
+
assertMerge(
|
|
178
|
+
claimed: true, supplied: suppliedTrackGain, detected: detectedAlbumOnly,
|
|
179
|
+
equals: suppliedTrackGain,
|
|
180
|
+
"detection is discarded even where supplied and detected do not overlap"
|
|
181
|
+
)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// MARK: - Claimed with no detection to discard
|
|
185
|
+
|
|
186
|
+
func testAFullySuppliedSetAppliesToAnUntaggedFile() {
|
|
187
|
+
assertMerge(
|
|
188
|
+
claimed: true, supplied: suppliedAll, detected: nil,
|
|
189
|
+
equals: suppliedAll,
|
|
190
|
+
"the motivating case — a server that stripped tags on transcode"
|
|
191
|
+
)
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
func testASuppliedTrackGainAppliesToAnUntaggedFile() {
|
|
195
|
+
assertMerge(
|
|
196
|
+
claimed: true, supplied: suppliedTrackGain, detected: nil,
|
|
197
|
+
equals: suppliedTrackGain,
|
|
198
|
+
"a single supplied field on an untagged file applies alone"
|
|
199
|
+
)
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// MARK: - Claimed but nothing usable — ownership without a value
|
|
203
|
+
|
|
204
|
+
func testAClaimWithNoUsableValueDiscardsAFullDetection() {
|
|
205
|
+
// Every supplied value was rejected by validation, so `supplied` is
|
|
206
|
+
// nil — but the claim was captured before validation, so the file's
|
|
207
|
+
// tags do not come back.
|
|
208
|
+
assertMerge(
|
|
209
|
+
claimed: true, supplied: nil, detected: detectedAll,
|
|
210
|
+
equals: nil,
|
|
211
|
+
"presence, not validity, is what claims the track"
|
|
212
|
+
)
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
func testAClaimWithNoUsableValueDiscardsAPartialDetection() {
|
|
216
|
+
assertMerge(
|
|
217
|
+
claimed: true, supplied: nil, detected: detectedTrackOnly,
|
|
218
|
+
equals: nil,
|
|
219
|
+
"a partial detection is discarded by a claim just as a full one is"
|
|
220
|
+
)
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
func testAClaimWithNoUsableValueAndNoDetectionHasNoReplayGain() {
|
|
224
|
+
assertMerge(
|
|
225
|
+
claimed: true, supplied: nil, detected: nil,
|
|
226
|
+
equals: nil,
|
|
227
|
+
"ownership claimed, nothing supplied, nothing detected"
|
|
228
|
+
)
|
|
229
|
+
}
|
|
230
|
+
}
|