EARLY DOCUMENT, NOT EXACTLY AS IMPLEMENTED
------------------------------------------

EVENTS RFC
==========


Scope
-----
This document tries to describe a possible implementation of an event
system for GStreamer that is able to handle all known problems and works
better than the current (0.3.1) system which evolved over time.


Definition 
----------

The event system is designed to be a mechanism for communication between 
elements. They are used to get information to the right point when this
point cannot be known in advance.
Events can be generated by either an element or the application and are
processed by elements.


Event Handling
--------------

Events may be inserted into a pipeline in the PAUSED or PLAYING state. Some
events may travel during the PAUSED state, others may only travel when PLAYING.
The insertion of events during the NULL or READY state should be supported if
at all possible. Events may not be processed in those states though.
After an event is inserted into the pipeline, no assumption may be made on how
the event will be processed. It is eg wrong to assume that an event that is 
inserted at the beginning of the pipeline may come out at the end.
There are 3 different directions an event can be processed.

* downstream events

  Downstream events are inserted on source pads and travel along the pipeline.
  They are handled like buffers and processed in order. If event x is inserted
  into a pipeline after buffer y, they are guaranteed to travel in that order.
  Downstream events therefore only travel when the pipeline is PLAYING.
  Downstream events must be handled by the routines that handle buffers, too.
  An example downstream event is the event signalling that the stream has ended.
  Please keep in mind that downstream events take the same way as buffers. So a
  ghost pad will never receive these events.

* upstream events
  
  Upstream events are inserted on sink pads and travel backwards through the 
  pipeline. They travel as fast as possible. Source pads must have a handler
  function in place to process events. A default handler is implemented.
  An example upstream event is an event that seeks inside the stream.
  Please keep in mind that upstream events take the same way as buffers in reverse
  direction. This means that ghost pads will never receive them.

* vertical events
  
  Vertical events travel from elements to their parents. They are targetted at
  the application. Vertical events should be used for information that an 
  application cannot receive in an easy way by using callbacks or properties.
  Vertical events are send to the application by the pipeline that collects those
  events and supplies a callback for the application. Vertical events are also only
  happening when the pipeline is in PAUSED or PLAZING state.
  An example vertical event is the error event informing the application about
  unexpected behaviour.


The GstEvent object
-------------------

struct _GstEvent {
  GstData data;

  GstEventType  type;
  guint64	timestamp;
  GstObject	*src;

  union {
    ...
  } event_data;
};

data:       The parent object.
type:       The type of the event. GStreamer aims to keep the number of different
            plugin types as small as possible.
timestamp:  The time when the event was created. This property is used to identify
            duplicated events. If the application inserts an event, the timestamp 
            is set by the element receiving the event from the application.
src:        The element that created the event. If an application inserts an event,
            the element that received the event from the application sets itself as
            the source.
event_data: data specific to the event type.


The different event types
-------------------------

The following names in brackets correspong to the event's type property.

GST_EVENT_DISCONTINUOUS
direction(s): downstream
event_data: struct {
              GstDiscontType type;
            } discontinuous;
This event is used to indicate that the current stream does not continue. Possible 
indications are a new stream (type = GST_DISCONT_NEW), the happening of a seek 
(type = GST_DISCONT_SEEK) or the end of the stream when no more data is available.
(type = GST_DISCONT_EOS)

GST_EVENT_SEEK
direction(s): upstream
event_data: struct {
              GstSeekType type;
              gint64 offset;
              gboolean flush;
            } seek;
This event is used if a seek is needed. Uses include applications or the avi demuxer
element requesting the end of the stream first. The seek can happen absolute (SET),
relative to the current position (CUR) or relative to the end (END). It is possible
to seek by frames (FRAME), time in microseconds (TIME) or bytes (BYTE). This is
indicated by the type field, which takes the values 
GST_SEEK_FRAME/TIME/BYTEOFFSET_SET/CUR/END. The offset field indicates how many units 
should be seeked. Negative values indicate seeking backwards from the indicated position.
The flush field indicates if buffered data shuold be flushed or discarded.

GST_EVENT_FLUSH
direction(s): upstream
event_data: none
This event indicates that all buffered data should be flushed out immediately.

GST_EVENT_INFO
direction(s): downstream, vertical
event_data: struct {
              GstProps *props;
            } info;
The Info event is used to transport meta information like bitrate, author, title, 
interpret or stream length. Most info events will be emitted vertical and downstream
at the same time. Vertical emission ensures that an application knows about those
properties and downstream emission ensures that elements can compute own information
from these infos. (eg converting stream length in bytes to song length in 
microseconds).
Props consist of key / value pairs, where the key is a string identifier and the value
is a GstPropEntry. Many key strings are predefined to allow consistency between elements.
Elements should try to suppy any information they can as soon as possible.

GST_EVENT_HAS_INFO
direction(s): upstream
void (*GstHasInfoCallback) (gchar *name, GstPropsEntry *info, gpointer data);
event_data: struct {
              GList *info;
	      GstHasInfoCallback callback;
	      gpointer data;
            } has_info;
The has_info event might be inserted by an application to find out if a pipeline can supply
the specified infos. the info list contains all information that the application is 
interested in. If an element can supply information it calls the supplied callback with the
name of the information it can supply, the information if it is already available or NULL and
the data. If this event is destroyed, it will call the callback with name = NULL to indicate
that no more data will be received.
This event will for example be used by playlists when they generate information.

GST_EVENT_ERROR
direction(s): vertical
event_data: struct {
              gchar *message
            } error;
An error event is emitted, whenever a recoverable error occurs that the application
should know about. The usage should be similar to GLibs GError. An example would be
"connection closed" for a host to host plugin.


Reference Counting
------------------

References to events are handled similar to buffers. An element receives an event with
a single reference. If it forwards the event, this reference is lost.
Events own a reference to the element that created them. They take care of all of all
data inside them too (strings, props). So elements and applications that want to keep
this informations need to copy or add a reference them.


Changing Events
---------------
It is not allowed to change any data inside an event. Changing events can only be 
accomplished by removing the reference to them and not forwarding the event and then
creating a new one.


Default Behaviour
-----------------

* downstream events

  These are not handled by default, because they must be handled by the chain handler
  of the sink pad. There is however a function called gst_pad_event_default(GstPad *, 
  GstData *) that will take care of events if your code doesn't want to handle them.
  But your code must be aware that not everything that your chain function receives
  is a buffer. It could be an event.
  
* upstream events

  Upstream events are handled by a default handler function that is inserted on sink
  pads when they are created. This function simply forwards the event to all connected
  sink pads of the element. You are free to change this handler.
  
* vertical events

  Vertical events can not be received by elements. Bins have a default handler function
  that simply forwards the event to their parent. Pipelines offer callbacks for events.
  You may change this handler for your custom bins.
  
  
Use Cases
---------

Following are some simple use cases describing how events are generated. The pipeline
decriptions use gst-launch syntax. "..." indicates that something follows there but is 
not important for the example.

* filesrc ! fakesink
 
  - When starting the pipeline, filesrc will emit a DISCONTINUOUS event of type NEW 
    indicating a new stream.
  - Following that event will be an INFO event containing the length of the file/stream
    in bytes.
  - After the file was played, the filesrc emits a "DISCONTINUOUS" of type EOS.

* filesrc ! mad ! ...

  - When starting, filesrc emits a DISCONTINUOUS event followed by an INFO event (see above).
    The mad plugin remembers the length of the file and removes the INFO element as it
    is no longer of use. The DISCONTINUOUS event has passed mad after making sure, that all
    buffers are cleared.
  - Mad will emit a SEEK event to BYTEOFFSET_END; offset = -sizeof(ID3_info) to read out the ID3 
    information.
  - Filesrc emits a DISCONTINUOUS event of type SEEK to indicate that it seeked to the end.
    This event will not be passed on by mad.
  - after receiving the ID 3 information, mad will issue an INFO event containing all data
    it extracted. This event will probably only be passed vertical as ID3 information is of
    no use to other elements.
  - mad then ISSUES a SEEK event of type BYTEOFFSET_SET; offset = 0 to make the filesrc start
    playing the file.
  - The filesrc will reset its offset and issue a DISCONTINUOUS event of type SEEK. This event
    will not be forwarded by mad.
  - When playing starts, mad is able to compute bitrate and other information including playing
    time with the help of the previous length information supplied by the filesrc. It will then
    issue another INFO event with that informations. This one will be send downstream and vertical.
    
