summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2008-06-06 12:17:58 +0000
committerLennart Poettering <lennart@poettering.net>2008-06-06 12:17:58 +0000
commit617c912e950d582c5690e558b28fa1070f9b8263 (patch)
treee0c2ef90b6fcd291f3466a2c703d07b208981d06
parent0cc6ddf46d77f0f8c657588b8373e1e87512d578 (diff)
unify double inclusion defines src/sound-theme-spec.h src/read-wav.h src/read-vorbis.h src/proplist.h src/mutex.h src/llist.h src/common.h
git-svn-id: file:///home/lennart/svn/public/libcanberra/trunk@52 01b60673-d06a-42c0-afdd-89cb8e0f78ac
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac54
-rw-r--r--src/Makefile.am18
-rw-r--r--src/alsa.c493
-rw-r--r--src/canberra-gtk-module.c101
-rw-r--r--src/common.c24
-rw-r--r--src/common.h4
-rw-r--r--src/dso.c8
-rw-r--r--src/llist.h4
-rw-r--r--src/mutex.h4
-rw-r--r--src/null.c82
-rw-r--r--src/proplist.h4
-rw-r--r--src/pulse.c1
-rw-r--r--src/read-sound-file.c10
-rw-r--r--src/read-sound-file.h6
-rw-r--r--src/read-vorbis.h4
-rw-r--r--src/read-wav.h4
-rw-r--r--src/sound-theme-spec.h4
18 files changed, 769 insertions, 60 deletions
diff --git a/Makefile.am b/Makefile.am
index 2cb96a6..0c85fe2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -26,3 +26,7 @@ noinst_DATA =
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libcanberra.pc
+
+if HAVE_GTK
+pkgconfig_DATA += libcanberra-gtk.pc
+endif
diff --git a/configure.ac b/configure.ac
index 707179e..0e7f310 100644
--- a/configure.ac
+++ b/configure.ac
@@ -258,6 +258,26 @@ fi
AC_SUBST(PULSE_CFLAGS)
AC_SUBST(PULSE_LIBS)
+### Null output (optional) ####
+
+AC_ARG_ENABLE([null],
+ AC_HELP_STRING([--disable-null], [Disable optional null output]),
+ [
+ case "${enableval}" in
+ yes) null=yes ;;
+ no) null=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for --disable-null) ;;
+ esac
+ ],
+ [null=yes])
+
+if test "x${null}" != xno ; then
+ HAVE_NULL=1
+ AC_DEFINE([HAVE_NULL], 1, [Have NULL output?])
+else
+ HAVE_NULL=0
+fi
+
### GTK (optional) ####
AC_ARG_ENABLE([gtk],
@@ -302,7 +322,7 @@ PKG_CHECK_MODULES(VORBIS, [ vorbisfile ])
### Chose builtin driver ###
- AC_ARG_WITH([builtin],
+AC_ARG_WITH([builtin],
[AS_HELP_STRING([--with-builtin], [Choose builtin driver])],
[],
[with_builtin=dso])
@@ -311,6 +331,7 @@ HAVE_DSO=0
BUILTIN_DSO=0
BUILTIN_PULSE=0
BUILTIN_ALSA=0
+BUILTIN_NULL=0
case "x$with_builtin" in
xpulse)
@@ -320,6 +341,7 @@ case "x$with_builtin" in
BUILTIN_PULSE=1
HAVE_ALSA=0
+ HAVE_NULL=0
;;
xalsa)
@@ -329,6 +351,17 @@ case "x$with_builtin" in
BUILTIN_ALSA=1
HAVE_PULSE=0
+ HAVE_NULL=0
+ ;;
+
+ xnull)
+ if test "x$HAVE_NULL" != x1 ; then
+ AC_MSG_ERROR([*** Null output selected for builtin driver, but not enabled. ***])
+ fi
+
+ BUILTIN_NULL=1
+ HAVE_PULSE=0
+ HAVE_ALSA=0
;;
xdso)
@@ -341,21 +374,25 @@ case "x$with_builtin" in
AC_MSG_ERROR([*** Unknown driver $with_builtin selected for builtin ***])
esac
-if test "x$HAVE_PULSE" != x1 -a "x$HAVE_ALSA" != x1 ; then
+if test "x$HAVE_PULSE" != x1 -a "x$HAVE_ALSA" != x1 -a "x$HAVE_NULL" != x1 ; then
AC_MSG_ERROR([*** No backend enabled. ***])
fi
AC_SUBST(HAVE_DSO)
AC_SUBST(HAVE_PULSE)
AC_SUBST(HAVE_ALSA)
+AC_SUBST(HAVE_NULL)
AC_SUBST(BUILTIN_DSO)
-AC_SUBST(BUILTIN_ALSA)
AC_SUBST(BUILTIN_PULSE)
+AC_SUBST(BUILTIN_ALSA)
+AC_SUBST(BUILTIN_NULL)
AM_CONDITIONAL([HAVE_PULSE], [test "x$HAVE_PULSE" = x1])
AM_CONDITIONAL([HAVE_ALSA], [test "x$HAVE_ALSA" = x1])
+AM_CONDITIONAL([HAVE_NULL], [test "x$HAVE_NULL" = x1])
AM_CONDITIONAL([BUILTIN_DSO], [test "x$BUILTIN_DSO" = x1])
AM_CONDITIONAL([BUILTIN_PULSE], [test "x$BUILTIN_PULSE" = x1])
AM_CONDITIONAL([BUILTIN_ALSA], [test "x$BUILTIN_ALSA" = x1])
+AM_CONDITIONAL([BUILTIN_NULL], [test "x$BUILTIN_NULL" = x1])
###################################
# Output #
@@ -393,6 +430,15 @@ if test "x$BUILTIN_ALSA" = "x1" ; then
ENABLE_BUILTIN_ALSA=yes
fi
+ENABLE_NULL=no
+if test "x$HAVE_NULL" = "x1" ; then
+ ENABLE_NULL=yes
+fi
+ENABLE_BUILTIN_NULL=no
+if test "x$BUILTIN_NULL" = "x1" ; then
+ ENABLE_BUILTIN_NULL=yes
+fi
+
ENABLE_GTK=no
if test "x$HAVE_GTK" = "x1" ; then
ENABLE_GTK=yes
@@ -413,6 +459,8 @@ echo "
Builtin PulseAudio: ${ENABLE_BUILTIN_PULSE}
Enable ALSA: ${ENABLE_ALSA}
Builtin ALSA: ${ENABLE_BUILTIN_ALSA}
+ Enable Null Output: ${ENABLE_NULL}
+ Builtin Null Output: ${ENABLE_BUILTIN_NULL}
Enable GTK+: ${ENABLE_GTK}
GTK Modules Directory: ${GTK_MODULES_DIR}
"
diff --git a/src/Makefile.am b/src/Makefile.am
index 393f0b8..ea17f5d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -89,7 +89,7 @@ else
lib_LTLIBRARIES += \
libcanberra-alsa.la
-libcanberra_alsa_la_SOURCE = \
+libcanberra_alsa_la_SOURCES = \
alsa.c
libcanberra_alsa_la_CFLAGS = \
$(ALSA_CFLAGS)
@@ -99,6 +99,22 @@ libcanberra_alsa_la_LIBADD = \
endif
endif
+if HAVE_NULL
+if BUILTIN_NULL
+
+libcanberra_la_SOURCES += \
+ null.c
+
+else
+
+lib_LTLIBRARIES += \
+ libcanberra-null.la
+
+libcanberra_null_la_SOURCES = \
+ null.c
+endif
+endif
+
if BUILTIN_DSO
libcanberra_la_SOURCES += \
diff --git a/src/alsa.c b/src/alsa.c
new file mode 100644
index 0000000..0eb7aa3
--- /dev/null
+++ b/src/alsa.c
@@ -0,0 +1,493 @@
+/* $Id$ */
+
+/***
+ This file is part of libcanberra.
+
+ Copyright 2008 Lennart Poettering
+
+ libcanberra is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 2.1 of the
+ License, or (at your option) any later version.
+
+ libcanberra is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with libcanberra. If not, If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <alsa/asoundlib.h>
+
+#include "canberra.h"
+#include "common.h"
+#include "driver.h"
+#include "llist.h"
+#include "read-sound-file.h"
+#include "sound-theme-spec.h"
+#include "malloc.h"
+
+struct private;
+
+struct outstanding {
+ CA_LLIST_FIELDS(struct outstanding);
+ ca_bool_t dead;
+ uint32_t id;
+ ca_finish_callback_t callback;
+ void *userdata;
+ ca_sound_file *file;
+ snd_pcm_t *pcm;
+ int pipe_fd[2];
+ ca_context *context;
+};
+
+struct private {
+ ca_theme_data *theme;
+ ca_mutex *outstanding_mutex;
+ ca_bool_t signal_semaphore;
+ sem_t semaphore;
+ ca_bool_t semaphore_allocated;
+ CA_LLIST_HEAD(struct outstanding, outstanding);
+};
+
+#define PRIVATE(c) ((struct private *) ((c)->private))
+
+static void outstanding_free(struct outstanding *o) {
+ ca_assert(o);
+
+ if (o->pipe_fd[1] >= 0)
+ close(o->pipe_fd[1]);
+
+ if (o->pipe_fd[0] >= 0)
+ close(o->pipe_fd[0]);
+
+ if (o->file)
+ ca_sound_file_close(o->file);
+
+ if (o->pcm)
+ snd_pcm_close(o->pcm);
+
+ ca_free(o);
+}
+
+int driver_open(ca_context *c) {
+ struct private *p;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(!c->driver || streq(c->driver, "alsa"), CA_ERROR_NODRIVER);
+ ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE);
+
+ if (!(c->private = p = ca_new0(struct private, 1)))
+ return CA_ERROR_OOM;
+
+ if (!(p->outstanding_mutex = ca_mutex_new())) {
+ driver_destroy(c);
+ return CA_ERROR_OOM;
+ }
+
+ if (sem_init(&p->semaphore, 0, 0) < 0) {
+ driver_destroy(c);
+ return CA_ERROR_OOM;
+ }
+
+ p->semaphore_allocated = TRUE;
+
+ return CA_SUCCESS;
+}
+
+int driver_destroy(ca_context *c) {
+ struct private *p;
+ struct outstanding *out;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(c->private, CA_ERROR_STATE);
+
+ p = PRIVATE(c);
+
+ if (p->outstanding_mutex) {
+ ca_mutex_lock(p->outstanding_mutex);
+
+ /* Tell all player threads to terminate */
+ for (out = p->outstanding; out; out = out->next) {
+
+ out->dead = TRUE;
+
+ if (out->callback)
+ out->callback(c, out->id, CA_ERROR_DESTROYED, out->userdata);
+
+ /* This will cause the thread to wakeup and terminate */
+ if (out->pipe_fd[1] >= 0) {
+ close(out->pipe_fd[1]);
+ out->pipe_fd[1] = -1;
+ }
+ }
+
+ if (p->semaphore_allocated) {
+ /* Now wait until all players are destroyed */
+ p->signal_semaphore = TRUE;
+ while (p->outstanding) {
+ ca_mutex_unlock(p->outstanding_mutex);
+ sem_wait(&p->semaphore);
+ ca_mutex_lock(p->outstanding_mutex);
+ }
+ }
+
+ ca_mutex_unlock(p->outstanding_mutex);
+ ca_mutex_free(p->outstanding_mutex);
+ }
+
+ if (p->theme)
+ ca_theme_data_free(p->theme);
+
+ if (p->semaphore_allocated)
+ sem_destroy(&p->semaphore);
+
+ ca_free(p);
+
+ c->private = NULL;
+
+ return CA_SUCCESS;
+}
+
+int driver_change_device(ca_context *c, char *device) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(c->private, CA_ERROR_STATE);
+
+ return CA_SUCCESS;
+}
+
+int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(changed, CA_ERROR_INVALID);
+ ca_return_val_if_fail(merged, CA_ERROR_INVALID);
+
+ return CA_SUCCESS;
+}
+
+int driver_cache(ca_context *c, ca_proplist *proplist) {
+ return CA_ERROR_NOTSUPPORTED;
+}
+
+static int translate_error(int error) {
+
+ switch (error) {
+ case -ENODEV:
+ case -ENOENT:
+ return CA_ERROR_NOTFOUND;
+ case -EACCES:
+ case -EPERM:
+ return CA_ERROR_ACCESS;
+ case -ENOMEM:
+ return CA_ERROR_OOM;
+ case -EBUSY:
+ return CA_ERROR_NOTAVAILABLE;
+ default:
+ return CA_ERROR_IO;
+ }
+}
+
+static const snd_pcm_format_t sample_type_table[] = {
+#ifdef WORDS_BIGENDIAN
+ [CA_SAMPLE_S16NE] = SND_PCM_FORMAT_S16_BE,
+ [CA_SAMPLE_S16RE] = SND_PCM_FORMAT_S16_LE,
+#else
+ [CA_SAMPLE_S16NE] = SND_PCM_FORMAT_S16_LE,
+ [CA_SAMPLE_S16RE] = SND_PCM_FORMAT_S16_BE,
+#endif
+ [CA_SAMPLE_U8] = SND_PCM_FORMAT_U8
+};
+
+static int open_alsa(ca_context *c, struct outstanding *out) {
+ struct private *p;
+ int ret;
+ snd_pcm_hw_params_t *hwparams;
+ unsigned rate;
+
+ snd_pcm_hw_params_alloca(&hwparams);
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(c->private, CA_ERROR_STATE);
+ ca_return_val_if_fail(out, CA_ERROR_INVALID);
+
+ p = PRIVATE(c);
+
+ if ((ret = snd_pcm_open(&out->pcm, c->device ? c->device : "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0)
+ goto finish;
+
+ if ((ret = snd_pcm_hw_params_any(out->pcm, hwparams)) < 0)
+ goto finish;
+
+ if ((ret = snd_pcm_hw_params_set_access(out->pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
+ goto finish;
+
+ if ((ret = snd_pcm_hw_params_set_format(out->pcm, hwparams, sample_type_table[ca_sound_file_get_sample_type(out->file)])) < 0)
+ goto finish;
+
+ rate = ca_sound_file_get_rate(out->file);
+ if ((ret = snd_pcm_hw_params_set_rate_near(out->pcm, hwparams, &rate, 0)) < 0)
+ goto finish;
+
+ if ((ret = snd_pcm_hw_params_set_channels(out->pcm, hwparams, ca_sound_file_get_nchannels(out->file))) < 0)
+ goto finish;
+
+ if ((ret = snd_pcm_hw_params(out->pcm, hwparams)) < 0)
+ goto finish;
+
+ if ((ret = snd_pcm_prepare(out->pcm)) < 0)
+ goto finish;
+
+ return CA_SUCCESS;
+
+finish:
+
+ return translate_error(ret);
+}
+
+#define BUFSIZE (16*1024)
+
+static void* thread_func(void *userdata) {
+ struct outstanding *out = userdata;
+ int ret;
+ void *data, *d = NULL;
+ size_t fs, data_size;
+ size_t nbytes = 0;
+ struct pollfd *pfd = NULL;
+ nfds_t n_pfd;
+ struct private *p;
+
+ p = PRIVATE(out->context);
+
+ pthread_detach(pthread_self());
+
+ data_size = (BUFSIZE/fs)*fs;
+
+ if (!(data = ca_malloc(data_size))) {
+ ret = CA_ERROR_OOM;
+ goto finish;
+ }
+
+ fs = ca_sound_file_frame_size(out->file);
+
+ if ((ret = snd_pcm_poll_descriptors_count(out->pcm)) < 0) {
+ ret = translate_error(ret);
+ goto finish;
+ }
+
+ n_pfd = ret + 1;
+ if (!(pfd = ca_new(struct pollfd, n_pfd))) {
+ ret = CA_ERROR_OOM;
+ goto finish;
+ }
+
+ if ((ret = snd_pcm_poll_descriptors(out->pcm, pfd+1, n_pfd-1)) < 0) {
+ ret = translate_error(ret);
+ goto finish;
+ }
+
+ pfd[0].fd = out->pipe_fd[0];
+ pfd[0].events = POLLIN;
+ pfd[0].revents = 0;
+
+ for (;;) {
+ unsigned short revents;
+
+ if (out->dead)
+ break;
+
+ if (poll(pfd, n_pfd, -1) < 0) {
+ ret = CA_ERROR_SYSTEM;
+ goto finish;
+ }
+
+ /* We have been asked to shut down */
+ if (pfd[0].revents)
+ break;
+
+ if ((ret = snd_pcm_poll_descriptors_revents(out->pcm, pfd, n_pfd, &revents)) < 0) {
+ ret = translate_error(ret);
+ goto finish;
+ }
+
+ if (revents != POLLOUT) {
+
+ switch (snd_pcm_state(out->pcm)) {
+
+ case SND_PCM_STATE_XRUN:
+
+ if ((ret = snd_pcm_recover(out->pcm, -EPIPE, 1)) != 0) {
+ ret = translate_error(ret);
+ goto finish;
+ }
+ break;
+
+ case SND_PCM_STATE_SUSPENDED:
+
+ if ((ret = snd_pcm_recover(out->pcm, -ESTRPIPE, 1)) != 0) {
+ ret = translate_error(ret);
+ goto finish;
+ }
+ break;
+
+ default:
+
+ snd_pcm_drop(out->pcm);
+
+ if ((ret = snd_pcm_prepare(out->pcm)) < 0) {
+ ret = translate_error(ret);
+ goto finish;
+ }
+ break;
+ }
+
+ continue;
+ }
+
+ if (nbytes <= 0) {
+
+ nbytes = data_size;
+
+ if ((ret = ca_sound_file_read_arbitrary(out->file, data, &nbytes)) < 0)
+ goto finish;
+
+ d = data;
+ }
+
+ if (nbytes <= 0) {
+ snd_pcm_drain(out->pcm);
+ break;
+ }
+
+ if ((ret = snd_pcm_writei(out->pcm, d, nbytes/fs)) < 0) {
+
+ if ((ret = snd_pcm_recover(out->pcm, ret, 1)) < 0) {
+ ret = translate_error(ret);
+ goto finish;
+ }
+
+ continue;
+ }
+
+ nbytes -= ret*fs;
+ d = (uint8_t*) d + ret*fs;
+ }
+
+ ret = CA_SUCCESS;
+
+finish:
+
+ ca_free(data);
+ ca_free(pfd);
+
+ if (!out->dead) {
+ if (out->callback)
+ out->callback(out->context, out->id, ret, out->userdata);
+ }
+
+ ca_mutex_lock(p->outstanding_mutex);
+
+ CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
+
+ if (!p->outstanding && p->signal_semaphore)
+ sem_post(&p->semaphore);
+
+ ca_mutex_unlock(p->outstanding_mutex);
+
+ outstanding_free(out);
+
+ return NULL;
+}
+
+int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) {
+ struct private *p;
+ struct outstanding *out = NULL;
+ int ret;
+ pthread_t thread;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
+ ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
+ ca_return_val_if_fail(c->private, CA_ERROR_STATE);
+
+ p = PRIVATE(c);
+
+ if (!(out = ca_new0(struct outstanding, 1))) {
+ ret = CA_ERROR_OOM;
+ goto finish;
+ }
+
+ out->context = c;
+ out->id = id;
+ out->callback = cb;
+ out->userdata = userdata;
+ out->pipe_fd[0] = out->pipe_fd[1] = -1;
+
+ if ((ret = ca_lookup_sound(&out->file, &p->theme, c->props, proplist)) < 0)
+ goto finish;
+
+ if ((ret = open_alsa(c, out)) < 0)
+ goto finish;
+
+ if (pthread_create(&thread, NULL, thread_func, out) < 0) {
+ ret = CA_ERROR_OOM;
+ goto finish;
+ }
+
+ ret = CA_SUCCESS;
+
+finish:
+
+ /* We keep the outstanding struct around if we need clean up later to */
+ if (ret == CA_SUCCESS) {
+ ca_mutex_lock(p->outstanding_mutex);
+ CA_LLIST_PREPEND(struct outstanding, p->outstanding, out);
+ ca_mutex_unlock(p->outstanding_mutex);
+ } else
+ outstanding_free(out);
+
+ return ret;
+}
+
+int driver_cancel(ca_context *c, uint32_t id) {
+ struct private *p;
+ struct outstanding *out;
+
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(c->private, CA_ERROR_STATE);
+
+ p = PRIVATE(c);
+
+ ca_mutex_lock(p->outstanding_mutex);
+
+ for (out = p->outstanding; out; out = out->next) {
+
+ if (out->id != id)
+ continue;
+
+ out->dead = TRUE;
+
+ if (out->callback)
+ out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata);
+
+ /* This will cause the thread to wakeup and terminate */
+ if (out->pipe_fd[1] >= 0) {
+ close(out->pipe_fd[1]);
+ out->pipe_fd[1] = -1;
+ }
+ }
+
+ ca_mutex_unlock(p->outstanding_mutex);
+
+ return CA_SUCCESS;
+}
diff --git a/src/canberra-gtk-module.c b/src/canberra-gtk-module.c
index 693e33b..2efe957 100644
--- a/src/canberra-gtk-module.c
+++ b/src/canberra-gtk-module.c
@@ -36,6 +36,10 @@ typedef struct {
GdkEvent *event;
} SoundEventData;
+static GQueue sound_event_queue = G_QUEUE_INIT;
+
+static int idle_id = 0;
+
static guint
signal_id_dialog_response,
signal_id_widget_show,
@@ -116,7 +120,7 @@ static GtkDialog* find_parent_dialog(GtkWidget *w) {
return NULL;
}
-static void destroy_cb(SoundEventData *d) {
+static void free_sound_event(SoundEventData *d) {
g_object_unref(d->object);
@@ -126,24 +130,28 @@ static void destroy_cb(SoundEventData *d) {
if (d->event)
gdk_event_free(d->event);
- g_slice_free(d, sizeof(SoundEventData));
+ g_slice_free(SoundEventData, d);
}
-static gboolean idle_cb(SoundEventData *d) {
- int ret = CA_SUCCESS;
+static void filter_sound_events(SoundEventData *d) {
- idle_id = 0;
+
+
+}
+
+static void dispatch_sound_event(SoundEventData *d) {
+ int ret = CA_SUCCESS;
if (!GTK_WIDGET_DRAWABLE(d->object))
- return FALSE;
+ return;
if (g_object_get_qdata(d->object, disable_sound_quark))
- return FALSE;
+ return;
if (d->signal_id == signal_id_widget_show) {
gboolean played_sound = FALSE;
- /* Show signals for non-dialogs have already been filtered out
+ /* Show signals for non-windows have already been filtered out
* by the emission hook! */
if (GTK_IS_MESSAGE_DIALOG(d->object)) {
@@ -161,10 +169,46 @@ static gboolean idle_cb(SoundEventData *d) {
played_sound = TRUE;
}
- } else {
+ } else if (GTK_IS_MENU(gtk_bin_get_child(GTK_BIN(d->object)))) {
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
+ CA_PROP_EVENT_ID, "menu-popup",
+ CA_PROP_EVENT_DESCRIPTION, "Menu popped up",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ played_sound = TRUE;
}
+ if (!played_sound)
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
+ CA_PROP_EVENT_ID, "window-new",
+ CA_PROP_EVENT_DESCRIPTION, "Window shown",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
+
+ if (d->signal_id == signal_id_widget_hide) {
+ gboolean played_sound = FALSE;
+
+ if (GTK_IS_MENU(gtk_bin_get_child(GTK_BIN(d->object)))) {
+
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
+ CA_PROP_EVENT_ID, "menu-popdown",
+ CA_PROP_EVENT_DESCRIPTION, "Menu popped up",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+
+ played_sound = TRUE;
+ }
+
+ if (!played_sound)
+ ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
+ CA_PROP_EVENT_ID, "window-close",
+ CA_PROP_EVENT_DESCRIPTION, "Window closed",
+ CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
+ NULL);
+ }
+
if (GTK_IS_DIALOG(d->object) && d->signal_id == signal_id_dialog_response) {
int response;
@@ -182,24 +226,6 @@ static gboolean idle_cb(SoundEventData *d) {
}
}
- if (GTK_IS_WINDOW(d->object) && GTK_IS_MENU(gtk_bin_get_child(GTK_BIN(d->object)))) {
-
- /* This doesn't work */
-
- if (d->signal_id == signal_id_widget_show)
- ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
- CA_PROP_EVENT_ID, "menu-popup",
- CA_PROP_EVENT_DESCRIPTION, "Menu popped up",
- CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
- NULL);
- else if (d->signal_id == signal_id_widget_hide)
- ret = ca_gtk_play_for_widget(GTK_WIDGET(d->object), 0,
- CA_PROP_EVENT_ID, "menu-popdown",
- CA_PROP_EVENT_DESCRIPTION, "Menu popped up",
- CA_PROP_CANBERRA_CACHE_CONTROL, "permanent",
- NULL);
- }
-
if (GTK_IS_CHECK_MENU_ITEM(d->object) && d->signal_id == signal_id_check_menu_item_toggled) {
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(d)))
@@ -270,9 +296,21 @@ static gboolean idle_cb(SoundEventData *d) {
if (ret != CA_SUCCESS)
g_warning("Failed to play event sound: %s", ca_strerror(ret));
+}
+
+static gboolean idle_cb(void *userdata) {
+ SoundEventData *d;
+
+ idle_id = 0;
+
+ while ((d = g_queue_pop_head(&sound_event_queue))) {
+ filter_sound_events(d);
+ dispatch_sound_event(d);
+ free_sound_event(d);
+ }
return FALSE;
- }
+}
static gboolean emission_hook_cb(GSignalInvocationHint *hint, guint n_param_values, const GValue *param_values, gpointer data) {
static SoundEventData *d = NULL;
@@ -288,7 +326,7 @@ static gboolean emission_hook_cb(GSignalInvocationHint *hint, guint n_param_valu
!GTK_IS_WINDOW(object))
return TRUE;
- d = g_slice_new0(SoundEventData, 1);
+ d = g_slice_new0(SoundEventData);
d->object = g_object_ref(object);
@@ -303,7 +341,10 @@ static gboolean emission_hook_cb(GSignalInvocationHint *hint, guint n_param_valu
d->arg1_is_set = TRUE;
}
- idle_id = g_idle_add_full(GTK_PRIORITY_REDRAW-1, (GSourceFunc) idle_cb, d, (GDestroyNotify) destroy_cb);
+ g_queue_push_tail(&sound_event_queue, e);
+
+ if (idle_id == 0)
+ idle_id = g_idle_add_full(GTK_PRIORITY_REDRAW-1, (GSourceFunc) idle_cb, NULL, NULL);
return TRUE;
}
diff --git a/src/common.c b/src/common.c
index 6e38c94..80be86c 100644
--- a/src/common.c
+++ b/src/common.c
@@ -36,6 +36,7 @@
int ca_context_create(ca_context **_c) {
ca_context *c;
int ret;
+ const char *d;
ca_return_val_if_fail(_c, CA_ERROR_INVALID);
@@ -43,16 +44,29 @@ int ca_context_create(ca_context **_c) {
return CA_ERROR_OOM;
if (!(c->mutex = ca_mutex_new())) {
- ca_free(c);
+ ca_context_destroy(c);
return CA_ERROR_OOM;
}
if ((ret = ca_proplist_create(&c->props)) < 0) {
- ca_mutex_free(c->mutex);
- ca_free(c);
+ ca_context_destroy(c);
return ret;
}
+ if ((d = getenv("CANBERRA_DRIVER"))) {
+ if ((ret = ca_context_set_driver(c, d)) < 0) {
+ ca_context_destroy(c);
+ return ret;
+ }
+ }
+
+ if ((d = getenv("CANBERRA_DEVICE"))) {
+ if ((ret = ca_context_change_device(c, d)) < 0) {
+ ca_context_destroy(c);
+ return ret;
+ }
+ }
+
*_c = c;
return CA_SUCCESS;
}
@@ -72,7 +86,9 @@ int ca_context_destroy(ca_context *c) {
if (c->props)
ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS);
- ca_mutex_free(c->mutex);
+ if (c->mutex)
+ ca_mutex_free(c->mutex);
+
ca_free(c->driver);
ca_free(c->device);
ca_free(c);
diff --git a/src/common.h b/src/common.h
index 8c7a762..8483ba6 100644
--- a/src/common.h
+++ b/src/common.h
@@ -1,5 +1,5 @@
-#ifndef foocacommonh
-#define foocacommonh
+#ifndef foocanberracommonh
+#define foocanberracommonh
/* $Id$ */
diff --git a/src/dso.c b/src/dso.c
index a302b27..5ff0fec 100644
--- a/src/dso.c
+++ b/src/dso.c
@@ -152,7 +152,6 @@ static int try_open(ca_context *c, const char *t) {
int driver_open(ca_context *c) {
int ret;
struct private_dso *p;
- const char *d;
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_return_val_if_fail(!PRIVATE_DSO(c), CA_ERROR_STATE);
@@ -168,12 +167,9 @@ int driver_open(ca_context *c) {
p->ltdl_initialized = TRUE;
- if (!(d = c->driver))
- d = getenv("CANBERRA_DRIVER");
+ if (c->driver) {
- if (d) {
-
- if ((ret = try_open(c, d)) < 0) {
+ if ((ret = try_open(c, c->driver)) < 0) {
driver_destroy(c);
return ret;
}
diff --git a/src/llist.h b/src/llist.h
index e9122ff..839818f 100644
--- a/src/llist.h
+++ b/src/llist.h
@@ -1,5 +1,5 @@
-#ifndef foocallistfoo
-#define foocallistfoo
+#ifndef foocanberrallistfoo
+#define foocanberrallistfoo
/* $Id$ */
diff --git a/src/mutex.h b/src/mutex.h
index 31b75b3..a00860f 100644
--- a/src/mutex.h
+++ b/src/mutex.h
@@ -1,5 +1,5 @@
-#ifndef foocamutexhfoo
-#define foocamutexhfoo
+#ifndef foocanberramutexhfoo
+#define foocanberramutexhfoo
/* $Id$ */
diff --git a/src/null.c b/src/null.c
new file mode 100644
index 0000000..5b66c1f
--- /dev/null
+++ b/src/null.c
@@ -0,0 +1,82 @@
+/* $Id$ */
+
+/***
+ This file is part of libcanberra.
+
+ Copyright 2008 Lennart Poettering
+
+ libcanberra is free software; you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 2.1 of the
+ License, or (at your option) any later version.
+
+ libcanberra is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with libcanberra. If not, If not, see
+ <http://www.gnu.org/licenses/>.
+***/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "canberra.h"
+#include "common.h"
+#include "driver.h"
+
+int driver_open(ca_context *c) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(!c->driver || streq(c->driver, "null"), CA_ERROR_NODRIVER);
+
+ return CA_SUCCESS;
+}
+
+int driver_destroy(ca_context *c) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+
+ return CA_SUCCESS;
+}
+
+int driver_change_device(ca_context *c, char *device) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+
+ return CA_SUCCESS;
+}
+
+int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(changed, CA_ERROR_INVALID);
+ ca_return_val_if_fail(merged, CA_ERROR_INVALID);
+
+ return CA_SUCCESS;
+}
+
+int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
+ ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
+
+ if (cb)
+ cb(c, id, CA_SUCCESS, userdata);
+
+ return CA_SUCCESS;
+}
+
+int driver_cancel(ca_context *c, uint32_t id) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+
+ return CA_SUCCESS;
+}
+
+int driver_cache(ca_context *c, ca_proplist *proplist) {
+ ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
+
+ return CA_ERROR_NOTSUPPORTED;
+}
diff --git a/src/proplist.h b/src/proplist.h
index d23e5dc..0716132 100644
--- a/src/proplist.h
+++ b/src/proplist.h
@@ -1,5 +1,5 @@
-#ifndef foocaproplisthfoo
-#define foocaproplisthfoo
+#ifndef foocanberraproplisthfoo
+#define foocanberraproplisthfoo
/* $Id$ */
diff --git a/src/pulse.c b/src/pulse.c
index 04dc5db..a720231 100644
--- a/src/pulse.c
+++ b/src/pulse.c
@@ -363,6 +363,7 @@ int driver_destroy(ca_context *c) {
int driver_change_device(ca_context *c, char *device) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
+ ca_return_val_if_fail(c->private, CA_ERROR_STATE);
/* We're happy with any device change. We might however add code
* here eventually to move all currently played back event sounds
diff --git a/src/read-sound-file.c b/src/read-sound-file.c
index 3a1f93c..b3a369f 100644
--- a/src/read-sound-file.c
+++ b/src/read-sound-file.c
@@ -196,3 +196,13 @@ size_t ca_sound_file_get_size(ca_sound_file *f) {
else
return ca_vorbis_get_size(f->vorbis);
}
+
+size_t ca_sound_file_frame_size(ca_sound_file *f) {
+ unsigned c;
+
+ ca_assert(f);
+
+ c = ca_sound_file_get_nchannels(f);
+
+ return c * (ca_sound_file_get_sample_type(f) == CA_SAMPLE_U8 ? 1 : 2);
+}
diff --git a/src/read-sound-file.h b/src/read-sound-file.h
index f236b13..bf39f8d 100644
--- a/src/read-sound-file.h
+++ b/src/read-sound-file.h
@@ -1,5 +1,5 @@
-#ifndef foocareadsoundfilehfoo
-#define foocareadsoundfilehfoo
+#ifndef foocanberrareadsoundfilehfoo
+#define foocanberrareadsoundfilehfoo
/* $Id$ */
@@ -48,4 +48,6 @@ int ca_sound_file_read_uint8(ca_sound_file *f, uint8_t *d, unsigned *n);
int ca_sound_file_read_arbitrary(ca_sound_file *f, void *d, size_t *n);
+size_t ca_sound_file_frame_size(ca_sound_file *f);
+
#endif
diff --git a/src/read-vorbis.h b/src/read-vorbis.h
index e23c1cc..76a54c7 100644
--- a/src/read-vorbis.h
+++ b/src/read-vorbis.h
@@ -1,5 +1,5 @@
-#ifndef foocareadvorbishfoo
-#define foocareadvorbishfoo
+#ifndef foocanberrareadvorbishfoo
+#define foocanberrareadvorbishfoo
/* $Id$ */
diff --git a/src/read-wav.h b/src/read-wav.h
index 4287ee1..7d0fdd2 100644
--- a/src/read-wav.h
+++ b/src/read-wav.h
@@ -1,5 +1,5 @@
-#ifndef foocareadwavhfoo
-#define foocareadwavhfoo
+#ifndef foocanberrareadwavhfoo
+#define foocanberrareadwavhfoo
/* $Id$ */
diff --git a/src/sound-theme-spec.h b/src/sound-theme-spec.h
index 652903a..a40ed00 100644
--- a/src/sound-theme-spec.h
+++ b/src/sound-theme-spec.h
@@ -1,5 +1,5 @@
-#ifndef foocasoundthemespechfoo
-#define foocasoundthemespechfoo
+#ifndef foocanberrasoundthemespechfoo
+#define foocanberrasoundthemespechfoo
/* $Id$ */