Allow specifying sound device codecs. See formatdomain.html for
more details.
---
docs/formatdomain.html.in | 19 +++++++
docs/schemas/domaincommon.rng | 29 +++++++---
src/conf/domain_conf.c | 120 ++++++++++++++++++++++++++++++++++++++++-
src/conf/domain_conf.h | 20 +++++++
4 files changed, 180 insertions(+), 8 deletions(-)
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index da61312..3875167 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3617,6 +3617,25 @@ qemu-kvm -net nic,model=? /dev/null
</dl>
<p>
+ <span class="since">Since 0.9.13</span>, a sound element
+ with <code>ich6</code> model can have optional
+ sub-elements <code><codec></code> to attach various
audio
+ codecs to the audio device. If not specified, a default codec
+ will be attached to allow playback and recording. Valid values
+ are 'duplex' (advertise a line-in and a line-out) and 'micro'
+ (advertise a speaker and a microphone).
+ </p>
+
+<pre>
+ ...
+ <devices>
+ <sound model='ich6'>
+ <codec type='micro'/>
+ <sound/>
+ </devices>
+ ...</pre>
+
+ <p>
Each <code>sound</code> element has an optional
sub-element <code><address></code> which can tie the
device to a particular PCI
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 4c4fa6a..34f63c3 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2250,6 +2250,16 @@
</choice>
</element>
</define>
+ <define name="codec">
+ <element name="codec">
+ <attribute name="type">
+ <choice>
+ <value>duplex</value>
+ <value>micro</value>
+ </choice>
+ </attribute>
+ </element>
+ </define>
<define name="sound">
<element name="sound">
<attribute name="model">
@@ -2261,12 +2271,19 @@
<value>ich6</value>
</choice>
</attribute>
- <optional>
- <ref name="alias"/>
- </optional>
- <optional>
- <ref name="address"/>
- </optional>
+ <interleave>
+ <optional>
+ <ref name="alias"/>
+ </optional>
+ <optional>
+ <ref name="address"/>
+ </optional>
+ <zeroOrMore>
+ <choice>
+ <ref name="codec"/>
+ </choice>
+ </zeroOrMore>
+ </interleave>
</element>
</define>
<define name="watchdog">
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 79355e2..78755cf 100644
--- a/src/conf/domain_conf.c
+++ b/src/conf/domain_conf.c
@@ -354,6 +354,10 @@ VIR_ENUM_IMPL(virDomainSmartcard, VIR_DOMAIN_SMARTCARD_TYPE_LAST,
"host-certificates",
"passthrough")
+VIR_ENUM_IMPL(virDomainSoundCodec, VIR_DOMAIN_SOUND_CODEC_TYPE_LAST,
+ "duplex",
+ "micro")
+
VIR_ENUM_IMPL(virDomainSoundModel, VIR_DOMAIN_SOUND_MODEL_LAST,
"sb16",
"es1370",
@@ -1304,6 +1308,14 @@ void virDomainSmartcardDefFree(virDomainSmartcardDefPtr def)
VIR_FREE(def);
}
+void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def)
+{
+ if (!def)
+ return;
+
+ VIR_FREE(def);
+}
+
void virDomainSoundDefFree(virDomainSoundDefPtr def)
{
if (!def)
@@ -1311,6 +1323,11 @@ void virDomainSoundDefFree(virDomainSoundDefPtr def)
virDomainDeviceInfoClear(&def->info);
+ int i;
+ for (i = 0 ; i < def->ncodecs ; i++)
+ virDomainSoundCodecDefFree(def->codecs[i]);
+ VIR_FREE(def->codecs);
+
VIR_FREE(def);
}
@@ -6374,18 +6391,52 @@ error:
}
+static virDomainSoundCodecDefPtr
+virDomainSoundCodecDefParseXML(const xmlNodePtr node)
+{
+ char *type;
+ virDomainSoundCodecDefPtr def;
+
+ if (VIR_ALLOC(def) < 0) {
+ virReportOOMError();
+ return NULL;
+ }
+
+ type = virXMLPropString(node, "type");
+ if ((def->type = virDomainSoundCodecTypeFromString(type)) < 0) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unknown codec type '%s'"), type);
+ goto error;
+ }
+
+cleanup:
+ VIR_FREE(type);
+
+ return def;
+
+error:
+ virDomainSoundCodecDefFree(def);
+ def = NULL;
+ goto cleanup;
+}
+
+
static virDomainSoundDefPtr
virDomainSoundDefParseXML(const xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
unsigned int flags)
{
char *model;
virDomainSoundDefPtr def;
+ xmlNodePtr save = ctxt->node;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
return NULL;
}
+ ctxt->node = node;
+
model = virXMLPropString(node, "model");
if ((def->model = virDomainSoundModelTypeFromString(model)) < 0) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -6393,12 +6444,43 @@ virDomainSoundDefParseXML(const xmlNodePtr node,
goto error;
}
+ if (def->model == VIR_DOMAIN_SOUND_MODEL_ICH6) {
+ int ncodecs;
+ xmlNodePtr *codecNodes = NULL;
+
+ /* parse the <codec> subelements for sound models that support it */
+ ncodecs = virXPathNodeSet("./codec", ctxt, &codecNodes);
+ if (ncodecs < 0)
+ goto error;
+
+ if (ncodecs > 0) {
+ int ii;
+
+ if (VIR_ALLOC_N(def->codecs, ncodecs) < 0) {
+ virReportOOMError();
+ VIR_FREE(codecNodes);
+ goto error;
+ }
+
+ for (ii = 0; ii < ncodecs; ii++) {
+ virDomainSoundCodecDefPtr codec =
virDomainSoundCodecDefParseXML(codecNodes[ii]);
+ if (codec == NULL)
+ goto error;
+
+ codec->cad = def->ncodecs; /* that will do for now */
+ def->codecs[def->ncodecs++] = codec;
+ }
+ VIR_FREE(codecNodes);
+ }
+ }
+
if (virDomainDeviceInfoParseXML(node, NULL, &def->info, flags) < 0)
goto error;
cleanup:
VIR_FREE(model);
+ ctxt->node = save;
return def;
error:
@@ -6951,7 +7033,7 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
goto error;
} else if (xmlStrEqual(node->name, BAD_CAST "sound")) {
dev->type = VIR_DOMAIN_DEVICE_SOUND;
- if (!(dev->data.sound = virDomainSoundDefParseXML(node, flags)))
+ if (!(dev->data.sound = virDomainSoundDefParseXML(node, ctxt, flags)))
goto error;
} else if (xmlStrEqual(node->name, BAD_CAST "watchdog")) {
dev->type = VIR_DOMAIN_DEVICE_WATCHDOG;
@@ -8818,6 +8900,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
goto no_memory;
for (i = 0 ; i < n ; i++) {
virDomainSoundDefPtr sound = virDomainSoundDefParseXML(nodes[i],
+ ctxt,
flags);
if (!sound)
goto error;
@@ -11783,11 +11866,30 @@ virDomainSmartcardDefFormat(virBufferPtr buf,
}
static int
+virDomainSoundCodecDefFormat(virBufferPtr buf,
+ virDomainSoundCodecDefPtr def)
+{
+ const char *type = virDomainSoundCodecTypeToString(def->type);
+
+ if (!type) {
+ virDomainReportError(VIR_ERR_INTERNAL_ERROR,
+ _("unexpected codec type %d"), def->type);
+ return -1;
+ }
+
+ virBufferAsprintf(buf, " <codec type='%s'/>\n", type);
+
+ return 0;
+}
+
+static int
virDomainSoundDefFormat(virBufferPtr buf,
virDomainSoundDefPtr def,
unsigned int flags)
{
const char *model = virDomainSoundModelTypeToString(def->model);
+ int children = 0;
+ int i;
if (!model) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -11797,10 +11899,24 @@ virDomainSoundDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " <sound model='%s'", model);
+ for (i = 0; i < def->ncodecs; i++) {
+ if (!children) {
+ virBufferAddLit(buf, ">\n");
+ children = 1;
+ }
+ virDomainSoundCodecDefFormat(buf, def->codecs[i]);
+ }
+
if (virDomainDeviceInfoIsSet(&def->info, flags)) {
- virBufferAddLit(buf, ">\n");
+ if (!children) {
+ virBufferAddLit(buf, ">\n");
+ children = 1;
+ }
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
return -1;
+ }
+
+ if (children) {
virBufferAddLit(buf, " </sound>\n");
} else {
virBufferAddLit(buf, "/>\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 1597212..4c56902 100644
--- a/src/conf/domain_conf.h
+++ b/src/conf/domain_conf.h
@@ -65,6 +65,9 @@ typedef virDomainNetDef *virDomainNetDefPtr;
typedef struct _virDomainInputDef virDomainInputDef;
typedef virDomainInputDef *virDomainInputDefPtr;
+typedef struct _virDomainSoundCodecDef virDomainSoundCodecDef;
+typedef virDomainSoundCodecDef *virDomainSoundCodecDefPtr;
+
typedef struct _virDomainSoundDef virDomainSoundDef;
typedef virDomainSoundDef *virDomainSoundDefPtr;
@@ -996,6 +999,13 @@ struct _virDomainInputDef {
virDomainDeviceInfo info;
};
+enum virDomainSoundCodecType {
+ VIR_DOMAIN_SOUND_CODEC_TYPE_DUPLEX,
+ VIR_DOMAIN_SOUND_CODEC_TYPE_MICRO,
+
+ VIR_DOMAIN_SOUND_CODEC_TYPE_LAST
+};
+
enum virDomainSoundModel {
VIR_DOMAIN_SOUND_MODEL_SB16,
VIR_DOMAIN_SOUND_MODEL_ES1370,
@@ -1006,9 +1016,17 @@ enum virDomainSoundModel {
VIR_DOMAIN_SOUND_MODEL_LAST
};
+struct _virDomainSoundCodecDef {
+ int type;
+ int cad;
+};
+
struct _virDomainSoundDef {
int model;
virDomainDeviceInfo info;
+
+ int ncodecs;
+ virDomainSoundCodecDefPtr *codecs;
};
enum virDomainWatchdogModel {
@@ -1848,6 +1866,7 @@ void virDomainChrDefFree(virDomainChrDefPtr def);
void virDomainChrSourceDefFree(virDomainChrSourceDefPtr def);
int virDomainChrSourceDefCopy(virDomainChrSourceDefPtr src,
virDomainChrSourceDefPtr dest);
+void virDomainSoundCodecDefFree(virDomainSoundCodecDefPtr def);
void virDomainSoundDefFree(virDomainSoundDefPtr def);
void virDomainMemballoonDefFree(virDomainMemballoonDefPtr def);
void virDomainWatchdogDefFree(virDomainWatchdogDefPtr def);
@@ -2164,6 +2183,7 @@ VIR_ENUM_DECL(virDomainSmartcard)
VIR_ENUM_DECL(virDomainChr)
VIR_ENUM_DECL(virDomainChrTcpProtocol)
VIR_ENUM_DECL(virDomainChrSpicevmc)
+VIR_ENUM_DECL(virDomainSoundCodec)
VIR_ENUM_DECL(virDomainSoundModel)
VIR_ENUM_DECL(virDomainMemballoonModel)
VIR_ENUM_DECL(virDomainSmbiosMode)
--
1.7.10.1