Merge branch 'master' into dbus-work

Conflicts:
	src/daemon/daemon-conf.c
	src/daemon/daemon-conf.h
	src/daemon/main.c
	src/pulsecore/dbus-util.h
This commit is contained in:
Tanu Kaskinen 2009-06-29 18:35:06 +03:00
commit 0bc538b08c
207 changed files with 33341 additions and 18718 deletions

View file

@ -23,6 +23,7 @@
#include <config.h>
#endif
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
#include <pulsecore/log.h>
@ -116,14 +117,13 @@ struct AvahiTimeout {
void *userdata;
};
static void timeout_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *tv, void *userdata) {
AvahiTimeout *t = userdata;
static void timeout_callback(pa_mainloop_api*a, pa_time_event* e, const struct timeval *t, void *userdata) {
AvahiTimeout *to = userdata;
pa_assert(a);
pa_assert(e);
pa_assert(t);
t->callback(t, t->userdata);
to->callback(to, to->userdata);
}
static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv, AvahiTimeoutCallback callback, void *userdata) {
@ -145,6 +145,7 @@ static AvahiTimeout* timeout_new(const AvahiPoll *api, const struct timeval *tv,
}
static void timeout_update(AvahiTimeout *t, const struct timeval *tv) {
pa_assert(t);
if (t->time_event && tv)

View file

@ -148,15 +148,12 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
c->save_profile = data->save_profile;
if (!c->active_profile && c->profiles) {
void *state = NULL;
void *state;
pa_card_profile *p;
while ((p = pa_hashmap_iterate(c->profiles, &state, NULL))) {
if (!c->active_profile ||
p->priority > c->active_profile->priority)
PA_HASHMAP_FOREACH(p, c->profiles, state)
if (!c->active_profile || p->priority > c->active_profile->priority)
c->active_profile = p;
}
}
c->userdata = NULL;
@ -164,6 +161,7 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
pa_device_init_description(c->proplist);
pa_device_init_icon(c->proplist, TRUE);
pa_device_init_intended_roles(c->proplist);
pa_assert_se(pa_idxset_put(core->cards, c, &c->index) >= 0);
@ -176,7 +174,6 @@ pa_card *pa_card_new(pa_core *core, pa_card_new_data *data) {
void pa_card_free(pa_card *c) {
pa_core *core;
pa_card_profile *profile;
pa_assert(c);
pa_assert(c->core);
@ -199,8 +196,10 @@ void pa_card_free(pa_card *c) {
pa_idxset_free(c->sources, NULL, NULL);
if (c->profiles) {
while ((profile = pa_hashmap_steal_first(c->profiles)))
pa_card_profile_free(profile);
pa_card_profile *p;
while ((p = pa_hashmap_steal_first(c->profiles)))
pa_card_profile_free(p);
pa_hashmap_free(c->profiles, NULL, NULL);
}
@ -213,26 +212,27 @@ void pa_card_free(pa_card *c) {
int pa_card_set_profile(pa_card *c, const char *name, pa_bool_t save) {
pa_card_profile *profile;
int r;
pa_assert(c);
if (!c->set_profile) {
pa_log_warn("set_profile() operation not implemented for card %u \"%s\"", c->index, c->name);
return -1;
pa_log_debug("set_profile() operation not implemented for card %u \"%s\"", c->index, c->name);
return -PA_ERR_NOTIMPLEMENTED;
}
if (!c->profiles)
return -1;
return -PA_ERR_NOENTITY;
if (!(profile = pa_hashmap_get(c->profiles, name)))
return -1;
return -PA_ERR_NOENTITY;
if (c->active_profile == profile) {
c->save_profile = c->save_profile || save;
return 0;
}
if (c->set_profile(c, profile) < 0)
return -1;
if ((r = c->set_profile(c, profile)) < 0)
return r;
pa_subscription_post(c->core, PA_SUBSCRIPTION_EVENT_CARD|PA_SUBSCRIPTION_EVENT_CHANGE, c->index);
@ -244,19 +244,28 @@ int pa_card_set_profile(pa_card *c, const char *name, pa_bool_t save) {
return 0;
}
int pa_card_suspend(pa_card *c, pa_bool_t suspend) {
int pa_card_suspend(pa_card *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
pa_sink *sink;
pa_source *source;
uint32_t idx;
int ret = 0;
pa_assert(c);
pa_assert(cause != 0);
for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx))
ret -= pa_sink_suspend(sink, suspend) < 0;
for (sink = pa_idxset_first(c->sinks, &idx); sink; sink = pa_idxset_next(c->sinks, &idx)) {
int r;
for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx))
ret -= pa_source_suspend(source, suspend) < 0;
if ((r = pa_sink_suspend(sink, suspend, cause)) < 0)
ret = r;
}
for (source = pa_idxset_first(c->sources, &idx); source; source = pa_idxset_next(c->sources, &idx)) {
int r;
if ((r = pa_source_suspend(source, suspend, cause)) < 0)
ret = r;
}
return ret;
}

View file

@ -63,7 +63,7 @@ struct pa_card {
pa_hashmap *profiles;
pa_card_profile *active_profile;
pa_bool_t save_profile;
pa_bool_t save_profile:1;
void *userdata;
@ -72,9 +72,8 @@ struct pa_card {
typedef struct pa_card_new_data {
char *name;
char *description;
pa_proplist *proplist;
const char *driver;
pa_module *module;
@ -99,6 +98,6 @@ void pa_card_free(pa_card *c);
int pa_card_set_profile(pa_card *c, const char *name, pa_bool_t save);
int pa_card_suspend(pa_card *c, pa_bool_t suspend);
int pa_card_suspend(pa_card *c, pa_bool_t suspend, pa_suspend_cause_t cause);
#endif

View file

@ -125,6 +125,8 @@ static int pa_cli_command_update_source_proplist(pa_core *c, pa_tokenizer *t, pa
static int pa_cli_command_update_sink_input_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
static int pa_cli_command_update_source_output_proplist(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail);
/* A method table for all available commands */
@ -176,10 +178,12 @@ static const struct command commands[] = {
{ "suspend-source", pa_cli_command_suspend_source, "Suspend source (args: index|name, bool)", 3},
{ "suspend", pa_cli_command_suspend, "Suspend all sinks and all sources (args: bool)", 2},
{ "set-card-profile", pa_cli_command_card_profile, "Change the profile of a card (args: index, name)", 3},
{ "set-sink-port", pa_cli_command_sink_port, "Change the port of a sink (args: index, name)", 3},
{ "set-source-port", pa_cli_command_source_port, "Change the port of a source (args: index, name)", 3},
{ "set-log-level", pa_cli_command_log_level, "Change the log level (args: numeric level)", 2},
{ "set-log-meta", pa_cli_command_log_meta, "Show source code location in log messages (args: bool)", 2},
{ "set-log-time", pa_cli_command_log_time, "Show timestamps in log messages (args: bool)", 2},
{ "set-log-backtrace", pa_cli_command_log_backtrace, "Show bakctrace in log messages (args: frames)", 2},
{ "set-log-backtrace", pa_cli_command_log_backtrace, "Show backtrace in log messages (args: frames)", 2},
{ NULL, NULL, NULL, 0 }
};
@ -526,7 +530,7 @@ static int pa_cli_command_sink_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
}
pa_cvolume_set(&cvolume, sink->sample_spec.channels, volume);
pa_sink_set_volume(sink, &cvolume, TRUE, TRUE, TRUE);
pa_sink_set_volume(sink, &cvolume, TRUE, TRUE, TRUE, TRUE);
return 0;
}
@ -604,7 +608,7 @@ static int pa_cli_command_source_volume(pa_core *c, pa_tokenizer *t, pa_strbuf *
}
pa_cvolume_set(&cvolume, source->sample_spec.channels, volume);
pa_source_set_volume(source, &cvolume);
pa_source_set_volume(source, &cvolume, TRUE);
return 0;
}
@ -638,7 +642,7 @@ static int pa_cli_command_sink_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *buf,
return -1;
}
pa_sink_set_mute(sink, mute);
pa_sink_set_mute(sink, mute, TRUE);
return 0;
}
@ -672,7 +676,7 @@ static int pa_cli_command_source_mute(pa_core *c, pa_tokenizer *t, pa_strbuf *bu
return -1;
}
pa_source_set_mute(source, mute);
pa_source_set_mute(source, mute, TRUE);
return 0;
}
@ -1278,7 +1282,7 @@ static int pa_cli_command_suspend_sink(pa_core *c, pa_tokenizer *t, pa_strbuf *b
return -1;
}
if ((r = pa_sink_suspend(sink, suspend)) < 0)
if ((r = pa_sink_suspend(sink, suspend, PA_SUSPEND_USER)) < 0)
pa_strbuf_printf(buf, "Failed to resume/suspend sink: %s\n", pa_strerror(r));
return 0;
@ -1314,7 +1318,7 @@ static int pa_cli_command_suspend_source(pa_core *c, pa_tokenizer *t, pa_strbuf
return -1;
}
if ((r = pa_source_suspend(source, suspend)) < 0)
if ((r = pa_source_suspend(source, suspend, PA_SUSPEND_USER)) < 0)
pa_strbuf_printf(buf, "Failed to resume/suspend source: %s\n", pa_strerror(r));
return 0;
@ -1339,10 +1343,10 @@ static int pa_cli_command_suspend(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, p
return -1;
}
if ((r = pa_sink_suspend_all(c, suspend)) < 0)
if ((r = pa_sink_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
pa_strbuf_printf(buf, "Failed to resume/suspend all sinks: %s\n", pa_strerror(r));
if ((r = pa_source_suspend_all(c, suspend)) < 0)
if ((r = pa_source_suspend_all(c, suspend, PA_SUSPEND_USER)) < 0)
pa_strbuf_printf(buf, "Failed to resume/suspend all sources: %s\n", pa_strerror(r));
return 0;
@ -1476,6 +1480,70 @@ static int pa_cli_command_card_profile(pa_core *c, pa_tokenizer *t, pa_strbuf *b
return 0;
}
static int pa_cli_command_sink_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
const char *n, *p;
pa_sink *sink;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a sink either by its name or its index.\n");
return -1;
}
if (!(p = pa_tokenizer_get(t, 2))) {
pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
return -1;
}
if (!(sink = pa_namereg_get(c, n, PA_NAMEREG_SINK))) {
pa_strbuf_puts(buf, "No sink found by this name or index.\n");
return -1;
}
if (pa_sink_set_port(sink, p, TRUE) < 0) {
pa_strbuf_printf(buf, "Failed to set sink port to '%s'.\n", p);
return -1;
}
return 0;
}
static int pa_cli_command_source_port(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
const char *n, *p;
pa_source *source;
pa_core_assert_ref(c);
pa_assert(t);
pa_assert(buf);
pa_assert(fail);
if (!(n = pa_tokenizer_get(t, 1))) {
pa_strbuf_puts(buf, "You need to specify a source either by its name or its index.\n");
return -1;
}
if (!(p = pa_tokenizer_get(t, 2))) {
pa_strbuf_puts(buf, "You need to specify a profile by its name.\n");
return -1;
}
if (!(source = pa_namereg_get(c, n, PA_NAMEREG_SOURCE))) {
pa_strbuf_puts(buf, "No source found by this name or index.\n");
return -1;
}
if (pa_source_set_port(source, p, TRUE) < 0) {
pa_strbuf_printf(buf, "Failed to set source port to '%s'.\n", p);
return -1;
}
return 0;
}
static int pa_cli_command_dump(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_bool_t *fail) {
pa_module *m;
pa_sink *sink;

View file

@ -139,11 +139,10 @@ char *pa_card_list_to_string(pa_core *c) {
if (card->profiles) {
pa_card_profile *p;
void *state = NULL;
void *state;
pa_strbuf_puts(s, "\tprofiles:\n");
while ((p = pa_hashmap_iterate(card->profiles, &state, NULL)))
PA_HASHMAP_FOREACH(p, card->profiles, state)
pa_strbuf_printf(s, "\t\t%s: %s (priority %u)\n", p->name, p->description, p->priority);
}
@ -232,6 +231,7 @@ char *pa_sink_list_to_string(pa_core *c) {
"\tdriver: <%s>\n"
"\tflags: %s%s%s%s%s%s%s%s\n"
"\tstate: %s\n"
"\tsuspend cause: %s%s%s%s\n"
"\tvolume: %s%s%s\n"
"\t balance %0.2f\n"
"\tbase volume: %s%s%s\n"
@ -258,6 +258,10 @@ char *pa_sink_list_to_string(pa_core *c) {
sink->flags & PA_SINK_FLAT_VOLUME ? "FLAT_VOLUME " : "",
sink->flags & PA_SINK_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
sink_state_to_string(pa_sink_get_state(sink)),
sink->suspend_cause & PA_SUSPEND_USER ? "USER " : "",
sink->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "",
sink->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "",
sink->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "",
pa_cvolume_snprint(cv, sizeof(cv), pa_sink_get_volume(sink, FALSE, FALSE)),
sink->flags & PA_SINK_DECIBEL_VOLUME ? "\n\t " : "",
sink->flags & PA_SINK_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_sink_get_volume(sink, FALSE, FALSE)) : "",
@ -302,6 +306,22 @@ char *pa_sink_list_to_string(pa_core *c) {
t = pa_proplist_to_string_sep(sink->proplist, "\n\t\t");
pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
pa_xfree(t);
if (sink->ports) {
pa_device_port *p;
void *state;
pa_strbuf_puts(s, "\tports:\n");
PA_HASHMAP_FOREACH(p, sink->ports, state)
pa_strbuf_printf(s, "\t\t%s: %s (priority %u)\n", p->name, p->description, p->priority);
}
if (sink->active_port)
pa_strbuf_printf(
s,
"\tactive port: <%s>\n",
sink->active_port->name);
}
return pa_strbuf_tostring_free(s);
@ -335,6 +355,7 @@ char *pa_source_list_to_string(pa_core *c) {
"\tdriver: <%s>\n"
"\tflags: %s%s%s%s%s%s%s\n"
"\tstate: %s\n"
"\tsuspend cause: %s%s%s%s\n"
"\tvolume: %s%s%s\n"
"\t balance %0.2f\n"
"\tbase volume: %s%s%s\n"
@ -358,6 +379,10 @@ char *pa_source_list_to_string(pa_core *c) {
source->flags & PA_SOURCE_LATENCY ? "LATENCY " : "",
source->flags & PA_SOURCE_DYNAMIC_LATENCY ? "DYNAMIC_LATENCY" : "",
source_state_to_string(pa_source_get_state(source)),
source->suspend_cause & PA_SUSPEND_USER ? "USER " : "",
source->suspend_cause & PA_SUSPEND_APPLICATION ? "APPLICATION " : "",
source->suspend_cause & PA_SUSPEND_IDLE ? "IDLE " : "",
source->suspend_cause & PA_SUSPEND_SESSION ? "SESSION" : "",
pa_cvolume_snprint(cv, sizeof(cv), pa_source_get_volume(source, FALSE)),
source->flags & PA_SOURCE_DECIBEL_VOLUME ? "\n\t " : "",
source->flags & PA_SOURCE_DECIBEL_VOLUME ? pa_sw_cvolume_snprint_dB(cvdb, sizeof(cvdb), pa_source_get_volume(source, FALSE)) : "",
@ -402,6 +427,21 @@ char *pa_source_list_to_string(pa_core *c) {
t = pa_proplist_to_string_sep(source->proplist, "\n\t\t");
pa_strbuf_printf(s, "\tproperties:\n\t\t%s\n", t);
pa_xfree(t);
if (source->ports) {
pa_device_port *p;
void *state;
pa_strbuf_puts(s, "\tports:\n");
PA_HASHMAP_FOREACH(p, source->ports, state)
pa_strbuf_printf(s, "\t\t%s: %s (priority %u)\n", p->name, p->description, p->priority);
}
if (source->active_port)
pa_strbuf_printf(
s,
"\tactive port: <%s>\n",
source->active_port->name);
}
return pa_strbuf_tostring_free(s);

View file

@ -40,19 +40,35 @@
#define COMMENTS "#;\n"
/* Run the user supplied parser for an assignment */
static int next_assignment(const char *filename, unsigned line, const char *section, const pa_config_item *t, const char *lvalue, const char *rvalue, void *userdata) {
static int next_assignment(
const char *filename,
unsigned line,
const char *section,
const pa_config_item *t,
const char *lvalue,
const char *rvalue,
void *userdata) {
pa_assert(filename);
pa_assert(t);
pa_assert(lvalue);
pa_assert(rvalue);
for (; t->parse; t++)
if (!t->lvalue ||
(pa_streq(lvalue, t->lvalue) &&
((!section && !t->section) || pa_streq(section, t->section))))
return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
for (; t->parse; t++) {
pa_log("[%s:%u] Unknown lvalue '%s' in section '%s'.", filename, line, lvalue, pa_strnull(section));
if (t->lvalue && !pa_streq(lvalue, t->lvalue))
continue;
if (t->section && !section)
continue;
if (t->section && !pa_streq(section, t->section))
continue;
return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
}
pa_log("[%s:%u] Unknown lvalue '%s' in section '%s'.", filename, line, lvalue, pa_strna(section));
return -1;
}
@ -96,6 +112,25 @@ static int parse_line(const char *filename, unsigned line, char **section, const
if (!*b)
return 0;
if (pa_startswith(b, ".include ")) {
char *path, *fn;
int r;
fn = strip(b+9);
if (!pa_is_path_absolute(fn)) {
const char *k;
if ((k = strrchr(filename, '/'))) {
char *dir = pa_xstrndup(filename, k-filename);
fn = path = pa_sprintf_malloc("%s" PA_PATH_SEP "%s", dir, fn);
pa_xfree(dir);
}
}
r = pa_config_parse(fn, NULL, t, userdata);
pa_xfree(path);
return r;
}
if (*b == '[') {
size_t k;
@ -135,6 +170,7 @@ int pa_config_parse(const char *filename, FILE *f, const pa_config_item *t, void
if (!f && !(f = fopen(filename, "r"))) {
if (errno == ENOENT) {
pa_log_debug("Failed to open configuration file '%s': %s", filename, pa_cstrerror(errno));
r = 0;
goto finish;
}

View file

@ -37,7 +37,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/core-error.h>
#include "rtclock.h"
#include "core-rtclock.h"
pa_usec_t pa_rtclock_age(const struct timeval *tv) {
struct timeval now;
@ -65,7 +65,7 @@ struct timeval *pa_rtclock_get(struct timeval *tv) {
pa_assert(tv);
tv->tv_sec = ts.tv_sec;
tv->tv_usec = ts.tv_nsec / 1000;
tv->tv_usec = ts.tv_nsec / PA_NSEC_PER_USEC;
return tv;
@ -82,11 +82,11 @@ pa_bool_t pa_rtclock_hrtimer(void) {
#ifdef CLOCK_MONOTONIC
if (clock_getres(CLOCK_MONOTONIC, &ts) >= 0)
return ts.tv_sec == 0 && ts.tv_nsec <= PA_HRTIMER_THRESHOLD_USEC*1000;
return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
#endif
pa_assert_se(clock_getres(CLOCK_REALTIME, &ts) == 0);
return ts.tv_sec == 0 && ts.tv_nsec <= PA_HRTIMER_THRESHOLD_USEC*1000;
return ts.tv_sec == 0 && ts.tv_nsec <= (long) (PA_HRTIMER_THRESHOLD_USEC*PA_NSEC_PER_USEC);
#else /* HAVE_CLOCK_GETTIME */
@ -122,12 +122,6 @@ void pa_rtclock_hrtimer_enable(void) {
#endif
}
pa_usec_t pa_rtclock_usec(void) {
struct timeval tv;
return pa_timeval_load(pa_rtclock_get(&tv));
}
struct timeval* pa_rtclock_from_wallclock(struct timeval *tv) {
#ifdef HAVE_CLOCK_GETTIME
@ -156,3 +150,41 @@ pa_usec_t pa_timespec_load(const struct timespec *ts) {
(pa_usec_t) ts->tv_sec * PA_USEC_PER_SEC +
(pa_usec_t) ts->tv_nsec / PA_NSEC_PER_USEC;
}
static struct timeval* wallclock_from_rtclock(struct timeval *tv) {
#ifdef HAVE_CLOCK_GETTIME
struct timeval wc_now, rt_now;
pa_gettimeofday(&wc_now);
pa_rtclock_get(&rt_now);
pa_assert(tv);
if (pa_timeval_cmp(&rt_now, tv) < 0)
pa_timeval_add(&wc_now, pa_timeval_diff(tv, &rt_now));
else
pa_timeval_sub(&wc_now, pa_timeval_diff(&rt_now, tv));
*tv = wc_now;
#endif
return tv;
}
struct timeval* pa_timeval_rtstore(struct timeval *tv, pa_usec_t v, pa_bool_t rtclock) {
pa_assert(tv);
if (v == PA_USEC_INVALID)
return NULL;
pa_timeval_store(tv, v);
if (rtclock)
tv->tv_usec |= PA_TIMEVAL_RTCLOCK;
else
wallclock_from_rtclock(tv);
return tv;
}

View file

@ -31,8 +31,6 @@ struct timeval;
struct timeval *pa_rtclock_get(struct timeval *ts);
pa_usec_t pa_rtclock_usec(void);
pa_usec_t pa_rtclock_age(const struct timeval *tv);
pa_bool_t pa_rtclock_hrtimer(void);
void pa_rtclock_hrtimer_enable(void);
@ -40,8 +38,13 @@ void pa_rtclock_hrtimer_enable(void);
/* timer with a resolution better than this are considered high-resolution */
#define PA_HRTIMER_THRESHOLD_USEC 10
/* bit to set in tv.tv_usec to mark that the timeval is in monotonic time */
#define PA_TIMEVAL_RTCLOCK ((time_t) (1LU << 30))
struct timeval* pa_rtclock_from_wallclock(struct timeval *tv);
pa_usec_t pa_timespec_load(const struct timespec *ts);
struct timeval* pa_timeval_rtstore(struct timeval *tv, pa_usec_t v, pa_bool_t rtclock);
#endif

View file

@ -47,6 +47,7 @@
#include <pulse/util.h>
#include <pulse/volume.h>
#include <pulse/xmalloc.h>
#include <pulse/rtclock.h>
#include <pulsecore/sink-input.h>
#include <pulsecore/sample-util.h>
@ -54,6 +55,7 @@
#include <pulsecore/core-subscribe.h>
#include <pulsecore/namereg.h>
#include <pulsecore/sound-file.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
#include <pulsecore/core-error.h>
@ -61,11 +63,10 @@
#include "core-scache.h"
#define UNLOAD_POLL_TIME 60
#define UNLOAD_POLL_TIME (60 * PA_USEC_PER_SEC)
static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, const struct timeval *tv, void *userdata) {
static void timeout_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
pa_core *c = userdata;
struct timeval ntv;
pa_assert(c);
pa_assert(c->mainloop == m);
@ -73,9 +74,7 @@ static void timeout_callback(pa_mainloop_api *m, pa_time_event*e, const struct t
pa_scache_unload_unused(c);
pa_gettimeofday(&ntv);
ntv.tv_sec += UNLOAD_POLL_TIME;
m->time_restart(e, &ntv);
pa_core_rttime_restart(c, e, pa_rtclock_now() + UNLOAD_POLL_TIME);
}
static void free_entry(pa_scache_entry *e) {
@ -256,12 +255,8 @@ int pa_scache_add_file_lazy(pa_core *c, const char *name, const char *filename,
pa_proplist_sets(e->proplist, PA_PROP_MEDIA_FILENAME, filename);
if (!c->scache_auto_unload_event) {
struct timeval ntv;
pa_gettimeofday(&ntv);
ntv.tv_sec += UNLOAD_POLL_TIME;
c->scache_auto_unload_event = c->mainloop->time_new(c->mainloop, &ntv, timeout_callback, c);
}
if (!c->scache_auto_unload_event)
c->scache_auto_unload_event = pa_core_rttime_new(c, pa_rtclock_now() + UNLOAD_POLL_TIME, timeout_callback, c);
if (idx)
*idx = e->index;

View file

@ -50,6 +50,10 @@
#ifdef HAVE_SCHED_H
#include <sched.h>
#if defined(__linux__) && !defined(SCHED_RESET_ON_FORK)
#define SCHED_RESET_ON_FORK 0x40000000
#endif
#endif
#ifdef HAVE_SYS_RESOURCE_H
@ -92,6 +96,10 @@
#include <xlocale.h>
#endif
#ifdef HAVE_DBUS
#include "rtkit.h"
#endif
#include <pulse/xmalloc.h>
#include <pulse/util.h>
#include <pulse/utf8.h>
@ -552,46 +560,78 @@ char *pa_strlcpy(char *b, const char *s, size_t l) {
return b;
}
static int set_scheduler(int rtprio) {
struct sched_param sp;
int r;
#ifdef HAVE_DBUS
DBusError error;
DBusConnection *bus;
dbus_error_init(&error);
#endif
pa_zero(sp);
sp.sched_priority = rtprio;
#ifdef SCHED_RESET_ON_FORK
if ((r = pthread_setschedparam(pthread_self(), SCHED_RR|SCHED_RESET_ON_FORK, &sp)) == 0) {
pa_log_debug("SCHED_RR|SCHED_RESET_ON_FORK worked.");
return 0;
}
#endif
if ((r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp)) == 0) {
pa_log_debug("SCHED_RR worked.");
return 0;
}
#ifdef HAVE_DBUS
/* Try to talk to RealtimeKit */
if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
pa_log("Failed to connect to system bus: %s\n", error.message);
dbus_error_free(&error);
errno = -EIO;
return -1;
}
r = rtkit_make_realtime(bus, 0, rtprio);
dbus_connection_unref(bus);
if (r >= 0) {
pa_log_debug("RealtimeKit worked.");
return 0;
}
errno = -r;
#else
errno = r;
#endif
return -1;
}
/* Make the current thread a realtime thread, and acquire the highest
* rtprio we can get that is less or equal the specified parameter. If
* the thread is already realtime, don't do anything. */
int pa_make_realtime(int rtprio) {
#ifdef _POSIX_PRIORITY_SCHEDULING
struct sched_param sp;
int r, policy;
int p;
memset(&sp, 0, sizeof(sp));
policy = 0;
if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) {
pa_log("pthread_getschedgetparam(): %s", pa_cstrerror(r));
return -1;
}
if (policy == SCHED_FIFO && sp.sched_priority >= rtprio) {
pa_log_info("Thread already being scheduled with SCHED_FIFO with priority %i.", sp.sched_priority);
if (set_scheduler(rtprio) >= 0) {
pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i.", rtprio);
return 0;
}
sp.sched_priority = rtprio;
if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) {
while (sp.sched_priority > 1) {
sp.sched_priority --;
if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) == 0) {
pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i, which is lower than the requested %i.", sp.sched_priority, rtprio);
return 0;
}
for (p = rtprio-1; p >= 1; p--)
if (set_scheduler(p)) {
pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", p, rtprio);
return 0;
}
pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r));
return -1;
}
pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority);
return 0;
pa_log_info("Failed to acquire real-time scheduling: %s", pa_cstrerror(errno));
return -1;
#else
errno = ENOTSUP;
@ -599,80 +639,42 @@ int pa_make_realtime(int rtprio) {
#endif
}
/* This is merely used for giving the user a hint. This is not correct
* for anything security related */
pa_bool_t pa_can_realtime(void) {
static int set_nice(int nice_level) {
#ifdef HAVE_DBUS
DBusError error;
DBusConnection *bus;
int r;
if (geteuid() == 0)
return TRUE;
#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
{
struct rlimit rl;
if (getrlimit(RLIMIT_RTPRIO, &rl) >= 0)
if (rl.rlim_cur > 0 || rl.rlim_cur == RLIM_INFINITY)
return TRUE;
}
dbus_error_init(&error);
#endif
#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
{
cap_t cap;
if ((cap = cap_get_proc())) {
cap_flag_value_t flag = CAP_CLEAR;
if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
if (flag == CAP_SET) {
cap_free(cap);
return TRUE;
}
cap_free(cap);
}
if (setpriority(PRIO_PROCESS, 0, nice_level) >= 0) {
pa_log_debug("setpriority() worked.");
return 0;
}
#ifdef HAVE_DBUS
/* Try to talk to RealtimeKit */
if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) {
pa_log("Failed to connect to system bus: %s\n", error.message);
dbus_error_free(&error);
errno = -EIO;
return -1;
}
r = rtkit_make_high_priority(bus, 0, nice_level);
dbus_connection_unref(bus);
if (r >= 0) {
pa_log_debug("RealtimeKit worked.");
return 0;
}
errno = -r;
#endif
return FALSE;
}
/* This is merely used for giving the user a hint. This is not correct
* for anything security related */
pa_bool_t pa_can_high_priority(void) {
if (geteuid() == 0)
return TRUE;
#if defined(HAVE_SYS_RESOURCE_H) && defined(RLIMIT_RTPRIO)
{
struct rlimit rl;
if (getrlimit(RLIMIT_NICE, &rl) >= 0)
if (rl.rlim_cur >= 21 || rl.rlim_cur == RLIM_INFINITY)
return TRUE;
}
#endif
#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_NICE)
{
cap_t cap;
if ((cap = cap_get_proc())) {
cap_flag_value_t flag = CAP_CLEAR;
if (cap_get_flag(cap, CAP_SYS_NICE, CAP_EFFECTIVE, &flag) >= 0)
if (flag == CAP_SET) {
cap_free(cap);
return TRUE;
}
cap_free(cap);
}
}
#endif
return FALSE;
return -1;
}
/* Raise the priority of the current process as much as possible that
@ -680,22 +682,21 @@ pa_bool_t pa_can_high_priority(void) {
int pa_raise_priority(int nice_level) {
#ifdef HAVE_SYS_RESOURCE_H
if (setpriority(PRIO_PROCESS, 0, nice_level) < 0) {
int n;
int n;
for (n = nice_level+1; n < 0; n++) {
if (setpriority(PRIO_PROCESS, 0, n) == 0) {
pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
return 0;
}
}
pa_log_warn("setpriority(): %s", pa_cstrerror(errno));
return -1;
if (set_nice(nice_level) >= 0) {
pa_log_info("Successfully gained nice level %i.", nice_level);
return 0;
}
pa_log_info("Successfully gained nice level %i.", nice_level);
for (n = nice_level+1; n < 0; n++)
if (set_nice(n) > 0) {
pa_log_info("Successfully acquired nice level %i, which is lower than the requested %i.", n, nice_level);
return 0;
}
pa_log_info("Failed to acquire high-priority scheduling: %s", pa_cstrerror(errno));
return -1;
#endif
#ifdef OS_IS_WIN32
@ -703,9 +704,10 @@ int pa_raise_priority(int nice_level) {
if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) {
pa_log_warn("SetPriorityClass() failed: 0x%08X", GetLastError());
errno = EPERM;
return .-1;
} else
pa_log_info("Successfully gained high priority class.");
return -1;
}
pa_log_info("Successfully gained high priority class.");
}
#endif
@ -720,8 +722,8 @@ void pa_reset_priority(void) {
setpriority(PRIO_PROCESS, 0, 0);
memset(&sp, 0, sizeof(sp));
pa_assert_se(pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp) == 0);
pa_zero(sp);
pthread_setschedparam(pthread_self(), SCHED_OTHER, &sp);
#endif
#ifdef OS_IS_WIN32
@ -2732,3 +2734,48 @@ void pa_disable_sigpipe(void) {
}
#endif
}
void pa_xfreev(void**a) {
void **p;
if (!a)
return;
for (p = a; *p; p++)
pa_xfree(*p);
pa_xfree(a);
}
char **pa_split_spaces_strv(const char *s) {
char **t, *e;
unsigned i = 0, n = 8;
const char *state = NULL;
t = pa_xnew(char*, n);
while ((e = pa_split_spaces(s, &state))) {
t[i++] = e;
if (i >= n) {
n *= 2;
t = pa_xrenew(char*, t, n);
}
}
if (i <= 0) {
pa_xfree(t);
return NULL;
}
t[i] = NULL;
return t;
}
char* pa_maybe_prefix_path(const char *path, const char *prefix) {
pa_assert(path);
if (pa_is_path_absolute(path))
return pa_xstrdup(path);
return pa_sprintf_malloc("%s" PA_PATH_SEP "%s", prefix, path);
}

View file

@ -80,9 +80,6 @@ int pa_make_realtime(int rtprio);
int pa_raise_priority(int nice_level);
void pa_reset_priority(void);
pa_bool_t pa_can_realtime(void);
pa_bool_t pa_can_high_priority(void);
int pa_parse_boolean(const char *s) PA_GCC_PURE;
static inline const char *pa_yes_no(pa_bool_t b) {
@ -229,4 +226,14 @@ char *pa_realpath(const char *path);
void pa_disable_sigpipe(void);
void pa_xfreev(void**a);
static inline void pa_xstrfreev(char **a) {
pa_xfreev((void**) a);
}
char **pa_split_spaces_strv(const char *s);
char* pa_maybe_prefix_path(const char *path, const char *prefix);
#endif

View file

@ -28,6 +28,7 @@
#include <stdio.h>
#include <signal.h>
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
@ -35,6 +36,7 @@
#include <pulsecore/sink.h>
#include <pulsecore/source.h>
#include <pulsecore/namereg.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/core-util.h>
#include <pulsecore/core-scache.h>
#include <pulsecore/core-subscribe.h>
@ -214,7 +216,7 @@ static void core_free(pa_object *o) {
pa_xfree(c);
}
static void exit_callback(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
static void exit_callback(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
pa_core *c = userdata;
pa_assert(c->exit_event == e);
@ -229,11 +231,7 @@ void pa_core_check_idle(pa_core *c) {
c->exit_idle_time >= 0 &&
pa_idxset_size(c->clients) == 0) {
struct timeval tv;
pa_gettimeofday(&tv);
tv.tv_sec+= c->exit_idle_time;
c->exit_event = c->mainloop->time_new(c->mainloop, &tv, exit_callback, c);
c->exit_event = pa_core_rttime_new(c, pa_rtclock_now() + c->exit_idle_time * PA_USEC_PER_SEC, exit_callback, c);
} else if (c->exit_event && pa_idxset_size(c->clients) > 0) {
c->mainloop->time_free(c->exit_event);
@ -261,3 +259,21 @@ void pa_core_maybe_vacuum(pa_core *c) {
pa_log_debug("Hmm, no streams around, trying to vacuum.");
pa_mempool_vacuum(c->mempool);
}
pa_time_event* pa_core_rttime_new(pa_core *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata) {
struct timeval tv;
pa_assert(c);
pa_assert(c->mainloop);
return c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, usec, TRUE), cb, userdata);
}
void pa_core_rttime_restart(pa_core *c, pa_time_event *e, pa_usec_t usec) {
struct timeval tv;
pa_assert(c);
pa_assert(c->mainloop);
c->mainloop->time_restart(e, pa_timeval_rtstore(&tv, usec, TRUE));
}

View file

@ -27,6 +27,16 @@
typedef struct pa_core pa_core;
/* This is a bitmask that encodes the cause why a sink/source is
* suspended. */
typedef enum pa_suspend_cause {
PA_SUSPEND_USER = 1, /* Exposed to the user via some protocol */
PA_SUSPEND_APPLICATION = 2, /* Used by the device reservation logic */
PA_SUSPEND_IDLE = 4, /* Used by module-suspend-on-idle */
PA_SUSPEND_SESSION = 8, /* Used by module-hal for mark inactive sessions */
PA_SUSPEND_ALL = 0xFFFF /* Magic cause that can be used to resume forcibly */
} pa_suspend_cause_t;
#include <pulsecore/idxset.h>
#include <pulsecore/hashmap.h>
#include <pulsecore/memblock.h>
@ -182,4 +192,8 @@ int pa_core_exit(pa_core *c, pa_bool_t force, int retval);
void pa_core_maybe_vacuum(pa_core *c);
/* wrapper for c->mainloop->time_*() RT time events */
pa_time_event* pa_core_rttime_new(pa_core *c, pa_usec_t usec, pa_time_event_cb_t cb, void *userdata);
void pa_core_rttime_restart(pa_core *c, pa_time_event *e, pa_usec_t usec);
#endif

View file

@ -71,10 +71,13 @@ pa_database* pa_database_open(const char *fn, pa_bool_t for_write) {
/* We include the host identifier in the file name because gdbm
* files are CPU dependant, and we don't want things to go wrong
* if we are on a multiarch system. */
path = pa_sprintf_malloc("%s."CANONICAL_HOST".gdbm", fn);
errno = 0;
f = gdbm_open((char*) path, 0, GDBM_NOLOCK | (for_write ? GDBM_WRCREAT : GDBM_READER), 0644, NULL);
/* We need to set the block size explicitly here, since otherwise
* gdbm takes the native block size of the underlying file system
* which might be incredibly large. */
f = gdbm_open((char*) path, 1024, GDBM_NOLOCK | (for_write ? GDBM_WRCREAT : GDBM_READER), 0644, NULL);
if (f)
pa_log_debug("Opened GDBM database '%s'", path);

View file

@ -26,6 +26,9 @@
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
/* Some versions of tdb lack inclusion of signal.h in the header files but use sigatomic_t */
#include <signal.h>
#include <tdb.h>
#include <pulse/xmalloc.h>

View file

@ -70,7 +70,7 @@ pa_dbus_connection* pa_dbus_bus_get(pa_core *c, DBusBusType type, DBusError *err
if ((pconn = pa_shared_get(c, prop_name[type])))
return pa_dbus_connection_ref(pconn);
if (!(conn = pa_dbus_wrap_connection_new(c->mainloop, type, error)))
if (!(conn = pa_dbus_wrap_connection_new(c->mainloop, TRUE, type, error)))
return NULL;
return dbus_connection_new(c, conn, prop_name[type]);

View file

@ -26,9 +26,11 @@
#include <stdarg.h>
#include <pulse/xmalloc.h>
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/core-util.h>
#include <pulsecore/log.h>
@ -38,6 +40,12 @@ struct pa_dbus_wrap_connection {
pa_mainloop_api *mainloop;
DBusConnection *connection;
pa_defer_event* dispatch_event;
pa_bool_t use_rtclock:1;
};
struct timeout_data {
pa_dbus_wrap_connection *c;
DBusTimeout *timeout;
};
static void dispatch_cb(pa_mainloop_api *ea, pa_defer_event *ev, void *userdata) {
@ -118,16 +126,18 @@ static void handle_io_event(pa_mainloop_api *ea, pa_io_event *e, int fd, pa_io_e
}
/* pa_time_event_cb_t timer event handler */
static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *tv, void *userdata) {
DBusTimeout *timeout = userdata;
static void handle_time_event(pa_mainloop_api *ea, pa_time_event* e, const struct timeval *t, void *userdata) {
struct timeval tv;
struct timeout_data *d = userdata;
if (dbus_timeout_get_enabled(timeout)) {
struct timeval next = *tv;
dbus_timeout_handle(timeout);
pa_assert(d);
pa_assert(d->c);
if (dbus_timeout_get_enabled(d->timeout)) {
dbus_timeout_handle(d->timeout);
/* restart it for the next scheduled time */
pa_timeval_add(&next, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
ea->time_restart(e, &next);
ea->time_restart(e, pa_timeval_rtstore(&tv, pa_timeval_load(t) + dbus_timeout_get_interval(d->timeout) * PA_USEC_PER_MSEC, d->c->use_rtclock));
}
}
@ -179,11 +189,16 @@ static void toggle_watch(DBusWatch *watch, void *data) {
c->mainloop->io_enable(ev, get_watch_flags(watch));
}
static void time_event_destroy_cb(pa_mainloop_api *a, pa_time_event *e, void *userdata) {
pa_xfree(userdata);
}
/* DBusAddTimeoutFunction callback for pa mainloop */
static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
pa_dbus_wrap_connection *c = data;
pa_time_event *ev;
struct timeval tv;
struct timeout_data *d;
pa_assert(timeout);
pa_assert(c);
@ -191,10 +206,11 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) {
if (!dbus_timeout_get_enabled(timeout))
return FALSE;
pa_gettimeofday(&tv);
pa_timeval_add(&tv, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
ev = c->mainloop->time_new(c->mainloop, &tv, handle_time_event, timeout);
d = pa_xnew(struct timeout_data, 1);
d->c = c;
d->timeout = timeout;
ev = c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, c->use_rtclock), handle_time_event, d);
c->mainloop->time_set_destroy(ev, time_event_destroy_cb);
dbus_timeout_set_data(timeout, ev, NULL);
@ -215,23 +231,20 @@ static void remove_timeout(DBusTimeout *timeout, void *data) {
/* DBusTimeoutToggledFunction callback for pa mainloop */
static void toggle_timeout(DBusTimeout *timeout, void *data) {
pa_dbus_wrap_connection *c = data;
struct timeout_data *d = data;
pa_time_event *ev;
struct timeval tv;
pa_assert(d);
pa_assert(d->c);
pa_assert(timeout);
pa_assert(c);
pa_assert_se(ev = dbus_timeout_get_data(timeout));
if (dbus_timeout_get_enabled(timeout)) {
struct timeval tv;
pa_gettimeofday(&tv);
pa_timeval_add(&tv, (pa_usec_t) dbus_timeout_get_interval(timeout) * 1000);
c->mainloop->time_restart(ev, &tv);
d->c->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, pa_rtclock_now() + dbus_timeout_get_interval(timeout) * PA_USEC_PER_MSEC, d->c->use_rtclock));
} else
c->mainloop->time_restart(ev, NULL);
d->c->mainloop->time_restart(ev, pa_timeval_rtstore(&tv, PA_USEC_INVALID, d->c->use_rtclock));
}
static void wakeup_main(void *userdata) {
@ -244,7 +257,7 @@ static void wakeup_main(void *userdata) {
c->mainloop->defer_enable(c->dispatch_event, 1);
}
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, DBusBusType type, DBusError *error) {
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, pa_bool_t use_rtclock, DBusBusType type, DBusError *error) {
DBusConnection *conn;
pa_dbus_wrap_connection *pconn;
char *id;
@ -257,6 +270,7 @@ pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, DBusBus
pconn = pa_xnew(pa_dbus_wrap_connection, 1);
pconn->mainloop = m;
pconn->connection = conn;
pconn->use_rtclock = use_rtclock;
dbus_connection_set_exit_on_disconnect(conn, FALSE);
dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);
@ -276,7 +290,7 @@ pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *m, DBusBus
return pconn;
}
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(pa_mainloop_api *m, DBusConnection *conn) {
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(pa_mainloop_api *m, pa_bool_t use_rtclock, DBusConnection *conn) {
pa_dbus_wrap_connection *pconn;
pa_assert(m);
@ -285,6 +299,7 @@ pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(pa_mainloop_a
pconn = pa_xnew(pa_dbus_wrap_connection, 1);
pconn->mainloop = m;
pconn->connection = dbus_connection_ref(conn);
pconn->use_rtclock = use_rtclock;
dbus_connection_set_exit_on_disconnect(conn, FALSE);
dbus_connection_set_dispatch_status_function(conn, dispatch_status, pconn, NULL);

View file

@ -30,8 +30,8 @@
/* A wrap connection is not shared or refcounted, it is available in client side */
typedef struct pa_dbus_wrap_connection pa_dbus_wrap_connection;
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *mainloop, DBusBusType type, DBusError *error);
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(pa_mainloop_api *mainloop, DBusConnection *conn);
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new(pa_mainloop_api *mainloop, pa_bool_t use_rtclock, DBusBusType type, DBusError *error);
pa_dbus_wrap_connection* pa_dbus_wrap_connection_new_from_existing(pa_mainloop_api *mainloop, pa_bool_t use_rtclock, DBusConnection *conn);
void pa_dbus_wrap_connection_free(pa_dbus_wrap_connection* conn);
DBusConnection* pa_dbus_wrap_connection_get(pa_dbus_wrap_connection *conn);

View file

@ -237,6 +237,39 @@ at_end:
return NULL;
}
void *pa_hashmap_iterate_backwards(pa_hashmap *h, void **state, const void **key) {
struct hashmap_entry *e;
pa_assert(h);
pa_assert(state);
if (*state == (void*) -1)
goto at_beginning;
if (!*state && !h->iterate_list_tail)
goto at_beginning;
e = *state ? *state : h->iterate_list_tail;
if (e->iterate_previous)
*state = e->iterate_previous;
else
*state = (void*) -1;
if (key)
*key = e->key;
return e->value;
at_beginning:
*state = (void *) -1;
if (key)
*key = NULL;
return NULL;
}
void* pa_hashmap_first(pa_hashmap *h) {
pa_assert(h);
@ -246,6 +279,15 @@ void* pa_hashmap_first(pa_hashmap *h) {
return h->iterate_list_head->value;
}
void* pa_hashmap_last(pa_hashmap *h) {
pa_assert(h);
if (!h->iterate_list_tail)
return NULL;
return h->iterate_list_tail->value;
}
void* pa_hashmap_steal_first(pa_hashmap *h) {
void *data;

View file

@ -26,7 +26,8 @@
/* Simple Implementation of a hash table. Memory management is the
* user's job. It's a good idea to have the key pointer point to a
* string in the value data. */
* string in the value data. The insertion order is preserved when
* iterating. */
typedef struct pa_hashmap pa_hashmap;
@ -59,10 +60,24 @@ pa_bool_t pa_hashmap_isempty(pa_hashmap *h);
returned. */
void *pa_hashmap_iterate(pa_hashmap *h, void **state, const void**key);
/* Same as pa_hashmap_iterate() but goes backwards */
void *pa_hashmap_iterate_backwards(pa_hashmap *h, void **state, const void**key);
/* Remove the oldest entry in the hashmap and return it */
void *pa_hashmap_steal_first(pa_hashmap *h);
/* Return the oldest entry in the hashmap */
void* pa_hashmap_first(pa_hashmap *h);
/* Return the newest entry in the hashmap */
void* pa_hashmap_last(pa_hashmap *h);
/* A macro to ease iteration through all entries */
#define PA_HASHMAP_FOREACH(e, h, state) \
for ((state) = NULL, (e) = pa_hashmap_iterate((h), &(state), NULL); (e); (e) = pa_hashmap_iterate((h), &(state), NULL))
/* A macro to ease iteration through all entries, backwards */
#define PA_HASHMAP_FOREACH_BACKWARDS(e, h, state) \
for ((state) = NULL, (e) = pa_hashmap_iterate_backwards((h), &(state), NULL); (e); (e) = pa_hashmap_iterate_backwards((h), &(state), NULL))
#endif

View file

@ -453,3 +453,17 @@ pa_bool_t pa_idxset_isempty(pa_idxset *s) {
return s->n_entries == 0;
}
pa_idxset *pa_idxset_copy(pa_idxset *s) {
pa_idxset *copy;
struct idxset_entry *i;
pa_assert(s);
copy = pa_idxset_new(s->hash_func, s->compare_func);
for (i = s->iterate_list_head; i; i = i->iterate_next)
pa_idxset_put(copy, i->data, NULL);
return copy;
}

View file

@ -103,7 +103,10 @@ unsigned pa_idxset_size(pa_idxset*s);
/* Return TRUE of the idxset is empty */
pa_bool_t pa_idxset_isempty(pa_idxset *s);
/* Duplicate the idxset. This will not copy the actual indexes */
pa_idxset *pa_idxset_copy(pa_idxset *s);
/* A macro to ease iteration through all entries */
#define PA_IDXSET_FOREACH(e, s, idx) \
for ((e) = pa_idxset_first((s), &(idx)); (e); (e) = pa_idxset_next((s), &(idx)))

View file

@ -38,6 +38,7 @@
#include <syslog.h>
#endif
#include <pulse/rtclock.h>
#include <pulse/utf8.h>
#include <pulse/xmalloc.h>
#include <pulse/util.h>
@ -45,7 +46,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/core-util.h>
#include <pulsecore/rtclock.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/once.h>
#include <pulsecore/ratelimit.h>
@ -294,7 +295,7 @@ void pa_log_levelv_meta(
static pa_usec_t start, last;
pa_usec_t u, a, r;
u = pa_rtclock_usec();
u = pa_rtclock_now();
PA_ONCE_BEGIN {
start = u;

View file

@ -165,6 +165,10 @@ enum {
PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED,
PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED,
/* Supported since protocol v16 (0.9.16) */
PA_COMMAND_SET_SINK_PORT,
PA_COMMAND_SET_SOURCE_PORT,
PA_COMMAND_MAX
};

View file

@ -27,6 +27,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
@ -37,6 +38,7 @@
#include <pulsecore/macro.h>
#include <pulsecore/refcnt.h>
#include <pulsecore/flist.h>
#include <pulsecore/core-rtclock.h>
#include "pdispatch.h"
@ -204,6 +206,7 @@ struct pa_pdispatch {
pa_pdispatch_drain_callback drain_callback;
void *drain_userdata;
const pa_creds *creds;
pa_bool_t use_rtclock:1;
};
static void reply_info_free(struct reply_info *r) {
@ -220,7 +223,7 @@ static void reply_info_free(struct reply_info *r) {
pa_xfree(r);
}
pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_t*table, unsigned entries) {
pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, pa_bool_t use_rtclock, const pa_pdispatch_cb_t *table, unsigned entries) {
pa_pdispatch *pd;
pa_assert(mainloop);
@ -235,6 +238,7 @@ pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *mainloop, const pa_pdispatch_cb_
pd->drain_callback = NULL;
pd->drain_userdata = NULL;
pd->creds = NULL;
pd->use_rtclock = use_rtclock;
return pd;
}
@ -304,7 +308,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds,
if (command >= PA_COMMAND_MAX || !(p = command_names[command]))
pa_snprintf((char*) (p = t), sizeof(t), "%u", command);
pa_log("[%p] Recieved opcode <%s>", pd, p);
pa_log("[%p] Received opcode <%s>", pd, p);
}
#endif
@ -325,7 +329,7 @@ int pa_pdispatch_run(pa_pdispatch *pd, pa_packet*packet, const pa_creds *creds,
(*c)(pd, command, tag, ts, userdata);
} else {
pa_log("Recieved unsupported command %u", command);
pa_log("Received unsupported command %u", command);
goto finish;
}
@ -342,7 +346,7 @@ finish:
return ret;
}
static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *tv, void *userdata) {
static void timeout_callback(pa_mainloop_api*m, pa_time_event*e, const struct timeval *t, void *userdata) {
struct reply_info*r = userdata;
pa_assert(r);
@ -371,10 +375,7 @@ void pa_pdispatch_register_reply(pa_pdispatch *pd, uint32_t tag, int timeout, pa
r->free_cb = free_cb;
r->tag = tag;
pa_gettimeofday(&tv);
tv.tv_sec += timeout;
pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop, &tv, timeout_callback, r));
pa_assert_se(r->time_event = pd->mainloop->time_new(pd->mainloop, pa_timeval_rtstore(&tv, pa_rtclock_now() + timeout * PA_USEC_PER_SEC, pd->use_rtclock), timeout_callback, r));
PA_LLIST_PREPEND(struct reply_info, pd->replies, r);
}

View file

@ -37,7 +37,7 @@ typedef struct pa_pdispatch pa_pdispatch;
typedef void (*pa_pdispatch_cb_t)(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
typedef void (*pa_pdispatch_drain_callback)(pa_pdispatch *pd, void *userdata);
pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, const pa_pdispatch_cb_t*table, unsigned entries);
pa_pdispatch* pa_pdispatch_new(pa_mainloop_api *m, pa_bool_t use_rtclock, const pa_pdispatch_cb_t*table, unsigned entries);
void pa_pdispatch_unref(pa_pdispatch *pd);
pa_pdispatch* pa_pdispatch_ref(pa_pdispatch *pd);

View file

@ -30,6 +30,7 @@
#include <stdlib.h>
#include <limits.h>
#include <pulse/rtclock.h>
#include <pulse/sample.h>
#include <pulse/timeval.h>
#include <pulse/utf8.h>
@ -63,7 +64,7 @@
#define MAX_CONNECTIONS 64
/* Kick a client if it doesn't authenticate within this time */
#define AUTH_TIMEOUT 5
#define AUTH_TIMEOUT (5*PA_USEC_PER_SEC)
#define DEFAULT_COOKIE_FILE ".esd_auth"
@ -947,10 +948,10 @@ static int esd_proto_standby_or_resume(connection *c, esd_proto_t request, const
connection_write(c, &ok, sizeof(int32_t));
if (request == ESD_PROTO_STANDBY)
ok = pa_sink_suspend_all(c->protocol->core, TRUE) >= 0;
ok = pa_sink_suspend_all(c->protocol->core, TRUE, PA_SUSPEND_USER) >= 0;
else {
pa_assert(request == ESD_PROTO_RESUME);
ok = pa_sink_suspend_all(c->protocol->core, FALSE) >= 0;
ok = pa_sink_suspend_all(c->protocol->core, FALSE, PA_SUSPEND_USER) >= 0;
}
connection_write(c, &ok, sizeof(int32_t));
@ -1459,11 +1460,10 @@ static pa_usec_t source_output_get_latency_cb(pa_source_output *o) {
/*** entry points ***/
static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
static void auth_timeout(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
connection *c = CONNECTION(userdata);
pa_assert(m);
pa_assert(tv);
connection_assert_ref(c);
pa_assert(c->auth_timeout_event == e);
@ -1553,12 +1553,9 @@ void pa_esound_protocol_connect(pa_esound_protocol *p, pa_iochannel *io, pa_esou
c->authorized = TRUE;
}
if (!c->authorized) {
struct timeval tv;
pa_gettimeofday(&tv);
tv.tv_sec += AUTH_TIMEOUT;
c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
} else
if (!c->authorized)
c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
else
c->auth_timeout_event = NULL;
c->defer_event = p->core->mainloop->defer_new(p->core->mainloop, defer_callback, c);

View file

@ -29,6 +29,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/version.h>
#include <pulse/utf8.h>
@ -61,7 +62,7 @@
#include "protocol-native.h"
/* Kick a client if it doesn't authenticate within this time */
#define AUTH_TIMEOUT 60
#define AUTH_TIMEOUT (60 * PA_USEC_PER_SEC)
/* Don't accept more connection than this */
#define MAX_CONNECTIONS 64
@ -284,6 +285,7 @@ static void command_update_proplist(pa_pdispatch *pd, uint32_t command, uint32_t
static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_ERROR] = NULL,
@ -380,6 +382,9 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
[PA_COMMAND_SET_CARD_PROFILE] = command_set_card_profile,
[PA_COMMAND_SET_SINK_PORT] = command_set_sink_or_source_port,
[PA_COMMAND_SET_SOURCE_PORT] = command_set_sink_or_source_port,
[PA_COMMAND_EXTENSION] = command_extension
};
@ -2841,6 +2846,23 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin
pa_tagstruct_putu32(t, sink->n_volume_steps);
pa_tagstruct_putu32(t, sink->card ? sink->card->index : PA_INVALID_INDEX);
}
if (c->version >= 16) {
pa_tagstruct_putu32(t, sink->ports ? pa_hashmap_size(sink->ports) : 0);
if (sink->ports) {
void *state;
pa_device_port *p;
PA_HASHMAP_FOREACH(p, sink->ports, state) {
pa_tagstruct_puts(t, p->name);
pa_tagstruct_puts(t, p->description);
pa_tagstruct_putu32(t, p->priority);
}
}
pa_tagstruct_puts(t, sink->active_port ? sink->active_port->name : NULL);
}
}
static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) {
@ -2881,6 +2903,24 @@ static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s
pa_tagstruct_putu32(t, source->n_volume_steps);
pa_tagstruct_putu32(t, source->card ? source->card->index : PA_INVALID_INDEX);
}
if (c->version >= 16) {
pa_tagstruct_putu32(t, source->ports ? pa_hashmap_size(source->ports) : 0);
if (source->ports) {
void *state;
pa_device_port *p;
PA_HASHMAP_FOREACH(p, source->ports, state) {
pa_tagstruct_puts(t, p->name);
pa_tagstruct_puts(t, p->description);
pa_tagstruct_putu32(t, p->priority);
}
}
pa_tagstruct_puts(t, source->active_port ? source->active_port->name : NULL);
}
}
static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) {
@ -3328,9 +3368,9 @@ static void command_set_volume(
CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
if (sink)
pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE);
pa_sink_set_volume(sink, &volume, TRUE, TRUE, TRUE, TRUE);
else if (source)
pa_source_set_volume(source, &volume);
pa_source_set_volume(source, &volume, TRUE);
else if (si)
pa_sink_input_set_volume(si, &volume, TRUE, TRUE);
@ -3400,9 +3440,9 @@ static void command_set_mute(
CHECK_VALIDITY(c->pstream, si || sink || source, tag, PA_ERR_NOENTITY);
if (sink)
pa_sink_set_mute(sink, mute);
pa_sink_set_mute(sink, mute, TRUE);
else if (source)
pa_source_set_mute(source, mute);
pa_source_set_mute(source, mute, TRUE);
else if (si)
pa_sink_input_set_mute(si, mute, TRUE);
@ -4098,7 +4138,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa
pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming");
if (pa_sink_suspend_all(c->protocol->core, b) < 0) {
if (pa_sink_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
return;
}
@ -4112,7 +4152,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa
CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
if (pa_sink_suspend(sink, b) < 0) {
if (pa_sink_suspend(sink, b, PA_SUSPEND_USER) < 0) {
pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
return;
}
@ -4125,7 +4165,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa
pa_log_debug("%s all sources", b ? "Suspending" : "Resuming");
if (pa_source_suspend_all(c->protocol->core, b) < 0) {
if (pa_source_suspend_all(c->protocol->core, b, PA_SUSPEND_USER) < 0) {
pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
return;
}
@ -4140,7 +4180,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa
CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
if (pa_source_suspend(source, b) < 0) {
if (pa_source_suspend(source, b, PA_SUSPEND_USER) < 0) {
pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
return;
}
@ -4195,6 +4235,7 @@ static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_
uint32_t idx = PA_INVALID_INDEX;
const char *name = NULL, *profile = NULL;
pa_card *card = NULL;
int ret;
pa_native_connection_assert_ref(c);
pa_assert(t);
@ -4220,14 +4261,72 @@ static void command_set_card_profile(pa_pdispatch *pd, uint32_t command, uint32_
CHECK_VALIDITY(c->pstream, card, tag, PA_ERR_NOENTITY);
if (pa_card_set_profile(card, profile, TRUE) < 0) {
pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID);
if ((ret = pa_card_set_profile(card, profile, TRUE)) < 0) {
pa_pstream_send_error(c->pstream, tag, -ret);
return;
}
pa_pstream_send_simple_ack(c->pstream, tag);
}
static void command_set_sink_or_source_port(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
uint32_t idx = PA_INVALID_INDEX;
const char *name = NULL, *port = NULL;
int ret;
pa_native_connection_assert_ref(c);
pa_assert(t);
if (pa_tagstruct_getu32(t, &idx) < 0 ||
pa_tagstruct_gets(t, &name) < 0 ||
pa_tagstruct_gets(t, &port) < 0 ||
!pa_tagstruct_eof(t)) {
protocol_error(c);
return;
}
CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS);
CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID);
CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID);
CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID);
CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID);
if (command == PA_COMMAND_SET_SINK_PORT) {
pa_sink *sink;
if (idx != PA_INVALID_INDEX)
sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx);
else
sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK);
CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY);
if ((ret = pa_sink_set_port(sink, port, TRUE)) < 0) {
pa_pstream_send_error(c->pstream, tag, -ret);
return;
}
} else {
pa_source *source;
pa_assert(command = PA_COMMAND_SET_SOURCE_PORT);
if (idx != PA_INVALID_INDEX)
source = pa_idxset_get_by_index(c->protocol->core->sources, idx);
else
source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE);
CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY);
if ((ret = pa_source_set_port(source, port, TRUE)) < 0) {
pa_pstream_send_error(c->pstream, tag, -ret);
return;
}
}
pa_pstream_send_simple_ack(c->pstream, tag);
}
/*** pstream callbacks ***/
static void pstream_packet_callback(pa_pstream *p, pa_packet *packet, const pa_creds *creds, void *userdata) {
@ -4381,11 +4480,10 @@ static void client_send_event_cb(pa_client *client, const char*event, pa_proplis
/*** module entry points ***/
static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *tv, void *userdata) {
static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timeval *t, void *userdata) {
pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
pa_assert(m);
pa_assert(tv);
pa_native_connection_assert_ref(c);
pa_assert(c->auth_timeout_event == e);
@ -4443,12 +4541,9 @@ void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_nati
c->authorized = TRUE;
}
if (!c->authorized) {
struct timeval tv;
pa_gettimeofday(&tv);
tv.tv_sec += AUTH_TIMEOUT;
c->auth_timeout_event = p->core->mainloop->time_new(p->core->mainloop, &tv, auth_timeout, c);
} else
if (!c->authorized)
c->auth_timeout_event = pa_core_rttime_new(p->core, pa_rtclock_now() + AUTH_TIMEOUT, auth_timeout, c);
else
c->auth_timeout_event = NULL;
c->is_local = pa_iochannel_socket_is_local(io);
@ -4467,7 +4562,7 @@ void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_nati
pa_pstream_set_revoke_callback(c->pstream, pstream_revoke_callback, c);
pa_pstream_set_release_callback(c->pstream, pstream_release_callback, c);
c->pdispatch = pa_pdispatch_new(p->core->mainloop, command_table, PA_COMMAND_MAX);
c->pdispatch = pa_pdispatch_new(p->core->mainloop, TRUE, command_table, PA_COMMAND_MAX);
c->record_streams = pa_idxset_new(NULL, NULL);
c->output_streams = pa_idxset_new(NULL, NULL);

View file

@ -684,7 +684,7 @@ static int do_read(pa_pstream *p) {
flags = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_FLAGS]);
if (!p->use_shm && (flags & PA_FLAG_SHMMASK) != 0) {
pa_log_warn("Recieved SHM frame on a socket where SHM is disabled.");
pa_log_warn("Received SHM frame on a socket where SHM is disabled.");
return -1;
}
@ -714,7 +714,7 @@ static int do_read(pa_pstream *p) {
length = ntohl(p->read.descriptor[PA_PSTREAM_DESCRIPTOR_LENGTH]);
if (length > FRAME_SIZE_MAX_ALLOW || length <= 0) {
pa_log_warn("Recieved invalid frame size: %lu", (unsigned long) length);
pa_log_warn("Received invalid frame size: %lu", (unsigned long) length);
return -1;
}
@ -743,7 +743,7 @@ static int do_read(pa_pstream *p) {
if ((flags & PA_FLAG_SHMMASK) == PA_FLAG_SHMDATA) {
if (length != sizeof(p->read.shm_info)) {
pa_log_warn("Recieved SHM memblock frame with Invalid frame length.");
pa_log_warn("Received SHM memblock frame with Invalid frame length.");
return -1;
}
@ -758,7 +758,7 @@ static int do_read(pa_pstream *p) {
p->read.data = NULL;
} else {
pa_log_warn("Recieved memblock frame with invalid flags value.");
pa_log_warn("Received memblock frame with invalid flags value.");
return -1;
}
}

View file

@ -23,7 +23,8 @@
#include <config.h>
#endif
#include <pulsecore/rtclock.h>
#include <pulse/rtclock.h>
#include <pulsecore/log.h>
#include <pulsecore/mutex.h>
@ -38,7 +39,7 @@ pa_bool_t pa_ratelimit_test(pa_ratelimit *r) {
pa_usec_t now;
pa_mutex *m;
now = pa_rtclock_usec();
now = pa_rtclock_now();
m = pa_static_mutex_get(&mutex, FALSE, FALSE);
pa_mutex_lock(m);

189
src/pulsecore/rtkit.c Normal file
View file

@ -0,0 +1,189 @@
/*-*- Mode: C; c-basic-offset: 8 -*-*/
/***
Copyright 2009 Lennart Poettering
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
***/
#include <errno.h>
#include "rtkit.h"
#ifdef __linux__
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/syscall.h>
static pid_t _gettid(void) {
return (pid_t) syscall(SYS_gettid);
}
static int translate_error(const char *name) {
if (strcmp(name, DBUS_ERROR_NO_MEMORY) == 0)
return -ENOMEM;
if (strcmp(name, DBUS_ERROR_SERVICE_UNKNOWN) == 0 ||
strcmp(name, DBUS_ERROR_NAME_HAS_NO_OWNER) == 0)
return -ENOENT;
if (strcmp(name, DBUS_ERROR_ACCESS_DENIED) == 0 ||
strcmp(name, DBUS_ERROR_AUTH_FAILED) == 0)
return -EACCES;
return -EIO;
}
int rtkit_make_realtime(DBusConnection *connection, pid_t thread, int priority) {
DBusMessage *m = NULL, *r = NULL;
dbus_uint64_t u64;
dbus_uint32_t u32;
DBusError error;
int ret;
dbus_error_init(&error);
if (thread == 0)
thread = _gettid();
if (!(m = dbus_message_new_method_call(
RTKIT_SERVICE_NAME,
RTKIT_OBJECT_PATH,
"org.freedesktop.RealtimeKit1",
"MakeThreadRealtime"))) {
ret = -ENOMEM;
goto finish;
}
u64 = (dbus_uint64_t) thread;
u32 = (dbus_uint32_t) priority;
if (!dbus_message_append_args(
m,
DBUS_TYPE_UINT64, &u64,
DBUS_TYPE_UINT32, &u32,
DBUS_TYPE_INVALID)) {
ret = -ENOMEM;
goto finish;
}
if (!(r = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
ret = translate_error(error.name);
goto finish;
}
if (dbus_set_error_from_message(&error, r)) {
ret = translate_error(error.name);
goto finish;
}
ret = 0;
finish:
if (m)
dbus_message_unref(m);
if (r)
dbus_message_unref(r);
dbus_error_free(&error);
return ret;
}
int rtkit_make_high_priority(DBusConnection *connection, pid_t thread, int nice_level) {
DBusMessage *m = NULL, *r = NULL;
dbus_uint64_t u64;
dbus_int32_t s32;
DBusError error;
int ret;
dbus_error_init(&error);
if (thread == 0)
thread = _gettid();
if (!(m = dbus_message_new_method_call(
RTKIT_SERVICE_NAME,
RTKIT_OBJECT_PATH,
"org.freedesktop.RealtimeKit1",
"MakeThreadHighPriority"))) {
ret = -ENOMEM;
goto finish;
}
u64 = (dbus_uint64_t) thread;
s32 = (dbus_int32_t) nice_level;
if (!dbus_message_append_args(
m,
DBUS_TYPE_UINT64, &u64,
DBUS_TYPE_INT32, &s32,
DBUS_TYPE_INVALID)) {
ret = -ENOMEM;
goto finish;
}
if (!(r = dbus_connection_send_with_reply_and_block(connection, m, -1, &error))) {
ret = translate_error(error.name);
goto finish;
}
if (dbus_set_error_from_message(&error, r)) {
ret = translate_error(error.name);
goto finish;
}
ret = 0;
finish:
if (m)
dbus_message_unref(m);
if (r)
dbus_message_unref(r);
dbus_error_free(&error);
return ret;
}
#else
int rtkit_make_realtime(DBusConnection *connection, pid_t thread, int priority) {
return -ENOTSUP;
}
int rtkit_make_high_priority(DBusConnection *connection, pid_t thread, int nice_level) {
return -ENOTSUP;
}
#endif

62
src/pulsecore/rtkit.h Normal file
View file

@ -0,0 +1,62 @@
/*-*- Mode: C; c-basic-offset: 8 -*-*/
#ifndef foortkithfoo
#define foortkithfoo
/***
Copyright 2009 Lennart Poettering
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
***/
#include <sys/types.h>
#include <dbus/dbus.h>
#ifdef __cplusplus
extern "C" {
#endif
/* This is the reference implementation for a client for
* RealtimeKit. You don't have to use this, but if do, just copy these
* sources into your repository */
#define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1"
#define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1"
/* This is mostly equivalent to sched_setparam(thread, SCHED_RR, {
* .sched_priority = priority }). 'thread' needs to be a kernel thread
* id as returned by gettid(), not a pthread_t! If 'thread' is 0 the
* current thread is used. The returned value is a negative errno
* style error code, or 0 on success. */
int rtkit_make_realtime(DBusConnection *system_bus, pid_t thread, int priority);
/* This is mostly equivalent to setpriority(PRIO_PROCESS, thread,
* nice_level). 'thread' needs to be a kernel thread id as returned by
* gettid(), not a pthread_t! If 'thread' is 0 the current thread is
* used. The returned value is a negative errno style error code, or 0
* on success.*/
int rtkit_make_high_priority(DBusConnection *system_bus, pid_t thread, int nice_level);
#ifdef __cplusplus
}
#endif
#endif

View file

@ -30,10 +30,6 @@
#include <string.h>
#include <errno.h>
#ifdef __linux__
#include <sys/utsname.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#else
@ -44,10 +40,9 @@
#include <pulse/timeval.h>
#include <pulsecore/core-error.h>
#include <pulsecore/rtclock.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/macro.h>
#include <pulsecore/llist.h>
#include <pulsecore/rtsig.h>
#include <pulsecore/flist.h>
#include <pulsecore/core-util.h>
#include <pulsecore/winsock.h>
@ -66,20 +61,9 @@ struct pa_rtpoll {
pa_bool_t scan_for_dead:1;
pa_bool_t running:1;
pa_bool_t installed:1;
pa_bool_t rebuild_needed:1;
pa_bool_t quit:1;
#ifdef HAVE_PPOLL
pa_bool_t timer_armed:1;
#ifdef __linux__
pa_bool_t dont_use_ppoll:1;
#endif
int rtsig;
sigset_t sigset_unblocked;
timer_t timer;
#endif
#ifdef DEBUG_TIMING
pa_usec_t timestamp;
pa_usec_t slept, awake;
@ -107,52 +91,20 @@ struct pa_rtpoll_item {
PA_STATIC_FLIST_DECLARE(items, 0, pa_xfree);
static void signal_handler_noop(int s) { /* write(2, "signal\n", 7); */ }
pa_rtpoll *pa_rtpoll_new(void) {
pa_rtpoll *p;
p = pa_xnew(pa_rtpoll, 1);
#ifdef HAVE_PPOLL
#ifdef __linux__
/* ppoll is broken on Linux < 2.6.16 */
p->dont_use_ppoll = FALSE;
{
struct utsname u;
unsigned major, minor, micro;
pa_assert_se(uname(&u) == 0);
if (sscanf(u.release, "%u.%u.%u", &major, &minor, &micro) != 3 ||
(major < 2) ||
(major == 2 && minor < 6) ||
(major == 2 && minor == 6 && micro < 16))
p->dont_use_ppoll = TRUE;
}
#endif
p->rtsig = -1;
sigemptyset(&p->sigset_unblocked);
p->timer = (timer_t) -1;
p->timer_armed = FALSE;
#endif
p->n_pollfd_alloc = 32;
p->pollfd = pa_xnew(struct pollfd, p->n_pollfd_alloc);
p->pollfd2 = pa_xnew(struct pollfd, p->n_pollfd_alloc);
p->n_pollfd_used = 0;
memset(&p->next_elapse, 0, sizeof(p->next_elapse));
pa_zero(p->next_elapse);
p->timer_enabled = FALSE;
p->running = FALSE;
p->installed = FALSE;
p->scan_for_dead = FALSE;
p->rebuild_needed = FALSE;
p->quit = FALSE;
@ -160,53 +112,13 @@ pa_rtpoll *pa_rtpoll_new(void) {
PA_LLIST_HEAD_INIT(pa_rtpoll_item, p->items);
#ifdef DEBUG_TIMING
p->timestamp = pa_rtclock_usec();
p->timestamp = pa_rtclock_now();
p->slept = p->awake = 0;
#endif
return p;
}
void pa_rtpoll_install(pa_rtpoll *p) {
pa_assert(p);
pa_assert(!p->installed);
p->installed = TRUE;
#ifdef HAVE_PPOLL
# ifdef __linux__
if (p->dont_use_ppoll)
return;
# endif
if ((p->rtsig = pa_rtsig_get_for_thread()) < 0) {
pa_log_warn("Failed to reserve POSIX realtime signal.");
return;
}
pa_log_debug("Acquired POSIX realtime signal %s", pa_sig2str(p->rtsig));
{
sigset_t ss;
struct sigaction sa;
pa_assert_se(sigemptyset(&ss) == 0);
pa_assert_se(sigaddset(&ss, p->rtsig) == 0);
pa_assert_se(pthread_sigmask(SIG_BLOCK, &ss, &p->sigset_unblocked) == 0);
pa_assert_se(sigdelset(&p->sigset_unblocked, p->rtsig) == 0);
memset(&sa, 0, sizeof(sa));
sa.sa_handler = signal_handler_noop;
pa_assert_se(sigemptyset(&sa.sa_mask) == 0);
pa_assert_se(sigaction(p->rtsig, &sa, NULL) == 0);
/* We never reset the signal handler. Why should we? */
}
#endif
}
static void rtpoll_rebuild(pa_rtpoll *p) {
struct pollfd *e, *t;
@ -250,7 +162,6 @@ static void rtpoll_rebuild(pa_rtpoll *p) {
if (ra)
p->pollfd2 = pa_xrealloc(p->pollfd2, p->n_pollfd_alloc * sizeof(struct pollfd));
}
static void rtpoll_item_destroy(pa_rtpoll_item *i) {
@ -279,11 +190,6 @@ void pa_rtpoll_free(pa_rtpoll *p) {
pa_xfree(p->pollfd);
pa_xfree(p->pollfd2);
#ifdef HAVE_PPOLL
if (p->timer != (timer_t) -1)
timer_delete(p->timer);
#endif
pa_xfree(p);
}
@ -321,7 +227,6 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait) {
pa_assert(p);
pa_assert(!p->running);
pa_assert(p->installed);
p->running = TRUE;
@ -394,7 +299,7 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait) {
#ifdef DEBUG_TIMING
{
pa_usec_t now = pa_rtclock_usec();
pa_usec_t now = pa_rtclock_now();
p->awake = now - p->timestamp;
p->timestamp = now;
}
@ -402,26 +307,19 @@ int pa_rtpoll_run(pa_rtpoll *p, pa_bool_t wait) {
/* OK, now let's sleep */
#ifdef HAVE_PPOLL
#ifdef __linux__
if (!p->dont_use_ppoll)
#endif
{
struct timespec ts;
ts.tv_sec = timeout.tv_sec;
ts.tv_nsec = timeout.tv_usec * 1000;
r = ppoll(p->pollfd, p->n_pollfd_used, (!wait || p->quit || p->timer_enabled) ? &ts : NULL, p->rtsig < 0 ? NULL : &p->sigset_unblocked);
r = ppoll(p->pollfd, p->n_pollfd_used, (!wait || p->quit || p->timer_enabled) ? &ts : NULL, NULL);
}
#ifdef __linux__
else
#endif
#endif
#else
r = poll(p->pollfd, p->n_pollfd_used, (!wait || p->quit || p->timer_enabled) ? (int) ((timeout.tv_sec*1000) + (timeout.tv_usec / 1000)) : -1);
#endif
#ifdef DEBUG_TIMING
{
pa_usec_t now = pa_rtclock_usec();
pa_usec_t now = pa_rtclock_now();
p->slept = now - p->timestamp;
p->timestamp = now;
@ -472,73 +370,11 @@ finish:
return r < 0 ? r : !p->quit;
}
static void update_timer(pa_rtpoll *p) {
pa_assert(p);
#ifdef HAVE_PPOLL
#ifdef __linux__
if (p->dont_use_ppoll)
return;
#endif
if (p->timer == (timer_t) -1) {
struct sigevent se;
memset(&se, 0, sizeof(se));
se.sigev_notify = SIGEV_SIGNAL;
se.sigev_signo = p->rtsig;
if (timer_create(CLOCK_MONOTONIC, &se, &p->timer) < 0)
if (timer_create(CLOCK_REALTIME, &se, &p->timer) < 0) {
pa_log_warn("Failed to allocate POSIX timer: %s", pa_cstrerror(errno));
p->timer = (timer_t) -1;
}
}
if (p->timer != (timer_t) -1) {
struct itimerspec its;
struct timespec ts = { .tv_sec = 0, .tv_nsec = 0 };
sigset_t ss;
if (p->timer_armed) {
/* First disarm timer */
memset(&its, 0, sizeof(its));
pa_assert_se(timer_settime(p->timer, TIMER_ABSTIME, &its, NULL) == 0);
/* Remove a signal that might be waiting in the signal q */
pa_assert_se(sigemptyset(&ss) == 0);
pa_assert_se(sigaddset(&ss, p->rtsig) == 0);
sigtimedwait(&ss, NULL, &ts);
}
/* And install the new timer */
if (p->timer_enabled) {
memset(&its, 0, sizeof(its));
its.it_value.tv_sec = p->next_elapse.tv_sec;
its.it_value.tv_nsec = p->next_elapse.tv_usec*1000;
/* Make sure that 0,0 is not understood as
* "disarming" */
if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0)
its.it_value.tv_nsec = 1;
pa_assert_se(timer_settime(p->timer, TIMER_ABSTIME, &its, NULL) == 0);
}
p->timer_armed = p->timer_enabled;
}
#endif
}
void pa_rtpoll_set_timer_absolute(pa_rtpoll *p, pa_usec_t usec) {
pa_assert(p);
pa_timeval_store(&p->next_elapse, usec);
p->timer_enabled = TRUE;
update_timer(p);
}
void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
@ -550,8 +386,6 @@ void pa_rtpoll_set_timer_relative(pa_rtpoll *p, pa_usec_t usec) {
pa_rtclock_get(&p->next_elapse);
pa_timeval_add(&p->next_elapse, usec);
p->timer_enabled = TRUE;
update_timer(p);
}
void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) {
@ -559,8 +393,6 @@ void pa_rtpoll_set_timer_disabled(pa_rtpoll *p) {
memset(&p->next_elapse, 0, sizeof(p->next_elapse));
p->timer_enabled = FALSE;
update_timer(p);
}
pa_rtpoll_item *pa_rtpoll_item_new(pa_rtpoll *p, pa_rtpoll_priority_t prio, unsigned n_fds) {

View file

@ -62,9 +62,6 @@ typedef enum pa_rtpoll_priority {
pa_rtpoll *pa_rtpoll_new(void);
void pa_rtpoll_free(pa_rtpoll *p);
/* Install the rtpoll in the current thread */
void pa_rtpoll_install(pa_rtpoll *p);
/* Sleep on the rtpoll until the time event, or any of the fd events
* is triggered. If "wait" is 0 we don't sleep but only update the
* struct pollfd. Returns negative on error, positive if the loop

View file

@ -1,131 +0,0 @@
/***
This file is part of PulseAudio.
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.1 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
Lesser 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 HAVE_CONFIG_H
#include <config.h>
#endif
#include <signal.h>
#include <pulsecore/macro.h>
#include <pulsecore/flist.h>
#include <pulsecore/once.h>
#include <pulsecore/thread.h>
#include <pulsecore/core-util.h>
#include "rtsig.h"
#ifdef SIGRTMIN
static void _free_rtsig(void *p) {
pa_rtsig_put(PA_PTR_TO_INT(p));
}
PA_STATIC_FLIST_DECLARE(rtsig_flist, pa_make_power_of_two((unsigned) (SIGRTMAX-SIGRTMIN+1)), NULL);
PA_STATIC_TLS_DECLARE(rtsig_tls, _free_rtsig);
static pa_atomic_t rtsig_current = PA_ATOMIC_INIT(-1);
static int rtsig_start = -1, rtsig_end = -1;
int pa_rtsig_get(void) {
void *p;
int sig;
if ((p = pa_flist_pop(PA_STATIC_FLIST_GET(rtsig_flist))))
return PA_PTR_TO_INT(p);
sig = pa_atomic_dec(&rtsig_current);
pa_assert(sig <= SIGRTMAX);
pa_assert(sig <= rtsig_end);
if (sig < rtsig_start) {
pa_atomic_inc(&rtsig_current);
return -1;
}
return sig;
}
int pa_rtsig_get_for_thread(void) {
int sig;
void *p;
if ((p = PA_STATIC_TLS_GET(rtsig_tls)))
return PA_PTR_TO_INT(p);
if ((sig = pa_rtsig_get()) < 0)
return -1;
PA_STATIC_TLS_SET(rtsig_tls, PA_INT_TO_PTR(sig));
return sig;
}
void pa_rtsig_put(int sig) {
pa_assert(sig >= rtsig_start);
pa_assert(sig <= rtsig_end);
pa_assert_se(pa_flist_push(PA_STATIC_FLIST_GET(rtsig_flist), PA_INT_TO_PTR(sig)) >= 0);
}
void pa_rtsig_configure(int start, int end) {
int s;
sigset_t ss;
pa_assert(pa_atomic_load(&rtsig_current) == -1);
pa_assert(SIGRTMIN <= start);
pa_assert(start <= end);
pa_assert(end <= SIGRTMAX);
rtsig_start = start;
rtsig_end = end;
sigemptyset(&ss);
for (s = rtsig_start; s <= rtsig_end; s++)
pa_assert_se(sigaddset(&ss, s) == 0);
pa_assert(pthread_sigmask(SIG_BLOCK, &ss, NULL) == 0);
/* We allocate starting from the end */
pa_atomic_store(&rtsig_current, rtsig_end);
}
#else /* SIGRTMIN */
int pa_rtsig_get(void) {
return -1;
}
int pa_rtsig_get_for_thread(void) {
return -1;
}
void pa_rtsig_put(int sig) {
}
void pa_rtsig_configure(int start, int end) {
}
#endif /* SIGRTMIN */

View file

@ -1,39 +0,0 @@
#ifndef foopulsertsighfoo
#define foopulsertsighfoo
/***
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.1 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
Lesser 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.
***/
/* Return the next unused POSIX Realtime signals */
int pa_rtsig_get(void);
/* If not called before in the current thread, return the next unused
* rtsig, and install it in a TLS region and give it up automatically
* when the thread shuts down */
int pa_rtsig_get_for_thread(void);
/* Give an rtsig back. */
void pa_rtsig_put(int sig);
/* Block all RT signals */
void pa_rtsig_configure(int start, int end);
#endif

View file

@ -1182,7 +1182,7 @@ pa_memchunk* pa_silence_memchunk_get(pa_silence_cache *cache, pa_mempool *pool,
case PA_SAMPLE_S24LE:
case PA_SAMPLE_S24BE:
case PA_SAMPLE_S24_32LE:
case PA_SAMPLE_S24_32RE:
case PA_SAMPLE_S24_32BE:
case PA_SAMPLE_FLOAT32LE:
case PA_SAMPLE_FLOAT32BE:
cache->blocks[PA_SAMPLE_S16LE] = b = silence_memblock_new(pool, 0);

View file

@ -25,6 +25,7 @@
#include <pulse/sample.h>
#include <pulse/volume.h>
#include <pulse/channelmap.h>
#include <pulsecore/memblock.h>
#include <pulsecore/memchunk.h>
@ -85,4 +86,62 @@ void pa_memchunk_dump_to_file(pa_memchunk *c, const char *fn);
void pa_memchunk_sine(pa_memchunk *c, pa_mempool *pool, unsigned rate, unsigned freq);
#define PA_CHANNEL_POSITION_MASK_LEFT \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT)) \
#define PA_CHANNEL_POSITION_MASK_RIGHT \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT))
#define PA_CHANNEL_POSITION_MASK_CENTER \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER))
#define PA_CHANNEL_POSITION_MASK_FRONT \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER))
#define PA_CHANNEL_POSITION_MASK_REAR \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_REAR_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER))
#define PA_CHANNEL_POSITION_MASK_SIDE_OR_TOP_CENTER \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_SIDE_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER))
#define PA_CHANNEL_POSITION_MASK_TOP \
(PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_FRONT_CENTER) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_LEFT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_RIGHT) \
| PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_TOP_REAR_CENTER))
#define PA_CHANNEL_POSITION_MASK_ALL \
((pa_channel_position_mask_t) (PA_CHANNEL_POSITION_MASK(PA_CHANNEL_POSITION_MAX)-1))
#endif

View file

@ -442,7 +442,7 @@ void pa_sink_input_unlink(pa_sink_input *i) {
if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
pa_cvolume new_volume;
pa_sink_update_flat_volume(i->sink, &new_volume);
pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE);
}
if (i->sink->asyncmsgq)
@ -520,7 +520,7 @@ void pa_sink_input_put(pa_sink_input *i) {
if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
pa_cvolume new_volume;
pa_sink_update_flat_volume(i->sink, &new_volume);
pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE);
} else
pa_sink_input_set_relative_volume(i, &i->virtual_volume);
@ -900,7 +900,7 @@ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume, pa_boo
* volumes and update the flat volume of the sink */
pa_sink_update_flat_volume(i->sink, &new_volume);
pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE, FALSE);
pa_sink_set_volume(i->sink, &new_volume, FALSE, TRUE, FALSE, FALSE);
} else {
@ -1159,7 +1159,7 @@ int pa_sink_input_start_move(pa_sink_input *i) {
/* We might need to update the sink's volume if we are in flat
* volume mode. */
pa_sink_update_flat_volume(i->sink, &new_volume);
pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE);
}
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_START_MOVE, i, 0, NULL) == 0);
@ -1252,7 +1252,7 @@ int pa_sink_input_finish_move(pa_sink_input *i, pa_sink *dest, pa_bool_t save) {
/* We might need to update the sink's volume if we are in flat volume mode. */
pa_sink_update_flat_volume(i->sink, &new_volume);
pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE);
pa_sink_set_volume(i->sink, &new_volume, FALSE, FALSE, FALSE, FALSE);
}
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i->sink), PA_SINK_MESSAGE_FINISH_MOVE, i, 0, NULL) == 0);

View file

@ -100,11 +100,51 @@ void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute) {
data->muted = !!mute;
}
void pa_sink_new_data_set_port(pa_sink_new_data *data, const char *port) {
pa_assert(data);
pa_xfree(data->active_port);
data->active_port = pa_xstrdup(port);
}
void pa_sink_new_data_done(pa_sink_new_data *data) {
pa_assert(data);
pa_xfree(data->name);
pa_proplist_free(data->proplist);
if (data->ports) {
pa_device_port *p;
while ((p = pa_hashmap_steal_first(data->ports)))
pa_device_port_free(p);
pa_hashmap_free(data->ports, NULL, NULL);
}
pa_xfree(data->name);
pa_xfree(data->active_port);
}
pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra) {
pa_device_port *p;
pa_assert(name);
p = pa_xmalloc(PA_ALIGN(sizeof(pa_device_port)) + extra);
p->name = pa_xstrdup(name);
p->description = pa_xstrdup(description);
p->priority = 0;
return p;
}
void pa_device_port_free(pa_device_port *p) {
pa_assert(p);
pa_xfree(p->name);
pa_xfree(p->description);
pa_xfree(p);
}
/* Called from main context */
@ -118,6 +158,7 @@ static void reset_callbacks(pa_sink *s) {
s->set_mute = NULL;
s->request_rewind = NULL;
s->update_requested_latency = NULL;
s->set_port = NULL;
}
/* Called from main context */
@ -140,6 +181,7 @@ pa_sink* pa_sink_new(
s = pa_msgobject_new(pa_sink);
if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SINK, s, data->namereg_fail))) {
pa_log_debug("Failed to register name %s.", data->name);
pa_xfree(s);
return NULL;
}
@ -152,6 +194,8 @@ pa_sink* pa_sink_new(
return NULL;
}
/* FIXME, need to free s here on failure */
pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
@ -177,6 +221,7 @@ pa_sink* pa_sink_new(
pa_device_init_description(data->proplist);
pa_device_init_icon(data->proplist, TRUE);
pa_device_init_intended_roles(data->proplist);
if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_FIXATE], data) < 0) {
pa_xfree(s);
@ -190,6 +235,7 @@ pa_sink* pa_sink_new(
s->core = core;
s->state = PA_SINK_INIT;
s->flags = flags;
s->suspend_cause = 0;
s->name = pa_xstrdup(name);
s->proplist = pa_proplist_copy(data->proplist);
s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
@ -217,6 +263,30 @@ pa_sink* pa_sink_new(
s->asyncmsgq = NULL;
s->rtpoll = NULL;
/* As a minor optimization we just steal the list instead of
* copying it here */
s->ports = data->ports;
data->ports = NULL;
s->active_port = NULL;
s->save_port = FALSE;
if (data->active_port && s->ports)
if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
s->save_port = data->save_port;
if (!s->active_port && s->ports) {
void *state;
pa_device_port *p;
PA_HASHMAP_FOREACH(p, s->ports, state)
if (!s->active_port || p->priority > s->active_port->priority)
s->active_port = p;
}
s->save_volume = data->save_volume;
s->save_muted = data->save_muted;
pa_silence_memchunk_get(
&core->silence_cache,
core->mempool,
@ -465,6 +535,15 @@ static void sink_free(pa_object *o) {
if (s->proplist)
pa_proplist_free(s->proplist);
if (s->ports) {
pa_device_port *p;
while ((p = pa_hashmap_steal_first(s->ports)))
pa_device_port_free(p);
pa_hashmap_free(s->ports, NULL, NULL);
}
pa_xfree(s);
}
@ -483,6 +562,7 @@ void pa_sink_set_rtpoll(pa_sink *s, pa_rtpoll *p) {
pa_sink_assert_ref(s);
s->rtpoll = p;
if (s->monitor_source)
pa_source_set_rtpoll(s->monitor_source, p);
}
@ -499,26 +579,40 @@ int pa_sink_update_status(pa_sink*s) {
}
/* Called from main context */
int pa_sink_suspend(pa_sink *s, pa_bool_t suspend) {
int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
pa_assert(cause != 0);
if (suspend)
if (suspend) {
s->suspend_cause |= cause;
s->monitor_source->suspend_cause |= cause;
} else {
s->suspend_cause &= ~cause;
s->monitor_source->suspend_cause &= ~cause;
}
if ((pa_sink_get_state(s) == PA_SINK_SUSPENDED) == !!s->suspend_cause)
return 0;
pa_log_debug("Suspend cause of sink %s is 0x%04x, %s", s->name, s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
if (s->suspend_cause)
return sink_set_state(s, PA_SINK_SUSPENDED);
else
return sink_set_state(s, pa_sink_used_by(s) ? PA_SINK_RUNNING : PA_SINK_IDLE);
}
/* Called from main context */
pa_queue *pa_sink_move_all_start(pa_sink *s) {
pa_queue *q;
pa_queue *pa_sink_move_all_start(pa_sink *s, pa_queue *q) {
pa_sink_input *i, *n;
uint32_t idx;
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
q = pa_queue_new();
if (!q)
q = pa_queue_new();
for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = n) {
n = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx));
@ -958,21 +1052,21 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
n = fill_mix_info(s, &length1st, info, MAX_MIX_CHANNELS);
if (n == 0) {
pa_silence_memchunk_get(&s->core->silence_cache,
s->core->mempool,
result,
&s->sample_spec,
length1st);
pa_silence_memchunk_get(&s->core->silence_cache,
s->core->mempool,
result,
&s->sample_spec,
length1st);
} else if (n == 1) {
pa_cvolume volume;
pa_cvolume volume;
*result = info[0].chunk;
pa_memblock_ref(result->memblock);
*result = info[0].chunk;
pa_memblock_ref(result->memblock);
if (result->length > length)
result->length = length;
if (result->length > length)
result->length = length;
pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
pa_sw_cvolume_multiply(&volume, &s->thread_info.soft_volume, &info[0].volume);
if (s->thread_info.soft_muted || !pa_cvolume_is_norm(&volume)) {
if (s->thread_info.soft_muted || pa_cvolume_is_muted(&volume)) {
@ -990,10 +1084,10 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
} else {
void *ptr;
result->index = 0;
result->memblock = pa_memblock_new(s->core->mempool, length);
result->index = 0;
result->memblock = pa_memblock_new(s->core->mempool, length);
ptr = pa_memblock_acquire(result->memblock);
ptr = pa_memblock_acquire(result->memblock);
result->length = pa_mix(info, n,
(uint8_t*) ptr + result->index, length1st,
@ -1007,24 +1101,23 @@ void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
inputs_drop(s, info, n, result);
if (result->length < length) {
pa_memchunk chunk;
size_t l, d;
pa_memchunk_make_writable(result, length);
result->length = length;
pa_memchunk chunk;
size_t l, d;
pa_memchunk_make_writable(result, length);
l = length - result->length;
d = result->index + result->length;
while (l > 0) {
chunk = *result;
chunk.index += d;
chunk.length -= d - result->index;
l = length - result->length;
d = result->index + result->length;
while (l > 0) {
chunk = *result;
chunk.index = d;
chunk.length = l;
pa_sink_render_into(s, &chunk);
pa_sink_render_into(s, &chunk);
d += chunk.length;
l -= chunk.length;
}
result->length = length;
d += chunk.length;
l -= chunk.length;
}
result->length = length;
}
pa_sink_unref(s);
@ -1222,7 +1315,7 @@ void pa_sink_propagate_flat_volume(pa_sink *s) {
}
/* Called from main thread */
void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference) {
void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference, pa_bool_t save) {
pa_bool_t virtual_volume_changed;
pa_sink_assert_ref(s);
@ -1233,6 +1326,7 @@ void pa_sink_set_volume(pa_sink *s, const pa_cvolume *volume, pa_bool_t propagat
virtual_volume_changed = !pa_cvolume_equal(volume, &s->virtual_volume);
s->virtual_volume = *volume;
s->save_volume = (!virtual_volume_changed && s->save_volume) || save;
if (become_reference)
s->reference_volume = s->virtual_volume;
@ -1303,15 +1397,17 @@ const pa_cvolume *pa_sink_get_volume(pa_sink *s, pa_bool_t force_refresh, pa_boo
}
/* Called from main thread */
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume, pa_bool_t save) {
pa_sink_assert_ref(s);
/* The sink implementor may call this if the volume changed to make sure everyone is notified */
if (pa_cvolume_equal(&s->virtual_volume, new_volume))
if (pa_cvolume_equal(&s->virtual_volume, new_volume)) {
s->save_volume = s->save_volume || save;
return;
}
s->reference_volume = s->virtual_volume = *new_volume;
s->save_volume = save;
if (s->flags & PA_SINK_FLAT_VOLUME)
pa_sink_propagate_flat_volume(s);
@ -1320,7 +1416,7 @@ void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume) {
}
/* Called from main thread */
void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
void pa_sink_set_mute(pa_sink *s, pa_bool_t mute, pa_bool_t save) {
pa_bool_t old_muted;
pa_sink_assert_ref(s);
@ -1328,6 +1424,7 @@ void pa_sink_set_mute(pa_sink *s, pa_bool_t mute) {
old_muted = s->muted;
s->muted = mute;
s->save_muted = (old_muted == s->muted && s->save_muted) || save;
if (s->set_mute)
s->set_mute(s);
@ -1351,23 +1448,31 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
if (old_muted != s->muted)
if (old_muted != s->muted) {
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
/* Make sure the soft mute status stays in sync */
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
}
}
return s->muted;
}
/* Called from main thread */
void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted) {
void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted, pa_bool_t save) {
pa_sink_assert_ref(s);
/* The sink implementor may call this if the volume changed to make sure everyone is notified */
if (s->muted == new_muted)
if (s->muted == new_muted) {
s->save_muted = s->save_muted || save;
return;
}
s->muted = new_muted;
s->save_muted = save;
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
@ -1465,7 +1570,7 @@ unsigned pa_sink_check_suspend(pa_sink *s) {
ret = 0;
for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx))) {
PA_IDXSET_FOREACH(i, s->inputs, idx) {
pa_sink_input_state_t st;
st = pa_sink_input_get_state(i);
@ -1823,17 +1928,18 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
}
/* Called from main thread */
int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend) {
int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
pa_sink *sink;
uint32_t idx;
int ret = 0;
pa_core_assert_ref(c);
pa_assert(cause != 0);
for (sink = PA_SINK(pa_idxset_first(c->sinks, &idx)); sink; sink = PA_SINK(pa_idxset_next(c->sinks, &idx))) {
int r;
if ((r = pa_sink_suspend(sink, suspend)) < 0)
if ((r = pa_sink_suspend(sink, suspend, cause)) < 0)
ret = r;
}
@ -2174,6 +2280,41 @@ size_t pa_sink_get_max_request(pa_sink *s) {
return r;
}
/* Called from main context */
int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save) {
pa_device_port *port;
pa_assert(s);
if (!s->set_port) {
pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
return -PA_ERR_NOTIMPLEMENTED;
}
if (!s->ports)
return -PA_ERR_NOENTITY;
if (!(port = pa_hashmap_get(s->ports, name)))
return -PA_ERR_NOENTITY;
if (s->active_port == port) {
s->save_port = s->save_port || save;
return 0;
}
if ((s->set_port(s, port)) < 0)
return -PA_ERR_NOENTITY;
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
pa_log_info("Changed port of sink %u \"%s\" to %s", s->index, s->name, port->name);
s->active_port = port;
s->save_port = save;
return 0;
}
/* Called from main context */
pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
const char *ff, *c, *t = NULL, *s = "", *profile, *bus;
@ -2243,28 +2384,49 @@ pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink) {
}
pa_bool_t pa_device_init_description(pa_proplist *p) {
const char *s;
const char *s, *d = NULL, *k;
pa_assert(p);
if (pa_proplist_contains(p, PA_PROP_DEVICE_DESCRIPTION))
return TRUE;
if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
if (pa_streq(s, "internal")) {
pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Internal Audio"));
return TRUE;
}
if (pa_streq(s, "internal"))
d = _("Internal Audio");
if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
if (pa_streq(s, "modem")) {
pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, _("Modem"));
return TRUE;
}
if (!d)
if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_CLASS)))
if (pa_streq(s, "modem"))
d = _("Modem");
if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME))) {
pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, s);
if (!d)
d = pa_proplist_gets(p, PA_PROP_DEVICE_PRODUCT_NAME);
if (!d)
return FALSE;
k = pa_proplist_gets(p, PA_PROP_DEVICE_PROFILE_DESCRIPTION);
if (d && k)
pa_proplist_setf(p, PA_PROP_DEVICE_DESCRIPTION, _("%s %s"), d, k);
else if (d)
pa_proplist_sets(p, PA_PROP_DEVICE_DESCRIPTION, d);
return TRUE;
}
pa_bool_t pa_device_init_intended_roles(pa_proplist *p) {
const char *s;
pa_assert(p);
if (pa_proplist_contains(p, PA_PROP_DEVICE_INTENDED_ROLES))
return TRUE;
}
if ((s = pa_proplist_gets(p, PA_PROP_DEVICE_FORM_FACTOR)))
if (pa_streq(s, "handset") || pa_streq(s, "hands-free")) {
pa_proplist_sets(p, PA_PROP_DEVICE_INTENDED_ROLES, "phone");
return TRUE;
}
return FALSE;
}

View file

@ -24,6 +24,7 @@
***/
typedef struct pa_sink pa_sink;
typedef struct pa_device_port pa_device_port;
#include <inttypes.h>
@ -49,13 +50,26 @@ static inline pa_bool_t PA_SINK_IS_LINKED(pa_sink_state_t x) {
return x == PA_SINK_RUNNING || x == PA_SINK_IDLE || x == PA_SINK_SUSPENDED;
}
struct pa_device_port {
char *name;
char *description;
unsigned priority;
/* .. followed by some implementation specific data */
};
#define PA_DEVICE_PORT_DATA(d) ((void*) ((uint8_t*) d + PA_ALIGN(sizeof(pa_device_port))))
struct pa_sink {
pa_msgobject parent;
uint32_t index;
pa_core *core;
pa_sink_state_t state;
pa_sink_flags_t flags;
pa_suspend_cause_t suspend_cause;
char *name;
char *driver; /* may be NULL */
@ -82,6 +96,9 @@ struct pa_sink {
pa_bool_t refresh_volume:1;
pa_bool_t refresh_muted:1;
pa_bool_t save_port:1;
pa_bool_t save_volume:1;
pa_bool_t save_muted:1;
pa_asyncmsgq *asyncmsgq;
pa_rtpoll *rtpoll;
@ -90,6 +107,9 @@ struct pa_sink {
pa_usec_t fixed_latency; /* for sinks with PA_SINK_DYNAMIC_LATENCY this is 0 */
pa_hashmap *ports;
pa_device_port *active_port;
/* Called when the main loop requests a state change. Called from
* main loop context. If returns -1 the state change will be
* inhibited */
@ -125,6 +145,10 @@ struct pa_sink {
* thread context. */
void (*update_requested_latency)(pa_sink *s); /* dito */
/* Called whenever the port shall be changed. Called from main
* thread. */
int (*set_port)(pa_sink *s, pa_device_port *port); /* dito */
/* Contains copies of the above data so that the real-time worker
* thread can work without access locking */
struct {
@ -191,6 +215,9 @@ typedef struct pa_sink_new_data {
pa_module *module;
pa_card *card;
pa_hashmap *ports;
char *active_port;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
pa_cvolume volume;
@ -202,6 +229,10 @@ typedef struct pa_sink_new_data {
pa_bool_t muted_is_set:1;
pa_bool_t namereg_fail:1;
pa_bool_t save_port:1;
pa_bool_t save_volume:1;
pa_bool_t save_muted:1;
} pa_sink_new_data;
pa_sink_new_data* pa_sink_new_data_init(pa_sink_new_data *data);
@ -210,6 +241,7 @@ void pa_sink_new_data_set_sample_spec(pa_sink_new_data *data, const pa_sample_sp
void pa_sink_new_data_set_channel_map(pa_sink_new_data *data, const pa_channel_map *map);
void pa_sink_new_data_set_volume(pa_sink_new_data *data, const pa_cvolume *volume);
void pa_sink_new_data_set_muted(pa_sink_new_data *data, pa_bool_t mute);
void pa_sink_new_data_set_port(pa_sink_new_data *data, const char *port);
void pa_sink_new_data_done(pa_sink_new_data *data);
/*** To be called exclusively by the sink driver, from main context */
@ -235,11 +267,12 @@ void pa_sink_detach(pa_sink *s);
void pa_sink_attach(pa_sink *s);
void pa_sink_set_soft_volume(pa_sink *s, const pa_cvolume *volume);
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume);
void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted);
void pa_sink_volume_changed(pa_sink *s, const pa_cvolume *new_volume, pa_bool_t save);
void pa_sink_mute_changed(pa_sink *s, pa_bool_t new_muted, pa_bool_t save);
pa_bool_t pa_device_init_description(pa_proplist *p);
pa_bool_t pa_device_init_icon(pa_proplist *p, pa_bool_t is_sink);
pa_bool_t pa_device_init_intended_roles(pa_proplist *p);
/**** May be called by everyone, from main context */
@ -252,27 +285,29 @@ size_t pa_sink_get_max_rewind(pa_sink *s);
size_t pa_sink_get_max_request(pa_sink *s);
int pa_sink_update_status(pa_sink*s);
int pa_sink_suspend(pa_sink *s, pa_bool_t suspend);
int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend);
int pa_sink_suspend(pa_sink *s, pa_bool_t suspend, pa_suspend_cause_t cause);
int pa_sink_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause);
void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume);
void pa_sink_propagate_flat_volume(pa_sink *s);
void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference);
void pa_sink_set_volume(pa_sink *sink, const pa_cvolume *volume, pa_bool_t propagate, pa_bool_t sendmsg, pa_bool_t become_reference, pa_bool_t save);
const pa_cvolume *pa_sink_get_volume(pa_sink *sink, pa_bool_t force_refresh, pa_bool_t reference);
void pa_sink_set_mute(pa_sink *sink, pa_bool_t mute);
void pa_sink_set_mute(pa_sink *sink, pa_bool_t mute, pa_bool_t save);
pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refresh);
pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p);
int pa_sink_set_port(pa_sink *s, const char *name, pa_bool_t save);
unsigned pa_sink_linked_by(pa_sink *s); /* Number of connected streams */
unsigned pa_sink_used_by(pa_sink *s); /* Number of connected streams which are not corked */
unsigned pa_sink_check_suspend(pa_sink *s); /* Returns how many streams are active that don't allow suspensions */
#define pa_sink_get_state(s) ((s)->state)
/* Moves all inputs away, and stores them in pa_queue */
pa_queue *pa_sink_move_all_start(pa_sink *s);
pa_queue *pa_sink_move_all_start(pa_sink *s, pa_queue *q);
void pa_sink_move_all_finish(pa_sink *s, pa_queue *q, pa_bool_t save);
void pa_sink_move_all_fail(pa_queue *q);
@ -305,4 +340,7 @@ void pa_sink_invalidate_requested_latency(pa_sink *s);
pa_usec_t pa_sink_get_latency_within_thread(pa_sink *s);
pa_device_port *pa_device_port_new(const char *name, const char *description, size_t extra);
void pa_device_port_free(pa_device_port *p);
#endif

View file

@ -113,7 +113,7 @@ int pa_sndfile_write_sample_spec(SF_INFO *sfi, pa_sample_spec *ss) {
break;
case PA_SAMPLE_S32LE:
case PA_SAMPLE_S32RE:
case PA_SAMPLE_S32BE:
ss->format = PA_SAMPLE_S32NE;
sfi->format |= SF_FORMAT_PCM_32;
break;

View file

@ -52,12 +52,14 @@
#include <asyncns.h>
#endif
#include <pulse/rtclock.h>
#include <pulse/timeval.h>
#include <pulse/xmalloc.h>
#include <pulsecore/winsock.h>
#include <pulsecore/core-error.h>
#include <pulsecore/socket-util.h>
#include <pulsecore/core-rtclock.h>
#include <pulsecore/core-util.h>
#include <pulsecore/socket-util.h>
#include <pulsecore/log.h>
@ -420,12 +422,11 @@ fail:
#endif
static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *tv, void *userdata) {
static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeval *t, void *userdata) {
pa_socket_client *c = userdata;
pa_assert(m);
pa_assert(e);
pa_assert(tv);
pa_assert(c);
if (c->fd >= 0) {
@ -437,17 +438,16 @@ static void timeout_cb(pa_mainloop_api *m, pa_time_event *e, const struct timeva
do_call(c);
}
static void start_timeout(pa_socket_client *c) {
static void start_timeout(pa_socket_client *c, pa_bool_t use_rtclock) {
struct timeval tv;
pa_assert(c);
pa_assert(!c->timeout_event);
pa_gettimeofday(&tv);
pa_timeval_add(&tv, CONNECT_TIMEOUT * PA_USEC_PER_SEC);
c->timeout_event = c->mainloop->time_new(c->mainloop, &tv, timeout_cb, c);
c->timeout_event = c->mainloop->time_new(c->mainloop, pa_timeval_rtstore(&tv, pa_rtclock_now() + CONNECT_TIMEOUT * PA_USEC_PER_SEC, use_rtclock), timeout_cb, c);
}
pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*name, uint16_t default_port) {
pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, pa_bool_t use_rtclock, const char*name, uint16_t default_port) {
pa_socket_client *c = NULL;
pa_parsed_address a;
@ -463,7 +463,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam
switch (a.type) {
case PA_PARSED_ADDRESS_UNIX:
if ((c = pa_socket_client_new_unix(m, a.path_or_host)))
start_timeout(c);
start_timeout(c, use_rtclock);
break;
case PA_PARSED_ADDRESS_TCP4: /* Fallthrough */
@ -499,7 +499,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam
c->asyncns_io_event = m->io_new(m, asyncns_fd(c->asyncns), PA_IO_EVENT_INPUT, asyncns_cb, c);
c->asyncns_query = asyncns_getaddrinfo(c->asyncns, a.path_or_host, port, &hints);
pa_assert(c->asyncns_query);
start_timeout(c);
start_timeout(c, use_rtclock);
}
#elif defined(HAVE_GETADDRINFO)
{
@ -513,7 +513,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam
if (res->ai_addr) {
if ((c = pa_socket_client_new_sockaddr(m, res->ai_addr, res->ai_addrlen)))
start_timeout(c);
start_timeout(c, use_rtclock);
}
freeaddrinfo(res);
@ -546,7 +546,7 @@ pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char*nam
s.sin_port = htons(a.port);
if ((c = pa_socket_client_new_sockaddr(m, (struct sockaddr*)&s, sizeof(s))))
start_timeout(c);
start_timeout(c, use_rtclock);
}
#endif /* HAVE_LIBASYNCNS */
}

View file

@ -40,7 +40,7 @@ pa_socket_client* pa_socket_client_new_ipv6(pa_mainloop_api *m, uint8_t address[
#endif
pa_socket_client* pa_socket_client_new_unix(pa_mainloop_api *m, const char *filename);
pa_socket_client* pa_socket_client_new_sockaddr(pa_mainloop_api *m, const struct sockaddr *sa, size_t salen);
pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, const char *a, uint16_t default_port);
pa_socket_client* pa_socket_client_new_string(pa_mainloop_api *m, pa_bool_t use_rtclock, const char *a, uint16_t default_port);
pa_socket_client* pa_socket_client_ref(pa_socket_client *c);
void pa_socket_client_unref(pa_socket_client *c);

View file

@ -93,11 +93,29 @@ void pa_source_new_data_set_muted(pa_source_new_data *data, pa_bool_t mute) {
data->muted = !!mute;
}
void pa_source_new_data_set_port(pa_source_new_data *data, const char *port) {
pa_assert(data);
pa_xfree(data->active_port);
data->active_port = pa_xstrdup(port);
}
void pa_source_new_data_done(pa_source_new_data *data) {
pa_assert(data);
pa_xfree(data->name);
pa_proplist_free(data->proplist);
if (data->ports) {
pa_device_port *p;
while ((p = pa_hashmap_steal_first(data->ports)))
pa_device_port_free(p);
pa_hashmap_free(data->ports, NULL, NULL);
}
pa_xfree(data->name);
pa_xfree(data->active_port);
}
/* Called from main context */
@ -110,6 +128,7 @@ static void reset_callbacks(pa_source *s) {
s->get_mute = NULL;
s->set_mute = NULL;
s->update_requested_latency = NULL;
s->set_port = NULL;
}
/* Called from main context */
@ -130,6 +149,7 @@ pa_source* pa_source_new(
s = pa_msgobject_new(pa_source);
if (!(name = pa_namereg_register(core, data->name, PA_NAMEREG_SOURCE, s, data->namereg_fail))) {
pa_log_debug("Failed to register name %s.", data->name);
pa_xfree(s);
return NULL;
}
@ -142,6 +162,8 @@ pa_source* pa_source_new(
return NULL;
}
/* FIXME, need to free s here on failure */
pa_return_null_if_fail(!data->driver || pa_utf8_valid(data->driver));
pa_return_null_if_fail(data->name && pa_utf8_valid(data->name) && data->name[0]);
@ -167,6 +189,7 @@ pa_source* pa_source_new(
pa_device_init_description(data->proplist);
pa_device_init_icon(data->proplist, FALSE);
pa_device_init_intended_roles(data->proplist);
if (pa_hook_fire(&core->hooks[PA_CORE_HOOK_SOURCE_FIXATE], data) < 0) {
pa_xfree(s);
@ -180,6 +203,7 @@ pa_source* pa_source_new(
s->core = core;
s->state = PA_SOURCE_INIT;
s->flags = flags;
s->suspend_cause = 0;
s->name = pa_xstrdup(name);
s->proplist = pa_proplist_copy(data->proplist);
s->driver = pa_xstrdup(pa_path_get_filename(data->driver));
@ -208,6 +232,30 @@ pa_source* pa_source_new(
s->asyncmsgq = NULL;
s->rtpoll = NULL;
/* As a minor optimization we just steal the list instead of
* copying it here */
s->ports = data->ports;
data->ports = NULL;
s->active_port = NULL;
s->save_port = FALSE;
if (data->active_port && s->ports)
if ((s->active_port = pa_hashmap_get(s->ports, data->active_port)))
s->save_port = data->save_port;
if (!s->active_port && s->ports) {
void *state;
pa_device_port *p;
PA_HASHMAP_FOREACH(p, s->ports, state)
if (!s->active_port || p->priority > s->active_port->priority)
s->active_port = p;
}
s->save_volume = data->save_volume;
s->save_muted = data->save_muted;
pa_silence_memchunk_get(
&core->silence_cache,
core->mempool,
@ -398,6 +446,15 @@ static void source_free(pa_object *o) {
if (s->proplist)
pa_proplist_free(s->proplist);
if (s->ports) {
pa_device_port *p;
while ((p = pa_hashmap_steal_first(s->ports)))
pa_device_port_free(p);
pa_hashmap_free(s->ports, NULL, NULL);
}
pa_xfree(s);
}
@ -427,13 +484,24 @@ int pa_source_update_status(pa_source*s) {
}
/* Called from main context */
int pa_source_suspend(pa_source *s, pa_bool_t suspend) {
int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause) {
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
pa_assert(cause != 0);
if (s->monitor_of)
return -PA_ERR_NOTSUPPORTED;
if (suspend)
s->suspend_cause |= cause;
else
s->suspend_cause &= ~cause;
if ((pa_source_get_state(s) == PA_SOURCE_SUSPENDED) == !!s->suspend_cause)
return 0;
pa_log_debug("Suspend cause of source %s is 0x%04x, %s", s->name, s->suspend_cause, s->suspend_cause ? "suspending" : "resuming");
if (suspend)
return source_set_state(s, PA_SOURCE_SUSPENDED);
else
@ -459,15 +527,15 @@ int pa_source_sync_suspend(pa_source *s) {
}
/* Called from main context */
pa_queue *pa_source_move_all_start(pa_source *s) {
pa_queue *q;
pa_queue *pa_source_move_all_start(pa_source *s, pa_queue *q) {
pa_source_output *o, *n;
uint32_t idx;
pa_source_assert_ref(s);
pa_assert(PA_SOURCE_IS_LINKED(s->state));
q = pa_queue_new();
if (!q)
q = pa_queue_new();
for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = n) {
n = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx));
@ -654,7 +722,7 @@ pa_usec_t pa_source_get_latency_within_thread(pa_source *s) {
}
/* Called from main thread */
void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
void pa_source_set_volume(pa_source *s, const pa_cvolume *volume, pa_bool_t save) {
pa_cvolume old_virtual_volume;
pa_bool_t virtual_volume_changed;
@ -667,6 +735,7 @@ void pa_source_set_volume(pa_source *s, const pa_cvolume *volume) {
old_virtual_volume = s->virtual_volume;
s->virtual_volume = *volume;
virtual_volume_changed = !pa_cvolume_equal(&old_virtual_volume, &s->virtual_volume);
s->save_volume = (!virtual_volume_changed && s->save_volume) || save;
if (s->set_volume) {
pa_cvolume_reset(&s->soft_volume, s->sample_spec.channels);
@ -712,20 +781,24 @@ const pa_cvolume *pa_source_get_volume(pa_source *s, pa_bool_t force_refresh) {
}
/* Called from main thread */
void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume) {
void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume, pa_bool_t save) {
pa_source_assert_ref(s);
/* The source implementor may call this if the volume changed to make sure everyone is notified */
if (pa_cvolume_equal(&s->virtual_volume, new_volume))
if (pa_cvolume_equal(&s->virtual_volume, new_volume)) {
s->save_volume = s->save_volume || save;
return;
}
s->virtual_volume = *new_volume;
s->save_volume = save;
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
/* Called from main thread */
void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
void pa_source_set_mute(pa_source *s, pa_bool_t mute, pa_bool_t save) {
pa_bool_t old_muted;
pa_source_assert_ref(s);
@ -733,6 +806,7 @@ void pa_source_set_mute(pa_source *s, pa_bool_t mute) {
old_muted = s->muted;
s->muted = mute;
s->save_muted = (old_muted == s->muted && s->save_muted) || save;
if (s->set_mute)
s->set_mute(s);
@ -756,23 +830,31 @@ pa_bool_t pa_source_get_mute(pa_source *s, pa_bool_t force_refresh) {
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_GET_MUTE, NULL, 0, NULL) == 0);
if (old_muted != s->muted)
if (old_muted != s->muted) {
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
/* Make sure the soft mute status stays in sync */
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SOURCE_MESSAGE_SET_MUTE, NULL, 0, NULL) == 0);
}
}
return s->muted;
}
/* Called from main thread */
void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted) {
void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted, pa_bool_t save) {
pa_source_assert_ref(s);
/* The source implementor may call this if the mute state changed to make sure everyone is notified */
if (s->muted == new_muted)
if (s->muted == new_muted) {
s->save_muted = s->save_muted || save;
return;
}
s->muted = new_muted;
s->save_muted = save;
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
}
@ -849,7 +931,7 @@ unsigned pa_source_check_suspend(pa_source *s) {
ret = 0;
for (o = PA_SOURCE_OUTPUT(pa_idxset_first(s->outputs, &idx)); o; o = PA_SOURCE_OUTPUT(pa_idxset_next(s->outputs, &idx))) {
PA_IDXSET_FOREACH(o, s->outputs, idx) {
pa_source_output_state_t st;
st = pa_source_output_get_state(o);
@ -1032,12 +1114,13 @@ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_
}
/* Called from main thread */
int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause) {
uint32_t idx;
pa_source *source;
int ret = 0;
pa_core_assert_ref(c);
pa_assert(cause != 0);
for (source = PA_SOURCE(pa_idxset_first(c->sources, &idx)); source; source = PA_SOURCE(pa_idxset_next(c->sources, &idx))) {
int r;
@ -1045,7 +1128,7 @@ int pa_source_suspend_all(pa_core *c, pa_bool_t suspend) {
if (source->monitor_of)
continue;
if ((r = pa_source_suspend(source, suspend)) < 0)
if ((r = pa_source_suspend(source, suspend, cause)) < 0)
ret = r;
}
@ -1305,3 +1388,38 @@ size_t pa_source_get_max_rewind(pa_source *s) {
return r;
}
/* Called from main context */
int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save) {
pa_device_port *port;
pa_assert(s);
if (!s->set_port) {
pa_log_debug("set_port() operation not implemented for sink %u \"%s\"", s->index, s->name);
return -PA_ERR_NOTIMPLEMENTED;
}
if (!s->ports)
return -PA_ERR_NOENTITY;
if (!(port = pa_hashmap_get(s->ports, name)))
return -PA_ERR_NOENTITY;
if (s->active_port == port) {
s->save_port = s->save_port || save;
return 0;
}
if ((s->set_port(s, port)) < 0)
return -PA_ERR_NOENTITY;
pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
pa_log_info("Changed port of source %u \"%s\" to %s", s->index, s->name, port->name);
s->active_port = port;
s->save_port = save;
return 0;
}

View file

@ -56,8 +56,10 @@ struct pa_source {
uint32_t index;
pa_core *core;
pa_source_state_t state;
pa_source_flags_t flags;
pa_suspend_cause_t suspend_cause;
char *name;
char *driver; /* may be NULL */
@ -82,6 +84,10 @@ struct pa_source {
pa_bool_t refresh_volume:1;
pa_bool_t refresh_muted:1;
pa_bool_t save_port:1;
pa_bool_t save_volume:1;
pa_bool_t save_muted:1;
pa_asyncmsgq *asyncmsgq;
pa_rtpoll *rtpoll;
@ -89,6 +95,9 @@ struct pa_source {
pa_usec_t fixed_latency; /* for sources with PA_SOURCE_DYNAMIC_LATENCY this is 0 */
pa_hashmap *ports;
pa_device_port *active_port;
/* Called when the main loop requests a state change. Called from
* main loop context. If returns -1 the state change will be
* inhibited */
@ -120,6 +129,10 @@ struct pa_source {
* thread context. */
void (*update_requested_latency)(pa_source *s); /* dito */
/* Called whenever the port shall be changed. Called from main
* thread. */
int (*set_port)(pa_source *s, pa_device_port *port); /*dito */
/* Contains copies of the above data so that the real-time worker
* thread can work without access locking */
struct {
@ -173,6 +186,9 @@ typedef struct pa_source_new_data {
pa_module *module;
pa_card *card;
pa_hashmap *ports;
char *active_port;
pa_sample_spec sample_spec;
pa_channel_map channel_map;
pa_cvolume volume;
@ -184,6 +200,10 @@ typedef struct pa_source_new_data {
pa_bool_t channel_map_is_set:1;
pa_bool_t namereg_fail:1;
pa_bool_t save_port:1;
pa_bool_t save_volume:1;
pa_bool_t save_muted:1;
} pa_source_new_data;
pa_source_new_data* pa_source_new_data_init(pa_source_new_data *data);
@ -192,6 +212,7 @@ void pa_source_new_data_set_sample_spec(pa_source_new_data *data, const pa_sampl
void pa_source_new_data_set_channel_map(pa_source_new_data *data, const pa_channel_map *map);
void pa_source_new_data_set_volume(pa_source_new_data *data, const pa_cvolume *volume);
void pa_source_new_data_set_muted(pa_source_new_data *data, pa_bool_t mute);
void pa_source_new_data_set_port(pa_source_new_data *data, const char *port);
void pa_source_new_data_done(pa_source_new_data *data);
/*** To be called exclusively by the source driver, from main context */
@ -216,8 +237,8 @@ void pa_source_detach(pa_source *s);
void pa_source_attach(pa_source *s);
void pa_source_set_soft_volume(pa_source *s, const pa_cvolume *volume);
void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume);
void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted);
void pa_source_volume_changed(pa_source *s, const pa_cvolume *new_volume, pa_bool_t save);
void pa_source_mute_changed(pa_source *s, pa_bool_t new_muted, pa_bool_t save);
int pa_source_sync_suspend(pa_source *s);
@ -231,23 +252,25 @@ void pa_source_get_latency_range(pa_source *s, pa_usec_t *min_latency, pa_usec_t
size_t pa_source_get_max_rewind(pa_source *s);
int pa_source_update_status(pa_source*s);
int pa_source_suspend(pa_source *s, pa_bool_t suspend);
int pa_source_suspend_all(pa_core *c, pa_bool_t suspend);
int pa_source_suspend(pa_source *s, pa_bool_t suspend, pa_suspend_cause_t cause);
int pa_source_suspend_all(pa_core *c, pa_bool_t suspend, pa_suspend_cause_t cause);
void pa_source_set_volume(pa_source *source, const pa_cvolume *volume);
void pa_source_set_volume(pa_source *source, const pa_cvolume *volume, pa_bool_t save);
const pa_cvolume *pa_source_get_volume(pa_source *source, pa_bool_t force_refresh);
void pa_source_set_mute(pa_source *source, pa_bool_t mute);
void pa_source_set_mute(pa_source *source, pa_bool_t mute, pa_bool_t save);
pa_bool_t pa_source_get_mute(pa_source *source, pa_bool_t force_refresh);
pa_bool_t pa_source_update_proplist(pa_source *s, pa_update_mode_t mode, pa_proplist *p);
int pa_source_set_port(pa_source *s, const char *name, pa_bool_t save);
unsigned pa_source_linked_by(pa_source *s); /* Number of connected streams */
unsigned pa_source_used_by(pa_source *s); /* Number of connected streams that are not corked */
unsigned pa_source_check_suspend(pa_source *s); /* Returns how many streams are active that don't allow suspensions */
#define pa_source_get_state(s) ((pa_source_state_t) (s)->state)
/* Moves all inputs away, and stores them in pa_queue */
pa_queue *pa_source_move_all_start(pa_source *s);
pa_queue *pa_source_move_all_start(pa_source *s, pa_queue *q);
void pa_source_move_all_finish(pa_source *s, pa_queue *q, pa_bool_t save);
void pa_source_move_all_fail(pa_queue *q);