Blame src/gstreamer.c

Packit 3ae693
/*-*- Mode: C; c-basic-offset: 8 -*-*/
Packit 3ae693
Packit 3ae693
/***
Packit 3ae693
  This file is part of libcanberra.
Packit 3ae693
Packit 3ae693
  Copyright 2008 Nokia Corporation and/or its subsidiary(-ies).
Packit 3ae693
Packit 3ae693
  Author: Marc-Andre Lureau <marc-andre.lureau@nokia.com>
Packit 3ae693
Packit 3ae693
  libcanberra is free software; you can redistribute it and/or modify
Packit 3ae693
  it under the terms of the GNU Lesser General Public License as
Packit 3ae693
  published by the Free Software Foundation, either version 2.1 of the
Packit 3ae693
  License, or (at your option) any later version.
Packit 3ae693
Packit 3ae693
  libcanberra is distributed in the hope that it will be useful, but
Packit 3ae693
  WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 3ae693
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Packit 3ae693
  Lesser General Public License for more details.
Packit 3ae693
Packit 3ae693
  You should have received a copy of the GNU Lesser General Public
Packit 3ae693
  License along with libcanberra. If not, see
Packit 3ae693
  <http://www.gnu.org/licenses/>.
Packit 3ae693
***/
Packit 3ae693
Packit 3ae693
#ifdef HAVE_CONFIG_H
Packit 3ae693
#include <config.h>
Packit 3ae693
#endif
Packit 3ae693
Packit 3ae693
#include <errno.h>
Packit 3ae693
#include <stdlib.h>
Packit 3ae693
#include <pthread.h>
Packit 3ae693
#include <semaphore.h>
Packit 3ae693
#include <sys/types.h>
Packit 3ae693
#include <sys/stat.h>
Packit 3ae693
#include <fcntl.h>
Packit 3ae693
#include <unistd.h>
Packit 3ae693
Packit 3ae693
#include <gst/gst.h>
Packit 3ae693
Packit 3ae693
#include "canberra.h"
Packit 3ae693
#include "common.h"
Packit 3ae693
#include "driver.h"
Packit 3ae693
#include "llist.h"
Packit 3ae693
#include "read-sound-file.h"
Packit 3ae693
#include "sound-theme-spec.h"
Packit 3ae693
#include "malloc.h"
Packit 3ae693
Packit 3ae693
struct outstanding {
Packit 3ae693
        CA_LLIST_FIELDS(struct outstanding);
Packit 3ae693
        ca_bool_t dead;
Packit 3ae693
        uint32_t id;
Packit 3ae693
        int err;
Packit 3ae693
        ca_finish_callback_t callback;
Packit 3ae693
        void *userdata;
Packit 3ae693
        GstElement *pipeline;
Packit 3ae693
        struct ca_context *context;
Packit 3ae693
};
Packit 3ae693
Packit 3ae693
struct private {
Packit 3ae693
        ca_theme_data *theme;
Packit 3ae693
        ca_bool_t signal_semaphore;
Packit 3ae693
        sem_t semaphore;
Packit 3ae693
Packit 3ae693
        GstBus *mgr_bus;
Packit 3ae693
Packit 3ae693
        /* Everything below protected by the outstanding_mutex */
Packit 3ae693
        ca_mutex *outstanding_mutex;
Packit 3ae693
        ca_bool_t mgr_thread_running;
Packit 3ae693
        ca_bool_t semaphore_allocated;
Packit 3ae693
        CA_LLIST_HEAD(struct outstanding, outstanding);
Packit 3ae693
};
Packit 3ae693
Packit 3ae693
#define PRIVATE(c) ((struct private *) ((c)->private))
Packit 3ae693
Packit 3ae693
static void* thread_func(void *userdata);
Packit 3ae693
static void send_eos_msg(struct outstanding *out, int err);
Packit 3ae693
static void send_mgr_exit_msg (struct private *p);
Packit 3ae693
Packit 3ae693
static void outstanding_free(struct outstanding *o) {
Packit 3ae693
        GstBus *bus;
Packit 3ae693
Packit 3ae693
        ca_assert(o);
Packit 3ae693
Packit 3ae693
        if (o->pipeline) {
Packit 3ae693
                bus = gst_pipeline_get_bus(GST_PIPELINE (o->pipeline));
Packit 3ae693
                if (bus != NULL) {
Packit 3ae693
                        gst_bus_set_sync_handler(bus, NULL, NULL, NULL);
Packit 3ae693
                        gst_object_unref(bus);
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                gst_object_unref(GST_OBJECT(o->pipeline));
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        ca_free(o);
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int driver_open(ca_context *c) {
Packit 3ae693
        GError *error = NULL;
Packit 3ae693
        struct private *p;
Packit 3ae693
        pthread_t thread;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(c, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "gstreamer"), CA_ERROR_NODRIVER);
Packit 3ae693
Packit 3ae693
        gst_init_check(NULL, NULL, &error);
Packit 3ae693
        if (error != NULL) {
Packit 3ae693
                g_warning("gst_init: %s ", error->message);
Packit 3ae693
                g_error_free(error);
Packit 3ae693
                return CA_ERROR_INVALID;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        if (!(p = ca_new0(struct private, 1)))
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
        c->private = p;
Packit 3ae693
Packit 3ae693
        if (!(p->outstanding_mutex = ca_mutex_new())) {
Packit 3ae693
                driver_destroy(c);
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        if (sem_init(&p->semaphore, 0, 0) < 0) {
Packit 3ae693
                driver_destroy(c);
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
        }
Packit 3ae693
        p->semaphore_allocated = TRUE;
Packit 3ae693
Packit 3ae693
        p->mgr_bus = gst_bus_new();
Packit 3ae693
        if (p->mgr_bus == NULL) {
Packit 3ae693
                driver_destroy(c);
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
        }
Packit 3ae693
        gst_bus_set_flushing(p->mgr_bus, FALSE);
Packit 3ae693
Packit 3ae693
        /* Give a reference to the bus to the mgr thread */
Packit 3ae693
        if (pthread_create(&thread, NULL, thread_func, p) < 0) {
Packit 3ae693
                driver_destroy(c);
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
        }
Packit 3ae693
        p->mgr_thread_running = TRUE;
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int driver_destroy(ca_context *c) {
Packit 3ae693
        struct private *p;
Packit 3ae693
        struct outstanding *out;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(c, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
Packit 3ae693
Packit 3ae693
        p = PRIVATE(c);
Packit 3ae693
Packit 3ae693
        if (p->outstanding_mutex) {
Packit 3ae693
                ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
                /* Tell all player threads to terminate */
Packit 3ae693
                out = p->outstanding;
Packit 3ae693
                while (out) {
Packit 3ae693
                        if (!out->dead)
Packit 3ae693
                                send_eos_msg(out, CA_ERROR_DESTROYED);
Packit 3ae693
                        out = out->next;
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                /* Now that we've sent EOS for all pending players, append a
Packit 3ae693
                 * message to wait for the mgr thread to exit */
Packit 3ae693
                if (p->mgr_thread_running && p->semaphore_allocated) {
Packit 3ae693
                        send_mgr_exit_msg(p);
Packit 3ae693
Packit 3ae693
                        p->signal_semaphore = TRUE;
Packit 3ae693
                        while (p->mgr_thread_running) {
Packit 3ae693
                                ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
                                sem_wait(&p->semaphore);
Packit 3ae693
                                ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
                        }
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
                ca_mutex_free(p->outstanding_mutex);
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        if (p->mgr_bus)
Packit 3ae693
                g_object_unref(p->mgr_bus);
Packit 3ae693
Packit 3ae693
        if (p->theme)
Packit 3ae693
                ca_theme_data_free(p->theme);
Packit 3ae693
Packit 3ae693
        if (p->semaphore_allocated)
Packit 3ae693
                sem_destroy(&p->semaphore);
Packit 3ae693
Packit 3ae693
        ca_free(p);
Packit 3ae693
Packit 3ae693
        /* no gst_deinit(), see doc */
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int driver_change_device(ca_context *c, const char *device) {
Packit 3ae693
        ca_return_val_if_fail(c, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int driver_change_props(ca_context *c, ca_proplist *changed, ca_proplist *merged) {
Packit 3ae693
        ca_return_val_if_fail(c, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(changed, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(merged, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
static void
Packit 3ae693
send_eos_msg(struct outstanding *out, int err) {
Packit 3ae693
        struct private *p;
Packit 3ae693
        GstMessage *m;
Packit 3ae693
        GstStructure *s;
Packit 3ae693
Packit 3ae693
        out->dead = TRUE;
Packit 3ae693
        out->err = err;
Packit 3ae693
Packit 3ae693
        p = PRIVATE(out->context);
Packit 3ae693
        s = gst_structure_new("application/eos", "info", G_TYPE_POINTER, out, NULL);
Packit 3ae693
        m = gst_message_new_application (GST_OBJECT (out->pipeline), s);
Packit 3ae693
Packit 3ae693
        gst_bus_post (p->mgr_bus, m);
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
static GstBusSyncReply
Packit 3ae693
bus_cb(GstBus *bus, GstMessage *message, gpointer data) {
Packit 3ae693
        int err;
Packit 3ae693
        struct outstanding *out;
Packit 3ae693
        struct private *p;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(bus, GST_BUS_DROP);
Packit 3ae693
        ca_return_val_if_fail(message, GST_BUS_DROP);
Packit 3ae693
        ca_return_val_if_fail(data, GST_BUS_DROP);
Packit 3ae693
Packit 3ae693
        out = data;
Packit 3ae693
        p = PRIVATE(out->context);
Packit 3ae693
Packit 3ae693
        switch (GST_MESSAGE_TYPE(message)) {
Packit 3ae693
                /* for all elements */
Packit 3ae693
        case GST_MESSAGE_ERROR:
Packit 3ae693
                err = CA_ERROR_SYSTEM;
Packit 3ae693
                break;
Packit 3ae693
        case GST_MESSAGE_EOS:
Packit 3ae693
                /* only respect EOS from the toplevel pipeline */
Packit 3ae693
                if (GST_OBJECT(out->pipeline) != GST_MESSAGE_SRC(message))
Packit 3ae693
                        return GST_BUS_PASS;
Packit 3ae693
Packit 3ae693
                err = CA_SUCCESS;
Packit 3ae693
                break;
Packit 3ae693
        default:
Packit 3ae693
                return GST_BUS_PASS;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        /* Bin finished playback: ask the manager thread to shut it
Packit 3ae693
         * down, since we can't from the sync message handler */
Packit 3ae693
        ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
        if (!out->dead)
Packit 3ae693
                send_eos_msg(out, err);
Packit 3ae693
        ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        return GST_BUS_PASS;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
struct ca_sound_file {
Packit 3ae693
        GstElement *fdsrc;
Packit 3ae693
};
Packit 3ae693
Packit 3ae693
static int ca_gst_sound_file_open(ca_sound_file **_f, const char *fn) {
Packit 3ae693
        int fd;
Packit 3ae693
        ca_sound_file *f;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(_f, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(fn, CA_ERROR_INVALID);
Packit 3ae693
Packit 3ae693
        if ((fd = open(fn, O_RDONLY)) == -1)
Packit 3ae693
                return errno == ENOENT ? CA_ERROR_NOTFOUND : CA_ERROR_SYSTEM;
Packit 3ae693
Packit 3ae693
        if (!(f = ca_new0(ca_sound_file, 1))) {
Packit 3ae693
                close(fd);
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        if (!(f->fdsrc = gst_element_factory_make("fdsrc", NULL))) {
Packit 3ae693
                close(fd);
Packit 3ae693
                ca_free(f);
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        g_object_set(GST_OBJECT(f->fdsrc), "fd", fd, NULL);
Packit 3ae693
        *_f = f;
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
static void on_pad_added(GstElement *element, GstPad *pad, gboolean arg1, gpointer data)
Packit 3ae693
{
Packit 3ae693
        GstStructure *structure;
Packit 3ae693
        GstElement *sinkelement;
Packit 3ae693
        GstCaps *caps;
Packit 3ae693
        GstPad *vpad;
Packit 3ae693
        const char *type;
Packit 3ae693
Packit 3ae693
        sinkelement = GST_ELEMENT(data);
Packit 3ae693
Packit 3ae693
        caps = gst_pad_query_caps(pad, NULL);
Packit 3ae693
        if (gst_caps_is_empty(caps) || gst_caps_is_any(caps)) {
Packit 3ae693
                gst_caps_unref(caps);
Packit 3ae693
                return;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        structure = gst_caps_get_structure(caps, 0);
Packit 3ae693
        type = gst_structure_get_name(structure);
Packit 3ae693
        if (g_str_has_prefix(type, "audio/x-raw") == TRUE) {
Packit 3ae693
                vpad = gst_element_get_static_pad(sinkelement, "sink");
Packit 3ae693
                gst_pad_link(pad, vpad);
Packit 3ae693
                gst_object_unref(vpad);
Packit 3ae693
        }
Packit 3ae693
        gst_caps_unref(caps);
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
static void
Packit 3ae693
send_mgr_exit_msg (struct private *p) {
Packit 3ae693
        GstMessage *m;
Packit 3ae693
        GstStructure *s;
Packit 3ae693
Packit 3ae693
        s = gst_structure_new("application/mgr-exit", NULL);
Packit 3ae693
        m = gst_message_new_application (NULL, s);
Packit 3ae693
Packit 3ae693
        gst_bus_post (p->mgr_bus, m);
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
/* Global manager thread that shuts down GStreamer pipelines when ordered */
Packit 3ae693
static void* thread_func(void *userdata) {
Packit 3ae693
        struct private *p = userdata;
Packit 3ae693
        GstBus *bus = g_object_ref(p->mgr_bus);
Packit 3ae693
Packit 3ae693
        pthread_detach(pthread_self());
Packit 3ae693
Packit 3ae693
        /* Pop messages from the manager bus until we see an exit command */
Packit 3ae693
        do {
Packit 3ae693
                GstMessage *m = gst_bus_timed_pop(bus, GST_CLOCK_TIME_NONE);
Packit 3ae693
                const GstStructure *s;
Packit 3ae693
                const GValue *v;
Packit 3ae693
                struct outstanding *out;
Packit 3ae693
Packit 3ae693
                if (m == NULL)
Packit 3ae693
                        break;
Packit 3ae693
                if (GST_MESSAGE_TYPE(m) != GST_MESSAGE_APPLICATION) {
Packit 3ae693
                        gst_message_unref (m);
Packit 3ae693
                        break;
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                s = gst_message_get_structure(m);
Packit 3ae693
                if (gst_structure_has_name(s, "application/mgr-exit")) {
Packit 3ae693
                        gst_message_unref (m);
Packit 3ae693
                        break;
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                /* Otherwise, this must be an EOS message for an outstanding pipe */
Packit 3ae693
                ca_assert(gst_structure_has_name(s, "application/eos"));
Packit 3ae693
                v  = gst_structure_get_value(s, "info");
Packit 3ae693
                ca_assert(v);
Packit 3ae693
                out = g_value_get_pointer(v);
Packit 3ae693
                ca_assert(out);
Packit 3ae693
Packit 3ae693
                /* Set pipeline back to NULL to close things. By the time this
Packit 3ae693
                 * completes, we can be sure bus_cb won't be called */
Packit 3ae693
                if (gst_element_set_state(out->pipeline, GST_STATE_NULL) ==
Packit 3ae693
                    GST_STATE_CHANGE_FAILURE) {
Packit 3ae693
                        gst_message_unref (m);
Packit 3ae693
                        break;
Packit 3ae693
                }
Packit 3ae693
                if (out->callback)
Packit 3ae693
                        out->callback(out->context, out->id, out->err, out->userdata);
Packit 3ae693
Packit 3ae693
                ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
                CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
Packit 3ae693
                outstanding_free(out);
Packit 3ae693
                ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
                gst_message_unref(m);
Packit 3ae693
        } while (TRUE);
Packit 3ae693
Packit 3ae693
        /* Signal the semaphore and exit */
Packit 3ae693
        ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
        if (p->signal_semaphore)
Packit 3ae693
                sem_post(&p->semaphore);
Packit 3ae693
        p->mgr_thread_running = FALSE;
Packit 3ae693
        ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        gst_bus_set_flushing(bus, TRUE);
Packit 3ae693
        g_object_unref (bus);
Packit 3ae693
        return NULL;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
Packit 3ae693
int driver_play(ca_context *c, uint32_t id, ca_proplist *proplist, ca_finish_callback_t cb, void *userdata) {
Packit 3ae693
        struct private *p;
Packit 3ae693
        struct outstanding *out;
Packit 3ae693
        ca_sound_file *f;
Packit 3ae693
        GstElement *decodebin, *sink, *audioconvert, *audioresample, *abin;
Packit 3ae693
        GstBus *bus;
Packit 3ae693
        GstPad *audiopad;
Packit 3ae693
        int ret;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(c, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
Packit 3ae693
Packit 3ae693
        out = NULL;
Packit 3ae693
        f = NULL;
Packit 3ae693
        sink = NULL;
Packit 3ae693
        decodebin = NULL;
Packit 3ae693
        audioconvert = NULL;
Packit 3ae693
        audioresample = NULL;
Packit 3ae693
        abin = NULL;
Packit 3ae693
        p = PRIVATE(c);
Packit 3ae693
Packit 3ae693
        if ((ret = ca_lookup_sound_with_callback(&f, ca_gst_sound_file_open, NULL, &p->theme, c->props, proplist)) < 0)
Packit 3ae693
                goto fail;
Packit 3ae693
Packit 3ae693
        if (!(out = ca_new0(struct outstanding, 1)))
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
Packit 3ae693
        out->id = id;
Packit 3ae693
        out->callback = cb;
Packit 3ae693
        out->userdata = userdata;
Packit 3ae693
        out->context = c;
Packit 3ae693
Packit 3ae693
        if (!(out->pipeline = gst_pipeline_new(NULL))
Packit 3ae693
            || !(decodebin = gst_element_factory_make("decodebin2", NULL))
Packit 3ae693
            || !(audioconvert = gst_element_factory_make("audioconvert", NULL))
Packit 3ae693
            || !(audioresample = gst_element_factory_make("audioresample", NULL))
Packit 3ae693
            || !(sink = gst_element_factory_make("autoaudiosink", NULL))
Packit 3ae693
            || !(abin = gst_bin_new ("audiobin"))) {
Packit 3ae693
Packit 3ae693
                /* At this point, if there is a failure, free each plugin separately. */
Packit 3ae693
                if (out->pipeline != NULL)
Packit 3ae693
                        g_object_unref (out->pipeline);
Packit 3ae693
                if (decodebin != NULL)
Packit 3ae693
                        g_object_unref(decodebin);
Packit 3ae693
                if (audioconvert != NULL)
Packit 3ae693
                        g_object_unref(audioconvert);
Packit 3ae693
                if (audioresample != NULL)
Packit 3ae693
                        g_object_unref(audioresample);
Packit 3ae693
                if (sink != NULL)
Packit 3ae693
                        g_object_unref(sink);
Packit 3ae693
                if (abin != NULL)
Packit 3ae693
                        g_object_unref(abin);
Packit 3ae693
Packit 3ae693
                ca_free(out);
Packit 3ae693
Packit 3ae693
                ret = CA_ERROR_OOM;
Packit 3ae693
                goto fail;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        bus = gst_pipeline_get_bus(GST_PIPELINE (out->pipeline));
Packit 3ae693
        gst_bus_set_sync_handler(bus, bus_cb, out, NULL);
Packit 3ae693
        gst_object_unref(bus);
Packit 3ae693
Packit 3ae693
        g_signal_connect(decodebin, "new-decoded-pad",
Packit 3ae693
                         G_CALLBACK (on_pad_added), abin);
Packit 3ae693
        gst_bin_add_many(GST_BIN (abin), audioconvert, audioresample, sink, NULL);
Packit 3ae693
        gst_element_link_many(audioconvert, audioresample, sink, NULL);
Packit 3ae693
Packit 3ae693
        audiopad = gst_element_get_static_pad(audioconvert, "sink");
Packit 3ae693
        gst_element_add_pad(abin, gst_ghost_pad_new("sink", audiopad));
Packit 3ae693
        gst_object_unref(audiopad);
Packit 3ae693
Packit 3ae693
        gst_bin_add_many(GST_BIN (out->pipeline),
Packit 3ae693
                         f->fdsrc, decodebin, abin, NULL);
Packit 3ae693
        if (!gst_element_link(f->fdsrc, decodebin)) {
Packit 3ae693
                /* Bin now owns the fdsrc... */
Packit 3ae693
                f->fdsrc = NULL;
Packit 3ae693
Packit 3ae693
                outstanding_free(out);
Packit 3ae693
                ret = CA_ERROR_OOM;
Packit 3ae693
                goto fail;
Packit 3ae693
        }
Packit 3ae693
        /* Bin now owns the fdsrc... */
Packit 3ae693
        f->fdsrc = NULL;
Packit 3ae693
Packit 3ae693
        ca_free(f);
Packit 3ae693
        f = NULL;
Packit 3ae693
Packit 3ae693
        ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
        CA_LLIST_PREPEND(struct outstanding, p->outstanding, out);
Packit 3ae693
        ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        if (gst_element_set_state(out->pipeline,
Packit 3ae693
                                  GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
Packit 3ae693
                ret = CA_ERROR_NOTAVAILABLE;
Packit 3ae693
                goto fail;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
Packit 3ae693
Packit 3ae693
fail:
Packit 3ae693
        if (f && f->fdsrc)
Packit 3ae693
                gst_object_unref(f->fdsrc);
Packit 3ae693
Packit 3ae693
        if (f)
Packit 3ae693
                ca_free(f);
Packit 3ae693
Packit 3ae693
        return ret;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int driver_cancel(ca_context *c, uint32_t id) {
Packit 3ae693
        struct private *p;
Packit 3ae693
        struct outstanding *out = NULL;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(c, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
Packit 3ae693
Packit 3ae693
        p = PRIVATE(c);
Packit 3ae693
Packit 3ae693
        ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        for (out = p->outstanding; out;/* out = out->next*/) {
Packit 3ae693
                struct outstanding *next;
Packit 3ae693
Packit 3ae693
                if (out->id != id || out->pipeline == NULL || out->dead == TRUE) {
Packit 3ae693
                        out = out->next;
Packit 3ae693
                        continue;
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                if (gst_element_set_state(out->pipeline, GST_STATE_NULL) ==
Packit 3ae693
                    GST_STATE_CHANGE_FAILURE)
Packit 3ae693
                        goto error;
Packit 3ae693
Packit 3ae693
                if (out->callback)
Packit 3ae693
                        out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata);
Packit 3ae693
                next = out->next;
Packit 3ae693
                CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
Packit 3ae693
                outstanding_free(out);
Packit 3ae693
                out = next;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
Packit 3ae693
Packit 3ae693
error:
Packit 3ae693
        ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
        return CA_ERROR_SYSTEM;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int driver_cache(ca_context *c, ca_proplist *proplist) {
Packit 3ae693
        ca_return_val_if_fail(c, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(proplist, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(PRIVATE(c), CA_ERROR_STATE);
Packit 3ae693
Packit 3ae693
        return CA_ERROR_NOTSUPPORTED;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int driver_playing(ca_context *c, uint32_t id, int *playing) {
Packit 3ae693
        struct private *p;
Packit 3ae693
        struct outstanding *out;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(c, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(c->private, CA_ERROR_STATE);
Packit 3ae693
        ca_return_val_if_fail(playing, CA_ERROR_INVALID);
Packit 3ae693
Packit 3ae693
        p = PRIVATE(c);
Packit 3ae693
Packit 3ae693
        *playing = 0;
Packit 3ae693
Packit 3ae693
        ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        for (out = p->outstanding; out; out = out->next) {
Packit 3ae693
Packit 3ae693
                if (out->id != id || out->pipeline == NULL || out->dead == TRUE)
Packit 3ae693
                        continue;
Packit 3ae693
Packit 3ae693
                *playing = 1;
Packit 3ae693
                break;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
Packit 3ae693
}