From e7bc50b73fe5e10149f7d8cf6d57653818909417 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 15 Feb 2026 09:33:31 +0200 Subject: [PATCH 1/2] Fix HDMI audio detection on Pi4 with dual HDMI ports Pi4 has two HDMI ports (HDMI-A-1 and HDMI-A-2), but the existing code always hardcodes `default:CARD=vc4hdmi0` regardless of which port has a display connected. This causes no audio when using HDMI-A-2. Changes: - Add `_detect_hdmi_audio_device()` that reads `/sys/class/drm/cardN-HDMI-A-N/status` to find which HDMI port is connected and returns the correct ALSA device - Use `sysdefault:CARD=` instead of `default:CARD=` for more reliable audio output (avoids PulseAudio/dmix interference) - Apply detection for Pi4 and Pi5 HDMI output - Keep headphones and Pi1-3 paths unchanged Tested on Pi4 Model B with single HDMI connected to HDMI-A-1. --- viewer/media_player.py | 44 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/viewer/media_player.py b/viewer/media_player.py index fba2db9e0..5bd9c8a6b 100644 --- a/viewer/media_player.py +++ b/viewer/media_player.py @@ -57,6 +57,42 @@ def is_playing(self): return False +def _detect_hdmi_audio_device(): + """Auto-detect connected HDMI audio device on Pi4/Pi5. + + Pi4 has two HDMI ports: + - HDMI-A-1 = card 1 = vc4hdmi0 + - HDMI-A-2 = card 2 = vc4hdmi1 + + Checks /sys/class/drm/cardN-HDMI-A-N/status to find + which port is connected and returns the matching ALSA device. + Uses sysdefault instead of default for reliable audio output. + """ + import os + for port, card_name in [ + ('card1-HDMI-A-1', 'vc4hdmi0'), + ('card1-HDMI-A-2', 'vc4hdmi1'), + ]: + status_path = f'/sys/class/drm/{port}/status' + try: + if os.path.exists(status_path): + with open(status_path) as f: + if f.read().strip() == 'connected': + logging.info( + 'Detected connected HDMI: %s -> ' + 'sysdefault:CARD=%s', port, card_name, + ) + return f'sysdefault:CARD={card_name}' + except OSError: + pass + + logging.warning( + 'No connected HDMI detected, ' + 'falling back to sysdefault:CARD=vc4hdmi0', + ) + return 'sysdefault:CARD=vc4hdmi0' + + class VLCMediaPlayer(MediaPlayer): def __init__(self): MediaPlayer.__init__(self) @@ -70,16 +106,16 @@ def __init__(self): def get_alsa_audio_device(self): if settings['audio_output'] == 'local': if get_device_type() == 'pi5': - return 'default:CARD=vc4hdmi0' + return 'sysdefault:CARD=vc4hdmi0' return 'plughw:CARD=Headphones' else: if get_device_type() in ['pi4', 'pi5']: - return 'default:CARD=vc4hdmi0' + return _detect_hdmi_audio_device() elif get_device_type() in ['pi1', 'pi2', 'pi3']: - return 'default:CARD=vc4hdmi' + return 'sysdefault:CARD=vc4hdmi' else: - return 'default:CARD=HID' + return 'sysdefault:CARD=HID' def __get_options(self): return [ From ad9a7b0a26d388c9e2e3521b0930e780924169f9 Mon Sep 17 00:00:00 2001 From: Alex Date: Tue, 17 Feb 2026 20:49:07 +0200 Subject: [PATCH 2/2] style: apply ruff format to viewer/media_player.py Co-Authored-By: Claude Opus 4.6 --- viewer/media_player.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/viewer/media_player.py b/viewer/media_player.py index 5bd9c8a6b..a9720a6a8 100644 --- a/viewer/media_player.py +++ b/viewer/media_player.py @@ -69,6 +69,7 @@ def _detect_hdmi_audio_device(): Uses sysdefault instead of default for reliable audio output. """ import os + for port, card_name in [ ('card1-HDMI-A-1', 'vc4hdmi0'), ('card1-HDMI-A-2', 'vc4hdmi1'), @@ -80,15 +81,16 @@ def _detect_hdmi_audio_device(): if f.read().strip() == 'connected': logging.info( 'Detected connected HDMI: %s -> ' - 'sysdefault:CARD=%s', port, card_name, + 'sysdefault:CARD=%s', + port, + card_name, ) return f'sysdefault:CARD={card_name}' except OSError: pass logging.warning( - 'No connected HDMI detected, ' - 'falling back to sysdefault:CARD=vc4hdmi0', + 'No connected HDMI detected, falling back to sysdefault:CARD=vc4hdmi0', ) return 'sysdefault:CARD=vc4hdmi0'