usb-audio XML example:
<devices>
<sound model='usb-audio'>
<buffer>1536</buffer>
<address type='usb' bus='0' port='1'/>
</sound>
</devices>
qemu ${other_vm_args} \
-device usb-audio,id=sound0,buffer=1536,bus=usb.0,port=1
there is an optional sub-element <buffer> to customize
the buffer size of usb audio device, if missing,
the default size is 1536(defined in qemu code).
Special size of value 0 means no buffer will be used,
so we use bool 'customized_buffer'to differentiate
user-defined 0 from being using default buffer value 1536.
---
docs/formatdomain.html.in | 10 +++++++--
docs/schemas/basictypes.rng | 11 ++++++++++
docs/schemas/domaincommon.rng | 9 ++++++++
docs/schemas/nwfilter.rng | 15 -------------
src/conf/domain_conf.c | 49 ++++++++++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 5 +++++
src/qemu/qemu_command.c | 19 ++++++++++++++++-
7 files changed, 99 insertions(+), 19 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index 94df6f8..354d4f6 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -4056,9 +4056,15 @@ qemu-kvm -net nic,model=? /dev/null
The <code>sound</code> element has one mandatory attribute,
<code>model</code>, which specifies what real sound device is
emulated.
Valid values are specific to the underlying hypervisor, though typical
- choices are 'es1370', 'sb16', 'ac97', and 'ich6'
+ choices are 'es1370', 'sb16', 'ac97', 'ich6' and
'usb-audio'
(<span class="since">
- 'ac97' only since 0.6.0, 'ich6' only since 0.8.8</span>)
+ 'ac97' only since 0.6.0, 'ich6' only since 0.8.8,
+ 'usb-audio' only since 1.0.2</span>)
+ For the 'usb-audio' model, there is an optional sub-element
<code><buffer></code>
+ to customize the buffer size of the audio device, if missing, the default size is
1536.
+ The goal of setting a buffer size is to reduce it as much as possible without
+ hearing any clicks, pops, or other glitches. Special size of value 0 means no
buffer
+ will be used, e.g.
<code><buffer>3072</buffer></code>.
</dd>
</dl>
diff --git a/docs/schemas/basictypes.rng b/docs/schemas/basictypes.rng
index 38cab16..4e8d4b8 100644
--- a/docs/schemas/basictypes.rng
+++ b/docs/schemas/basictypes.rng
@@ -42,6 +42,17 @@
</data>
</choice>
</define>
+ <define name="uint32range">
+ <choice>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,8}</param>
+ </data>
+ <data type="long">
+ <param name="minInclusive">0</param>
+ <param name="maxInclusive">4294967295</param>
+ </data>
+ </choice>
+ </define>
<define name="UUID">
<choice>
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 0529d62..55c1219 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2599,6 +2599,11 @@
</attribute>
</element>
</define>
+ <define name="audiobuffer">
+ <element name='buffer'>
+ <ref name="uint32range"/>
+ </element>
+ </define>
<define name="sound">
<element name="sound">
<attribute name="model">
@@ -2608,6 +2613,7 @@
<value>pcspk</value>
<value>ac97</value>
<value>ich6</value>
+ <value>usb-audio</value>
</choice>
</attribute>
<interleave>
@@ -2622,6 +2628,9 @@
<ref name="codec"/>
</choice>
</zeroOrMore>
+ <optional>
+ <ref name ="audiobuffer"/>
+ </optional>
</interleave>
</element>
</define>
diff --git a/docs/schemas/nwfilter.rng b/docs/schemas/nwfilter.rng
index cfd9ba5..5681083 100644
--- a/docs/schemas/nwfilter.rng
+++ b/docs/schemas/nwfilter.rng
@@ -942,21 +942,6 @@
</choice>
</define>
- <define name="uint32range">
- <choice>
- <ref name="variable-name-type"/>
-
- <data type="string">
- <param name="pattern">0x[0-9a-fA-F]{1,8}</param>
- </data>
-
- <data type="int">
- <param name="minInclusive">0</param>
- <param name="maxInclusive">4294967295</param>
- </data>
- </choice>
- </define>
-
<define name="boolean">
<choice>
<value>yes</value>
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 79af087..955e089 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -395,7 +395,8 @@ VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
"es1370",
"pcspk",
"ac97",
- "ich6")
+ "ich6",
+ "usb-audio")
VIR_ENUM_IMPL(virDomainMemDump, VIR_DOMAIN_MEM_DUMP_LAST,
"default",
@@ -7009,6 +7010,38 @@ error:
goto cleanup;
}
+static int
+virDomainSoundUSBAudioBufferParseXML(const xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ virDomainSoundDefPtr def)
+{
+ int ret;
+ unsigned long value;
+
+ if (!node || !ctxt)
+ return -1;
+
+ ret = virXPathULong("string(./buffer[1])", ctxt, &value);
+ if (ret < 0) {
+ if (ret == -2) {
+ virReportError(VIR_ERR_XML_ERROR,
+ "%s", _("could not parse usb-audio buffer
element"));
+ return -1;
+ } else {
+ def->customized_buffer = false;
+ }
+ } else if (value > UINT32_MAX) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("usb-audio buffer is too big, "
+ "no more than 4294967295"));
+ return -1;
+ } else {
+ def->buf_value = value;
+ def->customized_buffer = true;
+ }
+
+ return 0;
+}
static virDomainSoundDefPtr
virDomainSoundDefParseXML(const xmlNodePtr node,
@@ -7063,6 +7096,11 @@ virDomainSoundDefParseXML(const xmlNodePtr node,
}
}
+ if (def->model == VIR_DOMAIN_SOUND_MODEL_USB_AUDIO) {
+ if (virDomainSoundUSBAudioBufferParseXML(node, ctxt, def) < 0)
+ goto error;
+ }
+
if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
goto error;
@@ -13204,6 +13242,15 @@ virDomainSoundDefFormat(virBufferPtr buf,
virDomainSoundCodecDefFormat(buf, def->codecs[i]);
}
+ if (def->customized_buffer) {
+ if (!children) {
+ virBufferAddLit(buf, ">\n");
+ children = true;
+ }
+ virBufferAsprintf(buf, " <buffer>%lu</buffer>\n",
+ (unsigned long)def->buf_value);
+ }
+
if (virDomainDeviceInfoIsSet(&def->info, flags)) {
if (!children) {
virBufferAddLit(buf, ">\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index a975a63..6493443 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1073,6 +1073,7 @@ enum virDomainSoundModel {
VIR_DOMAIN_SOUND_MODEL_PCSPK,
VIR_DOMAIN_SOUND_MODEL_AC97,
VIR_DOMAIN_SOUND_MODEL_ICH6,
+ VIR_DOMAIN_SOUND_MODEL_USB_AUDIO,
VIR_DOMAIN_SOUND_MODEL_LAST
};
@@ -1088,6 +1089,10 @@ struct _virDomainSoundDef {
size_t ncodecs;
virDomainSoundCodecDefPtr *codecs;
+
+ /* for usb-audio only */
+ bool customized_buffer;
+ uint32_t buf_value;
};
enum virDomainWatchdogModel {
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 8a3de09..31b0d89 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -1571,7 +1571,8 @@ qemuAssignDevicePCISlots(virDomainDefPtr def,
continue;
/* Skip ISA sound card, and PCSPK */
if (def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_SB16 ||
- def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_PCSPK)
+ def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_PCSPK ||
+ def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_USB_AUDIO)
continue;
if (qemuDomainPCIAddressSetNextAddr(addrs, &def->sounds[i]->info) <
0)
@@ -3462,7 +3463,23 @@ qemuBuildSoundDevStr(virDomainSoundDefPtr sound,
else if (STREQ(model, "ich6"))
model = "intel-hda";
+ if (STREQ(model, "usb-audio")) {
+ if (!qemuCapsGet(caps, QEMU_CAPS_DEVICE_USB_AUDIO)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ "%s", _("usb-audio is not supported"
+ " by this version of QEMU"));
+ goto error;
+ } else {
+ model = "usb-audio";
+ }
+ }
+
virBufferAsprintf(&buf, "%s,id=%s", model, sound->info.alias);
+
+ if (sound->customized_buffer)
+ virBufferAsprintf(&buf, ",buffer=%lu",
+ (unsigned long)sound->buf_value);
+
if (qemuBuildDeviceAddressStr(&buf, &sound->info, caps) < 0)
goto error;
--
1.7.11.4