1/* built in types:
2   int8, uint8, 16, 32, 64
3*/
4
5typedef fixed28_4 int32 @ctype(SPICE_FIXED28_4);
6
7/* IDs of the video stream messages.
8 * These IDs are in the interval [0, SPICE_MAX_NUM_STREAMS)
9 */
10typedef stream_id_t uint32;
11
12struct Point {
13    int32 x;
14    int32 y;
15};
16
17struct Point16 {
18    int16 x;
19    int16 y;
20};
21
22struct PointFix {
23    fixed28_4 x;
24    fixed28_4 y;
25};
26
27struct Rect {
28    int32 top;
29    int32 left;
30    int32 bottom;
31    int32 right;
32};
33
34struct Transform {
35    uint32 t00;
36    uint32 t01;
37    uint32 t02;
38    uint32 t10;
39    uint32 t11;
40    uint32 t12;
41};
42
43enum32 link_err {
44    OK,
45    ERROR,
46    INVALID_MAGIC,
47    INVALID_DATA,
48    VERSION_MISMATCH,
49    NEED_SECURED,
50    NEED_UNSECURED,
51    PERMISSION_DENIED,
52    BAD_CONNECTION_ID,
53    CHANNEL_NOT_AVAILABLE
54};
55
56enum32 warn_code {
57    WARN_GENERAL
58} @prefix(SPICE_);
59
60enum32 info_code {
61    INFO_GENERAL
62} @prefix(SPICE_);
63
64flags32 migrate_flags {
65    NEED_FLUSH,
66    NEED_DATA_TRANSFER
67} @prefix(SPICE_MIGRATE_);
68
69flags32 composite_flags {
70    OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7,
71    SRC_FILTER0, SRC_FILTER1, SRC_FILTER2,
72    MASK_FILTER0, MASK_FITLER1, MASK_FILTER2,
73
74    SRC_REPEAT0, SRC_REPEAT1,
75    MASK_REPEAT0, MASK_REPEAT1,
76    COMPONENT_ALPHA,
77
78    HAS_MASK,
79    HAS_SRC_TRANSFORM,
80    HAS_MASK_TRANSFORM,
81
82    /* These are used to override the formats given in the images. For
83     * example, if the mask image has format a8r8g8b8, but MASK_OPAQUE
84     * is set, the image should be treated as if it were x8r8g8b8
85     */
86    SOURCE_OPAQUE,
87    MASK_OPAQUE,
88    DEST_OPAQUE,
89} @prefix(SPICE_COMPOSITE_);
90
91enum32 notify_severity {
92    INFO,
93    WARN,
94    ERROR,
95};
96
97enum32 notify_visibility {
98    LOW,
99    MEDIUM,
100    HIGH,
101};
102
103flags16 mouse_mode {
104    SERVER,
105    CLIENT,
106};
107
108message Empty {
109} @declare;
110
111message Data {
112    uint8 data[] @end;
113} @nocopy @declare;
114
115enum8 data_compression_type {
116    NONE,
117    LZ4,
118};
119
120struct EmptyStructure {
121};
122
123message CompressedData {
124    data_compression_type type;
125    switch (type) {
126    /* we cannot use !NONE (works only with flags) */
127    case NONE:
128        /* due to the way cases are defined after NONE we must have something */
129        /* due to a bug we cannot use @virtual to write 0 to compressed_size */
130        EmptyStructure empty;
131    default:
132        uint32 uncompressed_size;
133    } u @anon;
134    uint8 compressed_data[] @as_ptr(compressed_size);
135} @ctype(SpiceMsgCompressedData);
136
137struct ChannelWait {
138    uint8 channel_type;
139    uint8 channel_id;
140    uint64 message_serial;
141} @ctype(SpiceWaitForChannel) @declare;
142
143channel BaseChannel {
144 server:
145    message {
146        migrate_flags flags;
147    } @declare migrate;
148
149    Data migrate_data;
150
151    message {
152        uint32 generation;
153        uint32 window;
154    } @declare set_ack;
155
156    message {
157        uint32 id;
158        uint64 timestamp;
159        uint8 data[] @as_ptr(data_len);
160    } @declare ping;
161
162    message {
163        uint8 wait_count;
164        ChannelWait wait_list[wait_count] @end;
165    } @declare wait_for_channels;
166
167    message {
168        uint64 time_stamp;
169        link_err reason;
170    } @ctype(SpiceMsgDisconnect) @declare disconnecting;
171
172    message {
173        uint64 time_stamp;
174        notify_severity severity;
175        notify_visibility visibilty;
176        uint32 what; /* error_code/warn_code/info_code */
177        uint32 message_len;
178        uint8 message[message_len] @end @nomarshal;
179    } @declare notify;
180
181    Data list; /* the msg body is SpiceSubMessageList */
182
183    Empty base_last = 100;
184
185 client:
186    message {
187        uint32 generation;
188    } @declare ack_sync;
189
190    Empty ack;
191
192    message {
193        uint32 id;
194        uint64 timestamp;
195    } @ctype(SpiceMsgPing) pong;
196
197    Empty migrate_flush_mark;
198
199    Data migrate_data;
200
201    message {
202        uint64 time_stamp;
203        link_err reason;
204    } @ctype(SpiceMsgDisconnect) disconnecting;
205};
206
207struct ChannelId {
208    uint8 type;
209    uint8 id;
210} @declare;
211
212struct DstInfo {
213    uint16 port;
214    uint16 sport;
215    uint32 host_size;
216    uint8 *host_data[host_size] @zero_terminated @marshall @nonnull;
217    uint32 cert_subject_size;
218    uint8 *cert_subject_data[cert_subject_size] @zero_terminated @marshall;
219} @ctype(SpiceMigrationDstInfo) @declare;
220
221channel MainChannel : BaseChannel {
222 server:
223    message {
224        DstInfo dst_info;
225    } @ctype(SpiceMsgMainMigrationBegin) @declare migrate_begin = 101;
226
227    Empty migrate_cancel;
228
229    message {
230        uint32 session_id;
231        uint32 display_channels_hint;
232        uint32 supported_mouse_modes;
233        uint32 current_mouse_mode;
234        uint32 agent_connected;
235        uint32 agent_tokens;
236        uint32 multi_media_time;
237        uint32 ram_hint;
238    } @declare init;
239
240    message {
241        uint32 num_of_channels;
242        ChannelId channels[num_of_channels] @end;
243    } @ctype(SpiceMsgChannels) @declare channels_list;
244
245    message {
246        mouse_mode supported_modes;
247        mouse_mode current_mode @unique_flag;
248    } @declare mouse_mode;
249
250    message {
251        uint32 time;
252    } @ctype(SpiceMsgMainMultiMediaTime) @declare multi_media_time;
253
254    Empty agent_connected;
255
256    message {
257        link_err error_code;
258    } @ctype(SpiceMsgMainAgentDisconnect) @declare agent_disconnected;
259
260    Data agent_data;
261
262    message {
263        uint32 num_tokens;
264    } @ctype(SpiceMsgMainAgentTokens) @declare agent_token;
265
266    message {
267        uint16 port;
268        uint16 sport;
269        uint32 host_size;
270        uint8 *host_data[host_size] @zero_terminated @marshall;
271        uint32 cert_subject_size;
272        uint8 *cert_subject_data[cert_subject_size] @zero_terminated  @marshall;
273    } @ctype(SpiceMsgMainMigrationSwitchHost) @declare migrate_switch_host;
274
275    Empty migrate_end;
276
277    message {
278       uint32 name_len;
279       uint8 name[name_len] @end;
280    } @declare name;
281
282    message {
283       uint8 uuid[16];
284    } @declare uuid;
285
286    message {
287        uint32 num_tokens;
288    } @declare agent_connected_tokens;
289
290    message {
291        DstInfo dst_info;
292        uint32 src_mig_version;
293    } @declare migrate_begin_seamless;
294
295    Empty migrate_dst_seamless_ack;
296    Empty migrate_dst_seamless_nack;
297
298 client:
299    message {
300        uint64 cache_size;
301    } @ctype(SpiceMsgcClientInfo) @declare client_info = 101;
302
303    Empty migrate_connected;
304
305    Empty migrate_connect_error;
306
307    Empty attach_channels;
308
309    message {
310        mouse_mode mode;
311    } @declare mouse_mode_request;
312
313    message {
314        uint32 num_tokens;
315    } @ctype(SpiceMsgMainAgentTokens) @declare agent_start;
316
317    Data agent_data;
318
319    message {
320        uint32 num_tokens;
321    } @ctype(SpiceMsgMainAgentTokens) @declare agent_token;
322
323    Empty migrate_end;
324
325    message {
326        uint32 src_version;
327    } @declare migrate_dst_do_seamless;
328
329    Empty migrate_connected_seamless;
330
331    Data quality_indicator;
332};
333
334enum8 clip_type {
335    NONE,
336    RECTS
337};
338
339flags8 path_flags { /* TODO: C enum names changes */
340    BEGIN = 0,
341    END = 1,
342    CLOSE = 3,
343    BEZIER = 4,
344} @prefix(SPICE_PATH_);
345
346enum8 video_codec_type {
347    MJPEG = 1,
348    VP8,
349    H264,
350    VP9,
351    H265,
352};
353
354flags8 stream_flags {
355    TOP_DOWN = 0,
356};
357
358enum8 brush_type {
359    NONE,
360    SOLID,
361    PATTERN,
362};
363
364flags8 mask_flags {
365    INVERS,
366};
367
368enum8 image_type {
369    BITMAP,
370    QUIC,
371    RESERVED,
372    LZ_PLT = 100,
373    LZ_RGB,
374    GLZ_RGB,
375    FROM_CACHE,
376    SURFACE,
377    JPEG,
378    FROM_CACHE_LOSSLESS,
379    ZLIB_GLZ_RGB,
380    JPEG_ALPHA,
381    LZ4,
382};
383
384enum8 image_compression {
385    INVALID  = 0,
386    OFF,
387    AUTO_GLZ,
388    AUTO_LZ,
389    QUIC,
390    GLZ,
391    LZ,
392    LZ4,
393};
394
395flags8 image_flags {
396    CACHE_ME,
397    HIGH_BITS_SET,
398    CACHE_REPLACE_ME,
399};
400
401enum8 bitmap_fmt {
402    INVALID,
403    1BIT_LE,
404    1BIT_BE,
405    4BIT_LE,
406    4BIT_BE,
407    8BIT /* 8bit indexed mode */,
408    16BIT, /* 0555 mode */
409    24BIT /* 3 byte, brg */,
410    32BIT /* 4 byte, xrgb in little endian format */,
411    RGBA /* 4 byte, argb in little endian format */,
412    8BIT_A /* 1 byte, alpha */
413};
414
415flags8 bitmap_flags {
416    PAL_CACHE_ME,
417    PAL_FROM_CACHE,
418    TOP_DOWN,
419};
420
421flags8 jpeg_alpha_flags {
422    TOP_DOWN,
423};
424
425enum8 image_scale_mode {
426    INTERPOLATE,
427    NEAREST,
428};
429
430flags16 ropd {
431    INVERS_SRC,
432    INVERS_BRUSH,
433    INVERS_DEST,
434    OP_PUT,
435    OP_OR,
436    OP_AND,
437    OP_XOR,
438    OP_BLACKNESS,
439    OP_WHITENESS,
440    OP_INVERS,
441    INVERS_RES,
442};
443
444/* This *must* remain with values identical to api/winddi.h
445   LA_STYLED == 0x8 (log_2)=> 3
446   LA_STARTGAP == 0x4 (log_2)=> 2
447   This is used by the windows driver.
448 */
449flags8 line_flags {
450    STYLED = 3,
451    START_WITH_GAP = 2,
452};
453
454flags8 string_flags {
455    RASTER_A1,
456    RASTER_A4,
457    RASTER_A8,
458    RASTER_TOP_DOWN,
459};
460
461flags32 surface_flags {
462    /* Adding flags requires some caps check, since old clients only
463       treat the value as an enum and not as a flag (flag == PRIMARY).
464       Considering this was fixed by commit
465       5b6e3d1c16457c926322ce28d341af2e8d39efb5 in Aug 21 2013 is safe
466       to assume that if capabilities include SPICE_DISPLAY_CAP_MULTI_CODEC
467       we can use any flags */
468    PRIMARY,
469    /* The surface will be streamed entirely. This means that only
470       stream commands will be received and the stream will cover the
471       entire surface. This flag can be safely ignored and is intended
472       as an hint for the client */
473    STREAMING_MODE,
474};
475
476enum32 surface_fmt {
477    INVALID,
478    1_A     = 1,
479    8_A     = 8,
480    16_555  = 16 ,
481    16_565  = 80,
482    32_xRGB = 32,
483    32_ARGB = 96
484};
485
486flags8 alpha_flags {
487    DEST_HAS_ALPHA,
488    SRC_SURFACE_HAS_ALPHA
489};
490
491enum8 resource_type {
492    INVALID,
493    PIXMAP
494} @prefix(SPICE_RES_TYPE_);
495
496struct ClipRects {
497    uint32 num_rects;
498    Rect rects[num_rects] @end;
499};
500
501struct PathSegment {
502    path_flags flags;
503    uint32 count;
504    PointFix points[count] @end;
505}  @ctype(SpicePathSeg);
506
507struct Path {
508    uint32 num_segments;
509    PathSegment segments[num_segments] @ptr_array;
510};
511
512struct Clip {
513    clip_type type;
514    switch (type) {
515    case RECTS:
516        ClipRects rects @outvar(cliprects) @to_ptr;
517    } u @anon;
518};
519
520struct DisplayBase {
521    uint32 surface_id;
522    Rect box;
523    Clip clip;
524} @ctype(SpiceMsgDisplayBase) @declare;
525
526struct ResourceID {
527    uint8 type;  /* resource_type */
528    uint64 id;
529} @declare;
530
531struct WaitForChannel {
532    uint8 channel_type;
533    uint8 channel_id;
534    uint64 message_serial;
535} @declare;
536
537struct Palette {
538    uint64 unique;
539    uint16 num_ents;
540    uint32 ents[num_ents] @end;
541};
542
543struct BitmapData {
544    bitmap_fmt format;
545    bitmap_flags flags;
546    uint32 x;
547    uint32 y;
548    uint32 stride;
549    switch (flags) {
550    case PAL_FROM_CACHE:
551        uint64 palette_id;
552    default:
553        Palette *palette @outvar(bitmap);
554    } pal @anon;
555    uint8 data[image_size(8, stride, y)] @chunk @nomarshal;
556} @ctype(SpiceBitmap);
557
558struct BinaryData {
559    uint32 data_size;
560    uint8 data[data_size] @nomarshal @chunk;
561} @ctype(SpiceQUICData);
562
563struct LZPLTData {
564    bitmap_flags flags;
565    uint32 data_size;
566    switch (flags) {
567    case PAL_FROM_CACHE:
568        uint64 palette_id;
569    default:
570        Palette *palette @nonnull @outvar(lzplt);
571    } pal @anon;
572    uint8 data[data_size] @nomarshal @chunk;
573};
574
575struct ZlibGlzRGBData {
576    uint32 glz_data_size;
577    uint32 data_size;
578    uint8 data[data_size] @nomarshal @chunk;
579} @ctype(SpiceZlibGlzRGBData);
580
581struct JPEGAlphaData {
582    jpeg_alpha_flags flags;
583    uint32 jpeg_size;
584    uint32 data_size;
585    uint8 data[data_size] @nomarshal @chunk;
586} @ctype(SpiceJPEGAlphaData);
587
588struct Surface {
589    uint32 surface_id;
590};
591
592
593struct Image {
594    struct ImageDescriptor {
595        uint64 id;
596        image_type type;
597        image_flags flags;
598        uint32 width;
599        uint32 height;
600    } descriptor;
601
602    switch (descriptor.type) {
603    case BITMAP:
604        BitmapData bitmap;
605    case QUIC:
606        BinaryData quic;
607    case LZ_RGB:
608    case GLZ_RGB:
609        BinaryData lz_rgb;
610    case JPEG:
611        BinaryData jpeg;
612    case LZ4:
613        BinaryData lz4;
614    case LZ_PLT:
615        LZPLTData lz_plt;
616    case ZLIB_GLZ_RGB:
617        ZlibGlzRGBData zlib_glz;
618    case JPEG_ALPHA:
619        JPEGAlphaData jpeg_alpha;
620    case SURFACE:
621        Surface surface;
622    } u;
623};
624
625struct Pattern {
626    Image *pat @nonnull;
627    Point pos;
628};
629
630struct Brush {
631    brush_type type;
632    switch (type) {
633    case SOLID:
634        uint32 color;
635    case PATTERN:
636        Pattern pattern;
637    } u;
638};
639
640struct QMask {
641    mask_flags flags;
642    Point pos;
643    Image *bitmap;
644};
645
646struct LineAttr {
647    line_flags flags;
648    switch (flags) {
649    case STYLED:
650        uint8 style_nseg;
651   } u1 @anon;
652   switch (flags) {
653   case STYLED:
654        fixed28_4 *style[style_nseg];
655   } u2 @anon;
656};
657
658struct RasterGlyphA1 {
659    Point render_pos;
660    Point glyph_origin;
661    uint16 width;
662    uint16 height;
663    uint8 data[image_size(1, width, height)] @end;
664} @ctype(SpiceRasterGlyph);
665
666struct RasterGlyphA4 {
667    Point render_pos;
668    Point glyph_origin;
669    uint16 width;
670    uint16 height;
671    uint8 data[image_size(4, width, height)] @end;
672} @ctype(SpiceRasterGlyph);
673
674struct RasterGlyphA8 {
675    Point render_pos;
676    Point glyph_origin;
677    uint16 width;
678    uint16 height;
679    uint8 data[image_size(8, width, height)] @end;
680} @ctype(SpiceRasterGlyph);
681
682struct String {
683    uint16 length;
684    string_flags flags; /* Special: Only one of a1/a4/a8 set */
685    switch (flags) {
686    case RASTER_A1:
687        RasterGlyphA1 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array;
688    case RASTER_A4:
689        RasterGlyphA4 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array;
690    case RASTER_A8:
691        RasterGlyphA8 glyphs[length] @ctype(SpiceRasterGlyph) @ptr_array;
692    } u @anon;
693};
694
695struct StreamDataHeader {
696    stream_id_t id;
697    uint32 multi_media_time;
698} @declare;
699
700struct Head {
701    uint32 monitor_id;
702    uint32 surface_id;
703    uint32 width;
704    uint32 height;
705    uint32 x;
706    uint32 y;
707    uint32 flags;
708} @declare;
709
710flags32 gl_scanout_flags {
711    Y0TOP
712};
713
714channel DisplayChannel : BaseChannel {
715 server:
716    message {
717        uint32 x_res;
718        uint32 y_res;
719        uint32 bits;
720    } @declare mode = 101;
721
722    Empty mark;
723    Empty reset;
724    message {
725        DisplayBase base;
726        Point src_pos;
727    } @declare copy_bits;
728
729    message {
730        uint16 count;
731        ResourceID resources[count] @end;
732    } @ctype(SpiceResourceList) @declare inval_list;
733
734    /* This message is used to invalidate the complete image cache
735     * on the client.
736     * Due to synchronization for GLZ images we must make sure
737     * that messages related to cached images on other channels
738     * are processed so we send a list of channels with respective
739     * message serials to wait for.
740     */
741    message {
742        uint8 wait_count;
743        WaitForChannel wait_list[wait_count] @end;
744    } @ctype(SpiceMsgWaitForChannels) @declare inval_all_pixmaps;
745
746    message {
747        uint64 id;
748    } @ctype(SpiceMsgDisplayInvalOne) @declare inval_palette;
749
750    Empty inval_all_palettes;
751
752    message {
753        uint32 surface_id;
754        stream_id_t id;
755        stream_flags flags;
756        video_codec_type codec_type;
757        uint64 stamp;
758        uint32 stream_width;
759        uint32 stream_height;
760        uint32 src_width;
761        uint32 src_height;
762        Rect dest;
763        Clip clip;
764    } @declare stream_create = 122;
765
766    message {
767        StreamDataHeader base;
768        uint32 data_size;
769        uint8 data[data_size] @end @nomarshal;
770    } @declare stream_data;
771
772    message {
773        stream_id_t id;
774        Clip clip;
775    } @declare stream_clip;
776
777    message {
778        stream_id_t id;
779    } @declare stream_destroy;
780
781    Empty stream_destroy_all;
782
783    message {
784        DisplayBase base;
785        struct Fill {
786            Brush brush @outvar(brush);
787            ropd rop_descriptor;
788            QMask mask @outvar(mask);
789        } data;
790    } @declare draw_fill = 302;
791
792    message {
793        DisplayBase base;
794        struct Opaque {
795            Image *src_bitmap;
796            Rect src_area;
797            Brush brush;
798            ropd rop_descriptor;
799            image_scale_mode scale_mode;
800            QMask mask @outvar(mask);
801        } data;
802    } @declare draw_opaque;
803
804    message {
805        DisplayBase base;
806        struct Copy {
807            Image *src_bitmap;
808            Rect src_area;
809            ropd rop_descriptor;
810            image_scale_mode scale_mode;
811            QMask mask @outvar(mask);
812        } data;
813    } @declare draw_copy;
814
815    message {
816        DisplayBase base;
817        struct Blend {
818            Image *src_bitmap;
819            Rect src_area;
820            ropd rop_descriptor;
821            image_scale_mode scale_mode;
822            QMask mask @outvar(mask);
823        } @ctype(SpiceCopy) data;
824    } @ctype(SpiceMsgDisplayDrawCopy) draw_blend;
825
826    message {
827        DisplayBase base;
828        struct Blackness {
829            QMask mask @outvar(mask);
830        } data;
831    } @declare draw_blackness;
832
833    message {
834        DisplayBase base;
835        struct Whiteness {
836            QMask mask @outvar(mask);
837        } data;
838    } @declare draw_whiteness;
839
840    message {
841        DisplayBase base;
842        struct Invers {
843            QMask mask @outvar(mask);
844        } data;
845    } @declare draw_invers;
846
847    message {
848        DisplayBase base;
849        struct Rop3 {
850            Image *src_bitmap;
851            Rect src_area;
852            Brush brush;
853            uint8 rop3;
854            image_scale_mode scale_mode;
855            QMask mask @outvar(mask);
856        } data;
857    } @declare draw_rop3;
858
859    message {
860        DisplayBase base;
861        struct Stroke {
862            Path *path @marshall @nonnull;
863            LineAttr attr;
864            Brush brush;
865            uint16 fore_mode;
866            uint16 back_mode;
867        } data;
868    } @declare draw_stroke;
869
870    message {
871        DisplayBase base;
872        struct Text {
873            String *str @marshall @nonnull;
874            Rect back_area;
875            Brush fore_brush @outvar(fore_brush);
876            Brush back_brush @outvar(back_brush);
877            uint16 fore_mode;
878            uint16 back_mode;
879        } data;
880    } @declare draw_text;
881
882    message {
883        DisplayBase base;
884        struct Transparent {
885            Image *src_bitmap;
886            Rect src_area;
887            uint32 src_color;
888            uint32 true_color;
889        } data;
890    } @declare draw_transparent;
891
892    message {
893        DisplayBase base;
894        struct AlphaBlend {
895            alpha_flags alpha_flags;
896            uint8 alpha;
897            Image *src_bitmap;
898            Rect src_area;
899        } data;
900    } @declare draw_alpha_blend;
901
902    message {
903        uint32 surface_id;
904        uint32 width;
905        uint32 height;
906        surface_fmt format;
907        surface_flags flags;
908    } @ctype(SpiceMsgSurfaceCreate) @declare surface_create;
909
910    message {
911        uint32 surface_id;
912    } @ctype(SpiceMsgSurfaceDestroy) @declare surface_destroy;
913
914    message {
915        StreamDataHeader base;
916        uint32 width;
917        uint32 height;
918        Rect dest;
919        uint32 data_size;
920        uint8 data[data_size] @end @nomarshal;
921    } @declare stream_data_sized;
922
923    message {
924        uint16 count;
925        uint16 max_allowed;
926        Head heads[count] @end;
927    } @declare monitors_config;
928
929    message {
930        DisplayBase base;
931        struct Composite {
932            composite_flags flags;
933            Image *src_bitmap;
934            switch (flags) {
935            case HAS_MASK:
936                Image *mask_bitmap;
937            } a @anon;
938            switch (flags) {
939            case HAS_SRC_TRANSFORM:
940                Transform src_transform;
941            } b @anon;
942            switch (flags) {
943            case HAS_MASK_TRANSFORM:
944                Transform mask_transform;
945            } c @anon;
946            Point16 src_origin;
947            Point16 mask_origin;
948        } data;
949    } @declare draw_composite;
950
951    message {
952        stream_id_t stream_id;
953        uint32 unique_id;
954        uint32 max_window_size;
955        uint32 timeout_ms;
956    } @declare stream_activate_report;
957
958    message {
959        unix_fd drm_dma_buf_fd;
960        uint32 width;
961        uint32 height;
962        uint32 stride;
963        /* specifies the format of drm_dma_buf_fd defined in drm_fourcc.h */
964        uint32 drm_fourcc_format;
965        gl_scanout_flags flags;
966    } @declare gl_scanout_unix;
967
968    message {
969        uint32 x;
970        uint32 y;
971        uint32 w;
972        uint32 h;
973    } @declare gl_draw;
974
975    Data quality_indicator;
976 client:
977    message {
978        uint8 pixmap_cache_id;
979        int64 pixmap_cache_size; //in pixels
980        uint8 glz_dictionary_id;
981        int32 glz_dictionary_window_size;  // in pixels
982    } @declare init = 101;
983
984    message {
985        stream_id_t stream_id;
986        uint32 unique_id;
987        // the mm_time of the first frame included in the report
988        uint32 start_frame_mm_time;
989        // the mm_time of the last frame included in the report
990        uint32 end_frame_mm_time;
991        // the number of frames that reached the client during the time the
992        // report is referring to
993        // A special case is when num_frames == 0 and num_drops ==
994        // 0xffffffffu, this is used in the client to communicate that
995        // the stream is not supported or that the client was not able
996        // to decode it
997        uint32 num_frames;
998        // the part of the above frames that were dropped by the client due
999        // to late arrival time
1000        uint32 num_drops;
1001        // end_frame_mm_time - client_mm_time
1002        int32 last_frame_delay;
1003        // the latency of the audio playback
1004        // If there is no audio playback, set it to 0xffffffffu
1005        uint32 audio_delay;
1006    } @declare stream_report;
1007
1008    message {
1009        image_compression image_compression;
1010    } @declare preferred_compression;
1011
1012    message {
1013    } @declare gl_draw_done;
1014
1015    message {
1016        uint8 num_of_codecs;
1017        video_codec_type codecs[num_of_codecs] @end;
1018    } @declare preferred_video_codec_type;
1019};
1020
1021flags16 keyboard_modifier_flags {
1022    SCROLL_LOCK,
1023    NUM_LOCK,
1024    CAPS_LOCK
1025};
1026
1027enum8 mouse_button {
1028    INVALID,
1029    LEFT,
1030    MIDDLE,
1031    RIGHT,
1032    UP,
1033    DOWN,
1034    SIDE,
1035    EXTRA,
1036};
1037
1038flags16 mouse_button_mask {
1039    LEFT,
1040    MIDDLE,
1041    RIGHT,
1042    UP,
1043    DOWN,
1044    SIDE,
1045    EXTRA,
1046};
1047
1048channel InputsChannel : BaseChannel {
1049 client:
1050    message {
1051        uint32 code;
1052    } @ctype(SpiceMsgcKeyDown) @declare key_down = 101;
1053
1054    message {
1055        uint32 code;
1056    } @ctype(SpiceMsgcKeyUp) @declare key_up;
1057
1058    message {
1059        keyboard_modifier_flags modifiers;
1060    } @ctype(SpiceMsgcKeyModifiers) @declare key_modifiers;
1061
1062    Data key_scancode;
1063
1064    message {
1065        int32 dx;
1066        int32 dy;
1067        mouse_button_mask buttons_state;
1068    } @ctype(SpiceMsgcMouseMotion) @declare mouse_motion = 111;
1069
1070    message {
1071        uint32 x;
1072        uint32 y;
1073        mouse_button_mask buttons_state;
1074        uint8 display_id;
1075    } @ctype(SpiceMsgcMousePosition) @declare mouse_position;
1076
1077    message {
1078        mouse_button button;
1079        mouse_button_mask buttons_state;
1080    } @ctype(SpiceMsgcMousePress) @declare mouse_press;
1081
1082    message {
1083        mouse_button button;
1084        mouse_button_mask buttons_state;
1085    } @ctype(SpiceMsgcMouseRelease) @declare mouse_release;
1086
1087 server:
1088    message {
1089        keyboard_modifier_flags keyboard_modifiers;
1090    } @declare init = 101;
1091
1092    message {
1093        keyboard_modifier_flags modifiers;
1094    } @declare key_modifiers;
1095
1096    Empty mouse_motion_ack = 111;
1097};
1098
1099enum8 cursor_type {
1100    ALPHA,
1101    MONO,
1102    COLOR4,
1103    COLOR8,
1104    COLOR16,
1105    COLOR24,
1106    COLOR32,
1107};
1108
1109flags16 cursor_flags {
1110    NONE, /* Means no cursor */
1111    CACHE_ME,
1112    FROM_CACHE,
1113};
1114
1115struct CursorHeader {
1116    uint64 unique;
1117    cursor_type type;
1118    uint16 width;
1119    uint16 height;
1120    uint16 hot_spot_x;
1121    uint16 hot_spot_y;
1122};
1123
1124struct Cursor {
1125    cursor_flags flags;
1126    switch (flags) {
1127    case !NONE:
1128        CursorHeader header;
1129    } u @anon;
1130    uint8 data[] @as_ptr(data_size);
1131} @declare;
1132
1133channel CursorChannel : BaseChannel {
1134 server:
1135    message {
1136        Point16 position;
1137        uint16 trail_length;
1138        uint16 trail_frequency;
1139        uint8 visible;
1140        Cursor cursor;
1141    } @declare init = 101;
1142
1143    Empty reset;
1144
1145    message {
1146        Point16 position;
1147        uint8 visible;
1148        Cursor cursor;
1149    } @declare set;
1150
1151    message {
1152        Point16 position;
1153    } @declare move;
1154
1155    Empty hide;
1156
1157    message {
1158        uint16 length;
1159        uint16 frequency;
1160    } @declare trail;
1161
1162    message {
1163        uint64 id;
1164    } @ctype(SpiceMsgDisplayInvalOne) @declare inval_one;
1165
1166    Empty inval_all;
1167};
1168
1169enum16 audio_data_mode {
1170    INVALID,
1171    RAW,
1172    CELT_0_5_1 @deprecated,
1173    OPUS,
1174};
1175
1176enum16 audio_fmt {
1177    INVALID,
1178    S16,
1179};
1180
1181message AudioVolume {
1182    uint8 nchannels;
1183    uint16 volume[nchannels] @end;
1184} @declare;
1185
1186message AudioMute {
1187    uint8 mute;
1188} @declare;
1189
1190channel PlaybackChannel : BaseChannel {
1191 server:
1192    message {
1193        uint32 time;
1194        uint8 data[] @as_ptr(data_size);
1195    } @ctype(SpiceMsgPlaybackPacket) @declare data = 101;
1196
1197    message {
1198        uint32 time;
1199        audio_data_mode mode;
1200        uint8 data[] @as_ptr(data_size);
1201    } @declare mode;
1202
1203    message {
1204       uint32 channels;
1205       audio_fmt format;
1206       uint32 frequency;
1207       uint32 time;
1208    } @declare start;
1209
1210    Empty stop;
1211    AudioVolume volume;
1212    AudioMute mute;
1213
1214    message {
1215        uint32 latency_ms;
1216    } @declare latency;
1217};
1218
1219channel RecordChannel : BaseChannel {
1220 server:
1221    message {
1222        uint32 channels;
1223        audio_fmt format;
1224        uint32 frequency;
1225    } @declare start = 101;
1226
1227    Empty stop;
1228    AudioVolume volume;
1229    AudioMute mute;
1230 client:
1231    message {
1232        uint32 time;
1233        uint8 data[] @nomarshal @as_ptr(data_size);
1234    } @ctype(SpiceMsgPlaybackPacket) @declare data = 101;
1235
1236    message {
1237        uint32 time;
1238        audio_data_mode mode;
1239        uint8 data[] @as_ptr(data_size);
1240    } @ctype(SpiceMsgPlaybackMode) @declare mode;
1241
1242    message {
1243        uint32 time;
1244    } @declare start_mark;
1245};
1246
1247channel TunnelChannel {
1248};
1249
1250enum32 vsc_message_type {
1251    Init = 1,
1252    Error,
1253    ReaderAdd,
1254    ReaderRemove,
1255    ATR,
1256    CardRemove,
1257    APDU,
1258    Flush,
1259    FlushComplete
1260};
1261
1262struct VscMessageHeader {
1263    vsc_message_type type;
1264    uint32 reader_id;
1265    uint32 length;
1266} @ctype(VSCMsgHeader);
1267
1268struct VscMessageError {
1269    uint32 code;
1270} @ctype(VSCMsgError);
1271
1272struct VscMessageAPDU {
1273    uint8 data[];
1274} @ctype(VSCMsgAPDU);
1275
1276struct VscMessageATR {
1277    uint8 atr[];
1278} @ctype(VSCMsgATR);
1279
1280struct VscMessageReaderAdd {
1281    int8 *name[] @zero_terminated @nonnull @end @nomarshal;
1282} @ctype(VSCMsgReaderAdd);
1283
1284channel SmartcardChannel : BaseChannel {
1285 server:
1286    message {
1287        vsc_message_type type;
1288        uint32 reader_id;
1289        uint32 length;
1290        uint8 data[length] @end @nomarshal;
1291    } @ctype(SpiceMsgSmartcard) data = 101;
1292
1293 client:
1294/* Some of the following messages are duplicated, the protocol
1295 * definition was broken. Messages, as you can see have same ID.
1296 * Also code was not used and didn't compile correctly.
1297 * Keeping in the hope could be useful in the future.
1298 */
1299/*
1300    message {
1301        VscMessageHeader header;
1302        switch (header.type) {
1303        case ReaderAdd:
1304            VscMessageReaderAdd add;
1305        case ATR:
1306        case APDU:
1307            VscMessageATR atr_data;
1308        case Error:
1309            VscMessageError error;
1310        } u @anon;
1311    } @ctype(SpiceMsgcSmartcard) old_data = 101;
1312*/
1313    message {
1314        vsc_message_type type;
1315        uint32 reader_id;
1316        uint32 length;
1317        uint8 data[length] @end @nomarshal;
1318    } @ctype(VSCMsgHeader) data = 101;
1319/* See comment on client data message above */
1320/*
1321    message {
1322        uint32 code;
1323    } @ctype(VSCMsgError) error = 101;
1324
1325    message {
1326        uint8 data[];
1327    } @ctype(VSCMsgATR) atr = 101;
1328
1329    message {
1330        int8 name[] @zero_terminated @nonnull;
1331    } @ctype(VSCMsgReaderAdd) reader_add = 101;
1332*/
1333} @ifdef(USE_SMARTCARD);
1334
1335channel SpicevmcChannel : BaseChannel {
1336server:
1337    Data data = 101;
1338    CompressedData compressed_data = 102;
1339client:
1340    Data data = 101;
1341    CompressedData compressed_data = 102;
1342};
1343
1344channel UsbredirChannel : SpicevmcChannel {
1345};
1346
1347channel PortChannel : SpicevmcChannel {
1348 client:
1349    message {
1350        uint8 event;
1351    } @declare event = 201;
1352 server:
1353    message {
1354        uint32 name_size;
1355        uint8 *name[name_size] @zero_terminated @marshall @nonnull;
1356        uint8 opened;
1357    } @declare init = 201;
1358    message {
1359        uint8 event;
1360    } @declare event;
1361};
1362
1363channel WebDAVChannel : PortChannel {
1364};
1365
1366protocol Spice {
1367    MainChannel main = 1;
1368    DisplayChannel display;
1369    InputsChannel inputs;
1370    CursorChannel cursor;
1371    PlaybackChannel playback;
1372    RecordChannel record;
1373    TunnelChannel tunnel;
1374    SmartcardChannel smartcard;
1375    UsbredirChannel usbredir;
1376    PortChannel port;
1377    WebDAVChannel webdav;
1378};
1379