Search code examples
libvlcfsmlibvlcsharp

VLC libvlc_state_t State Machine?


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.

Update

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.


Solution

  • 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.

    State Machine

    A few notes:

    • Things did not seem to always work properly if you tried to e.g. seek while the media was 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.
    • The Buffering state was not seen to be in use, but the Buffering event would fire at least the Opening and Playing states.
    • As others have noted, you can't simply call 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().
    • I'm still not sure the exact behavior around 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!