Does anyone know if the VLC project has a defined state machine for the libvlc_state_t
states? The state machine states are exposed via libvlc and then again via bindings into other languages (for example, LibVLCSharp). The enum is documented here, but I can't find a description of transitions or other details.
I'd like to see this get rolled into VLC docs at some point. While the state machine might seem obvious, I am encountering small oddities like the Buffering event getting called but the Media not seeming to pass through the Buffering state - it's still in the Playing state.
These little things add up and it would probably help improve developer experience to get them added. What I'm looking for as a solution is a typical state machine that includes at a minimum the states, the transitions, and notes about which events are actually fired on which transitions (and if they happen before or after the state actually changes). Anything around threading concerns (e.g. sync vs. async transitions) and allowable actions while in a given state are a bonus.
I did some work to capture the observed behavior. This is incomplete and imperfect, but perhaps it may help others as they build on top of libvlc/LibVLCSharp (I was on v3.5.1, VideoLAN.LibVLC.Windows v3.0.14). The dashed arrows pointing to the right are to show when certain events fire. Note that some of these behaviors are potentially specific to the type of media or the fact that reading is occurring through the MediaInput
interface, so your mileage may vary.
A few notes:
Opening
. For example, I saw .Time
and .Position
fall permanently out of sync. I strongly recommend waiting until after a Play()
operation before doing much.Buffering
state was not seen to be in use, but the Buffering
event would fire at least the Opening
and Playing
states.Play()
once the media ends. You need to Stop()
after EndReached
fires, and - as with many of the callbacks - you need to make sure you handle this in a non-deadlocking way. It can and will silently deadlock. Even using Dispatcher
may choose to run on the same thread, so you have to guarantee a separate thread. So far I've had good luck with e.g. ThreadPool.QueueUserWorkItem(_ => yourMediaPlayer.Stop());
You can then hook Stopped
to trigger further behavior like Play()
.ErrorEncountered
and recovery to Play()
again; it wasn't easy to trigger this behavior.Ultimately this state machine allowed me to build one on top of it to handle behaviors like "make the file playable again when the end is reached".
Thanks @mfkl and many others for the hard work - with a bit of digging this has been a great library to build on!