summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2008-04-23 18:11:57 +0000
committerLennart Poettering <lennart@poettering.net>2008-04-23 18:11:57 +0000
commited0af46e69a207249bfbade2babfbc93b3f89fc9 (patch)
treeda25ac83c86af97939974525b154fd2d99c75b38
parentaf03dd4e4fe668c988e1d9e781212763d3e9d56e (diff)
unify code that fixes up buffering metrics
git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2302 fefdeb5f-60dc-0310-8127-8f9354f1896f
-rw-r--r--src/pulsecore/protocol-native.c345
1 files changed, 188 insertions, 157 deletions
diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c
index cde113df..ca14b955 100644
--- a/src/pulsecore/protocol-native.c
+++ b/src/pulsecore/protocol-native.c
@@ -470,11 +470,65 @@ static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, i
return 0;
}
+static void fix_record_buffer_attr_pre(record_stream *s, pa_bool_t adjust_latency, uint32_t *maxlength, uint32_t *fragsize) {
+ pa_assert(s);
+ pa_assert(maxlength);
+ pa_assert(fragsize);
+
+ if (*maxlength <= 0 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
+ *maxlength = MAX_MEMBLOCKQ_LENGTH;
+
+ if (*fragsize <= 0)
+ *fragsize = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
+
+ if (adjust_latency) {
+ pa_usec_t fragsize_usec;
+
+ /* So, the user asked us to adjust the latency according to
+ * the what the source can provide. Half the latency will be
+ * spent on the hw buffer, half of it in the async buffer
+ * queue we maintain for each client. */
+
+ fragsize_usec = pa_bytes_to_usec(*fragsize, &s->source_output->sample_spec);
+
+ s->source_latency = pa_source_output_set_requested_latency(s->source_output, fragsize_usec/2);
+
+ if (fragsize_usec >= s->source_latency*2)
+ fragsize_usec -= s->source_latency;
+ else
+ fragsize_usec = s->source_latency;
+
+ *fragsize = pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
+ }
+}
+
+static void fix_record_buffer_attr_post(record_stream *s, uint32_t *maxlength, uint32_t *fragsize) {
+ size_t base;
+
+ pa_assert(s);
+ pa_assert(maxlength);
+ pa_assert(fragsize);
+
+ *maxlength = pa_memblockq_get_maxlength(s->memblockq);
+
+ base = pa_frame_size(&s->source_output->sample_spec);
+
+ s->fragment_size = (*fragsize/base)*base;
+ if (s->fragment_size <= 0)
+ s->fragment_size = base;
+
+ if (s->fragment_size > *maxlength)
+ s->fragment_size = *maxlength;
+
+ *fragsize = s->fragment_size;
+}
+
static record_stream* record_stream_new(
connection *c,
pa_source *source,
pa_sample_spec *ss,
pa_channel_map *map,
+ pa_bool_t peak_detect,
uint32_t *maxlength,
uint32_t *fragsize,
pa_source_output_flags_t flags,
@@ -501,6 +555,8 @@ static record_stream* record_stream_new(
data.source = source;
pa_source_output_new_data_set_sample_spec(&data, ss);
pa_source_output_new_data_set_channel_map(&data, map);
+ if (peak_detect)
+ data.resample_method = PA_RESAMPLER_PEAKS;
source_output = pa_source_output_new(c->protocol->core, &data, flags);
@@ -522,30 +578,7 @@ static record_stream* record_stream_new(
s->source_output->suspend = source_output_suspend_cb;
s->source_output->userdata = s;
- if (*maxlength <= 0 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
- *maxlength = MAX_MEMBLOCKQ_LENGTH;
- if (*fragsize <= 0)
- *fragsize = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &source_output->sample_spec);
-
- if (adjust_latency) {
- pa_usec_t fragsize_usec;
-
- /* So, the user asked us to adjust the latency according to
- * the what the source can provide. Half the latency will be
- * spent on the hw buffer, half of it in the async buffer
- * queue we maintain for each client. */
-
- fragsize_usec = pa_bytes_to_usec(*fragsize, &source_output->sample_spec);
-
- s->source_latency = pa_source_output_set_requested_latency(source_output, fragsize_usec/2);
-
- if (fragsize_usec >= s->source_latency*2)
- fragsize_usec -= s->source_latency;
- else
- fragsize_usec = s->source_latency;
-
- *fragsize = pa_usec_to_bytes(fragsize_usec, &source_output->sample_spec);
- }
+ fix_record_buffer_attr_pre(s, adjust_latency, maxlength, fragsize);
s->memblockq = pa_memblockq_new(
0,
@@ -557,16 +590,7 @@ static record_stream* record_stream_new(
0,
NULL);
- *maxlength = pa_memblockq_get_maxlength(s->memblockq);
-
- s->fragment_size = (*fragsize/base)*base;
- if (s->fragment_size <= 0)
- s->fragment_size = base;
-
- if (s->fragment_size > *maxlength)
- s->fragment_size = *maxlength;
-
- *fragsize = s->fragment_size;
+ fix_record_buffer_attr_post(s, maxlength, fragsize);
*ss = s->source_output->sample_spec;
*map = s->source_output->channel_map;
@@ -674,6 +698,114 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata,
return 0;
}
+static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_latency, uint32_t *maxlength, uint32_t *tlength, uint32_t* prebuf, uint32_t* minreq) {
+ size_t frame_size;
+ pa_usec_t tlength_usec, minreq_usec, sink_usec;
+
+ pa_assert(s);
+ pa_assert(maxlength);
+ pa_assert(tlength);
+ pa_assert(prebuf);
+ pa_assert(minreq);
+
+ if (*maxlength <= 0 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
+ *maxlength = MAX_MEMBLOCKQ_LENGTH;
+ if (*tlength <= 0)
+ *tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
+ if (*minreq <= 0)
+ *minreq = pa_usec_to_bytes(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
+
+ frame_size = pa_frame_size(&s->sink_input->sample_spec);
+ if (*minreq <= 0)
+ *minreq = frame_size;
+ if (*tlength < *minreq+frame_size)
+ *tlength = *minreq+frame_size;
+
+ tlength_usec = pa_bytes_to_usec(*tlength, &s->sink_input->sample_spec);
+ minreq_usec = pa_bytes_to_usec(*minreq, &s->sink_input->sample_spec);
+
+ pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
+ (double) tlength_usec / PA_USEC_PER_MSEC,
+ (double) minreq_usec / PA_USEC_PER_MSEC);
+
+ if (adjust_latency) {
+
+ /* So, the user asked us to adjust the latency of the stream
+ * buffer according to the what the sink can provide. The
+ * tlength passed in shall be the overall latency. Roughly
+ * half the latency will be spent on the hw buffer, the other
+ * half of it in the async buffer queue we maintain for each
+ * client. In between we'll have a safety space of size
+ * 2*minreq. Why the 2*minreq? When the hw buffer is completey
+ * empty and needs to be filled, then our buffer must have
+ * enough data to fulfill this request immediatly and thus
+ * have at least the same tlength as the size of the hw
+ * buffer. It additionally needs space for 2 times minreq
+ * because if the buffer ran empty and a partial fillup
+ * happens immediately on the next iteration we need to be
+ * able to fulfill it and give the application also minreq
+ * time to fill it up again for the next request Makes 2 times
+ * minreq in plus.. */
+
+ if (tlength_usec > minreq_usec*2)
+ sink_usec = (tlength_usec - minreq_usec*2)/2;
+ else
+ sink_usec = 0;
+
+ } else {
+
+ /* Ok, the user didn't ask us to adjust the latency, but we
+ * still need to make sure that the parameters from the user
+ * do make sense. */
+
+ if (tlength_usec > minreq_usec*2)
+ sink_usec = (tlength_usec - minreq_usec*2);
+ else
+ sink_usec = 0;
+ }
+
+ s->sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
+
+ if (adjust_latency) {
+ /* Ok, we didn't necessarily get what we were asking for, so
+ * let's subtract from what we asked for for the remaining
+ * buffer space */
+
+ if (tlength_usec >= s->sink_latency)
+ tlength_usec -= s->sink_latency;
+ }
+
+ if (tlength_usec < s->sink_latency + 2*minreq_usec)
+ tlength_usec = s->sink_latency + 2*minreq_usec;
+
+ *tlength = pa_usec_to_bytes(tlength_usec, &s->sink_input->sample_spec);
+ *minreq = pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
+
+ if (*minreq <= 0) {
+ *minreq += frame_size;
+ *tlength += frame_size*2;
+ }
+
+ if (*tlength <= *minreq)
+ *tlength = *minreq*2 + frame_size;
+
+ if (*prebuf <= 0)
+ *prebuf = *tlength;
+}
+
+static void fix_playback_buffer_attr_post(playback_stream *s, uint32_t *maxlength, uint32_t *tlength, uint32_t* prebuf, uint32_t* minreq) {
+ pa_assert(s);
+ pa_assert(maxlength);
+ pa_assert(tlength);
+ pa_assert(prebuf);
+ pa_assert(minreq);
+
+ *maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq);
+ *tlength = (uint32_t) pa_memblockq_get_tlength(s->memblockq);
+ *prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq);
+ *minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq);
+}
+
static playback_stream* playback_stream_new(
connection *c,
pa_sink *sink,
@@ -697,8 +829,6 @@ static playback_stream* playback_stream_new(
uint32_t idx;
int64_t start_index;
pa_sink_input_new_data data;
- pa_usec_t tlength_usec, minreq_usec, sink_usec;
- size_t frame_size;
pa_assert(c);
pa_assert(ss);
@@ -769,90 +899,7 @@ static playback_stream* playback_stream_new(
start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
- if (*maxlength <= 0 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
- *maxlength = MAX_MEMBLOCKQ_LENGTH;
- if (*tlength <= 0)
- *tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &sink_input->sample_spec);
- if (*minreq <= 0)
- *minreq = pa_usec_to_bytes(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &sink_input->sample_spec);
-
- frame_size = pa_frame_size(&sink_input->sample_spec);
- if (*minreq <= 0)
- *minreq = frame_size;
- if (*tlength < *minreq+frame_size)
- *tlength = *minreq+frame_size;
-
- tlength_usec = pa_bytes_to_usec(*tlength, &sink_input->sample_spec);
- minreq_usec = pa_bytes_to_usec(*minreq, &sink_input->sample_spec);
-
- pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
- (double) tlength_usec / PA_USEC_PER_MSEC,
- (double) minreq_usec / PA_USEC_PER_MSEC);
-
- if (adjust_latency) {
-
- /* So, the user asked us to adjust the latency of the stream
- * buffer according to the what the sink can provide. The
- * tlength passed in shall be the overall latency. Roughly
- * half the latency will be spent on the hw buffer, the other
- * half of it in the async buffer queue we maintain for each
- * client. In between we'll have a safety space of size
- * 2*minreq. Why the 2*minreq? When the hw buffer is completey
- * empty and needs to be filled, then our buffer must have
- * enough data to fulfill this request immediatly and thus
- * have at least the same tlength as the size of the hw
- * buffer. It additionally needs space for 2 times minreq
- * because if the buffer ran empty and a partial fillup
- * happens immediately on the next iteration we need to be
- * able to fulfill it and give the application also minreq
- * time to fill it up again for the next request Makes 2 times
- * minreq in plus.. */
-
- if (tlength_usec > minreq_usec*2)
- sink_usec = (tlength_usec - minreq_usec*2)/2;
- else
- sink_usec = 0;
-
- } else {
-
- /* Ok, the user didn't ask us to adjust the latency, but we
- * still need to make sure that the parameters from the user
- * do make sense. */
-
- if (tlength_usec > minreq_usec*2)
- sink_usec = (tlength_usec - minreq_usec*2);
- else
- sink_usec = 0;
- }
-
- s->sink_latency = pa_sink_input_set_requested_latency(sink_input, sink_usec);
-
- if (adjust_latency) {
- /* Ok, we didn't necessarily get what we were asking for, so
- * let's subtract from what we asked for for the remaining
- * buffer space */
-
- if (tlength_usec >= s->sink_latency)
- tlength_usec -= s->sink_latency;
- }
-
- if (tlength_usec < s->sink_latency + 2*minreq_usec)
- tlength_usec = s->sink_latency + 2*minreq_usec;
-
- *tlength = pa_usec_to_bytes(tlength_usec, &sink_input->sample_spec);
- *minreq = pa_usec_to_bytes(minreq_usec, &sink_input->sample_spec);
-
- if (*minreq <= 0) {
- *minreq += frame_size;
- *tlength += frame_size*2;
- }
-
- if (*tlength <= *minreq)
- *tlength = *minreq*2 + frame_size;
-
- if (*prebuf <= 0)
- *prebuf = *tlength;
-
+ fix_playback_buffer_attr_pre(s, adjust_latency, maxlength, tlength, prebuf, minreq);
pa_sink_input_get_silence(sink_input, &silence);
s->memblockq = pa_memblockq_new(
@@ -866,17 +913,14 @@ static playback_stream* playback_stream_new(
&silence);
pa_memblock_unref(silence.memblock);
+ fix_playback_buffer_attr_post(s, maxlength, tlength, prebuf, minreq);
- *maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq);
- *tlength = (uint32_t) pa_memblockq_get_tlength(s->memblockq);
- *prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq);
- *minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq);
*missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
*ss = s->sink_input->sample_spec;
*map = s->sink_input->channel_map;
- s->minreq = pa_memblockq_get_minreq(s->memblockq);
+ s->minreq = *minreq;
pa_atomic_store(&s->missing, 0);
s->drain_request = FALSE;
@@ -1671,7 +1715,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
fix_channels = FALSE,
no_move = FALSE,
variable_rate = FALSE,
- adjust_latency = FALSE;
+ adjust_latency = FALSE,
+ peak_detect = FALSE;
pa_source_output_flags_t flags = 0;
pa_proplist *p;
@@ -1720,7 +1765,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
if (c->version >= 13) {
- if (pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
+ if (pa_tagstruct_get_boolean(t, &peak_detect) < 0 ||
+ pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
pa_tagstruct_get_proplist(t, p) < 0) {
protocol_error(c);
pa_proplist_free(p);
@@ -1761,7 +1807,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
(no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) |
(variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0);
- s = record_stream_new(c, source, &ss, &map, &maxlength, &fragment_size, flags, p, adjust_latency);
+ s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency);
pa_proplist_free(p);
CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
@@ -2940,6 +2986,7 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) {
playback_stream *s;
+ pa_bool_t adjust_latency = FALSE;
s = pa_idxset_get_by_index(c->output_streams, idx);
CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY);
@@ -2952,34 +2999,28 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
PA_TAG_U32, &prebuf,
PA_TAG_U32, &minreq,
PA_TAG_INVALID) < 0 ||
+ (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
!pa_tagstruct_eof(t)) {
protocol_error(c);
return;
}
- if (maxlength <= 0 || maxlength > MAX_MEMBLOCKQ_LENGTH)
- maxlength = MAX_MEMBLOCKQ_LENGTH;
- if (tlength <= 0)
- tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*1000, &s->sink_input->sample_spec);
- if (minreq <= 0)
- minreq = (tlength*9)/10;
- if (prebuf <= 0)
- prebuf = tlength;
-
+ fix_playback_buffer_attr_pre(s, adjust_latency, &maxlength, &tlength, &prebuf, &minreq);
pa_memblockq_set_maxlength(s->memblockq, maxlength);
pa_memblockq_set_tlength(s->memblockq, tlength);
pa_memblockq_set_prebuf(s->memblockq, prebuf);
pa_memblockq_set_minreq(s->memblockq, minreq);
+ fix_playback_buffer_attr_post(s, &maxlength, &tlength, &prebuf, &minreq);
reply = reply_new(tag);
- pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq));
- pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_tlength(s->memblockq));
- pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_prebuf(s->memblockq));
- pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_minreq(s->memblockq));
+ pa_tagstruct_putu32(reply, maxlength);
+ pa_tagstruct_putu32(reply, tlength);
+ pa_tagstruct_putu32(reply, prebuf);
+ pa_tagstruct_putu32(reply, minreq);
} else {
record_stream *s;
- size_t base;
+ pa_bool_t adjust_latency = FALSE;
pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR);
s = pa_idxset_get_by_index(c->record_streams, idx);
@@ -2990,29 +3031,19 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
PA_TAG_U32, &maxlength,
PA_TAG_U32, &fragsize,
PA_TAG_INVALID) < 0 ||
+ (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
!pa_tagstruct_eof(t)) {
protocol_error(c);
return;
}
- if (maxlength <= 0 || maxlength > MAX_MEMBLOCKQ_LENGTH)
- maxlength = MAX_MEMBLOCKQ_LENGTH;
- if (fragsize <= 0)
- fragsize = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*1000, &s->source_output->sample_spec);
-
+ fix_record_buffer_attr_pre(s, adjust_latency, &maxlength, &fragsize);
pa_memblockq_set_maxlength(s->memblockq, maxlength);
-
- base = pa_frame_size(&s->source_output->sample_spec);
- s->fragment_size = (fragsize/base)*base;
- if (s->fragment_size <= 0)
- s->fragment_size = base;
-
- if (s->fragment_size > pa_memblockq_get_maxlength(s->memblockq))
- s->fragment_size = pa_memblockq_get_maxlength(s->memblockq);
+ fix_record_buffer_attr_post(s, &maxlength, &fragsize);
reply = reply_new(tag);
- pa_tagstruct_putu32(reply, (uint32_t) pa_memblockq_get_maxlength(s->memblockq));
- pa_tagstruct_putu32(reply, s->fragment_size);
+ pa_tagstruct_putu32(reply, maxlength);
+ pa_tagstruct_putu32(reply, fragsize);
}
pa_pstream_send_tagstruct(c->pstream, reply);