A playing session reports neither what is playing nor how it is being encoded #166
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?
The playback stats overlay on a file playing over HLS:
and then straight to Original Media Info. Upstream shows
(Transcoding)there and a whole Transcoding Info section between the two.
Both holes are the session we report for the playing client.
NowPlayingItemis never sent.crates/ephyra-http/src/map/session.rs'sinfofillsnow_playing_queueand leavesnow_playing_itematSessionInfoDto::default(), though the registry has held it all along —crates/ephyra-app/src/session/sessions.rs:47, set from the playback report at389 and cleared at 406. The bundle's
getDisplayPlayMethodreturnsnullfora session with no
NowPlayingItembefore it ever looks atPlayState, and thecaller concatenates that into the label — which is the literal
(null)above.Anything else that asks what a session is doing reads the same field.
TranscodingInfois never sent either. Nothing outside the generated DTOmentions it. The stats panel gates the entire section on it —
o.TranscodingInfo && p.push({stats: m(o, t, i), name: h})— so target codecs,output container, bitrate, framerate, completion percentage and the transcode
reasons are all absent, and the section is titled Transcoding, Remuxing or
Direct streaming off the same object.
Upstream.
SessionManager.cs:430puts the item on the session from theplayback report and 1252/1256 copies both fields onto the DTO.
MediaBrowser.MediaEncoding/Transcoding/TranscodeManager.cs:351reportsTranscodingInfoon every progress line ffmpeg writes: bitrate, audio and videocodec, container, framerate, completion percentage, width, height, channels,
IsAudioDirect/IsVideoDirect, the hardware acceleration backend, and thetranscode reasons.
Most of that is already computed here.
crates/ephyra-ffmpeg/src/progress.rsparses
TranscodingProgress { position_ticks, framerate, percent_complete, bytes_transcoded, bit_rate }per job, and its only reader today is thesupervisor that kills a stalled one —
streaming/encoder/refusing.rs. Thecodecs, the container and the dimensions are the job's own request, and
IsAudioDirect/IsVideoDirectare whether either stream was a copy.Where to start
NowPlayingItemon its own settles the(null), and the item id is already onthe live session. The mapping has no repository to materialise it with, which is
presumably why it was skipped: upstream's session carries the built item rather
than an id, so the decision is where that materialisation happens rather than
whether the data is there.
TranscodingInfois the larger half: progress has to reach the session registry,keyed by device id, which is what upstream keys it by.
How to know it is done
With the pinned bundle: a file playing over HLS shows the play method rather
than
(null), and a Transcoding Info section whose completion percentagemoves; a direct play shows
(Direct playing)and no such section. A test thatasks for a session mid-playback and fails today.
House rules
CLAUDE.mdis the short version and these are the parts that bite: tests rununder
cargo nextest; upstream's source is the checkout inupstream/at thepin; generated files are regenerated rather than edited; a comment says what
the code does, not how it got there.
A test that cannot fail is worse than none.
Landed in
1d565f8, with review fixes in9f43537.NowPlayingItem. The registry held the id all along; the materialisinghappens in the route, which has the repository — one query for every session
rather than one per session. Described on nobody's behalf, which is what
upstream's
GetItemInfodoes: a session is read by whoever may see it, anddescribing the item as its own user would put their watched state on somebody
else's screen.
The review caught the field set. Upstream strips eighteen fields from a
session's copy (
SessionManager.GetItemInfo) —MediaSources,MediaStreams,People,Tags,ItemCountsand the rest — and we were sending all of them onevery
/Sessionspoll and every socket broadcast. The media sources among themcarry the path on disk, on a route anyone with
EnableRemoteControlOfOtherUserscan reach.
TranscodingInfo. Keyed by device, which is what upstream keys it by. Whatthe job was asked to produce is recorded when it starts — the codecs, the
container, the dimensions, the channels, the two direct flags and the reasons,
all settled before ffmpeg runs. The rate, the bitrate and the completion
percentage come off the progress
ephyra-ffmpegalready parses, whose onlyreader was the supervisor that kills a stalled job.
The review caught the device lookup. It used
rfindover aBTreeMapkeyed byjob id, and a job id is a counter rendered decimally — so
"9"sorts after"10", and a device that had seeked mid-playback would report the abandonedencode's container and codecs and ask the transcoder for its progress. It orders
by when a job was last heard from now, with a test over the 9→10 boundary.
A direct play shows no transcoding section, as upstream's does.