From: Marc-André Lureau <[EMAIL PROTECTED]>

Signed-off-by: Marc-Andr� Lureau <[EMAIL PROTECTED]>

diff --git a/configure.ac b/configure.ac
index f41cfe9..52cd26c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -272,6 +272,38 @@ fi
 AC_SUBST(PULSE_CFLAGS)
 AC_SUBST(PULSE_LIBS)
 
+#### GStreamer support (optional) ####
+
+AC_ARG_ENABLE([gstreamer],
+    AC_HELP_STRING([--disable-gstreamer], [Disable optional GStreamer 
support]),
+        [
+            case "${enableval}" in
+                yes) gstreamer=yes ;;
+                no) gstreamer=no ;;
+                *) AC_MSG_ERROR(bad value ${enableval} for 
--disable-gstreamer) ;;
+            esac
+        ],
+        [gstreamer=auto])
+
+if test "x${gstreamer}" != xno ; then
+    PKG_CHECK_MODULES(GST, [ gstreamer-0.10 >= 0.10.15 ],
+        [
+            HAVE_GSTREAMER=1
+            AC_DEFINE([HAVE_GSTREAMER], 1, [Have GStreamer?])
+        ],
+        [
+            HAVE_GSTREAMER=0
+            if test "x$gstreamer" = xyes ; then
+                AC_MSG_ERROR([*** GStreamer not found ***])
+            fi
+        ])
+else
+    HAVE_GSTREAMER=0
+fi
+
+AC_SUBST(GSTREAMER_CFLAGS)
+AC_SUBST(GSTREAMER_LIBS)
+
 ### Null output (optional) ####
 
 AC_ARG_ENABLE([null],
@@ -369,6 +401,7 @@ BUILTIN_DSO=0
 BUILTIN_PULSE=0
 BUILTIN_ALSA=0
 BUILTIN_OSS=0
+BUILTIN_GSTREAMER=0
 BUILTIN_NULL=0
 
 case "x$with_builtin" in
@@ -380,6 +413,7 @@ case "x$with_builtin" in
         BUILTIN_PULSE=1
         HAVE_ALSA=0
        HAVE_OSS=0
+       HAVE_GSTREAMER=0
         HAVE_NULL=0
      ;;
 
@@ -391,6 +425,19 @@ case "x$with_builtin" in
         BUILTIN_ALSA=1
        HAVE_OSS=0
         HAVE_PULSE=0
+       HAVE_GSTREAMER=0
+        HAVE_NULL=0
+     ;;
+
+     xgstreamer)
+        if test "x$HAVE_GSTREAMER" != x1 ; then
+                AC_MSG_ERROR([*** GStremaer selected for builtin driver, but 
not enabled. ***])
+        fi
+
+        BUILTIN_GSTREAMER=1
+        HAVE_ALSA=0
+       HAVE_OSS=0
+        HAVE_PULSE=0
         HAVE_NULL=0
      ;;
 
@@ -402,6 +449,7 @@ case "x$with_builtin" in
        BUILTIN_OSS=1
        HAVE_ALSA=0
        HAVE_PULSE=0
+       HAVE_GSTREAMER=0
        HAVE_NULL=0
      ;;
 
@@ -414,6 +462,7 @@ case "x$with_builtin" in
         HAVE_PULSE=0
         HAVE_ALSA=0
        HAVE_OSS=0
+       HAVE_GSTREAMER=0
      ;;
 
      xdso)
@@ -426,7 +475,7 @@ 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 -a "x$HAVE_OSS" != x1 -a 
"x$HAVE_NULL" != x1 ; then
+if test "x$HAVE_PULSE" != x1 -a "x$HAVE_ALSA" != x1 -a "x$HAVE_OSS" != x1 -a 
"x$HAVE_GSTREAMER" != x1 -a "x$HAVE_NULL" != x1 ; then
    AC_MSG_ERROR([*** No backend enabled. ***])
 fi
 
@@ -434,20 +483,24 @@ AC_SUBST(HAVE_DSO)
 AC_SUBST(HAVE_PULSE)
 AC_SUBST(HAVE_ALSA)
 AC_SUBST(HAVE_OSS)
+AC_SUBST(HAVE_GSTREAMER)
 AC_SUBST(HAVE_NULL)
 AC_SUBST(BUILTIN_DSO)
 AC_SUBST(BUILTIN_PULSE)
 AC_SUBST(BUILTIN_ALSA)
 AC_SUBST(BUILTIN_OSS)
+AC_SUBST(BUILTIN_GSTREAMER)
 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_OSS], [test "x$HAVE_OSS" = x1])
+AM_CONDITIONAL([HAVE_GSTREAMER], [test "x$HAVE_GSTREAMER" = 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_OSS], [test "x$BUILTIN_OSS" = x1])
+AM_CONDITIONAL([BUILTIN_GSTREAMER], [test "x$BUILTIN_GSTREAMER" = x1])
 AM_CONDITIONAL([BUILTIN_NULL], [test "x$BUILTIN_NULL" = x1])
 
 GTK_DOC_CHECK(1.9)
@@ -500,6 +553,15 @@ if test "x$BUILTIN_OSS" = "x1" ; then
     ENABLE_BUILTIN_OSS=yes
 fi
 
+ENABLE_GSTREAMER=no
+if test "x$HAVE_GSTREAMER" = "x1" ; then
+   ENABLE_GSTREAMER=yes
+fi
+ENABLE_BUILTIN_GSTREAMER=no
+if test "x$BUILTIN_GSTREAMER" = "x1" ; then
+   ENABLE_BUILTIN_GSTREAMER=yes
+fi
+
 ENABLE_NULL=no
 if test "x$HAVE_NULL" = "x1" ; then
    ENABLE_NULL=yes
@@ -531,6 +593,8 @@ echo "
     Builtin ALSA:           ${ENABLE_BUILTIN_ALSA}
     Enable OSS:             ${ENABLE_OSS}
     Builtin OSS:            ${ENABLE_BUILTIN_OSS}
+    Enable GStreamer:       ${ENABLE_GSTREAMER}
+    Builtin GStreamer:      ${ENABLE_BUILTIN_GSTREAMER}
     Enable Null Output:     ${ENABLE_NULL}
     Builtin Null Output:    ${ENABLE_BUILTIN_NULL}
     Enable GTK+:            ${ENABLE_GTK}
diff --git a/src/Makefile.am b/src/Makefile.am
index 9f1549b..dddfeba 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -195,6 +195,41 @@ libcanberra_oss_la_LDFLAGS = \
 endif
 endif
 
+if HAVE_GSTREAMER
+if BUILTIN_GSTREAMER
+
+libcanberra_la_SOURCES += \
+       gstreamer.c
+libcanberra_la_CFLAGS += \
+       $(GST_CFLAGS)
+libcanberra_la_LIBADD += \
+        $(GST_LIBS)
+
+else
+
+plugin_LTLIBRARIES += \
+       libcanberra-gstreamer.la
+
+libcanberra_gstreamer_la_SOURCES = \
+       gstreamer.c
+libcanberra_gstreamer_la_CFLAGS = \
+       $(GST_CFLAGS) \
+        -Ddriver_open=gstreamer_driver_open \
+        -Ddriver_destroy=gstreamer_driver_destroy \
+        -Ddriver_change_device=gstreamer_driver_change_device \
+        -Ddriver_change_props=gstreamer_driver_change_props \
+        -Ddriver_play=gstreamer_driver_play \
+        -Ddriver_cancel=gstreamer_driver_cancel \
+        -Ddriver_cache=gstreamer_driver_cache
+libcanberra_gstreamer_la_LIBADD = \
+       $(GST_LIBS) \
+       libcanberra.la
+libcanberra_gstreamer_la_LDFLAGS = \
+       -avoid-version -module -export-dynamic
+
+endif
+endif
+
 if HAVE_NULL
 if BUILTIN_NULL
 
