summaryrefslogtreecommitdiffstats
path: root/polyp
diff options
context:
space:
mode:
Diffstat (limited to 'polyp')
-rw-r--r--polyp/Makefile.am7
-rw-r--r--polyp/idxset.c16
-rw-r--r--polyp/module-x11-bell.c177
-rw-r--r--polyp/protocol-esound.c2
-rw-r--r--polyp/scache.c13
-rw-r--r--polyp/sink-input.c4
6 files changed, 204 insertions, 15 deletions
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 <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);
+}
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 <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) {
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);
}