[0.6.82] handle the gst msg in seperate thread 78/162378/5 accepted/tizen/4.0/unified/20171204.071041 submit/tizen_4.0/20171201.065254
authorEunhae Choi <eunhae1.choi@samsung.com>
Thu, 30 Nov 2017 13:52:33 +0000 (22:52 +0900)
committerEunhae Choi <eunhae1.choi@samsung.com>
Fri, 1 Dec 2017 06:21:10 +0000 (15:21 +0900)
- remove bus watch
- add new thread for handling bus msg

Change-Id: Idaf161fe8fe442a8b8f001ec93ca654fb9ba3f10

packaging/libmm-player.spec
src/include/mm_player_priv.h
src/include/mm_player_utils.h
src/mm_player.c
src/mm_player_priv.c

index 0d8cc64..b101953 100644 (file)
@@ -1,6 +1,6 @@
 Name:       libmm-player
 Summary:    Multimedia Framework Player Library
-Version:    0.6.81
+Version:    0.6.82
 Release:    0
 Group:      Multimedia/Libraries
 License:    Apache-2.0
index 78fd9f6..dbec7f9 100644 (file)
@@ -402,11 +402,6 @@ typedef struct {
 } MMPlayerSetMode;
 
 typedef struct {
-       GMainContext *global_default;
-       GMainContext *thread_default;
-} MMPlayerGMainContext;
-
-typedef struct {
        gint uri_idx;
        GList *uri_list;
 } MMPlayerUriList;