diff --git a/src/gstreamer.c b/src/gstreamer.c
new file mode 100644
index 0000000..439d7a6
--- /dev/null
+++ b/src/gstreamer.c
@@ -0,0 +1,437 @@
+/***
+    This file is part of libcanberra.
+
+    Copyright 2008 Nokia Corporation and/or its subsidiary(-ies).
+
+    Author: Marc-Andre Lureau <[EMAIL PROTECTED]>
+
+    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 <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <gst/gst.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 outstanding {
+    CA_LLIST_FIELDS(struct outstanding);
+    ca_bool_t dead;
+    uint32_t id;
+    ca_finish_callback_t callback;
+    void *userdata;
+    GstElement *pipeline;
+    struct 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) {
+    GstBus *bus;
+
+    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)
+        gst_object_unref(GST_OBJECT(o->pipeline));
+
+    ca_free(o);
+}
+
+int driver_open(ca_context *c) {
+    GError *error = NULL;
+    struct private *p;
+
+    ca_return_val_if_fail(c, CA_ERROR_INVALID);
+    ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_INVALID);
+    ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "gstreamer"), 
CA_ERROR_NODRIVER);
+
+    gst_init_check (NULL, NULL, &error);
+    if (error != NULL) {
+        g_warning("gst_init: %s ", error->message);
+        g_error_free(error);
+        return CA_ERROR_INVALID;
+    }
+
+    if (!(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;
+
+    c->private = p;
+
+    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(PRIVATE(c), CA_ERROR_STATE);
+
+    p = PRIVATE(c);
+
+    if (p->outstanding_mutex) {
+        ca_mutex_lock(p->outstanding_mutex);
+
+        /* Tell all player threads to terminate */
+        out = p->outstanding;
+        while (out) {
+            GstElement *pipeline;
+
+            if (out->dead) {
+                out = out->next;
+                continue;
+            }
+
+            pipeline = out->pipeline;
+            out->dead = TRUE;
+
+            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));
+
+            ca_mutex_lock(p->outstanding_mutex);
+        }
+
+        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);
+
+    /* no gst_deinit (), see doc */
+
+    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(PRIVATE(c), 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);
+    ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
+
+    return CA_SUCCESS;
+}
+
+static GstBusSyncReply bus_cb(GstBus *bus, GstMessage *message, gpointer data) 
{
+    int err;
+    struct outstanding *out;
+    struct private *p;
+
+    ca_return_val_if_fail(bus, GST_BUS_DROP);
+    ca_return_val_if_fail(message, GST_BUS_DROP);
+    ca_return_val_if_fail(data, GST_BUS_DROP);
+
+    out = data;
+    p = PRIVATE(out->context);
+
+    switch (GST_MESSAGE_TYPE(message)) {
+        /* for all elements */
+        case GST_MESSAGE_UNKNOWN:
+            return GST_BUS_DROP;
+        case GST_MESSAGE_ERROR:
+            err = CA_ERROR_SYSTEM;
+            break;
+        /* only from bin */
+        case GST_MESSAGE_EOS:
+            if (GST_OBJECT(out->pipeline) != GST_MESSAGE_SRC(message))
+                return GST_BUS_DROP;
+
+            err = CA_SUCCESS;
+            break;
+        case GST_MESSAGE_STATE_CHANGED: {
+            GstState pending;
+
+            if (GST_OBJECT(out->pipeline) != GST_MESSAGE_SRC(message))
+                return GST_BUS_DROP;
+
+            gst_message_parse_state_changed(message, NULL, NULL, &pending);
+            /* g_debug (gst_element_state_get_name (pending)); */
+
+            if (pending == GST_STATE_NULL || pending == GST_STATE_VOID_PENDING)
+                err = CA_SUCCESS;
+            else
+                return GST_BUS_DROP;
+            break;
+        }
+        default:
+            return GST_BUS_DROP;
+    }
+
+    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);
+
+    return GST_BUS_DROP;
+}
+
+struct ca_sound_file {
+    GstElement *fdsrc;
+};
+
+static int ca_gst_sound_file_open(ca_sound_file **_f, const char *fn) {
+    int fd;
+    ca_sound_file *f;
+
+    ca_return_val_if_fail(_f, CA_ERROR_INVALID);
+    ca_return_val_if_fail(fn, CA_ERROR_INVALID);
+
+    if ((fd = open(fn, O_RDONLY)) == -1)
+        return errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM;
+
+    if (!(f = ca_new0(ca_sound_file, 1)))
+        return CA_ERROR_OOM;
+
+    if (!(f->fdsrc = gst_element_factory_make("fdsrc", NULL))) {
+        ca_free(f);
+        return CA_ERROR_OOM;
+    }
+
+    g_object_set(GST_OBJECT(f->fdsrc), "fd", fd, NULL);
+    *_f = f;
+
+    return CA_SUCCESS;
+}
+
+static void on_pad_added(GstElement *element, GstPad *pad, gboolean arg1, 
gpointer data)
+{
+    GstPad *sinkpad;
+    GstElement *sink = GST_ELEMENT (data);
+
+    sinkpad = gst_element_get_static_pad (sink, "sink");
+
+    gst_pad_link (pad, sinkpad);
+
+    gst_object_unref (sinkpad);
+}
+
+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;
+    const char *fname;
+    ca_sound_file *f;
+    GstElement *decodebin, *sink;
+    GstBus *bus;
+    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);
+
+    f = NULL;
+    sink = NULL;
+    decodebin = NULL;
+
+    p = PRIVATE(c);
+
+    if ((ret = ca_lookup_sound_with_callback(&f, ca_gst_sound_file_open, 
&p->theme, c->props, proplist)) < 0)
+        goto fail;
+
+    if (!(out = ca_new0(struct outstanding, 1)))
+        return CA_ERROR_OOM;
+
+    out->id = id;
+    out->callback = cb;
+    out->userdata = userdata;
+    out->context = c;
+
+    if (!(out->pipeline = gst_pipeline_new(NULL))
+        || !(decodebin = gst_element_factory_make("decodebin2", NULL))
+        || !(sink = gst_element_factory_make("autoaudiosink", NULL))) {
+        ret = CA_ERROR_OOM;
+        goto fail;
+    }
+
+    bus = gst_pipeline_get_bus(GST_PIPELINE (out->pipeline));
+    gst_bus_set_sync_handler(bus, bus_cb, out);
+    gst_object_unref(bus);
+
+    gst_bin_add_many(GST_BIN (out->pipeline),
+                     f->fdsrc, decodebin, sink, NULL);
+
+    if (!gst_element_link(f->fdsrc, decodebin)) {
+        f->fdsrc = NULL;
+        decodebin = NULL;
+        sink = NULL;
+        goto fail;
+    }
+
+    g_signal_connect (decodebin, "new-decoded-pad", G_CALLBACK (on_pad_added), 
sink);
+
+    decodebin = NULL;
+    sink = NULL;
+    ca_free(f);
+    f = NULL;
+
+    ca_mutex_lock(p->outstanding_mutex);
+    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) {
+        ca_mutex_lock(p->outstanding_mutex);
+        CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
+        ca_mutex_unlock(p->outstanding_mutex);
+
+        ret = CA_ERROR_NOTAVAILABLE;
+        goto fail;
+    }
+
+    return CA_SUCCESS;
+
+ fail:
+    if (f && f->fdsrc)
+        gst_object_unref(f->fdsrc);
+
+    if (f)
+        ca_free(f);
+
+    if (sink)
+        gst_object_unref(sink);
+
+    if (decodebin)
+        gst_object_unref(decodebin);
+
+    if (out->pipeline)
+        gst_object_unref(out->pipeline);
+
+    ca_free(out);
+
+    return ret;
+}
+
+int driver_cancel(ca_context *c, uint32_t id) {
+    struct private *p;
+    struct outstanding *out = NULL;
+
+    ca_return_val_if_fail(c, CA_ERROR_INVALID);
+    ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
+
+    p = PRIVATE(c);
+
+    ca_mutex_lock(p->outstanding_mutex);
+
+    for (out = p->outstanding; out; out = out->next) {
+        GstElement *pipeline;
+
+        if (out->id != id)
+            continue;
+
+        if (out->pipeline == NULL)
+            break;
+
+        if (out->callback)
+            out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata);
+
+        pipeline = out->pipeline;
+        out->dead = TRUE;
+
+        ca_mutex_unlock(p->outstanding_mutex);
+        gst_element_set_state(out->pipeline, GST_STATE_NULL);
+        ca_mutex_lock(p->outstanding_mutex);
+
+        gst_object_unref(pipeline);
+    }
+
+    ca_mutex_unlock(p->outstanding_mutex);
+
+    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);
+    ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
+
+    return CA_ERROR_NOTSUPPORTED;
+}
-- 
1.5.6.3

_______________________________________________
libcanberra-discuss mailing list
[email protected]
https://tango.0pointer.de/mailman/listinfo/libcanberra-discuss

Reply via email to