mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2026-02-15 22:05:22 -05:00
Yes, yet another evil all-in-one commit of intervowen changes. I suck.
* Drop "state" directory, fold that into "runtime directory" * No longer automatically rewind when a new stream connects * Rework sound file stream, to cause a rewind on initialisation, shorten _pop() code a bit * Fix reference counting of pa_socket_server in the protocol implementations * Rework daemon initialization code to be compatible with non-SUID-root setups where RLIMIT_RTPRIO is non-zero * Print warning if RT/HP is enabled in the config, but due to missing caps, rlimits, policy we cannot enable it. * Fix potential memory leak in pa_open_config_file() * Add pa_find_config_file() which works much like pa_open_config_file() but doesn't actually open the config file in question. Just searches for it. * Add portable pa_is_path_absolute() * Add pa_close_all() and use it on daemon startup to close leaking file descriptors (inspired from what I did for libdaemon) * Add pa_unblock_sigs() and use it on daemon startup to unblock all signals (inspired from libdaemon, too) * Add pa_reset_sigs() and use it on daemon startup to reset all signal handlers (inspired from libdaemon as well) * Implement pa_set_env() * Define RLIMIT_RTTIME and friends if not defined by glibc * Add pa_strempty() * rename state testing macros to include _IS_, to make clearer that they are no states, but testing macros * Implement pa_source_output_set_requested_latency_within_thread() to be able to forward latency info to sources from within the IO thread * Similar for sink inputs * generelize since_underrun counter in sink inputs to "playing_for" and "underrun_for". Use only this for ignore potential rewind requests over underruns * Add new native protocol message PLAYBACK_STREAM_MESSAGE_STARTED for notification about the end of an underrun * Port native protocol to use underrun_for/playing_for which is maintained by the sink input anyway * Pass underrun_for/playing_for in timing info to client * Drop pa_sink_skip() since it breaks underrun detection code * Move PID file and unix sockets to the runtime dir (i.e. ~/.pulse). This fixes a potention DoS attack from other users stealing dirs in /tmp from us so that we cannot take them anymore) * Allow setting of more resource limits from the config file. Set RTTIME by default * Streamline daemon startup code * Rework algorithm to find default configuration files * If run in system mode use "system.pa" instead of "default.pa" as default script file * Change ladspa sink to use pa_clamp_samples() for clamping samples * Teach module-null-sink how to deal with rewinding * Try to support ALSA devices with no implicit channel map. Synthesize one by padding with PA_CHANNEL_POSITION_AUX channels. This is not tested since I lack hardware with these problems. * Make use of time smoother in the client libraries. * Add new pa_stream_is_corked() and pa_stream_set_started_callback() functions to public API * Since our native socket moved, add some code for finding sockets created by old versions of PA. This should ease upgrades git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2329 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
f94fae3da3
commit
52e3628c3e
48 changed files with 2408 additions and 1232 deletions
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -93,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
|
||||
};
|
||||
|
||||
|
|
@ -100,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;
|
||||
}
|
||||
}
|
||||
|
|
@ -114,6 +117,16 @@ 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;
|
||||
|
||||
|
|
@ -146,18 +159,14 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
|
|||
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
|
||||
|
|
@ -186,26 +195,48 @@ pa_context *pa_context_new_with_proplist(pa_mainloop_api *mainloop, const char *
|
|||
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)
|
||||
|
|
@ -252,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);
|
||||
|
|
@ -302,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;
|
||||
|
||||
|
|
@ -358,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;
|
||||
}
|
||||
|
||||
|
|
@ -390,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;
|
||||
}
|
||||
|
||||
|
|
@ -417,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
|
||||
|
|
@ -486,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);
|
||||
|
|
@ -525,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;
|
||||
}
|
||||
|
|
@ -542,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)
|
||||
|
|
@ -557,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();
|
||||
|
|
@ -592,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)
|
||||
|
|
@ -606,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);
|
||||
|
||||
|
|
@ -665,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;
|
||||
}
|
||||
|
|
@ -680,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);
|
||||
|
|
@ -692,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;
|
||||
}
|
||||
|
|
@ -708,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,
|
||||
|
|
@ -736,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 */
|
||||
|
||||
|
|
@ -757,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);
|
||||
|
|
@ -791,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) {
|
||||
|
|
@ -812,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;
|
||||
}
|
||||
|
|
@ -820,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)) ||
|
||||
|
|
@ -901,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;
|
||||
|
|
@ -920,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;
|
||||
|
|
@ -958,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;
|
||||
|
|
@ -969,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);
|
||||
|
|
@ -989,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);
|
||||
|
|
@ -1002,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);
|
||||
|
|
@ -1020,11 +1063,14 @@ pa_operation* pa_context_set_name(pa_context *c, const char *name, pa_context_su
|
|||
|
||||
if (c->version >= 13) {
|
||||
pa_proplist *p = pa_proplist_new();
|
||||
|
||||
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);
|
||||
|
|
@ -1062,7 +1108,7 @@ 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, c->state == PA_CONTEXT_READY, PA_ERR_BADSTATE, PA_INVALID_INDEX);
|
||||
PA_CHECK_VALIDITY_RETURN_ANY(c, PA_CONTEXT_IS_GOOD(c->state), PA_ERR_BADSTATE, PA_INVALID_INDEX);
|
||||
|
||||
return c->version;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -296,6 +312,7 @@ enum {
|
|||
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 */
|
||||
};
|
||||
|
||||
|
|
@ -368,7 +385,15 @@ typedef struct pa_timing_info {
|
|||
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
|
||||
|
|
@ -403,6 +428,14 @@ typedef struct pa_timing_info {
|
|||
* 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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
@ -89,35 +89,39 @@ struct pa_context {
|
|||
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);
|
||||
|
||||
pa_proplist *proplist;
|
||||
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_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;
|
||||
|
|
@ -127,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;
|
||||
|
|
@ -146,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;
|
||||
|
|
@ -168,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);
|
||||
|
|
@ -193,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);
|
||||
|
||||
|
|
@ -205,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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -261,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;
|
||||
|
|
@ -382,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;
|
||||
|
|
@ -464,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;
|
||||
|
|
@ -543,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;
|
||||
|
|
@ -637,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;
|
||||
|
|
@ -967,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;
|
||||
|
|
@ -1111,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;
|
||||
|
|
@ -1172,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;
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ static void play_sample_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_
|
|||
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;
|
||||
|
|
@ -141,7 +141,7 @@ static void play_sample_with_proplist_ack_callback(pa_pdispatch *pd, uint32_t co
|
|||
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;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -339,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 */,
|
||||
|
|
@ -368,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 */);
|
||||
|
|
@ -381,7 +385,7 @@ int pa_stream_write(
|
|||
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(). */
|
||||
|
|
@ -419,6 +423,13 @@ void pa_stream_set_overflow_callback(pa_stream *p, pa_stream_notify_cb_t cb, voi
|
|||
/** 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) */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue