Hi everybody,

As some of you know, liquidsoap is a bit limited in its realtime
interaction with the outside. There are still issues with ALSA and
RTP. Our ALSA I/O doesn't handle the case when ALSA doesn't accept
liquidsoap's buffer size as its internal buffer size. This could be
fixed, but anyway, ALSA is not very portable and is only local.
Regarding RTP there certainly are some problems with metadata
transmission, and it seems to slowly get out of sync if I remember
well -- it had to ignore warnings from the lib. It's be nice to know
more clearly the status of RTP actually.. but anyway, it's
liquidsoap-only.

A possibility I evoked is to embed minimal icecast (actually, HTTP)
features: allow source clients and source listeners to connect to
liquidsoap directly. First, this would remove the active wait that
input.http() currently does. Then it would be unbuffered, meant for
being used of reliable network connections, allowing near-realtime
communication: hear what's going on, interact with it immediately by
sending something. Finally, Romain pointed out that it'd also be
possible to stream WAV over HTTP in order to avoid encoding/decoding
-- but how to encode metadata then? And I almost forgot: it's very
standard and allows to use a lot of existing tools.

Anyway, I decided not to work on that right now. But I wanted to know
if it's worth trying hard. So I came up with two sources (in less than
an hour!) which are very crappy but give an idea of what's possible. I
attached the source code, and let you add them to liquidsoap (put them
in src/outputs and src/sources, edit src/Makefile, recompile). Code
re-use is not at its best, I'd be happy to improve that to make the
code clearer if anyone wants to understand/improve. It's really small
and simple.

What I tried: three instances of liquidsoap on my laptop.
I use the shortcut mksafe = fun (s) ->
fallback(track_sensitive=false,[s,blank()])
(1) output.http.passive(8888,mksafe(input.http.passive(7777)))
(2) output.icecast(port=7777,mount="whatever",single("file.ogg"))
(3) output.ao(mksafe(input.http("http://localhost:8888/dontcare";)))

The first one is a sort of mini icecast. It relays an input stream
(vorbis only). The second one sends a stream to the first. And the
third reads from the first, plays to the speakers. Ogg123 can be used
instead of the third, but it's buffered.

The point here was to see how much latency we have. There is almost no
buffering, except a little involved by vorbis decoding. For example if
you start the reader when (1) is streaming blank -- i.e. when (2) is
not yet started -- it seems to accumulate data... If you start them in
order, we get a pretty low latency, but not null, about half a second.
To measure that I skipped in (2) and waited to hear the track restart
on (3). Testing with a microphone is possible, replacing (2) by
darkice.

You'll notice that my files are very incomplete, don't handle
disconnections & other problems. It's just meant to check that this
idea is a good one, estimate if the remaining latency is still too
high, and work to reduce it (there might be room for it as I didn't
care at all here). Then if somebody want to do the full
implementation, easy to use (don't allocate one port per operator,
handle errors, maybe passwords..) that'd be cool, but it won't be me
in the near future :p

Cheers.
--
David

Attachment: http_output.ml
Description: Binary data

Attachment: http_passive.ml
Description: Binary data

Répondre à