webrtc_source: just move pad probe related APIs to webrtc_source_private.c 64/278464/2
authorhj kim <backto.kim@samsung.com>
Thu, 21 Jul 2022 01:29:04 +0000 (10:29 +0900)
committerhj kim <backto.kim@samsung.com>
Mon, 25 Jul 2022 05:02:49 +0000 (14:02 +0900)
[Version] 0.3.166
[Issue Type] Refactoring

Change-Id: I52dd7d78694645acf8da74d9ebfea60d9918c83d

include/webrtc_source_private.h
packaging/capi-media-webrtc.spec
src/webrtc_source.c
src/webrtc_source_private.c

index 48ec08e2ad18d6f52e99e68522e3bb7e6c9e5d8d..d2c332aa39986026a1c574a9a22f84295cf5c46a 100644 (file)
@@ -89,5 +89,11 @@ int _set_mediapacketsrc_codec_info(webrtc_s *webrtc, webrtc_gst_slot_s *source,
 int _get_screen_resolution(int *width, int *height);
 const char *_get_element_name(int av_idx, gst_element_e element);
 int _set_payload_type(webrtc_s *webrtc, webrtc_gst_slot_s *source, int av_idx, const gchar *media_type);
+GstPadProbeReturn _payloaded_data_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
+void _add_probe_to_pad_for_pause(webrtc_gst_slot_s *source, unsigned int idx, GstPad *pad, void *probe_cb);
+void _remove_probe_from_pad_for_pause(webrtc_gst_slot_s *source, unsigned int idx);
+GstPadProbeReturn _source_data_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
+void _add_probe_to_pad_for_render(webrtc_gst_slot_s *source, unsigned int idx, GstPad *pad, void *probe_cb);
+void _remove_probe_from_pad_for_render(webrtc_gst_slot_s *source, unsigned int idx);
 
 #endif /* __TIZEN_MEDIA_WEBRTC_SOURCE_COMMON_H__ */
index 506acd6d229d4dc403bbb584482c0a76bd4bbeec..b2df18c86e3dbecf4a2b14f5f7fa55bd22b79e12 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.3.165
+Version:    0.3.166
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 19c9ac1cf809d577903b107a764def5c6f8857dc..816b76c01f8a66ac2781c32ff30e218b88184586 100644 (file)
 #define MIN_DYNAMIC_PAYLOAD_TYPE             96
 #define MAX_DYNAMIC_PAYLOAD_TYPE             127
 
-typedef struct {
-       int av_idx;
-       webrtc_gst_slot_s *source;
-} probe_userdata_s;
-
 static direction_info_s __direction_info[] = {
        [WEBRTC_TRANSCEIVER_DIRECTION_SENDONLY] = { "SENDONLY", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY },
        [WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY] = { "RECVONLY", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY },
@@ -314,84 +309,6 @@ static void __return_payload_type(webrtc_s *webrtc, unsigned int payload_type)
        webrtc->payload_types ^= bitmask;
 }
 
-static GstPadProbeReturn __source_data_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
-{
-       probe_userdata_s *probe_data = (probe_userdata_s *)user_data;
-       GstBuffer *buffer;
-       GstElement *appsrc;
-       GstFlowReturn gst_ret = GST_FLOW_OK;
-
-       RET_VAL_IF(info == NULL, GST_PAD_PROBE_REMOVE, "info is NULL");
-       RET_VAL_IF(info->data == NULL, GST_PAD_PROBE_REMOVE, "info->data is NULL");
-       RET_VAL_IF(probe_data == NULL, GST_PAD_PROBE_REMOVE, "probe_data is NULL");
-       RET_VAL_IF(probe_data->source == NULL, GST_PAD_PROBE_REMOVE, "probe_data->source is NULL");
-
-       switch (probe_data->av_idx) {
-       case AV_IDX_AUDIO:
-               if (!probe_data->source->sound_stream_info.type)
-                       return GST_PAD_PROBE_OK;
-               break;
-       case AV_IDX_VIDEO:
-               if (!probe_data->source->display)
-                       return GST_PAD_PROBE_OK;
-               break;
-       default:
-               LOG_ERROR_IF_REACHED("av_idx(%d)", probe_data->av_idx);
-               return GST_PAD_PROBE_OK;
-       }
-
-       appsrc = probe_data->source->av[probe_data->av_idx].render.appsrc;
-       if (appsrc) {
-               buffer = gst_pad_probe_info_get_buffer(info);
-               LOG_VERBOSE("push buffer[%p] to the render pipeline, appsrc[%p]", buffer, appsrc);
-               g_signal_emit_by_name(G_OBJECT(appsrc), "push-buffer", buffer, &gst_ret, NULL);
-               if (gst_ret != GST_FLOW_OK)
-                       LOG_ERROR("failed to 'push-buffer', gst_ret[%d]", gst_ret);
-       }
-
-       return GST_PAD_PROBE_OK;
-}
-
-static void __add_probe_to_pad_for_render(webrtc_gst_slot_s *source, unsigned int idx, GstPad *pad, void *probe_cb)
-{
-       probe_userdata_s *probe_userdata;
-
-       RET_IF(source == NULL, "source is NULL");
-       RET_IF(idx >= AV_IDX_MAX, "invalid idx(%u)", idx);
-       RET_IF(pad == NULL, "pad is NULL");
-       RET_IF(probe_cb == NULL, "probe_cb is NULL");
-
-       probe_userdata = g_new0(probe_userdata_s, 1);
-       probe_userdata->source = source;
-       probe_userdata->av_idx = idx;
-       source->av[idx].render.src_pad = pad;
-       source->av[idx].render.src_pad_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
-                       probe_cb, probe_userdata, g_free);
-
-       LOG_DEBUG("source[id:%u, av_idx:%u] pad[%p] probe[id:%lu, callback:%p]",
-               source->id, idx, pad, source->av[idx].render.src_pad_probe_id, probe_cb);
-}
-
-static void __remove_probe_from_pad_for_render(webrtc_gst_slot_s *source, unsigned int idx)
-{
-       RET_IF(source == NULL, "source is NULL");
-       RET_IF(idx >= AV_IDX_MAX, "invalid idx(%u)", idx);
-
-       if (source->av[idx].render.src_pad_probe_id == 0)
-               return;
-
-       LOG_DEBUG("source[id:%u, av_idx:%u] pad[%p] probe_id[%lu]",
-               source->id, idx, source->av[idx].render.src_pad, source->av[idx].render.src_pad_probe_id);
-       gst_pad_remove_probe(source->av[idx].render.src_pad, source->av[idx].render.src_pad_probe_id);
-       source->av[idx].render.src_pad_probe_id = 0;
-       gst_object_unref(source->av[idx].render.src_pad);
-       source->av[idx].render.src_pad = NULL;
-       if (source->av[idx].render.appsrc_caps) {
-               gst_caps_unref(source->av[idx].render.appsrc_caps);
-               source->av[idx].render.appsrc_caps = NULL;
-       }
-}
-
 static GstElement * __prepare_encoder(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool is_audio)
 {
        GstElement *encoder = NULL;
@@ -449,71 +366,6 @@ static GstElement * __prepare_encoder(webrtc_s *webrtc, webrtc_gst_slot_s *sourc
        return encoder;
 }
 
-static GstPadProbeReturn __payloaded_data_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
-{
-       probe_userdata_s *probe_data = (probe_userdata_s *)user_data;
-       GstBuffer *buffer;
-       static unsigned int counts[AV_IDX_MAX] = { 0 };
-
-       RET_VAL_IF(info == NULL, GST_PAD_PROBE_REMOVE, "info is NULL");
-       RET_VAL_IF(info->data == NULL, GST_PAD_PROBE_REMOVE, "info->data is NULL");
-       RET_VAL_IF(probe_data == NULL, GST_PAD_PROBE_REMOVE, "probe_data is NULL");
-
-       buffer = gst_pad_probe_info_get_buffer(info);
-
-       if (probe_data->source->av[probe_data->av_idx].pause) {
-               if (counts[probe_data->av_idx]++ % 10 == 0)
-                       LOG_DEBUG("paused, drop [%s] buffer[%p] of pad[%p], source[%p], count[%u]",
-                               GET_MEDIA_TYPE_NAME(probe_data->av_idx == AV_IDX_AUDIO),
-                               buffer, pad, probe_data->source, counts[probe_data->av_idx]);
-               return GST_PAD_PROBE_DROP;
-       }
-
-       if (counts[probe_data->av_idx] > 0) {
-               counts[probe_data->av_idx] = 0;
-               LOG_DEBUG("play again, [%s] buffer[%p] of pad[%p], source[%p]",
-                       GET_MEDIA_TYPE_NAME(probe_data->av_idx == AV_IDX_AUDIO), buffer, pad, probe_data->source);
-       }
-
-       return GST_PAD_PROBE_OK;
-}
-
-static void __add_probe_to_pad_for_pause(webrtc_gst_slot_s *source, unsigned int idx, GstPad *pad, void *probe_cb)
-{
-       probe_userdata_s *probe_userdata;
-
-       RET_IF(source == NULL, "source is NULL");
-       RET_IF(idx >= AV_IDX_MAX, "invalid idx(%u)", idx);
-       RET_IF(pad == NULL, "pad is NULL");
-       RET_IF(probe_cb == NULL, "probe_cb is NULL");
-
-       probe_userdata = g_new0(probe_userdata_s, 1);
-       probe_userdata->source = source;
-       probe_userdata->av_idx = idx;
-       source->av[idx].src_pad = pad;
-       source->av[idx].src_pad_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
-                       probe_cb, probe_userdata, g_free);
-
-       LOG_DEBUG("source[id:%u, av_idx:%u] pad[%p] probe[id:%lu, callback:%p]",
-               source->id, idx, pad, source->av[idx].src_pad_probe_id, probe_cb);
-}
-
-static void __remove_probe_from_pad_for_pause(webrtc_gst_slot_s *source, unsigned int idx)
-{
-       RET_IF(source == NULL, "source is NULL");
-       RET_IF(idx >= AV_IDX_MAX, "invalid idx(%u)", idx);
-
-       if (source->av[idx].src_pad_probe_id == 0)
-               return;
-
-       LOG_DEBUG("source[id:%u, av_idx:%u] pad[%p] probe_id[%lu]",
-               source->id, idx, source->av[idx].src_pad, source->av[idx].src_pad_probe_id);
-       gst_pad_remove_probe(source->av[idx].src_pad, source->av[idx].src_pad_probe_id);
-       gst_element_remove_pad(GST_ELEMENT(source->bin), source->av[idx].src_pad);
-       source->av[idx].src_pad_probe_id = 0;
-       source->av[idx].src_pad = NULL;
-}
-
 static bool __link_switch_srcs(GstElement *switch_element, GList *switch_src_list)
 {
        GstElement *element;
@@ -742,7 +594,7 @@ int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool
                        }
 
                        source->av[idx].render.need_decoding = true;
-                       __add_probe_to_pad_for_render(source, idx, gst_element_get_static_pad(capsfilter, "src"), __source_data_probe_cb);
+                       _add_probe_to_pad_for_render(source, idx, gst_element_get_static_pad(capsfilter, "src"), _source_data_probe_cb);
 
                        goto skip_encoder;
                }
@@ -755,7 +607,7 @@ int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool
                                g_object_set(G_OBJECT(source->av[idx].render.appsrc), "caps", sink_caps, NULL);
                }
 
-               __add_probe_to_pad_for_render(source, idx, gst_element_get_static_pad(capsfilter, "src"), __source_data_probe_cb);
+               _add_probe_to_pad_for_render(source, idx, gst_element_get_static_pad(capsfilter, "src"), _source_data_probe_cb);
        }
 
        if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_SCREEN && !source->zerocopy_enabled) {
@@ -766,7 +618,7 @@ int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool
 
        encoder = __prepare_encoder(webrtc, source, is_audio);
        if (encoder == NULL) {
-               __remove_probe_from_pad_for_render(source, idx);
+               _remove_probe_from_pad_for_render(source, idx);
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
        APPEND_ELEMENT(*element_list, encoder);
@@ -804,7 +656,7 @@ skip_encoder:
        return WEBRTC_ERROR_NONE;
 
 error:
-       __remove_probe_from_pad_for_render(source, idx);
+       _remove_probe_from_pad_for_render(source, idx);
        g_free(media_type);
 
        return WEBRTC_ERROR_INVALID_OPERATION;
@@ -893,7 +745,7 @@ static int __complete_rest_of_videosrc(webrtc_s *webrtc, webrtc_gst_slot_s *sour
        if (__link_source_with_webrtcbin(source, webrtc->gst.webrtcbin) != WEBRTC_ERROR_NONE)
                goto exit_with_remove_from_bin;
 
-       __add_probe_to_pad_for_pause(source, AV_IDX_VIDEO, source->av[AV_IDX_VIDEO].src_pad, __payloaded_data_probe_cb);
+       _add_probe_to_pad_for_pause(source, AV_IDX_VIDEO, source->av[AV_IDX_VIDEO].src_pad, _payloaded_data_probe_cb);
 
        SAFE_G_LIST_FREE(element_list);
 
@@ -1007,7 +859,7 @@ static int __complete_rest_of_audiosrc(webrtc_s *webrtc, webrtc_gst_slot_s *sour
        if (__link_source_with_webrtcbin(source, webrtc->gst.webrtcbin) != WEBRTC_ERROR_NONE)
                goto exit_with_remove_from_bin;
 
-       __add_probe_to_pad_for_pause(source, AV_IDX_AUDIO, source->av[AV_IDX_AUDIO].src_pad, __payloaded_data_probe_cb);
+       _add_probe_to_pad_for_pause(source, AV_IDX_AUDIO, source->av[AV_IDX_AUDIO].src_pad, _payloaded_data_probe_cb);
 
        SAFE_G_LIST_FREE(element_list);
 
@@ -1302,7 +1154,7 @@ static int __build_filesrc_bin(webrtc_gst_slot_s *source, media_type_e media_typ
        if (_set_ghost_pad_target(src_pad, capsfilter, true) != WEBRTC_ERROR_NONE)
                goto exit_with_remove_from_bin;
 
-       __add_probe_to_pad_for_pause(source, av_idx, src_pad, __payloaded_data_probe_cb);
+       _add_probe_to_pad_for_pause(source, av_idx, src_pad, _payloaded_data_probe_cb);
 
        SAFE_G_LIST_FREE(element_list);
 
@@ -1663,7 +1515,7 @@ static void __filesrc_pipeline_decodebin_pad_added_cb(GstElement *element, GstPa
 
        source->av[av_idx].render.need_decoding = true;
        source->av[av_idx].render.appsrc_caps = gst_pad_get_current_caps(pad);
-       __add_probe_to_pad_for_render(source, av_idx, gst_element_get_static_pad(queue, "src"), __source_data_probe_cb);
+       _add_probe_to_pad_for_render(source, av_idx, gst_element_get_static_pad(queue, "src"), _source_data_probe_cb);
 
        GENERATE_DOT(source->webrtc, source->filesrc_pipeline, "%s.%s-%s",
                GST_ELEMENT_NAME(source->filesrc_pipeline), GST_ELEMENT_NAME(element), GST_PAD_NAME(pad));
@@ -1925,8 +1777,8 @@ void _source_slot_destroy_cb(gpointer data)
                gst_element_foreach_src_pad(GST_ELEMENT(source->bin), __foreach_src_pad_cb, source);
 
        for (i = 0; i < AV_IDX_MAX; i++) {
-               __remove_probe_from_pad_for_pause(source, i);
-               __remove_probe_from_pad_for_render(source, i);
+               _remove_probe_from_pad_for_pause(source, i);
+               _remove_probe_from_pad_for_render(source, i);
 
                if (source->av[i].pt > 0)
                        __return_payload_type(source->webrtc, source->av[i].pt);
@@ -2899,8 +2751,8 @@ static void __release_filesrc_resources(webrtc_gst_slot_s *source)
                if (source->av[av_idx].src_pad_probe_id == 0)
                        continue;
 
-               __remove_probe_from_pad_for_pause(source, av_idx);
-               __remove_probe_from_pad_for_render(source, av_idx);
+               _remove_probe_from_pad_for_pause(source, av_idx);
+               _remove_probe_from_pad_for_render(source, av_idx);
 
                if (source->av[av_idx].pt > 0)
                        __return_payload_type(source->webrtc, source->av[av_idx].pt);
index 2560d940ff958cbde2b9c91bcf3e8d7d9a3749e4..2e9d453e5302e93617bedcec553a1c70547b2938 100644 (file)
 #include "webrtc_private.h"
 #include "webrtc_source_private.h"
 
+typedef struct {
+       int av_idx;
+       webrtc_gst_slot_s *source;
+} probe_userdata_s;
+
 const char *_get_audio_format_name(media_format_mimetype_e mime_type)
 {
        switch (mime_type) {
@@ -413,3 +418,146 @@ out:
 
        return WEBRTC_ERROR_NONE;
 }
+
+GstPadProbeReturn _payloaded_data_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
+{
+       probe_userdata_s *probe_data = (probe_userdata_s *)user_data;
+       GstBuffer *buffer;
+       static unsigned int counts[AV_IDX_MAX] = { 0 };
+
+       RET_VAL_IF(info == NULL, GST_PAD_PROBE_REMOVE, "info is NULL");
+       RET_VAL_IF(info->data == NULL, GST_PAD_PROBE_REMOVE, "info->data is NULL");
+       RET_VAL_IF(probe_data == NULL, GST_PAD_PROBE_REMOVE, "probe_data is NULL");
+
+       buffer = gst_pad_probe_info_get_buffer(info);
+
+       if (probe_data->source->av[probe_data->av_idx].pause) {
+               if (counts[probe_data->av_idx]++ % 10 == 0)
+                       LOG_DEBUG("paused, drop [%s] buffer[%p] of pad[%p], source[%p], count[%u]",
+                               GET_MEDIA_TYPE_NAME(probe_data->av_idx == AV_IDX_AUDIO),
+                               buffer, pad, probe_data->source, counts[probe_data->av_idx]);
+               return GST_PAD_PROBE_DROP;
+       }
+
+       if (counts[probe_data->av_idx] > 0) {
+               counts[probe_data->av_idx] = 0;
+               LOG_DEBUG("play again, [%s] buffer[%p] of pad[%p], source[%p]",
+                       GET_MEDIA_TYPE_NAME(probe_data->av_idx == AV_IDX_AUDIO), buffer, pad, probe_data->source);
+       }
+
+       return GST_PAD_PROBE_OK;
+}
+
+void _add_probe_to_pad_for_pause(webrtc_gst_slot_s *source, unsigned int idx, GstPad *pad, void *probe_cb)
+{
+       probe_userdata_s *probe_userdata;
+
+       RET_IF(source == NULL, "source is NULL");
+       RET_IF(idx >= AV_IDX_MAX, "invalid idx(%u)", idx);
+       RET_IF(pad == NULL, "pad is NULL");
+       RET_IF(probe_cb == NULL, "probe_cb is NULL");
+
+       probe_userdata = g_new0(probe_userdata_s, 1);
+       probe_userdata->source = source;
+       probe_userdata->av_idx = idx;
+       source->av[idx].src_pad = pad;
+       source->av[idx].src_pad_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
+                       probe_cb, probe_userdata, g_free);
+
+       LOG_DEBUG("source[id:%u, av_idx:%u] pad[%p] probe[id:%lu, callback:%p]",
+               source->id, idx, pad, source->av[idx].src_pad_probe_id, probe_cb);
+}
+
+void _remove_probe_from_pad_for_pause(webrtc_gst_slot_s *source, unsigned int idx)
+{
+       RET_IF(source == NULL, "source is NULL");
+       RET_IF(idx >= AV_IDX_MAX, "invalid idx(%u)", idx);
+
+       if (source->av[idx].src_pad_probe_id == 0)
+               return;
+
+       LOG_DEBUG("source[id:%u, av_idx:%u] pad[%p] probe_id[%lu]",
+               source->id, idx, source->av[idx].src_pad, source->av[idx].src_pad_probe_id);
+       gst_pad_remove_probe(source->av[idx].src_pad, source->av[idx].src_pad_probe_id);
+       gst_element_remove_pad(GST_ELEMENT(source->bin), source->av[idx].src_pad);
+       source->av[idx].src_pad_probe_id = 0;
+       source->av[idx].src_pad = NULL;
+}
+
+GstPadProbeReturn _source_data_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
+{
+       probe_userdata_s *probe_data = (probe_userdata_s *)user_data;
+       GstBuffer *buffer;
+       GstElement *appsrc;
+       GstFlowReturn gst_ret = GST_FLOW_OK;
+
+       RET_VAL_IF(info == NULL, GST_PAD_PROBE_REMOVE, "info is NULL");
+       RET_VAL_IF(info->data == NULL, GST_PAD_PROBE_REMOVE, "info->data is NULL");
+       RET_VAL_IF(probe_data == NULL, GST_PAD_PROBE_REMOVE, "probe_data is NULL");
+       RET_VAL_IF(probe_data->source == NULL, GST_PAD_PROBE_REMOVE, "probe_data->source is NULL");
+
+       switch (probe_data->av_idx) {
+       case AV_IDX_AUDIO:
+               if (!probe_data->source->sound_stream_info.type)
+                       return GST_PAD_PROBE_OK;
+               break;
+       case AV_IDX_VIDEO:
+               if (!probe_data->source->display)
+                       return GST_PAD_PROBE_OK;
+               break;
+       default:
+               LOG_ERROR_IF_REACHED("av_idx(%d)", probe_data->av_idx);
+               return GST_PAD_PROBE_OK;
+       }
+
+       appsrc = probe_data->source->av[probe_data->av_idx].render.appsrc;
+       if (appsrc) {
+               buffer = gst_pad_probe_info_get_buffer(info);
+               LOG_VERBOSE("push buffer[%p] to the render pipeline, appsrc[%p]", buffer, appsrc);
+               g_signal_emit_by_name(G_OBJECT(appsrc), "push-buffer", buffer, &gst_ret, NULL);
+               if (gst_ret != GST_FLOW_OK)
+                       LOG_ERROR("failed to 'push-buffer', gst_ret[%d]", gst_ret);
+       }
+
+       return GST_PAD_PROBE_OK;
+}
+
+void _add_probe_to_pad_for_render(webrtc_gst_slot_s *source, unsigned int idx, GstPad *pad, void *probe_cb)
+{
+       probe_userdata_s *probe_userdata;
+
+       RET_IF(source == NULL, "source is NULL");
+       RET_IF(idx >= AV_IDX_MAX, "invalid idx(%u)", idx);
+       RET_IF(pad == NULL, "pad is NULL");
+       RET_IF(probe_cb == NULL, "probe_cb is NULL");
+
+       probe_userdata = g_new0(probe_userdata_s, 1);
+       probe_userdata->source = source;
+       probe_userdata->av_idx = idx;
+       source->av[idx].render.src_pad = pad;
+       source->av[idx].render.src_pad_probe_id = gst_pad_add_probe(pad, GST_PAD_PROBE_TYPE_BUFFER,
+                       probe_cb, probe_userdata, g_free);
+
+       LOG_DEBUG("source[id:%u, av_idx:%u] pad[%p] probe[id:%lu, callback:%p]",
+               source->id, idx, pad, source->av[idx].render.src_pad_probe_id, probe_cb);
+}
+
+void _remove_probe_from_pad_for_render(webrtc_gst_slot_s *source, unsigned int idx)
+{
+       RET_IF(source == NULL, "source is NULL");
+       RET_IF(idx >= AV_IDX_MAX, "invalid idx(%u)", idx);
+
+       if (source->av[idx].render.src_pad_probe_id == 0)
+               return;
+
+       LOG_DEBUG("source[id:%u, av_idx:%u] pad[%p] probe_id[%lu]",
+               source->id, idx, source->av[idx].render.src_pad, source->av[idx].render.src_pad_probe_id);
+       gst_pad_remove_probe(source->av[idx].render.src_pad, source->av[idx].render.src_pad_probe_id);
+       source->av[idx].render.src_pad_probe_id = 0;
+       gst_object_unref(source->av[idx].render.src_pad);
+       source->av[idx].render.src_pad = NULL;
+       if (source->av[idx].render.appsrc_caps) {
+               gst_caps_unref(source->av[idx].render.appsrc_caps);
+               source->av[idx].render.appsrc_caps = NULL;
+       }
+}