eshaz / icecast-metadata-js

Browser and NodeJS packages for playing and reading Icecast compatible streaming audio with realtime metadata updates.
164 stars 20 forks source link

AbortError with streams from Icecast 2.4.0-kh22 #186

Closed VocalZero closed 1 year ago

VocalZero commented 1 year ago

Hi, I noticed an error in icecast-metadata-js when trying to play a stream from an Icecast server with version 2.4.0-kh22 (latest). In the version Icecast 2.4.0-kh21.6 everything worked fine. An AbortError occurs: Fetch is aborted.

I have tested it on iOS and iPadOS and it seems to be only on the two the problem.

Test page with two streams (Icecast 2.4.0-kh22 (latest) and Icecast 2.4.0-kh21.6): https://testapp-icecastplayer.pages.dev/

IMG_0044 IMG_0045

VocalZero commented 1 year ago

image

They changed something in Icecast 2.4.0-kh21.7 for Safari. Could perhaps be due to this?

eshaz commented 1 year ago

That's really odd if there was a change made for Safari on the server side. I'll take a look.

Reading the commit history, it looks like there was a Safari change introduced and then reverted.

Which version(s) of iOS are running on your devices?

VocalZero commented 1 year ago

You're right, I hadn't seen that. We have this on iOS 17.0.2, iPadOS 17.0.1 and iPadOS 16.6.

VocalZero commented 1 year ago

I noticed something else between the two Icecast versions. If you try to call a stream URL from Icecast 2.4.0-kh22, you are redirected to the same URL, but this time a query parameter _ic2= is appended. This query parameter is only added in Safari. This was not the case before. Could it be that icecast-metadata-js can't handle this redirection?

Examples: Icecast 2.4.0-kh22: https://edge01.atomicradio.eu/one/highquality becomes https://edge01.atomicradio.eu/one/highquality?_ic2=1696156629148

IMG_0048

Icecast 2.4.0-kh21.6: https://edge02.atomicradio.eu/one/highquality still remains the same as the call. Nothing changes at all.

IMG_0049

Was changed in this commit: https://github.com/karlheyes/icecast-kh/commit/4addd45afaedb6c5f7fa60b521d73972c1cb9ce9

VocalZero commented 1 year ago

I just tried a little workaround, if you add the query parameter _ic2 yourself and start the playback via icecast-metadata-player it works again. It really looks like icecast-metadata-player can't handle the redirection.

I added this workaround to my test site: https://testapp-icecastplayer.pages.dev/

eshaz commented 1 year ago

I was able to reproduce the redirection error on the iOS simulator using my demo page. It appears to be a CORS restriction that is blocking the redirection. I think the best work around for now is to hardcode the query parameter like you're doing in your test page.

Icecast 2.4.0-kh22: https://edge01.atomicradio.eu/one/highquality image

The other URL worked just fine in my demo page.

I might be missing something, but it appears the redirect doesn't include the normal CORS headers. I think this would be fixed if those headers were present in the redirect response.

https://github.com/karlheyes/icecast-kh/commit/4addd45afaedb6c5f7fa60b521d73972c1cb9ce9#diff-8cd16d58009c14bba46f654ee9700f64f9da67ad24ff39b38b2b8130d7e4956aR386-R387

I'll see if I can fix this in icecast-kh.

eshaz commented 1 year ago

A wireshark capture of the redirect shows there are for sure no CORS headers on the redirect response.

OPTIONS /one/highquality HTTP/1.1
Host: edge01.atomicradio.eu
Origin: http://192.168.1.218:3000
Access-Control-Request-Method: GET
Content-Length: 0
Access-Control-Request-Headers: icy-metadata
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Mobile/15E148 Safari/604.1
Referer: http://192.168.1.218:3000/
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate

