savonet / liquidsoap

Liquidsoap is a statically typed scripting general-purpose language with dedicated operators and backend for all thing media, streaming, file generation, automation, HTTP backend and more.
http://liquidsoap.info
GNU General Public License v2.0
1.41k stars 130 forks source link

Recording live broadcast breaks liquidsoap #3537

Closed netbladenl closed 11 months ago

netbladenl commented 11 months ago

Describe the bug I'm using the latest rolling release of Azuracast, and when the function to record live broadcasts is on liquidsoap stops working correctly. ID3 information is not being showed correctly. And when the streamer is disconnecting most of the time the autodj of liquidsoap dont play. and if it works you can hear the last seconds of the song being played before the streamer connects instead of directly a new song.

To Reproduce In azuracast you have to go to edit station profile -> streamers/dj's Turn on the option "Record Live Broadcasts" connect with butt or anything else that is able to set up a shoutcast/icecast stream and disconnect after a minute. Most likely the autodj doesnt play as it should. Turning this off solves the problem but live streamers wont be recorded.

Expected behavior When streamer disconnects the autodj should be playing, and when the streamer is connected the ID3 information should be showed instead of the song before playing when the streamer connects

Version details

Install method It's included within the docker distribution of Azuracast

Ticket at github of Azuracast ; https://github.com/AzuraCast/AzuraCast/issues/6727

netbladenl commented 11 months ago

Logs :

2023/11/11 18:02:28 [lang:3] API feedback - Response (200): true
2023/11/11 18:03:12 [lang:3] API auth - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/auth' with body: { "user": "user", "password": "****" }
2023/11/11 18:03:12 [lang:3] API auth - Response (200): true
2023/11/11 18:03:12 [lang:3] DJ Source connected! Last authenticated DJ: iwan - [("Authorization", "Basic **Password**="), ("Host", "streaming.youradio.nl:8005"), ("User-Agent", "butt 0.1.39"), ("Content-Type", "audio/mpeg"), ("ice-name", "no name"), ("ice-public", "0"), ("ice-audio-info", "ice-bitrate=320;ice-channels=2;ice-samplerate=48000"), ("Expect", "100-continue")]
2023/11/11 18:03:12 [lang:3] API djon - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/djon' with body: { "user": "iwan" }
2023/11/11 18:03:12 [lang:3] API djon - Response (200): true
2023/11/11 18:03:12 [input_streamer:3] Decoding...
2023/11/11 18:03:42 [input_streamer:2] Error while reading from client: Timed out after waiting for 30.02 sec.
2023/11/11 18:03:42 [lang:3] API djoff - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/djoff' with body: { "user": "iwan" }
2023/11/11 18:03:42 [lang:3] API djoff - Response (200): true
2023/11/11 18:03:42 [input_streamer:2] Feeding stopped: Avutil.Error(Invalid data found when processing input).
2023/11/11 18:03:42 [lang:3] API djoff - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/djoff' with body: { "user": "" }
2023/11/11 18:03:42 [lang:3] API djoff - Response (200): true
2023/11/11 18:03:57 [lang:3] API auth - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/auth' with body: { "user": "iwan", "password": "***" }
2023/11/11 18:03:57 [lang:3] API auth - Response (200): true
2023/11/11 18:03:57 [lang:3] DJ Source connected! Last authenticated DJ: iwan - [("Authorization", "Basic *****="), ("Host", "streaming.youradio.nl:8005"), ("User-Agent", "butt 0.1.39"), ("Content-Type", "audio/mpeg"), ("ice-name", "no name"), ("ice-public", "0"), ("ice-audio-info", "ice-bitrate=320;ice-channels=2;ice-samplerate=48000"), ("Expect", "100-continue")]
2023/11/11 18:03:57 [lang:3] API djon - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/djon' with body: { "user": "iwan" }
2023/11/11 18:03:57 [lang:3] API djon - Response (200): true
2023/11/11 18:03:57 [input_streamer:3] Decoding...
2023/11/11 18:04:16 [input_streamer:2] Feeding stopped: Avutil.Error(Invalid data found when processing input).
2023/11/11 18:04:16 [lang:3] API djoff - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/djoff' with body: { "user": "iwan" }
2023/11/11 18:04:16 [lang:3] API djoff - Response (200): true
2023/11/11 18:04:35 [lang:3] API auth - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/auth' with body: { "user": "", "password": "" }
2023/11/11 18:04:35 [lang:3] API auth - Response (200): true
2023/11/11 18:04:35 [lang:3] DJ Source connected! Last authenticated DJ: iwan - [("Host", "streaming.youradio.nl:8005"), ("icy-name", "No Name"), ("icy-pub", "0"), ("icy-br", "320"), ("content-type", "audio/mpeg")]
2023/11/11 18:04:35 [lang:3] API djon - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/djon' with body: { "user": "iwan" }
2023/11/11 18:04:35 [lang:3] API djon - Response (200): true
2023/11/11 18:04:35 [input_streamer:3] Decoding...
2023/11/11 18:05:05 [input_streamer:2] Error while reading from client: Timed out after waiting for 30.00 sec.
2023/11/11 18:05:05 [lang:3] API djoff - Sending POST request to 'http://127.0.0.1:6010/api/internal/1/liquidsoap/djoff' with body: { "user": "iwan" }
2023/11/11 18:05:05 [lang:3] API djoff - Response (200): true

Liquidsoap config:

# WARNING! This file is automatically generated by AzuraCast.
# Do not update it directly!

init.daemon.set(false)
init.daemon.pidfile.path.set("/var/azuracast/stations/radio_netblade/config/liquidsoap.pid")

log.stdout.set(true)
log.file.set(false)

settings.server.log.level.set(4)

settings.server.socket.set(true)
settings.server.socket.permissions.set(0o660)
settings.server.socket.path.set("/var/azuracast/stations/radio_netblade/config/liquidsoap.sock")

settings.harbor.bind_addrs.set(["0.0.0.0"])
settings.encoder.metadata.export.set(["artist","title","album","song"])

environment.set("TZ", "Europe/Amsterdam")

autodj_is_loading = ref(true)
ignore(autodj_is_loading)

autodj_ping_attempts = ref(0)
ignore(autodj_ping_attempts)

# Track live-enabled status.
live_enabled = ref(false)
ignore(live_enabled)

# Track live transition for crossfades.
to_live = ref(false)
ignore(to_live)

# Reimplement LS's now-deprecated drop_metadata function.
def drop_metadata(~id=null(), s)
    let {metadata=_, ...tracks} = source.tracks(s)
    source(id=id, tracks)
end

