alsa-devel.alsa-project.org archive mirror
 help / color / mirror / Atom feed
From: GitHub issues - opened <github@alsa-project.org>
To: alsa-devel@alsa-project.org
Subject: [alsa-devel] alsa-lib Plugin: File deadlock when piping to shell command
Date: Thu, 21 Nov 2019 22:24:55 +0100 (CET)	[thread overview]
Message-ID: <20191121212455.1295BF80146@alsa1.perex.cz> (raw)
In-Reply-To: <1574371491782548904-webhooks-bot@alsa-project.org>

alsa-project/alsa-lib issue #14 was opened 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 022c790aabc300eabad4da8947a3f2bdadce41e1, 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
_______________________________________________
Alsa-devel mailing list
Alsa-devel@alsa-project.org
https://mailman.alsa-project.org/mailman/listinfo/alsa-devel

       reply	other threads:[~2019-11-21 21:25 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <1574371491782548904-webhooks-bot@alsa-project.org>
2019-11-21 21:24 ` GitHub issues - opened [this message]
     [not found] <1574371594062711000-webhooks-bot@alsa-project.org>
2019-11-21 21:26 ` [alsa-devel] alsa-lib Plugin: File deadlock when piping to shell command GitHub issues - edited

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191121212455.1295BF80146@alsa1.perex.cz \
    --to=github@alsa-project.org \
    --cc=alsa-devel@alsa-project.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).