conf: Introduce support for virtio-sound devices

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@gmail.com>
Reviewed-by: Ján Tomko <jtomko@redhat.com>
This commit is contained in:
Rayhan Faizel 2024-04-12 01:42:43 +05:30 committed by Ján Tomko
parent 9081320b53
commit bb593e3743
9 changed files with 80 additions and 3 deletions

View File

@ -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 what real sound device is emulated. Valid values are specific to the
underlying hypervisor, though typical choices are ``sb16``, ``es1370``, underlying hypervisor, though typical choices are ``sb16``, ``es1370``,
``pcspk``, ``ac97`` (:since:`Since 0.6.0`), ``ich6`` (:since:`Since 0.8.8`), ``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`` ``ich9`` (:since:`Since 1.1.3`), ``usb`` (:since:`Since 1.2.8`), ``ich7``
(:since:`Since 6.7.0`, bhyve only). (: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 :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 optional sub-elements ``<codec>`` to attach various audio codecs to the audio
@ -7434,6 +7435,12 @@ multi-channel mode by using the ``multichannel`` attribute::
<sound model='usb' multichannel='yes'/> <sound model='usb' multichannel='yes'/>
: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::
<sound model='virtio' streams='2'/>
Each ``sound`` element has an optional sub-element ``<address>`` which can tie Each ``sound`` element has an optional sub-element ``<address>`` which can tie
the device to a particular PCI slot. See `Device Addresses`_. the device to a particular PCI slot. See `Device Addresses`_.

View File

@ -779,6 +779,7 @@ VIR_ENUM_IMPL(virDomainSoundModel,
"ich9", "ich9",
"usb", "usb",
"ich7", "ich7",
"virtio",
); );
VIR_ENUM_IMPL(virDomainAudioType, VIR_ENUM_IMPL(virDomainAudioType,
@ -3212,6 +3213,7 @@ void virDomainSoundDefFree(virDomainSoundDef *def)
virDomainSoundCodecDefFree(def->codecs[i]); virDomainSoundCodecDefFree(def->codecs[i]);
g_free(def->codecs); g_free(def->codecs);
g_free(def->virtio);
g_free(def); g_free(def);
} }
@ -11887,6 +11889,13 @@ virDomainSoundDefParseXML(virDomainXMLOption *xmlopt,
return NULL; 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); audioNode = virXPathNode("./audio", ctxt);
if (audioNode) { if (audioNode) {
if (virXMLPropUInt(audioNode, "id", 10, if (virXMLPropUInt(audioNode, "id", 10,
@ -11898,6 +11907,10 @@ virDomainSoundDefParseXML(virDomainXMLOption *xmlopt,
if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) < 0) if (virDomainDeviceInfoParseXML(xmlopt, node, ctxt, &def->info, flags) < 0)
return NULL; return NULL;
if (virDomainVirtioOptionsParseXML(virXPathNode("./driver", ctxt),
&def->virtio) < 0)
return NULL;
return g_steal_pointer(&def); return g_steal_pointer(&def);
} }
@ -11922,6 +11935,9 @@ virDomainSoundDefEquals(const virDomainSoundDef *a,
if (a->multichannel != b->multichannel) if (a->multichannel != b->multichannel)
return false; return false;
if (a->streams != b->streams)
return false;
if (a->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE && if (a->info.type != VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE &&
!virDomainDeviceInfoAddressIsEqual(&a->info, &b->info)) !virDomainDeviceInfoAddressIsEqual(&a->info, &b->info))
return false; return false;
@ -24848,6 +24864,7 @@ virDomainSoundDefFormat(virBuffer *buf,
const char *model = virDomainSoundModelTypeToString(def->model); const char *model = virDomainSoundModelTypeToString(def->model);
g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf); g_auto(virBuffer) childBuf = VIR_BUFFER_INIT_CHILD(buf);
g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER; g_auto(virBuffer) attrBuf = VIR_BUFFER_INITIALIZER;
g_auto(virBuffer) driverAttrBuf = VIR_BUFFER_INITIALIZER;
size_t i; size_t i;
if (!model) { if (!model) {
@ -24872,6 +24889,14 @@ virDomainSoundDefFormat(virBuffer *buf,
virTristateBoolTypeToString(def->multichannel)); 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); virXMLFormatElement(buf, "sound", &attrBuf, &childBuf);
return 0; return 0;

View File

@ -1568,6 +1568,7 @@ typedef enum {
VIR_DOMAIN_SOUND_MODEL_ICH9, VIR_DOMAIN_SOUND_MODEL_ICH9,
VIR_DOMAIN_SOUND_MODEL_USB, VIR_DOMAIN_SOUND_MODEL_USB,
VIR_DOMAIN_SOUND_MODEL_ICH7, VIR_DOMAIN_SOUND_MODEL_ICH7,
VIR_DOMAIN_SOUND_MODEL_VIRTIO,
VIR_DOMAIN_SOUND_MODEL_LAST VIR_DOMAIN_SOUND_MODEL_LAST
} virDomainSoundModel; } virDomainSoundModel;
@ -1589,6 +1590,9 @@ struct _virDomainSoundDef {
virTristateBool multichannel; virTristateBool multichannel;
unsigned int audioId; unsigned int audioId;
unsigned int streams;
virDomainVirtioOptions *virtio;
}; };
typedef enum { typedef enum {

View File

@ -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 static int
virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev, virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev,
const virDomainDef *def, const virDomainDef *def,
@ -730,9 +737,13 @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDef *dev,
ret = 0; ret = 0;
break; break;
case VIR_DOMAIN_DEVICE_SOUND:
virDomainSoundDefPostParse(dev->data.sound);
ret = 0;
break;
case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_NET: case VIR_DOMAIN_DEVICE_NET:
case VIR_DOMAIN_DEVICE_SOUND:
case VIR_DOMAIN_DEVICE_WATCHDOG: case VIR_DOMAIN_DEVICE_WATCHDOG:
case VIR_DOMAIN_DEVICE_GRAPHICS: case VIR_DOMAIN_DEVICE_GRAPHICS:
case VIR_DOMAIN_DEVICE_HUB: case VIR_DOMAIN_DEVICE_HUB:

View File

@ -5062,6 +5062,7 @@
<value>ich7</value> <value>ich7</value>
<value>ich9</value> <value>ich9</value>
<value>usb</value> <value>usb</value>
<value>virtio</value>
</choice> </choice>
</attribute> </attribute>
<optional> <optional>
@ -5069,6 +5070,11 @@
<ref name="virYesNo"/> <ref name="virYesNo"/>
</attribute> </attribute>
</optional> </optional>
<optional>
<attribute name="streams">
<ref name="uint32"/>
</attribute>
</optional>
<interleave> <interleave>
<optional> <optional>
<ref name="alias"/> <ref name="alias"/>
@ -5089,6 +5095,11 @@
<zeroOrMore> <zeroOrMore>
<ref name="codec"/> <ref name="codec"/>
</zeroOrMore> </zeroOrMore>
<optional>
<element name="driver">
<ref name="virtioOptions"/>
</element>
</optional>
</interleave> </interleave>
</element> </element>
</define> </define>

View File

@ -344,6 +344,7 @@ libxlDomainDefValidate(const virDomainDef *def,
case VIR_DOMAIN_SOUND_MODEL_ICH7: case VIR_DOMAIN_SOUND_MODEL_ICH7:
case VIR_DOMAIN_SOUND_MODEL_USB: case VIR_DOMAIN_SOUND_MODEL_USB:
case VIR_DOMAIN_SOUND_MODEL_ICH9: case VIR_DOMAIN_SOUND_MODEL_ICH9:
case VIR_DOMAIN_SOUND_MODEL_VIRTIO:
case VIR_DOMAIN_SOUND_MODEL_LAST: case VIR_DOMAIN_SOUND_MODEL_LAST:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("unsupported audio model %1$s"), _("unsupported audio model %1$s"),

View File

@ -4482,6 +4482,7 @@ qemuBuildSoundDevCmd(virCommand *cmd,
case VIR_DOMAIN_SOUND_MODEL_SB16: case VIR_DOMAIN_SOUND_MODEL_SB16:
model = "sb16"; model = "sb16";
break; break;
case VIR_DOMAIN_SOUND_MODEL_VIRTIO:
case VIR_DOMAIN_SOUND_MODEL_PCSPK: /* pc-speaker is handled separately */ case VIR_DOMAIN_SOUND_MODEL_PCSPK: /* pc-speaker is handled separately */
case VIR_DOMAIN_SOUND_MODEL_ICH7: case VIR_DOMAIN_SOUND_MODEL_ICH7:
case VIR_DOMAIN_SOUND_MODEL_LAST: case VIR_DOMAIN_SOUND_MODEL_LAST:

View File

@ -324,6 +324,12 @@ qemuDomainPrimeVirtioDeviceAddresses(virDomainDef *def,
if (def->cryptos[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE) if (def->cryptos[i]->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_NONE)
def->cryptos[i]->info.type = type; 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: case VIR_DOMAIN_SOUND_MODEL_ICH9:
return pciFlags; return pciFlags;
case VIR_DOMAIN_SOUND_MODEL_VIRTIO:
return virtioFlags;
case VIR_DOMAIN_SOUND_MODEL_SB16: case VIR_DOMAIN_SOUND_MODEL_SB16:
case VIR_DOMAIN_SOUND_MODEL_PCSPK: case VIR_DOMAIN_SOUND_MODEL_PCSPK:
case VIR_DOMAIN_SOUND_MODEL_USB: case VIR_DOMAIN_SOUND_MODEL_USB:

View File

@ -4675,6 +4675,14 @@ qemuValidateDomainDeviceDefSound(virDomainSoundDef *sound,
} }
break; 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_ES1370:
case VIR_DOMAIN_SOUND_MODEL_AC97: case VIR_DOMAIN_SOUND_MODEL_AC97:
case VIR_DOMAIN_SOUND_MODEL_ICH6: case VIR_DOMAIN_SOUND_MODEL_ICH6: