X-Git-Url: https://code.delx.au/pulseaudio/blobdiff_plain/a68652a42c14e6d2136601d4a34ad1a2e7336e92..d806b197144733607b0ecb8678c6ee5d99ccc9ea:/src/modules/module-loopback.c diff --git a/src/modules/module-loopback.c b/src/modules/module-loopback.c index d80494a1..5876f9db 100644 --- a/src/modules/module-loopback.c +++ b/src/modules/module-loopback.c @@ -43,7 +43,7 @@ PA_MODULE_AUTHOR("Pierre-Louis Bossart"); PA_MODULE_DESCRIPTION("Loopback from source to sink"); PA_MODULE_VERSION(PACKAGE_VERSION); -PA_MODULE_LOAD_ONCE(FALSE); +PA_MODULE_LOAD_ONCE(false); PA_MODULE_USAGE( "source= " "sink= " @@ -86,7 +86,7 @@ struct userdata { size_t skip; pa_usec_t latency; - pa_bool_t in_pop; + bool in_pop; size_t min_memblockq_length; struct { @@ -138,29 +138,35 @@ static void teardown(struct userdata *u) { pa_assert(u); pa_assert_ctl_context(); - if (u->asyncmsgq) - pa_asyncmsgq_flush(u->asyncmsgq, 0); - u->adjust_time = 0; enable_adjust_timer(u, false); - if (u->sink_input) - pa_sink_input_unlink(u->sink_input); + /* Handling the asyncmsgq between the source output and the sink input + * requires some care. When the source output is unlinked, nothing needs + * to be done for the asyncmsgq, because the source output is the sending + * end. But when the sink input is unlinked, we should ensure that the + * asyncmsgq is emptied, because the messages in the queue hold references + * to the sink input. Also, we need to ensure that new messages won't be + * written to the queue after we have emptied it. + * + * Emptying the queue can be done in the state_changed() callback of the + * sink input, when the new state is "unlinked". + * + * Preventing new messages from being written to the queue can be achieved + * by unlinking the source output before unlinking the sink input. There + * are no other writers for that queue, so this is sufficient. */ - if (u->source_output) + if (u->source_output) { pa_source_output_unlink(u->source_output); + pa_source_output_unref(u->source_output); + u->source_output = NULL; + } if (u->sink_input) { - u->sink_input->parent.process_msg = pa_sink_input_process_msg; + pa_sink_input_unlink(u->sink_input); pa_sink_input_unref(u->sink_input); u->sink_input = NULL; } - - if (u->source_output) { - u->source_output->parent.process_msg = pa_source_output_process_msg; - pa_source_output_unref(u->source_output); - u->source_output = NULL; - } } /* Called from main context */ @@ -375,17 +381,20 @@ static void source_output_kill_cb(pa_source_output *o) { pa_assert_se(u = o->userdata); teardown(u); - pa_module_unload_request(u->module, TRUE); + pa_module_unload_request(u->module, true); } /* Called from main thread */ -static pa_bool_t source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) { +static bool source_output_may_move_to_cb(pa_source_output *o, pa_source *dest) { struct userdata *u; pa_source_output_assert_ref(o); pa_assert_ctl_context(); pa_assert_se(u = o->userdata); + if (!u->sink_input || !u->sink_input->sink) + return true; + return dest != u->sink_input->sink->monitor_source; } @@ -413,7 +422,7 @@ static void source_output_moving_cb(pa_source_output *o, pa_source *dest) { } /* Called from main thread */ -static void source_output_suspend_cb(pa_source_output *o, pa_bool_t suspended) { +static void source_output_suspend_cb(pa_source_output *o, bool suspended) { struct userdata *u; pa_source_output_assert_ref(o); @@ -448,10 +457,10 @@ static int sink_input_pop_cb(pa_sink_input *i, size_t nbytes, pa_memchunk *chunk pa_assert_se(u = i->userdata); pa_assert(chunk); - u->in_pop = TRUE; + u->in_pop = true; while (pa_asyncmsgq_process_one(u->asyncmsgq) > 0) ; - u->in_pop = FALSE; + u->in_pop = false; if (pa_memblockq_peek(u->memblockq, chunk) < 0) { pa_log_info("Could not peek into queue"); @@ -502,7 +511,7 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state)) pa_memblockq_push_align(u->memblockq, chunk); else - pa_memblockq_flush_write(u->memblockq, TRUE); + pa_memblockq_flush_write(u->memblockq, true); update_min_memblockq_length(u); @@ -515,7 +524,7 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in pa_log_debug("Requesting rewind due to end of underrun."); pa_sink_input_request_rewind(u->sink_input, (size_t) (u->sink_input->thread_info.underrun_for == (size_t) -1 ? 0 : u->sink_input->thread_info.underrun_for), - FALSE, TRUE, FALSE); + false, true, false); } u->recv_counter += (int64_t) chunk->length; @@ -527,9 +536,9 @@ static int sink_input_process_msg_cb(pa_msgobject *obj, int code, void *data, in pa_sink_input_assert_io_context(u->sink_input); if (PA_SINK_IS_OPENED(u->sink_input->sink->thread_info.state)) - pa_memblockq_seek(u->memblockq, -offset, PA_SEEK_RELATIVE, TRUE); + pa_memblockq_seek(u->memblockq, -offset, PA_SEEK_RELATIVE, true); else - pa_memblockq_flush_write(u->memblockq, TRUE); + pa_memblockq_flush_write(u->memblockq, true); u->recv_counter -= offset; @@ -640,7 +649,18 @@ static void sink_input_kill_cb(pa_sink_input *i) { pa_assert_se(u = i->userdata); teardown(u); - pa_module_unload_request(u->module, TRUE); + pa_module_unload_request(u->module, true); +} + +/* Called from the output thread context */ +static void sink_input_state_change_cb(pa_sink_input *i, pa_sink_input_state_t state) { + struct userdata *u; + + pa_sink_input_assert_ref(i); + pa_assert_se(u = i->userdata); + + if (state == PA_SINK_INPUT_UNLINKED) + pa_asyncmsgq_flush(u->asyncmsgq, false); } /* Called from main thread */ @@ -667,21 +687,21 @@ static void sink_input_moving_cb(pa_sink_input *i, pa_sink *dest) { } /* Called from main thread */ -static pa_bool_t sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) { +static bool sink_input_may_move_to_cb(pa_sink_input *i, pa_sink *dest) { struct userdata *u; pa_sink_input_assert_ref(i); pa_assert_ctl_context(); pa_assert_se(u = i->userdata); - if (!u->source_output->source->monitor_of) - return TRUE; + if (!u->source_output || !u->source_output->source) + return true; return dest != u->source_output->source->monitor_of; } /* Called from main thread */ -static void sink_input_suspend_cb(pa_sink_input *i, pa_bool_t suspended) { +static void sink_input_suspend_cb(pa_sink_input *i, bool suspended) { struct userdata *u; pa_sink_input_assert_ref(i); @@ -698,10 +718,10 @@ int pa__init(pa_module *m) { struct userdata *u; pa_sink *sink = NULL; pa_sink_input_new_data sink_input_data; - pa_bool_t sink_dont_move; + bool sink_dont_move; pa_source *source = NULL; pa_source_output_new_data source_output_data; - pa_bool_t source_dont_move; + bool source_dont_move; uint32_t latency_msec; pa_sample_spec ss; pa_channel_map map; @@ -711,7 +731,7 @@ int pa__init(pa_module *m) { pa_memchunk silence; uint32_t adjust_time_sec; const char *n; - pa_bool_t remix = TRUE; + bool remix = true; pa_assert(m); @@ -803,7 +823,7 @@ int pa__init(pa_module *m) { sink_input_data.module = m; if (sink) - pa_sink_input_new_data_set_sink(&sink_input_data, sink, FALSE); + pa_sink_input_new_data_set_sink(&sink_input_data, sink, false); if (pa_modargs_get_proplist(ma, "sink_input_properties", sink_input_data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Failed to parse the sink_input_properties value."); @@ -830,7 +850,7 @@ int pa__init(pa_module *m) { if (!channels_set) sink_input_data.flags |= PA_SINK_INPUT_FIX_CHANNELS; - sink_dont_move = FALSE; + sink_dont_move = false; if (pa_modargs_get_value_boolean(ma, "sink_dont_move", &sink_dont_move) < 0) { pa_log("sink_dont_move= expects a boolean argument."); goto fail; @@ -854,6 +874,7 @@ int pa__init(pa_module *m) { u->sink_input->pop = sink_input_pop_cb; u->sink_input->process_rewind = sink_input_process_rewind_cb; u->sink_input->kill = sink_input_kill_cb; + u->sink_input->state_change = sink_input_state_change_cb; u->sink_input->attach = sink_input_attach_cb; u->sink_input->detach = sink_input_detach_cb; u->sink_input->update_max_rewind = sink_input_update_max_rewind_cb; @@ -869,7 +890,7 @@ int pa__init(pa_module *m) { source_output_data.driver = __FILE__; source_output_data.module = m; if (source) - pa_source_output_new_data_set_source(&source_output_data, source, FALSE); + pa_source_output_new_data_set_source(&source_output_data, source, false); if (pa_modargs_get_proplist(ma, "source_output_properties", source_output_data.proplist, PA_UPDATE_REPLACE) < 0) { pa_log("Failed to parse the source_output_properties value."); @@ -887,16 +908,7 @@ int pa__init(pa_module *m) { if (!remix) source_output_data.flags |= PA_SOURCE_OUTPUT_NO_REMIX; - if (!format_set) - source_output_data.flags |= PA_SOURCE_OUTPUT_FIX_FORMAT; - - if (!rate_set) - source_output_data.flags |= PA_SOURCE_OUTPUT_FIX_RATE; - - if (!channels_set) - source_output_data.flags |= PA_SOURCE_OUTPUT_FIX_CHANNELS; - - source_dont_move = FALSE; + source_dont_move = false; if (pa_modargs_get_value_boolean(ma, "source_dont_move", &source_dont_move) < 0) { pa_log("source_dont_move= expects a boolean argument."); goto fail; @@ -960,10 +972,10 @@ int pa__init(pa_module *m) { pa_source_output_put(u->source_output); if (pa_source_get_state(u->source_output->source) != PA_SOURCE_SUSPENDED) - pa_sink_input_cork(u->sink_input, FALSE); + pa_sink_input_cork(u->sink_input, false); if (pa_sink_get_state(u->sink_input->sink) != PA_SINK_SUSPENDED) - pa_source_output_cork(u->source_output, FALSE); + pa_source_output_cork(u->source_output, false); update_adjust_timer(u);