Does it really work like that
I don't know how it works internally. OBJ_STATE_* are internal so I don't think there is a problem. From the outside, a seeking in IMFSession only transitions from STOPPED/PAUSED/STARTED to STARTED. I added SEEKING state only because it's needed for state changes. Otherwise, for example, the sink state would be started -> started and considered as no changes and don't proceed in session_set_sink_stream_state() and call session_set_started() to set the session state as started.
For example what happens if playback is running, you set new position, but source never produces MESourceStopped event? Is that ignored?
It's not waiting for MESourceStopped event at all. It waits for MESourceStarted. So basically the transitions that happen are like the initial start, just with a different source position.
Another thing, calling source->Stop() does not stop the clock, so how does that work?
Do I need to stop the clock? When handling the case SESSION_STATE_STARTING_SOURCES and sources are started, session_start_clock() is called to move the clock to a new position.
Regarding output nodes, if the clock is never stopped, do they really ever transition from SEEKING to STARTED?
No. SEEKING is only a state that I added internally for session. There is no real seeking state for output nodes. I guess it's possible to add a SEEKING state for session instead of source/sink nodes. And then, for example, when the output node state is not changed but session is in SEEKING, session_set_sink_stream_state() still proceeds and calls session_set_started().