hzeller / gmrender-resurrect

Resource efficient UPnP/DLNA renderer, optimal for Raspberry Pi, CuBox or a general MediaServer. Fork of GMediaRenderer to add some features to make it usable.
GNU General Public License v2.0
832 stars 202 forks source link

Select pulseaudio sink or fifo-pipe to play to #115

Closed maweki closed 6 years ago

maweki commented 7 years ago

As I understand it, gmrender-resurrect plays to alsa only. Is there any way (in pulseaudio, gmrender, with an environment variable, etc) to select beforehand, which pulseaudio sink (or fifo-pipe) to play into? I have a streaming server using snapcast (https://github.com/badaix/snapcast) that uses fifo-pipes on the server (one per zone).

So to use gmrender with this setup, I would either need it to play into a pulseaudio-sink (that is attached to the fifo-pipe, already got that configured), or play into a fifo-pipe directly.

Gmrender would be the missing link in my setup, having mopidy and analog sound-cards already playing into different zones, with published sinks in the network for pulseaudio streaming.

hzeller commented 7 years ago

gmrender-resurrect plays to any gstreamer backend you configure (see gstreamer documentation for that). I only suggest to use alsa, because it is usually the least trouble.

stanelie commented 7 years ago

@maweki Did you manage to do this? I'm trying to do the same thing as you and it's unclear to me.

maweki commented 7 years ago

I managed to use "pulsesink" and the sinkname as parameters. This worked but didn't solve my problem. I tried getting to run a while gstreamer pipeline and that decidedly didn't work, because gmrender-resurrect does something strange with the parameters so that an arbitrary pipeline is just broken.

stanelie commented 7 years ago

hzeller is right, gstreamer supports a wide array of outputs, there is a big list here : https://gstreamer.freedesktop.org/documentation/plugins.html On this list, I find something promising : filesink. It looks like it should do what I want. However, I have no idea how to tell this audio sink where to right to.

A command line example with gstreamer : gst-launch-1.0 v4l2src num-buffers=1 ! jpegenc ! filesink location=capture1.jpeg

@hzeller : how can I specify a location argument when launching gmediarender? I tried gmediarender -f patate --gstout-audiosink=filesink location=/tmp/snapfifo but it fails with gstreamer] sink: Error: No file name specified for writing.

The filesink specs are here : https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-plugins/html/gstreamer-plugins-filesink.html

stanelie commented 7 years ago

progress - somewhat : I edited line 519 of the file /src/output_gstreamer.c so that instead of passing the audio_device parameter, it passes the "location" parameter that filesink expects.

So, it went from g_object_set (G_OBJECT(sink), "device", audio_device, NULL); to g_object_set (G_OBJECT(sink), "location", audio_device, NULL);

I recompiled and tested : it does indeed send the output to the specified file that I set in this command line : ./gmediarender -f banane --gstout-audiosink=filesink --gstout-audiodevice=/tmp/snapfifo

This fifo file (/tmp/snapfifo) is the input "file" of snapcast. Snapcast does indeed receive the stream, but all I get is white noise out of the snapcast clients.

Thoughts?

maweki commented 7 years ago

Yeah, so for gstreamer there shouldn't be two parameters from the client side but one, to build the correct pipeline. Not every pipeline has a "device".

all I get is white noise out of the snapcast clients.

I am also using snapcast and I've never had that problem. Is there something else going on? You can always manually test it with something like this: gst-launch-1.0 filesrc location="/root/notify.mp3" ! decodebin ! audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! filesink location=/tmp/snapfifo

And as one can see here, the full pipeline might have many parameters and no "device"

