Developers Guide

From LinuxMCE
Jump to: navigation, search


LinuxMCE developer’s guide Document version 1.0


1. Architecture

LinuxMCE uses a modular architecture made of "devices" that are integrated to the system by interfacing them to the DCERouter.

DCERouter

The heart of LinuxMCE, the 'main application' DCERouter is nothing but a general-purpose message router. It has absolutely no code relating to any of LinuxMCE's functionality--it just relays messages between "Devices".

LinuxMCE architecture – the devices

Devices

The functionality of LinuxMCE is entirely in separate programs (aka "Devices") which all run independently and communicate with each other by passing messages through DCERouter over sockets. There can be hundreds of these "Devices" in a smart home, that do all sorts of things. As shown in the diagram below, many of LinuxMCE's devices are actually "wrappers" we have written for existing open source programs to allow them to work together seamlessly in a LinuxMCE system. An example of this is the wrapper written for Asterisk: it sends event messages to the DCERouter whenever a phone call comes in, and, receives command messages when it is time to place a call.
How the wrapper communicates with the open source program depends on that project. In the case of Asterisk, the wrapper communicates with Asterisk over a socket. It acts as a translator, converting messages from its socket connection with the DCERouter into messages from its socket connection with Asterisk. The wrapper for the Xine media player links in Xine's own library, and calls Xine functions directly, while for MythTV, the wrapper communicates via a special telnet interface. Each project's wrapper is written to meet its needs.

LinuxMCE uses the GPL home automation engine and UI front-end developed by Pluto, the GPL PVR developed by the MythTV folks, the GPL phone system Asterisk originally developed by Mark Spencer at Digium, the GPL Xine program, etc, and combines them into a whole using the DCERouter. Since these OSS projects all have disparate histories and development roadmaps, the wrappers need to be kept up to date as these applications develop, and we're hoping to get some of these applications to talk directly to the DCERouter in the future

Note
Some devices are not implemented as separate binaries, but as plug-ins that run as dynamic libraries in DCERouter’s memory space.



The GSD protocol

Since there are literally thousands of home automation components and pieces of A/V equipment that require controlling with serial port, USB, or Ethernet, LinuxMCE has been designed with GSD support to enable communication with these various technologies. GSD is a fast protocol which is simple to use, yet flexible enough to be used to support lighting control systems, climate and pool systems, cameras, or external devices such as IR blasters, and much more.




2. DCE

DCE (Data, Commands and Events) is a lightweight network protocol allowing any device to access its configuration (ie data) from a central database, send + receive commands, and fire + respond to events.

The DCE protocol can be implemented with any device that supports standard networking. LinuxMCE provides a DCE library written in Ansi C++ that implements the protocol on any socket-compatible operating system, and has been tested on Linux and Windows. Porting to other languages should not be a big task. Because the messaging is socket-based, any device, regardless of operating system or language, can be used with any other device.

In each installation there is also one DCE Router, through which all messages are routed. An "installation" is a group of devices treated as a unit, and normally corresponds to a physical residence.

The DCE Router is itself quite simple. It just opens a port for incoming connections. When a device connects, the device sends its unique ID, or Mac Address. The DCE Router does a lookup in a database, and returns that device's data (configuration). DCERouter also sends back a list of all the other devices in the installation with basic information including the commands they know how to implement. The DCE Device then opens a minimum of 2 socket connections to the router. One is for incoming messages (usually commands) from the router, another for outgoing messages (usually events) to it. The DCE Library, which implements the protocol for DCE Devices and the DCE Router, will also open a 3rd socket connection so that it has 2 outgoing sockets: 1 dedicated for sending events and the other for sending other types of messages, like requests and commands to other devices.

All messages go through the router. The devices do not communicate directly to each other. The message will contain information such as the destination device, the type of message, the message id and any number of optional parameters. The router does nothing with the message but forward it to the destination device or devices if the message is being sent to more than one. The DCE library, from which DCE Devices and the DCE Router are derived, knows how to receive incoming messages of the type command and route them to a message handler in the DCE Device.

Another important library is PlutoUtils. It has cross-platform wrapper classes to handle file, strings, processes, threads synchronization, database utils, etc.

Developing a DCE Device

