merge glitch-free branch back into trunk

git-svn-id: file:///home/lennart/svn/public/pulseaudio/trunk@2445 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
Lennart Poettering 2008-05-15 23:34:41 +00:00
parent 91f092eadc
commit 045c1d602d
189 changed files with 12559 additions and 4959 deletions

View file

@ -313,10 +313,15 @@ static void client_callback(AvahiClient *s, AvahiClientState state, void *userda
static void browser_free(pa_browser *b);
PA_WARN_REFERENCE(pa_browser_new, "libpulse-browse is being phased out.");
pa_browser *pa_browser_new(pa_mainloop_api *mainloop) {
return pa_browser_new_full(mainloop, PA_BROWSE_FOR_SERVERS|PA_BROWSE_FOR_SINKS|PA_BROWSE_FOR_SOURCES, NULL);
}
PA_WARN_REFERENCE(pa_browser_new_full, "libpulse-browse is being phased out.");
pa_browser *pa_browser_new_full(pa_mainloop_api *mainloop, pa_browse_flags_t flags, const char **error_string) {
pa_browser *b;
int error;
@ -420,6 +425,8 @@ static void browser_free(pa_browser *b) {
pa_xfree(b);
}
PA_WARN_REFERENCE(pa_browser_ref, "libpulse-browse is being phased out.");
pa_browser *pa_browser_ref(pa_browser *b) {
pa_assert(b);
pa_assert(PA_REFCNT_VALUE(b) >= 1);
@ -428,6 +435,8 @@ pa_browser *pa_browser_ref(pa_browser *b) {
return b;
}
PA_WARN_REFERENCE(pa_browser_unref, "libpulse-browse is being phased out.");
void pa_browser_unref(pa_browser *b) {
pa_assert(b);
pa_assert(PA_REFCNT_VALUE(b) >= 1);
@ -436,6 +445,8 @@ void pa_browser_unref(pa_browser *b) {
browser_free(b);
}
PA_WARN_REFERENCE(pa_browser_set_callback, "libpulse-browse is being phased out.");
void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) {
pa_assert(b);
pa_assert(PA_REFCNT_VALUE(b) >= 1);
@ -444,6 +455,8 @@ void pa_browser_set_callback(pa_browser *b, pa_browse_cb_t cb, void *userdata) {
b->userdata = userdata;
}
PA_WARN_REFERENCE(pa_browser_set_error_callback, "libpulse-browse is being phased out.");
void pa_browser_set_error_callback(pa_browser *b, pa_browser_error_cb_t cb, void *userdata) {
pa_assert(b);
pa_assert(PA_REFCNT_VALUE(b) >= 1);

View file

@ -41,22 +41,4 @@
#endif
#ifndef PA_GCC_PURE
#ifdef __GNUCC__
#define PA_GCC_PURE __attribute__ ((pure))
#else
/** This function's return value depends only the arguments list and global state **/
#define PA_GCC_PURE
#endif
#endif
#ifndef PA_GCC_CONST
#ifdef __GNUCC__
#define PA_GCC_CONST __attribute__ ((pure))
#else
/** This function's return value depends only the arguments list (stricter version of PA_GCC_CONST) **/
#define PA_GCC_CONST
#endif
#endif
#endif

View file

@ -27,6 +27,7 @@
#include <pulse/sample.h>
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
/** \page channelmap Channel Maps
*
@ -183,7 +184,7 @@ const char* pa_channel_position_to_pretty_string(pa_channel_position_t pos);
/** Make a humand readable string from the specified channel map */
char* pa_channel_map_snprint(char *s, size_t l, const pa_channel_map *map);
/** Parse a channel position list into a channel map structure. \since 0.8.1 */
/** Parse a channel position list into a channel map structure. */
pa_channel_map *pa_channel_map_parse(pa_channel_map *map, const char *s);
/** Compare two channel maps. Return 1 if both match. */

View file

@ -46,7 +46,10 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) {
pa_assert(c);
if (!dname && (!(dname = getenv("DISPLAY")) || *dname == '\0'))
if (!dname && !(dname = getenv("DISPLAY")))
goto finish;
if (*dname == 0)
goto finish;
if (!(d = XOpenDisplay(dname))) {
@ -80,7 +83,7 @@ int pa_client_conf_from_x11(pa_client_conf *c, const char *dname) {
pa_assert(sizeof(cookie) == sizeof(c->cookie));
memcpy(c->cookie, cookie, sizeof(cookie));
c->cookie_valid = 1;
c->cookie_valid = TRUE;
pa_xfree(c->cookie_file);
c->cookie_file = NULL;

View file

@ -112,13 +112,20 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) {
table[6].data = &c->cookie_file;
table[7].data = &c->disable_shm;
f = filename ?
fopen((fn = pa_xstrdup(filename)), "r") :
pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn, "r");
if (filename) {
if (!f && errno != EINTR) {
pa_log_warn("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
goto finish;
if (!(f = fopen(filename, "r"))) {
pa_log("Failed to open configuration file '%s': %s", fn, pa_cstrerror(errno));
goto finish;
}
fn = pa_xstrdup(fn);
} else {
if (!(f = pa_open_config_file(DEFAULT_CLIENT_CONFIG_FILE, DEFAULT_CLIENT_CONFIG_FILE_USER, ENV_CLIENT_CONFIG_FILE, &fn)))
if (errno != ENOENT)
goto finish;
}
r = f ? pa_config_parse(fn, f, table, NULL) : 0;
@ -126,7 +133,6 @@ int pa_client_conf_load(pa_client_conf *c, const char *filename) {
if (!r)
r = pa_client_conf_load_cookie(c);
finish:
pa_xfree(fn);

View file

@ -3,7 +3,7 @@
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2004-2008 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
@ -35,6 +35,7 @@
#include <errno.h>
#include <signal.h>
#include <limits.h>
#include <locale.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
@ -52,6 +53,8 @@
#include <pulse/version.h>
#include <pulse/xmalloc.h>
#include <pulse/utf8.h>
#include <pulse/util.h>
#include <pulsecore/winsock.h>
#include <pulsecore/core-error.h>
@ -90,6 +93,7 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_RECORD_STREAM_MOVED] = pa_command_stream_moved,
[PA_COMMAND_PLAYBACK_STREAM_SUSPENDED] = pa_command_stream_suspended,
[PA_COMMAND_RECORD_STREAM_SUSPENDED] = pa_command_stream_suspended,
[PA_COMMAND_STARTED] = pa_command_stream_started,
[PA_COMMAND_SUBSCRIBE_EVENT] = pa_command_subscribe_event
};
@ -97,10 +101,12 @@ static void unlock_autospawn_lock_file(pa_context *c) {
pa_assert(c);
if (c->autospawn_lock_fd >= 0) {
char lf[PATH_MAX];
pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf));
char *lf;
lf = pa_runtime_path(AUTOSPAWN_LOCK);
pa_unlock_lockfile(lf, c->autospawn_lock_fd);
pa_xfree(lf);
c->autospawn_lock_fd = -1;
}
}
@ -108,20 +114,42 @@ static void unlock_autospawn_lock_file(pa_context *c) {
static void context_free(pa_context *c);
pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
return pa_context_new_with_proplist(mainloop, name, NULL);
}
static void reset_callbacks(pa_context *c) {
pa_assert(c);
c->state_callback = NULL;
c->state_userdata = NULL;
c->subscribe_callback = NULL;
c->subscribe_userdata = NULL;
}
pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *p) {
pa_context *c;
pa_assert(mainloop);
pa_assert(name);
if (!name && !pa_proplist_contains(p, PA_PROP_APPLICATION_NAME))
return NULL;
c = pa_xnew(pa_context, 1);
PA_REFCNT_INIT(c);
c->name = pa_xstrdup(name);
c->proplist = p ? pa_proplist_copy(p) : pa_proplist_new();
if (name)
pa_proplist_sets(c->proplist, PA_PROP_APPLICATION_NAME, name);
c->mainloop = mainloop;
c->client = NULL;
c->pstream = NULL;
c->pdispatch = NULL;
c->playback_streams = pa_dynarray_new();
c->record_streams = pa_dynarray_new();
c->client_index = PA_INVALID_INDEX;
PA_LLIST_HEAD_INIT(pa_stream, c->streams);
PA_LLIST_HEAD_INIT(pa_operation, c->operations);
@ -131,18 +159,14 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
c->ctag = 0;
c->csyncid = 0;
c->state_callback = NULL;
c->state_userdata = NULL;
reset_callbacks(c);
c->subscribe_callback = NULL;
c->subscribe_userdata = NULL;
c->is_local = -1;
c->is_local = FALSE;
c->server_list = NULL;
c->server = NULL;
c->autospawn_lock_fd = -1;
memset(&c->spawn_api, 0, sizeof(c->spawn_api));
c->do_autospawn = 0;
c->do_autospawn = FALSE;
#ifndef MSG_NOSIGNAL
#ifdef SIGPIPE
@ -171,26 +195,48 @@ pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name) {
return c;
}
static void context_free(pa_context *c) {
static void context_unlink(pa_context *c) {
pa_stream *s;
pa_assert(c);
unlock_autospawn_lock_file(c);
s = c->streams ? pa_stream_ref(c->streams) : NULL;
while (s) {
pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
pa_stream_set_state(s, c->state == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
pa_stream_unref(s);
s = n;
}
while (c->operations)
pa_operation_cancel(c->operations);
while (c->streams)
pa_stream_set_state(c->streams, PA_STREAM_TERMINATED);
if (c->client)
pa_socket_client_unref(c->client);
if (c->pdispatch)
if (c->pdispatch) {
pa_pdispatch_unref(c->pdispatch);
c->pdispatch = NULL;
}
if (c->pstream) {
pa_pstream_unlink(c->pstream);
pa_pstream_unref(c->pstream);
c->pstream = NULL;
}
if (c->client) {
pa_socket_client_unref(c->client);
c->client = NULL;
}
reset_callbacks(c);
}
static void context_free(pa_context *c) {
pa_assert(c);
context_unlink(c);
unlock_autospawn_lock_file(c);
if (c->record_streams)
pa_dynarray_free(c->record_streams, NULL, NULL);
if (c->playback_streams)
@ -204,7 +250,9 @@ static void context_free(pa_context *c) {
pa_strlist_free(c->server_list);
pa_xfree(c->name);
if (c->proplist)
pa_proplist_free(c->proplist);
pa_xfree(c->server);
pa_xfree(c);
}
@ -235,46 +283,16 @@ void pa_context_set_state(pa_context *c, pa_context_state_t st) {
pa_context_ref(c);
c->state = st;
if (c->state_callback)
c->state_callback(c, c->state_userdata);
if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED) {
pa_stream *s;
s = c->streams ? pa_stream_ref(c->streams) : NULL;
while (s) {
pa_stream *n = s->next ? pa_stream_ref(s->next) : NULL;
pa_stream_set_state(s, st == PA_CONTEXT_FAILED ? PA_STREAM_FAILED : PA_STREAM_TERMINATED);
pa_stream_unref(s);
s = n;
}
if (c->pdispatch)
pa_pdispatch_unref(c->pdispatch);
c->pdispatch = NULL;
if (c->pstream) {
pa_pstream_unlink(c->pstream);
pa_pstream_unref(c->pstream);
}
c->pstream = NULL;
if (c->client)
pa_socket_client_unref(c->client);
c->client = NULL;
}
if (st == PA_CONTEXT_FAILED || st == PA_CONTEXT_TERMINATED)
context_unlink(c);
pa_context_unref(c);
}
void pa_context_fail(pa_context *c, int error) {
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
pa_context_set_error(c, error);
pa_context_set_state(c, PA_CONTEXT_FAILED);
}
int pa_context_set_error(pa_context *c, int error) {
pa_assert(error >= 0);
pa_assert(error < PA_ERR_MAX);
@ -285,6 +303,14 @@ int pa_context_set_error(pa_context *c, int error) {
return error;
}
void pa_context_fail(pa_context *c, int error) {
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
pa_context_set_error(c, error);
pa_context_set_state(c, PA_CONTEXT_FAILED);
}
static void pstream_die_callback(pa_pstream *p, void *userdata) {
pa_context *c = userdata;
@ -341,25 +367,41 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o
pa_context_unref(c);
}
int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t) {
int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, pa_bool_t fail) {
uint32_t err;
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
if (command == PA_COMMAND_ERROR) {
pa_assert(t);
if (pa_tagstruct_getu32(t, &c->error) < 0) {
if (pa_tagstruct_getu32(t, &err) < 0) {
pa_context_fail(c, PA_ERR_PROTOCOL);
return -1;
}
} else if (command == PA_COMMAND_TIMEOUT)
c->error = PA_ERR_TIMEOUT;
err = PA_ERR_TIMEOUT;
else {
pa_context_fail(c, PA_ERR_PROTOCOL);
return -1;
}
if (err == PA_OK) {
pa_context_fail(c, PA_ERR_PROTOCOL);
return -1;
}
if (err >= PA_ERR_MAX)
err = PA_ERR_UNKNOWN;
if (fail) {
pa_context_fail(c, err);
return -1;
}
pa_context_set_error(c, err);
return 0;
}
@ -373,11 +415,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
pa_context_ref(c);
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(c, command, t) < 0)
pa_context_fail(c, PA_ERR_PROTOCOL);
pa_context_fail(c, c->error);
pa_context_handle_error(c, command, t, TRUE);
goto finish;
}
@ -400,7 +438,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
/* Enable shared memory support if possible */
if (c->version >= 10 &&
pa_mempool_is_shared(c->mempool) &&
c->is_local > 0) {
c->is_local) {
/* Only enable SHM if both sides are owned by the same
* user. This is a security measure because otherwise
@ -410,12 +448,18 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
const pa_creds *creds;
if ((creds = pa_pdispatch_creds(pd)))
if (getuid() == creds->uid)
pa_pstream_use_shm(c->pstream, 1);
pa_pstream_enable_shm(c->pstream, TRUE);
#endif
}
reply = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
pa_tagstruct_puts(reply, c->name);
if (c->version >= 13) {
pa_init_proplist(c->proplist);
pa_tagstruct_put_proplist(reply, c->proplist);
} else
pa_tagstruct_puts(reply, pa_proplist_gets(c->proplist, PA_PROP_APPLICATION_NAME));
pa_pstream_send_tagstruct(c->pstream, reply);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, setup_complete_callback, c, NULL);
@ -424,11 +468,19 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
}
case PA_CONTEXT_SETTING_NAME :
if ((c->version >= 13 && (pa_tagstruct_getu32(t, &c->client_index) < 0 ||
c->client_index == PA_INVALID_INDEX)) ||
!pa_tagstruct_eof(t)) {
pa_context_fail(c, PA_ERR_PROTOCOL);
goto finish;
}
pa_context_set_state(c, PA_CONTEXT_READY);
break;
default:
pa_assert(0);
pa_assert_not_reached();
}
finish:
@ -455,7 +507,7 @@ static void setup_context(pa_context *c, pa_iochannel *io) {
c->pdispatch = pa_pdispatch_new(c->mainloop, command_table, PA_COMMAND_MAX);
if (!c->conf->cookie_valid)
pa_log_warn("No cookie loaded. Attempting to connect without.");
pa_log_info("No cookie loaded. Attempting to connect without.");
t = pa_tagstruct_command(c, PA_COMMAND_AUTH, &tag);
pa_tagstruct_putu32(t, PA_PROTOCOL_VERSION);
@ -494,10 +546,13 @@ static int context_connect_spawn(pa_context *c) {
int fds[2] = { -1, -1} ;
pa_iochannel *io;
if (getuid() == 0)
return -1;
pa_context_ref(c);
if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
pa_log("socketpair(): %s", pa_cstrerror(errno));
pa_log_error("socketpair(): %s", pa_cstrerror(errno));
pa_context_fail(c, PA_ERR_INTERNAL);
goto fail;
}
@ -511,7 +566,7 @@ static int context_connect_spawn(pa_context *c) {
c->spawn_api.prefork();
if ((pid = fork()) < 0) {
pa_log("fork(): %s", pa_cstrerror(errno));
pa_log_error("fork(): %s", pa_cstrerror(errno));
pa_context_fail(c, PA_ERR_INTERNAL);
if (c->spawn_api.postfork)
@ -526,9 +581,13 @@ static int context_connect_spawn(pa_context *c) {
#define MAX_ARGS 64
const char * argv[MAX_ARGS+1];
int n;
char *f;
/* Not required, since fds[0] has CLOEXEC enabled anyway */
pa_assert_se(pa_close(fds[0]) == 0);
pa_close_all(fds[1], -1);
f = pa_sprintf_malloc("%i", fds[1]);
pa_set_env("PULSE_PASSED_FD", f);
pa_xfree(f);
if (c->spawn_api.atfork)
c->spawn_api.atfork();
@ -561,6 +620,8 @@ static int context_connect_spawn(pa_context *c) {
/* Parent */
pa_assert_se(pa_close(fds[1]) == 0);
r = waitpid(pid, &status, 0);
if (c->spawn_api.postfork)
@ -575,14 +636,12 @@ static int context_connect_spawn(pa_context *c) {
goto fail;
}
pa_assert_se(pa_close(fds[1]) == 0);
c->is_local = TRUE;
c->is_local = 1;
unlock_autospawn_lock_file(c);
io = pa_iochannel_new(c->mainloop, fds[0], fds[0]);
setup_context(c, io);
unlock_autospawn_lock_file(c);
pa_context_unref(c);
@ -634,7 +693,7 @@ static int try_next_connection(pa_context *c) {
if (!(c->client = pa_socket_client_new_string(c->mainloop, u, PA_NATIVE_DEFAULT_PORT)))
continue;
c->is_local = pa_socket_client_is_local(c->client);
c->is_local = !!pa_socket_client_is_local(c->client);
pa_socket_client_set_callback(c->client, on_connection, c);
break;
}
@ -649,6 +708,7 @@ finish:
static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userdata) {
pa_context *c = userdata;
int saved_errno = errno;
pa_assert(client);
pa_assert(c);
@ -661,7 +721,9 @@ static void on_connection(pa_socket_client *client, pa_iochannel*io, void *userd
if (!io) {
/* Try the item in the list */
if (errno == ECONNREFUSED || errno == ETIMEDOUT || errno == EHOSTUNREACH) {
if (saved_errno == ECONNREFUSED ||
saved_errno == ETIMEDOUT ||
saved_errno == EHOSTUNREACH) {
try_next_connection(c);
goto finish;
}
@ -677,6 +739,25 @@ finish:
pa_context_unref(c);
}
static char *get_legacy_runtime_dir(void) {
char *p, u[128];
struct stat st;
if (!pa_get_user_name(u, sizeof(u)))
return NULL;
p = pa_sprintf_malloc("/tmp/pulse-%s", u);
if (stat(p, &st) < 0)
return NULL;
if (st.st_uid != getuid())
return NULL;
return p;
}
int pa_context_connect(
pa_context *c,
const char *server,
@ -705,8 +786,8 @@ int pa_context_connect(
goto finish;
}
} else {
char *d;
char ufn[PATH_MAX];
char *d, *ufn;
static char *legacy_dir;
/* Prepend in reverse order */
@ -726,25 +807,34 @@ int pa_context_connect(
c->server_list = pa_strlist_prepend(c->server_list, "tcp4:localhost");
/* The system wide instance */
c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH "/" PA_NATIVE_DEFAULT_UNIX_SOCKET);
c->server_list = pa_strlist_prepend(c->server_list, PA_SYSTEM_RUNTIME_PATH PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET);
/* The old per-user instance path. This is supported only to easy upgrades */
if ((legacy_dir = get_legacy_runtime_dir())) {
char *p = pa_sprintf_malloc("%s" PA_PATH_SEP PA_NATIVE_DEFAULT_UNIX_SOCKET, legacy_dir);
c->server_list = pa_strlist_prepend(c->server_list, p);
pa_xfree(p);
pa_xfree(legacy_dir);
}
/* The per-user instance */
c->server_list = pa_strlist_prepend(c->server_list, pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET, ufn, sizeof(ufn)));
c->server_list = pa_strlist_prepend(c->server_list, ufn = pa_runtime_path(PA_NATIVE_DEFAULT_UNIX_SOCKET));
pa_xfree(ufn);
/* Wrap the connection attempts in a single transaction for sane autospawn locking */
if (!(flags & PA_CONTEXT_NOAUTOSPAWN) && c->conf->autospawn) {
char lf[PATH_MAX];
char *lf;
pa_runtime_path(AUTOSPAWN_LOCK, lf, sizeof(lf));
pa_make_secure_parent_dir(lf, 0700, (uid_t)-1, (gid_t)-1);
lf = pa_runtime_path(AUTOSPAWN_LOCK);
pa_assert(c->autospawn_lock_fd <= 0);
c->autospawn_lock_fd = pa_lock_lockfile(lf);
pa_xfree(lf);
if (api)
c->spawn_api = *api;
c->do_autospawn = 1;
}
c->do_autospawn = TRUE;
}
}
pa_context_set_state(c, PA_CONTEXT_CONNECTING);
@ -760,7 +850,8 @@ void pa_context_disconnect(pa_context *c) {
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
pa_context_set_state(c, PA_CONTEXT_TERMINATED);
if (PA_CONTEXT_IS_GOOD(c->state))
pa_context_set_state(c, PA_CONTEXT_TERMINATED);
}
pa_context_state_t pa_context_get_state(pa_context *c) {
@ -781,6 +872,9 @@ void pa_context_set_state_callback(pa_context *c, pa_context_notify_cb_t cb, voi
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
return;
c->state_callback = cb;
c->state_userdata = userdata;
}
@ -789,11 +883,7 @@ int pa_context_is_pending(pa_context *c) {
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY(c,
c->state == PA_CONTEXT_CONNECTING ||
c->state == PA_CONTEXT_AUTHORIZING ||
c->state == PA_CONTEXT_SETTING_NAME ||
c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
PA_CHECK_VALIDITY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE);
return (c->pstream && pa_pstream_is_pending(c->pstream)) ||
(c->pdispatch && pa_pdispatch_is_pending(c->pdispatch)) ||
@ -870,7 +960,7 @@ void pa_context_simple_ack_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_U
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
success = 0;
@ -889,25 +979,6 @@ finish:
pa_operation_unref(o);
}
pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
pa_tagstruct *t;
pa_operation *o;
uint32_t tag;
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
t = pa_tagstruct_command(c, PA_COMMAND_EXIT, &tag);
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
return o;
}
pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa_pdispatch_cb_t internal_cb, pa_operation_cb_t cb, void *userdata) {
pa_tagstruct *t;
pa_operation *o;
@ -927,6 +998,13 @@ pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, pa
return o;
}
pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata) {
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
return pa_context_send_simple_command(c, PA_COMMAND_EXIT, pa_context_simple_ack_callback, (pa_operation_cb_t) cb, userdata);
}
pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
pa_tagstruct *t;
pa_operation *o;
@ -938,7 +1016,6 @@ pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_co
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SINK, &tag);
pa_tagstruct_puts(t, name);
pa_pstream_send_tagstruct(c->pstream, t);
@ -958,7 +1035,6 @@ pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
t = pa_tagstruct_command(c, PA_COMMAND_SET_DEFAULT_SOURCE, &tag);
pa_tagstruct_puts(t, name);
pa_pstream_send_tagstruct(c->pstream, t);
@ -971,15 +1047,13 @@ int pa_context_is_local(pa_context *c) {
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY(c, c->is_local >= 0, PA_ERR_BADSTATE);
PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, -1);
return c->is_local;
return !!c->is_local;
}
pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata) {
pa_tagstruct *t;
pa_operation *o;
uint32_t tag;
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
@ -987,12 +1061,22 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
if (c->version >= 13) {
pa_proplist *p = pa_proplist_new();
t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
pa_tagstruct_puts(t, name);
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, name);
o = pa_context_proplist_update(c, PA_UPDATE_REPLACE, p, cb, userdata);
pa_proplist_free(p);
} else {
pa_tagstruct *t;
uint32_t tag;
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
t = pa_tagstruct_command(c, PA_COMMAND_SET_CLIENT_NAME, &tag);
pa_tagstruct_puts(t, name);
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
}
return o;
}
@ -1024,6 +1108,8 @@ uint32_t pa_context_get_server_protocol_version(pa_context *c) {
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX);
return c->version;
}
@ -1039,3 +1125,153 @@ pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *ta
return t;
}
uint32_t pa_context_get_index(pa_context *c) {
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY_RETURN_ANY(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
PA_CHECK_VALIDITY_RETURN_ANY(c, c->version >= 13, PA_ERR_NOTSUPPORTED, PA_INVALID_INDEX);
return c->client_index;
}
pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata) {
pa_operation *o;
pa_tagstruct *t;
uint32_t tag;
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY_RETURN_NULL(c, mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE, PA_ERR_INVALID);
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
t = pa_tagstruct_command(c, PA_COMMAND_UPDATE_CLIENT_PROPLIST, &tag);
pa_tagstruct_putu32(t, (uint32_t) mode);
pa_tagstruct_put_proplist(t, p);
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
/* Please note that we don't update c->proplist here, because we
* don't export that field */
return o;
}
pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata) {
pa_operation *o;
pa_tagstruct *t;
uint32_t tag;
const char * const *k;
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY_RETURN_NULL(c, keys && keys[0], PA_ERR_INVALID);
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_CLIENT_PROPLIST, &tag);
for (k = keys; *k; k++)
pa_tagstruct_puts(t, *k);
pa_tagstruct_puts(t, NULL);
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
/* Please note that we don't update c->proplist here, because we
* don't export that field */
return o;
}
void pa_init_proplist(pa_proplist *p) {
int a, b;
#ifndef HAVE_DECL_ENVIRON
extern char **environ;
#endif
char **e;
pa_assert(p);
for (e = environ; *e; e++) {
if (pa_startswith(*e, "PULSE_PROP_")) {
size_t kl = strcspn(*e+11, "=");
char *k;
if ((*e)[11+kl] != '=')
continue;
if (!pa_utf8_valid(*e+11+kl+1))
continue;
k = pa_xstrndup(*e+11, kl);
if (pa_proplist_contains(p, k)) {
pa_xfree(k);
continue;
}
pa_proplist_sets(p, k, *e+11+kl+1);
pa_xfree(k);
}
}
if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_ID)) {
char t[32];
pa_snprintf(t, sizeof(t), "%lu", (unsigned long) getpid());
pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_ID, t);
}
if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_USER)) {
char t[64];
if (pa_get_user_name(t, sizeof(t))) {
char *c = pa_utf8_filter(t);
pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_USER, c);
pa_xfree(c);
}
}
if (!pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_HOST)) {
char t[64];
if (pa_get_host_name(t, sizeof(t))) {
char *c = pa_utf8_filter(t);
pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_HOST, c);
pa_xfree(c);
}
}
a = pa_proplist_contains(p, PA_PROP_APPLICATION_PROCESS_BINARY);
b = pa_proplist_contains(p, PA_PROP_APPLICATION_NAME);
if (!a || !b) {
char t[PATH_MAX];
if (pa_get_binary_name(t, sizeof(t))) {
char *c = pa_utf8_filter(t);
if (!a)
pa_proplist_sets(p, PA_PROP_APPLICATION_PROCESS_BINARY, c);
if (!b)
pa_proplist_sets(p, PA_PROP_APPLICATION_NAME, c);
pa_xfree(c);
}
}
if (!pa_proplist_contains(p, PA_PROP_APPLICATION_LANGUAGE)) {
const char *l;
if ((l = setlocale(LC_MESSAGES, NULL)))
pa_proplist_sets(p, PA_PROP_APPLICATION_LANGUAGE, l);
}
}

