Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions liquidsoap/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FROM archlinux

RUN yes | pacman -Sy opam make m4 gcc patch diffutils ffmpeg git automake autoconf pkg-config which taglib sudo glibc jq
RUN yes | pacman -Sy opam make m4 gcc patch diffutils ffmpeg git automake autoconf pkg-config which taglib sudo glibc jq libmad
RUN yes | pacman -Syu

RUN useradd liquidsoap && mkdir /home/liquidsoap && chown -R liquidsoap /home/liquidsoap
RUN usermod -aG wheel liquidsoap
Expand All @@ -25,13 +26,24 @@ WORKDIR /home/liquidsoap
RUN sudo touch /var/log/liquidsoap.log
RUN sudo chown liquidsoap:users /var/log/liquidsoap.log

RUN opam install depext -y
RUN opam depext taglib mad lame ogg vorbis cry samplerate liquidsoap -y
RUN opam install taglib mad lame ogg vorbis cry samplerate liquidsoap -y
#RUN opam install depext -y
#RUN opam depext gavl ffmpeg taglib mad lame ogg vorbis cry samplerate liquidsoap -y
#RUN opam install gavl ffmpeg taglib mad lame ogg vorbis cry samplerate liquidsoap -y
# RUN for i in ocaml-ffmpeg ocaml-dtools ocaml-duppy ocaml-mm ocaml-cry ocaml-taglib ocaml-lame ocaml-ogg ocaml-vorbis ocaml-samplerate liquidsoap; do \
# cd /home/liquidsoap && git clone https://github.com/savonet/$i && cd $i && opam pin add --yes --no-action .; \
# done
# RUN opam install --yes liquidsoap ffmpeg cry taglib lame ogg vorbis samplerate
# RUN opam install depext -y
# RUN opam depext taglib mad lame ogg vorbis cry samplerate liquidsoap -y
# RUN opam install taglib mad lame ogg vorbis cry samplerate liquidsoap -y

RUN for i in ocaml-gavl ocaml-ffmpeg ocaml-dtools ocaml-duppy ocaml-mm ocaml-cry ocaml-taglib ocaml-lame ocaml-mad ocaml-ogg ocaml-vorbis ocaml-samplerate; do \
cd /home/liquidsoap && git clone https://github.com/savonet/$i && cd $i && opam pin add --yes --no-action .; \
done
#RUN cd /home/liquidsoap && git clone https://github.com/savonet/liquidsoap && cd liquidsoap && git checkout v2.0.0-beta2 && opam pin add --yes --no-action .
RUN cd /home/liquidsoap && git clone https://github.com/savonet/liquidsoap && cd liquidsoap && opam pin add --yes --no-action .
RUN opam install --yes liquidsoap ffmpeg cry taglib lame mad ogg vorbis samplerate

RUN eval `opam config env`;liquidsoap --version

RUN mkdir /home/liquidsoap/radio
Expand All @@ -40,10 +52,13 @@ RUN mkdir /home/liquidsoap/tracks
RUN chown liquidsoap:liquidsoap /home/liquidsoap/tracks
RUN mkdir /home/liquidsoap/recordings
RUN chown liquidsoap:liquidsoap /home/liquidsoap/recordings
RUN mkdir /home/liquidsoap/hls
RUN chown liquidsoap:liquidsoap /home/liquidsoap/hls

WORKDIR /home/liquidsoap/radio
RUN chown 1000:1000 /home/liquidsoap/tracks
RUN chown 1000:1000 /home/liquidsoap/recordings
RUN chown 1000:1000 /home/liquidsoap/hls

EXPOSE 9000
CMD ["/bin/bash", "-c", "eval `opam config env`; liquidsoap radio.liq"]
CMD ["/bin/bash", "-c", "eval `opam config env` && liquidsoap radio.liq"]
6 changes: 3 additions & 3 deletions liquidsoap/PACKAGES
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ ocaml-cry
# Gstreamer is a library for constructing graphs of media-handling components.
# It is currently used to provide audio and video encoding and decoding
# as well as input and outputs such as V4l inputs.
# ocaml-gstreamer
ocaml-gstreamer

# ============================================================================
# Codecs
Expand Down Expand Up @@ -117,11 +117,11 @@ ocaml-flac
# is very efficient and has a quality setting for
# tweaking load vs. quality of the conversion.
# It is the recommended module to use with video
# ocaml-gavl
ocaml-gavl

# FFMPEG is currently only used to convert from
# and to many formats.
# ocaml-ffmpeg
ocaml-ffmpeg

