[libvirt PATCH 17/18] conf: add support for audio backend specific settings

Daniel P. Berrangé berrange at redhat.com
Wed Mar 3 18:18:33 UTC 2021


This pulls in the remaining QEMU audio backend specific settings to the
XML schema.

    <audio id="1" type="alsa">
      <input dev="/dev/dsp0"/>
      <output dev="/dev/dsp1"/>
    </audio>

    <audio id="1" type="coreaudio">
      <input bufferCount="50"/>
      <output bufferCount="42"/>
    </audio>

    <audio id="1" type="file" path="audio.wav"/>

    <audio id="1" type="jack">
      <input serverName="fish" clientName="food" connectPorts="yum"/>
      <output serverName="fish" clientName="food" connectPorts="yum"/>
    </audio>

    <audio id="1" type="oss" tryMMap="yes" exclusive="yes" dspPolicy="3">
      <input dev="/dev/dsp0" bufferCount="50" tryPoll="yes"/>
      <output dev="/dev/dsp1" bufferCount="30" tryPoll="no"/>
    </audio>

    <audio id="1" type="pulseaudio" serverName="acme.example.org">
      <input name="fish" streamName="food" latency="100"/>
      <output name="fish" streamName="food" latency="200"/>
    </audio>

    <audio type='sdl' id='1' driver='pulseaudio'>
      <input bufferCount='40'/>
      <output bufferCount='40'/>
    </audio>

Signed-off-by: Daniel P. Berrangé <berrange at redhat.com>
---
 docs/formatdomain.rst         | 140 +++++++++++++++++-
 docs/schemas/domaincommon.rng |  75 ++++++++++
 src/conf/domain_conf.c        | 271 +++++++++++++++++++++++++++++++++-
 src/conf/domain_conf.h        |  57 +++++++
 4 files changed, 538 insertions(+), 5 deletions(-)

diff --git a/docs/formatdomain.rst b/docs/formatdomain.rst
index d773341c66..2b1d045a70 100644
--- a/docs/formatdomain.rst
+++ b/docs/formatdomain.rst
@@ -6924,6 +6924,21 @@ ALSA audio backend
 
 The 'alsa' audio type uses the ALSA host audio device framework.
 
+The following additional attributes are permitted on the ``<input>``
+and ``<output>`` elements
+
+* ``dev``
+
+  Path to the host device node to connect the backend to. A hypervisor
+  specific default applies if not specified.
+
+::
+
+   <audio id="1" type="alsa">
+     <input dev="/dev/dsp0"/>
+     <output dev="/dev/dsp1"/>
+   </audio>
+
 :since:`Since 7.2.0, qemu`
 
 Coreaudio audio backend
@@ -6932,6 +6947,21 @@ Coreaudio audio backend
 The 'coreaudio' audio backend delegates to a CoreAudio host audio framework
 for input and output on macOS.
 
+The following additional attributes are permitted on the ``<input>``
+and ``<output>`` elements
+
+* ``bufferCount``
+
+  The number of buffers. It is recommended to set the ``bufferLength``
+  attribute at the same time.
+
+::
+
+   <audio id="1" type="coreaudio">
+     <input bufferCount="50"/>
+     <output bufferCount="42"/>
+   </audio>
+
 :since:`Since 7.2.0, qemu`
 
 Jack audio backend
@@ -6940,6 +6970,34 @@ Jack audio backend
 The 'jack' audio backend delegates to a Jack daemon for audio input
 and output.
 
+The following additional attributes are permitted on the ``<input>``
+and ``<output>`` elements
+
+* ``serverName``
+
+  Select the Jack server instance to connect to.
+
+* ``clientName``
+
+  The client name to identify as. The server may modify this to
+  ensure uniqueness unless ``exactName`` is enabled
+
+* ``connectPorts``
+
+  A regular expression of Jack client port names to monitor and
+  connect to.
+
+* ``exactName``
+
+  Use the exact ``clientName`` requested
+
+::
+
+   <audio id="1" type="jack">
+     <input serverName="fish" clientName="food" connectPorts="system:capture_[13]" exactName="yes"/>
+     <output serverName="fish" clientName="food" connectPorts="system:playback_[13]" exactName="yes"/>
+   </audio>
+
 :since:`Since 7.2.0, qemu`
 
 OSS audio backend
