ocamlliquidsoap

Getting Icecast output module settings within Liquidosap on_metadata handler


I have built a streaming server that is compatible with Icecast sources, but can accept additional metadata. A typical Icecast source client will send its out-of-band metadata update request to the server like this:

/admin/metadata?pass=hackme&mode=updinfo&song=Artist%20-%20Title

My server accepts additional querystring parameters, like meta[album] and meta[filename]:

/admin/metadata?pass=hackme&mode=updinfo&song=Artist%20-%20Title&meta[album]=Album%02Name&meta[filename]=somefile.mp3

I am trying to configure Liquidsoap to send this extended metadata. According to the documentation, it seems I can disable the built-in metadata updates by setting icy_metadata=false. From there, I should be able to write my own function to handle on_metadata. The documentation gives the following signature for on_metadata calls:

(?id:string,(([(string*string)])->unit),source('a))->
source('a)

Call a given handler on metadata packets.

  • id (string – defaults to ""): Force the value of the source ID.

  • (unlabeled) (([(string*string)])->unit): Function called on every metadata packet in the stream. It should be fast because it is ran in the main thread.

  • (unlabeled) (source('a))

I don't fully understand this signature, but I found a mailing list post that has a good example:

def send_meta(m) =
  system("/path/to/script #{m["title"]} #{m["artist"]}")
end

source = on_metadata(send_meta, source)

With this information, I should be able to call out to cURL to make a request to my server, updating the metadata. Something like this:

system("curl \"http://HOST:PORT/admin/metadata?pass=PASSWORD&mode=updinfo&song=#{m["artist"]}%20-%20#{m["title"]}&filename=#{m["filename"]}\"")

I'm close, but I can't figure out the last parts of this:


Solution

  • This all turned out to be very simple.

    How can I get the configured host, port, and password for the associated Icecast Output?

    It isn't possible, directly. The metadata handler doesn't get a reference to the source. However, it's trivial to write a function that sets up both at the same time.

    def output.my_custom_output(encoder, source, host, port, password, mount, genre, url, name) =
      def send_meta(m) = 
        # Code to send metadata here.
        # You can use source, host, port, etc
      end
    
      output.icecast(...)
    end
    

    How can I appropriately URL-encode the metadata parameters?

    url.encode(m['filename'])
    

    Is there some sort of debugging output I can use to show all available variables?

    There may be a better way, but I've found that JSON-encoding and outputting to the log to be helpful.

    log(json_of(m))