# Frei0r is a minimalistic plugin API for video sources and filters.
# ocaml-frei0r
Expand Down
139 changes: 108 additions & 31 deletions liquidsoap/radio.liq
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#!/usr/local/bin/liquidsoap
%include "tunein.liq"
# %include "tunein.liq"

set("sandbox.tool","disabled")
#set("sandbox.tool","disabled")
set("log.file",true)
set("log.file.path","/var/log/liquidsoap.log")
set("log.stdout",true)
set("log.level",4)
set("log.level",3)

set("server.telnet",true)
set("server.socket",true)
Expand All @@ -19,13 +19,13 @@ icecast_host = "icecast"
icecast_port = "8000"
crossfade_enabled = getenv("CROSSFADE")

tunein_partner_id = getenv("TUNEIN_PARTNER_ID")
tunein_partner_key = getenv("TUNEIN_PARTNER_KEY")
tunein_station_id = getenv("TUNEIN_STATION_ID")
tunein_metadata_updates_enabled = getenv("TUNEIN_METADATA_UPDATES_ENABLED")
# tunein_partner_id = getenv("TUNEIN_PARTNER_ID")
# tunein_partner_key = getenv("TUNEIN_PARTNER_KEY")
# tunein_station_id = getenv("TUNEIN_STATION_ID")
# tunein_metadata_updates_enabled = getenv("TUNEIN_METADATA_UPDATES_ENABLED")

# liq_secret = getenv("LIQ_SECRET")

#
def icy_update(v) =
# Parse the argument
l = string.split(separator=",",v)
Expand All @@ -47,24 +47,30 @@ def icy_update(v) =
"Done !"
end

# def clear_queue() =
# end

server.register("update",namespace="metadata",
description="Update metadata",
usage="update title=foo,album=bar,..",
icy_update)


# refs
title_prefix = ref ""
title_prefix = ref("")

current_dj = ref ""
last_dj_disconnected = ref ""
current_dj_connected_at = ref 0.0
last_dj_disconnected_at = ref 0.0
current_dump_filename = ref ""
current_dj = ref("")
last_dj_disconnected = ref("")
current_dj_connected_at = ref(0.0)
last_dj_disconnected_at = ref(0.0)
current_dump_filename = ref("")

stop_dump_f = ref (fun () -> ())
stop_dump_f = ref(fun () -> ())

live_dj = ref empty()
live_dj = ref(empty())
live_video_audio = ref(empty())
live_video = ref(empty())
vj_video = ref(empty())

def dj_dummy_started() =
log("dj dummy on_start")
Expand Down Expand Up @@ -98,18 +104,18 @@ def get_password(user,password) =
end

#auth function
def dj_auth(user,password) =
def dj_auth(args) =
log("dj auth")
u = get_user(user,password)
p = get_password(user,password)
ret = get_process_lines("./dj_auth.sh '#{u}' '#{p}' '#{radio_name}'")
u = get_user(args.user, args.password)
p = get_password(args.user, args.password)
ret = process.read.lines("./dj_auth.sh '#{u}' '#{p}' '#{radio_name}'")
#ret has now the value of the live client (dj1,dj2, or djx), or "ERROR"/"unknown"
ret = list.hd(default="",ret)
#return true to let the client transmit data, or false to tell harbor to decline
if ret == "true" then
title_prefix := "LIVE -- #{u}"
current_dj := "#{u}"
current_dj_connected_at := gettimeofday()
current_dj_connected_at := time()
log("dj auth succeeded")
log("#{current_dj}")
log("#{current_dj_connected_at}")
Expand All @@ -121,7 +127,7 @@ end


