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
851 stars 206 forks source link

DSD Native #260

Open antonellocaroli opened 1 year ago

antonellocaroli commented 1 year ago

It seems that someone is working on dsd integration in gstreamer, with already some results

https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/issues/972#note_1759303

Do you think that when it is merged with the main branch, it can be supported by gmediarender? I assume you would need to add a dsd option that would call up

--audiosink="dsdconvert ! alsasink device=........"

https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3901

mill1000 commented 1 year ago

The MR specifies that auto-plugging works. If we're lucky gmrender won't have to do anything at all.

antonellocaroli commented 1 year ago
gmediarender -f "PCx86" --gstout-audiopipe dsdconvert ! alsasink device=hw:CARD=Audio,DEV=0
gmediarender 0.1 started [ gmediarender 0.1_git2023-01-03_c455d13 (libupnp-1.14.15; glib-2.74.3; gstreamer-1.20.4) ].
Logging switched off. Enable with --logfile=<filename> (or --logfile=stdout for console)
Ready for rendering.
ERROR [2023-02-09 06:59:34.881789 | gstreamer] avdemux_dsf0: Error: Internal data stream error. (Debug: ../gst-libav-1.20.4/ext/libav/gstavdemux.c(1663): gst_ffmpegdemux_loop (): /GstPlayBin:play/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/avdemux_dsf:avdemux_dsf0:
streaming stopped, reason not-linked (-1))
ERROR [2023-02-09 06:59:34.882001 | gstreamer] aqueue: Error: Internal data stream error. (Debug: ../gstreamer-1.20.4/plugins/elements/gstqueue.c(992): gst_queue_handle_sink_event (): /GstPlayBin:play/GstPlaySink:playsink/GstBin:abin/GstQueue:aqueue:
streaming stopped, reason not-linked (-1))
ERROR [2023-02-09 06:59:35.129100 | gstreamer] Failed to get track duration.
ERROR [2023-02-09 06:59:35.129172 | gstreamer] Failed to get track pos
ERROR [2023-02-09 06:59:35.629323 | gstreamer] Failed to get track duration.
ERROR [2023-02-09 06:59:35.629382 | gstreamer] Failed to get track pos
ERROR [2023-02-09 06:59:36.129531 | gstreamer] Failed to get track duration.
ERROR [2023-02-09 06:59:36.129592 | gstreamer] Failed to get track pos
ERROR [2023-02-09 06:59:36.629751 | gstreamer] Failed to get track duration.
ERROR [2023-02-09 06:59:36.629808 | gstreamer] Failed to get track pos
ERROR [2023-02-09 06:59:37.129953 | gstreamer] Failed to get track duration.
ERROR [2023-02-09 06:59:37.130010 | gstreamer] Failed to get track pos
ERROR [2023-02-09 06:59:37.630154 | gstreamer] Failed to get track duration.
ERROR [2023-02-09 06:59:37.630209 | gstreamer] Failed to get track pos
ERROR [2023-02-09 06:59:38.130365 | gstreamer] Failed to get track duration.
ERROR [2023-02-09 06:59:38.130427 | gstreamer] Failed to get track pos
mill1000 commented 1 year ago

Did you build the referenced merge request? Is that what we're seeing?

Can you try the commands they MR used as example? e.g.

gst-play-1.0 --audiosink="dsdconvert ! alsasink device=hw:3,0" test-dsd-128.dsf
antonellocaroli commented 1 year ago

Did you build the referenced merge request? Is that what we're seeing?

Yes

Can you try the commands they MR used as example? e.g.

gst-play-1.0 --audiosink="dsdconvert ! alsasink device=hw:3,0" test-dsd-128.dsf

yes it works.

gst-play-1.0 --verbose --gapless --audiosink="dsdconvert ! alsasink device=hw:2,0" /tmp/01\ -\ David\ Elias\ -\ The\ Window\ -\ Vision\ of\ Her\ \(DSD64\).dsf 
Press 'k' to see a list of keyboard shortcuts.
Now playing /tmp/01 - David Elias - The Window - Vision of Her (DSD64).dsf
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0: ring-buffer-max-size = 0
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0: buffer-size = -1
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0: buffer-duration = -1
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0: force-sw-decoders = false
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0: use-buffering = false
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0: download = false
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0: uri = file:///tmp/01%20-%20David%20Elias%20-%20The%20Window%20-%20Vision%20of%20Her%20(DSD64).dsf
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0: connection-speed = 0
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0: source = "\(GstFileSrc\)\ source"
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstTypeFindElement:typefind.GstPad:src: caps = application/x-gst-av-dsf
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstTypeFindElement:typefind.GstPad:src: caps = NULL
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstMultiQueue:multiqueue0: max-size-buffers = 5
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstMultiQueue:multiqueue0: max-size-time = 0
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstMultiQueue:multiqueue0: max-size-bytes = 8388608
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstMultiQueue:multiqueue0.GstMultiQueuePad:sink_0: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0/GstMultiQueue:multiqueue0.GstMultiQueuePad:src_0: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstInputSelector:inputselector0.GstSelectorPad:sink_0: always-ok = false
/GstPlayBin:playbin/GstInputSelector:inputselector0.GstSelectorPad:sink_0: active = true
/GstPlayBin:playbin/GstInputSelector:inputselector0: active-pad = "\(GstSelectorPad\)\ sink_0"
/GstPlayBin:playbin/GstPlaySink:playsink: volume = 1
/GstPlayBin:playbin/GstPlaySink:playsink: mute = false
/GstPlayBin:playbin/GstInputSelector:inputselector0.GstPad:src: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink.GstGhostPad:audio_sink.GstProxyPad:proxypad5: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstTee:audiotee.GstTeePad:src_0: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstStreamSynchronizer:streamsynchronizer0.GstStreamSyncPad:src_0: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin.GstGhostPad:sink.GstProxyPad:proxypad8: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstQueue:aqueue.GstPad:sink: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstQueue:aqueue.GstPad:src: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstQueue:aqueue.GstPad:src: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstQueue:aqueue.GstPad:src: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink.GstGhostPad:audio_sink: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstInputSelector:inputselector0.GstSelectorPad:sink_0: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0.GstGhostPad:src_0.GstProxyPad:proxypad4: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstURIDecodeBin:uridecodebin0/GstDecodeBin:decodebin0.GstDecodePad:src_0.GstProxyPad:proxypad3: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstPlaySinkAudioConvert:aconv.GstGhostPad:sink.GstProxyPad:proxypad6: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstInputSelector:inputselector0.GstSelectorPad:sink_0: tags = taglist, title=(string)"Vision\ of\ Her", artist=(string)"David\ Elias", genre=(string)Folk, encoder=(string)"KORG\ AudioGate\ ver.1.5.0", datetime=(datetime)2007-11-20T22:52Z;
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstPlaySinkAudioConvert:aconv/GstIdentity:identity.GstPad:src: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstInputSelector:inputselector0.GstSelectorPad:sink_0: tags = taglist, title=(string)"Vision\ of\ Her", artist=(string)"David\ Elias", genre=(string)Folk, encoder=(string)"KORG\ AudioGate\ ver.1.5.0", datetime=(datetime)2007-11-20T22:52Z, audio-codec=(string)"DSD\ \(Direct\ Stream\ Digital\)\,\ least\ significant\ bit\ first\,\ planar";
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstPlaySinkAudioConvert:aconv.GstGhostPad:src: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstBin:bin0.GstGhostPad:sink.GstProxyPad:proxypad0: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstBin:bin0/GstDsdConvert:dsdconvert0.GstPad:src: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU32BE, layout=(string)interleaved, reversed-bytes=(boolean)false
Redistribute latency...
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstBin:bin0/GstAlsaSink:alsasink0.GstPad:sink: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU32BE, layout=(string)interleaved, reversed-bytes=(boolean)false
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstBin:bin0/GstDsdConvert:dsdconvert0.GstPad:sink: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstBin:bin0.GstGhostPad:sink: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstPlaySinkAudioConvert:aconv.GstGhostPad:src.GstProxyPad:proxypad7: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstPlaySinkAudioConvert:aconv/GstIdentity:identity.GstPad:sink: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
/GstPlayBin:playbin/GstPlaySink:playsink/GstBin:abin/GstPlaySinkAudioConvert:aconv.GstGhostPad:sink: caps = audio/x-dsd, rate=(int)352800, channels=(int)2, channel-mask=(bitmask)0x0000000000000003, format=(string)DSDU8, reversed-bytes=(boolean)true, layout=(string)non-interleaved
Redistribute latency...
0:01:48.3 / 0:05:07.1

But it is probably best to wait for the full integration....see todo

TODO: It is currently unclear if DSD conversion should be done automatically inside alsasink / audioringbuffer / audiobasesink. On one hand, from what I gather, such conversions are generally preferred to exist as separate elements, so integrated converters are less "gstreamer-like". On the other hand, you pretty much always have to insert a dsdconvert element in real world use cases that may involve DSD. This gets especially tricky if the same pipeline shall handle both PCM and DSD. That's because dsdconvert only handles DSD, and audioconvert does not handle DSD.
Perhaps one option would be to integrate the DSD converter into audioconvert. But - this would allow for DSD <-> PCM cases, which are covered by neither the DSD conversion functions nor the GstAudioConverter. (DSD -> PCM is covered by the avdec_dsd_ decoders; PCM -> DSD currently does not exist.)
Another option would be to add the gst_dsd_convert function (from the public gstdsd.h API) inside audioringbuffer. But, as said above, it is unclear if this is considered OK.
This MR is marked as a draft because of this open TODO.
MMinga commented 9 months ago

I tried it on my system, Armibian. But I cannot hear sound, other formats work, where is my fault? bash -c "sleep 10 && /home/minganoise/gmrender-resurrect/./src/gmediarender -f 'Volumio Album Mode' --uuid 666666 -p 49157 -d --gstout-initial-volume-db=-15 --gstout-audiopipe ' rgvolume pre-amp=0 headroom=0 album-mode=TRUE ! rglimiter ! dsdconvert ! autoaudiosink '"

cometdom commented 8 months ago

Hi, apparently, DSD is supported since GStreamer version 1.24. "DSD audio support

  1. DSD audio is a non-PCM raw audio format representation and the GstAudio library gained support for this in form of new GstDsdInfo and GstDsdFormat API.
  2. Support for DSD audio has been implemented in alsasink as well as the GstAudioSink and GstAudioRingBuffer base classes, and the gst-libav plugin to enable FFmpeg-based DSD elements and functionality."