Difference between revisions of "Developers Guide"
(→1. Architecture) |
|||
(52 intermediate revisions by 13 users not shown) | |||
Line 1: | Line 1: | ||
+ | [[Category: Programmer's Guide]] | ||
+ | [[Category:Development]] | ||
+ | [[Category:Documentation]] | ||
+ | |||
+ | {| align="right" | ||
+ | | __TOC__ | ||
+ | |} | ||
LinuxMCE developer’s guide | LinuxMCE developer’s guide | ||
Document version 1.0 | Document version 1.0 | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | ==1. Architecture== | |
− | + | {{#lsth:Programmer's Guide| LinuxMCE software architecture }} | |
− | + | ||
− | + | ||
− | + | ||
− | LinuxMCE architecture | + | |
− | + | ||
− | + | ||
− | + | ||
+ | <!-- | ||
A LinuxMCE system can have one or more Media Directors (MD’s). Also, a Core machine can have also the functionality of a Media Director. We call it a Hybrid: | A LinuxMCE system can have one or more Media Directors (MD’s). Also, a Core machine can have also the functionality of a Media Director. We call it a Hybrid: | ||
− | + | [[Image:LMCE_Architecture_-_the_machines.jpg|400px|Linux MCE architecture – the machines]] | |
− | [[Image: | + | --> |
+ | {{p}} | ||
− | 2. DCE | + | ==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. | 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. | 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. | 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. | 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. | 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 | + | ==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. | 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. | ||
Line 61: | Line 46: | ||
See below a simplified class diagram for DCERouter: | See below a simplified class diagram for DCERouter: | ||
− | [[Image:DCERouter. | + | [[Image:DCERouter.jpg|550px|Simplified class diagram for the DCE router]] |
− | 4. The binary communication protocol | + | ==4. The binary communication protocol== |
− | 4.1 Introduction | + | ===4.1 Introduction=== |
A device can create a command connection and one or more event connections to the router. | 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. | The DCERouter process is listening on 3450 port. | ||
− | 4.2. How to create an event connection | + | |
+ | |||
+ | ===4.2. How to create an event connection=== | ||
Here is how the handshake is made for an event connection: | Here is how the handshake is made for an event connection: | ||
+ | |||
>> Device sends: | >> Device sends: | ||
EVENT <my_device_id> '\n' | EVENT <my_device_id> '\n' | ||
Line 82: | Line 70: | ||
and then: | and then: | ||
− | <serialized_binary_message> | + | <serialized_binary_message> |
− | 4.3 How to serialize data | + | ===4.3 How to serialize data=== |
DCE uses SerializeClass to serialize/deserialize data. | DCE uses SerializeClass to serialize/deserialize data. | ||
The sources can be found here : src/SerializeClass/Serialize.h/cpp. | 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: | 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: | 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: | Complex types: | ||
− | + | #string | |
− | + | #*STR_LENGTH bytes, the array with chars | |
− | + | #*1 byte, '/0' (value 0x00) | |
− | + | #: | |
− | + | #block of data | |
− | + | #*BLOCK_LENGTH bytes, the array with bytes | |
− | + | #: | |
− | + | #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) : | 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: | SerializeClass also allowed you to serialize/deserialize custom objects. Examples: | ||
− | + | * PlutoColor | |
− | + | * PlutoPoint | |
− | + | * PlutoSize | |
− | + | * PlutoRectangle | |
− | + | * PlutoDataBlock | |
− | 4.4 How to serialize a message | + | ===4.4 How to serialize a message=== |
The class used by DCE is Message class from src/DCE/Message.h/cpp unit. | The class used by DCE is Message class from src/DCE/Message.h/cpp unit. | ||
Line 141: | Line 129: | ||
This is how the raw data looks like into a binary message: | 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: | + | '''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: | + | '''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. | 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 | 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.Connect(router_ip, 3450 /*port*/) |
− | MyDevice.SendData("EVENT 250\n") | + | *MyDevice.SendData("EVENT 250\n") |
− | MyDevice.ReceiveData() //until you'll get a '\n' ; you should receive: "OK 250 IP=<device_ip_address> '\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, 1234) //magic number |
− | SerializeLong(MyData, 250) //my id | + | *SerializeLong(MyData, 250) //my id |
− | SerializeLong(MyData, 100) //the light switch | + | *SerializeLong(MyData, 100) //the light switch |
− | SerializeLong(MyData, 0) //not used now | + | *SerializeLong(MyData, 0) //not used now |
− | SerializeLong(MyData, 192) //message id of command 'on' | + | *SerializeLong(MyData, 192) //message id of command 'on' |
− | SerializeLong(MyData, 1) //normal priority | + | *SerializeLong(MyData, 1) //normal priority |
− | SerializeLong(MyData, 1) //message type : command | + | *SerializeLong(MyData, 1) //message type : command |
− | SerializeLong(MyData, 0) //not used now | + | *SerializeLong(MyData, 0) //not used now |
− | SerializeLong(MyData, 0) //not used now | + | *SerializeLong(MyData, 0) //not used now |
− | SerializeUnsignedChar(MyData, 0) //not including children | + | *SerializeUnsignedChar(MyData, 0) //not including children |
− | SerializeLong(MyData, 0) //broadcast level : none | + | *SerializeLong(MyData, 0) //broadcast level : none |
− | SerializeLong(MyData, 0) //don't retry | + | *SerializeLong(MyData, 0) //don't retry |
− | SerializeUnsignedChar(MyData, 0) //relative to sender false | + | *SerializeUnsignedChar(MyData, 0) //relative to sender false |
− | SerializeLong(MyData, 3) //delivery confirmation | + | *SerializeLong(MyData, 3) //delivery confirmation |
− | SerializeString(MyData, "") //device list to empty | + | *SerializeString(MyData, "") //device list to empty |
− | SerializeUnsignedLong(MyData, 2) //2 parameters | + | *SerializeUnsignedLong(MyData, 2) //2 parameters |
− | SerializeLong(MyData, 98) //parameter type #98 | + | *SerializeLong(MyData, 98) //parameter type #98 |
− | SerializeString(MyData, "") //empty value | + | *SerializeString(MyData, "") //empty value |
− | SerializeLong(MyData, 97) //parameter type #97 | + | *SerializeLong(MyData, 97) //parameter type #97 |
− | SerializeString(MyData, "") //empty value | + | *SerializeString(MyData, "") //empty value |
− | SerializeUnsignedLong(MyData, 0) //no binary parameters | + | *SerializeUnsignedLong(MyData, 0) //no binary parameters |
− | SerializeUnsignedLong(MyData, 0) //no extra messages | + | *SerializeUnsignedLong(MyData, 0) //no extra messages |
− | SerializeUnsignedLong(6789) //magic number | + | *SerializeUnsignedLong(6789) //magic number |
− | MyDevice.SendData("MESSAGE " + MyData.length() + '\n') | + | *MyDevice.SendData("MESSAGE " + MyData.length() + '\n') |
− | MyDevice.SendData(MyData) | + | *MyDevice.SendData(MyData) |
− | MyDevice.ReceiveData() //until you'll get a '\n' ; you should receive: "OK" or an error message | + | *MyDevice.ReceiveData() //until you'll get a '\n' ; you should receive: "OK" or an error message |
− | MyDevice.CloseConnection(); | + | *MyDevice.CloseConnection(); |
− | 4.5 How to serialize data-grids | + | ===4.5 How to serialize data-grids === |
− | + | '''Complex objects:''' | |
− | + | # 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 }; | ||
+ | #: | ||
+ | # 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 | ||
+ | #: | ||
+ | #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> | ||
+ | #: | ||
+ | #DataGridTableCellIndex | ||
+ | #* unsigned int, <column_row_type> | ||
+ | #* unsigned int, <size> | ||
+ | #: | ||
+ | #DataGridTable | ||
+ | #* unsigned long, <sizeof(DataGridTableSerializableData)> | ||
+ | #* array of DataGridTableCellIndex, <col * row * sizeof(DataGridTableCellIndex)> | ||
+ | #* array of DataGridCell, <col * row * serialized DataGridCell> | ||
− | + | ---- | |
− | - | + | |
− | + | ||
− | + | ||
− | + | ||
− | - | + | |
− | - | + | |
− | - | + | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
Additional step: lzo compression/decompression | Additional step: lzo compression/decompression | ||
− | |||
− | |||
+ | '''Note:''' can be disabled if compiled with DISABLE_LZO_DATAGRID | ||
+ | ---- | ||
− | + | ==5. The devices== | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | 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). | 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). | ||
Line 307: | Line 281: | ||
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. | 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): | Here is the simplified class diagram for one of the devices (App_Server): | ||
− | |||
− | + | [[Image:App_Server.jpg|frame|none|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== | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | 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. | 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. | ||
− | + | # Implemented commands: | |
− | + | #*CMD_Spawn_Application - Spawns an application | |
− | CMD_Spawn_Application - Spawns an application | + | #*CMD_Kill_Application - Kills an application |
− | CMD_Kill_Application - Kills an application | + | #*CMD_Application_Is_Running - Checks if the given application is running. |
− | 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_Halt_Device - Halts or reboots this device | + | #*CMD_Vol_Down - Decreases the volume 1% |
− | + | #*CMD_Set_Volume - Sets the volume to a specific level between 0-100 | |
− | CMD_Vol_Up - Increases the volume 1% | + | #*CMD_Mute - Toggles mute/unmute |
− | 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 | + | #It doesn’t fire any events. |
− | + | #: | |
− | + | #: | |
− | + | #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. | 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. | ||
Line 398: | Line 325: | ||
3. Device data: | 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 | + | ==8. Media Player device== |
Currently there are two Media Players in LinuxMCE, the primary Xine_Player and | Currently there are two Media Players in LinuxMCE, the primary Xine_Player and | ||
Line 420: | Line 338: | ||
following formats: | following formats: | ||
− | + | *'''File formats (System layer / media types)supported:''' | |
− | 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 | ||
Line 512: | Line 428: | ||
1. Implemented commands | 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 | ||
− | |||
− | 9.1 Introduction | + | '''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. | 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. | ||
Line 587: | Line 504: | ||
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). | 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 | + | ===9.2 Architecture=== |
+ | |||
+ | [[Image:architecture.jpg|550px|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”. | 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 | + | ====9.2.1. The renderers==== |
There are two kinds of renders: | 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: | 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. | + | * etc. |
and applications flow : | 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: | 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: | Here is the class diagram for derived OrbiterRenderer‘s: | ||
− | + | ||
+ | [[Image:orbiterrenderer.jpg|550px|OrbiterRenderer class diagram]] | ||
Line 636: | Line 555: | ||
Here is the class diagram for OpenGL implementation: | Here is the class diagram for OpenGL implementation: | ||
− | + | [[Image:openGLimplementation.jpg|550px|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. | 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. | 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 | + | ====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. | 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. | ||
Line 649: | Line 569: | ||
− | 9.2.3. Cache image manager | + | ====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. | 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 | + | ====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. | 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 | + | ====9.2.5. Simulator==== |
The simulator is responsible for generating mouse and keyboard events used for stress testing. It also stores some configuration settings. | 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 | + | ====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. | 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. | 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 | + | ====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. | 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. | ||
− | + | [[Image:orbiterlogicclassdiagram.jpg|550px|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. | 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. | + | ====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. | 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. | ||
Line 681: | Line 601: | ||
See below the class diagram: | See below the class diagram: | ||
− | + | [[Image:mousehandlers.jpg|550px|Mouse handlers – class diagram]] | |
Line 689: | Line 609: | ||
MouseBehaviour handles special mouse behavior, such as locking axis’s, ramping and acceleration. | 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: | ||
+ | |||
+ | [[Image:HIDinterface.jpg|frame|none|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. --[[User:Tschak909|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_User's_manual|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 [[Installing_HADesigner | installation instructions for HADesigner]]. | ||
+ | |||
+ | |||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/01-basic_hadesigner_fundamentals.html Basic Designer Fundamentals] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/02_designobj_basics_1.ogg Design Object Basics] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/03_ui2_popup_part_1.ogg UI2 Popup Part I] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/04_ui2_popup_part_2.ogg UI2 Popup Part II] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/05_UI1_Orbiter.ogg UI1 Orbiter] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/06_UI1_Full_Screen_OSD.ogg UI1 Full Screen OSD] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/07_UI1_Full_Screen_OSD_2.ogg UI1 Full Screen OSD Part II] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/08_UI1_PDA.ogg UI1 PDA] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/09_Mobile_Remote.ogg Mobile Remote] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/10_cisco_7970_orbiter.ogg Cisco 7970 Orbiter] | ||
+ | # [http://www.localeconcept.com/HADesigner-Screencasts/ogg/11_Monitor_mode.ogg 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. | + | ====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. | ||
− | + | # [http://www.localeconcept.com/Skin-Screencasts/01_introduction_and_aesthetic.ogg Introduction and Aesthetic considerations] | |
+ | # [http://www.localeconcept.com/Skin-Screencasts/02_main_menu_first_pass.ogg First Pass at the Main Menu] | ||
+ | # [http://www.localeconcept.com/Skin-Screencasts/03_main_menu_notes_and_corrections.ogg Main Menu Notes and Corrections] | ||
+ | # [http://www.localeconcept.com/Skin-Screencasts/04_the_floorplan_buttons.ogg The Floorplan Buttons] |
Latest revision as of 17:05, 25 October 2012
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".
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:
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:
- string
- STR_LENGTH bytes, the array with chars
- 1 byte, '/0' (value 0x00)
- block of data
- BLOCK_LENGTH bytes, the array with bytes
- 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
- foreach <string_parameter>
- 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
- foreach <data_parameter>
- unsigned long, <number_of_extra_messages>
- foreach <extra_message>
- unsigned long, <serialized_extra_message_length>
- array of bytes, <serialized_extra_message_value>
- end_foreach
- foreach <extra_message>
- 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:
- 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 };
- 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
- foreach <cell_attribute>
- 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>
- DataGridTableCellIndex
- unsigned int, <column_row_type>
- unsigned int, <size>
- 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):
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.
- 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
- It doesn’t fire any events.
- 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
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:
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:
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.
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:
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:
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.
- Basic Designer Fundamentals
- Design Object Basics
- UI2 Popup Part I
- UI2 Popup Part II
- UI1 Orbiter
- UI1 Full Screen OSD
- UI1 Full Screen OSD Part II
- UI1 PDA
- Mobile Remote
- Cisco 7970 Orbiter
- 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.