mirror of
https://gitlab.freedesktop.org/pulseaudio/pulseaudio.git
synced 2025-11-18 06:59:57 -05:00
- deprecate autoload stuff
- allow setting of the requested latency of a sink input/source output before _put() is called - allow sinks/sources to have a "minimal" latency which applies to all requested latencies by sink inputs/source outputs - add new client library flags PA_STREAM_ADJUST_LATENCY, PA_STREAM_START_MUTED - allow client library to fill in 0 to buffer_attr fields - update module-alsa-source following module-alsa-sink - other cleanups and fixes git-svn-id: file:///home/lennart/svn/public/pulseaudio/branches/glitch-free@2215 fefdeb5f-60dc-0310-8127-8f9354f1896f
This commit is contained in:
parent
ecf6439661
commit
cdfcf6654c
26 changed files with 708 additions and 260 deletions
|
|
@ -155,10 +155,10 @@ static const struct command commands[] = {
|
|||
{ "load-sample-dir-lazy", pa_cli_command_scache_load_dir, "Lazily load all files in a directory into the sample cache (args: pathname)", 2},
|
||||
{ "play-file", pa_cli_command_play_file, "Play a sound file (args: filename, sink|index)", 3},
|
||||
{ "list-autoload", pa_cli_command_autoload_list, "List autoload entries", 1},
|
||||
{ "add-autoload-sink", pa_cli_command_autoload_add, "Add autoload entry for a sink (args: sink, module name, arguments)", 4},
|
||||
{ "add-autoload-source", pa_cli_command_autoload_add, "Add autoload entry for a source (args: source, module name, arguments)", 4},
|
||||
{ "remove-autoload-sink", pa_cli_command_autoload_remove, "Remove autoload entry for a sink (args: name)", 2},
|
||||
{ "remove-autoload-source", pa_cli_command_autoload_remove, "Remove autoload entry for a source (args: name)", 2},
|
||||
{ "add-autoload-sink", pa_cli_command_autoload_add, NULL /*"Add autoload entry for a sink (args: sink, module name, arguments)"*/, 4},
|
||||
{ "add-autoload-source", pa_cli_command_autoload_add, NULL /*"Add autoload entry for a source (args: source, module name, arguments)"*/, 4},
|
||||
{ "remove-autoload-sink", pa_cli_command_autoload_remove, NULL /*"Remove autoload entry for a sink (args: name)"*/, 2},
|
||||
{ "remove-autoload-source", pa_cli_command_autoload_remove, NULL /*"Remove autoload entry for a source (args: name)"*/, 2},
|
||||
{ "dump", pa_cli_command_dump, "Dump daemon configuration", 1},
|
||||
{ "list-props", pa_cli_command_list_props, NULL, 1},
|
||||
{ "move-sink-input", pa_cli_command_move_sink_input, "Move sink input to another sink (args: index, sink)", 3},
|
||||
|
|
@ -367,7 +367,7 @@ static int pa_cli_command_info(pa_core *c, pa_tokenizer *t, pa_strbuf *buf, pa_b
|
|||
pa_cli_command_sink_inputs(c, t, buf, fail);
|
||||
pa_cli_command_source_outputs(c, t, buf, fail);
|
||||
pa_cli_command_scache_list(c, t, buf, fail);
|
||||
pa_cli_command_autoload_list(c, t, buf, fail);
|
||||
/* pa_cli_command_autoload_list(c, t, buf, fail); */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -905,6 +905,8 @@ static int pa_cli_command_autoload_add(pa_core *c, pa_tokenizer *t, pa_strbuf *b
|
|||
pa_assert(buf);
|
||||
pa_assert(fail);
|
||||
|
||||
pa_log_warn("Autoload will no longer be implemented by future versions of the PulseAudio server.");
|
||||
|
||||
if (!(a = pa_tokenizer_get(t, 1)) || !(b = pa_tokenizer_get(t, 2))) {
|
||||
pa_strbuf_puts(buf, "You need to specify a device name, a filename or a module name and optionally module arguments\n");
|
||||
return -1;
|
||||
|
|
@ -923,6 +925,8 @@ static int pa_cli_command_autoload_remove(pa_core *c, pa_tokenizer *t, pa_strbuf
|
|||
pa_assert(buf);
|
||||
pa_assert(fail);
|
||||
|
||||
pa_log_warn("Autoload will no longer be implemented by future versions of the PulseAudio server.");
|
||||
|
||||
if (!(name = pa_tokenizer_get(t, 1))) {
|
||||
pa_strbuf_puts(buf, "You need to specify a device name\n");
|
||||
return -1;
|
||||
|
|
@ -944,6 +948,8 @@ static int pa_cli_command_autoload_list(pa_core *c, pa_tokenizer *t, pa_strbuf *
|
|||
pa_assert(buf);
|
||||
pa_assert(fail);
|
||||
|
||||
pa_log_warn("Autoload will no longer be implemented by future versions of the PulseAudio server.");
|
||||
|
||||
pa_assert_se(s = pa_autoload_list_to_string(c));
|
||||
pa_strbuf_puts(buf, s);
|
||||
pa_xfree(s);
|
||||
|
|
|
|||
|
|
@ -204,4 +204,17 @@ static inline const char *pa_strnull(const char *x) {
|
|||
return x ? x : "(null)";
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
|
||||
#define PA_WARN_REFERENCE(sym,msg) \
|
||||
__asm__(".section .gnu.warning.sym"); \
|
||||
__asm__(".asciz \"msg\""); \
|
||||
__asm__(".previous")
|
||||
|
||||
#else
|
||||
|
||||
#define PA_WARN_REFERENCE(sym,msg)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ static void fix_current_read(pa_memblockq *bq) {
|
|||
break;
|
||||
|
||||
/* Scan right */
|
||||
while (PA_LIKELY(bq->current_read != NULL) && PA_UNLIKELY(bq->current_read->index + bq->current_read->chunk.length <= bq->read_index))
|
||||
while (PA_LIKELY(bq->current_read != NULL) && PA_UNLIKELY(bq->current_read->index + (int64_t) bq->current_read->chunk.length <= bq->read_index))
|
||||
bq->current_read = bq->current_read->next;
|
||||
|
||||
/* At this point current_read will either point at or left of the
|
||||
|
|
@ -158,7 +158,7 @@ static void fix_current_write(pa_memblockq *bq) {
|
|||
bq->current_write = bq->blocks_tail;
|
||||
|
||||
/* Scan right */
|
||||
while (PA_UNLIKELY(bq->current_write->index + bq->current_write->chunk.length <= bq->write_index))
|
||||
while (PA_UNLIKELY(bq->current_write->index + (int64_t) bq->current_write->chunk.length <= bq->write_index))
|
||||
|
||||
if (bq->current_write->next)
|
||||
bq->current_write = bq->current_write->next;
|
||||
|
|
@ -214,7 +214,7 @@ static void drop_backlog(pa_memblockq *bq) {
|
|||
|
||||
boundary = bq->read_index - bq->maxrewind;
|
||||
|
||||
while (bq->blocks && (bq->blocks->index + bq->blocks->chunk.length <= boundary))
|
||||
while (bq->blocks && (bq->blocks->index + (int64_t) bq->blocks->chunk.length <= boundary))
|
||||
drop_block(bq, bq->blocks);
|
||||
}
|
||||
|
||||
|
|
@ -232,10 +232,10 @@ static pa_bool_t can_push(pa_memblockq *bq, size_t l) {
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
end = bq->blocks_tail ? bq->blocks_tail->index + bq->blocks_tail->chunk.length : bq->write_index;
|
||||
end = bq->blocks_tail ? bq->blocks_tail->index + (int64_t) bq->blocks_tail->chunk.length : bq->write_index;
|
||||
|
||||
/* Make sure that the list doesn't get too long */
|
||||
if (bq->write_index + l > end)
|
||||
if (bq->write_index + (int64_t) l > end)
|
||||
if (bq->write_index + l - bq->read_index > bq->maxlength)
|
||||
return FALSE;
|
||||
|
||||
|
|
@ -269,7 +269,7 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
|
|||
* write to */
|
||||
|
||||
if (q) {
|
||||
while (bq->write_index + chunk.length > q->index)
|
||||
while (bq->write_index + (int64_t) chunk.length > q->index)
|
||||
if (q->next)
|
||||
q = q->next;
|
||||
else
|
||||
|
|
@ -284,10 +284,10 @@ int pa_memblockq_push(pa_memblockq* bq, const pa_memchunk *uchunk) {
|
|||
|
||||
while (q) {
|
||||
|
||||
if (bq->write_index >= q->index + q->chunk.length)
|
||||
if (bq->write_index >= q->index + (int64_t) q->chunk.length)
|
||||
/* We found the entry where we need to place the new entry immediately after */
|
||||
break;
|
||||
else if (bq->write_index + chunk.length <= q->index) {
|
||||
else if (bq->write_index + (int64_t) chunk.length <= q->index) {
|
||||
/* This entry isn't touched at all, let's skip it */
|
||||
q = q->prev;
|
||||
} else if (bq->write_index <= q->index &&
|
||||
|
|
@ -407,7 +407,7 @@ finish:
|
|||
|
||||
delta = bq->write_index - old;
|
||||
|
||||
if (delta >= bq->requested) {
|
||||
if (delta >= (int64_t) bq->requested) {
|
||||
delta -= bq->requested;
|
||||
bq->requested = 0;
|
||||
} else {
|
||||
|
|
@ -526,7 +526,7 @@ void pa_memblockq_drop(pa_memblockq *bq, size_t length) {
|
|||
pa_assert(p >= bq->read_index);
|
||||
d = p - bq->read_index;
|
||||
|
||||
if (d > length)
|
||||
if (d > (int64_t) length)
|
||||
d = length;
|
||||
|
||||
bq->read_index += d;
|
||||
|
|
@ -606,7 +606,7 @@ void pa_memblockq_seek(pa_memblockq *bq, int64_t offset, pa_seek_mode_t seek) {
|
|||
|
||||
delta = bq->write_index - old;
|
||||
|
||||
if (delta >= bq->requested) {
|
||||
if (delta >= (int64_t) bq->requested) {
|
||||
delta -= bq->requested;
|
||||
bq->requested = 0;
|
||||
} else if (delta >= 0) {
|
||||
|
|
@ -633,7 +633,7 @@ void pa_memblockq_flush(pa_memblockq *bq) {
|
|||
|
||||
delta = bq->write_index - old;
|
||||
|
||||
if (delta >= bq->requested) {
|
||||
if (delta >= (int64_t) bq->requested) {
|
||||
delta -= bq->requested;
|
||||
bq->requested = 0;
|
||||
} else if (delta >= 0) {
|
||||
|
|
|
|||
|
|
@ -109,8 +109,8 @@ pa_module* pa_module_load(pa_core *c, const char *name, const char *argument) {
|
|||
m->userdata = NULL;
|
||||
m->core = c;
|
||||
m->n_used = -1;
|
||||
m->auto_unload = 0;
|
||||
m->unload_requested = 0;
|
||||
m->auto_unload = FALSE;
|
||||
m->unload_requested = FALSE;
|
||||
|
||||
if (m->init(m) < 0) {
|
||||
pa_log_error("Failed to load module \"%s\" (argument: \"%s\"): initialization failed.", name, argument ? argument : "");
|
||||
|
|
@ -281,7 +281,7 @@ static void defer_cb(pa_mainloop_api*api, pa_defer_event *e, void *userdata) {
|
|||
void pa_module_unload_request(pa_module *m) {
|
||||
pa_assert(m);
|
||||
|
||||
m->unload_requested = 1;
|
||||
m->unload_requested = TRUE;
|
||||
|
||||
if (!m->core->module_defer_unload_event)
|
||||
m->core->module_defer_unload_event = m->core->mainloop->defer_new(m->core->mainloop, defer_cb, m->core);
|
||||
|
|
|
|||
|
|
@ -45,10 +45,10 @@ struct pa_module {
|
|||
void *userdata;
|
||||
|
||||
int n_used;
|
||||
int auto_unload;
|
||||
pa_bool_t auto_unload;
|
||||
time_t last_used_time;
|
||||
|
||||
int unload_requested;
|
||||
pa_bool_t unload_requested;
|
||||
};
|
||||
|
||||
pa_module* pa_module_load(pa_core *c, const char *name, const char*argument);
|
||||
|
|
|
|||
|
|
@ -71,6 +71,8 @@
|
|||
#define MAX_CONNECTIONS 64
|
||||
|
||||
#define MAX_MEMBLOCKQ_LENGTH (4*1024*1024) /* 4MB */
|
||||
#define DEFAULT_TLENGTH_MSEC 2000 /* 2s */
|
||||
#define DEFAULT_FRAGSIZE_MSEC DEFAULT_TLENGTH_MSEC
|
||||
|
||||
typedef struct connection connection;
|
||||
struct pa_protocol_native;
|
||||
|
|
@ -469,9 +471,10 @@ static record_stream* record_stream_new(
|
|||
pa_channel_map *map,
|
||||
const char *name,
|
||||
uint32_t *maxlength,
|
||||
uint32_t fragment_size,
|
||||
uint32_t *fragsize,
|
||||
pa_source_output_flags_t flags,
|
||||
pa_proplist *p) {
|
||||
pa_proplist *p,
|
||||
pa_bool_t adjust_latency) {
|
||||
|
||||
record_stream *s;
|
||||
pa_source_output *source_output;
|
||||
|
|
@ -482,7 +485,6 @@ static record_stream* record_stream_new(
|
|||
pa_assert(ss);
|
||||
pa_assert(name);
|
||||
pa_assert(maxlength);
|
||||
pa_assert(*maxlength > 0);
|
||||
pa_assert(p);
|
||||
|
||||
pa_source_output_new_data_init(&data);
|
||||
|
|
@ -508,6 +510,7 @@ static record_stream* record_stream_new(
|
|||
s->parent.process_msg = record_stream_process_msg;
|
||||
s->connection = c;
|
||||
s->source_output = source_output;
|
||||
|
||||
s->source_output->push = source_output_push_cb;
|
||||
s->source_output->kill = source_output_kill_cb;
|
||||
s->source_output->get_latency = source_output_get_latency_cb;
|
||||
|
|
@ -515,11 +518,36 @@ 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*1000, &source_output->sample_spec);
|
||||
|
||||
if (adjust_latency) {
|
||||
pa_usec_t fragsize_usec, source_latency;
|
||||
|
||||
/* 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);
|
||||
|
||||
source_latency = pa_source_output_set_requested_latency(source_output, fragsize_usec/2);
|
||||
|
||||
if (fragsize_usec >= source_latency*2)
|
||||
fragsize_usec -= source_latency;
|
||||
else
|
||||
fragsize_usec = source_latency;
|
||||
|
||||
*fragsize = pa_usec_to_bytes(fragsize_usec, &source_output->sample_spec);
|
||||
}
|
||||
|
||||
s->memblockq = pa_memblockq_new(
|
||||
0,
|
||||
*maxlength,
|
||||
0,
|
||||
base = pa_frame_size(&s->source_output->sample_spec),
|
||||
base = pa_frame_size(&source_output->sample_spec),
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
|
|
@ -527,13 +555,15 @@ static record_stream* record_stream_new(
|
|||
|
||||
*maxlength = pa_memblockq_get_maxlength(s->memblockq);
|
||||
|
||||
s->fragment_size = (fragment_size/base)*base;
|
||||
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;
|
||||
|
||||
*ss = s->source_output->sample_spec;
|
||||
*map = s->source_output->channel_map;
|
||||
|
||||
|
|
@ -658,10 +688,12 @@ static playback_stream* playback_stream_new(
|
|||
uint32_t *prebuf,
|
||||
uint32_t *minreq,
|
||||
pa_cvolume *volume,
|
||||
pa_bool_t muted,
|
||||
uint32_t syncid,
|
||||
uint32_t *missing,
|
||||
pa_sink_input_flags_t flags,
|
||||
pa_proplist *p) {
|
||||
pa_proplist *p,
|
||||
pa_bool_t adjust_latency) {
|
||||
|
||||
playback_stream *s, *ssync;
|
||||
pa_sink_input *sink_input;
|
||||
|
|
@ -674,6 +706,11 @@ static playback_stream* playback_stream_new(
|
|||
pa_assert(ss);
|
||||
pa_assert(name);
|
||||
pa_assert(maxlength);
|
||||
pa_assert(tlength);
|
||||
pa_assert(prebuf);
|
||||
pa_assert(minreq);
|
||||
pa_assert(volume);
|
||||
pa_assert(missing);
|
||||
pa_assert(p);
|
||||
|
||||
/* Find syncid group */
|
||||
|
|
@ -706,6 +743,7 @@ static playback_stream* playback_stream_new(
|
|||
pa_sink_input_new_data_set_sample_spec(&data, ss);
|
||||
pa_sink_input_new_data_set_channel_map(&data, map);
|
||||
pa_sink_input_new_data_set_volume(&data, volume);
|
||||
pa_sink_input_new_data_set_muted(&data, muted);
|
||||
data.sync_base = ssync ? ssync->sink_input : NULL;
|
||||
|
||||
sink_input = pa_sink_input_new(c->protocol->core, &data, flags);
|
||||
|
|
@ -732,13 +770,49 @@ static playback_stream* playback_stream_new(
|
|||
|
||||
start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0;
|
||||
|
||||
silence = pa_silence_memblock_new(c->protocol->core->mempool, &s->sink_input->sample_spec, 0);
|
||||
if (*maxlength <= 0 || *maxlength > MAX_MEMBLOCKQ_LENGTH)
|
||||
*maxlength = MAX_MEMBLOCKQ_LENGTH;
|
||||
if (*tlength <= 0)
|
||||
*tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*1000, &sink_input->sample_spec);
|
||||
if (*minreq <= 0)
|
||||
*minreq = (*tlength*9)/10;
|
||||
if (*prebuf <= 0)
|
||||
*prebuf = *tlength;
|
||||
|
||||
if (adjust_latency) {
|
||||
pa_usec_t tlength_usec, minreq_usec, sink_latency;
|
||||
|
||||
/* So, the user asked us to adjust the latency according to
|
||||
* the what the sink 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. */
|
||||
|
||||
tlength_usec = pa_bytes_to_usec(*tlength, &sink_input->sample_spec);
|
||||
minreq_usec = pa_bytes_to_usec(*minreq, &sink_input->sample_spec);
|
||||
|
||||
sink_latency = pa_sink_input_set_requested_latency(sink_input, tlength_usec/2);
|
||||
|
||||
if (tlength_usec >= sink_latency*2)
|
||||
tlength_usec -= sink_latency;
|
||||
else
|
||||
tlength_usec = sink_latency;
|
||||
|
||||
if (minreq_usec >= sink_latency*2)
|
||||
minreq_usec -= sink_latency;
|
||||
else
|
||||
minreq_usec = sink_latency;
|
||||
|
||||
*tlength = pa_usec_to_bytes(tlength_usec, &sink_input->sample_spec);
|
||||
*minreq = pa_usec_to_bytes(minreq_usec, &sink_input->sample_spec);
|
||||
}
|
||||
|
||||
silence = pa_silence_memblock_new(c->protocol->core->mempool, &sink_input->sample_spec, 0);
|
||||
|
||||
s->memblockq = pa_memblockq_new(
|
||||
start_index,
|
||||
*maxlength,
|
||||
*tlength,
|
||||
pa_frame_size(&s->sink_input->sample_spec),
|
||||
pa_frame_size(&sink_input->sample_spec),
|
||||
*prebuf,
|
||||
*minreq,
|
||||
0,
|
||||
|
|
@ -762,7 +836,6 @@ static playback_stream* playback_stream_new(
|
|||
pa_idxset_put(c->output_streams, s, &s->index);
|
||||
|
||||
pa_sink_input_put(s->sink_input);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
|
@ -1230,8 +1303,18 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC
|
|||
pa_tagstruct *reply;
|
||||
pa_sink *sink = NULL;
|
||||
pa_cvolume volume;
|
||||
int corked;
|
||||
int no_remap = 0, no_remix = 0, fix_format = 0, fix_rate = 0, fix_channels = 0, no_move = 0, variable_rate = 0;
|
||||
pa_bool_t
|
||||
corked = FALSE,
|
||||
no_remap = FALSE,
|
||||
no_remix = FALSE,
|
||||
fix_format = FALSE,
|
||||
fix_rate = FALSE,
|
||||
fix_channels = FALSE,
|
||||
no_move = FALSE,
|
||||
variable_rate = FALSE,
|
||||
muted = FALSE,
|
||||
adjust_latency = FALSE;
|
||||
|
||||
pa_sink_input_flags_t flags = 0;
|
||||
pa_proplist *p;
|
||||
|
||||
|
|
@ -1264,8 +1347,6 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC
|
|||
CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, map.channels == ss.channels && volume.channels == ss.channels, tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID);
|
||||
|
||||
p = pa_proplist_new();
|
||||
|
||||
|
|
@ -1291,7 +1372,9 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC
|
|||
|
||||
if (c->version >= 13) {
|
||||
|
||||
if (pa_tagstruct_get_proplist(t, p) < 0) {
|
||||
if (pa_tagstruct_get_boolean(t, &muted) < 0 ||
|
||||
pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
|
||||
pa_tagstruct_get_proplist(t, p) < 0) {
|
||||
protocol_error(c);
|
||||
pa_proplist_free(p);
|
||||
return;
|
||||
|
|
@ -1331,7 +1414,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC
|
|||
(no_move ? PA_SINK_INPUT_DONT_MOVE : 0) |
|
||||
(variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0);
|
||||
|
||||
s = playback_stream_new(c, sink, &ss, &map, name, &maxlength, &tlength, &prebuf, &minreq, &volume, syncid, &missing, flags, p);
|
||||
s = playback_stream_new(c, sink, &ss, &map, name, &maxlength, &tlength, &prebuf, &minreq, &volume, muted, syncid, &missing, flags, p, adjust_latency);
|
||||
pa_proplist_free(p);
|
||||
|
||||
CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
|
||||
|
|
@ -1438,8 +1521,16 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
|
|||
pa_channel_map map;
|
||||
pa_tagstruct *reply;
|
||||
pa_source *source = NULL;
|
||||
int corked;
|
||||
int no_remap = 0, no_remix = 0, fix_format = 0, fix_rate = 0, fix_channels = 0, no_move = 0, variable_rate = 0;
|
||||
pa_bool_t
|
||||
corked = FALSE,
|
||||
no_remap = FALSE,
|
||||
no_remix = FALSE,
|
||||
fix_format = FALSE,
|
||||
fix_rate = FALSE,
|
||||
fix_channels = FALSE,
|
||||
no_move = FALSE,
|
||||
variable_rate = FALSE,
|
||||
adjust_latency = FALSE;
|
||||
pa_source_output_flags_t flags = 0;
|
||||
pa_proplist *p;
|
||||
|
||||
|
|
@ -1463,8 +1554,6 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
|
|||
CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, source_index != PA_INVALID_INDEX || !source_name || (*source_name && pa_utf8_valid(source_name)), tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, map.channels == ss.channels, tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID);
|
||||
|
||||
p = pa_proplist_new();
|
||||
|
||||
|
|
@ -1490,7 +1579,8 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
|
|||
|
||||
if (c->version >= 13) {
|
||||
|
||||
if (pa_tagstruct_get_proplist(t, p) < 0) {
|
||||
if (pa_tagstruct_get_boolean(t, &adjust_latency) < 0 ||
|
||||
pa_tagstruct_get_proplist(t, p) < 0) {
|
||||
protocol_error(c);
|
||||
pa_proplist_free(p);
|
||||
return;
|
||||
|
|
@ -1530,7 +1620,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, name, &maxlength, fragment_size, flags, p);
|
||||
s = record_stream_new(c, source, &ss, &map, name, &maxlength, &fragment_size, flags, p, adjust_latency);
|
||||
pa_proplist_free(p);
|
||||
|
||||
CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID);
|
||||
|
|
@ -1544,7 +1634,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_
|
|||
/* 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->fragment_size);
|
||||
pa_tagstruct_putu32(reply, (uint32_t) fragment_size);
|
||||
}
|
||||
|
||||
if (c->version >= 12) {
|
||||
|
|
@ -1873,7 +1963,7 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN
|
|||
reply = reply_new(tag);
|
||||
pa_tagstruct_put_usec(reply, s->source_output->source->monitor_of ? pa_sink_get_latency(s->source_output->source->monitor_of) : 0);
|
||||
pa_tagstruct_put_usec(reply, pa_source_get_latency(s->source_output->source));
|
||||
pa_tagstruct_put_boolean(reply, 0);
|
||||
pa_tagstruct_put_boolean(reply, FALSE);
|
||||
pa_tagstruct_put_timeval(reply, &tv);
|
||||
pa_tagstruct_put_timeval(reply, pa_gettimeofday(&now));
|
||||
pa_tagstruct_puts64(reply, pa_memblockq_get_write_index(s->memblockq));
|
||||
|
|
@ -2511,7 +2601,7 @@ static void command_set_mute(
|
|||
|
||||
connection *c = CONNECTION(userdata);
|
||||
uint32_t idx;
|
||||
int mute;
|
||||
pa_bool_t mute;
|
||||
pa_sink *sink = NULL;
|
||||
pa_source *source = NULL;
|
||||
pa_sink_input *si = NULL;
|
||||
|
|
@ -2574,7 +2664,7 @@ static void command_set_mute(
|
|||
static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) {
|
||||
connection *c = CONNECTION(userdata);
|
||||
uint32_t idx;
|
||||
int b;
|
||||
pa_bool_t b;
|
||||
playback_stream *s;
|
||||
|
||||
connection_assert_ref(c);
|
||||
|
|
@ -2641,7 +2731,7 @@ static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN
|
|||
connection *c = CONNECTION(userdata);
|
||||
uint32_t idx;
|
||||
record_stream *s;
|
||||
int b;
|
||||
pa_bool_t b;
|
||||
|
||||
connection_assert_ref(c);
|
||||
pa_assert(t);
|
||||
|
|
@ -2719,8 +2809,14 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
|
|||
return;
|
||||
}
|
||||
|
||||
CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID);
|
||||
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;
|
||||
|
||||
pa_memblockq_set_maxlength(s->memblockq, maxlength);
|
||||
pa_memblockq_set_tlength(s->memblockq, tlength);
|
||||
|
|
@ -2751,8 +2847,10 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u
|
|||
return;
|
||||
}
|
||||
|
||||
CHECK_VALIDITY(c->pstream, maxlength > 0, tag, PA_ERR_INVALID);
|
||||
CHECK_VALIDITY(c->pstream, maxlength <= MAX_MEMBLOCKQ_LENGTH, tag, PA_ERR_INVALID);
|
||||
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);
|
||||
|
||||
pa_memblockq_set_maxlength(s->memblockq, maxlength);
|
||||
|
||||
|
|
@ -3336,7 +3434,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa
|
|||
connection *c = CONNECTION(userdata);
|
||||
uint32_t idx = PA_INVALID_INDEX;
|
||||
const char *name = NULL;
|
||||
int b;
|
||||
pa_bool_t b;
|
||||
|
||||
connection_assert_ref(c);
|
||||
pa_assert(t);
|
||||
|
|
|
|||
|
|
@ -282,7 +282,9 @@ int pa_shm_attach_ro(pa_shm *m, unsigned id) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (st.st_size <= 0 || st.st_size > MAX_SHM_SIZE+PA_ALIGN(sizeof(struct shm_marker)) || PA_ALIGN(st.st_size) != st.st_size) {
|
||||
if (st.st_size <= 0 ||
|
||||
st.st_size > (off_t) (MAX_SHM_SIZE+PA_ALIGN(sizeof(struct shm_marker))) ||
|
||||
PA_ALIGN((size_t) st.st_size) != (size_t) st.st_size) {
|
||||
pa_log("Invalid shared memory segment size");
|
||||
goto fail;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -665,11 +665,18 @@ void pa_sink_input_set_max_rewind(pa_sink_input *i, size_t nbytes /* in the sin
|
|||
i->set_max_rewind(i, i->thread_info.resampler ? pa_resampler_request(i->thread_info.resampler, nbytes) : nbytes);
|
||||
}
|
||||
|
||||
void pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) {
|
||||
pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec) {
|
||||
pa_sink_input_assert_ref(i);
|
||||
pa_assert(PA_SINK_INPUT_LINKED(i->state));
|
||||
|
||||
pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL);
|
||||
if (usec < i->sink->min_latency)
|
||||
usec = i->sink->min_latency;
|
||||
|
||||
if (PA_SINK_INPUT_LINKED(i->state))
|
||||
pa_asyncmsgq_post(i->sink->asyncmsgq, PA_MSGOBJECT(i), PA_SINK_INPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL);
|
||||
else
|
||||
i->thread_info.requested_sink_latency = usec;
|
||||
|
||||
return usec;
|
||||
}
|
||||
|
||||
void pa_sink_input_set_volume(pa_sink_input *i, const pa_cvolume *volume) {
|
||||
|
|
|
|||
|
|
@ -226,7 +226,7 @@ void pa_sink_input_unlink(pa_sink_input* i);
|
|||
|
||||
void pa_sink_input_set_name(pa_sink_input *i, const char *name);
|
||||
|
||||
void pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec);
|
||||
pa_usec_t pa_sink_input_set_requested_latency(pa_sink_input *i, pa_usec_t usec);
|
||||
|
||||
/* Request that the specified number of bytes already written out to
|
||||
the hw device is rewritten, if possible. If this function is used you
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include <pulse/introspect.h>
|
||||
#include <pulse/utf8.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/timeval.h>
|
||||
|
||||
#include <pulsecore/sink-input.h>
|
||||
#include <pulsecore/namereg.h>
|
||||
|
|
@ -47,6 +48,7 @@
|
|||
|
||||
#define MAX_MIX_CHANNELS 32
|
||||
#define MIX_BUFFER_LENGTH (PA_PAGE_SIZE)
|
||||
#define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
|
||||
|
||||
static PA_DEFINE_CHECK_TYPE(pa_sink, pa_msgobject);
|
||||
|
||||
|
|
@ -185,6 +187,8 @@ pa_sink* pa_sink_new(
|
|||
s->rtpoll = NULL;
|
||||
s->silence = pa_silence_memblock_new(core->mempool, &s->sample_spec, 0);
|
||||
|
||||
s->min_latency = DEFAULT_MIN_LATENCY;
|
||||
|
||||
s->thread_info.inputs = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
|
||||
s->thread_info.soft_volume = s->volume;
|
||||
s->thread_info.soft_muted = s->muted;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ struct pa_sink {
|
|||
|
||||
pa_memblock *silence;
|
||||
|
||||
pa_usec_t min_latency; /* we won't go below this latency setting */
|
||||
|
||||
int (*set_state)(pa_sink *s, pa_sink_state_t state); /* may be NULL */
|
||||
int (*set_volume)(pa_sink *s); /* dito */
|
||||
int (*get_volume)(pa_sink *s); /* dito */
|
||||
|
|
|
|||
|
|
@ -360,13 +360,20 @@ void pa_source_output_push(pa_source_output *o, const pa_memchunk *chunk) {
|
|||
pa_memblock_unref(rchunk.memblock);
|
||||
}
|
||||
|
||||
void pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) {
|
||||
pa_usec_t pa_source_output_set_requested_latency(pa_source_output *o, pa_usec_t usec) {
|
||||
pa_source_output_assert_ref(o);
|
||||
pa_assert(PA_SOURCE_OUTPUT_LINKED(o->state));
|
||||
|
||||
pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL);
|
||||
}
|
||||
if (usec < o->source->min_latency)
|
||||
usec = o->source->min_latency;
|
||||
|
||||
if (PA_SOURCE_OUTPUT_LINKED(o->state))
|
||||
pa_asyncmsgq_post(o->source->asyncmsgq, PA_MSGOBJECT(o), PA_SOURCE_OUTPUT_MESSAGE_SET_REQUESTED_LATENCY, NULL, (int64_t) usec, NULL, NULL);
|
||||
else
|
||||
o->thread_info.requested_source_latency = usec;
|
||||
|
||||
return usec;
|
||||
}
|
||||
|
||||
void pa_source_output_cork(pa_source_output *o, pa_bool_t b) {
|
||||
pa_source_output_assert_ref(o);
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ void pa_source_output_unlink(pa_source_output*o);
|
|||
|
||||
void pa_source_output_set_name(pa_source_output *i, const char *name);
|
||||
|
||||
void pa_source_output_set_requested_latency(pa_source_output *i, pa_usec_t usec);
|
||||
pa_usec_t pa_source_output_set_requested_latency(pa_source_output *i, pa_usec_t usec);
|
||||
|
||||
/* Callable by everyone */
|
||||
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <pulse/utf8.h>
|
||||
#include <pulse/xmalloc.h>
|
||||
#include <pulse/timeval.h>
|
||||
|
||||
#include <pulsecore/source-output.h>
|
||||
#include <pulsecore/namereg.h>
|
||||
|
|
@ -41,6 +42,8 @@
|
|||
|
||||
#include "source.h"
|
||||
|
||||
#define DEFAULT_MIN_LATENCY (4*PA_USEC_PER_MSEC)
|
||||
|
||||
static PA_DEFINE_CHECK_TYPE(pa_source, pa_msgobject);
|
||||
|
||||
static void source_free(pa_object *o);
|
||||
|
|
@ -162,6 +165,8 @@ pa_source* pa_source_new(
|
|||
s->muted = data->muted;
|
||||
s->refresh_volume = s->refresh_muted = FALSE;
|
||||
|
||||
s->min_latency = DEFAULT_MIN_LATENCY;
|
||||
|
||||
s->get_latency = NULL;
|
||||
s->set_volume = NULL;
|
||||
s->get_volume = NULL;
|
||||
|
|
|
|||
|
|
@ -91,6 +91,8 @@ struct pa_source {
|
|||
pa_asyncmsgq *asyncmsgq;
|
||||
pa_rtpoll *rtpoll;
|
||||
|
||||
pa_usec_t min_latency; /* we won't go below this latency setting */
|
||||
|
||||
int (*set_state)(pa_source*source, pa_source_state_t state); /* may be NULL */
|
||||
int (*set_volume)(pa_source *s); /* dito */
|
||||
int (*get_volume)(pa_source *s); /* dito */
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ void pa_tagstruct_put_arbitrary(pa_tagstruct *t, const void *p, size_t length) {
|
|||
t->length += 5+length;
|
||||
}
|
||||
|
||||
void pa_tagstruct_put_boolean(pa_tagstruct*t, int b) {
|
||||
void pa_tagstruct_put_boolean(pa_tagstruct*t, pa_bool_t b) {
|
||||
pa_assert(t);
|
||||
|
||||
extend(t, 1);
|
||||
|
|
@ -407,7 +407,7 @@ const uint8_t* pa_tagstruct_data(pa_tagstruct*t, size_t *l) {
|
|||
return t->data;
|
||||
}
|
||||
|
||||
int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) {
|
||||
int pa_tagstruct_get_boolean(pa_tagstruct*t, pa_bool_t *b) {
|
||||
pa_assert(t);
|
||||
pa_assert(b);
|
||||
|
||||
|
|
@ -415,9 +415,9 @@ int pa_tagstruct_get_boolean(pa_tagstruct*t, int *b) {
|
|||
return -1;
|
||||
|
||||
if (t->data[t->rindex] == PA_TAG_BOOLEAN_TRUE)
|
||||
*b = 1;
|
||||
*b = TRUE;
|
||||
else if (t->data[t->rindex] == PA_TAG_BOOLEAN_FALSE)
|
||||
*b = 0;
|
||||
*b = FALSE;
|
||||
else
|
||||
return -1;
|
||||
|
||||
|
|
@ -725,7 +725,7 @@ int pa_tagstruct_get(pa_tagstruct *t, ...) {
|
|||
|
||||
case PA_TAG_BOOLEAN_TRUE:
|
||||
case PA_TAG_BOOLEAN_FALSE:
|
||||
ret = pa_tagstruct_get_boolean(t, va_arg(va, int*));
|
||||
ret = pa_tagstruct_get_boolean(t, va_arg(va, pa_bool_t*));
|
||||
break;
|
||||
|
||||
case PA_TAG_TIMEVAL:
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ void pa_tagstruct_putu64(pa_tagstruct*t, uint64_t i);
|
|||
void pa_tagstruct_puts64(pa_tagstruct*t, int64_t i);
|
||||
void pa_tagstruct_put_sample_spec(pa_tagstruct *t, const pa_sample_spec *ss);
|
||||
void pa_tagstruct_put_arbitrary(pa_tagstruct*t, const void *p, size_t length);
|
||||
void pa_tagstruct_put_boolean(pa_tagstruct*t, int b);
|
||||
void pa_tagstruct_put_boolean(pa_tagstruct*t, pa_bool_t b);
|
||||
void pa_tagstruct_put_timeval(pa_tagstruct*t, const struct timeval *tv);
|
||||
void pa_tagstruct_put_usec(pa_tagstruct*t, pa_usec_t u);
|
||||
void pa_tagstruct_put_channel_map(pa_tagstruct *t, const pa_channel_map *map);
|
||||
|
|
@ -88,7 +88,7 @@ int pa_tagstruct_getu64(pa_tagstruct*t, uint64_t *i);
|
|||
int pa_tagstruct_gets64(pa_tagstruct*t, int64_t *i);
|
||||
int pa_tagstruct_get_sample_spec(pa_tagstruct *t, pa_sample_spec *ss);
|
||||
int pa_tagstruct_get_arbitrary(pa_tagstruct *t, const void **p, size_t length);
|
||||
int pa_tagstruct_get_boolean(pa_tagstruct *t, int *b);
|
||||
int pa_tagstruct_get_boolean(pa_tagstruct *t, pa_bool_t *b);
|
||||
int pa_tagstruct_get_timeval(pa_tagstruct*t, struct timeval *tv);
|
||||
int pa_tagstruct_get_usec(pa_tagstruct*t, pa_usec_t *u);
|
||||
int pa_tagstruct_get_channel_map(pa_tagstruct *t, pa_channel_map *map);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue