rendered paste bodyFrom e291642d1767c75300f510db0e5ca562e2574dc0 Mon Sep 17 00:00:00 2001From: Marc-Andre Lureau (elmarco) <marcandre.lureau@gmail.com>Date: Wed, 23 May 2007 12:09:21 +0300Subject: [PATCH] Monitor ALSA fds with a GstTaskTo poll ALSA fds, I decided to drop the custom GSource and use poll directly inside the task.I am not confident how to handle errors in the task.I don't know if RecMutex are necessary (it depends if ALSA plugins could call cb from different threads - ideally not)I am unsure about the (un)locking places (I am not an expert in MT environnement)To sum up... this is a draft patch :)--- ext/alsa/gstalsamixer.c | 261 +++++++++++++++++++---------------------------- ext/alsa/gstalsamixer.h | 5 +- 2 files changed, 108 insertions(+), 158 deletions(-)diff --git a/ext/alsa/gstalsamixer.c b/ext/alsa/gstalsamixer.cindex b6a1f09..0c06c42 100644--- a/ext/alsa/gstalsamixer.c+++ b/ext/alsa/gstalsamixer.c@@ -46,78 +46,8 @@ static void gst_alsa_mixer_update_option (GstAlsaMixer * mixer, GstAlsaMixerOptions * alsa_opts); static void gst_alsa_mixer_update_track (GstAlsaMixer * mixer, GstAlsaMixerTrack * alsa_track);--static gboolean gst_alsa_mixer_prepare (GSource * source, gint * timeout);-static gboolean gst_alsa_mixer_check (GSource * source);-static gboolean gst_alsa_mixer_dispatch (GSource * source, GSourceFunc callback,- gpointer user_data);-static void gst_alsa_mixer_finalize (GSource * source);--static GMainContext *main_context;--typedef struct _GstAlsaMixerWatch GstAlsaMixerWatch;-struct _GstAlsaMixerWatch-{- GSource source;- gint n_poll_fds;- GPollFD *poll_fds;-};--GSourceFuncs gst_alsa_mixer_watch_funcs = {- gst_alsa_mixer_prepare,- gst_alsa_mixer_check,- gst_alsa_mixer_dispatch,- gst_alsa_mixer_finalize-};--static gboolean-gst_alsa_mixer_prepare (GSource * source, gint * timeout)-{- *timeout = -1;- return FALSE;-}--static gboolean-gst_alsa_mixer_check (GSource * source)-{- GstAlsaMixerWatch *watch = (GstAlsaMixerWatch *) source;- gint i;- gushort revents;-- /* Code based on snd_mixer_poll_descriptors_revents() adapted for glib */- revents = 0;- for (i = 0; i < watch->n_poll_fds; ++i) {- revents |= watch->poll_fds[i].revents & (G_IO_IN | G_IO_ERR | G_IO_HUP);- }-- if (revents & G_IO_ERR || revents & G_IO_HUP) {- GST_DEBUG ("ALSA poll fds returned ERR or HUP");- return FALSE;- }-- return (revents & G_IO_IN);-}--static gboolean-gst_alsa_mixer_dispatch (GSource * source, GSourceFunc callback,- gpointer user_data)-{- g_return_val_if_fail (callback, FALSE);- return (*callback) (user_data);-}--static void-gst_alsa_mixer_finalize (GSource * source)-{- GstAlsaMixerWatch *watch = (GstAlsaMixerWatch *) source;-- if (watch->poll_fds != NULL) {- g_free (watch->poll_fds);- watch->poll_fds = NULL;- }-- watch->n_poll_fds = 0;-}+static int gst_alsa_mixer_handle_callback (snd_mixer_t * handle, unsigned int mask,+ snd_mixer_elem_t * elem); /* First some utils, then the mixer implementation */ static gboolean@@ -150,6 +80,8 @@ gst_alsa_mixer_open (GstAlsaMixer * mixer) goto error; } + snd_mixer_set_callback_private (mixer->handle, mixer);+ snd_mixer_set_callback (mixer->handle, gst_alsa_mixer_handle_callback); /* now get the device name, any of this is not fatal */ g_free (mixer->cardname);@@ -245,65 +177,63 @@ gst_alsa_mixer_find_master_mixer (GstAlsaMixer * mixer, snd_mixer_t * handle) return NULL; } -static gboolean-gst_alsa_mixer_handle_source_callback (gpointer data)-{- GstAlsaMixer *mixer = (GstAlsaMixer *) data;-- GST_LOG ("Source cb");- snd_mixer_handle_events (mixer->handle);-- return TRUE;-} -static int-gst_alsa_mixer_handle_callback (snd_mixer_t * handle, unsigned int mask,- snd_mixer_elem_t * elem)+static void+gst_alsa_mixer_update (GstAlsaMixer *mixer, snd_mixer_elem_t * elem) {- GstAlsaMixer *mixer =- (GstAlsaMixer *) snd_mixer_get_callback_private (handle); GList *item; - GST_LOG ("ALSA cb");- snd_mixer_handle_events (mixer->handle);+ g_return_if_fail (mixer != NULL);++ g_static_rec_mutex_lock (mixer->rec_mutex); for (item = mixer->tracklist; item != NULL; item = item->next) { if (GST_IS_ALSA_MIXER_TRACK (item->data)) {- GstAlsaMixerTrack *item_alsa_track = GST_ALSA_MIXER_TRACK (item->data);+ if (elem && (GST_ALSA_MIXER_TRACK (item->data)->element != elem))+ continue; - gst_alsa_mixer_update_track (mixer, item_alsa_track);- } else {- GstAlsaMixerOptions *item_alsa_options =- GST_ALSA_MIXER_OPTIONS (item->data);- gst_alsa_mixer_update_option (mixer, item_alsa_options);+ gst_alsa_mixer_update_track (mixer, GST_ALSA_MIXER_TRACK (item->data));+ } else if (GST_IS_ALSA_MIXER_OPTIONS (item->data)) {+ if (elem && (GST_ALSA_MIXER_OPTIONS (item->data)->element != elem))+ continue;++ gst_alsa_mixer_update_option (mixer, GST_ALSA_MIXER_OPTIONS (item->data)); } } - return 0;+ g_static_rec_mutex_unlock (mixer->rec_mutex); } -int+static int gst_alsa_mixer_elem_handle_callback (snd_mixer_elem_t * elem, unsigned int mask) { GstAlsaMixer *mixer = (GstAlsaMixer *) snd_mixer_elem_get_callback_private (elem);- GList *item; GST_LOG ("ALSA elem cb"); - for (item = mixer->tracklist; item != NULL; item = item->next) {- if (GST_IS_ALSA_MIXER_TRACK (item->data)) {- if (GST_ALSA_MIXER_TRACK (item->data)->element != elem)- continue;+ g_return_val_if_fail (mixer != NULL, 1); - gst_alsa_mixer_update_track (mixer, GST_ALSA_MIXER_TRACK (item->data));- } else if (GST_IS_ALSA_MIXER_OPTIONS (item->data)) {- if (GST_ALSA_MIXER_OPTIONS (item->data)->element != elem)- continue;+ gst_alsa_mixer_update (mixer, elem); - gst_alsa_mixer_update_option (mixer, GST_ALSA_MIXER_OPTIONS (item->data));- }- }+ return 0;+}++static int+gst_alsa_mixer_handle_callback (snd_mixer_t * handle, unsigned int mask,+ snd_mixer_elem_t * elem)+{+ GstAlsaMixer *mixer =+ (GstAlsaMixer *) snd_mixer_get_callback_private (handle);++ GST_LOG ("ALSA cb");++ g_return_val_if_fail (mixer != NULL, 1);++ /* Hopefully won't be call recursively and will handle pending elem events */+ snd_mixer_handle_events (mixer->handle);++ gst_alsa_mixer_update (mixer, elem); return 0; }@@ -313,8 +243,6 @@ gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer) { gint i, count; snd_mixer_elem_t *element, *master;- struct pollfd *pfds;- GstAlsaMixerWatch *watch; GList *item; g_return_if_fail (mixer->handle != NULL);@@ -322,6 +250,8 @@ gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer) if (mixer->tracklist) return; + g_static_rec_mutex_lock (mixer->rec_mutex);+ master = gst_alsa_mixer_find_master_mixer (mixer, mixer->handle); count = snd_mixer_get_count (mixer->handle);@@ -428,64 +358,56 @@ gst_alsa_mixer_ensure_track_list (GstAlsaMixer * mixer) element = snd_mixer_elem_next (element); } - if (mixer->handle_source != NULL)- return;+ for (item = mixer->tracklist; item != NULL; item = item->next) {+ snd_mixer_elem_t *temp; - snd_mixer_set_callback_private (mixer->handle, mixer);- snd_mixer_set_callback (mixer->handle, gst_alsa_mixer_handle_callback);+ if (GST_IS_ALSA_MIXER_OPTIONS (item->data))+ temp = GST_ALSA_MIXER_OPTIONS (item->data)->element;+ else+ temp = GST_ALSA_MIXER_TRACK (item->data)->element; - main_context = g_main_context_default ();+ snd_mixer_elem_set_callback (temp, gst_alsa_mixer_elem_handle_callback);+ snd_mixer_elem_set_callback_private (temp, mixer);+ } - mixer->handle_source =- g_source_new (&gst_alsa_mixer_watch_funcs, sizeof (GstAlsaMixerWatch));- g_return_if_fail (main_context != NULL && mixer->handle_source != NULL);+ g_static_rec_mutex_unlock (mixer->rec_mutex);+} - count = snd_mixer_poll_descriptors_count (mixer->handle);- if (count < 1) {- GST_WARNING ("Poll descriptors count < 0: %d", count);- g_source_destroy (mixer->handle_source);- mixer->handle_source = NULL;+static void+task_monitor_alsa (gpointer data) +{+ struct pollfd *pfds;+ unsigned int nfds;+ unsigned short revents;+ GstAlsaMixer *mixer = (GstAlsaMixer *)data;+ + g_static_rec_mutex_lock (mixer->rec_mutex);++ nfds = snd_mixer_poll_descriptors_count (mixer->handle);+ if (nfds <= 0) {+ GST_ERROR ("snd_mixer_poll_descriptors_count <= 0: %d", nfds);+ /* FIXME: sleep ? stop monitoring ? */ return; } - pfds = g_newa (struct pollfd, count);+ pfds = g_newa (struct pollfd, nfds);+ nfds = snd_mixer_poll_descriptors (mixer->handle, pfds, nfds); - watch = (GstAlsaMixerWatch *) mixer->handle_source;- watch->n_poll_fds = snd_mixer_poll_descriptors (mixer->handle, pfds, count);;- watch->poll_fds = g_new0 (GPollFD, count);+ g_static_rec_mutex_unlock (mixer->rec_mutex); - for (i = 0; i < watch->n_poll_fds; ++i) {- watch->poll_fds[i].fd = pfds[i].fd;+ GST_LOG ("task loop");+ poll (pfds, nfds, -1); - if (pfds[i].events & POLLIN)- watch->poll_fds[i].events |= G_IO_IN;- if (pfds[i].events & POLLOUT)- watch->poll_fds[i].events |= G_IO_OUT;- if (pfds[i].events & POLLPRI)- watch->poll_fds[i].events |= G_IO_PRI;+ g_static_rec_mutex_lock (mixer->rec_mutex); - g_source_add_poll (mixer->handle_source, &watch->poll_fds[i]);+ snd_mixer_poll_descriptors_revents (mixer->handle, pfds, nfds, &revents);+ if (revents & POLLIN || revents & POLLPRI) {+ snd_mixer_handle_events (mixer->handle); } - /* FIXME mixer has to be protected, since cb could be made from different thread ? */- g_source_set_callback (mixer->handle_source,- gst_alsa_mixer_handle_source_callback, mixer, NULL);- g_source_attach (mixer->handle_source, main_context);-- for (item = mixer->tracklist; item != NULL; item = item->next) {- snd_mixer_elem_t *temp;-- if (GST_IS_ALSA_MIXER_OPTIONS (item->data))- temp = GST_ALSA_MIXER_OPTIONS (item->data)->element;- else- temp = GST_ALSA_MIXER_TRACK (item->data)->element;-- snd_mixer_elem_set_callback (temp, gst_alsa_mixer_elem_handle_callback);- snd_mixer_elem_set_callback_private (temp, mixer);- }+ g_static_rec_mutex_unlock (mixer->rec_mutex); } - /* API */ GstAlsaMixer *@@ -497,12 +419,25 @@ gst_alsa_mixer_new (const char *device, GstAlsaMixerDirection dir) ret = g_new0 (GstAlsaMixer, 1); + ret->rec_mutex = g_new (GStaticRecMutex, 1);+ g_static_rec_mutex_init (ret->rec_mutex);++ ret->task_mutex = g_new (GStaticRecMutex, 1);+ g_static_rec_mutex_init (ret->task_mutex);++ ret->task = gst_task_create (task_monitor_alsa, ret);+ gst_task_set_lock (ret->task, ret->task_mutex);+ ret->device = g_strdup (device); ret->dir = dir; if (!gst_alsa_mixer_open (ret)) goto error; + if (gst_task_start (ret->task) == FALSE) {+ GST_WARNING ("Could not start alsamixer task");+ }+ return ret; /* ERRORS */@@ -523,11 +458,23 @@ gst_alsa_mixer_free (GstAlsaMixer * mixer) mixer->interface = NULL; } - if (mixer->handle_source) {- g_source_destroy (mixer->handle_source);- mixer->handle_source = NULL;+ if (mixer->task) {+ if (gst_task_join (mixer->task) == FALSE) {+ GST_ERROR ("Cannot join alsamixer task");+ } ++ gst_object_unref (mixer->task);+ mixer->task = NULL; } + g_static_rec_mutex_free (mixer->task_mutex);+ g_free (mixer->task_mutex);+ mixer->task_mutex = NULL;++ g_static_rec_mutex_free (mixer->rec_mutex);+ g_free (mixer->rec_mutex);+ mixer->rec_mutex = NULL;+ if (mixer->device) { g_free (mixer->device); mixer->device = NULL;diff --git a/ext/alsa/gstalsamixer.h b/ext/alsa/gstalsamixer.hindex bf6457a..c319b2e 100644--- a/ext/alsa/gstalsamixer.h+++ b/ext/alsa/gstalsamixer.h@@ -51,7 +51,10 @@ struct _GstAlsaMixer GList * tracklist; /* list of available tracks */ snd_mixer_t * handle;- GSource * handle_source;++ GstTask * task;+ GStaticRecMutex * task_mutex;+ GStaticRecMutex * rec_mutex; GstMixer * interface; gchar * device;-- 1.5.2.rc0.71.g4342-dirty