Event Handler ~~~~~~~~~~~~~ concern: event.[ch] event_handler.[ch] supervisor.h The event handler manages all events sent with event_send() "event.c". This handler is not dependant of a supervisor. At the initialization, some variables needed for a synchronization can be ignored. And in this case, the handler is concurrent accordingly to the internal library _and_ the public API. To have asynchroneous public events but _not concurrent_, it is necessary to use a supervisor. The function player_event_send() can call a special function provided by the supervisor. This function is recatch() and releases the supervisor in favor of the event handler. So, when the event handler calls it own release() function, the supervisor can catch() the synchronization to continue the job previously interrupted by the event. This functionality can be compared as a preemption (1) by the event handler on the supervisor. You can only use this, if the variables for synchronization are used at the init (player_init() "player.c"). With MPlayer wrapper, the event handler is really interresting because it will not block the parser. Before, when an event was sent, the MPlayer parser was blocked in the public callback, then it was impossible to the parser to finish correctly the job at the right time. Supervisor ~~~~~~~~~~ concern: supervisor.[ch] player_internal.c mrl_internal.c The main goal of the supervisor is the serialization of all actions sent from the public API. The supervisor executes only a job even if the public API is used in concurrency. When a job is finished, the next is pop'ed from a queue. But if the synchronization variables are used, then the supervisor will released in favor of the event handler. Then each turn, the supervisor and the event handler is working (this is right only if the supervisor is not preempted (1) by the event_send() function, for example when an event is sent with the MPlayer parser or from xine, VLC or GStreamer callbacks). Two modes exists to send a control to the supervisor. First is WAIT_FOR_END, then the function will return only when the internal function is finished. This mode is mandatory with all functions that use an input and (or) an output variable(s). The second mode is NO_WAIT, then the function will return when this job is pushed in the queue. This is really useful when a control is sent from the internal callback, because the event handler is not blocked when the supervisor is executing the job. Warning: it is prohibited to use public API from the internal stuff because that will create deadlocks on the supervisor, always use player_internal and mrl_internal functions. Never send events from the public API, that will break the MT-Safe (2) state of the function. Only _one_ supervisor_send() must exist in every public function! Comments ~~~~~~~~ An other way (simpler) exists to send events without to use the recatch() functionality. The first idea was used the SCHED_RR with the supervisor and event_handler threads. In this case, priorities can be set and the events can be sent to the supervisor instead of sent directly to the public callback. But that is possible only with root privileges! (1) preemption (preempted) is not used here as a reference to the Real-Time, but only like a naive comparison. (2) not all public functions are MT-Safe; player_uninit() must be used only as the last function called for a specific player_t controller.