Issue
Playback error and end events do not identify their cause or media generation. An unattributed stop can be synthesized as natural end, and no terminal payload preserves the final timeline before the observable mirror is reset.
Evidence
PlayerEvent.swift:20-24 exposes payload-free .encounteredError.
PlaybackEndCoordinator.swift:3-17 and :70-82 can synthesize .endReached from an unattributed stop.
Player.swift:784-790 documents a stop/end race that can affect the next session.
EventBridge.swift:174-224 queues .stopped before synthesized .endReached onto independent internal and public streams.
Player+Events.swift:47-59 processes the internal stream on its own task, and :75-86 clears time, position, and buffer fill while handling .stopped. A public consumer can race ahead or behind that reset, so reading Player properties on .endReached cannot recover a reliable final snapshot.
- VLC commit
5e85463c0f7 adds native error/EOS/user-stop reasons after the bundled pin.
Expected
Emit exactly one structured terminal outcome per media generation: natural end, requested stop, replacement, cancellation, source/demux error, decoder error, renderer error, output error, or unknown native stop. Capture final time, duration, position, and relevant render counters before clearing the session.
Acceptance criteria
- Clean EOF, explicit stop, replacement, server close, malformed input, decode failure, renderer failure, and network loss are distinguishable.
- Every subscriber receives the same payload-bearing pre-reset final timeline, independent of task scheduling.
- A terminal event from generation A cannot end or classify generation B.
- An unattributed stop is never reported as a confirmed natural end.
Issue
Playback error and end events do not identify their cause or media generation. An unattributed stop can be synthesized as natural end, and no terminal payload preserves the final timeline before the observable mirror is reset.
Evidence
PlayerEvent.swift:20-24exposes payload-free.encounteredError.PlaybackEndCoordinator.swift:3-17and:70-82can synthesize.endReachedfrom an unattributed stop.Player.swift:784-790documents a stop/end race that can affect the next session.EventBridge.swift:174-224queues.stoppedbefore synthesized.endReachedonto independent internal and public streams.Player+Events.swift:47-59processes the internal stream on its own task, and:75-86clears time, position, and buffer fill while handling.stopped. A public consumer can race ahead or behind that reset, so readingPlayerproperties on.endReachedcannot recover a reliable final snapshot.5e85463c0f7adds native error/EOS/user-stop reasons after the bundled pin.Expected
Emit exactly one structured terminal outcome per media generation: natural end, requested stop, replacement, cancellation, source/demux error, decoder error, renderer error, output error, or unknown native stop. Capture final time, duration, position, and relevant render counters before clearing the session.
Acceptance criteria