diff --git a/lib/mpv/player/player_base.dart b/lib/mpv/player/player_base.dart index a8e1c8a5b..962768682 100644 --- a/lib/mpv/player/player_base.dart +++ b/lib/mpv/player/player_base.dart @@ -1149,7 +1149,15 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player { /// mpv loudnorm targeting streaming-style loudness; mirrored by the /// Android ExoPlayer effect parameters in AudioNormalizationEffect.kt. - static const _loudnormFilter = 'loudnorm=I=-14:TP=-3:LRA=4'; + /// + /// Dynamic-mode loudnorm always outputs float64 at 192 kHz, which made the + /// AO open at f64/192k and forced the OS mixer to convert/resample on the + /// deadline-critical path (~4x the per-cycle DSP work), underrunning during + /// playback startup (#1720). The trailing mpv-native format filter pins the + /// chain back to 48 kHz float, so the conversion runs once on the buffered + /// decode side. mpv's own `format` filter is used instead of lavfi + /// `aformat` because the bundled Linux ffmpeg prunes lavfi filters. + static const _loudnormFilter = 'loudnorm=I=-14:TP=-3:LRA=4,format=srate=48000:format=floatp'; @override Future setAudioNormalization(bool enabled) async { diff --git a/test/mpv/player_native_bridge_test.dart b/test/mpv/player_native_bridge_test.dart index 74ef30387..7df0be6cb 100644 --- a/test/mpv/player_native_bridge_test.dart +++ b/test/mpv/player_native_bridge_test.dart @@ -1003,9 +1003,9 @@ void main() { await expectLater(player.setAudioPassthrough(true), throwsA(isA())); expect(propertyWrites.where((write) => write.$1 == 'af').map((write) => write.$2), [ - 'loudnorm=I=-14:TP=-3:LRA=4', + 'loudnorm=I=-14:TP=-3:LRA=4,format=srate=48000:format=floatp', '', - 'loudnorm=I=-14:TP=-3:LRA=4', + 'loudnorm=I=-14:TP=-3:LRA=4,format=srate=48000:format=floatp', ]); expect(player.audioPassthroughActive, isFalse); } finally {