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 ``<codec>`` to attach various audio codecs to the audio
<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
the device to a particular PCI slot. See `Device Addresses`_.
"ich9",
"usb",
"ich7",
+ "virtio",
);
VIR_ENUM_IMPL(virDomainAudioType,
virDomainSoundCodecDefFree(def->codecs[i]);
g_free(def->codecs);
+ g_free(def->virtio);
g_free(def);
}
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,
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);
}
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;
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) {
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;
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;
virTristateBool multichannel;
unsigned int audioId;
+
+ unsigned int streams;
+ virDomainVirtioOptions *virtio;
};
typedef enum {
}
}
+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,
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:
<value>ich7</value>
<value>ich9</value>
<value>usb</value>
+ <value>virtio</value>
</choice>
</attribute>
<optional>
<ref name="virYesNo"/>
</attribute>
</optional>
+ <optional>
+ <attribute name="streams">
+ <ref name="uint32"/>
+ </attribute>
+ </optional>
<interleave>
<optional>
<ref name="alias"/>
<zeroOrMore>
<ref name="codec"/>
</zeroOrMore>
+ <optional>
+ <element name="driver">
+ <ref name="virtioOptions"/>
+ </element>
+ </optional>
</interleave>
</element>
</define>
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"),
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:
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;
+ }
}
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:
}
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: