The patch below adds xml support for the soundhw option to qemu
and xen. The new xml element takes the form:
<sound driver='drivername'/>
Where driver name can be pcspk, sb16, es1370, or all.
Everything seems to be in working order but I have a few
implementation questions:
1) Should multiple drivers be able to be specified? qemu
accommodates this, allowing '-soundhw sb16,pcspk' for example.
If this should be allowed, what should the xml format be?
2) Should acceptable driver options be hardcoded? The other option
is to just pass the input straight to qemu. This patch has the
options hardcoded.
Also I realize this will probably need to be rediff'd around
Dan's serial + parallel device patch, but I figured I would just
get this out there.
Thanks,
Cole
diff --git a/src/qemu_conf.c b/src/qemu_conf.c
index d9b82b2..bfd9ba4 100644
--- a/src/qemu_conf.c
+++ b/src/qemu_conf.c
@@ -1011,6 +1011,41 @@ static int qemudParseInputXML(virConnectPtr conn,
return -1;
}
+/* Sound device helper functions */
+static int qemudSoundDriverFromString(virConnectPtr conn,
+ const char *driver) {
+ if (STREQ(driver, "all")) {
+ return QEMU_SOUND_ALL;
+ } else if (STREQ(driver, "sb16")) {
+ return QEMU_SOUND_SB16;
+ } else if (STREQ(driver, "es1370")) {
+ return QEMU_SOUND_ES1370;
+ } else if (STREQ(driver, "pcspk")) {
+ return QEMU_SOUND_PCSPK;
+ }
+
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INVALID_ARG,
+ _("invalid sound driver '%s'"), driver);
+ return -1;
+}
+
+static const char *qemudSoundDriverToString(virConnectPtr conn,
+ const int driver) {
+
+ if (driver == QEMU_SOUND_ALL) {
+ return "all";
+ } else if (driver == QEMU_SOUND_SB16) {
+ return "sb16";
+ } else if (driver == QEMU_SOUND_ES1370) {
+ return "es1370";
+ } else if (driver == QEMU_SOUND_PCSPK) {
+ return "pcspk";
+ }
+
+ qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
+ _("invalid sound driver '%d'"), driver);
+ return NULL;
+}
/*
* Parses a libvirt XML definition of a guest, and populates the
@@ -1486,6 +1521,25 @@ static struct qemud_vm_def *qemudParseXML(virConnectPtr conn,
}
}
xmlXPathFreeObject(obj);
+
+ /* Parse sound driver xml */
+ obj = xmlXPathEval(BAD_CAST "/domain/devices/sound", ctxt);
+ if ((obj == NULL) || (obj->type != XPATH_NODESET) ||
+ (obj->nodesetval == NULL) || (obj->nodesetval->nodeNr == 0)) {
+ def->soundDriver = QEMU_SOUND_NONE;
+ } else if ((prop = xmlGetProp(obj->nodesetval->nodeTab[0],
+ BAD_CAST "driver"))) {
+
+ if ((def->soundDriver = qemudSoundDriverFromString(conn,
+ (char *) prop)) < 0)
+ goto error;
+
+ xmlFree(prop);
+ prop = NULL;
+ } else {
+ def->soundDriver = QEMU_SOUND_NONE;
+ }
+ xmlXPathFreeObject(obj);
obj = NULL;
/* If graphics are enabled, there's an implicit PS2 mouse */
@@ -1694,6 +1748,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
(vm->def->os.cmdline[0] ? 2 : 0) + /* cmdline */
(vm->def->graphicsType == QEMUD_GRAPHICS_VNC ? 2 :
(vm->def->graphicsType == QEMUD_GRAPHICS_SDL ? 0 : 1)) + /* graphics */
+ (vm->def->soundDriver == QEMU_SOUND_NONE ? 0 : 2) + /* sound */
(vm->migrateFrom[0] ? 3 : 0); /* migrateFrom */
snprintf(memory, sizeof(memory), "%lu", vm->def->memory/1024);
@@ -1970,6 +2025,14 @@ int qemudBuildCommandLine(virConnectPtr conn,
/* SDL is the default. no args needed */
}
+ /* Add sound hardware */
+ if (vm->def->soundDriver != QEMU_SOUND_NONE) {
+ if (!((*argv)[++n] = strdup("-soundhw")))
+ goto no_memory;
+ if (!((*argv)[++n] = strdup((char *) qemudSoundDriverToString(conn,
vm->def->soundDriver))))
+ goto no_memory;
+ }
+
if (vm->migrateFrom[0]) {
if (!((*argv)[++n] = strdup("-S")))
goto no_memory;
@@ -3125,7 +3188,11 @@ char *qemudGenerateXML(virConnectPtr conn,
break;
}
- if (def->graphicsType == QEMUD_GRAPHICS_VNC) {
+ if (def->soundDriver != QEMU_SOUND_NONE) {
+ if (virBufferVSprintf(buf, " <sound driver='%s'/>\n",
+ qemudSoundDriverToString(conn,
+ def->soundDriver)) < 0)
+ goto no_memory;
}
if (virBufferAddLit(buf, " </devices>\n") < 0)
diff --git a/src/qemu_conf.h b/src/qemu_conf.h
index c59b1fa..1383c10 100644
--- a/src/qemu_conf.h
+++ b/src/qemu_conf.h
@@ -136,6 +136,14 @@ struct qemud_vm_input_def {
struct qemud_vm_input_def *next;
};
+enum qemu_vm_sound_driver {
+ QEMU_SOUND_NONE,
+ QEMU_SOUND_ALL,
+ QEMU_SOUND_SB16,
+ QEMU_SOUND_ES1370,
+ QEMU_SOUND_PCSPK,
+};
+
/* Flags for the 'type' field in next struct */
enum qemud_vm_device_type {
QEMUD_DEVICE_DISK,
@@ -214,6 +222,7 @@ struct qemud_vm_def {
int vncActivePort;
char vncListen[BR_INET_ADDR_MAXLEN];
char *keymap;
+ int soundDriver;
int ndisks;
struct qemud_vm_disk_def *disks;
diff --git a/src/xend_internal.c b/src/xend_internal.c
index 6ba4571..b470731 100644
--- a/src/xend_internal.c
+++ b/src/xend_internal.c
@@ -1783,6 +1783,18 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root,
}
}
}
+
+ if (sexpr_node(root, "domain/image/hvm/soundhw")) {
+ tmp = sexpr_node(root, "domain/image/hvm/soundhw");
+ if (tmp && *tmp) {
+ if (STREQ(tmp, "all") ||
+ STREQ(tmp, "pcspk") ||
+ STREQ(tmp, "sb16") ||
+ STREQ(tmp, "es1370")) {
+ virBufferVSprintf(&buf, " <sound
driver='%s'/>\n", tmp);
+ }
+ }
+ }
}
/* Graphics device (HVM <= 3.0.4, or PV <= 3.0.3) vnc config */
diff --git a/src/xm_internal.c b/src/xm_internal.c
index 3d845dc..91c7cf1 100644
--- a/src/xm_internal.c
+++ b/src/xm_internal.c
@@ -934,6 +934,15 @@ char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf) {
/* Ignore else branch - probably some other non-input device we don't
support in libvirt yet */
}
+
+ if ((xenXMConfigGetString(conf, "soundhw", &str) == 0) &&
str) {
+ if (STREQ(str, "all") ||
+ STREQ(str, "pcspk") ||
+ STREQ(str, "sb16") ||
+ STREQ(str, "es1370")) {
+ virBufferVSprintf(buf, " <sound
driver='%s'/>\n", str);
+ }
+ }
}
/* HVM guests, or old PV guests use this config format */
@@ -2081,6 +2090,11 @@ virConfPtr xenXMParseXMLToConfig(virConnectPtr conn, const char
*xml) {
if (xenXMConfigSetStringFromXPath(conn, conf, ctxt, "usbdevice",
"string(/domain/devices/input[@bus='usb' or (not(@bus) and
@type='tablet')]/@type)", 1,
"cannot set the usbdevice parameter")
< 0)
goto error;
+
+ if (xenXMConfigSetStringFromXPath(conn, conf, ctxt, "soundhw",
+
"string(/domain/devices/sound[@driver]",
+ 1, "cannot set soundhw parameter")
< 0)
+ goto error;
}
if (hvm || priv->xendConfigVersion < 3) {
diff --git a/src/xml.c b/src/xml.c
index 8e95103..f4bfb29 100644
--- a/src/xml.c
+++ b/src/xml.c
@@ -877,6 +877,14 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node,
nodes = NULL;
}
+ cur = virXPathNode("/domain/devices/sound", ctxt);
+ if (cur) {
+ xmlChar *driver = NULL;
+ driver = xmlGetProp(cur, (xmlChar *) "driver");
+ if (driver)
+ virBufferVSprintf(buf, "(soundhw '%s')", driver);
+ xmlFree(driver);
+ }
res = virXPathBoolean("count(domain/devices/console) > 0", ctxt);
if (res < 0) {