# Transport for HTTPS outputs.
https_transport = http.transport.ssl()
ignore(https_transport)

azuracast_api_url = "http://127.0.0.1:6010/api/internal/4/liquidsoap"
azuracast_api_key = "(PASSWORD)"

def azuracast_api_call(~timeout=2.0, url, payload) =
    full_url = "#{azuracast_api_url}/#{url}"

    log("API #{url} - Sending POST request to '#{full_url}' with body: #{payload}")
    try
        response = http.post(full_url,
            headers=[
                ("Content-Type", "application/json"),
                ("User-Agent", "Liquidsoap AzuraCast"),
                ("X-Liquidsoap-Api-Key", "#{azuracast_api_key}")
            ],
            timeout=timeout,
            data=payload
        )

        log("API #{url} - Response (#{response.status_code}): #{response}")
        "#{response}"
    catch err do
        log("API #{url} - Error: #{error.kind(err)} - #{error.message(err)}")
        "false"
    end
end

station_media_dir = "/var/azuracast/stations/radio_netblade/media"
def azuracast_media_protocol(~rlog=_,~maxtime=_,arg) =
    ["#{station_media_dir}/#{arg}"]
end

protocol.add(
    "media",
    azuracast_media_protocol,
    doc="Pull files from AzuraCast media directory.",
    syntax="media:uri"
)

playlist_default = playlist(id="playlist_default",mime_type="audio/x-mpegurl",mode="randomize",reload_mode="watch","/var/azuracast/stations/radio_netblade/playlists/playlist_default.m3u")
playlist_default = cue_cut(id="cue_playlist_default", playlist_default)

playlist_jingles = playlist(id="playlist_jingles",mime_type="audio/x-mpegurl",mode="randomize",reload_mode="watch","/var/azuracast/stations/radio_netblade/playlists/playlist_jingles.m3u")
playlist_jingles = cue_cut(id="cue_playlist_jingles", playlist_jingles)
playlist_jingles = drop_metadata(playlist_jingles)

# Standard Playlists
radio = random(id="standard_playlists", weights=[3], [playlist_default])

# Once per x Songs Playlists
radio = rotate(weights=[1,3], [playlist_jingles, radio])

# AutoDJ Next Song Script
def autodj_next_song() =
    response = azuracast_api_call(
        "nextsong",
        ""
    )
    if (response == "") or (response == "false") then
        null()
    else
        r = request.create(response)
        if request.resolve(r) then
            r
        else
            null()
       end
    end
end

# Delayed ping for AutoDJ Next Song
def wait_for_next_song(autodj)
    autodj_ping_attempts.set(autodj_ping_attempts() + 1)

    if source.is_ready(autodj) then
        log("AutoDJ is ready!")
        autodj_is_loading.set(false)
        -1.0
    elsif autodj_ping_attempts() > 200 then
        log("AutoDJ could not be initialized within the specified timeout.")
        autodj_is_loading.set(false)
        -1.0
    else
        0.5
    end
end

dynamic = request.dynamic(id="next_song", timeout=20.0, retry_delay=10., autodj_next_song)
dynamic = cue_cut(id="cue_next_song", dynamic)

dynamic_startup = fallback(
    id = "dynamic_startup",
    track_sensitive = false,
    [
        dynamic,
        source.available(
            blank(id = "autodj_startup_blank", duration = 120.),
            predicate.activates({autodj_is_loading()})
        )
    ]
)
radio = fallback(id="autodj_fallback", track_sensitive = true, [dynamic_startup, radio])

ref_dynamic = ref(dynamic);
thread.run.recurrent(delay=0.25, { wait_for_next_song(ref_dynamic()) })

requests = request.queue(id="requests")
requests = cue_cut(id="cue_requests", requests)
radio = fallback(id="requests_fallback", track_sensitive = true, [requests, radio])

interrupting_queue = request.queue(id="interrupting_requests")
interrupting_queue = cue_cut(id="cue_interrupting_requests", interrupting_queue)
radio = fallback(id="interrupting_fallback", track_sensitive = false, [interrupting_queue, radio])

# Skip command (used by web UI)
def add_skip_command(s) =
    def skip(_) =
        source.skip(s)
        "Done!"
    end

    server.register(namespace="radio", usage="skip", description="Skip the current song.", "skip",skip)
end

add_skip_command(radio)

# Apply amplification metadata (if supplied)
radio = amplify(override="liq_amplify", 1., radio)

# Replaygain Metadata
enable_replaygain_metadata()
radio = replaygain(radio)

def live_aware_crossfade(old, new) =
    if to_live() then
        # If going to the live show, play a simple sequence
        sequence([fade.out(old.source),fade.in(new.source)])
    else
        # Otherwise, use the smart transition
        cross.smart(old, new, fade_in=3.00, fade_out=3.00)
    end
end

radio = cross(minimum=0., duration=4.50, live_aware_crossfade, radio)

# DJ Authentication
last_authenticated_dj = ref("")
live_dj = ref("")

def dj_auth(login) =
    auth_info =
        if (login.user == "source" or login.user == "") and (string.match(pattern="(:|,)+", login.password)) then
            auth_string = string.split(separator="(:|,)", login.password)
            {user = list.nth(default="", auth_string, 0),
            password = list.nth(default="", auth_string, 2)}
        else
            {user = login.user, password = login.password}
        end

    response = azuracast_api_call(
        timeout=5.0,
        "auth",
        json.stringify(auth_info)
    )

    if (response == "true") then
        last_authenticated_dj.set(auth_info.user)
        true
    else
        false
    end
end

def live_connected(header) =
    dj = last_authenticated_dj()
    log("DJ Source connected! Last authenticated DJ: #{dj} - #{header}")

    live_enabled.set(true)
    live_dj.set(dj)

    _ = azuracast_api_call(
        timeout=5.0,
        "djon",
        json.stringify({user = dj})
    )
end

def live_disconnected() =
    _ = azuracast_api_call(
        timeout=5.0,
        "djoff",
        json.stringify({user = live_dj()})
    )

    live_enabled.set(false)
    live_dj.set("")
end

# A Pre-DJ source of radio that can be broadcast if needed
radio_without_live = radio
ignore(radio_without_live)

# Live Broadcasting
live = input.harbor("/", id = "input_streamer", port = 9025, auth = dj_auth, icy = true, icy_metadata_charset = "UTF-8", metadata_charset = "UTF-8", on_connect = live_connected, on_disconnect = live_disconnected, buffer = 5.00, max = 10.00)

def insert_missing(m) =
    if m == [] then
        [("title", "Live Broadcast"), ("is_live", "true")]
    else
        [("is_live", "true")]
    end
