Updating Voxin TTS Server To Avoid A Possible ALSA Bug
1 Summary
I recently updated to a new Linux laptop running the latest Debian (Rodete). The upgrade went smoothly, but when I started using the machine, I found that the Emacspeak TTS server for Voxin (Outloud) crashed consistently; here, consistently equated to crashing on short utterances which made typing or navigating by character an extremely frustrating experience.
I fixed the issue by creating a work-around in the TTS server
atcleci.cpp::xrun
— if you run into this issue, make sure to update and rebuild
atcleci.so from GitHub; alternatively, you'll find an updated
atcleci.so
in the servers/linux-outloud/lib/
directory after a
git update that you can copy over to your servers/linux-outloud
directory.
2 What Was Crashing
I use a DMIX plugin as the default device — and have many ALSA virtual devices that are defined in terms of this device — see my asoundrc. With this configuration, writing to the ALSA device was raising an EPIPE error — normally this error indicates a buffer underrun — that's when ALSA is starved of audio data. But in many of these cases, the ALSA device was still in a RUNNING rather than an XRUN state — this caused the Emacspeak server to abort. Curiously, this happened only sporadically — and from my experimentation only happened when there were multiple streams of audio active on the machine. A few Google searches showed threads on the alsa/kernel devel lists that indicated that this bug was present in the case of DMIX devices — it was hard to tell if the patch that was submitted on the alsa-devel list had made it into my installation of Debian.
3 Fixing The Problem
My original implementation of function xrun had been cloned from aplay.c about 15+ years ago — looking at the newest aplay implementation, little to nothing had changed there. I finally worked around the issue by adding a call to
snd_pcm_prepare(AHandle)
whenever ALSA raised an EPIPE error during write — with the ALSA device state in a RUNNING rather than an XRUN state. This appears to fix the issue.