/Audio/{id}/universal answers 500 for anything that is not a direct play #184
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found running
transcoding.jsonover a live pair for #117./Audio/{id}/universalis the route a client asks for a track through, and itanswers
500for anything the negotiation does not settle as a direct play:crates/ephyra-http/src/routes/streaming/audio.rs:92-98says so outright:So a library holding anything a client cannot take as it is — a flac to a
browser wanting mp3 is the ordinary case — answers
500where upstream servesaudio.
The encoder path it needs is already there.
videos.rs:503-560builds theencoding request, calls
start_or_join, and serves the growing file; the samecall from this route is most of the progressive half. Upstream's other branch,
TranscodingSubProtocol == hls, answers with a playlist and is the rest.Where to start
crates/ephyra-http/src/routes/streaming/audio.rs:92, andcrates/ephyra-http/src/routes/streaming/videos.rs:503-560for the shape theprogressive answer takes. Upstream's
UniversalAudioControllerdecides betweenthe two branches on the profile the negotiation settled.
Worth knowing before writing the branch: upstream builds one transcoding
profile with
Container = transcodingContainer ?? "mp3"(
upstream/Jellyfin.Api/Controllers/UniversalAudioController.cs:293-303), soa request naming
container=aacand notranscodingContainergets mp3 anyway— and upstream then muxes AAC with the MP3 muxer and dies with its own
500.Matching that is matching a bug, but it is what the pinned server does.
How to know it is done
transcoding.json's two audio requests answer with audio on both servers andagree, which is measurable rather than assertable: they are two of the six the
#117gate drops today.House rules
Tests run under
cargo nextest; upstream's source is the checkout inupstream/at the pin. Generated artifacts are regenerated, never edited.Fixed in
4ee1184, with the review's findings folded in as92c3f94.The route now hands the request to the stream routes the way upstream hands it
to the same helper:
staticwhere the verdict was direct play, and into thetranscoding container the client named otherwise.
Measured. The
transcodingworkload gates every request against bothservers before timing anything. Before:
After, the request is no longer dropped — it is one of the two the gate now
agrees on, with nothing unanswered by either server.
A review against
UniversalAudioController.csturned up three things worthcorrecting, all in
92c3f94:-codec:v:0 copyinto an.mp3. Upstream's audio helper is audio-onlywhatever the item is, and the route decides that, not the row. This was
already true of
/Audio/{id}/stream; it is now right for both.maxAudioBitDepthwas not bound at all, so the audio stream-copy decisionwas made without it — a 24-bit source against
maxAudioBitDepth=16could becopied where upstream re-encodes.
transcodingAudioChannelsandenableAudioVbrEncodingwere being passed tothe encoder; upstream's progressive branch carries neither.
Two things the review found are real but out of this issue's scope and are
filed separately:
transcodingProtocol=hls(#186) and the audio negotiationnever answering
DirectStream(#187).