end
live = metadata.map(insert_missing, live)

radio = fallback(id="live_fallback", track_sensitive=false, replay_metadata=true, [live, radio])

# Skip non-live track when live DJ goes live.
def check_live() =
    if live.is_ready() then
        if not to_live() then
            to_live.set(true)
            radio_without_live.skip()
        end
    else
        to_live.set(false)
    end
end

# Continuously check on live.
radio = source.on_frame(radio, check_live)

# Record Live Broadcasts
recording_base_path = "/var/azuracast/stations/radio_netblade/temp"
recording_extension = "mp3"

output.file(
    %mp3(samplerate=44100, stereo=true, bitrate=128),
    fun () -> begin
        if (live_enabled()) then
            time.string("#{recording_base_path}/#{live_dj()}/stream_%Y%m%d-%H%M%S.#{recording_extension}.tmp")
        else
            ""
        end
    end,
    live,
    fallible=true,
    on_close=fun (tempPath) -> begin
        path = string.replace(pattern=".tmp$", (fun(_) -> ""), tempPath)

        log("Recording stopped: Switching from #{tempPath} to #{path}")

        process.run("mv #{tempPath} #{path}")
        ()
    end
)

# Allow for Telnet-driven insertion of custom metadata.
radio = server.insert_metadata(id="custom_metadata", radio)

radio = ladspa.master_me(
    bypass = false,
    target = -14,
    brickwall_bypass = false,
    brickwall_ceiling = -1.00,
    brickwall_release = 75.00,
    eq_bypass = false,
    eq_highpass_freq = 5.00,
    eq_side_bandwidth = 1.00,
    eq_side_freq = 600.00,
    eq_side_gain = 1.00,
    eq_tilt_gain = 0.00,
    gate_attack = 0.00,
    gate_bypass = true,
    gate_hold = 50.00,
    gate_release = 430.50,
    gate_threshold = -90.00,
    kneecomp_attack = 20.00,
    kneecomp_bypass = false,
    kneecomp_dry_wet = 50,
    kneecomp_ff_fb = 50,
    kneecomp_knee = 6.00,
    kneecomp_link = 60,
    kneecomp_makeup = 0.00,
    kneecomp_release = 340.00,
    kneecomp_strength = 20,
    kneecomp_tar_thresh = -4.00,
    leveler_brake_threshold = -10.00,
    leveler_bypass = false,
    leveler_max = 10.00,
    leveler_max__ = 10.00,
    leveler_speed = 20,
    limiter_attack = 3.00,
    limiter_bypass = false,
    limiter_ff_fb = 50,
    limiter_knee = 3.00,
    limiter_makeup = 0.00,
    limiter_release = 40.00,
    limiter_strength = 80,
    limiter_tar_thresh = 6.00,
    mscomp_bypass = false,
    high_attack = 8.00,
    high_crossover = 8000.00,
    high_knee = 12.00,
    high_link = 30,
    high_release = 30.00,
    high_strength = 30,
    high_tar_thresh = -12.00,
    low_attack = 15.00,
    low_crossover = 60.00,
    low_knee = 12.00,
    low_link = 70,
    low_release = 150.00,
    low_strength = 10,
    low_tar_thresh = -3.00,
    makeup = 1.00,
    dc_blocker = false,
    input_gain = 0.00,
    mono = false,
    phase_l = false,
    phase_r = false,
    stereo_correct = false,
    radio
)

error_file = single(id="error_jingle", "/usr/local/share/icecast/web/error.mp3")

def tag_error_file(m) =
    ignore(m)
    [("is_error_file", "true")]
end
error_file = metadata.map(tag_error_file, error_file)

radio = fallback(id="safe_fallback", track_sensitive = false, [radio, error_file])

# Send metadata changes back to AzuraCast
last_title = ref("")
last_artist = ref("")

def metadata_updated(m) =
    def f() =
        if (m["is_error_file"] != "true") then
            if (m["title"] != last_title() or m["artist"] != last_artist()) then
                last_title.set(m["title"])
                last_artist.set(m["artist"])

                j = json()

                if (m["song_id"] != "") then
                    j.add("song_id", m["song_id"])
                    j.add("media_id", m["media_id"])
                    j.add("playlist_id", m["playlist_id"])
                else
                    j.add("artist", m["artist"])
                    j.add("title", m["title"])
                end

                _ = azuracast_api_call(
                    "feedback",
                    json.stringify(j)
                )
            end
        end
    end

    thread.run(f)
end

radio.on_metadata(metadata_updated)

# Handle "Jingle Mode" tracks by replaying the previous metadata.
last_metadata = ref([])
def handle_jingle_mode(m) =
    if (m["jingle_mode"] == "true") then
        last_metadata()
    else
        last_metadata.set(m)
        m
    end
end

radio = metadata.map(update=false, strip=true, handle_jingle_mode, radio)

# Local Broadcasts
output.icecast(%fdkaac(channels=2, samplerate=44100, bitrate=128, afterburner=false, aot="mpeg4_aac_lc", sbr_mode=true), id="local_1", host = "127.0.0.1", port = 9021, password = "(PASSWORD)", mount = "/radio.aac", name = "Radio NetBlade", description = "netblade radio 10's", genre = "alternative", public = false, encoding = "UTF-8", radio)
output.icecast(%mp3(samplerate=44100, stereo=true, bitrate=320), id="local_2", host = "127.0.0.1", port = 9021, password = "(PASSWORD)", mount = "/radio.mp3", name = "Radio NetBlade", description = "netblade radio 10's", genre = "alternative", public = true, encoding = "UTF-8", radio)

# Remote Relays
vitoyucepi commented 11 months ago

Hi @netbladenl, I think the problem is in liquidsoap. I can't fix it, but I can reproduce it. It's not necessary for you to repeat the reproduction steps.

Reproduction

  1. Start liquidsoap with the following script

    s = sine(200.)
    
    l = input.harbor("/test", port=8000)
    
    l = metadata.map(fun(_) -> [], l)
    
    r = fallback([l, s], track_sensitive=false)
    
    output.file(%mp3, {"/tmp/f.mp3"}, l, fallible=true)
    output.dummy(r)
  2. It will start and output [switch:3] Switch to sine.
  3. Stream with the ffmpeg command. ffmpeg -hide_banner -re -f lavfi -i "sine=frequency=1000:duration=20" -b:a 128k -c:a mp3 -f mp3 icecast://source:hackme@127.0.0.1:8010/test.
  4. After the stream is finished, liquidsoap will become unresponsive. It will also output in a loop.
    [output_file:2] Warning: there may be an infinite sequence of empty tracks!

Versions

toots commented 11 months ago

