Tuesday, May 12, 2015

USB audio disconnect woes in FreeBSD with fstat: tales of a voltage-sensitive Topping TP30

I have a very nice "class T" Tripath audio amplifier: the Topping TP30 (MK I -- hopefully they fixed the MKII) with a very convenient integrated USB audio card. However, this device is VERY sensitive to line voltage. For example, when plugged into the same circuit as, say, a refrigerator, the motor spark is enough to pop the speakers and cause the device to perform a USB reset.

In the case of FreeBSD, this causes everything to come to a miserable, grinding halt. dmesg gives me repeated warnings of failure:

pcm2: unregister: mixer busy
pcm2: Waiting for sound application to exit!
pcm2: unregister: mixer busy
pcm2: Waiting for sound application to exit!
pcm2: unregister: mixer busy
pcm2: Waiting for sound application to exit!
pcm2: unregister: mixer busy
pcm2: Waiting for sound application to exit!
pcm2: unregister: channel pcm2:virtual:dsp2.vp0 busy (pid 11413)
pcm2: Waiting for sound application to exit!
pcm2: unregister: channel pcm2:virtual:dsp2.vp0 busy (pid 11413)
pcm2: Waiting for sound application to exit!
pcm2: chn_write(): pcm2:virtual:dsp2.vp0: play interrupt timeout, channel dead

Before I realized that fstat worked on character devices, I had to manually fish around for processes to kill, in order to give the USB audio subsystem the breathing room required for it to reset the audio device. Interestingly enough: if a process that was holding onto the mixer releases the corresponding /dev/mixer device, but then restarts quickly enough and grabs control of the (now defunct) mixer, the sound card still won't reset.

Below, find the one-liner script that goes out and kills every process that holds the audio devices open. I have to execute this twice in a row to kill off XFCE's mixer process until the USB audio card has time to fully reset:

fstat /dev/dsp* /dev/mixer* /dev/audio* | tail -n +2 | awk '{print $3}' | xargs sh -c 'sudo kill -9 $0 $*'

No comments: