summaryrefslogtreecommitdiffstats
path: root/src/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/common.c')
-rw-r--r--src/common.c293
1 files changed, 290 insertions, 3 deletions
diff --git a/src/common.c b/src/common.c
index 80be86c..a7b6945 100644
--- a/src/common.c
+++ b/src/common.c
@@ -33,6 +33,97 @@
#include "proplist.h"
#include "macro.h"
+/**
+ * SECTION:canberra
+ * @short_description: General libcanberra API
+ *
+ * libcanberra defines a simple abstract interface for playing event sounds.
+ *
+ * libcanberra relies on the XDG sound naming specification for
+ * identifying event sounds. On Unix/Linux the right sound to play is
+ * found via the mechanisms defined in the XDG sound themeing
+ * specification. On other systems the XDG sound name is translated to
+ * the native sound id for the operating system.
+ *
+ * An event sound is triggered via libcanberra by calling the
+ * ca_context_play() function on a previously created ca_context
+ * object. The ca_context_play() takes a list of key-value pairs that
+ * describe the event sound to generate as closely as possible. The
+ * most important property is %CA_PROP_EVENT_ID which defines the XDG
+ * sound name for the sound to play.
+ *
+ * libcanberra is not a generic event abstraction system. It's only
+ * purpose is playing sounds -- however in a very elaborate way. As
+ * much information about the context the sound is triggered from
+ * shall be supplied to the sound system as possible, so that it can
+ * replace the sound with some other kind of feedback for a11y
+ * cases. Also this additional information can be used to enhance user
+ * experience (e.g. by positioning sounds in space depending on the
+ * place on the screen the sound was triggered from, and similar
+ * uses).
+ *
+ * The set of properties defined for event sounds is extensible and
+ * shared with other audio systems, such as PulseAudio. Some of
+ * the properties that may be set are specific to an application, to a
+ * window, to an input event or to the media being played back.
+ *
+ * The user can attach a set of properties to the context itself,
+ * which is than automatically inherited by each sample being played
+ * back. (ca_context_change_props()).
+ *
+ * Some of the properties can be filled in by libcanberra or one of
+ * its backends automatically and thus need not be be filled in by the
+ * application (such as %CA_PROP_APPLICATION_PROCESS_ID and
+ * friends). However the application can always overwrite any of these
+ * implicit properties.
+ *
+ * libcanberra is thread-safe and OOM-safe (as far as the backend
+ * allows this). It is not async-signal safe.
+ *
+ * Most libcanberra functions return an integer that indicates success
+ * when 0 (%CA_SUCCESS) or an error when negative. In the latter case
+ * ca_strerror() can be used to convert this code into a human
+ * readable string.
+ *
+ * libcanberra property names need to be in 7bit ASCII, string
+ * property values UTF8.
+ *
+ * Optionally a libcanberra backend can support caching of sounds in a
+ * sound system. If this functionality is used, the latencies for
+ * event sound playback can be much smaller and fewer resources are
+ * needed to start playback. If a backend does not support cacheing,
+ * the respective functions will return an error code of
+ * %CA_ERROR_NOTSUPPORTED.
+ *
+ * It is highly recommended that the application sets the
+ * %CA_PROP_APPLICATION_NAME, %CA_PROP_APPLICATION_ID,
+ * %CA_PROP_APPLICATION_ICON_NAME/%CA_PROP_APPLICATION_ICON properties
+ * immediately after creating the ca_context, before calling
+ * ca_context_open() or ca_context_play().
+ *
+ * Its is highly recommended to pass at least %CA_PROP_EVENT_ID,
+ * %CA_PROP_EVENT_DESCRIPTION to ca_context_play() for each event
+ * sound generated. For sound events based on mouse inputs events
+ * %CA_PROP_EVENT_MOUSE_X, %CA_PROP_EVENT_MOUSE_Y, %CA_PROP_EVENT_MOUSE_HPOS,
+ * %CA_PROP_EVENT_MOUSE_VPOS, %CA_PROP_EVENT_MOUSE_BUTTON should be
+ * passed. For sound events attached to a widget on the screen, the
+ * %CA_PROP_WINDOW_xxx properties should be set.
+ *
+ *
+ */
+
+/**
+ * ca_context_create:
+ * @c: A pointer wheere to fill in the newly created context object.
+ *
+ * Create an (unconnected) context object. This call will not connect
+ * to the sound system, calling this function might even suceed if no
+ * working driver backend is available. To find out if one is
+ * available call ca_context_open().
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
int ca_context_create(ca_context **_c) {
ca_context *c;
int ret;
@@ -71,6 +162,14 @@ int ca_context_create(ca_context **_c) {
return CA_SUCCESS;
}
+/**
+ * ca_context_destroy:
+ * @c: the context to destroy.
+ *
+ * Destroy a (connected or unconnected) context object.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
int ca_context_destroy(ca_context *c) {
int ret = CA_SUCCESS;
@@ -96,6 +195,18 @@ int ca_context_destroy(ca_context *c) {
return ret;
}
+/**
+ * ca_context_set_driver:
+ * @c: the context to change the backend driver for
+ * @driver: the backend driver to use (e.g. "alsa", "pulse", "null", ...)
+ *
+ * Specify the backend driver used. This function may not be called again after
+ * ca_context_open() suceeded. This function might suceed even when
+ * the specified driver backend is not available. Use
+ * ca_context_open() to find out whether the backend is available.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
int ca_context_set_driver(ca_context *c, const char *driver) {
char *n;
int ret;
@@ -104,7 +215,9 @@ int ca_context_set_driver(ca_context *c, const char *driver) {
ca_mutex_lock(c->mutex);
ca_return_val_if_fail_unlock(!c->opened, CA_ERROR_STATE, c->mutex);
- if (!(n = ca_strdup(driver))) {
+ if (!driver)
+ n = NULL;
+ else if (!(n = ca_strdup(driver))) {
ret = CA_ERROR_OOM;
goto fail;
}
@@ -120,6 +233,21 @@ fail:
return ret;
}
+/**
+ * ca_context_change_device:
+ * @c: the context to change the backend device for
+ * @device: the backend device to use, in a format that is specific to the backend.
+ *
+ * Specify the backend device to use. This function may be called not be called after
+ * ca_context_open() suceeded. This function might suceed even when
+ * the specified driver backend is not available. Use
+ * ca_context_open() to find out whether the backend is available
+ *
+ * Depending on the backend use this might or might not cause all
+ * currently playing event sounds to be moved to the new device..
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
int ca_context_change_device(ca_context *c, const char *device) {
char *n;
int ret;
@@ -127,7 +255,9 @@ int ca_context_change_device(ca_context *c, const char *device) {
ca_return_val_if_fail(c, CA_ERROR_INVALID);
ca_mutex_lock(c->mutex);
- if (!(n = ca_strdup(device))) {
+ if (!device)
+ n = NULL;
+ else if (!(n = ca_strdup(device))) {
ret = CA_ERROR_OOM;
goto fail;
}
@@ -160,6 +290,17 @@ static int context_open_unlocked(ca_context *c) {
return ret;
}
+/**
+ * ca_context_open:
+ * @c: the context to connect.
+ *
+ * Connect the context to the sound system. This call is implicitly
+ * called in ca_context_play() or ca_context_cache() if not called
+ * explicitly. It is recommended to initialize application properties
+ * with ca_context_change_props() before calling this function.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
int ca_context_open(ca_context *c) {
int ret;
@@ -217,6 +358,24 @@ fail:
return ret;
}
+/**
+ * ca_context_change_props:
+ * @c: the context to set the properties on.
+ * @...: the list of string pairs for the properties. Needs to be a NULL terminated list.
+ *
+ * Write one or more string properties to the context object. Requires
+ * final NULL sentinel. Properties set like this will be attached to
+ * both the client object of the sound server and to all event sounds
+ * played or cached. It is recommended to call this function at least
+ * once before calling ca_context_open(), so that the initial
+ * application properties are set properly before the initial
+ * connection to the sound system. This function can be called both
+ * before and after the ca_context_open() call. Properties that have
+ * already been set before will be overwritten.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
int ca_context_change_props(ca_context *c, ...) {
va_list ap;
int ret;
@@ -238,6 +397,18 @@ int ca_context_change_props(ca_context *c, ...) {
return ret;
}
+/**
+ * ca_context_change_props_full:
+ * @c: the context to set the properties on.
+ * @p: the property list to set.
+ *
+ * Similar to ca_context_change_props(), but takes a ca_proplist
+ * instead of a variable list of properties. Can be used to set binary
+ * properties such as %CA_PROP_APPLICATION_ICON.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
int ca_context_change_props_full(ca_context *c, ca_proplist *p) {
int ret;
ca_proplist *merged;
@@ -265,6 +436,48 @@ finish:
return ret;
}
+/**
+ * ca_context_play:
+ * @c: the context to play the event sound on
+ * @id: an integer id this sound can later be identified with when calling ca_context_cancel()
+ * @...: additional properties for this sound event.
+ *
+ * Play one event sound. id can be any numeric value which later can
+ * be used to cancel an event sound that is currently being
+ * played. You may use the same id twice or more times if you want to
+ * cancel multiple event sounds with a single ca_context_cancel() call
+ * at once. It is recommended to pass 0 for the id if the event sound
+ * shall never be canceled. If the requested sound is not cached in
+ * the server yet this call might result in the sample being uploaded
+ * temporarily or permanently (this may be controlled with %CA_PROP_CANBERRA_CACHE_CONTROL). This function will start playback
+ * in the background. It will not wait until playback
+ * completed. Depending on the backend used a sound that is started
+ * shortly before your application terminates might or might not continue to
+ * play after your application terminated. If you want to make sure
+ * that all sounds finish to play you need to wait synchronously for
+ * the callback function of ca_context_play_full() to be called before you
+ * terminate your application.
+ *
+ * The sample to play is identified by the %CA_PROP_EVENT_ID
+ * property. If it is already cached in the server the cached version
+ * is played. The properties passed in this call are merged with the
+ * properties supplied when the sample was cached (if applicable)
+ * and the context properties as set with ca_context_change_props().
+ *
+ * If %CA_PROP_EVENT_ID is not defined the sound file passed in the
+ * %CA_PROP_MEDIA_FILENAME is played.
+ *
+ * On Linux/Unix the right sound to play is determined according to
+ * %CA_PROP_EVENT_ID,
+ * %CA_PROP_APPLICATION_LANGUAGE/%CA_PROP_MEDIA_LANGUAGE, the system
+ * locale, %CA_PROP_CANBERRA_XDG_THEME_NAME and
+ * %CA_PROP_CANBERRA_XDG_THEME_OUTPUT_PROFILE, following the XDG Sound
+ * Theming Specification. On non-Unix systems the native event sound
+ * that matches the XDG sound name in %CA_PROP_EVENT_ID is played.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
int ca_context_play(ca_context *c, uint32_t id, ...) {
int ret;
va_list ap;
@@ -286,6 +499,25 @@ int ca_context_play(ca_context *c, uint32_t id, ...) {
return ret;
}
+/**
+ * ca_context_play_full:
+ * @c: the context to play the event sound on
+ * @id: an integer id this sound can be later be identified with when calling ca_context_cancel() or when the callback is called.
+ * @p: A property list of properties for this event sound
+ * @cb: A callback to call when this sound event sucessfully finished playing or when an error occured during playback.
+ *
+ * Play one event sound, and call the specified callback function when
+ * completed. See ca_finish_callback_t for the semantics the callback
+ * is called in. Also see ca_context_play().
+ *
+ * It is guaranteed that the callback is called exactly once if
+ * ca_context_play_full() returns CA_SUCCESS. You thus may safely pass
+ * allocated memory to the callback and assume that it is freed
+ * properly.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_callback_t cb, void *userdata) {
int ret;
@@ -303,6 +535,8 @@ int ca_context_play_full(ca_context *c, uint32_t id, ca_proplist *p, ca_finish_c
ca_assert(c->opened);
+ fprintf(stderr, "Playing %s\n", ca_proplist_gets_unlocked(p, CA_PROP_EVENT_ID));
+
ret = driver_play(c, id, p, cb, userdata);
finish:
@@ -312,6 +546,20 @@ finish:
return ret;
}
+/**
+ *
+ * ca_context_cancel:
+ * @c: the context to cancel the sounds on
+ * @id: the id that identify the sounds to cancel.
+ *
+ * Cancel one or more event sounds that have been started via
+ * ca_context_play(). If the sound was started with
+ * ca_context_play_full() and a callback function was passed this
+ * might cause this function to be called with %CA_ERROR_CANCELED as
+ * error code.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
int ca_context_cancel(ca_context *c, uint32_t id) {
int ret;
@@ -326,6 +574,24 @@ int ca_context_cancel(ca_context *c, uint32_t id) {
return ret;
}
+/**
+ * ca_context_cache:
+ * @c: The context to use for uploading.
+ * @...: The properties for this event sound. Terminated with NULL.
+ *
+ * Upload the specified sample into the audio server and attach the
+ * specified properties to it. This function will only return after
+ * the sample upload was finished.
+ *
+ * The sound to cache is found with the same algorithm that is used to
+ * find the sounds for ca_context_play().
+ *
+ * If the backend doesn't support caching sound samples this function
+ * will return %CA_ERROR_NOTSUPPORTED.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
+
int ca_context_cache(ca_context *c, ...) {
int ret;
va_list ap;
@@ -347,6 +613,20 @@ int ca_context_cache(ca_context *c, ...) {
return ret;
}
+/**
+ * ca_context_cache_full:
+ * @c: The context to use for uploading.
+ * @p: The property list for this event sound.
+ *
+ * Upload the specified sample into the server and attach the
+ * specified properties to it. Similar to ca_context_cache() but takes
+ * a ca_proplist instead of a variable number of arguments.
+ *
+ * If the backend doesn't support caching sound samples this function
+ * will return CA_ERROR_NOTSUPPORTED.
+ *
+ * Returns: 0 on success, negative error code on error.
+ */
int ca_context_cache_full(ca_context *c, ca_proplist *p) {
int ret;
@@ -372,7 +652,14 @@ finish:
return ret;
}
-/** Return a human readable error */
+/**
+ * ca_strerror:
+ * @code: Numerical error code as returned by a canberra API function
+ *
+ * Converts a numerical error code as returned by most canberra API functions into a human readable error string.
+ *
+ * Returns: a human readable error string.
+ */
const char *ca_strerror(int code) {
const char * const error_table[-_CA_ERROR_MAX] = {