Thanks so much for the detailed steps @vitoyucepi. I haven't been able to reproduce, however, either with my local dev env or using savonet/liquidsoap:v2.2.2 on docker. Could you provide more details on the reproduction steps on your end?

Thanks!

vitoyucepi commented 11 months ago

OK, here's a docker-compose setup.

  1. compose.yaml
    version: "3.8"
    services:
     liquidsoap:
       image: savonet/liquidsoap:v2.2.2
       command:
         - "/tmp/test/main.liq"
       ports:
         - "127.0.0.1:8010:8000"
       logging:
         driver: "json-file"
         options:
           max-size: "1m"
           max-file: "3"
       volumes:
         - ./:/tmp/test
  2. mail.liq

    s = sine(200.)
    
    l = input.harbor("/test", port=8000)
    
    l = metadata.map(fun(_) -> [], l)
    
    r = fallback([l, s], track_sensitive=false)
    
    output.file(%mp3, {"/tmp/f.mp3"}, l, fallible=true)
    output.dummy(r)
  3. Start the compose project with the docker compose up command in the first terminal.
  4. In the second terminal, open docker stats and look for cpu usage. top will also work.
  5. In the third terminal, start the stream with ffmpeg -hide_banner -re -f lavfi -i "sine=frequency=1000:duration=30" -b:a 128k -c:a mp3 -f mp3 icecast://source:hackme@127.0.0.1:8010/test. I'm not sure if the duration of the stream makes any difference.
  6. In the stats monitor, you'll see the following sequence of events.

    1. While loading liquidsoap, the container will use 100% of the CPU. That's okay.

      Logs ``` test1-liquidsoap-1 | INFO: Loading Sdl_image, Target = linux test1-liquidsoap-1 | INFO: Loading Sdl_ttf, Target = linux test1-liquidsoap-1 | 2023/11/17 00:30:14 >>> LOG START test1-liquidsoap-1 | 2023/11/17 00:30:09 [ffmpeg.filter.bitstream:3] No valid mode found for filter pgs_frame_merge! test1-liquidsoap-1 | 2023/11/17 00:30:09 [main:3] Liquidsoap 2.2.2 test1-liquidsoap-1 | 2023/11/17 00:30:09 [main:3] Using: alsa=0.3.0 angstrom=0.15.0 ao=0.2.4 asetmap=0.8.1 asn1-combinators=0.2.6 astring=0.8.5 base64=3.5.1 bigarray=[distributed with OCaml] bigarray-compat=1.1.0 bigstringaf=0.9.1 bjack=0.1.6 bos=0.2.1 bytes=[distributed with OCaml] ca-certs=v0.2.3 camlimages.all_formats=4.2.6 camlimages.core=5.0.4 camlimages.exif=5.0.4 camlimages.gif=5.0.4 camlimages.jpeg=5.0.4 camlimages.png=5.0.4 camlimages.tiff=5.0.4 camlimages.xpm=5.0.4 camlp-streams camomile.lib=2.0 cohttp=5.1.0 cohttp-lwt=5.1.0 cohttp-lwt-unix=5.1.0 conduit=6.2.0 conduit-lwt=6.2.0 conduit-lwt-unix=6.2.0 cry=1.0.2 cstruct=6.2.0 ctypes=0.20.2 ctypes.foreign=0.20.2 ctypes.stubs=0.20.2 curl=0.9.2 domain-name=0.4.0 dssi=0.1.5 dtools=0.4.5 dune-build-info=3.8.2 dune-private-libs.dune-section=3.8.2 dune-site=3.8.2 dune-site.private=3.8.2 duppy=0.9.3 eqaf=0.9 eqaf.bigstring=0.9 eqaf.cstruct=0.9 faad=0.5.2 fdkaac=0.3.3 ffmpeg-av=1.1.9 ffmpeg-avcodec=1.1.9 ffmpeg-avdevice=1.1.9 ffmpeg-avfilter=1.1.9 ffmpeg-avutil=1.1.9 ffmpeg-swresample=1.1.9 ffmpeg-swscale=1.1.9 fileutils=0.6.4 flac=0.5.0 flac.decoder=0.5.0 flac.ogg=0.5.0 fmt=0.9.0 fpath=0.7.3 frei0r=0.1.2 gd=1.0a5 gen=1.1 gmap=0.3.0 hkdf=1.0.4 inotify=2.4.1 integers ipaddr=5.5.0 ipaddr-sexp=5.5.0 ipaddr.unix=5.5.0 irc-client irc-client-unix jemalloc ladspa=0.2.2 lame=0.3.7 lastfm=0.3.3 lilv=0.1.0 liquidsoap-lang=2.2.2 liquidsoap-lang.console=2.2.2 liquidsoap_alsa=v2.2.2-1-g93f305b liquidsoap_ao=v2.2.2-1-g93f305b liquidsoap_bjack=v2.2.2-1-g93f305b liquidsoap_builtins=v2.2.2-1-g93f305b liquidsoap_camlimages=v2.2.2-1-g93f305b liquidsoap_core=v2.2.2-1-g93f305b liquidsoap_dssi=v2.2.2-1-g93f305b liquidsoap_faad=v2.2.2-1-g93f305b liquidsoap_fdkaac=v2.2.2-1-g93f305b liquidsoap_ffmpeg=v2.2.2-1-g93f305b liquidsoap_flac=v2.2.2-1-g93f305b liquidsoap_frei0r=v2.2.2-1-g93f305b liquidsoap_gd=v2.2.2-1-g93f305b liquidsoap_irc=v2.2.2-1-g93f305b liquidsoap_jemalloc=v2.2.2-1-g93f305b liquidsoap_ladspa=v2.2.2-1-g93f305b liquidsoap_lame=v2.2.2-1-g93f305b liquidsoap_lastfm=v2.2.2-1-g93f305b liquidsoap_lilv=v2.2.2-1-g93f305b liquidsoap_lo=v2.2.2-1-g93f305b liquidsoap_mad=v2.2.2-1-g93f305b liquidsoap_magic=v2.2.2-1-g93f305b liquidsoap_mem_usage=v2.2.2-1-g93f305b liquidsoap_memtrace=v2.2.2-1-g93f305b liquidsoap_ogg=v2.2.2-1-g93f305b liquidsoap_ogg_flac=v2.2.2-1-g93f305b liquidsoap_optionals=v2.2.2-1-g93f305b liquidsoap_opus=v2.2.2-1-g93f305b liquidsoap_osc=v2.2.2-1-g93f305b liquidsoap_oss=v2.2.2-1-g93f305b liquidsoap_portaudio=v2.2.2-1-g93f305b liquidsoap_posix_time=v2.2.2-1-g93f305b liquidsoap_prometheus=v2.2.2-1-g93f305b liquidsoap_pulseaudio=v2.2.2-1-g93f305b liquidsoap_runtime=v2.2.2-1-g93f305b liquidsoap_samplerate=v2.2.2-1-g93f305b liquidsoap_sdl=v2.2.2-1-g93f305b liquidsoap_shine=v2.2.2-1-g93f305b liquidsoap_soundtouch=v2.2.2-1-g93f305b liquidsoap_speex=v2.2.2-1-g93f305b liquidsoap_srt=v2.2.2-1-g93f305b liquidsoap_ssl=v2.2.2-1-g93f305b liquidsoap_stereotool=v2.2.2-1-g93f305b liquidsoap_taglib=v2.2.2-1-g93f305b liquidsoap_theora=v2.2.2-1-g93f305b liquidsoap_tls=v2.2.2-1-g93f305b liquidsoap_vorbis=v2.2.2-1-g93f305b liquidsoap_xmlplaylist=v2.2.2-1-g93f305b liquidsoap_yaml=v2.2.2-1-g93f305b lo=0.2.0 logs=0.7.0 logs.fmt=0.7.0 logs.lwt=0.7.0 lwt=5.6.1 lwt.unix=5.6.1 macaddr=5.5.0 mad=0.5.3 magic=0.7.3 magic-mime=1.3.0 mem_usage=0.0.4 memtrace=0.2.3 menhirLib=20230608 metadata=0.2.0 mirage-crypto=0.11.1 mirage-crypto-ec=0.11.1 mirage-crypto-pk=0.11.1 mirage-crypto-rng=0.11.1 mirage-crypto-rng.unix=0.11.1 mm=0.8.4 mm.audio=0.8.4 mm.base=0.8.4 mm.image=0.8.4 mm.midi=0.8.4 mm.video=0.8.4 ocplib-endian ocplib-endian.bigstring ogg=0.7.4 ogg.decoder=0.7.4 opus=0.2.3 opus.decoder=0.2.3 osc osc-unix parsexp=v0.16.0 pbkdf pcre=7.5.0 portaudio=0.2.3 posix-base=b516d46 posix-socket=b516d46 posix-socket.constants=b516d46 posix-socket.stubs=b516d46 posix-socket.types=b516d46 posix-time2=b516d46 posix-time2.constants=b516d46 posix-time2.stubs=b516d46 posix-time2.types=b516d46 posix-types=b516d46 posix-types.constants=b516d46 ppx_sexp_conv.runtime-lib=v0.16.0 prometheus=1.2 prometheus-app=1.2 ptime=1.1.0 ptime.clock.os=1.1.0 pulseaudio=0.1.6 re=1.10.4 result=1.5 rresult=0.7.0 samplerate=0.1.7 sedlex=a1362bd seq=[distributed with OCaml 4.07 or above] sexplib=v0.16.0 sexplib0=v0.16.0 shine=0.2.3 soundtouch=0.1.9 speex=0.4.2 speex.decoder=0.4.2 srt=0.3.0 srt.constants=0.3.0 srt.stubs=0.3.0 srt.stubs.locked=0.3.0 srt.types=0.3.0 ssl=0.7.0 stdlib-shims=0.3.0 stereotool=v2.2.2-1-g93f305b str=[distributed with OCaml] stringext=1.6.0 taglib=0.3.10 theora=0.4.1 theora.decoder=0.4.1 threads=[distributed with OCaml] threads.posix=[distributed with OCaml] tls=0.17.0 tsdl=v1.0.0 tsdl-image=0.5 tsdl-ttf=0.5 unix=[distributed with OCaml] unix-errno=52c6ecb unix-errno.errno_bindings=52c6ecb unix-errno.errno_types=52c6ecb unix-errno.errno_types_detected=52c6ecb unix-errno.unix=52c6ecb uri=4.2.0 uri-sexp=4.2.0 uri.services=4.2.0 vorbis=0.8.1 vorbis.decoder=0.8.1 x509=0.16.4 xmlm=1.4.0 xmlplaylist=0.1.5 yaml=3.1.0 yaml.bindings=3.1.0 yaml.bindings.types=3.1.0 yaml.c=3.1.0 yaml.ffi=3.1.0 yaml.types=3.1.0 zarith=1.12 test1-liquidsoap-1 | 2023/11/17 00:30:09 [clock:3] Using native (high-precision) implementation for latency control test1-liquidsoap-1 | 2023/11/17 00:30:14 [main:3] Standard library loaded in 4.25 seconds. test1-liquidsoap-1 | 2023/11/17 00:30:14 [frame:3] Using 44100Hz audio, 25Hz video, 44100Hz main. test1-liquidsoap-1 | 2023/11/17 00:30:14 [frame:3] Video frame size set to: 1280x720 test1-liquidsoap-1 | 2023/11/17 00:30:14 [frame:3] Frame size must be a multiple of 1764 ticks = 1764 audio samples = 1 video samples. test1-liquidsoap-1 | 2023/11/17 00:30:14 [frame:3] Targeting 'frame.duration': 0.04s = 1764 audio samples = 1764 ticks. test1-liquidsoap-1 | 2023/11/17 00:30:14 [frame:3] Frames last 0.04s = 1764 audio samples = 1 video samples = 1764 ticks. test1-liquidsoap-1 | 2023/11/17 00:30:14 [sandbox:3] Sandboxing disabled test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] DSSI plugins registration: 0.00s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] FFmpeg filters registration: 0.02s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] FFmpeg bitstream filters registration: 0.00s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] Lilv plugins registration: 0.00s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] Frei0r plugin registration: 0.00s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] LADSPA plugins registration: 0.00s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] Typechecking: 4.02s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] Evaluation: 0.01s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] Typechecking: 0.02s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] Evaluation: 0.00s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] Typechecking: 0.00s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] Evaluation: 0.00s test1-liquidsoap-1 | 2023/11/17 00:30:14 [startup:3] Loaded /tmp/test/main.liq: 0.00s test1-liquidsoap-1 | 2023/11/17 00:30:14 [input.harbor:3] Content type is {audio=pcm(stereo)}. test1-liquidsoap-1 | 2023/11/17 00:30:14 [harbor:3] Adding mountpoint '/test' on port 8000 test1-liquidsoap-1 | 2023/11/17 00:30:14 [output_file:3] Content type is {audio=pcm(stereo)}. test1-liquidsoap-1 | 2023/11/17 00:30:14 [metadata_map.2:3] Content type is {audio=pcm(stereo)}. test1-liquidsoap-1 | 2023/11/17 00:30:14 [metadata_map:3] Content type is {}. test1-liquidsoap-1 | 2023/11/17 00:30:14 [dummy:3] Content type is {audio=pcm(stereo)}. test1-liquidsoap-1 | 2023/11/17 00:30:14 [sine:3] Content type is {audio=pcm(stereo)}. test1-liquidsoap-1 | 2023/11/17 00:30:14 [clock.main:3] Streaming loop starts in auto-sync mode test1-liquidsoap-1 | 2023/11/17 00:30:14 [clock.main:3] Delegating synchronization to CPU clock test1-liquidsoap-1 | 2023/11/17 00:30:14 [video.converter:3] Using preferred video converter: ffmpeg. test1-liquidsoap-1 | 2023/11/17 00:30:14 [audio.converter:3] Using samplerate converter: libsamplerate. test1-liquidsoap-1 | 2023/11/17 00:30:14 [video.text:3] Using sdl implementation test1-liquidsoap-1 | 2023/11/17 00:30:14 [switch:3] Switch to sine. ```
    2. After that, the CPU usage will decrease.
    3. Start the stream.

      Logs ``` test1-liquidsoap-1 | 2023/11/17 00:30:18 [input.harbor:3] Decoding... test1-liquidsoap-1 | 2023/11/17 00:30:30 [switch:3] Switch to metadata_map.2 with transition. test1-liquidsoap-1 | 2023/11/17 00:30:30 [replay_metadata:3] Content type is {audio=pcm(stereo)}. test1-liquidsoap-1 | 2023/11/17 00:30:38 [input.harbor:2] Feeding stopped: Ffmpeg_decoder.End_of_file. ```
    4. After that, the CPU usage will increase to 100%.
