From ddb2795b656a5ebc8f4398173bfbb26ad5d0bf2d Mon Sep 17 00:00:00 2001 From: Thiago Mendes Date: Mon, 10 Jul 2017 13:56:18 -0500 Subject: [PATCH] Converting Spice_protocol.odt to Asciidoc https://gitlab.freedesktop.org/spice/spice-server/issues/10 Acked-by: Frediano Ziglio --- docs/Makefile.am | 2 + docs/Spice_protocol.odt | Bin 44052 -> 0 bytes docs/spice_protocol.txt | 2728 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 2730 insertions(+) delete mode 100644 docs/Spice_protocol.odt create mode 100644 docs/spice_protocol.txt diff --git a/docs/Makefile.am b/docs/Makefile.am index 3a04abfc..e7c2b269 100644 --- a/docs/Makefile.am +++ b/docs/Makefile.am @@ -8,12 +8,14 @@ EXTRA_DIST = \ spice_threading_model.html \ spice_threading_model.txt \ vd_interfaces.txt \ + spice_protocol.txt \ $(NULL) HTML_FILES = \ spice_style.html \ spice_threading_model.html \ vd_interfaces.html \ + spice_protocol.html \ $(NULL) if BUILD_MANUAL diff --git a/docs/Spice_protocol.odt b/docs/Spice_protocol.odt deleted file mode 100644 index 02a17a45fa1fbec2334d1098527f029fd10af201..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 44052 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 Z|ACBE6)>?bVK>), 0 and 1 stand +for disconnected and connected state respectively. + +|UINT32 agent_tokens +|number of available tokens for sending messages to Spice agent. + +|UINT32 multi_media_time +|current server multimedia time. The multimedia time is used for synchronizing +video (for more information see <>) + +|UINT32 ram_hint +|optional hint for help in determining global LZ compression dictionary size +(for more information see section <> in “Display +Channel”). +|=== ++ +. Server side channels notification ++ +In order to have the ability to dynamically attach to the server side channels, +Spice protocol includes RED_MAIN_CHANNELS_LIST message. This massage informs +the client of available channels in the server side. In response to this +message the client can decide to link with the new available channel(s). The +server must receive REDC_MAIN_ATTACH_CHANNELS before sending any +RED_MAIN_CHANNELS_LIST message. ++ +.. RED_MAIN_CHANNELS_LIST, RedChannels ++ +[cols="2*"] +|=== +|UINT32 num_of_channels +|number of channels in this list + +|RedChanneID[] channels +|vector of “num_of_channels” channel ids +|=== ++ +.. RedChanneID ++ +[cols="2*"] +|=== +|UINT8 type +|channel type, one of RED_CHANNEL_? channel types, except for RED_CHANNEL_MAIN + +|UINT8 id +|channel id +|=== ++ +[[multimedia_time]] +. Multimedia time ++ +Spice defines messages for setting multimedia time for synchronization of video +and audio streams. Two methods for updating multimedia time are supported. The +first method uses the time stamp of data that arrives on the playback +channel.The second method uses the main channel RED_MAIN_MULTI_MEDIA_TIME +message. The latter method is used when no active playback channel exist. ++ +.. RED_MAIN_MULTI_MEDIA_TIME, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|multimedia time +|=== ++ +[[spice_agent]] +. Spice agent ++ +Spice protocol defines a set of messages for bidirectional communication +channel between Spice client and spice client agent on the remote server. Spice +provides a communication channel only, the actual transferred data content is +opaque to the protocol. This channel can be used for various purposes, for +example, client-guest clipboard sharing, authentication and display +configuration. ++ +Spice client receives notifications of remote site agent connection as part of +the RED_MAIN_INIT message or by a specific server RED_MAIN_AGENT_CONNECTED. +Remote agent disconnection notification is delivered by +RED_MAIN_AGENT_DISCONNECTED message. A bidirectional tokens mechanism is used +in order to prevent blocking of the main channel with agent messages (e.g., in +case the agent stops consuming the data). Each side is not allowed to send more +messages than the tokens allocated to it by the other side. The number of +tokens that are allocated for the client is initialized from RED_MAIN_INIT +message, and farther allocation of tokens is done using RED_MAIN_AGENT_TOKEN. +Server tokens initial count is delivered in REDC_MAIN_AGENT_START message. This +message must be the first agent related message that the client sends to the +server. Farther tokens allocation for the server is done using +REDC_MAIN_AGENT_TOKEN. Actual data packets are delivered using +RED_MAIN_AGENT_DATA and REDC_MAIN_AGENT_DATA. ++ +.. Although agent messages are opaque for the protocol, agent data stream is +defined by Spice protocol in order to delineate messages. Still, the +client-server communication is independent from the agent channel, e.g., agent +protocol conflicts don't affect the rest of the channels. Agent stream is +defined as a run of messages having the following format: ++ +[cols="2*"] +|=== +|UINT32 protocol +|unique protocol of this message. The protocol id must be registered in order +to prevent conflicts. + +|UINT32 type +|protocol dependent message type. + +|UINT64 opaque +|protocol dependent opaque data. + +|UINT32 size +|size of data in bytes. + +|UINT8 data[0] +|data of this message. +|=== ++ +Client and server must continue processing unknown protocols messages or +messages having unknown type (i.e., receive and dump). ++ +.. RED_MAIN_AGENT_CONNECTED, VOID +.. RED_MAIN_AGENT_DISCONNECTED, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|disconnect error code RED_ERROR_? +|=== ++ +.. RED_AGENT_MAX_DATA_SIZE = 2048 +.. RED_MAIN_AGENT_DATA, UINT8[] ++ +Agent packet is the entire message body (i.e. RedDataHeader.size). The maximum +packet size is RED_AGENT_MAX_DATA_SIZE. ++ +.. RED_MAIN_AGENT_TOKEN, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|allocated tokens count for the client +|=== ++ +.. REDC_MAIN_AGENT_START, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|allocated tokens count for the server +|=== ++ +.. REDC_MAIN_AGENT_DATA, UINT8[] ++ +Agent packet is the entire message body (i.e. RedDataHeader.size). The maximum +packet size is RED_AGENT_MAX_DATA_SIZE. ++ +.. REDC_MAIN_AGENT_TOKEN, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|allocated tokens count for the server +|=== + +== Inputs channel definition + +Spice Inputs channel controls the server mouse and the keyboard. + +. Client messages ++ +[source,c] +---- +REDC_INPUTS_KEY_DOWN = 101 +REDC_INPUTS_KEY_UP = 102 +REDC_INPUTS_KEY_MODIFAIERS = 103 + +REDC_INPUTS_MOUSE_MOTION = 111 +REDC_INPUTS_MOUSE_POSITION = 112 +REDC_INPUTS_MOUSE_PRESS = 113 +REDC_INPUTS_MOUSE_RELEASE = 114 +---- ++ +. Server Messages ++ +[source,c] +---- +RED_INPUTS_INIT = 101 +RED_INPUTS_KEY_MODIFAIERS = 102 + +RED_INPUTS_MOUSE_MOTION_ACK = 111 +---- ++ +. Keyboard messages ++ +Spice supports sending keyboard key events and keyboard leds synchronization. +The client sends key event using REDC_INPUTS_KEY_DOWN and REDC_INPUTS_KEY_UP +messages. Key value is expressed using PC AT scan code (see +<>). Keyboard leds synchronization is done by sending +RED_INPUTS_KEY_MODIFAIERS message by the server or by sending +REDC_INPUTS_KEY_MODIFAIERS by the client, these messages contain keyboard leds +state. Keyboard modifiers is also sent by the server using RED_INPUTS_INIT, +this message must be sent as the first server message and the server mustn't +send it at any other point. ++ +.. Keyboard led bits ++ +[source,c] +---- +RED_SCROLL_LOCK_MODIFIER = 1 +RED_NUM_LOCK_MODIFIER = 2 +RED_CAPS_LOCK_MODIFIER = 4 +---- ++ +.. RED_INPUTS_INIT, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|any combination of keyboard led bits. If bit is set then the led is on. +|=== ++ +.. RED_INPUTS_KEY_MODIFAIERS, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|any combination of keyboard led bits. If bit is set then the led is on. +|=== ++ +.. REDC_INPUTS_KEY_MODIFAIERS, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|any combination of keyboard led bits. If bit is set then the led is on. +|=== ++ +[[key_code]] +.. KeyCode ++ +[cols="2*"] +|=== +|UINT8[4] +|the value of key code is a PC AT scan code. The code is composed by up to four +bytes for supporting extended codes. A code is terminated by a zero byte. +|=== ++ +.. REDC_INPUTS_KEY_DOWN, KeyCode ++ +[cols="2*"] +|=== +|KeyCode +|client sends this message to notify of key press event. +|=== ++ +.. REDC_INPUTS_KEY_UP, KeyCode ++ +KeyCode – client sends this message to notify of key release event. ++ +. Mouse messages ++ +spice support two modes of mouse operation: client mouse and server mouse (for +more information see <>). in server mouse mode the +client sends mouse motion message (i.e., redc_inputs_mouse_motion), and in +client mouse mode it sends position message (i.e., redc_inputs_mouse_position). +position message holds the position of the client mouse on the display and the +id of the display channel, which is derived from redlinkmess.channel_id. in +order to prevent flood of mouse motion/position events, the server sends +red_inputs_mouse_motion_ack message on every red_motion_ack_bunch messages it +receive. this mechanism allows the client to keep track on the server's +messages consumption rate and to change the event pushing policy according to +it. mouse button events are sent to the server using redc_inputs_mouse_press +and redc_inputs_mouse_release messages. ++ +.. Red Button ID ++ +[source,c] +---- +REDC_MOUSE_LBUTTON = 1, left button +REDC_MOUSE_MBUTTON = 2, middle button +REDC_MOUSE_RBUTTON = 3, right button +REDC_MOUSE_UBUTTON = 4, scroll up button +REDC_MOUSE_DBUTTON = 5, scroll down button +---- ++ +.. Buttons masks ++ +[source,c] +---- +REDC_LBUTTON_MASK = 1, left button mask +REDC_MBUTTON_MASK = 2, middle button mask +REDC_RBUTTON_MASK = 4, right button mask +---- ++ +.. RED_MOTION_ACK_BUNCH ++ +[source,c] +---- +RED_MOTION_ACK_BUNCH = 4 +---- ++ +.. REDC_INPUTS_MOUSE_MOTION, RedcMouseMotion ++ +[cols="2*"] +|=== +|INT32 dx +|number of pixels the mouse had moved on x axis + +|INT32 dy +|number of pixels the mouse had moved on y axis + +|UINT32 buttons_state +|any combination of buttons mask. Set bit describe pressed button and clear bit +describe unpressed button. + +|=== ++ +.. REDC_INPUTS_MOUSE_POSITION, RedcMousePosition ++ +[cols="2*"] +|=== +|UINT32 x +|position on x axis + +|UINT32 y +|position on y axis + +|UINT32 buttons_state +|any combination of buttons mask. Set bit describe pressed button and clear bit +describe unpressed button. + +|UINT8 display_id +|id of the display that client mouse is on. +|=== ++ +.. REDC_INPUTS_MOUSE_PRESS, RedcMousePress ++ +[cols="2*"] +|=== +|UINT32 button_id +|one of REDC_MOUSE_?BUTTON + +|UINT32 buttons_state +|any combination of buttons masks. Set bit describes pressed button, and clear +bit describes unpressed button. +|=== ++ +.. REDC_INPUTS_MOUSE_RELEASE, RedcMouseRelease ++ +[cols="2*"] +|=== +|UINT32 button_id +|one of REDC_MOUSE_?BUTTON + +|UINT32 buttons_state +|any combination of buttons mask. Set bit describes pressed button and clear +bit describes unpressed button. +|=== + +== Display channel definition + +Spice protocol defines a set of messages for supporting rendering of the remote +display area on the client display. The protocol supports rendering of graphics +primitives (e.g., lines, images) and video streams. The protocol also supports +caching of images and color palettes on the client side. Spice display channel +supports several images compression methods for reducing network traffic. + +. Server messages ++ +[source,c] +---- +RED_DISPLAY_MODE = 101 +RED_DISPLAY_MARK = 102 +RED_DISPLAY_RESET = 103 +RED_DISPLAY_COPY_BITS = 104 + +RED_DISPLAY_INVAL_LIST = 105 +RED_DISPLAY_INVAL_ALL_IMAGES = 106 +RED_DISPLAY_INVAL_PALETTE = 107 +RED_DISPLAY_INVAL_ALL_PALETTES = 108 + +RED_DISPLAY_STREAM_CREATE = 122 +RED_DISPLAY_STREAM_DATA = 123 +RED_DISPLAY_STREAM_CLIP = 124 +RED_DISPLAY_STREAM_DESTROY = 125 +RED_DISPLAY_STREAM_DESTROY_ALL = 126 + +RED_DISPLAY_DRAW_FILL = 302 +RED_DISPLAY_DRAW_OPAQUE = 303 +RED_DISPLAY_DRAW_COPY = 304 +RED_DISPLAY_DRAW_BLEND = 305 +RED_DISPLAY_DRAW_BLACKNESS = 306 +RED_DISPLAY_DRAW_WHITENESS = 307 +RED_DISPLAY_DRAW_INVERS = 308 +RED_DISPLAY_DRAW_ROP3 = 309 +RED_DISPLAY_DRAW_STROKE = 310 +RED_DISPLAY_DRAW_TEXT = 311 +RED_DISPLAY_DRAW_TRANSPARENT = 312 +RED_DISPLAY_DRAW_ALPHA_BLEND = 313 +---- ++ +. Client messages ++ +[source,c] +---- +REDC_DISPLAY_INIT = 101 +---- ++ +. Operation flow ++ +Spice server sends to the client a mode message using RED_DISPLAY_MODE for +specifying the current draw area size and format. In response the client +creates a draw area for rendering all the followed rendering commands sent by +the server. The client will expose the new remote display area content (i.e., +after mode command) only after it receives a mark command (i.e., +RED_DISPLAY_MARK) from the server. The server can send a reset command using +RED_DISPLAY_RESET to instruct the client to drop its draw area and palette +cache. Sending mode message is allowed only while no active draw area exists +on the client side. Sending reset message is allowed only while active draw +area exists on client side. Sending mark message is allowed only once, between +mode and reset messages. Draw commands, copy bits command and stream commands +are allowed only if the client have an active display area (i.e., between +RED_DISPLAY_MODE to RED_DISPLAY_RESET). ++ +On channel connection, the client optionally sends an init message, using +REDC_DISPLAY_INIT, in order to enable image caching and global dictionary +compression. The message includes the cache id and its size and the size of the +dictionary compression window. These sizes and id are determined by the client. +It is disallowed to send more then one init message. ++ +Color pallets cache are manged by the server. +Items cache insertion commands are sent as part of the rendering commands. +Cache items removal are sent explicitly using RED_DISPLAY_INVAL_LIST or +RED_DISPLAY_INVAL_LIST server messages. Resetting client caches is done by +sending RED_DISPLAY_INVAL_ALL_IMAGES or RED_DISPLAY_INVAL_ALL_PALETTES server +messages. ++ +. Draw area control ++ +.. RED_DISPLAY_MODE, RedMode ++ +[cols="2*"] +|=== +|UINT32 width +|width of the display area + +|UINT32 height +|height of the display area + +|UINT32 depth +|color depth of the display area. Valid values are 16bpp or 32bpp. +|=== ++ +.. RED_DISPLAY_MARK, VOID ++ +Mark the beginning of the display area visibility ++ +.. RED_DISPLAY_RESET, VOID ++ +Drop current display area of the channel and reset palette cache ++ +. Raster operation descriptor ++ +The following defines a set of flags for describing raster operations that can +be applied on a source image, source brush, destination and the result during a +rendering operation. Combination of those flags defines the necessary steps +that are needed to be preformed during a rendering operation. In the +following definitions of rendering commands this combination is referred to by +'rop_descriptor'. ++ +[source,c] +---- +ROPD_INVERS_SRC = 1 +---- ++ +Source Image need to be inverted before rendering ++ +[source,c] +---- +ROPD_INVERS_BRUSH = 2 +---- ++ +Brush need to be inverted before rendering ++ +[source,c] +---- +ROPD_INVERS_DEST = 4 +---- ++ +Destination area need to be inverted before rendering ++ +[source,c] +---- +ROPD_OP_PUT = 8 +---- ++ +Copy operation should be used. ++ +[source,c] +---- +ROPD_OP_OR = 16 +---- ++ +OR operation should be used. ++ +[source,c] +---- +ROPD_OP_AND = 32 +---- ++ +AND operation should be used. ++ +[source,c] +---- +ROPD_OP_XOR = 64 +---- ++ +XOR operation should be used. ++ +[source,c] +---- +ROPD_OP_BLACKNESS = 128 +---- ++ +Destination pixel should be replaced by black ++ +[source,c] +---- +ROPD_OP_WHITENESS = 256 +---- ++ +Destination pixel should be replaced by white ++ +[source,c] +---- +ROPD_OP_INVERS = 512 +---- ++ +Destination pixel should be inverted ++ +[source,c] +---- +ROPD_INVERS_RES = 1024 +---- ++ +Result of the operation needs to be inverted ++ +OP_PUT, OP_OR, OP_AND, OP_XOR, OP_BLACKNESS, OP_WHITENESS, and OP_INVERS are +mutually exclusive ++ +OP_BLACKNESS, OP_WHITENESS, and OP_INVERS are exclusive ++ +. Raw raster image ++ +The following section describes Spice raw raster image (Pixmap). Pixmap is one +of several ways to transfer images in Spice protocol (for more information see +<>). ++ +.. Pixmap format types ++ +[source,c] +---- +PIXMAP_FORMAT_1BIT_LE = 1 +---- ++ +1 bit per pixel and bits order is little endian. Each pixel value is an index +in a color table. The color table size is 2. ++ +[source,c] +---- +PIXMAP_FORMAT_1BIT_BE = 2 +---- ++ +1 bit per pixel and bits order is big endian. Each pixel value is index in a +color table. The color table size is 2. ++ +[source,c] +---- +PIXMAP_FORMAT_4BIT_LE = 3 +---- ++ +4 bits per pixel and nibble order inside a byte is little endian. Each pixel +value is an index in a color table. The color table size is 16. ++ +[source,c] +---- +PIXMAP_FORMAT_4BIT_BE = 4 +---- ++ +4 bits per pixel and nibble order inside a byte is big endian. Each pixel value +is an index in a color table. The color table size is 16. ++ +[source,c] +---- +PIXMAP_FORMAT_8BIT = 5 +---- ++ +8 bits per pixel. Each pixel value is an index in a color table. The color +table size is 256. ++ +[source,c] +---- +PIXMAP_FORMAT_16BIT = 6 +---- ++ +pixel format is 16 bits RGB555. ++ +[source,c] +---- +PIXMAP_FORMAT_24BIT = 7 +---- ++ +pixel format is 24 bits RGB888. ++ +[source,c] +---- +PIXMAP_FORMAT_32BIT = 8 +---- ++ +pixel format is 32 bits RGB888. ++ +[source,c] +---- +PIXMAP_FORMAT_RGBA = 9 +---- ++ +pixel format is 32 bits ARGB8888. ++ +.. Palette ++ +[cols="2*"] +|=== +|UINT64 id +|unique id of the palette + +|UINT16 table_size +|number of entries in the color table + +|UINT32[] color_table +|each entry is RGB555 or RGB888 color depending on the current display area +mode. If display area mode color depth is 32, the effective format is RGB888. +If display area mode color depth is 16 the effective format is RGB555. +|=== ++ +.. Pixmap flags ++ +[source,c] +---- +PIXMAP_FLAG_PAL_CACHE_ME = 1 +---- ++ +Instruct the client to add the palette to cache ++ +[source,c] +---- +PIXMAP_FLAG_PAL_FROM_CACHE = 2 +---- ++ +Instruct the client to retrieve palette from cache. ++ +[source,c] +---- +PIXMAP_FLAG_TOP_DOWN = 4 +---- ++ +Pixmap lines are ordered from top to bottom (i.e., line 0 is the highest line). ++ +.. Pixmap ++ +[cols="2*"] +|=== +|UINT8 format +|one of PIXMAP_FORMAT_? + +|UINT8 flags +|combination of PIXMAP_FLAG_? + +|UINT32 width +|width of the pixmap + +|UINT32 height +|height of the pixmap + +|UINT32 stride +|number of bytes to add for moving from the beginning of line n to the +beginning of line n+1 +|=== ++ +[source,c] +---- +union { + ADDRESS palette; /* address of the color palette. Must be zero if no +color table is required for format */ +} +---- ++ +[cols="2*"] +|=== +|UINT64 palette_id +|id of the palette, valid if FLAG_PAL_FROM_CACHE is set + +|ADDRESS data +|address of line 0 of the pixmap. +|=== ++ +. LZ with palette ++ +This section describes a data structure that is combination of a color palette +and a compressed pixmap data. The pixmap is compressed using our implementation +of LZSS algorithm (see next section). Each decoded pixel value is an index in +the color palette. ++ +.. LZPalette Flags ++ +[source,c] +---- +LZPALETTE_FLAG_PAL_CACHE_ME = 1 +---- ++ +Instruct the client to add the palette to the cache ++ +[source,c] +---- +LZPALETTE_FLAG_PAL_FROM_CACHE = 2 +---- ++ +Instruct the client to retrieve palette from the cache. ++ +[source,c] +---- +LZPALETTE_FLAG_TOP_DOWN = 4 +---- ++ +pixmap lines are ordered from top to bottom (i.e. line 0 is the highest line). ++ +.. LZPalette ++ +[cols="2*"] +|=== +|UINT8 flags +|combination of LZPALETTE_FLAG_? + +|UINT32 data_size +|size of compressed data +|=== ++ +[source,c] +---- +union { + ADDRESS palette; /* address of the color palette (see Palette section +in “Raw raster image”). Zero value is disallowed. */ + UINT64 palette_id; /* id of the palette, valid if FLAG_PAL_FROM_CACHE +is set. */ +} +---- ++ +[cols="2*"] +|=== +|UINT8[] data +|compressed pixmap +|=== ++ +[[spice_image]] +. Spice Image ++ +The following section describes Spice image. Spice image is used in various +commands and data structures for representing a raster image. Spice image +supports several compression types in addition to the raw mode: Quic, LZ and +GLZ. Quic is a predictive coding algorithm. It is a generalization of SFALIC +from gray-scale to color images withe addition of RLE encoding. By LZ we refer +to the our implementation of the LZSS algorithm, which was adjusted for images +in different formats. By GLZ we refer to an extension of LZ that allows it to +use a dictionary that is based on a set of images and not just on the image +being compressed. ++ +.. Image types ++ +[source,c] +---- +IMAGE_TYPE_PIXMAP = 0 +IMAGE_TYPE_QUIC = 1 +IMAGE_TYPE_LZ_PLT = 100 +IMAGE_TYPE_LZ_RGB = 101 +IMAGE_TYPE_GLZ_RGB = 102 +IMAGE_TYPE_FROM_CACHE = 103 +---- ++ +.. Image flags ++ +IMAGE_FLAG_CACHE_ME = 1, this flag instruct the client to add the image to +image cache, cache key is ImageDescriptor.id (see below). ++ +.. ImageDescriptor ++ +[cols="2*"] +|=== +|UINT64 id +|unique id of the image + +|UINT8 type +|type of the image. One of IMAGE_TYPE_? + +|UINT8 flags +|any combination of IMAGE_FLAG_? + +|UINT32 width +|width of the image + +|UINT32 height +|height of the image +|=== ++ +.. Image data ++ +Image data follows ImageDescriptor and its content depends on +ImageDescriptor.type: ++ +* In case of PIXMAP – content is Pixmap. +* In case of QUIC – content is Quic compressed image. Data begins with the +size of the compressed data, represented by UINT32, followed by the compressed +data. +* In case of LZ_PLT – content is LZPalette. +* In case of LZ_RGB – content is LZ_RGB – LZ encoding of an RGB image. Data +begins with the size of the compressed data, represented by UINT32, followed +by the compressed data. +* In case of GLZ_RGB – content is GLZ_RGB – GLZ encoding of an RGB image. Data +begins with the size of the compressed data, represented by UINT32, , followed +by the compressed data. +* In case of FROM_CACHE – No image data. The client should use +ImageDescriptor.id to retrieve the relevant image from cache. ++ +. Glyph String ++ +Glyph string defines an array of glyphs for rendering. Glyphs in a string can +be in A1, A4 or A8 format (i.e., 1bpp, 4bpp, or 8bpp alpha mask). Every glyph +contains its rendering position on the destination draw area. ++ +.. RasterGlyph ++ +[cols="2*"] +|=== +|POINT render_pos +|location of the glyph on the draw area + +|POINT glyph_origin +|origin of the glyph. The origin is relative to the upper left corner of the +draw area. Positive value on x axis advances leftward and positive value on y +axis advances upward. + +|UINT16 width +|glyph's width + +|UINT16 height +|glyph's height + +|UINT8[] data +|alpha mask of the glyph. Actual mask data depends on the glyph string's flags. +If the format is A1 then the line stride is ALIGN(width, 8) / 8. If the format +is A4, the line stride is ALIGN(width, 2) / 2. If the format is A8, the line +stride is width. +|=== ++ +.. Glyph String flags ++ +[source,c] +---- +GLYPH_STRING_FLAG_RASTER_A1 = 1 +---- ++ +Glyphs type is 1bpp alpha value (i.e., 0 is transparent 1 is opaque) ++ +[source,c] +---- +GLYPH_STRING_FLAG_RASTER_A4 = 2 +---- ++ +Glyphs type is 4bpp alpha value (i.e., 0 is transparent 16 is opaque) ++ +[source,c] +---- +GLYPH_STRING_FLAG_RASTER_A8 = 4 +---- ++ +Glyphs type is 4bpp alpha value (i.e., 0 is transparent 256 is opaque) ++ +[source,c] +---- +GLYPH_STRING_FLAG_RASTER_TOP_DOWN = 8 +---- ++ +Line 0 is the top line of the mask ++ +.. GlyphString ++ +[cols="2*"] +|=== +|UINT16 length +|number of glyphs + +|UINT16 flags +|combination of GLYPH_STRING_FLAG_? + +|UINT8[] data +|glyphs +|=== ++ +. Data Types ++ +.. RectList ++ +[cols="2*"] +|=== +|UINT32 count +|number of RECT items in rects + +|RECT[] rects +|array of RECT +|=== ++ +.. Path segment flags ++ +[source,c] +---- +PATH_SEGMENT_FLAG_BEGIN = 1 +---- ++ +this segment begins a new path ++ +[source,c] +---- +PATH_SEGMENT_FLAG_END = 2 +---- ++ +this segment ends the current path ++ +[source,c] +---- +PATH_SEGMENT_FLAG_CLOSE = 8 +---- ++ +this segment closes the path and is invalid if PATH_SEGMENT_FLAG_END is not set ++ +[source,c] +---- +PATH_SEGMENT_FLAG_BEZIER = 16 +---- ++ +this segment content is a Bezier curve ++ +.. PathSeg ++ +[cols="2*"] +|=== +|UINT32 flags +|any combination of PATH_SEGMENT_FLAG_? + +|UINT32 count +|number of points in the segment + +|POINTFIX[] points +|segment points +|=== ++ +.. PathSegList ++ +List of PathSeg items. End of the list is reached if the sum of all previous +PathSegs' sizes is equal to list_size. Address of next segment is the address +of PathSeg.points[PathSeg.count] ++ +[cols="2*"] +|=== +|UINT32 list_size +|total size of in bytes of all PathSegs in the list, +|=== ++ +PathSeg seg0 – first path segment. ++ +.. Clip types ++ +[source,c] +---- +CLIP_TYPE_NONE = 0 +---- ++ +no clipping ++ +[source,c] +---- +CLIP_TYPE_RECTS = 1 +---- ++ +data is RectList and union of all rectangles in RectList is the effective clip ++ +[source,c] +---- +CLIP_TYPE_PATH = 2 +---- ++ +data is PathSegList and the figure described by PathSegList is the effective +clip ++ +.. Clip ++ +[cols="2*"] +|=== +|UIN32 type +|one of CLIP_TYPE_? + +|ADDRESS data +|address of clip data. The content depends on +|=== ++ +.. Mask flags ++ +[source,c] +---- +MASK_FLAG_INVERS = 1, the effective mask is the inverse of the mask +---- ++ +.. Mask ++ +[cols="2*"] +|=== +|UINT8 flags | flags of the mask, combination of MASK_FLAG_? + +|POINT position | origin of the mask in bitmap coordinates + +|ADDRESS bitmap | address of the mask's image, the format of the image must be +1bpp. If the bitmap is zero then no masking operation needs to be preformed. +|=== ++ +In all rendering commands, the mask must be big enough to cover the destination +rectangle ++ +.. Brush types ++ +[source,c] +---- +BRUSH_TYPE_NONE = 0 /* the brush is invalid */ +BRUSH_TYPE_SOLID = 1 /* the brush is solid RGB color */ +BRUSH_TYPE_PATTERN = 2 /* the brush is a pattern */ +---- ++ +.. Pattern ++ +[cols="2*"] +|=== +|ADDRESS image +|address of the pattern's Image + +|POINT position +|origin coordinates of the pattern in the image +|=== ++ +.. Brush ++ +[cols="2*"] +|=== +|UINT32 type +|one of BRUSH_TYPE_? +|=== ++ +[source,c] +---- +Union { + UINT32 color; */ RGB color. The format of the color depends on current +draw area mode.*/ + Pattern pattern; +} +---- ++ +.. Image scale mode ++ +The following defines the method for scaling image ++ +[source,c] +---- +IMAGE_SCALE_INTERPOLATE = 0 +---- ++ +The client is allowed to INTERPOLATE pixel color. ++ +[source,c] +---- +IMAGE_SCALE_NEAREST = 1 +---- ++ +The client must use the nearest pixel. ++ +.. LineAtrr flags ++ +[source,c] +---- +LINE_ATTR_FLAG_START_WITH_GAP = 4 +---- ++ +first style segment if gap (i.e., foreground) ++ +[source,c] +---- +LINE_ATTR_FLAG_STYLED = 8 +---- ++ +style member of LineAtrr is valid and contains effective line style for the +rendering operation. ++ +.. LineAtrr join style ++ +[source,c] +---- +LINE_ATTR_JOIN_ROUND = 0 +LINE_ATTR_JOIN_BEVEL = 1 +LINE_ATTR_JOIN_MITER = 2 +---- ++ +.. LineAtrr cap style ++ +[source,c] +---- +LINE_ATTR_CAP_ROUND = 0 +LINE_ATTR_CAP_SQUARE = 1 +LINE_ATTR_CAP_BUTT = 2 +---- ++ +.. LineAttr ++ +[cols="2*"] +|=== +|UINT8 flags +|combination of LINE_ATTR_? + +|UINT8 join_style +|one of LINE_ATTR_JOIN_? + +|UINT8 cap_style +|one of LINE_ATTR_CAP_? + +|UINT8 style_num_segments +|number of style segments in line style + +|FIXED28_4 width +|width of the line in pixels + +|FIXED28_4 miter_limit +|miter limit in pixels + +| ADDRESS style +|address of line style line style is array of FIXED28_4. The array defines +segments that each represents length of foreground or background pixels in the +style. If FLAG_START_WITH_GAP is defined then the first segment in the style is +background, otherwise it is foreground. Renderer uses this array of segments +repeatedly during rendering operation. +|=== ++ +. Rendering command ++ +.. RedDrawBase ++ +Common field to all rendering command ++ +[cols="2*"] +|=== +|RECT bounding_box +|the affected area on the display area + +|Clip clip +|the effective clip to set before rendering a command +|=== ++ +.. RED_DISPLAY_COPY_BITS ++ +[source,c] +---- +RedDrawBase +POINT source_position +---- ++ +Copy bits from the draw area to bounding_box on the draw area. Source area left +top corner is source_position and its height and width is equal to bounding_box +height and width. Source and destination rectangles can overlap. ++ +.. RED_DISPLAY_DRAW_FILL ++ +[source,c] +---- +RedDrawBase +Brush brush +UINT16 rop_descriptor +Mask mask +---- ++ +Fill bounding_box using brush as the fill pattern and rop_descriptor +instructions. If the mask is valid, it will limit the modified area (i.e., only +pixels on the destination area that their corresponding bits are set will be +affected). ++ +.. RED_DISPLAY_DRAW_OPAQUE ++ +[source,c] +---- +RedDrawBase +ADDRESS source_image +RECT source_area +Brush brush +UINT16 rop_descriptor +UINT8 scale_mode +Mask mask +---- ++ +Combine pixels from source_area in source_image with the brush's pattern using +rop_descriptor instructions. The result image will be rendered into +bounding_box. In case scaling of source image is required it will be performed +according to scale_mode and before the combination with brush pixels. If mask +is valid it will limit the modified area. ++ +.. RED_DISPLAY_DRAW_COPY ++ +[source,c] +---- +RedDrawBase +ADDRESS source_image +RECT source_area +UINT16 rop_descriptor +UINT8 scale_mode +Mask mask +---- ++ +Copy pixels from source_area in source_image to bounding_box using +rop_descriptor instructions. In case scaling of source image is required it +will be performed according to scale_mode and before the copying to the draw +area. If mask is valid it will limit the modified area. ++ +.. RED_DISPLAY_DRAW_BLEND ++ +[source,c] +---- +RedDrawBase +ADDRESS source_image +RECT source_area +UINT16 rop_descriptor +UINT8 scale_mode +Mask mask +---- ++ +Mixing pixels from source_area in source_image with bounding_box pixels on the +draw area using rop_descriptor instructions. In case scaling of source image is +required it will be performed according to scale_mode and before the mixing +with the draw area. If mask is valid it will limit the modified area. ++ +.. RED_DISPLAY_DRAW_BLACKNESS ++ +[source,c] +---- +RedDrawBase +Mask mask +---- ++ +Fill bounding_box with black pixels. If mask is valid it will limit the +modified area. ++ +.. RED_DISPLAY_DRAW_WHITENESS ++ +[source,c] +---- +RedDrawBase +Mask mask +---- ++ +Fill bounding_box with white pixels. If mask is valid it will limit the +modified area. ++ +.. RED_DISPLAY_DRAW_INVERS ++ +[source,c] +---- +RedDrawBase +Mask mask +---- ++ +Inverse all pixels in bounding_box. If mask is valid it will limit the modified +area. ++ +.. RED_DISPLAY_DRAW_ROP3 ++ +[source,c] +---- +RedDrawBase +ADDRESS source_image +RECT source_area +Brush brush +UINT8 rop3 +UINT8 scale_mode +Mask mask +---- ++ +Mix pixels from source_area in source_image, bounding_box pixels in the draw +area, and the brush pattern. The method for mixing three pixels into the +destination area (i.e., bounding_box) is defined by rop3 (i.e., ternary raster +operations). In case scaling of source image is required it will be performed +according to scale_mode and before the mixing. If mask is valid it will limit +the modified area. ++ +.. RED_DISPLAY_DRAW_TRANSPARENT ++ +[source,c] +---- +RedDrawBase +ADDRESS source_image +RECT source_area +UINT32 transparent_color +UINT32 transparent _true_color +---- ++ +Copy pixels from source_area on source_image to bounding_box on the draw area. +In case scaling of source image is required it will use IMAGE_SCALE_NEAREST. +Pixels with value equal to the transparent color will be masked out. +Transparent color is provided in two forms: true color (i.e., RGB888) and the +color in the original format (i.e., before compression) . ++ +.. RED_DISPLAY_DRAW_ALPHA_BLEND ++ +[source,c] +---- +RedDrawBase +UINT8 alpha +ADDRESS source_image +RECT source_area +---- ++ +Alpha blend source_area of source_image on bounding_box of draw area using +alpha value or alternatively per pixel alpha value. In case scaling of source +image is required, it will use IMAGE_SCALE_INTERPOLATE mode. Alpha value is +defined as 0 is full transparency and 255 is full opacity. Format of source +image can be pre-multiplied ARGB8888 for per pixel alpha value. ++ +New RGB color is defined as: ++ +[source,c] +---- +color' = (source_color * alpha) / 255 +alpha' = (source_alpha * alpha) / 255 +new_color = color' + ((255 - alpha' ) * destination_color) / 255 +---- ++ +.. RED_DISPLAY_DRAW_STROKE ++ +[source,c] +---- +RedDrawBase +ADDRESS path – address of the PathSegList that defines the path to render +LineAttr attr +Bush brush +UINT16 fore_mode - foreground rop_descriptor +UINT16 back_mode – background rop_descriptor +---- ++ +Render path using brush line attribute and rop descriptors. If the line is +styled (i.e., LINE_ATTR_FLAG_STYLED is set in attr.falgs) then background +(i.e., inverse of the style) is drawn using back_mode and the foreground is +drawn using fore_mode. If the line is not styled, the entire path is rendered +using fore_mode. ++ +.. RED_DISPLAY_DRAW_TEXT ++ +[source,c] +---- +RedDrawBase +ADDRESS string – address of GlyphString +RECT back_area +Brush fore_brush +Brush back_brush +UINT16 fore_mode +UINT16 back_mode +---- ++ +Render string of glyph on the display area using brush fore_brush and the +rop_descriptor fore_mode. If back_area is not empty the renderer fill back_area +on the display area prior to rendering the glyph string. back_area is filled +using back_brush and the rop_descriptor back_mode. ++ +. Video streaming commands ++ +Spice supports the creation of video streams by the server for rendering video +content on the client display area. Unlike other rendering commands, the +stream data can be compressed using lossy or video specific compression +algorithms. It is not required to render video frames as they arrive and it is +also allowed to drop video frames. This enables using video frames buffering +for having smoother playback and audio synchronization. Audio synchronization +is achieved by using time stamp that is attached to audio and video streams. +By using video streaming the network traffic can be dramatically reduced. When +the stream is created, the server sends create message using +RED_DISPLAY_STREAM_CREATE. After the server creates a stream he can send data +using RED_DISPLAY_STREAM_DATA, or set new stream clipping by sending clip +message using RED_DISPLAY_STREAM_CLIP. Once the server no longer needs the +stream, he can send destroy command using RED_DISPLAY_STREAM_DESTROY. The +server can also destroy all active streams by sending destroy all message using +RED_DISPLAY_STREAM_DESTROY_ALL. ++ +.. Stream flags ++ +[source,c] +---- +STREAM_FLAG_TOP_DOWN = 1 /* stream frame line order is from top to bottom */ +---- ++ +.. Codec types ++ +[source,c] +---- +STREAM_CODEC_TYPE_MJPEG = 1 /* this stream uses motion JPEG codec */ +---- ++ +.. RED_DISPLAY_STREAM_CREATE, RedStreamCreate ++ +[cols="2*"] +|=== +|UINT32 id +|id of the new stream. It is the server's responsibility to manage stream ids + +|UINT32 flags +|flags of the stream, any combination of STREAM_FLAG_? + +|UINT32 codec_type +|type of codec used for this stream, one of STREAM_CODEC_TYPE_? + +|UINT64 reserved +|must be zero + +|UINT32 stream_width +|width of the source frame. + +|UINT32 stream_height +|height of the source frame + +|UINT32 source_width +|actual frame width to use, must be less or equal to stream_width. + +|UINT32 source_height +|actual frame height to use, must be less or equal to stream_height. + +|RECT destination +|area to render into on the client display area + +|Clip clip +|clipping of the stream +|=== ++ +.. RED_DISPLAY_STREAM_DATA, RedStreamData ++ +[cols="2*"] +|=== +|UINT32 id +|stream id (i.e., RedStreamCreate.id) + +|UINT32 multimedia_time +|frame time stamp + +|UINT32 data_size +|stream data size to consume in bytes + +|UINT32 pad_size +|additional data padding in bytes + +|UINT8[] data +|stream data depending on RedStreamCreate.codec_type. Size of data is ( +data_size + pad_size) +|=== ++ +.. RED_DISPLAY_STREAM_CLIP, RedStreamClip ++ +[cols="2*"] +|=== +|UINT32 id +|stream id (i.e., RedStreamCreate.id) +|=== ++ +Clip clip – new clipping of the stream ++ +.. RED_DISPLAY_STREAM_DESTROY, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|id of stream to destroy +|=== ++ +.. RED_DISPLAY_STREAM_DESTROY_ALL, VOID ++ +Destroy all active streams ++ +. Cache control ++ +.. Resource type ++ +[source,c] +---- +RED_RES_TYPE_IMAGE = 1 +---- ++ +.. RedResourceID ++ +[cols="2*"] +|=== +|UINT8 type +|type of the resource, one of RED_RES_TYPE_? + +|UINT64 id +|id of the resource +|=== ++ +.. RedResourceList ++ +[cols="2*"] +|=== +|UINT16 count +|number of items in resources + +|RedResourceID[] resources +|list of resources id +|=== ++ +.. RED_DISPLAY_INVAL_LIST, RedResourceList ++ +[cols="2*"] +|=== +|RedResourceList +|list of resources to remove from cache +|=== ++ +.. RED_DISPLAY_INVAL_ALL_IMAGES, RedWaitForChannels ++ +Remove all images from the image cache. The client must use RedWaitForChannels +(for more info see <>) to synchronize +with other channels before clearing the cache. ++ +.. RED_DISPLAY_INVAL_PALETTE, UINT64 ++ +[cols="2*"] +|=== +|UINT64 id of palette +|client needs to remove palette with that id from the cache +|=== ++ +.. RED_DISPLAY_INVAL_ALL_PALETTES, VOID ++ +Remove all palettes from palette cache + +== Cursor channel definition + +Spice protocol defines a set of messages for controlling cursor shape and +position on the remote display area, cursor position messages are irrelevant +for client mouse mode (see <>). Spice protocol also +defines a set of messages for managing cursor shape cache on the client site. +Client must strictly obey all such instructions. The server sends +RED_CURSOR_INIT to set current pointer state (i.e., shape, position, visibility +etc.) and to clear shape cache. After the server sends init message it can send +any other cursor command except for RED_CURSOR_INIT. The server can send +RED_CURSOR_RESET message - this will disable the cursor and reset the cursor +cache. After this message the only valid message the server can send is +RED_CURSOR_INIT. The relevant remote display area for a cursor channel is the +one of the display channel that has the same channel id (i.e., +RedLinkMess.channel_id). + +. Server messages ++ +[source,c] +---- +RED_CURSOR_INIT = 101 +RED_CURSOR_RESET = 102 +RED_CURSOR_SET = 103 +RED_CURSOR_MOVE = 104 +RED_CURSOR_HIDE = 105 +RED_CURSOR_TRAIL = 106 +RED_CURSOR_INVAL_ONE = 107 +RED_CURSOR_INVAL_ALL = 108 +---- ++ +.. Cursors types ++ +[source,c] +---- +CURSOR_TYPE_ALPHA = 0 +CURSOR_TYPE_MONO = 1 +CURSOR_TYPE_COLOR4 = 2 +CURSOR_TYPE_COLOR8 = 3 +CURSOR_TYPE_COLOR16 = 4 +CURSOR_TYPE_COLOR24 = 5 +CURSOR_TYPE_COLOR32 = 6 +---- ++ +.. CursorHeader ++ +[cols="2*"] +|=== +|UINT64 unique +|unique identifier of the corresponding cursor shape. It is used for storing +and retrieving cursors from the cursor cache. + +|UINT16 type +|type of the shape, one of CURSOR_TYPE_? + +|UINT16 width +|width of the shape + +|UINT16 height +|height of the shape + +|UINT16 hot_spot_x +|position of hot spot on x axis + +|UINT16 hot_spot_y +|position of hot spot on y axis +|=== ++ +.. Cursor flags ++ +[source,c] +---- +CURSOR_FLAGS_NONE = 1 +---- ++ +set when RedCursor (see below) is invalid ++ +[source,c] +---- +CURSOR_CURSOR_FLAGS _CACHE_ME = 2 +---- ++ +set when the client should add this shape to the shapes cache. The client will +use CursorHeader.unique as cache key. ++ +[source,c] +---- +CURSOR_FLAGS_FROM_CACHE = 4 +---- ++ +set when the client should retrieve the cursor shape, using CursorHeader.unique +as key, from the shapes cache. In this case all fields of CursorHeader except +for 'unique' are invalid. ++ +.. RedCursor ++ +[cols="2*"] +|=== +|UINT32 flags +|any valid combination of RED_CURSOR_? + +|CursorHeader header +| + +|UINT8[] data +|actual cursor shape data, the size is determine by width, height and type from +CursorHeader. Next we will describe in detail the shape data format according +to cursor type: + +|ALPHA, alpha shape +|data contains pre-multiplied ARGB8888 pixmap. Line stride is . + +|MONO, monochrome shape +|data contains two bitmaps with size * . The first bitmap is +AND mask and the second is XOR mask. Line stride is ALIGN(, 8) / 8. +Bits order within every byte is big endian. + +|COLOR4, 4 bits per pixel shape +|First data region is pixmap: the stride of the pixmap is ALIGN(width , 2) / 2; +every nibble is translated to a color usingthe color palette; Nibble order is +big endian. Second data region contain 16 colors palette: each entry is 32 bit +RGB color. Third region is a bitmap mask: line stride is ALIGN(, 8) / +8; bits order within every byte is big endian. + +|COLOR4, 8 bits per pixel shape +|First data region is pixmap: the stride of the pixmap is ; every byte +is translated to color using the color palette. Second data region contain 256 +colors palette: each entry is 32 bit RGB color. Third region is a bitmap mask: +line stride is ALIGN(, 8) / 8; bits order within every byte is big +endian. + +|COLOR16, 16 bits per pixel shape +|First data region is pixmap: the stride of the pixmap is ; every +UINT16 is RGB_555. Second region is a bitmap mask: line stride is +ALIGN(, 8) / 8; bits order within every byte is big endian. + +|COLOR24, 24 bits per pixel shape +|First data region is pixmap: the stride of the pixmap is ; every +UINT8[3] is RGB_888. Second region is a bitmap mask: line stride is +ALIGN(, 8) / 8; bits order within every byte is big endian. + +|COLOR32, 32 bits per pixel shape +|First data region is pixmap: the stride of the pixmap is ,;every +UINT32 is RGB_888. Second region is a bitmap mask: line stride is +ALIGN(, 8) / 8; bits order within every byte is big endian. +|=== ++ +For more deatails on drawing the cursor shape see <> ++ +.. RED_CURSOR_INIT, RedCursorInit ++ +[cols="2*"] +|=== +|POINT16 position +|position of mouse pointer on the relevant display area. Not relevant in +client mode. + +|UINT16 trail_length +|number of cursors in the trail excluding main cursor. + +|UINT16 trail_frequency +|millisecond interval between trail updates. + +|UIN8 visible +|if 1, the cursor is visible. If 0, the cursor is invisible. + +|RedCursor cursor +|current cursor shape +|=== ++ +.. RED_CURSOR_RESET, VOID ++ +.. RED_CURSOR_SET, RedCursorSet ++ +[cols="2*"] +|=== +|POINT16 position +|position of mouse pointer on the relevant display area. not relevant in client +mode. + +|UINT8 visible +|if 1, the cursor is visible. If 0, the cursor is invisible. + +|RedCursor cursor +|current cursor shape +|=== ++ +.. RED_CURSOR_MOVE, POINT16 ++ +[cols="2*"] +|=== +|POINT16 +|new mouse position. Not relevant in client mode. This message also implicitly +sets cursor visibility to 1. +|=== ++ +.. RED_CURSOR_HIDE, VOID ++ +Hide pointer on the relevant display area. ++ +.. RED_CURSOR_TRAIL ++ +[cols="2*"] +|=== +|UINT16 length +|number of cursors in the trail excluding main cursor. + +|UINT16 frequency +|millisecond interval between trail updates +|=== ++ +.. RED_CURSOR_INVAL_ONE, UINT64 ++ +[cols="2*"] +|=== +|UINT64 +|id of cursor shape to remove from the cursor cache +|=== ++ +.. RED_CURSOR_INVAL_ALL, VOLD ++ +Clear cursor cache ++ +[[cursor_shape]] +. Drawing the cursor shape according to the cursor type ++ +This section is relevant only for server mouse mode. Cursor shape positioning +on the display area is done by placing cursor hot spot on the current cursor +position. ++ +.. Alpha - no spacial handling, just bland the shape on the display area. ++ +.. Monochrome ++ +For each cleared bit in the AND mask clear the corresponding bits in the +relevant pixel on the display area +For each set bit in the XOR mask reverse the +corresponding bits in the relevant pixel on the display area ++ +.. Color ++ +If the source color is black and mask bit is set, NOP. +Else, if the source color is white and the mask bit is set, reverse all bits in +the relevant pixel on the display area. +Else, put source color. + +== Playback channel definition + +Spice supports sending audio streams for playback on the client side. An audio +stream is sent by the server in an audio packet using RED_PLAYBACK_DATA +message. The content of the audio packet is controlled by the playback mode +that the server sends using RED_PLAYBACK_MODE message. The server can start and +stop the stream using RED_PLAYBACK_START and RED_PLAYBACK_STOP messages. +Sending audio packet is allowed only between start and stop messages. Sending +start message is allowed only in stop state and after at least one mode message +was sent. Sending a stop message is allowed only during a start state. + +. Server messages ++ +[source,c] +---- +RED_PLAYBACK_DATA = 101 +RED_PLAYBACK_MODE = 102 +RED_PLAYBACK_START = 103 +RED_PLAYBACK_STOP = 104 +---- ++ +. Audio format ++ +[source,c] +---- +RED_PLAYBACK_FMT_S16 = 1 /* each channel sample is a 16 bit +signed integer */ +---- ++ +. Playback data mode ++ +Two types of data mode are available: (1) raw PCM data and (2) compressed data +in CELT 0_5_1 format. ++ +[source,c] +---- +RED_PLAYBACK_DATA_MODE_RAW = 1 +RED_PLAYBACK_DATA_MODE_CELT_0_5_1 = 2 +---- ++ +. Playback channel capabilities ++ +[source,c] +---- +RED_PLAYBACK_CAP_CELT_0_5_1 = 0 +---- ++ +Spice client needs to declare support of CELT_5_1 in channel capabilities in +order to allow the server to send playback packets in CELT_0_5_1 format. ++ +. RED_PLAYBACK_MODE, RedPlaybackMode ++ +[cols="2*"] +|=== +|UINT32 time +|server time stamp + +|UINT32 mode +|one of RED_PLAYBACK_DATA_MODE_? + +|UINT8[] data +|specific data, content depend on mode +|=== ++ +. RED_PLAYBACK_START, RedRecordStart ++ +[cols="2*"] +|=== +|UINT32 channels +|number of audio channels + +|UINT32 format +|one of RED_PLAYBACK_FMT_? + +|UINT32 frequency +|channel samples per second +|=== ++ +. RED_PLAYBACK_DATA, RedPlaybackPacket ++ +[cols="2*"] +|=== +|UINT32 time +|server time stamp + +|UINT8[] data +|playback data , content depend on mode +|=== ++ +. RED_PLAYBACK_STOP, VOID ++ +Stop current audio playback + +== Record Channel definition + +Spice supports transmitting of audio captured streams from the client to the +server. Spice server starts audio capturing using RED_RECORD_START message. +This message instructs the client to start transmitting captured audio . In +response, the client sends time stamp of the stream start using +REDC_RECORD_START_MARK. After the client sends start mark it can start +transmitting audio stream data using REDC_RECORD_DATA. One mode message must be +sent by the client before any other message using REDC_RECORD_MODE. This, in +order to inform the server on what type of data will be transferred. Mode +message can also be transmitted at any other time in order to switch the data +type delivered by REDC_RECORD_DATA. The Server can send RED_RECORD_STOP for +stopping captured audio streaming. Sending a start message is allowed only +while the stream is in stop state. Sending a stop message and data messages is +allowed only while the stream is in start state. Sending mark message is +allowed only between start message and the first data message. + +. Server messages ++ +[source,c] +---- +RED_RECORD_START = 101 +RED_RECORD_STOP = 102 +---- ++ +. Client messages ++ +[source,c] +---- +REDC_RECORD_DATA = 101 +REDC_RECORD_MODE = 102 +REDC_RECORD_START_MARK = 103 +---- ++ +. Audio format ++ +[source,c] +---- +RED_RECORD_FMT_S16 = 1 /* each channel sample is a 16 bit +signed integer */ +---- ++ +. Record data mode ++ +Two types of data mode are available: (1) raw PCM data (2) compressed data in +CELT 0.5.1 format. ++ +[source,c] +---- +RED_RECORD_DATA_MODE_RAW = 1 +RED_RECORD_DATA_MODE_CELT_0_5_1 = 2 +---- ++ +. Record channel capabilities ++ +[source,c] +---- +RED_PLAYBACK_CAP_CELT_0_5_1 = 0 +---- ++ +Spice server needs to declare support of CELT_5_1 in channel capabilities in +order to allow the client to send recorded packets in CELT_0_5_1 format. ++ +. REDC_RECORD_MODE, RedcRecordMode ++ +[cols="2*"] +|=== +|UINT32 time +|client time stamp + +|UINT32 mode +|one of RED_RECORD_DATA_MODE_? + +|UINT8[] data +|specific data, content depend on mode +|=== ++ +. RED_RECORD_START, RedRecordStart ++ +[cols="2*"] +|=== +|UINT32 channel +|number of audio channels + +|UINT32 format +|one of RED_AUDIO_FMT_? + +|UINT32 frequency +|channel samples per second +|=== ++ +. REDC_RECORD_START_MARK, UINT32 ++ +[cols="2*"] +|=== +|UINT32 +|client time stamp of stream start +|=== ++ +. REDC_RECORD_DATA, RedcRecordPacket ++ +[cols="2*"] +|=== +|UINT32 time +|client time stamp + +|UINT8[] data +|recorded data , content depend on mode +|=== ++ +. RED_RECORD_STOP, VOID ++ +Stop current audio capture