diff --git a/README.md b/README.md index 76d6ceb..1c7f229 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ Radio streamer ([kawa](https://github.com/Luminarys/kawa) drop-in compatible). * Can read and apply ReplayGain tags, or normalize audio loudness. * Can have audio sources over HTTP(s) URLs on `path` property, and supports seeking. * Precise metadata and timing information packet stream, trigger via `x-audio-packet-stream: 1` HTTP header. +* Workaround to allow FLAC streaming under Safari ## Dependencies ### Go >= 1.18 diff --git a/queue.go b/queue.go index 2c20d30..9a7691f 100644 --- a/queue.go +++ b/queue.go @@ -450,6 +450,36 @@ func (q *Queue) HandleRadioRequest(writer http.ResponseWriter, request *http.Req rangeHeader := request.Header.Get("range") if rangeHeader != "" && rangeHeader != "bytes=0-" { //TODO: maybe should fail in case bytes are requested + + if strings.Index(request.UserAgent(), " Safari/") != -1 && mount.MimeType == "audio/flac" { + //Safari special case, fake Range check so it decodes afterwards. + //Safari creates a request with Range for 0-1, specifically for FLAC, and expects a result supporting range. Afterwards it requests the whole file. + //However the decoder is able to decode FLAC livestreams. If we fake the initial range response, then afterwards serve normal responses, Safari will happily work. + //TODO: remove this AS SOON as safari works on its own + //safariLargeFileValue arbitrary large value, cannot be that large or iOS Safari fails. + safariLargeFileValue := 1024 * 1024 * 1024 * 1024 * 16 // 16 TiB + + if rangeHeader == "bytes=0-1" { + //first request + writer.Header().Set("Accept-Ranges", "bytes") + writer.Header().Set("Content-Range", fmt.Sprintf("bytes 0-1/%d", safariLargeFileValue)) //64 TiB max fake size + writer.Header().Set("Content-Length", "2") + writer.WriteHeader(http.StatusPartialContent) + writer.Write([]byte{'\x00', '\x00'}) + return + } else if rangeHeader == fmt.Sprintf("bytes=0-%d", safariLargeFileValue-1) { + //second request, serve status 200 to keep retries to a minimum + writer.Header().Set("Content-Length", fmt.Sprintf("%d", safariLargeFileValue)) + writer.WriteHeader(http.StatusOK) + } else if strings.HasPrefix(rangeHeader, "bytes=") && strings.HasSuffix(rangeHeader, fmt.Sprintf("-%d", safariLargeFileValue-1)) { + //any other requests, these should fail + writer.Header().Set("Content-Range", fmt.Sprintf("bytes %s/%d", strings.TrimPrefix(rangeHeader, "bytes="), safariLargeFileValue)) + writer.Header().Set("Accept-Ranges", "bytes") + writer.WriteHeader(http.StatusRequestedRangeNotSatisfiable) + return + } + + } } bitrate := 0