diff --git a/lib/i18n/de.i18n.json b/lib/i18n/de.i18n.json index 254c0e44..91564fe0 100644 --- a/lib/i18n/de.i18n.json +++ b/lib/i18n/de.i18n.json @@ -806,7 +806,8 @@ "subtitleSync": "Untertitel-Synchronisation", "hdr": "HDR", "audioOutput": "Audioausgabe", - "performanceOverlay": "Leistungsanzeige" + "performanceOverlay": "Leistungsanzeige", + "audioPassthrough": "Audio-Durchleitung" }, "externalPlayer": { "title": "Externer Player", diff --git a/lib/i18n/en.i18n.json b/lib/i18n/en.i18n.json index 6b65b454..0546a4ad 100644 --- a/lib/i18n/en.i18n.json +++ b/lib/i18n/en.i18n.json @@ -806,7 +806,8 @@ "subtitleSync": "Subtitle Sync", "hdr": "HDR", "audioOutput": "Audio Output", - "performanceOverlay": "Performance Overlay" + "performanceOverlay": "Performance Overlay", + "audioPassthrough": "Audio Passthrough" }, "externalPlayer": { "title": "External Player", diff --git a/lib/i18n/es.i18n.json b/lib/i18n/es.i18n.json index 2191f767..0eb849a1 100644 --- a/lib/i18n/es.i18n.json +++ b/lib/i18n/es.i18n.json @@ -806,7 +806,8 @@ "subtitleSync": "Sincronización de subtítulos", "hdr": "HDR", "audioOutput": "Salida de audio", - "performanceOverlay": "Indicador de rendimiento" + "performanceOverlay": "Indicador de rendimiento", + "audioPassthrough": "Audio Passthrough" }, "externalPlayer": { "title": "Reproductor externo", diff --git a/lib/i18n/fr.i18n.json b/lib/i18n/fr.i18n.json index 09d81261..2c778ec7 100644 --- a/lib/i18n/fr.i18n.json +++ b/lib/i18n/fr.i18n.json @@ -806,7 +806,8 @@ "subtitleSync": "Synchronisation des sous-titres", "hdr": "HDR", "audioOutput": "Sortie audio", - "performanceOverlay": "Superposition de performance" + "performanceOverlay": "Superposition de performance", + "audioPassthrough": "Audio Pass-Through" }, "externalPlayer": { "title": "Lecteur externe", diff --git a/lib/i18n/it.i18n.json b/lib/i18n/it.i18n.json index d17307d2..6afb3ef4 100644 --- a/lib/i18n/it.i18n.json +++ b/lib/i18n/it.i18n.json @@ -806,7 +806,8 @@ "subtitleSync": "Sincronizzazione sottotitoli", "hdr": "HDR", "audioOutput": "Uscita audio", - "performanceOverlay": "Overlay prestazioni" + "performanceOverlay": "Overlay prestazioni", + "audioPassthrough": "Audio Passthrough" }, "externalPlayer": { "title": "Lettore esterno", diff --git a/lib/i18n/ko.i18n.json b/lib/i18n/ko.i18n.json index de81d476..568f8682 100644 --- a/lib/i18n/ko.i18n.json +++ b/lib/i18n/ko.i18n.json @@ -806,7 +806,8 @@ "subtitleSync": "자막 동기화", "hdr": "HDR", "audioOutput": "오디오 출력", - "performanceOverlay": "성능 오버레이" + "performanceOverlay": "성능 오버레이", + "audioPassthrough": "오디오 패스스루" }, "externalPlayer": { "title": "외부 플레이어", diff --git a/lib/i18n/nl.i18n.json b/lib/i18n/nl.i18n.json index 2f717b6d..4c8a834c 100644 --- a/lib/i18n/nl.i18n.json +++ b/lib/i18n/nl.i18n.json @@ -806,7 +806,8 @@ "subtitleSync": "Ondertitel synchronisatie", "hdr": "HDR", "audioOutput": "Audio-uitvoer", - "performanceOverlay": "Prestatie-overlay" + "performanceOverlay": "Prestatie-overlay", + "audioPassthrough": "Audio-doorvoer" }, "externalPlayer": { "title": "Externe speler", diff --git a/lib/i18n/strings_de.g.dart b/lib/i18n/strings_de.g.dart index 86371601..aa3b2248 100644 --- a/lib/i18n/strings_de.g.dart +++ b/lib/i18n/strings_de.g.dart @@ -1018,6 +1018,7 @@ class _TranslationsVideoSettingsDe implements TranslationsVideoSettingsEn { @override String get hdr => 'HDR'; @override String get audioOutput => 'Audioausgabe'; @override String get performanceOverlay => 'Leistungsanzeige'; + @override String get audioPassthrough => 'Audio-Durchleitung'; } // Path: externalPlayer @@ -2019,6 +2020,7 @@ extension on TranslationsDe { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Audioausgabe', 'videoSettings.performanceOverlay' => 'Leistungsanzeige', + 'videoSettings.audioPassthrough' => 'Audio-Durchleitung', 'externalPlayer.title' => 'Externer Player', 'externalPlayer.useExternalPlayer' => 'Externen Player verwenden', 'externalPlayer.useExternalPlayerDescription' => 'Videos in einer externen App statt im integrierten Player öffnen', diff --git a/lib/i18n/strings_en.g.dart b/lib/i18n/strings_en.g.dart index a8fe3fb6..b65113db 100644 --- a/lib/i18n/strings_en.g.dart +++ b/lib/i18n/strings_en.g.dart @@ -2249,6 +2249,9 @@ class TranslationsVideoSettingsEn { /// en: 'Performance Overlay' String get performanceOverlay => 'Performance Overlay'; + + /// en: 'Audio Passthrough' + String get audioPassthrough => 'Audio Passthrough'; } // Path: externalPlayer @@ -3620,6 +3623,7 @@ extension on Translations { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Audio Output', 'videoSettings.performanceOverlay' => 'Performance Overlay', + 'videoSettings.audioPassthrough' => 'Audio Passthrough', 'externalPlayer.title' => 'External Player', 'externalPlayer.useExternalPlayer' => 'Use External Player', 'externalPlayer.useExternalPlayerDescription' => 'Open videos in an external app instead of the built-in player', diff --git a/lib/i18n/strings_es.g.dart b/lib/i18n/strings_es.g.dart index 8c51862c..e11c72a1 100644 --- a/lib/i18n/strings_es.g.dart +++ b/lib/i18n/strings_es.g.dart @@ -1018,6 +1018,7 @@ class _TranslationsVideoSettingsEs implements TranslationsVideoSettingsEn { @override String get hdr => 'HDR'; @override String get audioOutput => 'Salida de audio'; @override String get performanceOverlay => 'Indicador de rendimiento'; + @override String get audioPassthrough => 'Audio Passthrough'; } // Path: externalPlayer @@ -2019,6 +2020,7 @@ extension on TranslationsEs { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Salida de audio', 'videoSettings.performanceOverlay' => 'Indicador de rendimiento', + 'videoSettings.audioPassthrough' => 'Audio Passthrough', 'externalPlayer.title' => 'Reproductor externo', 'externalPlayer.useExternalPlayer' => 'Usar reproductor externo', 'externalPlayer.useExternalPlayerDescription' => 'Abrir vídeos en una app externa en lugar del reproductor integrado', diff --git a/lib/i18n/strings_fr.g.dart b/lib/i18n/strings_fr.g.dart index 2c13e988..77e93c6e 100644 --- a/lib/i18n/strings_fr.g.dart +++ b/lib/i18n/strings_fr.g.dart @@ -1018,6 +1018,7 @@ class _TranslationsVideoSettingsFr implements TranslationsVideoSettingsEn { @override String get hdr => 'HDR'; @override String get audioOutput => 'Sortie audio'; @override String get performanceOverlay => 'Superposition de performance'; + @override String get audioPassthrough => 'Audio Pass-Through'; } // Path: externalPlayer @@ -2019,6 +2020,7 @@ extension on TranslationsFr { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Sortie audio', 'videoSettings.performanceOverlay' => 'Superposition de performance', + 'videoSettings.audioPassthrough' => 'Audio Pass-Through', 'externalPlayer.title' => 'Lecteur externe', 'externalPlayer.useExternalPlayer' => 'Utiliser un lecteur externe', 'externalPlayer.useExternalPlayerDescription' => 'Ouvrir les vidéos dans une application externe au lieu du lecteur intégré', diff --git a/lib/i18n/strings_it.g.dart b/lib/i18n/strings_it.g.dart index 3992dfe5..4b9b882c 100644 --- a/lib/i18n/strings_it.g.dart +++ b/lib/i18n/strings_it.g.dart @@ -1018,6 +1018,7 @@ class _TranslationsVideoSettingsIt implements TranslationsVideoSettingsEn { @override String get hdr => 'HDR'; @override String get audioOutput => 'Uscita audio'; @override String get performanceOverlay => 'Overlay prestazioni'; + @override String get audioPassthrough => 'Audio Passthrough'; } // Path: externalPlayer @@ -2019,6 +2020,7 @@ extension on TranslationsIt { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Uscita audio', 'videoSettings.performanceOverlay' => 'Overlay prestazioni', + 'videoSettings.audioPassthrough' => 'Audio Passthrough', 'externalPlayer.title' => 'Lettore esterno', 'externalPlayer.useExternalPlayer' => 'Usa lettore esterno', 'externalPlayer.useExternalPlayerDescription' => 'Apri i video in un\'app esterna invece del lettore integrato', diff --git a/lib/i18n/strings_ko.g.dart b/lib/i18n/strings_ko.g.dart index fa2c8f74..c6b8f173 100644 --- a/lib/i18n/strings_ko.g.dart +++ b/lib/i18n/strings_ko.g.dart @@ -1018,6 +1018,7 @@ class _TranslationsVideoSettingsKo implements TranslationsVideoSettingsEn { @override String get hdr => 'HDR'; @override String get audioOutput => '오디오 출력'; @override String get performanceOverlay => '성능 오버레이'; + @override String get audioPassthrough => '오디오 패스스루'; } // Path: externalPlayer @@ -2019,6 +2020,7 @@ extension on TranslationsKo { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => '오디오 출력', 'videoSettings.performanceOverlay' => '성능 오버레이', + 'videoSettings.audioPassthrough' => '오디오 패스스루', 'externalPlayer.title' => '외부 플레이어', 'externalPlayer.useExternalPlayer' => '외부 플레이어 사용', 'externalPlayer.useExternalPlayerDescription' => '내장 플레이어 대신 외부 앱에서 동영상 열기', diff --git a/lib/i18n/strings_nl.g.dart b/lib/i18n/strings_nl.g.dart index 084aae4c..5709fcb8 100644 --- a/lib/i18n/strings_nl.g.dart +++ b/lib/i18n/strings_nl.g.dart @@ -1018,6 +1018,7 @@ class _TranslationsVideoSettingsNl implements TranslationsVideoSettingsEn { @override String get hdr => 'HDR'; @override String get audioOutput => 'Audio-uitvoer'; @override String get performanceOverlay => 'Prestatie-overlay'; + @override String get audioPassthrough => 'Audio-doorvoer'; } // Path: externalPlayer @@ -2019,6 +2020,7 @@ extension on TranslationsNl { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Audio-uitvoer', 'videoSettings.performanceOverlay' => 'Prestatie-overlay', + 'videoSettings.audioPassthrough' => 'Audio-doorvoer', 'externalPlayer.title' => 'Externe speler', 'externalPlayer.useExternalPlayer' => 'Externe speler gebruiken', 'externalPlayer.useExternalPlayerDescription' => 'Open video\'s in een externe app in plaats van de ingebouwde speler', diff --git a/lib/i18n/strings_sv.g.dart b/lib/i18n/strings_sv.g.dart index ef1658f5..c4f1e0ce 100644 --- a/lib/i18n/strings_sv.g.dart +++ b/lib/i18n/strings_sv.g.dart @@ -1018,6 +1018,7 @@ class _TranslationsVideoSettingsSv implements TranslationsVideoSettingsEn { @override String get hdr => 'HDR'; @override String get audioOutput => 'Ljudutgång'; @override String get performanceOverlay => 'Prestandaöverlägg'; + @override String get audioPassthrough => 'Ljudgenomkoppling'; } // Path: externalPlayer @@ -2019,6 +2020,7 @@ extension on TranslationsSv { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => 'Ljudutgång', 'videoSettings.performanceOverlay' => 'Prestandaöverlägg', + 'videoSettings.audioPassthrough' => 'Ljudgenomkoppling', 'externalPlayer.title' => 'Extern spelare', 'externalPlayer.useExternalPlayer' => 'Använd extern spelare', 'externalPlayer.useExternalPlayerDescription' => 'Öppna videor i en extern app istället för den inbyggda spelaren', diff --git a/lib/i18n/strings_zh.g.dart b/lib/i18n/strings_zh.g.dart index d8b08f44..4cfb9323 100644 --- a/lib/i18n/strings_zh.g.dart +++ b/lib/i18n/strings_zh.g.dart @@ -1018,6 +1018,7 @@ class _TranslationsVideoSettingsZh implements TranslationsVideoSettingsEn { @override String get hdr => 'HDR'; @override String get audioOutput => '音频输出'; @override String get performanceOverlay => '性能监控'; + @override String get audioPassthrough => '音频直通'; } // Path: externalPlayer @@ -2019,6 +2020,7 @@ extension on TranslationsZh { 'videoSettings.hdr' => 'HDR', 'videoSettings.audioOutput' => '音频输出', 'videoSettings.performanceOverlay' => '性能监控', + 'videoSettings.audioPassthrough' => '音频直通', 'externalPlayer.title' => '外部播放器', 'externalPlayer.useExternalPlayer' => '使用外部播放器', 'externalPlayer.useExternalPlayerDescription' => '在外部应用中打开视频,而不是使用内置播放器', diff --git a/lib/i18n/sv.i18n.json b/lib/i18n/sv.i18n.json index 520f1992..b9370a02 100644 --- a/lib/i18n/sv.i18n.json +++ b/lib/i18n/sv.i18n.json @@ -806,7 +806,8 @@ "subtitleSync": "Undertextsynkronisering", "hdr": "HDR", "audioOutput": "Ljudutgång", - "performanceOverlay": "Prestandaöverlägg" + "performanceOverlay": "Prestandaöverlägg", + "audioPassthrough": "Ljudgenomkoppling" }, "externalPlayer": { "title": "Extern spelare", diff --git a/lib/i18n/zh.i18n.json b/lib/i18n/zh.i18n.json index df3ccb2e..867c769b 100644 --- a/lib/i18n/zh.i18n.json +++ b/lib/i18n/zh.i18n.json @@ -806,7 +806,8 @@ "subtitleSync": "字幕同步", "hdr": "HDR", "audioOutput": "音频输出", - "performanceOverlay": "性能监控" + "performanceOverlay": "性能监控", + "audioPassthrough": "音频直通" }, "externalPlayer": { "title": "外部播放器", diff --git a/lib/screens/video_player_screen.dart b/lib/screens/video_player_screen.dart index efe4b534..7c4899f4 100644 --- a/lib/screens/video_player_screen.dart +++ b/lib/screens/video_player_screen.dart @@ -433,6 +433,13 @@ class VideoPlayerScreenState extends State with WidgetsBindin await player!.setProperty('audio-exclusive', 'yes'); } + // Audio passthrough (desktop only - sends bitstream to receiver) + if (Platform.isWindows || Platform.isMacOS || Platform.isLinux) { + if (settingsService.getAudioPassthrough()) { + await player!.setAudioPassthrough(true); + } + } + // HDR is controlled via custom hdr-enabled property on iOS/macOS/Windows if (Platform.isIOS || Platform.isMacOS || Platform.isWindows) { final enableHDR = settingsService.getEnableHDR(); diff --git a/lib/services/settings_service.dart b/lib/services/settings_service.dart index cb68e9e5..518a9c67 100644 --- a/lib/services/settings_service.dart +++ b/lib/services/settings_service.dart @@ -77,6 +77,7 @@ class SettingsService extends BaseSharedPreferencesService { static const String _keyCustomExternalPlayers = 'custom_external_players'; static const String _keyConfirmExitOnBack = 'confirm_exit_on_back'; static const String _keyAmbientLighting = 'ambient_lighting'; + static const String _keyAudioPassthrough = 'audio_passthrough'; SettingsService._(); @@ -1129,6 +1130,15 @@ class SettingsService extends BaseSharedPreferencesService { return prefs.getBool(_keyAmbientLighting) ?? false; } + // Audio Passthrough + Future setAudioPassthrough(bool enabled) async { + await prefs.setBool(_keyAudioPassthrough, enabled); + } + + bool getAudioPassthrough() { + return prefs.getBool(_keyAudioPassthrough) ?? false; + } + // Reset all settings to defaults Future resetAllSettings() async { await Future.wait([ @@ -1184,6 +1194,7 @@ class SettingsService extends BaseSharedPreferencesService { prefs.remove(_keyCustomExternalPlayers), prefs.remove(_keyConfirmExitOnBack), prefs.remove(_keyAmbientLighting), + prefs.remove(_keyAudioPassthrough), prefs.remove(_keyBufferSizeMigratedToAuto), ]); } diff --git a/lib/widgets/video_controls/sheets/video_settings_sheet.dart b/lib/widgets/video_controls/sheets/video_settings_sheet.dart index 9b854ece..2c94a438 100644 --- a/lib/widgets/video_controls/sheets/video_settings_sheet.dart +++ b/lib/widgets/video_controls/sheets/video_settings_sheet.dart @@ -115,6 +115,7 @@ class _VideoSettingsSheetState extends State { bool _enableHDR = true; bool _showPerformanceOverlay = false; bool _autoPlayNextEpisode = true; + bool _audioPassthrough = false; @override void initState() { @@ -131,6 +132,7 @@ class _VideoSettingsSheetState extends State { _enableHDR = settings.getEnableHDR(); _showPerformanceOverlay = settings.getShowPerformanceOverlay(); _autoPlayNextEpisode = settings.getAutoPlayNextEpisode(); + _audioPassthrough = settings.getAudioPassthrough(); }); } @@ -166,6 +168,17 @@ class _VideoSettingsSheetState extends State { }); } + Future _toggleAudioPassthrough() async { + final newValue = !_audioPassthrough; + final settings = await SettingsService.getInstance(); + await settings.setAudioPassthrough(newValue); + if (!mounted) return; + setState(() { + _audioPassthrough = newValue; + }); + await widget.player.setAudioPassthrough(newValue); + } + void _navigateTo(_SettingsView view) { setState(() { _currentView = view; @@ -331,6 +344,23 @@ class _VideoSettingsSheetState extends State { }, ), + // Audio Passthrough (Desktop only) + if (isDesktop) + ListTile( + leading: AppIcon( + Symbols.surround_sound_rounded, + fill: 1, + color: _audioPassthrough ? Colors.amber : tokens(context).textMuted, + ), + title: Text(t.videoSettings.audioPassthrough), + trailing: Switch( + value: _audioPassthrough, + onChanged: (_) => _toggleAudioPassthrough(), + activeThumbColor: Colors.amber, + ), + onTap: _toggleAudioPassthrough, + ), + // Shader Preset (MPV only) if (widget.shaderService != null && widget.shaderService!.isSupported) _SettingsMenuItem(