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)