webrtc_source: Use GList to carry elements via parameter 56/259456/7
authorSangchul Lee <sc11.lee@samsung.com>
Tue, 8 Jun 2021 08:32:49 +0000 (17:32 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Thu, 10 Jun 2021 08:05:41 +0000 (17:05 +0900)
[Version] 0.2.8
[Issue Type] Refactoring

Change-Id: Id19b2b6052799491b4c7558ea18170e203d94746
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
include/webrtc_private.h
packaging/capi-media-webrtc.spec
src/webrtc_private.c
src/webrtc_source.c

index d05da8ee138983450292e23710267c3a69956606..db07de5272a8e7df623f62582e0b47185cf4f91b 100644 (file)
@@ -158,9 +158,10 @@ do { \
        return WEBRTC_ERROR_NOT_SUPPORTED; \
 } while (0)
 
-#define SAFE_FREE(src)    { if (src) { free(src); src = NULL; } }
-#define SAFE_GST_OBJECT_UNREF(src)    { if (src) { gst_object_unref(src); src = NULL; } }
-#define SAFE_STR(str)     (str) ? str : "null"
+#define SAFE_FREE(src)              { if (src) { free(src); src = NULL; } }
+#define SAFE_GST_OBJECT_UNREF(src)  { if (src) { gst_object_unref(src); src = NULL; } }
+#define SAFE_G_LIST_FREE(src)       { if (src) { g_list_free(src); src = NULL; } }
+#define SAFE_STR(str)               (str) ? str : "null"
 
 #define PRINT_CAPS(x_caps, x_prefix) \
 do { \
index 96923de644da7765fe6abda471f00ec1af617253..770ca9be104effb096255ce1ad58848e037dec8d 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.2.7
+Version:    0.2.8
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 16e4300b59cda3ac698d1596ded3eaab9f4723ba..9f86acc69c23824792c8ced6ed9c6902c8c03393 100644 (file)
@@ -690,6 +690,7 @@ static void __webrtcbin_on_negotiation_needed_cb(GstElement *webrtcbin, gpointer
        webrtc->state = webrtc->pend_state;
 
        g_mutex_unlock(&webrtc->mutex);
+
        _invoke_state_changed_cb(webrtc, old_state, webrtc->state);
        webrtc->negotiation_needed_cb_invoked = true;
 
index c051d01fdb92453f236d9a2530506b661eb2f277..2ad282aa2cb13e2d2d56ae3f0d58e641f52ba312 100644 (file)
 #define GST_KLASS_NAME_CONVERTER_AUDIO "Filter/Converter/Audio"
 #define GST_KLASS_NAME_CONVERTER_VIDEO "Filter/Converter/Video"
 
-#define DEFAULT_ELEMENT_CAMERASRC     "v4l2src"
-#define DEFAULT_ELEMENT_AUDIOSRC      "pulsesrc"
-#define DEFAULT_ELEMENT_VIDEOTESTSRC  "videotestsrc"
-#define DEFAULT_ELEMENT_AUDIOTESTSRC  "audiotestsrc"
-#define DEFAULT_ELEMENT_APPSRC        "appsrc"
-#define DEFAULT_ELEMENT_SCREENSRC     "waylandsrc"
-#define DEFAULT_ELEMENT_VIDEOCONVERT  "videoconvert"
-#define DEFAULT_ELEMENT_CAPSFILTER    "capsfilter"
-#define DEFAULT_ELEMENT_QUEUE         "queue"
-#define DEFAULT_ELEMENT_VOLUME        "volume"
+#define DEFAULT_ELEMENT_CAMERASRC      "v4l2src"
+#define DEFAULT_ELEMENT_AUDIOSRC       "pulsesrc"
+#define DEFAULT_ELEMENT_VIDEOTESTSRC   "videotestsrc"
+#define DEFAULT_ELEMENT_AUDIOTESTSRC   "audiotestsrc"
+#define DEFAULT_ELEMENT_APPSRC         "appsrc"
+#define DEFAULT_ELEMENT_SCREENSRC      "waylandsrc"
+#define DEFAULT_ELEMENT_VIDEOCONVERT   "videoconvert"
+#define DEFAULT_ELEMENT_CAPSFILTER     "capsfilter"
+#define DEFAULT_ELEMENT_QUEUE          "queue"
+#define DEFAULT_ELEMENT_VOLUME         "volume"
+#define DEFAULT_ELEMENT_INPUT_SELECTOR "input-selector"
 
 #define ELEMENT_NAME_FIRST_CAPSFILTER "firstCapsfilter"
+#define ELEMENT_NAME_RTP_CAPSFILTER   "rtpCapsfilter"
 #define ELEMENT_NAME_VIDEO_SRC        "videoSrc"
 #define ELEMENT_NAME_VIDEO_SWITCH     "videoSwitch"
 #define ELEMENT_NAME_VIDEO_MUTE_SRC   "videoMuteSrc"
 #define ELEMENT_NAME_VOLUME           "volume"
 
+#define APPEND_ELEMENT(x_list, x_element) \
+do { \
+       if (!(x_element)) \
+               break; \
+       x_list = g_list_append(x_list, x_element); \
+       LOG_DEBUG("%s is appended", GST_ELEMENT_NAME(x_element)); \
+} while (0)
+
+#define PREPEND_ELEMENT(x_list, x_element) \
+do { \
+       if (!(x_element)) \
+               break; \
+       x_list = g_list_prepend(x_list, x_element); \
+       LOG_DEBUG("%s is prepended", GST_ELEMENT_NAME(x_element)); \
+} while (0)
+
 typedef enum {
        CODEC_TYPE_OPUS,
        CODEC_TYPE_VORBIS,
@@ -616,9 +634,13 @@ static GstElement *__get_hw_encoder_element(webrtc_s *webrtc, webrtc_gst_slot_s
        return NULL;
 }
 
-static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source,
-       GstElement **capsfilter, GstElement **encoder, GstElement **payloader, GstElement **queue, GstElement **capsfilter2)
+static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool need_capsfilter, GList **element_list)
 {
+       GstElement *capsfilter = NULL;
+       GstElement *encoder;
+       GstElement *payloader;
+       GstElement *queue;
+       GstElement *capsfilter2;
        GstCaps *sink_caps;
        element_info_s elem_info;
        const gchar *encoder_klass_name;
@@ -627,20 +649,16 @@ static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source
 
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
        RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
-       RET_VAL_IF(encoder == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "encoder is NULL");
-       RET_VAL_IF(payloader == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payloader is NULL");
-       RET_VAL_IF(queue == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "queue is NULL");
-       RET_VAL_IF(capsfilter2 == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "capsfilter2 is NULL");
+       RET_VAL_IF(element_list == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "element_list is NULL");
 
-       if (capsfilter) {
-               if (!(*capsfilter = _create_element(DEFAULT_ELEMENT_CAPSFILTER, ELEMENT_NAME_FIRST_CAPSFILTER))) {
+       if (need_capsfilter) {
+               if (!(capsfilter = _create_element(DEFAULT_ELEMENT_CAPSFILTER, ELEMENT_NAME_FIRST_CAPSFILTER))) {
                        LOG_ERROR("failed to create capsfilter");
                        return WEBRTC_ERROR_INVALID_OPERATION;
                }
                if ((sink_caps = __make_default_raw_caps(source, &webrtc->ini))) {
                        PRINT_CAPS(sink_caps, "capsfilter");
-
-                       g_object_set(G_OBJECT(*capsfilter), "caps", sink_caps, NULL);
+                       g_object_set(G_OBJECT(capsfilter), "caps", sink_caps, NULL);
                        gst_caps_unref(sink_caps);
                }
        }
@@ -655,18 +673,18 @@ static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source
        }
 
        if (source->zerocopy_enabled)
-               *encoder = __get_hw_encoder_element(webrtc, source);
+               encoder = __get_hw_encoder_element(webrtc, source);
        else
                CREATE_ELEMENT_FROM_REGISTRY(elem_info, encoder_klass_name,
                                                        __make_default_raw_caps(source, &webrtc->ini),
                                                        __make_default_encoded_caps(source, &webrtc->ini, NULL),
-                                                       *encoder);
-       if (*encoder == NULL)
+                                                       encoder);
+       if (encoder == NULL)
                return WEBRTC_ERROR_INVALID_OPERATION;
 
-       encoder_name = gst_element_get_name(*encoder);
+       encoder_name = gst_element_get_name(encoder);
        if (encoder_name && (!g_strcmp0(encoder_name, "vp8enc") || !g_strcmp0(encoder_name, "vp9enc"))) {
-               g_object_set(G_OBJECT(*encoder), "threads", webrtc->ini.vpxenc_params.threads,
+               g_object_set(G_OBJECT(encoder), "threads", webrtc->ini.vpxenc_params.threads,
                                                "end-usage", webrtc->ini.vpxenc_params.end_usage,
                                                "cpu-used", webrtc->ini.vpxenc_params.cpu_used,
                                                "target-bitrate", webrtc->ini.vpxenc_params.target_bitrate,
@@ -680,30 +698,36 @@ static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source
        CREATE_ELEMENT_FROM_REGISTRY(elem_info, GST_KLASS_NAME_PAYLOADER_RTP,
                                                __make_default_encoded_caps(source, &webrtc->ini, &media_type),
                                                NULL,
-                                               *payloader);
-       if (*payloader == NULL) {
+                                               payloader);
+       if (payloader == NULL) {
                g_free(media_type);
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
 
-       if (!(*queue = _create_element(DEFAULT_ELEMENT_QUEUE, NULL))) {
+       if (!(queue = _create_element(DEFAULT_ELEMENT_QUEUE, NULL))) {
                LOG_ERROR("failed to create queue");
                g_free(media_type);
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
 
-       if (!(*capsfilter2 = _create_element(DEFAULT_ELEMENT_CAPSFILTER, NULL))) {
+       if (!(capsfilter2 = _create_element(DEFAULT_ELEMENT_CAPSFILTER, ELEMENT_NAME_RTP_CAPSFILTER))) {
                LOG_ERROR("failed to create capsfilter");
                g_free(media_type);
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
        if ((sink_caps = __make_rtp_caps(media_type, source->id))) {
-               g_object_set(G_OBJECT(*capsfilter2), "caps", sink_caps, NULL);
+               g_object_set(G_OBJECT(capsfilter2), "caps", sink_caps, NULL);
                gst_caps_unref(sink_caps);
        }
 
        g_free(media_type);
 
+       APPEND_ELEMENT(*element_list, capsfilter);
+       APPEND_ELEMENT(*element_list, encoder);
+       APPEND_ELEMENT(*element_list, payloader);
+       APPEND_ELEMENT(*element_list, queue);
+       APPEND_ELEMENT(*element_list, capsfilter2);
+
        return WEBRTC_ERROR_NONE;
 }
 
@@ -833,41 +857,128 @@ static void __add_probe_to_pad(GstPad *pad, media_type_e media_type, webrtc_gst_
                source->av[probe_userdata->av_idx].src_pad_probe_id, pad, probe_userdata->av_idx, source);
 }
 
-static GstElement * __link_video_switch(GstBin *bin, GstElement *src)
+static bool __add_elements_to_bin(GstBin *bin, GList *element_list)
 {
-       GstElement *videotestsrc = NULL;
-       GstElement *videoswitch = NULL;
+       GstElement *element;
+       GList *list;
+       int count = 0;
 
-       RET_VAL_IF(bin == NULL, NULL, "bin is NULL");
-       RET_VAL_IF(src == NULL, NULL, "src is NULL");
+       RET_VAL_IF(bin == NULL, false, "bin is NULL");
+       RET_VAL_IF(element_list == NULL, false, "element_list is NULL");
 
-       if (!(videotestsrc = _create_element(DEFAULT_ELEMENT_VIDEOTESTSRC, ELEMENT_NAME_VIDEO_MUTE_SRC)))
-               return NULL;
+       for (list = element_list; list; list = list->next) {
+               element = (GstElement *)list->data;
+               RET_VAL_IF(!gst_bin_add(bin, element), false,
+                       "failed to gst_bin_add(), bin[%s], element[%s]", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(element));
+               count++;
+       }
 
-       g_object_set(G_OBJECT(videotestsrc), "is-live", TRUE, "pattern", 2, NULL); /* 2: black */
+       LOG_DEBUG("%d elements are added to bin[%s]", count, GST_ELEMENT_NAME(bin));
 
-       if (!(videoswitch = _create_element("input-selector", ELEMENT_NAME_VIDEO_SWITCH))) {
-               SAFE_GST_OBJECT_UNREF(videotestsrc);
-               return NULL;
+       return true;
+}
+
+static bool __remove_elements_from_bin(GstBin *bin, GList *element_list)
+{
+       GstElement *element;
+       GList *list;
+       int count = 0;
+
+       RET_VAL_IF(bin == NULL, false, "bin is NULL");
+       RET_VAL_IF(element_list == NULL, false, "element_list is NULL");
+
+       for (list = element_list; list; list = g_list_next(list)) {
+               element = (GstElement *)list->data;
+               RET_VAL_IF(!gst_bin_remove(bin, element), false,
+                       "failed to gst_bin_remove(), bin[%s], element[%s]", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(element));
+               count++;
        }
 
-       gst_bin_add_many(bin, videotestsrc, videoswitch, NULL);
+       LOG_DEBUG("%d elements are removed from bin[%s]", count, GST_ELEMENT_NAME(bin));
+
+       return true;
+}
+
+static void __unref_elements(GList *element_list)
+{
+       GList *list;
+
+       if (!element_list)
+               return;
+
+       for (list = element_list; list; list = g_list_next(list))
+               SAFE_GST_OBJECT_UNREF(list->data);
+}
+
+static bool __link_elements(GList *element_list)
+{
+       GstElement *curr;
+       GstElement *prev = NULL;
+       GList *list;
+       int count = 0;
+
+       RET_VAL_IF(element_list == NULL, false, "element_list is NULL");
+
+       for (list = element_list; list; list = g_list_next(list)) {
+               if (!g_list_previous(list))
+                       continue;
+               prev = (GstElement *)(g_list_previous(list)->data);
+               curr = (GstElement *)list->data;
+               RET_VAL_IF(!gst_element_link(prev, curr), false,
+                       "failed to gst_element_link(), [%s] - [%s]", GST_ELEMENT_NAME(prev), GST_ELEMENT_NAME(curr));
+               LOG_DEBUG("[%s] - [%s]", GST_ELEMENT_NAME(prev), GST_ELEMENT_NAME(curr));
+               count++;
+       }
+
+       LOG_DEBUG("%d elements are linked", count);
+
+       return true;
+}
+
+static bool __link_switch_srcs(GstElement *switch_element, GList *switch_src_list)
+{
+       GstElement *element;
+       GList *list;
+
+       RET_VAL_IF(switch_element == NULL, false, "switch_element is NULL");
+       RET_VAL_IF(switch_src_list == NULL, false, "switch_src_list is NULL");
 
-       gst_element_link(src, videoswitch);
-       gst_element_link(videotestsrc, videoswitch);
+       for (list = switch_src_list; list; list = g_list_next(list)) {
+               element = (GstElement *)list->data;
+               RET_VAL_IF(!gst_element_link(element, switch_element), false,
+                       "failed to gst_element_link(), [%s] - [%s]", GST_ELEMENT_NAME(element), GST_ELEMENT_NAME(switch_element));
 
-       return videoswitch;
+               LOG_DEBUG("[%s] - [%s]", GST_ELEMENT_NAME(element), GST_ELEMENT_NAME(switch_element));
+       }
+
+       return true;
 }
 
-static void __unlink_video_switch(GstBin *bin)
+static GstElement *__find_element_in_bin(GstBin *bin, const gchar *name)
 {
-       GstElement *videotestsrc = NULL;
-       GstElement *videoswitch = NULL;
+       GValue value = G_VALUE_INIT;
+       GstElement *element;
+       GstIterator *bin_iterator;
 
-       videotestsrc = gst_bin_get_by_name(bin, ELEMENT_NAME_VIDEO_MUTE_SRC);
-       videoswitch = gst_bin_get_by_name(bin, ELEMENT_NAME_VIDEO_SWITCH);
+       RET_VAL_IF(bin == NULL, NULL, "bin is NULL");
+       RET_VAL_IF(name == NULL, NULL, "name is NULL");
+       RET_VAL_IF(!(bin_iterator = gst_bin_iterate_sorted(bin)), NULL, "bin_iterator is NULL");
 
-       gst_bin_remove_many(bin, videotestsrc, videoswitch, NULL);
+       while (GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &value)) {
+               element = GST_ELEMENT(g_value_get_object(&value));
+
+               if (g_strrstr(GST_ELEMENT_NAME(element), name)) {
+                       LOG_DEBUG("found element by name [%s]", GST_ELEMENT_NAME(element));
+                       gst_iterator_free(bin_iterator);
+                       return element;
+               }
+
+               g_value_reset(&value);
+       }
+
+       gst_iterator_free(bin_iterator);
+
+       return NULL;
 }
 
 static int __build_screensrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
@@ -875,12 +986,11 @@ static int __build_screensrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
        int ret = WEBRTC_ERROR_NONE;
        GstElement *screensrc;
        GstElement *videoconvert;
-       GstElement *capsfilter = NULL;
-       GstElement *videoenc = NULL;
-       GstElement *videopay = NULL;
-       GstElement *queue = NULL;
-       GstElement *capsfilter2 = NULL;
-       GstElement *video_switch = NULL;
+       GstElement *videotestsrc;
+       GstElement *videoswitch;
+       GstElement *capsfilter;
+       GList *switch_src_list = NULL;
+       GList *element_list = NULL;
 
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
        RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
@@ -894,46 +1004,70 @@ static int __build_screensrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
 
        if (!(screensrc = _create_element(__get_source_element(webrtc, WEBRTC_MEDIA_SOURCE_TYPE_SCREEN), ELEMENT_NAME_VIDEO_SRC)))
                return WEBRTC_ERROR_INVALID_OPERATION;
+       APPEND_ELEMENT(switch_src_list, screensrc);
+
+       if (!(videotestsrc = _create_element(DEFAULT_ELEMENT_VIDEOTESTSRC, ELEMENT_NAME_VIDEO_MUTE_SRC)))
+               goto exit;
+       APPEND_ELEMENT(switch_src_list, videotestsrc);
+
+       g_object_set(G_OBJECT(videotestsrc), "is-live", TRUE, "pattern", 2, NULL); /* 2: black */
+
+       if (!(videoswitch = _create_element(DEFAULT_ELEMENT_INPUT_SELECTOR, ELEMENT_NAME_VIDEO_SWITCH)))
+               goto exit;
+       APPEND_ELEMENT(element_list, videoswitch);
 
        if (!(videoconvert = _create_element(DEFAULT_ELEMENT_VIDEOCONVERT, NULL)))
                goto exit;
+       APPEND_ELEMENT(element_list, videoconvert);
 
-       if ((ret = __create_rest_of_elements(webrtc, source, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE)
+       if ((ret = __create_rest_of_elements(webrtc, source, true, &element_list)) != WEBRTC_ERROR_NONE)
                goto exit;
 
-       gst_bin_add_many(source->bin, screensrc, videoconvert, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
+       if (!__add_elements_to_bin(source->bin, switch_src_list))
+               goto exit;
 
-       video_switch = __link_video_switch(source->bin, screensrc);
-       if (!video_switch)
+       if (!__add_elements_to_bin(source->bin, element_list)) {
+               ret = WEBRTC_ERROR_INVALID_OPERATION;
                goto exit_with_remove_from_bin;
+       }
 
-       if (!gst_element_link_many(video_switch, videoconvert, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) {
-               LOG_ERROR("failed to gst_element_link_many()");
+       if (!__link_switch_srcs(videoswitch, switch_src_list)) {
+               ret = WEBRTC_ERROR_INVALID_OPERATION;
+               goto exit_with_remove_from_bin;
+       }
+
+       if (!__link_elements(element_list)) {
                ret = WEBRTC_ERROR_INVALID_OPERATION;
                goto exit_with_remove_from_bin;
        }
 
-       ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter2, true);
+       if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) {
+               ret = WEBRTC_ERROR_INVALID_OPERATION;
+               goto exit_with_remove_from_bin;
+       }
+       ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter, true);
        if (ret != WEBRTC_ERROR_NONE)
                goto exit_with_remove_from_bin;
 
        __add_probe_to_pad(source->av[AV_IDX_VIDEO].src_pad, MEDIA_TYPE_VIDEO, source);
 
+       SAFE_G_LIST_FREE(switch_src_list);
+       SAFE_G_LIST_FREE(element_list);
+
        return WEBRTC_ERROR_NONE;
 
 exit_with_remove_from_bin:
        /* elements will be dereferenced */
-       gst_bin_remove_many(source->bin, screensrc, videoconvert, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
-       __unlink_video_switch(source->bin);
+       __remove_elements_from_bin(source->bin, switch_src_list);
+       __remove_elements_from_bin(source->bin, element_list);
+       SAFE_G_LIST_FREE(switch_src_list);
+       SAFE_G_LIST_FREE(element_list);
        return ret;
 exit:
-       SAFE_GST_OBJECT_UNREF(screensrc);
-       SAFE_GST_OBJECT_UNREF(videoconvert);
-       SAFE_GST_OBJECT_UNREF(capsfilter);
-       SAFE_GST_OBJECT_UNREF(videoenc);
-       SAFE_GST_OBJECT_UNREF(videopay);
-       SAFE_GST_OBJECT_UNREF(queue);
-       SAFE_GST_OBJECT_UNREF(capsfilter2);
+       __unref_elements(switch_src_list);
+       __unref_elements(element_list);
+       SAFE_G_LIST_FREE(switch_src_list);
+       SAFE_G_LIST_FREE(element_list);
        return ret;
 }
 
@@ -941,11 +1075,8 @@ static int __build_camerasrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
 {
        int ret = WEBRTC_ERROR_NONE;
        GstElement *camerasrc;
-       GstElement *capsfilter = NULL;
-       GstElement *videoenc = NULL;
-       GstElement *videopay = NULL;
-       GstElement *queue = NULL;
-       GstElement *capsfilter2 = NULL;
+       GstElement *capsfilter;
+       GList *element_list = NULL;
 
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
        RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
@@ -961,6 +1092,7 @@ static int __build_camerasrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
 #endif
        if (!(camerasrc = _create_element(__get_source_element(webrtc, WEBRTC_MEDIA_SOURCE_TYPE_CAMERA), ELEMENT_NAME_VIDEO_SRC)))
                return WEBRTC_ERROR_INVALID_OPERATION;
+       APPEND_ELEMENT(element_list, camerasrc);
 
        /* FIXME: set camera default setting from ini */
 
@@ -969,49 +1101,50 @@ static int __build_camerasrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
        if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(camerasrc)), "empty-buffer-timeout"))
                g_object_set(G_OBJECT(camerasrc), "empty-buffer-timeout", 0, NULL);
 
-       if ((ret = __create_rest_of_elements(webrtc, source, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE)
+       if ((ret = __create_rest_of_elements(webrtc, source, true, &element_list)) != WEBRTC_ERROR_NONE)
                goto exit;
 
-       gst_bin_add_many(source->bin, camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
-       if (!gst_element_link_many(camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) {
-               LOG_ERROR("failed to gst_element_link_many()");
+       if (!__add_elements_to_bin(source->bin, element_list))
+               goto exit;
+
+       if (!__link_elements(element_list)) {
                ret = WEBRTC_ERROR_INVALID_OPERATION;
                goto exit_with_remove_from_bin;
        }
 
-       ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter2, true);
+       if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) {
+               ret = WEBRTC_ERROR_INVALID_OPERATION;
+               goto exit_with_remove_from_bin;
+       }
+       ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter, true);
        if (ret != WEBRTC_ERROR_NONE)
                goto exit_with_remove_from_bin;
 
        __add_probe_to_pad(source->av[AV_IDX_VIDEO].src_pad, MEDIA_TYPE_VIDEO, source);
 
+       SAFE_G_LIST_FREE(element_list);
+
        return WEBRTC_ERROR_NONE;
 
 exit_with_remove_from_bin:
        /* elements will be dereferenced */
-       gst_bin_remove_many(source->bin, camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
+       __remove_elements_from_bin(source->bin, element_list);
+       SAFE_G_LIST_FREE(element_list);
        return ret;
 exit:
-       SAFE_GST_OBJECT_UNREF(camerasrc);
-       SAFE_GST_OBJECT_UNREF(capsfilter);
-       SAFE_GST_OBJECT_UNREF(videoenc);
-       SAFE_GST_OBJECT_UNREF(videopay);
-       SAFE_GST_OBJECT_UNREF(queue);
-       SAFE_GST_OBJECT_UNREF(capsfilter2);
+       __unref_elements(element_list);
+       SAFE_G_LIST_FREE(element_list);
        return ret;
 }
 
-static int __build_audiosrc(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool is_mic)
+static int __build_audiosrc(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool use_mic)
 {
        int ret = WEBRTC_ERROR_NONE;
        const char *source_factory_name;
        GstElement *audiosrc;
-       GstElement *volume = NULL;
-       GstElement *capsfilter = NULL;
-       GstElement *audioenc = NULL;
-       GstElement *audiopay = NULL;
-       GstElement *queue = NULL;
-       GstElement *capsfilter2 = NULL;
+       GstElement *volume;
+       GstElement *capsfilter;
+       GList *element_list = NULL;
 
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
        RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
@@ -1023,46 +1156,51 @@ static int __build_audiosrc(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool is
        source->media_types = MEDIA_TYPE_AUDIO;
        source->zerocopy_enabled = __is_hw_encoder_used(webrtc, source->type, source->media_types);
 
-       source_factory_name = __get_source_element(webrtc, is_mic ? WEBRTC_MEDIA_SOURCE_TYPE_MIC : WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST);
+       source_factory_name = __get_source_element(webrtc, use_mic ? WEBRTC_MEDIA_SOURCE_TYPE_MIC : WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST);
        if (!(audiosrc = _create_element(source_factory_name, NULL)))
                return WEBRTC_ERROR_INVALID_OPERATION;
+       APPEND_ELEMENT(element_list, audiosrc);
 
-       if (!is_mic)
+       if (!use_mic)
                g_object_set(G_OBJECT(audiosrc), "is-live", TRUE, NULL);
 
        if (!(volume = _create_element(DEFAULT_ELEMENT_VOLUME, ELEMENT_NAME_VOLUME)))
                goto exit;
+       APPEND_ELEMENT(element_list, volume);
 
-       if ((ret = __create_rest_of_elements(webrtc, source, &capsfilter, &audioenc, &audiopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE)
+       if ((ret = __create_rest_of_elements(webrtc, source, true, &element_list)) != WEBRTC_ERROR_NONE)
                goto exit;
 
-       gst_bin_add_many(source->bin, audiosrc, volume, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL);
-       if (!gst_element_link_many(audiosrc, volume, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL)) {
-               LOG_ERROR("failed to gst_element_link_many()");
+       if (!__add_elements_to_bin(source->bin, element_list))
+               goto exit;
+
+       if (!__link_elements(element_list)) {
                ret = WEBRTC_ERROR_INVALID_OPERATION;
                goto exit_with_remove_from_bin;
        }
 
-       ret = _set_ghost_pad_target(source->av[AV_IDX_AUDIO].src_pad, capsfilter2, true);
+       if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) {
+               ret = WEBRTC_ERROR_INVALID_OPERATION;
+               goto exit_with_remove_from_bin;
+       }
+       ret = _set_ghost_pad_target(source->av[AV_IDX_AUDIO].src_pad, capsfilter, true);
        if (ret != WEBRTC_ERROR_NONE)
                goto exit_with_remove_from_bin;
 
        __add_probe_to_pad(source->av[AV_IDX_AUDIO].src_pad, MEDIA_TYPE_AUDIO, source);
 
+       SAFE_G_LIST_FREE(element_list);
+
        return WEBRTC_ERROR_NONE;
 
 exit_with_remove_from_bin:
        /* elements will be dereferenced */
-       gst_bin_remove_many(source->bin, audiosrc, volume, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL);
+       __remove_elements_from_bin(source->bin, element_list);
+       SAFE_G_LIST_FREE(element_list);
        return ret;
 exit:
-       SAFE_GST_OBJECT_UNREF(audiosrc);
-       SAFE_GST_OBJECT_UNREF(volume);
-       SAFE_GST_OBJECT_UNREF(capsfilter);
-       SAFE_GST_OBJECT_UNREF(audioenc);
-       SAFE_GST_OBJECT_UNREF(audiopay);
-       SAFE_GST_OBJECT_UNREF(queue);
-       SAFE_GST_OBJECT_UNREF(capsfilter2);
+       __unref_elements(element_list);
+       SAFE_G_LIST_FREE(element_list);
        return ret;
 }
 
@@ -1070,11 +1208,8 @@ static int __build_videotestsrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
 {
        int ret = WEBRTC_ERROR_NONE;
        GstElement *videotestsrc;
-       GstElement *capsfilter = NULL;
-       GstElement *videoenc = NULL;
-       GstElement *videopay = NULL;
-       GstElement *queue = NULL;
-       GstElement *capsfilter2 = NULL;
+       GstElement *capsfilter;
+       GList *element_list = NULL;
 
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
        RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
@@ -1088,38 +1223,43 @@ static int __build_videotestsrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
 
        if (!(videotestsrc = _create_element(__get_source_element(webrtc, WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST), ELEMENT_NAME_VIDEO_SRC)))
                return WEBRTC_ERROR_INVALID_OPERATION;
+       APPEND_ELEMENT(element_list, videotestsrc);
 
        g_object_set(G_OBJECT(videotestsrc), "is-live", TRUE, "pattern", 18, NULL); /* 18: ball */
 
-       if ((ret = __create_rest_of_elements(webrtc, source, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE)
+       if ((ret = __create_rest_of_elements(webrtc, source, true, &element_list)) != WEBRTC_ERROR_NONE)
                goto exit;
 
-       gst_bin_add_many(source->bin, videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
-       if (!gst_element_link_many(videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) {
-               LOG_ERROR("failed to gst_element_link_many()");
+       if (!__add_elements_to_bin(source->bin, element_list))
+               goto exit;
+
+       if (!__link_elements(element_list)) {
                ret = WEBRTC_ERROR_INVALID_OPERATION;
                goto exit_with_remove_from_bin;
        }
 
-       ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter2, true);
+       if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) {
+               ret = WEBRTC_ERROR_INVALID_OPERATION;
+               goto exit_with_remove_from_bin;
+       }
+       ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter, true);
        if (ret != WEBRTC_ERROR_NONE)
                goto exit_with_remove_from_bin;
 
        __add_probe_to_pad(source->av[AV_IDX_VIDEO].src_pad, MEDIA_TYPE_VIDEO, source);
 
+       SAFE_G_LIST_FREE(element_list);
+
        return WEBRTC_ERROR_NONE;
 
 exit_with_remove_from_bin:
        /* elements will be dereferenced */
-       gst_bin_remove_many(source->bin, videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
+       __remove_elements_from_bin(source->bin, element_list);
+       SAFE_G_LIST_FREE(element_list);
        return ret;
 exit:
-       SAFE_GST_OBJECT_UNREF(videotestsrc);
-       SAFE_GST_OBJECT_UNREF(capsfilter);
-       SAFE_GST_OBJECT_UNREF(videoenc);
-       SAFE_GST_OBJECT_UNREF(videopay);
-       SAFE_GST_OBJECT_UNREF(queue);
-       SAFE_GST_OBJECT_UNREF(capsfilter2);
+       __unref_elements(element_list);
+       SAFE_G_LIST_FREE(element_list);
        return ret;
 }
 
@@ -1186,43 +1326,13 @@ static int __build_mediapacketsrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
        return WEBRTC_ERROR_NONE;
 }
 
-static GstElement *__find_element_in_bin(GstBin *bin, const gchar *name)
-{
-       GValue value = G_VALUE_INIT;
-       GstElement *element;
-       GstIterator *bin_iterator;
-
-       RET_VAL_IF(bin == NULL, NULL, "bin is NULL");
-       RET_VAL_IF(name == NULL, NULL, "name is NULL");
-
-       bin_iterator = gst_bin_iterate_sorted(bin);
-
-       while (GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &value)) {
-               element = GST_ELEMENT(g_value_get_object(&value));
-
-               if (g_strrstr(GST_ELEMENT_NAME(element), name)) {
-                       LOG_DEBUG("found element by name [%s]", GST_ELEMENT_NAME(element));
-                       gst_iterator_free(bin_iterator);
-                       return element;
-               }
-
-               g_value_reset(&value);
-       }
-
-       gst_iterator_free(bin_iterator);
-
-       return NULL;
-}
-
 static int __complete_mediapacketsrc_from_raw_format(webrtc_s *webrtc, webrtc_gst_slot_s *source)
 {
        int ret = WEBRTC_ERROR_NONE;
        GstPad **src_pad;
        GstElement *appsrc;
-       GstElement *encoder;
-       GstElement *payloader;
-       GstElement *queue;
        GstElement *capsfilter;
+       GList *element_list = NULL;
        GstCaps *sink_caps;
 
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
@@ -1238,7 +1348,7 @@ static int __complete_mediapacketsrc_from_raw_format(webrtc_s *webrtc, webrtc_gs
 
        source->zerocopy_enabled = __is_hw_encoder_used(webrtc, source->type, source->media_types);
 
-       if ((ret = __create_rest_of_elements(webrtc, source, NULL, &encoder, &payloader, &queue, &capsfilter)) != WEBRTC_ERROR_NONE)
+       if ((ret = __create_rest_of_elements(webrtc, source, false, &element_list)) != WEBRTC_ERROR_NONE)
                return ret;
 
        if (!(sink_caps = __make_raw_caps_from_media_format(source))) {
@@ -1250,13 +1360,34 @@ static int __complete_mediapacketsrc_from_raw_format(webrtc_s *webrtc, webrtc_gs
        g_object_set(G_OBJECT(appsrc), "caps", sink_caps, NULL);
        gst_caps_unref(sink_caps);
 
-       gst_bin_add_many(source->bin, encoder, payloader, queue, capsfilter, NULL);
-       if (!gst_element_link_many(appsrc, encoder, payloader, queue, capsfilter, NULL)) {
-               LOG_ERROR("failed to gst_element_link_many()");
-               return WEBRTC_ERROR_INVALID_OPERATION;
+       if (!__add_elements_to_bin(source->bin, element_list))
+               goto exit;
+
+       PREPEND_ELEMENT(element_list, appsrc);
+       if (!__link_elements(element_list)) {
+               ret = WEBRTC_ERROR_INVALID_OPERATION;
+               goto exit_with_remove_from_bin;
        }
 
+       if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) {
+               element_list = g_list_nth(element_list, 1); /* skip removing appsrc from bin */
+               ret = WEBRTC_ERROR_INVALID_OPERATION;
+               goto exit_with_remove_from_bin;
+       }
+
+       SAFE_G_LIST_FREE(element_list);
+
        return _set_ghost_pad_target(*src_pad, capsfilter, true);
+
+exit_with_remove_from_bin:
+       /* elements will be dereferenced */
+       __remove_elements_from_bin(source->bin, element_list);
+       SAFE_G_LIST_FREE(element_list);
+       return ret;
+exit:
+       __unref_elements(element_list);
+       SAFE_G_LIST_FREE(element_list);
+       return ret;
 }
 
 static GstCaps *__make_encoded_caps_for_appsrc(webrtc_gst_slot_s *source)