preprocess: Support source and source2 both 76/294876/2
authorJaechul Lee <jcsing.lee@samsung.com>
Wed, 28 Jun 2023 05:42:23 +0000 (14:42 +0900)
committerJaechul Lee <jcsing.lee@samsung.com>
Wed, 28 Jun 2023 05:44:40 +0000 (14:44 +0900)
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 <jcsing.lee@samsung.com>
packaging/pulseaudio-modules-tizen.spec
src/preprocessor/module-tizenaudio-preprocessor.c
src/preprocessor/processor.c
src/preprocessor/processor_holder.c

index 1d7a4df..ebc9709 100644 (file)
@@ -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+
index 37f93ff..19857b7 100644 (file)
@@ -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);
 
index e0ff03e..c4e97fa 100644 (file)
@@ -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;
index 046c81f..6f3855e 100644 (file)
@@ -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;