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@xxxxxxxxx> > --- > 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 :|