Blame src/oss.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 Lennart Poettering
Packit 3ae693
                 Joe Marcus Clarke
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 <sys/types.h>
Packit 3ae693
#include <sys/ioctl.h>
Packit 3ae693
#include <sys/param.h>
Packit 3ae693
#include <sys/uio.h>
Packit 3ae693
#include <math.h>
Packit 3ae693
#include <unistd.h>
Packit 3ae693
#include <errno.h>
Packit 3ae693
#include <fcntl.h>
Packit 3ae693
#include <stdlib.h>
Packit 3ae693
#include <poll.h>
Packit 3ae693
#include <pthread.h>
Packit 3ae693
#include <semaphore.h>
Packit 3ae693
Packit 3ae693
#ifdef HAVE_MACHINE_SOUNDCARD_H
Packit 3ae693
#  include <machine/soundcard.h>
Packit 3ae693
#else
Packit 3ae693
#  ifdef HAVE_SOUNDCARD_H
Packit 3ae693
#    include <soundcard.h>
Packit 3ae693
#  else
Packit 3ae693
#    include <sys/soundcard.h>
Packit 3ae693
#  endif
Packit 3ae693
#endif
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 private;
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
        ca_finish_callback_t callback;
Packit 3ae693
        void *userdata;
Packit 3ae693
        ca_sound_file *file;
Packit 3ae693
        int pcm;
Packit 3ae693
        int pipe_fd[2];
Packit 3ae693
        ca_context *context;
