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 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list