Repository navigation
fix: find the correct control to change volume on USB DAC - #851
Open
nborodikhin wants to merge 7 commits into
Open
nborodikhin wants to merge 7 commits into
nborodikhin wants to merge 7 commits into
Conversation
nborodikhin
marked this pull request as ready for review
October 1, 2026 21:11
8 tasks done
nborodikhin
added a commit
to nborodikhin/nextui-music-player
that referenced
this pull request
Oct 2, 2026
…ving (#52) ## Description There are a few issues with playback: - when audio device connects/disconnects (e.g. Bluetooth, USB DAC or USB headphones), playback keeps playing on the current sound device until restart - podcast speed change stops Bluetooth playback - playback speed change on podcast affects pitch - with some headphones, the player gives no sound over Bluetooth at all, and it hangs when the user exits it, while the emulators plays just fine - status pill does not update on audio change events ## Change - `launch.sh`: - export `LIBASOUND_THREAD_SAFE=0` to avoid BlueALSA stalls, see also LoveRetro/NextUI#811 - `bluetooth_sample_rate()`: - use NextUI sample rate setting to Bluetooth audio - `Player_handleAudioSinkChange()`: - called from `ModuleCommon_frameEnd()` to move the audio to a new output on the main thread - the reopen stops SDL audio and lets alsa-lib read its configuration again - use dlsym to find `snd_config_update_free_global()` (my355 workaround) - let NextUI to drive the volume - this avoids double application of volume adjustment - also see LoveRetro/NextUI#851 - `Player_pollUSBHID()`: - periodically check for headset controls presence, as they appear asynchronously - `load_streaming()`: - create the resampler for each track, not only when the rates differ - reset the resampler every time an audio device reopens - add Sonic pitch-preserving speed change library in `src/audio/sonic.{c,h}` (Apache-2.0) - `resample_chunk()` converts the rate only, then `time_stretch_write()` applies the speed - add the time of each audio callback at its own speed, not the total time at the current speed - `dev`: add `./dev kill <device>` to stop the app on a device or on the desktop ## Testing - [x] unit tests - [x] tested on TrimUI Brick, Miyoo Mini - [x] during playback: speaker to Bluetooth, Bluetooth to speaker, Bluetooth to USB DAC, USB DAC to speaker - [x] main menu with no input: the Bluetooth icon reflects the changing state of headset - [x] volume is consistent over the handoff to and from Bluetooth, with no large step at the first key press - [x] switch the headset off and on during playback: play/pause, next and previous on the headset work - [x] at 1.5x and 2x, podcast voice sounds natural, speaker and Bluetooth - [x] playback progress is consistent with actual position
With a USB audio device as the output, the volume keys could do nothing: - SetRawVolume() set the first control whose name had PCM or Playback and Volume, and stopped. On a USB headset adapter that is "Sidetone Playback Volume" (the microphone fed back into the headphones), which comes before "Headset Playback Volume" in the order of the controls. - It took the first card that is not audiocodec. A device that registers two USB cards (a Spark 40 guitar amp: one for the amp, one for the playback) got the volume on the wrong card. Now SetRawVolume() takes the card that audiomon wrote into .asoundrc, and the first USB card only where the file names none. It ranks the volume controls: Master, then the outputs (Headphone, Headset, Speaker, Line Out, Digital Out, IEC958), then PCM, then other Playback controls. Capture, the microphone and the inputs played into the output (Sidetone, Monitor, Loopback, Bypass, line in) are not the output. It sets each volume and switch of the best rank; the switches mute at 0. Other controls keep their level. Related: LoveRetro#485
The USB DAC path takes the card from .asoundrc, which audiomon writes, and the first card that is not audiocodec only as a fallback. The comment of AUDIO_SINK_USBDAC still said that the DAC is card 1.
get_asoundrc_card_num() and get_usbc_card_num() had one caller, which called the second only where the first gave no card. get_usbc_card_num() now reads .asoundrc first and falls back to the first card that is not audiocodec.
The volume is a mixer control, thus the card is the one of the control interface, ctl.!default. The lookup took the first card line, which is pcm.!default. audiomon writes the same card in both today, but a file can name another one for each, as a Bluetooth .asoundrc does (pcm BlueALSA, ctl hw card 0). Any card line stays the fallback.
Apply the same USB DAC fix h700: take the card from the .asoundrc of audiomon, then drive the output volume control skipping sidetone and monitor controls.
frysee
force-pushed
the
fix/usb-dac-volume-sidetone
branch
from
October 13, 2026 21:09
7a07975 to
e11a714
Compare
This branch has not been deployed
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.
Description
I found at least two cases where USB volume adjustment misses the control and does nothing to the output volume.
In the first case, device registers Sidetone controls before Headset (USB-C
Google Inc. Pixel earbudsid 18d1:5033 andGoogle Inc. Headphone adapterid 18d1:5034):volume control acts on control with the lowest id, which happens to be the sidetone control.
In the second case, device registers two devices (PositiveGrid Spark 40 amp id 10d6:1319):
where the first one has no controls. Due to the difference in card identification, volume control tries to find a suitable control on card
#3, whileaudiomonroutes the sound through card#4.Related: #485
Change
get_dac_control_playback_priority():SetRawVolume():rankof output exposed by the cardallcontrols that have that rankget_asoundrc_card_num():.asoundrcTesting