From 8705af792b0c95ec94822b1727addb54389db674 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 2 Aug 2004 16:24:14 +0000 Subject: add new module "module-x11-bell" fix scache memory leak git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@100 fefdeb5f-60dc-0310-8127-8f9354f1896f --- polyp/Makefile.am | 7 +- polyp/idxset.c | 16 ++--- polyp/module-x11-bell.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++ polyp/protocol-esound.c | 2 +- polyp/scache.c | 13 +++- polyp/sink-input.c | 4 +- 6 files changed, 204 insertions(+), 15 deletions(-) create mode 100644 polyp/module-x11-bell.c diff --git a/polyp/Makefile.am b/polyp/Makefile.am index d1615585..abe1d074 100644 --- a/polyp/Makefile.am +++ b/polyp/Makefile.am @@ -65,7 +65,8 @@ pkglib_LTLIBRARIES=libiochannel.la \ module-esound-protocol-tcp.la \ module-esound-protocol-unix.la \ module-native-protocol-tcp.la \ - module-native-protocol-unix.la + module-native-protocol-unix.la \ + module-x11-bell.la lib_LTLIBRARIES=libpolyp.la \ libpolyp-simple.la \ @@ -247,6 +248,10 @@ module_cli_la_SOURCES = module-cli.c module_cli_la_LDFLAGS = -module -avoid-version module_cli_la_LIBADD = $(AM_LIBADD) libcli.la libiochannel.la +module_x11_bell_la_SOURCES = module-x11-bell.c +module_x11_bell_la_LDFLAGS = -module -avoid-version +module_x11_bell_la_LIBADD = $(AM_LIBADD) -lX11 -L/usr/X11R6/lib + libpolyp_la_SOURCES = polyplib.c polyplib.h \ polyplib-def.h \ tagstruct.c tagstruct.h \ diff --git a/polyp/idxset.c b/polyp/idxset.c index cecda6b7..0072e3cd 100644 --- a/polyp/idxset.c +++ b/polyp/idxset.c @@ -95,15 +95,13 @@ struct pa_idxset* pa_idxset_new(unsigned (*hash_func) (const void *p), int (*com void pa_idxset_free(struct pa_idxset *s, void (*free_func) (void *p, void *userdata), void *userdata) { assert(s); - if (free_func) { - while (s->iterate_list_head) { - struct idxset_entry *e = s->iterate_list_head; - s->iterate_list_head = s->iterate_list_head->iterate_next; - - if (free_func) - free_func(e->data, userdata); - free(e); - } + while (s->iterate_list_head) { + struct idxset_entry *e = s->iterate_list_head; + s->iterate_list_head = s->iterate_list_head->iterate_next; + + if (free_func) + free_func(e->data, userdata); + free(e); } free(s->hash_table); diff --git a/polyp/module-x11-bell.c b/polyp/module-x11-bell.c new file mode 100644 index 00000000..29663134 --- /dev/null +++ b/polyp/module-x11-bell.c @@ -0,0 +1,177 @@ +#include +#include +#include +#include + +#include +#include + +#include "module.h" +#include "sink.h" +#include "scache.h" +#include "modargs.h" + +struct x11_source { + void *io_source; + struct x11_source *next; +}; + +struct userdata { + struct pa_core *core; + Display *display; + struct x11_source *x11_sources; + int xkb_event_base; + + int sink_index; + char *scache_item; +}; + +static const char* const valid_modargs[] = { + "sink", + "sample", + "display", + NULL +}; + +static struct pa_sink* get_output_sink(struct userdata *u) { + struct pa_sink *s; + assert(u); + + if (!(s = pa_idxset_get_by_index(u->core->sinks, u->sink_index))) + s = pa_sink_get_default(u->core); + + u->sink_index = s ? s->index : PA_IDXSET_INVALID; + return s; +} + +static int ring_bell(struct userdata *u, int percent) { + struct pa_sink *s; + assert(u); + + if (!(s = get_output_sink(u))) { + fprintf(stderr, __FILE__": Invalid sink\n"); + return -1; + } + + if (pa_scache_play_item(u->core, u->scache_item, s, percent*2) < 0) { + fprintf(stderr, __FILE__": Failed to play sample\n"); + return -1; + } + + return 0; +} + +static void io_callback(struct pa_mainloop_api*a, void *id, int fd, enum pa_mainloop_api_io_events events, void *userdata) { + struct userdata *u = userdata; + assert(u); + + while (XPending(u->display)) { + XEvent e; + XkbBellNotifyEvent *bne; + XNextEvent(u->display, &e); + + if (((XkbEvent*) &e)->any.xkb_type != XkbBellNotify) + continue; + + bne = ((XkbBellNotifyEvent*) &e); + + if (ring_bell(u, bne->percent) < 0) { + fprintf(stderr, __FILE__": Ringing bell failed, reverting to X11 device bell.\n"); + XkbForceDeviceBell(u->display, bne->device, bne->bell_class, bne->bell_id, bne->percent); + } + } +} + +static void new_io_source(struct userdata *u, int fd) { + struct x11_source *s; + + s = malloc(sizeof(struct x11_source)); + assert(s); + s->io_source = u->core->mainloop->source_io(u->core->mainloop, fd, PA_MAINLOOP_API_IO_EVENT_INPUT, io_callback, u); + assert(s->io_source); + s->next = u->x11_sources; + u->x11_sources = s; +} + +int pa_module_init(struct pa_core *c, struct pa_module*m) { + struct userdata *u = NULL; + struct pa_modargs *ma = NULL; + int major, minor; + unsigned int auto_ctrls, auto_values; + assert(c && m); + + if (!(ma = pa_modargs_new(m->argument, valid_modargs))) { + fprintf(stderr, __FILE__": failed to parse module arguments\n"); + goto fail; + } + + m->userdata = u = malloc(sizeof(struct userdata)); + assert(u); + u->core = c; + u->display = NULL; + u->x11_sources = NULL; + u->scache_item = strdup(pa_modargs_get_value(ma, "sample", "bell")); + assert(u->scache_item); + + if (pa_modargs_get_sink_index(ma, c, &u->sink_index) < 0) { + fprintf(stderr, __FILE__": Invalid sink specified\n"); + goto fail; + } + + if (!(u->display = XOpenDisplay(pa_modargs_get_value(ma, "display", NULL)))) { + fprintf(stderr, __FILE__": XOpenDisplay() failed\n"); + goto fail; + } + + new_io_source(u, ConnectionNumber(u->display)); + + major = XkbMajorVersion; + minor = XkbMinorVersion; + + if (!XkbLibraryVersion(&major, &minor)) { + fprintf(stderr, __FILE__": XkbLibraryVersion() failed\n"); + goto fail; + } + + major = XkbMajorVersion; + minor = XkbMinorVersion; + + if (!XkbQueryExtension(u->display, NULL, &u->xkb_event_base, NULL, &major, &minor)) { + fprintf(stderr, __FILE__": XkbQueryExtension() failed\n"); + goto fail; + } + + XkbSelectEvents(u->display, XkbUseCoreKbd, XkbBellNotifyMask, XkbBellNotifyMask); + auto_ctrls = auto_values = XkbAudibleBellMask; + XkbSetAutoResetControls(u->display, XkbAudibleBellMask, &auto_ctrls, &auto_values); + XkbChangeEnabledControls(u->display, XkbUseCoreKbd, XkbAudibleBellMask, 0); + + pa_modargs_free(ma); + + return 0; + +fail: + if (ma) + pa_modargs_free(ma); + if (m->userdata) + pa_module_done(c, m); + return -1; +} + +void pa_module_done(struct pa_core *c, struct pa_module*m) { + struct userdata *u = m->userdata; + assert(c && m && u); + + while (u->x11_sources) { + struct x11_source *s = u->x11_sources; + u->x11_sources = u->x11_sources->next; + c->mainloop->cancel_io(c->mainloop, s->io_source); + free(s); + } + + free(u->scache_item); + + if (u->display) + XCloseDisplay(u->display); + free(u); +} diff --git a/polyp/protocol-esound.c b/polyp/protocol-esound.c index 91e6b7d6..7a141d3a 100644 --- a/polyp/protocol-esound.c +++ b/polyp/protocol-esound.c @@ -202,7 +202,7 @@ static struct pa_sink* get_output_sink(struct pa_protocol_esound *p) { p->sink_index = s ? s->index : PA_IDXSET_INVALID; return s; } - + static struct pa_source* get_input_source(struct pa_protocol_esound *p) { struct pa_source *s; assert(p); diff --git a/polyp/scache.c b/polyp/scache.c index d2a84827..c1505046 100644 --- a/polyp/scache.c +++ b/polyp/scache.c @@ -1,9 +1,11 @@ #include #include #include +#include #include "scache.h" #include "sink-input.h" +#include "mainloop.h" static void free_entry(struct pa_scache_entry *e) { assert(e); @@ -70,7 +72,8 @@ int pa_scache_remove_item(struct pa_core *c, const char *name) { return -1; pa_hashmap_remove(c->scache_hashmap, name); - pa_idxset_remove_by_index(c->scache_idxset, e->index); + if (pa_idxset_remove_by_data(c->scache_idxset, e, NULL) != e) + assert(0); free_entry(e); return 0; } @@ -113,10 +116,14 @@ static int sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { assert(c->length && c->memblock && c->memblock->length); *chunk = *c; pa_memblock_ref(c->memblock); - + return 0; } +static void si_kill(void *i) { + sink_input_kill(i); +} + static void sink_input_drop(struct pa_sink_input *i, size_t length) { struct pa_memchunk *c; assert(i && length && i->userdata); @@ -128,7 +135,7 @@ static void sink_input_drop(struct pa_sink_input *i, size_t length) { c->index += length; if (c->length <= 0) - sink_input_kill(i); + pa_mainloop_api_once(i->sink->core->mainloop, si_kill, i); } int pa_scache_play_item(struct pa_core *c, const char *name, struct pa_sink *sink, uint32_t volume) { diff --git a/polyp/sink-input.c b/polyp/sink-input.c index 5c2d3a13..25d8022f 100644 --- a/polyp/sink-input.c +++ b/polyp/sink-input.c @@ -126,12 +126,14 @@ int pa_sink_input_peek(struct pa_sink_input *i, struct pa_memchunk *chunk) { if ((ret = i->peek(i, &tchunk)) < 0) return ret; + assert(tchunk.length); + l = pa_resampler_request(i->resampler, CONVERT_BUFFER_LENGTH); if (tchunk.length > l) tchunk.length = l; i->drop(i, tchunk.length); - + pa_resampler_run(i->resampler, &tchunk, &i->resampled_chunk); pa_memblock_unref(tchunk.memblock); } -- cgit