HTTP/1.1 204 No Content
Server: Icecast
Connection: keep-alive
Pragma: no-cache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, private
Vary: Origin
Access-Control-Allow-Origin: http://192.168.1.218:3000
Access-Control-Allow-Credentials: True
Access-Control-Allow-Headers: Origin, Icy-MetaData, Range
Access-Control-Expose-Headers: Icy-Br, Icy-Description, Icy-Genre, Icy-MetaInt, Icy-Name, Icy-Pub, Icy-Url
Access-Control-Allow-Methods: GET, OPTIONS, SOURCE, PUT, HEAD, STATS
Date: Sun, 01 Oct 2023 17:43:53 GMT
Content-Type: text/html
Content-Length: 0

GET /one/highquality HTTP/1.1
Host: edge01.atomicradio.eu
Origin: http://192.168.1.218:3000
Connection: keep-alive
Icy-Metadata: 1
Accept: */*
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Mobile/15E148 Safari/604.1
Referer: http://192.168.1.218:3000/
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate

HTTP/1.0 302 Found
Connection: Close
Date: Sun, 01 Oct 2023 17:43:54 GMT
Content-Type: text/html
Location: http://edge01.atomicradio.eu/one/highquality?_ic2=1696182234062
Content-Length: 0
eshaz commented 1 year ago

I looked through icecast-kh, and found the issue. I'm not sure what this line is doing, but it's causing the problem by filtering out the CORS headers. Removing the line, and allowing the CORS headers to be sent on the 302 response, fixed the error in iOS.

https://github.com/karlheyes/icecast-kh/blob/a8cfaae2bde027f714b8d1099c5adb88f4bed922/src/params.c#L306

Wireshark tap of the HTTP stream with this line removed:

OPTIONS /stream HTTP/1.1
Host: 192.168.1.218:8000
Origin: http://192.168.1.218:3000
Access-Control-Request-Method: GET
Content-Length: 0
Access-Control-Request-Headers: icy-metadata
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Mobile/15E148 Safari/604.1
Referer: http://192.168.1.218:3000/
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate

HTTP/1.1 204 No Content
Server: Icecast
Connection: keep-alive
Pragma: no-cache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, private
Vary: Origin
Access-Control-Allow-Origin: http://192.168.1.218:3000
Access-Control-Allow-Credentials: True
Access-Control-Allow-Headers: Origin, Icy-MetaData, Range
Access-Control-Expose-Headers: Icy-Br, Icy-Description, Icy-Genre, Icy-MetaInt, Icy-Name, Icy-Pub, Icy-Url
Access-Control-Allow-Methods: GET, OPTIONS, SOURCE, PUT, HEAD, STATS
Date: Sun, 01 Oct 2023 19:47:30 GMT
Content-Type: text/html
Content-Length: 0

GET /stream HTTP/1.1
Host: 192.168.1.218:8000
Origin: http://192.168.1.218:3000
Connection: keep-alive
Icy-Metadata: 1
Accept: */*
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.2 Mobile/15E148 Safari/604.1
Referer: http://192.168.1.218:3000/
Accept-Language: en-US,en;q=0.9
Accept-Encoding: gzip, deflate

HTTP/1.0 302 Found
Server: Icecast
Connection: Close
Pragma: no-cache
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, private
Vary: Origin
Access-Control-Allow-Origin: http://192.168.1.218:3000
Access-Control-Allow-Credentials: True
Access-Control-Allow-Headers: Origin, Icy-MetaData, Range
Access-Control-Expose-Headers: Icy-Br, Icy-Description, Icy-Genre, Icy-MetaInt, Icy-Name, Icy-Pub, Icy-Url
Access-Control-Allow-Methods: GET, OPTIONS, SOURCE, PUT, HEAD, STATS
Date: Sun, 01 Oct 2023 19:47:30 GMT
Content-Type: text/html
Location: http://192.168.1.218:8000/stream?_ic2=1696189650203
Content-Length: 0
eshaz commented 1 year ago

I opened a PR in icecast-kh for this. It might be a while until that's merged / released, so you might want to implement the work around as your solution for now.

VocalZero commented 1 year ago

Thank you. Yes for the time until your PR is accepted I will have to work with the workaround.