toots commented 11 months ago

I can reproduce now but weirdly enough, on amd64 only. The issue does not seem to pop out on arm64, that's puzzling.

SkillenUK commented 11 months ago

I'm having this same issue in 2.2.2. I just came on here to see if there was a solution, I may just roll back to 2.2.1 for now.

toots commented 11 months ago

I'll get to this as soon as possible. Thanks for y'all patience.

toots commented 11 months ago

I believe that the changes in this CI build might fix the problem: https://github.com/savonet/liquidsoap/actions/runs/6991394869 Any chance one of y'all could test them?

vitoyucepi commented 11 months ago

Version 2.2.3+git@b2df6caed has the same problem.

Log ``` 2023/11/26 05:46:57 >>> LOG START 2023/11/26 05:46:53 [main:3] Liquidsoap 2.2.3+git@b2df6caed 2023/11/26 05:46:53 [main:3] Using: alsa=0.3.0 angstrom=0.15.0 ao=0.2.4 asetmap=0.8.1 asn1-combinators=0.2.6 astring=0.8.5 base64=3.5.1 bigarray=[distributed with Ocaml] bigarray-compat=1.1.0 bigstringaf=0.9.1 bjack=0.1.6 bos=0.2.1 bytes=[distributed with OCaml 4.02 or above] ca-certs=v0.2.3 camlimages.all_formats=4.2.6 camlimages.core=5.0.4 camlimages.exif=5.0.4 camlimages.gif=5.0.4 camlimages.jpeg=5.0.4 camlimages.png=5.0.4 camlimages.tiff=5.0.4 camlimages.xpm=5.0.4 camlp-streams camomile.lib=2.0 cohttp=5.3.0 cohttp-lwt=5.3.0 cohttp-lwt-unix=5.3.0 conduit=6.2.0 conduit-lwt=6.2.0 conduit-lwt-unix=6.2.0 cry=1.0.2 cstruct=6.2.0 ctypes=0.21.1 ctypes-foreign=0.21.1 ctypes.stubs=0.21.1 curl=0.9.2 domain-name=0.4.0 dssi=0.1.5 dtools=0.4.5 dune-build-info=3.11.1 dune-private-libs.dune-section=3.11.1 dune-site=3.11.1 dune-site.private=3.11.1 duppy=0.9.3 eqaf=0.9 eqaf.bigstring=0.9 eqaf.cstruct=0.9 faad=0.5.2 fdkaac=0.3.3 ffmpeg-av=1.1.9 ffmpeg-avcodec=1.1.9 ffmpeg-avdevice=1.1.9 ffmpeg-avfilter=1.1.9 ffmpeg-avutil=1.1.9 ffmpeg-swresample=1.1.9 ffmpeg-swscale=1.1.9 fileutils=0.6.4 flac=0.5.1 flac.decoder=0.5.1 flac.ogg=0.5.1 fmt=0.9.0 fpath=0.7.3 frei0r=0.1.2 gd=1.0a5 gen=1.1 gmap=0.3.0 hkdf=1.0.4 inotify=2.4.1 integers ipaddr=5.5.0 ipaddr-sexp=5.5.0 ipaddr.unix=5.5.0 irc-client irc-client-unix jemalloc ladspa=0.2.2 lame=0.3.7 lastfm=0.3.3 lilv=0.1.0 liquidsoap-lang=2.2.3 liquidsoap-lang.console=2.2.3 liquidsoap_alsa=76de133-dirty liquidsoap_ao=76de133-dirty liquidsoap_bjack=76de133-dirty liquidsoap_builtins=76de133-dirty liquidsoap_camlimages=76de133-dirty liquidsoap_core=76de133-dirty liquidsoap_dssi=76de133-dirty liquidsoap_faad=76de133-dirty liquidsoap_fdkaac=76de133-dirty liquidsoap_ffmpeg=76de133-dirty liquidsoap_flac=76de133-dirty liquidsoap_frei0r=76de133-dirty liquidsoap_gd=76de133-dirty liquidsoap_irc=76de133-dirty liquidsoap_jemalloc=76de133-dirty liquidsoap_ladspa=76de133-dirty liquidsoap_lame=76de133-dirty liquidsoap_lastfm=76de133-dirty liquidsoap_lilv=76de133-dirty liquidsoap_lo=76de133-dirty liquidsoap_mad=76de133-dirty liquidsoap_magic=76de133-dirty liquidsoap_mem_usage=76de133-dirty liquidsoap_memtrace=76de133-dirty liquidsoap_ogg=76de133-dirty liquidsoap_ogg_flac=76de133-dirty liquidsoap_optionals=76de133-dirty liquidsoap_opus=76de133-dirty liquidsoap_osc=76de133-dirty liquidsoap_oss=76de133-dirty liquidsoap_portaudio=76de133-dirty liquidsoap_posix_time=76de133-dirty liquidsoap_prometheus=76de133-dirty liquidsoap_pulseaudio=76de133-dirty liquidsoap_runtime=76de133-dirty liquidsoap_samplerate=76de133-dirty liquidsoap_sdl=76de133-dirty liquidsoap_shine=76de133-dirty liquidsoap_soundtouch=76de133-dirty liquidsoap_speex=76de133-dirty liquidsoap_srt=76de133-dirty liquidsoap_ssl=76de133-dirty liquidsoap_stereotool=76de133-dirty liquidsoap_taglib=76de133-dirty liquidsoap_theora=76de133-dirty liquidsoap_tls=76de133-dirty liquidsoap_vorbis=76de133-dirty liquidsoap_xmlplaylist=76de133-dirty liquidsoap_yaml=76de133-dirty lo=0.2.0 logs=0.7.0 logs.fmt=0.7.0 logs.lwt=0.7.0 lwt=5.7.0 lwt.unix=5.7.0 macaddr=5.5.0 mad=0.5.3 magic=0.7.3 magic-mime=1.3.1 mem_usage=0.0.4 memtrace=0.2.3 menhirLib=20230608 metadata=0.2.0 mirage-crypto=0.11.2 mirage-crypto-ec=0.11.2 mirage-crypto-pk=0.11.2 mirage-crypto-rng=0.11.2 mirage-crypto-rng.unix=0.11.2 mm=0.8.4 mm.audio=0.8.4 mm.base=0.8.4 mm.image=0.8.4 mm.midi=0.8.4 mm.video=0.8.4 ocplib-endian ocplib-endian.bigstring ogg=0.7.4 ogg.decoder=0.7.4 opus=0.2.3 opus.decoder=0.2.3 osc osc-unix parsexp=v0.16.0 pbkdf pcre=7.5.0 portaudio=0.2.3 posix-base=5a7f328 posix-socket=5a7f328 posix-socket.constants=5a7f328 posix-socket.stubs=5a7f328 posix-socket.types=5a7f328 posix-time2=5a7f328 posix-time2.constants=5a7f328 posix-time2.stubs=5a7f328 posix-time2.types=5a7f328 posix-types=5a7f328 posix-types.constants=5a7f328 ppx_sexp_conv.runtime-lib=v0.16.0 prometheus=1.2 prometheus-app=1.2 ptime=1.1.0 ptime.clock.os=1.1.0 pulseaudio=0.1.6 re=1.11.0 result=1.5 rresult=0.7.0 samplerate=0.1.7 sedlex=3.2 seq=[distributed with OCaml 4.07 or above] sexplib=v0.16.0 sexplib0=v0.16.0 shine=0.2.3 soundtouch=0.1.9 speex=0.4.2 speex.decoder=0.4.2 srt=0.3.0 srt.constants=0.3.0 srt.stubs=0.3.0 srt.stubs.locked=0.3.0 srt.types=0.3.0 ssl=0.7.0 stdlib-shims=0.3.0 stereotool=76de133-dirty str=[distributed with Ocaml] stringext=1.6.0 taglib=0.3.10 theora=0.4.1 theora.decoder=0.4.1 threads=[distributed with Ocaml] threads.posix=[internal] tls=0.17.1 tsdl=v1.0.0 tsdl-image=0.5 tsdl-ttf=0.6 unix=[distributed with Ocaml] unix-errno=52c6ecb unix-errno.errno_bindings=52c6ecb unix-errno.errno_types=52c6ecb unix-errno.errno_types_detected=52c6ecb unix-errno.unix=52c6ecb uri=4.4.0 uri-sexp=4.4.0 uri.services=4.4.0 vorbis=0.8.1 vorbis.decoder=0.8.1 x509=0.16.5 xmlm=1.4.0 xmlplaylist=0.1.5 yaml=3.2.0 yaml.bindings=3.2.0 yaml.bindings.types=3.2.0 yaml.c=3.2.0 yaml.ffi=3.2.0 yaml.types=3.2.0 zarith=1.13 2023/11/26 05:46:53 [main:3] 2023/11/26 05:46:53 [main:3] DISCLAIMER: This version of Liquidsoap has been compiled from a snapshot of the 2023/11/26 05:46:53 [main:3] development code. As such, it should not be used in production unless you know 2023/11/26 05:46:53 [main:3] what you are doing! 2023/11/26 05:46:53 [main:3] 2023/11/26 05:46:53 [main:3] We are, however, very interested in any feedback about our development code and 2023/11/26 05:46:53 [main:3] committed to fix issues as soon as possible. 2023/11/26 05:46:53 [main:3] 2023/11/26 05:46:53 [main:3] If you are interested in collaborating to the development of Liquidsoap, feel 2023/11/26 05:46:53 [main:3] free to drop us a mail at or to join the slack chat 2023/11/26 05:46:53 [main:3] at . 2023/11/26 05:46:53 [main:3] 2023/11/26 05:46:53 [main:3] Please send any bug report or feature request at 2023/11/26 05:46:53 [main:3] . 2023/11/26 05:46:53 [main:3] 2023/11/26 05:46:53 [main:3] We hope you enjoy this snapshot build of Liquidsoap! 2023/11/26 05:46:53 [main:3] 2023/11/26 05:46:53 [clock:3] Using native (high-precision) implementation for latency control 2023/11/26 05:46:57 [main:3] Standard library loaded in 3.46 seconds. 2023/11/26 05:46:57 [frame:3] Using 44100Hz audio, 25Hz video, 44100Hz main. 2023/11/26 05:46:57 [frame:3] Video frame size set to: 1280x720 2023/11/26 05:46:57 [frame:3] Frame size must be a multiple of 1764 ticks = 1764 audio samples = 1 video samples. 2023/11/26 05:46:57 [frame:3] Targeting 'frame.duration': 0.04s = 1764 audio samples = 1764 ticks. 2023/11/26 05:46:57 [frame:3] Frames last 0.04s = 1764 audio samples = 1 video samples = 1764 ticks. 2023/11/26 05:46:57 [sandbox:3] Sandboxing disabled 2023/11/26 05:46:57 [startup:3] DSSI plugins registration: 0.00s 2023/11/26 05:46:57 [startup:3] FFmpeg filters registration: 0.02s 2023/11/26 05:46:57 [startup:3] FFmpeg bitstream filters registration: 0.00s 2023/11/26 05:46:57 [startup:3] Lilv plugins registration: 0.00s 2023/11/26 05:46:57 [startup:3] Frei0r plugin registration: 0.00s 2023/11/26 05:46:57 [startup:3] LADSPA plugins registration: 0.00s 2023/11/26 05:46:57 [startup:3] Typechecking: 3.25s 2023/11/26 05:46:57 [startup:3] Evaluation: 0.01s 2023/11/26 05:46:57 [startup:3] Typechecking: 0.03s 2023/11/26 05:46:57 [startup:3] Evaluation: 0.00s 2023/11/26 05:46:57 [startup:3] Typechecking: 0.00s 2023/11/26 05:46:57 [startup:3] Evaluation: 0.00s 2023/11/26 05:46:57 [startup:3] Loaded /tmp/test/main2.liq: 0.00s 2023/11/26 05:46:57 [input.harbor:3] Content type is {audio=pcm(stereo)}. 2023/11/26 05:46:57 [harbor:3] Adding mountpoint '/test' on port 8000 2023/11/26 05:46:57 [output_file:3] Content type is {audio=pcm(stereo)}. 2023/11/26 05:46:57 [metadata_map.2:3] Content type is {audio=pcm(stereo)}. 2023/11/26 05:46:57 [metadata_map:3] Content type is {}. 2023/11/26 05:46:57 [dummy:3] Content type is {audio=pcm(stereo)}. 2023/11/26 05:46:57 [sine:3] Content type is {audio=pcm(stereo)}. 2023/11/26 05:46:57 [clock.main:3] Streaming loop starts in auto-sync mode 2023/11/26 05:46:57 [clock.main:3] Delegating synchronization to CPU clock 2023/11/26 05:46:57 [video.converter:3] Using preferred video converter: ffmpeg. 2023/11/26 05:46:57 [audio.converter:3] Using samplerate converter: libsamplerate. 2023/11/26 05:46:57 [video.text:3] Using sdl implementation 2023/11/26 05:46:57 [switch:3] Switch to sine. 2023/11/26 05:47:35 [input.harbor:3] Decoding... 2023/11/26 05:47:47 [switch:3] Switch to metadata_map.2 with transition. 2023/11/26 05:47:47 [replay_metadata:3] Content type is {audio=pcm(stereo)}. 2023/11/26 05:48:05 [input.harbor:2] Feeding stopped: Ffmpeg_decoder.End_of_file. 2023/11/26 05:48:17 [switch:3] Switch to sine with forgetful transition. 2023/11/26 05:48:17 [output_file:3] Source failed (no more tracks) stopping output... 2023/11/26 05:48:28 [input.harbor:3] Decoding... 2023/11/26 05:48:40 [switch:3] Switch to metadata_map.2 with transition. 2023/11/26 05:48:40 [replay_metadata.2:3] Content type is {audio=pcm(stereo)}. 2023/11/26 05:48:58 [input.harbor:2] Feeding stopped: Ffmpeg_decoder.End_of_file. 2023/11/26 05:50:46 [output_file:2] Warning: there may be an infinite sequence of empty tracks! 2023/11/26 05:50:46 [output_file:2] Warning: there may be an infinite sequence of empty tracks! 2023/11/26 05:50:46 [output_file:2] Warning: there may be an infinite sequence of empty tracks! ```
toots commented 11 months ago

I was able to test and confirm that the latest commit on the fix-has-ticked-2.2.x branch does fix the issue.

Reproduction was tricky because it relied on two elements:

Partial frame fill can depend on timing such as when the harbor gets available. By changing the duration to 20.03 (frame sizes are 0.04 by default), I was able to make the test case reproducible.

netbladenl commented 11 months ago

Thanks for your work, unfortunately the problem still exists with the new version of liquidsoap

2023/11/28 13:09:30 [lang:3] API djon - Response (200): true
2023/11/28 13:09:30 [input_streamer:3] Decoding...
2023/11/28 13:09:39 [live_fallback:3] Switch to metadata_map.4 with transition.
2023/11/28 13:09:39 [metadata_map.7:3] Inserting missing metadata.
2023/11/28 13:10:09 [input_streamer:2] Error while reading from client: Harbor.Make(T).Websocket_closed
2023/11/28 13:10:09 [lang:3] API djoff - Sending POST request to 'http://127.0.0.1:6010/api/internal/4/liquidsoap/djoff' with body: { "user": "iwan" }
[matroska,webm @ 0x7f84e2e17000] File ended prematurely at pos. 198330 (0x306ba)
[matroska,webm @ 0x7f84e2e17000] Seek to desired resync point failed. Seeking to earliest point available instead.
2023/11/28 13:10:09 [lang:3] API djoff - Response (200): true
2023/11/28 13:10:09 [input_streamer:2] Feeding stopped: Ffmpeg_decoder.End_of_file.
2023/11/28 13:10:09 [lang:3] API djoff - Sending POST request to 'http://127.0.0.1:6010/api/internal/4/liquidsoap/djoff' with body: { "user": "" }
2023/11/28 13:10:09 [lang:3] API djoff - Response (200): true

