[PATCH v3 3/6] conf: allow to map sound device to host device

Daniel P. Berrangé berrange at redhat.com
Fri Aug 7 16:07:55 UTC 2020


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 at 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 :|




More information about the libvir-list mailing list