|
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 |
|
|
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 <stdarg.h>
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
#include "canberra.h"
|
|
Packit |
3ae693 |
#include "common.h"
|
|
Packit |
3ae693 |
#include "malloc.h"
|
|
Packit |
3ae693 |
#include "driver.h"
|
|
Packit |
3ae693 |
#include "proplist.h"
|
|
Packit |
3ae693 |
#include "macro.h"
|
|
Packit |
3ae693 |
#include "fork-detect.h"
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* SECTION:canberra
|
|
Packit |
3ae693 |
* @short_description: General libcanberra API
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* libcanberra defines a simple abstract interface for playing event sounds.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* libcanberra relies on the XDG sound naming specification for
|
|
Packit |
3ae693 |
* identifying event sounds. On Unix/Linux the right sound to play is
|
|
Packit |
3ae693 |
* found via the mechanisms defined in the XDG sound themeing
|
|
Packit |
3ae693 |
* specification. On other systems the XDG sound name is translated to
|
|
Packit |
3ae693 |
* the native sound id for the operating system.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* An event sound is triggered via libcanberra by calling the
|
|
Packit |
3ae693 |
* ca_context_play() function on a previously created ca_context
|
|
Packit |
3ae693 |
* object. The ca_context_play() takes a list of key-value pairs that
|
|
Packit |
3ae693 |
* describe the event sound to generate as closely as possible. The
|
|
Packit |
3ae693 |
* most important property is %CA_PROP_EVENT_ID which defines the XDG
|
|
Packit |
3ae693 |
* sound name for the sound to play.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* libcanberra is not a generic event abstraction system. It's only
|
|
Packit |
3ae693 |
* purpose is playing sounds -- however in a very elaborate way. As
|
|
Packit |
3ae693 |
* much information about the context the sound is triggered from
|
|
Packit |
3ae693 |
* shall be supplied to the sound system as possible, so that it can
|
|
Packit |
3ae693 |
* replace the sound with some other kind of feedback for a11y
|
|
Packit |
3ae693 |
* cases. Also this additional information can be used to enhance user
|
|
Packit |
3ae693 |
* experience (e.g. by positioning sounds in space depending on the
|
|
Packit |
3ae693 |
* place on the screen the sound was triggered from, and similar
|
|
Packit |
3ae693 |
* uses).
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* The set of properties defined for event sounds is extensible and
|
|
Packit |
3ae693 |
* shared with other audio systems, such as PulseAudio. Some of
|
|
Packit |
3ae693 |
* the properties that may be set are specific to an application, to a
|
|
Packit |
3ae693 |
* window, to an input event or to the media being played back.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* The user can attach a set of properties to the context itself,
|
|
Packit |
3ae693 |
* which is than automatically inherited by each sample being played
|
|
Packit |
3ae693 |
* back. (ca_context_change_props()).
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Some of the properties can be filled in by libcanberra or one of
|
|
Packit |
3ae693 |
* its backends automatically and thus need not be be filled in by the
|
|
Packit |
3ae693 |
* application (such as %CA_PROP_APPLICATION_PROCESS_ID and
|
|
Packit |
3ae693 |
* friends). However the application can always overwrite any of these
|
|
Packit |
3ae693 |
* implicit properties.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* libcanberra is thread-safe and OOM-safe (as far as the backend
|
|
Packit |
3ae693 |
* allows this). It is not async-signal safe.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Most libcanberra functions return an integer that indicates success
|
|
Packit |
3ae693 |
* when 0 (%CA_SUCCESS) or an error when negative. In the latter case
|
|
Packit |
3ae693 |
* ca_strerror() can be used to convert this code into a human
|
|
Packit |
3ae693 |
* readable string.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* libcanberra property names need to be in 7bit ASCII, string
|
|
Packit |
3ae693 |
* property values UTF8.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Optionally a libcanberra backend can support caching of sounds in a
|
|
Packit |
3ae693 |
* sound system. If this functionality is used, the latencies for
|
|
Packit |
3ae693 |
* event sound playback can be much smaller and fewer resources are
|
|
Packit |
3ae693 |
* needed to start playback. If a backend does not support cacheing,
|
|
Packit |
3ae693 |
* the respective functions will return an error code of
|
|
Packit |
3ae693 |
* %CA_ERROR_NOTSUPPORTED.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* It is highly recommended that the application sets the
|
|
Packit |
3ae693 |
* %CA_PROP_APPLICATION_NAME, %CA_PROP_APPLICATION_ID,
|
|
Packit |
3ae693 |
* %CA_PROP_APPLICATION_ICON_NAME/%CA_PROP_APPLICATION_ICON properties
|
|
Packit |
3ae693 |
* immediately after creating the ca_context, before calling
|
|
Packit |
3ae693 |
* ca_context_open() or ca_context_play().
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Its is highly recommended to pass at least %CA_PROP_EVENT_ID,
|
|
Packit |
3ae693 |
* %CA_PROP_EVENT_DESCRIPTION to ca_context_play() for each event
|
|
Packit |
3ae693 |
* sound generated. For sound events based on mouse inputs events
|
|
Packit |
3ae693 |
* %CA_PROP_EVENT_MOUSE_X, %CA_PROP_EVENT_MOUSE_Y, %CA_PROP_EVENT_MOUSE_HPOS,
|
|
Packit |
3ae693 |
* %CA_PROP_EVENT_MOUSE_VPOS, %CA_PROP_EVENT_MOUSE_BUTTON should be
|
|
Packit |
3ae693 |
* passed. For sound events attached to a widget on the screen, the
|
|
Packit |
3ae693 |
* %CA_PROP_WINDOW_xxx properties should be set.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_create:
|
|
Packit |
3ae693 |
* @c: A pointer wheere to fill in the newly created context object.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Create an (unconnected) context object. This call will not connect
|
|
Packit |
3ae693 |
* to the sound system, calling this function might even suceed if no
|
|
Packit |
3ae693 |
* working driver backend is available. To find out if one is
|
|
Packit |
3ae693 |
* available call ca_context_open().
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_context_create(ca_context **_c) {
|
|
Packit |
3ae693 |
ca_context *c;
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
const char *d;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(_c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(c = ca_new0(ca_context, 1)))
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!(c->mutex = ca_mutex_new())) {
|
|
Packit |
3ae693 |
ca_context_destroy(c);
|
|
Packit |
3ae693 |
return CA_ERROR_OOM;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = ca_proplist_create(&c->props)) < 0) {
|
|
Packit |
3ae693 |
ca_context_destroy(c);
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((d = getenv("CANBERRA_DRIVER"))) {
|
|
Packit |
3ae693 |
if ((ret = ca_context_set_driver(c, d)) < 0) {
|
|
Packit |
3ae693 |
ca_context_destroy(c);
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((d = getenv("CANBERRA_DEVICE"))) {
|
|
Packit |
3ae693 |
if ((ret = ca_context_change_device(c, d)) < 0) {
|
|
Packit |
3ae693 |
ca_context_destroy(c);
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
*_c = c;
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_destroy:
|
|
Packit |
3ae693 |
* @c: the context to destroy.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Destroy a (connected or unconnected) context object.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
int ca_context_destroy(ca_context *c) {
|
|
Packit |
3ae693 |
int ret = CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* There's no locking necessary here, because the application is
|
|
Packit |
3ae693 |
* broken anyway if it destructs this object in one thread and
|
|
Packit |
3ae693 |
* still is calling a method of it in another. */
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (c->opened)
|
|
Packit |
3ae693 |
ret = driver_destroy(c);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (c->props)
|
|
Packit |
3ae693 |
ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (c->mutex)
|
|
Packit |
3ae693 |
ca_mutex_free(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_free(c->driver);
|
|
Packit |
3ae693 |
ca_free(c->device);
|
|
Packit |
3ae693 |
ca_free(c);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_set_driver:
|
|
Packit |
3ae693 |
* @c: the context to change the backend driver for
|
|
Packit |
3ae693 |
* @driver: the backend driver to use (e.g. "alsa", "pulse", "null", ...)
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Specify the backend driver used. This function may not be called again after
|
|
Packit |
3ae693 |
* ca_context_open() suceeded. This function might suceed even when
|
|
Packit |
3ae693 |
* the specified driver backend is not available. Use
|
|
Packit |
3ae693 |
* ca_context_open() to find out whether the backend is available.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
int ca_context_set_driver(ca_context *c, const char *driver) {
|
|
Packit |
3ae693 |
char *n;
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_mutex_lock(c->mutex);
|
|
Packit |
3ae693 |
ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!driver)
|
|
Packit |
3ae693 |
n = NULL;
|
|
Packit |
3ae693 |
else if (!(n = ca_strdup(driver))) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_OOM;
|
|
Packit |
3ae693 |
goto fail;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_free(c->driver);
|
|
Packit |
3ae693 |
c->driver = n;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
fail:
|
|
Packit |
3ae693 |
ca_mutex_unlock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_change_device:
|
|
Packit |
3ae693 |
* @c: the context to change the backend device for
|
|
Packit |
3ae693 |
* @device: the backend device to use, in a format that is specific to the backend.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Specify the backend device to use. This function may be called not be called after
|
|
Packit |
3ae693 |
* ca_context_open() suceeded. This function might suceed even when
|
|
Packit |
3ae693 |
* the specified driver backend is not available. Use
|
|
Packit |
3ae693 |
* ca_context_open() to find out whether the backend is available
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Depending on the backend use this might or might not cause all
|
|
Packit |
3ae693 |
* currently playing event sounds to be moved to the new device..
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
int ca_context_change_device(ca_context *c, const char *device) {
|
|
Packit |
3ae693 |
char *n;
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_mutex_lock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (!device)
|
|
Packit |
3ae693 |
n = NULL;
|
|
Packit |
3ae693 |
else if (!(n = ca_strdup(device))) {
|
|
Packit |
3ae693 |
ret = CA_ERROR_OOM;
|
|
Packit |
3ae693 |
goto fail;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = c->opened ? driver_change_device(c, n) : CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (ret == CA_SUCCESS) {
|
|
Packit |
3ae693 |
ca_free(c->device);
|
|
Packit |
3ae693 |
c->device = n;
|
|
Packit |
3ae693 |
} else
|
|
Packit |
3ae693 |
ca_free(n);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
fail:
|
|
Packit |
3ae693 |
ca_mutex_unlock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
static int context_open_unlocked(ca_context *c) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (c->opened)
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = driver_open(c)) == CA_SUCCESS)
|
|
Packit |
3ae693 |
c->opened = TRUE;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_open:
|
|
Packit |
3ae693 |
* @c: the context to connect.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Connect the context to the sound system. This call is implicitly
|
|
Packit |
3ae693 |
* called in ca_context_play() or ca_context_cache() if not called
|
|
Packit |
3ae693 |
* explicitly. It is recommended to initialize application properties
|
|
Packit |
3ae693 |
* with ca_context_change_props() before calling this function.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
int ca_context_open(ca_context *c) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_mutex_lock(c->mutex);
|
|
Packit |
3ae693 |
ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = context_open_unlocked(c);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_unlock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_change_props:
|
|
Packit |
3ae693 |
* @c: the context to set the properties on.
|
|
Packit |
3ae693 |
* @...: the list of string pairs for the properties. Needs to be a NULL terminated list.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Write one or more string properties to the context object. Requires
|
|
Packit |
3ae693 |
* final NULL sentinel. Properties set like this will be attached to
|
|
Packit |
3ae693 |
* both the client object of the sound server and to all event sounds
|
|
Packit |
3ae693 |
* played or cached. It is recommended to call this function at least
|
|
Packit |
3ae693 |
* once before calling ca_context_open(), so that the initial
|
|
Packit |
3ae693 |
* application properties are set properly before the initial
|
|
Packit |
3ae693 |
* connection to the sound system. This function can be called both
|
|
Packit |
3ae693 |
* before and after the ca_context_open() call. Properties that have
|
|
Packit |
3ae693 |
* already been set before will be overwritten.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_context_change_props(ca_context *c, ...) {
|
|
Packit |
3ae693 |
va_list ap;
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
ca_proplist *p = NULL;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
va_start(ap, c);
|
|
Packit |
3ae693 |
ret = ca_proplist_from_ap(&p, ap);
|
|
Packit |
3ae693 |
va_end(ap);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (ret < 0)
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = ca_context_change_props_full(c, p);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert_se(ca_proplist_destroy(p) == 0);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_change_props_full:
|
|
Packit |
3ae693 |
* @c: the context to set the properties on.
|
|
Packit |
3ae693 |
* @p: the property list to set.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Similar to ca_context_change_props(), but takes a ca_proplist
|
|
Packit |
3ae693 |
* instead of a variable list of properties. Can be used to set binary
|
|
Packit |
3ae693 |
* properties such as %CA_PROP_APPLICATION_ICON.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_context_change_props_full(ca_context *c, ca_proplist *p) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
ca_proplist *merged;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(p, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = ca_proplist_merge(&merged, c->props, p)) < 0)
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = c->opened ? driver_change_props(c, p, merged) : CA_SUCCESS;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (ret == CA_SUCCESS) {
|
|
Packit |
3ae693 |
ca_assert_se(ca_proplist_destroy(c->props) == CA_SUCCESS);
|
|
Packit |
3ae693 |
c->props = merged;
|
|
Packit |
3ae693 |
} else
|
|
Packit |
3ae693 |
ca_assert_se(ca_proplist_destroy(merged) == CA_SUCCESS);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_unlock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_play:
|
|
Packit |
3ae693 |
* @c: the context to play the event sound on
|
|
Packit |
3ae693 |
* @id: an integer id this sound can later be identified with when calling ca_context_cancel()
|
|
Packit |
3ae693 |
* @...: additional properties for this sound event.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Play one event sound. id can be any numeric value which later can
|
|
Packit |
3ae693 |
* be used to cancel an event sound that is currently being
|
|
Packit |
3ae693 |
* played. You may use the same id twice or more times if you want to
|
|
Packit |
3ae693 |
* cancel multiple event sounds with a single ca_context_cancel() call
|
|
Packit |
3ae693 |
* at once. It is recommended to pass 0 for the id if the event sound
|
|
Packit |
3ae693 |
* shall never be canceled. If the requested sound is not cached in
|
|
Packit |
3ae693 |
* the server yet this call might result in the sample being uploaded
|
|
Packit |
3ae693 |
* temporarily or permanently (this may be controlled with %CA_PROP_CANBERRA_CACHE_CONTROL). This function will start playback
|
|
Packit |
3ae693 |
* in the background. It will not wait until playback
|
|
Packit |
3ae693 |
* completed. Depending on the backend used a sound that is started
|
|
Packit |
3ae693 |
* shortly before your application terminates might or might not continue to
|
|
Packit |
3ae693 |
* play after your application terminated. If you want to make sure
|
|
Packit |
3ae693 |
* that all sounds finish to play you need to wait synchronously for
|
|
Packit |
3ae693 |
* the callback function of ca_context_play_full() to be called before you
|
|
Packit |
3ae693 |
* terminate your application.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* The sample to play is identified by the %CA_PROP_EVENT_ID
|
|
Packit |
3ae693 |
* property. If it is already cached in the server the cached version
|
|
Packit |
3ae693 |
* is played. The properties passed in this call are merged with the
|
|
Packit |
3ae693 |
* properties supplied when the sample was cached (if applicable)
|
|
Packit |
3ae693 |
* and the context properties as set with ca_context_change_props().
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* If %CA_PROP_EVENT_ID is not defined the sound file passed in the
|
|
Packit |
3ae693 |
* %CA_PROP_MEDIA_FILENAME is played.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* On Linux/Unix the right sound to play is determined according to
|
|
Packit |
3ae693 |
* %CA_PROP_EVENT_ID,
|
|
Packit |
3ae693 |
* %CA_PROP_APPLICATION_LANGUAGE/%CA_PROP_MEDIA_LANGUAGE, the system
|
|
Packit |
3ae693 |
* locale, %CA_PROP_CANBERRA_XDG_THEME_NAME and
|
|
Packit |
3ae693 |
* %CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE, following the XDG Sound
|
|
Packit |
3ae693 |
* Theming Specification. On non-Unix systems the native event sound
|
|
Packit |
3ae693 |
* that matches the XDG sound name in %CA_PROP_EVENT_ID is played.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_context_play(ca_context *c, uint32_t id, ...) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
va_list ap;
|
|
Packit |
3ae693 |
ca_proplist *p = NULL;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
va_start(ap, id);
|
|
Packit |
3ae693 |
ret = ca_proplist_from_ap(&p, ap);
|
|
Packit |
3ae693 |
va_end(ap);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (ret < 0)
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = ca_context_play_full(c, id, p, NULL, NULL);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert_se(ca_proplist_destroy(p) == 0);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_play_full:
|
|
Packit |
3ae693 |
* @c: the context to play the event sound on
|
|
Packit |
3ae693 |
* @id: an integer id this sound can be later be identified with when calling ca_context_cancel() or when the callback is called.
|
|
Packit |
3ae693 |
* @p: A property list of properties for this event sound
|
|
Packit |
3ae693 |
* @cb: A callback to call when this sound event sucessfully finished playing or when an error occured during playback.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Play one event sound, and call the specified callback function when
|
|
Packit |
3ae693 |
* completed. See ca_finish_callback_t for the semantics the callback
|
|
Packit |
3ae693 |
* is called in. Also see ca_context_play().
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* It is guaranteed that the callback is called exactly once if
|
|
Packit |
3ae693 |
* ca_context_play_full() returns CA_SUCCESS. You thus may safely pass
|
|
Packit |
3ae693 |
* allocated memory to the callback and assume that it is freed
|
|
Packit |
3ae693 |
* properly.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
const char *t;
|
|
Packit |
3ae693 |
ca_bool_t enabled = TRUE;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(p, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!userdata || cb, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) ||
|
|
Packit |
3ae693 |
ca_proplist_contains(c->props, CA_PROP_EVENT_ID) ||
|
|
Packit |
3ae693 |
ca_proplist_contains(p, CA_PROP_MEDIA_FILENAME) ||
|
|
Packit |
3ae693 |
ca_proplist_contains(c->props, CA_PROP_MEDIA_FILENAME), CA_ERROR_INVALID, c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(c->props->mutex);
|
|
Packit |
3ae693 |
if ((t = ca_proplist_gets_unlocked(c->props, CA_PROP_CANBERRA_ENABLE)))
|
|
Packit |
3ae693 |
enabled = !ca_streq(t, "0");
|
|
Packit |
3ae693 |
ca_mutex_unlock(c->props->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(p->mutex);
|
|
Packit |
3ae693 |
if ((t = ca_proplist_gets_unlocked(p, CA_PROP_CANBERRA_ENABLE)))
|
|
Packit |
3ae693 |
enabled = !ca_streq(t, "0");
|
|
Packit |
3ae693 |
ca_mutex_unlock(p->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail_unlock(enabled, CA_ERROR_DISABLED, c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = context_open_unlocked(c)) < 0)
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert(c->opened);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = driver_play(c, id, p, cb, userdata);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_unlock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* ca_context_cancel:
|
|
Packit |
3ae693 |
* @c: the context to cancel the sounds on
|
|
Packit |
3ae693 |
* @id: the id that identify the sounds to cancel.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Cancel one or more event sounds that have been started via
|
|
Packit |
3ae693 |
* ca_context_play(). If the sound was started with
|
|
Packit |
3ae693 |
* ca_context_play_full() and a callback function was passed this
|
|
Packit |
3ae693 |
* might cause this function to be called with %CA_ERROR_CANCELED as
|
|
Packit |
3ae693 |
* error code.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
int ca_context_cancel(ca_context *c, uint32_t id) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_mutex_lock(c->mutex);
|
|
Packit |
3ae693 |
ca_return_val_if_fail_unlock(c->opened, CA_ERROR_STATE, c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = driver_cancel(c, id);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_unlock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_cache:
|
|
Packit |
3ae693 |
* @c: The context to use for uploading.
|
|
Packit |
3ae693 |
* @...: The properties for this event sound. Terminated with NULL.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Upload the specified sample into the audio server and attach the
|
|
Packit |
3ae693 |
* specified properties to it. This function will only return after
|
|
Packit |
3ae693 |
* the sample upload was finished.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* The sound to cache is found with the same algorithm that is used to
|
|
Packit |
3ae693 |
* find the sounds for ca_context_play().
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* If the backend doesn't support caching sound samples this function
|
|
Packit |
3ae693 |
* will return %CA_ERROR_NOTSUPPORTED.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
int ca_context_cache(ca_context *c, ...) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
va_list ap;
|
|
Packit |
3ae693 |
ca_proplist *p = NULL;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
va_start(ap, c);
|
|
Packit |
3ae693 |
ret = ca_proplist_from_ap(&p, ap);
|
|
Packit |
3ae693 |
va_end(ap);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (ret < 0)
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = ca_context_cache_full(c, p);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert_se(ca_proplist_destroy(p) == 0);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_cache_full:
|
|
Packit |
3ae693 |
* @c: The context to use for uploading.
|
|
Packit |
3ae693 |
* @p: The property list for this event sound.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Upload the specified sample into the server and attach the
|
|
Packit |
3ae693 |
* specified properties to it. Similar to ca_context_cache() but takes
|
|
Packit |
3ae693 |
* a ca_proplist instead of a variable number of arguments.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* If the backend doesn't support caching sound samples this function
|
|
Packit |
3ae693 |
* will return CA_ERROR_NOTSUPPORTED.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
int ca_context_cache_full(ca_context *c, ca_proplist *p) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(p, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_lock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail_unlock(ca_proplist_contains(p, CA_PROP_EVENT_ID) ||
|
|
Packit |
3ae693 |
ca_proplist_contains(c->props, CA_PROP_EVENT_ID), CA_ERROR_INVALID, c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if ((ret = context_open_unlocked(c)) < 0)
|
|
Packit |
3ae693 |
goto finish;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_assert(c->opened);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = driver_cache(c, p);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
finish:
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_unlock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_strerror:
|
|
Packit |
3ae693 |
* @code: Numerical error code as returned by a libcanberra API function
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Converts a numerical error code as returned by most libcanberra API functions into a human readable error string.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: a human readable error string.
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
const char *ca_strerror(int code) {
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
const char * const error_table[-_CA_ERROR_MAX] = {
|
|
Packit |
3ae693 |
[-CA_SUCCESS] = "Success",
|
|
Packit |
3ae693 |
[-CA_ERROR_NOTSUPPORTED] = "Operation not supported",
|
|
Packit |
3ae693 |
[-CA_ERROR_INVALID] = "Invalid argument",
|
|
Packit |
3ae693 |
[-CA_ERROR_STATE] = "Invalid state",
|
|
Packit |
3ae693 |
[-CA_ERROR_OOM] = "Out of memory",
|
|
Packit |
3ae693 |
[-CA_ERROR_NODRIVER] = "No such driver",
|
|
Packit |
3ae693 |
[-CA_ERROR_SYSTEM] = "System error",
|
|
Packit |
3ae693 |
[-CA_ERROR_CORRUPT] = "File or data corrupt",
|
|
Packit |
3ae693 |
[-CA_ERROR_TOOBIG] = "File or data too large",
|
|
Packit |
3ae693 |
[-CA_ERROR_NOTFOUND] = "File or data not found",
|
|
Packit |
3ae693 |
[-CA_ERROR_DESTROYED] = "Destroyed",
|
|
Packit |
3ae693 |
[-CA_ERROR_CANCELED] = "Canceled",
|
|
Packit |
3ae693 |
[-CA_ERROR_NOTAVAILABLE] = "Not available",
|
|
Packit |
3ae693 |
[-CA_ERROR_ACCESS] = "Access forbidden",
|
|
Packit |
3ae693 |
[-CA_ERROR_IO] = "IO error",
|
|
Packit |
3ae693 |
[-CA_ERROR_INTERNAL] = "Internal error",
|
|
Packit |
3ae693 |
[-CA_ERROR_DISABLED] = "Sound disabled",
|
|
Packit |
3ae693 |
[-CA_ERROR_FORKED] = "Process forked",
|
|
Packit |
3ae693 |
[-CA_ERROR_DISCONNECTED] = "Disconnected"
|
|
Packit |
3ae693 |
};
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(code <= 0, NULL);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(code > _CA_ERROR_MAX, NULL);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return error_table[-code];
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/* Not exported */
|
|
Packit |
3ae693 |
int ca_parse_cache_control(ca_cache_control_t *control, const char *c) {
|
|
Packit |
3ae693 |
ca_return_val_if_fail(control, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
if (ca_streq(c, "never"))
|
|
Packit |
3ae693 |
*control = CA_CACHE_CONTROL_NEVER;
|
|
Packit |
3ae693 |
else if (ca_streq(c, "permanent"))
|
|
Packit |
3ae693 |
*control = CA_CACHE_CONTROL_PERMANENT;
|
|
Packit |
3ae693 |
else if (ca_streq(c, "volatile"))
|
|
Packit |
3ae693 |
*control = CA_CACHE_CONTROL_VOLATILE;
|
|
Packit |
3ae693 |
else
|
|
Packit |
3ae693 |
return CA_ERROR_INVALID;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return CA_SUCCESS;
|
|
Packit |
3ae693 |
}
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
/**
|
|
Packit |
3ae693 |
* ca_context_playing:
|
|
Packit |
3ae693 |
* @c: the context to check if sound is still playing
|
|
Packit |
3ae693 |
* @id: the id that identify the sounds to check
|
|
Packit |
3ae693 |
* @playing: a pointer to a boolean that will be updated with the play status
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Check if at least one sound with the specified id is still
|
|
Packit |
3ae693 |
* playing. Returns 0 in *playing if no sound with this id is playing
|
|
Packit |
3ae693 |
* anymore or non-zero if there is at least one playing.
|
|
Packit |
3ae693 |
*
|
|
Packit |
3ae693 |
* Returns: 0 on success, negative error code on error.
|
|
Packit |
3ae693 |
* Since: 0.16
|
|
Packit |
3ae693 |
*/
|
|
Packit |
3ae693 |
int ca_context_playing(ca_context *c, uint32_t id, int *playing) {
|
|
Packit |
3ae693 |
int ret;
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_return_val_if_fail(!ca_detect_fork(), CA_ERROR_FORKED);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(c, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_return_val_if_fail(playing, CA_ERROR_INVALID);
|
|
Packit |
3ae693 |
ca_mutex_lock(c->mutex);
|
|
Packit |
3ae693 |
ca_return_val_if_fail_unlock(c->opened, CA_ERROR_STATE, c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ret = driver_playing(c, id, playing);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
ca_mutex_unlock(c->mutex);
|
|
Packit |
3ae693 |
|
|
Packit |
3ae693 |
return ret;
|
|
Packit |
3ae693 |
}
|