[alsa-devel] alsa-lib Plugin: File deadlock when piping to shell command
GitHub issues - edited
github at alsa-project.org
Thu Nov 21 22:26:36 CET 2019
alsa-project/alsa-lib issue #14 was edited from bharris6:
When using the [ALSA File plugin](https://www.alsa-project.org/alsa-doc/alsa-lib/pcm_plugins.html) you can tell it to pipe playback data to either a file or a program/shell command.
>Output filename (or shell command the stream will be piped to if STR starts with the pipe char).
Piping to a shell command (as shown below) causes a deadlock where alsa waits for the shell command to return at the same time that the shell command is waiting for alsa to write to its STDIN.
>From the [source code](https://github.com/alsa-project/alsa-lib/blob/master/src/pcm/pcm_file.c), it appears that [popen](https://pubs.opengroup.org/onlinepubs/009695399/functions/popen.html) is being used to initialize/open the output file specified in configuration:
static int snd_pcm_file_open_output_file(snd_pcm_file_t *file)
{
int err, fd;
/* fname can contain keys, generating final_fname */
err = snd_pcm_file_replace_fname(file, &(file->final_fname));
if (err < 0)
return err;
/*printf("DEBUG - original fname: %s, final fname: %s\n",
file->fname, file->final_fname);*/
if (file->final_fname[0] == '|') {
/* pipe mode */
FILE *pipe;
/* clearing */
pipe = popen(file->final_fname + 1, "w");
if (!pipe) {
SYSERR("running %s for writing failed",
file->final_fname);
return -errno;
}
fd = dup(fileno(pipe));
err = -errno;
pclose(pipe);
if (fd < 0) {
SYSERR("unable to dup pipe file handle for command %s",
file->final_fname);
return err;
Although I can confirm the file I pass in my ALSA configuration gets started fine, it never receives anything on its `stdin` like ALSA's (and popen's) documentation states it should:
>If mode is w, *when the child process is started its file descriptor STDIN_FILENO shall be the readable end of the pipe*, and the file descriptor fileno(stream) in the calling process, where stream is the stream pointer returned by popen(), shall be the writable end of the pipe.
My /etc/asound.conf:
pcm.!default {
type plug
slave.pcm "duplicator
}
pcm.default {
type plug
slave.pcm "duplicator"
}
pcm.dmixer {
type dmix
ipc_key 1024
ipc_key_add_uid false
ipc_perm 0666
slave {
pcm "hw:0,0"
period_time 0
period_size 1024
buffer_size 8192
rate 44100
}
}
pcm.duplicator {
type plug
slave.pcm {
type multi
slave {
a { pcm "dmixer" channels 2 }
b { pcm "fileout" channels 2 }
}
bindings [
{ slave a channel 0 }
{ slave a channel 1 }
{ slave b channel 0 }
{ slave b channel 1 }
]
}
ttable [
[ 1 0 1 0 ]
[ 0 1 0 1 ]
]
}
pcm.fileout {
type file
slave.pcm "null"
file "|safe_fifo_alt"
format raw
perm 0666
}
safe_fifo_alt:
#!/usr/bin/python3
import os, sys
BUFFER_SIZE = 16384
path = "/tmp/audio"
if not os.path.exists(path):
os.mkfifo(path)
_fifo_in = os.open(path, os.O_RDONLY | os.O_NONBLOCK)
_fifo_out = os.open(path, os.WR_ONLY | os.O_NONBLOCK)
for chunk in iter(lambda: sys.stdin.buffer.read(BUFFER_SIZE), b''):
os.write(_fifo_out, chunk)
os.close(_fifo_in)
os.close(_fifo_out)
I based `safe_fifo_alt` on [safe_fifo](https://github.com/dpayne/cli-visualizer/blob/master/bin/safe_fifo.c) from `cli-visualizer`. They both hang indefinitely on their STDIN read because alsa is hanging on its `pclose()`.
I've tested an alternative method to simulate the popen and pipe into their STDIN to make sure it worked, specifically:
head -c 500 /dev/urandom | sh -c safe_fifo_alt
It appears this was changed in revision 22ade9b8c150240a960ca683ee6d8f53ce8bc6ea, where the `dup()` and `pclose()` calls were added and introduced the deadlock.
Issue URL : https://github.com/alsa-project/alsa-lib/issues/14
Repository URL: https://github.com/alsa-project/alsa-lib
More information about the Alsa-devel
mailing list