audiotest test: sound playability 1 month ago
dll inital commit: necessary files to create linux software for ears 2 months ago
Readme.md docs: included instruction to play sound on original mahcine. The reason is that in wsl there is a jittering sound which is absent in hardware 1 month ago
ReadmeQuick.md docs: instruction if anyone wants to rebuld the files 1 month ago
Readme.md

Audio Test Bundle

Standalone harness for verifying the OpenAL playback path used by the EARS Linux build. Plays a WAV twice — once through paplay (reference), once through OpenAL via OpenTK — so a bad file, a bad parser and a bad audio backend can be told apart.

Contents

FilePurpose
altest.exethe test program
OpenTK.dllmanaged OpenAL binding
OpenTK.dll.configdllmap: openal32.dll → libopenal.so.1
alsoft.confOpenAL Soft settings (backend, resampler, buffers)
sound/*.wavtest assets
src/altest.cs, src/WavFile.cssources, only needed to rebuild

OpenTK.dll and OpenTK.dll.config must sit next to altest.exe. Mono resolves assemblies relative to the executable, not the working directory. A missing .config produces DllNotFoundException: openal32.dll on Linux, which reads like nonsense until you know what it means.

Install

sudo apt install mono-runtime libmono-system-drawing4.0-cil \
                 libopenal1 openal-info pulseaudio-utils sox

libmono-system-drawing4.0-cil is easy to miss. OpenTK's net45 build references System.Drawing even though the audio path never touches it.

Add mono-mcs only if rebuilding on this machine.

Run

cd audiotest
export ALSOFT_CONF=$PWD/alsoft.conf

soxi sound/SND200.wav            # what the file actually is
paplay sound/SND200.wav          # reference playback
mono ./altest.exe sound/SND200.wav
mono ./altest.exe sound/SND200.wav 0.5    # optional gain, 0..1

ALSOFT_CONF is required. Without it OpenAL only reads ~/.alsoftrc, which won't exist on a fresh machine, and the bundled settings are ignored silently.

Verbose mixer log:

ALSOFT_LOGLEVEL=3 mono ./altest.exe sound/SND200.wav 2>&1 | \
  grep -E "backend|Post-start|underrun|Error|resampler|Created device"

Reading the result

SymptomMeaning
Clean in bothaudio path is good
Clean in paplay, bad in altestbackend or resampler config — check the log
Bad in bothsource file, or the sound device itself
Bad at gain 1.0, clean at 0.5clipping; cap gain at 0.85 in AudioEngine.SetGain
DllNotFoundExceptionOpenTK.dll.config missing next to the exe

Key log lines:

  • Initialized backend "pulse" — which backend won
  • Post-start: Stereo, Float32, 44100hz, 882 / 2646 buffer — negotiated rate and buffer. Small buffers on a slow transport cause periodic ticks.
  • Created device ... "RDP Sink" — under WSL this is the WSLg bridge, not real hardware. Jitter here is usually the transport and disappears on the target device. Don't tune against it.

Assets are 11025 Hz mono. Against a 44100 or 48000 Hz device everything is resampled; bsinc24 in alsoft.conf handles this well. If a future device negotiates a rate that isn't an integer multiple, pre-converting the assets removes the question entirely:

sox in.wav -r 48000 out.wav

Sound comes out the wrong device

Common on the tablet, where HDMI wins the default.

pactl list short sinks     # what exists right now
wpctl status               # default is marked with *

Set the default by name, not by node ID:

pactl set-default-sink alsa_output.platform-cht-bsw-rt5645.HiFi__Speaker__sink

Node IDs are not stable. UCM destroys and recreates the built-in sink every time the headphone jack is plugged or unplugged, and the new node gets a new ID. An ID captured a minute ago is probably already dead — this looks like a sink "disappearing" but is normal behaviour. HDMI keeps a stable ID precisely because nothing switches it, which is why it tends to win by default.

The durable fix for a kiosk is to remove HDMI from the running: pavucontrol → Configuration → HDMI card → Off. This persists across reboots (WirePlumber stores card profiles in ~/.local/state/wireplumber/). With HDMI gone, whichever built-in sink exists is the only candidate and jack switching just works.

Note: under PipeWire, /etc/pulse/default.pa and ~/.config/pulse/default.pa are ignored. An old config there will look like it should work while doing nothing. The live state is ~/.local/state/wireplumber/default-nodes.

If a sink seems missing, restart the stack before assuming hardware failure:

systemctl --user restart wireplumber pipewire pipewire-pulse

Rebuilding

mcs src/altest.cs src/WavFile.cs -r:OpenTK.dll -out:altest.exe

Keep altest.cs out of the main program's *.cs glob — two Main methods in one build is a duplicate-entry-point error.