From adc2973c8dfab862d4333e0c1206995cd2df20c6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Sun, 26 Oct 2008 19:32:04 +0100 Subject: Implement new flags DONT_INHIBIT_AUTO_SUSPEND and START_UNMUTED --- PROTOCOL | 11 ++++++++++ configure.ac | 2 +- src/modules/module-suspend-on-idle.c | 20 ++++++++--------- src/modules/rtp/module-rtp-send.c | 2 +- src/pulse/def.h | 20 +++++++++++++++-- src/pulse/stream.c | 12 ++++++++++- src/pulsecore/protocol-native.c | 42 ++++++++++++++++++++++++++++++------ src/pulsecore/sink-input.h | 3 ++- src/pulsecore/sink.c | 34 ++++++++++++++++++++++++++++- src/pulsecore/sink.h | 1 + src/pulsecore/source-output.h | 3 ++- src/pulsecore/source.c | 29 +++++++++++++++++++++++++ src/pulsecore/source.h | 1 + 13 files changed, 156 insertions(+), 24 deletions(-) diff --git a/PROTOCOL b/PROTOCOL index 1e2a832f..80a0c331 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -153,3 +153,14 @@ New field for PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR, PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR at the end: early_requests (bool) + + +### v15, implemented by >= 0.9.14 + +PA_COMMAND_CREATE_PLAYBACK_STREAM + + bool muted at the end + +PA_COMMAND_CREATE_PLAYBACK_STREAM, PA_COMMAND_CREATE_RECORD_STREAM: + + bool dont_inhibit_auto_suspend ate the end diff --git a/configure.ac b/configure.ac index 955ee3b8..c5930c01 100644 --- a/configure.ac +++ b/configure.ac @@ -37,7 +37,7 @@ AC_SUBST(PA_MAJORMINORMICRO, PA_MAJOR.PA_MINOR.PA_MICRO) AC_SUBST(PACKAGE_URL, [http://pulseaudio.org/]) AC_SUBST(PA_API_VERSION, 12) -AC_SUBST(PA_PROTOCOL_VERSION, 14) +AC_SUBST(PA_PROTOCOL_VERSION, 15) # The stable ABI for client applications, for the version info x:y:z # always will hold y=z diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c index 6cc28ec5..8ab84e08 100644 --- a/src/modules/module-suspend-on-idle.c +++ b/src/modules/module-suspend-on-idle.c @@ -83,12 +83,12 @@ static void timeout_cb(pa_mainloop_api*a, pa_time_event* e, const struct timeval d->userdata->core->mainloop->time_restart(d->time_event, NULL); - if (d->sink && pa_sink_used_by(d->sink) <= 0 && pa_sink_get_state(d->sink) != PA_SINK_SUSPENDED) { + if (d->sink && pa_sink_check_suspend(d->sink) <= 0 && pa_sink_get_state(d->sink) != PA_SINK_SUSPENDED) { pa_log_info("Sink %s idle for too long, suspending ...", d->sink->name); pa_sink_suspend(d->sink, TRUE); } - if (d->source && pa_source_used_by(d->source) <= 0 && pa_source_get_state(d->source) != PA_SOURCE_SUSPENDED) { + if (d->source && pa_source_check_suspend(d->source) <= 0 && pa_source_get_state(d->source) != PA_SOURCE_SUSPENDED) { pa_log_info("Source %s idle for too long, suspending ...", d->source->name); pa_source_suspend(d->source, TRUE); } @@ -158,7 +158,7 @@ static pa_hook_result_t sink_input_unlink_hook_cb(pa_core *c, pa_sink_input *s, pa_sink_input_assert_ref(s); pa_assert(u); - if (pa_sink_used_by(s->sink) <= 0) { + if (pa_sink_check_suspend(s->sink) <= 0) { struct device_info *d; if ((d = pa_hashmap_get(u->device_infos, s->sink))) restart(d); @@ -172,7 +172,7 @@ static pa_hook_result_t source_output_unlink_hook_cb(pa_core *c, pa_source_outpu pa_source_output_assert_ref(s); pa_assert(u); - if (pa_source_used_by(s->source) <= 0) { + if (pa_source_check_suspend(s->source) <= 0) { struct device_info *d; if ((d = pa_hashmap_get(u->device_infos, s->source))) restart(d); @@ -191,7 +191,7 @@ static pa_hook_result_t sink_input_move_hook_cb(pa_core *c, pa_sink_input_move_h if ((d = pa_hashmap_get(u->device_infos, data->destination))) resume(d); - if (pa_sink_used_by(data->sink_input->sink) <= 1) + if (pa_sink_check_suspend(data->sink_input->sink) <= 1) if ((d = pa_hashmap_get(u->device_infos, data->sink_input->sink))) restart(d); @@ -208,7 +208,7 @@ static pa_hook_result_t source_output_move_hook_cb(pa_core *c, pa_source_output_ if ((d = pa_hashmap_get(u->device_infos, data->destination))) resume(d); - if (pa_source_used_by(data->source_output->source) <= 1) + if (pa_source_check_suspend(data->source_output->source) <= 1) if ((d = pa_hashmap_get(u->device_infos, data->source_output->source))) restart(d); @@ -266,8 +266,8 @@ static pa_hook_result_t device_new_hook_cb(pa_core *c, pa_object *o, struct user d->time_event = c->mainloop->time_new(c->mainloop, NULL, timeout_cb, d); pa_hashmap_put(u->device_infos, o, d); - if ((d->sink && pa_sink_used_by(d->sink) <= 0) || - (d->source && pa_source_used_by(d->source) <= 0)) + if ((d->sink && pa_sink_check_suspend(d->sink) <= 0) || + (d->source && pa_source_check_suspend(d->source) <= 0)) restart(d); return PA_HOOK_OK; @@ -313,7 +313,7 @@ static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, s pa_sink *s = PA_SINK(o); pa_sink_state_t state = pa_sink_get_state(s); - if (pa_sink_used_by(s) <= 0) { + if (pa_sink_check_suspend(s) <= 0) { if (PA_SINK_IS_OPENED(state)) restart(d); @@ -324,7 +324,7 @@ static pa_hook_result_t device_state_changed_hook_cb(pa_core *c, pa_object *o, s pa_source *s = PA_SOURCE(o); pa_source_state_t state = pa_source_get_state(s); - if (pa_source_used_by(s) <= 0) { + if (pa_source_check_suspend(s) <= 0) { if (PA_SOURCE_IS_OPENED(state)) restart(d); diff --git a/src/modules/rtp/module-rtp-send.c b/src/modules/rtp/module-rtp-send.c index 280067a5..8d1e92fe 100644 --- a/src/modules/rtp/module-rtp-send.c +++ b/src/modules/rtp/module-rtp-send.c @@ -316,7 +316,7 @@ int pa__init(pa_module*m) { pa_source_output_new_data_set_sample_spec(&data, &ss); pa_source_output_new_data_set_channel_map(&data, &cm); - o = pa_source_output_new(m->core, &data, 0); + o = pa_source_output_new(m->core, &data, PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND); pa_source_output_new_data_done(&data); if (!o) { diff --git a/src/pulse/def.h b/src/pulse/def.h index 66d9aff8..ace56574 100644 --- a/src/pulse/def.h +++ b/src/pulse/def.h @@ -194,7 +194,10 @@ typedef enum pa_stream_flags { /**< Find peaks instead of resampling. \since 0.9.11 */ PA_STREAM_START_MUTED = 0x1000U, - /**< Create in muted state. \since 0.9.11 */ + /**< Create in muted state. If neither PA_STREAM_START_UNMUTED nor + * PA_STREAM_START_MUTED it is left to the server to decide + * whether to create the stream in muted or in unmuted + * state. \since 0.9.11 */ PA_STREAM_ADJUST_LATENCY = 0x2000U, /**< Try to adjust the latency of the sink/source based on the @@ -203,7 +206,7 @@ typedef enum pa_stream_flags { * specified at the same time as PA_STREAM_EARLY_REQUESTS. \since * 0.9.11 */ - PA_STREAM_EARLY_REQUESTS = 0x4000U + PA_STREAM_EARLY_REQUESTS = 0x4000U, /**< Enable compatibility mode for legacy clients that rely on a * "classic" hardware device fragment-style playback model. If * this option is set, the minreq value of the buffer metrics gets @@ -220,6 +223,17 @@ typedef enum pa_stream_flags { * not be specified at the same time as * PA_STREAM_ADJUST_LATENCY. \since 0.9.12 */ + PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND = 0x8000U, + /**< If set this stream won't be taken into account when we it is + * checked whether the device this stream is connected to should + * auto-suspend. \ since 0.9.14 */ + + PA_STREAM_START_UNMUTED = 0x10000U + /**< Create in unmuted state. If neither PA_STREAM_START_UNMUTED + * nor PA_STREAM_START_MUTED it is left to the server to decide + * whether to create the stream in muted or in unmuted + * state. \since 0.9.14 */ + } pa_stream_flags_t; /** \cond fulldocs */ @@ -243,6 +257,8 @@ typedef enum pa_stream_flags { #define PA_STREAM_START_MUTED PA_STREAM_START_MUTED #define PA_STREAM_ADJUST_LATENCY PA_STREAM_ADJUST_LATENCY #define PA_STREAM_EARLY_REQUESTS PA_STREAM_EARLY_REQUESTS +#define PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND +#define PA_STREAM_START_UNMUTED PA_STREAM_START_UNMUTED /** \endcond */ diff --git a/src/pulse/stream.c b/src/pulse/stream.c index 00aa1cf9..c0ae4ac2 100644 --- a/src/pulse/stream.c +++ b/src/pulse/stream.c @@ -887,7 +887,9 @@ static int create_stream( PA_STREAM_PEAK_DETECT| PA_STREAM_START_MUTED| PA_STREAM_ADJUST_LATENCY| - PA_STREAM_EARLY_REQUESTS)), PA_ERR_INVALID); + PA_STREAM_EARLY_REQUESTS| + PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND| + PA_STREAM_START_UNMUTED)), PA_ERR_INVALID); PA_CHECK_VALIDITY(s->context, s->context->version >= 12 || !(flags & PA_STREAM_VARIABLE_RATE), PA_ERR_NOTSUPPORTED); PA_CHECK_VALIDITY(s->context, s->context->version >= 13 || !(flags & PA_STREAM_PEAK_DETECT), PA_ERR_NOTSUPPORTED); @@ -1007,6 +1009,14 @@ static int create_stream( pa_tagstruct_put_boolean(t, flags & PA_STREAM_EARLY_REQUESTS); } + if (s->context->version >= 15) { + + if (s->direction == PA_STREAM_PLAYBACK) + pa_tagstruct_put_boolean(t, flags & (PA_STREAM_START_MUTED|PA_STREAM_START_UNMUTED)); + + pa_tagstruct_put_boolean(t, flags & PA_STREAM_DONT_INHIBIT_AUTO_SUSPEND); + } + pa_pstream_send_tagstruct(s->context->pstream, t); pa_pdispatch_register_reply(s->context->pdispatch, tag, DEFAULT_TIMEOUT, pa_create_stream_callback, s, NULL); diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 46dcb14a..56e86cb4 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -959,6 +959,7 @@ static playback_stream* playback_stream_new( uint32_t *minreq, pa_cvolume *volume, pa_bool_t muted, + pa_bool_t muted_set, uint32_t syncid, uint32_t *missing, pa_sink_input_flags_t flags, @@ -1013,7 +1014,8 @@ static playback_stream* playback_stream_new( pa_sink_input_new_data_set_channel_map(&data, map); if (volume) pa_sink_input_new_data_set_volume(&data, volume); - pa_sink_input_new_data_set_muted(&data, muted); + if (muted_set) + pa_sink_input_new_data_set_muted(&data, muted); data.sync_base = ssync ? ssync->sink_input : NULL; sink_input = pa_sink_input_new(c->protocol->core, &data, flags); @@ -1688,7 +1690,9 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u variable_rate = FALSE, muted = FALSE, adjust_latency = FALSE, - early_requests = FALSE; + early_requests = FALSE, + dont_inhibit_auto_suspend = FALSE, + muted_set = FALSE; pa_sink_input_flags_t flags = 0; pa_proplist *p; @@ -1769,6 +1773,16 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u } } + if (c->version >= 15) { + + if (pa_tagstruct_get_boolean(t, &muted_set) < 0 || + pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + if (!pa_tagstruct_eof(t)) { protocol_error(c); pa_proplist_free(p); @@ -1800,9 +1814,14 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) | (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) | (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) | - (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0); + (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) | + (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0); + + /* Only since protocol version 15 there's a seperate muted_set + * flag. For older versions we synthesize it here */ + muted_set = muted_set || muted; - s = playback_stream_new(c, sink, &ss, &map, &maxlength, &tlength, &prebuf, &minreq, volume_set ? &volume : NULL, muted, syncid, &missing, flags, p, adjust_latency, early_requests); + s = playback_stream_new(c, sink, &ss, &map, &maxlength, &tlength, &prebuf, &minreq, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests); pa_proplist_free(p); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -1923,7 +1942,8 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin variable_rate = FALSE, adjust_latency = FALSE, peak_detect = FALSE, - early_requests = FALSE; + early_requests = FALSE, + dont_inhibit_auto_suspend = FALSE; pa_source_output_flags_t flags = 0; pa_proplist *p; uint32_t direct_on_input_idx = PA_INVALID_INDEX; @@ -1995,6 +2015,15 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin } } + if (c->version >= 15) { + + if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + if (!pa_tagstruct_eof(t)) { protocol_error(c); pa_proplist_free(p); @@ -2035,7 +2064,8 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) | (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) | (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) | - (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0); + (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) | + (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0); s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input, early_requests); pa_proplist_free(p); diff --git a/src/pulsecore/sink-input.h b/src/pulsecore/sink-input.h index 97668c52..27125988 100644 --- a/src/pulsecore/sink-input.h +++ b/src/pulsecore/sink-input.h @@ -56,7 +56,8 @@ typedef enum pa_sink_input_flags { PA_SINK_INPUT_NO_REMIX = 16, PA_SINK_INPUT_FIX_FORMAT = 32, PA_SINK_INPUT_FIX_RATE = 64, - PA_SINK_INPUT_FIX_CHANNELS = 128 + PA_SINK_INPUT_FIX_CHANNELS = 128, + PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND = 256, } pa_sink_input_flags_t; struct pa_sink_input { diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c index d8d1f792..a6027e70 100644 --- a/src/pulsecore/sink.c +++ b/src/pulsecore/sink.c @@ -991,7 +991,7 @@ unsigned pa_sink_linked_by(pa_sink *s) { ret = pa_idxset_size(s->inputs); /* We add in the number of streams connected to us here. Please - * not the asymmmetry to pa_sink_used_by()! */ + * note the asymmmetry to pa_sink_used_by()! */ if (s->monitor_source) ret += pa_source_linked_by(s->monitor_source); @@ -1015,6 +1015,38 @@ unsigned pa_sink_used_by(pa_sink *s) { return ret - s->n_corked; } +/* Called from main thread */ +unsigned pa_sink_check_suspend(pa_sink *s) { + unsigned ret; + pa_sink_input *i; + uint32_t idx; + + pa_sink_assert_ref(s); + pa_assert(PA_SINK_IS_LINKED(s->state)); + + 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_sink_input_state_t st; + + st = pa_sink_input_get_state(i); + pa_assert(PA_SINK_INPUT_IS_LINKED(st)); + + if (st == PA_SINK_INPUT_CORKED) + continue; + + if (i->flags & PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND) + continue; + + ret ++; + } + + if (s->monitor_source) + ret += pa_source_check_suspend(s->monitor_source); + + return ret; +} + /* Called from IO thread, except when it is not */ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { pa_sink *s = PA_SINK(o); diff --git a/src/pulsecore/sink.h b/src/pulsecore/sink.h index 74671b44..c5a73214 100644 --- a/src/pulsecore/sink.h +++ b/src/pulsecore/sink.h @@ -252,6 +252,7 @@ pa_bool_t pa_sink_get_mute(pa_sink *sink, pa_bool_t force_refres); 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) /* To be called exclusively by the sink driver, from IO context */ diff --git a/src/pulsecore/source-output.h b/src/pulsecore/source-output.h index 6ae10c62..f011f9bd 100644 --- a/src/pulsecore/source-output.h +++ b/src/pulsecore/source-output.h @@ -52,7 +52,8 @@ typedef enum pa_source_output_flags { PA_SOURCE_OUTPUT_NO_REMIX = 16, PA_SOURCE_OUTPUT_FIX_FORMAT = 32, PA_SOURCE_OUTPUT_FIX_RATE = 64, - PA_SOURCE_OUTPUT_FIX_CHANNELS = 128 + PA_SOURCE_OUTPUT_FIX_CHANNELS = 128, + PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND = 256 } pa_source_output_flags_t; struct pa_source_output { diff --git a/src/pulsecore/source.c b/src/pulsecore/source.c index edbbf017..7d927faa 100644 --- a/src/pulsecore/source.c +++ b/src/pulsecore/source.c @@ -645,6 +645,35 @@ unsigned pa_source_used_by(pa_source *s) { return ret - s->n_corked; } +/* Called from main thread */ +unsigned pa_source_check_suspend(pa_source *s) { + unsigned ret; + pa_source_output *o; + uint32_t idx; + + pa_source_assert_ref(s); + pa_assert(PA_SOURCE_IS_LINKED(s->state)); + + 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_source_output_state_t st; + + st = pa_source_output_get_state(o); + pa_assert(PA_SOURCE_OUTPUT_IS_LINKED(st)); + + if (st == PA_SOURCE_OUTPUT_CORKED) + continue; + + if (o->flags & PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND) + continue; + + ret ++; + } + + return ret; +} + /* Called from IO thread, except when it is not */ int pa_source_process_msg(pa_msgobject *object, int code, void *userdata, int64_t offset, pa_memchunk *chunk) { pa_source *s = PA_SOURCE(object); diff --git a/src/pulsecore/source.h b/src/pulsecore/source.h index cae78693..aaf904b4 100644 --- a/src/pulsecore/source.h +++ b/src/pulsecore/source.h @@ -234,6 +234,7 @@ pa_bool_t pa_source_get_mute(pa_source *source, pa_bool_t force_refresh); 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) /* To be called exclusively by the source driver, from IO context */ -- cgit