]> code.delx.au - pulseaudio/commitdiff
add new module "module-x11-bell"
authorLennart Poettering <lennart@poettering.net>
Mon, 2 Aug 2004 16:24:14 +0000 (16:24 +0000)
committerLennart Poettering <lennart@poettering.net>
Mon, 2 Aug 2004 16:24:14 +0000 (16:24 +0000)
fix scache memory leak

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@100 fefdeb5f-60dc-0310-8127-8f9354f1896f

polyp/Makefile.am
polyp/idxset.c
polyp/module-x11-bell.c [new file with mode: 0644]
polyp/protocol-esound.c
polyp/scache.c
polyp/sink-input.c

index d16155857e8bdf3effec053e1325a6656c11659c..abe1d0747225e788aec88e566f9366d847f1d6a9 100644 (file)
@@ -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 \
index cecda6b7c516f21d9b11f72d887b3b4bc8489856..0072e3cd365a21e901ea6b473130bee58a617272 100644 (file)
@@ -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 (file)
index 0000000..2966313
--- /dev/null
@@ -0,0 +1,177 @@
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <X11/Xlib.h>
+#include <X11/XKBlib.h>
+
+#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);
+}
index 91e6b7d68053db96aa39982c76f6c433a8be9e2c..7a141d3a1b96be900823d58b15df35ed4368493c 100644 (file)
@@ -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);
index d2a84827c06713115c37fe088beab8e4c5e4dad9..c1505046da7ede4549508a6c6ccf08e19bd47fa8 100644 (file)
@@ -1,9 +1,11 @@
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdio.h>
 
 #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) {
index 5c2d3a13941eec8447464611caa4f53df8abb239..25d8022f359e32110bb96e68136841f6ae14f43b 100644 (file)
@@ -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);
     }