View file

@ -30,6 +30,7 @@
#include <pulse/mainloop-api.h>
#include <pulse/cdecl.h>
#include <pulse/operation.h>
#include <pulse/proplist.h>
/** \page async Asynchronous API
*
@ -166,9 +167,15 @@ typedef void (*pa_context_notify_cb_t)(pa_context *c, void *userdata);
typedef void (*pa_context_success_cb_t) (pa_context *c, int success, void *userdata);
/** Instantiate a new connection context with an abstract mainloop API
* and an application name */
* and an application name. It is recommended to use pa_context_new_with_proplist()
* instead and specify some initial properties.*/
pa_context *pa_context_new(pa_mainloop_api *mainloop, const char *name);
/** Instantiate a new connection context with an abstract mainloop API
* and an application name, and specify the the initial client property
* list. \since 0.9.11 */
pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *name, pa_proplist *proplist);
/** Decrease the reference counter of the context by one */
void pa_context_unref(pa_context *c);
@ -207,27 +214,42 @@ pa_operation* pa_context_drain(pa_context *c, pa_context_notify_cb_t cb, void *u
* returning a success notification */
pa_operation* pa_context_exit_daemon(pa_context *c, pa_context_success_cb_t cb, void *userdata);
/** Set the name of the default sink. \since 0.4 */
/** Set the name of the default sink. */
pa_operation* pa_context_set_default_sink(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata);
/** Set the name of the default source. \since 0.4 */
/** Set the name of the default source. */
pa_operation* pa_context_set_default_source(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata);
/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. \since 0.5 */
/** Returns 1 when the connection is to a local daemon. Returns negative when no connection has been made yet. */
int pa_context_is_local(pa_context *c);
/** Set a different application name for context on the server. \since 0.5 */
/** Set a different application name for context on the server. */
pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata);
/** Return the server name this context is connected to. \since 0.7 */
/** Return the server name this context is connected to. */
const char* pa_context_get_server(pa_context *c);
/** Return the protocol version of the library. \since 0.8 */
/** Return the protocol version of the library. */
uint32_t pa_context_get_protocol_version(pa_context *c);
/** Return the protocol version of the connected server. \since 0.8 */
/** Return the protocol version of the connected server. */
uint32_t pa_context_get_server_protocol_version(pa_context *c);
/* Update the property list of the client, adding new entries. Please
* note that it is highly recommended to set as much properties
* initially via pa_context_new_with_proplist() as possible instead a
* posteriori with this function, since that information may then be
* used to route streams of the client to the right device. \since 0.9.11 */
pa_operation *pa_context_proplist_update(pa_context *c, pa_update_mode_t mode, pa_proplist *p, pa_context_success_cb_t cb, void *userdata);
/* Update the property list of the client, remove entries. \since 0.9.11 */
pa_operation *pa_context_proplist_remove(pa_context *c, const char *const keys[], pa_context_success_cb_t cb, void *userdata);
/** Return the client index this context is
* identified in the server with. This is useful for usage with the
* introspection functions, such as pa_context_get_client_info(). \since 0.9.11 */
uint32_t pa_context_get_index(pa_context *s);
PA_C_DECL_END
#endif

View file