[2023-11-28 13:10:20] WARN source/_source_read Nothing received on /radio.aac for 3 seconds
[2023-11-28 13:10:20] WARN source/_source_read Nothing received on /radio.mp3 for 3 seconds
[2023-11-28 13:10:20] WARN source/_source_read Nothing received on /radio.aac for 3 seconds
[2023-11-28 13:10:20] WARN source/_source_read Nothing received on /radio.mp3 for 3 seconds
[2023-11-28 13:10:20] WARN source/_source_read Nothing received on /radio.aac for 3 seconds
[2023-11-28 13:10:28] WARN source/_source_read Disconnecting /radio.aac due to socket timeout
[2023-11-28 13:10:28] WARN source/_source_read Disconnecting /radio.mp3 due to socket timeout
[2023-11-28 13:11:01] WARN fserve/fserve_client_create req for file "/usr/local/share/icecast/web/radio.mp3" No such file or directory
[2023-11-28 13:12:21] WARN fserve/fserve_client_create req for file "/usr/local/share/icecast/web/radio.mp3" No such file or directory
[2023-11-28 13:12:22] WARN fserve/fserve_client_create req for file "/usr/local/share/icecast/web/radio.mp3" No such file or directory

The autodj dont come back, after the streamer disconnects

toots commented 11 months ago

Sorry to hear. How did you test it? The rolling release guide hasn't completed yet..

netbladenl commented 11 months ago

commit on the fix-has-ticked-2.2.x branch does fix the issue.

Oh I thought that the patch was already released, my bad. I've asked Buster to use the newest rolling release of liquidsoap with the Azuracast rolling release. Maybe I'm a bit to fast.

vitoyucepi commented 11 months ago

2.2.3+git@4181a8c9d works fine.

toots commented 11 months ago

The build of rolling-release-v2.2.x including the fix has just finished!

netbladenl commented 11 months ago

The problem has been resolved, thanks for all of your help!