A new tutorial for Developing a DCE Device is available. This focuses on developing a device using C++ and the DCE and PlutoUtils libraries.. A new GSD tutorial for Ruby is forthcoming.

3. DCERouter

When a DCE Device connects, DCERouter gives it its configuration data and is responsible for receiving and forwarding any messages to and from the devices that connect to it. The most common types of messages are commands and events. All communication goes through DCE Router. If a doorbell device fires an event that the button was pushed, that event goes to DCERouter, which will forward it whatever plug-in has indicated it wants to handle that type of event. If the plug-in then wants to send a command to the media player, this command goes first to the DCE Router, which will then forward it to the media player. The DCE Devices never communicate with each other directly--everything goes through DCE Router. Devices can create their own types of messages specific to them--not just commands and events. For example, a DVD player may send a message that contains a screen capture, or a TV program may send a stream of messages with streaming video. To DCE Router it makes no difference. Messages just have sources and destinations, and DCE Router does not care what type of message it is.

DCERouter also allows you to Message Interceptors. This means a device or plug-in can say that it wants to pre-process all messages that meet a certain criteria. For example, a security plug-in may want to see all events relating to security. Plug-in’s are DCE Devices that run within the DCERouter's memory space. They are DCE Devices just like any other and they are created like any other DCE Device. The code is the same, it's just a compilation option whether the device is built as a normal DCE Device, which runs in its own memory space and communicates with DCERouter over a socket, or if it's a plug-in which gets loaded into DCERouter's memory space. Plug-in’s have the ability to get pointers to the in-memory instance of the other plug-ins so they can share memory and call each others methods.

See below a simplified class diagram for DCERouter: Simplified class diagram for the DCE router

4. The binary communication protocol

4.1 Introduction

A device can create a command connection and one or more event connections to the router.

  • The command connection is used as an incoming connection and device will use it to receive message from the router (commands).
  • An event connection is used by the device as an outgoing connection to notify the router about events or the deliver commands to other devices.

The DCERouter process is listening on 3450 port.


4.2. How to create an event connection

Here is how the handshake is made for an event connection:

>> Device sends: EVENT <my_device_id> '\n'

<< The router will respond with : OK <my_device_id> IP=<device_ip_address> '\n'

>> To send a message, the device will send : MESSAGE <size_of_binary_message> '\n'

and then: <serialized_binary_message>

4.3 How to serialize data

DCE uses SerializeClass to serialize/deserialize data. The sources can be found here : src/SerializeClass/Serialize.h/cpp. The deserialize the data, the deserializing module must know the way the data was serialized like this:

  • 4 bytes, unsigned long
  • 1 byte, unsigned char

Primitives:

  • 8 bytes, unsigned int64
  • 8 bytes, int64
  • 4 bytes, unsigned long
  • 4 bytes, unsigned short
  • 1 byte, unsigned char
  • 1 byte, char
  • 4 byte, long
  • 4 bytes, float
  • 8 bytes, double
  • 2 bytes, short

Complex types:

  1. string
    • STR_LENGTH bytes, the array with chars
    • 1 byte, '/0' (value 0x00)
  2. block of data
    • BLOCK_LENGTH bytes, the array with bytes
  3. vector of strings
    • VECT_LENGTH bytes, the number of strings from vector
    • string 0
    • string 1
    • ...
    • string VECT_LENGTH - 1

Other complex types serialized (see SerializeClass.cpp for details) :

  • map<int,string>
  • map<u_int64_t,string>
  • map<int,int>
  • map<string,string>
  • vector<int>
  • vector< pair<int,int> >
  • map<string, pair<int,int> >

SerializeClass also allowed you to serialize/deserialize custom objects. Examples:

  • PlutoColor
  • PlutoPoint
  • PlutoSize
  • PlutoRectangle
  • PlutoDataBlock

4.4 How to serialize a message

The class used by DCE is Message class from src/DCE/Message.h/cpp unit.

