stream-manager: handle ramp finished task at core mainloop 32/255532/6 accepted/tizen/unified/20210321.225639 submit/tizen/20210319.091643
authorSeungbae Shin <seungbae.shin@samsung.com>
Fri, 19 Mar 2021 05:34:21 +0000 (14:34 +0900)
committerSeungbae Shin <seungbae.shin@samsung.com>
Fri, 19 Mar 2021 07:32:36 +0000 (16:32 +0900)
Sometimes sd handle is accessed simultaneously, which may leads to memory corruption.

[Version] 13.0.55
[Issue Type] Bug fix

Change-Id: I214c58c1ccde292c918033aaded695f6b59324ef

packaging/pulseaudio-modules-tizen.spec
src/stream-manager-priv.h
src/stream-manager.c

index 6478812264d0d28fee978071d9b772d9d33e450b..51228a848f603dfbd55a8834615c02cde043c2c7 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          13.0.54
+Version:          13.0.55
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index 677defff7a0c41942c1ab73098002692d3c2e61c..e3d9298b82e527b0ade2895f3fac1f7f222d0608 100644 (file)
@@ -233,6 +233,10 @@ typedef struct _filter_info {
     uint32_t n_controls;
 } filter_info;
 
+typedef struct _stream_manager_msg {
+    pa_msgobject parent;
+} stream_manager_msg;
+
 struct _stream_manager {
     PA_REFCNT_DECLARE;
 
@@ -255,6 +259,10 @@ struct _stream_manager {
     pa_time_event *time_event_for_unmute;
     pa_hashmap *filter_infos;
 
+    pa_thread_mq thread_mq;
+    pa_rtpoll *rtpoll;
+    stream_manager_msg *msg;
+
     pa_hook_slot
         *sink_input_new_slot,
         *sink_input_put_slot,
index 8232c1ac3a738266b8121fef78a51bc0ae8039cf..9a6928900571300ef8c7105b4bedfaf9e49c5217 100644 (file)
@@ -129,6 +129,17 @@ static const char* notify_command_type_str[] = {
 #define STREAM_MAP_STREAM_AVAIL_OUT_DEVICES "avail-out-devices"
 #define STREAM_MAP_STREAM_AVAIL_FRAMEWORKS "avail-frameworks"
 
+PA_DEFINE_PRIVATE_CLASS(stream_manager_msg, pa_msgobject);
+
+enum {
+    MESSAGE_RAMP_FINISHED,
+};
+
+struct stream_manager_param {
+    pa_stream_manager *m;
+    pa_sink_input *i;
+};
+
 static bool is_valid_notify_command(notify_command_type_t command) {
     return (command < sizeof(notify_command_type_str) / sizeof(char *));
 }
@@ -2566,7 +2577,7 @@ static pa_hook_result_t sink_input_state_changed_cb(pa_core *core, pa_sink_input
     pa_assert(i);
     pa_assert(m);
 
-    pa_log_debug("sink-input(%p, index:%u), state(%d)", i, i->index, i->state);
+    pa_log_debug("sink-input(%p, index:%u, state:%d)", i, i->index, i->state);
 
     switch (i->state) {
     case PA_SINK_INPUT_CORKED:
@@ -2615,8 +2626,7 @@ static pa_hook_result_t sink_input_move_finish_cb(pa_core *core, pa_sink_input *
 }
 
 static pa_hook_result_t sink_input_ramp_finish_cb(pa_core *core, pa_sink_input *i, pa_stream_manager *m) {
-    stream_ducking *sd;
-    void *state;
+    struct stream_manager_param param = { m, i };
 
     pa_core_assert_ref(core);
     pa_sink_input_assert_ref(i);
@@ -2625,44 +2635,9 @@ static pa_hook_result_t sink_input_ramp_finish_cb(pa_core *core, pa_sink_input *
     if (core->state == PA_CORE_SHUTDOWN)
         return PA_HOOK_OK;
 
-    pa_log_debug("sink-input(%p, index:%u)", i, i->index);
-
-    /* Find a context id from all the ducked stream list by this stream index.
-     * Check the number of managed streams of the context id, if it is the last one
-     * then broadcast a signal with context id.*/
-    PA_HASHMAP_FOREACH(sd, m->stream_duckings, state) {
-        if (!pa_idxset_get_by_data(sd->idx_ducking_streams, i, NULL)) {
-            pa_log_debug("not found matched stream(%p, index:%u) in sd(%p)", i, i->index, sd);
-            continue;
-        }
-
-        pa_log_info("found matched stream(%p, index:%u) in sd(%p, ducking_stream_count:%d, state:%u)",
-            i, i->index, sd, sd->ducking_stream_count, sd->state);
-
-        if (sd->ducking_stream_count <= 0)
-            continue;
-
-        /* Remove trigger when unducked */
-        if (sd->state == STREAM_DUCKING_STATE_UNDUCKING)
-            pa_idxset_remove_by_data(sd->idx_ducking_streams, (void *)i, NULL);
-
-        /* Send signal when all streams are ducked.
-        * Note that the condition of increasing count value below is located in
-        * handle_activate_ducking() of DBus handler. */
-        if (--sd->ducking_stream_count == 0) {
-            if (sd->state == STREAM_DUCKING_STATE_DUCKING) {
-                sd->state = STREAM_DUCKING_STATE_DUCKED;
-            } else if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) {
-                sd->state = STREAM_DUCKING_STATE_UNDUCKED;
-            } else {
-                pa_log_warn("sd->state(%d), already ducked or unducked, skip sending signal", sd->state);
-                continue;
-            }
-
-            pa_log_info("send signal for ramp finished - sd(%p, state:%u)", sd, sd->state);
-            send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd));
-        }
-    }
+    pa_log_info("sink-input(%p, index:%u)", i, i->index);
+    pa_asyncmsgq_send(m->thread_mq.outq, PA_MSGOBJECT(m->msg), MESSAGE_RAMP_FINISHED, &param, 0, NULL);
+    pa_log_info("sink-input(%p, index:%u) : pa_asyncmsgq_send() done", i, i->index);
 
     return PA_HOOK_OK;
 }
@@ -3765,6 +3740,70 @@ const char* pa_stream_manager_get_volume_type(pa_stream_manager *m, stream_type_
     return s->volume_types[stream_type == STREAM_SINK_INPUT ? STREAM_DIRECTION_OUT : STREAM_DIRECTION_IN];
 }
 
+static int stream_manager_process_msg(pa_msgobject *o, int code, void *data, int64_t offset, pa_memchunk *chunk) {
+    struct stream_manager_param* param = (struct stream_manager_param*)data;
+    pa_stream_manager *m;
+    pa_sink_input *i;
+    stream_ducking *sd;
+    void *state;
+
+    pa_assert(param);
+
+    m = param->m;
+    i = param->i;
+
+    pa_log_info("code(%d), sink-input(%p, index:%u, state:%d)", code, i, i->index, i->state);
+
+    if (param->m->core->state == PA_CORE_SHUTDOWN)
+        return 0;
+
+    switch (code) {
+        case MESSAGE_RAMP_FINISHED:
+            /* Find a context id from all the ducked stream list by this stream index.
+             * Check the number of managed streams of the context id, if it is the last one
+             * then broadcast a signal with context id.*/
+            PA_HASHMAP_FOREACH(sd, m->stream_duckings, state) {
+                if (!pa_idxset_get_by_data(sd->idx_ducking_streams, i, NULL)) {
+                    pa_log_debug("not found matched stream(%p, index:%u) in sd(%p)", i, i->index, sd);
+                    continue;
+                }
+
+                pa_log_info("found matched stream(%p, index:%u) in sd(%p, ducking_stream_count:%d, state:%u)",
+                    i, i->index, sd, sd->ducking_stream_count, sd->state);
+
+                if (sd->ducking_stream_count <= 0)
+                    continue;
+
+                /* Remove trigger when unducked */
+                if (sd->state == STREAM_DUCKING_STATE_UNDUCKING)
+                    pa_idxset_remove_by_data(sd->idx_ducking_streams, (void *)i, NULL);
+
+                /* Send signal when all streams are ducked.
+                 * Note that the condition of increasing count value below is located in
+                 * handle_activate_ducking() of DBus handler. */
+                if (--sd->ducking_stream_count == 0) {
+                    if (sd->state == STREAM_DUCKING_STATE_DUCKING) {
+                        sd->state = STREAM_DUCKING_STATE_DUCKED;
+                    } else if (sd->state == STREAM_DUCKING_STATE_UNDUCKING) {
+                        sd->state = STREAM_DUCKING_STATE_UNDUCKED;
+                    } else {
+                        pa_log_warn("sd->state(%d), already ducked or unducked, skip sending signal", sd->state);
+                        continue;
+                    }
+
+                    pa_log_info("send signal for ramp finished - sd(%p, state:%u)", sd, sd->state);
+                    send_ducking_state_changed_signal(pa_dbus_connection_get(m->dbus_conn), sd->trigger_index, is_stream_ducked(sd));
+                }
+            }
+            break;
+
+        default:
+            pa_assert_not_reached();
+    }
+
+    return 0;
+}
+
 pa_stream_manager* pa_stream_manager_get(pa_core *c) {
     pa_stream_manager *m;
 
@@ -3779,6 +3818,14 @@ pa_stream_manager* pa_stream_manager_get(pa_core *c) {
     PA_REFCNT_INIT(m);
     m->core = c;
 
+    m->rtpoll = pa_rtpoll_new();
+    if (pa_thread_mq_init(&m->thread_mq, m->core->mainloop, m->rtpoll) < 0) {
+        pa_log("pa_thread_mq_init() failed.");
+        goto fail;
+    }
+    m->msg = pa_msgobject_new(stream_manager_msg);
+    m->msg->parent.process_msg = stream_manager_process_msg;
+
     if (!(m->hal = pa_hal_interface_get(c)))
         goto fail;
 
@@ -3921,6 +3968,10 @@ void pa_stream_manager_unref(pa_stream_manager *m) {
     if (PA_REFCNT_DEC(m) > 0)
         return;
 
+    pa_thread_mq_done(&m->thread_mq);
+    pa_rtpoll_free(m->rtpoll);
+    pa_xfree(m->msg);
+
     free_hook_slots(m);
 
     if (m->comm.comm)