@@ -6947,6 +7005,23 @@ OSS audio backend
 
 The 'oss' audio type uses the OSS host audio device framework.
 
+The following additional attributes are permitted on the ``<audio>``
+element
+
+* ``tryMMap``
+
+  Attempt to use mmap for data transfer
+
+* ``exclusive``
+
+  Enforce exclusive access to the host device
+
+* ``dspPolicy``
+
+  Set the timing policy of the device, values between -1 and 10.
+  Smaller numbers result in lower latency but higher CPU usage.
+  A negatve value requests use of fragment mode.
+
 The following additional attributes are permitted on the ``<input>``
 and ``<output>`` elements
 
@@ -6955,11 +7030,20 @@ and ``<output>`` elements
   Path to the host device node to connect the backend to. A hypervisor
   specific default applies if not specified.
 
+* ``bufferCount``
+
+  The number of buffers. It is recommended to set the ``bufferLength``
+  attribute at the same time.
+
+* ``tryPoll``
+
+  Attempt to use polling mode
+
 ::
 
-   <audio type='oss' id='1'>
-     <input dev='/dev/dsp0'/>
-     <output dev='/dev/dsp0'/>
+   <audio type='oss' id='1' tryMMap='yes' exclusive='yes' dspPolicy='4'>
+     <input dev='/dev/dsp0' bufferCount='40' tryPoll='yes'/>
+     <output dev='/dev/dsp0' bufferCount='40' tryPoll='yes'/>
    </audio>
 
 :since:`Since 6.7.0, bhyve; Since 7.2.0, qemu`
@@ -6970,6 +7054,35 @@ PulseAudio audio backend
 The 'pulseaudio' audio backend delegates to a PulseAudio daemon audio input
 and output.
 
+The following additional attributes are permitted on the ``<audio>``
+element
+
+* ``serverName``
+
+  Hostname of the PulseAudio server
+
+The following additional attributes are permitted on the ``<input>``
+and ``<output>`` elements
+
+* ``name``
+
+  The sink/source name to use
+
+* ``streamName``
+
+  The name to identify the stream associated with the VM
+
+* ``latency``
+
+  Desired latency for the server to target in microseconds
+
+::
+
+   <audio id="1" type="pulseaudio" serverName="acme.example.org">
+     <input name="fish" streamName="food" latency="100"/>
+     <output name="fish" streamName="food" latency="200"/>
+   </audio>
+
 :since:`Since 7.2.0, qemu`
 
 SDL audio backend
@@ -6986,9 +7099,20 @@ element
   SDL audio driver. The ``name`` attribute specifies SDL driver name,
   one of 'esd', 'alsa', 'arts', 'pulseaudio'.
 
+The following additional attributes are permitted on the ``<input>``
+and ``<output>`` elements
+
+* ``bufferCount``
+
+  The number of buffers. It is recommended to set the ``bufferLength``
+  attribute at the same time.
+
 ::
 
-   <audio type='sdl' id='1' driver='pulseaudio'/>
+   <audio type='sdl' id='1' driver='pulseaudio'>
+     <input bufferCount='40'/>
+     <output bufferCount='40'/>
+   </audio>
 
 :since:`Since 7.2.0, qemu`
 
@@ -7000,6 +7124,10 @@ it does not connect to any host audio framework. It exclusively
 allows a SPICE server to send and receive audio. This is the default
 backend when SPICE graphics are enabled in QEMU.
 
+::
+
+   <audio type='spice' id='1'/>
+
 :since:`Since 7.2.0, qemu`
 
 File audio backend
@@ -7009,6 +7137,10 @@ The 'file' audio backend is an output only driver which records
 audio to a file. The file format is implementation defined, and
 defaults to 'WAV' with QEMU.
 
+::
+
+   <audio id="1" type="file" path="audio.wav"/>
+
 :since:`Since 7.2.0, qemu`
 
 :anchor:`<a id="elementsWatchdog"/>`
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 82fc74ca00..84a4910203 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -4603,6 +4603,26 @@
 
   <define name="audiojack">
     <ref name="audiocommonattr"/>
+    <optional>
+      <attribute name="serverName">
+        <data type="string"/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name="clientName">
+        <data type="string"/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name="connectPorts">
+        <data type="string"/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name="exactName">
+        <ref name="virYesNo"/>
+      </attribute>
+    </optional>
     <ref name="audiocommonchild"/>
   </define>
 
@@ -4613,16 +4633,46 @@
         <ref name="filePath"/>
       </attribute>
     </optional>
+    <optional>
+      <attribute name="bufferCount">
+        <ref name="uint32"/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name="tryPoll">
+        <ref name="virYesNo"/>
+      </attribute>
+    </optional>
     <ref name="audiocommonchild"/>
   </define>
 
   <define name="audiopulseaudio">
     <ref name="audiocommonattr"/>
+    <optional>
+      <attribute name="name">
+        <data type="string"/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name="streamName">
+        <data type="string"/>
+      </attribute>
+    </optional>
+    <optional>
+      <attribute name="latency">
+        <ref name="uint32"/>
+      </attribute>
+    </optional>
     <ref name="audiocommonchild"/>
   </define>
 
   <define name="audiosdl">
     <ref name="audiocommonattr"/>
+    <optional>
+      <attribute name="bufferCount">
+        <ref name="uint32"/>
+      </attribute>
+    </optional>
     <ref name="audiocommonchild"/>
   </define>
 
@@ -4716,6 +4766,21 @@
               <value>oss</value>
             </choice>
           </attribute>
+          <optional>
+            <attribute name="tryMMap">
+              <ref name="virYesNo"/>
+            </attribute>
+          </optional>
+          <optional>
+            <attribute name="exclusive">
+              <ref name="virYesNo"/>
+            </attribute>
+          </optional>
+          <optional>
+            <attribute name="dspPolicy">
+              <data type="int"/>
+            </attribute>
+          </optional>
           <interleave>
             <optional>
               <element name="input">
@@ -4733,6 +4798,11 @@
           <attribute name="type">
             <value>pulseaudio</value>
           </attribute>
+          <optional>
+            <attribute name="serverName">
+              <data type="string"/>
+            </attribute>
+          </optional>
           <interleave>
             <optional>
               <element name="input">
@@ -4794,6 +4864,11 @@
           <attribute name="type">
             <value>file</value>
           </attribute>
+          <optional>
+            <attribute name="path">
+              <ref name="filePath"/>
+            </attribute>
+          </optional>
           <interleave>
             <optional>
               <element name="input">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 5936f5937f..71bd2d06db 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -2918,12 +2918,33 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def)
     g_free(def);
 }
 
+static void
+virDomainAudioIOALSAFree(virDomainAudioIOALSA *def)
+{
+    g_free(def->dev);
+}
+
+static void
+virDomainAudioIOJackFree(virDomainAudioIOJack *def)
+{
+    g_free(def->serverName);
+    g_free(def->clientName);
+    g_free(def->connectPorts);
+}
+
 static void
 virDomainAudioIOOSSFree(virDomainAudioIOOSS *def)
 {
     g_free(def->dev);
 }
 
+static void
+virDomainAudioIOPulseAudioFree(virDomainAudioIOPulseAudio *def)
+{
+    g_free(def->name);
+    g_free(def->streamName);
+}
+
 void
 virDomainAudioDefFree(virDomainAudioDefPtr def)
 {
@@ -2935,12 +2956,16 @@ virDomainAudioDefFree(virDomainAudioDefPtr def)
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_ALSA:
+        virDomainAudioIOALSAFree(&def->backend.alsa.input);
+        virDomainAudioIOALSAFree(&def->backend.alsa.output);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_COREAUDIO:
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_JACK:
+        virDomainAudioIOJackFree(&def->backend.jack.input);
+        virDomainAudioIOJackFree(&def->backend.jack.output);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_OSS:
@@ -2949,6 +2974,9 @@ virDomainAudioDefFree(virDomainAudioDefPtr def)
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_PULSEAUDIO:
+        virDomainAudioIOPulseAudioFree(&def->backend.pulseaudio.input);
+        virDomainAudioIOPulseAudioFree(&def->backend.pulseaudio.output);
+        g_free(def->backend.pulseaudio.serverName);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_SDL:
@@ -2958,6 +2986,7 @@ virDomainAudioDefFree(virDomainAudioDefPtr def)
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_FILE:
+        g_free(def->backend.file.path);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_LAST:
@@ -14036,12 +14065,118 @@ virDomainAudioCommonParse(virDomainAudioIOCommon *def,
 }
 
 
+static void
+virDomainAudioALSAParse(virDomainAudioIOALSA *def,
+                        xmlNodePtr node)
+{
+    def->dev = virXMLPropString(node, "dev");
+}
+
+
+static int
+virDomainAudioCoreAudioParse(virDomainAudioIOCoreAudio *def,
+                             xmlNodePtr node)
+{
+    g_autofree char *bufferCount = virXMLPropString(node, "bufferCount");
+
+    if (bufferCount &&
+        virStrToLong_ui(bufferCount, NULL, 10,
+                        &def->bufferCount) < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("cannot parse 'bufferCount' value '%s'"), bufferCount);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int
+virDomainAudioJackParse(virDomainAudioIOJack *def,
+                        xmlNodePtr node)
+{
+    g_autofree char *exactName = virXMLPropString(node, "exactName");
+
+    def->serverName = virXMLPropString(node, "serverName");
+    def->clientName = virXMLPropString(node, "clientName");
+    def->connectPorts = virXMLPropString(node, "connectPorts");
+
+    if (exactName &&
+        ((def->exactName =
+          virTristateBoolTypeFromString(exactName)) <= 0)) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("unknown 'exactName' value '%s'"), exactName);
+        return -1;
+    }
+
+    return 0;
+}
+
+
 static int
 virDomainAudioOSSParse(virDomainAudioIOOSS *def,
                        xmlNodePtr node)
 {
+    g_autofree char *tryPoll = virXMLPropString(node, "tryPoll");
+    g_autofree char *bufferCount = virXMLPropString(node, "bufferCount");
+
     def->dev = virXMLPropString(node, "dev");
 
+    if (tryPoll &&
+        ((def->tryPoll =
+          virTristateBoolTypeFromString(tryPoll)) <= 0)) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("unknown 'tryPoll' value '%s'"), tryPoll);
+        return -1;
+    }
+
+    if (bufferCount &&
+        virStrToLong_ui(bufferCount, NULL, 10,
+                        &def->bufferCount) < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("cannot parse 'bufferCount' value '%s'"), bufferCount);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int
+virDomainAudioPulseAudioParse(virDomainAudioIOPulseAudio *def,
+                              xmlNodePtr node)
+{
+    g_autofree char *latency = virXMLPropString(node, "latency");
+
+    def->name = virXMLPropString(node, "name");
+    def->streamName = virXMLPropString(node, "streamName");
+
+    if (latency &&
+        virStrToLong_ui(latency, NULL, 10,
+                        &def->latency) < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("cannot parse 'latency' value '%s'"), latency);
+        return -1;
+    }
+
+    return 0;
+}
+
+
+static int
+virDomainAudioSDLParse(virDomainAudioIOSDL *def,
+                       xmlNodePtr node)
+{
+    g_autofree char *bufferCount = virXMLPropString(node, "bufferCount");
+
+    if (bufferCount &&
+        virStrToLong_ui(bufferCount, NULL, 10,
+                        &def->bufferCount) < 0) {
+        virReportError(VIR_ERR_XML_ERROR,
+                       _("cannot parse 'bufferCount' value '%s'"), bufferCount);
+        return -1;
+    }
+
     return 0;
 }
 
@@ -14099,22 +14234,69 @@ virDomainAudioDefParseXML(virDomainXMLOptionPtr xmlopt G_GNUC_UNUSED,
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_ALSA:
+        if (inputNode)
+            virDomainAudioALSAParse(&def->backend.alsa.input, inputNode);
+        if (outputNode)
+            virDomainAudioALSAParse(&def->backend.alsa.output, outputNode);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_COREAUDIO:
+        if (inputNode)
+            virDomainAudioCoreAudioParse(&def->backend.coreaudio.input, inputNode);
+        if (outputNode)
+            virDomainAudioCoreAudioParse(&def->backend.coreaudio.output, outputNode);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_JACK:
+        if (inputNode)
+            virDomainAudioJackParse(&def->backend.jack.input, inputNode);
+        if (outputNode)
+            virDomainAudioJackParse(&def->backend.jack.output, outputNode);
         break;
 
-    case VIR_DOMAIN_AUDIO_TYPE_OSS:
+    case VIR_DOMAIN_AUDIO_TYPE_OSS: {
+        g_autofree char *tryMMap = virXMLPropString(node, "tryMMap");
+        g_autofree char *exclusive = virXMLPropString(node, "exclusive");
+        g_autofree char *dspPolicy = virXMLPropString(node, "dspPolicy");
+
+        if (tryMMap && ((def->backend.oss.tryMMap =
+                         virTristateBoolTypeFromString(tryMMap)) <= 0)) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("unknown 'tryMMap' value '%s'"), tryMMap);
+            goto error;
+        }
+
+        if (exclusive && ((def->backend.oss.exclusive =
+                           virTristateBoolTypeFromString(exclusive)) <= 0)) {
+            virReportError(VIR_ERR_XML_ERROR,
+                           _("unknown 'exclusive' value '%s'"), exclusive);
+            goto error;
+        }
+
+        if (dspPolicy) {
+            if (virStrToLong_i(dspPolicy, NULL, 10,
+                               &def->backend.oss.dspPolicy) < 0) {
+                virReportError(VIR_ERR_XML_ERROR,
+                               _("cannot parse 'dspPolicy' value '%s'"), dspPolicy);
+                goto error;
+            }
+            def->backend.oss.dspPolicySet = true;
+        }
+
         if (inputNode)
             virDomainAudioOSSParse(&def->backend.oss.input, inputNode);
         if (outputNode)
             virDomainAudioOSSParse(&def->backend.oss.output, outputNode);
         break;
+    }
 
     case VIR_DOMAIN_AUDIO_TYPE_PULSEAUDIO:
+        def->backend.pulseaudio.serverName = virXMLPropString(node, "serverName");
+
+        if (inputNode)
+            virDomainAudioPulseAudioParse(&def->backend.pulseaudio.input, inputNode);
+        if (outputNode)
+            virDomainAudioPulseAudioParse(&def->backend.pulseaudio.output, outputNode);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_SDL: {
@@ -14126,6 +14308,11 @@ virDomainAudioDefParseXML(virDomainXMLOptionPtr xmlopt G_GNUC_UNUSED,
                            _("unknown SDL driver '%s'"), driver);
             goto error;
         }
+
+        if (inputNode)
+            virDomainAudioSDLParse(&def->backend.sdl.input, inputNode);
+        if (outputNode)
+            virDomainAudioSDLParse(&def->backend.sdl.output, outputNode);
         break;
     }
 
@@ -14133,6 +14320,7 @@ virDomainAudioDefParseXML(virDomainXMLOptionPtr xmlopt G_GNUC_UNUSED,
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_FILE:
+        def->backend.file.path = virXMLPropString(node, "path");
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_LAST:
@@ -26656,11 +26844,68 @@ virDomainAudioCommonFormat(virDomainAudioIOCommon *def,
     }
 }
 
+
+static void
+virDomainAudioALSAFormat(virDomainAudioIOALSA *def,
+                         virBufferPtr buf)
+{
+    virBufferEscapeString(buf, " dev='%s'", def->dev);
+}
+
+
+static void
+virDomainAudioCoreAudioFormat(virDomainAudioIOCoreAudio *def,
+                              virBufferPtr buf)
+{
+    if (def->bufferCount)
+        virBufferAsprintf(buf, " bufferCount='%u'", def->bufferCount);
+}
+
+
+static void
+virDomainAudioJackFormat(virDomainAudioIOJack *def,
+                         virBufferPtr buf)
+{
+    virBufferEscapeString(buf, " serverName='%s'", def->serverName);
+    virBufferEscapeString(buf, " clientName='%s'", def->clientName);
+    virBufferEscapeString(buf, " connectPorts='%s'", def->connectPorts);
+    if (def->exactName)
+        virBufferAsprintf(buf, " exactName='%s'",
+                          virTristateBoolTypeToString(def->exactName));
+}
+
+
 static void
 virDomainAudioOSSFormat(virDomainAudioIOOSS *def,
                         virBufferPtr buf)
 {
     virBufferEscapeString(buf, " dev='%s'", def->dev);
+    if (def->bufferCount)
+        virBufferAsprintf(buf, " bufferCount='%u'", def->bufferCount);
+    if (def->tryPoll)
+        virBufferAsprintf(buf, " tryPoll='%s'",
+                          virTristateBoolTypeToString(def->tryPoll));
+}
+
+
+static void
+virDomainAudioPulseAudioFormat(virDomainAudioIOPulseAudio *def,
+                               virBufferPtr buf)
+{
+    virBufferEscapeString(buf, " name='%s'", def->name);
+    virBufferEscapeString(buf, " streamName='%s'", def->streamName);
+    if (def->latency)
+        virBufferAsprintf(buf, " latency='%u'", def->latency);
+
+}
+
+
+static void
+virDomainAudioSDLFormat(virDomainAudioIOSDL *def,
+                        virBufferPtr buf)
+{
+    if (def->bufferCount)
+        virBufferAsprintf(buf, " bufferCount='%u'", def->bufferCount);
 }
 
 
@@ -26686,20 +26931,40 @@ virDomainAudioDefFormat(virBufferPtr buf,
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_ALSA:
+        virDomainAudioALSAFormat(&def->backend.alsa.input, &inputBuf);
+        virDomainAudioALSAFormat(&def->backend.alsa.output, &outputBuf);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_COREAUDIO:
+        virDomainAudioCoreAudioFormat(&def->backend.coreaudio.input, &inputBuf);
+        virDomainAudioCoreAudioFormat(&def->backend.coreaudio.output, &outputBuf);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_JACK:
+        virDomainAudioJackFormat(&def->backend.jack.input, &inputBuf);
+        virDomainAudioJackFormat(&def->backend.jack.output, &outputBuf);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_OSS:
+        if (def->backend.oss.tryMMap)
+            virBufferAsprintf(buf, " tryMMap='%s'",
+                              virTristateBoolTypeToString(def->backend.oss.tryMMap));
+        if (def->backend.oss.exclusive)
+            virBufferAsprintf(buf, " exclusive='%s'",
+                              virTristateBoolTypeToString(def->backend.oss.exclusive));
+        if (def->backend.oss.dspPolicySet)
+            virBufferAsprintf(buf, " dspPolicy='%d'", def->backend.oss.dspPolicy);
+
         virDomainAudioOSSFormat(&def->backend.oss.input, &inputBuf);
         virDomainAudioOSSFormat(&def->backend.oss.output, &outputBuf);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_PULSEAUDIO:
+        virBufferEscapeString(buf, " serverName='%s'",
+                              def->backend.pulseaudio.serverName);
+
+        virDomainAudioPulseAudioFormat(&def->backend.pulseaudio.input, &inputBuf);
+        virDomainAudioPulseAudioFormat(&def->backend.pulseaudio.output, &outputBuf);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_SDL:
@@ -26707,12 +26972,16 @@ virDomainAudioDefFormat(virBufferPtr buf,
             virBufferAsprintf(buf, " driver='%s'",
                               virDomainAudioSDLDriverTypeToString(
                                   def->backend.sdl.driver));
+
+        virDomainAudioSDLFormat(&def->backend.sdl.input, &inputBuf);
+        virDomainAudioSDLFormat(&def->backend.sdl.output, &outputBuf);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_SPICE:
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_FILE:
+        virBufferEscapeString(buf, " path='%s'", def->backend.file.path);
         break;
 
     case VIR_DOMAIN_AUDIO_TYPE_LAST:
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 4ccadbaf37..2a174a60cf 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -1493,10 +1493,41 @@ struct _virDomainAudioIOCommon {
     unsigned int bufferLength; /* milliseconds */
 };
 
+typedef struct _virDomainAudioIOALSA virDomainAudioIOALSA;
+struct _virDomainAudioIOALSA {
+    char *dev;
+};
+
+typedef struct _virDomainAudioIOCoreAudio virDomainAudioIOCoreAudio;
+struct _virDomainAudioIOCoreAudio {
+    unsigned int bufferCount;
+};
+
+typedef struct _virDomainAudioIOJack virDomainAudioIOJack;
+struct _virDomainAudioIOJack {
+    char *serverName;
+    char *clientName;
+    char *connectPorts;
+    virTristateBool exactName;
+};
 
 typedef struct _virDomainAudioIOOSS virDomainAudioIOOSS;
 struct _virDomainAudioIOOSS {
     char *dev;
+    unsigned int bufferCount;
+    virTristateBool tryPoll;
+};
+
+typedef struct _virDomainAudioIOPulseAudio virDomainAudioIOPulseAudio;
+struct _virDomainAudioIOPulseAudio {
+    char *name;
+    char *streamName;
+    unsigned int latency;
+};
+
+typedef struct _virDomainAudioIOSDL virDomainAudioIOSDL;
+struct _virDomainAudioIOSDL {
+    unsigned int bufferCount;
 };
 
 struct _virDomainAudioDef {
@@ -1507,13 +1538,39 @@ struct _virDomainAudioDef {
     virDomainAudioIOCommon input;
     virDomainAudioIOCommon output;
     union {
+        struct {
+            virDomainAudioIOALSA input;
+            virDomainAudioIOALSA output;
+        } alsa;
+        struct {
+            virDomainAudioIOCoreAudio input;
+            virDomainAudioIOCoreAudio output;
+        } coreaudio;
+        struct {
+            virDomainAudioIOJack input;
+            virDomainAudioIOJack output;
+        } jack;
         struct {
             virDomainAudioIOOSS input;
             virDomainAudioIOOSS output;
+            virTristateBool tryMMap;
+            virTristateBool exclusive;
+            bool dspPolicySet;
+            int dspPolicy;
         } oss;
         struct {
+            virDomainAudioIOPulseAudio input;
+            virDomainAudioIOPulseAudio output;
+            char *serverName;
+        } pulseaudio;
+        struct {
+            virDomainAudioIOSDL input;
+            virDomainAudioIOSDL output;
             int driver; /* virDomainAudioSDLDriver */
         } sdl;
+        struct {
+            char *path;
+        } file;
     } backend;
 };
 
-- 
2.29.2




More information about the libvir-list mailing list