Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

can liquidsoap listen/produce for RTP streams? #109

Open
anarcat opened this issue Oct 21, 2013 · 13 comments
Open

can liquidsoap listen/produce for RTP streams? #109

anarcat opened this issue Oct 21, 2013 · 13 comments

Comments

@anarcat
Copy link

anarcat commented Oct 21, 2013

I have come to like RTP to produce a low-latency, high quality (but incidentally high bandwidth) stream within the house. I currently use MPD to stream audio to icecast and RTP, as described here. I know I can make liquidsoap stream to/from icecast fairly easily, but then I can't make it stream RTP in a meaningful way. I have tried various hacks with mplayer, pipes and all sorts of hacks, but couldn't get anything reliable going.

@toots
Copy link
Member

toots commented Oct 24, 2013

This is not supported for now, unfortunately. I would love to add RTP support but I don't think we've ever come to a library simple enough to be used. Do you know of one that you would recommend?

@anarcat
Copy link
Author

anarcat commented Oct 24, 2013

So far I have used:

  • VLC (cvlc rtp://@224.0.0.56:5004)
  • mplayer (mplayer -demuxer rawaudio -rawaudio format=0x20776172 rtp://224.0.0.56:5004)
  • pulseaudio (server side: load-module module-rtp-send source=rtp.monitor port=5004 loop=1 and load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100 sink_properties="device.description='RTP Multicast Sink'")
  • gstreamer (gst-launch udpsrc multicast-group=224.0.0.56 port=5004 ! "application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10" ! rtpL16depay ! audioconvert ! alsasink)

I am guessing gstreamer may be the solution since liquidsoap already supports it, but it doesn't work at all in Debian right now (or is this 1.0?): http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=727044

I am not sure a library would suffice either, as it may not appear as "playing" if no stream is available... I guess this should be tested...

@smimram
Copy link
Member

smimram commented Oct 24, 2013

I also think that

input.gstreamer.audio("udpsrc multicast-group=224.0.0.56 port=5004 ! "application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10" ! rtpL16depay ! audioconvert")

is the right solution. I am currently using 1.1.1-6 version of liquidsoap in Debian (testing) and just tested that gstreamer is working. I think that Sourcefabric has updated packages for currenst stable Debian here: http://apt.sourcefabric.org/

@anarcat
Copy link
Author

anarcat commented Feb 5, 2014

Okay for that's for listening on a multicast RTP stream, how about generating one?

@anarcat
Copy link
Author

anarcat commented Feb 5, 2014

Also, while this works:

gst-launch udpsrc multicast-group=224.0.0.56 port=5004 ! "application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10" ! rtpL16depay ! audioconvert ! alsasink

This doesn't:

liquidsoap 'out(input.gstreamer.audio(pipeline="udpsrc multicast-group=224.0.0.56 port=5004 ! \"application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10\" ! rtpL16depay ! audioconvert ! alsasink sync=false"))'

Because:

gst-launch audiotestsrc ! audioconvert ! alsasink

and:

liquidsoap 'out(input.gstreamer.audio(pipeline="audiotestsrc"))'

yield the same result, I would have assumed this would work, but whereas the latter eventually yields:

2014/02/04 23:18:25 [clock.wallclock_pulse:3] Streaming loop starts, synchronized by active sources.
2014/02/04 23:18:25 [mksafe:3] Switch to safe_blank.
2014/02/04 23:18:25 [mksafe:3] Switch to input(dot)gstreamer(dot)audio_video_9110 with transition.

the other never switches to the gstreamer input:

anarcat@marcos:~$ liquidsoap 'out(input.gstreamer.audio(pipeline="udpsrc multicast-group=224.0.0.56 port=5004 ! \"application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10\" ! rtpL16depay"))'
ERROR: Could not load classifier cascade /usr/share/opencv/haarcascades/haarcascade_frontalface_alt2.xml
Failed to register plugin /usr/lib/frei0r-1/facedetect.so: Frei0r.Failure
2014/02/04 23:19:06 >>> LOG START
2014/02/04 23:19:06 [protocols.external:3] Found "/usr/bin/wget".
2014/02/04 23:19:06 [main:3] Liquidsoap 1.1.1
2014/02/04 23:19:06 [main:3] Using: graphics=[distributed with Ocaml] pcre=7.0.2 dtools=0.3.1 duppy=0.5.1 duppy.syntax=0.5.1 cry=0.2.2 mm=0.2.1 xmlplaylist=0.1.3 lastfm=0.3.0 ogg=0.4.5 vorbis=0.6.1 opus=0.1.0 speex=0.2.0 mad=0.4.4 flac=0.1.1 flac.ogg=0.1.1 dynlink=[distributed with Ocaml] lame=0.3.2 shine=0.1.1 gstreamer=0.2.0 frei0r=0.1.0 voaacenc=0.1.0 theora=0.3.0 schroedinger=0.1.0 gavl=0.1.5 bjack=0.1.4 alsa=0.2.1 ao=0.2.0 samplerate=0.1.2 taglib=0.3.1 magic=0.7.3 camomile=0.8.4 inotify=1.0 faad=0.3.2 soundtouch=0.1.7 portaudio=0.2.0 pulseaudio=0.1.2 ladspa=0.1.4 dssi=0.1.1 sdl=0.9.1 camlimages=4.0.0 lo=0.1.0 yojson=1.1.7 gd=1.0a5
2014/02/04 23:19:06 [dynamic.loader:3] Could not find dynamic module for fdkaac encoder.
2014/02/04 23:19:06 [dynamic.loader:3] Could not find dynamic module for aacplus encoder.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/mad.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/shine.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/frei0r.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/oss.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/ao.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/ladspa.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/ogg.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/dssi.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/pulseaudio.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/bjack.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/speex.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/xmlplaylist.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/samplerate.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/soundtouch.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/gavl.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/portaudio.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/theora.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/vorbis.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/taglib.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/lo.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/lame.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/gstreamer.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/camlimages.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/flac_ogg.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/cry.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/voaacenc.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/sdl.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/opus.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/graphics.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/flac.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/faad.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/schroedinger.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/gd.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/alsa.cmxs.
2014/02/04 23:19:06 [dynamic.loader:2] Loaded plugin file /usr/lib/liquidsoap/1.1.1/plugins/lastfm.cmxs.
2014/02/04 23:19:06 [frame:3] Using 44100Hz audio, 25Hz video, 44100Hz master.
2014/02/04 23:19:06 [frame:3] Frame size must be a multiple of 1764 ticks = 1764 audio samples = 1 video samples.
2014/02/04 23:19:06 [frame:3] Targetting 'frame.duration': 0.04s = 1764 audio samples = 1764 ticks.
2014/02/04 23:19:06 [frame:3] Frames last 0.04s = 1764 audio samples = 1 video samples = 1764 ticks.
2014/02/04 23:19:06 [threads:3] Created thread "generic queue #1".
2014/02/04 23:19:06 [threads:3] Created thread "generic queue #2".
2014/02/04 23:19:06 [threads:3] Created thread "wallclock_pulse" (1 total).
2014/02/04 23:19:06 [clock.wallclock_pulse:3] Streaming loop starts, synchronized by active sources.
2014/02/04 23:19:06 [mksafe:3] Switch to safe_blank.

@anarcat
Copy link
Author

anarcat commented Feb 5, 2014

oh oh oh, i found it:

liquidsoap 'out(input.gstreamer.audio(pipeline="udpsrc multicast-group=224.0.0.56 port=5004 caps=\"application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10\" ! rtpL16depay"))'

i was missing the caps= bit, which seems to be optional on the commandline! --debug helped quite a bit in debugging that.

And now it works and fallbacks as well! ie. this also works:

rtpsrc = input.gstreamer.audio(pipeline="udpsrc multicast-group=224.0.0.56 port=5004 caps=\"application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10\" ! rtpL16depay")
security = single('/srv/mp3/misc/smash.mp3')
radio= fallback([rtpsrc,security])
out(radio)

Unfortunately the fallback starts first, and there's a ~5 seconds delay when the rtp stream goes blank, but it works.

@anarcat
Copy link
Author

anarcat commented Feb 5, 2014

I also found out how to produce the RTP stream, so here's everything from the top:

generating the stream

liquidsoap 'output.gstreamer.audio(single("/srv/mp3/misc/smash.mp3"), pipeline="audioconvert ! rtpL16pay ! udpsink host=224.0.0.56 auto-multicast=true port=5004")'

listening to the stream

liquidsoap 'out(input.gstreamer.audio(pipeline="udpsrc multicast-group=224.0.0.56 port=5004 caps=\"application/x-rtp, media=(string)audio, clock-rate=44100, payload=(int)10\" ! rtpL16depay"))'

boo-ya. i guess we can close this now, although having that documentation somewhere would just rock.

@anarcat
Copy link
Author

anarcat commented Feb 5, 2014

So while this works in and out, it won't work with VLC or other clients, because the udpsink doesn't seem to send SDP announcements to describe the stream. VLC complains with:

anarcat@marcos:~$ cvlc rtp://@224.0.0.1:5004
VLC media player 2.1.2 Rincewind (revision 2.1.2-0-ga4c4876)
[0x1ac9588] dummy interface: using the dummy interface module...
[0x7eff48000e28] rtp demux error: unspecified payload format (type 96)
[0x7eff48000e28] rtp demux: A valid SDP is needed to parse this RTP stream.
[0x7eff48000e28] main demux error: SDP required
[0x7ff7c4000e38] main demux error: A description in SDP format is required to receive the RTP stream. Note that rtp:// URIs cannot work with dynamic RTP payload format (96).

@anarcat
Copy link
Author

anarcat commented Feb 5, 2014

The fix is of course to work pulseaudio:

output.pulseaudio(final)

and then set a default sink in PA:

# we need the following config appended to a default.pa:
load-module module-null-sink sink_name=rtp format=s16be channels=2 rate=44100 sink_properties="device.description='RTP Multicast Sink'"
load-module module-rtp-send source=rtp.monitor port=5004 destination_ip=224.0.0.1 loop=1
set-default-sink rtp

@dbaelde
Copy link
Member

dbaelde commented Aug 25, 2015

What's the status here? I the recipe stable enough? If so, could you please document it as an extra page in doc/content and create a pull request?

@anarcat
Copy link
Author

anarcat commented Aug 25, 2015

the recipe works, but i have given up on the whole stack because of latency problems after an upgrade to debian jessie... not sure what happened there. the jukebox is just turned off now... but my last comment here worked and could be reused.

@kmahelona
Copy link

According to this documentation , you need to create a .sdp file and open that in VLC:

v=0
m=video 5000 RTP/AVP 96
c=IN IP4 127.0.0.1
a=rtpmap:96 MP4V-ES/90000

While that's for video, perhaps if you change it for audio it might work? I'm gonna give this a try. I'd like Airtime to have a low latency stream back to our station.

@anarcat
Copy link
Author

anarcat commented Jan 20, 2017

for the record, i turned off RTP here because of the interference it does over wifi - it completely destroys the network here...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants