3

My PC is connected to an audio amplifier that I can switch on or off over the network. I would like to set things up to switch it off automatically after no audio has been playing for 10 minutes.

I found some similar questions here which advised looking at /proc/asound/card*/pcm*/sub*/status to check for the word RUNNING which indicates audio is being output, however many programs seem to leave their audio running even when they aren't making any noise, just outputting silence. I have noticed that some Python programs do this, as does Firefox when run through apulse.

This means that I cannot detect via /proc/asound/ when there is no audio coming out of the speakers, as it is permanently RUNNING.

Is there another way to detect when the only audio signal being played is silence? Is there some way to record or otherwise intercept ALSA output, even when a hw device is the one in use?

Malvineous
  • 6,883
  • 1
    sox has an effect which can detect silence, and stop, but you would have to pipe your sound data through it. Aren't you using pulseaudio? – meuh Aug 07 '17 at 17:19
  • Hmm, I'll have to investigate that then. No I had trouble getting pulseaudio working when I tried a few years ago and now I'm not sure what it does that ALSA doesn't do already so not sure why I'd need it. – Malvineous Aug 08 '17 at 06:10

1 Answers1

1

This is a proof of concept demonstration using just alsa, the alsa loopback module, and sox to detect silence. The loopback module provides you with an output device that you can play sound into, and then record back from it. So, for example, you could direct mplayer to use the loopback for sound output, then run sox to record from the loopback, detect silence, and output to the original hardware output device.

Load the module with

sudo modprobe snd-aloop

(It was in my list of available kernel modules). aplay -l will now list a new card with 2 devices. Device 0 is to play into, device 1 to record from. There are 8 independent "subdevice" channels, and it is easiest to use number 0 as often it can be then be omitted. (I found aplay in package alsa-utils).

$ aplay -l
...
card 1: Loopback [Loopback], device 0: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
...
  Subdevice #7: subdevice #7
card 1: Loopback [Loopback], device 1: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
...
  Subdevice #7: subdevice #7

You can now use another utility from the package to generate a continuous tone into the loopback device 0 (subdevice 0):

speaker-test -t sine -D hw:Loopback

or for example tell mplayer to use the device with option -ao alsa:device=hw=Loopback

You will hear nothing until you also run sox getting it to read the other side of the device and write it to the real hardware, assuming this is card 0:

sox -q  -t alsa hw:Loopback,1  -t alsa hw:0  silence 0 1 10.0 2%

(I saw quite a few warnings sox WARN alsa: under-run). If you stop the speaker test, after 10 seconds of silence the sox command will stop. Note, if you mute mplayer you get silence but this seems to be independent of the data level (which you can visualise if you remove the -q from sox). You need to pause or lower the sound level of mplayer to have the silence detected. sox may also introduce a second or two of delay in the audio. You should be able to configure alsa to make the Loopback device the default instead of your card 0.

A more satisfactory solution is to let the kernel sound drivers handle the real-time audio, and use sox only to detect the silence, throwing away its output. This seems to be possible, but with just alsa it is also a bit complicated and needs knowledge I don't have, though you can find examples of duplicating sound to two devices, your original audio card, and a virtual device which sox can then read.

A simpler solution using pulseaudio to enable monitoring is possible, using pactl load-module module-combine-sink which I will probably investigate.

meuh
  • 51,383