The routes tell the encoder no URL, so an audio codec is never inferred from one #189
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?
Upstream reads the path a streaming request arrived on and infers an audio
codec from it when the client named none. Ours never passes the path at all,
so the inference always answers the same thing.
upstream/Jellyfin.Api/Helpers/StreamingHelpers.cs:70-75:RightPart('.')is the part after the last dot, or the whole path when thereis none.
EncodingHelper.InferAudioCodecmapsm4a/mp4/mkvtoaac,ts/avi/flvtomp3,ogg/webmtoopus, an empty string toaac,and anything else to itself, lowercased.
Ours has the same function —
ephyra_encoding::codec::infer_audio_codec— andthe only caller that could feed it (
Helper::attach) is givenrequested_url: Noneby every route (crates/ephyra-app/src/streaming/encoder/jobs.rs:49).It therefore always sees an empty string and always answers
aac.Measured
Both servers on the anchor,
GET /Audio/{id}/universal?container=mp3&transcodingProtocol=hls(no
audioCodec), the master playlist each answers with:The path carries no dot, so what upstream infers is the whole path — a URL
where a codec belongs, and a request nothing can encode. It is upstream's
answer nonetheless, and the bodies differ.
The interesting half is not that one:
/Audio/{id}/stream.mp3with noaudioCodecinfersmp3upstream andaachere, which is a real transcodeinto the wrong codec rather than a curiosity.
Two things to settle: whether the port carries the inference at all, given
that the only shape a client really sends it in is the one with an extension;
and
infer_audio_codec's fallthrough arm, which answers the containerunlowercased where upstream lowercases it.
How to know it is done
A request naming no audio codec is encoded to the codec upstream infers from
the same path, on the routes that carry an extension and on the one that does
not, and the harness agrees on what each answers.
House rules
Tests run under
cargo nextest; upstream's source is the checkout inupstream/at the pin.Done in
bfd35d8.Every streaming route now hands the encoder the path the request arrived on,
and the inference is upstream's: the part after the path's last dot, or the
whole path where it has none, mapped by
InferAudioCodec— with thefallthrough lowercased, which was the second half of what this asked to settle.
The answer to the first half is that the port carries it. A request for
stream.tsnaming no audio codec is encoded to mp3 rather than aac, which isthe shape a real client can land on; the odd values the rule produces for a
path with no extension are upstream's own and cost nothing, because a client
that names its codec — all of them do — never reaches them.
The master playlist's query rewriting moved to one place while this was being
done: the codec rewrite already lived in the playlist itself, and the two
parameters the universal audio route settles now sit beside it, where upstream
does all three. A value that has never been through a URL is escaped as it goes
into one.
Measured
Both servers on the anchor, five playlist shapes, byte for byte:
and the three shapes that already agreed still do.
A review of the commit found four parity gaps in the surrounding query
rewriting, three of them older than this change: the rotation refusal upstream
appends for a copied, rotated video cut into ts; the renormalisation upstream's
rebuild applies to every pair (
+for a space, lowercase hex, a repeated key);and a trim this introduced. They are being fixed on top rather than left.