X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/eec623a23b6c30508d8bb4ecbdd1fff7c715a3f8..47a2b17d01cc0dceb964df07d17e406726d50d45:/src/pulsecore/protocol-native.c diff --git a/src/pulsecore/protocol-native.c b/src/pulsecore/protocol-native.c index 0eac3c26..0a070f47 100644 --- a/src/pulsecore/protocol-native.c +++ b/src/pulsecore/protocol-native.c @@ -49,8 +49,6 @@ #include #include #include -#include -#include #include #include #include @@ -249,10 +247,6 @@ static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_add_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_remove_autoload(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_autoload_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); -static void command_get_autoload_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata); @@ -331,10 +325,11 @@ static const pa_pdispatch_cb_t command_table[PA_COMMAND_MAX] = { [PA_COMMAND_KILL_SOURCE_OUTPUT] = command_kill, [PA_COMMAND_LOAD_MODULE] = command_load_module, [PA_COMMAND_UNLOAD_MODULE] = command_unload_module, - [PA_COMMAND_GET_AUTOLOAD_INFO] = command_get_autoload_info, - [PA_COMMAND_GET_AUTOLOAD_INFO_LIST] = command_get_autoload_info_list, - [PA_COMMAND_ADD_AUTOLOAD] = command_add_autoload, - [PA_COMMAND_REMOVE_AUTOLOAD] = command_remove_autoload, + + [PA_COMMAND_GET_AUTOLOAD_INFO___OBSOLETE] = NULL, + [PA_COMMAND_GET_AUTOLOAD_INFO_LIST___OBSOLETE] = NULL, + [PA_COMMAND_ADD_AUTOLOAD___OBSOLETE] = NULL, + [PA_COMMAND_REMOVE_AUTOLOAD___OBSOLETE] = NULL, [PA_COMMAND_MOVE_SINK_INPUT] = command_move_stream, [PA_COMMAND_MOVE_SOURCE_OUTPUT] = command_move_stream, @@ -470,51 +465,102 @@ static int record_stream_process_msg(pa_msgobject *o, int code, void*userdata, i return 0; } -static void fix_record_buffer_attr_pre(record_stream *s, pa_bool_t adjust_latency, uint32_t *maxlength, uint32_t *fragsize) { +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; + pa_usec_t orig_fragsize_usec, fragsize_usec, source_usec; + pa_assert(s); pa_assert(maxlength); pa_assert(fragsize); + frame_size = pa_frame_size(&s->source_output->sample_spec); + if (*maxlength == (uint32_t) -1 || *maxlength > MAX_MEMBLOCKQ_LENGTH) *maxlength = MAX_MEMBLOCKQ_LENGTH; if (*maxlength <= 0) - *maxlength = pa_frame_size(&s->source_output->sample_spec); + *maxlength = (uint32_t) frame_size; if (*fragsize == (uint32_t) -1) - *fragsize = pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec); + *fragsize = (uint32_t) pa_usec_to_bytes(DEFAULT_FRAGSIZE_MSEC*PA_USEC_PER_MSEC, &s->source_output->sample_spec); if (*fragsize <= 0) - *fragsize = pa_frame_size(&s->source_output->sample_spec); + *fragsize = (uint32_t) frame_size; - if (adjust_latency) { - pa_usec_t fragsize_usec; + orig_fragsize_usec = fragsize_usec = pa_bytes_to_usec(*fragsize, &s->source_output->sample_spec); + + if (early_requests) { + + /* In early request mode we need to emulate the classic + * fragment-based playback model. We do this setting the source + * latency to the fragment size. */ + + source_usec = fragsize_usec; + + } else if (adjust_latency) { /* So, the user asked us to adjust the latency according to * what the source can provide. Half the latency will be * spent on the hw buffer, half of it in the async buffer * queue we maintain for each client. */ - fragsize_usec = pa_bytes_to_usec(*fragsize, &s->source_output->sample_spec); + source_usec = fragsize_usec/2; + + } else { + + /* Ok, the user didn't ask us to adjust the latency, hence we + * don't */ - s->source_latency = pa_source_output_set_requested_latency(s->source_output, fragsize_usec/2); + source_usec = 0; + } + + if (source_usec > 0) + s->source_latency = pa_source_output_set_requested_latency(s->source_output, source_usec); + else + s->source_latency = 0; + + if (early_requests) { + + /* Ok, we didn't necessarily get what we were asking for, so + * let's tell the user */ + + fragsize_usec = s->source_latency; + + } else if (adjust_latency) { + + /* Now subtract what we actually got */ if (fragsize_usec >= s->source_latency*2) fragsize_usec -= s->source_latency; else fragsize_usec = s->source_latency; + } - *fragsize = pa_usec_to_bytes(fragsize_usec, &s->source_output->sample_spec); - } else - s->source_latency = 0; + if (pa_usec_to_bytes(orig_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); + + if (*fragsize <= 0) + *fragsize = (uint32_t) frame_size; } -static void fix_record_buffer_attr_post(record_stream *s, uint32_t *maxlength, uint32_t *fragsize) { +static void fix_record_buffer_attr_post( + record_stream *s, + uint32_t *maxlength, + uint32_t *fragsize) { + size_t base; pa_assert(s); pa_assert(maxlength); pa_assert(fragsize); - *maxlength = pa_memblockq_get_maxlength(s->memblockq); + *maxlength = (uint32_t) pa_memblockq_get_maxlength(s->memblockq); base = pa_frame_size(&s->source_output->sample_spec); @@ -525,7 +571,7 @@ static void fix_record_buffer_attr_post(record_stream *s, uint32_t *maxlength, u if (s->fragment_size > *maxlength) s->fragment_size = *maxlength; - *fragsize = s->fragment_size; + *fragsize = (uint32_t) s->fragment_size; } static record_stream* record_stream_new( @@ -539,7 +585,8 @@ static record_stream* record_stream_new( pa_source_output_flags_t flags, pa_proplist *p, pa_bool_t adjust_latency, - pa_sink_input *direct_on_input) { + pa_sink_input *direct_on_input, + pa_bool_t early_requests) { record_stream *s; pa_source_output *source_output; @@ -554,7 +601,6 @@ static record_stream* record_stream_new( pa_source_output_new_data_init(&data); pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p); - pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); data.driver = __FILE__; data.module = c->options->module; data.client = c->client; @@ -585,7 +631,7 @@ static record_stream* record_stream_new( s->source_output->suspend = source_output_suspend_cb; s->source_output->userdata = s; - fix_record_buffer_attr_pre(s, adjust_latency, maxlength, fragsize); + fix_record_buffer_attr_pre(s, adjust_latency, early_requests, maxlength, fragsize); s->memblockq = pa_memblockq_new( 0, @@ -667,10 +713,10 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, uint32_t l = 0; for (;;) { - if ((l = pa_atomic_load(&s->missing)) <= 0) + if ((l = (uint32_t) pa_atomic_load(&s->missing)) <= 0) break; - if (pa_atomic_cmpxchg(&s->missing, l, 0)) + if (pa_atomic_cmpxchg(&s->missing, (int) l, 0)) break; } @@ -691,6 +737,8 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, case PLAYBACK_STREAM_MESSAGE_UNDERFLOW: { pa_tagstruct *t; +/* pa_log("signalling underflow"); */ + /* Report that we're empty */ t = pa_tagstruct_new(NULL, 0); pa_tagstruct_putu32(t, PA_COMMAND_UNDERFLOW); @@ -735,9 +783,17 @@ static int playback_stream_process_msg(pa_msgobject *o, int code, void*userdata, return 0; } -static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_latency, uint32_t *maxlength, uint32_t *tlength, uint32_t* prebuf, uint32_t* minreq) { +static void fix_playback_buffer_attr_pre( + 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; - pa_usec_t tlength_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(maxlength); @@ -750,29 +806,39 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la if (*maxlength == (uint32_t) -1 || *maxlength > MAX_MEMBLOCKQ_LENGTH) *maxlength = MAX_MEMBLOCKQ_LENGTH; if (*maxlength <= 0) - *maxlength = frame_size; + *maxlength = (uint32_t) frame_size; if (*tlength == (uint32_t) -1) - *tlength = pa_usec_to_bytes(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); + *tlength = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_TLENGTH_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); if (*tlength <= 0) - *tlength = frame_size; + *tlength = (uint32_t) frame_size; if (*minreq == (uint32_t) -1) - *minreq = pa_usec_to_bytes(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); + *minreq = (uint32_t) pa_usec_to_bytes_round_up(DEFAULT_PROCESS_MSEC*PA_USEC_PER_MSEC, &s->sink_input->sample_spec); if (*minreq <= 0) - *minreq = frame_size; + *minreq = (uint32_t) frame_size; if (*tlength < *minreq+frame_size) - *tlength = *minreq+frame_size; + *tlength = *minreq+(uint32_t) frame_size; - tlength_usec = pa_bytes_to_usec(*tlength, &s->sink_input->sample_spec); - minreq_usec = pa_bytes_to_usec(*minreq, &s->sink_input->sample_spec); + orig_tlength_usec = tlength_usec = pa_bytes_to_usec(*tlength, &s->sink_input->sample_spec); + orig_minreq_usec = minreq_usec = pa_bytes_to_usec(*minreq, &s->sink_input->sample_spec); pa_log_info("Requested tlength=%0.2f ms, minreq=%0.2f ms", (double) tlength_usec / PA_USEC_PER_MSEC, (double) minreq_usec / PA_USEC_PER_MSEC); - if (adjust_latency) { + if (early_requests) { + + /* In early request mode we need to emulate the classic + * fragment-based playback model. We do this setting the sink + * latency to the fragment size. */ + + sink_usec = minreq_usec; + + pa_log_debug("Early requests mode enabled, configuring sink latency to minreq."); + + } else if (adjust_latency) { /* So, the user asked us to adjust the latency of the stream * buffer according to the what the sink can provide. The @@ -796,6 +862,8 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la else sink_usec = 0; + pa_log_debug("Adjust latency mode enabled, configuring sink latency to half of overall latency."); + } else { /* Ok, the user didn't ask us to adjust the latency, but we @@ -806,11 +874,21 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la sink_usec = (tlength_usec - minreq_usec*2); else sink_usec = 0; + + pa_log_debug("Traditional mode enabled, modifying sink usec only for compat with minreq."); } s->sink_latency = pa_sink_input_set_requested_latency(s->sink_input, sink_usec); - if (adjust_latency) { + if (early_requests) { + + /* Ok, we didn't necessarily get what we were asking for, so + * let's tell the user */ + + minreq_usec = s->sink_latency; + + } else if (adjust_latency) { + /* Ok, we didn't necessarily get what we were asking for, so * let's subtract from what we asked for for the remaining * buffer space */ @@ -824,22 +902,33 @@ static void fix_playback_buffer_attr_pre(playback_stream *s, pa_bool_t adjust_la if (tlength_usec < s->sink_latency + 2*minreq_usec) tlength_usec = s->sink_latency + 2*minreq_usec; - *tlength = pa_usec_to_bytes(tlength_usec, &s->sink_input->sample_spec); - *minreq = pa_usec_to_bytes(minreq_usec, &s->sink_input->sample_spec); + if (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)) + *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) != + 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); if (*minreq <= 0) { - *minreq += frame_size; - *tlength += frame_size*2; + *minreq = (uint32_t) frame_size; + *tlength += (uint32_t) frame_size*2; } if (*tlength <= *minreq) - *tlength = *minreq*2 + frame_size; + *tlength = *minreq*2 + (uint32_t) frame_size; if (*prebuf == (uint32_t) -1 || *prebuf > *tlength) *prebuf = *tlength; } -static void fix_playback_buffer_attr_post(playback_stream *s, uint32_t *maxlength, uint32_t *tlength, uint32_t* prebuf, uint32_t* minreq) { +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); @@ -865,11 +954,13 @@ static playback_stream* playback_stream_new( uint32_t *minreq, pa_cvolume *volume, pa_bool_t muted, + pa_bool_t muted_set, uint32_t syncid, uint32_t *missing, pa_sink_input_flags_t flags, pa_proplist *p, - pa_bool_t adjust_latency) { + pa_bool_t adjust_latency, + pa_bool_t early_requests) { playback_stream *s, *ssync; pa_sink_input *sink_input; @@ -884,7 +975,6 @@ static playback_stream* playback_stream_new( pa_assert(tlength); pa_assert(prebuf); pa_assert(minreq); - pa_assert(volume); pa_assert(missing); pa_assert(p); @@ -910,15 +1000,16 @@ static playback_stream* playback_stream_new( pa_sink_input_new_data_init(&data); pa_proplist_update(data.proplist, PA_UPDATE_REPLACE, p); - pa_proplist_update(data.proplist, PA_UPDATE_MERGE, c->client->proplist); data.driver = __FILE__; data.module = c->options->module; data.client = c->client; data.sink = sink; 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); + if (volume) + pa_sink_input_new_data_set_volume(&data, volume); + if (muted_set) + 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); @@ -950,7 +1041,7 @@ static playback_stream* playback_stream_new( start_index = ssync ? pa_memblockq_get_read_index(ssync->memblockq) : 0; - fix_playback_buffer_attr_pre(s, adjust_latency, maxlength, tlength, prebuf, minreq); + fix_playback_buffer_attr_pre(s, adjust_latency, early_requests, maxlength, tlength, prebuf, minreq); pa_sink_input_get_silence(sink_input, &silence); s->memblockq = pa_memblockq_new( @@ -983,7 +1074,6 @@ static playback_stream* playback_stream_new( return s; } - /* Called from thread context */ static void playback_stream_request_bytes(playback_stream *s) { size_t m, previous_missing; @@ -997,7 +1087,7 @@ static void playback_stream_request_bytes(playback_stream *s) { /* pa_log("request_bytes(%lu)", (unsigned long) m); */ - previous_missing = pa_atomic_add(&s->missing, m); + previous_missing = (size_t) pa_atomic_add(&s->missing, (int) m); if (pa_memblockq_prebuf_active(s->memblockq) || (previous_missing < s->minreq && previous_missing+m >= s->minreq)) @@ -1143,8 +1233,8 @@ static void handle_seek(playback_stream *s, int64_t indexw) { pa_log_debug("Requesting rewind due to end of underrun."); pa_sink_input_request_rewind(s->sink_input, - s->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : s->sink_input->thread_info.underrun_for, - FALSE, TRUE); + (size_t) (s->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : s->sink_input->thread_info.underrun_for), + FALSE, TRUE, FALSE); } } else { @@ -1157,7 +1247,7 @@ static void handle_seek(playback_stream *s, int64_t indexw) { * let's have it usk us again */ pa_log_debug("Requesting rewind due to rewrite."); - pa_sink_input_request_rewind(s->sink_input, indexr - indexw, TRUE, FALSE); + pa_sink_input_request_rewind(s->sink_input, (size_t) (indexr - indexw), TRUE, FALSE, FALSE); } } @@ -1197,7 +1287,7 @@ static int sink_input_process_msg(pa_msgobject *o, int code, void *userdata, int if (pa_memblockq_push_align(s->memblockq, chunk) < 0) { pa_log_warn("Failed to push data into queue"); pa_asyncmsgq_post(pa_thread_mq_get()->outq, PA_MSGOBJECT(s), PLAYBACK_STREAM_MESSAGE_OVERFLOW, NULL, 0, NULL, NULL); - pa_memblockq_seek(s->memblockq, chunk->length, PA_SEEK_RELATIVE); + pa_memblockq_seek(s->memblockq, (int64_t) chunk->length, PA_SEEK_RELATIVE); } handle_seek(s, windex); @@ -1427,7 +1517,7 @@ static void sink_input_moved_cb(pa_sink_input *i) { prebuf = (uint32_t) pa_memblockq_get_prebuf(s->memblockq); minreq = (uint32_t) pa_memblockq_get_minreq(s->memblockq); - fix_playback_buffer_attr_pre(s, TRUE, &maxlength, &tlength, &prebuf, &minreq); + 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); @@ -1526,7 +1616,7 @@ static void source_output_moved_cb(pa_source_output *o) { fragsize = (uint32_t) s->fragment_size; maxlength = (uint32_t) pa_memblockq_get_length(s->memblockq); - fix_record_buffer_attr_pre(s, TRUE, &maxlength, &fragsize); + fix_record_buffer_attr_pre(s, TRUE, FALSE, &maxlength, &fragsize); pa_memblockq_set_maxlength(s->memblockq, maxlength); fix_record_buffer_attr_post(s, &maxlength, &fragsize); @@ -1573,7 +1663,7 @@ static pa_tagstruct *reply_new(uint32_t tag) { return reply; } -static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED 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); playback_stream *s; uint32_t maxlength, tlength, prebuf, minreq, sink_index, syncid, missing; @@ -1593,10 +1683,14 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC no_move = FALSE, variable_rate = FALSE, muted = FALSE, - adjust_latency = FALSE; + adjust_latency = FALSE, + early_requests = FALSE, + dont_inhibit_auto_suspend = FALSE, + muted_set = FALSE; pa_sink_input_flags_t flags = 0; pa_proplist *p; + pa_bool_t volume_set = TRUE; pa_native_connection_assert_ref(c); pa_assert(t); @@ -1622,7 +1716,9 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(sink_name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_channel_map_valid(&map), tag, PA_ERR_INVALID); 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); @@ -1661,6 +1757,26 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC } } + if (c->version >= 14) { + + if (pa_tagstruct_get_boolean(t, &volume_set) < 0 || + pa_tagstruct_get_boolean(t, &early_requests) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + + if (c->version >= 15) { + + if (pa_tagstruct_get_boolean(t, &muted_set) < 0 || + pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + if (!pa_tagstruct_eof(t)) { protocol_error(c); pa_proplist_free(p); @@ -1677,7 +1793,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC } else if (sink_name) { - if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1))) { + if (!(sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK))) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); pa_proplist_free(p); return; @@ -1692,9 +1808,14 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC (fix_rate ? PA_SINK_INPUT_FIX_RATE : 0) | (fix_channels ? PA_SINK_INPUT_FIX_CHANNELS : 0) | (no_move ? PA_SINK_INPUT_DONT_MOVE : 0) | - (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0); + (variable_rate ? PA_SINK_INPUT_VARIABLE_RATE : 0) | + (dont_inhibit_auto_suspend ? PA_SINK_INPUT_DONT_INHIBIT_AUTO_SUSPEND : 0); - s = playback_stream_new(c, sink, &ss, &map, &maxlength, &tlength, &prebuf, &minreq, &volume, muted, syncid, &missing, flags, p, adjust_latency); + /* Only since protocol version 15 there's a seperate muted_set + * flag. For older versions we synthesize it here */ + 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); pa_proplist_free(p); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -1736,7 +1857,7 @@ static void command_create_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GC pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_delete_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t channel; @@ -1794,7 +1915,7 @@ static void command_delete_stream(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED 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); record_stream *s; uint32_t maxlength, fragment_size; @@ -1814,7 +1935,9 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ no_move = FALSE, variable_rate = FALSE, adjust_latency = FALSE, - peak_detect = FALSE; + peak_detect = FALSE, + early_requests = FALSE, + dont_inhibit_auto_suspend = FALSE; pa_source_output_flags_t flags = 0; pa_proplist *p; uint32_t direct_on_input_idx = PA_INVALID_INDEX; @@ -1836,9 +1959,11 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + CHECK_VALIDITY(c->pstream, !source_name || pa_namereg_is_valid_name(source_name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, source_index == PA_INVALID_INDEX || !source_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !source_name || source_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_sample_spec_valid(&ss), tag, PA_ERR_INVALID); 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); p = pa_proplist_new(); @@ -1875,6 +2000,24 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } } + if (c->version >= 14) { + + if (pa_tagstruct_get_boolean(t, &early_requests) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + + if (c->version >= 15) { + + if (pa_tagstruct_get_boolean(t, &dont_inhibit_auto_suspend) < 0) { + protocol_error(c); + pa_proplist_free(p); + return; + } + } + if (!pa_tagstruct_eof(t)) { protocol_error(c); pa_proplist_free(p); @@ -1891,7 +2034,7 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ } else if (source_name) { - if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE, 1))) { + if (!(source = pa_namereg_get(c->protocol->core, source_name, PA_NAMEREG_SOURCE))) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); pa_proplist_free(p); return; @@ -1915,9 +2058,10 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ (fix_rate ? PA_SOURCE_OUTPUT_FIX_RATE : 0) | (fix_channels ? PA_SOURCE_OUTPUT_FIX_CHANNELS : 0) | (no_move ? PA_SOURCE_OUTPUT_DONT_MOVE : 0) | - (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0); + (variable_rate ? PA_SOURCE_OUTPUT_VARIABLE_RATE : 0) | + (dont_inhibit_auto_suspend ? PA_SOURCE_OUTPUT_DONT_INHIBIT_AUTO_SUSPEND : 0); - s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input); + s = record_stream_new(c, source, &ss, &map, peak_detect, &maxlength, &fragment_size, flags, p, adjust_latency, direct_on_input, early_requests); pa_proplist_free(p); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_INVALID); @@ -1954,8 +2098,9 @@ static void command_create_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_exit(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); + int ret; pa_native_connection_assert_ref(c); pa_assert(t); @@ -1966,16 +2111,17 @@ static void command_exit(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); + ret = pa_core_exit(c->protocol->core, FALSE, 0); + CHECK_VALIDITY(c->pstream, ret >= 0, tag, PA_ERR_ACCESS); - c->protocol->core->mainloop->quit(c->protocol->core->mainloop, 0); pa_pstream_send_simple_ack(c->pstream, tag); /* nonsense */ } -static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_auth(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const void*cookie; pa_tagstruct *reply; - pa_bool_t shm_on_remote, do_shm; + pa_bool_t shm_on_remote = FALSE, do_shm; pa_native_connection_assert_ref(c); pa_assert(t); @@ -2070,6 +2216,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t if (c->version < 10 || (c->version >= 13 && !shm_on_remote)) do_shm = FALSE; +#ifdef HAVE_CREDS if (do_shm) { /* Only enable SHM if both sides are owned by the same * user. This is a security measure because otherwise data @@ -2079,6 +2226,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t if (!(creds = pa_pdispatch_creds(pd)) || getuid() != creds->uid) do_shm = FALSE; } +#endif pa_log_debug("Negotiated SHM: %s", pa_yes_no(do_shm)); pa_pstream_enable_shm(c->pstream, do_shm); @@ -2102,7 +2250,7 @@ static void command_auth(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t #endif } -static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_set_client_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *name = NULL; pa_proplist *p; @@ -2142,7 +2290,7 @@ static void command_set_client_name(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSE pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_lookup(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *name; uint32_t idx = PA_IDXSET_INVALID; @@ -2157,16 +2305,16 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); if (command == PA_COMMAND_LOOKUP_SINK) { pa_sink *sink; - if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1))) + if ((sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK))) idx = sink->index; } else { pa_source *source; pa_assert(command == PA_COMMAND_LOOKUP_SOURCE); - if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1))) + if ((source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE))) idx = source->index; } @@ -2180,7 +2328,7 @@ static void command_lookup(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uin } } -static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_drain_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; playback_stream *s; @@ -2202,7 +2350,7 @@ static void command_drain_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC pa_asyncmsgq_post(s->sink_input->sink->asyncmsgq, PA_MSGOBJECT(s->sink_input), SINK_INPUT_MESSAGE_DRAIN, PA_UINT_TO_PTR(tag), 0, NULL, NULL); } -static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_stat(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_tagstruct *reply; const pa_mempool_stat *stat; @@ -2224,11 +2372,11 @@ static void command_stat(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->allocated_size)); pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->n_accumulated)); pa_tagstruct_putu32(reply, (uint32_t) pa_atomic_load(&stat->accumulated_size)); - pa_tagstruct_putu32(reply, pa_scache_total_size(c->protocol->core)); + pa_tagstruct_putu32(reply, (uint32_t) pa_scache_total_size(c->protocol->core)); pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_playback_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_tagstruct *reply; playback_stream *s; @@ -2274,7 +2422,7 @@ static void command_get_playback_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_record_latency(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_tagstruct *reply; record_stream *s; @@ -2306,7 +2454,7 @@ static void command_get_record_latency(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_create_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); upload_stream *s; uint32_t length; @@ -2348,7 +2496,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ if (!(name = pa_proplist_gets(p, PA_PROP_EVENT_ID))) name = pa_proplist_gets(p, PA_PROP_MEDIA_NAME); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); s = upload_stream_new(c, &ss, &map, name, length, p); pa_proplist_free(p); @@ -2361,7 +2509,7 @@ static void command_create_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_finish_upload_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t channel; upload_stream *s; @@ -2390,7 +2538,7 @@ static void command_finish_upload_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ upload_stream_unlink(s); } -static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_play_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t sink_index; pa_volume_t volume; @@ -2413,13 +2561,15 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui return; } - CHECK_VALIDITY(c->pstream, sink_index != PA_INVALID_INDEX || !sink_name || (*sink_name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || pa_namereg_is_valid_name(sink_name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, sink_index == PA_INVALID_INDEX || !sink_name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !sink_name || sink_index == PA_INVALID_INDEX, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); if (sink_index != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, sink_index); else - sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, sink_name, PA_NAMEREG_SINK); CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); @@ -2432,6 +2582,8 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui return; } + pa_proplist_update(p, PA_UPDATE_MERGE, c->client->proplist); + if (pa_scache_play_item(c->protocol->core, name, sink, volume, p, &idx) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); pa_proplist_free(p); @@ -2448,7 +2600,7 @@ static void command_play_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_remove_sample(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *name; @@ -2462,7 +2614,7 @@ static void command_remove_sample(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, name && pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); if (pa_scache_remove_item(c->protocol->core, name) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_NOENTITY); @@ -2506,8 +2658,8 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin PA_TAG_SAMPLE_SPEC, &fixed_ss, PA_TAG_CHANNEL_MAP, &sink->channel_map, PA_TAG_U32, sink->module ? sink->module->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_sink_get_volume(sink), - PA_TAG_BOOLEAN, pa_sink_get_mute(sink), + PA_TAG_CVOLUME, pa_sink_get_volume(sink, FALSE), + PA_TAG_BOOLEAN, pa_sink_get_mute(sink, FALSE), PA_TAG_U32, sink->monitor_source ? sink->monitor_source->index : PA_INVALID_INDEX, PA_TAG_STRING, sink->monitor_source ? sink->monitor_source->name : NULL, PA_TAG_USEC, pa_sink_get_latency(sink), @@ -2519,6 +2671,9 @@ static void sink_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sin pa_tagstruct_put_proplist(t, sink->proplist); pa_tagstruct_put_usec(t, pa_sink_get_requested_latency(sink)); } + + if (c->version >= 15) + pa_tagstruct_put_volume(t, sink->base_volume); } static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_source *source) { @@ -2537,8 +2692,8 @@ static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s PA_TAG_SAMPLE_SPEC, &fixed_ss, PA_TAG_CHANNEL_MAP, &source->channel_map, PA_TAG_U32, source->module ? source->module->index : PA_INVALID_INDEX, - PA_TAG_CVOLUME, pa_source_get_volume(source), - PA_TAG_BOOLEAN, pa_source_get_mute(source), + PA_TAG_CVOLUME, pa_source_get_volume(source, FALSE), + PA_TAG_BOOLEAN, pa_source_get_mute(source, FALSE), PA_TAG_U32, source->monitor_of ? source->monitor_of->index : PA_INVALID_INDEX, PA_TAG_STRING, source->monitor_of ? source->monitor_of->name : NULL, PA_TAG_USEC, pa_source_get_latency(source), @@ -2550,8 +2705,10 @@ static void source_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s pa_tagstruct_put_proplist(t, source->proplist); pa_tagstruct_put_usec(t, pa_source_get_requested_latency(source)); } -} + if (c->version >= 15) + pa_tagstruct_put_volume(t, source->base_volume); +} static void client_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_client *client) { pa_assert(t); @@ -2574,8 +2731,8 @@ static void module_fill_tagstruct(pa_tagstruct *t, pa_module *module) { pa_tagstruct_putu32(t, module->index); pa_tagstruct_puts(t, module->name); pa_tagstruct_puts(t, module->argument); - pa_tagstruct_putu32(t, module->n_used); - pa_tagstruct_put_boolean(t, module->auto_unload); + pa_tagstruct_putu32(t, (uint32_t) module->n_used); + pa_tagstruct_put_boolean(t, FALSE); } static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_sink_input *s) { @@ -2594,7 +2751,7 @@ static void sink_input_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_tagstruct_putu32(t, s->sink->index); pa_tagstruct_put_sample_spec(t, &fixed_ss); pa_tagstruct_put_channel_map(t, &s->channel_map); - pa_tagstruct_put_cvolume(t, &s->volume); + pa_tagstruct_put_cvolume(t, pa_sink_input_get_volume(s)); pa_tagstruct_put_usec(t, pa_sink_input_get_latency(s, &sink_latency)); pa_tagstruct_put_usec(t, sink_latency); pa_tagstruct_puts(t, pa_resample_method_to_string(pa_sink_input_get_resample_method(s))); @@ -2647,7 +2804,7 @@ static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s pa_tagstruct_put_usec(t, e->memchunk.memblock ? pa_bytes_to_usec(e->memchunk.length, &e->sample_spec) : 0); pa_tagstruct_put_sample_spec(t, &fixed_ss); pa_tagstruct_put_channel_map(t, &e->channel_map); - pa_tagstruct_putu32(t, e->memchunk.length); + pa_tagstruct_putu32(t, (uint32_t) e->memchunk.length); pa_tagstruct_put_boolean(t, e->lazy); pa_tagstruct_puts(t, e->filename); @@ -2655,7 +2812,7 @@ static void scache_fill_tagstruct(pa_native_connection *c, pa_tagstruct *t, pa_s pa_tagstruct_put_proplist(t, e->proplist); } -static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; pa_sink *sink = NULL; @@ -2665,7 +2822,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u pa_sink_input *si = NULL; pa_source_output *so = NULL; pa_scache_entry *sce = NULL; - const char *name; + const char *name = NULL; pa_tagstruct *reply; pa_native_connection_assert_ref(c); @@ -2683,18 +2840,21 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); if (command == PA_COMMAND_GET_SINK_INFO) { if (idx != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK); } else if (command == PA_COMMAND_GET_SOURCE_INFO) { if (idx != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, idx); else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE); } else if (command == PA_COMMAND_GET_CLIENT_INFO) client = pa_idxset_get_by_index(c->protocol->core->clients, idx); else if (command == PA_COMMAND_GET_MODULE_INFO) @@ -2708,7 +2868,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u if (idx != PA_INVALID_INDEX) sce = pa_idxset_get_by_index(c->protocol->core->scache, idx); else - sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE, 0); + sce = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SAMPLE); } if (!sink && !source && !client && !module && !si && !so && !sce) { @@ -2734,7 +2894,7 @@ static void command_get_info(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, u pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_info_list(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_idxset *i; uint32_t idx; @@ -2794,7 +2954,7 @@ static void command_get_info_list(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t comma pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_get_server_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_get_server_info(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_tagstruct *reply; char txt[256]; @@ -2844,7 +3004,7 @@ static void subscription_cb(pa_core *core, pa_subscription_event_type_t e, uint3 pa_pstream_send_tagstruct(c->pstream, t); } -static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_subscribe(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_subscription_mask_t m; @@ -2873,7 +3033,7 @@ static void command_subscribe(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint } static void command_set_volume( - PA_GCC_UNUSED pa_pdispatch *pd, + pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, @@ -2900,7 +3060,10 @@ static void command_set_volume( } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); CHECK_VALIDITY(c->pstream, pa_cvolume_valid(&volume), tag, PA_ERR_INVALID); switch (command) { @@ -2909,14 +3072,14 @@ static void command_set_volume( if (idx != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK); break; case PA_COMMAND_SET_SOURCE_VOLUME: if (idx != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, idx); else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE); break; case PA_COMMAND_SET_SINK_INPUT_VOLUME: @@ -2940,7 +3103,7 @@ static void command_set_volume( } static void command_set_mute( - PA_GCC_UNUSED pa_pdispatch *pd, + pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, @@ -2967,7 +3130,10 @@ static void command_set_mute( } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); switch (command) { @@ -2976,7 +3142,7 @@ static void command_set_mute( if (idx != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK); break; @@ -2984,7 +3150,7 @@ static void command_set_mute( if (idx != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, idx); else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE); break; @@ -3008,7 +3174,7 @@ static void command_set_mute( pa_pstream_send_simple_ack(c->pstream, tag); } -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) { +static void command_cork_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; pa_bool_t b; @@ -3031,10 +3197,14 @@ static void command_cork_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_ CHECK_VALIDITY(c->pstream, playback_stream_isinstance(s), tag, PA_ERR_NOENTITY); pa_sink_input_cork(s->sink_input, b); + + if (b) + s->is_underrun = TRUE; + pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_trigger_or_flush_or_prebuf_playback_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_trigger_or_flush_or_prebuf_playback_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; playback_stream *s; @@ -3074,7 +3244,7 @@ static void command_trigger_or_flush_or_prebuf_playback_stream(PA_GCC_UNUSED pa_ pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_cork_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; record_stream *s; @@ -3099,7 +3269,7 @@ static void command_cork_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UN pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_flush_record_stream(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_flush_record_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; record_stream *s; @@ -3139,7 +3309,7 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u if (command == PA_COMMAND_SET_PLAYBACK_STREAM_BUFFER_ATTR) { playback_stream *s; - pa_bool_t adjust_latency = FALSE; + pa_bool_t adjust_latency = FALSE, early_requests = FALSE; s = pa_idxset_get_by_index(c->output_streams, idx); CHECK_VALIDITY(c->pstream, s, tag, PA_ERR_NOENTITY); @@ -3153,12 +3323,13 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u PA_TAG_U32, &minreq, PA_TAG_INVALID) < 0 || (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) || + (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - fix_playback_buffer_attr_pre(s, adjust_latency, &maxlength, &tlength, &prebuf, &minreq); + fix_playback_buffer_attr_pre(s, adjust_latency, early_requests, &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); @@ -3176,7 +3347,7 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u } else { record_stream *s; - pa_bool_t adjust_latency = FALSE; + pa_bool_t adjust_latency = FALSE, early_requests = FALSE; pa_assert(command == PA_COMMAND_SET_RECORD_STREAM_BUFFER_ATTR); s = pa_idxset_get_by_index(c->record_streams, idx); @@ -3188,12 +3359,13 @@ static void command_set_stream_buffer_attr(pa_pdispatch *pd, uint32_t command, u PA_TAG_U32, &fragsize, PA_TAG_INVALID) < 0 || (c->version >= 13 && pa_tagstruct_get_boolean(t, &adjust_latency) < 0) || + (c->version >= 14 && pa_tagstruct_get_boolean(t, &early_requests) < 0) || !pa_tagstruct_eof(t)) { protocol_error(c); return; } - fix_record_buffer_attr_pre(s, adjust_latency, &maxlength, &fragsize); + fix_record_buffer_attr_pre(s, adjust_latency, early_requests, &maxlength, &fragsize); pa_memblockq_set_maxlength(s->memblockq, maxlength); fix_record_buffer_attr_post(s, &maxlength, &fragsize); @@ -3384,7 +3556,7 @@ static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t if (!z) break; - changed += pa_proplist_unset(p, z) >= 0; + changed += (unsigned) (pa_proplist_unset(p, z) >= 0); pa_xfree(z); } @@ -3410,7 +3582,7 @@ static void command_remove_proplist(pa_pdispatch *pd, uint32_t command, uint32_t } } -static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_set_default_sink_or_source(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); const char *s; @@ -3424,13 +3596,13 @@ static void command_set_default_sink_or_source(PA_GCC_UNUSED pa_pdispatch *pd, u } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, !s || (*s && pa_utf8_valid(s)), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !s || pa_namereg_is_valid_name(s), tag, PA_ERR_INVALID); pa_namereg_set_default(c->protocol->core, s, command == PA_COMMAND_SET_DEFAULT_SOURCE ? PA_NAMEREG_SOURCE : PA_NAMEREG_SINK); pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_set_stream_name(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; const char *name; @@ -3470,7 +3642,7 @@ static void command_set_stream_name(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t com pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_kill(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; @@ -3518,7 +3690,7 @@ static void command_kill(PA_GCC_UNUSED pa_pdispatch *pd, uint32_t command, uint3 pa_native_connection_unref(c); } -static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_load_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); pa_module *m; const char *name, *argument; @@ -3548,7 +3720,7 @@ static void command_load_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED ui pa_pstream_send_tagstruct(c->pstream, reply); } -static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { +static void command_unload_module(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx; pa_module *m; @@ -3566,158 +3738,21 @@ static void command_unload_module(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED m = pa_idxset_get_by_index(c->protocol->core->modules, idx); CHECK_VALIDITY(c->pstream, m, tag, PA_ERR_NOENTITY); - pa_module_unload_request(m); + pa_module_unload_request(m, FALSE); pa_pstream_send_simple_ack(c->pstream, tag); } -static void command_add_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); - const char *name, *module, *argument; - uint32_t type; - uint32_t idx; - pa_tagstruct *reply; - - pa_native_connection_assert_ref(c); - pa_assert(t); - - if (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_getu32(t, &type) < 0 || - pa_tagstruct_gets(t, &module) < 0 || - pa_tagstruct_gets(t, &argument) < 0 || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name && *name && pa_utf8_valid(name), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, type == 0 || type == 1, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, module && *module && pa_utf8_valid(module), tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !argument || pa_utf8_valid(argument), tag, PA_ERR_INVALID); - - if (pa_autoload_add(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE, module, argument, &idx) < 0) { - pa_pstream_send_error(c->pstream, tag, PA_ERR_EXIST); - return; - } - - reply = reply_new(tag); - pa_tagstruct_putu32(reply, idx); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_remove_autoload(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); - const char *name = NULL; - uint32_t type, idx = PA_IDXSET_INVALID; - int r; - - pa_native_connection_assert_ref(c); - pa_assert(t); - - if ((pa_tagstruct_getu32(t, &idx) < 0 && - (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_getu32(t, &type) < 0)) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !name || (*name && pa_utf8_valid(name) && (type == 0 || type == 1)), tag, PA_ERR_INVALID); - - if (name) - r = pa_autoload_remove_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); - else - r = pa_autoload_remove_by_index(c->protocol->core, idx); - - CHECK_VALIDITY(c->pstream, r >= 0, tag, PA_ERR_NOENTITY); - - pa_pstream_send_simple_ack(c->pstream, tag); -} - -static void autoload_fill_tagstruct(pa_tagstruct *t, const pa_autoload_entry *e) { - pa_assert(t && e); - - pa_tagstruct_putu32(t, e->index); - pa_tagstruct_puts(t, e->name); - pa_tagstruct_putu32(t, e->type == PA_NAMEREG_SINK ? 0 : 1); - pa_tagstruct_puts(t, e->module); - pa_tagstruct_puts(t, e->argument); -} - -static void command_get_autoload_info(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); - const pa_autoload_entry *a = NULL; - uint32_t type, idx; - const char *name; - pa_tagstruct *reply; - - pa_native_connection_assert_ref(c); - pa_assert(t); - - if ((pa_tagstruct_getu32(t, &idx) < 0 && - (pa_tagstruct_gets(t, &name) < 0 || - pa_tagstruct_getu32(t, &type) < 0)) || - !pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, name || idx != PA_IDXSET_INVALID, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, !name || (*name && (type == 0 || type == 1) && pa_utf8_valid(name)), tag, PA_ERR_INVALID); - - if (name) - a = pa_autoload_get_by_name(c->protocol->core, name, type == 0 ? PA_NAMEREG_SINK : PA_NAMEREG_SOURCE); - else - a = pa_autoload_get_by_index(c->protocol->core, idx); - - CHECK_VALIDITY(c->pstream, a, tag, PA_ERR_NOENTITY); - - reply = reply_new(tag); - autoload_fill_tagstruct(reply, a); - pa_pstream_send_tagstruct(c->pstream, reply); -} - -static void command_get_autoload_info_list(PA_GCC_UNUSED pa_pdispatch *pd, PA_GCC_UNUSED uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { - pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); - pa_tagstruct *reply; - - pa_native_connection_assert_ref(c); - pa_assert(t); - - if (!pa_tagstruct_eof(t)) { - protocol_error(c); - return; - } - - CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - - reply = reply_new(tag); - - if (c->protocol->core->autoload_hashmap) { - pa_autoload_entry *a; - void *state = NULL; - - while ((a = pa_hashmap_iterate(c->protocol->core->autoload_hashmap, &state, NULL))) - autoload_fill_tagstruct(reply, a); - } - - pa_pstream_send_tagstruct(c->pstream, reply); -} - static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa_tagstruct *t, void *userdata) { pa_native_connection *c = PA_NATIVE_CONNECTION(userdata); uint32_t idx = PA_INVALID_INDEX, idx_device = PA_INVALID_INDEX; - const char *name = NULL; + const char *name_device = NULL; pa_native_connection_assert_ref(c); pa_assert(t); if (pa_tagstruct_getu32(t, &idx) < 0 || pa_tagstruct_getu32(t, &idx_device) < 0 || - pa_tagstruct_gets(t, &name) < 0 || + pa_tagstruct_gets(t, &name_device) < 0 || !pa_tagstruct_eof(t)) { protocol_error(c); return; @@ -3725,7 +3760,11 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX, tag, PA_ERR_INVALID); - CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || !name || (*name && pa_utf8_valid(name)), tag, PA_ERR_INVALID); + + CHECK_VALIDITY(c->pstream, !name_device || pa_namereg_is_valid_name(name_device), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx_device != PA_INVALID_INDEX || name_device, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx_device == PA_INVALID_INDEX || !name_device, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name_device || idx_device == PA_INVALID_INDEX, tag, PA_ERR_INVALID); if (command == PA_COMMAND_MOVE_SINK_INPUT) { pa_sink_input *si = NULL; @@ -3736,7 +3775,7 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag if (idx_device != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx_device); else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SINK); CHECK_VALIDITY(c->pstream, si && sink, tag, PA_ERR_NOENTITY); @@ -3755,7 +3794,7 @@ static void command_move_stream(pa_pdispatch *pd, uint32_t command, uint32_t tag if (idx_device != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, idx_device); else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, name_device, PA_NAMEREG_SOURCE); CHECK_VALIDITY(c->pstream, so && source, tag, PA_ERR_NOENTITY); @@ -3786,12 +3825,17 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || !*name || pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_namereg_is_valid_name(name) || *name == 0, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); if (command == PA_COMMAND_SUSPEND_SINK) { if (idx == PA_INVALID_INDEX && name && !*name) { + pa_log_debug("%s all sinks", b ? "Suspending" : "Resuming"); + if (pa_sink_suspend_all(c->protocol->core, b) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); return; @@ -3802,7 +3846,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa if (idx != PA_INVALID_INDEX) sink = pa_idxset_get_by_index(c->protocol->core->sinks, idx); else - sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK, 1); + sink = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SINK); CHECK_VALIDITY(c->pstream, sink, tag, PA_ERR_NOENTITY); @@ -3817,6 +3861,8 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa if (idx == PA_INVALID_INDEX && name && !*name) { + pa_log_debug("%s all sources", b ? "Suspending" : "Resuming"); + if (pa_source_suspend_all(c->protocol->core, b) < 0) { pa_pstream_send_error(c->pstream, tag, PA_ERR_INVALID); return; @@ -3828,7 +3874,7 @@ static void command_suspend(pa_pdispatch *pd, uint32_t command, uint32_t tag, pa if (idx != PA_INVALID_INDEX) source = pa_idxset_get_by_index(c->protocol->core->sources, idx); else - source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE, 1); + source = pa_namereg_get(c->protocol->core, name, PA_NAMEREG_SOURCE); CHECK_VALIDITY(c->pstream, source, tag, PA_ERR_NOENTITY); @@ -3859,7 +3905,10 @@ static void command_extension(pa_pdispatch *pd, uint32_t command, uint32_t tag, } CHECK_VALIDITY(c->pstream, c->authorized, tag, PA_ERR_ACCESS); - CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || !name || !*name || pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || pa_utf8_valid(name), tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx != PA_INVALID_INDEX || name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, idx == PA_INVALID_INDEX || !name, tag, PA_ERR_INVALID); + CHECK_VALIDITY(c->pstream, !name || idx == PA_INVALID_INDEX, tag, PA_ERR_INVALID); if (idx != PA_INVALID_INDEX) m = pa_idxset_get_by_index(c->protocol->core->modules, idx); @@ -3909,6 +3958,8 @@ static void pstream_memblock_callback(pa_pstream *p, uint32_t channel, int64_t o return; } +/* pa_log("got %lu bytes", (unsigned long) chunk->length); */ + if (playback_stream_isinstance(stream)) { playback_stream *ps = PLAYBACK_STREAM(stream); @@ -4020,7 +4071,9 @@ static void auth_timeout(pa_mainloop_api*m, pa_time_event *e, const struct timev void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_native_options *o) { pa_native_connection *c; - char cname[256], pname[128]; + char pname[128]; + pa_client *client; + pa_client_new_data data; pa_assert(p); pa_assert(io); @@ -4032,6 +4085,18 @@ void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_nati return; } + pa_client_new_data_init(&data); + data.module = o->module; + data.driver = __FILE__; + pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); + pa_proplist_setf(data.proplist, PA_PROP_APPLICATION_NAME, "Native client (%s)", pname); + pa_proplist_sets(data.proplist, "native-protocol.peer", pname); + client = pa_client_new(p->core, &data); + pa_client_new_data_done(&data); + + if (!client) + return; + c = pa_msgobject_new(pa_native_connection); c->parent.parent.free = native_connection_free; c->parent.process_msg = native_connection_process_msg; @@ -4063,13 +4128,9 @@ void pa_native_protocol_connect(pa_native_protocol *p, pa_iochannel *io, pa_nati c->is_local = pa_iochannel_socket_is_local(io); c->version = 8; - pa_iochannel_socket_peer_to_string(io, pname, sizeof(pname)); - pa_snprintf(cname, sizeof(cname), "Native client (%s)", pname); - c->client = pa_client_new(p->core, __FILE__, cname); - pa_proplist_sets(c->client->proplist, "native-protocol.peer", pname); + c->client = client; c->client->kill = client_kill_cb; c->client->userdata = c; - c->client->module = o->module; c->pstream = pa_pstream_new(p->core->mainloop, io, p->core->mempool); pa_pstream_set_recieve_packet_callback(c->pstream, pstream_packet_callback, c); @@ -4296,7 +4357,7 @@ int pa_native_options_parse(pa_native_options *o, pa_core *c, pa_modargs *ma) { if ((acl = pa_modargs_get_value(ma, "auth-ip-acl", NULL))) { pa_ip_acl *ipa; - if (!(o->auth_ip_acl = pa_ip_acl_new(acl))) { + if (!(ipa = pa_ip_acl_new(acl))) { pa_log("Failed to parse IP ACL '%s'", acl); return -1; }