Re: [Qemu-devel] [PATCH v2 1/2] qxl: introduce QXLCookie
Hi On Fri, Feb 17, 2012 at 9:44 AM, Alon Levy wrote: > +/* called from spice server thread context only */ > +static void interface_async_complete(QXLInstance *sin, uint64_t cookie_token) > +{ > + PCIQXLDevice *qxl = container_of(sin, PCIQXLDevice, ssd.qxl); > + QXLCookie *cookie = (QXLCookie*)cookie_token; > + > + switch (cookie->type) { We still have spice_qxl_flush_surfaces_async(&qxl->ssd.qxl, 0); So cookie might be NULL in this case. -- Marc-André Lureau
Re: [Qemu-devel] [PATCH v2 1/2] qxl: introduce QXLCookie
Hi On Fri, Feb 17, 2012 at 9:44 AM, Alon Levy wrote: > +QXLCookie *qxl_cookie_new(int type, uint64_t io, uint64_t data) > +{ > + QXLCookie *cookie; > + > + cookie = g_malloc0(sizeof(*cookie)); > + cookie->type = type; > + cookie->io = io; > + cookie->data = data; > + return cookie; > +} I don't know if it's prohibited in qemu code, but g_slice would be a good fit here: frequently allocated bits of same size. -- Marc-André Lureau
[Qemu-devel] [PATCH 2/6] spice-qemu-char: factor out CharDriverState creation
Make the CharDriverState creation code reusable by spicevmc port. --- spice-qemu-char.c | 37 +++-- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 665efd3..b86e83a 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -186,13 +186,32 @@ static void print_allowed_subtypes(void) fprintf(stderr, "\n"); } -CharDriverState *qemu_chr_open_spice(QemuOpts *opts) +static CharDriverState *chr_open(QemuOpts *opts, const char *subtype) { CharDriverState *chr; SpiceCharDriver *s; -const char* name = qemu_opt_get(opts, "name"); uint32_t debug = qemu_opt_get_number(opts, "debug", 0); -const char** psubtype = spice_server_char_device_recognized_subtypes(); + +chr = g_malloc0(sizeof(CharDriverState)); +s = g_malloc0(sizeof(SpiceCharDriver)); +s->chr = chr; +s->debug = debug; +s->active = false; +s->sin.subtype = subtype; +chr->opaque = s; +chr->chr_write = spice_chr_write; +chr->chr_close = spice_chr_close; +chr->chr_guest_open = spice_chr_guest_open; +chr->chr_guest_close = spice_chr_guest_close; + +return chr; +} + +CharDriverState *qemu_chr_open_spice(QemuOpts *opts) +{ +CharDriverState *chr; +const char *name = qemu_opt_get(opts, "name"); +const char **psubtype = spice_server_char_device_recognized_subtypes(); const char *subtype = NULL; if (name == NULL) { @@ -212,17 +231,7 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts) return NULL; } -chr = g_malloc0(sizeof(CharDriverState)); -s = g_malloc0(sizeof(SpiceCharDriver)); -s->chr = chr; -s->debug = debug; -s->active = false; -s->sin.subtype = subtype; -chr->opaque = s; -chr->chr_write = spice_chr_write; -chr->chr_close = spice_chr_close; -chr->chr_guest_open = spice_chr_guest_open; -chr->chr_guest_close = spice_chr_guest_close; +chr = chr_open(opts, subtype); #if SPICE_SERVER_VERSION < 0x000901 /* See comment in vmc_state() */ -- 1.7.11.7
[Qemu-devel] [PATCH 4/6] spice-qemu-char: keep a list of spice chardev
--- spice-qemu-char.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 4be75ba..4eb85ae 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -24,8 +24,12 @@ typedef struct SpiceCharDriver { uint8_t *datapos; ssize_t bufsize, datalen; uint32_t debug; +QLIST_ENTRY(SpiceCharDriver) next; } SpiceCharDriver; +static QLIST_HEAD(, SpiceCharDriver) spice_chars = +QLIST_HEAD_INITIALIZER(spice_chars); + static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) { SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); @@ -179,6 +183,7 @@ static void spice_chr_close(struct CharDriverState *chr) printf("%s\n", __func__); vmc_unregister_interface(s); +QLIST_REMOVE(s, next); g_free(s); } @@ -229,6 +234,8 @@ static CharDriverState *chr_open(QemuOpts *opts, const char *subtype) chr->chr_guest_open = spice_chr_guest_open; chr->chr_guest_close = spice_chr_guest_close; +QLIST_INSERT_HEAD(&spice_chars, s, next); + return chr; } -- 1.7.11.7
[Qemu-devel] [PATCH 5/6] spice-qemu-char: register spicevmc ports during qemu_spice_init()
Do the delayed registration of spicevmc ports after Spice server is initialized. --- spice-qemu-char.c | 12 ui/qemu-spice.h | 1 + ui/spice-core.c | 4 3 files changed, 17 insertions(+) diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 4eb85ae..b2586c2 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -293,4 +293,16 @@ CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts) return chr; } + +void qemu_spice_register_ports(void) +{ +SpiceCharDriver *s; + +QLIST_FOREACH(s, &spice_chars, next) { +if (s->sin.portname == NULL) { +continue; +} +vmc_register_interface(s); +} +} #endif diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index 5669767..642f012 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -48,6 +48,7 @@ void do_info_spice(Monitor *mon, QObject **ret_data); CharDriverState *qemu_chr_open_spice(QemuOpts *opts); #if SPICE_SERVER_VERSION >= 0x000c02 CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts); +void qemu_spice_register_ports(void); #endif #else /* CONFIG_SPICE */ diff --git a/ui/spice-core.c b/ui/spice-core.c index 261c6f2..ddbcd08 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -714,6 +714,10 @@ void qemu_spice_init(void) g_free(x509_key_file); g_free(x509_cert_file); g_free(x509_cacert_file); + +#if SPICE_SERVER_VERSION >= 0x000c02 +qemu_spice_register_ports(); +#endif } int qemu_spice_add_interface(SpiceBaseInstance *sin) -- 1.7.11.7
[Qemu-devel] [PATCH 1/6] spice-qemu-char: write to chardev whatever amount it can read
The current code waits until the chardev can read MIN(len, VMC_MAX) But some chardev may never reach than amount, in fact some of them will only ever accept write of 1. Fix the min computation and remove the VMC_MAX constant. --- spice-qemu-char.c | 6 ++ 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 09aa22d..665efd3 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -14,8 +14,6 @@ } \ } while (0) -#define VMC_MAX_HOST_WRITE2048 - typedef struct SpiceCharDriver { CharDriverState* chr; SpiceCharDeviceInstance sin; @@ -35,8 +33,8 @@ static int vmc_write(SpiceCharDeviceInstance *sin, const uint8_t *buf, int len) uint8_t* p = (uint8_t*)buf; while (len > 0) { -last_out = MIN(len, VMC_MAX_HOST_WRITE); -if (qemu_chr_be_can_write(scd->chr) < last_out) { +last_out = MIN(len, qemu_chr_be_can_write(scd->chr)); +if (last_out <= 0) { break; } qemu_chr_be_write(scd->chr, p, last_out); -- 1.7.11.7
[Qemu-devel] [PATCH 3/6] spice-qemu-char: add spiceport chardev
Add a new spice chardev to allow arbitrary communication between the host and the Spice client via the spice server. Examples: This allows the Spice client to have a special port for the qemu monitor: ... -chardev spiceport,name=org.qemu.monitor,id=monitorport -mon chardev=monitorport v2: - remove support for chardev to chardev linking - conditionnaly compile with SPICE_SERVER_VERSION --- qemu-char.c | 3 +++ qemu-options.hx | 13 + spice-qemu-char.c | 45 + trace-events | 1 + ui/qemu-spice.h | 3 +++ 5 files changed, 65 insertions(+) diff --git a/qemu-char.c b/qemu-char.c index 242b799..9940701 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -2762,6 +2762,9 @@ static const struct { #endif #ifdef CONFIG_SPICE { .name = "spicevmc", .open = qemu_chr_open_spice }, +#if SPICE_SERVER_VERSION >= 0x000c02 +{ .name = "spiceport",.open = qemu_chr_open_spice_port }, +#endif #endif }; diff --git a/qemu-options.hx b/qemu-options.hx index de43b1b..6b5669d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -1749,6 +1749,7 @@ DEF("chardev", HAS_ARG, QEMU_OPTION_chardev, #endif #if defined(CONFIG_SPICE) "-chardev spicevmc,id=id,name=name[,debug=debug]\n" +"-chardev spiceport,id=id,name=name[,debug=debug]\n" #endif , QEMU_ARCH_ALL ) @@ -1776,6 +1777,7 @@ Backend is one of: @option{tty}, @option{parport}, @option{spicevmc}. +@option{spiceport}. The specific backend will determine the applicable options. All devices must have an id, which can be any string up to 127 characters long. @@ -1961,6 +1963,17 @@ required. Connect to a spice virtual machine channel, such as vdiport. +@item -chardev spiceport ,id=@var{id} ,debug=@var{debug}, name=@var{name} + +@option{spiceport} is only available when spice support is built in. + +@option{debug} debug level for spicevmc + +@option{name} name of spice port to connect to + +Connect to a spice port, allowing a Spice client to handle the traffic +identified by a name (preferably a fqdn). + @end table ETEXI diff --git a/spice-qemu-char.c b/spice-qemu-char.c index b86e83a..4be75ba 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -3,6 +3,7 @@ #include "ui/qemu-spice.h" #include #include +#include #include "osdep.h" @@ -67,6 +68,27 @@ static int vmc_read(SpiceCharDeviceInstance *sin, uint8_t *buf, int len) return bytes; } +#if SPICE_SERVER_VERSION >= 0x000c02 +static void vmc_event(SpiceCharDeviceInstance *sin, uint8_t event) +{ +SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); +int chr_event; + +switch (event) { +case SPICE_PORT_EVENT_BREAK: +chr_event = CHR_EVENT_BREAK; +break; +default: +dprintf(scd, 2, "%s: unknown %d\n", __func__, event); +return; +} + +dprintf(scd, 2, "%s: %d\n", __func__, event); +trace_spice_vmc_event(chr_event); +qemu_chr_be_event(scd->chr, chr_event); +} +#endif + static void vmc_state(SpiceCharDeviceInstance *sin, int connected) { SpiceCharDriver *scd = container_of(sin, SpiceCharDriver, sin); @@ -103,6 +125,9 @@ static SpiceCharDeviceInterface vmc_interface = { .state = vmc_state, .write = vmc_write, .read = vmc_read, +#if SPICE_SERVER_VERSION >= 0x000c02 +.event = vmc_event, +#endif }; @@ -242,3 +267,23 @@ CharDriverState *qemu_chr_open_spice(QemuOpts *opts) return chr; } + +#if SPICE_SERVER_VERSION >= 0x000c02 +CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts) +{ +CharDriverState *chr; +SpiceCharDriver *s; +const char *name = qemu_opt_get(opts, "name"); + +if (name == NULL) { +fprintf(stderr, "spice-qemu-char: missing name parameter\n"); +return NULL; +} + +chr = chr_open(opts, "port"); +s = chr->opaque; +s->sin.portname = name; + +return chr; +} +#endif diff --git a/trace-events b/trace-events index 6c6cbf1..77247d9 100644 --- a/trace-events +++ b/trace-events @@ -535,6 +535,7 @@ spice_vmc_write(ssize_t out, int len) "spice wrottn %zd of requested %d" spice_vmc_read(int bytes, int len) "spice read %d of requested %d" spice_vmc_register_interface(void *scd) "spice vmc registered interface %p" spice_vmc_unregister_interface(void *scd) "spice vmc unregistered interface %p" +spice_vmc_event(int event) "spice vmc event %d" # hw/lm32_pic.c lm32_pic_raise_irq(void) "Raise CPU interrupt" diff --git a/ui/qemu-spice.h b/ui/qemu-spice.h index 3299da8..5669767 100644 --- a/ui/qemu-spice.h +++ b/ui/qemu-spice.h @@ -46,6 +46,9 @@ void do_info_spice_print(Monitor *mon, const QObject *data); void do_info_spice(Monitor *mon, QObject **ret_data); CharDriverState *qemu_chr_open_spice(QemuOpts *opts); +#if SPICE_SERVER_VERSION >= 0x000c02 +CharDriverState *qemu_chr_open_spice_port(QemuOpts *opts); +#endif #else /* CONFIG_SPICE */ #include "monitor.h" -- 1.7.11.7
[Qemu-devel] [PATCH 6/6] docs: add spice-port-fqdn.txt
Start a simple org.qemu.* registry of well known name. --- docs/spice-port-fqdn.txt | 19 +++ 1 file changed, 19 insertions(+) create mode 100644 docs/spice-port-fqdn.txt diff --git a/docs/spice-port-fqdn.txt b/docs/spice-port-fqdn.txt new file mode 100644 index 000..5077895 --- /dev/null +++ b/docs/spice-port-fqdn.txt @@ -0,0 +1,19 @@ +A Spice port channel is an arbitrary communication between the Spice +server host side and the client side. + +Thanks to the associated reverse fully qualified domain name (fqdn), +a Spice client can handle the various ports appropriately. + +The following fqdn names are reserved by the QEMU project: + +org.qemu.monitor.hmp.0 + QEMU human monitor + +org.qemu.monitor.qmp.0: + QEMU control monitor + +org.qemu.console.serial.0 + QEMU virtual serial port + +org.qemu.console.debug.0 + QEMU debug console -- 1.7.11.7
[Qemu-devel] [PATCH 1/4] util: move socket_init() to osdep.c
vscclient needs to call socket_init() for portability. Moving to osdep.c since it has no internal dependency. Signed-off-by: Marc-André Lureau --- util/osdep.c| 23 +++ util/qemu-sockets.c | 24 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/util/osdep.c b/util/osdep.c index 5b51a03..3c1a0a3 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -400,3 +400,26 @@ bool fips_get_state(void) return fips_enabled; } +#ifdef _WIN32 +static void socket_cleanup(void) +{ +WSACleanup(); +} +#endif + +int socket_init(void) +{ +#ifdef _WIN32 +WSADATA Data; +int ret, err; + +ret = WSAStartup(MAKEWORD(2, 2), &Data); +if (ret != 0) { +err = WSAGetLastError(); +fprintf(stderr, "WSAStartup: %d\n", err); +return -1; +} +atexit(socket_cleanup); +#endif +return 0; +} diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 1350ccc..d8994c1 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -944,27 +944,3 @@ int socket_listen(SocketAddress *addr, Error **errp) qemu_opts_del(opts); return fd; } - -#ifdef _WIN32 -static void socket_cleanup(void) -{ -WSACleanup(); -} -#endif - -int socket_init(void) -{ -#ifdef _WIN32 -WSADATA Data; -int ret, err; - -ret = WSAStartup(MAKEWORD(2,2), &Data); -if (ret != 0) { -err = WSAGetLastError(); -fprintf(stderr, "WSAStartup: %d\n", err); -return -1; -} -atexit(socket_cleanup); -#endif -return 0; -} -- 1.8.1.1.439.g50a6b54
[Qemu-devel] [PATCH 2/4] build-sys: must link with -fstack-protector
From: Marc-André Lureau It is needed to give that flag to the linker as well, but latest libtool 2.4.2 still swallows that argument, so let's pass it with libtool -Wc argument. qemu-1.4.0/stubs/arch-query-cpu-def.c:6: undefined reference to `__stack_chk_guard' Signed-off-by: Marc-André Lureau --- configure | 8 +++- rules.mak | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/configure b/configure index dcaa67c..c591314 100755 --- a/configure +++ b/configure @@ -1196,7 +1196,7 @@ fi gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" -gcc_flags="-fstack-protector-all -Wendif-labels $gcc_flags" +gcc_flags="-Wendif-labels $gcc_flags" gcc_flags="-Wno-initializer-overrides $gcc_flags" # Note that we do not add -Werror to gcc_flags here, because that would # enable it for all configure tests. If a configure test failed due @@ -1215,6 +1215,11 @@ for flag in $gcc_flags; do fi done +if compile_prog "-Werror -fstack-protector-all" "" ; then +QEMU_CFLAGS="$QEMU_CFLAGS -fstack-protector-all" +LIBTOOLFLAGS="$LIBTOOLFLAGS -Wc,-fstack-protector-all" +fi + # Workaround for http://gcc.gnu.org/PR55489. Happens with -fPIE/-fPIC and # large functions that use global variables. The bug is in all releases of # GCC, but it became particularly acute in 4.6.x and 4.7.x. It is fixed in @@ -3842,6 +3847,7 @@ else echo "AUTOCONF_HOST := " >> $config_host_mak fi echo "LDFLAGS=$LDFLAGS" >> $config_host_mak +echo "LIBTOOLFLAGS=$LIBTOOLFLAGS" >> $config_host_mak echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak echo "ARLIBS_END=$arlibs_end" >> $config_host_mak echo "LIBS+=$LIBS" >> $config_host_mak diff --git a/rules.mak b/rules.mak index edc2552..0be8e60 100644 --- a/rules.mak +++ b/rules.mak @@ -34,7 +34,7 @@ LIBTOOL += $(if $(V),,--quiet) LINK = $(call quiet-command,\ $(if $(filter %.lo %.la,$^),$(LIBTOOL) --mode=link --tag=CC \ - )$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \ + )$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) $(LIBTOOLFLAGS) -o $@ \ $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(version-obj-y) \ $(LIBS),$(if $(filter %.lo %.la,$^),"lt LINK ", " LINK ")"$(TARGET_DIR)$@") endif -- 1.8.1.1.439.g50a6b54
[Qemu-devel] [PATCH 3/4] libcacard: fix mingw64 cross-compilation
From: Marc-André Lureau Compile and link with version.lo Signed-off-by: Marc-André Lureau --- Makefile | 8 ++-- rules.mak | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 2262410..5f0ded1 100644 --- a/Makefile +++ b/Makefile @@ -148,11 +148,15 @@ recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) -version.o: $(SRC_PATH)/version.rc config-host.h +version.o: $(SRC_PATH)/version.rc config-host.h | version.lo $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC$(TARGET_DIR)$@") +version.lo: $(SRC_PATH)/version.rc config-host.h + $(call quiet-command,$(LIBTOOL) --mode=compile --tag=RC $(WINDRES) -I. -o $@ $<,"lt RC $(TARGET_DIR)$@") version-obj-$(CONFIG_WIN32) += version.o -Makefile: $(version-obj-y) +version-lobj-$(CONFIG_WIN32) += $(if $(LIBTOOL),version.lo) +Makefile: $(version-obj-y) $(version-lobj-y) + ## # Build libraries diff --git a/rules.mak b/rules.mak index 0be8e60..939fb5e 100644 --- a/rules.mak +++ b/rules.mak @@ -35,7 +35,7 @@ LIBTOOL += $(if $(V),,--quiet) LINK = $(call quiet-command,\ $(if $(filter %.lo %.la,$^),$(LIBTOOL) --mode=link --tag=CC \ )$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) $(LIBTOOLFLAGS) -o $@ \ - $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(version-obj-y) \ + $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(version-lobj-y) \ $(LIBS),$(if $(filter %.lo %.la,$^),"lt LINK ", " LINK ")"$(TARGET_DIR)$@") endif -- 1.8.1.1.439.g50a6b54
[Qemu-devel] [PATCH 4/4] libcacard: teach vscclient to use GMainLoop for portability
From: Marc-André Lureau Signed-off-by: Marc-André Lureau --- libcacard/vscclient.c | 374 ++ 1 file changed, 198 insertions(+), 176 deletions(-) diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c index 9b744f2..ad2ffd1 100644 --- a/libcacard/vscclient.c +++ b/libcacard/vscclient.c @@ -10,7 +10,10 @@ * See the COPYING.LIB file in the top-level directory. */ +#ifndef _WIN32 #include +#endif +#include #include "qemu-common.h" #include "qemu/thread.h" @@ -73,7 +76,7 @@ send_msg( mhHeader.type = htonl(type); mhHeader.reader_id = 0; mhHeader.length = htonl(length); -rv = write(sock, &mhHeader, sizeof(mhHeader)); +rv = send(sock, (char *)&mhHeader, sizeof(mhHeader), 0); if (rv < 0) { /* Error */ fprintf(stderr, "write header error\n"); @@ -81,7 +84,7 @@ send_msg( qemu_mutex_unlock(&write_lock); return 16; } -rv = write(sock, msg, length); +rv = send(sock, (char *)msg, length, 0); if (rv < 0) { /* Error */ fprintf(stderr, "write error\n"); @@ -211,18 +214,179 @@ get_id_from_string(char *string, unsigned int default_id) return id; } -static void -do_command(void) +static int +on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) +{ +uint32_t *capabilities = (incoming->capabilities); +int num_capabilities = +1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t)); +int i; +QemuThread thread_id; + +incoming->version = ntohl(incoming->version); +if (incoming->version != VSCARD_VERSION) { +if (verbose > 0) { +printf("warning: host has version %d, we have %d\n", +verbose, VSCARD_VERSION); +} +} +if (incoming->magic != VSCARD_MAGIC) { +printf("unexpected magic: got %d, expected %d\n", +incoming->magic, VSCARD_MAGIC); +return -1; +} +for (i = 0 ; i < num_capabilities; ++i) { +capabilities[i] = ntohl(capabilities[i]); +} +/* Future: check capabilities */ +/* remove whatever reader might be left in qemu, + * in case of an unclean previous exit. */ +send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0); +/* launch the event_thread. This will trigger reader adds for all the + * existing readers */ +qemu_thread_create(&thread_id, event_thread, NULL, 0); +return 0; +} + +#define APDUBufSize 270 + +static gboolean +do_socket(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ +gsize rv; +int dwSendLength; +int dwRecvLength; +uint8_t pbRecvBuffer[APDUBufSize]; +uint8_t pbSendBuffer[APDUBufSize]; +VReaderStatus reader_status; +VReader *reader = NULL; +VSCMsgHeader mhHeader; +VSCMsgError *error_msg; + +if (g_io_channel_read_chars(source, +(gchar *)&mhHeader, sizeof(mhHeader), &rv, NULL) +!= G_IO_STATUS_NORMAL) { +g_error("error while reading from socket"); +} + +if (rv < sizeof(mhHeader)) { +fprintf(stderr, "header short read %" G_GSIZE_FORMAT "\n", rv); +return 8; +} +mhHeader.type = ntohl(mhHeader.type); +mhHeader.reader_id = ntohl(mhHeader.reader_id); +mhHeader.length = ntohl(mhHeader.length); +if (verbose) { +printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n", + mhHeader.type, mhHeader.reader_id, mhHeader.length, + mhHeader.length); +} +switch (mhHeader.type) { +case VSC_APDU: +case VSC_Flush: +case VSC_Error: +case VSC_Init: +if (g_io_channel_read_chars(source, +(gchar *)pbSendBuffer, mhHeader.length, &rv, NULL) +!= G_IO_STATUS_NORMAL) { +g_error("error while reading from socket"); +} +break; +default: +fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type); +return 0; +} +switch (mhHeader.type) { +case VSC_APDU: +if (verbose) { +printf(" recv APDU: "); +print_byte_array(pbSendBuffer, mhHeader.length); +} +/* Transmit received APDU */ +dwSendLength = mhHeader.length; +dwRecvLength = sizeof(pbRecvBuffer); +reader = vreader_get_reader_by_id(mhHeader.reader_id); +reader_status = vreader_xfr_bytes(reader, + pbSendBuffer, dwSendLength, + pbRecvBuffer, &dwRecvLength); +if (reader_status == VREADER_OK) { +mhHeader.length = dwRecvLength; +if (verbose) { +printf(" send response: "); +print_byte_array(pbRecvBuffer, mhHea
[Qemu-devel] [PATCH 1/2] build-sys: must link with -fstack-protector
From: Marc-André Lureau It is needed to give that flag to the linker as well, but latest libtool 2.4.2 still swallows that argument, so let's pass it with libtool -Wc argument. qemu-1.4.0/stubs/arch-query-cpu-def.c:6: undefined reference to `__stack_chk_guard' Signed-off-by: Marc-André Lureau --- configure | 8 +++- rules.mak | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/configure b/configure index dcaa67c..c591314 100755 --- a/configure +++ b/configure @@ -1196,7 +1196,7 @@ fi gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" -gcc_flags="-fstack-protector-all -Wendif-labels $gcc_flags" +gcc_flags="-Wendif-labels $gcc_flags" gcc_flags="-Wno-initializer-overrides $gcc_flags" # Note that we do not add -Werror to gcc_flags here, because that would # enable it for all configure tests. If a configure test failed due @@ -1215,6 +1215,11 @@ for flag in $gcc_flags; do fi done +if compile_prog "-Werror -fstack-protector-all" "" ; then +QEMU_CFLAGS="$QEMU_CFLAGS -fstack-protector-all" +LIBTOOLFLAGS="$LIBTOOLFLAGS -Wc,-fstack-protector-all" +fi + # Workaround for http://gcc.gnu.org/PR55489. Happens with -fPIE/-fPIC and # large functions that use global variables. The bug is in all releases of # GCC, but it became particularly acute in 4.6.x and 4.7.x. It is fixed in @@ -3842,6 +3847,7 @@ else echo "AUTOCONF_HOST := " >> $config_host_mak fi echo "LDFLAGS=$LDFLAGS" >> $config_host_mak +echo "LIBTOOLFLAGS=$LIBTOOLFLAGS" >> $config_host_mak echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak echo "ARLIBS_END=$arlibs_end" >> $config_host_mak echo "LIBS+=$LIBS" >> $config_host_mak diff --git a/rules.mak b/rules.mak index edc2552..36aba2d 100644 --- a/rules.mak +++ b/rules.mak @@ -36,6 +36,7 @@ LINK = $(call quiet-command,\ $(if $(filter %.lo %.la,$^),$(LIBTOOL) --mode=link --tag=CC \ )$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \ $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(version-obj-y) \ + $(if $(filter %.lo %.la,$^),$(LIBTOOLFLAGS)) \ $(LIBS),$(if $(filter %.lo %.la,$^),"lt LINK ", " LINK ")"$(TARGET_DIR)$@") endif -- 1.8.1.1.439.g50a6b54
[Qemu-devel] [PATCH 2/2] libcacard: fix mingw64 cross-compilation
From: Marc-André Lureau Compile and link with version.lo Signed-off-by: Marc-André Lureau --- Makefile | 8 ++-- rules.mak | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 2262410..5f0ded1 100644 --- a/Makefile +++ b/Makefile @@ -148,11 +148,15 @@ recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) -version.o: $(SRC_PATH)/version.rc config-host.h +version.o: $(SRC_PATH)/version.rc config-host.h | version.lo $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC$(TARGET_DIR)$@") +version.lo: $(SRC_PATH)/version.rc config-host.h + $(call quiet-command,$(LIBTOOL) --mode=compile --tag=RC $(WINDRES) -I. -o $@ $<,"lt RC $(TARGET_DIR)$@") version-obj-$(CONFIG_WIN32) += version.o -Makefile: $(version-obj-y) +version-lobj-$(CONFIG_WIN32) += $(if $(LIBTOOL),version.lo) +Makefile: $(version-obj-y) $(version-lobj-y) + ## # Build libraries diff --git a/rules.mak b/rules.mak index 36aba2d..292a422 100644 --- a/rules.mak +++ b/rules.mak @@ -35,7 +35,8 @@ LIBTOOL += $(if $(V),,--quiet) LINK = $(call quiet-command,\ $(if $(filter %.lo %.la,$^),$(LIBTOOL) --mode=link --tag=CC \ )$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \ - $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(version-obj-y) \ + $(sort $(filter %.o, $1)) $(filter-out %.o, $1) \ + $(if $(filter %.lo %.la,$^),$(version-lobj-y),$(version-obj-y)) \ $(if $(filter %.lo %.la,$^),$(LIBTOOLFLAGS)) \ $(LIBS),$(if $(filter %.lo %.la,$^),"lt LINK ", " LINK ")"$(TARGET_DIR)$@") endif -- 1.8.1.1.439.g50a6b54
[Qemu-devel] [PATCH v2 1/6] util: move socket_init() to osdep.c
From: Marc-André Lureau vscclient needs to call socket_init() for portability. Moving to osdep.c since it has no internal dependency. Signed-off-by: Marc-André Lureau --- util/osdep.c| 23 +++ util/qemu-sockets.c | 24 2 files changed, 23 insertions(+), 24 deletions(-) diff --git a/util/osdep.c b/util/osdep.c index 5b51a03..3c1a0a3 100644 --- a/util/osdep.c +++ b/util/osdep.c @@ -400,3 +400,26 @@ bool fips_get_state(void) return fips_enabled; } +#ifdef _WIN32 +static void socket_cleanup(void) +{ +WSACleanup(); +} +#endif + +int socket_init(void) +{ +#ifdef _WIN32 +WSADATA Data; +int ret, err; + +ret = WSAStartup(MAKEWORD(2, 2), &Data); +if (ret != 0) { +err = WSAGetLastError(); +fprintf(stderr, "WSAStartup: %d\n", err); +return -1; +} +atexit(socket_cleanup); +#endif +return 0; +} diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 1350ccc..d8994c1 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -944,27 +944,3 @@ int socket_listen(SocketAddress *addr, Error **errp) qemu_opts_del(opts); return fd; } - -#ifdef _WIN32 -static void socket_cleanup(void) -{ -WSACleanup(); -} -#endif - -int socket_init(void) -{ -#ifdef _WIN32 -WSADATA Data; -int ret, err; - -ret = WSAStartup(MAKEWORD(2,2), &Data); -if (ret != 0) { -err = WSAGetLastError(); -fprintf(stderr, "WSAStartup: %d\n", err); -return -1; -} -atexit(socket_cleanup); -#endif -return 0; -} -- 1.8.1.1.439.g50a6b54
[Qemu-devel] [PATCH v2 2/6] build-sys: must link with -fstack-protector
It is needed to give that flag to the linker as well, but latest libtool 2.4.2 still swallows that argument, so let's pass it with libtool -Wc argument. qemu-1.4.0/stubs/arch-query-cpu-def.c:6: undefined reference to `__stack_chk_guard' Signed-off-by: Marc-André Lureau --- configure | 8 +++- rules.mak | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/configure b/configure index dcaa67c..c591314 100755 --- a/configure +++ b/configure @@ -1196,7 +1196,7 @@ fi gcc_flags="-Wold-style-declaration -Wold-style-definition -Wtype-limits" gcc_flags="-Wformat-security -Wformat-y2k -Winit-self -Wignored-qualifiers $gcc_flags" gcc_flags="-Wmissing-include-dirs -Wempty-body -Wnested-externs $gcc_flags" -gcc_flags="-fstack-protector-all -Wendif-labels $gcc_flags" +gcc_flags="-Wendif-labels $gcc_flags" gcc_flags="-Wno-initializer-overrides $gcc_flags" # Note that we do not add -Werror to gcc_flags here, because that would # enable it for all configure tests. If a configure test failed due @@ -1215,6 +1215,11 @@ for flag in $gcc_flags; do fi done +if compile_prog "-Werror -fstack-protector-all" "" ; then +QEMU_CFLAGS="$QEMU_CFLAGS -fstack-protector-all" +LIBTOOLFLAGS="$LIBTOOLFLAGS -Wc,-fstack-protector-all" +fi + # Workaround for http://gcc.gnu.org/PR55489. Happens with -fPIE/-fPIC and # large functions that use global variables. The bug is in all releases of # GCC, but it became particularly acute in 4.6.x and 4.7.x. It is fixed in @@ -3842,6 +3847,7 @@ else echo "AUTOCONF_HOST := " >> $config_host_mak fi echo "LDFLAGS=$LDFLAGS" >> $config_host_mak +echo "LIBTOOLFLAGS=$LIBTOOLFLAGS" >> $config_host_mak echo "ARLIBS_BEGIN=$arlibs_begin" >> $config_host_mak echo "ARLIBS_END=$arlibs_end" >> $config_host_mak echo "LIBS+=$LIBS" >> $config_host_mak diff --git a/rules.mak b/rules.mak index edc2552..36aba2d 100644 --- a/rules.mak +++ b/rules.mak @@ -36,6 +36,7 @@ LINK = $(call quiet-command,\ $(if $(filter %.lo %.la,$^),$(LIBTOOL) --mode=link --tag=CC \ )$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \ $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(version-obj-y) \ + $(if $(filter %.lo %.la,$^),$(LIBTOOLFLAGS)) \ $(LIBS),$(if $(filter %.lo %.la,$^),"lt LINK ", " LINK ")"$(TARGET_DIR)$@") endif -- 1.8.1.1.439.g50a6b54
[Qemu-devel] [PATCH v2 5/6] libcacard: vscclient to use QemuThread for portability
From: Marc-André Lureau --- libcacard/vscclient.c | 9 ++--- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c index 5e00db3..5f47634 100644 --- a/libcacard/vscclient.c +++ b/libcacard/vscclient.c @@ -218,8 +218,7 @@ on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) int num_capabilities = 1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t)); int i; -int rv; -pthread_t thread_id; +QemuThread thread_id; incoming->version = ntohl(incoming->version); if (incoming->version != VSCARD_VERSION) { @@ -242,11 +241,7 @@ on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0); /* launch the event_thread. This will trigger reader adds for all the * existing readers */ -rv = pthread_create(&thread_id, NULL, event_thread, NULL); -if (rv < 0) { -perror("pthread_create"); -return rv; -} +qemu_thread_create(&thread_id, event_thread, NULL, 0); return 0; } -- 1.8.1.1.439.g50a6b54
[Qemu-devel] [PATCH v2 6/6] libcacard: teach vscclient to use GMainLoop for portability
This version handles non-blocking sending and receiving from the socket. Signed-off-by: Marc-André Lureau --- libcacard/vscclient.c | 391 +++--- 1 file changed, 246 insertions(+), 145 deletions(-) diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c index 5f47634..ac23647 100644 --- a/libcacard/vscclient.c +++ b/libcacard/vscclient.c @@ -10,7 +10,10 @@ * See the COPYING.LIB file in the top-level directory. */ +#ifndef _WIN32 #include +#endif +#include #include "qemu-common.h" #include "qemu/thread.h" @@ -22,9 +25,7 @@ #include "vcard_emul.h" #include "vevent.h" -int verbose; - -int sock; +static int verbose; static void print_byte_array( @@ -51,7 +52,47 @@ print_usage(void) { vcard_emul_usage(); } -static QemuMutex write_lock; +static GIOChannel *channel_socket; +static GByteArray *socket_to_send; +static QemuMutex socket_to_send_lock; +static guint socket_tag; + +static void +update_socket_watch(gboolean out); + +static gboolean +do_socket_send(GIOChannel *source, + GIOCondition condition, + gpointer data) +{ +gsize bw; +GError *err = NULL; + +g_return_val_if_fail(socket_to_send->len != 0, FALSE); +g_return_val_if_fail(condition & G_IO_OUT, FALSE); + +g_io_channel_write_chars(channel_socket, +(gchar *)socket_to_send->data, socket_to_send->len, &bw, &err); +if (err != NULL) { +g_error("Error while sending socket %s", err->message); +return FALSE; +} +g_byte_array_remove_range(socket_to_send, 0, bw); + +if (socket_to_send->len == 0) { +update_socket_watch(FALSE); +return FALSE; +} +return TRUE; +} + +static gboolean +socket_prepare_sending(gpointer user_data) +{ +update_socket_watch(TRUE); + +return FALSE; +} static int send_msg( @@ -60,10 +101,9 @@ send_msg( const void *msg, unsigned int length ) { -int rv; VSCMsgHeader mhHeader; -qemu_mutex_lock(&write_lock); +qemu_mutex_lock(&socket_to_send_lock); if (verbose > 10) { printf("sending type=%d id=%u, len =%u (0x%x)\n", @@ -73,23 +113,11 @@ send_msg( mhHeader.type = htonl(type); mhHeader.reader_id = 0; mhHeader.length = htonl(length); -rv = write(sock, &mhHeader, sizeof(mhHeader)); -if (rv < 0) { -/* Error */ -fprintf(stderr, "write header error\n"); -close(sock); -qemu_mutex_unlock(&write_lock); -return 16; -} -rv = write(sock, msg, length); -if (rv < 0) { -/* Error */ -fprintf(stderr, "write error\n"); -close(sock); -qemu_mutex_unlock(&write_lock); -return 16; -} -qemu_mutex_unlock(&write_lock); +g_byte_array_append(socket_to_send, (guint8 *)&mhHeader, sizeof(mhHeader)); +g_byte_array_append(socket_to_send, (guint8 *)msg, length); +g_idle_add(socket_prepare_sending, NULL); + +qemu_mutex_unlock(&socket_to_send_lock); return 0; } @@ -245,139 +273,203 @@ on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) return 0; } + +enum { +STATE_HEADER, +STATE_MESSAGE, +}; + #define APDUBufSize 270 -static int -do_socket_read(void) +static gboolean +do_socket_read(GIOChannel *source, + GIOCondition condition, + gpointer data) { int rv; int dwSendLength; int dwRecvLength; uint8_t pbRecvBuffer[APDUBufSize]; -uint8_t pbSendBuffer[APDUBufSize]; +static uint8_t pbSendBuffer[APDUBufSize]; VReaderStatus reader_status; VReader *reader = NULL; -VSCMsgHeader mhHeader; +static VSCMsgHeader mhHeader; VSCMsgError *error_msg; +GError *err = NULL; -rv = read(sock, &mhHeader, sizeof(mhHeader)); -if (rv < sizeof(mhHeader)) { -/* Error */ -if (rv < 0) { -perror("header read error\n"); -} else { -fprintf(stderr, "header short read %d\n", rv); -} -return -1; -} -mhHeader.type = ntohl(mhHeader.type); -mhHeader.reader_id = ntohl(mhHeader.reader_id); -mhHeader.length = ntohl(mhHeader.length); -if (verbose) { -printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n", - mhHeader.type, mhHeader.reader_id, mhHeader.length, - mhHeader.length); -} -switch (mhHeader.type) { -case VSC_APDU: -case VSC_Flush: -case VSC_Error: -case VSC_Init: -rv = read(sock, pbSendBuffer, mhHeader.length); -break; -default: -fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type); -return -1; +static gchar *buf; +static gsize br, to_read; +static int state = STATE_HEADER; + +if (state == STATE_H
Re: [Qemu-devel] [PATCH 2/4] build-sys: must link with -fstack-protector
self nack, it fails to link without libtool
[Qemu-devel] [PATCH v2 3/6] libcacard: fix mingw64 cross-compilation
Compile and link with version.lo Signed-off-by: Marc-André Lureau --- Makefile | 8 ++-- rules.mak | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 2262410..5f0ded1 100644 --- a/Makefile +++ b/Makefile @@ -148,11 +148,15 @@ recurse-all: $(SUBDIR_RULES) $(ROMSUBDIR_RULES) bt-host.o: QEMU_CFLAGS += $(BLUEZ_CFLAGS) -version.o: $(SRC_PATH)/version.rc config-host.h +version.o: $(SRC_PATH)/version.rc config-host.h | version.lo $(call quiet-command,$(WINDRES) -I. -o $@ $<," RC$(TARGET_DIR)$@") +version.lo: $(SRC_PATH)/version.rc config-host.h + $(call quiet-command,$(LIBTOOL) --mode=compile --tag=RC $(WINDRES) -I. -o $@ $<,"lt RC $(TARGET_DIR)$@") version-obj-$(CONFIG_WIN32) += version.o -Makefile: $(version-obj-y) +version-lobj-$(CONFIG_WIN32) += $(if $(LIBTOOL),version.lo) +Makefile: $(version-obj-y) $(version-lobj-y) + ## # Build libraries diff --git a/rules.mak b/rules.mak index 36aba2d..292a422 100644 --- a/rules.mak +++ b/rules.mak @@ -35,7 +35,8 @@ LIBTOOL += $(if $(V),,--quiet) LINK = $(call quiet-command,\ $(if $(filter %.lo %.la,$^),$(LIBTOOL) --mode=link --tag=CC \ )$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ \ - $(sort $(filter %.o, $1)) $(filter-out %.o, $1) $(version-obj-y) \ + $(sort $(filter %.o, $1)) $(filter-out %.o, $1) \ + $(if $(filter %.lo %.la,$^),$(version-lobj-y),$(version-obj-y)) \ $(if $(filter %.lo %.la,$^),$(LIBTOOLFLAGS)) \ $(LIBS),$(if $(filter %.lo %.la,$^),"lt LINK ", " LINK ")"$(TARGET_DIR)$@") endif -- 1.8.1.1.439.g50a6b54
[Qemu-devel] [PATCH v2 4/6] libcacard: split vscclient main() from socket reading
From: Marc-André Lureau --- libcacard/vscclient.c | 314 ++ 1 file changed, 162 insertions(+), 152 deletions(-) diff --git a/libcacard/vscclient.c b/libcacard/vscclient.c index 9b744f2..5e00db3 100644 --- a/libcacard/vscclient.c +++ b/libcacard/vscclient.c @@ -211,6 +211,166 @@ get_id_from_string(char *string, unsigned int default_id) return id; } +static int +on_host_init(VSCMsgHeader *mhHeader, VSCMsgInit *incoming) +{ +uint32_t *capabilities = (incoming->capabilities); +int num_capabilities = +1 + ((mhHeader->length - sizeof(VSCMsgInit)) / sizeof(uint32_t)); +int i; +int rv; +pthread_t thread_id; + +incoming->version = ntohl(incoming->version); +if (incoming->version != VSCARD_VERSION) { +if (verbose > 0) { +printf("warning: host has version %d, we have %d\n", +verbose, VSCARD_VERSION); +} +} +if (incoming->magic != VSCARD_MAGIC) { +printf("unexpected magic: got %d, expected %d\n", +incoming->magic, VSCARD_MAGIC); +return -1; +} +for (i = 0 ; i < num_capabilities; ++i) { +capabilities[i] = ntohl(capabilities[i]); +} +/* Future: check capabilities */ +/* remove whatever reader might be left in qemu, + * in case of an unclean previous exit. */ +send_msg(VSC_ReaderRemove, VSCARD_MINIMAL_READER_ID, NULL, 0); +/* launch the event_thread. This will trigger reader adds for all the + * existing readers */ +rv = pthread_create(&thread_id, NULL, event_thread, NULL); +if (rv < 0) { +perror("pthread_create"); +return rv; +} +return 0; +} + +#define APDUBufSize 270 + +static int +do_socket_read(void) +{ +int rv; +int dwSendLength; +int dwRecvLength; +uint8_t pbRecvBuffer[APDUBufSize]; +uint8_t pbSendBuffer[APDUBufSize]; +VReaderStatus reader_status; +VReader *reader = NULL; +VSCMsgHeader mhHeader; +VSCMsgError *error_msg; + +rv = read(sock, &mhHeader, sizeof(mhHeader)); +if (rv < sizeof(mhHeader)) { +/* Error */ +if (rv < 0) { +perror("header read error\n"); +} else { +fprintf(stderr, "header short read %d\n", rv); +} +return -1; +} +mhHeader.type = ntohl(mhHeader.type); +mhHeader.reader_id = ntohl(mhHeader.reader_id); +mhHeader.length = ntohl(mhHeader.length); +if (verbose) { +printf("Header: type=%d, reader_id=%u length=%d (0x%x)\n", + mhHeader.type, mhHeader.reader_id, mhHeader.length, + mhHeader.length); +} +switch (mhHeader.type) { +case VSC_APDU: +case VSC_Flush: +case VSC_Error: +case VSC_Init: +rv = read(sock, pbSendBuffer, mhHeader.length); +break; +default: +fprintf(stderr, "Unexpected message of type 0x%X\n", mhHeader.type); +return -1; +} +switch (mhHeader.type) { +case VSC_APDU: +if (rv < 0) { +/* Error */ +fprintf(stderr, "read error\n"); +close(sock); +return -1; +} +if (verbose) { +printf(" recv APDU: "); +print_byte_array(pbSendBuffer, mhHeader.length); +} +/* Transmit received APDU */ +dwSendLength = mhHeader.length; +dwRecvLength = sizeof(pbRecvBuffer); +reader = vreader_get_reader_by_id(mhHeader.reader_id); +reader_status = vreader_xfr_bytes(reader, + pbSendBuffer, dwSendLength, + pbRecvBuffer, &dwRecvLength); +if (reader_status == VREADER_OK) { +mhHeader.length = dwRecvLength; +if (verbose) { +printf(" send response: "); +print_byte_array(pbRecvBuffer, mhHeader.length); +} +send_msg(VSC_APDU, mhHeader.reader_id, + pbRecvBuffer, dwRecvLength); +} else { +rv = reader_status; /* warning: not meaningful */ +send_msg(VSC_Error, mhHeader.reader_id, &rv, sizeof(uint32_t)); +} +vreader_free(reader); +reader = NULL; /* we've freed it, don't use it by accident + again */ +break; +case VSC_Flush: +/* TODO: actually flush */ +send_msg(VSC_FlushComplete, mhHeader.reader_id, NULL, 0); +break; +case VSC_Error: +error_msg = (VSCMsgError *) pbSendBuffer; +if (error_msg->code == VSC_SUCCESS) { +qemu_mutex_lock(&pending_reader_lock); +if (pending_reader) { +vreader_set_id(pending_reader, mhHeader.reader_id); +vreader_free(pending_reade
Re: [Qemu-devel] [PATCH 3/4] libcacard: fix mingw64 cross-compilation
- Mensaje original - > Il 25/02/2013 18:56, Marc-André Lureau ha scritto: > > LINK = $(call quiet-command,\ > > $(if $(filter %.lo %.la,$^),$(LIBTOOL) --mode=link --tag=CC > > \ > > )$(CC) $(QEMU_CFLAGS) $(CFLAGS) $(LDFLAGS) $(LIBTOOLFLAGS) > > -o $@ \ > > - $(sort $(filter %.o, $1)) $(filter-out %.o, $1) > > $(version-obj-y) \ > > + $(sort $(filter %.o, $1)) $(filter-out %.o, $1) > > $(version-lobj-y) \ > > $(LIBS),$(if $(filter %.lo %.la,$^),"lt LINK ", " LINK > > ")"$(TARGET_DIR)$@") > > Unfortunately, this does not work if linking without libtool. Same problem with LIBTOOLFLAGS -Wc,-fstack-protector-all... I must say the qemu configure/build-sys gets me very confused.
Re: [Qemu-devel] [PATCH] libcacard: correct T0 historical bytes size
ping On Mon, Jan 14, 2013 at 5:18 PM, Marc-André Lureau wrote: > ping > > On Sun, Dec 2, 2012 at 10:00 PM, Marc-André Lureau > wrote: >> The VCARD_ATR_PREFIX macro adds a prefix of 6 characters only. >> >> pcsc_scan was complaining before the patch: >> >> + Historical bytes: 56 43 41 52 44 5F 4E 53 53 >> ERROR! ATR is truncated: 2 byte(s) is/are missing >> --- >> libcacard/vcardt.h | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/libcacard/vcardt.h b/libcacard/vcardt.h >> index d3e9522..538bdde 100644 >> --- a/libcacard/vcardt.h >> +++ b/libcacard/vcardt.h >> @@ -26,7 +26,7 @@ typedef struct VCardEmulStruct VCardEmul; >> #define MAX_CHANNEL 4 >> >> /* create an ATR with appropriate historical bytes */ >> -#define VCARD_ATR_PREFIX(size) 0x3b, 0x68+(size), 0x00, 0xff, \ >> +#define VCARD_ATR_PREFIX(size) 0x3b, 0x66+(size), 0x00, 0xff, \ >> 'V', 'C', 'A', 'R', 'D', '_' >> >> >> -- >> 1.7.11.7 >> > > > > -- > Marc-André Lureau -- Marc-André Lureau
[Qemu-devel] [PATCH] libcacard: use system config directory for nss db on win32
It's a bit nicer to look for default database under CSIDL_COMMON_APPDATA\pki\nss rather that /etc/pki/nss. Signed-off-by: Marc-André Lureau --- libcacard/vcard_emul_nss.c | 18 +- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/libcacard/vcard_emul_nss.c b/libcacard/vcard_emul_nss.c index df79476..21d4689 100644 --- a/libcacard/vcard_emul_nss.c +++ b/libcacard/vcard_emul_nss.c @@ -893,7 +893,23 @@ vcard_emul_init(const VCardEmulOptions *options) if (options->nss_db) { rv = NSS_Init(options->nss_db); } else { -rv = NSS_Init("sql:/etc/pki/nssdb"); +gchar *path, *db; +#ifndef _WIN32 +path = g_strdup("/etc/pki/nssdb"); +#else +if (g_get_system_config_dirs() == NULL || +g_get_system_config_dirs()[0] == NULL) { +return VCARD_EMUL_FAIL; +} + +path = g_build_filename( +g_get_system_config_dirs()[0], "pki", "nssdb", NULL); +#endif +db = g_strdup_printf("sql:%s", path); + +rv = NSS_Init(db); +g_free(db); +g_free(path); } if (rv != SECSuccess) { return VCARD_EMUL_FAIL; -- 1.8.1.1.439.g50a6b54
Re: [Qemu-devel] [PATCH] spice-core: Use g_strdup_printf instead of snprintf
ack On Mon, Sep 2, 2013 at 11:53 AM, Christophe Fergeau wrote: > Several places in spice-core.c were using either g_malloc+snprintf > or snprintf+g_strdup to achieve the same result as g_strdup_printf. > > Signed-off-by: Christophe Fergeau > --- > ui/spice-core.c | 22 -- > 1 file changed, 8 insertions(+), 14 deletions(-) > > diff --git a/ui/spice-core.c b/ui/spice-core.c > index bd7a248..01b9906 100644 > --- a/ui/spice-core.c > +++ b/ui/spice-core.c > @@ -511,7 +511,6 @@ SpiceInfo *qmp_query_spice(Error **errp) > int port, tls_port; > const char *addr; > SpiceInfo *info; > -char version_string[20]; /* 12 = |255.255.255\0| is the max */ > > info = g_malloc0(sizeof(*info)); > > @@ -534,11 +533,10 @@ SpiceInfo *qmp_query_spice(Error **errp) > info->host = g_strdup(addr ? addr : "0.0.0.0"); > > info->has_compiled_version = true; > -snprintf(version_string, sizeof(version_string), "%d.%d.%d", > - (SPICE_SERVER_VERSION & 0xff) >> 16, > - (SPICE_SERVER_VERSION & 0xff00) >> 8, > - SPICE_SERVER_VERSION & 0xff); > -info->compiled_version = g_strdup(version_string); > +info->compiled_version = g_strdup_printf("%d.%d.%d", > + (SPICE_SERVER_VERSION & > 0xff) >> 16, > + (SPICE_SERVER_VERSION & 0xff00) > >> 8, > + SPICE_SERVER_VERSION & 0xff); > > if (port) { > info->has_port = true; > @@ -640,7 +638,7 @@ void qemu_spice_init(void) > char *x509_key_file = NULL, > *x509_cert_file = NULL, > *x509_cacert_file = NULL; > -int port, tls_port, len, addr_flags; > +int port, tls_port, addr_flags; > spice_image_compression_t compression; > spice_wan_compression_t wan_compr; > bool seamless_migration; > @@ -671,30 +669,26 @@ void qemu_spice_init(void) > if (NULL == x509_dir) { > x509_dir = "."; > } > -len = strlen(x509_dir) + 32; > > str = qemu_opt_get(opts, "x509-key-file"); > if (str) { > x509_key_file = g_strdup(str); > } else { > -x509_key_file = g_malloc(len); > -snprintf(x509_key_file, len, "%s/%s", x509_dir, > X509_SERVER_KEY_FILE); > +x509_key_file = g_strdup_printf("%s/%s", x509_dir, > X509_SERVER_KEY_FILE); > } > > str = qemu_opt_get(opts, "x509-cert-file"); > if (str) { > x509_cert_file = g_strdup(str); > } else { > -x509_cert_file = g_malloc(len); > -snprintf(x509_cert_file, len, "%s/%s", x509_dir, > X509_SERVER_CERT_FILE); > +x509_cert_file = g_strdup_printf("%s/%s", x509_dir, > X509_SERVER_CERT_FILE); > } > > str = qemu_opt_get(opts, "x509-cacert-file"); > if (str) { > x509_cacert_file = g_strdup(str); > } else { > -x509_cacert_file = g_malloc(len); > -snprintf(x509_cacert_file, len, "%s/%s", x509_dir, > X509_CA_CERT_FILE); > +x509_cacert_file = g_strdup_printf("%s/%s", x509_dir, > X509_CA_CERT_FILE); > } > > x509_key_password = qemu_opt_get(opts, "x509-key-password"); > -- > 1.8.3.1 > > -- Marc-André Lureau
Re: [Qemu-devel] [PATCH v2 00/10] ccid and libcacard fixes for windows/mingw
Hi On Wed, Mar 27, 2013 at 9:36 PM, Alon Levy wrote: > This series: > 1. fixes windows guests to show the ccid device > 2. changes libcacard to use glib > 3. makes libcacard build under mingw > 4. does some cleanups > > It contains a few patches already posted to the list (the two Jim Meyering > patches) which were already acked. > > I'll make a pull request once this had some time to be reviewed. > > Tested with a fedora and windows 7 guest. > > The main non cleanup patches are: > hw/usb/dev-smartcard-reader: support windows guest > libcacard: correct T0 historical bytes size > > The patch series doesn't do what you describe. Many patches are missing from the v1: http://lists.nongnu.org/archive/html/qemu-devel/2013-03/msg02925.html -- Marc-André Lureau
Re: [Qemu-devel] [PATCH v3 00/28] ccid and libcacard fixes for windows/mingw
Reviewed-by: Marc-André Lureau
[Qemu-devel] [PATCH] qxl: keep going if reaching guest bug on empty area
Xorg server hangs when using xfig and typing a text with space: #0 qxl_wait_for_io_command (qxl=) at qxl_io.c:47 #1 0x7f826a49a299 in qxl_download_box (surface=0x221d030, x1=231, y1=259, x2=, y2=) at qxl_surface.c:143 while (!(ram_header->int_pending & QXL_INTERRUPT_IO_CMD)) usleep (1); The QXL driver is calling QXL_IO_UPDATE_AREA with an empty area. This is a guest bug. The call is async and no ack is sent back on guest bug, so the X server will hang. The driver should be improved to avoid this situation and also to abort on QXL_INTERRUPT_ERROR. This will be a different patch series for the driver. However, it is simple enough to keep qemu running on empty areas update, which is what this patch provides. https://bugzilla.redhat.com/show_bug.cgi?id=1151363 --- hw/display/qxl.c | 5 + 1 file changed, 5 insertions(+) diff --git a/hw/display/qxl.c b/hw/display/qxl.c index 93b3518..b540dd6 100644 --- a/hw/display/qxl.c +++ b/hw/display/qxl.c @@ -1591,6 +1591,11 @@ async_common: qxl_set_guest_bug(d, "QXL_IO_UPDATE_AREA: invalid area (%ux%u)x(%ux%u)\n", update.left, update.top, update.right, update.bottom); +if (update.left == update.right || update.top == update.bottom) { +/* old drivers may provide empty area, keep going */ +qxl_clear_guest_bug(d); +goto cancel_async; +} break; } if (async == QXL_ASYNC) { -- 1.9.3
[Qemu-devel] [PATCH 2/2] spice-char: notify the server when chardev is writable
The spice server is polling on write, unless SPICE_CHAR_DEVICE_NOTIFY_WRITABLE flag is set. In this case, qemu must call spice_server_char_device_wakeup() when the frontend is writable. Signed-off-by: Marc-André Lureau --- spice-qemu-char.c | 11 +++ 1 file changed, 11 insertions(+) diff --git a/spice-qemu-char.c b/spice-qemu-char.c index 8106e06..3de01d1 100644 --- a/spice-qemu-char.c +++ b/spice-qemu-char.c @@ -111,6 +111,9 @@ static SpiceCharDeviceInterface vmc_interface = { #if SPICE_SERVER_VERSION >= 0x000c02 .event = vmc_event, #endif +#if SPICE_SERVER_VERSION >= 0x000c06 +.flags = SPICE_CHAR_DEVICE_NOTIFY_WRITABLE, +#endif }; @@ -261,6 +264,13 @@ static void print_allowed_subtypes(void) fprintf(stderr, "\n"); } +static void spice_chr_accept_input(struct CharDriverState *chr) +{ +SpiceCharDriver *s = chr->opaque; + +spice_server_char_device_wakeup(&s->sin); +} + static CharDriverState *chr_open(const char *subtype, void (*set_fe_open)(struct CharDriverState *, int)) @@ -280,6 +290,7 @@ static CharDriverState *chr_open(const char *subtype, chr->chr_set_fe_open = set_fe_open; chr->explicit_be_open = true; chr->chr_fe_event = spice_chr_fe_event; +chr->chr_accept_input = spice_chr_accept_input; QLIST_INSERT_HEAD(&spice_chars, s, next); -- 1.9.3
[Qemu-devel] [PATCH 1/2] virtio-console: notify chardev when writable
When the virtio serial is writable, notify the chardev backend with qemu_chr_accept_input(). Signed-off-by: Marc-André Lureau --- Note: This patch depends on Amit Shah patch: "virtio: serial: expose a 'guest_writable' callback for users" hw/char/virtio-console.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/hw/char/virtio-console.c b/hw/char/virtio-console.c index 752ed2c..2a867cb 100644 --- a/hw/char/virtio-console.c +++ b/hw/char/virtio-console.c @@ -95,6 +95,15 @@ static void set_guest_connected(VirtIOSerialPort *port, int guest_connected) } } +static void guest_writable(VirtIOSerialPort *port) +{ +VirtConsole *vcon = VIRTIO_CONSOLE(port); + +if (vcon->chr) { +qemu_chr_accept_input(vcon->chr); +} +} + /* Readiness of the guest to accept data on a port */ static int chr_can_read(void *opaque) { @@ -188,6 +197,7 @@ static void virtserialport_class_init(ObjectClass *klass, void *data) k->unrealize = virtconsole_unrealize; k->have_data = flush_buf; k->set_guest_connected = set_guest_connected; +k->guest_writable = guest_writable; dc->props = virtserialport_properties; } -- 1.9.3
Re: [Qemu-devel] [PATCH 2/2] spice-char: notify the server when chardev is writable
Hi On Mon, Oct 27, 2014 at 9:08 AM, Gerd Hoffmann wrote: > > +static void spice_chr_accept_input(struct CharDriverState *chr) > > +{ > > +SpiceCharDriver *s = chr->opaque; > > + > > +spice_server_char_device_wakeup(&s->sin); > > Does this build on older spice versions? I'd suspect this needs #if > SPICE_SERVER_VERSION too ... There is already a spice_server_char_device_wakeup() call there. On older servers, this additional call will trigger just a read try. With the proposed patch in Spice server, it will do read & write try (I didn't see the need to create a new function to do only read or write, both should be fine) -- Marc-André Lureau
Re: [Qemu-devel] [PATCH 2/2] spice-char: notify the server when chardev is writable
On Mon, Oct 27, 2014 at 1:43 PM, Amit Shah wrote: > Great, so there's no other change required to actually use the > functionality in my patch? Does my patch fit your need fine, or do > you need to tweak the notification somehow? > > It seems to be working nicely. > It would be great to get your reviewed-by to my patch in case > everything's fine. > > Peter has asked me to update the comments on my patch; I'll fix that > up right away since this showed up. > Sure, I'll wait for next updated patch then. -- Marc-André Lureau
Re: [Qemu-devel] [PATCH v3 1/1] virtio: serial: expose a 'guest_writable' callback for users
Reviewed-by: Marc-André Lureau I have a somewhat related question, that perhaps someone may help me with: Why isn't the qemu char driver/device interface based (for most devices) on socketpair (and equivalent bi-directional pipe on other OS). It looks to me like it could simplify API and event handling on both fe/be sides, although it may cost a few more open fds and additional copy. - Mail original - > Users of virtio-serial may want to know when a port becomes writable. A > port can stop accepting writes if the guest port is open but not being > read from. In this case, data gets queued up in the virtqueue, and > after the vq is full, writes to the port do not succeed. > > When the guest reads off a vq element, and adds a new one for the host > to put data in, we can tell users the port is available for more writes, > via the new ->guest_writable() callback. > > Signed-off-by: Amit Shah > > --- > v3: document the semantics of the callback (Peter Maydell, Markus) > v2: check for port != NULL (Peter Maydell) > --- > hw/char/virtio-serial-bus.c | 31 +++ > include/hw/virtio/virtio-serial.h | 11 +++ > 2 files changed, 42 insertions(+) > > diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c > index c6870f1..bea7a17 100644 > --- a/hw/char/virtio-serial-bus.c > +++ b/hw/char/virtio-serial-bus.c > @@ -465,6 +465,37 @@ static void handle_output(VirtIODevice *vdev, VirtQueue > *vq) > > static void handle_input(VirtIODevice *vdev, VirtQueue *vq) > { > +/* > + * Users of virtio-serial would like to know when guest becomes > + * writable again -- i.e. if a vq had stuff queued up and the > + * guest wasn't reading at all, the host would not be able to > + * write to the vq anymore. Once the guest reads off something, > + * we can start queueing things up again. However, this call is > + * made for each buffer addition by the guest -- even though free > + * buffers existed prior to the current buffer addition. This is > + * done so as not to maintain previous state, which will need > + * additional live-migration-related changes. > + */ > +VirtIOSerial *vser; > +VirtIOSerialPort *port; > +VirtIOSerialPortClass *vsc; > + > +vser = VIRTIO_SERIAL(vdev); > +port = find_port_by_vq(vser, vq); > + > +if (!port) { > +return; > +} > +vsc = VIRTIO_SERIAL_PORT_GET_CLASS(port); > + > +/* > + * If guest_connected is false, this call is being made by the > + * early-boot queueing up of descriptors, which is just noise for > + * the host apps -- don't disturb them in that case. > + */ > +if (port->guest_connected && port->host_connected && > vsc->guest_writable) { > +vsc->guest_writable(port); > +} > } > > static uint32_t get_features(VirtIODevice *vdev, uint32_t features) > diff --git a/include/hw/virtio/virtio-serial.h > b/include/hw/virtio/virtio-serial.h > index a679e54..fe6e696 100644 > --- a/include/hw/virtio/virtio-serial.h > +++ b/include/hw/virtio/virtio-serial.h > @@ -98,6 +98,17 @@ typedef struct VirtIOSerialPortClass { > /* Guest is now ready to accept data (virtqueues set up). */ > void (*guest_ready)(VirtIOSerialPort *port); > > +/* > + * Guest has enqueued a buffer for the host to write into. > + * Called each time a buffer is enqueued by the guest; > + * irrespective of whether there already were free buffers the > + * host could have consumed. > + * > + * This is dependent on both, the guest and host ends being > + * connected. > + */ > +void (*guest_writable)(VirtIOSerialPort *port); > + > /* > * Guest wrote some data to the port. This data is handed over to > * the app via this callback. The app can return a size less than > -- > 1.9.3 > >
[Qemu-devel] [PATCH] virtio-serial: avoid crash when port has no name
It seems "name" is not mandatory, and the following command line (based on one generated by current libvirt) will crash qemu at start: qemu-system-x86_64 \ -device virtio-serial-pci \ -device virtserialport,name=foo \ -device virtconsole Program received signal SIGSEGV, Segmentation fault. __strcmp_ssse3 () at ../sysdeps/x86_64/strcmp.S:210 210movlpd(%rsi), %xmm2 Missing separate debuginfos, use: debuginfo-install python-libs-2.7.5-13.fc20.x86_64 (gdb) bt #0 __strcmp_ssse3 () at ../sysdeps/x86_64/strcmp.S:210 #1 0x5566bdc6 in find_port_by_name (name=0x0) at /home/elmarco/src/qemu/hw/char/virtio-serial-bus.c:67 --- hw/char/virtio-serial-bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 3931085..f16452e 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -871,7 +871,7 @@ static void virtser_port_device_realize(DeviceState *dev, Error **errp) return; } -if (find_port_by_name(port->name)) { +if (port->name != NULL && find_port_by_name(port->name)) { error_setg(errp, "virtio-serial-bus: A port already exists by name %s", port->name); return; -- 1.9.3
[Qemu-devel] [PATCH] spice: call qemu_spice_set_passwd() during init
Don't call SPICE API directly to set password given in command line, but use the internal API, saving password for later calls. This solves losing password when changing expiration in qemu monitor. https://bugzilla.redhat.com/show_bug.cgi?id=1138639 --- ui/spice-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/spice-core.c b/ui/spice-core.c index 7bb91e6..f2e6521 100644 --- a/ui/spice-core.c +++ b/ui/spice-core.c @@ -733,7 +733,7 @@ void qemu_spice_init(void) tls_ciphers); } if (password) { -spice_server_set_ticket(spice_server, password, 0, 0, 0); +qemu_spice_set_passwd(password, false, false); } if (qemu_opt_get_bool(opts, "sasl", 0)) { if (spice_server_set_sasl_appname(spice_server, "qemu") == -1 || -- 1.9.3
Re: [Qemu-devel] [Spice-devel] qemu run crash when divice_add another qxl display card
On Tue, Jul 29, 2014 at 9:50 AM, zhou link wrote: > here hit an assertion: > > qemu-system-x86_64 -monitor stdio -vga qxl -spice > port=,disable-ticketing > (/home/brook/local/bin/qemu-system-x86_64:27280): Spice-Warning **: > reds.c:3295:spice_server_init: [07-29 23:41:47]ct: Jul 26 2014 00:28:12 > > QEMU 2.0.0 monitor - type 'help' for more information > (qemu) > (qemu) > (qemu) > (qemu) device_add qxl > (/home/brook/local/bin/qemu-system-x86_64:27280): SpiceWorker-ERROR **: > red_worker.c:12385:handle_dev_stop: [07-29 23:41:56]assertion > `worker->running' failed > > Breakpoint 3, qemu_spice_display_stop () at ui/spice-core.c:922 922spice_server_vm_stop(spice_ server); (gdb) bt #0 qemu_spice_display_stop () at ui/spice-core.c:922 #1 0x55806910 in qxl_hard_reset (d=0x56612660, loadvm=0) at hw/display/qxl.c:1158 #2 0x558069b9 in qxl_reset_handler (dev=0x56612660) at hw/display/qxl.c:1184 #3 0x557d25a9 in device_reset (dev=0x56612660) at hw/core/qdev.c:996 #4 0x557d1e85 in device_set_realized (obj=0x56612660, value=true, errp=0x7fffc298) at hw/core/qdev.c:833 #5 0x558c76c7 in property_set_bool (obj=0x56612660, v=0x5637d770, opaque=0x5639ddb0, name=0x559ae629 "realized", errp=0x7fffc298) at qom/object.c:1421 #6 0x558c6245 in object_property_set (obj=0x56612660, v=0x5637d770, name=0x559ae629 "realized", errp=0x7fffc298) at qom/object.c:819 #7 0x558c7d0f in object_property_set_qobject (obj=0x56612660, value=0x56388f50, name=0x559ae629 "realized", errp=0x7fffc298) at qom/qom-qobject.c:24 #8 0x558c6490 in object_property_set_bool (obj=0x56612660, value=true, name=0x559ae629 "realized", errp=0x7fffc298) at qom/object.c:883 #9 0x5570fda2 in qdev_device_add (opts=0x565bbca0) at qdev-monitor.c:560 In qemu, spice_server_vm_stop() is called from device "reset" when it is added, because spice_display_is_running. The spice server exposes a single state, regardless the number of devices/worker, In Spice server, handle_dev_stop: -spice_assert(worker->running); +if (!worker->running) +return; + It looks like replacing the assert with a simple check solves the issue, but I am not sure qemu or the spice code handles the rest fine. What were you trying to achieve? cheers -- Marc-André Lureau
[Qemu-devel] [PATCH 01/11] audio: add VOICE_VOLUME ctl
Add a new PCM control operation to update the stream volume on the audio backend. The argument given is a SWVoiceOut/SWVoiceIn. --- audio/audio.c | 12 audio/audio_int.h |1 + 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 398763f..d76c342 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2053,17 +2053,29 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) { if (sw) { +HWVoiceOut *hw = sw->hw; + sw->vol.mute = mute; sw->vol.l = nominal_volume.l * lvol / 255; sw->vol.r = nominal_volume.r * rvol / 255; + +if (hw->pcm_ops->ctl_out) { +hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw); +} } } void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) { if (sw) { +HWVoiceIn *hw = sw->hw; + sw->vol.mute = mute; sw->vol.l = nominal_volume.l * lvol / 255; sw->vol.r = nominal_volume.r * rvol / 255; + +if (hw->pcm_ops->ctl_in) { +hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw); +} } } diff --git a/audio/audio_int.h b/audio/audio_int.h index 2003f8b..117f95e 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -231,6 +231,7 @@ void audio_run (const char *msg); #define VOICE_ENABLE 1 #define VOICE_DISABLE 2 +#define VOICE_VOLUME 3 static inline int audio_ring_dist (int dst, int src, int len) { -- 1.7.7.6
[Qemu-devel] [PATCH 02/11] audio: don't apply volume effect if backend has VOICE_VOLUME_CAP
If the audio backend is capable of volume control, don't apply software volume (mixeng_volume ()), but instead, rely on backend volume control. This will allow guest to have full range volume control. --- audio/audio.c |9 +++-- audio/audio_int.h |5 + audio/audio_template.h |2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index d76c342..bd9237e 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -957,7 +957,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) total += isamp; } -mixeng_volume (sw->buf, ret, &sw->vol); +if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) { +mixeng_volume (sw->buf, ret, &sw->vol); +} sw->clip (buf, sw->buf, ret); sw->total_hw_samples_acquired += total; @@ -1041,7 +1043,10 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) swlim = audio_MIN (swlim, samples); if (swlim) { sw->conv (sw->buf, buf, swlim); -mixeng_volume (sw->buf, swlim, &sw->vol); + +if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { +mixeng_volume (sw->buf, swlim, &sw->vol); +} } while (swlim) { diff --git a/audio/audio_int.h b/audio/audio_int.h index 117f95e..b9b0676 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -82,6 +82,7 @@ typedef struct HWVoiceOut { int samples; QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; +int ctl_caps; struct audio_pcm_ops *pcm_ops; QLIST_ENTRY (HWVoiceOut) entries; } HWVoiceOut; @@ -101,6 +102,7 @@ typedef struct HWVoiceIn { int samples; QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; +int ctl_caps; struct audio_pcm_ops *pcm_ops; QLIST_ENTRY (HWVoiceIn) entries; } HWVoiceIn; @@ -150,6 +152,7 @@ struct audio_driver { int max_voices_in; int voice_size_out; int voice_size_in; +int ctl_caps; }; struct audio_pcm_ops { @@ -233,6 +236,8 @@ void audio_run (const char *msg); #define VOICE_DISABLE 2 #define VOICE_VOLUME 3 +#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME) + static inline int audio_ring_dist (int dst, int src, int len) { return (dst >= src) ? (dst - src) : (len - src + dst); diff --git a/audio/audio_template.h b/audio/audio_template.h index e62a713..519432a 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -263,6 +263,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) } hw->pcm_ops = drv->pcm_ops; +hw->ctl_caps = drv->ctl_caps; + QLIST_INIT (&hw->sw_head); #ifdef DAC QLIST_INIT (&hw->cap_head); -- 1.7.7.6
[Qemu-devel] [PATCH 04/11] hw/ac97: remove USE_MIXER code
That code doesn't compile. The interesting bits for volume control are going to be rewritten in the following patch. --- hw/ac97.c | 121 - 1 files changed, 0 insertions(+), 121 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index c0fd019..f2804e6 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -437,99 +437,6 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) AUD_set_active_in (s->voice_mc, active[MC_INDEX]); } -#ifdef USE_MIXER -static void set_volume (AC97LinkState *s, int index, -audmixerctl_t mt, uint32_t val) -{ -int mute = (val >> MUTE_SHIFT) & 1; -uint8_t rvol = VOL_MASK - (val & VOL_MASK); -uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK); -rvol = 255 * rvol / VOL_MASK; -lvol = 255 * lvol / VOL_MASK; - -#ifdef SOFT_VOLUME -if (index == AC97_Master_Volume_Mute) { -AUD_set_volume_out (s->voice_po, mute, lvol, rvol); -} -else { -AUD_set_volume (mt, &mute, &lvol, &rvol); -} -#else -AUD_set_volume (mt, &mute, &lvol, &rvol); -#endif - -rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); -lvol = VOL_MASK - ((VOL_MASK * lvol) / 255); -mixer_store (s, index, val); -} - -static audrecsource_t ac97_to_aud_record_source (uint8_t i) -{ -switch (i) { -case REC_MIC: -return AUD_REC_MIC; - -case REC_CD: -return AUD_REC_CD; - -case REC_VIDEO: -return AUD_REC_VIDEO; - -case REC_AUX: -return AUD_REC_AUX; - -case REC_LINE_IN: -return AUD_REC_LINE_IN; - -case REC_PHONE: -return AUD_REC_PHONE; - -default: -dolog ("Unknown record source %d, using MIC\n", i); -return AUD_REC_MIC; -} -} - -static uint8_t aud_to_ac97_record_source (audrecsource_t rs) -{ -switch (rs) { -case AUD_REC_MIC: -return REC_MIC; - -case AUD_REC_CD: -return REC_CD; - -case AUD_REC_VIDEO: -return REC_VIDEO; - -case AUD_REC_AUX: -return REC_AUX; - -case AUD_REC_LINE_IN: -return REC_LINE_IN; - -case AUD_REC_PHONE: -return REC_PHONE; - -default: -dolog ("Unknown audio recording source %d using MIC\n", rs); -return REC_MIC; -} -} - -static void record_select (AC97LinkState *s, uint32_t val) -{ -uint8_t rs = val & REC_MASK; -uint8_t ls = (val >> 8) & REC_MASK; -audrecsource_t ars = ac97_to_aud_record_source (rs); -audrecsource_t als = ac97_to_aud_record_source (ls); -AUD_set_record_source (&als, &ars); -rs = aud_to_ac97_record_source (ars); -ls = aud_to_ac97_record_source (als); -mixer_store (s, AC97_Record_Select, rs | (ls << 8)); -} -#endif - static void mixer_reset (AC97LinkState *s) { uint8_t active[LAST_INDEX]; @@ -564,12 +471,6 @@ static void mixer_reset (AC97LinkState *s) mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); -#ifdef USE_MIXER -record_select (s, 0); -set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000); -set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM, 0x8808); -set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); -#endif reset_voices (s, active); } @@ -628,20 +529,6 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; -#ifdef USE_MIXER -case AC97_Master_Volume_Mute: -set_volume (s, index, AUD_MIXER_VOLUME, val); -break; -case AC97_PCM_Out_Volume_Mute: -set_volume (s, index, AUD_MIXER_PCM, val); -break; -case AC97_Line_In_Volume_Mute: -set_volume (s, index, AUD_MIXER_LINE_IN, val); -break; -case AC97_Record_Select: -record_select (s, val); -break; -#endif case AC97_Vendor_ID1: case AC97_Vendor_ID2: dolog ("Attempt to write vendor ID to %#x\n", val); @@ -1194,14 +1081,6 @@ static int ac97_post_load (void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; -#ifdef USE_MIXER -record_select (s, mixer_load (s, AC97_Record_Select)); -#define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) -V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); -V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); -V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); -#undef V_ -#endif active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); -- 1.7.7.6
[Qemu-devel] [PATCH 09/11] configure: pa_simple is not needed anymore
--- configure |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 39d2b54..160bf63 100755 --- a/configure +++ b/configure @@ -1842,9 +1842,9 @@ for drv in $audio_drv_list; do ;; pa) -audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \ -"pa_simple *s = 0; pa_simple_free(s); return 0;" -libs_softmmu="-lpulse -lpulse-simple $libs_softmmu" +audio_drv_probe $drv pulse/mainloop.h "-lpulse" \ +"pa_mainloop *m = 0; pa_mainloop_free (m); return 0;" +libs_softmmu="-lpulse $libs_softmmu" audio_pt_int="yes" ;; -- 1.7.7.6
Re: [Qemu-devel] [PATCH/RFC 0/7] Screendump to UNIX socket & in PNG format
On Mon, Mar 12, 2012 at 7:53 PM, Anthony Liguori wrote: > Why not just return the screendump through QMP? in base64, base85? -- Marc-André Lureau
[Qemu-devel] [PATCH 11/11] Make mixemu mandatory
Without MIXEMU, volume control on the guest doesn't work (except when volume is applied by guest "emulation", in Win7 for example). Instead rely on backend volume support, or fallback on mixeng if backend doesn't support volume control. --- audio/mixeng.c |6 -- configure |8 hw/hda-audio.c |4 3 files changed, 0 insertions(+), 18 deletions(-) diff --git a/audio/mixeng.c b/audio/mixeng.c index 5446be6..0b060e3 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -336,7 +336,6 @@ void mixeng_clear (struct st_sample *buf, int len) void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol) { -#ifdef CONFIG_MIXEMU if (vol->mute) { mixeng_clear (buf, len); return; @@ -352,9 +351,4 @@ void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol) #endif buf += 1; } -#else -(void) buf; -(void) len; -(void) vol; -#endif } diff --git a/configure b/configure index 160bf63..09fc408 100755 --- a/configure +++ b/configure @@ -177,7 +177,6 @@ darwin_user="no" bsd_user="no" guest_base="" uname_release="" -mixemu="no" aix="no" blobs="yes" pkgversion="" @@ -770,8 +769,6 @@ for opt do ;; --enable-nptl) nptl="yes" ;; - --enable-mixemu) mixemu="yes" - ;; --disable-linux-aio) linux_aio="no" ;; --enable-linux-aio) linux_aio="yes" @@ -1028,7 +1025,6 @@ echo " --audio-card-list=LIST set list of emulated audio cards [$audio_card_l echo " Available cards: $audio_possible_cards" echo " --block-drv-whitelist=L set block driver whitelist" echo " (affects only QEMU, not qemu-img)" -echo " --enable-mixemu enable mixer emulation" echo " --disable-xendisable xen backend driver support" echo " --enable-xen enable xen backend driver support" echo " --disable-brlapi disable BrlAPI" @@ -2885,7 +2881,6 @@ echo "mingw32 support $mingw32" echo "Audio drivers $audio_drv_list" echo "Extra audio cards $audio_card_list" echo "Block whitelist $block_drv_whitelist" -echo "Mixer emulation $mixemu" echo "VirtFS support$virtfs" echo "VNC support $vnc" if test "$vnc" = "yes" ; then @@ -3047,9 +3042,6 @@ if test "$audio_win_int" = "yes" ; then echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak fi echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak -if test "$mixemu" = "yes" ; then - echo "CONFIG_MIXEMU=y" >> $config_host_mak -fi if test "$vnc" = "yes" ; then echo "CONFIG_VNC=y" >> $config_host_mak fi diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 8995519..75f1402 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -121,15 +121,11 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) #define QEMU_HDA_AMP_NONE(0) #define QEMU_HDA_AMP_STEPS 0x4a -#ifdef CONFIG_MIXEMU #define QEMU_HDA_AMP_CAPS \ (AC_AMPCAP_MUTE | \ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT)|\ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) |\ (3 << AC_AMPCAP_STEP_SIZE_SHIFT)) -#else -#define QEMU_HDA_AMP_CAPSQEMU_HDA_AMP_NONE -#endif /* common: audio output widget */ static const desc_param common_params_audio_dac[] = { -- 1.7.7.6
[Qemu-devel] [PATCH 05/11] hw/ac97: the volume mask is not only 0x1f
It's a case by case (see Table 66. AC ‘97 Baseline Audio Register Map) --- hw/ac97.c |1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index f2804e6..f7866ed 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -118,7 +118,6 @@ enum { #define EACS_VRA 1 #define EACS_VRM 8 -#define VOL_MASK 0x1f #define MUTE_SHIFT 15 #define REC_MASK 7 -- 1.7.7.6
[Qemu-devel] [PATCH 03/11] audio: use a nominal volume of UINT_MAX
It's more appropriate to set the maximum value into a fitting integer. --- audio/audio.c |4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index bd9237e..06c2384 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -110,8 +110,8 @@ const struct mixeng_volume nominal_volume = { .r = 1.0, .l = 1.0, #else -.r = 1ULL << 32, -.l = 1ULL << 32, +.r = UINT_MAX, +.l = UINT_MAX, #endif }; -- 1.7.7.6
[Qemu-devel] [PATCH 07/11] audio/spice: add support for volume control
Use Spice server volume control API when available. --- audio/spiceaudio.c | 41 + 1 files changed, 41 insertions(+), 0 deletions(-) diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index f972110..92964ae 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -202,7 +202,26 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) } spice_server_playback_stop (&out->sin); break; +case VOICE_VOLUME: +{ +#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) +SWVoiceOut *sw; +va_list ap; +uint16_t vol[2]; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceOut *); +va_end (ap); + +vol[0] = sw->vol.l >> 16; +vol[1] = sw->vol.r >> 16; +spice_server_playback_set_volume (&out->sin, 2, vol); +spice_server_playback_set_mute (&out->sin, sw->vol.mute); +#endif +break; +} } + return 0; } @@ -304,7 +323,26 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) in->active = 0; spice_server_record_stop (&in->sin); break; +case VOICE_VOLUME: +{ +#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) +SWVoiceIn *sw; +va_list ap; +uint16_t vol[2]; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceIn *); +va_end (ap); + +vol[0] = sw->vol.l >> 16; +vol[1] = sw->vol.r >> 16; +spice_server_record_set_volume (&in->sin, 2, vol); +spice_server_record_set_mute (&in->sin, sw->vol.mute); +#endif +break; +} } + return 0; } @@ -337,6 +375,9 @@ struct audio_driver spice_audio_driver = { .max_voices_in = 1, .voice_size_out = sizeof (SpiceVoiceOut), .voice_size_in = sizeof (SpiceVoiceIn), +#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) +.ctl_caps = VOICE_VOLUME_CAP +#endif }; void qemu_spice_audio_init (void) -- 1.7.7.6
Re: [Qemu-devel] [PATCH/RFC 0/7] Screendump to UNIX socket & in PNG format
On Mon, Mar 12, 2012 at 7:06 PM, Stefan Hajnoczi wrote: > > I think ppm for lossless and png for small file size are good options to > have. Beyond that it's up to the caller to deal with the screenshot, > which might be scaling, detecting diffs, encoding in a fancier format, > etc. Daniel Berrange suggested we use gdk-pixbuf for saving into various formats and scaling support. If we make it optionnal, it brings a few more dependencies although the library itself is fairly small (140k, but adds gobject), and we would gain optionnal support for other formats (noteably jpeg) and scaling. -- Marc-André Lureau
Re: [Qemu-devel] [PATCH/RFC 0/7] Screendump to UNIX socket & in PNG format
Hi On Mon, Mar 12, 2012 at 4:42 PM, Eric Blake wrote: > Libvirt would also benefit from screendump to fd:name (where name refers > to an fd passed via getfd). Is this all it takes? or am I missing something? +} else if (strstart(uri, "fd:", &p)) { +int fd = strtol(p, NULL, 0); +f = qemu_fdopen(fd, mode); -- Marc-André Lureau
[Qemu-devel] [PATCH 10/11] Allow controlling volume with PulseAudio backend
--- audio/paaudio.c | 96 --- 1 files changed, 91 insertions(+), 5 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index beed434..7ddc16d 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -664,15 +664,100 @@ static void qpa_fini_in (HWVoiceIn *hw) static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) { -(void) hw; -(void) cmd; +PAVoiceOut *pa = (PAVoiceOut *) hw; +pa_operation *op; +pa_cvolume v; +paaudio *g = &glob_paaudio; + +pa_cvolume_init (&v); + +switch (cmd) { +case VOICE_VOLUME: +{ +SWVoiceOut *sw; +va_list ap; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceOut *); +va_end (ap); + +v.channels = 2; +v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; +v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; + +pa_threaded_mainloop_lock (g->mainloop); + +op = pa_context_set_sink_input_volume (g->context, +pa_stream_get_index (pa->stream), +&v, NULL, NULL); +if (!op) +qpa_logerr (pa_context_errno (g->context), +"set_sink_input_volume() failed\n"); +else +pa_operation_unref (op); + +op = pa_context_set_sink_input_mute (g->context, +pa_stream_get_index (pa->stream), + sw->vol.mute, NULL, NULL); +if (!op) +qpa_logerr (pa_context_errno (g->context), +"set_sink_input_mute() failed\n"); +else +pa_operation_unref (op); + +pa_threaded_mainloop_unlock (g->mainloop); +} +} return 0; } static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) { -(void) hw; -(void) cmd; +PAVoiceIn *pa = (PAVoiceIn *) hw; +pa_operation *op; +pa_cvolume v; +paaudio *g = &glob_paaudio; + +pa_cvolume_init (&v); + +switch (cmd) { +case VOICE_VOLUME: +{ +SWVoiceIn *sw; +va_list ap; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceIn *); +va_end (ap); + +v.channels = 2; +v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; +v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; + +pa_threaded_mainloop_lock (g->mainloop); + +/* FIXME: use the upcoming "set_source_output_{volume,mute}" */ +op = pa_context_set_source_volume_by_index (g->context, +pa_stream_get_device_index (pa->stream), +&v, NULL, NULL); +if (!op) +qpa_logerr (pa_context_errno (g->context), +"set_source_volume() failed\n"); +else +pa_operation_unref(op); + +op = pa_context_set_source_mute_by_index (g->context, +pa_stream_get_index (pa->stream), +sw->vol.mute, NULL, NULL); +if (!op) +qpa_logerr (pa_context_errno (g->context), +"set_source_mute() failed\n"); +else +pa_operation_unref (op); + +pa_threaded_mainloop_unlock (g->mainloop); +} +} return 0; } @@ -801,5 +886,6 @@ struct audio_driver pa_audio_driver = { .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof (PAVoiceOut), -.voice_size_in = sizeof (PAVoiceIn) +.voice_size_in = sizeof (PAVoiceIn), +.ctl_caps = VOICE_VOLUME_CAP }; -- 1.7.7.6
[Qemu-devel] [PATCH 06/11] hw/ac97: add support for volume control
Combine output volume with Master and PCM registers values. Use default values in mixer_reset (). Set volume on post-load to update backend values. --- hw/ac97.c | 79 + 1 files changed, 79 insertions(+), 0 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index f7866ed..227233c 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -436,6 +436,63 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) AUD_set_active_in (s->voice_mc, active[MC_INDEX]); } +static void get_volume (uint16_t vol, uint16_t mask, int inverse, +int *mute, uint8_t *lvol, uint8_t *rvol) +{ + *mute = (vol >> MUTE_SHIFT) & 1; + *rvol = (255 * (vol & mask)) / mask; + *lvol = (255 * ((vol >> 8) & mask)) / mask; + if (inverse) { +*rvol = 255 - *rvol; +*lvol = 255 - *lvol; + } +} + +static void update_combined_volume_out (AC97LinkState *s) +{ +uint8_t lvol, rvol, plvol, prvol; +int mute, pmute; + +get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, +&mute, &lvol, &rvol); +/* FIXME: should be 1f according to spec */ +get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, +&pmute, &plvol, &prvol); + +mute = mute | pmute; +lvol = (lvol * plvol) / 255; +rvol = (rvol * prvol) / 255; + +AUD_set_volume_out (s->voice_po, mute, lvol, rvol); +} + +static void update_volume_in(AC97LinkState *s) +{ +uint8_t lvol, rvol; +int mute; + +get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, +&mute, &lvol, &rvol); + +AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); +} + +static void set_volume (AC97LinkState *s, int index, uint32_t val) +{ +mixer_store (s, index, val); +if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) + update_combined_volume_out (s); +else if (index == AC97_Record_Gain_Mute) + update_volume_in (s); +} + +static void record_select (AC97LinkState *s, uint32_t val) +{ +uint8_t rs = val & REC_MASK; +uint8_t ls = (val >> 8) & REC_MASK; +mixer_store (s, AC97_Record_Select, rs | (ls << 8)); +} + static void mixer_reset (AC97LinkState *s) { uint8_t active[LAST_INDEX]; @@ -470,6 +527,11 @@ static void mixer_reset (AC97LinkState *s) mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); +record_select (s, 0); +set_volume (s, AC97_Master_Volume_Mute, 0x8000); +set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); +set_volume (s, AC97_Line_In_Volume_Mute, 0x8808); + reset_voices (s, active); } @@ -528,6 +590,15 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; +case AC97_PCM_Out_Volume_Mute: +case AC97_Master_Volume_Mute: +case AC97_Record_Gain_Mute: +case AC97_Line_In_Volume_Mute: +set_volume (s, index, val); +break; +case AC97_Record_Select: +record_select (s, val); +break; case AC97_Vendor_ID1: case AC97_Vendor_ID2: dolog ("Attempt to write vendor ID to %#x\n", val); @@ -1080,6 +1151,14 @@ static int ac97_post_load (void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; +record_select (s, mixer_load (s, AC97_Record_Select)); +set_volume (s, AC97_Master_Volume_Mute, +mixer_load (s, AC97_Master_Volume_Mute)); +set_volume (s, AC97_PCM_Out_Volume_Mute, +mixer_load (s, AC97_PCM_Out_Volume_Mute)); +set_volume (s, AC97_Line_In_Volume_Mute, +mixer_load (s, AC97_Line_In_Volume_Mute)); + active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); -- 1.7.7.6
[Qemu-devel] [PATCH 08/11] Do not use pa_simple PulseAudio API
Unfortunately, pa_simple is a limited API which doesn't let us retrieve the associated pa_stream. It is needed to control the volume of the stream. --- audio/paaudio.c | 356 +-- 1 files changed, 318 insertions(+), 38 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index d1f3912..beed434 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -2,8 +2,7 @@ #include "qemu-common.h" #include "audio.h" -#include -#include +#include #define AUDIO_CAP "pulseaudio" #include "audio_int.h" @@ -15,7 +14,7 @@ typedef struct { int live; int decr; int rpos; -pa_simple *s; +pa_stream *stream; void *pcm_buf; struct audio_pt pt; } PAVoiceOut; @@ -26,17 +25,23 @@ typedef struct { int dead; int incr; int wpos; -pa_simple *s; +pa_stream *stream; void *pcm_buf; struct audio_pt pt; +const void *read_data; +size_t read_index, read_length; } PAVoiceIn; -static struct { +typedef struct { int samples; char *server; char *sink; char *source; -} conf = { +pa_threaded_mainloop *mainloop; +pa_context *context; +} paaudio; + +static paaudio glob_paaudio = { .samples = 4096, }; @@ -51,6 +56,120 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); } +#define CHECK_SUCCESS_GOTO(c, rerror, expression, label)\ +do {\ +if (!(expression)) {\ +if (rerror) \ +*(rerror) = pa_context_errno((c)->context); \ +goto label; \ +} \ +} while(0); + +#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ +do {\ +if (!(c)->context || !PA_CONTEXT_IS_GOOD(pa_context_get_state((c)->context)) || \ +!(stream) || !PA_STREAM_IS_GOOD(pa_stream_get_state((stream { \ +if (((c)->context && pa_context_get_state((c)->context) == PA_CONTEXT_FAILED) || \ +((stream) && pa_stream_get_state((stream)) == PA_STREAM_FAILED)) { \ +if (rerror) \ +*(rerror) = pa_context_errno((c)->context); \ +} else \ +if (rerror) \ +*(rerror) = PA_ERR_BADSTATE;\ +goto label; \ +} \ +} while(0); + +static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror) +{ +paaudio *g = &glob_paaudio; + +pa_threaded_mainloop_lock (g->mainloop); + +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); + +while (length > 0) { +size_t l; + +while (!p->read_data) { +int r; + +r = pa_stream_peek (p->stream, &p->read_data, &p->read_length); +CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); + +if (!p->read_data) { +pa_threaded_mainloop_wait (g->mainloop); +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); +} else +p->read_index = 0; +} + +l = p->read_length < length ? p->read_length : length; +memcpy (data, (const uint8_t*) p->read_data+p->read_index, l); + +data = (uint8_t*) data + l; +length -= l; + +p->read_index += l; +p->read_length -= l; + +if (!p->read_length) { +int r; + +r = pa_stream_drop (p->stream); +p->read_data = NULL; +p->read_length = 0; +p->read_index = 0; + +CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); +} +} + +pa_threaded_mainloop_unlock (g->mainloop); +return 0; + +unlock_and_fail: +pa_threaded_mainloop_unlock (g->mainloop); +return -1; +} + +static int qpa_simple_write (PAVoiceOut *p, const void *data, size_t length, int *rerror) +{ +paaudio *g = &glob_paaudio; + +pa_threaded_mainloop_lock(g->mainloop); + +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); + +while (length > 0) { +size_t l; +int r; + +while (!(l = pa_stream_writable_size (p->stream))) { +pa_threaded_mainloop_wait (g->mainloop); +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); +} + +CHECK_SUCCESS_GOTO (g, rerror, l != (size_t) -1, unlock_and_fail); + +if (l > length) +l =
[Qemu-devel] [PATCH 00/11] apply volume on client side (v3)
Hello, This patch series implements client-side audio volume support. This reduces confusion of guest users when volume control is not effective (because mixemu is disabled or because client-side is muted and can't be unmuted by the guest..) Instead, the backend is responsible for applying volume giving the guest control over the full range of the client, and avoiding multiple level of volume/mute effects. Although I was mainly interested in having the Spice audio backend support, I also added PulseAudio backend support (which unfortunately requires full-blown API, even after quick discussion with upstream). Marc-André Lureau (11): audio: add VOICE_VOLUME ctl audio: don't apply volume effect if backend has VOICE_VOLUME_CAP audio: use a nominal volume of UINT_MAX hw/ac97: remove USE_MIXER code hw/ac97: the volume mask is not only 0x1f hw/ac97: add support for volume control audio/spice: add support for volume control Do not use pa_simple PulseAudio API configure: pa_simple is not needed anymore Allow controlling volume with PulseAudio backend Make mixemu mandatory audio/audio.c | 25 +++- audio/audio_int.h |6 + audio/audio_template.h |2 + audio/mixeng.c |6 - audio/paaudio.c| 452 +++- audio/spiceaudio.c | 41 + configure | 14 +-- hw/ac97.c | 141 ++-- hw/hda-audio.c |4 - 9 files changed, 531 insertions(+), 160 deletions(-) -- 1.7.7.6
Re: [Qemu-devel] [PATCH 03/11] audio: use a nominal volume of UINT_MAX
On Mon, Mar 12, 2012 at 9:03 PM, malc wrote: > How's putting UINT_MAX into int64_t more appropriate? UINT_MAX is > even one less than one in 32.32 fixpoint... I must be missing something > here. Right, the patch series used to have 2^32 -1, so it can fit in a 16bits or 32bits integer. So what I meant is rather G_MAXUINT32. -- Marc-André Lureau
Re: [Qemu-devel] [PATCH 00/11] apply volume on client side (v3)
Hi Vassili Thanks for your review! On Mon, Mar 12, 2012 at 8:44 PM, malc wrote: > a. Pulse/Spice have per connection volume Each playback/recorde stream has it's own volume, and that's what we control. We get the client full range thanks to flat-volume logic (implemented by PulseAudio and Windows Vista+) > b. Other drivers are not affected I don't see yet how, but I will review other drivers ctl_{in,out} implementations > c. mixeng is not the default So you mean the last patch shouldn't be applied? Can you explain the rationale? Why would we want broken behaviour by default? cheers -- Marc-André Lureau
Re: [Qemu-devel] [PATCH 03/11] audio: use a nominal volume of UINT_MAX
On Mon, Mar 12, 2012 at 9:29 PM, malc wrote: >> So what I meant is rather G_MAXUINT32. > > Just leave it as is, it's perfectly fine. But it's not convenient to fit into a regular integer, as the number of steps is 2^32 + 1. Why is it preferrable this way rather than a MAXUINT? I must be missing something. Hardware range for example is usually 0...2^nbits-1 -- Marc-André Lureau
Re: [Qemu-devel] [PATCH 00/11] apply volume on client side (v3)
On Mon, Mar 12, 2012 at 9:51 PM, malc wrote: >> >> > b. Other drivers are not affected >> >> I don't see yet how, but I will review other drivers ctl_{in,out} >> implementations > > You don't see how they can be affected or you don't see how you can > figure that out? I don't see how they can be affected, unless they assert on an unknown pcm_ctrl value VOICE_VOLUME for example (the calling call ignores return value, so it alsa for example, can return -1 and it will get ignored). >> > c. mixeng is not the default >> >> So you mean the last patch shouldn't be applied? Can you explain the >> rationale? Why would we want broken behaviour by default? >> > > Because i hate change. I do to, except when they fix broken behaviour. More seriously, do you have other concerns with the mixemu code? -- Marc-André Lureau
Re: [Qemu-devel] [PATCH 03/11] audio: use a nominal volume of UINT_MAX
On Mon, Mar 12, 2012 at 10:00 PM, malc wrote: > I really do not understand your point at all, mixeng_volume fields > are int64_t's it's irrelevant what you initialize them with, they > are still 64bit integers, and UINT_MAX as i already said is not even > correct, it's 1/(2**32-1) less than one in fixed point. But the current code does this: AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol..) sw->vol.l = nominal_volume.l * lvol / 255; So the range was [0..2^8-1] and then it becomes [0..2^32], which looks wrong to me. And Spice uses [0..2^16-1]. So it is simpler to stay within the range of an integer.. -- Marc-André Lureau
Re: [Qemu-devel] [PATCH 03/11] audio: use a nominal volume of UINT_MAX
On Mon, Mar 12, 2012 at 10:11 PM, malc wrote: >> AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol..) >> >> sw->vol.l = nominal_volume.l * lvol / 255; >> >> So the range was [0..2^8-1] and then it becomes [0..2^32], which looks >> wrong to me. > > It actually becomes [-2^63..2^63-1] nominal_volume.l being 64 bit signed > and all. uint8_t [0..255] / 255 * 2^32 = [0..2^32] >> And Spice uses [0..2^16-1]. So it is simpler to stay within the range >> of an integer.. > > I do not get you, i really don't. The audio hw volume range is within a uint8 [0..2^8-1] that is then scaled into a [0..2^32], it would be easier to stay within a [0..2^n-1] range all the way. -- Marc-André Lureau
Re: [Qemu-devel] [PATCH 03/11] audio: use a nominal volume of UINT_MAX
On Mon, Mar 12, 2012 at 10:42 PM, malc wrote: > nominal_volume.[lr] is int64_t... i don't get where you take this ^32 > from. from where it is defined, audio/audio.c: const struct mixeng_volume nominal_volume = { .mute = 0, #ifdef FLOAT_MIXENG .r = 1.0, .l = 1.0, #else .r = 1ULL << 32, .l = 1ULL << 32, #endif }; -- Marc-André Lureau
Re: [Qemu-devel] [PATCH 03/11] audio: use a nominal volume of UINT_MAX
On Mon, Mar 12, 2012 at 11:52 PM, malc wrote: > 1 << 32 = 1.0 in 64(32.32) fixed point... the type of l/r is int64_t Ok, I'll leave it as is then if it is on purpose. -- Marc-André Lureau
Re: [Qemu-devel] [PATCH 00/11] apply volume on client side (v3)
On Tue, Mar 13, 2012 at 11:19 AM, Gerd Hoffmann wrote: > I think we should remove the mixemu configure option. It makes code > bitrot. Patch #4 proves that. If you want to keep it because of the > overhead or other reasons I'd suggest to make it a runtime option. To be fair, the patch #4 only remove dead code (USE_MIXER wasn't enabled by mixemu). Making mixemu a runtime option sounds good to me. -- Marc-André Lureau
Re: [Qemu-devel] [PATCH/RFC 0/7] Screendump to UNIX socket & in PNG format
Hi - Mensaje original - > Yeah it wants png, jpeg, tiff. What I'm concerned about is that QEMU > should be doing emulation/virtualization, not processing images for > an > end-user. Its main loop is not structured to do utility tasks > unrelated to running the guest. If implemented properly QEMU isn't a > good place to host this processing, and if done badly we block the > guest and make it unresponsive. This is a general architectural > problem, not something specific to your proposal but this is why I'm > against putting this into QEMU. > > If you send a ppm over a file descriptor, what's the fundamental > limitation which requires you to add this code to QEMU? Perhaps > simply supporting file descriptors is the right level of support from > QEMU. That sounds reasonable to me, I would even remove the PPM support, and the format conversion in this case. It needs to be done somewhere though, and it seems reasonable to do it from the source. What if we fork a subprocess (linked with gdkpixbuf) that would do the job with stdin/stdout?
[Qemu-devel] [PATCH v4 00/11] apply volume on client side
Hi, This patch series implements client-side audio volume support. This reduces confusion of guest users when volume control is not effective (because mixemu is disabled or because client-side is muted and can't be unmuted by the guest..) Instead, the backend is responsible for applying volume giving the guest control over the full range of the client, and avoiding multiple level of volume/mute effects. Although I was mainly interested in having the Spice audio backend support, I also added PulseAudio backend support (which unfortunately requires full-blown API, even after quick discussion with upstream). v4: - code style fixes (only warnings left - mostly spaces) - dropped the 1 << 32 -1 change - added QEMU_MIXEMU runtime option, enabled by default - rfc: removed some deprecated audio options Marc-André Lureau (11): audio: add VOICE_VOLUME ctl audio: don't apply volume effect if backend has VOICE_VOLUME_CAP hw/ac97: remove USE_MIXER code hw/ac97: the volume mask is not only 0x1f hw/ac97: add support for volume control audio/spice: add support for volume control Do not use pa_simple PulseAudio API configure: pa_simple is not needed anymore Allow controlling volume with PulseAudio backend Enable mixemu by default, add runtime option audio/rfc: remove PLIVE and PERIOD options audio/audio.c | 64 +++ audio/audio_int.h |6 + audio/audio_template.h | 28 +--- audio/mixeng.c |6 - audio/paaudio.c| 476 +++- audio/spiceaudio.c | 41 configure | 14 +- hw/ac97.c | 140 +- hw/hda-audio.c |4 - 9 files changed, 561 insertions(+), 218 deletions(-) -- 1.7.7.6
[Qemu-devel] [PATCH v4 03/11] hw/ac97: remove USE_MIXER code
That code doesn't compile. The interesting bits for volume control are going to be rewritten in the following patch. Signed-off-by: Marc-André Lureau --- hw/ac97.c | 121 - 1 files changed, 0 insertions(+), 121 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index c0fd019..f2804e6 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -437,99 +437,6 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) AUD_set_active_in (s->voice_mc, active[MC_INDEX]); } -#ifdef USE_MIXER -static void set_volume (AC97LinkState *s, int index, -audmixerctl_t mt, uint32_t val) -{ -int mute = (val >> MUTE_SHIFT) & 1; -uint8_t rvol = VOL_MASK - (val & VOL_MASK); -uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK); -rvol = 255 * rvol / VOL_MASK; -lvol = 255 * lvol / VOL_MASK; - -#ifdef SOFT_VOLUME -if (index == AC97_Master_Volume_Mute) { -AUD_set_volume_out (s->voice_po, mute, lvol, rvol); -} -else { -AUD_set_volume (mt, &mute, &lvol, &rvol); -} -#else -AUD_set_volume (mt, &mute, &lvol, &rvol); -#endif - -rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); -lvol = VOL_MASK - ((VOL_MASK * lvol) / 255); -mixer_store (s, index, val); -} - -static audrecsource_t ac97_to_aud_record_source (uint8_t i) -{ -switch (i) { -case REC_MIC: -return AUD_REC_MIC; - -case REC_CD: -return AUD_REC_CD; - -case REC_VIDEO: -return AUD_REC_VIDEO; - -case REC_AUX: -return AUD_REC_AUX; - -case REC_LINE_IN: -return AUD_REC_LINE_IN; - -case REC_PHONE: -return AUD_REC_PHONE; - -default: -dolog ("Unknown record source %d, using MIC\n", i); -return AUD_REC_MIC; -} -} - -static uint8_t aud_to_ac97_record_source (audrecsource_t rs) -{ -switch (rs) { -case AUD_REC_MIC: -return REC_MIC; - -case AUD_REC_CD: -return REC_CD; - -case AUD_REC_VIDEO: -return REC_VIDEO; - -case AUD_REC_AUX: -return REC_AUX; - -case AUD_REC_LINE_IN: -return REC_LINE_IN; - -case AUD_REC_PHONE: -return REC_PHONE; - -default: -dolog ("Unknown audio recording source %d using MIC\n", rs); -return REC_MIC; -} -} - -static void record_select (AC97LinkState *s, uint32_t val) -{ -uint8_t rs = val & REC_MASK; -uint8_t ls = (val >> 8) & REC_MASK; -audrecsource_t ars = ac97_to_aud_record_source (rs); -audrecsource_t als = ac97_to_aud_record_source (ls); -AUD_set_record_source (&als, &ars); -rs = aud_to_ac97_record_source (ars); -ls = aud_to_ac97_record_source (als); -mixer_store (s, AC97_Record_Select, rs | (ls << 8)); -} -#endif - static void mixer_reset (AC97LinkState *s) { uint8_t active[LAST_INDEX]; @@ -564,12 +471,6 @@ static void mixer_reset (AC97LinkState *s) mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); -#ifdef USE_MIXER -record_select (s, 0); -set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000); -set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM, 0x8808); -set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); -#endif reset_voices (s, active); } @@ -628,20 +529,6 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; -#ifdef USE_MIXER -case AC97_Master_Volume_Mute: -set_volume (s, index, AUD_MIXER_VOLUME, val); -break; -case AC97_PCM_Out_Volume_Mute: -set_volume (s, index, AUD_MIXER_PCM, val); -break; -case AC97_Line_In_Volume_Mute: -set_volume (s, index, AUD_MIXER_LINE_IN, val); -break; -case AC97_Record_Select: -record_select (s, val); -break; -#endif case AC97_Vendor_ID1: case AC97_Vendor_ID2: dolog ("Attempt to write vendor ID to %#x\n", val); @@ -1194,14 +1081,6 @@ static int ac97_post_load (void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; -#ifdef USE_MIXER -record_select (s, mixer_load (s, AC97_Record_Select)); -#define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) -V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); -V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); -V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); -#undef V_ -#endif active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); -- 1.7.7.6
[Qemu-devel] [PATCH v4 02/11] audio: don't apply volume effect if backend has VOICE_VOLUME_CAP
If the audio backend is capable of volume control, don't apply software volume (mixeng_volume ()), but instead, rely on backend volume control. This will allow guest to have full range volume control. Signed-off-by: Marc-André Lureau --- audio/audio.c |9 +++-- audio/audio_int.h |5 + audio/audio_template.h |2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index d76c342..bd9237e 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -957,7 +957,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) total += isamp; } -mixeng_volume (sw->buf, ret, &sw->vol); +if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) { +mixeng_volume (sw->buf, ret, &sw->vol); +} sw->clip (buf, sw->buf, ret); sw->total_hw_samples_acquired += total; @@ -1041,7 +1043,10 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) swlim = audio_MIN (swlim, samples); if (swlim) { sw->conv (sw->buf, buf, swlim); -mixeng_volume (sw->buf, swlim, &sw->vol); + +if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { +mixeng_volume (sw->buf, swlim, &sw->vol); +} } while (swlim) { diff --git a/audio/audio_int.h b/audio/audio_int.h index 117f95e..b9b0676 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -82,6 +82,7 @@ typedef struct HWVoiceOut { int samples; QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; +int ctl_caps; struct audio_pcm_ops *pcm_ops; QLIST_ENTRY (HWVoiceOut) entries; } HWVoiceOut; @@ -101,6 +102,7 @@ typedef struct HWVoiceIn { int samples; QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; +int ctl_caps; struct audio_pcm_ops *pcm_ops; QLIST_ENTRY (HWVoiceIn) entries; } HWVoiceIn; @@ -150,6 +152,7 @@ struct audio_driver { int max_voices_in; int voice_size_out; int voice_size_in; +int ctl_caps; }; struct audio_pcm_ops { @@ -233,6 +236,8 @@ void audio_run (const char *msg); #define VOICE_DISABLE 2 #define VOICE_VOLUME 3 +#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME) + static inline int audio_ring_dist (int dst, int src, int len) { return (dst >= src) ? (dst - src) : (len - src + dst); diff --git a/audio/audio_template.h b/audio/audio_template.h index e62a713..519432a 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -263,6 +263,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) } hw->pcm_ops = drv->pcm_ops; +hw->ctl_caps = drv->ctl_caps; + QLIST_INIT (&hw->sw_head); #ifdef DAC QLIST_INIT (&hw->cap_head); -- 1.7.7.6
[Qemu-devel] [PATCH v4 01/11] audio: add VOICE_VOLUME ctl
Add a new PCM control operation to update the stream volume on the audio backend. The argument given is a SWVoiceOut/SWVoiceIn. v4: - verified other backends didn't fail/assert on this new control they randomly return 0 or -1, but we ignore return value. Signed-off-by: Marc-André Lureau --- audio/audio.c | 12 audio/audio_int.h |1 + 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 398763f..d76c342 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2053,17 +2053,29 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) { if (sw) { +HWVoiceOut *hw = sw->hw; + sw->vol.mute = mute; sw->vol.l = nominal_volume.l * lvol / 255; sw->vol.r = nominal_volume.r * rvol / 255; + +if (hw->pcm_ops->ctl_out) { +hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw); +} } } void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) { if (sw) { +HWVoiceIn *hw = sw->hw; + sw->vol.mute = mute; sw->vol.l = nominal_volume.l * lvol / 255; sw->vol.r = nominal_volume.r * rvol / 255; + +if (hw->pcm_ops->ctl_in) { +hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw); +} } } diff --git a/audio/audio_int.h b/audio/audio_int.h index 2003f8b..117f95e 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -231,6 +231,7 @@ void audio_run (const char *msg); #define VOICE_ENABLE 1 #define VOICE_DISABLE 2 +#define VOICE_VOLUME 3 static inline int audio_ring_dist (int dst, int src, int len) { -- 1.7.7.6
[Qemu-devel] [PATCH v4 11/11] audio/rfc: remove PLIVE and PERIOD options
- period seems to be unused now - plive is very obscure and should either be documented or perhaps removed Signed-off-by: Marc-André Lureau --- audio/audio.c | 35 --- audio/audio_template.h | 26 -- 2 files changed, 0 insertions(+), 61 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index bb94133..c2e6e15 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -30,7 +30,6 @@ #define AUDIO_CAP "audio" #include "audio_int.h" -/* #define DEBUG_PLIVE */ /* #define DEBUG_LIVE */ /* #define DEBUG_OUT */ /* #define DEBUG_CAPTURE */ @@ -62,11 +61,6 @@ struct fixed_settings { static struct { struct fixed_settings fixed_out; struct fixed_settings fixed_in; -union { -int hertz; -int64_t ticks; -} period; -int plive; int log_to_monitor; int try_poll_in; int try_poll_out; @@ -96,8 +90,6 @@ static struct { } }, -.period = { .hertz = 250 }, -.plive = 0, .log_to_monitor = 0, .try_poll_in = 1, .try_poll_out = 1, @@ -1453,9 +1445,6 @@ static void audio_run_out (AudioState *s) while (sw) { sw1 = sw->entries.le_next; if (!sw->active && !sw->callback.fn) { -#ifdef DEBUG_PLIVE -dolog ("Finishing with old voice\n"); -#endif audio_close_out (sw); } sw = sw1; @@ -1642,18 +1631,6 @@ static struct audio_option audio_options[] = { }, /* Misc */ { -.name = "TIMER_PERIOD", -.tag = AUD_OPT_INT, -.valp = &conf.period.hertz, -.descr = "Timer period in HZ (0 - use lowest possible)" -}, -{ -.name = "PLIVE", -.tag = AUD_OPT_BOOL, -.valp = &conf.plive, -.descr = "(undocumented)" -}, -{ .name = "LOG_TO_MONITOR", .tag = AUD_OPT_BOOL, .valp = &conf.log_to_monitor, @@ -1898,18 +1875,6 @@ static void audio_init (void) } } -if (conf.period.hertz <= 0) { -if (conf.period.hertz < 0) { -dolog ("warning: Timer period is negative - %d " - "treating as zero\n", - conf.period.hertz); -} -conf.period.ticks = 1; -} else { -conf.period.ticks = -muldiv64 (1, get_ticks_per_sec (), conf.period.hertz); -} - e = qemu_add_vm_change_state_handler (audio_vm_change_state_handler, s); if (!e) { dolog ("warning: Could not register change state handler\n" diff --git a/audio/audio_template.h b/audio/audio_template.h index 519432a..4120afb 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -433,29 +433,6 @@ SW *glue (AUD_open_, TYPE) ( return sw; } -#ifdef DAC -if (conf.plive && sw && (!sw->active && !sw->empty)) { -live = sw->total_hw_samples_mixed; - -#ifdef DEBUG_PLIVE -dolog ("Replacing voice %s with %d live samples\n", SW_NAME (sw), live); -dolog ("Old %s freq %d, bits %d, channels %d\n", - SW_NAME (sw), sw->info.freq, sw->info.bits, sw->info.nchannels); -dolog ("New %s freq %d, bits %d, channels %d\n", - name, - as->freq, - (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) ? 16 : 8, - as->nchannels); -#endif - -if (live) { -old_sw = sw; -old_sw->callback.fn = NULL; -sw = NULL; -} -} -#endif - if (!glue (conf.fixed_, TYPE).enabled && sw) { glue (AUD_close_, TYPE) (card, sw); sw = NULL; @@ -495,9 +472,6 @@ SW *glue (AUD_open_, TYPE) ( * old_sw->info.bytes_per_second / sw->info.bytes_per_second; -#ifdef DEBUG_PLIVE -dolog ("Silence will be mixed %d\n", mixed); -#endif sw->total_hw_samples_mixed += mixed; } #endif -- 1.7.7.6
[Qemu-devel] [PATCH v4 08/11] configure: pa_simple is not needed anymore
Signed-off-by: Marc-André Lureau --- configure |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 39d2b54..160bf63 100755 --- a/configure +++ b/configure @@ -1842,9 +1842,9 @@ for drv in $audio_drv_list; do ;; pa) -audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \ -"pa_simple *s = 0; pa_simple_free(s); return 0;" -libs_softmmu="-lpulse -lpulse-simple $libs_softmmu" +audio_drv_probe $drv pulse/mainloop.h "-lpulse" \ +"pa_mainloop *m = 0; pa_mainloop_free (m); return 0;" +libs_softmmu="-lpulse $libs_softmmu" audio_pt_int="yes" ;; -- 1.7.7.6
[Qemu-devel] [PATCH v4 07/11] Do not use pa_simple PulseAudio API
Unfortunately, pa_simple is a limited API which doesn't let us retrieve the associated pa_stream. It is needed to control the volume of the stream. In v4: - add missing braces Signed-off-by: Marc-André Lureau --- audio/paaudio.c | 377 +-- 1 files changed, 339 insertions(+), 38 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index d1f3912..6f50c1c 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -2,8 +2,7 @@ #include "qemu-common.h" #include "audio.h" -#include -#include +#include #define AUDIO_CAP "pulseaudio" #include "audio_int.h" @@ -15,7 +14,7 @@ typedef struct { int live; int decr; int rpos; -pa_simple *s; +pa_stream *stream; void *pcm_buf; struct audio_pt pt; } PAVoiceOut; @@ -26,17 +25,23 @@ typedef struct { int dead; int incr; int wpos; -pa_simple *s; +pa_stream *stream; void *pcm_buf; struct audio_pt pt; +const void *read_data; +size_t read_index, read_length; } PAVoiceIn; -static struct { +typedef struct { int samples; char *server; char *sink; char *source; -} conf = { +pa_threaded_mainloop *mainloop; +pa_context *context; +} paaudio; + +static paaudio glob_paaudio = { .samples = 4096, }; @@ -51,6 +56,126 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); } +#define CHECK_SUCCESS_GOTO(c, rerror, expression, label)\ +do {\ +if (!(expression)) {\ +if (rerror) { \ +*(rerror) = pa_context_errno ((c)->context);\ +} \ +goto label; \ +} \ +} while (0); + +#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ +do {\ +if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ +!(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream { \ +if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ +((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ +if (rerror) { \ +*(rerror) = pa_context_errno ((c)->context);\ +} \ +} else {\ +if (rerror) { \ +*(rerror) = PA_ERR_BADSTATE;\ +} \ +} \ +goto label; \ +} \ +} while (0); + +static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror) +{ +paaudio *g = &glob_paaudio; + +pa_threaded_mainloop_lock (g->mainloop); + +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); + +while (length > 0) { +size_t l; + +while (!p->read_data) { +int r; + +r = pa_stream_peek (p->stream, &p->read_data, &p->read_length); +CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); + +if (!p->read_data) { +pa_threaded_mainloop_wait (g->mainloop); +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); +} else { +p->read_index = 0; +} +} + +l = p->read_length < length ? p->read_length : length; +memcpy (data, (const uint8_t *) p->read_data+p->read_index, l); + +data = (uint8_t *) data + l; +length -= l; + +p->read_index += l; +p->read_length -= l; + +if (!p->read_length) { +int r; + +r = pa_stream_drop (p->stream); +p->read_data = NULL; +p->read_length = 0; +p->read_index = 0; + +CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); +} +} + +pa_threaded_mainloop_unlock (g->mainloop); +return 0; + +unlock_and_fail: +pa_threaded_mainloop_unlock (g->mainloop); +return -1; +} + +static int qpa_simple_write (PAVoiceOut *p, const void *data
[Qemu-devel] [PATCH v4 04/11] hw/ac97: the volume mask is not only 0x1f
It's a case by case (see Table 66. AC ‘97 Baseline Audio Register Map) Signed-off-by: Marc-André Lureau --- hw/ac97.c |1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index f2804e6..f7866ed 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -118,7 +118,6 @@ enum { #define EACS_VRA 1 #define EACS_VRM 8 -#define VOL_MASK 0x1f #define MUTE_SHIFT 15 #define REC_MASK 7 -- 1.7.7.6
Re: [Qemu-devel] [PATCH v4 05/11] hw/ac97: add support for volume control
On Tue, Mar 13, 2012 at 4:37 PM, malc wrote: > On Tue, 13 Mar 2012, Marc-Andr? Lureau wrote: > >> Combine output volume with Master and PCM registers values. >> Use default values in mixer_reset (). >> Set volume on post-load to update backend values. >> >> v4: >> - fix some code style > > Don't think it fixes anything... > >> >> Signed-off-by: Marc-Andr? Lureau >> --- >> hw/ac97.c | 80 >> + >> 1 files changed, 80 insertions(+), 0 deletions(-) >> >> diff --git a/hw/ac97.c b/hw/ac97.c >> index f7866ed..f5ae637 100644 >> --- a/hw/ac97.c >> +++ b/hw/ac97.c >> @@ -436,6 +436,64 @@ static void reset_voices (AC97LinkState *s, uint8_t >> active[LAST_INDEX]) >> AUD_set_active_in (s->voice_mc, active[MC_INDEX]); >> } >> >> +static void get_volume (uint16_t vol, uint16_t mask, int inverse, >> + int *mute, uint8_t *lvol, uint8_t *rvol) >> +{ >> + *mute = (vol >> MUTE_SHIFT) & 1; >> + *rvol = (255 * (vol & mask)) / mask; >> + *lvol = (255 * ((vol >> 8) & mask)) / mask; >> + if (inverse) { >> + *rvol = 255 - *rvol; >> + *lvol = 255 - *lvol; > > Here. > > [..snip..] checkpatch doesn't complain here, I only get 30 warnings: WARNING: space prohibited between function name and open parenthesis '(' which seems to be the code style in audio/ thanks -- Marc-André Lureau
[Qemu-devel] [PATCH v4 06/11] audio/spice: add support for volume control
Use Spice server volume control API when available. Signed-off-by: Marc-André Lureau --- audio/spiceaudio.c | 41 + 1 files changed, 41 insertions(+), 0 deletions(-) diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index f972110..6f15591 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -202,7 +202,26 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) } spice_server_playback_stop (&out->sin); break; +case VOICE_VOLUME: +{ +#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) +SWVoiceOut *sw; +va_list ap; +uint16_t vol[2]; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceOut *); +va_end (ap); + +vol[0] = sw->vol.l / ((1ULL << 16) + 1); +vol[1] = sw->vol.r / ((1ULL << 16) + 1); +spice_server_playback_set_volume (&out->sin, 2, vol); +spice_server_playback_set_mute (&out->sin, sw->vol.mute); +#endif +break; +} } + return 0; } @@ -304,7 +323,26 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) in->active = 0; spice_server_record_stop (&in->sin); break; +case VOICE_VOLUME: +{ +#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) +SWVoiceIn *sw; +va_list ap; +uint16_t vol[2]; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceIn *); +va_end (ap); + +vol[0] = sw->vol.l / ((1ULL << 16) + 1); +vol[1] = sw->vol.r / ((1ULL << 16) + 1); +spice_server_record_set_volume (&in->sin, 2, vol); +spice_server_record_set_mute (&in->sin, sw->vol.mute); +#endif +break; +} } + return 0; } @@ -337,6 +375,9 @@ struct audio_driver spice_audio_driver = { .max_voices_in = 1, .voice_size_out = sizeof (SpiceVoiceOut), .voice_size_in = sizeof (SpiceVoiceIn), +#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) +.ctl_caps = VOICE_VOLUME_CAP +#endif }; void qemu_spice_audio_init (void) -- 1.7.7.6
Re: [Qemu-devel] [PATCH v4 05/11] hw/ac97: add support for volume control
On Tue, Mar 13, 2012 at 5:07 PM, malc wrote: > That's right. But the whole get_volume function is indented with 2 > instead of 4 spaces. fixed! thanks -- Marc-André Lureau
[Qemu-devel] [PATCH v4 05/11] hw/ac97: add support for volume control
Combine output volume with Master and PCM registers values. Use default values in mixer_reset (). Set volume on post-load to update backend values. v4: - fix some code style Signed-off-by: Marc-André Lureau --- hw/ac97.c | 80 + 1 files changed, 80 insertions(+), 0 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index f7866ed..f5ae637 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -436,6 +436,64 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) AUD_set_active_in (s->voice_mc, active[MC_INDEX]); } +static void get_volume (uint16_t vol, uint16_t mask, int inverse, +int *mute, uint8_t *lvol, uint8_t *rvol) +{ + *mute = (vol >> MUTE_SHIFT) & 1; + *rvol = (255 * (vol & mask)) / mask; + *lvol = (255 * ((vol >> 8) & mask)) / mask; + if (inverse) { +*rvol = 255 - *rvol; +*lvol = 255 - *lvol; + } +} + +static void update_combined_volume_out (AC97LinkState *s) +{ +uint8_t lvol, rvol, plvol, prvol; +int mute, pmute; + +get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, +&mute, &lvol, &rvol); +/* FIXME: should be 1f according to spec */ +get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, +&pmute, &plvol, &prvol); + +mute = mute | pmute; +lvol = (lvol * plvol) / 255; +rvol = (rvol * prvol) / 255; + +AUD_set_volume_out (s->voice_po, mute, lvol, rvol); +} + +static void update_volume_in(AC97LinkState *s) +{ +uint8_t lvol, rvol; +int mute; + +get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, +&mute, &lvol, &rvol); + +AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); +} + +static void set_volume (AC97LinkState *s, int index, uint32_t val) +{ +mixer_store (s, index, val); +if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) { +update_combined_volume_out (s); +} else if (index == AC97_Record_Gain_Mute) { +update_volume_in (s); +} +} + +static void record_select (AC97LinkState *s, uint32_t val) +{ +uint8_t rs = val & REC_MASK; +uint8_t ls = (val >> 8) & REC_MASK; +mixer_store (s, AC97_Record_Select, rs | (ls << 8)); +} + static void mixer_reset (AC97LinkState *s) { uint8_t active[LAST_INDEX]; @@ -470,6 +528,11 @@ static void mixer_reset (AC97LinkState *s) mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); +record_select (s, 0); +set_volume (s, AC97_Master_Volume_Mute, 0x8000); +set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); +set_volume (s, AC97_Line_In_Volume_Mute, 0x8808); + reset_voices (s, active); } @@ -528,6 +591,15 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; +case AC97_PCM_Out_Volume_Mute: +case AC97_Master_Volume_Mute: +case AC97_Record_Gain_Mute: +case AC97_Line_In_Volume_Mute: +set_volume (s, index, val); +break; +case AC97_Record_Select: +record_select (s, val); +break; case AC97_Vendor_ID1: case AC97_Vendor_ID2: dolog ("Attempt to write vendor ID to %#x\n", val); @@ -1080,6 +1152,14 @@ static int ac97_post_load (void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; +record_select (s, mixer_load (s, AC97_Record_Select)); +set_volume (s, AC97_Master_Volume_Mute, +mixer_load (s, AC97_Master_Volume_Mute)); +set_volume (s, AC97_PCM_Out_Volume_Mute, +mixer_load (s, AC97_PCM_Out_Volume_Mute)); +set_volume (s, AC97_Line_In_Volume_Mute, +mixer_load (s, AC97_Line_In_Volume_Mute)); + active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); -- 1.7.7.6
[Qemu-devel] [PATCH v4 09/11] Allow controlling volume with PulseAudio backend
Signed-off-by: Marc-André Lureau --- audio/paaudio.c | 99 --- 1 files changed, 94 insertions(+), 5 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index 6f50c1c..e6708d0 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -677,15 +677,103 @@ static void qpa_fini_in (HWVoiceIn *hw) static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) { -(void) hw; -(void) cmd; +PAVoiceOut *pa = (PAVoiceOut *) hw; +pa_operation *op; +pa_cvolume v; +paaudio *g = &glob_paaudio; + +pa_cvolume_init (&v); + +switch (cmd) { +case VOICE_VOLUME: +{ +SWVoiceOut *sw; +va_list ap; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceOut *); +va_end (ap); + +v.channels = 2; +v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; +v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; + +pa_threaded_mainloop_lock (g->mainloop); + +op = pa_context_set_sink_input_volume (g->context, +pa_stream_get_index (pa->stream), +&v, NULL, NULL); +if (!op) +qpa_logerr (pa_context_errno (g->context), +"set_sink_input_volume() failed\n"); +else +pa_operation_unref (op); + +op = pa_context_set_sink_input_mute (g->context, +pa_stream_get_index (pa->stream), + sw->vol.mute, NULL, NULL); +if (!op) { +qpa_logerr (pa_context_errno (g->context), +"set_sink_input_mute() failed\n"); +} else { +pa_operation_unref (op); +} + +pa_threaded_mainloop_unlock (g->mainloop); +} +} return 0; } static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) { -(void) hw; -(void) cmd; +PAVoiceIn *pa = (PAVoiceIn *) hw; +pa_operation *op; +pa_cvolume v; +paaudio *g = &glob_paaudio; + +pa_cvolume_init (&v); + +switch (cmd) { +case VOICE_VOLUME: +{ +SWVoiceIn *sw; +va_list ap; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceIn *); +va_end (ap); + +v.channels = 2; +v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; +v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; + +pa_threaded_mainloop_lock (g->mainloop); + +/* FIXME: use the upcoming "set_source_output_{volume,mute}" */ +op = pa_context_set_source_volume_by_index (g->context, +pa_stream_get_device_index (pa->stream), +&v, NULL, NULL); +if (!op) { +qpa_logerr (pa_context_errno (g->context), +"set_source_volume() failed\n"); +} else { +pa_operation_unref(op); +} + +op = pa_context_set_source_mute_by_index (g->context, +pa_stream_get_index (pa->stream), +sw->vol.mute, NULL, NULL); +if (!op) { +qpa_logerr (pa_context_errno (g->context), +"set_source_mute() failed\n"); +} else { +pa_operation_unref (op); +} + +pa_threaded_mainloop_unlock (g->mainloop); +} +} return 0; } @@ -822,5 +910,6 @@ struct audio_driver pa_audio_driver = { .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof (PAVoiceOut), -.voice_size_in = sizeof (PAVoiceIn) +.voice_size_in = sizeof (PAVoiceIn), +.ctl_caps = VOICE_VOLUME_CAP }; -- 1.7.7.6
[Qemu-devel] [PATCH v4 10/11] Enable mixemu by default, add runtime option
Without MIXEMU, volume control on the guest doesn't work (except when volume is applied by guest "emulation", in Win7 for example). Instead rely on backend volume support, or fallback on mixeng if backend doesn't support volume control, except if mixemu is disabled with QEMU_MIXEMU=0. Signed-off-by: Marc-André Lureau --- audio/audio.c | 10 +- audio/mixeng.c |6 -- configure |8 hw/hda-audio.c |4 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index bd9237e..bb94133 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -70,6 +70,7 @@ static struct { int log_to_monitor; int try_poll_in; int try_poll_out; +int mixemu; } conf = { .fixed_out = { /* DAC fixed settings */ .enabled = 1, @@ -100,6 +101,7 @@ static struct { .log_to_monitor = 0, .try_poll_in = 1, .try_poll_out = 1, +.mixemu = 1, }; static AudioState glob_audio_state; @@ -1044,7 +1046,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) if (swlim) { sw->conv (sw->buf, buf, swlim); -if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { +if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP) && conf.mixemu) { mixeng_volume (sw->buf, swlim, &sw->vol); } } @@ -1657,6 +1659,12 @@ static struct audio_option audio_options[] = { .valp = &conf.log_to_monitor, .descr = "Print logging messages to monitor instead of stderr" }, +{ +.name = "MIXEMU", +.tag = AUD_OPT_BOOL, +.valp = &conf.mixemu, +.descr = "Enable mixer emulation (1 - enabled, 0 - disabled)" +}, { /* End of list */ } }; diff --git a/audio/mixeng.c b/audio/mixeng.c index 5446be6..0b060e3 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -336,7 +336,6 @@ void mixeng_clear (struct st_sample *buf, int len) void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol) { -#ifdef CONFIG_MIXEMU if (vol->mute) { mixeng_clear (buf, len); return; @@ -352,9 +351,4 @@ void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol) #endif buf += 1; } -#else -(void) buf; -(void) len; -(void) vol; -#endif } diff --git a/configure b/configure index 160bf63..09fc408 100755 --- a/configure +++ b/configure @@ -177,7 +177,6 @@ darwin_user="no" bsd_user="no" guest_base="" uname_release="" -mixemu="no" aix="no" blobs="yes" pkgversion="" @@ -770,8 +769,6 @@ for opt do ;; --enable-nptl) nptl="yes" ;; - --enable-mixemu) mixemu="yes" - ;; --disable-linux-aio) linux_aio="no" ;; --enable-linux-aio) linux_aio="yes" @@ -1028,7 +1025,6 @@ echo " --audio-card-list=LIST set list of emulated audio cards [$audio_card_l echo " Available cards: $audio_possible_cards" echo " --block-drv-whitelist=L set block driver whitelist" echo " (affects only QEMU, not qemu-img)" -echo " --enable-mixemu enable mixer emulation" echo " --disable-xendisable xen backend driver support" echo " --enable-xen enable xen backend driver support" echo " --disable-brlapi disable BrlAPI" @@ -2885,7 +2881,6 @@ echo "mingw32 support $mingw32" echo "Audio drivers $audio_drv_list" echo "Extra audio cards $audio_card_list" echo "Block whitelist $block_drv_whitelist" -echo "Mixer emulation $mixemu" echo "VirtFS support$virtfs" echo "VNC support $vnc" if test "$vnc" = "yes" ; then @@ -3047,9 +3042,6 @@ if test "$audio_win_int" = "yes" ; then echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak fi echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak -if test "$mixemu" = "yes" ; then - echo "CONFIG_MIXEMU=y" >> $config_host_mak -fi if test "$vnc" = "yes" ; then echo "CONFIG_VNC=y" >> $config_host_mak fi diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 8995519..75f1402 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -121,15 +121,11 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) #define QEMU_HDA_AMP_NONE(0) #define QEMU_HDA_AMP_STEPS 0x4a -#ifdef CONFIG_MIXEMU #define QEMU_HDA_AMP_CAPS \ (AC_AMPCAP_MUTE | \ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT)|\ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) |\ (3 << AC_AMPCAP_STEP_SIZE_SHIFT)) -#else -#define QEMU_HDA_AMP_CAPSQEMU_HDA_AMP_NONE -#endif /* common: audio output widget */ static const desc_param common_params_audio_dac[] = { -- 1.7.7.6
Re: [Qemu-devel] [PATCH v4 11/11] audio/rfc: remove PLIVE and PERIOD options
Hi On Wed, Mar 14, 2012 at 10:22 AM, Gerd Hoffmann wrote: > On 03/13/12 16:47, malc wrote: >> On Tue, 13 Mar 2012, Marc-Andr? Lureau wrote: >> >>> - period seems to be unused now > >> Period on the other hand is unused because i somehow missed the subtle >> change of behavior in one of the patches made by, i think, Gerd. > > Uhm, which patch? I think that wasn't intentional, at least I can't > remember intentionally disabling period. Maybe I missed the subtle > change of behavior too. Could be: 39deb1e496de81957167daebf5cf5d1fbd5e47c2 > I do see the point in having this configurable as this is a cpu overhead > vs. latency tradeoff which one might want to tweak depending on the use > case. But that would impact a/v sync, or can you report added latency back to the guest somehow? I imagine audio backend latency should depend on the configured device buffering/latency, not on an environment tweak. regards -- Marc-André Lureau
Re: [Qemu-devel] [PATCH v4 11/11] audio/rfc: remove PLIVE and PERIOD options
Hi > Guest interfacing is next to impossible I think, simply because real > hardware has no need for that and thus the interfaces simply don't > exist > in the hardware we are emulating. We can try to fix that with a > virtio > soundcard which has such interfaces, but it could be this simply > shifts > the issue from the driver/hardware interface to the os-kernel/driver > interface. btw, the Xen folks just merged a PulseAudio sink/src implementation a few days ago: http://cgit.freedesktop.org/pulseaudio/pulseaudio/commit/?id=50a7bf1175eaf07521c00bde8eed2f820e64437f
[Qemu-devel] [PATCH 00/10] apply volume on client side v5
Hi, This patch series implements client-side audio volume support. This reduces confusion of guest users when volume control is not effective (because mixemu is disabled or because client-side is muted and can't be unmuted by the guest..) Instead, the backend is responsible for applying volume giving the guest control over the full range of the client, and avoiding multiple level of volume/mute effects. Although I was mainly interested in having the Spice audio backend support, I also added PulseAudio backend support (which unfortunately requires full-blown API, even after quick discussion with upstream). v5: - code style fixes (spaces) - left out from patch series the RFC "remove PLIVE and PERIOD options" Marc-André Lureau (10): audio: add VOICE_VOLUME ctl audio: don't apply volume effect if backend has VOICE_VOLUME_CAP hw/ac97: remove USE_MIXER code hw/ac97: the volume mask is not only 0x1f hw/ac97: add support for volume control audio/spice: add support for volume control Do not use pa_simple PulseAudio API configure: pa_simple is not needed anymore Allow controlling volume with PulseAudio backend Enable mixemu by default, add runtime option audio/audio.c | 29 +++- audio/audio_int.h |6 + audio/audio_template.h |2 + audio/mixeng.c |6 - audio/paaudio.c| 476 +++- audio/spiceaudio.c | 41 configure | 14 +- hw/ac97.c | 139 +- hw/hda-audio.c |4 - 9 files changed, 561 insertions(+), 156 deletions(-) -- 1.7.7.6
[Qemu-devel] [PATCH 08/10] configure: pa_simple is not needed anymore
Signed-off-by: Marc-André Lureau --- configure |6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 8b4e3c1..907a655 100755 --- a/configure +++ b/configure @@ -1847,9 +1847,9 @@ for drv in $audio_drv_list; do ;; pa) -audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \ -"pa_simple *s = 0; pa_simple_free(s); return 0;" -libs_softmmu="-lpulse -lpulse-simple $libs_softmmu" +audio_drv_probe $drv pulse/mainloop.h "-lpulse" \ +"pa_mainloop *m = 0; pa_mainloop_free (m); return 0;" +libs_softmmu="-lpulse $libs_softmmu" audio_pt_int="yes" ;; -- 1.7.7.6
[Qemu-devel] [PATCH 09/10] Allow controlling volume with PulseAudio backend
Signed-off-by: Marc-André Lureau --- audio/paaudio.c | 99 --- 1 files changed, 94 insertions(+), 5 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index 6f50c1c..e6708d0 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -677,15 +677,103 @@ static void qpa_fini_in (HWVoiceIn *hw) static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) { -(void) hw; -(void) cmd; +PAVoiceOut *pa = (PAVoiceOut *) hw; +pa_operation *op; +pa_cvolume v; +paaudio *g = &glob_paaudio; + +pa_cvolume_init (&v); + +switch (cmd) { +case VOICE_VOLUME: +{ +SWVoiceOut *sw; +va_list ap; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceOut *); +va_end (ap); + +v.channels = 2; +v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; +v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; + +pa_threaded_mainloop_lock (g->mainloop); + +op = pa_context_set_sink_input_volume (g->context, +pa_stream_get_index (pa->stream), +&v, NULL, NULL); +if (!op) +qpa_logerr (pa_context_errno (g->context), +"set_sink_input_volume() failed\n"); +else +pa_operation_unref (op); + +op = pa_context_set_sink_input_mute (g->context, +pa_stream_get_index (pa->stream), + sw->vol.mute, NULL, NULL); +if (!op) { +qpa_logerr (pa_context_errno (g->context), +"set_sink_input_mute() failed\n"); +} else { +pa_operation_unref (op); +} + +pa_threaded_mainloop_unlock (g->mainloop); +} +} return 0; } static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) { -(void) hw; -(void) cmd; +PAVoiceIn *pa = (PAVoiceIn *) hw; +pa_operation *op; +pa_cvolume v; +paaudio *g = &glob_paaudio; + +pa_cvolume_init (&v); + +switch (cmd) { +case VOICE_VOLUME: +{ +SWVoiceIn *sw; +va_list ap; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceIn *); +va_end (ap); + +v.channels = 2; +v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; +v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; + +pa_threaded_mainloop_lock (g->mainloop); + +/* FIXME: use the upcoming "set_source_output_{volume,mute}" */ +op = pa_context_set_source_volume_by_index (g->context, +pa_stream_get_device_index (pa->stream), +&v, NULL, NULL); +if (!op) { +qpa_logerr (pa_context_errno (g->context), +"set_source_volume() failed\n"); +} else { +pa_operation_unref(op); +} + +op = pa_context_set_source_mute_by_index (g->context, +pa_stream_get_index (pa->stream), +sw->vol.mute, NULL, NULL); +if (!op) { +qpa_logerr (pa_context_errno (g->context), +"set_source_mute() failed\n"); +} else { +pa_operation_unref (op); +} + +pa_threaded_mainloop_unlock (g->mainloop); +} +} return 0; } @@ -822,5 +910,6 @@ struct audio_driver pa_audio_driver = { .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof (PAVoiceOut), -.voice_size_in = sizeof (PAVoiceIn) +.voice_size_in = sizeof (PAVoiceIn), +.ctl_caps = VOICE_VOLUME_CAP }; -- 1.7.7.6
[Qemu-devel] [PATCH 10/10] Enable mixemu by default, add runtime option
Without MIXEMU, volume control on the guest doesn't work (except when volume is applied by guest "emulation", in Win7 for example). Instead rely on backend volume support, or fallback on mixeng if backend doesn't support volume control, except if mixemu is disabled with QEMU_MIXEMU=0. Signed-off-by: Marc-André Lureau --- audio/audio.c | 10 +- audio/mixeng.c |6 -- configure |8 hw/hda-audio.c |4 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index bd9237e..bb94133 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -70,6 +70,7 @@ static struct { int log_to_monitor; int try_poll_in; int try_poll_out; +int mixemu; } conf = { .fixed_out = { /* DAC fixed settings */ .enabled = 1, @@ -100,6 +101,7 @@ static struct { .log_to_monitor = 0, .try_poll_in = 1, .try_poll_out = 1, +.mixemu = 1, }; static AudioState glob_audio_state; @@ -1044,7 +1046,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) if (swlim) { sw->conv (sw->buf, buf, swlim); -if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { +if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP) && conf.mixemu) { mixeng_volume (sw->buf, swlim, &sw->vol); } } @@ -1657,6 +1659,12 @@ static struct audio_option audio_options[] = { .valp = &conf.log_to_monitor, .descr = "Print logging messages to monitor instead of stderr" }, +{ +.name = "MIXEMU", +.tag = AUD_OPT_BOOL, +.valp = &conf.mixemu, +.descr = "Enable mixer emulation (1 - enabled, 0 - disabled)" +}, { /* End of list */ } }; diff --git a/audio/mixeng.c b/audio/mixeng.c index 5446be6..0b060e3 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -336,7 +336,6 @@ void mixeng_clear (struct st_sample *buf, int len) void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol) { -#ifdef CONFIG_MIXEMU if (vol->mute) { mixeng_clear (buf, len); return; @@ -352,9 +351,4 @@ void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol) #endif buf += 1; } -#else -(void) buf; -(void) len; -(void) vol; -#endif } diff --git a/configure b/configure index 907a655..d13238f 100755 --- a/configure +++ b/configure @@ -177,7 +177,6 @@ darwin_user="no" bsd_user="no" guest_base="" uname_release="" -mixemu="no" aix="no" blobs="yes" pkgversion="" @@ -771,8 +770,6 @@ for opt do ;; --enable-nptl) nptl="yes" ;; - --enable-mixemu) mixemu="yes" - ;; --disable-linux-aio) linux_aio="no" ;; --enable-linux-aio) linux_aio="yes" @@ -1031,7 +1028,6 @@ echo " --audio-card-list=LIST set list of emulated audio cards [$audio_card_l echo " Available cards: $audio_possible_cards" echo " --block-drv-whitelist=L set block driver whitelist" echo " (affects only QEMU, not qemu-img)" -echo " --enable-mixemu enable mixer emulation" echo " --disable-xendisable xen backend driver support" echo " --enable-xen enable xen backend driver support" echo " --disable-brlapi disable BrlAPI" @@ -2907,7 +2903,6 @@ echo "mingw32 support $mingw32" echo "Audio drivers $audio_drv_list" echo "Extra audio cards $audio_card_list" echo "Block whitelist $block_drv_whitelist" -echo "Mixer emulation $mixemu" echo "VirtFS support$virtfs" echo "VNC support $vnc" if test "$vnc" = "yes" ; then @@ -3070,9 +3065,6 @@ if test "$audio_win_int" = "yes" ; then echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak fi echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak -if test "$mixemu" = "yes" ; then - echo "CONFIG_MIXEMU=y" >> $config_host_mak -fi if test "$vnc" = "yes" ; then echo "CONFIG_VNC=y" >> $config_host_mak fi diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 8995519..75f1402 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -121,15 +121,11 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) #define QEMU_HDA_AMP_NONE(0) #define QEMU_HDA_AMP_STEPS 0x4a -#ifdef CONFIG_MIXEMU #define QEMU_HDA_AMP_CAPS \ (AC_AMPCAP_MUTE | \ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT)|\ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) |\ (3 << AC_AMPCAP_STEP_SIZE_SHIFT)) -#else -#define QEMU_HDA_AMP_CAPSQEMU_HDA_AMP_NONE -#endif /* common: audio output widget */ static const desc_param common_params_audio_dac[] = { -- 1.7.7.6
[Qemu-devel] [PATCH 06/10] audio/spice: add support for volume control
Use Spice server volume control API when available. Signed-off-by: Marc-André Lureau --- audio/spiceaudio.c | 41 + 1 files changed, 41 insertions(+), 0 deletions(-) diff --git a/audio/spiceaudio.c b/audio/spiceaudio.c index f972110..6f15591 100644 --- a/audio/spiceaudio.c +++ b/audio/spiceaudio.c @@ -202,7 +202,26 @@ static int line_out_ctl (HWVoiceOut *hw, int cmd, ...) } spice_server_playback_stop (&out->sin); break; +case VOICE_VOLUME: +{ +#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) +SWVoiceOut *sw; +va_list ap; +uint16_t vol[2]; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceOut *); +va_end (ap); + +vol[0] = sw->vol.l / ((1ULL << 16) + 1); +vol[1] = sw->vol.r / ((1ULL << 16) + 1); +spice_server_playback_set_volume (&out->sin, 2, vol); +spice_server_playback_set_mute (&out->sin, sw->vol.mute); +#endif +break; +} } + return 0; } @@ -304,7 +323,26 @@ static int line_in_ctl (HWVoiceIn *hw, int cmd, ...) in->active = 0; spice_server_record_stop (&in->sin); break; +case VOICE_VOLUME: +{ +#if ((SPICE_INTERFACE_RECORD_MAJOR >= 2) && (SPICE_INTERFACE_RECORD_MINOR >= 2)) +SWVoiceIn *sw; +va_list ap; +uint16_t vol[2]; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceIn *); +va_end (ap); + +vol[0] = sw->vol.l / ((1ULL << 16) + 1); +vol[1] = sw->vol.r / ((1ULL << 16) + 1); +spice_server_record_set_volume (&in->sin, 2, vol); +spice_server_record_set_mute (&in->sin, sw->vol.mute); +#endif +break; +} } + return 0; } @@ -337,6 +375,9 @@ struct audio_driver spice_audio_driver = { .max_voices_in = 1, .voice_size_out = sizeof (SpiceVoiceOut), .voice_size_in = sizeof (SpiceVoiceIn), +#if ((SPICE_INTERFACE_PLAYBACK_MAJOR >= 1) && (SPICE_INTERFACE_PLAYBACK_MINOR >= 2)) +.ctl_caps = VOICE_VOLUME_CAP +#endif }; void qemu_spice_audio_init (void) -- 1.7.7.6
[Qemu-devel] [PATCH 02/10] audio: don't apply volume effect if backend has VOICE_VOLUME_CAP
If the audio backend is capable of volume control, don't apply software volume (mixeng_volume ()), but instead, rely on backend volume control. This will allow guest to have full range volume control. Signed-off-by: Marc-André Lureau --- audio/audio.c |9 +++-- audio/audio_int.h |5 + audio/audio_template.h |2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index d76c342..bd9237e 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -957,7 +957,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) total += isamp; } -mixeng_volume (sw->buf, ret, &sw->vol); +if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) { +mixeng_volume (sw->buf, ret, &sw->vol); +} sw->clip (buf, sw->buf, ret); sw->total_hw_samples_acquired += total; @@ -1041,7 +1043,10 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) swlim = audio_MIN (swlim, samples); if (swlim) { sw->conv (sw->buf, buf, swlim); -mixeng_volume (sw->buf, swlim, &sw->vol); + +if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { +mixeng_volume (sw->buf, swlim, &sw->vol); +} } while (swlim) { diff --git a/audio/audio_int.h b/audio/audio_int.h index 117f95e..b9b0676 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -82,6 +82,7 @@ typedef struct HWVoiceOut { int samples; QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; +int ctl_caps; struct audio_pcm_ops *pcm_ops; QLIST_ENTRY (HWVoiceOut) entries; } HWVoiceOut; @@ -101,6 +102,7 @@ typedef struct HWVoiceIn { int samples; QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; +int ctl_caps; struct audio_pcm_ops *pcm_ops; QLIST_ENTRY (HWVoiceIn) entries; } HWVoiceIn; @@ -150,6 +152,7 @@ struct audio_driver { int max_voices_in; int voice_size_out; int voice_size_in; +int ctl_caps; }; struct audio_pcm_ops { @@ -233,6 +236,8 @@ void audio_run (const char *msg); #define VOICE_DISABLE 2 #define VOICE_VOLUME 3 +#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME) + static inline int audio_ring_dist (int dst, int src, int len) { return (dst >= src) ? (dst - src) : (len - src + dst); diff --git a/audio/audio_template.h b/audio/audio_template.h index e62a713..519432a 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -263,6 +263,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) } hw->pcm_ops = drv->pcm_ops; +hw->ctl_caps = drv->ctl_caps; + QLIST_INIT (&hw->sw_head); #ifdef DAC QLIST_INIT (&hw->cap_head); -- 1.7.7.6
[Qemu-devel] [PATCH 05/10] hw/ac97: add support for volume control
Combine output volume with Master and PCM registers values. Use default values in mixer_reset (). Set volume on post-load to update backend values. v4,v5: - fix some code style Signed-off-by: Marc-André Lureau --- hw/ac97.c | 81 + 1 files changed, 81 insertions(+), 0 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index f7866ed..177f729 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -436,6 +436,65 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) AUD_set_active_in (s->voice_mc, active[MC_INDEX]); } +static void get_volume (uint16_t vol, uint16_t mask, int inverse, +int *mute, uint8_t *lvol, uint8_t *rvol) +{ +*mute = (vol >> MUTE_SHIFT) & 1; +*rvol = (255 * (vol & mask)) / mask; +*lvol = (255 * ((vol >> 8) & mask)) / mask; + +if (inverse) { +*rvol = 255 - *rvol; +*lvol = 255 - *lvol; +} +} + +static void update_combined_volume_out (AC97LinkState *s) +{ +uint8_t lvol, rvol, plvol, prvol; +int mute, pmute; + +get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, +&mute, &lvol, &rvol); +/* FIXME: should be 1f according to spec */ +get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, +&pmute, &plvol, &prvol); + +mute = mute | pmute; +lvol = (lvol * plvol) / 255; +rvol = (rvol * prvol) / 255; + +AUD_set_volume_out (s->voice_po, mute, lvol, rvol); +} + +static void update_volume_in (AC97LinkState *s) +{ +uint8_t lvol, rvol; +int mute; + +get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, +&mute, &lvol, &rvol); + +AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); +} + +static void set_volume (AC97LinkState *s, int index, uint32_t val) +{ +mixer_store (s, index, val); +if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) { +update_combined_volume_out (s); +} else if (index == AC97_Record_Gain_Mute) { +update_volume_in (s); +} +} + +static void record_select (AC97LinkState *s, uint32_t val) +{ +uint8_t rs = val & REC_MASK; +uint8_t ls = (val >> 8) & REC_MASK; +mixer_store (s, AC97_Record_Select, rs | (ls << 8)); +} + static void mixer_reset (AC97LinkState *s) { uint8_t active[LAST_INDEX]; @@ -470,6 +529,11 @@ static void mixer_reset (AC97LinkState *s) mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); +record_select (s, 0); +set_volume (s, AC97_Master_Volume_Mute, 0x8000); +set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); +set_volume (s, AC97_Line_In_Volume_Mute, 0x8808); + reset_voices (s, active); } @@ -528,6 +592,15 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; +case AC97_PCM_Out_Volume_Mute: +case AC97_Master_Volume_Mute: +case AC97_Record_Gain_Mute: +case AC97_Line_In_Volume_Mute: +set_volume (s, index, val); +break; +case AC97_Record_Select: +record_select (s, val); +break; case AC97_Vendor_ID1: case AC97_Vendor_ID2: dolog ("Attempt to write vendor ID to %#x\n", val); @@ -1080,6 +1153,14 @@ static int ac97_post_load (void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; +record_select (s, mixer_load (s, AC97_Record_Select)); +set_volume (s, AC97_Master_Volume_Mute, +mixer_load (s, AC97_Master_Volume_Mute)); +set_volume (s, AC97_PCM_Out_Volume_Mute, +mixer_load (s, AC97_PCM_Out_Volume_Mute)); +set_volume (s, AC97_Line_In_Volume_Mute, +mixer_load (s, AC97_Line_In_Volume_Mute)); + active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); -- 1.7.7.6
[Qemu-devel] [PATCH 03/10] hw/ac97: remove USE_MIXER code
That code doesn't compile. The interesting bits for volume control are going to be rewritten in the following patch. Signed-off-by: Marc-André Lureau --- hw/ac97.c | 121 - 1 files changed, 0 insertions(+), 121 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index c0fd019..f2804e6 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -437,99 +437,6 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) AUD_set_active_in (s->voice_mc, active[MC_INDEX]); } -#ifdef USE_MIXER -static void set_volume (AC97LinkState *s, int index, -audmixerctl_t mt, uint32_t val) -{ -int mute = (val >> MUTE_SHIFT) & 1; -uint8_t rvol = VOL_MASK - (val & VOL_MASK); -uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK); -rvol = 255 * rvol / VOL_MASK; -lvol = 255 * lvol / VOL_MASK; - -#ifdef SOFT_VOLUME -if (index == AC97_Master_Volume_Mute) { -AUD_set_volume_out (s->voice_po, mute, lvol, rvol); -} -else { -AUD_set_volume (mt, &mute, &lvol, &rvol); -} -#else -AUD_set_volume (mt, &mute, &lvol, &rvol); -#endif - -rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); -lvol = VOL_MASK - ((VOL_MASK * lvol) / 255); -mixer_store (s, index, val); -} - -static audrecsource_t ac97_to_aud_record_source (uint8_t i) -{ -switch (i) { -case REC_MIC: -return AUD_REC_MIC; - -case REC_CD: -return AUD_REC_CD; - -case REC_VIDEO: -return AUD_REC_VIDEO; - -case REC_AUX: -return AUD_REC_AUX; - -case REC_LINE_IN: -return AUD_REC_LINE_IN; - -case REC_PHONE: -return AUD_REC_PHONE; - -default: -dolog ("Unknown record source %d, using MIC\n", i); -return AUD_REC_MIC; -} -} - -static uint8_t aud_to_ac97_record_source (audrecsource_t rs) -{ -switch (rs) { -case AUD_REC_MIC: -return REC_MIC; - -case AUD_REC_CD: -return REC_CD; - -case AUD_REC_VIDEO: -return REC_VIDEO; - -case AUD_REC_AUX: -return REC_AUX; - -case AUD_REC_LINE_IN: -return REC_LINE_IN; - -case AUD_REC_PHONE: -return REC_PHONE; - -default: -dolog ("Unknown audio recording source %d using MIC\n", rs); -return REC_MIC; -} -} - -static void record_select (AC97LinkState *s, uint32_t val) -{ -uint8_t rs = val & REC_MASK; -uint8_t ls = (val >> 8) & REC_MASK; -audrecsource_t ars = ac97_to_aud_record_source (rs); -audrecsource_t als = ac97_to_aud_record_source (ls); -AUD_set_record_source (&als, &ars); -rs = aud_to_ac97_record_source (ars); -ls = aud_to_ac97_record_source (als); -mixer_store (s, AC97_Record_Select, rs | (ls << 8)); -} -#endif - static void mixer_reset (AC97LinkState *s) { uint8_t active[LAST_INDEX]; @@ -564,12 +471,6 @@ static void mixer_reset (AC97LinkState *s) mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); -#ifdef USE_MIXER -record_select (s, 0); -set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000); -set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM, 0x8808); -set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); -#endif reset_voices (s, active); } @@ -628,20 +529,6 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; -#ifdef USE_MIXER -case AC97_Master_Volume_Mute: -set_volume (s, index, AUD_MIXER_VOLUME, val); -break; -case AC97_PCM_Out_Volume_Mute: -set_volume (s, index, AUD_MIXER_PCM, val); -break; -case AC97_Line_In_Volume_Mute: -set_volume (s, index, AUD_MIXER_LINE_IN, val); -break; -case AC97_Record_Select: -record_select (s, val); -break; -#endif case AC97_Vendor_ID1: case AC97_Vendor_ID2: dolog ("Attempt to write vendor ID to %#x\n", val); @@ -1194,14 +1081,6 @@ static int ac97_post_load (void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; -#ifdef USE_MIXER -record_select (s, mixer_load (s, AC97_Record_Select)); -#define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) -V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); -V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); -V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); -#undef V_ -#endif active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); -- 1.7.7.6
[Qemu-devel] [PATCH 01/10] audio: add VOICE_VOLUME ctl
Add a new PCM control operation to update the stream volume on the audio backend. The argument given is a SWVoiceOut/SWVoiceIn. v4: - verified other backends didn't fail/assert on this new control they randomly return 0 or -1, but we ignore return value. Signed-off-by: Marc-André Lureau --- audio/audio.c | 12 audio/audio_int.h |1 + 2 files changed, 13 insertions(+), 0 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index 398763f..d76c342 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2053,17 +2053,29 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) { if (sw) { +HWVoiceOut *hw = sw->hw; + sw->vol.mute = mute; sw->vol.l = nominal_volume.l * lvol / 255; sw->vol.r = nominal_volume.r * rvol / 255; + +if (hw->pcm_ops->ctl_out) { +hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw); +} } } void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) { if (sw) { +HWVoiceIn *hw = sw->hw; + sw->vol.mute = mute; sw->vol.l = nominal_volume.l * lvol / 255; sw->vol.r = nominal_volume.r * rvol / 255; + +if (hw->pcm_ops->ctl_in) { +hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw); +} } } diff --git a/audio/audio_int.h b/audio/audio_int.h index 2003f8b..117f95e 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -231,6 +231,7 @@ void audio_run (const char *msg); #define VOICE_ENABLE 1 #define VOICE_DISABLE 2 +#define VOICE_VOLUME 3 static inline int audio_ring_dist (int dst, int src, int len) { -- 1.7.7.6
[Qemu-devel] [PATCH 04/10] hw/ac97: the volume mask is not only 0x1f
It's a case by case (see Table 66. AC ‘97 Baseline Audio Register Map) Signed-off-by: Marc-André Lureau --- hw/ac97.c |1 - 1 files changed, 0 insertions(+), 1 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index f2804e6..f7866ed 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -118,7 +118,6 @@ enum { #define EACS_VRA 1 #define EACS_VRM 8 -#define VOL_MASK 0x1f #define MUTE_SHIFT 15 #define REC_MASK 7 -- 1.7.7.6
[Qemu-devel] [PATCH 07/10] Do not use pa_simple PulseAudio API
Unfortunately, pa_simple is a limited API which doesn't let us retrieve the associated pa_stream. It is needed to control the volume of the stream. In v4: - add missing braces Signed-off-by: Marc-André Lureau --- audio/paaudio.c | 377 +-- 1 files changed, 339 insertions(+), 38 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index d1f3912..6f50c1c 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -2,8 +2,7 @@ #include "qemu-common.h" #include "audio.h" -#include -#include +#include #define AUDIO_CAP "pulseaudio" #include "audio_int.h" @@ -15,7 +14,7 @@ typedef struct { int live; int decr; int rpos; -pa_simple *s; +pa_stream *stream; void *pcm_buf; struct audio_pt pt; } PAVoiceOut; @@ -26,17 +25,23 @@ typedef struct { int dead; int incr; int wpos; -pa_simple *s; +pa_stream *stream; void *pcm_buf; struct audio_pt pt; +const void *read_data; +size_t read_index, read_length; } PAVoiceIn; -static struct { +typedef struct { int samples; char *server; char *sink; char *source; -} conf = { +pa_threaded_mainloop *mainloop; +pa_context *context; +} paaudio; + +static paaudio glob_paaudio = { .samples = 4096, }; @@ -51,6 +56,126 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); } +#define CHECK_SUCCESS_GOTO(c, rerror, expression, label)\ +do {\ +if (!(expression)) {\ +if (rerror) { \ +*(rerror) = pa_context_errno ((c)->context);\ +} \ +goto label; \ +} \ +} while (0); + +#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ +do {\ +if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ +!(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream { \ +if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ +((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ +if (rerror) { \ +*(rerror) = pa_context_errno ((c)->context);\ +} \ +} else {\ +if (rerror) { \ +*(rerror) = PA_ERR_BADSTATE;\ +} \ +} \ +goto label; \ +} \ +} while (0); + +static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror) +{ +paaudio *g = &glob_paaudio; + +pa_threaded_mainloop_lock (g->mainloop); + +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); + +while (length > 0) { +size_t l; + +while (!p->read_data) { +int r; + +r = pa_stream_peek (p->stream, &p->read_data, &p->read_length); +CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); + +if (!p->read_data) { +pa_threaded_mainloop_wait (g->mainloop); +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); +} else { +p->read_index = 0; +} +} + +l = p->read_length < length ? p->read_length : length; +memcpy (data, (const uint8_t *) p->read_data+p->read_index, l); + +data = (uint8_t *) data + l; +length -= l; + +p->read_index += l; +p->read_length -= l; + +if (!p->read_length) { +int r; + +r = pa_stream_drop (p->stream); +p->read_data = NULL; +p->read_length = 0; +p->read_index = 0; + +CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); +} +} + +pa_threaded_mainloop_unlock (g->mainloop); +return 0; + +unlock_and_fail: +pa_threaded_mainloop_unlock (g->mainloop); +return -1; +} + +static int qpa_simple_write (PAVoiceOut *p, const void *data
Re: [Qemu-devel] Spice bug with qemu_name
On Fri, Mar 23, 2012 at 9:10 AM, Lee Essen wrote: > In ui/spice_core.c spice_server_set_name() is called with qemu_name, which if > not set causes a core dump. I forgot strdup didn't like NULL values, and I forgot to push the patches fixing this in spice. I've now pushed it. Since it's not officially release, I don't think we should work around it in qemu. cheers -- Marc-André Lureau
Re: [Qemu-devel] [PATCH v5] Release 0.11.0
ack On Tue, Jun 12, 2012 at 4:27 PM, Alon Levy wrote: > Current bumped and age bumped for new intefaces only (no backward > incompatible changes). > > New libtool version is 2.0.1, using --version-info instead of > --version-name. Doing the version change and --version-name to > --version-info change here to avoid changing the libtool version twice. > > Added interfaces: > spice_server_set_name > spice_server_set_uuid > spice_server_set_listen_socket_fd > spice_server_is_server_mouse > > New library name in linux: > libspice-server.so.1.1.0 > Old: > libspice-server.so.1.0.2 > --- > v4->v5: > no libtool docs, merge patches, library name suffix is 1.1.0 > > > NEWS | 33 + > configure.ac | 24 +--- > server/Makefile.am | 2 +- > 3 files changed, 55 insertions(+), 4 deletions(-) > > diff --git a/NEWS b/NEWS > index 2deba57..68369af 100644 > --- a/NEWS > +++ b/NEWS > @@ -1,3 +1,36 @@ > +Major changes in 0.11.0: > + > +* !Development Release! > +* 8817549..d905a1f > +* now using git submodules: spice-common and spice-protocol. > +* New spice protocol messages: (changes in spice-protocol, here for > reference) > + * SPICE_MSG_MAIN_NAME, SPICE_MSG_MAIN_UUID > + * SPICE_MSG_DISPLAY_STREAM_DATA_SIZED > +* New corresponding caps: (changes in spice-protocol, here for reference) > + * SPICE_MAIN_CAP_NAME_AND_UUID > + * SPICE_DISPLAY_CAP_SIZED_STREAM. > +* Send name & uuid to capable clients > +* add support for frames of different sizes RHBZ #813826 > +* server: > + * support a pre-opened file descriptor > + * Solaris support. Now using poll instead of epoll. > + * Support IPV6 addresses in channel events RHBZ #788444 > + * other fixed RHBZ#: 787669, 787678, 819484 > +* spicec > + * alsa: use "default" instead of "hw:0,0" > + * volume keys support RHBZ #552539 > + * other fixed RHBZ#: 78655, 804561, 641828 > +* solaris, mingw & windows, 32 bit fixes. > +* enable server only build. > +* GNULIB manywarnings.m4 & warnings.m4 module added. > +* Many more bug fixes & code cleanups. > +* spice-protocol no longer external. > +* new server functions: > + + spice_server_set_name > + + spice_server_set_uuid > + + spice_server_set_listen_socket_fd > + + spice_server_is_server_mouse > + > Major changes in 0.10.1: > > * Mini header support > diff --git a/configure.ac b/configure.ac > index 66f9d12..aee2975 100644 > --- a/configure.ac > +++ b/configure.ac > @@ -1,8 +1,26 @@ > AC_PREREQ([2.57]) > > +# Making releases: > +# 1. Increment SPICE_MICRO if no interface change has been done > +# 2. Increment SPICE_MINOR and zero SPICE_MICRO if new interfaces have been > added, > +# no changes to existing interfaces. > +# 3. Increment SPICE_MAJOR and zero both SPICE_MINOR and SPICE_MICRO if non > +# backward compatible changes (interface changed or removed). > +# > +# Then change the libtool versions according to libtool manual: > +# > http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html > + > m4_define([SPICE_MAJOR], 0) > -m4_define([SPICE_MINOR], 10) > -m4_define([SPICE_MICRO], 1) > +m4_define([SPICE_MINOR], 11) > +m4_define([SPICE_MICRO], 0) > +m4_define([SPICE_CURRENT], [2]) > +m4_define([SPICE_REVISION], [0]) > +m4_define([SPICE_AGE], [1]) > + > +# Note on the library name on linux (SONAME) produced by libtool (for > reference, gleaned > +# from looking at libtool 2.4.2) > +# > +# libspice-servver.so.current-age.age.revision > > AC_INIT(spice, [SPICE_MAJOR.SPICE_MINOR.SPICE_MICRO], [], spice) > > @@ -33,7 +51,7 @@ AC_FUNC_ALLOCA > > AC_DEFINE([__STDC_FORMAT_MACROS],[],[Force definition of format macros for > C++]) > > -SPICE_LT_VERSION=m4_format("%d:%d:%d", 1, 0, 2) > +SPICE_LT_VERSION=m4_format("%d:%d:%d", SPICE_CURRENT, SPICE_REVISION, > SPICE_AGE) > AC_SUBST(SPICE_LT_VERSION) > > # Check for the CPU we are using > diff --git a/server/Makefile.am b/server/Makefile.am > index 97e7dfe..47b3c10 100644 > --- a/server/Makefile.am > +++ b/server/Makefile.am > @@ -17,7 +17,7 @@ AM_CPPFLAGS = \ > lib_LTLIBRARIES = libspice-server.la > > libspice_server_la_LDFLAGS = \ > - -version-number $(SPICE_LT_VERSION) \ > + -version-info $(SPICE_LT_VERSION) \ > -no-undefined \ > $(NULL) > > -- > 1.7.10.1 > > -- Marc-André Lureau
[Qemu-devel] [PATCH 00/10] apply volume on client side v5 bis
Just resending as a reminder, thanks. Marc-André Lureau (10): audio: add VOICE_VOLUME ctl audio: don't apply volume effect if backend has VOICE_VOLUME_CAP hw/ac97: remove USE_MIXER code hw/ac97: the volume mask is not only 0x1f hw/ac97: add support for volume control audio/spice: add support for volume control Do not use pa_simple PulseAudio API configure: pa_simple is not needed anymore Allow controlling volume with PulseAudio backend Enable mixemu by default, add runtime option audio/audio.c | 29 ++- audio/audio_int.h |6 + audio/audio_template.h |2 + audio/mixeng.c |6 - audio/paaudio.c| 476 +++- audio/spiceaudio.c | 41 + configure | 14 +- hw/ac97.c | 139 +- hw/hda-audio.c |4 - 9 files changed, 561 insertions(+), 156 deletions(-) -- 1.7.10
[Qemu-devel] [PATCH 05/10] hw/ac97: add support for volume control
Combine output volume with Master and PCM registers values. Use default values in mixer_reset (). Set volume on post-load to update backend values. v4,v5: - fix some code style Signed-off-by: Marc-André Lureau --- hw/ac97.c | 81 + 1 file changed, 81 insertions(+) diff --git a/hw/ac97.c b/hw/ac97.c index f7866ed..177f729 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -436,6 +436,65 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) AUD_set_active_in (s->voice_mc, active[MC_INDEX]); } +static void get_volume (uint16_t vol, uint16_t mask, int inverse, +int *mute, uint8_t *lvol, uint8_t *rvol) +{ +*mute = (vol >> MUTE_SHIFT) & 1; +*rvol = (255 * (vol & mask)) / mask; +*lvol = (255 * ((vol >> 8) & mask)) / mask; + +if (inverse) { +*rvol = 255 - *rvol; +*lvol = 255 - *lvol; +} +} + +static void update_combined_volume_out (AC97LinkState *s) +{ +uint8_t lvol, rvol, plvol, prvol; +int mute, pmute; + +get_volume (mixer_load (s, AC97_Master_Volume_Mute), 0x3f, 1, +&mute, &lvol, &rvol); +/* FIXME: should be 1f according to spec */ +get_volume (mixer_load (s, AC97_PCM_Out_Volume_Mute), 0x3f, 1, +&pmute, &plvol, &prvol); + +mute = mute | pmute; +lvol = (lvol * plvol) / 255; +rvol = (rvol * prvol) / 255; + +AUD_set_volume_out (s->voice_po, mute, lvol, rvol); +} + +static void update_volume_in (AC97LinkState *s) +{ +uint8_t lvol, rvol; +int mute; + +get_volume (mixer_load (s, AC97_Record_Gain_Mute), 0x0f, 0, +&mute, &lvol, &rvol); + +AUD_set_volume_in (s->voice_pi, mute, lvol, rvol); +} + +static void set_volume (AC97LinkState *s, int index, uint32_t val) +{ +mixer_store (s, index, val); +if (index == AC97_Master_Volume_Mute || index == AC97_PCM_Out_Volume_Mute) { +update_combined_volume_out (s); +} else if (index == AC97_Record_Gain_Mute) { +update_volume_in (s); +} +} + +static void record_select (AC97LinkState *s, uint32_t val) +{ +uint8_t rs = val & REC_MASK; +uint8_t ls = (val >> 8) & REC_MASK; +mixer_store (s, AC97_Record_Select, rs | (ls << 8)); +} + static void mixer_reset (AC97LinkState *s) { uint8_t active[LAST_INDEX]; @@ -470,6 +529,11 @@ static void mixer_reset (AC97LinkState *s) mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); +record_select (s, 0); +set_volume (s, AC97_Master_Volume_Mute, 0x8000); +set_volume (s, AC97_PCM_Out_Volume_Mute, 0x8808); +set_volume (s, AC97_Line_In_Volume_Mute, 0x8808); + reset_voices (s, active); } @@ -528,6 +592,15 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; +case AC97_PCM_Out_Volume_Mute: +case AC97_Master_Volume_Mute: +case AC97_Record_Gain_Mute: +case AC97_Line_In_Volume_Mute: +set_volume (s, index, val); +break; +case AC97_Record_Select: +record_select (s, val); +break; case AC97_Vendor_ID1: case AC97_Vendor_ID2: dolog ("Attempt to write vendor ID to %#x\n", val); @@ -1080,6 +1153,14 @@ static int ac97_post_load (void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; +record_select (s, mixer_load (s, AC97_Record_Select)); +set_volume (s, AC97_Master_Volume_Mute, +mixer_load (s, AC97_Master_Volume_Mute)); +set_volume (s, AC97_PCM_Out_Volume_Mute, +mixer_load (s, AC97_PCM_Out_Volume_Mute)); +set_volume (s, AC97_Line_In_Volume_Mute, +mixer_load (s, AC97_Line_In_Volume_Mute)); + active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); -- 1.7.10
[Qemu-devel] [PATCH 04/10] hw/ac97: the volume mask is not only 0x1f
It's a case by case (see Table 66. AC ‘97 Baseline Audio Register Map) Signed-off-by: Marc-André Lureau --- hw/ac97.c |1 - 1 file changed, 1 deletion(-) diff --git a/hw/ac97.c b/hw/ac97.c index f2804e6..f7866ed 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -118,7 +118,6 @@ enum { #define EACS_VRA 1 #define EACS_VRM 8 -#define VOL_MASK 0x1f #define MUTE_SHIFT 15 #define REC_MASK 7 -- 1.7.10
[Qemu-devel] [PATCH 10/10] Enable mixemu by default, add runtime option
Without MIXEMU, volume control on the guest doesn't work (except when volume is applied by guest "emulation", in Win7 for example). Instead rely on backend volume support, or fallback on mixeng if backend doesn't support volume control, except if mixemu is disabled with QEMU_MIXEMU=0. Signed-off-by: Marc-André Lureau --- audio/audio.c | 10 +- audio/mixeng.c |6 -- configure |8 hw/hda-audio.c |4 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index bd9237e..bb94133 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -70,6 +70,7 @@ static struct { int log_to_monitor; int try_poll_in; int try_poll_out; +int mixemu; } conf = { .fixed_out = { /* DAC fixed settings */ .enabled = 1, @@ -100,6 +101,7 @@ static struct { .log_to_monitor = 0, .try_poll_in = 1, .try_poll_out = 1, +.mixemu = 1, }; static AudioState glob_audio_state; @@ -1044,7 +1046,7 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) if (swlim) { sw->conv (sw->buf, buf, swlim); -if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { +if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP) && conf.mixemu) { mixeng_volume (sw->buf, swlim, &sw->vol); } } @@ -1657,6 +1659,12 @@ static struct audio_option audio_options[] = { .valp = &conf.log_to_monitor, .descr = "Print logging messages to monitor instead of stderr" }, +{ +.name = "MIXEMU", +.tag = AUD_OPT_BOOL, +.valp = &conf.mixemu, +.descr = "Enable mixer emulation (1 - enabled, 0 - disabled)" +}, { /* End of list */ } }; diff --git a/audio/mixeng.c b/audio/mixeng.c index 5446be6..0b060e3 100644 --- a/audio/mixeng.c +++ b/audio/mixeng.c @@ -336,7 +336,6 @@ void mixeng_clear (struct st_sample *buf, int len) void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol) { -#ifdef CONFIG_MIXEMU if (vol->mute) { mixeng_clear (buf, len); return; @@ -352,9 +351,4 @@ void mixeng_volume (struct st_sample *buf, int len, struct mixeng_volume *vol) #endif buf += 1; } -#else -(void) buf; -(void) len; -(void) vol; -#endif } diff --git a/configure b/configure index 2d62d12..9923887 100755 --- a/configure +++ b/configure @@ -177,7 +177,6 @@ darwin_user="no" bsd_user="no" guest_base="" uname_release="" -mixemu="no" aix="no" blobs="yes" pkgversion="" @@ -771,8 +770,6 @@ for opt do ;; --enable-nptl) nptl="yes" ;; - --enable-mixemu) mixemu="yes" - ;; --disable-linux-aio) linux_aio="no" ;; --enable-linux-aio) linux_aio="yes" @@ -1031,7 +1028,6 @@ echo " --audio-card-list=LIST set list of emulated audio cards [$audio_card_l echo " Available cards: $audio_possible_cards" echo " --block-drv-whitelist=L set block driver whitelist" echo " (affects only QEMU, not qemu-img)" -echo " --enable-mixemu enable mixer emulation" echo " --disable-xendisable xen backend driver support" echo " --enable-xen enable xen backend driver support" echo " --disable-brlapi disable BrlAPI" @@ -2931,7 +2927,6 @@ echo "mingw32 support $mingw32" echo "Audio drivers $audio_drv_list" echo "Extra audio cards $audio_card_list" echo "Block whitelist $block_drv_whitelist" -echo "Mixer emulation $mixemu" echo "VirtFS support$virtfs" echo "VNC support $vnc" if test "$vnc" = "yes" ; then @@ -3094,9 +3089,6 @@ if test "$audio_win_int" = "yes" ; then echo "CONFIG_AUDIO_WIN_INT=y" >> $config_host_mak fi echo "CONFIG_BDRV_WHITELIST=$block_drv_whitelist" >> $config_host_mak -if test "$mixemu" = "yes" ; then - echo "CONFIG_MIXEMU=y" >> $config_host_mak -fi if test "$vnc" = "yes" ; then echo "CONFIG_VNC=y" >> $config_host_mak fi diff --git a/hw/hda-audio.c b/hw/hda-audio.c index 8995519..75f1402 100644 --- a/hw/hda-audio.c +++ b/hw/hda-audio.c @@ -121,15 +121,11 @@ static void hda_codec_parse_fmt(uint32_t format, struct audsettings *as) #define QEMU_HDA_AMP_NONE(0) #define QEMU_HDA_AMP_STEPS 0x4a -#ifdef CONFIG_MIXEMU #define QEMU_HDA_AMP_CAPS \ (AC_AMPCAP_MUTE | \ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_OFFSET_SHIFT)|\ (QEMU_HDA_AMP_STEPS << AC_AMPCAP_NUM_STEPS_SHIFT) |\ (3 << AC_AMPCAP_STEP_SIZE_SHIFT)) -#else -#define QEMU_HDA_AMP_CAPSQEMU_HDA_AMP_NONE -#endif /* common: audio output widget */ static const desc_param common_params_audio_dac[] = { -- 1.7.10
[Qemu-devel] [PATCH 01/10] audio: add VOICE_VOLUME ctl
Add a new PCM control operation to update the stream volume on the audio backend. The argument given is a SWVoiceOut/SWVoiceIn. v4: - verified other backends didn't fail/assert on this new control they randomly return 0 or -1, but we ignore return value. Signed-off-by: Marc-André Lureau --- audio/audio.c | 12 audio/audio_int.h |1 + 2 files changed, 13 insertions(+) diff --git a/audio/audio.c b/audio/audio.c index 398763f..d76c342 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -2053,17 +2053,29 @@ void AUD_del_capture (CaptureVoiceOut *cap, void *cb_opaque) void AUD_set_volume_out (SWVoiceOut *sw, int mute, uint8_t lvol, uint8_t rvol) { if (sw) { +HWVoiceOut *hw = sw->hw; + sw->vol.mute = mute; sw->vol.l = nominal_volume.l * lvol / 255; sw->vol.r = nominal_volume.r * rvol / 255; + +if (hw->pcm_ops->ctl_out) { +hw->pcm_ops->ctl_out (hw, VOICE_VOLUME, sw); +} } } void AUD_set_volume_in (SWVoiceIn *sw, int mute, uint8_t lvol, uint8_t rvol) { if (sw) { +HWVoiceIn *hw = sw->hw; + sw->vol.mute = mute; sw->vol.l = nominal_volume.l * lvol / 255; sw->vol.r = nominal_volume.r * rvol / 255; + +if (hw->pcm_ops->ctl_in) { +hw->pcm_ops->ctl_in (hw, VOICE_VOLUME, sw); +} } } diff --git a/audio/audio_int.h b/audio/audio_int.h index 2003f8b..117f95e 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -231,6 +231,7 @@ void audio_run (const char *msg); #define VOICE_ENABLE 1 #define VOICE_DISABLE 2 +#define VOICE_VOLUME 3 static inline int audio_ring_dist (int dst, int src, int len) { -- 1.7.10
[Qemu-devel] [PATCH 09/10] Allow controlling volume with PulseAudio backend
Signed-off-by: Marc-André Lureau --- audio/paaudio.c | 99 --- 1 file changed, 94 insertions(+), 5 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index 6f50c1c..e6708d0 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -677,15 +677,103 @@ static void qpa_fini_in (HWVoiceIn *hw) static int qpa_ctl_out (HWVoiceOut *hw, int cmd, ...) { -(void) hw; -(void) cmd; +PAVoiceOut *pa = (PAVoiceOut *) hw; +pa_operation *op; +pa_cvolume v; +paaudio *g = &glob_paaudio; + +pa_cvolume_init (&v); + +switch (cmd) { +case VOICE_VOLUME: +{ +SWVoiceOut *sw; +va_list ap; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceOut *); +va_end (ap); + +v.channels = 2; +v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; +v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; + +pa_threaded_mainloop_lock (g->mainloop); + +op = pa_context_set_sink_input_volume (g->context, +pa_stream_get_index (pa->stream), +&v, NULL, NULL); +if (!op) +qpa_logerr (pa_context_errno (g->context), +"set_sink_input_volume() failed\n"); +else +pa_operation_unref (op); + +op = pa_context_set_sink_input_mute (g->context, +pa_stream_get_index (pa->stream), + sw->vol.mute, NULL, NULL); +if (!op) { +qpa_logerr (pa_context_errno (g->context), +"set_sink_input_mute() failed\n"); +} else { +pa_operation_unref (op); +} + +pa_threaded_mainloop_unlock (g->mainloop); +} +} return 0; } static int qpa_ctl_in (HWVoiceIn *hw, int cmd, ...) { -(void) hw; -(void) cmd; +PAVoiceIn *pa = (PAVoiceIn *) hw; +pa_operation *op; +pa_cvolume v; +paaudio *g = &glob_paaudio; + +pa_cvolume_init (&v); + +switch (cmd) { +case VOICE_VOLUME: +{ +SWVoiceIn *sw; +va_list ap; + +va_start (ap, cmd); +sw = va_arg (ap, SWVoiceIn *); +va_end (ap); + +v.channels = 2; +v.values[0] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.l) / UINT32_MAX; +v.values[1] = ((PA_VOLUME_NORM - PA_VOLUME_MUTED) * sw->vol.r) / UINT32_MAX; + +pa_threaded_mainloop_lock (g->mainloop); + +/* FIXME: use the upcoming "set_source_output_{volume,mute}" */ +op = pa_context_set_source_volume_by_index (g->context, +pa_stream_get_device_index (pa->stream), +&v, NULL, NULL); +if (!op) { +qpa_logerr (pa_context_errno (g->context), +"set_source_volume() failed\n"); +} else { +pa_operation_unref(op); +} + +op = pa_context_set_source_mute_by_index (g->context, +pa_stream_get_index (pa->stream), +sw->vol.mute, NULL, NULL); +if (!op) { +qpa_logerr (pa_context_errno (g->context), +"set_source_mute() failed\n"); +} else { +pa_operation_unref (op); +} + +pa_threaded_mainloop_unlock (g->mainloop); +} +} return 0; } @@ -822,5 +910,6 @@ struct audio_driver pa_audio_driver = { .max_voices_out = INT_MAX, .max_voices_in = INT_MAX, .voice_size_out = sizeof (PAVoiceOut), -.voice_size_in = sizeof (PAVoiceIn) +.voice_size_in = sizeof (PAVoiceIn), +.ctl_caps = VOICE_VOLUME_CAP }; -- 1.7.10
[Qemu-devel] [PATCH 03/10] hw/ac97: remove USE_MIXER code
That code doesn't compile. The interesting bits for volume control are going to be rewritten in the following patch. Signed-off-by: Marc-André Lureau --- hw/ac97.c | 121 - 1 file changed, 121 deletions(-) diff --git a/hw/ac97.c b/hw/ac97.c index c0fd019..f2804e6 100644 --- a/hw/ac97.c +++ b/hw/ac97.c @@ -437,99 +437,6 @@ static void reset_voices (AC97LinkState *s, uint8_t active[LAST_INDEX]) AUD_set_active_in (s->voice_mc, active[MC_INDEX]); } -#ifdef USE_MIXER -static void set_volume (AC97LinkState *s, int index, -audmixerctl_t mt, uint32_t val) -{ -int mute = (val >> MUTE_SHIFT) & 1; -uint8_t rvol = VOL_MASK - (val & VOL_MASK); -uint8_t lvol = VOL_MASK - ((val >> 8) & VOL_MASK); -rvol = 255 * rvol / VOL_MASK; -lvol = 255 * lvol / VOL_MASK; - -#ifdef SOFT_VOLUME -if (index == AC97_Master_Volume_Mute) { -AUD_set_volume_out (s->voice_po, mute, lvol, rvol); -} -else { -AUD_set_volume (mt, &mute, &lvol, &rvol); -} -#else -AUD_set_volume (mt, &mute, &lvol, &rvol); -#endif - -rvol = VOL_MASK - ((VOL_MASK * rvol) / 255); -lvol = VOL_MASK - ((VOL_MASK * lvol) / 255); -mixer_store (s, index, val); -} - -static audrecsource_t ac97_to_aud_record_source (uint8_t i) -{ -switch (i) { -case REC_MIC: -return AUD_REC_MIC; - -case REC_CD: -return AUD_REC_CD; - -case REC_VIDEO: -return AUD_REC_VIDEO; - -case REC_AUX: -return AUD_REC_AUX; - -case REC_LINE_IN: -return AUD_REC_LINE_IN; - -case REC_PHONE: -return AUD_REC_PHONE; - -default: -dolog ("Unknown record source %d, using MIC\n", i); -return AUD_REC_MIC; -} -} - -static uint8_t aud_to_ac97_record_source (audrecsource_t rs) -{ -switch (rs) { -case AUD_REC_MIC: -return REC_MIC; - -case AUD_REC_CD: -return REC_CD; - -case AUD_REC_VIDEO: -return REC_VIDEO; - -case AUD_REC_AUX: -return REC_AUX; - -case AUD_REC_LINE_IN: -return REC_LINE_IN; - -case AUD_REC_PHONE: -return REC_PHONE; - -default: -dolog ("Unknown audio recording source %d using MIC\n", rs); -return REC_MIC; -} -} - -static void record_select (AC97LinkState *s, uint32_t val) -{ -uint8_t rs = val & REC_MASK; -uint8_t ls = (val >> 8) & REC_MASK; -audrecsource_t ars = ac97_to_aud_record_source (rs); -audrecsource_t als = ac97_to_aud_record_source (ls); -AUD_set_record_source (&als, &ars); -rs = aud_to_ac97_record_source (ars); -ls = aud_to_ac97_record_source (als); -mixer_store (s, AC97_Record_Select, rs | (ls << 8)); -} -#endif - static void mixer_reset (AC97LinkState *s) { uint8_t active[LAST_INDEX]; @@ -564,12 +471,6 @@ static void mixer_reset (AC97LinkState *s) mixer_store (s, AC97_PCM_LR_ADC_Rate , 0xbb80); mixer_store (s, AC97_MIC_ADC_Rate, 0xbb80); -#ifdef USE_MIXER -record_select (s, 0); -set_volume (s, AC97_Master_Volume_Mute, AUD_MIXER_VOLUME , 0x8000); -set_volume (s, AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM, 0x8808); -set_volume (s, AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN, 0x8808); -#endif reset_voices (s, active); } @@ -628,20 +529,6 @@ static void nam_writew (void *opaque, uint32_t addr, uint32_t val) val |= mixer_load (s, index) & 0xf; mixer_store (s, index, val); break; -#ifdef USE_MIXER -case AC97_Master_Volume_Mute: -set_volume (s, index, AUD_MIXER_VOLUME, val); -break; -case AC97_PCM_Out_Volume_Mute: -set_volume (s, index, AUD_MIXER_PCM, val); -break; -case AC97_Line_In_Volume_Mute: -set_volume (s, index, AUD_MIXER_LINE_IN, val); -break; -case AC97_Record_Select: -record_select (s, val); -break; -#endif case AC97_Vendor_ID1: case AC97_Vendor_ID2: dolog ("Attempt to write vendor ID to %#x\n", val); @@ -1194,14 +1081,6 @@ static int ac97_post_load (void *opaque, int version_id) uint8_t active[LAST_INDEX]; AC97LinkState *s = opaque; -#ifdef USE_MIXER -record_select (s, mixer_load (s, AC97_Record_Select)); -#define V_(a, b) set_volume (s, a, b, mixer_load (s, a)) -V_ (AC97_Master_Volume_Mute, AUD_MIXER_VOLUME); -V_ (AC97_PCM_Out_Volume_Mute, AUD_MIXER_PCM); -V_ (AC97_Line_In_Volume_Mute, AUD_MIXER_LINE_IN); -#undef V_ -#endif active[PI_INDEX] = !!(s->bm_regs[PI_INDEX].cr & CR_RPBM); active[PO_INDEX] = !!(s->bm_regs[PO_INDEX].cr & CR_RPBM); active[MC_INDEX] = !!(s->bm_regs[MC_INDEX].cr & CR_RPBM); -- 1.7.10
[Qemu-devel] [PATCH 02/10] audio: don't apply volume effect if backend has VOICE_VOLUME_CAP
If the audio backend is capable of volume control, don't apply software volume (mixeng_volume ()), but instead, rely on backend volume control. This will allow guest to have full range volume control. Signed-off-by: Marc-André Lureau --- audio/audio.c |9 +++-- audio/audio_int.h |5 + audio/audio_template.h |2 ++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/audio/audio.c b/audio/audio.c index d76c342..bd9237e 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -957,7 +957,9 @@ int audio_pcm_sw_read (SWVoiceIn *sw, void *buf, int size) total += isamp; } -mixeng_volume (sw->buf, ret, &sw->vol); +if (!(hw->ctl_caps & VOICE_VOLUME_CAP)) { +mixeng_volume (sw->buf, ret, &sw->vol); +} sw->clip (buf, sw->buf, ret); sw->total_hw_samples_acquired += total; @@ -1041,7 +1043,10 @@ int audio_pcm_sw_write (SWVoiceOut *sw, void *buf, int size) swlim = audio_MIN (swlim, samples); if (swlim) { sw->conv (sw->buf, buf, swlim); -mixeng_volume (sw->buf, swlim, &sw->vol); + +if (!(sw->hw->ctl_caps & VOICE_VOLUME_CAP)) { +mixeng_volume (sw->buf, swlim, &sw->vol); +} } while (swlim) { diff --git a/audio/audio_int.h b/audio/audio_int.h index 117f95e..b9b0676 100644 --- a/audio/audio_int.h +++ b/audio/audio_int.h @@ -82,6 +82,7 @@ typedef struct HWVoiceOut { int samples; QLIST_HEAD (sw_out_listhead, SWVoiceOut) sw_head; QLIST_HEAD (sw_cap_listhead, SWVoiceCap) cap_head; +int ctl_caps; struct audio_pcm_ops *pcm_ops; QLIST_ENTRY (HWVoiceOut) entries; } HWVoiceOut; @@ -101,6 +102,7 @@ typedef struct HWVoiceIn { int samples; QLIST_HEAD (sw_in_listhead, SWVoiceIn) sw_head; +int ctl_caps; struct audio_pcm_ops *pcm_ops; QLIST_ENTRY (HWVoiceIn) entries; } HWVoiceIn; @@ -150,6 +152,7 @@ struct audio_driver { int max_voices_in; int voice_size_out; int voice_size_in; +int ctl_caps; }; struct audio_pcm_ops { @@ -233,6 +236,8 @@ void audio_run (const char *msg); #define VOICE_DISABLE 2 #define VOICE_VOLUME 3 +#define VOICE_VOLUME_CAP (1 << VOICE_VOLUME) + static inline int audio_ring_dist (int dst, int src, int len) { return (dst >= src) ? (dst - src) : (len - src + dst); diff --git a/audio/audio_template.h b/audio/audio_template.h index e62a713..519432a 100644 --- a/audio/audio_template.h +++ b/audio/audio_template.h @@ -263,6 +263,8 @@ static HW *glue (audio_pcm_hw_add_new_, TYPE) (struct audsettings *as) } hw->pcm_ops = drv->pcm_ops; +hw->ctl_caps = drv->ctl_caps; + QLIST_INIT (&hw->sw_head); #ifdef DAC QLIST_INIT (&hw->cap_head); -- 1.7.10
[Qemu-devel] [PATCH 07/10] Do not use pa_simple PulseAudio API
Unfortunately, pa_simple is a limited API which doesn't let us retrieve the associated pa_stream. It is needed to control the volume of the stream. In v4: - add missing braces Signed-off-by: Marc-André Lureau --- audio/paaudio.c | 377 +-- 1 file changed, 339 insertions(+), 38 deletions(-) diff --git a/audio/paaudio.c b/audio/paaudio.c index d1f3912..6f50c1c 100644 --- a/audio/paaudio.c +++ b/audio/paaudio.c @@ -2,8 +2,7 @@ #include "qemu-common.h" #include "audio.h" -#include -#include +#include #define AUDIO_CAP "pulseaudio" #include "audio_int.h" @@ -15,7 +14,7 @@ typedef struct { int live; int decr; int rpos; -pa_simple *s; +pa_stream *stream; void *pcm_buf; struct audio_pt pt; } PAVoiceOut; @@ -26,17 +25,23 @@ typedef struct { int dead; int incr; int wpos; -pa_simple *s; +pa_stream *stream; void *pcm_buf; struct audio_pt pt; +const void *read_data; +size_t read_index, read_length; } PAVoiceIn; -static struct { +typedef struct { int samples; char *server; char *sink; char *source; -} conf = { +pa_threaded_mainloop *mainloop; +pa_context *context; +} paaudio; + +static paaudio glob_paaudio = { .samples = 4096, }; @@ -51,6 +56,126 @@ static void GCC_FMT_ATTR (2, 3) qpa_logerr (int err, const char *fmt, ...) AUD_log (AUDIO_CAP, "Reason: %s\n", pa_strerror (err)); } +#define CHECK_SUCCESS_GOTO(c, rerror, expression, label)\ +do {\ +if (!(expression)) {\ +if (rerror) { \ +*(rerror) = pa_context_errno ((c)->context);\ +} \ +goto label; \ +} \ +} while (0); + +#define CHECK_DEAD_GOTO(c, stream, rerror, label) \ +do {\ +if (!(c)->context || !PA_CONTEXT_IS_GOOD (pa_context_get_state((c)->context)) || \ +!(stream) || !PA_STREAM_IS_GOOD (pa_stream_get_state ((stream { \ +if (((c)->context && pa_context_get_state ((c)->context) == PA_CONTEXT_FAILED) || \ +((stream) && pa_stream_get_state ((stream)) == PA_STREAM_FAILED)) { \ +if (rerror) { \ +*(rerror) = pa_context_errno ((c)->context);\ +} \ +} else {\ +if (rerror) { \ +*(rerror) = PA_ERR_BADSTATE;\ +} \ +} \ +goto label; \ +} \ +} while (0); + +static int qpa_simple_read (PAVoiceIn *p, void *data, size_t length, int *rerror) +{ +paaudio *g = &glob_paaudio; + +pa_threaded_mainloop_lock (g->mainloop); + +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); + +while (length > 0) { +size_t l; + +while (!p->read_data) { +int r; + +r = pa_stream_peek (p->stream, &p->read_data, &p->read_length); +CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); + +if (!p->read_data) { +pa_threaded_mainloop_wait (g->mainloop); +CHECK_DEAD_GOTO (g, p->stream, rerror, unlock_and_fail); +} else { +p->read_index = 0; +} +} + +l = p->read_length < length ? p->read_length : length; +memcpy (data, (const uint8_t *) p->read_data+p->read_index, l); + +data = (uint8_t *) data + l; +length -= l; + +p->read_index += l; +p->read_length -= l; + +if (!p->read_length) { +int r; + +r = pa_stream_drop (p->stream); +p->read_data = NULL; +p->read_length = 0; +p->read_index = 0; + +CHECK_SUCCESS_GOTO (g, rerror, r == 0, unlock_and_fail); +} +} + +pa_threaded_mainloop_unlock (g->mainloop); +return 0; + +unlock_and_fail: +pa_threaded_mainloop_unlock (g->mainloop); +return -1; +} + +static int qpa_simple_write (PAVoiceOut *p, const void *data
[Qemu-devel] [PATCH 08/10] configure: pa_simple is not needed anymore
Signed-off-by: Marc-André Lureau --- configure |6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/configure b/configure index 1d94acd..2d62d12 100755 --- a/configure +++ b/configure @@ -1855,9 +1855,9 @@ for drv in $audio_drv_list; do ;; pa) -audio_drv_probe $drv pulse/simple.h "-lpulse-simple -lpulse" \ -"pa_simple *s = 0; pa_simple_free(s); return 0;" -libs_softmmu="-lpulse -lpulse-simple $libs_softmmu" +audio_drv_probe $drv pulse/mainloop.h "-lpulse" \ +"pa_mainloop *m = 0; pa_mainloop_free (m); return 0;" +libs_softmmu="-lpulse $libs_softmmu" audio_pt_int="yes" ;; -- 1.7.10