mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-10-29 05:40:23 -04:00
notify clients about tlength changes
This commit is contained in:
parent
491aafd8dc
commit
65b787d000
7 changed files with 327 additions and 206 deletions
13
PROTOCOL
13
PROTOCOL
|
|
@ -168,3 +168,16 @@ PA_COMMAND_GET_MODULE_INFO_LIST
|
||||||
|
|
||||||
remove bool auto_unload
|
remove bool auto_unload
|
||||||
add proplist at the end
|
add proplist at the end
|
||||||
|
|
||||||
|
new messages:
|
||||||
|
|
||||||
|
PA_COMMAND_GET_CARD_INFO
|
||||||
|
PA_COMMAND_GET_CARD_INFO_LIST
|
||||||
|
PA_COMMAND_SET_CARD_PROFILE
|
||||||
|
|
||||||
|
PA_COMMAND_CLIENT_EVENT
|
||||||
|
PA_COMMAND_PLAYBACK_STREAM_EVENT
|
||||||
|
PA_COMMAND_RECORD_STREAM_EVENT
|
||||||
|
|
||||||
|
PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED
|
||||||
|
PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,9 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = {
|
||||||
[PA_COMMAND_EXTENSION] = pa_command_extension,
|
[PA_COMMAND_EXTENSION] = pa_command_extension,
|
||||||
[PA_COMMAND_PLAYBACK_STREAM_EVENT] = pa_command_stream_event,
|
[PA_COMMAND_PLAYBACK_STREAM_EVENT] = pa_command_stream_event,
|
||||||
[PA_COMMAND_RECORD_STREAM_EVENT] = pa_command_stream_event,
|
[PA_COMMAND_RECORD_STREAM_EVENT] = pa_command_stream_event,
|
||||||
[PA_COMMAND_CLIENT_EVENT] = pa_command_client_event
|
[PA_COMMAND_CLIENT_EVENT] = pa_command_client_event,
|
||||||
|
[PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr,
|
||||||
|
[PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED] = pa_command_stream_buffer_attr
|
||||||
};
|
};
|
||||||
static void context_free(pa_context *c);
|
static void context_free(pa_context *c);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -185,6 +185,8 @@ struct pa_stream {
|
||||||
void *started_userdata;
|
void *started_userdata;
|
||||||
pa_stream_event_cb_t event_callback;
|
pa_stream_event_cb_t event_callback;
|
||||||
void *event_userdata;
|
void *event_userdata;
|
||||||
|
pa_stream_notify_cb_t buffer_attr_callback;
|
||||||
|
void *buffer_attr_userdata;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*pa_operation_cb_t)(void);
|
typedef void (*pa_operation_cb_t)(void);
|
||||||
|
|
@ -213,6 +215,7 @@ void pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, p
|
||||||
void pa_command_stream_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
|
void pa_command_stream_started(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
|
||||||
void pa_command_stream_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
|
void pa_command_stream_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
|
||||||
void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
|
void pa_command_client_event(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
|
||||||
|
void pa_command_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata);
|
||||||
|
|
||||||
pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t callback, void *userdata);
|
pa_operation *pa_operation_new(pa_context *c, pa_stream *s, pa_operation_cb_t callback, void *userdata);
|
||||||
void pa_operation_done(pa_operation *o);
|
void pa_operation_done(pa_operation *o);
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ static void reset_callbacks(pa_stream *s) {
|
||||||
s->started_userdata = NULL;
|
s->started_userdata = NULL;
|
||||||
s->event_callback = NULL;
|
s->event_callback = NULL;
|
||||||
s->event_userdata = NULL;
|
s->event_userdata = NULL;
|
||||||
|
s->buffer_attr_callback = NULL;
|
||||||
|
s->buffer_attr_userdata = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pa_stream *pa_stream_new_with_proplist(
|
pa_stream *pa_stream_new_with_proplist(
|
||||||
|
|
@ -396,7 +398,7 @@ void pa_command_stream_moved(pa_pdispatch *pd, uint32_t command, uint32_t tag, p
|
||||||
const char *dn;
|
const char *dn;
|
||||||
pa_bool_t suspended;
|
pa_bool_t suspended;
|
||||||
uint32_t di;
|
uint32_t di;
|
||||||
pa_usec_t usec;
|
pa_usec_t usec = 0;
|
||||||
uint32_t maxlength = 0, fragsize = 0, minreq = 0, tlength = 0, prebuf = 0;
|
uint32_t maxlength = 0, fragsize = 0, minreq = 0, tlength = 0, prebuf = 0;
|
||||||
|
|
||||||
pa_assert(pd);
|
pa_assert(pd);
|
||||||
|
|
@ -486,6 +488,80 @@ finish:
|
||||||
pa_context_unref(c);
|
pa_context_unref(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pa_command_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||||
|
pa_context *c = userdata;
|
||||||
|
pa_stream *s;
|
||||||
|
uint32_t channel;
|
||||||
|
pa_usec_t usec = 0;
|
||||||
|
uint32_t maxlength = 0, fragsize = 0, minreq = 0, tlength = 0, prebuf = 0;
|
||||||
|
|
||||||
|
pa_assert(pd);
|
||||||
|
pa_assert(command == PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED || command == PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED);
|
||||||
|
pa_assert(t);
|
||||||
|
pa_assert(c);
|
||||||
|
pa_assert(PA_REFCNT_VALUE(c) >= 1);
|
||||||
|
|
||||||
|
pa_context_ref(c);
|
||||||
|
|
||||||
|
if (c->version < 15) {
|
||||||
|
pa_context_fail(c, PA_ERR_PROTOCOL);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pa_tagstruct_getu32(t, &channel) < 0) {
|
||||||
|
pa_context_fail(c, PA_ERR_PROTOCOL);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command == PA_COMMAND_RECORD_STREAM_MOVED) {
|
||||||
|
if (pa_tagstruct_getu32(t, &maxlength) < 0 ||
|
||||||
|
pa_tagstruct_getu32(t, &fragsize) < 0 ||
|
||||||
|
pa_tagstruct_get_usec(t, &usec) < 0) {
|
||||||
|
pa_context_fail(c, PA_ERR_PROTOCOL);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (pa_tagstruct_getu32(t, &maxlength) < 0 ||
|
||||||
|
pa_tagstruct_getu32(t, &tlength) < 0 ||
|
||||||
|
pa_tagstruct_getu32(t, &prebuf) < 0 ||
|
||||||
|
pa_tagstruct_getu32(t, &minreq) < 0 ||
|
||||||
|
pa_tagstruct_get_usec(t, &usec) < 0) {
|
||||||
|
pa_context_fail(c, PA_ERR_PROTOCOL);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pa_tagstruct_eof(t)) {
|
||||||
|
pa_context_fail(c, PA_ERR_PROTOCOL);
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(s = pa_dynarray_get(command == PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED ? c->playback_streams : c->record_streams, channel)))
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
if (s->state != PA_STREAM_READY)
|
||||||
|
goto finish;
|
||||||
|
|
||||||
|
if (s->direction == PA_STREAM_RECORD)
|
||||||
|
s->timing_info.configured_source_usec = usec;
|
||||||
|
else
|
||||||
|
s->timing_info.configured_sink_usec = usec;
|
||||||
|
|
||||||
|
s->buffer_attr.maxlength = maxlength;
|
||||||
|
s->buffer_attr.fragsize = fragsize;
|
||||||
|
s->buffer_attr.tlength = tlength;
|
||||||
|
s->buffer_attr.prebuf = prebuf;
|
||||||
|
s->buffer_attr.minreq = minreq;
|
||||||
|
|
||||||
|
request_auto_timing_update(s, TRUE);
|
||||||
|
|
||||||
|
if (s->buffer_attr_callback)
|
||||||
|
s->buffer_attr_callback(s, s->buffer_attr_userdata);
|
||||||
|
|
||||||
|
finish:
|
||||||
|
pa_context_unref(c);
|
||||||
|
}
|
||||||
|
|
||||||
void pa_command_stream_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
void pa_command_stream_suspended(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||||
pa_context *c = userdata;
|
pa_context *c = userdata;
|
||||||
pa_stream *s;
|
pa_stream *s;
|
||||||
|
|
@ -1798,6 +1874,20 @@ void pa_stream_set_event_callback(pa_stream *s, pa_stream_event_cb_t cb, void *u
|
||||||
s->event_userdata = userdata;
|
s->event_userdata = userdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pa_stream_set_buffer_attr_callback(pa_stream *s, pa_stream_notify_cb_t cb, void *userdata) {
|
||||||
|
pa_assert(s);
|
||||||
|
pa_assert(PA_REFCNT_VALUE(s) >= 1);
|
||||||
|
|
||||||
|
if (pa_detect_fork())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (s->state == PA_STREAM_TERMINATED || s->state == PA_STREAM_FAILED)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s->buffer_attr_callback = cb;
|
||||||
|
s->buffer_attr_userdata = userdata;
|
||||||
|
}
|
||||||
|
|
||||||
void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
void pa_stream_simple_ack_callback(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||||
pa_operation *o = userdata;
|
pa_operation *o = userdata;
|
||||||
int success = 1;
|
int success = 1;
|
||||||
|
|
|
||||||
|
|
@ -512,6 +512,13 @@ void pa_stream_set_suspended_callback(pa_stream *p, pa_stream_notify_cb_t cb, vo
|
||||||
* control event is received.\since 0.9.15 */
|
* control event is received.\since 0.9.15 */
|
||||||
void pa_stream_set_event_callback(pa_stream *p, pa_stream_event_cb_t cb, void *userdata);
|
void pa_stream_set_event_callback(pa_stream *p, pa_stream_event_cb_t cb, void *userdata);
|
||||||
|
|
||||||
|
/** Set the callback function that is called whenver the buffer
|
||||||
|
* attributes on the server side change. Please note that the buffer
|
||||||
|
* attributes can change when moving a stream to a different
|
||||||
|
* sink/source too, hence if you use this callback you should use
|
||||||
|
* pa_stream_set_moved_callback() as well. \since 0.9.15 */
|
||||||
|
void pa_stream_set_buffer_attr_callback(pa_stream *p, pa_stream_notify_cb_t cb, void *userdata);
|
||||||
|
|
||||||
/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. */
|
/** Pause (or resume) playback of this stream temporarily. Available on both playback and recording streams. */
|
||||||
pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata);
|
pa_operation* pa_stream_cork(pa_stream *s, int b, pa_stream_success_cb_t cb, void *userdata);
|
||||||
|
|
||||||
|
|
@ -530,7 +537,7 @@ pa_operation* pa_stream_prebuf(pa_stream *s, pa_stream_success_cb_t cb, void *us
|
||||||
* temporarily. Available for playback streams only. */
|
* temporarily. Available for playback streams only. */
|
||||||
pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
|
pa_operation* pa_stream_trigger(pa_stream *s, pa_stream_success_cb_t cb, void *userdata);
|
||||||
|
|
||||||
/** Rename the stream.*/
|
/** Rename the stream. */
|
||||||
pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata);
|
pa_operation* pa_stream_set_name(pa_stream *s, const char *name, pa_stream_success_cb_t cb, void *userdata);
|
||||||
|
|
||||||
/** Return the current playback/recording time. This is based on the
|
/** Return the current playback/recording time. This is based on the
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ enum {
|
||||||
/* Supported since protocol v14 (0.9.12) */
|
/* Supported since protocol v14 (0.9.12) */
|
||||||
PA_COMMAND_EXTENSION,
|
PA_COMMAND_EXTENSION,
|
||||||
|
|
||||||
/* Supported since protocol v15 (0.9.15*/
|
/* Supported since protocol v15 (0.9.15) */
|
||||||
PA_COMMAND_GET_CARD_INFO,
|
PA_COMMAND_GET_CARD_INFO,
|
||||||
PA_COMMAND_GET_CARD_INFO_LIST,
|
PA_COMMAND_GET_CARD_INFO_LIST,
|
||||||
PA_COMMAND_SET_CARD_PROFILE,
|
PA_COMMAND_SET_CARD_PROFILE,
|
||||||
|
|
@ -161,6 +161,10 @@ enum {
|
||||||
PA_COMMAND_PLAYBACK_STREAM_EVENT,
|
PA_COMMAND_PLAYBACK_STREAM_EVENT,
|
||||||
PA_COMMAND_RECORD_STREAM_EVENT,
|
PA_COMMAND_RECORD_STREAM_EVENT,
|
||||||
|
|
||||||
|
/* SERVER->CLIENT */
|
||||||
|
PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED,
|
||||||
|
PA_COMMAND_RECORD_BUFFER_ATTR_CHANGED,
|
||||||
|
|
||||||
PA_COMMAND_MAX
|
PA_COMMAND_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,11 @@ typedef struct record_stream {
|
||||||
|
|
||||||
pa_source_output *source_output;
|
pa_source_output *source_output;
|
||||||
pa_memblockq *memblockq;
|
pa_memblockq *memblockq;
|
||||||
size_t fragment_size;
|
|
||||||
|
pa_bool_t adjust_latency:1;
|
||||||
|
pa_bool_t early_requests:1;
|
||||||
|
|
||||||
|
pa_buffer_attr buffer_attr;
|
||||||
pa_usec_t source_latency;
|
pa_usec_t source_latency;
|
||||||
} record_stream;
|
} record_stream;
|
||||||
|
|
||||||
|
|
@ -105,14 +109,18 @@ typedef struct playback_stream {
|
||||||
|
|
||||||
pa_sink_input *sink_input;
|
pa_sink_input *sink_input;
|
||||||
pa_memblockq *memblockq;
|
pa_memblockq *memblockq;
|
||||||
|
|
||||||
|
pa_bool_t adjust_latency:1;
|
||||||
|
pa_bool_t early_requests:1;
|
||||||
|
|
||||||
pa_bool_t is_underrun:1;
|
pa_bool_t is_underrun:1;
|
||||||
pa_bool_t drain_request:1;
|
pa_bool_t drain_request:1;
|
||||||
uint32_t drain_tag;
|
uint32_t drain_tag;
|
||||||
uint32_t syncid;
|
uint32_t syncid;
|
||||||
|
|
||||||
pa_atomic_t missing;
|
pa_atomic_t missing;
|
||||||
size_t minreq;
|
|
||||||
pa_usec_t sink_latency;
|
pa_usec_t sink_latency;
|
||||||
|
pa_buffer_attr buffer_attr;
|
||||||
|
|
||||||
/* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
|
/* Only updated after SINK_INPUT_MESSAGE_UPDATE_LATENCY */
|
||||||
int64_t read_index, write_index;
|
int64_t read_index, write_index;
|
||||||
|
|
@ -180,7 +188,8 @@ enum {
|
||||||
SINK_INPUT_MESSAGE_TRIGGER,
|
SINK_INPUT_MESSAGE_TRIGGER,
|
||||||
SINK_INPUT_MESSAGE_SEEK,
|
SINK_INPUT_MESSAGE_SEEK,
|
||||||
SINK_INPUT_MESSAGE_PREBUF_FORCE,
|
SINK_INPUT_MESSAGE_PREBUF_FORCE,
|
||||||
SINK_INPUT_MESSAGE_UPDATE_LATENCY
|
SINK_INPUT_MESSAGE_UPDATE_LATENCY,
|
||||||
|
SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -188,7 +197,8 @@ enum {
|
||||||
PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
|
PLAYBACK_STREAM_MESSAGE_UNDERFLOW,
|
||||||
PLAYBACK_STREAM_MESSAGE_OVERFLOW,
|
PLAYBACK_STREAM_MESSAGE_OVERFLOW,
|
||||||
PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
|
PLAYBACK_STREAM_MESSAGE_DRAIN_ACK,
|
||||||
PLAYBACK_STREAM_MESSAGE_STARTED
|
PLAYBACK_STREAM_MESSAGE_STARTED,
|
||||||
|
PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
@ -478,35 +488,34 @@ static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, i
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fix_record_buffer_attr_pre(
|
/* Called from main context */
|
||||||
record_stream *s,
|
static void fix_record_buffer_attr_pre(record_stream *s) {
|
||||||
pa_bool_t adjust_latency,
|
|
||||||
pa_bool_t early_requests,
|
|
||||||
uint32_t *maxlength,
|
|
||||||
uint32_t *fragsize) {
|
|
||||||
|
|
||||||
size_t frame_size;
|
size_t frame_size;
|
||||||
pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
|
pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec;
|
||||||
|
|
||||||
pa_assert(s);
|
pa_assert(s);
|
||||||
pa_assert(maxlength);
|
|
||||||
pa_assert(fragsize);
|
/* This function will be called from the main thread, before as
|
||||||
|
* well as after the source output has been activated using
|
||||||
|
* pa_source_output_put()! That means it may not touch any
|
||||||
|
* ->thread_info data! */
|
||||||
|
|
||||||
frame_size = pa_frame_size(&s->source_output->sample_spec);
|
frame_size = pa_frame_size(&s->source_output->sample_spec);
|
||||||
|
|
||||||
if (*maxlength == (uint32_t) -1 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
|
if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
|
||||||
*maxlength = MAX_MEMBLOCKQ_LENGTH;
|
s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
|
||||||
if (*maxlength <= 0)
|
if (s->buffer_attr.maxlength <= 0)
|
||||||
*maxlength = (uint32_t) frame_size;
|
s->buffer_attr.maxlength = (uint32_t) frame_size;
|
||||||
|
|
||||||
if (*fragsize == (uint32_t) -1)
|
if (s->buffer_attr.fragsize == (uint32_t) -1)
|
||||||
*fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
|
s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec);
|
||||||
if (*fragsize <= 0)
|
if (s->buffer_attr.fragsize <= 0)
|
||||||
*fragsize = (uint32_t) frame_size;
|
s->buffer_attr.fragsize = (uint32_t) frame_size;
|
||||||
|
|
||||||
orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(*fragsize, &s->source_output->sample_spec);
|
orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(s->buffer_attr.fragsize, &s->source_output->sample_spec);
|
||||||
|
|
||||||
if (early_requests) {
|
if (s->early_requests) {
|
||||||
|
|
||||||
/* In early request mode we need to emulate the classic
|
/* In early request mode we need to emulate the classic
|
||||||
* fragment-based playback model. We do this setting the source
|
* fragment-based playback model. We do this setting the source
|
||||||
|
|
@ -514,7 +523,7 @@ static void fix_record_buffer_attr_pre(
|
||||||
|
|
||||||
source_usec = fragsize_usec;
|
source_usec = fragsize_usec;
|
||||||
|
|
||||||
} else if (adjust_latency) {
|
} else if (s->adjust_latency) {
|
||||||
|
|
||||||
/* So, the user asked us to adjust the latency according to
|
/* So, the user asked us to adjust the latency according to
|
||||||
* what the source can provide. Half the latency will be
|
* what the source can provide. Half the latency will be
|
||||||
|
|
@ -536,14 +545,14 @@ static void fix_record_buffer_attr_pre(
|
||||||
else
|
else
|
||||||
s->source_latency = 0;
|
s->source_latency = 0;
|
||||||
|
|
||||||
if (early_requests) {
|
if (s->early_requests) {
|
||||||
|
|
||||||
/* Ok, we didn't necessarily get what we were asking for, so
|
/* Ok, we didn't necessarily get what we were asking for, so
|
||||||
* let's tell the user */
|
* let's tell the user */
|
||||||
|
|
||||||
fragsize_usec = s->source_latency;
|
fragsize_usec = s->source_latency;
|
||||||
|
|
||||||
} else if (adjust_latency) {
|
} else if (s->adjust_latency) {
|
||||||
|
|
||||||
/* Now subtract what we actually got */
|
/* Now subtract what we actually got */
|
||||||
|
|
||||||
|
|
@ -556,35 +565,31 @@ static void fix_record_buffer_attr_pre(
|
||||||
if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
|
if (pa_usec_to_bytes(orig_fragsize_usec, &s->source_output->sample_spec) !=
|
||||||
pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
|
pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec))
|
||||||
|
|
||||||
*fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
|
s->buffer_attr.fragsize = (uint32_t) pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec);
|
||||||
|
|
||||||
if (*fragsize <= 0)
|
if (s->buffer_attr.fragsize <= 0)
|
||||||
*fragsize = (uint32_t) frame_size;
|
s->buffer_attr.fragsize = (uint32_t) frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fix_record_buffer_attr_post(
|
/* Called from main context */
|
||||||
record_stream *s,
|
static void fix_record_buffer_attr_post(record_stream *s) {
|
||||||
uint32_t *maxlength,
|
|
||||||
uint32_t *fragsize) {
|
|
||||||
|
|
||||||
size_t base;
|
size_t base;
|
||||||
|
|
||||||
pa_assert(s);
|
pa_assert(s);
|
||||||
pa_assert(maxlength);
|
|
||||||
pa_assert(fragsize);
|
|
||||||
|
|
||||||
*maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq);
|
/* This function will be called from the main thread, before as
|
||||||
|
* well as after the source output has been activated using
|
||||||
|
* pa_source_output_put()! That means it may not touch and
|
||||||
|
* ->thread_info data! */
|
||||||
|
|
||||||
base = pa_frame_size(&s->source_output->sample_spec);
|
base = pa_frame_size(&s->source_output->sample_spec);
|
||||||
|
|
||||||
s->fragment_size = (*fragsize/base)*base;
|
s->buffer_attr.fragsize = (s->buffer_attr.fragsize/base)*base;
|
||||||
if (s->fragment_size <= 0)
|
if (s->buffer_attr.fragsize <= 0)
|
||||||
s->fragment_size = base;
|
s->buffer_attr.fragsize = base;
|
||||||
|
|
||||||
if (s->fragment_size > *maxlength)
|
if (s->buffer_attr.fragsize > s->buffer_attr.maxlength)
|
||||||
s->fragment_size = *maxlength;
|
s->buffer_attr.fragsize = s->buffer_attr.maxlength;
|
||||||
|
|
||||||
*fragsize = (uint32_t) s->fragment_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from main context */
|
/* Called from main context */
|
||||||
|
|
@ -594,8 +599,7 @@ static record_stream* record_stream_new(
|
||||||
pa_sample_spec *ss,
|
pa_sample_spec *ss,
|
||||||
pa_channel_map *map,
|
pa_channel_map *map,
|
||||||
pa_bool_t peak_detect,
|
pa_bool_t peak_detect,
|
||||||
uint32_t *maxlength,
|
pa_buffer_attr *attr,
|
||||||
uint32_t *fragsize,
|
|
||||||
pa_source_output_flags_t flags,
|
pa_source_output_flags_t flags,
|
||||||
pa_proplist *p,
|
pa_proplist *p,
|
||||||
pa_bool_t adjust_latency,
|
pa_bool_t adjust_latency,
|
||||||
|
|
@ -610,7 +614,6 @@ static record_stream* record_stream_new(
|
||||||
|
|
||||||
pa_assert(c);
|
pa_assert(c);
|
||||||
pa_assert(ss);
|
pa_assert(ss);
|
||||||
pa_assert(maxlength);
|
|
||||||
pa_assert(p);
|
pa_assert(p);
|
||||||
pa_assert(ret);
|
pa_assert(ret);
|
||||||
|
|
||||||
|
|
@ -639,6 +642,9 @@ static record_stream* record_stream_new(
|
||||||
s->parent.process_msg = record_stream_process_msg;
|
s->parent.process_msg = record_stream_process_msg;
|
||||||
s->connection = c;
|
s->connection = c;
|
||||||
s->source_output = source_output;
|
s->source_output = source_output;
|
||||||
|
s->buffer_attr = *attr;
|
||||||
|
s->adjust_latency = adjust_latency;
|
||||||
|
s->early_requests = early_requests;
|
||||||
|
|
||||||
s->source_output->push = source_output_push_cb;
|
s->source_output->push = source_output_push_cb;
|
||||||
s->source_output->kill = source_output_kill_cb;
|
s->source_output->kill = source_output_kill_cb;
|
||||||
|
|
@ -648,11 +654,11 @@ static record_stream* record_stream_new(
|
||||||
s->source_output->send_event = source_output_send_event_cb;
|
s->source_output->send_event = source_output_send_event_cb;
|
||||||
s->source_output->userdata = s;
|
s->source_output->userdata = s;
|
||||||
|
|
||||||
fix_record_buffer_attr_pre(s, adjust_latency, early_requests, maxlength, fragsize);
|
fix_record_buffer_attr_pre(s);
|
||||||
|
|
||||||
s->memblockq = pa_memblockq_new(
|
s->memblockq = pa_memblockq_new(
|
||||||
0,
|
0,
|
||||||
*maxlength,
|
s->buffer_attr.maxlength,
|
||||||
0,
|
0,
|
||||||
base = pa_frame_size(&source_output->sample_spec),
|
base = pa_frame_size(&source_output->sample_spec),
|
||||||
1,
|
1,
|
||||||
|
|
@ -660,7 +666,8 @@ static record_stream* record_stream_new(
|
||||||
0,
|
0,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
fix_record_buffer_attr_post(s, maxlength, fragsize);
|
pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
|
||||||
|
fix_record_buffer_attr_post(s);
|
||||||
|
|
||||||
*ss = s->source_output->sample_spec;
|
*ss = s->source_output->sample_spec;
|
||||||
*map = s->source_output->channel_map;
|
*map = s->source_output->channel_map;
|
||||||
|
|
@ -668,8 +675,8 @@ static record_stream* record_stream_new(
|
||||||
pa_idxset_put(c->record_streams, s, &s->index);
|
pa_idxset_put(c->record_streams, s, &s->index);
|
||||||
|
|
||||||
pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
|
pa_log_info("Final latency %0.2f ms = %0.2f ms + %0.2f ms",
|
||||||
((double) pa_bytes_to_usec(s->fragment_size, &source_output->sample_spec) + (double) s->source_latency) / PA_USEC_PER_MSEC,
|
((double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) + (double) s->source_latency) / PA_USEC_PER_MSEC,
|
||||||
(double) pa_bytes_to_usec(s->fragment_size, &source_output->sample_spec) / PA_USEC_PER_MSEC,
|
(double) pa_bytes_to_usec(s->buffer_attr.fragsize, &source_output->sample_spec) / PA_USEC_PER_MSEC,
|
||||||
(double) s->source_latency / PA_USEC_PER_MSEC);
|
(double) s->source_latency / PA_USEC_PER_MSEC);
|
||||||
|
|
||||||
pa_source_output_put(s->source_output);
|
pa_source_output_put(s->source_output);
|
||||||
|
|
@ -799,67 +806,79 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata,
|
||||||
case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
|
case PLAYBACK_STREAM_MESSAGE_DRAIN_ACK:
|
||||||
pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
|
pa_pstream_send_simple_ack(s->connection->pstream, PA_PTR_TO_UINT(userdata));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH: {
|
||||||
|
pa_tagstruct *t;
|
||||||
|
|
||||||
|
s->buffer_attr.tlength = (uint32_t) offset;
|
||||||
|
|
||||||
|
t = pa_tagstruct_new(NULL, 0);
|
||||||
|
pa_tagstruct_putu32(t, PA_COMMAND_PLAYBACK_BUFFER_ATTR_CHANGED);
|
||||||
|
pa_tagstruct_putu32(t, (uint32_t) -1); /* tag */
|
||||||
|
pa_tagstruct_putu32(t, s->index);
|
||||||
|
pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
|
||||||
|
pa_tagstruct_putu32(t, s->buffer_attr.tlength);
|
||||||
|
pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
|
||||||
|
pa_tagstruct_putu32(t, s->buffer_attr.minreq);
|
||||||
|
pa_tagstruct_put_usec(t, s->sink_latency);
|
||||||
|
pa_pstream_send_tagstruct(s->connection->pstream, t);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fix_playback_buffer_attr_pre(
|
/* Called from main context */
|
||||||
playback_stream *s,
|
static void fix_playback_buffer_attr(playback_stream *s) {
|
||||||
pa_bool_t adjust_latency,
|
|
||||||
pa_bool_t early_requests,
|
|
||||||
uint32_t *maxlength,
|
|
||||||
uint32_t *tlength,
|
|
||||||
uint32_t* prebuf,
|
|
||||||
uint32_t* minreq) {
|
|
||||||
|
|
||||||
size_t frame_size;
|
size_t frame_size;
|
||||||
pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
|
pa_usec_t orig_tlength_usec, tlength_usec, orig_minreq_usec, minreq_usec, sink_usec;
|
||||||
|
|
||||||
pa_assert(s);
|
pa_assert(s);
|
||||||
pa_assert(maxlength);
|
|
||||||
pa_assert(tlength);
|
/* This function will be called from the main thread, before as
|
||||||
pa_assert(prebuf);
|
* well as after the sink input has been activated using
|
||||||
pa_assert(minreq);
|
* pa_sink_input_put()! That means it may not touch any
|
||||||
|
* ->thread_info data, such as the memblockq! */
|
||||||
|
|
||||||
frame_size = pa_frame_size(&s->sink_input->sample_spec);
|
frame_size = pa_frame_size(&s->sink_input->sample_spec);
|
||||||
|
|
||||||
if (*maxlength == (uint32_t) -1 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
|
if (s->buffer_attr.maxlength == (uint32_t) -1 || s->buffer_attr.maxlength > MAX_MEMBLOCKQ_LENGTH)
|
||||||
*maxlength = MAX_MEMBLOCKQ_LENGTH;
|
s->buffer_attr.maxlength = MAX_MEMBLOCKQ_LENGTH;
|
||||||
if (*maxlength <= 0)
|
if (s->buffer_attr.maxlength <= 0)
|
||||||
*maxlength = (uint32_t) frame_size;
|
s->buffer_attr.maxlength = (uint32_t) frame_size;
|
||||||
|
|
||||||
if (*tlength == (uint32_t) -1)
|
if (s->buffer_attr.tlength == (uint32_t) -1)
|
||||||
*tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
|
s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
|
||||||
if (*tlength <= 0)
|
if (s->buffer_attr.tlength <= 0)
|
||||||
*tlength = (uint32_t) frame_size;
|
s->buffer_attr.tlength = (uint32_t) frame_size;
|
||||||
|
|
||||||
if (*minreq == (uint32_t) -1)
|
if (s->buffer_attr.minreq == (uint32_t) -1)
|
||||||
*minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
|
s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec);
|
||||||
if (*minreq <= 0)
|
if (s->buffer_attr.minreq <= 0)
|
||||||
*minreq = (uint32_t) frame_size;
|
s->buffer_attr.minreq = (uint32_t) frame_size;
|
||||||
|
|
||||||
if (*tlength < *minreq+frame_size)
|
if (s->buffer_attr.tlength < s->buffer_attr.minreq+frame_size)
|
||||||
*tlength = *minreq+(uint32_t) frame_size;
|
s->buffer_attr.tlength = s->buffer_attr.minreq+(uint32_t) frame_size;
|
||||||
|
|
||||||
orig_tlength_usec = tlength_usec = pa_bytes_to_usec(*tlength, &s->sink_input->sample_spec);
|
orig_tlength_usec = tlength_usec = pa_bytes_to_usec(s->buffer_attr.tlength, &s->sink_input->sample_spec);
|
||||||
orig_minreq_usec = minreq_usec = pa_bytes_to_usec(*minreq, &s->sink_input->sample_spec);
|
orig_minreq_usec = minreq_usec = pa_bytes_to_usec(s->buffer_attr.minreq, &s->sink_input->sample_spec);
|
||||||
|
|
||||||
pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
|
pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms",
|
||||||
(double) tlength_usec / PA_USEC_PER_MSEC,
|
(double) tlength_usec / PA_USEC_PER_MSEC,
|
||||||
(double) minreq_usec / PA_USEC_PER_MSEC);
|
(double) minreq_usec / PA_USEC_PER_MSEC);
|
||||||
|
|
||||||
if (early_requests) {
|
if (s->early_requests) {
|
||||||
|
|
||||||
/* In early request mode we need to emulate the classic
|
/* In early request mode we need to emulate the classic
|
||||||
* fragment-based playback model. We do this setting the sink
|
* fragment-based playback model. We do this setting the sink
|
||||||
* latency to the fragment size. */
|
* latency to the fragment size. */
|
||||||
|
|
||||||
sink_usec = minreq_usec;
|
sink_usec = minreq_usec;
|
||||||
|
|
||||||
pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
|
pa_log_debug("Early requests mode enabled, configuring sink latency to minreq.");
|
||||||
|
|
||||||
} else if (adjust_latency) {
|
} else if (s->adjust_latency) {
|
||||||
|
|
||||||
/* So, the user asked us to adjust the latency of the stream
|
/* So, the user asked us to adjust the latency of the stream
|
||||||
* buffer according to the what the sink can provide. The
|
* buffer according to the what the sink can provide. The
|
||||||
|
|
@ -901,14 +920,14 @@ static void fix_playback_buffer_attr_pre(
|
||||||
|
|
||||||
s->sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
|
s->sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec);
|
||||||
|
|
||||||
if (early_requests) {
|
if (s->early_requests) {
|
||||||
|
|
||||||
/* Ok, we didn't necessarily get what we were asking for, so
|
/* Ok, we didn't necessarily get what we were asking for, so
|
||||||
* let's tell the user */
|
* let's tell the user */
|
||||||
|
|
||||||
minreq_usec = s->sink_latency;
|
minreq_usec = s->sink_latency;
|
||||||
|
|
||||||
} else if (adjust_latency) {
|
} else if (s->adjust_latency) {
|
||||||
|
|
||||||
/* Ok, we didn't necessarily get what we were asking for, so
|
/* Ok, we didn't necessarily get what we were asking for, so
|
||||||
* let's subtract from what we asked for for the remaining
|
* let's subtract from what we asked for for the remaining
|
||||||
|
|
@ -925,43 +944,22 @@ static void fix_playback_buffer_attr_pre(
|
||||||
|
|
||||||
if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
|
if (pa_usec_to_bytes_round_up(orig_tlength_usec, &s->sink_input->sample_spec) !=
|
||||||
pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
|
pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec))
|
||||||
*tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
|
s->buffer_attr.tlength = (uint32_t) pa_usec_to_bytes_round_up(tlength_usec, &s->sink_input->sample_spec);
|
||||||
|
|
||||||
if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
|
if (pa_usec_to_bytes(orig_minreq_usec, &s->sink_input->sample_spec) !=
|
||||||
pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
|
pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec))
|
||||||
*minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
|
s->buffer_attr.minreq = (uint32_t) pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec);
|
||||||
|
|
||||||
if (*minreq <= 0) {
|
if (s->buffer_attr.minreq <= 0) {
|
||||||
*minreq = (uint32_t) frame_size;
|
s->buffer_attr.minreq = (uint32_t) frame_size;
|
||||||
*tlength += (uint32_t) frame_size*2;
|
s->buffer_attr.tlength += (uint32_t) frame_size*2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*tlength <= *minreq)
|
if (s->buffer_attr.tlength <= s->buffer_attr.minreq)
|
||||||
*tlength = *minreq*2 + (uint32_t) frame_size;
|
s->buffer_attr.tlength = s->buffer_attr.minreq*2 + (uint32_t) frame_size;
|
||||||
|
|
||||||
if (*prebuf == (uint32_t) -1 || *prebuf > *tlength)
|
if (s->buffer_attr.prebuf == (uint32_t) -1 || s->buffer_attr.prebuf > s->buffer_attr.tlength)
|
||||||
*prebuf = *tlength;
|
s->buffer_attr.prebuf = s->buffer_attr.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);
|
|
||||||
|
|
||||||
s->minreq = *minreq;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from main context */
|
/* Called from main context */
|
||||||
|
|
@ -970,10 +968,7 @@ static playback_stream* playback_stream_new(
|
||||||
pa_sink *sink,
|
pa_sink *sink,
|
||||||
pa_sample_spec *ss,
|
pa_sample_spec *ss,
|
||||||
pa_channel_map *map,
|
pa_channel_map *map,
|
||||||
uint32_t *maxlength,
|
pa_buffer_attr *a,
|
||||||
uint32_t *tlength,
|
|
||||||
uint32_t *prebuf,
|
|
||||||
uint32_t *minreq,
|
|
||||||
pa_cvolume *volume,
|
pa_cvolume *volume,
|
||||||
pa_bool_t muted,
|
pa_bool_t muted,
|
||||||
pa_bool_t muted_set,
|
pa_bool_t muted_set,
|
||||||
|
|
@ -994,10 +989,6 @@ static playback_stream* playback_stream_new(
|
||||||
|
|
||||||
pa_assert(c);
|
pa_assert(c);
|
||||||
pa_assert(ss);
|
pa_assert(ss);
|
||||||
pa_assert(maxlength);
|
|
||||||
pa_assert(tlength);
|
|
||||||
pa_assert(prebuf);
|
|
||||||
pa_assert(minreq);
|
|
||||||
pa_assert(missing);
|
pa_assert(missing);
|
||||||
pa_assert(p);
|
pa_assert(p);
|
||||||
pa_assert(ret);
|
pa_assert(ret);
|
||||||
|
|
@ -1054,6 +1045,9 @@ static playback_stream* playback_stream_new(
|
||||||
s->is_underrun = TRUE;
|
s->is_underrun = TRUE;
|
||||||
s->drain_request = FALSE;
|
s->drain_request = FALSE;
|
||||||
pa_atomic_store(&s->missing, 0);
|
pa_atomic_store(&s->missing, 0);
|
||||||
|
s->buffer_attr = *a;
|
||||||
|
s->adjust_latency = adjust_latency;
|
||||||
|
s->early_requests = early_requests;
|
||||||
|
|
||||||
s->sink_input->parent.process_msg = sink_input_process_msg;
|
s->sink_input->parent.process_msg = sink_input_process_msg;
|
||||||
s->sink_input->pop = sink_input_pop_cb;
|
s->sink_input->pop = sink_input_pop_cb;
|
||||||
|
|
@ -1068,21 +1062,21 @@ static playback_stream* playback_stream_new(
|
||||||
|
|
||||||
start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
|
start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
|
||||||
|
|
||||||
fix_playback_buffer_attr_pre(s, adjust_latency, early_requests, maxlength, tlength, prebuf, minreq);
|
fix_playback_buffer_attr(s);
|
||||||
pa_sink_input_get_silence(sink_input, &silence);
|
|
||||||
|
|
||||||
|
pa_sink_input_get_silence(sink_input, &silence);
|
||||||
s->memblockq = pa_memblockq_new(
|
s->memblockq = pa_memblockq_new(
|
||||||
start_index,
|
start_index,
|
||||||
*maxlength,
|
s->buffer_attr.maxlength,
|
||||||
*tlength,
|
s->buffer_attr.tlength,
|
||||||
pa_frame_size(&sink_input->sample_spec),
|
pa_frame_size(&sink_input->sample_spec),
|
||||||
*prebuf,
|
s->buffer_attr.prebuf,
|
||||||
*minreq,
|
s->buffer_attr.minreq,
|
||||||
0,
|
0,
|
||||||
&silence);
|
&silence);
|
||||||
|
|
||||||
pa_memblock_unref(silence.memblock);
|
pa_memblock_unref(silence.memblock);
|
||||||
fix_playback_buffer_attr_post(s, maxlength, tlength, prebuf, minreq);
|
|
||||||
|
pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
|
||||||
|
|
||||||
*missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
|
*missing = (uint32_t) pa_memblockq_pop_missing(s->memblockq);
|
||||||
|
|
||||||
|
|
@ -1092,9 +1086,9 @@ static playback_stream* playback_stream_new(
|
||||||
pa_idxset_put(c->output_streams, s, &s->index);
|
pa_idxset_put(c->output_streams, s, &s->index);
|
||||||
|
|
||||||
pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
|
pa_log_info("Final latency %0.2f ms = %0.2f ms + 2*%0.2f ms + %0.2f ms",
|
||||||
((double) pa_bytes_to_usec(*tlength, &sink_input->sample_spec) + (double) s->sink_latency) / PA_USEC_PER_MSEC,
|
((double) pa_bytes_to_usec(s->buffer_attr.tlength, &sink_input->sample_spec) + (double) s->sink_latency) / PA_USEC_PER_MSEC,
|
||||||
(double) pa_bytes_to_usec(*tlength-*minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
|
(double) pa_bytes_to_usec(s->buffer_attr.tlength-s->buffer_attr.minreq*2, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
|
||||||
(double) pa_bytes_to_usec(*minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
|
(double) pa_bytes_to_usec(s->buffer_attr.minreq, &sink_input->sample_spec) / PA_USEC_PER_MSEC,
|
||||||
(double) s->sink_latency / PA_USEC_PER_MSEC);
|
(double) s->sink_latency / PA_USEC_PER_MSEC);
|
||||||
|
|
||||||
pa_sink_input_put(s->sink_input);
|
pa_sink_input_put(s->sink_input);
|
||||||
|
|
@ -1103,7 +1097,7 @@ static playback_stream* playback_stream_new(
|
||||||
|
|
||||||
/* Called from IO context */
|
/* Called from IO context */
|
||||||
static void playback_stream_request_bytes(playback_stream *s) {
|
static void playback_stream_request_bytes(playback_stream *s) {
|
||||||
size_t m, previous_missing;
|
size_t m, previous_missing, minreq;
|
||||||
|
|
||||||
playback_stream_assert_ref(s);
|
playback_stream_assert_ref(s);
|
||||||
|
|
||||||
|
|
@ -1115,9 +1109,10 @@ static void playback_stream_request_bytes(playback_stream *s) {
|
||||||
/* pa_log("request_bytes(%lu)", (unsigned long) m); */
|
/* pa_log("request_bytes(%lu)", (unsigned long) m); */
|
||||||
|
|
||||||
previous_missing = (size_t) pa_atomic_add(&s->missing, (int) m);
|
previous_missing = (size_t) pa_atomic_add(&s->missing, (int) m);
|
||||||
|
minreq = pa_memblockq_get_minreq(s->memblockq);
|
||||||
|
|
||||||
if (pa_memblockq_prebuf_active(s->memblockq) ||
|
if (pa_memblockq_prebuf_active(s->memblockq) ||
|
||||||
(previous_missing < s->minreq && previous_missing+m >= s->minreq))
|
(previous_missing < minreq && previous_missing+m >= minreq))
|
||||||
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
|
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_REQUEST_DATA, NULL, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1234,8 +1229,8 @@ static void native_connection_send_memblock(pa_native_connection *c) {
|
||||||
if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
|
if (pa_memblockq_peek(r->memblockq, &chunk) >= 0) {
|
||||||
pa_memchunk schunk = chunk;
|
pa_memchunk schunk = chunk;
|
||||||
|
|
||||||
if (schunk.length > r->fragment_size)
|
if (schunk.length > r->buffer_attr.fragsize)
|
||||||
schunk.length = r->fragment_size;
|
schunk.length = r->buffer_attr.fragsize;
|
||||||
|
|
||||||
pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
|
pa_pstream_send_memblock(c->pstream, r->index, 0, PA_SEEK_RELATIVE, &schunk);
|
||||||
|
|
||||||
|
|
@ -1417,6 +1412,12 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int
|
||||||
* latency added by the resampler */
|
* latency added by the resampler */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR: {
|
||||||
|
pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
|
||||||
|
pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
|
return pa_sink_input_process_msg(o, code, userdata, offset, chunk);
|
||||||
|
|
@ -1502,8 +1503,10 @@ static void sink_input_update_max_request_cb(pa_sink_input *i, size_t nbytes) {
|
||||||
|
|
||||||
tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
|
tlength = nbytes+2*pa_memblockq_get_minreq(s->memblockq);
|
||||||
|
|
||||||
if (pa_memblockq_get_tlength(s->memblockq) < tlength)
|
if (pa_memblockq_get_tlength(s->memblockq) < tlength) {
|
||||||
pa_memblockq_set_tlength(s->memblockq, tlength);
|
pa_memblockq_set_tlength(s->memblockq, tlength);
|
||||||
|
pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_UPDATE_TLENGTH, NULL, pa_memblockq_get_tlength(s->memblockq), NULL, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called from main context */
|
/* Called from main context */
|
||||||
|
|
@ -1563,23 +1566,14 @@ static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspend) {
|
||||||
static void sink_input_moving_cb(pa_sink_input *i) {
|
static void sink_input_moving_cb(pa_sink_input *i) {
|
||||||
playback_stream *s;
|
playback_stream *s;
|
||||||
pa_tagstruct *t;
|
pa_tagstruct *t;
|
||||||
uint32_t maxlength, tlength, prebuf, minreq;
|
|
||||||
|
|
||||||
pa_sink_input_assert_ref(i);
|
pa_sink_input_assert_ref(i);
|
||||||
s = PLAYBACK_STREAM(i->userdata);
|
s = PLAYBACK_STREAM(i->userdata);
|
||||||
playback_stream_assert_ref(s);
|
playback_stream_assert_ref(s);
|
||||||
|
|
||||||
maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq);
|
fix_playback_buffer_attr(s);
|
||||||
tlength = (uint32_t) pa_memblockq_get_tlength(s->memblockq);
|
pa_memblockq_apply_attr(s->memblockq, &s->buffer_attr);
|
||||||
prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq);
|
pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
|
||||||
minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq);
|
|
||||||
|
|
||||||
fix_playback_buffer_attr_pre(s, TRUE, FALSE, &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);
|
|
||||||
|
|
||||||
if (s->connection->version < 12)
|
if (s->connection->version < 12)
|
||||||
return;
|
return;
|
||||||
|
|
@ -1593,10 +1587,10 @@ static void sink_input_moving_cb(pa_sink_input *i) {
|
||||||
pa_tagstruct_put_boolean(t, pa_sink_get_state(i->sink) == PA_SINK_SUSPENDED);
|
pa_tagstruct_put_boolean(t, pa_sink_get_state(i->sink) == PA_SINK_SUSPENDED);
|
||||||
|
|
||||||
if (s->connection->version >= 13) {
|
if (s->connection->version >= 13) {
|
||||||
pa_tagstruct_putu32(t, maxlength);
|
pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
|
||||||
pa_tagstruct_putu32(t, tlength);
|
pa_tagstruct_putu32(t, s->buffer_attr.tlength);
|
||||||
pa_tagstruct_putu32(t, prebuf);
|
pa_tagstruct_putu32(t, s->buffer_attr.prebuf);
|
||||||
pa_tagstruct_putu32(t, minreq);
|
pa_tagstruct_putu32(t, s->buffer_attr.minreq);
|
||||||
pa_tagstruct_put_usec(t, s->sink_latency);
|
pa_tagstruct_put_usec(t, s->sink_latency);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1685,18 +1679,15 @@ static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspend) {
|
||||||
static void source_output_moving_cb(pa_source_output *o) {
|
static void source_output_moving_cb(pa_source_output *o) {
|
||||||
record_stream *s;
|
record_stream *s;
|
||||||
pa_tagstruct *t;
|
pa_tagstruct *t;
|
||||||
uint32_t maxlength, fragsize;
|
|
||||||
|
|
||||||
pa_source_output_assert_ref(o);
|
pa_source_output_assert_ref(o);
|
||||||
s = RECORD_STREAM(o->userdata);
|
s = RECORD_STREAM(o->userdata);
|
||||||
record_stream_assert_ref(s);
|
record_stream_assert_ref(s);
|
||||||
|
|
||||||
fragsize = (uint32_t) s->fragment_size;
|
fix_record_buffer_attr_pre(s);
|
||||||
maxlength = (uint32_t) pa_memblockq_get_length(s->memblockq);
|
pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
|
||||||
|
pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
|
||||||
fix_record_buffer_attr_pre(s, TRUE, FALSE, &maxlength, &fragsize);
|
fix_record_buffer_attr_post(s);
|
||||||
pa_memblockq_set_maxlength(s->memblockq, maxlength);
|
|
||||||
fix_record_buffer_attr_post(s, &maxlength, &fragsize);
|
|
||||||
|
|
||||||
if (s->connection->version < 12)
|
if (s->connection->version < 12)
|
||||||
return;
|
return;
|
||||||
|
|
@ -1710,8 +1701,8 @@ static void source_output_moving_cb(pa_source_output *o) {
|
||||||
pa_tagstruct_put_boolean(t, pa_source_get_state(o->source) == PA_SOURCE_SUSPENDED);
|
pa_tagstruct_put_boolean(t, pa_source_get_state(o->source) == PA_SOURCE_SUSPENDED);
|
||||||
|
|
||||||
if (s->connection->version >= 13) {
|
if (s->connection->version >= 13) {
|
||||||
pa_tagstruct_putu32(t, maxlength);
|
pa_tagstruct_putu32(t, s->buffer_attr.maxlength);
|
||||||
pa_tagstruct_putu32(t, fragsize);
|
pa_tagstruct_putu32(t, s->buffer_attr.fragsize);
|
||||||
pa_tagstruct_put_usec(t, s->source_latency);
|
pa_tagstruct_put_usec(t, s->source_latency);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1744,7 +1735,8 @@ static pa_tagstruct *reply_new(uint32_t tag) {
|
||||||
static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||||
pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
|
pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
|
||||||
playback_stream *s;
|
playback_stream *s;
|
||||||
uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid, missing;
|
uint32_t sink_index, syncid, missing;
|
||||||
|
pa_buffer_attr attr;
|
||||||
const char *name = NULL, *sink_name;
|
const char *name = NULL, *sink_name;
|
||||||
pa_sample_spec ss;
|
pa_sample_spec ss;
|
||||||
pa_channel_map map;
|
pa_channel_map map;
|
||||||
|
|
@ -1773,6 +1765,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
|
||||||
|
|
||||||
pa_native_connection_assert_ref(c);
|
pa_native_connection_assert_ref(c);
|
||||||
pa_assert(t);
|
pa_assert(t);
|
||||||
|
memset(&attr, 0, sizeof(attr));
|
||||||
|
|
||||||
if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
|
if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
|
||||||
pa_tagstruct_get(
|
pa_tagstruct_get(
|
||||||
|
|
@ -1781,11 +1774,11 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
|
||||||
PA_TAG_CHANNEL_MAP, &map,
|
PA_TAG_CHANNEL_MAP, &map,
|
||||||
PA_TAG_U32, &sink_index,
|
PA_TAG_U32, &sink_index,
|
||||||
PA_TAG_STRING, &sink_name,
|
PA_TAG_STRING, &sink_name,
|
||||||
PA_TAG_U32, &maxlength,
|
PA_TAG_U32, &attr.maxlength,
|
||||||
PA_TAG_BOOLEAN, &corked,
|
PA_TAG_BOOLEAN, &corked,
|
||||||
PA_TAG_U32, &tlength,
|
PA_TAG_U32, &attr.tlength,
|
||||||
PA_TAG_U32, &prebuf,
|
PA_TAG_U32, &attr.prebuf,
|
||||||
PA_TAG_U32, &minreq,
|
PA_TAG_U32, &attr.minreq,
|
||||||
PA_TAG_U32, &syncid,
|
PA_TAG_U32, &syncid,
|
||||||
PA_TAG_CVOLUME, &volume,
|
PA_TAG_CVOLUME, &volume,
|
||||||
PA_TAG_INVALID) < 0) {
|
PA_TAG_INVALID) < 0) {
|
||||||
|
|
@ -1896,7 +1889,7 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
|
||||||
* flag. For older versions we synthesize it here */
|
* flag. For older versions we synthesize it here */
|
||||||
muted_set = muted_set || muted;
|
muted_set = muted_set || muted;
|
||||||
|
|
||||||
s = playback_stream_new(c, sink, &ss, &map, &maxlength, &tlength, &prebuf, &minreq, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, &ret);
|
s = playback_stream_new(c, sink, &ss, &map, &attr, volume_set ? &volume : NULL, muted, muted_set, syncid, &missing, flags, p, adjust_latency, early_requests, &ret);
|
||||||
pa_proplist_free(p);
|
pa_proplist_free(p);
|
||||||
|
|
||||||
CHECK_VALIDITY(c->pstream, s, tag, ret);
|
CHECK_VALIDITY(c->pstream, s, tag, ret);
|
||||||
|
|
@ -1912,10 +1905,10 @@ static void command_create_playback_stream(pa_pdispatch *pd, uint32_t command, u
|
||||||
if (c->version >= 9) {
|
if (c->version >= 9) {
|
||||||
/* Since 0.9.0 we support sending the buffer metrics back to the client */
|
/* Since 0.9.0 we support sending the buffer metrics back to the client */
|
||||||
|
|
||||||
pa_tagstruct_putu32(reply, (uint32_t) maxlength);
|
pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
|
||||||
pa_tagstruct_putu32(reply, (uint32_t) tlength);
|
pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.tlength);
|
||||||
pa_tagstruct_putu32(reply, (uint32_t) prebuf);
|
pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.prebuf);
|
||||||
pa_tagstruct_putu32(reply, (uint32_t) minreq);
|
pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.minreq);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->version >= 12) {
|
if (c->version >= 12) {
|
||||||
|
|
@ -1999,7 +1992,7 @@ static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t t
|
||||||
static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||||
pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
|
pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
|
||||||
record_stream *s;
|
record_stream *s;
|
||||||
uint32_t maxlength, fragment_size;
|
pa_buffer_attr attr;
|
||||||
uint32_t source_index;
|
uint32_t source_index;
|
||||||
const char *name = NULL, *source_name;
|
const char *name = NULL, *source_name;
|
||||||
pa_sample_spec ss;
|
pa_sample_spec ss;
|
||||||
|
|
@ -2029,14 +2022,16 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
|
||||||
pa_native_connection_assert_ref(c);
|
pa_native_connection_assert_ref(c);
|
||||||
pa_assert(t);
|
pa_assert(t);
|
||||||
|
|
||||||
|
memset(&attr, 0, sizeof(attr));
|
||||||
|
|
||||||
if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
|
if ((c->version < 13 && (pa_tagstruct_gets(t, &name) < 0 || !name)) ||
|
||||||
pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
|
pa_tagstruct_get_sample_spec(t, &ss) < 0 ||
|
||||||
pa_tagstruct_get_channel_map(t, &map) < 0 ||
|
pa_tagstruct_get_channel_map(t, &map) < 0 ||
|
||||||
pa_tagstruct_getu32(t, &source_index) < 0 ||
|
pa_tagstruct_getu32(t, &source_index) < 0 ||
|
||||||
pa_tagstruct_gets(t, &source_name) < 0 ||
|
pa_tagstruct_gets(t, &source_name) < 0 ||
|
||||||
pa_tagstruct_getu32(t, &maxlength) < 0 ||
|
pa_tagstruct_getu32(t, &attr.maxlength) < 0 ||
|
||||||
pa_tagstruct_get_boolean(t, &corked) < 0 ||
|
pa_tagstruct_get_boolean(t, &corked) < 0 ||
|
||||||
pa_tagstruct_getu32(t, &fragment_size) < 0) {
|
pa_tagstruct_getu32(t, &attr.fragsize) < 0) {
|
||||||
protocol_error(c);
|
protocol_error(c);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -2146,7 +2141,7 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
|
||||||
(dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
|
(dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0) |
|
||||||
(fail_on_suspend ? PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND : 0);
|
(fail_on_suspend ? PA_SOURCE_OUTPUT_FAIL_ON_SUSPEND : 0);
|
||||||
|
|
||||||
s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
|
s = record_stream_new(c, source, &ss, &map, peak_detect, &attr, flags, p, adjust_latency, direct_on_input, early_requests, &ret);
|
||||||
pa_proplist_free(p);
|
pa_proplist_free(p);
|
||||||
|
|
||||||
CHECK_VALIDITY(c->pstream, s, tag, ret);
|
CHECK_VALIDITY(c->pstream, s, tag, ret);
|
||||||
|
|
@ -2159,8 +2154,8 @@ static void command_create_record_stream(pa_pdispatch *pd, uint32_t command, uin
|
||||||
if (c->version >= 9) {
|
if (c->version >= 9) {
|
||||||
/* Since 0.9 we support sending the buffer metrics back to the client */
|
/* Since 0.9 we support sending the buffer metrics back to the client */
|
||||||
|
|
||||||
pa_tagstruct_putu32(reply, (uint32_t) maxlength);
|
pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.maxlength);
|
||||||
pa_tagstruct_putu32(reply, (uint32_t) fragment_size);
|
pa_tagstruct_putu32(reply, (uint32_t) s->buffer_attr.fragsize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->version >= 12) {
|
if (c->version >= 12) {
|
||||||
|
|
@ -3456,12 +3451,14 @@ static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint
|
||||||
static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||||
pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
|
pa_native_connection *c = PA_NATIVE_CONNECTION(userdata);
|
||||||
uint32_t idx;
|
uint32_t idx;
|
||||||
uint32_t maxlength, tlength, prebuf, minreq, fragsize;
|
pa_buffer_attr a;
|
||||||
pa_tagstruct *reply;
|
pa_tagstruct *reply;
|
||||||
|
|
||||||
pa_native_connection_assert_ref(c);
|
pa_native_connection_assert_ref(c);
|
||||||
pa_assert(t);
|
pa_assert(t);
|
||||||
|
|
||||||
|
memset(&a, 0, sizeof(a));
|
||||||
|
|
||||||
if (pa_tagstruct_getu32(t, &idx) < 0) {
|
if (pa_tagstruct_getu32(t, &idx) < 0) {
|
||||||
protocol_error(c);
|
protocol_error(c);
|
||||||
return;
|
return;
|
||||||
|
|
@ -3479,10 +3476,10 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
|
||||||
|
|
||||||
if (pa_tagstruct_get(
|
if (pa_tagstruct_get(
|
||||||
t,
|
t,
|
||||||
PA_TAG_U32, &maxlength,
|
PA_TAG_U32, &a.maxlength,
|
||||||
PA_TAG_U32, &tlength,
|
PA_TAG_U32, &a.tlength,
|
||||||
PA_TAG_U32, &prebuf,
|
PA_TAG_U32, &a.prebuf,
|
||||||
PA_TAG_U32, &minreq,
|
PA_TAG_U32, &a.minreq,
|
||||||
PA_TAG_INVALID) < 0 ||
|
PA_TAG_INVALID) < 0 ||
|
||||||
(c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
|
(c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
|
||||||
(c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
|
(c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
|
||||||
|
|
@ -3491,18 +3488,18 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fix_playback_buffer_attr_pre(s, adjust_latency, early_requests, &maxlength, &tlength, &prebuf, &minreq);
|
s->adjust_latency = adjust_latency;
|
||||||
pa_memblockq_set_maxlength(s->memblockq, maxlength);
|
s->early_requests = early_requests;
|
||||||
pa_memblockq_set_tlength(s->memblockq, tlength);
|
s->buffer_attr = a;
|
||||||
pa_memblockq_set_prebuf(s->memblockq, prebuf);
|
|
||||||
pa_memblockq_set_minreq(s->memblockq, minreq);
|
fix_playback_buffer_attr(s);
|
||||||
fix_playback_buffer_attr_post(s, &maxlength, &tlength, &prebuf, &minreq);
|
pa_assert_se(pa_asyncmsgq_send(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_UPDATE_BUFFER_ATTR, NULL, 0, NULL) == 0);
|
||||||
|
|
||||||
reply = reply_new(tag);
|
reply = reply_new(tag);
|
||||||
pa_tagstruct_putu32(reply, maxlength);
|
pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
|
||||||
pa_tagstruct_putu32(reply, tlength);
|
pa_tagstruct_putu32(reply, s->buffer_attr.tlength);
|
||||||
pa_tagstruct_putu32(reply, prebuf);
|
pa_tagstruct_putu32(reply, s->buffer_attr.prebuf);
|
||||||
pa_tagstruct_putu32(reply, minreq);
|
pa_tagstruct_putu32(reply, s->buffer_attr.minreq);
|
||||||
|
|
||||||
if (c->version >= 13)
|
if (c->version >= 13)
|
||||||
pa_tagstruct_put_usec(reply, s->sink_latency);
|
pa_tagstruct_put_usec(reply, s->sink_latency);
|
||||||
|
|
@ -3517,8 +3514,8 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
|
||||||
|
|
||||||
if (pa_tagstruct_get(
|
if (pa_tagstruct_get(
|
||||||
t,
|
t,
|
||||||
PA_TAG_U32, &maxlength,
|
PA_TAG_U32, &a.maxlength,
|
||||||
PA_TAG_U32, &fragsize,
|
PA_TAG_U32, &a.fragsize,
|
||||||
PA_TAG_INVALID) < 0 ||
|
PA_TAG_INVALID) < 0 ||
|
||||||
(c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
|
(c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) ||
|
||||||
(c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
|
(c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) ||
|
||||||
|
|
@ -3527,13 +3524,18 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fix_record_buffer_attr_pre(s, adjust_latency, early_requests, &maxlength, &fragsize);
|
s->adjust_latency = adjust_latency;
|
||||||
pa_memblockq_set_maxlength(s->memblockq, maxlength);
|
s->early_requests = early_requests;
|
||||||
fix_record_buffer_attr_post(s, &maxlength, &fragsize);
|
s->buffer_attr = a;
|
||||||
|
|
||||||
|
fix_record_buffer_attr_pre(s);
|
||||||
|
pa_memblockq_set_maxlength(s->memblockq, s->buffer_attr.maxlength);
|
||||||
|
pa_memblockq_get_attr(s->memblockq, &s->buffer_attr);
|
||||||
|
fix_record_buffer_attr_post(s);
|
||||||
|
|
||||||
reply = reply_new(tag);
|
reply = reply_new(tag);
|
||||||
pa_tagstruct_putu32(reply, maxlength);
|
pa_tagstruct_putu32(reply, s->buffer_attr.maxlength);
|
||||||
pa_tagstruct_putu32(reply, fragsize);
|
pa_tagstruct_putu32(reply, s->buffer_attr.fragsize);
|
||||||
|
|
||||||
if (c->version >= 13)
|
if (c->version >= 13)
|
||||||
pa_tagstruct_put_usec(reply, s->source_latency);
|
pa_tagstruct_put_usec(reply, s->source_latency);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue