mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-11 13:30:02 -05:00
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:
commit
0bc538b08c
207 changed files with 33341 additions and 18718 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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]);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
189
src/pulsecore/rtkit.c
Normal 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
62
src/pulsecore/rtkit.h
Normal 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
|
||||
|
|
@ -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, µ) != 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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue