Skip to content

Fix HDMI audio detection on Pi4 with dual HDMI ports#2811

Open
vpetersson wants to merge 3 commits intomasterfrom
alex-hdmi-audio-pi4
Open

Fix HDMI audio detection on Pi4 with dual HDMI ports#2811
vpetersson wants to merge 3 commits intomasterfrom
alex-hdmi-audio-pi4

Conversation

@vpetersson
Copy link
Copy Markdown
Contributor

Summary

Supersedes #2667 by @Alex1981-tech, rebased onto current master with conflicts resolved against the recent media_player.py refactor (top-level get_alsa_audio_device() shared across MPV and VLC) and tests updated.

Original work and the fix itself are by @Alex1981-tech; Alex's commit is preserved as-is.

Changes (from @Alex1981-tech)

  • Pi4 has two HDMI ports (HDMI-A-1 / HDMI-A-2), but VLC audio always targeted default:CARD=vc4hdmi0 regardless of which port had a display connected — no audio when using HDMI-A-2.
  • The default:CARD= ALSA device name is unreliable when PulseAudio or dmix is involved.

The fix:

  • Adds _detect_hdmi_audio_device() that reads /sys/class/drm/cardN-HDMI-A-N/status to find which HDMI port is connected and returns the matching ALSA device.
  • Switches from default:CARD= to sysdefault:CARD= for direct hardware access.
  • Applies auto-detection for Pi4 and Pi5 HDMI output. The detection now naturally benefits MPV too (Pi4-64 / Pi5), since master's refactor moved get_alsa_audio_device() to a top-level helper used by both players.
  • Headphones and Pi1-3 paths are unchanged in behavior; their device strings move from default: to sysdefault: for consistency.

Conflict resolution notes

  • Master refactored get_alsa_audio_device into a top-level function shared by MPVMediaPlayer and VLCMediaPlayer. Alex's PR was based on a version where it lived as a method on VLCMediaPlayer. Alex's intent has been ported onto the current top-level helper.
  • Alex's second commit (style: apply ruff format) was redundant on the resolved structure and was dropped during rebase; an equivalent format pass is already folded into his fix commit.

Tests

  • Existing tests/test_media_player.py cases updated for default:sysdefault:.
  • HDMI Pi4/Pi5 dispatch test now mocks _detect_hdmi_audio_device and asserts it's called.
  • New cases cover _detect_hdmi_audio_device itself: first-port-connected, second-port-only-connected, no status files (fallback), and OSError on read (fallback).

Test plan

  • uv run ruff check viewer/media_player.py tests/test_media_player.py — clean
  • uv run ruff format --check viewer/media_player.py tests/test_media_player.py — clean
  • uv run pytest -m "not integration" — 413 passed
  • Hardware verification on Pi4 with HDMI-A-1 only (already confirmed in Fix HDMI audio detection on Pi4 with dual HDMI ports #2667)
  • Hardware verification on Pi4 with HDMI-A-2 only
  • Hardware verification on Pi5

🤖 Generated with Claude Code

Alex and others added 2 commits May 2, 2026 13:09
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.
…ings

Update existing tests for the default: -> sysdefault: switch and add
coverage for _detect_hdmi_audio_device(): both port preferences,
missing status files, and OSError fall-through.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes HDMI audio device selection on Raspberry Pi 4/5 by auto-detecting which HDMI connector is physically connected and selecting the corresponding ALSA card, improving reliability when default: is affected by PulseAudio/dmix.

Changes:

  • Add _detect_hdmi_audio_device() that reads /sys/class/drm/*/status for HDMI connector connection state and returns a matching sysdefault:CARD=... device string.
  • Update get_alsa_audio_device() to use HDMI auto-detection on Pi4/Pi5 and switch several ALSA device strings from default: to sysdefault:.
  • Update and extend unit tests to cover the new detection helper and the updated device selection behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
viewer/media_player.py Introduces HDMI connector detection helper and routes Pi4/Pi5 HDMI output through it; switches ALSA device strings to sysdefault:.
tests/test_media_player.py Updates expectations for sysdefault: and adds direct tests for HDMI detection/fallback behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread viewer/media_player.py Outdated
Comment on lines +13 to +26
"""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 to bypass PulseAudio/dmix.
"""
for port, card_name in [
('card1-HDMI-A-1', 'vc4hdmi0'),
('card1-HDMI-A-2', 'vc4hdmi1'),
]:
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 85fc3dd. The docstring now describes the two layers separately: the DRM connector paths (/sys/class/drm/card1-HDMI-A-{1,2}/) and the ALSA card names (vc4hdmi0/vc4hdmi1), and notes that the ALSA card name doesn't track the DRM card index.

Comment thread viewer/media_player.py Outdated
Comment on lines +39 to +40
except OSError:
pass
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 85fc3dd. The except OSError branch now logs at debug level with the status_path and the exception, so field debugging has something to grep for. Behavior is unchanged — still falls back to sysdefault:CARD=vc4hdmi0.

…Error

Address PR feedback:
- Docstring previously conflated DRM card directories
  (/sys/class/drm/cardN-HDMI-A-N/) with ALSA card names
  (vc4hdmiN). Rewrite to describe the two layers separately and
  document the card1 / vc4hdmi0|1 mapping explicitly.
- The except OSError branch silently swallowed read failures.
  Log them at debug level with the path and exception so field
  debugging has something to grep for; behavior (fallback to
  vc4hdmi0) is unchanged.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented May 2, 2026

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants