It was almost a month ago that Hotti provided an updated GStreamer patch for
libcanberra. Has this gone upstream yet? I think the issues that were
raised have all been addressed, and it would be good to get this upstream, I
think.
Also it would be nice if the libcanberra-01-solaris.diff patch could go
upstream. It is needed for libcanberaa to compile on Solaris. I don't
think this is needed on other platforms, so I surrounded the needed
"#include" with "#ifdef __sun".
Thanks,
Brian
Hotti Timo wrote:
Hi,
I fixed a small bug from canberra and I used this patch as a base. When a sound
is playing and you are trying to destroy the canberra context, it just freezes
because the pthread_cond_signal was called only when EOS was received. I added
this pthread_cond_signal-call to driver_cancel and driver_destroy to fix the
problem. But a better fix could be that the NULL-state change is handled
differently in bus_cb, so we don't need to destroy the pipeline in thread_func
and we can just set the pipeline state to NULL instead of using this
pthread_cond_signal. There was also a small error in configure.ac, it did set
GSTREAMER_CFLAGS and GSTREAMER_LIBS and in makefile.am GST_CFLAGS and GST_LIBS
was used. The attached patch includes the Brian's patch and the fixes.
Timo Hotti
-----Original Message-----
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] On
Behalf Of Brian Cameron
Sent: Wednesday, November 12, 2008 6:51 PM
To: Brian Cameron
Cc: Jan Schmidt; [email protected]
Subject: Re: [libcanberra-discuss] Bugs with libcanberra
*ping*
Can this patch go upstream? I believe I addressed all issues that
Marc-Andre brought up with my original patch.
Thanks,
Brian
Marc-André:
I think I have fixed all the problems I found with the GStreamer
backend. See attached libcanberra-02-gstreamer.diff
patch. This patch
Great! Sorry for causing extra work. Thank you for your patch fix.
Attached find an updated patch. This patch removes the
C-style changes
I made in the previous patch.
I also improved the cleanup code so that the code calls
outstanding_free
in the various error conditions and avoid using the
"set_state" boolean.
Can this patch go upstream? Hopefully it addresses the issues in the
previous patch.
Brian
--- libcanberra-0.10/src/gstreamer.c-orig 2008-10-30
02:01:23.980831000 -0500
+++ libcanberra-0.10/src/gstreamer.c 2008-10-30
02:34:00.030254000
-0500
struct private {
@@ -242,16 +244,9 @@ static GstBusSyncReply bus_cb(GstBus *bu
if (!out->dead && out->callback)
out->callback(out->context, out->id, err, 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);
-
- outstanding_free(out);
-
- ca_mutex_unlock(p->outstanding_mutex);
+ pthread_mutex_lock(&out->mutex);
+ pthread_cond_signal(&out->cond);
+ pthread_mutex_unlock(&out->mutex);
That make sense according to your comments.
+static void* thread_func(void *userdata) {
+ struct outstanding *out = userdata;
+ struct private *p;
+
+ p = PRIVATE(out->context);
+
+ pthread_detach(pthread_self());
+
+ /* Wait until we receive EOS */
+ pthread_mutex_lock(&out->mutex);
+ pthread_cond_wait (&out->cond, &out->mutex);
+
+ ca_mutex_lock(p->outstanding_mutex);
+
+ /* Set pipeline back to NULL to close things */
+ if (gst_element_set_state(out->pipeline,
+ GST_STATE_NULL) ==
GST_STATE_CHANGE_FAILURE) {
+ goto fail;
+ }
+
+ CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
+
+ if (!p->outstanding && p->signal_semaphore)
+ sem_post(&p->semaphore);
+
+ outstanding_free(out);
+
+fail:
+ ca_mutex_unlock(p->outstanding_mutex);
+ pthread_mutex_unlock(&out->mutex);
+ return NULL;
+}
Looks good yes.
- f = NULL;
- sink = NULL;
- decodebin = NULL;
-
- p = PRIVATE(c);
+ out = NULL;
+ f = NULL;
+ decodebin = NULL;
+ sink = NULL;
+ audioconvert = NULL;
+ audioresample = NULL;
+ bin = NULL;
+ p = PRIVATE(c);
+ set_state = FALSE;
I am not sure if it's lennart-c-mode compliant ;)
- if ((ret = ca_lookup_sound_with_callback(&f,
ca_gst_sound_file_open, NULL, &p->theme, c->props, proplist)) < 0)
+ if ((ret = ca_lookup_sound_with_callback(&f,
ca_gst_sound_file_open,
+ NULL, &p->theme, c->props, proplist)) < 0)
goto fail;
- out->id = id;
+ out->id = id;
out->callback = cb;
out->userdata = userdata;
- out->context = c;
+ out->context = c;
- g_signal_connect(decodebin, "new-decoded-pad", G_CALLBACK
(on_pad_added), bin);
+ g_signal_connect(decodebin, "new-decoded-pad",
+ G_CALLBACK (on_pad_added), bin);
bus = gst_pipeline_get_bus(GST_PIPELINE (out->pipeline));
Not really necessary, imho.
- if (gst_element_set_state(out->pipeline,
GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
+ if (pthread_create(&thread, NULL, thread_func, out) < 0) {
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
+ ret=CA_ERROR_OOM;
+ goto fail;
+ }
+ + set_state = TRUE;
+ if (gst_element_set_state(out->pipeline,
+ GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
ret = CA_ERROR_NOTAVAILABLE;
goto fail;
}
@@ -400,22 +435,21 @@ int driver_play(ca_context *c, uint32_t
return CA_SUCCESS;
fail:
- if (f && f->fdsrc)
- gst_object_unref(f->fdsrc);
-
- if (f)
+ if (f) {
ca_free(f);
- if (sink)
- gst_object_unref(sink);
-
- if (decodebin)
- gst_object_unref(decodebin);
-
- if (out && out->pipeline)
- gst_object_unref(out->pipeline);
+ if (f->fdsrc)
+ gst_object_unref(f->fdsrc);
+ }
I prefer a branch-less condition for the unref/free "fail"
section. But ok for me!
- ca_free(out);
+ /*
+ * If we did not start playing, then we need to free
any allocated
+ * variables. If the pipeline did start, the free
will be done by
+ * thread_func() .
+ */
+ if (set_state == FALSE) {
+ outstanding_free(out);
+ }
You could outstanding_free(out) under the gst_element_set_state
condition and avoid the set_state variable?
I still need to run/test it now, but that was for the patch.
Are you ok to resend an improved version of the patch?
/me learning to do code review with git/mutt/emacsclient (& emacs
-daemon). :-P
thanks again
cheers,
---------------------------------------------------------------
---------
_______________________________________________
libcanberra-discuss mailing list
[email protected]
https://tango.0pointer.de/mailman/listinfo/libcanberra-discuss
diff -pruN libcanberra-0.10/configure.ac libcanberra-0.10-mod/configure.ac
--- libcanberra-0.10/configure.ac 2008-10-06 17:10:29.000000000 +0300
+++ libcanberra-0.10-mod/configure.ac 2008-11-14 15:17:12.000000000 +0200
@@ -303,8 +303,8 @@ else
HAVE_GSTREAMER=0
fi
-AC_SUBST(GSTREAMER_CFLAGS)
-AC_SUBST(GSTREAMER_LIBS)
+AC_SUBST(GST_CFLAGS)
+AC_SUBST(GST_LIBS)
### Null output (optional) ####
diff -pruN libcanberra-0.10/src/gstreamer.c libcanberra-0.10-mod/src/gstreamer.c
--- libcanberra-0.10/src/gstreamer.c 2008-10-06 17:10:29.000000000 +0300
+++ libcanberra-0.10-mod/src/gstreamer.c 2008-11-14 15:15:52.000000000
+0200
@@ -50,6 +50,8 @@ struct outstanding {
void *userdata;
GstElement *pipeline;
struct ca_context *context;
+ pthread_cond_t cond;
+ pthread_mutex_t mutex;
};
struct private {
@@ -68,12 +70,13 @@ static void outstanding_free(struct outs
ca_assert(o);
- bus = gst_pipeline_get_bus(GST_PIPELINE (o->pipeline));
- gst_bus_set_sync_handler(bus, NULL, NULL);
- gst_object_unref(bus);
+ if (o->pipeline) {
+ bus = gst_pipeline_get_bus(GST_PIPELINE (o->pipeline));
+ gst_bus_set_sync_handler(bus, NULL, NULL);
+ gst_object_unref(bus);
- if (o->pipeline)
gst_object_unref(GST_OBJECT(o->pipeline));
+ }
ca_free(o);
}
@@ -141,14 +144,13 @@ int driver_destroy(ca_context *c) {
if (out->callback)
out->callback(c, out->id, CA_ERROR_DESTROYED, out->userdata);
- out = out->next;
-
ca_mutex_unlock(p->outstanding_mutex);
-
- gst_element_set_state(pipeline, GST_STATE_NULL);
- gst_object_unref(GST_OBJECT(pipeline));
-
+ pthread_mutex_lock(&out->mutex);
+ pthread_cond_signal(&out->cond);
+ pthread_mutex_unlock(&out->mutex);
ca_mutex_lock(p->outstanding_mutex);
+
+ out = out->next;
}
if (p->semaphore_allocated) {
@@ -242,16 +244,9 @@ static GstBusSyncReply bus_cb(GstBus *bu
if (!out->dead && out->callback)
out->callback(out->context, out->id, err, 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);
-
- outstanding_free(out);
-
- ca_mutex_unlock(p->outstanding_mutex);
+ pthread_mutex_lock(&out->mutex);
+ pthread_cond_signal(&out->cond);
+ pthread_mutex_unlock(&out->mutex);
return GST_BUS_DROP;
}
@@ -310,23 +305,62 @@ static void on_pad_added(GstElement *ele
gst_caps_unref(caps);
}
+static void* thread_func(void *userdata) {
+ struct outstanding *out = userdata;
+ struct private *p;
+
+ p = PRIVATE(out->context);
+
+ pthread_detach(pthread_self());
+
+ /* Wait until we receive EOS -> also close and destroy needs to get here.
*/
+ pthread_mutex_lock(&out->mutex);
+ pthread_cond_wait (&out->cond, &out->mutex);
+
+ ca_mutex_lock(p->outstanding_mutex);
+
+ /* Set pipeline back to NULL to close things */
+ if (gst_element_set_state(out->pipeline,
+ GST_STATE_NULL) == GST_STATE_CHANGE_FAILURE) {
+ goto fail;
+ }
+
+ gst_object_unref(GST_OBJECT(out->pipeline));
+
+ CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
+
+ if (!p->outstanding && p->signal_semaphore)
+ sem_post(&p->semaphore);
+
+ outstanding_free(out);
+
+fail:
+ ca_mutex_unlock(p->outstanding_mutex);
+ pthread_mutex_unlock(&out->mutex);
+ 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;
+ struct outstanding *out;
ca_sound_file *f;
GstElement *decodebin, *sink, *audioconvert, *audioresample, *bin;
GstBus *bus;
GstPad *audiopad;
+ pthread_t thread;
int ret;
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);
+ out = NULL;
f = NULL;
sink = NULL;
decodebin = NULL;
-
+ audioconvert = NULL;
+ audioresample = NULL;
+ bin = NULL;
p = PRIVATE(c);
if ((ret = ca_lookup_sound_with_callback(&f, ca_gst_sound_file_open, NULL,
&p->theme, c->props, proplist)) < 0)
@@ -345,6 +379,19 @@ int driver_play(ca_context *c, uint32_t
|| !(audioconvert = gst_element_factory_make("audioconvert", NULL))
|| !(audioresample = gst_element_factory_make("audioresample", NULL))
|| !(sink = gst_element_factory_make("autoaudiosink", NULL))) {
+
+ /* At this point, if there is a failure, free each plugin separately.
*/
+ if (out->pipeline != NULL)
+ g_object_unref (out->pipeline);
+ if (decodebin != NULL)
+ g_object_unref(decodebin);
+ if (audioconvert != NULL)
+ g_object_unref(audioconvert);
+ if (audioresample != NULL)
+ g_object_unref(audioresample);
+ if (sink != NULL)
+ g_object_unref(sink);
+
ret = CA_ERROR_OOM;
goto fail;
}
@@ -361,11 +408,8 @@ int driver_play(ca_context *c, uint32_t
f->fdsrc, decodebin, NULL);
if (!gst_element_link(f->fdsrc, decodebin)) {
- f->fdsrc = NULL;
- decodebin = NULL;
- audioconvert = NULL;
- audioresample = NULL;
- sink = NULL;
+ outstanding_free(out);
+ ret = CA_ERROR_OOM;
goto fail;
}
@@ -379,8 +423,6 @@ int driver_play(ca_context *c, uint32_t
gst_bin_add(GST_BIN (out->pipeline), bin);
- decodebin = NULL;
- sink = NULL;
ca_free(f);
f = NULL;
@@ -388,11 +430,17 @@ int driver_play(ca_context *c, uint32_t
CA_LLIST_PREPEND(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
- if (gst_element_set_state(out->pipeline, GST_STATE_PLAYING) ==
GST_STATE_CHANGE_FAILURE) {
+ if (pthread_create(&thread, NULL, thread_func, out) < 0) {
ca_mutex_lock(p->outstanding_mutex);
CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
ca_mutex_unlock(p->outstanding_mutex);
+ outstanding_free(out);
+ ret = CA_ERROR_OOM;
+ goto fail;
+ }
+ if (gst_element_set_state(out->pipeline,
+ GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
ret = CA_ERROR_NOTAVAILABLE;
goto fail;
}
@@ -406,17 +454,6 @@ fail:
if (f)
ca_free(f);
- if (sink)
- gst_object_unref(sink);
-
- if (decodebin)
- gst_object_unref(decodebin);
-
- if (out && out->pipeline)
- gst_object_unref(out->pipeline);
-
- ca_free(out);
-
return ret;
}
@@ -431,15 +468,15 @@ int driver_cancel(ca_context *c, uint32_
ca_mutex_lock(p->outstanding_mutex);
- for (out = p->outstanding; out; out = out->next) {
+ for (out = p->outstanding; out;/* out = out->next*/) {
GstElement *pipeline;
- if (out->id != id)
+ if (out->id != id || out->pipeline == NULL)
+ {
+ out = out->next;
continue;
-
- if (out->pipeline == NULL)
- break;
-
+ }
+
if (out->callback)
out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata);
@@ -447,10 +484,11 @@ int driver_cancel(ca_context *c, uint32_
out->dead = TRUE;
ca_mutex_unlock(p->outstanding_mutex);
- gst_element_set_state(out->pipeline, GST_STATE_NULL);
+ pthread_mutex_lock(&out->mutex);
+ pthread_cond_signal(&out->cond);
+ pthread_mutex_unlock(&out->mutex);
+ out = out->next;
ca_mutex_lock(p->outstanding_mutex);
-
- gst_object_unref(pipeline);
}
ca_mutex_unlock(p->outstanding_mutex);
--- libcanberra-0.8/src/common.h-orig 2008-08-21 00:21:50.594788000 -0500
+++ libcanberra-0.8/src/common.h 2008-08-21 00:22:25.218467000 -0500
@@ -21,6 +21,10 @@
<http://www.gnu.org/licenses/>.
***/
+#ifdef __sun
+#include <sys/varargs.h>
+#endif
+
#include "canberra.h"
#include "macro.h"
#include "mutex.h"
_______________________________________________
libcanberra-discuss mailing list
[email protected]
https://tango.0pointer.de/mailman/listinfo/libcanberra-discuss