summaryrefslogtreecommitdiffstats
path: root/src/pulsecore/sink-input.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pulsecore/sink-input.c')
-rw-r--r--src/pulsecore/sink-input.c144
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 */