summaryrefslogtreecommitdiffstats
path: root/src/pulsecore/sink.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore/sink.c')
-rw-r--r--src/pulsecore/sink.c88
1 files changed, 67 insertions, 21 deletions
diff --git a/src/pulsecore/sink.c b/src/pulsecore/sink.c
index 3afeadb0..0c297ec3 100644
--- a/src/pulsecore/sink.c
+++ b/src/pulsecore/sink.c
@@ -128,6 +128,7 @@ pa_sink* pa_sink_new(
char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX];
pa_source_new_data source_data;
const char *dn;
+ char *pt;
pa_assert(core);
pa_assert(data);
@@ -233,11 +234,14 @@ pa_sink* pa_sink_new(
if (s->card)
pa_assert_se(pa_idxset_put(s->card->sinks, s, NULL) >= 0);
- pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s",
+ pt = pa_proplist_to_string_sep(s->proplist, "\n ");
+ pa_log_info("Created sink %u \"%s\" with sample spec %s and channel map %s\n %s",
s->index,
s->name,
pa_sample_spec_snprint(st, sizeof(st), &s->sample_spec),
- pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map));
+ pa_channel_map_snprint(cm, sizeof(cm), &s->channel_map),
+ pt);
+ pa_xfree(pt);
pa_source_new_data_init(&source_data);
pa_source_new_data_set_sample_spec(&source_data, &s->sample_spec);
@@ -301,6 +305,11 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
s->state = state;
+ if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
+ pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
+ pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
+ }
+
if (suspend_change) {
pa_sink_input *i;
uint32_t idx;
@@ -308,15 +317,13 @@ static int sink_set_state(pa_sink *s, pa_sink_state_t state) {
/* We're suspending or resuming, tell everyone about it */
for (i = PA_SINK_INPUT(pa_idxset_first(s->inputs, &idx)); i; i = PA_SINK_INPUT(pa_idxset_next(s->inputs, &idx)))
- if (i->suspend)
+ if (s->state == PA_SINK_SUSPENDED &&
+ (i->flags & PA_SINK_INPUT_FAIL_ON_SUSPEND))
+ pa_sink_input_kill(i);
+ else if (i->suspend)
i->suspend(i, state == PA_SINK_SUSPENDED);
}
- if (state != PA_SINK_UNLINKED) { /* if we enter UNLINKED state pa_sink_unlink() will fire the apropriate events */
- pa_hook_fire(&s->core->hooks[PA_CORE_HOOK_SINK_STATE_CHANGED], s);
- pa_subscription_post(s->core, PA_SUBSCRIPTION_EVENT_SINK | PA_SUBSCRIPTION_EVENT_CHANGE, s->index);
- }
-
return 0;
}
@@ -540,9 +547,17 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
+ /* If nobody requested this and this is actually no real rewind
+ * then we can short cut this */
+ if (!s->thread_info.rewind_requested && nbytes <= 0)
+ return;
+
s->thread_info.rewind_nbytes = 0;
s->thread_info.rewind_requested = FALSE;
+ if (s->thread_info.state == PA_SINK_SUSPENDED)
+ return;
+
if (nbytes > 0)
pa_log_debug("Processing rewind...");
@@ -552,7 +567,7 @@ void pa_sink_process_rewind(pa_sink *s, size_t nbytes) {
}
if (nbytes > 0)
- if (s->monitor_source && PA_SOURCE_IS_OPENED(s->monitor_source->thread_info.state))
+ if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
pa_source_process_rewind(s->monitor_source, nbytes);
}
@@ -569,8 +584,7 @@ static unsigned fill_mix_info(pa_sink *s, size_t *length, pa_mix_info *info, uns
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL)) && maxinfo > 0) {
pa_sink_input_assert_ref(i);
- if (pa_sink_input_peek(i, *length, &info->chunk, &info->volume) < 0)
- continue;
+ pa_sink_input_peek(i, *length, &info->chunk, &info->volume);
if (mixlength == 0 || info->chunk.length < mixlength)
mixlength = info->chunk.length;
@@ -632,7 +646,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *
/* Drop read data */
pa_sink_input_drop(i, result->length);
- if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) {
+ if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state)) {
if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
void *ostate = NULL;
@@ -688,7 +702,7 @@ static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *
}
}
- if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
+ if (s->monitor_source && PA_SOURCE_IS_LINKED(s->monitor_source->thread_info.state))
pa_source_post(s->monitor_source, result);
}
@@ -699,7 +713,7 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
size_t block_size_max;
pa_sink_assert_ref(s);
- pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
+ pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
pa_assert(pa_frame_aligned(length, &s->sample_spec));
pa_assert(result);
@@ -708,6 +722,13 @@ void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
pa_assert(!s->thread_info.rewind_requested);
pa_assert(s->thread_info.rewind_nbytes == 0);
+ if (s->thread_info.state == PA_SINK_SUSPENDED) {
+ result->memblock = pa_memblock_ref(s->silence.memblock);
+ result->index = s->silence.index;
+ result->length = PA_MIN(s->silence.length, length);
+ return;
+ }
+
if (length <= 0)
length = pa_frame_align(MIX_BUFFER_LENGTH, &s->sample_spec);
@@ -772,7 +793,7 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
size_t length, block_size_max;
pa_sink_assert_ref(s);
- pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
+ pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
pa_assert(target);
pa_assert(target->memblock);
pa_assert(target->length > 0);
@@ -783,6 +804,11 @@ void pa_sink_render_into(pa_sink*s, pa_memchunk *target) {
pa_assert(!s->thread_info.rewind_requested);
pa_assert(s->thread_info.rewind_nbytes == 0);
+ if (s->thread_info.state == PA_SINK_SUSPENDED) {
+ pa_silence_memchunk(target, &s->sample_spec);
+ return;
+ }
+
length = target->length;
block_size_max = pa_mempool_block_size_max(s->core->mempool);
if (length > block_size_max)
@@ -850,7 +876,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
size_t l, d;
pa_sink_assert_ref(s);
- pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
+ pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
pa_assert(target);
pa_assert(target->memblock);
pa_assert(target->length > 0);
@@ -880,7 +906,7 @@ void pa_sink_render_into_full(pa_sink *s, pa_memchunk *target) {
/* Called from IO thread context */
void pa_sink_render_full(pa_sink *s, size_t length, pa_memchunk *result) {
pa_sink_assert_ref(s);
- pa_assert(PA_SINK_IS_OPENED(s->thread_info.state));
+ pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
pa_assert(length > 0);
pa_assert(pa_frame_aligned(length, &s->sample_spec));
pa_assert(result);
@@ -906,7 +932,7 @@ pa_usec_t pa_sink_get_latency(pa_sink *s) {
/* The returned value is supposed to be in the time domain of the sound card! */
- if (!PA_SINK_IS_OPENED(s->state))
+ if (s->state == PA_SINK_SUSPENDED)
return 0;
if (!(s->flags & PA_SINK_LATENCY))
@@ -922,12 +948,24 @@ void pa_sink_update_flat_volume(pa_sink *s, pa_cvolume *new_volume) {
pa_sink_input *i;
uint32_t idx;
+ pa_sink_assert_ref(s);
+ pa_assert(new_volume);
+ pa_assert(PA_SINK_IS_LINKED(s->state));
+ pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
+
/* This is called whenever a sink input volume changes and we
* might need to fix up the sink volume accordingly. Please note
* that we don't actually update the sinks volume here, we only
* return how it needs to be updated. The caller should then call
* pa_sink_set_flat_volume().*/
+ if (pa_idxset_isempty(s->inputs)) {
+ /* In the special case that we have no sink input we leave the
+ * volume unmodified. */
+ *new_volume = s->virtual_volume;
+ return;
+ }
+
pa_cvolume_mute(new_volume, s->channel_map.channels);
/* First let's determine the new maximum volume of all inputs
@@ -969,8 +1007,8 @@ void pa_sink_propagate_flat_volume(pa_sink *s, const pa_cvolume *old_volume) {
uint32_t idx;
pa_sink_assert_ref(s);
- pa_assert(PA_SINK_IS_LINKED(s->state));
pa_assert(old_volume);
+ pa_assert(PA_SINK_IS_LINKED(s->state));
pa_assert(s->flags & PA_SINK_FLAT_VOLUME);
/* This is called whenever the sink volume changes that is not
@@ -1129,6 +1167,7 @@ pa_bool_t pa_sink_get_mute(pa_sink *s, pa_bool_t force_refresh) {
pa_bool_t pa_sink_update_proplist(pa_sink *s, pa_update_mode_t mode, pa_proplist *p) {
pa_sink_assert_ref(s);
+ pa_assert(p);
pa_proplist_update(s->proplist, mode, p);
@@ -1469,7 +1508,7 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
case PA_SINK_MESSAGE_SET_MUTE:
- if (!s->thread_info.soft_muted != s->muted) {
+ if (s->thread_info.soft_muted != s->muted) {
s->thread_info.soft_muted = s->muted;
pa_sink_request_rewind(s, (size_t) -1);
}
@@ -1482,6 +1521,10 @@ int pa_sink_process_msg(pa_msgobject *o, int code, void *userdata, int64_t offse
case PA_SINK_MESSAGE_SET_STATE:
s->thread_info.state = PA_PTR_TO_UINT(userdata);
+
+ if (s->thread_info.state == PA_SINK_SUSPENDED)
+ s->thread_info.rewind_requested = FALSE;
+
return 0;
case PA_SINK_MESSAGE_DETACH:
@@ -1609,6 +1652,9 @@ void pa_sink_request_rewind(pa_sink*s, size_t nbytes) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
+ if (s->thread_info.state == PA_SINK_SUSPENDED)
+ return;
+
if (nbytes == (size_t) -1)
nbytes = s->thread_info.max_rewind;
@@ -1670,7 +1716,7 @@ pa_usec_t pa_sink_get_requested_latency(pa_sink *s) {
pa_sink_assert_ref(s);
pa_assert(PA_SINK_IS_LINKED(s->state));
- if (!PA_SINK_IS_OPENED(s->state))
+ if (s->state == PA_SINK_SUSPENDED)
return 0;
pa_assert_se(pa_asyncmsgq_send(s->asyncmsgq, PA_MSGOBJECT(s), PA_SINK_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);