@ -48,6 +48,15 @@ typedef enum pa_context_state {
PA_CONTEXT_TERMINATED /**< The connection was terminated cleanly */
} pa_context_state_t;
/** Return non-zero if the passed state is one of the connected states */
static inline int PA_CONTEXT_IS_GOOD(pa_context_state_t x) {
return
x == PA_CONTEXT_CONNECTING ||
x == PA_CONTEXT_AUTHORIZING ||
x == PA_CONTEXT_SETTING_NAME ||
x == PA_CONTEXT_READY;
}
/** The state of a stream */
typedef enum pa_stream_state {
PA_STREAM_UNCONNECTED, /**< The stream is not yet connected to any sink or source */
@ -57,6 +66,13 @@ typedef enum pa_stream_state {
PA_STREAM_TERMINATED /**< The stream has been terminated cleanly */
} pa_stream_state_t;
/** Return non-zero if the passed state is one of the connected states */
static inline int PA_STREAM_IS_GOOD(pa_stream_state_t x) {
return
x == PA_STREAM_CREATING ||
x == PA_STREAM_READY;
}
/** The state of an operation */
typedef enum pa_operation_state {
PA_OPERATION_RUNNING, /**< The operation is still running */
@ -67,7 +83,7 @@ typedef enum pa_operation_state {
/** An invalid index */
#define PA_INVALID_INDEX ((uint32_t) -1)
/** Some special flags for contexts. \since 0.8 */
/** Some special flags for contexts. */
typedef enum pa_context_flags {
PA_CONTEXT_NOAUTOSPAWN = 1 /**< Disabled autospawning of the PulseAudio daemon if required */
} pa_context_flags_t;
@ -80,7 +96,7 @@ typedef enum pa_stream_direction {
PA_STREAM_UPLOAD /**< Sample upload stream */
} pa_stream_direction_t;
/** Some special flags for stream connections. \since 0.6 */
/** Some special flags for stream connections. */
typedef enum pa_stream_flags {
PA_STREAM_START_CORKED = 1, /**< Create the stream corked, requiring an explicit pa_stream_cork() call to uncork it. */
PA_STREAM_INTERPOLATE_TIMING = 2, /**< Interpolate the latency for
@ -209,15 +225,73 @@ typedef enum pa_stream_flags {
* least PA 0.9.8. It is ignored
* on older servers. \since
* 0.9.8 */
PA_STREAM_PEAK_DETECT = 2048, /**< Find peaks instead of
* resampling. \since 0.9.11 */
PA_STREAM_START_MUTED = 4096, /**< Create in muted state. \since 0.9.11 */
PA_STREAM_ADJUST_LATENCY = 8192, /**< Try to adjust the latency of
* the sink/source based on the
* requested buffer metrics and
* adjust buffer metrics
* accordingly. \since 0.9.11 */
} pa_stream_flags_t;
/** English is an evil language \since 0.9.11 */
#define PA_STREAM_NOT_MONOTONIC PA_STREAM_NOT_MONOTONOUS
/** Playback and record buffer metrics */
typedef struct pa_buffer_attr {
uint32_t maxlength; /**< Maximum length of the buffer */
uint32_t tlength; /**< Playback only: target length of the buffer. The server tries to assure that at least tlength bytes are always available in the buffer */
uint32_t prebuf; /**< Playback only: pre-buffering. The server does not start with playback before at least prebug bytes are available in the buffer */
uint32_t minreq; /**< Playback only: minimum request. The server does not request less than minreq bytes from the client, instead waints until the buffer is free enough to request more bytes at once */
uint32_t fragsize; /**< Recording only: fragment size. The server sends data in blocks of fragsize bytes size. Large values deminish interactivity with other operations on the connection context but decrease control overhead. */
uint32_t maxlength; /**< Maximum length of the
* buffer. Setting this to 0 will
* initialize this to the maximum value
* supported by server, which is
* recommended. */
uint32_t tlength; /**< Playback only: target length of the
* buffer. The server tries to assure
* that at least tlength bytes are always
* available in the buffer. It is
* recommended to set this to 0, which
* will initialize this to a value that
* is deemed sensible by the
* server. However, this value will
* default to something like 2s, i.e. for
* applications that have specific
* latency requirements this value should
* be set to the maximum latency that the
* application can deal with. */
uint32_t prebuf; /**< Playback only: pre-buffering. The
* server does not start with playback
* before at least prebug bytes are
* available in the buffer. It is
* recommended to set this to 0, which
* will initialize this to the same value
* as tlength, whatever that may be. */
uint32_t minreq; /**< Playback only: minimum request. The
* server does not request less than
* minreq bytes from the client, instead
* waits until the buffer is free enough
* to request more bytes at once. It is
* recommended to set this to 0, which
* will initialize this to a value that
* is deemed sensible by the server. */
uint32_t fragsize; /**< Recording only: fragment size. The
* server sends data in blocks of
* fragsize bytes size. Large values
* deminish interactivity with other
* operations on the connection context
* but decrease control overhead. It is
* recommended to set this to 0, which
* will initialize this to a value that
* is deemed sensible by the
* server. However, this value will
* default to something like 2s, i.e. for
* applications that have specific
* latency requirements this value should
* be set to the maximum latency that the
* application can deal with. */
} pa_buffer_attr;
/** Error values as used by pa_context_errno(). Use pa_strerror() to convert these values to human readable strings */
@ -239,9 +313,10 @@ enum {
PA_ERR_MODINITFAILED, /**< Module initialization failed */
PA_ERR_BADSTATE, /**< Bad state */
PA_ERR_NODATA, /**< No data */
PA_ERR_VERSION, /**< Incompatible protocol version \since 0.8 */
PA_ERR_TOOLARGE, /**< Data too large \since 0.8.1 */
PA_ERR_VERSION, /**< Incompatible protocol version */
PA_ERR_TOOLARGE, /**< Data too large */
PA_ERR_NOTSUPPORTED, /**< Operation not supported \since 0.9.5 */
PA_ERR_UNKNOWN, /**< The error code was unknown to the client */
PA_ERR_MAX /**< Not really an error but the first invalid error code */
};
@ -255,9 +330,9 @@ typedef enum pa_subscription_mask {
PA_SUBSCRIPTION_MASK_MODULE = 16, /**< Module events */
PA_SUBSCRIPTION_MASK_CLIENT = 32, /**< Client events */
PA_SUBSCRIPTION_MASK_SAMPLE_CACHE = 64, /**< Sample cache events */
PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. \since 0.4 */
PA_SUBSCRIPTION_MASK_AUTOLOAD = 256, /**< Autoload table events. \since 0.5 */
PA_SUBSCRIPTION_MASK_ALL = 511 /**< Catch all events \since 0.8 */
PA_SUBSCRIPTION_MASK_SERVER = 128, /**< Other global server changes. */
PA_SUBSCRIPTION_MASK_AUTOLOAD = 256, /**< Autoload table events. */
PA_SUBSCRIPTION_MASK_ALL = 511 /**< Catch all events */
} pa_subscription_mask_t;
/** Subscription event types, as used by pa_context_subscribe() */
@ -269,8 +344,8 @@ typedef enum pa_subscription_event_type {
PA_SUBSCRIPTION_EVENT_MODULE = 4, /**< Event type: Module */
PA_SUBSCRIPTION_EVENT_CLIENT = 5, /**< Event type: Client */
PA_SUBSCRIPTION_EVENT_SAMPLE_CACHE = 6, /**< Event type: Sample cache item */
PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. \since 0.4 */
PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. \since 0.5 */
PA_SUBSCRIPTION_EVENT_SERVER = 7, /**< Event type: Global server change, only occuring with PA_SUBSCRIPTION_EVENT_CHANGE. */
PA_SUBSCRIPTION_EVENT_AUTOLOAD = 8, /**< Event type: Autoload table changes. */
PA_SUBSCRIPTION_EVENT_FACILITY_MASK = 15, /**< A mask to extract the event type from an event value */
PA_SUBSCRIPTION_EVENT_NEW = 0, /**< A new object was created */
@ -297,7 +372,9 @@ typedef enum pa_subscription_event_type {
* source_usec+buffer_usec+transport_usec-sink_usec. (Take care of
* sign issues!) When connected to a monitor source sink_usec contains
* the latency of the owning sink. The two latency estimations
* described here are implemented in pa_stream_get_latency().*/
* described here are implemented in pa_stream_get_latency(). Please
* note that this structure can be extended as part of evolutionary
* API updates at any time in any new release.*/
typedef struct pa_timing_info {
struct timeval timestamp; /**< The time when this timing info structure was current */
int synchronized_clocks; /**< Non-zero if the local and the
@ -306,14 +383,21 @@ typedef struct pa_timing_info {
* detected transport_usec becomes much
* more reliable. However, the code that
* detects synchronized clocks is very
* limited und unreliable itself. \since
* 0.5 */
* limited und unreliable itself. */
pa_usec_t sink_usec; /**< Time in usecs a sample takes to be played on the sink. For playback streams and record streams connected to a monitor source. */
pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. \since 0.5*/
pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. \since 0.5 */
pa_usec_t source_usec; /**< Time in usecs a sample takes from being recorded to being delivered to the application. Only for record streams. */
pa_usec_t transport_usec; /**< Estimated time in usecs a sample takes to be transferred to/from the daemon. For both playback and record streams. */
int playing; /**< Non-zero when the stream is currently playing. Only for playback streams. */
int playing; /**< Non-zero when the stream is
* currently not underrun and data is
* being passed on to the device. Only
* for playback streams. This field does
* not say whether the data is actually
* already being played. To determine
* this check whether since_underrun
* (converted to usec) is larger than
* sink_usec.*/
int write_index_corrupt; /**< Non-zero if write_index is not
* up-to-date because a local write
@ -322,20 +406,19 @@ typedef struct pa_timing_info {
* info was current . Only write
* commands with SEEK_RELATIVE_ON_READ
* and SEEK_RELATIVE_END can corrupt
* write_index. \since 0.8 */
* write_index. */
int64_t write_index; /**< Current write index into the
* playback buffer in bytes. Think twice before
* using this for seeking purposes: it
* might be out of date a the time you
* want to use it. Consider using
* PA_SEEK_RELATIVE instead. \since
* 0.8 */
* PA_SEEK_RELATIVE instead. */
int read_index_corrupt; /**< Non-zero if read_index is not
* up-to-date because a local pause or
* flush request that corrupted it has
* been issued in the time since this
* latency info was current. \since 0.8 */
* latency info was current. */
int64_t read_index; /**< Current read index into the
* playback buffer in bytes. Think twice before
@ -343,7 +426,20 @@ typedef struct pa_timing_info {
* might be out of date a the time you
* want to use it. Consider using
* PA_SEEK_RELATIVE_ON_READ
* instead. \since 0.8 */
* instead. */
pa_usec_t configured_sink_usec; /**< The static configured latency for
* the sink. \since 0.9.11 */
pa_usec_t configured_source_usec; /**< The static configured latency for
* the source. \since 0.9.11 */
int64_t since_underrun; /**< Bytes that were handed to the sink
since the last underrun happened, or
since playback started again after
the last underrun. playing will tell
you which case it is. \since
0.9.11 */
} pa_timing_info;
/** A structure for the spawn api. This may be used to integrate auto
@ -352,7 +448,7 @@ typedef struct pa_timing_info {
* waitpid() is used on the child's PID. The spawn routine will not
* block or ignore SIGCHLD signals, since this cannot be done in a
* thread compatible way. You might have to do this in
* prefork/postfork. \since 0.4 */
* prefork/postfork. */
typedef struct pa_spawn_api {
void (*prefork)(void); /**< Is called just before the fork in the parent process. May be NULL. */
void (*postfork)(void); /**< Is called immediately after the fork in the parent process. May be NULL.*/
@ -365,7 +461,7 @@ typedef struct pa_spawn_api {
* passed to the new process. */
} pa_spawn_api;
/** Seek type for pa_stream_write(). \since 0.8*/
/** Seek type for pa_stream_write(). */
typedef enum pa_seek_mode {
PA_SEEK_RELATIVE = 0, /**< Seek relatively to the write index */
PA_SEEK_ABSOLUTE = 1, /**< Seek relatively to the start of the buffer queue */
@ -373,20 +469,24 @@ typedef enum pa_seek_mode {
PA_SEEK_RELATIVE_END = 3 /**< Seek relatively to the current end of the buffer queue. */
} pa_seek_mode_t;
/** Special sink flags. \since 0.8 */
/** Special sink flags. */
typedef enum pa_sink_flags {
PA_SINK_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */
PA_SINK_LATENCY = 2, /**< Supports latency querying */
PA_SINK_HARDWARE = 4, /**< Is a hardware sink of some kind, in contrast to "virtual"/software sinks \since 0.9.3 */
PA_SINK_NETWORK = 8 /**< Is a networked sink of some kind. \since 0.9.7 */
PA_SINK_NETWORK = 8, /**< Is a networked sink of some kind. \since 0.9.7 */
PA_SINK_HW_MUTE_CTRL = 16, /**< Supports hardware mute control \since 0.9.11 */
PA_SINK_DECIBEL_VOLUME = 32 /**< Volume can be translated to dB with pa_sw_volume_to_dB() \since 0.9.11 */
} pa_sink_flags_t;
/** Special source flags. \since 0.8 */
/** Special source flags. */
typedef enum pa_source_flags {
PA_SOURCE_HW_VOLUME_CTRL = 1, /**< Supports hardware volume control */
PA_SOURCE_LATENCY = 2, /**< Supports latency querying */
PA_SOURCE_HARDWARE = 4, /**< Is a hardware source of some kind, in contrast to "virtual"/software source \since 0.9.3 */
PA_SOURCE_NETWORK = 8 /**< Is a networked sink of some kind. \since 0.9.7 */
PA_SOURCE_NETWORK = 8, /**< Is a networked sink of some kind. \since 0.9.7 */
PA_SOURCE_HW_MUTE_CTRL = 16, /**< Supports hardware mute control \since 0.9.11 */
PA_SOURCE_DECIBEL_VOLUME = 32 /**< Volume can be translated to dB with pa_sw_volume_to_dB() \since 0.9.11 */
} pa_source_flags_t;
/** A generic free() like callback prototype */

98
src/pulse/gccmacro.h Normal file
View file

@ -0,0 +1,98 @@
#ifndef foopulsegccmacrohfoo
#define foopulsegccmacrohfoo
/* $Id$ */
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
USA.
***/
#ifdef __GNUC__
#define PA_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b)))
#else
/** If we're in GNU C, use some magic for detecting invalid format strings */
#define PA_GCC_PRINTF_ATTR(a,b)
#endif
#if defined(__GNUC__) && (__GNUC__ >= 4)
#define PA_GCC_SENTINEL __attribute__ ((sentinel))
#else
/** Macro for usage of GCC's sentinel compilation warnings */
#define PA_GCC_SENTINEL
#endif
#ifdef __GNUC__
#define PA_GCC_NORETURN __attribute__((noreturn))
#else
/** Macro for no-return functions */
#define PA_GCC_NORETURN
#endif
#ifdef __GNUC__
#define PA_GCC_UNUSED __attribute__ ((unused))
#else
/** Macro for not used parameter */
#define PA_GCC_UNUSED
#endif
#ifdef __GNUC__
#define PA_GCC_DESTRUCTOR __attribute__ ((destructor))
#else
/** Call this function when process terminates */
#define PA_GCC_DESTRUCTOR
#endif
#ifndef PA_GCC_PURE
#ifdef __GNUC__
#define PA_GCC_PURE __attribute__ ((pure))
#else
/** This function's return value depends only the arguments list and global state **/
#define PA_GCC_PURE
#endif
#endif
#ifndef PA_GCC_CONST
#ifdef __GNUC__
#define PA_GCC_CONST __attribute__ ((const))
#else
/** This function's return value depends only the arguments list (stricter version of PA_GCC_PURE) **/
#define PA_GCC_CONST
#endif
#endif
#ifndef PA_GCC_DEPRECATED
#ifdef __GNUC__
#define PA_GCC_DEPRECATED __attribute__ ((deprecated))
#else
/** This function is deprecated **/
#define PA_GCC_DEPRECATED
#endif
#endif
#ifndef PA_GCC_PACKED
#ifdef __GNUCC__
#define PA_GCC_PACKED __attribute__ ((packed))
#else
/** Structure shall be packed in memory **/
#define PA_GCC_PACKED
#endif
#endif
#endif

View file

@ -42,6 +42,7 @@
#include <pulsecore/memblockq.h>
#include <pulsecore/hashmap.h>
#include <pulsecore/refcnt.h>
#include <pulsecore/time-smoother.h>
#include "client-conf.h"
@ -50,7 +51,7 @@
struct pa_context {
PA_REFCNT_DECLARE;
char *name;
pa_proplist *proplist;
pa_mainloop_api* mainloop;
pa_socket_client *client;
@ -69,14 +70,13 @@ struct pa_context {
pa_context_notify_cb_t state_callback;
void *state_userdata;
pa_context_subscribe_cb_t subscribe_callback;
void *subscribe_userdata;
pa_mempool *mempool;
int is_local;
int do_autospawn;
pa_bool_t is_local;
pa_bool_t do_autospawn;
int autospawn_lock_fd;
pa_spawn_api spawn_api;
@ -85,38 +85,43 @@ struct pa_context {
char *server;
pa_client_conf *conf;
uint32_t client_index;
};
#define PA_MAX_WRITE_INDEX_CORRECTIONS 10
#define PA_MAX_WRITE_INDEX_CORRECTIONS 32
typedef struct pa_index_correction {
uint32_t tag;
int valid;
int64_t value;
int absolute, corrupt;
pa_bool_t valid:1;
pa_bool_t absolute:1;
pa_bool_t corrupt:1;
} pa_index_correction;
struct pa_stream {
PA_REFCNT_DECLARE;
pa_context *context;
pa_mainloop_api *mainloop;
PA_LLIST_FIELDS(pa_stream);
char *name;
pa_bool_t manual_buffer_attr;
pa_buffer_attr buffer_attr;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
pa_stream_flags_t flags;
uint32_t channel;
uint32_t syncid;
int channel_valid;
uint32_t stream_index;
pa_context *context;
pa_mainloop_api *mainloop;
pa_stream_direction_t direction;
pa_stream_state_t state;
pa_bool_t buffer_attr_not_ready, timing_info_not_ready;
pa_stream_flags_t flags;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
pa_proplist *proplist;
uint32_t channel;
pa_bool_t channel_valid;
uint32_t syncid;
uint32_t stream_index;
uint32_t requested_bytes;
pa_buffer_attr buffer_attr;
uint32_t device_index;
char *device_name;
@ -126,11 +131,11 @@ struct pa_stream {
void *peek_data;
pa_memblockq *record_memblockq;
int corked;
pa_bool_t corked;
/* Store latest latency info */
pa_timing_info timing_info;
int timing_info_valid;
pa_bool_t timing_info_valid;
/* Use to make sure that time advances monotonically */
pa_usec_t previous_time;
@ -145,10 +150,9 @@ struct pa_stream {
/* Latency interpolation stuff */
pa_time_event *auto_timing_update_event;
int auto_timing_update_requested;
pa_bool_t auto_timing_update_requested;
pa_usec_t cached_time;
int cached_time_valid;
pa_smoother *smoother;
/* Callbacks */
pa_stream_notify_cb_t state_callback;
@ -167,6 +171,8 @@ struct pa_stream {
void *moved_userdata;
pa_stream_notify_cb_t suspended_callback;
void *suspended_userdata;
pa_stream_notify_cb_t started_callback;
void *started_userdata;
};
typedef void (*pa_operation_cb_t)(void);
@ -192,7 +198,7 @@ void pa_command_subscribe_event(pa_pdispatch *pd, uint32_t command, uint32_t tag
void pa_command_overflow_or_underflow(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
void pa_command_stream_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
void pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
void pa_command_stream_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t callback, void *userdata);
void pa_operation_done(pa_operation *o);
@ -204,7 +210,7 @@ void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t
void pa_context_fail(pa_context *c, int error);
int pa_context_set_error(pa_context *c, int error);
void pa_context_set_state(pa_context *c, pa_context_state_t st);
int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t);
int pa_context_handle_error(pa_context *c, uint32_t command, pa_tagstruct *t, pa_bool_t fail);
pa_operation* pa_context_send_simple_command(pa_context *c, uint32_t command, void (*internal_callback)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata), void (*cb)(void), void *userdata);
void pa_stream_set_state(pa_stream *s, pa_stream_state_t st);
@ -226,5 +232,6 @@ pa_tagstruct *pa_tagstruct_command(pa_context *c, uint32_t command, uint32_t *ta
#define PA_CHECK_VALIDITY_RETURN_NULL(context, expression, error) PA_CHECK_VALIDITY_RETURN_ANY(context, expression, error, NULL)
void pa_init_proplist(pa_proplist *p);
#endif

View file

@ -27,8 +27,8 @@
#endif
#include <pulse/context.h>
#include <pulse/gccmacro.h>
#include <pulsecore/gccmacro.h>
#include <pulsecore/macro.h>
#include <pulsecore/pstream-util.h>
@ -52,7 +52,7 @@ static void context_stat_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UNU
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
p = NULL;
@ -95,7 +95,7 @@ static void context_get_server_info_callback(pa_pdispatch *pd, uint32_t command,
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
p = NULL;
@ -140,7 +140,7 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
eol = -1;
@ -149,7 +149,10 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P
while (!pa_tagstruct_eof(t)) {
pa_sink_info i;
pa_bool_t mute = FALSE;
memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 ||
@ -158,23 +161,30 @@ static void context_get_sink_info_callback(pa_pdispatch *pd, uint32_t command, P
pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 ||
pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
pa_tagstruct_get_cvolume(t, &i.volume) < 0 ||
pa_tagstruct_get_boolean(t, &i.mute) < 0 ||
pa_tagstruct_get_boolean(t, &mute) < 0 ||
pa_tagstruct_getu32(t, &i.monitor_source) < 0 ||
pa_tagstruct_gets(t, &i.monitor_source_name) < 0 ||
pa_tagstruct_get_usec(t, &i.latency) < 0 ||
pa_tagstruct_gets(t, &i.driver) < 0 ||
pa_tagstruct_getu32(t, &flags) < 0) {
pa_tagstruct_getu32(t, &flags) < 0 ||
(o->context->version >= 13 &&
(pa_tagstruct_get_proplist(t, i.proplist) < 0 ||
pa_tagstruct_get_usec(t, &i.configured_latency) < 0))) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
goto finish;
}
i.mute = (int) mute;
i.flags = (pa_sink_flags_t) flags;
if (o->callback) {
pa_sink_info_cb_t cb = (pa_sink_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata);
}
pa_proplist_free(i.proplist);
}
}
@ -251,7 +261,7 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
eol = -1;
@ -260,7 +270,10 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
while (!pa_tagstruct_eof(t)) {
pa_source_info i;
uint32_t flags;
pa_bool_t mute = FALSE;
memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 ||
@ -269,23 +282,30 @@ static void context_get_source_info_callback(pa_pdispatch *pd, uint32_t command,
pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 ||
pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
pa_tagstruct_get_cvolume(t, &i.volume) < 0 ||
pa_tagstruct_get_boolean(t, &i.mute) < 0 ||
pa_tagstruct_get_boolean(t, &mute) < 0 ||
pa_tagstruct_getu32(t, &i.monitor_of_sink) < 0 ||
pa_tagstruct_gets(t, &i.monitor_of_sink_name) < 0 ||
pa_tagstruct_get_usec(t, &i.latency) < 0 ||
pa_tagstruct_gets(t, &i.driver) < 0 ||
pa_tagstruct_getu32(t, &flags) < 0) {
pa_tagstruct_getu32(t, &flags) < 0 ||
(o->context->version >= 13 &&
(pa_tagstruct_get_proplist(t, i.proplist) < 0 ||
pa_tagstruct_get_usec(t, &i.configured_latency) < 0))) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
goto finish;
}
i.mute = (int) mute;
i.flags = (pa_source_flags_t) flags;
if (o->callback) {
pa_source_info_cb_t cb = (pa_source_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata);
}
pa_proplist_free(i.proplist);
}
}
@ -362,7 +382,7 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command,
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
eol = -1;
@ -370,13 +390,18 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command,
while (!pa_tagstruct_eof(t)) {
pa_client_info i;
memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 ||
pa_tagstruct_getu32(t, &i.owner_module) < 0 ||
pa_tagstruct_gets(t, &i.driver) < 0 ) {
pa_tagstruct_gets(t, &i.driver) < 0 ||
(o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0)) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
goto finish;
}
@ -384,6 +409,8 @@ static void context_get_client_info_callback(pa_pdispatch *pd, uint32_t command,
pa_client_info_cb_t cb = (pa_client_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata);
}
pa_proplist_free(i.proplist);
}
}
@ -437,7 +464,7 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command,
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
eol = -1;
@ -445,17 +472,20 @@ static void context_get_module_info_callback(pa_pdispatch *pd, uint32_t command,
while (!pa_tagstruct_eof(t)) {
pa_module_info i;
pa_bool_t auto_unload = FALSE;
memset(&i, 0, sizeof(i));
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 ||
pa_tagstruct_gets(t, &i.argument) < 0 ||
pa_tagstruct_getu32(t, &i.n_used) < 0 ||
pa_tagstruct_get_boolean(t, &i.auto_unload) < 0) {
pa_tagstruct_get_boolean(t, &auto_unload) < 0) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
goto finish;
}
i.auto_unload = (int) auto_unload;
if (o->callback) {
pa_module_info_cb_t cb = (pa_module_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata);
@ -513,7 +543,7 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
eol = -1;
@ -521,7 +551,10 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
while (!pa_tagstruct_eof(t)) {
pa_sink_input_info i;
pa_bool_t mute = FALSE;
memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 ||
@ -535,16 +568,22 @@ static void context_get_sink_input_info_callback(pa_pdispatch *pd, uint32_t comm
pa_tagstruct_get_usec(t, &i.sink_usec) < 0 ||
pa_tagstruct_gets(t, &i.resample_method) < 0 ||
pa_tagstruct_gets(t, &i.driver) < 0 ||
(o->context->version >= 11 && pa_tagstruct_get_boolean(t, &i.mute) < 0)) {
(o->context->version >= 11 && pa_tagstruct_get_boolean(t, &mute) < 0) ||
(o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0)) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
goto finish;
}
i.mute = (int) mute;
if (o->callback) {
pa_sink_input_info_cb_t cb = (pa_sink_input_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata);
}
pa_proplist_free(i.proplist);
}
}
@ -598,7 +637,7 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
eol = -1;
@ -608,6 +647,7 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c
pa_source_output_info i;
memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 ||
@ -619,9 +659,11 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c
pa_tagstruct_get_usec(t, &i.buffer_usec) < 0 ||
pa_tagstruct_get_usec(t, &i.source_usec) < 0 ||
pa_tagstruct_gets(t, &i.resample_method) < 0 ||
pa_tagstruct_gets(t, &i.driver) < 0) {
pa_tagstruct_gets(t, &i.driver) < 0 ||
(o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0)) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
pa_proplist_free(i.proplist);
goto finish;
}
@ -629,6 +671,8 @@ static void context_get_source_output_info_callback(pa_pdispatch *pd, uint32_t c
pa_source_output_info_cb_t cb = (pa_source_output_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata);
}
pa_proplist_free(i.proplist);
}
}
@ -923,7 +967,7 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command,
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
eol = -1;
@ -931,8 +975,10 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command,
while (!pa_tagstruct_eof(t)) {
pa_sample_info i;
pa_bool_t lazy = FALSE;
memset(&i, 0, sizeof(i));
i.proplist = pa_proplist_new();
if (pa_tagstruct_getu32(t, &i.index) < 0 ||
pa_tagstruct_gets(t, &i.name) < 0 ||
@ -941,17 +987,22 @@ static void context_get_sample_info_callback(pa_pdispatch *pd, uint32_t command,
pa_tagstruct_get_sample_spec(t, &i.sample_spec) < 0 ||
pa_tagstruct_get_channel_map(t, &i.channel_map) < 0 ||
pa_tagstruct_getu32(t, &i.bytes) < 0 ||
pa_tagstruct_get_boolean(t, &i.lazy) < 0 ||
pa_tagstruct_gets(t, &i.filename) < 0) {
pa_tagstruct_get_boolean(t, &lazy) < 0 ||
pa_tagstruct_gets(t, &i.filename) < 0 ||
(o->context->version >= 13 && pa_tagstruct_get_proplist(t, i.proplist) < 0)) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
goto finish;
}
i.lazy = (int) lazy;
if (o->callback) {
pa_sample_info_cb_t cb = (pa_sample_info_cb_t) o->callback;
cb(o->context, &i, 0, o->userdata);
}
pa_proplist_free(i.proplist);
}
}
@ -1060,7 +1111,7 @@ static void context_index_callback(pa_pdispatch *pd, uint32_t command, PA_GCC_UN
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
idx = PA_INVALID_INDEX;
@ -1121,7 +1172,7 @@ static void context_get_autoload_info_callback(pa_pdispatch *pd, uint32_t comman
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t) < 0)
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
eol = -1;
@ -1158,6 +1209,8 @@ finish:
pa_operation_unref(o);
}
PA_WARN_REFERENCE(pa_context_get_autoload_info_by_name, "Autoload will no longer be implemented by future versions of the PulseAudio server.");
pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata) {
pa_tagstruct *t;
pa_operation *o;
@ -1182,6 +1235,8 @@ pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *na
return o;
}
PA_WARN_REFERENCE(pa_context_get_autoload_info_by_index, "Autoload will no longer be implemented by future versions of the PulseAudio server.");
pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) {
pa_tagstruct *t;
pa_operation *o;
@ -1204,10 +1259,15 @@ pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx,
return o;
}
PA_WARN_REFERENCE(pa_context_get_autoload_info_list, "Autoload will no longer be implemented by future versions of the PulseAudio server.");
pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) {
return pa_context_send_simple_command(c, PA_COMMAND_GET_AUTOLOAD_INFO_LIST, context_get_autoload_info_callback, (pa_operation_cb_t) cb, userdata);
}
PA_WARN_REFERENCE(pa_context_add_autoload, "Autoload will no longer be implemented by future versions of the PulseAudio server.");
pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t cb, void* userdata) {
pa_operation *o;
pa_tagstruct *t;
@ -1234,6 +1294,8 @@ pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autolo
return o;
}
PA_WARN_REFERENCE(pa_context_remove_autoload_by_name, "Autoload will no longer be implemented by future versions of the PulseAudio server.");
pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata) {
pa_operation *o;
pa_tagstruct *t;
@ -1257,6 +1319,8 @@ pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name
return o;
}
PA_WARN_REFERENCE(pa_context_remove_autoload_by_index, "Autoload will no longer be implemented by future versions of the PulseAudio server.");
pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) {
pa_operation *o;
pa_tagstruct *t;

View file

@ -30,8 +30,10 @@
#include <pulse/operation.h>
#include <pulse/context.h>
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
#include <pulse/channelmap.h>
#include <pulse/volume.h>
#include <pulse/proplist.h>
/** \page introspect Server Query and Control
*
@ -206,21 +208,32 @@
PA_C_DECL_BEGIN
/** Stores information about sinks */
#define PA_PORT_DIGITAL "spdif"
#define PA_PORT_ANALOG_STEREO "analog-stereo"
#define PA_PORT_ANALOG_5_1 "analog-5-1"
#define PA_PORT_ANALOG_4_0 "analog-4-0"
/** @{ \name Sinks */
/** Stores information about sinks. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
typedef struct pa_sink_info {
const char *name; /**< Name of the sink */
uint32_t index; /**< Index of the sink */
const char *description; /**< Description of this sink */
pa_sample_spec sample_spec; /**< Sample spec of this sink */
pa_channel_map channel_map; /**< Channel map \since 0.8 */
pa_channel_map channel_map; /**< Channel map */
uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */
pa_cvolume volume; /**< Volume of the sink */
int mute; /**< Mute switch of the sink \since 0.8 */
int mute; /**< Mute switch of the sink */
uint32_t monitor_source; /**< Index of the monitor source connected to this sink */
const char *monitor_source_name; /**< The name of the monitor source */
pa_usec_t latency; /**< Length of filled playback buffer of this sink */
const char *driver; /**< Driver name. \since 0.8 */
pa_sink_flags_t flags; /**< Flags \since 0.8 */
pa_usec_t latency; /**< Length of queued audio in the output buffer. */
const char *driver; /**< Driver name. */
pa_sink_flags_t flags; /**< Flags */
pa_proplist *proplist; /**< Property list \since 0.9.11 */
pa_usec_t configured_latency; /**< The latency this device has been configured to. \since 0.9.11 */
} pa_sink_info;
/** Callback prototype for pa_context_get_sink_info_by_name() and friends */
@ -235,21 +248,47 @@ pa_operation* pa_context_get_sink_info_by_index(pa_context *c, uint32_t id, pa_s
/** Get the complete sink list */
pa_operation* pa_context_get_sink_info_list(pa_context *c, pa_sink_info_cb_t cb, void *userdata);
/** Stores information about sources */
/** Set the volume of a sink device specified by its index */
pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** Set the volume of a sink device specified by its name */
pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** Set the mute switch of a sink device specified by its index */
pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata);
/** Set the mute switch of a sink device specified by its name */
pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata);
/** Suspend/Resume a sink. \since 0.9.7 */
pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata);
/** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */
pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata);
/** @} */
/** @{ \name Sources */
/** Stores information about sources. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
typedef struct pa_source_info {
const char *name ; /**< Name of the source */
const char *name; /**< Name of the source */
uint32_t index; /**< Index of the source */
const char *description; /**< Description of this source */
pa_sample_spec sample_spec; /**< Sample spec of this source */
pa_channel_map channel_map; /**< Channel map \since 0.8 */
pa_channel_map channel_map; /**< Channel map */
uint32_t owner_module; /**< Owning module index, or PA_INVALID_INDEX */
pa_cvolume volume; /**< Volume of the source \since 0.8 */
int mute; /**< Mute switch of the sink \since 0.8 */
pa_cvolume volume; /**< Volume of the source */
int mute; /**< Mute switch of the sink */
uint32_t monitor_of_sink; /**< If this is a monitor source the index of the owning sink, otherwise PA_INVALID_INDEX */
const char *monitor_of_sink_name; /**< Name of the owning sink, or PA_INVALID_INDEX */
pa_usec_t latency; /**< Length of filled record buffer of this source. \since 0.5 */
const char *driver; /**< Driver name \since 0.8 */
pa_source_flags_t flags; /**< Flags \since 0.8 */
pa_usec_t latency; /**< Length of filled record buffer of this source. */
const char *driver; /**< Driver name */
pa_source_flags_t flags; /**< Flags */
pa_proplist *proplist; /**< Property list \since 0.9.11 */
pa_usec_t configured_latency; /**< The latency this device has been configured to. \since 0.9.11 */
} pa_source_info;
/** Callback prototype for pa_context_get_source_info_by_name() and friends */
@ -264,16 +303,34 @@ pa_operation* pa_context_get_source_info_by_index(pa_context *c, uint32_t id, pa
/** Get the complete source list */
pa_operation* pa_context_get_source_info_list(pa_context *c, pa_source_info_cb_t cb, void *userdata);
/** Server information */
/** Set the volume of a source device specified by its index */
pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** Set the volume of a source device specified by its name */
pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** Set the mute switch of a source device specified by its index */
pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata);
/** Set the mute switch of a source device specified by its name */
pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata);
/** @} */
/** @{ \name Server */
/** Server information. Please note that this structure can be
* extended as part of evolutionary API updates at any time in any new
* release. */
typedef struct pa_server_info {
const char *user_name; /**< User name of the daemon process */
const char *host_name; /**< Host name the daemon is running on */
const char *server_version; /**< Version string of the daemon */
const char *server_name; /**< Server package name (usually "pulseaudio") */
pa_sample_spec sample_spec; /**< Default sample specification */
const char *default_sink_name; /**< Name of default sink. \since 0.4 */
const char *default_source_name; /**< Name of default sink. \since 0.4*/
uint32_t cookie; /**< A random cookie for identifying this instance of PulseAudio. \since 0.8 */
const char *default_sink_name; /**< Name of default sink. */
const char *default_source_name; /**< Name of default sink. */
uint32_t cookie; /**< A random cookie for identifying this instance of PulseAudio. */
} pa_server_info;
/** Callback prototype for pa_context_get_server_info() */
@ -282,7 +339,13 @@ typedef void (*pa_server_info_cb_t) (pa_context *c, const pa_server_info*i, void
/** Get some information about the server */
pa_operation* pa_context_get_server_info(pa_context *c, pa_server_info_cb_t cb, void *userdata);
/** Stores information about modules */
/** @} */
/** @{ \name Modules */
/** Stores information about modules. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
typedef struct pa_module_info {
uint32_t index; /**< Index of the module */
const char*name, /**< Name of the module */
@ -300,12 +363,28 @@ pa_operation* pa_context_get_module_info(pa_context *c, uint32_t idx, pa_module_
/** Get the complete list of currently loaded modules */
pa_operation* pa_context_get_module_info_list(pa_context *c, pa_module_info_cb_t cb, void *userdata);
/** Stores information about clients */
/** Callback prototype for pa_context_load_module() */
typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdata);
/** Load a module. */
pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata);
/** Unload a module. */
pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
/** @} */
/** @{ \name Clients */
/** Stores information about clients. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
typedef struct pa_client_info {
uint32_t index; /**< Index of this client */
const char *name; /**< Name of this client */
uint32_t owner_module; /**< Index of the owning module, or PA_INVALID_INDEX */
const char *driver; /**< Driver name \since 0.8 */
const char *driver; /**< Driver name */
pa_proplist *proplist; /**< Property list \since 0.9.11 */
} pa_client_info;
/** Callback prototype for pa_context_get_client_info() and firends*/
@ -317,7 +396,16 @@ pa_operation* pa_context_get_client_info(pa_context *c, uint32_t idx, pa_client_
/** Get the complete client list */
pa_operation* pa_context_get_client_info_list(pa_context *c, pa_client_info_cb_t cb, void *userdata);
/** Stores information about sink inputs */
/** Kill a client. */
pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
/** @} */
/** @{ \name Sink Inputs */
/** Stores information about sink inputs. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
typedef struct pa_sink_input_info {
uint32_t index; /**< Index of the sink input */
const char *name; /**< Name of the sink input */
@ -329,9 +417,10 @@ typedef struct pa_sink_input_info {
pa_cvolume volume; /**< The volume of this sink input */
pa_usec_t buffer_usec; /**< Latency due to buffering in sink input, see pa_latency_info for details */
pa_usec_t sink_usec; /**< Latency of the sink device, see pa_latency_info for details */
const char *resample_method; /**< Thre resampling method used by this sink input. \since 0.7 */
const char *driver; /**< Driver name \since 0.8 */
const char *resample_method; /**< Thre resampling method used by this sink input. */
const char *driver; /**< Driver name */
int mute; /**< Stream muted \since 0.9.7 */
pa_proplist *proplist; /**< Property list \since 0.9.11 */
} pa_sink_input_info;
/** Callback prototype for pa_context_get_sink_input_info() and firends*/
@ -343,7 +432,28 @@ pa_operation* pa_context_get_sink_input_info(pa_context *c, uint32_t idx, pa_sin
/** Get the complete sink input list */
pa_operation* pa_context_get_sink_input_info_list(pa_context *c, pa_sink_input_info_cb_t cb, void *userdata);
/** Stores information about source outputs */
/** Move the specified sink input to a different sink. \since 0.9.5 */
pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, char *sink_name, pa_context_success_cb_t cb, void* userdata);
/** Move the specified sink input to a different sink. \since 0.9.5 */
pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void* userdata);
/** Set the volume of a sink input stream */
pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** Set the mute switch of a sink input stream \since 0.9.7 */
pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata);
/** Kill a sink input. */
pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
/** @} */
/** @{ \name Source Outputs */
/** Stores information about source outputs. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
typedef struct pa_source_output_info {
uint32_t index; /**< Index of the sink input */
const char *name; /**< Name of the sink input */
@ -352,10 +462,11 @@ typedef struct pa_source_output_info {
uint32_t source; /**< Index of the connected source */
pa_sample_spec sample_spec; /**< The sample specification of the source output */
pa_channel_map channel_map; /**< Channel map */
pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. \since 0.5 */
pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. \since 0.5 */
const char *resample_method; /**< Thre resampling method used by this source output. \since 0.7 */
const char *driver; /**< Driver name \since 0.8 */
pa_usec_t buffer_usec; /**< Latency due to buffering in the source output, see pa_latency_info for details. */
pa_usec_t source_usec; /**< Latency of the source device, see pa_latency_info for details. */
const char *resample_method; /**< Thre resampling method used by this source output. */
const char *driver; /**< Driver name */
pa_proplist *proplist; /**< Property list \since 0.9.11 */
} pa_source_output_info;
/** Callback prototype for pa_context_get_source_output_info() and firends*/
@ -367,43 +478,34 @@ pa_operation* pa_context_get_source_output_info(pa_context *c, uint32_t idx, pa_
/** Get the complete list of source outputs */
pa_operation* pa_context_get_source_output_info_list(pa_context *c, pa_source_output_info_cb_t cb, void *userdata);
/** Set the volume of a sink device specified by its index */
pa_operation* pa_context_set_sink_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** Move the specified source output to a different source. \since 0.9.5 */
pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, char *source_name, pa_context_success_cb_t cb, void* userdata);
/** Set the volume of a sink device specified by its name */
pa_operation* pa_context_set_sink_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** Move the specified source output to a different source. \since 0.9.5 */
pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata);
/** Set the mute switch of a sink device specified by its index \since 0.8 */
pa_operation* pa_context_set_sink_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata);
/** Suspend/Resume a source. \since 0.9.7 */
pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata);
/** Set the mute switch of a sink device specified by its name \since 0.8 */
pa_operation* pa_context_set_sink_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata);
/** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */
pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata);
/** Set the volume of a sink input stream */
pa_operation* pa_context_set_sink_input_volume(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** Kill a source output. */
pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
/** Set the mute switch of a sink input stream \since 0.9.7 */
pa_operation* pa_context_set_sink_input_mute(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata);
/** @} */
/** Set the volume of a source device specified by its index \since 0.8 */
pa_operation* pa_context_set_source_volume_by_index(pa_context *c, uint32_t idx, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** @{ \name Statistics */
/** Set the volume of a source device specified by its name \since 0.8 */
pa_operation* pa_context_set_source_volume_by_name(pa_context *c, const char *name, const pa_cvolume *volume, pa_context_success_cb_t cb, void *userdata);
/** Set the mute switch of a source device specified by its index \since 0.8 */
pa_operation* pa_context_set_source_mute_by_index(pa_context *c, uint32_t idx, int mute, pa_context_success_cb_t cb, void *userdata);
/** Set the mute switch of a source device specified by its name \since 0.8 */
pa_operation* pa_context_set_source_mute_by_name(pa_context *c, const char *name, int mute, pa_context_success_cb_t cb, void *userdata);
/** Memory block statistics */
/** Memory block statistics. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
typedef struct pa_stat_info {
uint32_t memblock_total; /**< Currently allocated memory blocks */
uint32_t memblock_total_size; /**< Currentl total size of allocated memory blocks */
uint32_t memblock_allocated; /**< Allocated memory blocks during the whole lifetime of the daemon */
uint32_t memblock_allocated_size; /**< Total size of all memory blocks allocated during the whole lifetime of the daemon */
uint32_t scache_size; /**< Total size of all sample cache entries. \since 0.4 */
uint32_t scache_size; /**< Total size of all sample cache entries. */
} pa_stat_info;
/** Callback prototype for pa_context_stat() */
@ -412,7 +514,13 @@ typedef void (*pa_stat_info_cb_t) (pa_context *c, const pa_stat_info *i, void *u
/** Get daemon memory block statistics */
pa_operation* pa_context_stat(pa_context *c, pa_stat_info_cb_t cb, void *userdata);
/** Stores information about sample cache entries */
/** @} */
/** @{ \name Cached Samples */
/** Stores information about sample cache entries. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
typedef struct pa_sample_info {
uint32_t index; /**< Index of this entry */
const char *name; /**< Name of this entry */
@ -420,9 +528,10 @@ typedef struct pa_sample_info {
pa_sample_spec sample_spec; /**< Sample specification of the sample */
pa_channel_map channel_map; /**< The channel map */
pa_usec_t duration; /**< Duration of this entry */
uint32_t bytes; /**< Length of this sample in bytes. \since 0.4 */
int lazy; /**< Non-zero when this is a lazy cache entry. \since 0.5 */
const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. \since 0.5 */
uint32_t bytes; /**< Length of this sample in bytes. */
int lazy; /**< Non-zero when this is a lazy cache entry. */
const char *filename; /**< In case this is a lazy cache entry, the filename for the sound file to be loaded on demand. */
pa_proplist *proplist; /**< Property list for this sample. \since 0.9.11 */
} pa_sample_info;
/** Callback prototype for pa_context_get_sample_info_by_name() and firends */
@ -437,31 +546,21 @@ pa_operation* pa_context_get_sample_info_by_index(pa_context *c, uint32_t idx, p
/** Get the complete list of samples stored in the daemon. */
pa_operation* pa_context_get_sample_info_list(pa_context *c, pa_sample_info_cb_t cb, void *userdata);
/** Kill a client. \since 0.5 */
pa_operation* pa_context_kill_client(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
/** @} */
/** Kill a sink input. \since 0.5 */
pa_operation* pa_context_kill_sink_input(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
/** \cond fulldocs */
/** Kill a source output. \since 0.5 */
pa_operation* pa_context_kill_source_output(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
/** @{ \name Autoload Entries */
/** Callback prototype for pa_context_load_module() and pa_context_add_autoload() */
typedef void (*pa_context_index_cb_t)(pa_context *c, uint32_t idx, void *userdata);
/** Load a module. \since 0.5 */
pa_operation* pa_context_load_module(pa_context *c, const char*name, const char *argument, pa_context_index_cb_t cb, void *userdata);
/** Unload a module. \since 0.5 */
pa_operation* pa_context_unload_module(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void *userdata);
/** Type of an autoload entry. \since 0.5 */
/** Type of an autoload entry. */
typedef enum pa_autoload_type {
PA_AUTOLOAD_SINK = 0,
PA_AUTOLOAD_SOURCE = 1
} pa_autoload_type_t;
/** Stores information about autoload entries. \since 0.5 */
/** Stores information about autoload entries. Please note that this structure
* can be extended as part of evolutionary API updates at any time in
* any new release. */
typedef struct pa_autoload_info {
uint32_t index; /**< Index of this autoload entry */
const char *name; /**< Name of the sink or source */
@ -473,47 +572,27 @@ typedef struct pa_autoload_info {
/** Callback prototype for pa_context_get_autoload_info_by_name() and firends */
typedef void (*pa_autoload_info_cb_t)(pa_context *c, const pa_autoload_info *i, int eol, void *userdata);
/** Get info about a specific autoload entry. \since 0.6 */
pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata);
/** Get info about a specific autoload entry. */
pa_operation* pa_context_get_autoload_info_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_autoload_info_cb_t cb, void *userdata) PA_GCC_DEPRECATED;
/** Get info about a specific autoload entry. \since 0.6 */
pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata);
/** Get info about a specific autoload entry. */
pa_operation* pa_context_get_autoload_info_by_index(pa_context *c, uint32_t idx, pa_autoload_info_cb_t cb, void *userdata) PA_GCC_DEPRECATED;
/** Get the complete list of autoload entries. \since 0.5 */
pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata);
/** Get the complete list of autoload entries. */
pa_operation* pa_context_get_autoload_info_list(pa_context *c, pa_autoload_info_cb_t cb, void *userdata) PA_GCC_DEPRECATED;
/** Add a new autoload entry. \since 0.5 */
pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t, void* userdata);
/** Add a new autoload entry. */
pa_operation* pa_context_add_autoload(pa_context *c, const char *name, pa_autoload_type_t type, const char *module, const char*argument, pa_context_index_cb_t, void* userdata) PA_GCC_DEPRECATED;
/** Remove an autoload entry. \since 0.6 */
pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata);
/** Remove an autoload entry. */
pa_operation* pa_context_remove_autoload_by_name(pa_context *c, const char *name, pa_autoload_type_t type, pa_context_success_cb_t cb, void* userdata) PA_GCC_DEPRECATED;
/** Remove an autoload entry. \since 0.6 */
pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata);
/** Remove an autoload entry. */
pa_operation* pa_context_remove_autoload_by_index(pa_context *c, uint32_t idx, pa_context_success_cb_t cb, void* userdata) PA_GCC_DEPRECATED;
/** Move the specified sink input to a different sink. \since 0.9.5 */
pa_operation* pa_context_move_sink_input_by_name(pa_context *c, uint32_t idx, char *sink_name, pa_context_success_cb_t cb, void* userdata);
/** @} */
/** Move the specified sink input to a different sink. \since 0.9.5 */
pa_operation* pa_context_move_sink_input_by_index(pa_context *c, uint32_t idx, uint32_t sink_idx, pa_context_success_cb_t cb, void* userdata);
/** Move the specified source output to a different source. \since 0.9.5 */
pa_operation* pa_context_move_source_output_by_name(pa_context *c, uint32_t idx, char *source_name, pa_context_success_cb_t cb, void* userdata);
/** Move the specified source output to a different source. \since 0.9.5 */
pa_operation* pa_context_move_source_output_by_index(pa_context *c, uint32_t idx, uint32_t source_idx, pa_context_success_cb_t cb, void* userdata);
/** Suspend/Resume a sink. \since 0.9.7 */
pa_operation* pa_context_suspend_sink_by_name(pa_context *c, char *sink_name, int suspend, pa_context_success_cb_t cb, void* userdata);
/** Suspend/Resume a sink. If idx is PA_INVALID_INDEX all sinks will be suspended. \since 0.9.7 */
pa_operation* pa_context_suspend_sink_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata);
/** Suspend/Resume a source. \since 0.9.7 */
pa_operation* pa_context_suspend_source_by_name(pa_context *c, char *source_name, int suspend, pa_context_success_cb_t cb, void* userdata);
/** Suspend/Resume a source. If idx is PA_INVALID_INDEX all sources will be suspended. \since 0.9.7 */
pa_operation* pa_context_suspend_source_by_index(pa_context *c, uint32_t idx, int suspend, pa_context_success_cb_t cb, void* userdata);
/** \endcond */
PA_C_DECL_END

View file

@ -28,8 +28,8 @@
#include <stdlib.h>
#include <pulse/xmalloc.h>
#include <pulse/gccmacro.h>
#include <pulsecore/gccmacro.h>
#include <pulsecore/macro.h>
#include "mainloop-api.h"
@ -75,4 +75,3 @@ void pa_mainloop_api_once(pa_mainloop_api* m, void (*callback)(pa_mainloop_api *
pa_assert_se(e = m->defer_new(m, once_callback, i));
m->defer_set_destroy(e, free_callback);
}

View file

@ -3,7 +3,7 @@
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2004-2008 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
@ -39,11 +39,11 @@
#endif
#include <pulse/xmalloc.h>
#include <pulse/gccmacro.h>
#include <pulsecore/core-error.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/gccmacro.h>
#include <pulsecore/macro.h>
#include "mainloop-signal.h"
@ -55,9 +55,9 @@ struct pa_signal_event {
#else
void (*saved_handler)(int sig);
#endif
void (*callback) (pa_mainloop_api*a, pa_signal_event *e, int sig, void *userdata);
void *userdata;
void (*destroy_callback) (pa_mainloop_api*a, pa_signal_event*e, void *userdata);
pa_signal_cb_t callback;
pa_signal_destroy_cb_t destroy_callback;
pa_signal_event *previous, *next;
};
@ -74,6 +74,7 @@ static void signal_handler(int sig) {
#ifndef HAVE_SIGACTION
signal(sig, signal_handler);
#endif
pa_write(signal_pipe[1], &sig, sizeof(sig), NULL);
errno = saved_errno;
@ -142,23 +143,21 @@ int pa_signal_init(pa_mainloop_api *a) {
}
void pa_signal_done(void) {
pa_assert(api);
pa_assert(signal_pipe[0] >= 0);
pa_assert(signal_pipe[1] >= 0);
pa_assert(io_event);
while (signals)
pa_signal_free(signals);
api->io_free(io_event);
io_event = NULL;
if (io_event) {
pa_assert(api);
api->io_free(io_event);
io_event = NULL;
}
pa_close_pipe(signal_pipe);
api = NULL;
}
pa_signal_event* pa_signal_new(int sig, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata) {
pa_signal_event* pa_signal_new(int sig, pa_signal_cb_t _callback, void *userdata) {
pa_signal_event *e = NULL;
#ifdef HAVE_SIGACTION
@ -223,7 +222,7 @@ void pa_signal_free(pa_signal_event *e) {
pa_xfree(e);
}
void pa_signal_set_destroy(pa_signal_event *e, void (*_callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata)) {
void pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t _callback) {
pa_assert(e);
e->destroy_callback = _callback;

View file

@ -6,7 +6,7 @@
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2004-2008 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
@ -39,23 +39,27 @@ PA_C_DECL_BEGIN
* signals. However, you may hook signal support into an abstract main loop via the routines defined herein.
*/
/** An opaque UNIX signal event source object */
typedef struct pa_signal_event pa_signal_event;
typedef void (*pa_signal_cb_t) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata);
typedef void (*pa_signal_destroy_cb_t) (pa_mainloop_api *api, pa_signal_event*e, void *userdata);
/** Initialize the UNIX signal subsystem and bind it to the specified main loop */
int pa_signal_init(pa_mainloop_api *api);
/** Cleanup the signal subsystem */
void pa_signal_done(void);
/** An opaque UNIX signal event source object */
typedef struct pa_signal_event pa_signal_event;
/** Create a new UNIX signal event source object */
pa_signal_event* pa_signal_new(int sig, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, int sig, void *userdata), void *userdata);
pa_signal_event* pa_signal_new(int sig, pa_signal_cb_t callback, void *userdata);
/** Free a UNIX signal event source object */
void pa_signal_free(pa_signal_event *e);
/** Set a function that is called when the signal event source is destroyed. Use this to free the userdata argument if required */
void pa_signal_set_destroy(pa_signal_event *e, void (*callback) (pa_mainloop_api *api, pa_signal_event*e, void *userdata));
void pa_signal_set_destroy(pa_signal_event *e, pa_signal_destroy_cb_t callback);
PA_C_DECL_END

View file

@ -77,6 +77,23 @@ void pa_operation_unref(pa_operation *o) {
}
}
static void operation_unlink(pa_operation *o) {
pa_assert(o);
if (o->context) {
pa_assert(PA_REFCNT_VALUE(o) >= 2);
PA_LLIST_REMOVE(pa_operation, o->context->operations, o);
pa_operation_unref(o);
o->context = NULL;
}
o->stream = NULL;
o->callback = NULL;
o->userdata = NULL;
}
static void operation_set_state(pa_operation *o, pa_operation_state_t st) {
pa_assert(o);
pa_assert(PA_REFCNT_VALUE(o) >= 1);
@ -88,20 +105,8 @@ static void operation_set_state(pa_operation *o, pa_operation_state_t st) {
o->state = st;
if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED)) {
if (o->context) {
pa_assert(PA_REFCNT_VALUE(o) >= 2);
PA_LLIST_REMOVE(pa_operation, o->context->operations, o);
pa_operation_unref(o);
}
o->context = NULL;
o->stream = NULL;
o->callback = NULL;
o->userdata = NULL;
}
if ((o->state == PA_OPERATION_DONE) || (o->state == PA_OPERATION_CANCELED))
operation_unlink(o);
pa_operation_unref(o);
}

View file

@ -69,16 +69,14 @@ pa_proplist* pa_proplist_new(void) {
}
void pa_proplist_free(pa_proplist* p) {
struct property *prop;
while ((prop = pa_hashmap_steal_first(MAKE_HASHMAP(p))))
property_free(prop);
pa_assert(p);
pa_proplist_clear(p);
pa_hashmap_free(MAKE_HASHMAP(p), NULL, NULL);
}
/** Will accept only valid UTF-8 */
int pa_proplist_puts(pa_proplist *p, const char *key, const char *value) {
int pa_proplist_sets(pa_proplist *p, const char *key, const char *value) {
struct property *prop;
pa_bool_t add = FALSE;
@ -104,7 +102,29 @@ int pa_proplist_puts(pa_proplist *p, const char *key, const char *value) {
return 0;
}
int pa_proplist_put(pa_proplist *p, const char *key, const void *data, size_t nbytes) {
/** Will accept only valid UTF-8 */
int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) {
va_list ap;
int r;
char *t;
pa_assert(p);
pa_assert(key);
if (!property_name_valid(key) || !pa_utf8_valid(format))
return -1;
va_start(ap, format);
t = pa_vsprintf_malloc(format, ap);
va_end(ap);
r = pa_proplist_sets(p, key, t);
pa_xfree(t);
return r;
}
int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes) {
struct property *prop;
pa_bool_t add = FALSE;
@ -175,18 +195,27 @@ int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *
return 0;
}
void pa_proplist_merge(pa_proplist *p, pa_proplist *other) {
void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, pa_proplist *other) {
struct property *prop;
void *state = NULL;
pa_assert(p);
pa_assert(mode == PA_UPDATE_SET || mode == PA_UPDATE_MERGE || mode == PA_UPDATE_REPLACE);
pa_assert(other);
while ((prop = pa_hashmap_iterate(MAKE_HASHMAP(other), &state, NULL)))
pa_assert_se(pa_proplist_put(p, prop->key, prop->value, prop->nbytes) == 0);
if (mode == PA_UPDATE_SET)
pa_proplist_clear(p);
while ((prop = pa_hashmap_iterate(MAKE_HASHMAP(other), &state, NULL))) {
if (mode == PA_UPDATE_MERGE && pa_proplist_contains(p, prop->key))
continue;
pa_assert_se(pa_proplist_set(p, prop->key, prop->value, prop->nbytes) == 0);
}
}
int pa_proplist_remove(pa_proplist *p, const char *key) {
int pa_proplist_unset(pa_proplist *p, const char *key) {
struct property *prop;
pa_assert(p);
@ -196,12 +225,30 @@ int pa_proplist_remove(pa_proplist *p, const char *key) {
return -1;
if (!(prop = pa_hashmap_remove(MAKE_HASHMAP(p), key)))
return -1;
return -2;
property_free(prop);
return 0;
}
int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]) {
const char * const * k;
int n = 0;
pa_assert(p);
pa_assert(keys);
for (k = keys; *k; k++)
if (!property_name_valid(*k))
return -1;
for (k = keys; *k; k++)
if (pa_proplist_unset(p, *k) >= 0)
n++;
return n;
}
const char *pa_proplist_iterate(pa_proplist *p, void **state) {
struct property *prop;
@ -255,3 +302,22 @@ int pa_proplist_contains(pa_proplist *p, const char *key) {
return 1;
}
void pa_proplist_clear(pa_proplist *p) {
struct property *prop;
pa_assert(p);
while ((prop = pa_hashmap_steal_first(MAKE_HASHMAP(p))))
property_free(prop);
}
pa_proplist* pa_proplist_copy(pa_proplist *template) {
pa_proplist *p;
pa_assert_se(p = pa_proplist_new());
if (template)
pa_proplist_update(p, PA_UPDATE_REPLACE, template);
return p;
}

View file

@ -24,67 +24,176 @@
USA.
***/
#include <pulsecore/macro.h>
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
PA_C_DECL_BEGIN
/* Defined properties:
*
* x11.xid
* x11.display
* x11.x_pointer
* x11.y_pointer
* x11.button
* media.name
* media.title
* media.artist
* media.language
* media.name "Guns'N'Roses: Civil War"
* media.title "Civil War"
* media.artist "Guns'N'Roses"
* media.language "de_DE"
* media.filename
* media.icon
* media.icon_name
* media.role video, music, game, event, phone, production
* application.name
* media.role video, music, game, event, phone, production, filter, abstract, stream
* event.id button-click, session-login
* event.x11.display
* event.x11.xid
* event.x11.x_pointer
* event.x11.y_pointer
* event.x11.button
* application.name "Rhythmbox Media Player"
* application.id "org.gnome.rhythmbox"
* application.version
* application.icon
* application.icon_name
* application.process.id
* application.process.binary
* application.process.user
* application.process.host
* device.string
* device.api oss, alsa, sunaudio
* device.description
* device.bus_path
* device.serial
* device.vendor_product_id
* device.class sound, modem, monitor, filter
* device.form_factor laptop-speakers, external-speakers, telephone, tv-capture, webcam-capture, microphone-capture, headset
* device.connector isa, pci, usb, firewire, bluetooth
* device.access_mode mmap, mmap_rewrite, serial
* device.master_device
* device.buffer_size
*/
#define PA_PROP_X11_XID "x11.xid"
#define PA_PROP_X11_DISPLAY "x11.display"
#define PA_PROP_X11_X_POINTER "x11.x_pointer"
#define PA_PROP_X11_Y_POINTER "x11.y_pointer"
#define PA_PROP_X11_BUTTON "x11.button"
#define PA_PROP_MEDIA_NAME "media.name"
#define PA_PROP_MEDIA_TITLE "media.title"
#define PA_PROP_MEDIA_ARTIST "media.artist"
#define PA_PROP_MEDIA_LANGUAGE "media.language"
#define PA_PROP_MEDIA_FILENAME "media.filename"
#define PA_PROP_MEDIA_ICON "media.icon"
#define PA_PROP_MEDIA_ICON_NAME "media.icon_name"
#define PA_PROP_MEDIA_ROLE "media.role"
#define PA_PROP_APPLICATION_NAME "application.name"
#define PA_PROP_APPLICATION_VERSION "application.version"
#define PA_PROP_APPLICATION_ICON "application.icon"
#define PA_PROP_APPLICATION_ICON_NAME "application.icon_name"
#define PA_PROP_MEDIA_NAME "media.name"
#define PA_PROP_MEDIA_TITLE "media.title"
#define PA_PROP_MEDIA_ARTIST "media.artist"
#define PA_PROP_MEDIA_LANGUAGE "media.language"
#define PA_PROP_MEDIA_FILENAME "media.filename"
#define PA_PROP_MEDIA_ICON "media.icon"
#define PA_PROP_MEDIA_ICON_NAME "media.icon_name"
#define PA_PROP_MEDIA_ROLE "media.role"
#define PA_PROP_EVENT_ID "event.id"
#define PA_PROP_EVENT_X11_DISPLAY "event.x11.display"
#define PA_PROP_EVENT_X11_XID "event.x11.xid"
#define PA_PROP_EVENT_MOUSE_X "event.mouse.x"
#define PA_PROP_EVENT_MOUSE_Y "event.mouse.y"
#define PA_PROP_EVENT_MOUSE_BUTTON "event.mouse.button"
#define PA_PROP_APPLICATION_NAME "application.name"
#define PA_PROP_APPLICATION_ID "application.id"
#define PA_PROP_APPLICATION_VERSION "application.version"
#define PA_PROP_APPLICATION_ICON "application.icon"
#define PA_PROP_APPLICATION_ICON_NAME "application.icon_name"
#define PA_PROP_APPLICATION_LANGUAGE "application.language"
#define PA_PROP_APPLICATION_PROCESS_ID "application.process.id"
#define PA_PROP_APPLICATION_PROCESS_BINARY "application.process.binary"
#define PA_PROP_APPLICATION_PROCESS_USER "application.process.user"
#define PA_PROP_APPLICATION_PROCESS_HOST "application.process.host"
#define PA_PROP_DEVICE_STRING "device.string"
#define PA_PROP_DEVICE_API "device.api"
#define PA_PROP_DEVICE_DESCRIPTION "device.description"
#define PA_PROP_DEVICE_BUS_PATH "device.bus_path"
#define PA_PROP_DEVICE_SERIAL "device.serial"
#define PA_PROP_DEVICE_VENDOR_PRODUCT_ID "device.vendor_product_id"
#define PA_PROP_DEVICE_CLASS "device.class"
#define PA_PROP_DEVICE_FORM_FACTOR "device.form_factor"
#define PA_PROP_DEVICE_CONNECTOR "device.connector"
#define PA_PROP_DEVICE_ACCESS_MODE "device.access_mode"
#define PA_PROP_DEVICE_MASTER_DEVICE "device.master_device"
#define PA_PROP_DEVICE_BUFFERING_BUFFER_SIZE "device.buffering.buffer_size"
#define PA_PROP_DEVICE_BUFFERING_FRAGMENT_SIZE "device.buffering.fragment_size"
/** A property list object. Basically a dictionary with UTF-8 strings
* as keys and arbitrary data as values. \since 0.9.11 */
typedef struct pa_proplist pa_proplist;
/** Allocate a property list. \since 0.9.11 */
pa_proplist* pa_proplist_new(void);
/** Free the property list. \since 0.9.11 */
void pa_proplist_free(pa_proplist* p);
/** Will accept only valid UTF-8 */
int pa_proplist_puts(pa_proplist *p, const char *key, const char *value);
int pa_proplist_put(pa_proplist *p, const char *key, const void *data, size_t nbytes);
/** Append a new string entry to the property list, possibly
* overwriting an already existing entry with the same key. An
* internal copy of the data passed is made. Will accept only valid
* UTF-8. \since 0.9.11 */
int pa_proplist_sets(pa_proplist *p, const char *key, const char *value);
/* Will return NULL if the data is not valid UTF-8 */
/** Append a new string entry to the property list, possibly
* overwriting an already existing entry with the same key. An
* internal copy of the data passed is made. Will accept only valid
* UTF-8. The data can be passed as printf()-style format string with
* arguments. \since 0.9.11 */
int pa_proplist_setf(pa_proplist *p, const char *key, const char *format, ...) PA_GCC_PRINTF_ATTR(3,4);
/** Append a new arbitrary data entry to the property list, possibly
* overwriting an already existing entry with the same key. An
* internal copy of the data passed is made. \since 0.9.11 */
int pa_proplist_set(pa_proplist *p, const char *key, const void *data, size_t nbytes);
/* Return a string entry for the specified key. Will return NULL if
* the data is not valid UTF-8. Will return a NUL-terminated string in
* an internally allocated buffer. The caller should make a copy of
* the data before accessing the property list again. \since 0.9.11 */
const char *pa_proplist_gets(pa_proplist *p, const char *key);
/** Return the the value for the specified key. Will return a
* NUL-terminated string for string entries. The pointer returned will
* point to an internally allocated buffer. The caller should make a
* copy of the data before the property list is accessed again. \since
* 0.9.11 */
int pa_proplist_get(pa_proplist *p, const char *key, const void **data, size_t *nbytes);
void pa_proplist_merge(pa_proplist *p, pa_proplist *other);
int pa_proplist_remove(pa_proplist *p, const char *key);
/** Update mode enum for pa_proplist_update(). \since 0.9.11 */
typedef enum pa_update_mode {
PA_UPDATE_SET, /*< Replace the entirey property list with the new one. Don't keep any of the old data around */
PA_UPDATE_MERGE, /*< Merge new property list into the existing one, not replacing any old entries if they share a common key with the new property list. */
PA_UPDATE_REPLACE /*< Merge new property list into the existing one, replacing all old entries that share a common key with the new property list. */
} pa_update_mode_t;
/** Merge property list "other" into "p", adhering the merge mode as
* specified in "mode". \since 0.9.11 */
void pa_proplist_update(pa_proplist *p, pa_update_mode_t mode, pa_proplist *other);
/** Removes a single entry from the property list, identified be the
* specified key name. \since 0.9.11 */
int pa_proplist_unset(pa_proplist *p, const char *key);
/** Similar to pa_proplist_remove() but takes an array of keys to
* remove. The array should be terminated by a NULL pointer. Return -1
* on failure, otherwise the number of entries actually removed (which
* might even be 0, if there where no matching entries to
* remove). \since 0.9.11 */
int pa_proplist_unset_many(pa_proplist *p, const char * const keys[]);
/** Iterate through the property list. The user should allocate a
* state variable of type void* and initialize it with NULL. A pointer
* to this variable should then be passed to pa_proplist_iterate()
* which should be called in a loop until it returns NULL which
* signifies EOL. The property list should not be modified during
* iteration through the list. On each invication this function will
* return the key string for the next entry. The keys in the property
* list do not have any particular order. \since 0.9.11 */
const char *pa_proplist_iterate(pa_proplist *p, void **state);
/** Format the property list nicely as a human readable string. Call pa_xfree() on the result. \since
* 0.9.11 */
char *pa_proplist_to_string(pa_proplist *p);
/** Returns 1 if an entry for the specified key is existant in the
* property list. \since 0.9.11 */
int pa_proplist_contains(pa_proplist *p, const char *key);
/** Remove all entries from the property list object. \since 0.9.11 */
void pa_proplist_clear(pa_proplist *p);
/** Allocate a new property list and copy over every single entry from
* the specific list. \since 0.9.11 */
pa_proplist* pa_proplist_copy(pa_proplist *t);
PA_C_DECL_END
#endif

View file

@ -32,6 +32,7 @@
#include <pulsecore/core-util.h>
#include <pulsecore/macro.h>
#include <pulse/timeval.h>
#include "sample.h"
@ -70,13 +71,13 @@ size_t pa_bytes_per_second(const pa_sample_spec *spec) {
pa_usec_t pa_bytes_to_usec(uint64_t length, const pa_sample_spec *spec) {
pa_assert(spec);
return (pa_usec_t) (((double) length/pa_frame_size(spec)*1000000)/spec->rate);
return (((pa_usec_t) (length / pa_frame_size(spec)) * PA_USEC_PER_SEC) / spec->rate);
}
size_t pa_usec_to_bytes(pa_usec_t t, const pa_sample_spec *spec) {
pa_assert(spec);
return (size_t) (((double) t * spec->rate / 1000000))*pa_frame_size(spec);
return (size_t) (((t * spec->rate) / PA_USEC_PER_SEC)) * pa_frame_size(spec);
}
int pa_sample_spec_valid(const pa_sample_spec *spec) {
@ -97,7 +98,10 @@ int pa_sample_spec_equal(const pa_sample_spec*a, const pa_sample_spec*b) {
pa_assert(a);
pa_assert(b);
return (a->format == b->format) && (a->rate == b->rate) && (a->channels == b->channels);
return
(a->format == b->format) &&
(a->rate == b->rate) &&
(a->channels == b->channels);
}
const char *pa_sample_format_to_string(pa_sample_format_t f) {

View file

@ -30,6 +30,7 @@
#include <sys/param.h>
#include <math.h>
#include <pulse/gccmacro.h>
#include <pulse/cdecl.h>
/** \page sample Sample Format Specifications
@ -172,7 +173,7 @@ typedef struct pa_sample_spec {
uint8_t channels; /**< Audio channels. (1 for mono, 2 for stereo, ...) */
} pa_sample_spec;
/** Type for usec specifications (unsigned). May be either 32 or 64 bit, depending on the architecture */
/** Type for usec specifications (unsigned). Always 64 bit. */
typedef uint64_t pa_usec_t;
/** Return the amount of bytes playback of a second of audio with the specified sample type takes */

View file

@ -49,12 +49,22 @@ int pa_stream_connect_upload(pa_stream *s, size_t length) {
pa_stream_ref(s);
s->direction = PA_STREAM_UPLOAD;
s->flags = 0;
t = pa_tagstruct_command(s->context, PA_COMMAND_CREATE_UPLOAD_STREAM, &tag);
pa_tagstruct_puts(t, s->name);
if (s->context->version < 13)
pa_tagstruct_puts(t, pa_proplist_gets(s->proplist, PA_PROP_MEDIA_NAME));
pa_tagstruct_put_sample_spec(t, &s->sample_spec);
pa_tagstruct_put_channel_map(t, &s->channel_map);
pa_tagstruct_putu32(t, length);
if (s->context->version >= 13) {
pa_init_proplist(s->proplist);
pa_tagstruct_put_proplist(t, s->proplist);
}
pa_pstream_send_tagstruct(s->context->pstream, t);
pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL);
@ -85,6 +95,73 @@ int pa_stream_finish_upload(pa_stream *s) {
return 0;
}
static void play_sample_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
pa_operation *o = userdata;
int success = 1;
uint32_t idx = PA_INVALID_INDEX;
pa_assert(pd);
pa_assert(o);
pa_assert(PA_REFCNT_VALUE(o) >= 1);
if (!o->context)
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
success = 0;
} else if ((o->context->version >= 13 && pa_tagstruct_getu32(t, &idx) < 0) ||
!pa_tagstruct_eof(t)) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
goto finish;
} else if (o->context->version >= 13 && idx == PA_INVALID_INDEX)
success = 0;
if (o->callback) {
pa_context_success_cb_t cb = (pa_context_success_cb_t) o->callback;
cb(o->context, success, o->userdata);
}
finish:
pa_operation_done(o);
pa_operation_unref(o);
}
static void play_sample_with_proplist_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
pa_operation *o = userdata;
uint32_t idx;
pa_assert(pd);
pa_assert(o);
pa_assert(PA_REFCNT_VALUE(o) >= 1);
if (!o->context)
goto finish;
if (command != PA_COMMAND_REPLY) {
if (pa_context_handle_error(o->context, command, t, FALSE) < 0)
goto finish;
idx = PA_INVALID_INDEX;
} else if (pa_tagstruct_getu32(t, &idx) < 0 ||
!pa_tagstruct_eof(t)) {
pa_context_fail(o->context, PA_ERR_PROTOCOL);
goto finish;
}
if (o->callback) {
pa_context_play_sample_cb_t cb = (pa_context_play_sample_cb_t) o->callback;
cb(o->context, idx, o->userdata);
}
finish:
pa_operation_done(o);
pa_operation_unref(o);
}
pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_context_success_cb_t cb, void *userdata) {
pa_operation *o;
pa_tagstruct *t;
@ -107,8 +184,47 @@ pa_operation *pa_context_play_sample(pa_context *c, const char *name, const char
pa_tagstruct_puts(t, dev);
pa_tagstruct_putu32(t, volume);
pa_tagstruct_puts(t, name);
if (c->version >= 13) {
pa_proplist *p = pa_proplist_new();
pa_tagstruct_put_proplist(t, p);
pa_proplist_free(p);
}
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, play_sample_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
return o;
}
pa_operation *pa_context_play_sample_with_proplist(pa_context *c, const char *name, const char *dev, pa_volume_t volume, pa_proplist *p, pa_context_play_sample_cb_t cb, void *userdata) {
pa_operation *o;
pa_tagstruct *t;
uint32_t tag;
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
PA_CHECK_VALIDITY_RETURN_NULL(c, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE);
PA_CHECK_VALIDITY_RETURN_NULL(c, name && *name, PA_ERR_INVALID);
PA_CHECK_VALIDITY_RETURN_NULL(c, !dev || *dev, PA_ERR_INVALID);
PA_CHECK_VALIDITY_RETURN_NULL(c, p, PA_ERR_INVALID);
PA_CHECK_VALIDITY_RETURN_NULL(c, c->version >= 13, PA_ERR_NOTSUPPORTED);
o = pa_operation_new(c, NULL, (pa_operation_cb_t) cb, userdata);
if (!dev)
dev = c->conf->default_sink;
t = pa_tagstruct_command(c, PA_COMMAND_PLAY_SAMPLE, &tag);
pa_tagstruct_putu32(t, PA_INVALID_INDEX);
pa_tagstruct_puts(t, dev);
pa_tagstruct_putu32(t, volume);
pa_tagstruct_puts(t, name);
pa_tagstruct_put_proplist(t, p);
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, play_sample_with_proplist_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
return o;
}
@ -128,9 +244,9 @@ pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_conte
t = pa_tagstruct_command(c, PA_COMMAND_REMOVE_SAMPLE, &tag);
pa_tagstruct_puts(t, name);
pa_pstream_send_tagstruct(c->pstream, t);
pa_pdispatch_register_reply(c->pdispatch, tag, DEFAULT_TIMEOUT, pa_context_simple_ack_callback, pa_operation_ref(o), (pa_free_cb_t) pa_operation_unref);
return o;
}

View file

@ -79,14 +79,25 @@
PA_C_DECL_BEGIN
/** Callback prototype for pa_context_play_sample_with_proplist(). The
* idx value is the index of the sink input object, or
* PA_INVALID_INDEX on failure. \since 0.9.11 */
typedef void (*pa_context_play_sample_cb_t)(pa_context *c, uint32_t idx, void *userdata);
/** Make this stream a sample upload stream */
int pa_stream_connect_upload(pa_stream *s, size_t length);
/** Finish the sample upload, the stream name will become the sample name. You cancel a samp
* le upload by issuing pa_stream_disconnect() */
/** Finish the sample upload, the stream name will become the sample
* name. You cancel a sample upload by issuing
* pa_stream_disconnect() */
int pa_stream_finish_upload(pa_stream *s);
/** Play a sample from the sample cache to the specified device. If the latter is NULL use the default sink. Returns an operation object */
/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */
pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t cb, void *userdata);
/** Play a sample from the sample cache to the specified device. If
* the latter is NULL use the default sink. Returns an operation
* object */
pa_operation* pa_context_play_sample(
pa_context *c /**< Context */,
const char *name /**< Name of the sample to play */,
@ -95,8 +106,18 @@ pa_operation* pa_context_play_sample(
pa_context_success_cb_t cb /**< Call this function after successfully starting playback, or NULL */,
void *userdata /**< Userdata to pass to the callback */);
/** Remove a sample from the sample cache. Returns an operation object which may be used to cancel the operation while it is running */
pa_operation* pa_context_remove_sample(pa_context *c, const char *name, pa_context_success_cb_t, void *userdata);
/** Play a sample from the sample cache to the specified device,
* allowing specification of a property list for the playback
* stream. If the latter is NULL use the default sink. Returns an
* operation object. \since 0.9.11 */
pa_operation* pa_context_play_sample_with_proplist(
pa_context *c /**< Context */,
const char *name /**< Name of the sample to play */,
const char *dev /**< Sink to play this sample on */,
pa_volume_t volume /**< Volume to play this sample with */ ,
pa_proplist *proplist /**< Property list for this sound. The property list of the cached entry will be merged into this property list */,
pa_context_play_sample_cb_t cb /**< Call this function after successfully starting playback, or NULL */,
void *userdata /**< Userdata to pass to the callback */);
PA_C_DECL_END

View file

@ -138,10 +138,10 @@ int pa_simple_drain(pa_simple *s, int *error);
/** Read some data from the server */
int pa_simple_read(pa_simple *s, void*data, size_t bytes, int *error);
/** Return the playback latency. \since 0.5 */
/** Return the playback latency. */
pa_usec_t pa_simple_get_latency(pa_simple *s, int *error);
/** Flush the playback buffer. \since 0.5 */
/** Flush the playback buffer. */
int pa_simple_flush(pa_simple *s, int *error);
PA_C_DECL_END

File diff suppressed because it is too large Load diff

View file

@ -276,13 +276,25 @@ typedef void (*pa_stream_request_cb_t)(pa_stream *p, size_t bytes, void *userdat
/** A generic notification callback */
typedef void (*pa_stream_notify_cb_t)(pa_stream *p, void *userdata);
/** Create a new, unconnected stream with the specified name and sample type */
/** Create a new, unconnected stream with the specified name and
* sample type. It is recommended to use pa_stream_new_with_proplist()
* instead and specify some initial properties. */
pa_stream* pa_stream_new(
pa_context *c /**< The context to create this stream in */,
const char *name /**< A name for this stream */,
const pa_sample_spec *ss /**< The desired sample format */,
const pa_channel_map *map /**< The desired channel map, or NULL for default */);
/** Create a new, unconnected stream with the specified name and
* sample type, and specify the the initial stream property
* list. \since 0.9.11 */
pa_stream* pa_stream_new_with_proplist(
pa_context *c /**< The context to create this stream in */,
const char *name /**< A name for this stream */,
const pa_sample_spec *ss /**< The desired sample format */,
const pa_channel_map *map /**< The desired channel map, or NULL for default */,
pa_proplist *p /**< The initial property list */);
/** Decrease the reference counter by one */
void pa_stream_unref(pa_stream *s);
@ -327,6 +339,10 @@ const char *pa_stream_get_device_name(pa_stream *s);
* server is older than 0.9.8. \since 0.9.8 */
int pa_stream_is_suspended(pa_stream *s);
/** Return 1 if the this stream has been corked. This will return 0 if
* not, and negative on error. \since 0.9.11 */
int pa_stream_is_corked(pa_stream *s);
/** Connect the stream to a sink */
int pa_stream_connect_playback(
pa_stream *s /**< The stream to connect to a sink */,
@ -356,7 +372,7 @@ int pa_stream_disconnect(pa_stream *s);
int pa_stream_write(
pa_stream *p /**< The stream to use */,
const void *data /**< The data to write */,
size_t bytes /**< The length of the data to write in bytes*/,
size_t nbytes /**< The length of the data to write in bytes*/,
pa_free_cb_t free_cb /**< A cleanup routine for the data or NULL to request an internal copy */,
int64_t offset, /**< Offset for seeking, must be 0 for upload streams */
pa_seek_mode_t seek /**< Seek mode, must be PA_SEEK_RELATIVE for upload streams */);
@ -365,20 +381,20 @@ int pa_stream_write(
* data will point to the actual data and length will contain the size
* of the data in bytes (which can be less than a complete framgnet).
* Use pa_stream_drop() to actually remove the data from the
* buffer. If no data is available will return a NULL pointer \since 0.8 */
* buffer. If no data is available will return a NULL pointer */
int pa_stream_peek(
pa_stream *p /**< The stream to use */,
const void **data /**< Pointer to pointer that will point to data */,
size_t *bytes /**< The length of the data read in bytes */);
size_t *nbytes /**< The length of the data read in bytes */);
/** Remove the current fragment on record streams. It is invalid to do this without first
* calling pa_stream_peek(). \since 0.8 */
* calling pa_stream_peek(). */
int pa_stream_drop(pa_stream *p);
/** Return the number of bytes that may be written using pa_stream_write() */
size_t pa_stream_writable_size(pa_stream *p);
/** Return the number of bytes that may be read using pa_stream_read() \since 0.8 */
/** Return the number of bytes that may be read using pa_stream_read()*/
size_t pa_stream_readable_size(pa_stream *p);
/** Drain a playback stream. Use this for notification when the buffer is empty */
@ -398,18 +414,25 @@ void pa_stream_set_state_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *
void pa_stream_set_write_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata);
/** Set the callback function that is called when new data is available from the stream.
* Return the number of bytes read. \since 0.8 */
* Return the number of bytes read.*/
void pa_stream_set_read_callback(pa_stream *p, pa_stream_request_cb_t cb, void *userdata);
/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) \since 0.8 */
/** Set the callback function that is called when a buffer overflow happens. (Only for playback streams) */
void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata);
/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) \since 0.8 */
/** Set the callback function that is called when a buffer underflow happens. (Only for playback streams) */
void pa_stream_set_underflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata);
/** Set the callback function that is called when a the server starts
* playback after an underrun or on initial startup. This only informs
* that audio is flowing again, it is no indication that audio startet
* to reach the speakers already. (Only for playback streams). \since
* 0.9.11 */
void pa_stream_set_started_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata);
/** Set the callback function that is called whenever a latency
* information update happens. Useful on PA_STREAM_AUTO_TIMING_UPDATE
* streams only. (Only for playback streams) \since 0.8.2 */
* streams only. (Only for playback streams) */
void pa_stream_set_latency_update_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata);
/** Set the callback function that is called whenever the stream is
@ -429,24 +452,25 @@ void pa_stream_set_moved_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *
* 0.9.8. \since 0.9.8 */
void pa_stream_set_suspended_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata);
/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. \since 0.3 */
/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. */
pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata);
/** Flush the playback buffer of this stream. Most of the time you're
* better off using the parameter delta of pa_stream_write() instead of this
* function. Available on both playback and recording streams. \since 0.3 */
* better off using the parameter delta of pa_stream_write() instead
* of this function. Available on both playback and recording
* streams. */
pa_operation* pa_stream_flush(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
/** Reenable prebuffering as specified in the pa_buffer_attr
* structure. Available for playback streams only. \since 0.6 */
* structure. Available for playback streams only. */
pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
/** Request immediate start of playback on this stream. This disables
* prebuffering as specified in the pa_buffer_attr
* structure, temporarily. Available for playback streams only. \since 0.3 */
* prebuffering as specified in the pa_buffer_attr structure,
* temporarily. Available for playback streams only. */
pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
/** Rename the stream. \since 0.5 */
/** Rename the stream. */
pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata);
/** Return the current playback/recording time. This is based on the
@ -463,13 +487,13 @@ pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_succe
* be disabled by using PA_STREAM_NOT_MONOTONOUS. This may be
* desirable to deal better with bad estimations of transport
* latencies, but may have strange effects if the application is not
* able to deal with time going 'backwards'. \since 0.6 */
* able to deal with time going 'backwards'. */
int pa_stream_get_time(pa_stream *s, pa_usec_t *r_usec);
/** Return the total stream latency. This function is based on
* pa_stream_get_time(). In case the stream is a monitoring stream the
* result can be negative, i.e. the captured samples are not yet
* played. In this case *negative is set to 1. \since 0.6 */
* played. In this case *negative is set to 1. */
int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative);
/** Return the latest raw timing data structure. The returned pointer
@ -481,13 +505,13 @@ int pa_stream_get_latency(pa_stream *s, pa_usec_t *r_usec, int *negative);
* function will fail with PA_ERR_NODATA. Please note that the
* write_index member field (and only this field) is updated on each
* pa_stream_write() call, not just when a timing update has been
* recieved. \since 0.8 */
* recieved. */
const pa_timing_info* pa_stream_get_timing_info(pa_stream *s);
/** Return a pointer to the stream's sample specification. \since 0.6 */
/** Return a pointer to the stream's sample specification. */
const pa_sample_spec* pa_stream_get_sample_spec(pa_stream *s);
/** Return a pointer to the stream's channel map. \since 0.8 */
/** Return a pointer to the stream's channel map. */
const pa_channel_map* pa_stream_get_channel_map(pa_stream *s);
/** Return the buffer metrics of the stream. Only valid after the
@ -510,6 +534,18 @@ pa_operation *pa_stream_set_buffer_attr(pa_stream *s, const pa_buffer_attr *attr
* is at least PulseAudio 0.9.8. \since 0.9.8 */
pa_operation *pa_stream_update_sample_rate(pa_stream *s, uint32_t rate, pa_stream_success_cb_t cb, void *userdata);
/* Update the property list of the sink input/source output of this
* stream, adding new entries. Please note that it is highly
* recommended to set as much properties initially via
* pa_stream_new_with_proplist() as possible instead a posteriori with
* this function, since that information may then be used to route
* this stream to the right device. \since 0.9.11 */
pa_operation *pa_stream_proplist_update(pa_stream *s, pa_update_mode_t mode, pa_proplist *p, pa_stream_success_cb_t cb, void *userdata);
/* Update the property list of the sink input/source output of this
* stream, remove entries. \since 0.9.11 */
pa_operation *pa_stream_proplist_remove(pa_stream *s, const char *const keys[], pa_stream_success_cb_t cb, void *userdata);
PA_C_DECL_END
#endif

