Tiny Core Linux
Tiny Core Extensions => TCE Talk => Topic started by: GNUser on March 31, 2021, 02:09:18 PM
-
With pulseaudio, I can use this trick to figure out if my machine is producing sound:
$ grep RUNNING /proc/asound/card*/pcm*/sub*/status
For example, with pulseaudio, I get this when a video or sound file is playing in mpv:
$ grep RUNNING /proc/asound/card*/pcm*/sub*/status
/proc/asound/card0/pcm0p/sub0/status:state: RUNNING
$
If I pause the playback in mpv, I get this (as expected):
$ grep RUNNING /proc/asound/card*/pcm*/sub*/status
$
The trick doesn't work if I ditch pulseaudio and use apulse instead: Whether mpv is playing or paused, I get this same output:
$ grep RUNNING /proc/asound/card*/pcm*/sub*/status
/proc/asound/card0/pcm0p/sub0/status:state: RUNNING
$
So with apulse, if an mpv window exists, card0's state is "RUNNING" even if playback is paused.
So my question is this: Is there a different way to detect whether the soundcard is producing sound, a way that would give me the right answer even in the setting of apulse + paused mpv?
-
I found this alternative:
$ fuser /dev/snd/timer
The command is supposed to succeed only if sound is playing but, unfortunately, it also succeeds when mpv is paused.
I have a hard time believing that there's no reliable/low-level way to determine whether sound card is producing sound.
P.S. I don't like the title of my thread. A better title would be "how to detect audio playback using only alsa, without pulseaudio".
-
Hi GNUser
... A better title would be "how to detect audio playback using only alsa, without pulseaudio".
Done. :)
-
If your card offers loopback (reading its output as an input), you could write a program to read a few samples, and if their volume is under a threshold, presume silence? Just an idea, otherwise you should ask on the alsa ML.
-
Rich,
Thanks for changing the thread title :)
curaga,
It seems the strategy would be to configure my machine to output audio simultaneously to both ALSA loopback and normal sound device (speakers/audio jack), then write a script that every few seconds records an audio sample from loopback and tests if the sample volume is below a certain low threshold. If so, presume silence.
The ALSA solution seems more complex than dealing with pulseaudio's shenanigans. Since my ultimate goal is to keep things as simple as possible, in this case it seems that loading pulseaudio is the way to go.
-
Hi, GNUser!
In my system /proc/asound/card0/pcm0p/sub0/status file shows the status of playback.
-
Just a quick follow-up about the observations in the initial post in this thread: ALSA was innocent. MPV is the culprit.
I recompiled mpv using the "--disable-pulse" flag. Then I rebooted my TCL box, making sure to load neither pulseaudio nor apulse. Only alsa was loaded.
I then did some tests using Brave (a web browser which, similar to chromium, does not use pulseaudio) and my recompiled mpv:
Results with Brave
When playing audio in the browser, "cat /proc/asound/card*/pcm*/sub*/status" shows "state: RUNNING". If I pause the audio in the browser, after about 5-10 seconds Brave releases the audio card because "cat /proc/asound/card*/pcm*/sub*/status" just shows "closed".
Results with MPV
When playing audio file in my recompiled mpv, "cat /proc/asound/card*/pcm*/sub*/status" shows "state: RUNNING". If I pause the audio, no matter how long I wait "cat /proc/asound/card*/pcm*/sub*/status" continues to show "state: RUNNING". So it seems that unless pulseaudio is being used, mpv does not know how to release the sound card when playback is paused.
[EDIT]: Changed --without-pulse to --disable-pulse. Rich
-
But there are numbers too. hw_ptr and appl_ptr. Does their behaviour changes while paused and running?
-
Whether playback is paused or running, those numbers are constantly changing (seemingly randomly).
-
Hmm, it means mpv continues sending zero samples... I use mplayer, in case playback is paused, it sends nothing, while keeping device owned. Seems curaga's proposal is the only possible way.
-
Hi GNUser
I did a little experimenting and found:
/proc/asound/card0/pcm0p/sub0/info
and
/proc/asound/card0/pcm0p/info
showed changes when playing/pausing YouTube videos.
The following lines showed this when playing:
subdevices_count: 1
subdevices_avail: 0
and this when paused:
subdevices_count: 1
subdevices_avail: 1
-
Thanks for the tip, Rich. On my TCL11 x86_64 system, I loaded alsa only (no pulseaudio or apulse). Then I did some tests with mpv (compiled with --disable-pulse flag). When I cat the two info files you pointed out, I get this output whether mpv is playing or paused:
subdevices_count: 1
subdevices_avail: 0
So I'm still stuck. So far, I cannot find a way for a shell script to distinguish between "mpv playing" and "mpv paused" using only alsa.
P.S. In reply #6, "--without-pulse" is a mistake. I meant "--disable-pulse".
-
Hi GNUser
... P.S. In reply #6, "--without-pulse" is a mistake. I meant "--disable-pulse".
Fixed. :)
-
Hi, GNUser!
The matter is mpv behavior. What are mpv benefits over mplayer?
Another option is curaga's proposal - create additional alsa device, duplicating Your sound, make short record of its output and check whether it is exceeding some limit. If this is acceptable, i can try to write .asoundrc for Your needs, I think it is not complicated, but I never wrote alsa configs.
-
Rich,
mpv is what I use in my family media player. It has a pseudoGUI, which makes it easier for the wife and kids to use.
I submitted a bug report for mpv here: https://github.com/mpv-player/mpv/issues/8691
It's generous of you to offer to write the alsa config that sends output to both loopback and normal device. There is some guidance here (https://github.com/karlstav/cava#alsa-loopback-device-tricky) but I was too intimidated to try it. I'd be very happy to try what you put together. It would be rewarding to solve this using curaga's approach.
-
Hi, GNUser!
For my system getting alsa loopback passed flawlessly. i think You can try too. First You will need virtual audio card added with the help of
s u d o modprobe snd-aloop
(The word, which starts with the 's' letter and ends with 'o' letter is split to avoid You know what, please ignore this extra spaces)
This will create virtual audio card with even-numbered pcm subdevices looped back to odd-numbered capture subdevices. So if Your physical sound card is hw:0, this virtual will be hw:1, and hw:1,0 sent to hw:1,1, hw:1,2 to hw:1,3 and so forth.
Then You will need .asoundrc file, which will duplicate the default alsa output stream to Your physical device and to the virtual one. I've got such an example here https://dt.iki.fi/record-system-output-alsa, placed it in my $HOME and
a l s a c t l i n i t
These steps allow to capture the output to the default alsa device at hw:1,1, for example
a r e c o r d -D hw:1,1 -f cd -s 1000 silence.wav
As I can see, wav file have the header sized around 0x30 bytes, followed by the sound samples. In case of silence, all the consequent samples are zeroes.
I think if You don't use some special alsa config, You can try these steps without any changes.
The only correction I've made for downloaded .asoundrc was substituting "Loopback" card name with the "1" constant at line 43.
-
jazzbiker, I tried your steps and it worked perfectly! cat'ing the wav file always gives me this when there is no sound, even if mpv is open but paused:
RIFFWAVEfmt D±data
If mpv or another application is playing something, cat'ing the wav file shows the same header followed by a lot of gibberish characters (binary data representing the recorded sound).
Just brilliant :o Thank you very much. Thread may be marked as solved.
P.S. Your steps worked for me without any changes to the downloaded .asoundrc file. I kept line 43 unchanged, like this:
pcm "hw:Loopback,0,0"
Can you show me what your line 43 looks like and help me understand why you changed it?
-
jazzbiker, another quick question: Whether the wav file contains sound or silence, the file is the same size (I guess just header plus a bunch of zeros if the wav contains only silence). What's the easiest way you can think of to check if somefile.wav is just header followed by zeros? (It seems it would be a simple operation, but I don't think I've ever had the need to look inside a binary file before, so I'm quite out of my element here.)
-
Quick answer, probably not the best one.
dd if=/dev/zero bs=1 count=1K status=none > zeroes.bin
arecord -D hw:1,1 -f cd -s 1100 2>/dev/null | dd skip=48 bs=1 count=1K status=none | cmp -s zeroes.bin
$? == 0 means playback is paused.
Edit: sorry for too fast answer :) it works, but reads samples which will not be used for compare, because sample is 4-byte. Better will be:
dd if=/dev/zero bs=4 count=1K status=none > zeroes.bin
arecord -D hw:1,1 -f cd -s 1100 2>/dev/null | dd skip=12 bs=4 count=1K status=none | cmp -s zeroes.bin
-
The line 43 in my .asoundrc looks like:
pcm "hw:1,0,0"
but referring to "Loopback" name is better, because You may have more than one physical soundcard and "Loopback" may be 1,2 or even bigger.
-
Edit2 to Reply #18:
arecord -D hw:Loopback,1 -f cd -s 1100 2>/dev/null | dd skip=12 bs=4 count=1K status=none | cmp -s zeroes.bin
works fine.
-
but referring to "Loopback" name is better, because You may have more than one physical soundcard and "Loopback" may be 1,2 or even bigger.
Thanks, jazzbiker. I'll just use the .asoundrc without modification, then.
arecord -D hw:Loopback,1 -f cd -s 1100 2>/dev/null | dd skip=12 bs=4 count=1K status=none | cmp -s zeroes.bin
works fine.
Wow, that's beautiful. Hats off to you. I wondered about the question in the thread's subject line for for a long time before finally starting this thread. Thank you very much for helping me finally solve the mystery :)
-
Hi, GNUser!
Right question is half an answer itself. At this moment I don't need to capture my audio, but if such need will appear, I will exactly know what to do :) Thanks to curaga for pushing into right direction and this guy https://bbs.archlinux.org/viewtopic.php?pid=1153194#p1153194 for config template.
Best regards!
PS: arecord has quiet option, so probably
arecord -q -D hw:Loopback,1 -f cd -s 1100 | dd skip=12 bs=4 count=1K status=none | cmp -s zeroes.bin
will avoid producing bytes in order to waste them
-
Hi GNUser
You can also use arecord as a command line VU meter:
echo -ne '\033[?25l' # Turns off cursor so it's not flickering.
arecord -D hw:Loopback,1 -V stereo -c 2 -f cd -q /dev/null
To make the cursor visible again:
echo -ne '\033[?25h'
or:
echo -ne '\e[?25h'
-
Hi, Rich!
Nice functionality, thanks for the tip! And its CPU time consumption is very close to zero.
-
Hi, jazzbiker. Byte counts and wav headers are tripping me up, so I dumbed it down for my own use.
I noticed that the wav header changes depending on source, but it is always exactly 44 bytes long.
So dummy approach is to first record known silence and strip the wav header:
arecord -q -D hw:Loopback,1 -f cd -s 1000 | dd skip=44 bs=1 2>/dev/null > $HOME/known-silence.wav
Now we have a reference file that we know represents silence.
After that, we can compare periodic samples of same size (likewise with stripped wav header), to our reference file:
[attached because of broken posting]
-
Hi, GNUser!
The "skip" parameter of dd tells about number of blocks to skip, not bytes,, maybe this looks unexpected.
-
Hi GNUser
Does this attachment work?
-
Hi jazzbiker
The "skip" parameter of dd tells about number of blocks to skip, not bytes,, maybe this looks unexpected.
Yes, but doesn't this set the block size to 1 byte:
bs=1
-
Hi, jazzbiker. I'm good with dd's "skip" and "bs"--that wasn't the trouble. The issue was that sometimes cmp would give unexpected results ($? == 0 when there's sound, $? != 0 when there's silence).
I tried to troubleshoot but was not able to pinpoint the trouble. Using "count=1K" for zeroes.bin but "-s 1100" for the audio samples was particularly confusing to me.
Thanks for introducing me to cmp by the way. Hadn't used that one before. I love the Unix philosophy of having such tiny tools to do one specific job really well :)
Thanks, Rich. The approach in reply #25 is working reliably and I can understand it, so I'm perfectly happy with it.
-
Hi GNUser
... The approach in reply #25 is working reliably and I can understand it, so I'm perfectly happy with it.
That's OK, I was just curious if it worked.
-
Hi jazzbiker
Straight from:
dd --help
It says (emphasis mine):
skip=N skip N ibs-sized blocks at start of input
and:
bs=BYTES read and write up to BYTES bytes at a time (default: 512);
overrides ibs and obs
-
Hi, Rich!
Thanks for reminder, i was trying to guess, what is looking suspicious in the command I proposed. Those 1100 are 1K+ header + extra samples, which were to be cut by dd, precise number not significant. I don't believe, that cmp was making mistakes, wrong output meant something was wrong with the input data.
-
Hi jazzbiker
... I don't believe, that cmp was making mistakes, wrong output meant something was wrong with the input data.
Agreed.
-
Hi, guys!
Those alsa config, which I've found seems too complicated. Additional module to be loaded, long chain of plugins... Of course it works, but I was anxious about the shorter way. If it is not interesting for You, please don't read this post ;)
So, alsa have the plugin, which can write raw headerless data directly into file. And even more, this data can be redirected to the executable, .asoundrc attached. As seen, default device data are passed directly to /home/tc/c/vmeter/vmeter binary through the pipe. vmeter source attached. It keeps file /tmp/volume in accordance with the current signal volume of the alsa output. This file can be monitored in any desirable way, for example
w h i l e t r u e
d o
r e a d N < /tmp/volume
e c h o $N
s l e e p 1
d o n e
Must say, that assumptions are made about data format and channels number - signed 16-bit numbers and 2 channels.