Skip to content

fix(h700): prevent RG SP speaker pops during audio transitions - #46

Open
cstaavetti wants to merge 1 commit into
pvaibhav:h700from
cstaavetti:codex/rgsp-speaker-pop
Open

cstaavetti wants to merge 1 commit into
pvaibhav:h700from
cstaavetti:codex/rgsp-speaker-pop

Conversation

@cstaavetti

Copy link
Copy Markdown

Addresses #25 on the Anbernic RG SP. Game startup, game exit, and sleep/wake are silent in the tested scenarios, while normal playback and volume adjustment continue to work.

Problem

On the tested BaseOS device, the vendor kernel's sunxi_spk_event callback simply returns success without controlling the speaker amplifier. Disassembly of the device's kernel confirmed this, and GPIO readback showed the amplifier still enabled when the SPK DAPM widget was off. Consequently, muting the SPK mixer control did not reliably isolate the speaker from codec transitions; game exit could pop even at volume zero.

A diagnostic using the original emulator and library held the device-tree-defined amplifier enable pin, PI5, low. This silenced playback and both startup and exit pops.

Changes

  • Add an RG SP amplifier-control workaround, guarded by DEVICE=rgsp and matching device-tree pin, output function, polarity, and pin-count properties. It uses the vendor debugfs data interface and checks the resulting GPIO state.
  • Disable the amplifier before audio initialization, exit cleanup, and PCM teardown. Enable it after buffered playback starts, with settling delays around amplifier transitions.
  • Share the transient mute state between settings clients without changing the saved volume or the settings structure size. Frontend initialization no longer unconditionally enables the speaker outputs.
  • Keep the original ALSA routing configuration on the verified RG SP path. Hold digital gain at the vendor's value of 63 and apply user volume through the lineout gain.
  • Close the built-in PCM on normal emulator exit, retaining the Bluetooth/external-output exclusions. Preserve the existing close-before-suspend behavior and avoid creating audio on wake when it was not previously initialized.

Alternative considered

Turro75's audio-server solution addresses the same transition noise by keeping ALSA open across application launches and exits. An OSS/DSP preload wrapper redirects application audio into a FIFO, and a persistent server writes it to ALSA. This is compatible with our finding: avoiding codec transitions and disabling the amplifier during those transitions are two ways to keep the transient from reaching the speaker.

The trade-offs are:

  • Audio server: can cover other SDL binaries through their launch environment, provided SDL includes the OSS/DSP backend, and does not require the RG SP amplifier pin workaround. It adds a server, FIFO, preload wrapper, and lifecycle integration. The implementation reviewed uses fixed 48 kHz stereo S16 audio and its own buffering and pacing. Its output routing, suspend behavior, and recovery would need integration and validation with NextUI.
  • This change: preserves the existing ALSA playback path and format negotiation, while allowing PCM to close on exit and before suspend. It adds no persistent audio service, but relies on a vendor debugfs interface and verified RG SP pin configuration, adds 100 ms settling waits when changing amplifier state, and does not automatically cover other binaries that bypass these mute calls.

The amplifier approach was chosen because physical pin testing directly confirmed that it suppresses the pops on the affected device, and it fits NextUI's existing audio lifecycle, including close-before-suspend. It has passed the hardware checks below. The audio-server alternative has not been tested on this device during this investigation; no comparative latency, power, or audio-quality claim is made. Repairing the kernel amplifier callback remains the cleaner long-term solution.

Validation

Tested on an Anbernic RG SP running BaseOS 1.1.0, vendor kernel 4.9.170, and NextUI 6.14.0-rc9-based binaries.

  • Normal playback and volume adjustment worked, with no startup or exit pop.
  • Zero-volume launch and exit produced no pops; GPIO readback confirmed the amplifier stayed disabled throughout.
  • Game sleep/wake restored audio normally, with no pops during sleep, wake, or subsequent exit. Sleep/wake from the rebuilt frontend also passed.
  • A fresh boot confirmed the frontend and volume daemon loaded the replacement library. No .asoundrc override was used.
  • A bounded GPIO/PCM trace confirmed the amplifier enabled after PCM playback began and disabled before PCM close. In the normal exit test, amplifier disable preceded PCM close by approximately 367 ms.
  • Upstream GCC 8.3 builds, in-memory volume checks, amplifier identity/readback checks, and git diff --check passed. The diagnostic harnesses and captures are local investigation artifacts and are not included in this branch.

Limitations

This is a userspace workaround for the tested vendor kernel and depends on its debugfs GPIO interface. Repairing the kernel speaker-event callback would provide a cleaner long-term solution.

Hardware validation covers one RG SP and one game/core. Headphones, Bluetooth, HDMI, USB DACs, and other H700 models have not been tested. Although direct PI5 control is restricted to the verified RG SP configuration, the branch also changes shared H700 mute and mixer behavior.

The settings library, emulator, frontend, and volume daemon were built using the project makefiles and upstream GCC 8.3 image ghcr.io/loveretro/h700-toolchain@sha256:47148fa93d6c3196956aef4f418cb5a2d4f373ce0881e7e8d92c51ac5ef60afc, with the project’s optimization and LTO settings. All four resulting binaries were installed for the hardware test. Existing device runtime libraries and the tested dependency source revisions were retained.

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.

1 participant