Liquidsoap dev : Harbor input

Harbor input

Liquidsoap is also able to receive a source using icecast or shoutcast source protocol with the input.harbor operator. Using this operator, the running liquidsoap will open a network socket and wait for an incoming connection.

This operator is very useful to seamlessly add live streams into your final streams: you configure the live source client to connect directly to liquidsoap, and manage the switch to and from the live inside your script.

Additionally, liquidsoap can handle many simulataneous harbor sources on different ports, with finer-grained authentication schemes that can be particularly useful when used with source clients designed for the shoutcast servers.

SSL support in harbor can be enabled using of of the following opam packages: ssl, osx-secure-transport. If enabled using ssl, input.harbor.ssl will be available. If enabled with osx-secure-transport, it will be input.harbor.secure_transport.

Parameters

The global parameters for harbor can be retreived using liquidsoap --conf-descr-key harbor. They are:

If SSL support was enabled via ssl, you will have the following additional settings:

Obtaining a proper SSL certificate can be tricky. You may want to start with a self-signed certificate first. You can obtain a free, valid certificate at: https://letsencrypt.org/

If SSL support is enable via osx-secure-transport, you will have the same settings but named: harbor.secure_transport.*.

To create a self-signed certificate for local testing you can use the following one-liner:

openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout server.key -out server.crt -subj "/CN=localhost" -days 3650
Grab the code!

You also have per-source parameters. You can retreive them using the command liquidsoap -h input.harbor. The most important one are:

When using different ports with different harbor inputs, mountpoints are attributed per-port. Hence, there can be a harbor input with mountpoint "foo" on port 1356 and a harbor input with mountpoint "foo" on port 3567. Additionaly, if an harbor source uses custom port n with shoutcast (ICY) source protocol enabled, shoutcast source clients should set their connection port to n+1.

The auth function is a function, that takes a pair (user,password) and returns a boolean representing whether the user should be granted access or not. Typical example can be:

def auth(user,password) = 
  # Call an external process to check 
  # the credentials:
  # The script will return the string 
  # "true" of "false"
  #
  # First call the script
  ret = get_process_lines("/path/to/script \
         --user=#{user} --password=#{password}")
  # Then get the first line of its output
  ret = list.hd(default="",ret)
  # Finally returns the boolean represented 
  # by the output (bool_of_string can also 
  # be used)
  if ret == "true" then
    true
  else
    false
  end
end
Grab the code!

In the case of the ICY (shoutcast) source protocol, there is no user parameter for the source connection. Thus, the user used will be the user parameter passed to the input.harbor source.

When using a custom authentication function, in case of a ICY (shoutcast) connection, the function will receive this value for the username.

Usage

When using harbor inputs, you first set the required settings, as described above. Then, you define each source using input.harbor("mountpoint"). This source is faillible and will become available when a source client is connected.

The unlabeled parameter is the mount point that the source client may connect to. It should be "/" for shoutcast source clients.

The source client may use any of the recognized audio input codec. Hence, when using shoucast source clients, you need to have compiled liquidsoap with mp3 decoding support (ocaml-mad)

A sample code can be:

set("harbor.bind_addr","0.0.0.0")

# Some code...

# This defines a source waiting on mount point 
# /test-harbor
live = input.harbor("test-harbor",port=8080,password="xxx")

# This is the final stream.
# Uses the live source as soon as available,
# and don't wait for an end of track, since 
# we don't want to cut the beginning of the live
# stream.
#
# You may insert a jingle transition here...
radio = fallback(track_sensitive=false,
                 [live,files])
Grab the code!