@@ -506,6 +501,12 @@ typedef struct {
        MMPlayerVideoColorspace video_cs;
        MMVideoBuffer captured;
 
+       /* gst bus msg thread, create during realize */
+       GThread* bus_msg_thread;
+       gboolean bus_msg_thread_exit;
+       GCond bus_msg_thread_cond;
+       GMutex bus_msg_thread_mutex;
+
        /* fakesink handling lock */
        GMutex fsink_lock;
 
@@ -665,8 +666,7 @@ typedef struct {
 
        /* signal notifiers */
        GList* signals[MM_PLAYER_SIGNAL_TYPE_MAX];
-       guint bus_watcher;
-       MMPlayerGMainContext context;
+       GMainContext *global_default;
        MMPlayerUriList uri_info;
 
        gboolean is_sound_extraction;
@@ -865,6 +865,8 @@ int __mmplayer_set_state(mm_player_t* player, int state);
 int __mmplayer_check_state(mm_player_t* player, enum PlayerCommandState command);
 gboolean __mmplayer_dump_pipeline_state(mm_player_t* player);
 void __mmplayer_remove_g_source_from_context(GMainContext *context, guint source_id);
+void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer);
+
 /* util */
 const gchar * __get_state_name(int state);
 gboolean __mmplayer_can_do_interrupt(mm_player_t *player);
index 6890e58..0ff257a 100644 (file)
@@ -84,6 +84,13 @@ do { \
 #define MMPLAYER_REPEAT_THREAD_WAIT(x_player)                g_cond_wait(&((mm_player_t *)x_player)->repeat_thread_cond, &((mm_player_t *)x_player)->repeat_thread_mutex)
 #define MMPLAYER_REPEAT_THREAD_SIGNAL(x_player)              g_cond_signal(&((mm_player_t *)x_player)->repeat_thread_cond);
 
+/* gst bus msg thread */
+#define MMPLAYER_BUS_MSG_THREAD_LOCK(x_player)                   g_mutex_lock(&((mm_player_t *)x_player)->bus_msg_thread_mutex)
+#define MMPLAYER_BUS_MSG_THREAD_UNLOCK(x_player)                 g_mutex_unlock(&((mm_player_t *)x_player)->bus_msg_thread_mutex)
+#define MMPLAYER_BUS_MSG_THREAD_WAIT(x_player)                   g_cond_wait(&((mm_player_t *)x_player)->bus_msg_thread_cond, &((mm_player_t *)x_player)->bus_msg_thread_mutex)
+#define MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(x_player, end_time)   g_cond_wait_until(&((mm_player_t *)x_player)->bus_msg_thread_cond, &((mm_player_t *)x_player)->bus_msg_thread_mutex, end_time)
+#define MMPLAYER_BUS_MSG_THREAD_SIGNAL(x_player)                 g_cond_signal(&((mm_player_t *)x_player)->bus_msg_thread_cond);
+
 /* handling fakesink */
 #define MMPLAYER_FSINK_LOCK(x_player)                        g_mutex_lock(&((mm_player_t *)x_player)->fsink_lock)
 #define MMPLAYER_FSINK_UNLOCK(x_player)                      g_mutex_unlock(&((mm_player_t *)x_player)->fsink_lock)
index 5fce28b..13f8684 100644 (file)
@@ -104,17 +104,16 @@ int  mm_player_destroy(MMHandleType player)
 
        MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
 
+       /* destroy the gst bus msg thread if it is remained.
+          this funct have to be called before getting cmd lock. */
+       _mmplayer_bus_msg_thread_destroy(player);
+
        MMPLAYER_CMD_LOCK(player);
 
        result = _mmplayer_destroy(player);
 
        MMPLAYER_CMD_UNLOCK(player);
 
-       /* to make sure unlocked.
-          @see __mmplayer_gst_callback, GST_MESSAGE_BUFFERING handling */
-       MMPLAYER_CMD_LOCK(player);
-       MMPLAYER_CMD_UNLOCK(player);
-
        g_mutex_clear(&((mm_player_t*)player)->cmd_lock);
        g_mutex_clear(&((mm_player_t*)player)->playback_lock);
 
index 677c1b9..1d292b4 100644 (file)
@@ -151,7 +151,7 @@ static void         __mmplayer_release_misc(mm_player_t* player);
 static void            __mmplayer_release_misc_post(mm_player_t* player);
 static gboolean        __mmplayer_init_gstreamer(mm_player_t* player);
 static GstBusSyncReply __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data);
-static gboolean __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data);
+static void __mmplayer_gst_callback(GstMessage *msg, gpointer data);
 static gboolean        __mmplayer_gst_extract_tag_from_msg(mm_player_t* player, GstMessage *msg);
 static gboolean      __mmplayer_gst_handle_duration(mm_player_t* player, GstMessage* msg);
 static gboolean __mmplayer_gst_remove_fakesink(mm_player_t* player, MMPlayerGstElement* fakesink);
@@ -1081,15 +1081,83 @@ __mmplayer_adaptive_var_info(const VariantData *self, gpointer user_data)
        return var_info;
 }
 
