-/* $Id$ */
-
/***
This file is part of PulseAudio.
return NULL;
}
+ s->monitor_source->min_latency = s->min_latency;
+ s->monitor_source->max_latency = s->max_latency;
+
s->monitor_source->monitor_of = s;
pa_source_set_max_rewind(s->monitor_source, s->thread_info.max_rewind);
return n;
}
-static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, size_t length) {
+static void inputs_drop(pa_sink *s, pa_mix_info *info, unsigned n, pa_memchunk *result) {
pa_sink_input *i;
void *state = NULL;
unsigned p = 0;
unsigned n_unreffed = 0;
pa_sink_assert_ref(s);
+ pa_assert(result);
+ pa_assert(result->memblock);
+ pa_assert(result->length > 0);
/* We optimize for the case where the order of the inputs has not changed */
while ((i = pa_hashmap_iterate(s->thread_info.inputs, &state, NULL))) {
unsigned j;
- pa_mix_info* m;
+ pa_mix_info* m = NULL;
pa_sink_input_assert_ref(i);
- m = NULL;
-
/* Let's try to find the matching entry info the pa_mix_info array */
for (j = 0; j < n; j ++) {
}
/* Drop read data */
- pa_sink_input_drop(i, length);
+ pa_sink_input_drop(i, result->length);
+
+ if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source))) {
+
+ if (pa_hashmap_size(i->thread_info.direct_outputs) > 0) {
+ void *ostate = NULL;
+ pa_source_output *o;
+ pa_memchunk c;
+
+ if (m && m->chunk.memblock) {
+ c = m->chunk;
+ pa_memblock_ref(c.memblock);
+ pa_assert(result->length <= c.length);
+ c.length = result->length;
+
+ pa_memchunk_make_writable(&c, 0);
+ pa_volume_memchunk(&c, &s->sample_spec, &m->volume);
+ } else {
+ c = s->silence;
+ pa_memblock_ref(c.memblock);
+ pa_assert(result->length <= c.length);
+ c.length = result->length;
+ }
+
+ while ((o = pa_hashmap_iterate(i->thread_info.direct_outputs, &ostate, NULL))) {
+ pa_source_output_assert_ref(o);
+ pa_assert(o->direct_on_input == i);
+ pa_source_post_direct(s->monitor_source, o, &c);
+ }
+
+ pa_memblock_unref(c.memblock);
+ }
+ }
if (m) {
- pa_sink_input_unref(m->userdata);
- m->userdata = NULL;
if (m->chunk.memblock)
pa_memblock_unref(m->chunk.memblock);
- pa_memchunk_reset(&m->chunk);
+ pa_memchunk_reset(&m->chunk);
+
+ pa_sink_input_unref(m->userdata);
+ m->userdata = NULL;
n_unreffed += 1;
}
pa_memblock_unref(info->chunk.memblock);
}
}
+
+ if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
+ pa_source_post(s->monitor_source, result);
}
void pa_sink_render(pa_sink*s, size_t length, pa_memchunk *result) {
}
if (s->thread_info.state == PA_SINK_RUNNING)
- inputs_drop(s, info, n, result->length);
-
- if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
- pa_source_post(s->monitor_source, result);
+ inputs_drop(s, info, n, result);
pa_sink_unref(s);
}
if (length > block_size_max)
length = pa_frame_align(block_size_max, &s->sample_spec);
+ pa_assert(length > 0);
+
n = s->thread_info.state == PA_SINK_RUNNING ? fill_mix_info(s, &length, info, MAX_MIX_CHANNELS) : 0;
if (n == 0) {
vchunk = info[0].chunk;
pa_memblock_ref(vchunk.memblock);
- if (vchunk.length > target->length)
- vchunk.length = target->length;
+ if (vchunk.length > length)
+ vchunk.length = length;
if (!pa_cvolume_is_norm(&volume)) {
pa_memchunk_make_writable(&vchunk, 0);
}
if (s->thread_info.state == PA_SINK_RUNNING)
- inputs_drop(s, info, n, target->length);
-
- if (s->monitor_source && PA_SOURCE_IS_OPENED(pa_source_get_state(s->monitor_source)))
- pa_source_post(s->monitor_source, target);
+ inputs_drop(s, info, n, target);
pa_sink_unref(s);
}
pa_usec_t result = (pa_usec_t) -1;
pa_sink_input *i;
void *state = NULL;
+ pa_usec_t monitor_latency;
pa_sink_assert_ref(s);
(result == (pa_usec_t) -1 || result > i->thread_info.requested_sink_latency))
result = i->thread_info.requested_sink_latency;
+ monitor_latency = pa_source_get_requested_latency_within_thread(s->monitor_source);
+
+ if (monitor_latency != (pa_usec_t) -1 &&
+ (result == (pa_usec_t) -1 || result > monitor_latency))
+ result = monitor_latency;
+
if (result != (pa_usec_t) -1) {
if (s->max_latency > 0 && result > s->max_latency)
result = s->max_latency;
void pa_sink_invalidate_requested_latency(pa_sink *s) {
pa_sink_assert_ref(s);
- pa_assert(PA_SINK_IS_LINKED(s->thread_info.state));
s->thread_info.requested_latency_valid = FALSE;
if (s->update_requested_latency)
s->update_requested_latency(s);
}
+
+void pa_sink_set_latency_range(pa_sink *s, pa_usec_t min_latency, pa_usec_t max_latency) {
+ pa_sink_assert_ref(s);
+
+ /* min_latency == 0: no limit
+ * min_latency == (size_t) -1: default limit
+ * min_latency anything else: specified limit
+ *
+ * Similar for max_latency */
+
+ if (min_latency == (pa_usec_t) -1)
+ min_latency = DEFAULT_MIN_LATENCY;
+
+ if (max_latency == (pa_usec_t) -1)
+ max_latency = min_latency;
+
+ pa_assert(!min_latency || !max_latency ||
+ min_latency <= max_latency);
+
+ s->min_latency = min_latency;
+ s->max_latency = max_latency;
+
+ pa_source_set_latency_range(s->monitor_source, min_latency, max_latency);
+}