This patch adds parsing of the virtio sound model, along with parsing
of virtio options and PCI/virtio-mmio address assignment.
A new 'streams' attribute is added for configuring number of PCM streams
(default is 2) in virtio sound devices. QEMU additionally has jacks and chmaps
parameters but these are currently stubbed, hence they are excluded in this
patch series.
Signed-off-by: Rayhan Faizel <rayhan.faizel(a)gmail.com>
---
docs/formatdomain.rst | 11 +++++++++--
src/conf/domain_conf.c | 25 +++++++++++++++++++++++++
src/conf/domain_conf.h | 4 ++++
src/conf/domain_postparse.c | 13 ++++++++++++-
src/conf/schemas/domaincommon.rng | 11 +++++++++++
src/libxl/libxl_domain.c | 1 +
src/qemu/qemu_command.c | 1 +
src/qemu/qemu_domain_address.c | 9 +++++++++
src/qemu/qemu_validate.c | 8 ++++++++
9 files changed, 80 insertions(+), 3 deletions(-)
diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index e2f66b982c..43d5928ffa 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -7390,8 +7390,9 @@ A virtual sound card can be attached to the host via the ``sound``
element.
what real sound device is emulated. Valid values are specific to the
underlying hypervisor, though typical choices are ``sb16``, ``es1370``,
``pcspk``, ``ac97`` (:since:`Since 0.6.0`), ``ich6`` (:since:`Since 0.8.8`),
- ``ich9`` (:since:`Since 1.1.3`), ``usb`` (:since:`Since 1.2.8`) and ``ich7``
- (:since:`Since 6.7.0`, bhyve only).
+ ``ich9`` (:since:`Since 1.1.3`), ``usb`` (:since:`Since 1.2.8`), ``ich7``
+ (:since:`Since 6.7.0`, bhyve only) and ``virtio``
+ (:since:`Since 10.3.0 and QEMU 8.2.0`).
:since:`Since 0.9.13`, a sound element with ``ich6`` or ``ich9`` models can have
optional sub-elements ``<codec>`` to attach various audio codecs to the audio
@@ -7419,6 +7420,12 @@ multi-channel mode by using the ``multichannel`` attribute::
<sound model='usb' multichannel='yes'/>
+:since:`Since 10.3.0 and QEMU 8.2.0` the number of PCM streams in a ``virtio``
+sound device can be configured by using the ``streams`` attribute, which
+defaults to ``2`` if left unspecified::
+
+ <sound model='virtio' streams='2'/>
+
Each ``sound`` element has an optional sub-element ``<address>`` which can tie
the device to a particular PCI slot. See `Device Addresses`_.
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 48c5d546da..d63cb9bf64 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -778,6 +778,7 @@ VIR_ENUM_IMPL(virDomainSoundModel,
"ich9",
"usb",
"ich7",
+ "virtio",
);
VIR_ENUM_IMPL(virDomainAudioType,
@@ -3211,6 +3212,7 @@ void virDomainSoundDefFree(virDomainSoundDef *def)
virDomainSoundCodecDefFree(def->codecs[i]);
g_free(def->codecs);
+ g_free(def->virtio);
g_free(def);
}
@@ -11881,6 +11883,13 @@ virDomainSoundDefParseXML(virDomainXMLOption *xmlopt,
return NULL;
}
+ if (def->model == VIR_DOMAIN_SOUND_MODEL_VIRTIO) {
+ if (virXMLPropUInt(node, "streams", 10,
+ VIR_XML_PROP_NONZERO,
+ &def->streams) < 0)
+ return NULL;
+ }
+
audioNode = virXPathNode("./audio", ctxt);
if (audioNode) {
if (virXMLPropUInt(audioNode, "id", 10,
@@ -11892,6 +11901,10 @@ virDomainSoundDefParseXML(virDomainXMLOption *xmlopt,
if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) <
0)
return NULL;
+ if (virDomainVirtioOptionsParseXML(virXPathNode("./driver", ctxt),
+ &def->virtio) < 0)
+ return NULL;
+
return g_steal_pointer(&def);
}
@@ -11916,6 +11929,9 @@ virDomainSoundDefEquals(const virDomainSoundDef *a,
if (a->multichannel != b->multichannel)
return false;
+ if (a->streams != b->streams)
+ return false;
+
if (a->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
!virDomainDeviceInfoAddressIsEqual(&a->info, &b->info))
return false;
@@ -24836,6 +24852,7 @@ virDomainSoundDefFormat(virBuffer *buf,
const char *model = virDomainSoundModelTypeToString(def->model);
g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
+ g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER;
size_t i;
if (!model) {
@@ -24860,6 +24877,14 @@ virDomainSoundDefFormat(virBuffer *buf,
virTristateBoolTypeToString(def->multichannel));
}
+ if (def->model == VIR_DOMAIN_SOUND_MODEL_VIRTIO) {
+ virBufferAsprintf(&attrBuf, " streams='%d'",
def->streams);
+
+ virDomainVirtioOptionsFormat(&driverAttrBuf, def->virtio);
+
+ virXMLFormatElement(&childBuf, "driver", &driverAttrBuf,
NULL);
+ }
+
virXMLFormatElement(buf, "sound", &attrBuf, &childBuf);
return 0;
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 5925faaf1a..13ca722019 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1565,6 +1565,7 @@ typedef enum {
VIR_DOMAIN_SOUND_MODEL_ICH9,
VIR_DOMAIN_SOUND_MODEL_USB,
VIR_DOMAIN_SOUND_MODEL_ICH7,
+ VIR_DOMAIN_SOUND_MODEL_VIRTIO,
VIR_DOMAIN_SOUND_MODEL_LAST
} virDomainSoundModel;
@@ -1586,6 +1587,9 @@ struct _virDomainSoundDef {
virTristateBool multichannel;
unsigned int audioId;
+
+ unsigned int streams;
+ virDomainVirtioOptions *virtio;
};
typedef enum {
diff --git a/src/conf/domain_postparse.c b/src/conf/domain_postparse.c
index cafa2d235d..112795ea65 100644
--- a/src/conf/domain_postparse.c
+++ b/src/conf/domain_postparse.c
@@ -677,6 +677,13 @@ virDomainInputDefPostParse(virDomainInputDef *input,
}
}
+static void
+virDomainSoundDefPostParse(virDomainSoundDef *sound)
+{
+ if (sound->model == VIR_DOMAIN_SOUND_MODEL_VIRTIO && sound->streams ==
0)
+ sound->streams = 2;
+}
+
static int
virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev,
const virDomainDef *def,
@@ -730,9 +737,13 @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev,
ret = 0;
break;
+ case VIR_DOMAIN_DEVICE_SOUND:
+ virDomainSoundDefPostParse(dev->data.sound);
+ ret = 0;
+ break;
+
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_NET:
- case VIR_DOMAIN_DEVICE_SOUND:
case VIR_DOMAIN_DEVICE_WATCHDOG:
case VIR_DOMAIN_DEVICE_GRAPHICS:
case VIR_DOMAIN_DEVICE_HUB:
diff --git a/src/conf/schemas/domaincommon.rng b/src/conf/schemas/domaincommon.rng
index f386e46fae..5cdd8328b6 100644
--- a/src/conf/schemas/domaincommon.rng
+++ b/src/conf/schemas/domaincommon.rng
@@ -5057,6 +5057,7 @@
<value>ich7</value>
<value>ich9</value>
<value>usb</value>
+ <value>virtio</value>
</choice>
</attribute>
<optional>
@@ -5064,6 +5065,11 @@
<ref name="virYesNo"/>
</attribute>
</optional>
+ <optional>
+ <attribute name="streams">
+ <ref name="uint32"/>
+ </attribute>
+ </optional>
<interleave>
<optional>
<ref name="alias"/>
@@ -5084,6 +5090,11 @@
<zeroOrMore>
<ref name="codec"/>
</zeroOrMore>
+ <optional>
+ <element name="driver">
+ <ref name="virtioOptions"/>
+ </element>
+ </optional>
</interleave>
</element>
</define>
diff --git a/src/libxl/libxl_domain.c b/src/libxl/libxl_domain.c
index 16c2ab973b..0f129ec69c 100644
--- a/src/libxl/libxl_domain.c
+++ b/src/libxl/libxl_domain.c
@@ -344,6 +344,7 @@ libxlDomainDefValidate(const virDomainDef *def,
case VIR_DOMAIN_SOUND_MODEL_ICH7:
case VIR_DOMAIN_SOUND_MODEL_USB:
case VIR_DOMAIN_SOUND_MODEL_ICH9:
+ case VIR_DOMAIN_SOUND_MODEL_VIRTIO:
case VIR_DOMAIN_SOUND_MODEL_LAST:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported audio model %1$s"),
diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c
index 9d4563861f..5e69e71c6f 100644
--- a/src/qemu/qemu_command.c
+++ b/src/qemu/qemu_command.c
@@ -4479,6 +4479,7 @@ qemuBuildSoundDevCmd(virCommand *cmd,
case VIR_DOMAIN_SOUND_MODEL_SB16:
model = "sb16";
break;
+ case VIR_DOMAIN_SOUND_MODEL_VIRTIO:
case VIR_DOMAIN_SOUND_MODEL_PCSPK: /* pc-speaker is handled separately */
case VIR_DOMAIN_SOUND_MODEL_ICH7:
case VIR_DOMAIN_SOUND_MODEL_LAST:
diff --git a/src/qemu/qemu_domain_address.c b/src/qemu/qemu_domain_address.c
index 7690021ca7..251f5b7e1a 100644
--- a/src/qemu/qemu_domain_address.c
+++ b/src/qemu/qemu_domain_address.c
@@ -324,6 +324,12 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDef *def,
if (def->cryptos[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
def->cryptos[i]->info.type = type;
}
+
+ for (i = 0; i < def->nsounds; i++) {
+ if (def->sounds[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE
&&
+ def->sounds[i]->model == VIR_DOMAIN_SOUND_MODEL_VIRTIO)
+ def->sounds[i]->info.type = type;
+ }
}
@@ -694,6 +700,9 @@ qemuDomainDeviceCalculatePCIConnectFlags(virDomainDeviceDef *dev,
case VIR_DOMAIN_SOUND_MODEL_ICH9:
return pciFlags;
+ case VIR_DOMAIN_SOUND_MODEL_VIRTIO:
+ return virtioFlags;
+
case VIR_DOMAIN_SOUND_MODEL_SB16:
case VIR_DOMAIN_SOUND_MODEL_PCSPK:
case VIR_DOMAIN_SOUND_MODEL_USB:
diff --git a/src/qemu/qemu_validate.c b/src/qemu/qemu_validate.c
index de0867c4b1..9dea33bb53 100644
--- a/src/qemu/qemu_validate.c
+++ b/src/qemu/qemu_validate.c
@@ -4625,6 +4625,14 @@ qemuValidateDomainDeviceDefSound(virDomainSoundDef *sound,
}
break;
+ case VIR_DOMAIN_SOUND_MODEL_VIRTIO:
+ if (!virQEMUCapsGet(qemuCaps, QEMU_CAPS_DEVICE_VIRTIO_SOUND)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("virtio-sound controller is not supported in this QEMU
binary"));
+ return -1;
+ }
+ break;
+
case VIR_DOMAIN_SOUND_MODEL_ES1370:
case VIR_DOMAIN_SOUND_MODEL_AC97:
case VIR_DOMAIN_SOUND_MODEL_ICH6:
--
2.34.1