-static gboolean
-__mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data)
+void _mmplayer_bus_msg_thread_destroy(MMHandleType hplayer)
 {
-       mm_player_t* player = (mm_player_t*) data;
-       gboolean ret = TRUE;
+       mm_player_t* player = (mm_player_t*)hplayer;
+
+       MMPLAYER_FENTER();
+       MMPLAYER_RETURN_IF_FAIL(player);
+
+       /* destroy the gst bus msg thread */
+       if (player->bus_msg_thread) {
+               MMPLAYER_BUS_MSG_THREAD_LOCK(player);
+               player->bus_msg_thread_exit = TRUE;
+               MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
+               MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
+
+               LOGD("gst bus msg thread exit.");
+               g_thread_join(player->bus_msg_thread); /* can request cmd lock */
+               player->bus_msg_thread = NULL;
+
+               g_mutex_clear(&player->bus_msg_thread_mutex);
+               g_cond_clear(&player->bus_msg_thread_cond);
+       }
+
+       MMPLAYER_FLEAVE();
+}
+
+static gpointer __mmplayer_gst_bus_msg_thread(gpointer data)
+{
+       mm_player_t *player = (mm_player_t*)(data);
+       GstMessage *msg = NULL;
+       GstBus *bus = NULL;
+
+       MMPLAYER_FENTER();
+       MMPLAYER_RETURN_VAL_IF_FAIL(player &&
+                                               player->pipeline &&
+                                               player->pipeline->mainbin &&
+                                               player->pipeline->mainbin[MMPLAYER_M_PIPE].gst,
+                                               NULL);
+
+       bus = gst_pipeline_get_bus(GST_PIPELINE(player->pipeline->mainbin[MMPLAYER_M_PIPE].gst));
+       if (!bus) {
+               LOGE("cannot get BUS from the pipeline");
+               return NULL;
+       }
+
+       MMPLAYER_BUS_MSG_THREAD_LOCK(player);
+
+       LOGD("gst bus msg thread will be started.");
+       while (!player->bus_msg_thread_exit) {
+               msg = gst_bus_pop(bus);
+               if (msg == NULL) {
+                       /* set the max timeout as 500 ms */
+                       MMPLAYER_BUS_MSG_THREAD_WAIT_UNTIL(player, (g_get_monotonic_time() + 500 * G_TIME_SPAN_MILLISECOND));
+                       continue;
+               }
+
+               MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
+               /* handle the gst msg */
+               __mmplayer_gst_callback(msg, player);
+               MMPLAYER_BUS_MSG_THREAD_LOCK(player);
+               gst_message_unref(msg);
+       }
+
+       MMPLAYER_BUS_MSG_THREAD_UNLOCK(player);
+       gst_object_unref(GST_OBJECT(bus));
+
+       MMPLAYER_FLEAVE();
+       return NULL;
+}
+
+static void
+__mmplayer_gst_callback(GstMessage *msg, gpointer data)
+{
+       mm_player_t* player = (mm_player_t*)(data);
        static gboolean async_done = FALSE;
 
-       MMPLAYER_RETURN_VAL_IF_FAIL(player, FALSE);
-       MMPLAYER_RETURN_VAL_IF_FAIL(msg && GST_IS_MESSAGE(msg), FALSE);
+       MMPLAYER_RETURN_IF_FAIL(player);
+       MMPLAYER_RETURN_IF_FAIL(msg && GST_IS_MESSAGE(msg));
 
        switch (GST_MESSAGE_TYPE(msg)) {
        case GST_MESSAGE_UNKNOWN:
@@ -1269,6 +1337,7 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data)
 
                        if (player->pd_mode == MM_PLAYER_PD_MODE_URI) {
                                if (!MMPLAYER_CMD_TRYLOCK(player)) {
+                                       /* skip the playback control by buffering msg while user request is handled. */
                                        gint per = 0;
 
                                        LOGW("[PD mode] can't get cmd lock, only post buffering msg");
@@ -1282,11 +1351,6 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data)
                                }
                        } else {
                                MMPLAYER_CMD_LOCK(player);
-                               if (!player->pipeline) { /* during destroy, msg can be delivered. */
-                                       LOGE("pipeline is destroyed.");
-                                       MMPLAYER_CMD_UNLOCK(player);
-                                       break;
-                               }
                        }
 
                        /* ignore the prev buffering message */
@@ -1449,6 +1513,13 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data)
                                                if (MMPLAYER_IS_STREAMING(player) && (player->streamer))
                                                        __mm_player_streaming_set_content_bitrate(player->streamer,
                                                                player->total_maximum_bitrate, player->total_bitrate);
+
+                                               if (player->pending_seek.is_pending) {
+                                                       LOGW("trying to do pending seek");
+                                                       MMPLAYER_CMD_LOCK(player);
+                                                       __gst_pending_seek(player);
+                                                       MMPLAYER_CMD_UNLOCK(player);
+                                               }
                                        }
                                }
                                break;
@@ -1533,7 +1604,6 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data)
                                attrs = MMPLAYER_GET_ATTRS(player);
                                if (!attrs) {
                                        LOGE("cannot get content attribute");
-                                       ret = FALSE;
                                        break;
                                }
 
@@ -1683,8 +1753,7 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data)
        case GST_MESSAGE_DURATION_CHANGED:
                {
                        LOGD("GST_MESSAGE_DURATION_CHANGED\n");
-                       ret = __mmplayer_gst_handle_duration(player, msg);
-                       if (!ret)
+                       if (!__mmplayer_gst_handle_duration(player, msg))
                                LOGW("failed to update duration");
                }
 
@@ -1759,12 +1828,8 @@ __mmplayer_gst_callback(GstBus *bus, GstMessage *msg, gpointer data)
                break;
        }
 
-       /* FIXIT : this cause so many warnings/errors from glib/gstreamer. we should not call it since
-        * gst_element_post_message api takes ownership of the message.
-        */
-       //gst_message_unref(msg);
-
-       return ret;
+       /* should not call 'gst_message_unref(msg)' */
+       return;
 }
 
 static gboolean
@@ -5932,7 +5997,7 @@ __mmplayer_bus_sync_callback(GstBus * bus, GstMessage * message, gpointer data)
        case GST_MESSAGE_STATE_CHANGED:
                /* post directly for fast launch */
                if (player->sync_handler) {
-                       __mmplayer_gst_callback(NULL, message, player);
+                       __mmplayer_gst_callback(message, player);
                        reply = GST_BUS_DROP;
                } else
                        reply = GST_BUS_PASS;
@@ -6690,6 +6755,12 @@ __mmplayer_gst_create_pipeline(mm_player_t* player)
                        __mmplayer_try_to_plug_decodebin(player, gst_element_get_static_pad(mainbin[MMPLAYER_M_S_BUFFER].gst, "src"), player->s_stream_caps);
        }
 
+       /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
+       if (__mmplayer_check_subtitle(player)) {
+               if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
+                       LOGE("fail to create text pipeline");
+       }
+
        /* connect bus callback */
        bus = gst_pipeline_get_bus(GST_PIPELINE(mainbin[MMPLAYER_M_PIPE].gst));
        if (!bus) {
@@ -6697,22 +6768,6 @@ __mmplayer_gst_create_pipeline(mm_player_t* player)
                goto INIT_ERROR;
        }
 
-       player->bus_watcher = gst_bus_add_watch(bus, (GstBusFunc)__mmplayer_gst_callback, player);
-
-       player->context.thread_default = g_main_context_get_thread_default();
-
-       if (NULL == player->context.thread_default) {
-               player->context.thread_default = g_main_context_default();
-               LOGD("thread-default context is the global default context");
-       }
-       LOGW("bus watcher thread context = %p, watcher : %d", player->context.thread_default, player->bus_watcher);
-
-       /* Note : check whether subtitle atrribute uri is set. If uri is set, then try to play subtitle file */
-       if (__mmplayer_check_subtitle(player)) {
-               if (MM_ERROR_NONE != __mmplayer_gst_create_text_pipeline(player))
-                       LOGE("fail to create text pipeline");
-       }
-
        /* set sync handler to get tag synchronously */
        gst_bus_set_sync_handler(bus, __mmplayer_bus_sync_callback, player, NULL);
 
@@ -6720,12 +6775,24 @@ __mmplayer_gst_create_pipeline(mm_player_t* player)
        gst_object_unref(GST_OBJECT(bus));
        g_list_free(element_bucket);
 