This is how the raw data looks like into a binary message:

  • long, value must be 1234 (magic number)
  • long, <device_from_id>
  • long, <device_to_id>
  • long, <device_group_to_id>
  • long, <message_id>
  • long, <message_priority>
  • long, <message_type>
  • long, <device_category_to>
  • long, <device_template_to>
  • unsigned char, <include_children>
  • long, <message_broadcast_level>
  • long, <message_retry>
  • unsigned char, <relative_to_sender>
  • long, <expected_response>
  • string, <device_list_to>
  • unsigned long, <number_of_string_parameters>
    • foreach <string_parameter>
      • long, <string_parameter_id>
      • string, <string_parameter_value>
    • end_foreach
  • unsigned long, <number_of_data_parameters>
    • foreach <data_parameter>
      • long, <data_parameter_id>
      • unsigned long, <data_parameter_length>
      • array of bytes, <data_parameter_value>
    • end_foreach
  • unsigned long, <number_of_extra_messages>
    • foreach <extra_message>
      • unsigned long, <serialized_extra_message_length>
      • array of bytes, <serialized_extra_message_value>
    • end_foreach
  • unsigned long, must be 6789

Enums:

  • enum eBroadcastLevel { BL_None=0, BL_DirectSiblings=1, BL_SameComputer=2, BL_SameRoom=3, BL_SameHouse=4, BL_AllHouses=5 };
  • enum eRetry { MR_None=0, MR_Retry=1, MR_Persist=2 };
  • enum eExpectedResponse { ER_None=0, ER_ReplyMessage, ER_ReplyString, ER_DeliveryConfirmation };
  • message types: enum { MESSAGETYPE_COMMAND=1, MESSAGETYPE_EVENT=2, MESSAGETYPE_DATAPARM_CHANGE=3, MESSAGETYPE_REPLY=4, MESSAGETYPE_DATAPARM_REQUEST=5, MESSAGETYPE_LOG=6, MESSAGETYPE_SYSCOMMAND=7, MESSAGETYPE_REGISTER_INTERCEPTOR=8, MESSAGETYPE_MESSAGE_INTERCEPTED=9, MESSAGETYPE_EXEC_COMMAND_GROUP=10, MESSAGETYPE_START_PING=11, MESSAGETYPE_STOP_PING=12, MESSAGETYPE_PURGE_INTERCEPTORS=13, MESSAGETYPE_PENDING_TASKS=14 };
  • message priority : enum { PRIORITY_LOW=0, PRIORITY_NORMAL=1, PRIORITY_HIGH=2, PRIORITY_URGENT=3 };

Important notes:

  • when sending to device template, set <device_template_to> to desired device template and also <device_to_id> to -2000 (DEVICEID_MASTERDEVICE)
  • when sending to device category, set <device_category_to> to desired device category and also <device_to_id> to -2001 (DEVICEID_CATEGORY)
  • when sending to a list with devices, set <device_list_to> to comma delimited list with devices and also <device_to_id> to -2002 (DEVICEID_LIST).

Example: Here is the pseudocode to send the "on" command to a light switch. We'll assume that the your device has #id 250 and the light switch has device #id 100

  • MyDevice.Connect(router_ip, 3450 /*port*/)
  • MyDevice.SendData("EVENT 250\n")
  • MyDevice.ReceiveData() //until you'll get a '\n' ; you should receive: "OK 250 IP=<device_ip_address> '\n';

next: creating a message let's say MyData is an array of bytes

  • SerializeLong(MyData, 1234) //magic number
  • SerializeLong(MyData, 250) //my id
  • SerializeLong(MyData, 100) //the light switch
  • SerializeLong(MyData, 0) //not used now
  • SerializeLong(MyData, 192) //message id of command 'on'
  • SerializeLong(MyData, 1) //normal priority
  • SerializeLong(MyData, 1) //message type : command
  • SerializeLong(MyData, 0) //not used now
  • SerializeLong(MyData, 0) //not used now
  • SerializeUnsignedChar(MyData, 0) //not including children
  • SerializeLong(MyData, 0) //broadcast level : none
  • SerializeLong(MyData, 0) //don't retry
  • SerializeUnsignedChar(MyData, 0) //relative to sender false
  • SerializeLong(MyData, 3) //delivery confirmation
  • SerializeString(MyData, "") //device list to empty
  • SerializeUnsignedLong(MyData, 2) //2 parameters
  • SerializeLong(MyData, 98) //parameter type #98
  • SerializeString(MyData, "") //empty value
  • SerializeLong(MyData, 97) //parameter type #97
  • SerializeString(MyData, "") //empty value
  • SerializeUnsignedLong(MyData, 0) //no binary parameters
  • SerializeUnsignedLong(MyData, 0) //no extra messages
  • SerializeUnsignedLong(6789) //magic number
  • MyDevice.SendData("MESSAGE " + MyData.length() + '\n')
  • MyDevice.SendData(MyData)
  • MyDevice.ReceiveData() //until you'll get a '\n' ; you should receive: "OK" or an error message
  • MyDevice.CloseConnection();

