From f1cd41e46df3d317c1f7483c0f64333f4f993b80 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Wed, 28 Jun 2023 14:42:23 +0900 Subject: [PATCH] preprocess: Support source and source2 both preprocess will be available when a source that is connected to a source-output is tizen source. [Version] 15.0.46 [Issue Type] New feature Change-Id: I9111da7eb5960502aab7d5c3d4ce1d265c48584e Signed-off-by: Jaechul Lee --- packaging/pulseaudio-modules-tizen.spec | 2 +- src/preprocessor/module-tizenaudio-preprocessor.c | 144 ++++++++++++++++++++-- src/preprocessor/processor.c | 19 ++- src/preprocessor/processor_holder.c | 37 ++++-- 4 files changed, 178 insertions(+), 24 deletions(-) diff --git a/packaging/pulseaudio-modules-tizen.spec b/packaging/pulseaudio-modules-tizen.spec index 1d7a4df..ebc9709 100644 --- a/packaging/pulseaudio-modules-tizen.spec +++ b/packaging/pulseaudio-modules-tizen.spec @@ -2,7 +2,7 @@ Name: pulseaudio-modules-tizen Summary: Pulseaudio modules for Tizen -Version: 15.0.45 +Version: 15.0.46 Release: 0 Group: Multimedia/Audio License: LGPL-2.1+ diff --git a/src/preprocessor/module-tizenaudio-preprocessor.c b/src/preprocessor/module-tizenaudio-preprocessor.c index 37f93ff..19857b7 100644 --- a/src/preprocessor/module-tizenaudio-preprocessor.c +++ b/src/preprocessor/module-tizenaudio-preprocessor.c @@ -59,8 +59,12 @@ struct userdata { pa_hook_slot *source_output_fixate_slot; pa_hook_slot *source_output_put_slot; + pa_hook_slot *source_output_unlink_slot; pa_hook_slot *source_output_unlink_post_slot; + pa_hook_slot *source_output_move_start_slot; + pa_hook_slot *source_output_move_finish_slot; + pa_rtpoll *rtpoll; pa_thread *thread; pa_thread_mq thread_mq; @@ -86,6 +90,31 @@ static const char* const valid_modargs[] = { NULL, }; +static bool proplist_test_tizen_version2(pa_proplist *p) { + const char *tizen_version; + uint32_t version; + + pa_assert(p); + + if (!(tizen_version = pa_proplist_gets(p, "tizen.version"))) + return false; + + if (pa_atou(tizen_version, &version)) + return false; + + if (version < 2) + return false; + + return true; +} + +static void process_msg_main_thread(pa_msgobject *o, int code, void *userdata) { + pa_assert(o); + pa_assert(userdata); + + o->process_msg(o, code, userdata, 0UL, NULL); +} + static int proplist_get_fragment_size_usec(pa_proplist *p, pa_sample_spec *sample_spec, pa_usec_t *usec) { const char *prop_fragsize; uint32_t fragsize; @@ -252,7 +281,7 @@ static pa_processor_holder *build_processor_holder(pa_core *core, pa_source_outp char *processor_str = NULL; pa_processor_holder *holder; - pa_usec_t process_usec; + pa_usec_t process_usec = 10 * PA_USEC_PER_MSEC; pa_assert(core); pa_assert(data); @@ -266,11 +295,10 @@ static pa_processor_holder *build_processor_holder(pa_core *core, pa_source_outp processors_list = pa_proplist_gets(data->proplist, PA_PROP_MEDIA_PREPROCESSOR_METHOD); pa_assert(processors_list); - if (proplist_get_fragment_size_usec(data->source->proplist, &data->source->sample_spec, &process_usec) < 0) { - pa_processor_holder_free(holder); - pa_log_error("Failed to get source fragment usec. use default process usec"); - return NULL; - } + if (proplist_get_fragment_size_usec(data->source->proplist, &data->source->sample_spec, &process_usec) < 0) + pa_log_warn("Failed to get source fragment usec. use default process usec"); + + pa_log_info("request to build processors_list(%s)", processors_list); while ((processor_str = pa_split(processors_list, ",", &state))) { pa_processor *processor; @@ -357,7 +385,10 @@ static void destroy_source_output_preprocessor(pa_source_output *o) { pa_assert(o); holder = (pa_processor_holder *)o->thread_info.processor_holder; - pa_processor_holder_free(holder); + if (holder) { + pa_processor_holder_free(holder); + o->thread_info.processor_holder = NULL; + } o->preprocess = NULL; o->thread_info.processor_holder = NULL; @@ -376,6 +407,7 @@ static int preprocess(pa_source_output *o, pa_memchunk *chunk, pa_memchunk *ochu /* chunk must contain resampled sound pcm */ pa_processor_holder_push_data(holder, chunk); + ret = pa_processor_holder_pump(holder); if (ret != PROCESSOR_OK) { if (ret != -PROCESSOR_ERR_BUFFERING) @@ -564,15 +596,59 @@ static pa_hook_result_t source_output_put_cb(pa_core *c, pa_source_output *o, vo return PA_HOOK_OK; holder = (pa_processor_holder *)o->thread_info.processor_holder; + if (!holder) { + pa_log_error("Failed to get processor holder"); + return PA_HOOK_OK; + } - pa_assert(holder); - pa_assert(pa_processor_holder_get_current_source(holder)); /* source must be set at ADD_SOURCE_OUTPUT */ + if (!proplist_test_tizen_version2(o->source->proplist)) { + pa_msgobject *msgobject = PA_MSGOBJECT(u->preprocessor); + pa_assert(msgobject); + + process_msg_main_thread(msgobject, PA_SOURCE_MESSAGE_PREPROCESSOR_ADD_OUTPUT, o); + + connect_to_reference_sink(holder, PA_MSGOBJECT(u->preprocessor), u->asyncmsgq_sink, true); + + return PA_HOOK_OK; + } connect_to_reference_sink(holder, PA_MSGOBJECT(u->preprocessor), u->asyncmsgq_sink, true); return PA_HOOK_OK; } +static pa_hook_result_t source_output_unlink_cb(pa_core *c, pa_source_output *o, void *userdata) { + struct userdata *u = (struct userdata *)userdata; + pa_processor_holder *holder; + + pa_assert(c); + pa_assert(o); + pa_assert(u); + + if (!is_preprocessor_marked(o->flags)) + return PA_HOOK_OK; + + holder = (pa_processor_holder *)o->thread_info.processor_holder; + if (!holder) { + pa_log_error("Failed to get processor holder"); + return PA_HOOK_OK; + } + + /* in case of normal source(not tizen2) + * This should be destroy in unlink process + * because o->source wouldn't exist in the unlink_post step. */ + if (!proplist_test_tizen_version2(o->source->proplist)) { + pa_msgobject *msgobject = PA_MSGOBJECT(u->preprocessor); + pa_assert(msgobject); + + process_msg_main_thread(msgobject, PA_SOURCE_MESSAGE_PREPROCESSOR_DESTROY, o); + + connect_to_reference_sink(holder, NULL, NULL, false); + } + + return PA_HOOK_OK; +} + /* This function will be also called when source unlink */ static pa_hook_result_t source_output_unlink_post_cb(pa_core *c, pa_source_output *o, void *userdata) { struct userdata *u = (struct userdata *)userdata; @@ -586,6 +662,10 @@ static pa_hook_result_t source_output_unlink_post_cb(pa_core *c, pa_source_outpu return PA_HOOK_OK; holder = (pa_processor_holder *)o->thread_info.processor_holder; + if (!holder) { + pa_log_info("holder doesn't exist. source-output might not be connected to tizen2 source"); + return PA_HOOK_OK; + } connect_to_reference_sink(holder, NULL, NULL, false); @@ -595,6 +675,40 @@ static pa_hook_result_t source_output_unlink_post_cb(pa_core *c, pa_source_outpu return PA_HOOK_OK; } +static pa_hook_result_t source_output_move_start_cb(pa_core *c, pa_source_output *o, void *userdata) { + struct userdata *u = (struct userdata *)userdata; + + pa_assert(c); + pa_assert(o); + pa_assert(u); + + if (!proplist_test_tizen_version2(o->source->proplist)) { + pa_msgobject *msgobject = PA_MSGOBJECT(u->preprocessor); + pa_assert(msgobject); + + process_msg_main_thread(msgobject, PA_SOURCE_MESSAGE_PREPROCESSOR_REMOVE_OUTPUT, o); + } + + return PA_HOOK_OK; +} + +static pa_hook_result_t source_output_move_finish_cb(pa_core *c, pa_source_output *o, void *userdata) { + struct userdata *u = (struct userdata *)userdata; + + pa_assert(c); + pa_assert(o); + pa_assert(u); + + if (!proplist_test_tizen_version2(o->source->proplist)) { + pa_msgobject *msgobject = PA_MSGOBJECT(u->preprocessor); + pa_assert(msgobject); + + process_msg_main_thread(msgobject, PA_SOURCE_MESSAGE_PREPROCESSOR_ADD_OUTPUT, o); + } + + return PA_HOOK_OK; +} + static void thread_func(void *userdata) { struct userdata *u = (struct userdata *)userdata; @@ -658,6 +772,10 @@ int pa__init(pa_module *m) { goto fail; } + u->source_output_unlink_slot = + pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK], + PA_HOOK_EARLY, (pa_hook_cb_t) source_output_unlink_cb, u); + u->source_output_unlink_post_slot = pa_hook_connect(&u->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_UNLINK_POST], PA_HOOK_EARLY, (pa_hook_cb_t) source_output_unlink_post_cb, u); @@ -672,6 +790,14 @@ int pa__init(pa_module *m) { pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_PUT], PA_HOOK_LATE, (pa_hook_cb_t) source_output_put_cb, u); + u->source_output_move_start_slot = + pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_START], + PA_HOOK_LATE, (pa_hook_cb_t) source_output_move_start_cb, u); + + u->source_output_move_finish_slot = + pa_hook_connect(&m->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_MOVE_FINISH], + PA_HOOK_LATE, (pa_hook_cb_t) source_output_move_finish_cb, u); + /* TODO : need to check sink configuration change */ pa_modargs_free(ma); diff --git a/src/preprocessor/processor.c b/src/preprocessor/processor.c index e0ff03e..c4e97fa 100644 --- a/src/preprocessor/processor.c +++ b/src/preprocessor/processor.c @@ -158,6 +158,7 @@ pa_processor *pa_processor_new(pa_core *core, processor->audio_effect = audio_effect_create(audio_effect_method, ss->rate, ss->channels, format, processor->process_frames); + if (!processor->audio_effect) { pa_log_error("Failed to create audio effect. audio_effect_method(%d), " "rate(%d), ch(%d), format(%d), frames(%zu)", @@ -167,13 +168,15 @@ pa_processor *pa_processor_new(pa_core *core, } process_framesize = audio_effect_get_process_framesize(processor->audio_effect); - if (process_framesize > 0) { processor->process_frames = process_framesize; processor->process_usec = pa_processor_frame_to_usec(processor->process_frames, ss); processor->process_bytes = pa_usec_to_bytes(processor->process_usec, ss); - pa_log_info("Changed process_frame. constraint process_frame(%zu)", processor->process_frames); + pa_log_info("Changed process_frame. constraint process_frame(%zu), usec(%" PRIu64 "ms), bytes(%zu)", + processor->process_frames, + processor->process_usec / PA_USEC_PER_MSEC, + processor->process_bytes); } pa_silence_memchunk_get(&core->silence_cache, core->mempool, &silence, &processor->ss, 0); @@ -249,8 +252,8 @@ int pa_processor_process(pa_processor *processor, pa_memchunk *chunk) { ochunk.length = chunk->length; ochunk.memblock = pa_memblock_new(processor->core->mempool, ochunk.length); - recording = pa_memblock_acquire_chunk(chunk); - output = pa_memblock_acquire_chunk(&ochunk); + recording = (uint8_t *)pa_memblock_acquire_chunk(chunk); + output = (uint8_t *)pa_memblock_acquire_chunk(&ochunk); debug_timestamp_begin(processor); @@ -274,7 +277,6 @@ int pa_processor_process(pa_processor *processor, pa_memchunk *chunk) { } else { char *reference_dump = pa_processor_reference_dump_index(processor->reference); - // need to add chunk->index pa_log_debug("Post-process(%s). rec(%" PRIu64 "ms), ref(%" PRIu64 "ms), out(%" PRIu64 "ms), " \ "reference memblockq %s, silence %d", pa_processor_method_str(processor->method), @@ -321,7 +323,12 @@ pa_memblockq *pa_processor_get_result_memblockq(pa_processor *processor) { } const char *pa_processor_method_str(pa_processor_method_t method) { - static const char *method_table[] = { "speex", "webrtc", "reference_copy", "rnnoise", "none-pse" }; + static const char *method_table[] = { + [PROCESSOR_METHOD_SPEEX] = "speex", + [PROCESSOR_METHOD_WEBRTC] = "webrtc", + [PROCESSOR_METHOD_REFERENCE_COPY] = "reference_copy", + [PROCESSOR_METHOD_RNNOISE] = "rnnoise", + [PROCESSOR_METHOD_NONE_PSE] = "none-pse" }; if (method >= PROCESSOR_METHOD_MAX) return NULL; diff --git a/src/preprocessor/processor_holder.c b/src/preprocessor/processor_holder.c index 046c81f..6f3855e 100644 --- a/src/preprocessor/processor_holder.c +++ b/src/preprocessor/processor_holder.c @@ -95,10 +95,17 @@ int pa_processor_holder_connect_reference(pa_processor_holder *holder, pa_proces } int pa_processor_holder_push_data(pa_processor_holder *holder, pa_memchunk *chunk) { + int ret; + pa_assert(holder); pa_assert(chunk); - return pa_memblockq_push(holder->input, chunk); + ret = pa_memblockq_push(holder->input, chunk); + + pa_log_debug("push data to the input queue. chunk length(%zu), memblockq length(%zu)", + chunk->length, pa_memblockq_get_length(holder->input)); + + return ret; } int pa_processor_holder_push_reference_data(pa_processor_holder *holder, pa_memchunk *chunk) { @@ -111,16 +118,22 @@ int pa_processor_holder_push_reference_data(pa_processor_holder *holder, pa_memc int pa_processor_holder_pull_data(pa_processor_holder *holder, pa_memchunk *chunk) { int r; + size_t length; pa_assert(holder); pa_assert(chunk); - if ((r = pa_memblockq_peek(holder->output, chunk)) < 0) + length = pa_memblockq_get_length(holder->output); + + if ((r = pa_memblockq_peek_fixed_size(holder->output, length, chunk)) < 0) pa_log_error("Failed to get memblock from output memblockq"); /* chunk ref count must be one after dropping */ pa_memblockq_drop(holder->output, chunk->length); + pa_log_debug("pull from the output queue. chunk length(%zu), memblockq_length(%zu)", + chunk->length, pa_memblockq_get_length(holder->output)); + return r; } @@ -142,8 +155,11 @@ int pa_processor_holder_pump(pa_processor_holder *holder) { process_size = pa_processor_get_process_bytes(p); length = pa_memblockq_get_length(pull_queue); - if (length < process_size) + if (length < process_size) { + pa_log_info("processor(%s) needs process_size(%zu) but there are bytes(%zu) in the queue", + pa_processor_method_str(p->method), process_size, length); return -PROCESSOR_ERR_BUFFERING; + } while (length >= process_size) { ret = pa_memblockq_peek_fixed_size(pull_queue, process_size, &chunk); @@ -152,6 +168,7 @@ int pa_processor_holder_pump(pa_processor_holder *holder) { if ((ret = pa_processor_process(p, &chunk)) < 0) { pa_memblock_unref(chunk.memblock); pa_memblockq_drop(pull_queue, chunk.length); + pa_log_error("Failed to process"); return ret; } @@ -165,11 +182,15 @@ int pa_processor_holder_pump(pa_processor_holder *holder) { } length = pa_memblockq_get_length(pull_queue); - if (length > 0) { - pa_memblockq_peek_fixed_size(pull_queue, length, &chunk); - pa_memblockq_push(holder->output, &chunk); - pa_memblock_unref(chunk.memblock); - pa_memblockq_drop(pull_queue, chunk.length); + + while (length > 0) { + pa_memchunk tchunk; + + pa_memblockq_peek(pull_queue, &tchunk); + pa_memblockq_push(holder->output, &tchunk); + pa_memblock_unref(tchunk.memblock); + pa_memblockq_drop(pull_queue, tchunk.length); + length = pa_memblockq_get_length(pull_queue); } return 0; -- 2.7.4