diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index da61312ce46683d1a0f4db36e31ffd33b573c2ca..38751679b92e0315d0e711476d369627d66f9d0e 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3616,6 +3616,25 @@ qemu-kvm -net nic,model=? /dev/null
+
+ Since 0.9.13, a sound element
+ with ich6
model can have optional
+ sub-elements <codec>
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).
+
+
+
+ ...
+ <devices>
+ <sound model='ich6'>
+ <codec type='micro'/>
+ <sound/>
+ </devices>
+ ...
+
Each sound
element has an optional
sub-element <address>
which can tie the
diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng
index 4c4fa6a6d01fe67b946b18cca8ce2b68a3217245..34f63c3b95b8c068523c99640a3330f54e1e6c9a 100644
--- a/docs/schemas/domaincommon.rng
+++ b/docs/schemas/domaincommon.rng
@@ -2250,6 +2250,16 @@
+
+
+
+
+ duplex
+ micro
+
+
+
+
@@ -2261,12 +2271,19 @@
ich6
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c
index 79355e2f780df55edf020871b0cbc2e893f0c6b1..9def71db38bfeb6909df824a4b5a0833deb7f922 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 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;
@@ -11782,12 +11865,31 @@ virDomainSmartcardDefFormat(virBufferPtr buf,
return 0;
}
+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, " \n", type);
+
+ return 0;
+}
+
static int
virDomainSoundDefFormat(virBufferPtr buf,
virDomainSoundDefPtr def,
unsigned int flags)
{
const char *model = virDomainSoundModelTypeToString(def->model);
+ bool children = false;
+ int i;
if (!model) {
virDomainReportError(VIR_ERR_INTERNAL_ERROR,
@@ -11797,10 +11899,24 @@ virDomainSoundDefFormat(virBufferPtr buf,
virBufferAsprintf(buf, " ncodecs; i++) {
+ if (!children) {
+ virBufferAddLit(buf, ">\n");
+ children = true;
+ }
+ virDomainSoundCodecDefFormat(buf, def->codecs[i]);
+ }
+
if (virDomainDeviceInfoIsSet(&def->info, flags)) {
- virBufferAddLit(buf, ">\n");
+ if (!children) {
+ virBufferAddLit(buf, ">\n");
+ children = true;
+ }
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
return -1;
+ }
+
+ if (children) {
virBufferAddLit(buf, " \n");
} else {
virBufferAddLit(buf, "/>\n");
diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h
index 1597212fcb3112f113656e3038eb2605d87dd57d..4c56902ee6f36d1f801e329197445176d0666221 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)