On Fri, Aug 07, 2020 at 07:09:32PM +0400, Roman Bogorodskiy wrote:
Introduce a new device element "<audio>" which
allows
to map guest sound device specified using the "<sound>"
element to specific audio backend.
Example:
<sound model='ich7'>
<audio id='1'/>
</sound>
<audio id='1' type='oss'>
<input dev='/dev/dsp0'/>
<output dev='/dev/dsp0'/>
</audio>
This block maps to OSS audio backend on the host using
/dev/dsp0 device for both input (recording)
and output (playback).
OSS is the only backend supported so far.
Signed-off-by: Roman Bogorodskiy <bogorodskiy(a)gmail.com>
---
docs/schemas/domaincommon.rng | 36 +++++++
src/conf/domain_capabilities.c | 4 +
src/conf/domain_conf.c | 176 ++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 28 ++++++
src/conf/virconftypes.h | 3 +
src/libvirt_private.syms | 2 +
src/qemu/qemu_command.c | 1 +
src/qemu/qemu_domain.c | 1 +
src/qemu/qemu_domain_address.c | 2 +
src/qemu/qemu_driver.c | 5 +
src/qemu/qemu_hotplug.c | 3 +
src/qemu/qemu_validate.c | 1 +
12 files changed, 260 insertions(+), 2 deletions(-)
+void virDomainAudioDefFree(virDomainAudioDefPtr def)
+{
+ if (!def)
+ return;
+
+ switch (def->type) {
Cast to (virDomainAudioType), so the compiler forces the
existance of all possible cases.
+ case VIR_DOMAIN_AUDIO_TYPE_OSS:
+ VIR_FREE(def->backend.oss.inputDev);
+ VIR_FREE(def->backend.oss.outputDev);
+ break;
+
+ case VIR_DOMAIN_AUDIO_TYPE_LAST:
+ break;
+ }
+
+ VIR_FREE(def);
+}
+
virDomainSoundDefPtr
virDomainSoundDefRemove(virDomainDefPtr def, size_t idx)
{
@@ -3225,6 +3249,9 @@ void virDomainDeviceDefFree(virDomainDeviceDefPtr def)
case VIR_DOMAIN_DEVICE_VSOCK:
virDomainVsockDefFree(def->data.vsock);
break;
+ case VIR_DOMAIN_DEVICE_AUDIO:
+ virDomainAudioDefFree(def->data.audio);
+ break;
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_NONE:
break;
@@ -3485,6 +3512,10 @@ void virDomainDefFree(virDomainDefPtr def)
virDomainSoundDefFree(def->sounds[i]);
VIR_FREE(def->sounds);
+ for (i = 0; i < def->naudios; i++)
+ virDomainAudioDefFree(def->audios[i]);
+ VIR_FREE(def->audios);
+
for (i = 0; i < def->nvideos; i++)
virDomainVideoDefFree(def->videos[i]);
VIR_FREE(def->videos);
@@ -4073,6 +4104,7 @@ virDomainDeviceGetInfo(virDomainDeviceDefPtr device)
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_GRAPHICS:
case VIR_DOMAIN_DEVICE_IOMMU:
+ case VIR_DOMAIN_DEVICE_AUDIO:
case VIR_DOMAIN_DEVICE_LAST:
case VIR_DOMAIN_DEVICE_NONE:
break;
@@ -4167,6 +4199,9 @@ virDomainDeviceSetData(virDomainDeviceDefPtr device,
case VIR_DOMAIN_DEVICE_LEASE:
device->data.lease = devicedata;
break;
+ case VIR_DOMAIN_DEVICE_AUDIO:
+ device->data.audio = devicedata;
+ break;
case VIR_DOMAIN_DEVICE_NONE:
case VIR_DOMAIN_DEVICE_LAST:
break;
@@ -4433,6 +4468,7 @@ virDomainDeviceInfoIterateInternal(virDomainDefPtr def,
case VIR_DOMAIN_DEVICE_MEMORY:
case VIR_DOMAIN_DEVICE_IOMMU:
case VIR_DOMAIN_DEVICE_VSOCK:
+ case VIR_DOMAIN_DEVICE_AUDIO:
break;
}
#endif
@@ -5425,6 +5461,7 @@ virDomainDeviceDefPostParseCommon(virDomainDeviceDefPtr dev,
case VIR_DOMAIN_DEVICE_PANIC:
case VIR_DOMAIN_DEVICE_MEMORY:
case VIR_DOMAIN_DEVICE_IOMMU:
+ case VIR_DOMAIN_DEVICE_AUDIO:
ret = 0;
break;
@@ -6814,6 +6851,8 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev,
case VIR_DOMAIN_DEVICE_SHMEM:
return virDomainShmemDefValidate(dev->data.shmem);
+ case VIR_DOMAIN_DEVICE_AUDIO:
+ /* TODO: validate? */
case VIR_DOMAIN_DEVICE_LEASE:
case VIR_DOMAIN_DEVICE_FS:
case VIR_DOMAIN_DEVICE_SOUND:
@@ -15016,10 +15055,10 @@ virDomainSoundDefParseXML(virDomainXMLOptionPtr xmlopt,
virDomainSoundDefPtr def;
VIR_XPATH_NODE_AUTORESTORE(ctxt);
g_autofree char *model = NULL;
+ xmlNodePtr audioNode;
if (VIR_ALLOC(def) < 0)
return NULL;
-
ctxt->node = node;
model = virXMLPropString(node, "model");
@@ -15056,6 +15095,18 @@ virDomainSoundDefParseXML(virDomainXMLOptionPtr xmlopt,
}
}
+ audioNode = virXPathNode("./audio", ctxt);
+ if (audioNode) {
+ g_autofree char *tmp = NULL;
+ tmp = virXMLPropString(audioNode, "id");
+ if (virStrToLong_ui(tmp, NULL, 10, &def->audioId) < 0 ||
+ def->audioId == 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Invalid audio 'id' value '%s'"),
tmp);
+ goto error;
+ }
+ }
+
if (virDomainDeviceInfoParseXML(xmlopt, node, &def->info, flags) < 0)
goto error;
@@ -15107,6 +15158,58 @@ virDomainSoundDefFind(const virDomainDef *def,
}
+static virDomainAudioDefPtr
+virDomainAudioDefParseXML(virDomainXMLOptionPtr xmlopt G_GNUC_UNUSED,
+ xmlNodePtr node G_GNUC_UNUSED,
+ xmlXPathContextPtr ctxt G_GNUC_UNUSED)
+{
+ virDomainAudioDefPtr def;
+ VIR_XPATH_NODE_AUTORESTORE(ctxt);
+ g_autofree char *tmp = NULL;
+ g_autofree char *type = NULL;
+
+ if (VIR_ALLOC(def) < 0)
+ return NULL;
+ ctxt->node = node;
+
+ type = virXMLPropString(node, "type");
+ if ((def->type = virDomainAudioTypeTypeFromString(type)) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("unknown audio type '%s'"), type);
+ goto error;
+ }
+
+ tmp = virXMLPropString(node, "id");
+ if (virStrToLong_ui(tmp, NULL, 10, &def->id) < 0 ||
+ def->id == 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid audio 'id' value '%s'"),
tmp);
+ goto error;
+ }
+
+ if (def->type == VIR_DOMAIN_AUDIO_TYPE_OSS) {
Use a switch here again to force compiler checking of all csaes.
+ xmlNodePtr inputDevNode, outputDevNode;
+
+ inputDevNode = virXPathNode("./input", ctxt);
+ outputDevNode = virXPathNode("./output", ctxt);
+
+ if (!inputDevNode || !outputDevNode) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("Audio type OSS requires to have <input> "
+ "and <output> specified"));
+ goto error;
+ }
+
+ def->backend.oss.inputDev = virXMLPropString(inputDevNode, "dev");
+ def->backend.oss.outputDev = virXMLPropString(outputDevNode,
"dev");
+ }
Looks fine bar the switch()
Regards,
Daniel
--
|:
https://berrange.com -o-
https://www.flickr.com/photos/dberrange :|
|:
https://libvirt.org -o-
https://fstop138.berrange.com :|
|:
https://entangle-photo.org -o-
https://www.instagram.com/dberrange :|