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:
Lennart Poettering 2008-05-01 19:51:05 +00:00
parent f94fae3da3
commit 52e3628c3e
48 changed files with 2408 additions and 1232 deletions

View file

@ -671,8 +671,24 @@ snd_pcm_t *pa_alsa_open_by_device_string(
*dev = d;
if (ss->channels != map->channels) {
pa_assert_se(pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_AUX));
pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_ALSA);
if (!pa_channel_map_init_auto(map, ss->channels, PA_CHANNEL_MAP_ALSA)) {
unsigned c;
pa_channel_position_t pos;
pa_log_warn("Device has an unknown channel mapping. This is a limitation of ALSA. Synthesizing channel map.");
for (c = ss->channels; c > 0; c--)
if (pa_channel_map_init_auto(map, c, PA_CHANNEL_MAP_ALSA))
break;
pa_assert(c > 0);
pos = PA_CHANNEL_POSITION_AUX0;
for (; c < map->channels; c ++)
map->map[c] = pos++;
map->channels = ss->channels;
}
}
return pcm_handle;

View file

@ -665,7 +665,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
case PA_SINK_SUSPENDED:
pa_assert(PA_SINK_OPENED(u->sink->thread_info.state));
pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
if (suspend(u) < 0)
return -1;
@ -836,9 +836,20 @@ static int sink_set_mute_cb(pa_sink *s) {
static void sink_update_requested_latency_cb(pa_sink *s) {
struct userdata *u = s->userdata;
snd_pcm_sframes_t before;
pa_assert(u);
before = u->hwbuf_unused_frames;
update_sw_params(u);
/* Let's check whether we now use only a smaller part of the
buffer then before. If so, we need to make sure that subsequent
rewinds are relative to the new maxium fill level and not to the
current fill level. Thus, let's do a full rewind once, to clear
things up. */
if (u->hwbuf_unused_frames > before)
pa_sink_request_rewind(s, 0);
}
static int process_rewind(struct userdata *u) {
@ -846,6 +857,7 @@ static int process_rewind(struct userdata *u) {
size_t rewind_nbytes, unused_nbytes, limit_nbytes;
pa_assert(u);
/* Figure out how much we shall rewind and reset the counter */
rewind_nbytes = u->sink->thread_info.rewind_nbytes;
u->sink->thread_info.rewind_nbytes = 0;
@ -917,7 +929,7 @@ static void thread_func(void *userdata) {
/* pa_log_debug("loop"); */
/* Render some data and write it to the dsp */
if (PA_SINK_OPENED(u->sink->thread_info.state)) {
if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
int work_done = 0;
if (u->sink->thread_info.rewind_nbytes > 0)
@ -982,7 +994,7 @@ static void thread_func(void *userdata) {
goto finish;
/* Tell ALSA about this and process its response */
if (PA_SINK_OPENED(u->sink->thread_info.state)) {
if (PA_SINK_IS_OPENED(u->sink->thread_info.state)) {
struct pollfd *pollfd;
unsigned short revents = 0;
int err;

View file

@ -621,7 +621,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
case PA_SOURCE_SUSPENDED:
pa_assert(PA_SOURCE_OPENED(u->source->thread_info.state));
pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
if (suspend(u) < 0)
return -1;
@ -819,7 +819,7 @@ static void thread_func(void *userdata) {
pa_log_debug("loop");
/* Read some data and pass it to the sources */
if (PA_SOURCE_OPENED(u->source->thread_info.state)) {
if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
int work_done = 0;
if (u->use_mmap)
@ -867,7 +867,7 @@ static void thread_func(void *userdata) {
goto finish;
/* Tell ALSA about this and process its response */
if (PA_SOURCE_OPENED(u->source->thread_info.state)) {
if (PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
struct pollfd *pollfd;
unsigned short revents = 0;
int err;

View file

@ -162,13 +162,13 @@ static void adjust_rates(struct userdata *u) {
if (!u->master)
return;
if (!PA_SINK_OPENED(pa_sink_get_state(u->sink)))
if (!PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)))
return;
for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) {
pa_usec_t sink_latency;
if (!o->sink_input || !PA_SINK_OPENED(pa_sink_get_state(o->sink)))
if (!o->sink_input || !PA_SINK_IS_OPENED(pa_sink_get_state(o->sink)))
continue;
sink_latency = pa_sink_get_latency(o->sink);
@ -194,7 +194,7 @@ static void adjust_rates(struct userdata *u) {
for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx)) {
uint32_t r = base_rate;
if (!o->sink_input || !PA_SINK_OPENED(pa_sink_get_state(o->sink)))
if (!o->sink_input || !PA_SINK_IS_OPENED(pa_sink_get_state(o->sink)))
continue;
if (o->total_latency < target_latency)
@ -258,7 +258,10 @@ static void thread_func(void *userdata) {
pa_rtclock_get(&now);
if (!u->thread_info.in_null_mode || pa_timeval_cmp(&u->thread_info.timestamp, &now) <= 0) {
pa_sink_skip(u->sink, u->block_size);
pa_memchunk chunk;
pa_sink_render_full(u->sink, u->block_size, &chunk);
pa_memblock_unref(chunk.memblock);
if (!u->thread_info.in_null_mode)
u->thread_info.timestamp = now;
@ -432,7 +435,7 @@ static int sink_input_process_msg(pa_msgobject *obj, int code, void *data, int64
case SINK_INPUT_MESSAGE_POST:
if (PA_SINK_OPENED(o->sink_input->sink->thread_info.state))
if (PA_SINK_IS_OPENED(o->sink_input->sink->thread_info.state))
pa_memblockq_push_align(o->memblockq, chunk);
else
pa_memblockq_flush(o->memblockq);
@ -471,7 +474,7 @@ static void enable_output(struct output *o) {
pa_sink_input_put(o->sink_input);
if (o->userdata->sink && PA_SINK_LINKED(pa_sink_get_state(o->userdata->sink)))
if (o->userdata->sink && PA_SINK_IS_LINKED(pa_sink_get_state(o->userdata->sink)))
pa_asyncmsgq_send(o->userdata->sink->asyncmsgq, PA_MSGOBJECT(o->userdata->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL);
}
}
@ -504,7 +507,7 @@ static void unsuspend(struct userdata *u) {
pa_sink_suspend(o->sink, FALSE);
if (PA_SINK_OPENED(pa_sink_get_state(o->sink)))
if (PA_SINK_IS_OPENED(pa_sink_get_state(o->sink)))
enable_output(o);
}
@ -525,7 +528,7 @@ static int sink_set_state(pa_sink *sink, pa_sink_state_t state) {
switch (state) {
case PA_SINK_SUSPENDED:
pa_assert(PA_SINK_OPENED(pa_sink_get_state(u->sink)));
pa_assert(PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)));
suspend(u);
break;
@ -697,7 +700,7 @@ static void pick_master(struct userdata *u, struct output *except) {
if (u->master &&
u->master != except &&
u->master->sink_input &&
PA_SINK_OPENED(pa_sink_get_state(u->master->sink))) {
PA_SINK_IS_OPENED(pa_sink_get_state(u->master->sink))) {
update_master(u, u->master);
return;
}
@ -705,7 +708,7 @@ static void pick_master(struct userdata *u, struct output *except) {
for (o = pa_idxset_first(u->outputs, &idx); o; o = pa_idxset_next(u->outputs, &idx))
if (o != except &&
o->sink_input &&
PA_SINK_OPENED(pa_sink_get_state(o->sink))) {
PA_SINK_IS_OPENED(pa_sink_get_state(o->sink))) {
update_master(u, o);
return;
}
@ -780,7 +783,7 @@ static struct output *output_new(struct userdata *u, pa_sink *sink) {
pa_assert_se(pa_idxset_put(u->outputs, o, NULL) == 0);
if (u->sink && PA_SINK_LINKED(pa_sink_get_state(u->sink)))
if (u->sink && PA_SINK_IS_LINKED(pa_sink_get_state(u->sink)))
pa_asyncmsgq_send(u->sink->asyncmsgq, PA_MSGOBJECT(u->sink), SINK_MESSAGE_ADD_OUTPUT, o, 0, NULL);
else {
/* If the sink is not yet started, we need to do the activation ourselves */
@ -792,10 +795,10 @@ static struct output *output_new(struct userdata *u, pa_sink *sink) {
o->outq);
}
if (PA_SINK_OPENED(pa_sink_get_state(u->sink)) || pa_sink_get_state(u->sink) == PA_SINK_INIT) {
if (PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)) || pa_sink_get_state(u->sink) == PA_SINK_INIT) {
pa_sink_suspend(sink, FALSE);
if (PA_SINK_OPENED(pa_sink_get_state(sink)))
if (PA_SINK_IS_OPENED(pa_sink_get_state(sink)))
if (output_create_sink_input(o) < 0)
goto fail;
}
@ -898,7 +901,7 @@ static pa_hook_result_t sink_state_changed_hook_cb(pa_core *c, pa_sink *s, struc
state = pa_sink_get_state(s);
if (PA_SINK_OPENED(state) && PA_SINK_OPENED(pa_sink_get_state(u->sink)) && !o->sink_input) {
if (PA_SINK_IS_OPENED(state) && PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)) && !o->sink_input) {
enable_output(o);
pick_master(u, NULL);
}

View file

@ -3,7 +3,7 @@
/***
This file is part of PulseAudio.
Copyright 2006 Lennart Poettering
Copyright 2006-2008 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
@ -25,10 +25,16 @@
#include <config.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <pulse/timeval.h>
#include <pulsecore/core-util.h>
#include <pulsecore/module.h>
#include <pulsecore/log.h>
#include <pulsecore/namereg.h>
#include <pulsecore/core-error.h>
#include "module-default-device-restore-symdef.h"
@ -39,15 +45,24 @@ PA_MODULE_LOAD_ONCE(TRUE);
#define DEFAULT_SINK_FILE "default-sink"
#define DEFAULT_SOURCE_FILE "default-source"
#define DEFAULT_SAVE_INTERVAL 5
int pa__init(pa_module *m) {
struct userdata {
pa_core *core;
pa_subscription *subscription;
pa_time_event *time_event;
char *sink_filename, *source_filename;
pa_bool_t modified;
};
static void load(struct userdata *u) {
FILE *f;
/* We never overwrite manually configured settings */
if (m->core->default_sink_name)
if (u->core->default_sink_name)
pa_log_info("Manually configured default sink, not overwriting.");
else if ((f = pa_open_config_file(NULL, DEFAULT_SINK_FILE, NULL, NULL, "r"))) {
else if ((f = fopen(u->sink_filename, "r"))) {
char ln[256] = "";
fgets(ln, sizeof(ln)-1, f);
@ -55,17 +70,19 @@ int pa__init(pa_module *m) {
fclose(f);
if (!ln[0])
pa_log_debug("No previous default sink setting, ignoring.");
else if (pa_namereg_get(m->core, ln, PA_NAMEREG_SINK, 1)) {
pa_namereg_set_default(m->core, ln, PA_NAMEREG_SINK);
pa_log_debug("Restored default sink '%s'.", ln);
pa_log_info("No previous default sink setting, ignoring.");
else if (pa_namereg_get(u->core, ln, PA_NAMEREG_SINK, TRUE)) {
pa_namereg_set_default(u->core, ln, PA_NAMEREG_SINK);
pa_log_info("Restored default sink '%s'.", ln);
} else
pa_log_info("Saved default sink '%s' not existant, not restoring default sink setting.", ln);
}
if (m->core->default_source_name)
} else if (errno != ENOENT)
pa_log("Failed to load default sink: %s", pa_cstrerror(errno));
if (u->core->default_source_name)
pa_log_info("Manually configured default source, not overwriting.");
else if ((f = pa_open_config_file(NULL, DEFAULT_SOURCE_FILE, NULL, NULL, "r"))) {
else if ((f = fopen(u->source_filename, "r"))) {
char ln[256] = "";
fgets(ln, sizeof(ln)-1, f);
@ -73,29 +90,114 @@ int pa__init(pa_module *m) {
fclose(f);
if (!ln[0])
pa_log_debug("No previous default source setting, ignoring.");
else if (pa_namereg_get(m->core, ln, PA_NAMEREG_SOURCE, 1)) {
pa_namereg_set_default(m->core, ln, PA_NAMEREG_SOURCE);
pa_log_debug("Restored default source '%s'.", ln);
pa_log_info("No previous default source setting, ignoring.");
else if (pa_namereg_get(u->core, ln, PA_NAMEREG_SOURCE, TRUE)) {
pa_namereg_set_default(u->core, ln, PA_NAMEREG_SOURCE);
pa_log_info("Restored default source '%s'.", ln);
} else
pa_log_info("Saved default source '%s' not existant, not restoring default source setting.", ln);
} else if (errno != ENOENT)
pa_log("Failed to load default sink: %s", pa_cstrerror(errno));
}
static void save(struct userdata *u) {
FILE *f;
if (!u->modified)
return;
if (u->sink_filename) {
if ((f = fopen(u->sink_filename, "w"))) {
const char *n = pa_namereg_get_default_sink_name(u->core);
fprintf(f, "%s\n", pa_strempty(n));
fclose(f);
} else
pa_log("Failed to save default sink: %s", pa_cstrerror(errno));
}
if (u->source_filename) {
if ((f = fopen(u->source_filename, "w"))) {
const char *n = pa_namereg_get_default_source_name(u->core);
fprintf(f, "%s\n", pa_strempty(n));
fclose(f);
} else
pa_log("Failed to save default source: %s", pa_cstrerror(errno));
}
u->modified = FALSE;
}
static void time_cb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *tv, void *userdata) {
struct userdata *u = userdata;
pa_assert(u);
save(u);
if (u->time_event) {
u->core->mainloop->time_free(u->time_event);
u->time_event = NULL;
}
}
static void subscribe_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
struct userdata *u = userdata;
pa_assert(u);
u->modified = TRUE;
if (!u->time_event) {
struct timeval tv;
pa_gettimeofday(&tv);
pa_timeval_add(&tv, DEFAULT_SAVE_INTERVAL*PA_USEC_PER_SEC);
u->time_event = u->core->mainloop->time_new(u->core->mainloop, &tv, time_cb, u);
}
}
int pa__init(pa_module *m) {
struct userdata *u;
pa_assert(u);
u = pa_xnew0(struct userdata, 1);
u->core = m->core;
if (!(u->sink_filename = pa_runtime_path(DEFAULT_SINK_FILE)))
goto fail;
if (!(u->source_filename = pa_runtime_path(DEFAULT_SOURCE_FILE)))
goto fail;
load(u);
u->subscription = pa_subscription_new(u->core, PA_SUBSCRIPTION_MASK_SERVER, subscribe_cb, u);
return 0;
fail:
pa__done(m);
return -1;
}
void pa__done(pa_module*m) {
FILE *f;
struct userdata *u;
if ((f = pa_open_config_file(NULL, DEFAULT_SINK_FILE, NULL, NULL, "w"))) {
const char *n = pa_namereg_get_default_sink_name(m->core);
fprintf(f, "%s\n", n ? n : "");
fclose(f);
}
pa_assert(m);
if ((f = pa_open_config_file(NULL, DEFAULT_SOURCE_FILE, NULL, NULL, "w"))) {
const char *n = pa_namereg_get_default_source_name(m->core);
fprintf(f, "%s\n", n ? n : "");
fclose(f);
}
if (!(u = m->userdata))
return;
save(u);
if (u->subscription)
pa_subscription_free(u->subscription);
if (u->time_event)
m->core->mainloop->time_free(u->time_event);
pa_xfree(u->sink_filename);
pa_xfree(u->source_filename);
pa_xfree(u);
}

View file

@ -263,7 +263,7 @@ static pa_hook_result_t source_fixate_hook_callback(pa_core *c, pa_source_new_da
int pa__init(pa_module*m) {
pa_modargs *ma = NULL;
struct userdata *u;
char *fname, *state_dir;
char *fname, *runtime_dir;
char hn[256];
pa_sink *sink;
pa_source *source;
@ -290,11 +290,11 @@ int pa__init(pa_module*m) {
if (!pa_get_host_name(hn, sizeof(hn)))
goto fail;
if (!(state_dir = pa_get_state_dir()))
if (!(runtime_dir = pa_get_runtime_dir()))
goto fail;
fname = pa_sprintf_malloc("%s/device-volumes.%s.gdbm", state_dir, hn);
pa_xfree(state_dir);
fname = pa_sprintf_malloc("%s/device-volumes.%s.gdbm", runtime_dir, hn);
pa_xfree(runtime_dir);
if (!(u->gdbm_file = gdbm_open(fname, 0, GDBM_WRCREAT, 0600, NULL))) {
pa_log("Failed to open volume database '%s': %s", fname, gdbm_strerror(gdbm_errno));
@ -316,6 +316,7 @@ int pa__init(pa_module*m) {
fail:
pa__done(m);
if (ma)
pa_modargs_free(ma);

View file

@ -143,7 +143,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
case PA_SINK_SUSPENDED:
pa_assert(PA_SINK_OPENED(u->sink->thread_info.state));
pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
pa_smoother_pause(u->smoother, pa_rtclock_usec());
break;
@ -211,7 +211,7 @@ static void thread_func(void *userdata) {
pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
/* Render some data and write it to the fifo */
if (PA_SINK_OPENED(u->sink->thread_info.state) && pollfd->revents) {
if (PA_SINK_IS_OPENED(u->sink->thread_info.state) && pollfd->revents) {
pa_usec_t usec;
int64_t n;
@ -294,7 +294,7 @@ static void thread_func(void *userdata) {
}
/* Hmm, nothing to do. Let's sleep */
pollfd->events = PA_SINK_OPENED(u->sink->thread_info.state) ? POLLOUT : 0;
pollfd->events = PA_SINK_IS_OPENED(u->sink->thread_info.state) ? POLLOUT : 0;
}
if ((ret = pa_rtpoll_run(u->rtpoll, TRUE)) < 0)

View file

@ -102,10 +102,14 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
case PA_SINK_MESSAGE_GET_LATENCY: {
pa_usec_t usec = 0;
/* Get the latency of the master sink */
if (PA_MSGOBJECT(u->master)->process_msg(PA_MSGOBJECT(u->master), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
usec = 0;
*((pa_usec_t*) data) = usec /* + pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec) */;
/* Add the latency internal to our sink input on top */
usec += pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->master->sample_spec);
*((pa_usec_t*) data) = usec;
return 0;
}
}
@ -120,7 +124,10 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
pa_sink_assert_ref(s);
pa_assert_se(u = s->userdata);
if (PA_SINK_LINKED(state) && u->sink_input && PA_SINK_INPUT_LINKED(pa_sink_input_get_state(u->sink_input)))
if (PA_SINK_IS_LINKED(state) &&
u->sink_input &&
PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
return 0;
@ -134,7 +141,7 @@ static void sink_request_rewind(pa_sink *s) {
pa_assert_se(u = s->userdata);
/* Just hand this one over to the master sink */
pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes, FALSE);
pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes, FALSE, FALSE);
}
/* Called from I/O thread context */
@ -145,24 +152,9 @@ static void sink_update_requested_latency(pa_sink *s) {
pa_assert_se(u = s->userdata);
/* Just hand this one over to the master sink */
u->sink_input->thread_info.requested_sink_latency = pa_sink_get_requested_latency_within_thread(s);
pa_sink_invalidate_requested_latency(u->master);
}
/* Called from I/O thread context */
static int sink_input_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SINK_INPUT(o)->userdata;
switch (code) {
case PA_SINK_INPUT_MESSAGE_GET_LATENCY:
*((pa_usec_t*) data) = 0 /*pa_bytes_to_usec(u->memchunk.length, &u->sink_input->sample_spec)*/;
/* Fall through, the default handler will add in the extra
* latency added by the resampler */
break;
}
return pa_sink_input_process_msg(o, code, data, offset, chunk);
pa_sink_input_set_requested_latency_within_thread(
u->sink_input,
pa_sink_get_requested_latency_within_thread(s));
}
/* Called from I/O thread context */
@ -192,20 +184,9 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
dst = (float*) pa_memblock_acquire(chunk->memblock);
for (c = 0; c < u->channels; c++) {
unsigned j;
float *p, *q;
p = src + c;
q = u->input;
for (j = 0; j < n; j++, p += u->channels, q++)
*q = PA_CLAMP_UNLIKELY(*p, -1.0, 1.0);
pa_sample_clamp(PA_SAMPLE_FLOAT32NE, u->input, sizeof(float), src+c, u->channels*sizeof(float), n);
u->descriptor->run(u->handle[c], n);
q = u->output;
p = dst + c;
for (j = 0; j < n; j++, q++, p += u->channels)
*p = PA_CLAMP_UNLIKELY(*q, -1.0, 1.0);
pa_sample_clamp(PA_SAMPLE_FLOAT32NE, dst+c, u->channels*sizeof(float), u->output, sizeof(float), n);
}
pa_memblock_release(tchunk.memblock);
@ -245,6 +226,9 @@ static void sink_input_detach_cb(pa_sink_input *i) {
pa_assert_se(u = i->userdata);
pa_sink_detach_within_thread(u->sink);
pa_sink_set_asyncmsgq(u->sink, NULL);
pa_sink_set_rtpoll(u->sink, NULL);
}
/* Called from I/O thread context */
@ -648,7 +632,6 @@ int pa__init(pa_module*m) {
if (!u->sink_input)
goto fail;
u->sink_input->parent.process_msg = sink_input_process_msg;
u->sink_input->pop = sink_input_pop_cb;
u->sink_input->process_rewind = sink_input_process_rewind_cb;
u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;

View file

@ -82,12 +82,14 @@ static int load_rules(struct userdata *u, const char *filename) {
pa_assert(u);
f = filename ?
fopen(fn = pa_xstrdup(filename), "r") :
pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn, "r");
if (filename)
f = fopen(fn = pa_xstrdup(filename), "r");
else
f = pa_open_config_file(DEFAULT_MATCH_TABLE_FILE, DEFAULT_MATCH_TABLE_FILE_USER, NULL, &fn);
if (!f) {
pa_log("failed to open file '%s': %s", fn, pa_cstrerror(errno));
pa_xfree(fn);
pa_log("Failed to open file config file: %s", pa_cstrerror(errno));
goto finish;
}

View file

@ -3,7 +3,7 @@
/***
This file is part of PulseAudio.
Copyright 2004-2006 Lennart Poettering
Copyright 2004-2008 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
@ -64,6 +64,7 @@ PA_MODULE_USAGE(
"description=<description for the sink>");
#define DEFAULT_SINK_NAME "null"
#define MAX_LATENCY_USEC (PA_USEC_PER_SEC * 2)
struct userdata {
pa_core *core;
@ -76,7 +77,8 @@ struct userdata {
size_t block_size;
struct timeval timestamp;
pa_usec_t block_usec;
pa_usec_t timestamp;
};
static const char* const valid_modargs[] = {
@ -96,26 +98,93 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
case PA_SINK_MESSAGE_SET_STATE:
if (PA_PTR_TO_UINT(data) == PA_SINK_RUNNING)
pa_rtclock_get(&u->timestamp);
u->timestamp = pa_rtclock_usec();
break;
case PA_SINK_MESSAGE_GET_LATENCY: {
struct timeval now;
pa_usec_t now;
pa_rtclock_get(&now);
now = pa_rtclock_usec();
*((pa_usec_t*) data) = u->timestamp > now ? u->timestamp - now : 0;
if (pa_timeval_cmp(&u->timestamp, &now) > 0)
*((pa_usec_t*) data) = 0;
else
*((pa_usec_t*) data) = pa_timeval_diff(&u->timestamp, &now);
break;
return 0;
}
}
return pa_sink_process_msg(o, code, data, offset, chunk);
}
static void sink_update_requested_latency_cb(pa_sink *s) {
struct userdata *u;
pa_sink_assert_ref(s);
u = s->userdata;
pa_assert(u);
u->block_usec = pa_sink_get_requested_latency_within_thread(s);
}
static void process_rewind(struct userdata *u, pa_usec_t now) {
size_t rewind_nbytes, in_buffer;
pa_usec_t delay;
pa_assert(u);
/* Figure out how much we shall rewind and reset the counter */
rewind_nbytes = u->sink->thread_info.rewind_nbytes;
u->sink->thread_info.rewind_nbytes = 0;
pa_assert(rewind_nbytes > 0);
pa_log_debug("Requested to rewind %lu bytes.", (unsigned long) rewind_nbytes);
if (u->timestamp <= now)
return;
delay = u->timestamp - now;
in_buffer = pa_usec_to_bytes(delay, &u->sink->sample_spec);
if (in_buffer <= 0)
return;
if (rewind_nbytes > in_buffer)
rewind_nbytes = in_buffer;
pa_sink_process_rewind(u->sink, rewind_nbytes);
u->timestamp -= pa_bytes_to_usec(rewind_nbytes, &u->sink->sample_spec);
pa_log_debug("Rewound %lu bytes.", (unsigned long) rewind_nbytes);
}
static void process_render(struct userdata *u, pa_usec_t now) {
size_t nbytes;
size_t ate = 0;
/* This is the configured latency. Sink inputs connected to us
might not have a single frame more than this value queued. Hence:
at maximum read this many bytes from the sink inputs. */
nbytes = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
/* Fill the buffer up the the latency size */
while (u->timestamp < now + u->block_usec) {
pa_memchunk chunk;
pa_sink_render(u->sink, nbytes, &chunk);
pa_memblock_unref(chunk.memblock);
pa_log_debug("Ate %lu bytes.", (unsigned long) chunk.length);
u->timestamp += pa_bytes_to_usec(chunk.length, &u->sink->sample_spec);
ate += chunk.length;
if (ate >= nbytes)
break;
}
pa_log_debug("Ate in sum %lu bytes (of %lu)", (unsigned long) ate, (unsigned long) nbytes);
}
static void thread_func(void *userdata) {
struct userdata *u = userdata;
@ -126,23 +195,24 @@ static void thread_func(void *userdata) {
pa_thread_mq_install(&u->thread_mq);
pa_rtpoll_install(u->rtpoll);
pa_rtclock_get(&u->timestamp);
u->timestamp = pa_rtclock_usec();
for (;;) {
int ret;
/* Render some data and drop it immediately */
if (u->sink->thread_info.state == PA_SINK_RUNNING) {
struct timeval now;
pa_usec_t now;
pa_rtclock_get(&now);
now = pa_rtclock_usec();
if (pa_timeval_cmp(&u->timestamp, &now) <= 0) {
pa_sink_skip(u->sink, u->block_size);
pa_timeval_add(&u->timestamp, pa_bytes_to_usec(u->block_size, &u->sink->sample_spec));
}
if (u->sink->thread_info.rewind_nbytes > 0)
process_rewind(u, now);
pa_rtpoll_set_timer_absolute(u->rtpoll, &u->timestamp);
if (u->timestamp <= now)
process_render(u, now);
pa_rtpoll_set_timer_absolute(u->rtpoll, u->timestamp);
} else
pa_rtpoll_set_timer_disabled(u->rtpoll);
@ -197,26 +267,26 @@ int pa__init(pa_module*m) {
pa_sink_new_data_set_name(&data, pa_modargs_get_value(ma, "sink_name", DEFAULT_SINK_NAME));
pa_sink_new_data_set_sample_spec(&data, &ss);
pa_sink_new_data_set_channel_map(&data, &map);
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "NULL sink"));
pa_proplist_sets(data.proplist, PA_PROP_DEVICE_DESCRIPTION, pa_modargs_get_value(ma, "description", "Null Output"));
u->sink = pa_sink_new(m->core, &data, 0);
u->sink = pa_sink_new(m->core, &data, PA_SINK_LATENCY);
pa_sink_new_data_done(&data);
if (!u->sink) {
pa_log("Failed to create sink.");
pa_log("Failed to create sink object.");
goto fail;
}
u->sink->parent.process_msg = sink_process_msg;
u->sink->update_requested_latency = sink_update_requested_latency_cb;
u->sink->userdata = u;
u->sink->flags = PA_SINK_LATENCY;
pa_sink_set_asyncmsgq(u->sink, u->thread_mq.inq);
pa_sink_set_rtpoll(u->sink, u->rtpoll);
u->block_size = pa_bytes_per_second(&ss) / 20; /* 50 ms */
if (u->block_size <= 0)
u->block_size = pa_frame_size(&ss);
u->block_usec = u->sink->max_latency = MAX_LATENCY_USEC;
u->sink->thread_info.max_rewind = pa_usec_to_bytes(u->block_usec, &u->sink->sample_spec);
if (!(u->thread = pa_thread_new(thread_func, u))) {
pa_log("Failed to create thread.");

View file

@ -161,10 +161,10 @@ static void trigger(struct userdata *u, pa_bool_t quick) {
pa_log_debug("trigger");
if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state))
if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state))
enable_bits |= PCM_ENABLE_INPUT;
if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state))
if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state))
enable_bits |= PCM_ENABLE_OUTPUT;
pa_log_debug("trigger: %i", enable_bits);
@ -202,7 +202,7 @@ static void trigger(struct userdata *u, pa_bool_t quick) {
* register the fd as ready.
*/
if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) {
if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) {
uint8_t *buf = pa_xnew(uint8_t, u->in_fragment_size);
pa_read(u->fd, buf, u->in_fragment_size, NULL);
pa_xfree(buf);
@ -641,7 +641,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
switch ((pa_sink_state_t) PA_PTR_TO_UINT(data)) {
case PA_SINK_SUSPENDED:
pa_assert(PA_SINK_OPENED(u->sink->thread_info.state));
pa_assert(PA_SINK_IS_OPENED(u->sink->thread_info.state));
if (!u->source || u->source_suspended) {
if (suspend(u) < 0)
@ -658,7 +658,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
if (u->sink->thread_info.state == PA_SINK_INIT) {
do_trigger = TRUE;
quick = u->source && PA_SOURCE_OPENED(u->source->thread_info.state);
quick = u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state);
}
if (u->sink->thread_info.state == PA_SINK_SUSPENDED) {
@ -721,7 +721,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
switch ((pa_source_state_t) PA_PTR_TO_UINT(data)) {
case PA_SOURCE_SUSPENDED:
pa_assert(PA_SOURCE_OPENED(u->source->thread_info.state));
pa_assert(PA_SOURCE_IS_OPENED(u->source->thread_info.state));
if (!u->sink || u->sink_suspended) {
if (suspend(u) < 0)
@ -738,7 +738,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
if (u->source->thread_info.state == PA_SOURCE_INIT) {
do_trigger = TRUE;
quick = u->sink && PA_SINK_OPENED(u->sink->thread_info.state);
quick = u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state);
}
if (u->source->thread_info.state == PA_SOURCE_SUSPENDED) {
@ -877,7 +877,7 @@ static void thread_func(void *userdata) {
/* Render some data and write it to the dsp */
if (u->sink && PA_SINK_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) {
if (u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state) && ((revents & POLLOUT) || u->use_mmap || u->use_getospace)) {
if (u->use_mmap) {
@ -985,7 +985,7 @@ static void thread_func(void *userdata) {
/* Try to read some data and pass it on to the source driver. */
if (u->source && PA_SOURCE_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) {
if (u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state) && ((revents & POLLIN) || u->use_mmap || u->use_getispace)) {
if (u->use_mmap) {
@ -1095,8 +1095,8 @@ static void thread_func(void *userdata) {
pollfd = pa_rtpoll_item_get_pollfd(u->rtpoll_item, NULL);
pollfd->events =
((u->source && PA_SOURCE_OPENED(u->source->thread_info.state)) ? POLLIN : 0) |
((u->sink && PA_SINK_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0);
((u->source && PA_SOURCE_IS_OPENED(u->source->thread_info.state)) ? POLLIN : 0) |
((u->sink && PA_SINK_IS_OPENED(u->sink->thread_info.state)) ? POLLOUT : 0);
}
/* Hmm, nothing to do. Let's sleep */

View file

@ -215,15 +215,6 @@ int pa__init(pa_module*m) {
#else
pa_socket_server *s;
int r;
char tmp[PATH_MAX];
#if defined(USE_PROTOCOL_ESOUND)
#if defined(USE_PER_USER_ESOUND_SOCKET)
char esdsocketpath[PATH_MAX];
#else
const char esdsocketpath[] = "/tmp/.esd/socket";
#endif
#endif
#endif
pa_assert(m);
@ -255,27 +246,28 @@ int pa__init(pa_module*m) {
goto fail;
if (s_ipv4)
if (!(u->protocol_ipv4 = protocol_new(m->core, s_ipv4, m, ma)))
pa_socket_server_unref(s_ipv4);
u->protocol_ipv4 = protocol_new(m->core, s_ipv4, m, ma);
if (s_ipv6)
if (!(u->protocol_ipv6 = protocol_new(m->core, s_ipv6, m, ma)))
pa_socket_server_unref(s_ipv6);
u->protocol_ipv6 = protocol_new(m->core, s_ipv6, m, ma);
if (!u->protocol_ipv4 && !u->protocol_ipv6)
goto fail;
if (s_ipv6)
pa_socket_server_unref(s_ipv6);
if (s_ipv6)
pa_socket_server_unref(s_ipv4);
#else
#if defined(USE_PROTOCOL_ESOUND)
#if defined(USE_PER_USER_ESOUND_SOCKET)
snprintf(esdsocketpath, sizeof(esdsocketpath), "/tmp/.esd-%lu/socket", (unsigned long) getuid());
u->socket_path = pa_sprintf_malloc("/tmp/.esd-%lu/socket", (unsigned long) getuid());
#else
u->socket_path = pa_xstrdup("/tmp/.esd/socket");
#endif
pa_runtime_path(pa_modargs_get_value(ma, "socket", esdsocketpath), tmp, sizeof(tmp));
u->socket_path = pa_xstrdup(tmp);
/* This socket doesn't reside in our own runtime dir but in
* /tmp/.esd/, hence we have to create the dir first */
@ -285,24 +277,26 @@ int pa__init(pa_module*m) {
}
#else
pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET), tmp, sizeof(tmp));
u->socket_path = pa_xstrdup(tmp);
#endif
if ((r = pa_unix_socket_remove_stale(tmp)) < 0) {
pa_log("Failed to remove stale UNIX socket '%s': %s", tmp, pa_cstrerror(errno));
if (!(u->socket_path = pa_runtime_path(pa_modargs_get_value(ma, "socket", UNIX_SOCKET)))) {
pa_log("Failed to generate socket path.");
goto fail;
}
#endif
if (r)
pa_log("Removed stale UNIX socket '%s'.", tmp);
if ((r = pa_unix_socket_remove_stale(u->socket_path)) < 0) {
pa_log("Failed to remove stale UNIX socket '%s': %s", u->socket_path, pa_cstrerror(errno));
goto fail;
} else if (r > 0)
pa_log_info("Removed stale UNIX socket '%s'.", u->socket_path);
if (!(s = pa_socket_server_new_unix(m->core->mainloop, tmp)))
if (!(s = pa_socket_server_new_unix(m->core->mainloop, u->socket_path)))
goto fail;
if (!(u->protocol_unix = protocol_new(m->core, s, m, ma)))
goto fail;
pa_socket_server_unref(s);
#endif
m->userdata = u;
@ -325,24 +319,22 @@ fail:
#else
if (u->protocol_unix)
protocol_free(u->protocol_unix);
if (u->socket_path)
pa_xfree(u->socket_path);
pa_xfree(u->socket_path);
#endif
pa_xfree(u);
} else {
#if defined(USE_TCP_SOCKETS)
if (s_ipv4)
pa_socket_server_unref(s_ipv4);
if (s_ipv6)
pa_socket_server_unref(s_ipv6);
#else
if (s)
pa_socket_server_unref(s);
#endif
}
#if defined(USE_TCP_SOCKETS)
if (s_ipv4)
pa_socket_server_unref(s_ipv4);
if (s_ipv6)
pa_socket_server_unref(s_ipv6);
#else
if (s)
pa_socket_server_unref(s);
#endif
goto finish;
}
@ -362,7 +354,7 @@ void pa__done(pa_module*m) {
if (u->protocol_unix)
protocol_free(u->protocol_unix);
#if defined(USE_PROTOCOL_ESOUND)
#if defined(USE_PROTOCOL_ESOUND) && !defined(USE_PER_USER_ESOUND_SOCKET)
if (u->socket_path) {
char *p = pa_parent_dir(u->socket_path);
rmdir(p);

View file

@ -81,10 +81,14 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
case PA_SINK_MESSAGE_GET_LATENCY: {
pa_usec_t usec = 0;
/* Get the latency of the master sink */
if (PA_MSGOBJECT(u->master)->process_msg(PA_MSGOBJECT(u->master), PA_SINK_MESSAGE_GET_LATENCY, &usec, 0, NULL) < 0)
usec = 0;
*((pa_usec_t*) data) = usec/* + pa_bytes_to_usec(u->memchunk.length, &u->sink->sample_spec)*/;
/* Add the latency internal to our sink input on top */
usec += pa_bytes_to_usec(pa_memblockq_get_length(u->sink_input->thread_info.render_memblockq), &u->master->sample_spec);
*((pa_usec_t*) data) = usec;
return 0;
}
}
@ -99,7 +103,10 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
pa_sink_assert_ref(s);
pa_assert_se(u = s->userdata);
if (PA_SINK_LINKED(state) && u->sink_input && PA_SINK_INPUT_LINKED(pa_sink_input_get_state(u->sink_input)))
if (PA_SINK_IS_LINKED(state) &&
u->sink_input &&
PA_SINK_INPUT_IS_LINKED(pa_sink_input_get_state(u->sink_input)))
pa_sink_input_cork(u->sink_input, state == PA_SINK_SUSPENDED);
return 0;
@ -112,7 +119,7 @@ static void sink_request_rewind(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert_se(u = s->userdata);
pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes, FALSE);
pa_sink_input_request_rewind(u->sink_input, s->thread_info.rewind_nbytes, FALSE, FALSE);
}
/* Called from I/O thread context */
@ -123,24 +130,9 @@ static void sink_update_requested_latency(pa_sink *s) {
pa_assert_se(u = s->userdata);
/* Just hand this one over to the master sink */
u->sink_input->thread_info.requested_sink_latency = pa_sink_get_requested_latency_within_thread(s);
pa_sink_invalidate_requested_latency(u->master);
}
/* Called from I/O thread context */
static int sink_input_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
struct userdata *u = PA_SINK_INPUT(o)->userdata;
switch (code) {
case PA_SINK_INPUT_MESSAGE_GET_LATENCY:
*((pa_usec_t*) data) = 0; /*pa_bytes_to_usec(u->memchunk.length, &u->sink_input->sample_spec);*/
/* Fall through, the default handler will add in the extra
* latency added by the resampler */
break;
}
return pa_sink_input_process_msg(o, code, data, offset, chunk);
pa_sink_input_set_requested_latency_within_thread(
u->sink_input,
pa_sink_get_requested_latency_within_thread(s));
}
/* Called from I/O thread context */
@ -152,7 +144,6 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk
pa_assert_se(u = i->userdata);
pa_sink_render(u->sink, nbytes, chunk);
return 0;
}
@ -185,6 +176,9 @@ static void sink_input_detach_cb(pa_sink_input *i) {
pa_assert_se(u = i->userdata);
pa_sink_detach_within_thread(u->sink);
pa_sink_set_asyncmsgq(u->sink, NULL);
pa_sink_set_rtpoll(u->sink, NULL);
}
/* Called from I/O thread context */
@ -317,7 +311,6 @@ int pa__init(pa_module*m) {
if (!u->sink_input)
goto fail;
u->sink_input->parent.process_msg = sink_input_process_msg;
u->sink_input->pop = sink_input_pop_cb;
u->sink_input->process_rewind = sink_input_process_rewind_cb;
u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb;

View file

@ -317,7 +317,7 @@ static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, s
if (pa_sink_used_by(s) <= 0) {
if (PA_SINK_OPENED(state))
if (PA_SINK_IS_OPENED(state))
restart(d);
}
@ -328,7 +328,7 @@ static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, s
if (pa_source_used_by(s) <= 0) {
if (PA_SOURCE_OPENED(state))
if (PA_SOURCE_IS_OPENED(state))
restart(d);
}
}

View file

@ -303,7 +303,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
/* First, change the state, because otherwide pa_sink_render() would fail */
if ((r = pa_sink_process_msg(o, code, data, offset, chunk)) >= 0)
if (PA_SINK_OPENED((pa_sink_state_t) PA_PTR_TO_UINT(data)))
if (PA_SINK_IS_OPENED((pa_sink_state_t) PA_PTR_TO_UINT(data)))
send_data(u);
return r;
@ -314,7 +314,7 @@ static int sink_process_msg(pa_msgobject *o, int code, void *data, int64_t offse
pa_assert(offset > 0);
u->requested_bytes += (size_t) offset;
if (PA_SINK_OPENED(u->sink->thread_info.state))
if (PA_SINK_IS_OPENED(u->sink->thread_info.state))
send_data(u);
return 0;
@ -343,7 +343,7 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
switch ((pa_sink_state_t) state) {
case PA_SINK_SUSPENDED:
pa_assert(PA_SINK_OPENED(s->state));
pa_assert(PA_SINK_IS_OPENED(s->state));
stream_cork(u, TRUE);
break;
@ -369,7 +369,7 @@ static int source_process_msg(pa_msgobject *o, int code, void *data, int64_t off
switch (code) {
case SOURCE_MESSAGE_POST:
if (PA_SOURCE_OPENED(u->source->thread_info.state))
if (PA_SOURCE_IS_OPENED(u->source->thread_info.state))
pa_source_post(u->source, chunk);
return 0;
}
@ -385,7 +385,7 @@ static int source_set_state(pa_source *s, pa_source_state_t state) {
switch ((pa_source_state_t) state) {
case PA_SOURCE_SUSPENDED:
pa_assert(PA_SOURCE_OPENED(s->state));
pa_assert(PA_SOURCE_IS_OPENED(s->state));
stream_cork(u, TRUE);
break;
@ -1066,7 +1066,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
pa_tagstruct_putu32(reply, PA_INVALID_INDEX);
pa_tagstruct_puts(reply, u->sink_name);
pa_tagstruct_putu32(reply, u->maxlength);
pa_tagstruct_put_boolean(reply, !PA_SINK_OPENED(pa_sink_get_state(u->sink)));
pa_tagstruct_put_boolean(reply, !PA_SINK_IS_OPENED(pa_sink_get_state(u->sink)));
pa_tagstruct_putu32(reply, u->tlength);
pa_tagstruct_putu32(reply, u->prebuf);
pa_tagstruct_putu32(reply, u->minreq);
@ -1082,7 +1082,7 @@ static void setup_complete_callback(pa_pdispatch *pd, uint32_t command, uint32_t
pa_tagstruct_putu32(reply, PA_INVALID_INDEX);
pa_tagstruct_puts(reply, u->source_name);
pa_tagstruct_putu32(reply, u->maxlength);
pa_tagstruct_put_boolean(reply, !PA_SOURCE_OPENED(pa_source_get_state(u->source)));
pa_tagstruct_put_boolean(reply, !PA_SOURCE_IS_OPENED(pa_source_get_state(u->source)));
pa_tagstruct_putu32(reply, u->fragsize);
#endif

View file

@ -134,16 +134,12 @@ static int load_rules(struct userdata *u) {
char buf_name[256], buf_volume[256], buf_sink[256], buf_source[256];
char *ln = buf_name;
f = u->table_file ?
fopen(u->table_file, "r") :
pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "r");
if (!f) {
if (!(f = fopen(u->table_file, "r"))) {
if (errno == ENOENT) {
pa_log_info("starting with empty ruleset.");
pa_log_info("Starting with empty ruleset.");
ret = 0;
} else
pa_log("failed to open file '%s': %s", u->table_file, pa_cstrerror(errno));
pa_log("Failed to open file '%s': %s", u->table_file, pa_cstrerror(errno));
goto finish;
}
@ -236,11 +232,7 @@ static int save_rules(struct userdata *u) {
pa_log_info("Saving rules...");
f = u->table_file ?
fopen(u->table_file, "w") :
pa_open_config_file(NULL, DEFAULT_VOLUME_TABLE_FILE, NULL, &u->table_file, "w");
if (!f) {
if (!(f = fopen(u->table_file, "w"))) {
pa_log("Failed to open file '%s': %s", u->table_file, pa_cstrerror(errno));
goto finish;
}
@ -496,7 +488,7 @@ int pa__init(pa_module*m) {
u = pa_xnew(struct userdata, 1);
u->core = m->core;
u->hashmap = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
u->table_file = pa_xstrdup(pa_modargs_get_value(ma, "table", NULL));
u->table_file = pa_runtime_path(pa_modargs_get_value(ma, "table", DEFAULT_VOLUME_TABLE_FILE));
u->modified = FALSE;
u->subscription = NULL;
u->sink_input_new_hook_slot = u->sink_input_fixate_hook_slot = u->source_output_new_hook_slot = NULL;