From 3084f6b85aa3fdf9e47bc65db4f98debd9787222 Mon Sep 17 00:00:00 2001 From: Maxime Bugeia Date: Thu, 30 Jul 2020 13:14:15 +0200 Subject: [PATCH] Update liquidsoap to master --- README.md | 15 +++++----- docker-compose.yml | 18 +++++------- liquidsoap/Dockerfile | 27 +++-------------- liquidsoap/liquidsoap.key | 49 ------------------------------- radio/live.liq | 61 ++++++++++++++++----------------------- 5 files changed, 44 insertions(+), 126 deletions(-) delete mode 100644 liquidsoap/liquidsoap.key diff --git a/README.md b/README.md index 697168a..55ccd65 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,10 @@ The goal of this program is to receive an audio stream with [SRT](https://github srt2hls use [Liquidsoap](https://www.liquidsoap.info) to receive a stream and encode it in HLS, then it use [nginx] (https://www.nginx.com/) to serve HLS content. The Liquidsoap container, by default, run radio/live.liq script. It's a fully functionnal example that will : -1. Receive an SRT input on port 10000 -2. Encode it in aac with 3 quality -3. Segment it in HLS format in /hls directory +1. Receive 2 SRT inputs on ports 10000 and 10001 +2. Create a production stream with basic logic between the 2 inputs +3. Encode the stream in aac with 3 quality +4. Segment it in HLS format in /hls directory The Nginx container come with a specific configuration to serve HLS content with proper Content-Type, CORS and Cache-Control headers. It need read only access to /hls directory to serve HLS segments and playlists. @@ -27,10 +28,8 @@ sudo docker-compose up ### Local installation requirements -[Liquidsoap](https://www.liquidsoap.info) 1.5.0+ (not released yet, use master) - -ffmpeg compiled with fdkaac support (the one on liquidsoap debian/ubuntu repository is fine) - +- [Liquidsoap](https://www.liquidsoap.info) 2.0.0+ (not released yet, use master) +- ffmpeg ## Basic usage @@ -59,7 +58,7 @@ curl http://localhost:8080/api/get?livesource ### Sending audio to the streaming server #### Using ffmpeg -Requirement : ffmpeg compiled with srt support (the one on liquidsoap debian/ubuntu repository is fine) +Requirement : ffmpeg compiled with srt support (https://johnvansickle.com/ffmpeg/ for example) ```bash # static file diff --git a/docker-compose.yml b/docker-compose.yml index 9caa000..810c7ce 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,16 +4,12 @@ services: liquidsoap: build: context: liquidsoap - args: - gitbranch: master - version: 1.5.0 - buildnumber: 2857 - image: privyplace/liquidsoap:master-1.5.0-2857 + image: privyplace/liquidsoap:master container_name: liquidsoap command: /radio/live.liq restart: unless-stopped networks: - - default + - default expose: - "8500" - "8081" @@ -41,10 +37,10 @@ services: - ./hls:/hls - ./nginxhls/stream.conf:/etc/nginx/conf.d/stream.conf prometheus: - image: prom/prometheus:v2.19.3 + image: prom/prometheus:v2.23.0 container_name: prometheus volumes: - - ./monitoring/prometheus:/etc/prometheus + - ./monitoring/prometheus/:/etc/prometheus/ - prometheus_data:/prometheus command: - '--config.file=/etc/prometheus/prometheus.yml' @@ -78,7 +74,7 @@ services: labels: org.label-schema.group: "monitoring" grafana: - image: grafana/grafana:7.1.1 + image: grafana/grafana:7.3.5 container_name: grafana volumes: - grafana_data:/var/lib/grafana @@ -87,6 +83,7 @@ services: - GF_SECURITY_ADMIN_USER=${ADMIN_USER:-admin} - GF_SECURITY_ADMIN_PASSWORD=${ADMIN_PASSWORD:-admin} - GF_USERS_ALLOW_SIGN_UP=false + - GF_LOG_LEVEL=warn restart: unless-stopped ports: - 3000:3000/tcp @@ -95,8 +92,9 @@ services: labels: org.label-schema.group: "monitoring" cadvisor: - image: gcr.io/google-containers/cadvisor:v0.36.0 + image: gcr.io/cadvisor/cadvisor:v0.37.0 container_name: cadvisor + privileged: true volumes: - /:/rootfs:ro - /var/run:/var/run:rw diff --git a/liquidsoap/Dockerfile b/liquidsoap/Dockerfile index 51356d5..7a64ece 100644 --- a/liquidsoap/Dockerfile +++ b/liquidsoap/Dockerfile @@ -1,32 +1,13 @@ -FROM debian:buster-slim +FROM savonet/liquidsoap:master -ARG gitbranch -ARG version -ARG buildnumber - -COPY liquidsoap.key /tmp/liquidsoap.key +USER root ENV DEBIAN_FRONTEND noninteractive -RUN echo "\ -deb http://deb.debian.org/debian buster main contrib non-free\n\ -deb http://security.debian.org/debian-security buster/updates main contrib non-free\n\ -deb http://deb.debian.org/debian buster-updates main contrib non-free\n\ -" > /etc/apt/sources.list \ - && echo "\ -Package: *\n\ -Pin: origin deb.liquidsoap.info\n\ -Pin-Priority: 900" > /etc/apt/preferences.d/liquidsoap \ - && apt-get update \ +RUN apt-get update \ && apt-get install -y \ - gnupg2 \ - ca-certificates \ dumb-init \ - && apt-key add /tmp/liquidsoap.key \ - && echo "deb http://deb.liquidsoap.info/debian stable main" > /etc/apt/sources.list.d/liquidsoap.list \ - && apt-get update \ - && apt-get install -y \ - liquidsoap-"$gitbranch"=1:"$version"-"$buildnumber"~stable \ + && apt-get clean \ && rm -rf /var/lib/apt/lists/* \ && groupadd -g 2000 radio \ && useradd -m -u 2001 -g radio radio diff --git a/liquidsoap/liquidsoap.key b/liquidsoap/liquidsoap.key deleted file mode 100644 index 52b50c4..0000000 --- a/liquidsoap/liquidsoap.key +++ /dev/null @@ -1,49 +0,0 @@ ------BEGIN PGP PUBLIC KEY BLOCK----- -Version: SKS 1.1.6 -Comment: Hostname: keyserver.ubuntu.com - -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 -ccU4 -=OKlE ------END PGP PUBLIC KEY BLOCK----- diff --git a/radio/live.liq b/radio/live.liq index 3f5dae9..f597f4a 100644 --- a/radio/live.liq +++ b/radio/live.liq @@ -33,7 +33,7 @@ set("clock.allow_streaming_errors",false) # Retrieve configuration from environment -hlspath = ref getenv("HLSPATH") +hlspath = ref(getenv("HLSPATH")) if !hlspath == "" then hlspath := "/hls" @@ -49,9 +49,9 @@ duration_unready_seconds_metric = prometheus.counter(labels=["radio","type","nam is_blank_metric = prometheus.gauge(labels=["radio","type","name"],help="is source blank?","liquidsoap_is_blank") # Prometheus metrics helpers -def check_if_ready(set_is_ready, increase_duration_unready_seconds, source) = +def check_if_ready(set_is_ready, increase_duration_unready_seconds, s) = def callback() = - if source.is_ready(source) then + if s.is_ready() then set_is_ready(1.) else set_is_ready(0.) @@ -73,7 +73,7 @@ end ### Inputs -preferred_live_source = ref "srt1" +preferred_live_source = ref("srt1") def check_if_preferred_livesource(set_is_preferred_livesource, source) = def callback() = @@ -87,7 +87,7 @@ def check_if_preferred_livesource(set_is_preferred_livesource, source) = callback end -srt1 = input.srt(id="input_srt1", +srt1 = input.srt(id="input_srt1", port=10000) # Get metrics @@ -101,14 +101,14 @@ thread.run.recurrent(delay=0.,check_if_preferred_livesource(set_is_preferred_liv # Wrap input in a buffer srt1 = buffer(id="buffer_srt1", - fallible=true, + fallible=true, max=3.0, srt1) # Tag source with it's name in metadata srt1 = source_tag(srt1, "srt1") -srt2 = input.srt(id="input_srt2", +srt2 = input.srt(id="input_srt2", port=10001) # Get metrics @@ -122,7 +122,7 @@ thread.run.recurrent(delay=0.,check_if_preferred_livesource(set_is_preferred_liv # Wrap input in a buffer srt2 = buffer(id="buffer_srt2", - fallible=true, + fallible=true, max=3.0, srt2) @@ -144,9 +144,9 @@ def is_playing(n) = fun () -> n == !preferred_live_source end -live = switch(id="switch_live", - track_sensitive=false, - [(is_playing("srt1"), srt1), +live = switch(id="switch_live", + track_sensitive=false, + [(is_playing("srt1"), srt1), (is_playing("srt2"), srt2)]) radio_prod = fallback(id="fallback_prod", @@ -194,7 +194,7 @@ def blank_detect_handler() = set_is_blank(1.0) end -radio_prod = on_blank(id="on_blank_radio_prod", +radio_prod = blank.detect(id="on_blank_radio_prod", max_blank=1.0, min_noise=0.0, on_noise=noise_detect_handler, @@ -212,7 +212,7 @@ radio_prod = on_blank(id="on_blank_radio_prod", # Define default http response def http_response(level="error",msg="Unknow error",code=500) = log.important(label="httplog", "#{level} #{msg} #{code}") - http_response(code=code, + http.response(code=code, headers=[("Content-Type","application/json")], data='{"level": #{json_of(level)}, "msg": #{json_of(msg)},"code": #{json_of(code)}}') end @@ -286,55 +286,46 @@ harbor.http.register(port=8081,method="GET","^/",httphandler) # Define outputs formats -aac_lofi = +aac_lofi = %ffmpeg( format="mpegts", %audio( channels=2, samplerate=44100, - codec="libfdk_aac", + codec="aac", b="32k", - afterburner=1, profile="aac_low" ) ) -aac_midfi = +aac_midfi = %ffmpeg( format="mpegts", %audio( channels=2, samplerate=44100, - codec="libfdk_aac", + codec="aac", b="96k", - afterburner=1, profile="aac_low" ) ) -aac_hifi = +aac_hifi = %ffmpeg( format="mpegts", %audio( channels=2, samplerate=44100, - codec="libfdk_aac", + codec="aac", b="196k", - afterburner=1, profile="aac_low" ) ) -# Defines stream infos that cannot be guessed by liqudisoap - -streams_info = [("aac_lofi",(78000,"mp4a.40.2","ts")), - ("aac_midfi",(160000,"mp4a.40.2","ts")), - ("aac_hifi",(252000,"mp4a.40.2","ts"))] - # Output to HLS def segment_name(~position,~extname,stream_name) = - timestamp = int_of_float(gettimeofday()) + timestamp = int_of_float(time()) duration = 2 "#{stream_name}_#{duration}_#{timestamp}_#{position}.ts" end @@ -348,17 +339,15 @@ end output.file.hls(id="output_hls", playlist="live.m3u8", segment_duration=2.0, - segments=3, - segments_overhead=10, + segments=5, + segments_overhead=5, segment_name=segment_name, - streams_info=streams_info, on_file_change=on_file_change, - persist=true, persist_at="state.config", !hlspath, - [("aac_lofi",aac_lofi), - ("aac_midfi", aac_midfi), + [("aac_lofi",aac_lofi), + ("aac_midfi", aac_midfi), ("aac_hifi", aac_hifi)], radio_prod) -### END Outputs \ No newline at end of file +### END Outputs