Packit 3ae693
};
Packit 3ae693
Packit 3ae693
struct private {
Packit 3ae693
        ca_theme_data *theme;
Packit 3ae693
        ca_mutex *outstanding_mutex;
Packit 3ae693
        ca_bool_t signal_semaphore;
Packit 3ae693
        sem_t semaphore;
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 outstanding_free(struct outstanding *o) {
Packit 3ae693
        ca_assert(o);
Packit 3ae693
Packit 3ae693
        if (o->pipe_fd[1] >= 0)
Packit 3ae693
                close(o->pipe_fd[1]);
Packit 3ae693
Packit 3ae693
        if (o->pipe_fd[0] >= 0)
Packit 3ae693
                close(o->pipe_fd[0]);
Packit 3ae693
Packit 3ae693
        if (o->file)
Packit 3ae693
                ca_sound_file_close(o->file);
Packit 3ae693
Packit 3ae693
        if (o->pcm >= 0) {
Packit 3ae693
                close(o->pcm);
Packit 3ae693
                o->pcm = -1;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        ca_free(o);
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
int driver_open(ca_context *c) {
Packit 3ae693
        struct private *p;
Packit 3ae693
Packit 3ae693
        ca_return_val_if_fail(c, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(!c->driver || ca_streq(c->driver, "oss"), CA_ERROR_NODRIVER);
Packit 3ae693
        ca_return_val_if_fail(!PRIVATE(c), CA_ERROR_STATE);
Packit 3ae693
Packit 3ae693
        if (!(c->private = p = ca_new0(struct private, 1)))
Packit 3ae693
                return CA_ERROR_OOM;
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
Packit 3ae693
        p->semaphore_allocated = 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(c->private, 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
                for (out = p->outstanding; out; out = out->next) {
Packit 3ae693
Packit 3ae693
                        if (out->dead)
Packit 3ae693
                                continue;
Packit 3ae693
Packit 3ae693
                        out->dead = TRUE;
Packit 3ae693
Packit 3ae693
                        if (out->callback)
Packit 3ae693
                                out->callback(c, out->id, CA_ERROR_DESTROYED, out->userdata);
Packit 3ae693
Packit 3ae693
                        /* This will cause the thread to wakeup and terminate */
Packit 3ae693
                        if (out->pipe_fd[1] >= 0) {
Packit 3ae693
                                close(out->pipe_fd[1]);
Packit 3ae693
                                out->pipe_fd[1] = -1;
Packit 3ae693
                        }
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                if (p->semaphore_allocated) {
Packit 3ae693
                        /* Now wait until all players are destroyed */
Packit 3ae693
                        p->signal_semaphore = TRUE;
Packit 3ae693
                        while (p->outstanding) {
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->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
        c->private = NULL;
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(c->private, 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
Packit 3ae693
        return CA_SUCCESS;
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
Packit 3ae693
        return CA_ERROR_NOTSUPPORTED;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
static int translate_error(int error) {
Packit 3ae693
Packit 3ae693
        switch (error) {
Packit 3ae693
        case ENODEV:
Packit 3ae693
        case ENOENT:
Packit 3ae693
                return CA_ERROR_NOTFOUND;
Packit 3ae693
        case EACCES:
Packit 3ae693
        case EPERM:
Packit 3ae693
                return CA_ERROR_ACCESS;
Packit 3ae693
        case ENOMEM:
Packit 3ae693
                return CA_ERROR_OOM;
Packit 3ae693
        case EBUSY:
Packit 3ae693
                return CA_ERROR_NOTAVAILABLE;
Packit 3ae693
        case EINVAL:
Packit 3ae693
                return CA_ERROR_INVALID;
Packit 3ae693
        case ENOSYS:
Packit 3ae693
                return CA_ERROR_NOTSUPPORTED;
Packit 3ae693
        default:
Packit 3ae693
                if (ca_debug())
Packit 3ae693
                        fprintf(stderr, "Got unhandled error from OSS: %s\n", strerror(error));
Packit 3ae693
                return CA_ERROR_IO;
Packit 3ae693
        }
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
static int open_oss(ca_context *c, struct outstanding *out) {
Packit 3ae693
        int mode, val, test, ret;
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(out, CA_ERROR_INVALID);
Packit 3ae693
Packit 3ae693
        /* In OSS we have no way to configure a channel mapping for
Packit 3ae693
         * multichannel streams. We cannot support those files hence */
Packit 3ae693
        ca_return_val_if_fail(ca_sound_file_get_nchannels(out->file) <= 2, CA_ERROR_NOTSUPPORTED);
Packit 3ae693
Packit 3ae693
        if ((out->pcm = open(c->device ? c->device : "/dev/dsp", O_WRONLY | O_NONBLOCK, 0)) < 0)
Packit 3ae693
                goto finish_errno;
Packit 3ae693
Packit 3ae693
        if ((mode = fcntl(out->pcm, F_GETFL)) < 0)
Packit 3ae693
                goto finish_errno;
Packit 3ae693
Packit 3ae693
        mode &= ~O_NONBLOCK;
Packit 3ae693
Packit 3ae693
        if (fcntl(out->pcm, F_SETFL, mode) < 0)
Packit 3ae693
                goto finish_errno;
Packit 3ae693
Packit 3ae693
        switch (ca_sound_file_get_sample_type(out->file)) {
Packit 3ae693
        case CA_SAMPLE_U8:
Packit 3ae693
                val = AFMT_U8;
Packit 3ae693
                break;
Packit 3ae693
        case CA_SAMPLE_S16NE:
Packit 3ae693
                val = AFMT_S16_NE;
Packit 3ae693
                break;
Packit 3ae693
        case CA_SAMPLE_S16RE:
Packit 3ae693
#if __BYTE_ORDER == __LITTLE_ENDIAN
Packit 3ae693
                val = AFMT_S16_BE;
Packit 3ae693
#else
Packit 3ae693
                val = AFMT_S16_LE;
Packit 3ae693
#endif
Packit 3ae693
                break;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        test = val;
Packit 3ae693
        if (ioctl(out->pcm, SNDCTL_DSP_SETFMT, &val) < 0)
Packit 3ae693
                goto finish_errno;
Packit 3ae693
Packit 3ae693
        if (val != test) {
Packit 3ae693
                ret = CA_ERROR_NOTSUPPORTED;
Packit 3ae693
                goto finish_ret;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        test = val = (int) ca_sound_file_get_nchannels(out->file);
Packit 3ae693
        if (ioctl(out->pcm, SNDCTL_DSP_CHANNELS, &val) < 0)
Packit 3ae693
                goto finish_errno;
Packit 3ae693
Packit 3ae693
        if (val != test) {
Packit 3ae693
                ret = CA_ERROR_NOTSUPPORTED;
Packit 3ae693
                goto finish_ret;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        test = val = (int) ca_sound_file_get_rate(out->file);
Packit 3ae693
        if (ioctl(out->pcm, SNDCTL_DSP_SPEED, &val) < 0)
Packit 3ae693
                goto finish_errno;
Packit 3ae693
Packit 3ae693
        /* Check to make sure the configured rate is close enough to the
Packit 3ae693
         * requested rate. */
Packit 3ae693
        if (fabs((double) (val - test)) > test * 0.05) {
Packit 3ae693
                ret = CA_ERROR_NOTSUPPORTED;
Packit 3ae693
                goto finish_ret;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
Packit 3ae693
Packit 3ae693
finish_errno:
Packit 3ae693
        return translate_error(errno);
Packit 3ae693
Packit 3ae693
finish_ret:
Packit 3ae693
        return ret;
Packit 3ae693
}
Packit 3ae693
Packit 3ae693
#define BUFSIZE (4*1024)
Packit 3ae693
Packit 3ae693
static void* thread_func(void *userdata) {
Packit 3ae693
        struct outstanding *out = userdata;
Packit 3ae693
        int ret;
Packit 3ae693
        void *data, *d = NULL;
Packit 3ae693
        size_t fs, data_size;
Packit 3ae693
        size_t nbytes = 0;
Packit 3ae693
        struct pollfd pfd[2];
Packit 3ae693
        nfds_t n_pfd = 2;
Packit 3ae693
        struct private *p;
Packit 3ae693
Packit 3ae693
        p = PRIVATE(out->context);
Packit 3ae693
Packit 3ae693
        pthread_detach(pthread_self());
Packit 3ae693
Packit 3ae693
        fs = ca_sound_file_frame_size(out->file);
Packit 3ae693
        data_size = (BUFSIZE/fs)*fs;
Packit 3ae693
Packit 3ae693
        if (!(data = ca_malloc(data_size))) {
Packit 3ae693
                ret = CA_ERROR_OOM;
Packit 3ae693
                goto finish;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        pfd[0].fd = out->pipe_fd[0];
Packit 3ae693
        pfd[0].events = POLLIN;
Packit 3ae693
        pfd[0].revents = 0;
Packit 3ae693
        pfd[1].fd = out->pcm;
Packit 3ae693
        pfd[1].events = POLLOUT;
Packit 3ae693
        pfd[1].revents = 0;
Packit 3ae693
Packit 3ae693
        for (;;) {
Packit 3ae693
                ssize_t bytes_written;
Packit 3ae693
Packit 3ae693
                if (out->dead)
Packit 3ae693
                        break;
Packit 3ae693
Packit 3ae693
                if (poll(pfd, n_pfd, -1) < 0) {
Packit 3ae693
                        ret = CA_ERROR_SYSTEM;
Packit 3ae693
                        goto finish;
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                /* We have been asked to shut down */
Packit 3ae693
                if (pfd[0].revents)
Packit 3ae693
                        break;
Packit 3ae693
Packit 3ae693
                if (pfd[1].revents != POLLOUT) {
Packit 3ae693
                        ret = CA_ERROR_IO;
Packit 3ae693
                        goto finish;
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                if (nbytes <= 0) {
Packit 3ae693
                        nbytes = data_size;
Packit 3ae693
Packit 3ae693
                        if ((ret = ca_sound_file_read_arbitrary(out->file, data, &nbytes)) < 0)
Packit 3ae693
                                goto finish;
Packit 3ae693
Packit 3ae693
                        d = data;
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                if (nbytes <= 0)
Packit 3ae693
                        break;
Packit 3ae693
Packit 3ae693
                if ((bytes_written = write(out->pcm, d, nbytes)) <= 0) {
Packit 3ae693
                        ret = translate_error(errno);
Packit 3ae693
                        goto finish;
Packit 3ae693
                }
Packit 3ae693
Packit 3ae693
                nbytes -= (size_t) bytes_written;
Packit 3ae693
                d = (uint8_t*) d + (size_t) bytes_written;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        ret = CA_SUCCESS;
Packit 3ae693
Packit 3ae693
finish:
Packit 3ae693
Packit 3ae693
        ca_free(data);
Packit 3ae693
Packit 3ae693
        if (!out->dead)
Packit 3ae693
                if (out->callback)
Packit 3ae693
                        out->callback(out->context, out->id, ret, out->userdata);
Packit 3ae693
Packit 3ae693
        ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
Packit 3ae693
Packit 3ae693
        if (!p->outstanding && p->signal_semaphore)
Packit 3ae693
                sem_post(&p->semaphore);
Packit 3ae693
Packit 3ae693
        outstanding_free(out);
Packit 3ae693
Packit 3ae693
        ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        return NULL;
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 = NULL;
Packit 3ae693
        int ret;
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(proplist, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
Packit 3ae693
        ca_return_val_if_fail(c->private, CA_ERROR_STATE);
Packit 3ae693
Packit 3ae693
        p = PRIVATE(c);
Packit 3ae693
Packit 3ae693
        if (!(out = ca_new0(struct outstanding, 1))) {
Packit 3ae693
                ret = CA_ERROR_OOM;
Packit 3ae693
                goto finish;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        out->context = c;
Packit 3ae693
        out->id = id;
Packit 3ae693
        out->callback = cb;
Packit 3ae693
        out->userdata = userdata;
Packit 3ae693
        out->pipe_fd[0] = out->pipe_fd[1] = -1;
Packit 3ae693
        out->pcm = -1;
Packit 3ae693
Packit 3ae693
        if (pipe(out->pipe_fd) < 0) {
Packit 3ae693
                ret = CA_ERROR_SYSTEM;
Packit 3ae693
                goto finish;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        if ((ret = ca_lookup_sound(&out->file, NULL, &p->theme, c->props, proplist)) < 0)
Packit 3ae693
                goto finish;
Packit 3ae693
Packit 3ae693
        if ((ret = open_oss(c, out)) < 0)
Packit 3ae693
                goto finish;
Packit 3ae693
Packit 3ae693
        /* OK, we're ready to go, so let's add this to our list */
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 (pthread_create(&thread, NULL, thread_func, out) < 0) {
Packit 3ae693
                ret = CA_ERROR_OOM;
Packit 3ae693
Packit 3ae693
                ca_mutex_lock(p->outstanding_mutex);
Packit 3ae693
                CA_LLIST_REMOVE(struct outstanding, p->outstanding, out);
Packit 3ae693
                ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
                goto finish;
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        ret = CA_SUCCESS;
Packit 3ae693
Packit 3ae693
finish:
Packit 3ae693
Packit 3ae693
        /* We keep the outstanding struct around if we need clean up later to */
Packit 3ae693
        if (ret != CA_SUCCESS)
Packit 3ae693
                outstanding_free(out);
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;
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
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
Packit 3ae693
                if (out->id != id)
Packit 3ae693
                        continue;
Packit 3ae693
Packit 3ae693
                if (out->dead)
Packit 3ae693
                        continue;
Packit 3ae693
Packit 3ae693
                out->dead = TRUE;
Packit 3ae693
Packit 3ae693
                if (out->callback)
Packit 3ae693
                        out->callback(c, out->id, CA_ERROR_CANCELED, out->userdata);
Packit 3ae693
Packit 3ae693
                /* This will cause the thread to wakeup and terminate */
Packit 3ae693
                if (out->pipe_fd[1] >= 0) {
Packit 3ae693
                        close(out->pipe_fd[1]);
Packit 3ae693
                        out->pipe_fd[1] = -1;
Packit 3ae693
                }
Packit 3ae693
        }
Packit 3ae693
Packit 3ae693
        ca_mutex_unlock(p->outstanding_mutex);
Packit 3ae693
Packit 3ae693
        return CA_SUCCESS;
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->dead ||
Packit 3ae693
                    out->id != id)
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
}