feat(android): loudness normalization for exoplayer via audiofx

close #1289
This commit is contained in:
edde746
2026-06-12 12:38:57 +02:00
parent 71b05fd4b2
commit bd0a0c5d6b
8 changed files with 327 additions and 11 deletions
@@ -12,6 +12,7 @@ class PlayerAndroid extends PlayerBase {
int? _bufferSizeBytes;
bool _tunnelingEnabled = true;
String _dvConversionMode = 'auto';
bool _audioNormalizationEnabled = false;
/// The native plugin switched from ExoPlayer to its mpv fallback for this
/// session. Sticky for the instance lifetime, mirroring the native flag
@@ -259,6 +260,24 @@ class PlayerAndroid extends PlayerBase {
}
}
@override
Future<void> setAudioNormalization(bool enabled) async {
if (disposed) return;
_audioNormalizationEnabled = enabled;
final initFuture = _initFuture;
if (initialized) {
await invoke('setAudioNormalization', {'enabled': enabled});
} else if (initFuture != null) {
await initFuture;
if (!disposed && initialized && _audioNormalizationEnabled == enabled) {
await invoke('setAudioNormalization', {'enabled': enabled});
}
}
// Keep the mpv af property flowing through setMpvProperty so the plugin's
// pendingMpvProperties replay applies loudnorm if exo falls back to mpv.
await super.setAudioNormalization(enabled);
}
@override
Future<String?> getProperty(String name) async {
if (disposed) return null;
+8
View File
@@ -209,6 +209,14 @@ abstract class Player {
/// passed through to the audio device without decoding.
Future<void> setAudioPassthrough(bool enabled);
/// Enable or disable loudness normalization.
///
/// mpv backends insert/remove the `loudnorm` audio filter. Android
/// ExoPlayer attaches platform audio effects (DynamicsProcessing on
/// API 28+, LoudnessEnhancer otherwise) and forces decoded non-tunneled
/// PCM output while enabled so the effects can process the stream.
Future<void> setAudioNormalization(bool enabled);
/// Show or hide the video rendering layer.
///
/// On macOS, this controls the Metal layer visibility.
+9
View File
@@ -668,6 +668,15 @@ abstract class PlayerBase with PlayerStreamControllersMixin implements Player {
// ignore: no-empty-block - base no-op, overridden by platform subclasses
Future<void> setAudioPassthrough(bool enabled) async {}
/// 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';
@override
Future<void> setAudioNormalization(bool enabled) async {
await setProperty('af', enabled ? _loudnormFilter : '');
}
@override
// ignore: no-empty-block - base no-op, overridden by platform subclasses
Future<void> setLogLevel(String level) async {}