def my_request_function () =
lines = get_process_lines("./next_song.sh")
lines = process.read.lines("./next_song.sh")
result = list.hd(default="", lines)
log("result: #{result}")
log("lines: #{lines}")
Expand Down Expand Up @@ -158,20 +164,20 @@ def on_connect(headers) =
log("last_dj_disconnected_at: #{!last_dj_disconnected_at}")
if (!last_dj_disconnected_at == 0.0) then
log("*****************************************CREATING NEW DUMP, last_dj_disconnected_at is null***************************************************")
current_dump_filename := "#{!current_dj}-#{localtime(!current_dj_connected_at, format_time)}"
current_dump_filename := "#{!current_dj}-#{time.local(!current_dj_connected_at)}"
log("new dump filename (first dump):")
log(!current_dump_filename);
log("sending live notification")
ret = get_process_lines("./live_notification.sh 'LIVE - #{!current_dj}'")
ret = process.read.lines("./live_notification.sh 'LIVE - #{!current_dj}'")
ret = list.hd(default="",ret)
log(ret)
elsif (((!current_dj_connected_at - !last_dj_disconnected_at) > 60.0) or (!current_dj != !last_dj_disconnected)) then
log("*****************************************CREATING NEW DUMP***************************************************")
current_dump_filename := "#{!current_dj}-#{localtime(!current_dj_connected_at, format_time)}"
current_dump_filename := "#{!current_dj}-#{time.local(!current_dj_connected_at)}"
log("new dump filename:")
log(!current_dump_filename);
log("sending live notification")
ret = get_process_lines("./live_notification.sh 'LIVE - #{!current_dj}'")
ret = process.read.lines("./live_notification.sh 'LIVE - #{!current_dj}'")
ret = list.hd(default="",ret)
log(ret)
else
Expand Down Expand Up @@ -211,7 +217,7 @@ end
def pub_metadata(m) =
log("on_track");
title = m["title"]
ret = get_process_lines("./pub_metadata.sh '#{title}'")
ret = process.read.lines("./pub_metadata.sh '#{title}'")
ret = list.hd(default="",ret)
log(ret)
#url = "https://#{radio_name}.streampusher.com/publish_metadata.json"
Expand All @@ -227,18 +233,31 @@ def pub_metadata(m) =
# log("desc: #{desc}");
end

live_video := input.ffmpeg(id="main_video", fallible=true, buffer=60.0, "https://viz.streampusher.com:16666/hls/datafruits.m3u8")
vj_video := input.ffmpeg(id="vj_video", fallible=true, buffer=60.0, "https://viz.streampusher.com:16666/vj/datafruits.m3u8")

live_video_audio := audio_to_stereo(drop_video(!live_video))

live_dj := map_metadata(new_meta, !live_dj,update=false)

live_dj := pipe(process='./stereo_tool_cmd_64 - - -s ./stereotool.sts', buffer=10.0, !live_dj)
# live_audio = fallback(id="live_audio_fallback", track_sensitive=false, [!live_video_audio, !live_dj])
# live_audio = pipe(process='./stereo_tool_cmd_64 - - -s ./stereotool.sts', buffer=10.0, live_audio)

output.dummy(fallible=true, on_start=dj_dummy_started, on_stop=dj_dummy_stopped, !live_dj)

source = fallback(id="fallback",track_sensitive=false,
[!live_dj,mksafe(backup_playlist)])
[!live_video_audio, !live_dj, mksafe(backup_playlist)])

single_video = noise()

source = if tunein_metadata_updates_enabled == "true" then on_track(tunein.submit(partnerid=tunein_partner_id,partnerkey=tunein_partner_key,stationid=tunein_station_id), source) else source end
video_source = fallback(id="video_fallback",track_sensitive=false,
[!live_video,
mux_audio(drop_audio(!vj_video), audio=source),
mksafe(mux_audio(single_video, audio=source))])

source = on_track(pub_metadata, source)
#source = if tunein_metadata_updates_enabled == "true" then on_track(tunein.submit(partnerid=tunein_partner_id,partnerkey=tunein_partner_key,stationid=tunein_station_id), source) else source end

source.on_track(pub_metadata)

source = server.insert_metadata(id="fallback", source)

Expand All @@ -254,3 +273,61 @@ clock.assign_new(id="mp3_icecast", [output.icecast(%mp3,id="icecast",
icy_metadata="true",description="",
url="", encoding="UTF-8",
mksafe(buffer(source)))])

aac_lofi = %ffmpeg(format="mpegts",
%audio(
codec="aac",
channels=2,
ar=44100
),
%video(
codec="libx264",
b="5M"
)
)

aac_midfi = %ffmpeg(format="mpegts",
%audio(
codec="aac",
channels=2,
ar=44100,
b="96k"
),
%video(
codec="libx264",
b="5M"
)
)

aac_hifi = %ffmpeg(format="mpegts",
%audio(
codec="aac",
channels=2,
ar=44100,
b="192k"
),
%video(
codec="libx264",
b="5M"
)
)

streams = [("aac_lofi",aac_lofi),
("aac_midfi", aac_midfi),
("aac_hifi", aac_hifi)]

def segment_name(~position,~extname,stream_name) =
timestamp = int_of_float(time())
duration = 2
"#{stream_name}_#{duration}_#{timestamp}_#{position}.#{extname}"
end

output.file.hls(playlist="#{radio_name}.m3u8",
segment_duration=2.0,
segments=5,
segments_overhead=5,
segment_name=segment_name,
persist_at="/home/liquidsoap/state.config",
"/home/liquidsoap/hls",
streams,
video_source)