Repository navigation
host/audio: play 5.1 on output routes that take six channels - #2234
Open
maxdavidson wants to merge 1 commit into
Open
maxdavidson wants to merge 1 commit into
maxdavidson wants to merge 1 commit into
Conversation
maxdavidson
marked this pull request as ready for review
November 10, 2026 21:49
maxdavidson
force-pushed
the
multichannel-output
branch
3 times, most recently
from
November 13, 2026 12:56
ced43ba to
b12f4fc
Compare
Audio plays in 5.1 where the output route takes six channels: GetActiveAudioDeviceChannelCountForOutput reports the route's count (six when the Mac's output device has a stream format of six or more channels, or when the iOS session's output does; stereo otherwise), a six-channel output goes to the AudioUnit as it is with the input layout MPEG_5_1_A, so Core Audio puts each channel on its speaker even on an HDMI sink whose order has the LFE before the center, and the in-process renderer opens at six. On a stereo route the host downmixes a six-channel output with the renderer's default coefficients (Core Audio's own 6 → 2 would keep only the front pair); outputs of other channel counts go as the guest writes them. A route change while an output plays replaces the units whose channel count no longer fits the route, through the media services reset path (au_reopen), and an output whose new unit could not be made is tried again at the next change; on iOS the session asks for the new route's channels first. Checked on BlackHole 16ch and 2ch (dm/tools/audio_channel_check.py: each tone on its own channel, the downmix within 0.05 dB of the host's coefficients; t_audio_live moved the output between the two while it played), and by ear on a Mac over HDMI to an LG TV and over eARC to a Sonos system. DM_AUDIO_DEVICE pins the Mac's output to a device by name, for tests. Not yet checked in a game or on an iPhone; Spatial Audio over AirPods is not done Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
maxdavidson
force-pushed
the
multichannel-output
branch
from
November 13, 2026 19:27
b12f4fc to
06b8126
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
On a Mac over HDMI to a 5.1 TV, receiver or soundbar (or an iPhone on a multichannel route), a game that writes six channels plays in stereo.
GetActiveAudioDeviceChannelCountForOutputreported two channels on every route, and every six-channel output was folded to stereo before Core Audio.The change:
dm_audio_route) because a Core Audio read can need more stack than a game thread has.MPEG_5_1_A. Core Audio then maps them onto the device's own layout. That matters on HDMI, whose order puts the LFE before the center.DM_AUDIO_DEVICE(Mac, diagnostic) pins the output to a device by name.t_audio_liveanddm/tools/audio_channel_check.pycheck the channels on a loopback device.This overlaps #1381, the opt-in Spatial Audio through macOS's renderer. Both PRs hand six channels on in
hle_audio.candhle_audren.c. This PR is the default path for six-channel devices and iOS, and #1381 is the opt-in system spatializer for headphones. Whichever lands second adapts to the other.Reference entry: Stereo only on a 5.1 system.
Checked
make -C dm/host/tests GAME=010015100B514000 runpasses. That includest_audio_device, which uses mock units and covers:t_audio_devicepassed 20 runs in a row.t_audren_layout: six channels in sink order, and a mono sink on the front pair.make -C dm/gfx/tests GAME=010015100B514000 runpasses.dm/tools/tests:test_docs,test_env_switches,test_pr_areasandtest_audio_channel_checkpass, and so doesenv_switches.py --check.lint_pythonreports 0 new.lint_c.py tidy(LLVM 23.1.4) reports nothing in the files this change touches; its seven findings above the baseline are in fivedm/gfx/testsfiles that are the same on main.hle_audio.c,hle_audren.candfront_ios.mcompile for iOS 26.audio_channel_check.py, test tones captured in-process): each tone on its own channel, the others more than 100 dB down. The downmix came within 0.05 dB of the host's coefficients. With BlackHole 16ch set to HDMI's layout, the center and the LFE land on HDMI's channels 4 and 3.t_audio_livemoved the output between the two devices mid-run. Each device carried the 5.1 signal or the downmix right after the switch.t_audio_liveplayed a spoken channel name on each channel, and each came from the right speaker.regress.py: not run yet; the report will be added here.regress.py impactnames Hades, Breath of the Wild, Pokémon Scarlet and Tears of the Kingdom by their usage manifests.Docs
docs/reference/audio.mdentry, andpython3 dm/tools/docs_symptoms.pywas run (the symptom index)🤖 Generated with Claude Code