4.5 How to serialize data-grids

Complex objects:

  1. DataGridCellSerializableData
    • unsigned long, <sizeof(DataGridCellSerializableData)>
    • unsigned long, <graphic_length>
    • unsigned long, <message_length>
    • unsigned long, <text_length>
    • unsigned long, <value_length>
    • unsigned long, <image_path_length>
    • unsigned long, <number_of_attributes_length>
    • unsigned long, <attributes_length>
    • int, <alternate_color>
    • unsigned long, <graphic_format>
    • unsigned char, <selectable>
    • int, <style_detail>
    • int, <col_span>
    • int, <row_span>
    • unsigned char, <dont_fire_grid_event>
    Enums:
    • enum eGraphicFormat { GR_UNKNOWN=0, GR_JPG=1, GR_GIF=2, GR_TIF=3, GR_PNG=4, GR_MNG=5, GR_BMP=6, GR_OCG=7, GR_PFG=8 };
  2. DataGridCell
    • DataGridCellSerializableData, <datagrid_cell_serializable_data>
    • array of chars, <text>
    • array of chars, <value>
    • array of bytes, <graphic_data>
    • array of bytes, <message_data>
    • array of chars, <image_path>
      • foreach <cell_attribute>
        • array of chars ended with '\0' , <cell_attribute_name>
        • array of chars ended with '\0', <cell_attribute_value>
      • end_foreach
  3. DataGridTableSerializableData
    • int, <total_number_of_columns>
    • int, <total_number_of_rows>
    • unsigned char, <keep_row_header>
    • unsigned char, <keep_column_header>
    • int, <column_count>
    • int, <row_count>
    • int, <starting_column>
    • int, <starting_row>
    • int, <cell_count>
  4. DataGridTableCellIndex
    • unsigned int, <column_row_type>
    • unsigned int, <size>
  5. DataGridTable
    • unsigned long, <sizeof(DataGridTableSerializableData)>
    • array of DataGridTableCellIndex, <col * row * sizeof(DataGridTableCellIndex)>
    • array of DataGridCell, <col * row * serialized DataGridCell>

Additional step: lzo compression/decompression

Note: can be disabled if compiled with DISABLE_LZO_DATAGRID


5. The devices

Each device has associated an interface, which we call device template. A device template is a set of commands to be implemented, events which can be fired by the device and device data (persistent information for device). To create device templates and modify them, go to LinuxMCE Web Admin -> Advanced -> Configuration -> Device Templates. To generate the C++ code for the device implementing a device template interface, you must use DCEGen tool, specifying the database ip address and the device template number. Here is the simplified class diagram for one of the devices (App_Server):

Simplified class diagram for a DCE device

The classes App_Server_Event, App_Server_Command and App_Server_Data are generated using DCEGen tool. The base classes for them are implemented in DCE Library.

6. App_Server device

App_Server device is present by default on all LinuxMCE machines. It spawns/kills applications, handles volume of sound on that machine, restarts/halts the device.

  1. Implemented commands:
    • CMD_Spawn_Application - Spawns an application
    • CMD_Kill_Application - Kills an application
    • CMD_Application_Is_Running - Checks if the given application is running.
    • CMD_Halt_Device - Halts or reboots this device
    • CMD_Vol_Up - Increases the volume 1%
    • CMD_Vol_Down - Decreases the volume 1%
    • CMD_Set_Volume - Sets the volume to a specific level between 0-100
    • CMD_Mute - Toggles mute/unmute
  2. It doesn’t fire any events.
  3. It has the following device data:
    • Discrete Volume
    • Volume Level

7. Photo_Screen_Saver device

