[alsa-devel] alsa-lib Plugin: File deadlock when piping to shell command
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
participants (1)
-
GitHub issues - edited