* ... ! avimux ! filesink

  This example is showing a more exotic way of using events. The reader should be aware that AVI
  files have a limited filesize. Only 4 GB are allowed. We now show what happens when the avimux
  encoder hits that limit.
  - When the internal counter of avimux shows that it is approaching the filesize limit, the 
    avimux element pushes a buffer containig the footer to the filesink.
  - After that it issues a DISCONTINUOUS event of the type DISCONT_NEW indicating a new stream.
    The filesink will close the file and reopen a new one.
  - The avimux plugin resets its internal size counter and restarts sending data to the new file.

* filesrc ! gunzip ! mikmod ! osssink

  (please note that this example is purely theoretical. It should just show ideas)
  During playback, an application is interested in "interpret", "title", "length_time",
  "length_size" and "URI" of the current stream. 
  - The application creates a HAS_INFO event and inserts it at the end of the pipeline into the
    osssink.
  - The osssink cannot supply any info so it forwards the event to the mikmod element.
  - The mikmod element can supply "title" and "length_time". It calls the supplied callback twice
    and gives these two options. It forwards the event to the gunzip element.
  - The gunzip element has already decoded the whole data so it knows the size of the stream. It
    calls the callback for "length_size" and forwards the event.
  - The filesrc supplies the "URI" and the "length_size" for a second time. It is now up to the
    application's callback function to handle this second occurence of "length_size" information.
    The filesrc does not forward the event and dereferences it.
  - During disposal of the event, the callback function is called again with name=NULL. The
    application now knows that no "title" can be supplied.  
  
  
Open Questions
--------------

Open questions are issues that should probably be solved by events but can not be solved
currently.

* A filesink needs to be able to inform elements of a restricted file size. Simply closing
  the file and opening a new one might not work because elements might need to supply a 
  footer. (eg avimux)



Issues / changes (to be deleted in final version)
----------------

? Are the event directions distinct? Or is it possible that some type of event
  can travel eg upstream _and_ vertical?
? How are upstream/vertical events supposed to be handled if they occur when 
  the element is READY or NULL? Buffer the event? How many events should be 
  buffered? Maybe a READY element is attached to a PLAYING/PAUSED one and
  constantly receiving events, no?
! The EOS event was merged with the DISCONTINUOUS event.
? Does the DISCONTINUOUS event need a "flush" option?
? Should chain funcs be changed to expect GstData instead of GstBuffer?
  It's a little bit misleading if events can arrive there.
! added information about timestamp.
? Should timestamps of "follow up" events (eg conversion of seek) keep the 
  timestamp?
? src = NULL, when app inserts event?
? How do elements handle events they cannot use? (eg filesrc getting timebased 
  seek request)
? Somebody fix the GST_EVENT_FLUSH part.
? GValue or GstProps for INFO events? First requires to open up the props headers
  and writing some API to ease the retrieval of the elements, the second requires
  a rewrite of GST_EVENT_INFO.
? GQuark/GValue possible in INFO events?
! Merged INFO and PROPS event. They are nearly the same. Added documentation.
? Need to work out the ERROR event.
! changed prototype for gst_pad_event_default to accept buffers so the function checks
  if it is an event and not every chain handler has to.
! added HAS_INFO event. An alternative to the callback function could be another vertical
  event.
? Should HAS_INFO callback supply the element calling the function?
? Use case one: start with discont event?
? Do we need a state change event?
? Should we make elements supply information as soon as possible or only upon HAS_INFO 
  request?
? should the second example be done with region requesting instead of events?
? "location" or "URI"?
? What about suggesting buffer sizes?
? What about QoS?
