``id``
Integer id of the audio device. Must be greater than 0.
+All the backends support child element for configuring input and
+output properties
+
+::
+
+ ...
+ <devices>
+ <audio id='1' type='pulseaudio'>
+ <input mixingEngine='yes' fixedSettings='yes' voices='1' bufferLength='100'>
+ <settings frequency='44100' channels='2' format='s16'/>
+ </input>
+ <output mixingEngine='yes' fixedSettings='yes' voices='2' bufferLength='100'>
+ <settings frequency='22050' channels='4' format='f32'/>
+ </output>
+ </audio>
+ </devices>
+ ...
+
+The input and output elements support the same set of attributes and
+elements
+
+* ``mixingEngine``
+
+ Control whether the host mixing engine is used to convert between
+ different audio formats and sampling rates. When the mixing engine
+ is disabled it is possible to make use of improved audio formats
+ such as 5.1/7.1. If not specified, a hypervisor default applies.
+
+* ``fixedSettings``
+
+ Control whether the mixing engine can dynamically choose settings
+ to mimimize format conversion. This is only valid when the
+ mixing engine is explicitly enabled.
+
+* ``voices``
+
+ The number of voices voices to use, usually defaults to 1
+
+* ``bufferLength``
+
+ The length of the audio buffer in microseconds. Default is
+ backend specific.
+
+The ``<input>`` and ``<output>`` elements may also permit backend
+specific options.
+
+When fixed settings are enabled, the ``<settings>`` child element
+is permitted with the following attributes.
+
+* ``frequency``
+
+ The frequency in HZ, usually defaulting to 44100
+
+* ``channels``
+
+ The number of channels, usually defaulting to 2. The permitted
+ max number of channels is hypervisor specific.
+
+* ``format``
+
+ The audio format, one of ``s8``, ``u8``, ``s16``, ``u16``,
+ ``s32``, ``u32``, ``f32``. The defalt is hypervisor specific.
+
None audio backend
^^^^^^^^^^^^^^^^^^
</element>
</define>
+ <define name="audiocommonattr">
+ <optional>
+ <attribute name="mixingEngine">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="fixedSettings">
+ <ref name="virYesNo"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="voices">
+ <ref name="uint32"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="bufferLength">
+ <ref name="uint32"/>
+ </attribute>
+ </optional>
+ </define>
+
+ <define name="audiocommonchild">
+ <optional>
+ <element name="settings">
+ <optional>
+ <attribute name="frequency">
+ <ref name="uint32"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="channels">
+ <ref name="uint32"/>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="format">
+ <choice>
+ <value>s8</value>
+ <value>u8</value>
+ <value>s16</value>
+ <value>u16</value>
+ <value>s32</value>
+ <value>u32</value>
+ <value>f32</value>
+ </choice>
+ </attribute>
+ </optional>
+ </element>
+ </optional>
+ </define>
+
+ <define name="audionone">
+ <ref name="audiocommonattr"/>
+ <ref name="audiocommonchild"/>
+ </define>
+
+ <define name="audioalsa">
+ <ref name="audiocommonattr"/>
+ <optional>
+ <attribute name="dev">
+ <ref name="filePath"/>
+ </attribute>
+ </optional>
+ <ref name="audiocommonchild"/>
+ </define>
+
+ <define name="audiocoreaudio">
+ <ref name="audiocommonattr"/>
+ <optional>
+ <attribute name="bufferCount">
+ <ref name="uint32"/>
+ </attribute>
+ </optional>
+ <ref name="audiocommonchild"/>
+ </define>
+
+ <define name="audiojack">
+ <ref name="audiocommonattr"/>
+ <ref name="audiocommonchild"/>
+ </define>
+
<define name="audiooss">
+ <ref name="audiocommonattr"/>
<optional>
<attribute name="dev">
<ref name="deviceName"/>
</attribute>
</optional>
+ <ref name="audiocommonchild"/>
+ </define>
+
+ <define name="audiopulseaudio">
+ <ref name="audiocommonattr"/>
+ <ref name="audiocommonchild"/>
+ </define>
+
+ <define name="audiosdl">
+ <ref name="audiocommonattr"/>
+ <ref name="audiocommonchild"/>
+ </define>
+
+ <define name="audiospice">
+ <ref name="audiocommonattr"/>
+ <ref name="audiocommonchild"/>
+ </define>
+
+ <define name="audiofile">
+ <ref name="audiocommonattr"/>
+ <ref name="audiocommonchild"/>
</define>
<define name="audio">
<attribute name="type">
<value>none</value>
</attribute>
+ <interleave>
+ <optional>
+ <element name="input">
+ <ref name="audionone"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="output">
+ <ref name="audionone"/>
+ </element>
+ </optional>
+ </interleave>
</group>
<group>
<attribute name="type">
<value>alsa</value>
</attribute>
+ <interleave>
+ <optional>
+ <element name="input">
+ <ref name="audioalsa"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="output">
+ <ref name="audioalsa"/>
+ </element>
+ </optional>
+ </interleave>
</group>
<group>
<attribute name="type">
<value>coreaudio</value>
</attribute>
+ <interleave>
+ <optional>
+ <element name="input">
+ <ref name="audiocoreaudio"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="output">
+ <ref name="audiocoreaudio"/>
+ </element>
+ </optional>
+ </interleave>
</group>
<group>
<attribute name="type">
<value>jack</value>
</attribute>
+ <interleave>
+ <optional>
+ <element name="input">
+ <ref name="audiojack"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="output">
+ <ref name="audiojack"/>
+ </element>
+ </optional>
+ </interleave>
</group>
<group>
<attribute name="type">
<attribute name="type">
<value>pulseaudio</value>
</attribute>
+ <interleave>
+ <optional>
+ <element name="input">
+ <ref name="audiopulseaudio"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="output">
+ <ref name="audiopulseaudio"/>
+ </element>
+ </optional>
+ </interleave>
</group>
<group>
<attribute name="type">
</choice>
</attribute>
</optional>
+ <interleave>
+ <optional>
+ <element name="input">
+ <ref name="audiosdl"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="output">
+ <ref name="audiosdl"/>
+ </element>
+ </optional>
+ </interleave>
</group>
<group>
<attribute name="type">
<value>spice</value>
</attribute>
+ <interleave>
+ <optional>
+ <element name="input">
+ <ref name="audiospice"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="output">
+ <ref name="audiospice"/>
+ </element>
+ </optional>
+ </interleave>
</group>
<group>
<attribute name="type">
<value>file</value>
</attribute>
+ <interleave>
+ <optional>
+ <element name="input">
+ <ref name="audiofile"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="output">
+ <ref name="audiofile"/>
+ </element>
+ </optional>
+ </interleave>
</group>
</choice>
</element>
"pulseaudio",
);
+VIR_ENUM_IMPL(virDomainAudioFormat,
+ VIR_DOMAIN_AUDIO_FORMAT_LAST,
+ "",
+ "u8",
+ "s8",
+ "u16",
+ "s16",
+ "u32",
+ "s32",
+ "f32",
+);
+
VIR_ENUM_IMPL(virDomainKeyWrapCipherName,
VIR_DOMAIN_KEY_WRAP_CIPHER_NAME_LAST,
"aes",
}
+static int
+virDomainAudioCommonParse(virDomainAudioIOCommonPtr def,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
+{
+ g_autofree char *mixingEngine = virXMLPropString(node, "mixingEngine");
+ g_autofree char *fixedSettings = virXMLPropString(node, "fixedSettings");
+ g_autofree char *voices = virXMLPropString(node, "voices");
+ g_autofree char *bufferLength = virXMLPropString(node, "bufferLength");
+ xmlNodePtr settings;
+ VIR_XPATH_NODE_AUTORESTORE(ctxt);
+
+ ctxt->node = node;
+ settings = virXPathNode("./settings", ctxt);
+
+ if (mixingEngine &&
+ ((def->mixingEngine =
+ virTristateBoolTypeFromString(mixingEngine)) <= 0)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unknown 'mixingEngine' value '%s'"), mixingEngine);
+ return -1;
+ }
+
+ if (fixedSettings &&
+ ((def->fixedSettings =
+ virTristateBoolTypeFromString(fixedSettings)) <= 0)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("unknown 'fixedSettings' value '%s'"), fixedSettings);
+ return -1;
+ }
+
+ if (def->fixedSettings == VIR_TRISTATE_BOOL_YES &&
+ def->mixingEngine != VIR_TRISTATE_BOOL_YES) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("fixed audio settings requires mixing engine"));
+ return -1;
+ }
+
+ if (voices &&
+ (virStrToLong_ui(voices, NULL, 10, &def->voices) < 0 ||
+ !def->voices)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("cannot parse 'voices' value '%s'"), voices);
+ return -1;
+ }
+
+ if (bufferLength &&
+ (virStrToLong_ui(bufferLength, NULL, 10, &def->bufferLength) < 0 ||
+ !def->bufferLength)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("cannot parse 'bufferLength' value '%s'"), bufferLength);
+ return -1;
+ }
+
+ if (settings) {
+ g_autofree char *frequency = virXMLPropString(settings, "frequency");
+ g_autofree char *channels = virXMLPropString(settings, "channels");
+ g_autofree char *format = virXMLPropString(settings, "format");
+
+ if (def->fixedSettings != VIR_TRISTATE_BOOL_YES) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("audio settings specified without fixed settings flag"));
+ return -1;
+ }
+
+ if (frequency &&
+ (virStrToLong_ui(frequency, NULL, 10, &def->frequency) < 0 ||
+ !def->frequency)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("cannot parse 'frequency' value '%s'"), frequency);
+ return -1;
+ }
+
+ if (channels &&
+ (virStrToLong_ui(channels, NULL, 10, &def->channels) < 0 ||
+ !def->channels)) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("cannot parse 'channels' value '%s'"), channels);
+ return -1;
+ }
+
+ if (format &&
+ (def->format = virDomainAudioFormatTypeFromString(format)) <= 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("cannot parse 'format' value '%s'"), format);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
static int
virDomainAudioOSSParse(virDomainAudioIOOSSPtr def,
xmlNodePtr node)
static virDomainAudioDefPtr
virDomainAudioDefParseXML(virDomainXMLOptionPtr xmlopt G_GNUC_UNUSED,
- xmlNodePtr node G_GNUC_UNUSED,
- xmlXPathContextPtr ctxt G_GNUC_UNUSED)
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
{
virDomainAudioDefPtr def;
VIR_XPATH_NODE_AUTORESTORE(ctxt)
inputNode = virXPathNode("./input", ctxt);
outputNode = virXPathNode("./output", ctxt);
+ if (inputNode && virDomainAudioCommonParse(&def->input, inputNode, ctxt) < 0)
+ goto error;
+ if (outputNode && virDomainAudioCommonParse(&def->output, outputNode, ctxt) < 0)
+ goto error;
+
switch ((virDomainAudioType) def->type) {
case VIR_DOMAIN_AUDIO_TYPE_NONE:
break;
}
case VIR_DOMAIN_AUDIO_TYPE_SPICE:
+ break;
+
case VIR_DOMAIN_AUDIO_TYPE_FILE:
break;
static void
-virDomainAudioCommonFormat(virBufferPtr childBuf,
+virDomainAudioCommonFormat(virDomainAudioIOCommonPtr def,
+ virBufferPtr childBuf,
virBufferPtr backendAttrBuf,
const char *direction)
{
- if (virBufferUse(backendAttrBuf)) {
+ g_auto(virBuffer) settingsBuf = VIR_BUFFER_INITIALIZER;
+
+ if (def->fixedSettings == VIR_TRISTATE_BOOL_YES) {
+ if (def->frequency)
+ virBufferAsprintf(&settingsBuf, " frequency='%u'",
+ def->frequency);
+ if (def->channels)
+ virBufferAsprintf(&settingsBuf, " channels='%u'",
+ def->channels);
+ if (def->format)
+ virBufferAsprintf(&settingsBuf, " format='%s'",
+ virDomainAudioFormatTypeToString(def->format));
+ }
+
+ if (def->mixingEngine || def->fixedSettings ||
+ def->voices || def->bufferLength ||
+ virBufferUse(backendAttrBuf)) {
virBufferAsprintf(childBuf, "<%s", direction);
- virBufferAdd(childBuf, virBufferCurrentContent(backendAttrBuf), -1);
- virBufferAddLit(childBuf, "/>\n");
+ if (def->mixingEngine)
+ virBufferAsprintf(childBuf, " mixingEngine='%s'",
+ virTristateBoolTypeToString(def->mixingEngine));
+ if (def->fixedSettings)
+ virBufferAsprintf(childBuf, " fixedSettings='%s'",
+ virTristateBoolTypeToString(def->fixedSettings));
+ if (def->voices)
+ virBufferAsprintf(childBuf, " voices='%u'",
+ def->voices);
+ if (def->bufferLength)
+ virBufferAsprintf(childBuf, " bufferLength='%u'",
+ def->bufferLength);
+ if (virBufferUse(backendAttrBuf))
+ virBufferAdd(childBuf, virBufferCurrentContent(backendAttrBuf), -1);
+ if (def->fixedSettings == VIR_TRISTATE_BOOL_YES) {
+ virBufferAddLit(childBuf, ">\n");
+ virBufferAdjustIndent(childBuf, 2);
+ virBufferAddLit(childBuf, "<settings");
+ if (virBufferUse(&settingsBuf)) {
+ virBufferAdd(childBuf, virBufferCurrentContent(&settingsBuf), -1);
+ }
+ virBufferAddLit(childBuf, "/>\n");
+ virBufferAdjustIndent(childBuf, -2);
+ virBufferAsprintf(childBuf, "</%s>\n", direction);
+ } else {
+ virBufferAddLit(childBuf, "/>\n");
+ }
}
}
-
static void
virDomainAudioOSSFormat(virDomainAudioIOOSSPtr def,
virBufferPtr buf)
return -1;
}
- virDomainAudioCommonFormat(&childBuf, &inputBuf, "input");
- virDomainAudioCommonFormat(&childBuf, &outputBuf, "output");
+ virDomainAudioCommonFormat(&def->input, &childBuf, &inputBuf, "input");
+ virDomainAudioCommonFormat(&def->output, &childBuf, &outputBuf, "output");
if (virBufferUse(&childBuf)) {
virBufferAddLit(buf, ">\n");
def->model == VIR_DOMAIN_SOUND_MODEL_ICH9;
}
+bool
+virDomainAudioIOCommonIsSet(virDomainAudioIOCommonPtr common)
+{
+ return common->mixingEngine ||
+ common->fixedSettings ||
+ common->frequency ||
+ common->channels ||
+ common->voices ||
+ common->format ||
+ common->bufferLength;
+}
char *
virDomainObjGetMetadata(virDomainObjPtr vm,
VIR_DOMAIN_AUDIO_SDL_DRIVER_LAST
} virDomainAudioSDLDriver;
+typedef enum {
+ VIR_DOMAIN_AUDIO_FORMAT_DEFAULT,
+ VIR_DOMAIN_AUDIO_FORMAT_U8,
+ VIR_DOMAIN_AUDIO_FORMAT_S8,
+ VIR_DOMAIN_AUDIO_FORMAT_U16,
+ VIR_DOMAIN_AUDIO_FORMAT_S16,
+ VIR_DOMAIN_AUDIO_FORMAT_U32,
+ VIR_DOMAIN_AUDIO_FORMAT_S32,
+ VIR_DOMAIN_AUDIO_FORMAT_F32,
+
+ VIR_DOMAIN_AUDIO_FORMAT_LAST
+} virDomainAudioFormat;
+
+typedef struct _virDomainAudioIOCommon virDomainAudioIOCommon;
+typedef virDomainAudioIOCommon *virDomainAudioIOCommonPtr;
+struct _virDomainAudioIOCommon {
+ virTristateBool mixingEngine;
+ virTristateBool fixedSettings;
+ unsigned int frequency;
+ unsigned int channels;
+ unsigned int voices;
+ int format; /* virDomainAudioFormat */
+ unsigned int bufferLength; /* milliseconds */
+};
+
+
typedef struct _virDomainAudioIOOSS virDomainAudioIOOSS;
typedef virDomainAudioIOOSS *virDomainAudioIOOSSPtr;
struct _virDomainAudioIOOSS {
unsigned int id;
+ virDomainAudioIOCommon input;
+ virDomainAudioIOCommon output;
union {
struct {
virDomainAudioIOOSS input;
VIR_ENUM_DECL(virDomainChrSpicevmc);
VIR_ENUM_DECL(virDomainSoundCodec);
VIR_ENUM_DECL(virDomainSoundModel);
+VIR_ENUM_DECL(virDomainAudioFormat);
VIR_ENUM_DECL(virDomainAudioType);
VIR_ENUM_DECL(virDomainAudioSDLDriver);
VIR_ENUM_DECL(virDomainKeyWrapCipherName);
int id);
bool
virDomainSoundModelSupportsCodecs(virDomainSoundDefPtr def);
+bool
+virDomainAudioIOCommonIsSet(virDomainAudioIOCommonPtr common);
const char *virDomainChrSourceDefGetPath(virDomainChrSourceDefPtr chr);