DISCLAIMER:
I am not a programmer, but only a copy-paster-enthusiast who shares what he could figure out. Therefore, it is possible that knowledgeable experts may find some points or formulations incorrect or ridiculous.
The submission of this material assumes that you have a some level of knowledge of Liquidsoap.
Anyway, the following articles and tutorials will help you figure it out:
Creating a 24/7 stream (Liquidsoap)
Creating a 24/7 stream part 2(Liquidsoap)
Your own Restream Server(nginx_rtmp)
The syntax and methods described in this article should technically work in Liquidsoap versions 2.1.x - 2.2.x
My version at the time of publication is 2.2.3
Introduction and pre-setup
Well, in the post Creating a 24/7 stream part 2(Liquidsoap) I described the possibility of direct connection of audio streams to the stream via the input.harbor
operator. However, Liquidsoap also provides a mechanism for connecting rtmp sources, for example, a stream from OBS.
In this article, I will show several examples of configuring such connections: using the built-in capabilities of Liquidsoap and by enabling the nginx-rtmp stream.
By default, rtmp connections use port 1935. Therefore, in order to avoid possible conflicts (for example, with the nginx-rtmp that will occupy it), I recommend configuring an additional port in the firewall, for example, 1969, which will be used in Liquidsoap.
input.rtmp
For clarity, let’s take a fragment of the script, based on previous articles: where we have a playlist with audio files and looped animation as a background, grouped into a single radio
source:
audio = playlist(reload_mode="watch", "/home/user/radio/music")
audio = mksafe(audio)
background = single("/home/user/radio/background.gif")
radio = source.mux_video(video=background, audio)
#radio = mux_video(video=background, audio) for 2.1.x versions
Now let’s add the live
source for rtmp connections here:
audio = playlist(reload_mode="watch", "/home/user/radio/music")
audio = mksafe(audio)
background = single("/home/user/radio/background.gif")
radio = source.mux_video(video=background, audio)
#radio = mux_video(video=background, audio) for 2.1.x versions
live = input.rtmp(listen=true, "rtmp://localhost:1969/live/key")
Let me explain what happens here:
The listen=true
parameter means that Liquidsoap acts as an independent rtmp server and “listens” to the rtmp address specified next in order to pick up the stream from there when it connects.
In the address, the values of live
and key
can be substituted for any of your invented ones. You then specify this address in OBS to send a stream there, where localhost:1969
is your VPS IP and port, and key
is the stream key.
Next, we combine radio
and live
into a stream
source with a fallback
–switch
so that the playlist automatically switches from playlist to live stream:
audio = playlist(reload_mode="watch", "/home/user/radio/music")
audio = mksafe(audio)
background = single("/home/user/radio/background.gif")
radio = source.mux_video(video=background, audio)
#radio = mux_video(video=background, audio) for 2.1.x versions
live = input.rtmp(listen=true, "rtmp://localhost:1969/live/key")
stream = fallback(track_sensitive=false, [live, radio])
The track_ensitive=false
parameter means that the playlist will immediately switch to the rtmp source without waiting for the track to finish playing.
Set track_sensitive=true
so that the sources switch only when the current track ends. But keep in mind that this can create additional load on the CPU and, accordingly, cause unwanted lags.
If you created your script based on my previous guides, then note that now you will need to specify stream
in output.url()
instead of radio
:
audio = playlist(reload_mode="watch", "/home/user/radio/music")
audio = mksafe(audio)
background = single("/home/user/radio/background.gif")
radio = source.mux_video(video=background, audio)
#radio = mux_video(video=background, audio) for 2.1.x versions
live = input.rtmp(listen=true, "rtmp://localhost:1969/live/key")
stream = fallback(track_sensitive=false, [live, radio])
#rtmp+codec
url = "rtmp://localhost/live"
enc = %ffmpeg(format="flv",
%video(codec="libx264", width=1280, height=720, pixel_format="yuv420p",
b="750k", maxrate="750k", minrate="750k", bufsize="1500k", profile="Main", preset="veryfast", framerate=30, g=60),
%audio(codec="aac", samplerate=44100, b="128k"))
#output
output.url(fallible=true, url=url, enc, stream)
nginx-rtmp
If you use nginx-rtmp
and want to take the stream from there, then there are a few nuances
[well, let’s assume that you left the default rtmp port in nginx settings – 1935]:
The listen
parameter must be set to false
live = input.rtmp(listen=false, "rtmp://localhost:1935/live/key")
And in the nginx-rtmp
config for the “listened” app
, it is important to add the line play_restart on;
so that nginx-rtmp
sends additional signals about the beginning/end of the stream.
Otherwise, at the end of the live broadcast, Liquidsoap will simply hang, waiting for data from nginx.
application live {
live on;
record off;
play_restart on;
}
Calling functions
If you are a more advanced Liquidsoap user, then you will probably want to call any functions on the connect/disconnect stream.
The input.rtmp
statement does not provide arguments for such purposes. However, if you dig into the source code libraries, you can understand that input.rtmp
is a shortened version of the input.ffmpeg
operator for convenience, where there is a richer assortment of all possible parameters.
Using the example of a small fragment with the simplest functions, it will look something like this:
def live_start()
log("LiveStream is Started!")
end
def live_stop()
log("LiveStream is Stopped!")
end
listen = true
live = input.ffmpeg(on_connect=live_start, on_disconnect=live_stop, max_buffer=5., format="live_flv", self_sync=true, int_args=[("listen", listen ? 1 : 0)], "rtmp://localhost:1969/live/key")
on_connect
& on_disconnect
– this is a call to the necessary functions.listen
now it is placed in a separate variable.
All other parameters (format, self_sync, max_buffer
) are taken from the input.rtmp
constructor.