liquidsoap icon indicating copy to clipboard operation
liquidsoap copied to clipboard

output.harbor does not send ICY metadata

Open x00e opened this issue 11 months ago • 2 comments

Using Liquidsoap in docker via official savonet/liquidsoap:b9b936d image from docker http://hub.docker.com, when connecting directly to output.harbor, ICY metadata is not sent (though metadata seems to be read from files). Listening to same stream via IceCast2, ICY metadata is received in player.

using:

INFO: Loading Sdl_image, Target = linux
INFO: Loading Sdl_ttf, Target = linux
Liquidsoap 2.2.1+git@b9b936dbb
Copyright (c) 2003-2023 Savonet team
Liquidsoap is open-source software, released under GNU General Public License.
See <http://liquidsoap.info> for more information.

and this test script:

set("log.level", 6)
set("log.stdout", true)
set("log.file", false)

song1 = single("music/song1.mp3") 
song2 = single("music/song2.mp3") 
ad = single("music/ad_placeholder.mp3")


source = rotate([song1, ad, song2, ad]) 

# MP3 stream
output.harbor(%mp3(bitrate=192),
      port = 8500, mount = "/stream.mp3",
      metaint=512, mksafe(source))

# AAC stream
output.harbor(%fdkaac(channels=2, samplerate=44100, bandwidth="auto",
      bitrate=128, afterburner=false, aot="mpeg4_aac_lc",
      transmux="adts", sbr_mode=false),
      port = 8500, mount = "/stream.aac",
      metaint=512, mksafe(source))

connecting to stream output.harbor via: > mpv --http-header-fields='Icy-MetaData: 1' 'http://127.0.0.1:8500/stream.mp3'

Liquidsoap shows:

2023/08/29 15:14:49 [harbor:4] Method: GET, uri: /stream.mp3, protocol: HTTP/1.1
2023/08/29 15:14:49 [harbor:4] Header: User-Agent, value: libmpv.
2023/08/29 15:14:49 [harbor:4] Header: Accept, value: */*.
2023/08/29 15:14:49 [harbor:4] Header: Range, value: bytes=0-.
2023/08/29 15:14:49 [harbor:4] Header: Connection, value: close.
2023/08/29 15:14:49 [harbor:4] Header: Host, value: 127.0.0.1:8500.
2023/08/29 15:14:49 [harbor:4] Header: Icy-MetaData, value: 1.
2023/08/29 15:14:49 [harbor:4] http/unix GET request on /stream.mp3.
2023/08/29 15:14:49 [harbor:4] Found handler 'GET ^/stream.mp3$' on port 8500.
2023/08/29 15:14:49 [/stream_mp3:4] Serving client 127.0.0.1:41534.
2023/08/29 15:14:49 [/stream_mp3:4] Client 127.0.0.1:41534 connected
2023/08/29 15:15:12 [decoder:2] Decoding "music/song2.mp3" ended: Ffmpeg_decoder.End_of_file.
2023/08/29 15:15:12 [decoder:4] Raised at Ffmpeg_decoder.mk_decoder.(fun).f in file "src/core/decoder/ffmpeg_decoder.ml", line 827, characters 12-29
2023/08/29 15:15:12 [decoder:4] Called from Decoder.mk_decoder.fill in file "src/core/decoder/decoder.ml", line 504, characters 10-31
2023/08/29 15:15:12 [decoder:4] 
2023/08/29 15:15:13 [single.2:4] Finished with "music/song2.mp3".
2023/08/29 15:15:13 [single.3:3] Prepared "music/ad_placeholder.mp3" (RID 2).
2023/08/29 15:15:13 [switch:3] Switch to single.3 with forgetful transition.
2023/08/29 15:15:13 [replay_metadata.5:5] Activations changed: static=[], dynamic=[].
2023/08/29 15:15:13 [source:4] Source replay_metadata.5 gets down.
2023/08/29 15:15:13 [single.2:5] Activations changed: static=[], dynamic=[switch.2:mksafe:/stream_mp3:/stream_mp3, switch:on_track:switch.2:mksafe:/stream_mp3:/stream_mp3].
2023/08/29 15:15:13 [replay_metadata.6:5] Assigning source content type for frame type: {audio : pcm(stereo)}
2023/08/29 15:15:13 [replay_metadata.6:5] Content type: {audio=pcm(stereo)}
2023/08/29 15:15:13 [source:4] Source replay_metadata.6 gets up with content type: {audio=pcm(stereo)}.

Same thing on /stream.aac Using savonet/liquidsoap:v2.2.0, same behavior as above. Using savonet/liquidsoap:v2.1.4, everything works as expected.

It seems to be the exact same behavior as described by bug https://github.com/savonet/liquidsoap/issues/358, which is now marked as closed, so maybe a regression was introduced?

x00e avatar Aug 29 '23 15:08 x00e

I would like to include additional information regarding this issue.

  1. Create two files ffmpeg -f lavfi -i "sine=frequency=100:duration=5" -metadata title=1 1.mp3 ffmpeg -f lavfi -i "sine=frequency=200:duration=5" -metadata title=2 2.mp3
  2. main.liq
    s1 = single("1.mp3")
    s2 = single("2.mp3")
    
    s = rotate([s1, s2])
    
    output.harbor(
      %mp3(bitrate=320),
      mksafe(s),
      port=8000,
      mount="/stream",
      metaint=512,
    )
    

Tests:

  1. curl https://localhost:8000/stream -H 'Icy-MetaData: 1' -s -v curl https://localhost:8000/stream -H 'icy-metadata: 1' -s -v Should print icy-metaint: 512. Because http headers should be case insensitive.
  2. curl https://localhost:8000/stream -H 'Icy-MetaData: 1' -s | head -c 700 | grep -aoP 'StreamTitle=.*?; Should print StreamTitle='1'; or StreamTitle='2';
  3. for i in $(seq 1 10);do curl https://localhost:8000/stream -H 'Icy-MetaData: 1' -s | head -c 700 | grep -aoP 'StreamTitle=.*?;';done Should print StreamTitle='1'; or StreamTitle='2'; 10 times.

vitoyucepi avatar Aug 29 '23 19:08 vitoyucepi

ok, had to adapt the main.liq a bit since i'm running liquidsoap from a docker container

❯ ls
main.liq  music
❯ ls music
1.mp3  2.mp3
❯ cat main.liq
s1 = single("music/1.mp3")
s2 = single("music/2.mp3")

s = rotate([s1, s2])

output.harbor(
  %mp3(bitrate=320),
  mksafe(s),
  port=8000,
  mount="/stream",
  metaint=512,
)

starting liquidsoap container with version v2.2.0:

docker run --rm -v $(pwd)/main.liq:/etc/liquidsoap/liquidsoap.liq -v $(pwd)/music:/music  --network host  --name liq savonet/liquidsoap:v2.2.0 /etc/liquidsoap/liquidsoap.liq

:exclamation: had to use http instead of https running curl http://localhost:8000/stream -H 'Icy-MetaData: 1' -s -v:

❯ curl http://localhost:8000/stream -H 'Icy-MetaData: 1' -s -v
*   Trying 127.0.0.1:8000...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /stream HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.81.0
> Accept: */*
> Icy-MetaData: 1
> 
* Received HTTP/0.9 when not allowed
* Closing connection 0

running curl http://localhost:8000/stream -H 'icy-metaData: 1' -s -v:

❯ curl http://localhost:8000/stream -H 'icy-metaData: 1' -s -v
*   Trying 127.0.0.1:8000...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /stream HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.81.0
> Accept: */*
> icy-metaData: 1
> 
* Received HTTP/0.9 when not allowed
* Closing connection 0

running curl http://localhost:8000/stream -H 'Icy-MetaData: 1' -s | head -c 700 | grep -aoP 'StreamTitle=.*?;' does not output anything. same for:

for i in $(seq 1 10);do curl https://localhost:8000/stream -H 'Icy-MetaData: 1' -s | head -c 700 | grep -aoP 'StreamTitle=.*?;';done

Now, running same commands on liquidsoap container with version v2.1.4 :

docker run --rm -v $(pwd)/main.liq:/etc/liquidsoap/liquidsoap.liq -v $(pwd)/music:/music  --network host  --name liq savonet/liquidsoap:v2.1.4 /etc/liquidsoap/liquidsoap.liq

i get the following:

❯ curl http://localhost:8000/stream -H 'Icy-MetaData: 1' -s -v
*   Trying 127.0.0.1:8000...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /stream HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.81.0
> Accept: */*
> Icy-MetaData: 1
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-type: audio/mpeg
< icy-metaint: 512
* no chunk, no close, no size. Assume close to signal end
< 
* Failure writing output to destination
* Closing connection 0
* 

❯ curl http://localhost:8000/stream -H 'icy-metaData: 1' -s -v
*   Trying 127.0.0.1:8000...
* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET /stream HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.81.0
> Accept: */*
> icy-metaData: 1
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-type: audio/mpeg
* no chunk, no close, no size. Assume close to signal end
< 
* Failure writing output to destination
* Closing connection 0

❯ curl http://localhost:8000/stream -H 'Icy-MetaData: 1' -s | head -c 700 | grep -aoP 'StreamTitle=.*?;'
StreamTitle='1';

❯ for i in $(seq 1 10);do curl http://localhost:8000/stream -H 'Icy-MetaData: 1' -s | head -c 700 | grep -aoP 'StreamTitle=.*?;';done
StreamTitle='2';

x00e avatar Aug 31 '23 15:08 x00e