diff --git a/liquidsoap/Dockerfile b/liquidsoap/Dockerfile index 4ae3be8..3690d47 100644 --- a/liquidsoap/Dockerfile +++ b/liquidsoap/Dockerfile @@ -1,21 +1,27 @@ -FROM archlinux +# FROM archlinux +# +# RUN pacman -Sy --noconfirm archlinux-keyring +# +# RUN pacman-key --init +# RUN pacman-key --populate archlinux +# RUN yes | pacman -Syu --noconfirm opam make m4 gcc patch diffutils gavl ffmpeg git automake autoconf pkg-config which taglib sudo glibc jq libffi pcre libmad +# -RUN pacman -Sy --noconfirm archlinux-keyring +FROM savonet/liquidsoap:v2.4.x-latest +#RUN useradd liquidsoap && mkdir /home/liquidsoap && chown -R liquidsoap /home/liquidsoap +#RUN usermod -aG wheel liquidsoap +# RUN echo "Defaults !requiretty" >> /etc/sudoers +# RUN echo "%wheel ALL=NOPASSWD: ALL" >> /etc/sudoers -RUN pacman-key --init -RUN pacman-key --populate archlinux -RUN yes | pacman -Syu --noconfirm opam make m4 gcc patch diffutils ffmpeg git automake autoconf pkg-config which taglib sudo glibc jq libffi pcre libmad +ENV HOME=/home/liquidsoap -RUN useradd liquidsoap && mkdir /home/liquidsoap && chown -R liquidsoap /home/liquidsoap -RUN usermod -aG wheel liquidsoap -RUN echo "Defaults !requiretty" >> /etc/sudoers -RUN echo "%wheel ALL=NOPASSWD: ALL" >> /etc/sudoers +USER root -ENV HOME=/home/liquidsoap +RUN apt-get update +RUN apt-get install -y --no-install-recommends curl jq -USER liquidsoap -RUN opam init --disable-sandboxing --yes +# RUN opam init --disable-sandboxing --yes WORKDIR /home/liquidsoap @@ -26,17 +32,17 @@ WORKDIR /home/liquidsoap # RUN echo "%sudo ALL=NOPASSWD: ALL" >> /etc/sudoers #RUN echo 'eval "$(opam config env)"' >> /home/liquidsoap/.bashrc -RUN sudo touch /var/log/liquidsoap.log -RUN sudo chown liquidsoap:users /var/log/liquidsoap.log - -RUN opam switch create 4.14.2 -RUN opam update +RUN touch /var/log/liquidsoap.log +RUN chown liquidsoap:users /var/log/liquidsoap.log +# RUN opam switch create 4.14.2 +# RUN opam update +# # depext no longer required to install, integrated with opam # 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 ocurl liquidsoap -y -RUN opam install ctypes-foreign metadata mad lame ogg vorbis cry samplerate ocurl liquidsoap -y +#RUN opam install ctypes-foreign metadata mad lame ogg vorbis cry samplerate ocurl gavl ffmpeg 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 .; \ @@ -45,12 +51,12 @@ RUN opam install ctypes-foreign metadata mad lame ogg vorbis cry samplerate ocur #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 env) && liquidsoap --version - +# RUN eval $(opam env) && liquidsoap --version +# RUN mkdir /home/liquidsoap/radio ADD ./ /home/liquidsoap/radio/ -RUN sudo chown -R liquidsoap:liquidsoap /home/liquidsoap/radio/ +#RUN chown -R liquidsoap:liquidsoap /home/liquidsoap/radio/ RUN chmod +x /home/liquidsoap/radio/libStereoTool_64.so RUN mkdir /home/liquidsoap/tracks @@ -58,10 +64,23 @@ 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 + +RUN chown -R liquidsoap:liquidsoap /home/liquidsoap/ + WORKDIR /home/liquidsoap/radio -RUN eval $(opam env) && liquidsoap --check radio.liq +RUN liquidsoap --version +RUN liquidsoap --check radio.liq # RUN chown 1000:1000 /home/liquidsoap/tracks # RUN chown 1000:1000 /home/liquidsoap/recordings +#RUN chown liquidsoap:liquidsoap /home/liquidsoap/tracks +#RUN chown liquidsoap:liquidsoap /home/liquidsoap/recordings + +USER liquidsoap EXPOSE 9000 -CMD ["/bin/bash", "-c", "eval `opam config env`; liquidsoap radio.liq"] +EXPOSE 9001 +EXPOSE 1936 +# CMD ["/bin/bash", "-c", "eval `opam config env`; liquidsoap radio.liq"] +CMD ["liquidsoap", "radio.liq"] diff --git a/liquidsoap/PACKAGES b/liquidsoap/PACKAGES index be4b45c..af1d642 100644 --- a/liquidsoap/PACKAGES +++ b/liquidsoap/PACKAGES @@ -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 diff --git a/liquidsoap/radio.liq b/liquidsoap/radio.liq index 778034e..38585da 100755 --- a/liquidsoap/radio.liq +++ b/liquidsoap/radio.liq @@ -6,12 +6,13 @@ set("sandbox.tool","disabled") set("log.file",true) set("log.file.path","/var/log/liquidsoap.log") set("log.stdout",true) -set("log.level", 5) +set("log.level", 3) set("request.deprecated_on_air_metadata", true) #set("server.telnet",true) set("server.socket",true) +# set("server.socket.path","/tmp/datafruits/liquidsoap.sock") set("server.socket.path","/home/liquidsoap/tracks/liquidsoap.sock") set("harbor.bind_addrs",["0.0.0.0"]) @@ -43,6 +44,7 @@ stop_dump_f = ref (fun () -> ()) # live_dj = ref empty() live_dj = ref(source.fail()) +# rtmp_relay = ref(source.fail()) # fallback_ref = ref(fallback([source.fail()])) def icy_update(v) = @@ -85,7 +87,7 @@ def dj_dummy_stopped() = f() end -def get_user(user,password) = +def get_user(user, password) = if user == "source" then x = string.split(separator=';',password) list.nth(x,0,default="") @@ -94,7 +96,7 @@ def get_user(user,password) = end end -def get_password(user,password) = +def get_password(user, password) = if user == "source" then x = string.split(separator=';',password) list.nth(x,1,default="") @@ -104,10 +106,10 @@ def get_password(user,password) = end #auth function -def dj_auth(params) = +def dj_auth(req) = log("dj auth") - u = get_user(params.user,params.password) - p = get_password(params.user,params.password) + u = get_user(req.user, req.password) + p = get_password(req.user, req.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) @@ -223,15 +225,12 @@ def on_disconnect() = log(ret) end -# buffer breaks fallback? live_dj := stereo(input.harbor("#{radio_name}",id="live_dj",port=9000,auth=dj_auth,on_connect=on_connect,on_disconnect=on_disconnect,logfile="/tmp/liquidsoap_harbor.log",buffer=15.0,max=40.0)) -# live_dj := input.harbor( -# "liq_live_dj", -# port=9000, -# password="abc123" -# ) -# +# this source doesn't need on_connect handler, all recording/metadata is handled elsewhere +# disconnect handler to clear metadata is necessary though +rtmp_audio = stereo(input.harbor("#{radio_name}_rtmp",id="rtmp_relay",port=9001,logfile="/tmp/liquidsoap_rtmp_relay_harbor.log",user="rtmp_source",password="pricemaster9876",on_disconnect=on_disconnect,buffer=15.0,max=40.0)) + def new_meta(m) = log("in new meta") log(string(m)) @@ -293,13 +292,16 @@ end output.file(%mp3, current_dump_filename_getter, live_dj(), fallible=true, reopen_when=reopen_when, reopen_delay=0.0, append=true) -source = fallback(id="fallback",track_sensitive=false, - [live_dj(),scheduled_shows,mksafe(id="backup_playlist_mksafe", backup_playlist)]) +# nginx-rtmp pushes the live RTMP stream here when a DJ is streaming with obs +rtmp_relay = input.rtmp(listen=true, "rtmp://0.0.0.0:1936/live") -source.on_metadata(synchronous=false, pub_metadata) +radio_fallback = fallback(id="fallback",track_sensitive=false, + [rtmp_audio, live_dj(),scheduled_shows,mksafe(id="backup_playlist_mksafe", backup_playlist)]) + +radio_fallback.on_metadata(synchronous=false, pub_metadata) def current_fallback_source(v) = - selected_source = "#{source.selected()}" + selected_source = "#{radio_fallback.selected()}" selected_source end @@ -309,9 +311,9 @@ server.register("current_source", namespace="fallback", current_fallback_source) def current_fallback_duration(v) = - duration = "#{source.duration()}" - elapsed = "#{source.elapsed()}" - remaining = "#{source.remaining()}" + duration = "#{radio_fallback.duration()}" + elapsed = "#{radio_fallback.elapsed()}" + remaining = "#{radio_fallback.remaining()}" "elapsed: #{elapsed} / duration: #{duration} / remaining: #{remaining}" end @@ -320,19 +322,52 @@ server.register("duration", namespace="fallback", usage="duration", current_fallback_duration) -# TODO unneeded ??? -# source.on_track(pub_metadata) -# source = server.insert_metadata(id="fallback", source) - output.icecast(%vorbis,id="icecast", mount="#{radio_name}.ogg", host=icecast_host, port=int_of_string(icecast_port), password="hackme", send_icy_metadata=true,description="", url="", encoding="UTF-8", - mksafe(buffer(source))) + mksafe(buffer(radio_fallback))) output.icecast(%mp3,id="icecast", mount="#{radio_name}.mp3", host=icecast_host, port=int_of_string(icecast_port), password="hackme", send_icy_metadata=true,description="", url="", encoding="UTF-8", - mksafe(buffer(source))) + mksafe(buffer(radio_fallback))) + +# HLS video output + +hls_audio_fallback = fallback(id="fallback",track_sensitive=false, + [live_dj(),scheduled_shows,mksafe(id="backup_playlist_mksafe", backup_playlist)]) + +single_video = video.testsrc.ffmpeg() + +single_video = video.add_image(width=200, height=200, x=10, y=10, file="df_logo_2019.png", single_video) + +single_video = video.add_text.sdl( + font="./hinted-Debussy.woff", + "DATAFRUITS.FM", + single_video + ) + +logo_fallback = source.mux.audio(single_video, audio=hls_audio_fallback) + +# RTMP video takes priority; fall back to static logo + audio +hls_source = fallback(id="hls_fallback", track_sensitive=false, [rtmp_relay, mksafe(logo_fallback)]) + +hls_enc = %ffmpeg( + format="mpegts", + %video(codec="libx264", x264opts="keyint=100:min-keyint=100"), + %audio(codec="aac", channels=2, ar=44100) +) + +output.file.hls( + id="hls_output", + playlist="live.m3u8", + segment_duration=4.0, + segments=5, + segments_overhead=5, + "/home/liquidsoap/hls/", + [("live", hls_enc)], + hls_source +)