View file

@ -27,7 +27,8 @@
#include <stdio.h>
#include <pulsecore/gccmacro.h>
#include <pulse/gccmacro.h>
#include <pulsecore/macro.h>
#include <pulsecore/pstream-util.h>
@ -87,6 +88,9 @@ void pa_context_set_subscribe_callback(pa_context *c, pa_context_subscribe_cb_t
pa_assert(c);
pa_assert(PA_REFCNT_VALUE(c) >= 1);
if (c->state == PA_CONTEXT_TERMINATED || c->state == PA_CONTEXT_FAILED)
return;
c->subscribe_callback = cb;
c->subscribe_userdata = userdata;
}

View file

@ -148,6 +148,24 @@ struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) {
return tv;
}
struct timeval* pa_timeval_sub(struct timeval *tv, pa_usec_t v) {
unsigned long secs;
pa_assert(tv);
secs = (unsigned long) (v/PA_USEC_PER_SEC);
tv->tv_sec -= secs;
v -= ((pa_usec_t) secs) * PA_USEC_PER_SEC;
if (tv->tv_usec >= (suseconds_t) v)
tv->tv_usec -= (suseconds_t) v;
else {
tv->tv_sec --;
tv->tv_usec = tv->tv_usec + PA_USEC_PER_SEC - v;
}
return tv;
}
struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v) {
pa_assert(tv);

View file

@ -26,6 +26,7 @@
***/
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
#include <pulse/sample.h>
/** \file
@ -37,6 +38,8 @@ PA_C_DECL_BEGIN
#define PA_USEC_PER_SEC 1000000
#define PA_NSEC_PER_SEC 1000000000
#define PA_USEC_PER_MSEC 1000
#define PA_NSEC_PER_MSEC 1000000
#define PA_NSEC_PER_USEC 1000
struct timeval;
@ -54,7 +57,10 @@ int pa_timeval_cmp(const struct timeval *a, const struct timeval *b) PA_GCC_PURE
pa_usec_t pa_timeval_age(const struct timeval *tv);
/** Add the specified time inmicroseconds to the specified timeval structure */
struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v) PA_GCC_PURE;
struct timeval* pa_timeval_add(struct timeval *tv, pa_usec_t v);
/** Subtract the specified time inmicroseconds to the specified timeval structure. \since 0.9.11 */
struct timeval* pa_timeval_sub(struct timeval *tv, pa_usec_t v);
/** Store the specified uec value in the timeval struct. \since 0.9.7 */
struct timeval* pa_timeval_store(struct timeval *tv, pa_usec_t v);

View file

@ -26,6 +26,7 @@
***/
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
/** \file
* UTF8 Validation functions

View file

@ -28,6 +28,7 @@
#include <stddef.h>
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
/** \file
* Assorted utility functions */

View file

@ -8,17 +8,17 @@
Copyright 2004-2006 Lennart Poettering
Copyright 2006 Pierre Ossman <ossman@cendio.se> for Cendio AB
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
@ -39,7 +39,8 @@ a macro and not a function, so it is impossible to get the pointer of
it. */
#define pa_get_headers_version() ("@PACKAGE_VERSION@")
/** Return the version of the library the current application is linked to. */
/** Return the version of the library the current application is
* linked to. */
const char* pa_get_library_version(void);
/** The current API version. Version 6 relates to Polypaudio
@ -47,8 +48,8 @@ const char* pa_get_library_version(void);
* PA_API_VERSION undefined. */
#define PA_API_VERSION @PA_API_VERSION@
/** The current protocol version. Version 8 relates to Polypaudio 0.8/PulseAudio 0.9.
* \since 0.8 */
/** The current protocol version. Version 8 relates to Polypaudio
* 0.8/PulseAudio 0.9. */
#define PA_PROTOCOL_VERSION @PA_PROTOCOL_VERSION@
PA_C_DECL_END

View file

@ -80,10 +80,10 @@ pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) {
return pa_sw_volume_from_linear(pa_sw_volume_to_linear(a)* pa_sw_volume_to_linear(b));
}
#define USER_DECIBEL_RANGE 30
#define USER_DECIBEL_RANGE 60
pa_volume_t pa_sw_volume_from_dB(double dB) {
if (dB <= -USER_DECIBEL_RANGE)
if (isinf(dB) < 0 || dB <= -USER_DECIBEL_RANGE)
return PA_VOLUME_MUTED;
return (pa_volume_t) ((dB/USER_DECIBEL_RANGE+1)*PA_VOLUME_NORM);

View file

@ -26,7 +26,9 @@
***/
#include <inttypes.h>
#include <pulse/cdecl.h>
#include <pulse/gccmacro.h>
#include <pulse/sample.h>
/** \page volume Volume Control
@ -101,10 +103,10 @@ PA_C_DECL_BEGIN
typedef uint32_t pa_volume_t;
/** Normal volume (100%) */
#define PA_VOLUME_NORM (0x10000)
#define PA_VOLUME_NORM ((pa_volume_t) 0x10000)
/** Muted volume (0%) */
#define PA_VOLUME_MUTED (0)
#define PA_VOLUME_MUTED ((pa_volume_t) 0)
/** A structure encapsulating a per-channel volume */
typedef struct pa_cvolume {
@ -149,25 +151,25 @@ int pa_cvolume_channels_equal_to(const pa_cvolume *a, pa_volume_t v) PA_GCC_PURE
pa_volume_t pa_sw_volume_multiply(pa_volume_t a, pa_volume_t b) PA_GCC_CONST;
/** Multiply to per-channel volumes and return the result in *dest. This is only valid for software volumes! */
pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b) PA_GCC_PURE;
pa_cvolume *pa_sw_cvolume_multiply(pa_cvolume *dest, const pa_cvolume *a, const pa_cvolume *b);
/** Convert a decibel value to a volume. This is only valid for software volumes! \since 0.4 */
/** Convert a decibel value to a volume. This is only valid for software volumes! */
pa_volume_t pa_sw_volume_from_dB(double f) PA_GCC_CONST;
/** Convert a volume to a decibel value. This is only valid for software volumes! \since 0.4 */
/** Convert a volume to a decibel value. This is only valid for software volumes! */
double pa_sw_volume_to_dB(pa_volume_t v) PA_GCC_CONST;
/** Convert a linear factor to a volume. This is only valid for software volumes! \since 0.8 */
/** Convert a linear factor to a volume. This is only valid for software volumes! */
pa_volume_t pa_sw_volume_from_linear(double v) PA_GCC_CONST;
/** Convert a volume to a linear factor. This is only valid for software volumes! \since 0.8 */
/** Convert a volume to a linear factor. This is only valid for software volumes! */
double pa_sw_volume_to_linear(pa_volume_t v) PA_GCC_CONST;
#ifdef INFINITY
#define PA_DECIBEL_MININFTY (-INFINITY)
#define PA_DECIBEL_MININFTY ((double) -INFINITY)
#else
/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). \since 0.4 */
#define PA_DECIBEL_MININFTY (-200)
/** This value is used as minus infinity when using pa_volume_{to,from}_dB(). */
#define PA_DECIBEL_MININFTY ((double) -200)
#endif
PA_C_DECL_END

View file

@ -29,9 +29,10 @@
#include <signal.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pulse/gccmacro.h>
#include <pulsecore/core-util.h>
#include <pulsecore/gccmacro.h>
#include <pulsecore/macro.h>
#include "xmalloc.h"
@ -123,8 +124,12 @@ char *pa_xstrndup(const char *s, size_t l) {
}
void pa_xfree(void *p) {
int saved_errno;
if (!p)
return;
saved_errno = errno;
free(p);
errno = saved_errno;
}