Edit: that's my pipeline going out of mopidy and my notification-script. That should be the one out of gmrender as well, but it doesn't work because auf the added device (at least I think that's it).

jaecksch commented 7 years ago

I had the same problem, because I was also looking for a dlna renderer for snapcast. I digged into the details and found, that the reason for the noise is the output format. I used an audio pipeline similar to what @maweki proposed to convert. This ended up in a fork https://github.com/jaecksch/gmrender-resurrect. The output format is currently fixed to 44100:16:2 For me it works fine, please test if it works for you too. The audiosink must be named snapcast and the device parameter contains the file to write to.

--gstout-audiosink=snapcast --gstout-audiodevice=/tmp/snapfifo

I tested it with a named pipe, as well with the "process" method via stdout.
For "process" the parameter for snapcast is as follows:

... -s \"process:///usr/local/bin/gmediarender?name=upnp&params=-f Snapcast --gstout-audiosink=snapcast --gstout-audiodevice=/dev/stdout&sampleformat=44100:16:2&codec=flac\" ...

maweki commented 7 years ago

That fork is a little bit heavy on builtin/compiled stuff. Can't we just make the device parameter optional and have correct gstreamer pipe parsing like every other application?

jaecksch commented 7 years ago

Thanks for your comment. Its really heavy change for a very specific application. Based on your comment I used a more generic approach: I added a parameter gstout-audiopipe which makes pipe parsing like gst-launch. Was this your intention? This approach is more flexible for the user and not really big:

if (audio_pipe != NULL)  { 
    GstElement *sink = NULL;
    Log_info("gstreamer", "Setting audio sink-pipeline to %s\n",audio_pipe);
    sink = gst_parse_bin_from_description(audio_pipe,TRUE,NULL);
    if (sink==NULL) {
        Log_error("gstreamer","Could not create pipeline\n")
    }
    else
    {
        g_object_set (G_OBJECT (player_), "audio-sink", sink, NULL);
    }
}

The command line would like like this:

gmediarender --gstout-audiopipe 'audioresample ! audioconvert ! audio/x-raw,rate=44100,channels=2,format=S16LE ! filesink location=/tmp/upnp'

stanelie commented 7 years ago

@jaecksch I'll keep the conversation here as this branch will eventually be merged with this repository, hopefully.

With your latest build piped into Snapcast on OSMC (a dedicated Kodi distro for raspberry pi), I get the wrong music pitch (I think the driver on osmc is running at 48 khz) and silent pauses every few seconds (for the buffer to fill up again?) and I get this repeated error message on the console : ERROR [2017-01-05 20:14:15.431336 | gstreamer] Failed to get track pos

Also, if I set the sample rate at 48 khz with this command line switch : gmediarender --gstout-audiopipe 'audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! filesink location=/tmp/snapfifo'

I get this repeated error message : (gmediarender:13701): GStreamer-CRITICAL **: gst_segment_to_stream_time: assertion 'segment->format == format' failed

Is there any way to make this work on a system running the sound card at 48khz?

stanelie commented 7 years ago

Never mind, the 48000 setting works as it should.

I only have the ERROR [2017-01-05 20:14:15.431336 | gstreamer] Failed to get track pos error, I probably made a typo before.

stanelie commented 7 years ago

Never mind again, the Failed to get track pos error is only present with AirAudio (android app), not with DSub (another android app), so, it's probably the fault of the app.

maweki commented 7 years ago

I added a parameter gstout-audiopipe which makes pipe parsing like gst-launch

That's the best solution, I think. I can't try it right now but if this is available, all advanced use cases should be covered

koenig-dro commented 7 years ago

looking this issue for help with the same problem. I am new to linux and tried to set up an multi-room system with high women-acceptance-factor....

My english isnt perfect, so my question: How to solve it; Is it solvable? I tried some things from this thread, but nothing worked..just white noise as stanelie at Dec 15 says.. Open for help in german, or light english

dddesign commented 6 years ago

I'm using this code, not the fork of jaecksch! gmediarender -f "mediarenderer" --logfile=/dev/stdout --gstout-initial-volume-db=-10 --gstout-audiosink=filesink --gstout-audiodevice=/tmp/snapfifo is not working, I get this error Error: No file name specified for writing. so how can I specify the file name? I one comment option --gstout-audiopipe is mentioned, but this does not exist... any tips?

dddesign commented 6 years ago

UPDATE: I replaced src/output_gstreamer.c with the version of jaecksch/gmrender-resurrect so I get the --gstout-audiopipe option, so know it's working!

maweki commented 6 years ago

Yeah. It's sad to see that specifying a generic pipe hasn't found its way into gmrender. Any advanced pipeline is impossible and you're stuck with a few possible options.

hzeller commented 6 years ago

Sending a pull request that fixes the itch it is probably more fruitful than being passive aggressive about it.

gerroon commented 6 years ago

Hi

Is this merged in to the main code? I need to cast it to Snapcast as well, but the filefinsk with fifo does not workas others stated here.

this is what I have gmediarender 0.0.7-git; 0.0.7-git

hzeller commented 6 years ago

Now it is :) (github makes it hard to discover pending pull requests, so they sometimes go unnoticed)

gerroon commented 6 years ago

@hzeller thanks!!!!!!!!!!

gerroon commented 6 years ago

ok here is initial test

/usr/local/bin/gmediarender  -gstout-audiosink=filesink  --gstout-audiopipe=/tmp/snapfifo

gmediarender 0.0.7-git started [ gmediarender 2018-06-18_d0f46f5 (libupnp-1.6.24; glib-2.56.1; gstreamer-1.14.1) ].
Logging switched off. Enable with --logfile=<filename> (e.g. --logfile=/dev/stdout for console)
ERROR [2018-06-18 19:30:00.807502 | gstreamer] --gstout-audosink and --gstout-audiopipe are mutually exclusive.
ERROR [2018-06-18 19:30:00.807521 | main] ERROR: Failed to initialize Output subsystem
/usr/local/bin/gmediarender  --gstout-audiopipe=/tmp/snapfifo

0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 >)                                                                                                                             
)                                                                                                                                                                         
ERROR [2018-06-18 19:22:43.378267 | gstreamer] source: Error: Internal data stream error. (Debug: gstbasesrc.c(3055): gst_base_src_loop (): /GstPlayBin:play/GstURIDecodeBin:uridecodebin1/GstSoupHTTPSrc:source:                                                                                                                                   
streaming stopped, reason not-linked (-1))                                                                                                                                
ERROR [2018-06-18 19:22:47.136208 | upnp] upnp_set_error: Pause failed 

also tried withoiut success.

gmediarender --gstout-audiopipe 'audioresample ! audioconvert ! audio/x raw,rate=44100,channels=2,format=S16LE ! filesink location=/tmp/snapfifo'
gerroon commented 6 years ago

Nevermind! I was not sure about the right option and my snapclient crashed when testing the last method. The last option seems to work.

maweki commented 6 years ago

How did it work at the end and what options does the fix give?

gerroon commented 6 years ago

I am using this one

gmediarender --gstout-audiopipe 'audioresample ! audioconvert ! audio/x raw,rate=44100,channels=2,format=S16LE ! filesink location=/tmp/snapfifo'

debfx commented 6 years ago

FWIW the default sample rate of snapcast is 48000 (check snapserver --help).

You can also let snapserver start gmediarender like this: snapserver -s "process:///usr/bin/gmediarender?name=DLNA&params=--gstout-audiopipe 'audioresample ! audioconvert ! audio/x-raw,rate=48000,channels=2,format=S16LE ! wavenc ! filesink location=/dev/stdout' --logfile /dev/null"

claes commented 4 years ago

When using command arguments like above, it worked well for some audio, but not others. For example, some podcasts worked but others were too fast or too slow. Now instead I use the command line

--gstout-audiosink=alsasink --gstout-audiodevice=snapcast

combined with /etc/asound.conf like below

    pcm.snapcast {
        type rate
        slave {
            pcm writeSnapFifo # Direct to the plugin which will write to a file
            format S16_LE
            rate 48000
        }
    }

    pcm.writeSnapFifo {
        type file
        slave.pcm null
        file "/tmp/snapfifo"
        format "raw"
    }

And it seems to adjust better to differences in the source audio format

mill1000 commented 4 years ago

Here's the correct audio pipeline to handle different sample rates and bit depth.

gmediarender --gstout-audiopipe 'audioresample ! audio/x-raw, rate=44100, format=S16LE ! filesink location=/tmp/fifo'