From 8a64e5568e959759e95e56f967153c7f5253cacc Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Tue, 13 Oct 2020 15:20:33 +0900 Subject: [PATCH] Revise webrtc_stop() The gstreamer pipeline state is changed to NULL when after webrtc_stop(). In this situation, webrtc state is IDLE in which a media source can be added or removed. This change intends to be sure to release all the resources inside of the webrtcbin as well as avoid warning message when calling the gst_bin_remove() within gstreamer READY state. Release missing sink slots which have been created after finishing negotiation APIs. [Version] 0.1.39 [Issue Type] Improvement Change-Id: Ia51d8f98d8e778619e20c36c6a87ed56721065db Signed-off-by: Sangchul Lee --- include/webrtc_private.h | 6 +++++- packaging/capi-media-webrtc.spec | 2 +- src/webrtc.c | 4 +++- src/webrtc_private.c | 24 ++++----------------- src/webrtc_sink.c | 16 +++++++++++++- src/webrtc_source.c | 37 +++++++++++++++++++++++++++++++- 6 files changed, 64 insertions(+), 25 deletions(-) diff --git a/include/webrtc_private.h b/include/webrtc_private.h index 6ee446e3..2406bdc5 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -123,13 +123,14 @@ do { \ } \ } while (0) -#define MALLOC_AND_INIT_SLOT(x_slot, x_id, x_bin_name) \ +#define MALLOC_AND_INIT_SLOT(x_slot, x_id, x_bin_name, x_webrtcbin) \ do { \ x_slot = g_new0(webrtc_gst_slot_s, 1); \ x_slot->id = x_id; \ x_slot->bin = gst_bin_new(x_bin_name); \ x_slot->mlines[MLINES_IDX_AUDIO] = -1; \ x_slot->mlines[MLINES_IDX_VIDEO] = -1; \ + x_slot->webrtcbin = x_webrtcbin; \ } while (0) #define GENERATE_DOT(x_webrtc, x_fmt, x_arg...) \ @@ -160,6 +161,7 @@ typedef struct _webrtc_gst_slot_s { GstElement *bin; int media_types; /* values of media_type_e combined with bitwise 'or' */ int mlines[2]; /* index 0 for audio, 1 for video */ + GstElement *webrtcbin; } webrtc_gst_slot_s; typedef struct _webrtc_gst_s { @@ -227,6 +229,8 @@ GstElement *_create_element_from_registry(element_info_s *elem_info); int _add_no_target_ghostpad_to_slot(webrtc_gst_slot_s *slot, gboolean is_src, GstPad **new_pad); int _set_ghost_pad_target(GstPad *ghost_pad, GstElement *target_element, gboolean is_src); int _add_rendering_sink_bin(webrtc_s *webrtc, GstPad *src_pad); +void _sink_slot_destroy_cb(gpointer data); +void _source_slot_destroy_cb(gpointer data); void _generate_dot(webrtc_s *webrtc, const gchar *name); int _webrtcbin_create_offer(webrtc_s *webrtc, char **offer); diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index b2c2ef5e..79f88206 100644 --- a/packaging/capi-media-webrtc.spec +++ b/packaging/capi-media-webrtc.spec @@ -1,6 +1,6 @@ Name: capi-media-webrtc Summary: A WebRTC library in Tizen Native API -Version: 0.1.38 +Version: 0.1.39 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc.c b/src/webrtc.c index 3475d6d2..0e2637b4 100644 --- a/src/webrtc.c +++ b/src/webrtc.c @@ -192,12 +192,14 @@ int webrtc_stop(webrtc_h webrtc) RET_VAL_WITH_UNLOCK_IF(_webrtc->state == WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should not be IDLE"); - _gst_pipeline_set_state(_webrtc, GST_STATE_READY); + _gst_pipeline_set_state(_webrtc, GST_STATE_NULL); _post_state_in_idle(_webrtc, WEBRTC_STATE_IDLE); LOG_INFO("webrtc[%p] is stopping", webrtc); + g_hash_table_remove_all(_webrtc->gst.sink_slots); + g_mutex_unlock(&_webrtc->mutex); return WEBRTC_ERROR_NONE; diff --git a/src/webrtc_private.c b/src/webrtc_private.c index 1583a7cf..410cd3c1 100644 --- a/src/webrtc_private.c +++ b/src/webrtc_private.c @@ -273,7 +273,7 @@ static gboolean __idle_cb(gpointer user_data) __invoke_state_changed_cb(webrtc, old_state, webrtc->state); - return FALSE; + return G_SOURCE_REMOVE; } void _post_state_in_idle(webrtc_s *webrtc, webrtc_state_e new_state) @@ -377,22 +377,6 @@ GstElement *_create_element_from_registry(element_info_s *elem_info) return element; } -static void __value_destroy_cb(gpointer data) -{ - webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)data; - - RET_IF(data == NULL, "data is NULL"); - - LOG_DEBUG("[%s, id:%u, media_types:0x%x, mlines[AUDIO]:%d, mlines[VIDEO]:%d] is removed", - GST_ELEMENT_NAME(source->bin), source->id, source->media_types, source->mlines[MLINES_IDX_AUDIO], source->mlines[MLINES_IDX_VIDEO]); - - /* FIXME: do unlink */ - - gst_bin_remove(GST_BIN(gst_element_get_parent(source->bin)), source->bin); - - g_free(source); -} - int _ini_load(webrtc_s *webrtc) { RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); @@ -485,7 +469,7 @@ static void __disconnect_signal(gpointer data) { webrtc_signal_s *sig_data = (webrtc_signal_s *)data; - RET_IF(data == NULL, "data is NULL"); + RET_IF(sig_data == NULL, "sig_data is NULL"); if (GST_IS_ELEMENT(sig_data->obj)) { if (g_signal_handler_is_connected(sig_data->obj, sig_data->signal_id)) { @@ -877,8 +861,8 @@ int _gst_build_pipeline(webrtc_s *webrtc) goto error; } - webrtc->gst.source_slots = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, __value_destroy_cb); - webrtc->gst.sink_slots = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, __value_destroy_cb); + webrtc->gst.source_slots = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _source_slot_destroy_cb); + webrtc->gst.sink_slots = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, _sink_slot_destroy_cb); return WEBRTC_ERROR_NONE; diff --git a/src/webrtc_sink.c b/src/webrtc_sink.c index 5f07664f..fce1ab19 100644 --- a/src/webrtc_sink.c +++ b/src/webrtc_sink.c @@ -202,6 +202,20 @@ static unsigned int __get_id_from_pad_name(const gchar* name) return (unsigned int)id; } +void _sink_slot_destroy_cb(gpointer data) +{ + webrtc_gst_slot_s *sink = (webrtc_gst_slot_s *)data; + + RET_IF(sink == NULL, "sink is NULL"); + + LOG_DEBUG("[%s, id:%u, media_types:0x%x] is removed", + GST_ELEMENT_NAME(sink->bin), sink->id, sink->media_types); + + gst_bin_remove(GST_BIN(gst_element_get_parent(sink->bin)), sink->bin); + + g_free(sink); +} + int _add_rendering_sink_bin(webrtc_s *webrtc, GstPad *src_pad) { int ret = WEBRTC_ERROR_NONE; @@ -220,7 +234,7 @@ int _add_rendering_sink_bin(webrtc_s *webrtc, GstPad *src_pad) bin_name = g_strdup_printf("rendering_sink_%u", id); decodebin_name = g_strdup_printf("%s_decodebin", bin_name); - MALLOC_AND_INIT_SLOT(sink, id, bin_name); + MALLOC_AND_INIT_SLOT(sink, id, bin_name, webrtc->gst.webrtcbin); g_free(bin_name); diff --git a/src/webrtc_source.c b/src/webrtc_source.c index b1146841..aae7ecda 100644 --- a/src/webrtc_source.c +++ b/src/webrtc_source.c @@ -441,6 +441,41 @@ static unsigned int __get_unoccupied_id(GHashTable *slots) return 0; } +static gboolean __foreach_src_pad_cb(GstElement *element, GstPad *pad, gpointer user_data) +{ + webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)user_data; + GstPad *peer = gst_pad_get_peer(pad); + + RET_VAL_IF(source == NULL, FALSE, "source is NULL"); + RET_VAL_IF(peer == NULL, TRUE, "peer pad is NULL"); + + LOG_DEBUG("about to release request pad[%s]", GST_PAD_NAME(peer)); + + gst_element_release_request_pad(source->webrtcbin, peer); + + /* Two unrefing here, one for getting request pad, another one for getting peer pad */ + gst_object_unref(peer); + gst_object_unref(peer); + + return TRUE; +} + +void _source_slot_destroy_cb(gpointer data) +{ + webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)data; + + RET_IF(source == NULL, "source is NULL"); + + LOG_DEBUG("[%s, id:%u, media_types:0x%x, mlines[AUDIO]:%d, mlines[VIDEO]:%d] is removed", + GST_ELEMENT_NAME(source->bin), source->id, source->media_types, source->mlines[MLINES_IDX_AUDIO], source->mlines[MLINES_IDX_VIDEO]); + + gst_element_foreach_src_pad(source->bin, __foreach_src_pad_cb, source); + + gst_bin_remove(GST_BIN(gst_element_get_parent(source->bin)), source->bin); + + g_free(source); +} + int _add_media_source(webrtc_s *webrtc, webrtc_media_source_type_e type, unsigned int *source_id) { int ret = WEBRTC_ERROR_NONE; @@ -461,7 +496,7 @@ int _add_media_source(webrtc_s *webrtc, webrtc_media_source_type_e type, unsigne bin_name = g_strdup_printf("media_source_%u", id); - MALLOC_AND_INIT_SLOT(source, id, bin_name); + MALLOC_AND_INIT_SLOT(source, id, bin_name, webrtc->gst.webrtcbin); ret = __build_source_bin(source, type); if (ret != WEBRTC_ERROR_NONE) { -- 2.34.1