diff options
Diffstat (limited to 'src/pulsecore/sink-input.c')
-rw-r--r-- | src/pulsecore/sink-input.c | 144 |
1 files changed, 101 insertions, 43 deletions
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c index 4f70347f..d25cd797 100644 --- a/src/pulsecore/sink-input.c +++ b/src/pulsecore/sink-input.c @@ -75,7 +75,7 @@ void pa_sink_input_new_data_set_volume(pa_sink_input_new_data *data, const pa_cv pa_assert(data); if ((data->volume_is_set = !!volume)) - data->volume = *volume; + data->volume = data->virtual_volume = *volume; } void pa_sink_input_new_data_set_muted(pa_sink_input_new_data *data, pa_bool_t mute) { @@ -108,6 +108,7 @@ static void reset_callbacks(pa_sink_input *i) { i->kill = NULL; i->get_latency = NULL; i->state_change = NULL; + i->may_move_to = NULL; } /* Called from main context */ @@ -119,6 +120,7 @@ pa_sink_input* pa_sink_input_new( pa_sink_input *i; pa_resampler *resampler = NULL; char st[PA_SAMPLE_SPEC_SNPRINT_MAX], cm[PA_CHANNEL_MAP_SNPRINT_MAX]; + pa_channel_map original_cm; pa_assert(core); pa_assert(data); @@ -141,20 +143,25 @@ pa_sink_input* pa_sink_input_new( pa_return_null_if_fail(pa_sample_spec_valid(&data->sample_spec)); if (!data->channel_map_is_set) { - if (data->sink->channel_map.channels == data->sample_spec.channels) + if (pa_channel_map_compatible(&data->sink->channel_map, &data->sample_spec)) data->channel_map = data->sink->channel_map; else - pa_return_null_if_fail(pa_channel_map_init_auto(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT)); + pa_channel_map_init_extend(&data->channel_map, data->sample_spec.channels, PA_CHANNEL_MAP_DEFAULT); } pa_return_null_if_fail(pa_channel_map_valid(&data->channel_map)); - pa_return_null_if_fail(data->channel_map.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_channel_map_compatible(&data->channel_map, &data->sample_spec)); - if (!data->volume_is_set) + if (!data->volume_is_set) { pa_cvolume_reset(&data->volume, data->sample_spec.channels); + pa_cvolume_reset(&data->virtual_volume, data->sample_spec.channels); + } pa_return_null_if_fail(pa_cvolume_valid(&data->volume)); - pa_return_null_if_fail(data->volume.channels == data->sample_spec.channels); + pa_return_null_if_fail(pa_cvolume_compatible(&data->volume, &data->sample_spec)); + + pa_return_null_if_fail(pa_cvolume_valid(&data->virtual_volume)); + pa_return_null_if_fail(pa_cvolume_compatible(&data->virtual_volume, &data->sample_spec)); if (!data->muted_is_set) data->muted = FALSE; @@ -165,6 +172,8 @@ pa_sink_input* pa_sink_input_new( if (flags & PA_SINK_INPUT_FIX_RATE) data->sample_spec.rate = data->sink->sample_spec.rate; + original_cm = data->channel_map; + if (flags & PA_SINK_INPUT_FIX_CHANNELS) { data->sample_spec.channels = data->sink->sample_spec.channels; data->channel_map = data->sink->channel_map; @@ -174,8 +183,7 @@ pa_sink_input* pa_sink_input_new( pa_assert(pa_channel_map_valid(&data->channel_map)); /* Due to the fixing of the sample spec the volume might not match anymore */ - if (data->volume.channels != data->sample_spec.channels) - pa_cvolume_set(&data->volume, data->sample_spec.channels, pa_cvolume_avg(&data->volume)); + pa_cvolume_remap(&data->volume, &original_cm, &data->channel_map); if (data->resample_method == PA_RESAMPLER_INVALID) data->resample_method = core->resample_method; @@ -227,7 +235,9 @@ pa_sink_input* pa_sink_input_new( i->sample_spec = data->sample_spec; i->channel_map = data->channel_map; + i->virtual_volume = data->virtual_volume; i->volume = data->volume; + i->muted = data->muted; if (data->sync_base) { @@ -292,8 +302,6 @@ static void update_n_corked(pa_sink_input *i, pa_sink_input_state_t state) { pa_assert_se(i->sink->n_corked -- >= 1); else if (i->state != PA_SINK_INPUT_CORKED && state == PA_SINK_INPUT_CORKED) i->sink->n_corked++; - - pa_sink_update_status(i->sink); } /* Called from main context */ @@ -331,6 +339,8 @@ static int sink_input_set_state(pa_sink_input *i, pa_sink_input_state_t state) { pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_STATE_CHANGED], ssync); } + pa_sink_update_status(i->sink); + return 0; } @@ -381,6 +391,8 @@ void pa_sink_input_unlink(pa_sink_input *i) { pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_UNLINK_POST], i); } + pa_sink_update_status(i->sink); + i->sink = NULL; pa_sink_input_unref(i); } @@ -442,6 +454,8 @@ void pa_sink_input_put(pa_sink_input *i) { pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_NEW, i->index); pa_hook_fire(&i->sink->core->hooks[PA_CORE_HOOK_SINK_INPUT_PUT], i); + + pa_sink_update_status(i->sink); } /* Called from main context */ @@ -784,17 +798,34 @@ pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) { /* Called from main context */ void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) { + pa_sink_input_set_volume_data data; + pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); pa_assert(volume); + pa_assert(pa_cvolume_valid(volume)); + pa_assert(pa_cvolume_compatible(volume, &i->sample_spec)); + + data.sink_input = i; + data.virtual_volume = *volume; + data.volume = *volume; + + /* If you change something here, consider looking into + * module-flat-volume.c as well since it uses very similar + * code. */ - if (pa_cvolume_equal(&i->volume, volume)) + if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SET_VOLUME], &data) < 0) return; - i->volume = *volume; + if (!pa_cvolume_equal(&i->volume, &data.volume)) { + i->volume = data.volume; + pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, &data.volume, 0, NULL) == 0); + } - pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_VOLUME, &i->volume, 0, NULL) == 0); - pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + if (!pa_cvolume_equal(&i->virtual_volume, &data.virtual_volume)) { + i->virtual_volume = data.virtual_volume; + pa_subscription_post(i->sink->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index); + } } /* Called from main context */ @@ -802,7 +833,7 @@ const pa_cvolume *pa_sink_input_get_volume(pa_sink_input *i) { pa_sink_input_assert_ref(i); pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); - return &i->volume; + return &i->virtual_volume; } /* Called from main context */ @@ -885,6 +916,35 @@ pa_resample_method_t pa_sink_input_get_resample_method(pa_sink_input *i) { } /* Called from main context */ +pa_bool_t pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) { + pa_sink_input_assert_ref(i); + pa_assert(PA_SINK_INPUT_IS_LINKED(i->state)); + pa_sink_assert_ref(dest); + + if (dest == i->sink) + return TRUE; + + if (i->flags & PA_SINK_INPUT_DONT_MOVE) + return FALSE; + + if (i->sync_next || i->sync_prev) { + pa_log_warn("Moving synchronised streams not supported."); + return FALSE; + } + + if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) { + pa_log_warn("Failed to move sink input: too many inputs per sink."); + return FALSE; + } + + if (i->may_move_to) + if (!i->may_move_to(i, dest)) + return FALSE; + + return TRUE; +} + +/* Called from main context */ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) { pa_resampler *new_resampler; pa_sink *origin; @@ -900,19 +960,9 @@ int pa_sink_input_move_to(pa_sink_input *i, pa_sink *dest) { if (dest == origin) return 0; - if (i->flags & PA_SINK_INPUT_DONT_MOVE) + if (!pa_sink_input_may_move_to(i, dest)) return -1; - if (i->sync_next || i->sync_prev) { - pa_log_warn("Moving synchronised streams not supported."); - return -1; - } - - if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) { - pa_log_warn("Failed to move sink input: too many inputs per sink."); - return -1; - } - /* Kill directly connected outputs */ while ((o = pa_idxset_first(i->direct_outputs, NULL))) { pa_assert(o != p); @@ -1144,7 +1194,8 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam * implementor. This implies 'flush' is TRUE. */ pa_sink_input_assert_ref(i); - pa_assert(i->thread_info.rewrite_nbytes == 0); + + nbytes = PA_MAX(i->thread_info.rewrite_nbytes, nbytes); /* pa_log_debug("request rewrite %lu", (unsigned long) nbytes); */ @@ -1172,26 +1223,33 @@ void pa_sink_input_request_rewind(pa_sink_input *i, size_t nbytes /* in our sam nbytes = pa_resampler_request(i->thread_info.resampler, nbytes); } - if (rewrite) { - /* Make sure to not overwrite over underruns */ - if (nbytes > i->thread_info.playing_for) - nbytes = (size_t) i->thread_info.playing_for; + if (i->thread_info.rewrite_nbytes != (size_t) -1) { + if (rewrite) { + /* Make sure to not overwrite over underruns */ + if (nbytes > i->thread_info.playing_for) + nbytes = (size_t) i->thread_info.playing_for; - i->thread_info.rewrite_nbytes = nbytes; - } else - i->thread_info.rewrite_nbytes = (size_t) -1; + i->thread_info.rewrite_nbytes = nbytes; + } else + i->thread_info.rewrite_nbytes = (size_t) -1; + } - i->thread_info.rewrite_flush = flush && i->thread_info.rewrite_nbytes != 0; + i->thread_info.rewrite_flush = + i->thread_info.rewrite_flush || + (flush && i->thread_info.rewrite_nbytes != 0); - /* Transform to sink domain */ - if (i->thread_info.resampler) - nbytes = pa_resampler_result(i->thread_info.resampler, nbytes); + if (nbytes != (size_t) -1) { - if (nbytes > lbq) - pa_sink_request_rewind(i->sink, nbytes - lbq); - else - /* This call will make sure process_rewind() is called later */ - pa_sink_request_rewind(i->sink, 0); + /* Transform to sink domain */ + if (i->thread_info.resampler) + nbytes = pa_resampler_result(i->thread_info.resampler, nbytes); + + if (nbytes > lbq) + pa_sink_request_rewind(i->sink, nbytes - lbq); + else + /* This call will make sure process_rewind() is called later */ + pa_sink_request_rewind(i->sink, 0); + } } /* Called from main context */ |