diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst index 89e634e16a..00f861e385 100644 --- a/docs/formatdomain.rst +++ b/docs/formatdomain.rst @@ -7405,8 +7405,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.4.0 and QEMU 8.2.0`). :since:`Since 0.9.13`, a sound element with ``ich6`` or ``ich9`` models can have optional sub-elements ```` to attach various audio codecs to the audio @@ -7434,6 +7435,12 @@ multi-channel mode by using the ``multichannel`` attribute:: +:since:`Since 10.4.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:: + + + Each ``sound`` element has an optional sub-element ``
`` 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 9eaec76b07..fde594f811 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -779,6 +779,7 @@ VIR_ENUM_IMPL(virDomainSoundModel, "ich9", "usb", "ich7", + "virtio", ); VIR_ENUM_IMPL(virDomainAudioType, @@ -3212,6 +3213,7 @@ void virDomainSoundDefFree(virDomainSoundDef *def) virDomainSoundCodecDefFree(def->codecs[i]); g_free(def->codecs); + g_free(def->virtio); g_free(def); } @@ -11887,6 +11889,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, @@ -11898,6 +11907,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); } @@ -11922,6 +11935,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; @@ -24848,6 +24864,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) { @@ -24872,6 +24889,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 c2abdb9f52..a06f015444 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -1568,6 +1568,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; @@ -1589,6 +1590,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 86d9e391d8..a46a824f88 100644 --- a/src/conf/schemas/domaincommon.rng +++ b/src/conf/schemas/domaincommon.rng @@ -5062,6 +5062,7 @@ ich7 ich9 usb + virtio @@ -5069,6 +5070,11 @@ + + + + + @@ -5089,6 +5095,11 @@ + + + + + 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 807f013713..c32f577339 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -4482,6 +4482,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 d4ac721c06..ac1940cb31 100644 --- a/src/qemu/qemu_validate.c +++ b/src/qemu/qemu_validate.c @@ -4675,6 +4675,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: