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@xxxxxxxxxx> --- 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