This extends the SPICE XML to allow variable compression settings for audio,
images and streaming:
<graphics type='spice' port='5901' tlsPort='-1'
autoport='yes'>
<image compression='auto_glz'/>
<jpeg compression='auto'/>
<zlib compression='auto'/>
<playback compression='on'/>
</graphics>
All new element are optional.
---
docs/formatdomain.html.in | 12 ++
docs/schemas/domain.rng | 50 ++++++++
src/conf/domain_conf.c | 130 ++++++++++++++++++++
src/conf/domain_conf.h | 42 +++++++
src/libvirt_private.syms | 8 ++
src/qemu/qemu_command.c | 16 +++
.../qemuxml2argv-graphics-spice.args | 4 +-
.../qemuxml2argv-graphics-spice.xml | 4 +
8 files changed, 265 insertions(+), 1 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 3c4c656..c5edf53 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -1664,6 +1664,18 @@ qemu-kvm -net nic,model=? /dev/null
<channel name='main' mode='secure'/>
<channel name='record' mode='insecure'/>
</graphics></pre>
+ <p>
+Spice supports variable compression settings for audio, images and streaming.
+This setting are accessible via <code>compression</code> attribute in all
+following elements: <code>image</code> to set image compression (accept
+<code>auto_glz</code>, <code>auto_lz</code>,
<code>quic</code>,
+<code>glz</code>, <code>lz</code>, <code>off</code>),
<code>jpeg</code> for
+JPEG compression for images over wan (accept <code>auto</code>,
+<code>never</code>, <code>always</code>),
<code>zlib</code> for configuring
+wan image compression (accept <code>auto</code>,
<code>never</code>,
+<code>always</code>) and <code>playback</code> for enabling audio
stream
+compression (accept <code>on</code> or <code>off</code>)
+ </p>
</dd>
<dt><code>"rdp"</code></dt>
<dd>
diff --git a/docs/schemas/domain.rng b/docs/schemas/domain.rng
index 0fbf326..f0578f8 100644
--- a/docs/schemas/domain.rng
+++ b/docs/schemas/domain.rng
@@ -1283,6 +1283,56 @@
<empty/>
</element>
</zeroOrMore>
+ <optional>
+ <element name="image">
+ <attribute name="compression">
+ <choice>
+ <value>auto_glz</value>
+ <value>auto_lz</value>
+ <value>quic</value>
+ <value>glz</value>
+ <value>lz</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
+ <element name="jpeg">
+ <attribute name="compression">
+ <choice>
+ <value>auto</value>
+ <value>never</value>
+ <value>always</value>
+ </choice>
+ </attribute>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
+ <element name="zlib">
+ <attribute name="compression">
+ <choice>
+ <value>auto</value>
+ <value>never</value>
+ <value>always</value>
+ </choice>
+ </attribute>
+ <empty/>
+ </element>
+ </optional>
+ <optional>
+ <element name="playback">
+ <attribute name="compression">
+ <choice>
+ <value>on</value>
+ <value>off</value>
+ </choice>
+ </attribute>
+ <empty/>
+ </element>
+ </optional>
</group>
<group>
<attribute name="type">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 90a1317..f215e7d 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -322,6 +322,32 @@ VIR_ENUM_IMPL(virDomainGraphicsSpiceChannelMode,
"secure",
"insecure");
+VIR_ENUM_IMPL(virDomainGraphicsSpiceImageCompression,
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_LAST,
+ "auto_glz",
+ "auto_lz",
+ "quic",
+ "glz",
+ "lz",
+ "off");
+
+VIR_ENUM_IMPL(virDomainGraphicsSpiceJpegCompression,
+ VIR_DOMAIN_GRAPHICS_SPICE_JPEG_COMPRESSION_LAST,
+ "auto",
+ "never",
+ "always");
+
+VIR_ENUM_IMPL(virDomainGraphicsSpiceZlibCompression,
+ VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_LAST,
+ "auto",
+ "never",
+ "always");
+
+VIR_ENUM_IMPL(virDomainGraphicsSpicePlaybackCompression,
+ VIR_DOMAIN_GRAPHICS_SPICE_PLAYBACK_COMPRESSION_LAST,
+ "on",
+ "off");
+
VIR_ENUM_IMPL(virDomainHostdevMode, VIR_DOMAIN_HOSTDEV_MODE_LAST,
"subsystem",
"capabilities")
@@ -3917,6 +3943,11 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) {
if (virDomainGraphicsAuthDefParseXML(node, &def->data.spice.auth) < 0)
goto error;
+ def->data.spice.image = VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_LAST;
+ def->data.spice.jpeg = VIR_DOMAIN_GRAPHICS_SPICE_JPEG_COMPRESSION_LAST;
+ def->data.spice.zlib = VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_LAST;
+ def->data.spice.playback =
VIR_DOMAIN_GRAPHICS_SPICE_PLAYBACK_COMPRESSION_LAST;
+
cur = node->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE) {
@@ -3954,6 +3985,89 @@ virDomainGraphicsDefParseXML(xmlNodePtr node, int flags) {
VIR_FREE(mode);
def->data.spice.channels[nameval] = modeval;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "image")) {
+ const char *compression = virXMLPropString(cur,
"compression");
+ int compressionVal;
+
+ if (!compression) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("spice image missing
compression"));
+ goto error;
+ }
+
+ if ((compressionVal =
+
virDomainGraphicsSpiceImageCompressionTypeFromString(compression)) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown spice image compression
%s"),
+ compression);
+ VIR_FREE(compression);
+ goto error;
+ }
+ VIR_FREE(compression);
+
+ def->data.spice.image = compressionVal;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "jpeg")) {
+ const char *compression = virXMLPropString(cur,
"compression");
+ int compressionVal;
+
+ if (!compression) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("spice jpeg missing
compression"));
+ goto error;
+ }
+
+ if ((compressionVal =
+
virDomainGraphicsSpiceJpegCompressionTypeFromString(compression)) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown spice jpeg compression
%s"),
+ compression);
+ VIR_FREE(compression);
+ goto error;
+ }
+ VIR_FREE(compression);
+
+ def->data.spice.jpeg = compressionVal;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "zlib")) {
+ const char *compression = virXMLPropString(cur,
"compression");
+ int compressionVal;
+
+ if (!compression) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("spice zlib missing
compression"));
+ goto error;
+ }
+
+ if ((compressionVal =
+
virDomainGraphicsSpiceZlibCompressionTypeFromString(compression)) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown spice zlib compression
%s"),
+ compression);
+ VIR_FREE(compression);
+ goto error;
+ }
+
+ def->data.spice.zlib = compressionVal;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "playback")) {
+ const char *compression = virXMLPropString(cur,
"compression");
+ int compressionVal;
+
+ if (!compression) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("spice playback missing
compression"));
+ goto error;
+ }
+
+ if ((compressionVal =
+
virDomainGraphicsSpicePlaybackCompressionTypeFromString(compression)) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown spice playback
compression"));
+ VIR_FREE(compression);
+ goto error;
+
+ }
+ VIR_FREE(compression);
+
+ def->data.spice.playback = compressionVal;
}
}
cur = cur->next;
@@ -7817,6 +7931,22 @@ virDomainGraphicsDefFormat(virBufferPtr buf,
virDomainGraphicsSpiceChannelNameTypeToString(i),
virDomainGraphicsSpiceChannelModeTypeToString(mode));
}
+ if (def->data.spice.image !=
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_LAST)
+ virBufferVSprintf(buf, " <image
compression='%s'/>\n",
+
virDomainGraphicsSpiceImageCompressionTypeToString(def->data.spice.image));
+ if (def->data.spice.jpeg !=
+ VIR_DOMAIN_GRAPHICS_SPICE_JPEG_COMPRESSION_LAST)
+ virBufferVSprintf(buf, " <jpeg
compression='%s'/>\n",
+
virDomainGraphicsSpiceJpegCompressionTypeToString(def->data.spice.jpeg));
+ if (def->data.spice.zlib !=
+ VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_LAST)
+ virBufferVSprintf(buf, " <zlib
compression='%s'/>\n",
+
virDomainGraphicsSpiceZlibCompressionTypeToString(def->data.spice.zlib));
+ if (def->data.spice.playback !=
+ VIR_DOMAIN_GRAPHICS_SPICE_PLAYBACK_COMPRESSION_LAST)
+ virBufferVSprintf(buf, " <playback
compression='%s'/>\n",
+
virDomainGraphicsSpicePlaybackCompressionTypeToString(def->data.spice.playback));
}
if (children) {
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 95bd11e..e36f0ed 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -658,6 +658,40 @@ enum virDomainGraphicsSpiceChannelMode {
VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_MODE_LAST
};
+enum virDomainGraphicsSpiceImageCompression {
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_AUTO_GLZ,
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_AUTO_LZ,
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_QUIC,
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_GLZ,
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_LZ,
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_OFF,
+
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_LAST
+};
+
+enum virDomainGraphicsSpiceJpegCompression {
+ VIR_DOMAIN_GRAPHICS_SPICE_JPEG_COMPRESSION_AUTO,
+ VIR_DOMAIN_GRAPHICS_SPICE_JPEG_COMPRESSION_NEVER,
+ VIR_DOMAIN_GRAPHICS_SPICE_JPEG_COMPRESSION_ALWAYS,
+
+ VIR_DOMAIN_GRAPHICS_SPICE_JPEG_COMPRESSION_LAST
+};
+
+enum virDomainGraphicsSpiceZlibCompression {
+ VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_AUTO,
+ VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_NEVER,
+ VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_ALWAYS,
+
+ VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_LAST
+};
+
+enum virDomainGraphicsSpicePlaybackCompression {
+ VIR_DOMAIN_GRAPHICS_SPICE_PLAYBACK_COMPRESSION_ON,
+ VIR_DOMAIN_GRAPHICS_SPICE_PLAYBACK_COMPRESSION_OFF,
+
+ VIR_DOMAIN_GRAPHICS_SPICE_PLAYBACK_COMPRESSION_LAST
+};
+
typedef struct _virDomainGraphicsDef virDomainGraphicsDef;
typedef virDomainGraphicsDef *virDomainGraphicsDefPtr;
struct _virDomainGraphicsDef {
@@ -695,6 +729,10 @@ struct _virDomainGraphicsDef {
virDomainGraphicsAuthDef auth;
unsigned int autoport :1;
int channels[VIR_DOMAIN_GRAPHICS_SPICE_CHANNEL_LAST];
+ int image;
+ int jpeg;
+ int zlib;
+ int playback;
} spice;
} data;
};
@@ -1423,6 +1461,10 @@ VIR_ENUM_DECL(virDomainInputBus)
VIR_ENUM_DECL(virDomainGraphics)
VIR_ENUM_DECL(virDomainGraphicsSpiceChannelName)
VIR_ENUM_DECL(virDomainGraphicsSpiceChannelMode)
+VIR_ENUM_DECL(virDomainGraphicsSpiceImageCompression)
+VIR_ENUM_DECL(virDomainGraphicsSpiceJpegCompression)
+VIR_ENUM_DECL(virDomainGraphicsSpiceZlibCompression)
+VIR_ENUM_DECL(virDomainGraphicsSpicePlaybackCompression)
/* from libvirt.h */
VIR_ENUM_DECL(virDomainState)
VIR_ENUM_DECL(virDomainSeclabel)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 54e4482..d2aa077 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -262,6 +262,14 @@ virDomainGraphicsSpiceChannelModeTypeFromString;
virDomainGraphicsSpiceChannelModeTypeToString;
virDomainGraphicsSpiceChannelNameTypeFromString;
virDomainGraphicsSpiceChannelNameTypeToString;
+virDomainGraphicsSpiceImageCompressionTypeToString;
+virDomainGraphicsSpiceImageCompressionTypeFromString;
+virDomainGraphicsSpiceJpegCompressionTypeFromString;
+virDomainGraphicsSpiceJpegCompressionTypeToString;
+virDomainGraphicsSpicePlaybackCompressionTypeFromString;
+virDomainGraphicsSpicePlaybackCompressionTypeToString;
+virDomainGraphicsSpiceZlibCompressionTypeFromString;
+virDomainGraphicsSpiceZlibCompressionTypeToString;
virDomainGraphicsTypeFromString;
virDomainGraphicsTypeToString;
virDomainHostdevDefFree;
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index fea0068..6272910 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4032,6 +4032,22 @@ qemuBuildCommandLine(virConnectPtr conn,
break;
}
}
+ if (def->graphics[0]->data.spice.image !=
+ VIR_DOMAIN_GRAPHICS_SPICE_IMAGE_COMPRESSION_LAST)
+ virBufferVSprintf(&opt, ",image-compression=%s",
+
virDomainGraphicsSpiceImageCompressionTypeToString(def->graphics[0]->data.spice.image));
+ if (def->graphics[0]->data.spice.jpeg !=
+ VIR_DOMAIN_GRAPHICS_SPICE_JPEG_COMPRESSION_LAST)
+ virBufferVSprintf(&opt, ",jpeg-wan-compression=%s",
+
virDomainGraphicsSpiceJpegCompressionTypeToString(def->graphics[0]->data.spice.jpeg));
+ if (def->graphics[0]->data.spice.zlib !=
+ VIR_DOMAIN_GRAPHICS_SPICE_ZLIB_COMPRESSION_LAST)
+ virBufferVSprintf(&opt, ",zlib-glz-wan-compression=%s",
+
virDomainGraphicsSpiceZlibCompressionTypeToString(def->graphics[0]->data.spice.zlib));
+ if (def->graphics[0]->data.spice.playback !=
+ VIR_DOMAIN_GRAPHICS_SPICE_PLAYBACK_COMPRESSION_LAST)
+ virBufferVSprintf(&opt, ",playback-compression=%s",
+
virDomainGraphicsSpicePlaybackCompressionTypeToString(def->graphics[0]->data.spice.playback));
virCommandAddArg(cmd, "-spice");
virCommandAddArgBuffer(cmd, &opt);
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.args
b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.args
index c788bb6..70cd35b 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.args
+++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.args
@@ -2,6 +2,8 @@ LC_ALL=C PATH=/bin HOME=/home/test USER=test LOGNAME=test
QEMU_AUDIO_DRV=spice \
/usr/bin/qemu -S -M pc -m 214 -smp 1 -nodefaults -monitor \
unix:/tmp/test-monitor,server,nowait -no-acpi -boot c -hda \
/dev/HostVG/QEMUGuest1 -usb -spice port=5903,tls-port=5904,addr=127.0.0.1,\
-x509-dir=/etc/pki/libvirt-spice,tls-channel=main,plaintext-channel=inputs -vga \
+x509-dir=/etc/pki/libvirt-spice,tls-channel=main,plaintext-channel=inputs,\
+image-compression=auto_glz,jpeg-wan-compression=auto,zlib-glz-wan-compression=auto,\
+playback-compression=on -vga \
qxl -global qxl.vram_size=18874368 -device
qxl,id=video1,vram_size=33554432,bus=pci.0,addr=0x4 \
-device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x3
diff --git a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.xml
b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.xml
index 5d46509..a29f50d 100644
--- a/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.xml
+++ b/tests/qemuxml2argvdata/qemuxml2argv-graphics-spice.xml
@@ -24,6 +24,10 @@
<graphics type='spice' port='5903' tlsPort='5904'
autoport='no' listen='127.0.0.1'>
<channel name='main' mode='secure'/>
<channel name='inputs' mode='insecure'/>
+ <image compression='auto_glz'/>
+ <jpeg compression='auto'/>
+ <zlib compression='auto'/>
+ <playback compression='on'/>
</graphics>
<video>
<model type='qxl' vram='18432' heads='1'/>
--
1.7.4.2