The photo screen saver (PSS) displays pictures when there is no video playing, even if you just happen to be listening to music. By default, the photos come from Flickr and are downloaded regularly to local drive.

PSS is a OpenGL application and it slides pictures and fades them between transitions.

1. Implemented commands

The list with pictures is taken by sending a command to Orbiter Plugin : CMD_Get_Screen_Saver_Files which has an output parameter Filename. The filenames are delimited by a ‘\n’ character.

The PSS animations are started/stopped using CMD_On/CMD_Off commands. To force PSS reload the list with pictures from Orbiter Plugin, CMD_Reload is used.

When PSS starts, it should check every 10 minutes if there are any pictures downloaded and ready to be displayed. If there are pictures to display it should display them on CMD_On command and refresh the list with pictures every 24 hours.

2. It doesn’t fire any events

3. Device data:

  • ZoomTime - Value in miliseconds that a zoom effect will take
  • FadeTime - value in miliseconds that a fade effect will take
  • Name - The window name to activate


8. Media Player device

Currently there are two Media Players in LinuxMCE, the primary Xine_Player and secondary MPlayer_Player. First one is based one the Xine engine (http://xinehq.de) and supports the following formats:

  • File formats (System layer / media types)supported:
    • direct DVD playback (of unlocked/unencrypted DVDs, see below)
    • Video CD
    • Audio CD
    • mpeg program streams (.mpg, .mpeg)
    • mpeg transport streams (.ts)
    • ogg (.ogg, .ogm)
    • avi (.avi)
    • asf (.asf, .wmv, .wma)
    • quicktime (.mov, .mp4)
    • mpeg-video (.mpv, .m2v)
    • mpeg-audio (.mp2, .mp3)
    • Sega Saturn FILM (.cpk)
    • Id Software RoQ (.roq)
    • wav (.wav)
    • Autodesk FLIC (.fli)
    • real (.rm, .ra, .ram)
    • raw dv (.dv)
    • network graphics format (.png, .mng)
    • Creative Voice (.voc)
    • Sun/NeXT SND/AU (.snd, .au)
    • Wing Commander III (.mve)
    • Westwood Studios files (.vqa, .aud)
    • Electronic Arts WVE (.wve)
    • AIFF (.aif, .aiff)
    • YUV4MPEG2 (.y4m)
    • SMJPEG (.mjpg)
    • raw AC3 (.ac3)
    • Dialogic VOX (.vox)
    • TechnoTrend PVA (.pva)
    • Playstation STR (.str)
    • Nullsoft Video (.nsv)
    • 4X Technologies (.4xm)


  • Video codecs supported:
    • mpeg 1/2
    • mpeg 4 (aka OpenDivX)
    • ms mpeg 4
    • divx 3/4/5
    • windows media video 7 & 8
    • motion jpeg
    • Cinepak
    • DV
    • ms video 1 (msvc)
    • ms rle
    • Sorenson SVQ1/SVQ3 (often used in Quicktime trailers)
    • creative yuv (cyuv)
    • roq video
    • QT RLE, SMC, RPZA
    • theora
    • via external binary/win32 codecs (not included in xine):
    • Indeo 3.1-5.0
    • Window Media Video 8,9
    • On2 VP3.1
    • I263
    • Real Media 2.0, 3.0, 4.0
  • currently unsupported/untested Formats:
    • 3ivx
    • h263 (aka Real Video 1.0)


  • Audio codecs
    • mpeg audio (layer 1,2,3)
    • a/52 (aka ac3, dolby digital)
    • aac (used in .mp4 files)
    • dts (via external decoder)
    • vorbis
    • pcm
    • adpcm (MS/IMA/DVI/Dialogic)
    • mu-law and A-law
    • roq dpcm
    • Real Media dnet audio
    • Real Media 28.8 audio
    • DivX audio (WMA)
    • GSM 6.10
    • FLAC
    • NSF (NES sound format)
    • Speex


The MPlayer_Player is used as the fallback player for the formats Xine doesn't support/supports not well and currently is used for playing HD-DVD/Bluray video files and disks.

A media player device plays all kind of media: audio and video, stored media or from cd/dvd/hd/bluray drivers, etc.

1. Implemented commands


  • Keyboard input:
    • CMD_EnterGo - Select the currently highlighted menu item
    • CMD_Move_Up, CMD_Move_Down, CMD_Move_Left, CMD_Move_Right - Move the highlighter


  • Media Player Commands
    • CMD_Pause - Pause the media
    • CMD_Play - Play the media
    • CMD_Skip_Back_ChannelTrack_Lower - Lower the channel, track, station, etc. by 1. Same as Jump to Pos in Playlist with value -1 for a smart media player
    • CMD_Skip_Fwd_ChannelTrack_Greater - Raise the channel, track, station, etc. by 1. Same as Jump to Pos in Playlist with value +1 for a smart media player
    • CMD_Stop - Stop the media


  • Menu Navigation
    • CMD_EnterGo - Select the currently highlighted menu item
    • CMD_Move_Up, CMD_Move_Down, CMD_Move_Left, CMD_Move_Right - Move the highlighter
    • CMD_Get_Video_Frame - Gets the current video frame from the media player.
    • CMD_Goto_Media_Menu - Goto to the current media Root Menu.
    • CMD_Navigate_Next - Nagivate to the next possible navigable area. (The actual outcome depends on the specifc device)
    • CMD_Navigate_Prev - Nagivate the previous possible navigable area. (The actual outcome depends on the specific device).
    • CMD_Simulate_Mouse_Click - Simlate a mouse click at a certain position on the screen


  • Smart DVD commands
    • CMD_Angle – Go to an angle
    • CMD_Audio_Track – Go to an audio track
    • Subtitle – Go to a subtitle


  • Smart Media Player
    • CMD_Change_Playback_Speed – Will make the playback to FF with a configurable amount of speed.
    • CMD_Guide - Show guide information. For a dvd this may be the menu, just like the menu command
    • CMD_Jump_Position_In_Playlist - Jump to a specific position in the playlist, or a track, or a chapter. Smart media players should also understand the skip fwd/skip back (which non-DCE media players use) to be the same thing as a jump +1 or -1
    • CMD_Jump_To_Position_In_Stream - Jump to a position in the stream, specified in seconds.
    • CMD_Menu - Show a menu associated with this media
    • CMD_Pause_Media - This will stop a media that is currently played. This method should be paired with the "Restart Media" and used when the playback will be stopped and restarted on the same display device.
    • CMD_Play_Media - This command will instruct a Media Player to play a media stream identified by a media descriptor created by the "Create Media" command.
    • CMD_Report_Playback_Position - This will report the playback position of the current stream.
    • CMD_Restart_Media - This will restart a media was paused with the above command
    • CMD_Set_Aspect_Ratio - Force aspect ratio
    • CMD_Set_Media_ID - Set Media ID - information about media stream
    • CMD_Set_Media_Position - Jump to a certain media position
    • CMD_SetZoom - Sets zoom level, relative, absolute or 'auto'
    • CMD_Simulate_Keypress - Send a key to the device's OSD, or simulate keypresses on the device's panel
    • CMD_Start_Streaming - Like play media, but it means the destination device is not the same as the source
    • CMD_Stop_Media - This will instruct the media player to stop the playback of a media started with the "Play Media" Command
    • CMD_Update_Object_Image - Display an image on the media player


2. It fires the following events

  • EVENT_Menu_Onscreen - A DVD Menu appeared on screen
  • EVENT_Playblack_Completed - Fired when the playback of a stream has completed.
  • EVENT_Playback_Info_Changed – Playback info changed
  • EVENT_Playback_Started – Media has start playing


3. Device data:

  • Name - The name of the window for this app
  • Hardware acceleration - driver used
  • Deinterlacing Mode - Movie deinterlacing filter status
  • Port – Time code notification every second
  • Zoom Level – default zoom level


NOTE: A deviation from design, the media player must bind on a port specified in the device data and report the time code every one second. Any device like an Orbiter could connect to that port and read the time code. Here is the format used for time code: Speed,CurrentTime,TotalTime,StreamID,Title,Chapter,MediaType,MediaID,Filename (comma delimited).

9. Orbiter

9.1 Introduction

The Orbiter is really a device just like any other. The main class, Orbiter, is a normal DCE command implementation. However, the Orbiter class was written so that it has no platform-specific functions, such as graphics and sound. It handles the basic logic, and calls pure virtual functions that derived classes must implement to handle the platform-specific commands. Most of the code and virtually all of the logic is contained in the base classes. Therefore, it is a fairly easy task to make a new version of Orbiter for a platform other than SDL, perhaps one that uses Windows SDK calls, or another image library.

Right now there are implementations of Orbiter using SDL. PocketFrog and OpenGL engines. Orbiter runs on different operation systems like Linux, Windows, Windows CE, Window Mobile, Symbian60. There also implementation for web orbiter (running into a browser) or for a Cisco hard phones (using XML services).

9.2 Architecture

Orbiter application architecture

The present diagram shows how the Orbiter application architecture looks like. Depending on the Graphic Engine and the platform, the only modules dependent on them are “Renderers – engine specific” and “Orbiter - platform specific”.

9.2.1. The renderers

There are two kinds of renders:

  • orbiter renderers
  • object renderers

The orbiter renderers (derived from OrbiterRenderer class) handle the graphic primitives, having pure virtual methods for operations like this:

  • RenderText
  • SolidRectangle
  • HollowRectangle
  • DrawLine
  • FloodFill
  • RenderGraphic
  • ReplaceColorInRectangle
  • etc.

and applications flow :

  • event loop
  • configure
  • destroy
  • on quit
  • on reload

However, OrbiterRenderer is not an interface. It also has implemented the logic needed for:

  • render screen action
  • show a progress bar
  • highlighting / un-highlighting objects
  • render shortcuts
  • show / hide popup’s
  • redraw objects
  • refresh screen
  • render object asynchronously
  • object on screen / off screen actions
  • background image loading
  • drawing an arrow

Here is the class diagram for derived OrbiterRenderer‘s:

OrbiterRenderer class diagram


Also, there are renderer classes of complex objects like button, data grid, edit box, etc. The base classes for them are : ObjectRenderer, DataGridRenderer. Each renderer is attached to an object like DesignObj_Orbiter, DesignObj_DataGrid.

Here is the class diagram for OpenGL implementation:

OpenGL implementation


The screens are actually trees of objects. The characteristics of the objects are set using the Designer application and stored in the database, then serialized by OrbiterGen and then deserialized by Orbiter. OrbiterGen scales and pre-renders the screens. Also, OrbiterGen embeds in the serialized data info about the actions to be executed when an object is loaded, activated, unloaded, etc.

9.2.2. Orbiter – platform specific

Orbiter also has to take care of the input events like mouse click, keyboard events, etc. For example, Orbiter_Win32 is derived from Orbiter class and takes care of enabling the auto-update mechanism. Platform specific are the external dialogs with progress bar and prompt user, or the way the composite or masks are used (see OrbiterRenderer_Linux, OrbiterLinux, OrbiterRenderer_SDL_Win32

The Linux version uses XRecord extension to intercept events. The Windows versions use PocketFrog engine’s event loop or SDL event loop.


9.2.3. Cache image manager

This module is mainly used by remote orbiters, non-OSD orbiters. Because these orbiters don’t have access to core’s file system, all the graphic files are obtained by network connection and it might be slow. So instead of requesting same image over and over, the image is cached on the local drivers. The collection of images cached are associated with a timestamp (the generation date for the screens). If the user decides to regenerate the screens, the timestamp is changed and the cache is purged and the images are requested, on demand, again from the server.

9.2.4. Self update module

The “Self update” module is also used for non-OSD orbiters. Once a new version of the Orbiter XP/CE is available, a new binary data is stored on core’s filesystem. When an non-OSD orbiter starts, compares the md5sum of the current binary with the one from the server. If it’s different, the UpdateBinary is spawned, Orbiter exits and UpdateBinary requests the new binary from server, it downloads it, replaces the old binary and restart Orbiter.

9.2.5. Simulator

The simulator is responsible for generating mouse and keyboard events used for stress testing. It also stores some configuration settings.

9.2.6. Graphic objects

They are all derived from PlutoGraphic class and store info about the filename, width, height, the block of data and its length, graphic format and graphic management. The operations required are related to loading graphics from a file or a block of data, clearing the data stored, initializations, etc. In the derived classes like PocketFrogGraphic, SDLGraphic, OpenGLGraphic, specific info are stored like the Surface for PocketFrong, SDL_Surface for SDL and the texture for OpenGL.

9.2.7. Orbiter logic module

Just like any other device, Orbiter is derived from a {Device_name}_Command class, the wrapper class generated by DCEGen to allow the device communicate with the router. However, Orbiter is also derived from OrbiterData and IRReceiverBase.

Orbiter logic – class diagram


OrbiterData helps Orbiter deserialize the data needed for its graphic objects, data serialized by OrbiterGen. IRReceiverBase is the base class for all IR receiver devices and it translates IR codes into actions, base on the current screen type and remote layout.

9.2.8. Mouse handlers

The goal of handlers is the interpret mouse movements and perform specific actions depending on current screen type. This is one of the main features add in UI2 version.

See below the class diagram:

Mouse handlers – class diagram


Note that the mouse handlers are not available for UI1 version of Orbiter.

MouseIterator and MouseGovernor limit the mouse movements the only one move per x ms to prevent extreme numbers of messages burdening the system. MouseBehaviour handles special mouse behavior, such as locking axis’s, ramping and acceleration.

9.2.9. HID interface

This module gets events from the Fiire remote. See below the class diagram:

HID interface – class diagram

This code has been augmented by the Generic HID Interface, below.


9.2.10. Generic HID Interface

The Generic HID Handler is implemented in http://svn.linuxmce.org/trac.cgi/browser/branches/LinuxMCE-0810/src/Orbiter/Linux/GenericHIDInterface.cpp and http://svn.linuxmce.org/trac.cgi/browser/branches/LinuxMCE-0810/src/Orbiter/Linux/GenericHIDInterface.h

And basically consists of:

  • UpdateEventFDs - a function which scans /dev/input looking for event* devices, opening them read-only, and setting descriptors in a vector, which...
  • ProcessGenericHIDEvents - is passed back into here, and the vector is iterated, filling the parameters of a select() call to determine which event devices need to be read. Those devices are checked, and passed into...
  • DecodeEventFDs - This takes a file descriptor, and reads it, looking for EV_KEY events, those are found, the resulting key code is grabbed, and 20000 is added to it to indicate a synthetic key event. The resulting keycode is then passed to Orbiter's event queue, which can then be used by configuration device data for a given remote to map keys. This loop between ProcessGenericHIDEvents and DecodeEventFDs repeats until m_bQuit is set true from orbiter, at which point....
  • CloseEventFDs - closes the file descriptors in the vector, the remainder of CloseEventFDs is procedded, and the thread simply exits.
Things left to do

The thread handler is still very early in design. It merely passes any EV_KEY value that's greater than 0 as a KEY_DOWN. For Gyration 3101's, this also means the value of 2 gets passed as KEY_DOWN. Some interesting things happen as a result,

Held down keys need to be properly handled. --Tschak909 23:11, 27 June 2009 (CEST)

How to Implement a Remote Template that uses Generic HID Interface

See this page: Creating a Device Template for a Remote that uses the kernel input subsystem

9.3 Skinning and User Interface

9.3.1 HADesigner

The graphics, layout and display for the screens rendered in different Orbiter interfaces for the different UI versions are generated and manipulated using a Windows UI management tool called HADesigner.

The following series of screencasts describes the use of the HADesigner tool and the process of generating a brand new UI for a specific plugin for all different variations of the Orbiter UI versions.

Before proceeding, follow the installation instructions for HADesigner.


  1. Basic Designer Fundamentals
  2. Design Object Basics
  3. UI2 Popup Part I
  4. UI2 Popup Part II
  5. UI1 Orbiter
  6. UI1 Full Screen OSD
  7. UI1 Full Screen OSD Part II
  8. UI1 PDA
  9. Mobile Remote
  10. Cisco 7970 Orbiter
  11. Monitor Mode

The Basic skin, included with LinuxMCE, should really not be modified, since it is used extensively by LinuxMCE and Pluto and is known to work.

9.3.2 UI Design and process

The following series of screencasts walks through the design considerations involved in creating a brand new skin for LinuxMCE.

  1. Introduction and Aesthetic considerations
  2. First Pass at the Main Menu
  3. Main Menu Notes and Corrections
  4. The Floorplan Buttons