Ginga  0.13.6.2086-83aa
The iTV middleware.
Architecture and Internal API

Architecture

The external API of libginga consists of the abstract class Ginga. Internally, the functionality exposed by the Ginga class is implemented by the class Formatter. Along with Formatter, the other main components of libginga's internal API are the classes Parser and Document. The diagram below depicts the flow of information between the external world and the three main classes of libginga's internal API.

dia-architecture.png

The Formatter controls the life-cycle of the presentation. When it receives a start (Ginga::start), it creates and uses a Parser to obtain a Document from the given NCL file. After the Document is obtained, the Parser is no longer needed and it is destroyed by the Formatter. (The Parser exists only during this brief moment; that is why it is drawn with dashed lines in the above diagram).

The Document contains the NCL object tree derived from the NCL file. This tree holds the state of the current NCL presentation. Before returning from the start call, the Formatter bootstraps the presentation by starting the root (Context) of the object tree. This action propagates through the object tree possibly triggering further actions and changing the state of the Document as a whole. We call the process of evaluating an action over the Document a reaction. In libginga, reactions are non-blocking and always terminate.

After the start call returns, the Formatter is driven by the caller, that is, the program using the external API.

  • When the Formatter receives a key (Ginga::sendKey) it delivers it to all objects in the Document.
  • When the Formatter receives a tick (Ginga::sendTick) it advances the time of all objects in the Document. This is the only place in which time advances, and it does so in lockstep: two objects that have been started in the same tick will always be synchronized.
  • When the Formatter receives a redraw request (Ginga::redraw) it renders and draws the frame corresponding to the current Document state in the given Cairo context.
  • When the Formatter receives a state request (Ginga::getState) it checks if the Document is still running and send this information back to the caller.
  • Finally, when the formatter receives a stop request (Ginga::stop) it stops the presentation and destroys the Document.
Todo:
Errors in the input NCL file may lead to feedback loops in action propagation and, consequently, to endless reactions. If this happens and if the program has only one thread, which is usually the case, the program will enter an infinite loop.
Todo:
Libginga handles audio output internally by itself. One cannot use the external API to get the audio samples corresponding to the current Document state.

Internal API

Document and Objects

The Document contains the object tree of the NCL presentation and act as a high-level interface to this tree. It has methods to query the tree contents and to evaluate NCL actions over it, but not to change the tree contents or its structure.

The next diagram depicts the class hierarchy of the objects that can occur in the Document's object tree.

dia-objects.png

The classes Object and Composition are abstract. The concrete classes Media, MediaSettings, Context, and Switch stand for the corresponding elements in the NCL language:

  • A Media represents a <media> element in the NCL document.
  • A MediaSettings represents the settings <media> element. There is exactly one settings object per Document. (Although the document may contain multiple settings <media> elements, all of them represent the same object.)
  • Context represents a <context> element.
  • Switch represents a <switch> element.

Every Object has an id which must be unique within the Document. Objects can also have aliases which are collected and installed by the Parser. The id of the root object is always "__root__" and the id of the settings object is always "__settings__".

Events

Every Object has a set of events, class Event, each representing an event state machine of NCL. Events are not first-class citizens. They exist within exactly one Object and are owned by it.

There are three types of events (Event::Type):

  1. Event::PRESENTATION: Represents the presentation of a particular time interval of its object. Every object has at least one presentation event, called lambda, which represents the presentation of the object itself. Besides the lambda presentation event, which is created by default for every object, the Parser creates a presentation event every time it encounters an <area> element. The container Object in this case is the object corresponding to the parent <media> element.
  2. Event::ATTRIBUTION: Represents the attribution of some value to a particular property of its object. The Parser creates an attribution event every time it encounters a <property> element. The container Object in this case is the object corresponding to the parent <media> or <property> elements.
  3. Event::SELECTION: Represents the selection of the container object via a particular key. The Parser creates a selection event every time it encounters a link <bind> with role "onSelection" or "onKeySelection". The container Object in this case is the object referenced by the <bind> element.

Independently of its type, every Event maintains a state machine with three states, namely, Event::OCCURRING, Event::PAUSED, and Event::SLEEPING (the initial state), and labeled transitions between these states. The possible state transitions and their labels (Event::Transition) are listed in the table below.

From To Transition (label)
Event::SLEEPING Event::OCCURRING Event::START
Event::OCCURRING Event::SLEEPING Event::STOP or Event::ABORT
Event::PAUSED Event::OCCURRING Event::START or Event::RESUME
Event::OCCURRING Event::PAUSED Event::PAUSE
Event::PAUSED Event::SLEEPING Event::STOP or Event::ABORT

The method Event::transition transitions an Event. When transitioning, the Event notify its container Object, via Object::beforeTransition and Object::afterTransition, which can act accordingly. For instance, the start transition of the lambda event of a Context should cause the Context to schedule the start of events referenced by its ports in the next tick.

Although a call to Event::transition may lead to further implicit transitions, Event::transition calls by themselves do not do not trigger links. What trigger links in libginga are actions. Actions and links are discussed in the next section. But before that there is one last thing we have to say about events: how libginga references them in logs.

Every Event has an id which must be unique within its Object. Libginga adopts a specific format when creating an pretty-printing event ids. This format is detailed in the table below.

ID Pretty-Printing Format Type Description
obj@area Event::PRESENTATION obj is the id of the container Object and area is the id of the corresponding <area> element. If this event has no corresponding <area> element, then evt is the lambda event and its id is the string "lambda".
obj.name Event::ATTRIBUTION obj is the id of the container object and name is the name of the corresponding <property> element.
obj<key> Event::SELECTION obj is the id of the container object and key is the name of the key expected by the corresponding <bind> element.

Actions and Links

An Action is a structure that associates an Event to a desired Event::Transition. One evaluates an Action over a Document using Document::evalAction. This method applies the desired transition over the event and, if the transition is successfully executed, triggers any links that are waiting for it, initiating a chain reaction.

In libginga, links is are stored in a list in the Context object (member Context::_links). Each link is a pair. The first member of the pair, called the link head, is the list of actions whose execution should cause the link to trigger. The second member of the pair, called the link tail, is the sequence of actions that should be evaluated over the document when the link is triggered.

Players

Each Media maintains a single Player. This Player is created when the Media's lambda event is started, and it is destroyed as soon as the Media's lambda event is stopped.

dia-players.png