+       /* create gst bus_msb_cb thread */
+       g_mutex_init(&player->bus_msg_thread_mutex);
+       g_cond_init(&player->bus_msg_thread_cond);
+       player->bus_msg_thread_exit = FALSE;
+       player->bus_msg_thread =
+               g_thread_try_new("gst_bus_msg_thread", __mmplayer_gst_bus_msg_thread, (gpointer)player, NULL);
+       if (!player->bus_msg_thread) {
+               LOGE("failed to create gst BUS msg thread");
+               g_mutex_clear(&player->bus_msg_thread_mutex);
+               g_cond_clear(&player->bus_msg_thread_cond);
+               goto INIT_ERROR;
+       }
+
        MMPLAYER_FLEAVE();
 
        return MM_ERROR_NONE;
 
 INIT_ERROR:
-
        __mmplayer_gst_destroy_pipeline(player);
        g_list_free(element_bucket);
 
@@ -6817,11 +6884,6 @@ __mmplayer_gst_destroy_pipeline(mm_player_t* player)
                /* first we need to disconnect all signal hander */
                __mmplayer_release_signal_connection(player, MM_PLAYER_SIGNAL_TYPE_ALL);
 
-               /* disconnecting bus watch */
-               if (player->bus_watcher)
-                       __mmplayer_remove_g_source_from_context(player->context.thread_default, player->bus_watcher);
-               player->bus_watcher = 0;
-
                if (mainbin) {
                        MMPlayerGstElement* audiobin = player->pipeline->audiobin;
                        MMPlayerGstElement* videobin = player->pipeline->videobin;
@@ -8150,9 +8212,10 @@ void __mmplayer_sound_focus_watch_callback(int id, mm_sound_focus_type_e focus_t
                                }
 
                                __mmplayer_undo_sound_fadedown(player);
-                       } else
+                       } else {
                                /* rtsp should connect again in specific network becasue tcp session can't be kept any more */
                                _mmplayer_unrealize((MMHandleType)player);
+                       }
                } else {
                        LOGW("pause immediately");
                        result = _mmplayer_pause((MMHandleType)player);
@@ -8935,7 +8998,13 @@ _mmplayer_unrealize(MMHandleType hplayer)
 
        MMPLAYER_FENTER();
 
-       MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED)
+       MMPLAYER_RETURN_VAL_IF_FAIL(player, MM_ERROR_PLAYER_NOT_INITIALIZED);
+
+       MMPLAYER_CMD_UNLOCK(player);
+       /* destroy the gst bus msg thread which is created during realize.
+          this funct have to be called before getting cmd lock. */
+       _mmplayer_bus_msg_thread_destroy(player);
+       MMPLAYER_CMD_LOCK(player);
 
        /* check current state */
        MMPLAYER_CHECK_STATE(player, MMPLAYER_COMMAND_UNREALIZE);
@@ -12063,8 +12132,8 @@ __mmplayer_handle_eos_delay(mm_player_t* player, int delay_in_ms)
        player->eos_timer = g_timeout_add(delay_in_ms,
                __mmplayer_eos_timer_cb, player);
 
-       player->context.global_default = g_main_context_default();
-       LOGD("global default context = %p, eos timer id = %d", player->context.global_default, player->eos_timer);
+       player->global_default = g_main_context_default();
+       LOGD("global default context = %p, eos timer id = %d", player->global_default, player->eos_timer);
 
        /* check timer is valid. if not, send EOS now */
        if (player->eos_timer == 0) {
@@ -12080,7 +12149,7 @@ __mmplayer_cancel_eos_timer(mm_player_t* player)
 
        if (player->eos_timer) {
                LOGD("cancel eos timer");
-               __mmplayer_remove_g_source_from_context(player->context.global_default, player->eos_timer);
+               __mmplayer_remove_g_source_from_context(player->global_default, player->eos_timer);
                player->eos_timer = 0;
        }
 
@@ -12989,6 +13058,7 @@ int _mmplayer_set_external_subtitle_path(MMHandleType hplayer, const char* filep
                        result = __mmplayer_change_external_subtitle_language(player, filepath);
                }
 
+               MMPLAYER_BUS_MSG_THREAD_SIGNAL(player);
                player->is_external_subtitle_added_now = TRUE;
        }