mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-07-30 21:47:18 +00:00
Sound support for QEmu and Xen
* src/qemu_conf.c src/qemu_conf.h src/xend_internal.c src/xend_internal.h src/xm_internal.c src/xml.c src/xml.h: Patch from Cole Robinson adding sound support for QEmu and Xen * tests/qemuxml2argvtest.c tests/sexpr2xmltest.c tests/xmconfigtest.c tests/xml2sexprtest.c: Associated regression tests Daniel
This commit is contained in:
parent
ff2ea6de4e
commit
70f446631f
@ -1,3 +1,12 @@
|
|||||||
|
Wed May 7 16:02:07 CEST 2008 Daniel Veillard <veillard@redhat.com>
|
||||||
|
|
||||||
|
* src/qemu_conf.c src/qemu_conf.h src/xend_internal.c
|
||||||
|
src/xend_internal.h src/xm_internal.c src/xml.c src/xml.h:
|
||||||
|
Patch from Cole Robinson adding sound support for QEmu and Xen
|
||||||
|
* tests/qemuxml2argvtest.c tests/sexpr2xmltest.c
|
||||||
|
tests/xmconfigtest.c tests/xml2sexprtest.c:
|
||||||
|
Associated regression tests
|
||||||
|
|
||||||
Mon May 6 17:43:28 EST 2008 Daniel P. Berrange <berrange@redhat.com>
|
Mon May 6 17:43:28 EST 2008 Daniel P. Berrange <berrange@redhat.com>
|
||||||
|
|
||||||
* src/memory.c: Add missing stddefs.h for ptrdiff_t type
|
* src/memory.c: Add missing stddefs.h for ptrdiff_t type
|
||||||
|
140
src/qemu_conf.c
140
src/qemu_conf.c
@ -1373,6 +1373,58 @@ static int qemudParseInputXML(virConnectPtr conn,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sound device helper functions */
|
||||||
|
static int qemudSoundModelFromString(const char *model) {
|
||||||
|
if (STREQ(model, "sb16")) {
|
||||||
|
return QEMU_SOUND_SB16;
|
||||||
|
} else if (STREQ(model, "es1370")) {
|
||||||
|
return QEMU_SOUND_ES1370;
|
||||||
|
} else if (STREQ(model, "pcspk")) {
|
||||||
|
return QEMU_SOUND_PCSPK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *qemudSoundModelToString(const int model) {
|
||||||
|
|
||||||
|
if (model == QEMU_SOUND_SB16) {
|
||||||
|
return "sb16";
|
||||||
|
} else if (model == QEMU_SOUND_ES1370) {
|
||||||
|
return "es1370";
|
||||||
|
} else if (model == QEMU_SOUND_PCSPK) {
|
||||||
|
return "pcspk";
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int qemudParseSoundXML(virConnectPtr conn,
|
||||||
|
struct qemud_vm_sound_def *sound,
|
||||||
|
const xmlNodePtr node) {
|
||||||
|
|
||||||
|
int err = -1;
|
||||||
|
xmlChar *model = NULL;
|
||||||
|
model = xmlGetProp(node, BAD_CAST "model");
|
||||||
|
|
||||||
|
if (!model) {
|
||||||
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("missing sound model"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if ((sound->model = qemudSoundModelFromString((char *) model)) < 0) {
|
||||||
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("invalid sound model '%s'"), (char *) model);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
error:
|
||||||
|
xmlFree(model);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parses a libvirt XML definition of a guest, and populates the
|
* Parses a libvirt XML definition of a guest, and populates the
|
||||||
@ -1887,6 +1939,50 @@ static struct qemud_vm_def *qemudParseXML(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
xmlXPathFreeObject(obj);
|
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)) {
|
||||||
|
struct qemud_vm_sound_def *prev = NULL;
|
||||||
|
for (i = 0; i < obj->nodesetval->nodeNr; i++) {
|
||||||
|
|
||||||
|
struct qemud_vm_sound_def *sound = calloc(1, sizeof(*sound));
|
||||||
|
struct qemud_vm_sound_def *check = def->sounds;
|
||||||
|
int collision = 0;
|
||||||
|
if (!sound) {
|
||||||
|
qemudReportError(conn, NULL, NULL, VIR_ERR_NO_MEMORY,
|
||||||
|
"%s", _("failed to allocate space for sound dev"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
if (qemudParseSoundXML(conn, sound,
|
||||||
|
obj->nodesetval->nodeTab[i]) < 0) {
|
||||||
|
free(sound);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that model type isn't already present in sound dev list
|
||||||
|
while(check) {
|
||||||
|
if (check->model == sound->model) {
|
||||||
|
collision = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
check = check->next;
|
||||||
|
}
|
||||||
|
if (collision)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
def->nsounds++;
|
||||||
|
sound->next = NULL;
|
||||||
|
if (def->sounds == NULL) {
|
||||||
|
def->sounds = sound;
|
||||||
|
} else {
|
||||||
|
prev->next = sound;
|
||||||
|
}
|
||||||
|
prev = sound;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xmlXPathFreeObject(obj);
|
||||||
obj = NULL;
|
obj = NULL;
|
||||||
|
|
||||||
/* If graphics are enabled, there's an implicit PS2 mouse */
|
/* If graphics are enabled, there's an implicit PS2 mouse */
|
||||||
@ -2106,6 +2202,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
|
|||||||
struct qemud_vm_disk_def *disk = vm->def->disks;
|
struct qemud_vm_disk_def *disk = vm->def->disks;
|
||||||
struct qemud_vm_net_def *net = vm->def->nets;
|
struct qemud_vm_net_def *net = vm->def->nets;
|
||||||
struct qemud_vm_input_def *input = vm->def->inputs;
|
struct qemud_vm_input_def *input = vm->def->inputs;
|
||||||
|
struct qemud_vm_sound_def *sound = vm->def->sounds;
|
||||||
struct qemud_vm_chr_def *serial = vm->def->serials;
|
struct qemud_vm_chr_def *serial = vm->def->serials;
|
||||||
struct qemud_vm_chr_def *parallel = vm->def->parallels;
|
struct qemud_vm_chr_def *parallel = vm->def->parallels;
|
||||||
struct utsname ut;
|
struct utsname ut;
|
||||||
@ -2156,6 +2253,7 @@ int qemudBuildCommandLine(virConnectPtr conn,
|
|||||||
(vm->def->nnets > 0 ? (4 * vm->def->nnets) : 2) + /* networks */
|
(vm->def->nnets > 0 ? (4 * vm->def->nnets) : 2) + /* networks */
|
||||||
1 + /* usb */
|
1 + /* usb */
|
||||||
2 * vm->def->ninputs + /* input devices */
|
2 * vm->def->ninputs + /* input devices */
|
||||||
|
((vm->def->nsounds > 0) ? 2 : 0) + /* sound */
|
||||||
(vm->def->nserials > 0 ? (2 * vm->def->nserials) : 2) + /* character devices */
|
(vm->def->nserials > 0 ? (2 * vm->def->nserials) : 2) + /* character devices */
|
||||||
(vm->def->nparallels > 0 ? (2 * vm->def->nparallels) : 2) + /* character devices */
|
(vm->def->nparallels > 0 ? (2 * vm->def->nparallels) : 2) + /* character devices */
|
||||||
2 + /* memory*/
|
2 + /* memory*/
|
||||||
@ -2491,6 +2589,32 @@ int qemudBuildCommandLine(virConnectPtr conn,
|
|||||||
/* SDL is the default. no args needed */
|
/* SDL is the default. no args needed */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add sound hardware */
|
||||||
|
if (sound) {
|
||||||
|
int size = 100;
|
||||||
|
char *modstr = calloc(1, size+1);
|
||||||
|
if (!modstr)
|
||||||
|
goto no_memory;
|
||||||
|
if (!((*argv)[++n] = strdup("-soundhw")))
|
||||||
|
goto no_memory;
|
||||||
|
|
||||||
|
while(sound && size > 0) {
|
||||||
|
const char *model = qemudSoundModelToString(sound->model);
|
||||||
|
if (!model) {
|
||||||
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("invalid sound model"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
strncat(modstr, model, size);
|
||||||
|
size -= strlen(model);
|
||||||
|
sound = sound->next;
|
||||||
|
if (sound)
|
||||||
|
strncat(modstr, ",", size--);
|
||||||
|
}
|
||||||
|
if (!((*argv)[++n] = modstr))
|
||||||
|
goto no_memory;
|
||||||
|
}
|
||||||
|
|
||||||
if (vm->migrateFrom[0]) {
|
if (vm->migrateFrom[0]) {
|
||||||
if (!((*argv)[++n] = strdup("-S")))
|
if (!((*argv)[++n] = strdup("-S")))
|
||||||
goto no_memory;
|
goto no_memory;
|
||||||
@ -2602,6 +2726,9 @@ qemudParseVMDeviceDef(virConnectPtr conn,
|
|||||||
} else if (xmlStrEqual(node->name, BAD_CAST "input")) {
|
} else if (xmlStrEqual(node->name, BAD_CAST "input")) {
|
||||||
dev->type = QEMUD_DEVICE_DISK;
|
dev->type = QEMUD_DEVICE_DISK;
|
||||||
qemudParseInputXML(conn, &(dev->data.input), node);
|
qemudParseInputXML(conn, &(dev->data.input), node);
|
||||||
|
} else if (xmlStrEqual(node->name, BAD_CAST "sound")) {
|
||||||
|
dev->type = QEMUD_DEVICE_SOUND;
|
||||||
|
qemudParseSoundXML(conn, &(dev->data.sound), node);
|
||||||
} else {
|
} else {
|
||||||
qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR,
|
qemudReportError(conn, NULL, NULL, VIR_ERR_XML_ERROR,
|
||||||
"%s", _("unknown device type"));
|
"%s", _("unknown device type"));
|
||||||
@ -3475,6 +3602,7 @@ char *qemudGenerateXML(virConnectPtr conn,
|
|||||||
const struct qemud_vm_disk_def *disk;
|
const struct qemud_vm_disk_def *disk;
|
||||||
const struct qemud_vm_net_def *net;
|
const struct qemud_vm_net_def *net;
|
||||||
const struct qemud_vm_input_def *input;
|
const struct qemud_vm_input_def *input;
|
||||||
|
const struct qemud_vm_sound_def *sound;
|
||||||
const struct qemud_vm_chr_def *chr;
|
const struct qemud_vm_chr_def *chr;
|
||||||
const char *type = NULL;
|
const char *type = NULL;
|
||||||
int n;
|
int n;
|
||||||
@ -3717,6 +3845,18 @@ char *qemudGenerateXML(virConnectPtr conn,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sound = def->sounds;
|
||||||
|
while(sound) {
|
||||||
|
const char *model = qemudSoundModelToString(sound->model);
|
||||||
|
if (!model) {
|
||||||
|
qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("invalid sound model"));
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
virBufferVSprintf(&buf, " <sound model='%s'/>\n", model);
|
||||||
|
sound = sound->next;
|
||||||
|
}
|
||||||
|
|
||||||
virBufferAddLit(&buf, " </devices>\n");
|
virBufferAddLit(&buf, " </devices>\n");
|
||||||
virBufferAddLit(&buf, "</domain>\n");
|
virBufferAddLit(&buf, "</domain>\n");
|
||||||
|
|
||||||
|
@ -186,11 +186,24 @@ struct qemud_vm_input_def {
|
|||||||
struct qemud_vm_input_def *next;
|
struct qemud_vm_input_def *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum qemu_vm_sound_model {
|
||||||
|
QEMU_SOUND_NONE = 0,
|
||||||
|
QEMU_SOUND_SB16,
|
||||||
|
QEMU_SOUND_ES1370,
|
||||||
|
QEMU_SOUND_PCSPK,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct qemud_vm_sound_def {
|
||||||
|
int model;
|
||||||
|
struct qemud_vm_sound_def *next;
|
||||||
|
};
|
||||||
|
|
||||||
/* Flags for the 'type' field in next struct */
|
/* Flags for the 'type' field in next struct */
|
||||||
enum qemud_vm_device_type {
|
enum qemud_vm_device_type {
|
||||||
QEMUD_DEVICE_DISK,
|
QEMUD_DEVICE_DISK,
|
||||||
QEMUD_DEVICE_NET,
|
QEMUD_DEVICE_NET,
|
||||||
QEMUD_DEVICE_INPUT,
|
QEMUD_DEVICE_INPUT,
|
||||||
|
QEMUD_DEVICE_SOUND,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct qemud_vm_device_def {
|
struct qemud_vm_device_def {
|
||||||
@ -199,6 +212,7 @@ struct qemud_vm_device_def {
|
|||||||
struct qemud_vm_disk_def disk;
|
struct qemud_vm_disk_def disk;
|
||||||
struct qemud_vm_net_def net;
|
struct qemud_vm_net_def net;
|
||||||
struct qemud_vm_input_def input;
|
struct qemud_vm_input_def input;
|
||||||
|
struct qemud_vm_sound_def sound;
|
||||||
} data;
|
} data;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -274,6 +288,9 @@ struct qemud_vm_def {
|
|||||||
unsigned int ninputs;
|
unsigned int ninputs;
|
||||||
struct qemud_vm_input_def *inputs;
|
struct qemud_vm_input_def *inputs;
|
||||||
|
|
||||||
|
unsigned int nsounds;
|
||||||
|
struct qemud_vm_sound_def *sounds;
|
||||||
|
|
||||||
unsigned int nserials;
|
unsigned int nserials;
|
||||||
struct qemud_vm_chr_def *serials;
|
struct qemud_vm_chr_def *serials;
|
||||||
|
|
||||||
|
@ -851,6 +851,107 @@ urlencode(const char *string)
|
|||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Applicable sound models */
|
||||||
|
const char *sound_models[] = { "sb16", "es1370" };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is_sound_model_valid:
|
||||||
|
* @model : model string to check against whitelist
|
||||||
|
*
|
||||||
|
* checks passed model string against whitelist of acceptable models
|
||||||
|
*
|
||||||
|
* Returns 0 if invalid, 1 otherwise
|
||||||
|
*/
|
||||||
|
int is_sound_model_valid(const char *model) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(sound_models)/sizeof(*sound_models); ++i) {
|
||||||
|
if (STREQ(model, sound_models[i])) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is_sound_model_conflict:
|
||||||
|
* @model : model string to look for duplicates of
|
||||||
|
* @soundstr : soundhw string for the form m1,m2,m3 ...
|
||||||
|
*
|
||||||
|
* Returns 0 if no conflict, 1 otherwise
|
||||||
|
*/
|
||||||
|
int is_sound_model_conflict(const char *model, const char *soundstr) {
|
||||||
|
|
||||||
|
char *dupe;
|
||||||
|
char *cur = (char *) soundstr;
|
||||||
|
while ((dupe = strstr(cur, model))) {
|
||||||
|
if (( (dupe == cur) || // (Start of line |
|
||||||
|
(*(dupe - 1) == ',') ) && // Preceded by comma) &
|
||||||
|
( (dupe[strlen(model)] == ',') || // (Ends with comma |
|
||||||
|
(dupe[strlen(model)] == '\0') )) // Ends whole string)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
cur = dupe + strlen(model);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sound_string_to_xml:
|
||||||
|
* @soundstr : soundhw string for the form m1,m2,m3 ...
|
||||||
|
*
|
||||||
|
* Parses the passed string and returns a heap allocated string containing
|
||||||
|
* the valid libvirt soundxml. Must be free'd by caller.
|
||||||
|
*
|
||||||
|
* Returns NULL on fail, xml string on success (can be the empty string).
|
||||||
|
*/
|
||||||
|
char *sound_string_to_xml(const char *sound) {
|
||||||
|
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
|
||||||
|
while (sound) {
|
||||||
|
int modelsize, valid, collision = 0;
|
||||||
|
char *model = NULL;
|
||||||
|
char *model_end = strchr(sound, ',');
|
||||||
|
modelsize = (model_end ? (model_end - sound) : strlen(sound));
|
||||||
|
|
||||||
|
if(!(model = strndup(sound, modelsize)))
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
if (!(valid = is_sound_model_valid(model))) {
|
||||||
|
// Check for magic 'all' model. If found, throw out current xml
|
||||||
|
// and build with all available models
|
||||||
|
if (STREQ(model, "all")) {
|
||||||
|
int i;
|
||||||
|
free(virBufferContentAndReset(&buf));
|
||||||
|
|
||||||
|
for (i=0; i < sizeof(sound_models)/sizeof(*sound_models); ++i)
|
||||||
|
virBufferVSprintf(&buf, " <sound model='%s'/>\n",
|
||||||
|
sound_models[i]);
|
||||||
|
free(model);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valid && model_end)
|
||||||
|
collision = is_sound_model_conflict(model, model_end);
|
||||||
|
if (valid && !collision)
|
||||||
|
virBufferVSprintf(&buf, " <sound model='%s'/>\n", model);
|
||||||
|
|
||||||
|
sound = (model_end ? ++model_end : NULL);
|
||||||
|
free(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virBufferError(&buf))
|
||||||
|
goto error;
|
||||||
|
return virBufferContentAndReset(&buf);
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(virBufferContentAndReset(&buf));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* ! PROXY */
|
#endif /* ! PROXY */
|
||||||
|
|
||||||
/* PUBLIC FUNCTIONS */
|
/* PUBLIC FUNCTIONS */
|
||||||
@ -2079,6 +2180,23 @@ xend_parse_sexp_desc(virConnectPtr conn, struct sexpr *root,
|
|||||||
}
|
}
|
||||||
free(tty);
|
free(tty);
|
||||||
|
|
||||||
|
if (hvm) {
|
||||||
|
if (sexpr_node(root, "domain/image/hvm/soundhw")) {
|
||||||
|
char *soundxml;
|
||||||
|
tmp = sexpr_node(root, "domain/image/hvm/soundhw");
|
||||||
|
if (tmp && *tmp) {
|
||||||
|
if ((soundxml = sound_string_to_xml(tmp))) {
|
||||||
|
virBufferVSprintf(&buf, "%s", soundxml);
|
||||||
|
free(soundxml);
|
||||||
|
} else {
|
||||||
|
virXendError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("parsing soundhw string failed."));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virBufferAddLit(&buf, " </devices>\n");
|
virBufferAddLit(&buf, " </devices>\n");
|
||||||
virBufferAddLit(&buf, "</domain>\n");
|
virBufferAddLit(&buf, "</domain>\n");
|
||||||
|
|
||||||
|
@ -189,6 +189,11 @@ char *xenDaemonDomainDumpXMLByName(virConnectPtr xend,
|
|||||||
|
|
||||||
char *xend_parse_domain_sexp(virConnectPtr conn, char *root, int xendConfigVersion);
|
char *xend_parse_domain_sexp(virConnectPtr conn, char *root, int xendConfigVersion);
|
||||||
|
|
||||||
|
int is_sound_model_valid(const char *model);
|
||||||
|
int is_sound_model_conflict(const char *model, const char *soundstr);
|
||||||
|
char *sound_string_to_xml(const char *sound);
|
||||||
|
|
||||||
|
|
||||||
/* refactored ones */
|
/* refactored ones */
|
||||||
int xenDaemonOpen(virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth, int flags);
|
int xenDaemonOpen(virConnectPtr conn, xmlURIPtr uri, virConnectAuthPtr auth, int flags);
|
||||||
int xenDaemonClose(virConnectPtr conn);
|
int xenDaemonClose(virConnectPtr conn);
|
||||||
|
@ -1050,16 +1050,34 @@ char *xenXMDomainFormatXML(virConnectPtr conn, virConfPtr conf) {
|
|||||||
virBufferAddLit(&buf, " </console>\n");
|
virBufferAddLit(&buf, " </console>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hvm) {
|
||||||
|
if ((xenXMConfigGetString(conf, "soundhw", &str) == 0) && str) {
|
||||||
|
char *soundxml;
|
||||||
|
if ((soundxml = sound_string_to_xml(str))) {
|
||||||
|
virBufferVSprintf(&buf, "%s", soundxml);
|
||||||
|
free(soundxml);
|
||||||
|
} else {
|
||||||
|
xenXMError(conn, VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("parsing soundhw string failed."));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virBufferAddLit(&buf, " </devices>\n");
|
virBufferAddLit(&buf, " </devices>\n");
|
||||||
|
|
||||||
virBufferAddLit(&buf, "</domain>\n");
|
virBufferAddLit(&buf, "</domain>\n");
|
||||||
|
|
||||||
if (virBufferError(&buf)) {
|
if (virBufferError(&buf)) {
|
||||||
xenXMError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"));
|
xenXMError(conn, VIR_ERR_NO_MEMORY, _("allocate buffer"));
|
||||||
return NULL;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
return virBufferContentAndReset(&buf);
|
return virBufferContentAndReset(&buf);
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(virBufferContentAndReset(&buf));
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2311,6 +2329,17 @@ virConfPtr xenXMParseXMLToConfig(virConnectPtr conn, const char *xml) {
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (virXPathNode("/domain/devices/sound", ctxt)) {
|
||||||
|
char *soundstr;
|
||||||
|
if (!(soundstr = virBuildSoundStringFromXML(conn, ctxt)))
|
||||||
|
goto error;
|
||||||
|
if (xenXMConfigSetString(conf, "soundhw", soundstr) < 0) {
|
||||||
|
free(soundstr);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
free(soundstr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
|
83
src/xml.c
83
src/xml.c
@ -29,6 +29,7 @@
|
|||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "xs_internal.h" /* for xenStoreDomainGetNetworkID */
|
#include "xs_internal.h" /* for xenStoreDomainGetNetworkID */
|
||||||
#include "xen_unified.h"
|
#include "xen_unified.h"
|
||||||
|
#include "xend_internal.h" /* for is_sound_* functions */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* virXMLError:
|
* virXMLError:
|
||||||
@ -288,6 +289,78 @@ virConvertCpuSet(virConnectPtr conn, const char *str, int maxcpu) {
|
|||||||
free(cpuset);
|
free(cpuset);
|
||||||
return (res);
|
return (res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virBuildSoundStringFromXML
|
||||||
|
* @sound buffer to populate
|
||||||
|
* @len size of preallocated buffer 'sound'
|
||||||
|
* @ctxt xml context to pull sound info from
|
||||||
|
*
|
||||||
|
* Builds a string of the form m1,m2,m3 from the different sound models
|
||||||
|
* in the xml. String must be free'd by caller.
|
||||||
|
*
|
||||||
|
* Returns string on success, NULL on error
|
||||||
|
*/
|
||||||
|
char * virBuildSoundStringFromXML(virConnectPtr conn,
|
||||||
|
xmlXPathContextPtr ctxt) {
|
||||||
|
|
||||||
|
int nb_nodes, size = 256;
|
||||||
|
char *sound;
|
||||||
|
xmlNodePtr *nodes = NULL;
|
||||||
|
|
||||||
|
if (!(sound = calloc(1, size+1))) {
|
||||||
|
virXMLError(conn, VIR_ERR_NO_MEMORY,
|
||||||
|
_("failed to allocate sound string"), 0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nb_nodes = virXPathNodeSet("/domain/devices/sound", ctxt, &nodes);
|
||||||
|
if (nb_nodes > 0) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < nb_nodes && size > 0; i++) {
|
||||||
|
char *model = NULL;
|
||||||
|
int collision = 0;
|
||||||
|
|
||||||
|
model = (char *) xmlGetProp(nodes[i], (xmlChar *) "model");
|
||||||
|
if (!model) {
|
||||||
|
virXMLError(conn, VIR_ERR_XML_ERROR,
|
||||||
|
_("no model for sound device"), 0);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_sound_model_valid(model)) {
|
||||||
|
virXMLError(conn, VIR_ERR_XML_ERROR,
|
||||||
|
_("unknown sound model type"), 0);
|
||||||
|
free(model);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for duplicates in currently built string
|
||||||
|
if (*sound)
|
||||||
|
collision = is_sound_model_conflict(model, sound);
|
||||||
|
|
||||||
|
// If no collision, add to string
|
||||||
|
if (!collision) {
|
||||||
|
if (*sound && (size >= (strlen(model) + 1))) {
|
||||||
|
strncat(sound, ",", size--);
|
||||||
|
} else if (*sound || size < strlen(model)) {
|
||||||
|
free(model);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
strncat(sound, model, size);
|
||||||
|
size -= strlen(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(nodes);
|
||||||
|
return sound;
|
||||||
|
|
||||||
|
error:
|
||||||
|
free(nodes);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
#endif /* WITH_XEN */
|
#endif /* WITH_XEN */
|
||||||
#ifndef PROXY
|
#ifndef PROXY
|
||||||
|
|
||||||
@ -969,7 +1042,6 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* get the cdrom device file */
|
/* get the cdrom device file */
|
||||||
/* Only XenD <= 3.0.2 wants cdrom config here */
|
/* Only XenD <= 3.0.2 wants cdrom config here */
|
||||||
if (xendConfigVersion == 1) {
|
if (xendConfigVersion == 1) {
|
||||||
@ -1077,6 +1149,15 @@ virDomainParseXMLOSDescHVM(virConnectPtr conn, xmlNodePtr node,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cur = virXPathNode("/domain/devices/sound", ctxt);
|
||||||
|
if (cur) {
|
||||||
|
char *soundstr;
|
||||||
|
if (!(soundstr = virBuildSoundStringFromXML(conn, ctxt)))
|
||||||
|
goto error;
|
||||||
|
virBufferVSprintf(buf, "(soundhw '%s')", soundstr);
|
||||||
|
free(soundstr);
|
||||||
|
}
|
||||||
|
|
||||||
str = virXPathString("string(/domain/clock/@offset)", ctxt);
|
str = virXPathString("string(/domain/clock/@offset)", ctxt);
|
||||||
if (str != NULL && STREQ(str, "localtime")) {
|
if (str != NULL && STREQ(str, "localtime")) {
|
||||||
virBufferAddLit(buf, "(localtime 1)");
|
virBufferAddLit(buf, "(localtime 1)");
|
||||||
|
@ -61,6 +61,8 @@ int virDomainXMLDevID(virDomainPtr domain,
|
|||||||
char *class,
|
char *class,
|
||||||
char *ref,
|
char *ref,
|
||||||
int ref_len);
|
int ref_len);
|
||||||
|
char * virBuildSoundStringFromXML(virConnectPtr conn,
|
||||||
|
xmlXPathContextPtr ctxt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -159,6 +159,7 @@ main(int argc, char **argv)
|
|||||||
DO_TEST("serial-many");
|
DO_TEST("serial-many");
|
||||||
DO_TEST("parallel-tcp");
|
DO_TEST("parallel-tcp");
|
||||||
DO_TEST("console-compat");
|
DO_TEST("console-compat");
|
||||||
|
DO_TEST("sound");
|
||||||
|
|
||||||
virCapabilitiesFree(driver.caps);
|
virCapabilitiesFree(driver.caps);
|
||||||
|
|
||||||
|
@ -136,6 +136,9 @@ main(int argc, char **argv)
|
|||||||
DO_TEST("fv-serial-unix", "fv-serial-unix", 1);
|
DO_TEST("fv-serial-unix", "fv-serial-unix", 1);
|
||||||
DO_TEST("fv-parallel-tcp", "fv-parallel-tcp", 1);
|
DO_TEST("fv-parallel-tcp", "fv-parallel-tcp", 1);
|
||||||
|
|
||||||
|
DO_TEST("fv-sound", "fv-sound", 1);
|
||||||
|
DO_TEST("fv-sound-all", "fv-sound-all", 1);
|
||||||
|
|
||||||
exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
#else /* WITHOUT_XEN */
|
#else /* WITHOUT_XEN */
|
||||||
|
@ -221,6 +221,8 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
DO_TEST("fullvirt-parallel-tcp", 2);
|
DO_TEST("fullvirt-parallel-tcp", 2);
|
||||||
|
|
||||||
|
DO_TEST("fullvirt-sound", 2);
|
||||||
|
|
||||||
exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
#else /* WITHOUT_XEN */
|
#else /* WITHOUT_XEN */
|
||||||
|
@ -143,6 +143,8 @@ main(int argc, char **argv)
|
|||||||
DO_TEST("fv-serial-unix", "fv-serial-unix", "fvtest", 1);
|
DO_TEST("fv-serial-unix", "fv-serial-unix", "fvtest", 1);
|
||||||
DO_TEST("fv-parallel-tcp", "fv-parallel-tcp", "fvtest", 1);
|
DO_TEST("fv-parallel-tcp", "fv-parallel-tcp", "fvtest", 1);
|
||||||
|
|
||||||
|
DO_TEST("fv-sound", "fv-sound", "fvtest", 1);
|
||||||
|
|
||||||
exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
exit(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user