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 of the License,
+ 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
i->attach = NULL;
i->detach = NULL;
i->suspend = NULL;
- i->moved = NULL;
+ i->moving = NULL;
i->kill = NULL;
i->get_latency = NULL;
i->state_change = NULL;
i->may_move_to = NULL;
+ i->send_event = NULL;
}
/* Called from main context */
pa_return_val_if_fail(data->sink, -PA_ERR_NOENTITY);
pa_return_val_if_fail(PA_SINK_IS_LINKED(pa_sink_get_state(data->sink)), -PA_ERR_BADSTATE);
pa_return_val_if_fail(!data->sync_base || (data->sync_base->sink == data->sink && pa_sink_input_get_state(data->sync_base) == PA_SINK_INPUT_CORKED), -PA_ERR_INVALID);
- pa_return_val_if_fail(!(flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) || pa_sink_get_state(data->sink) != PA_SINK_SUSPENDED, -PA_ERR_BADSTATE);
if (!data->sample_spec_is_set)
data->sample_spec = data->sink->sample_spec;
if ((r = pa_hook_fire(&core->hooks[PA_CORE_HOOK_SINK_INPUT_FIXATE], data)) < 0)
return r;
+ if ((flags & PA_SINK_INPUT_FAIL_ON_SUSPEND) &&
+ pa_sink_get_state(data->sink) == PA_SINK_SUSPENDED) {
+ pa_log_warn("Failed to create sink input: sink is suspended.");
+ return -PA_ERR_BADSTATE;
+ }
+
if (pa_idxset_size(data->sink->inputs) >= PA_MAX_INPUTS_PER_SINK) {
pa_log_warn("Failed to create sink input: too many inputs per sink.");
return -PA_ERR_TOOLARGE;
i->sink = NULL;
}
+ pa_core_maybe_vacuum(i->core);
+
pa_sink_input_unref(i);
}
i->update_max_request(i, i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, nbytes) : nbytes);
}
-/* Called from thread context */
-static pa_usec_t fixup_latency(pa_sink *s, pa_usec_t usec) {
- pa_sink_assert_ref(s);
-
- if (usec == (pa_usec_t) -1)
- return usec;
-
- if (s->thread_info.max_latency > 0 && usec > s->thread_info.max_latency)
- usec = s->thread_info.max_latency;
-
- if (s->thread_info.min_latency > 0 && usec < s->thread_info.min_latency)
- usec = s->thread_info.min_latency;
-
- return usec;
-}
-
/* Called from thread context */
pa_usec_t pa_sink_input_set_requested_latency_within_thread(pa_sink_input *i, pa_usec_t usec) {
pa_sink_input_assert_ref(i);
- usec = fixup_latency(i->sink, usec);
+ if (usec != (pa_usec_t) -1)
+ usec = PA_CLAMP(usec, i->sink->thread_info.min_latency, i->sink->thread_info.max_latency);
+
i->thread_info.requested_sink_latency = usec;
pa_sink_invalidate_requested_latency(i->sink);
/* Called from main context */
pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) {
+ pa_usec_t min_latency, max_latency;
+
pa_sink_input_assert_ref(i);
- if (PA_SINK_INPUT_IS_LINKED(i->state))
+ if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
- else
- /* If this sink input is not realized yet, we have to touch
- * the thread info data directly */
+ return usec;
+ }
+
+ /* If this sink input is not realized yet or we are being moved,
+ * we have to touch the thread info data directly */
+
+ pa_sink_get_latency_range(i->sink, &min_latency, &max_latency);
- i->thread_info.requested_sink_latency = usec;
+ if (usec != (pa_usec_t) -1)
+ usec = PA_CLAMP(usec, min_latency, max_latency);
+
+ i->thread_info.requested_sink_latency = usec;
return usec;
}
/* Called from main context */
pa_usec_t pa_sink_input_get_requested_latency(pa_sink_input *i) {
- pa_usec_t usec = 0;
-
pa_sink_input_assert_ref(i);
- if (PA_SINK_INPUT_IS_LINKED(i->state))
+ if (PA_SINK_INPUT_IS_LINKED(i->state) && i->sink) {
+ pa_usec_t usec = 0;
pa_assert_se(pa_asyncmsgq_send(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_GET_REQUESTED_LATENCY, &usec, 0, NULL) == 0);
- else
- /* If this sink input is not realized yet, we have to touch
- * the thread info data directly */
- usec = i->thread_info.requested_sink_latency;
+ return usec;
+ }
- return usec;
+ /* If this sink input is not realized yet or we are being moved,
+ * we have to touch the thread info data directly */
+
+ return i->thread_info.requested_sink_latency;
}
/* Called from main context */
return &i->virtual_volume;
}
+/* Called from main context */
+pa_cvolume *pa_sink_input_get_relative_volume(pa_sink_input *i, pa_cvolume *v) {
+ pa_sink_input_assert_ref(i);
+ pa_assert(v);
+ pa_assert(PA_SINK_INPUT_IS_LINKED(i->state));
+
+ *v = i->virtual_volume;
+
+ /* This always returns a relative volume, even in flat volume mode */
+
+ if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
+ pa_cvolume sv;
+
+ sv = *pa_sink_get_volume(i->sink, FALSE);
+
+ pa_sw_cvolume_divide(v, v,
+ pa_cvolume_remap(&sv, &i->sink->channel_map, &i->channel_map));
+ }
+
+ return v;
+}
+
/* Called from main context */
void pa_sink_input_set_mute(pa_sink_input *i, pa_bool_t mute, pa_bool_t save) {
pa_assert(i);
}
/* Called from main thread */
-pa_bool_t pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
-
- pa_sink_input_assert_ref(i);
-
- pa_proplist_update(i->proplist, mode, p);
+void pa_sink_input_update_proplist(pa_sink_input *i, pa_update_mode_t mode, pa_proplist *p) {
+ pa_sink_input_assert_ref(i);
- if (PA_SINK_IS_LINKED(i->state)) {
- pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
- pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
- }
+ if (p)
+ pa_proplist_update(i->proplist, mode, p);
- return TRUE;
+ if (PA_SINK_IS_LINKED(i->state)) {
+ pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_PROPLIST_CHANGED], i);
+ pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
+ }
}
/* Called from main context */
} else
new_resampler = NULL;
+ if (i->moving)
+ i->moving(i);
+
i->sink = dest;
i->save_sink = save;
pa_idxset_put(dest->inputs, i, NULL);
0,
&i->sink->silence);
}
-
pa_sink_update_status(dest);
if (i->sink->flags & PA_SINK_FLAT_VOLUME) {
pa_log_debug("Successfully moved sink input %i to %s.", i->index, dest->name);
/* Notify everyone */
- if (i->moved)
- i->moved(i);
-
pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_MOVE_FINISH], i);
pa_subscription_post(i->core, PA_SUBSCRIPTION_EVENT_SINK_INPUT|PA_SUBSCRIPTION_EVENT_CHANGE, i->index);
return ret;
}
+
+/* Called from main context */
+void pa_sink_input_send_event(pa_sink_input *i, const char *event, pa_proplist *data) {
+ pa_proplist *pl = NULL;
+ pa_sink_input_send_event_hook_data hook_data;
+
+ pa_sink_input_assert_ref(i);
+ pa_assert(event);
+
+ if (!i->send_event)
+ return;
+
+ if (!data)
+ data = pl = pa_proplist_new();
+
+ hook_data.sink_input = i;
+ hook_data.data = data;
+ hook_data.event = event;
+
+ if (pa_hook_fire(&i->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT], &hook_data) < 0)
+ goto finish;
+
+ i->send_event(i, event, data);
+
+finish:
+ if (pl)
+ pa_proplist_free(pl);
+}