Add new API set for media packet source 15/249715/12
authorSangchul Lee <sc11.lee@samsung.com>
Wed, 16 Dec 2020 08:30:18 +0000 (17:30 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Wed, 6 Jan 2021 02:46:45 +0000 (11:46 +0900)
Enumeration is added as below.
 - WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_UNDERFLOW
 - WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_OVERFLOW

Functions are added as below.
 - webrtc_media_packet_source_set_format()
 - webrtc_media_packet_source_push_packet()
 - webrtc_media_packet_source_set_buffer_state_changed_cb()
 - webrtc_media_packet_source_unset_buffer_state_changed_cb()

[Version] 0.1.76
[Issue Type] API

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

index aa700fd05f11ac892c15768138914e58e78b3e31..b2e5f25c8da5a2b6686aacf489ff68b6f5fa7ae5 100644 (file)
@@ -18,6 +18,8 @@
 #define __TIZEN_MEDIA_WEBRTC_H__
 
 #include <tizen.h>
+#include <media_format.h>
+#include <media_packet.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -102,6 +104,15 @@ typedef enum {
        WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET /**<  Media packet */
 } webrtc_media_source_type_e;
 
+/**
+ * @brief Enumeration for buffer state type of media packet source.
+ * @since_tizen 6.5
+ */
+typedef enum {
+       WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_UNDERFLOW,     /**< Buffer underflow */
+       WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_OVERFLOW,      /**< Buffer overflow */
+} webrtc_media_packet_source_buffer_state_e;
+
 /**
  * @brief Enumeration for WebRTC media type.
  * @since_tizen 6.5
@@ -171,6 +182,17 @@ typedef void (*webrtc_error_cb)(webrtc_h webrtc, webrtc_error_e error, webrtc_st
  */
 typedef void (*webrtc_state_changed_cb)(webrtc_h webrtc, webrtc_state_e previous, webrtc_state_e current, void *user_data);
 
+/**
+ * @brief Called when the buffer state of media packet source is changed.
+ * @since_tizen 6.5
+ * @param[in] source_id  The media source id
+ * @param[in] state      The buffer state (underflow or overflow)
+ * @param[in] user_data  The user data passed from the callback registration function
+ * @see webrtc_media_packet_source_set_buffer_state_changed_cb()
+ * @see webrtc_media_packet_source_unset_buffer_state_changed_cb()
+ */
+typedef void (*webrtc_media_packet_source_buffer_state_changed_cb)(unsigned int source_id, webrtc_media_packet_source_buffer_state_e state, void *user_data);
+
 /**
  * @brief Called when the WebRTC needs session negotiation.
  * @since_tizen 6.5
@@ -370,6 +392,7 @@ int webrtc_create(webrtc_h *webrtc);
  * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
  * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
  * @pre webrtc_ice_candidate_cb() must be set by calling webrtc_set_ice_candidate_cb().
+ * @pre webrtc_media_packet_source_set_format() must be set by calling webrtc_set_ice_candidate_cb().
  * @pre @a webrtc state must be set to #WEBRTC_STATE_IDLE.
  * @post @a webrtc state will be #WEBRTC_STATE_NEGOTIATING.
  * @see webrtc_create()
@@ -456,6 +479,78 @@ int webrtc_add_media_source(webrtc_h webrtc, webrtc_media_source_type_e type, un
  */
 int webrtc_remove_media_source(webrtc_h webrtc, unsigned int source_id);
 
+/**
+ * @brief Sets a callback function to be invoked when the buffer state of media packet source is changed.
+ * @since_tizen 6.5
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] source_id   The media packet source id
+ * @param[in] callback    Callback function pointer
+ * @param[in] user_data   The user data to be passed to the callback function
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @pre Add media packet source to @a webrtc to get @a source_id by calling webrtc_add_media_source().
+ * @post webrtc_media_packet_source_buffer_state_changed_cb() will be invoked.
+ * @see webrtc_media_packet_source_push_packet()
+ * @see webrtc_media_packet_source_unset_buffer_state_changed_cb()
+ * @see webrtc_media_packet_source_buffer_state_changed_cb()
+ */
+int webrtc_media_packet_source_set_buffer_state_changed_cb(webrtc_h webrtc, unsigned int source_id, webrtc_media_packet_source_buffer_state_changed_cb callback, void *user_data);
+
+/**
+ * @brief Unsets the buffer state changed callback function.
+ * @since_tizen 6.5
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] source_id   The media packet source id
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @pre Add media packet source to @a webrtc to get @a source_id by calling webrtc_add_media_source().
+ * @see webrtc_media_packet_source_set_buffer_state_changed_cb()
+ */
+int webrtc_media_packet_source_unset_buffer_state_changed_cb(webrtc_h webrtc, unsigned int source_id);
+
+/**
+ * @brief Sets media format to the media packet source.
+ * @since_tizen 6.5
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] source_id   The media packet source id
+ * @param[in] format      The media format
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
+ * @pre Add media packet source to @a webrtc to get @a source_id by calling webrtc_add_media_source().
+ * @pre @a webrtc state must be set to #WEBRTC_STATE_IDLE.
+ * @see webrtc_media_packet_source_push_packet()
+ * @see webrtc_media_packet_source_set_buffer_state_changed_cb()
+ */
+int webrtc_media_packet_source_set_format(webrtc_h webrtc, unsigned int source_id, media_format_h format);
+
+/**
+ * @brief Pushes media packet to the media packet source.
+ * @since_tizen 6.5
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] source_id   The media packet source id
+ * @param[in] packet      The media packet
+ * @return @c 0 on success,
+ *         otherwise a negative error value
+ * @retval #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation
+ * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
+ * @pre Add media packet source to @a webrtc to get @a source_id by calling webrtc_add_media_source().
+ * @pre @a webrtc state must be set to #WEBRTC_STATE_NEGOTIATING or #WEBRTC_STATE_PLAYING.
+ * @see webrtc_media_packet_source_set_format()
+ * @see webrtc_media_packet_source_set_buffer_state_changed_cb()
+ */
+int webrtc_media_packet_source_push_packet(webrtc_h webrtc, unsigned int source_id, media_packet_h packet);
+
 /**
  * @brief Gets the transceiver direction of the media source with specified media type.
  * @since_tizen 6.5
index c53acdbd9ff63141f27393d745248e4a81af9af4..96580831f4e597b675da23967abadbe6e0b7289f 100644 (file)
@@ -249,6 +249,7 @@ typedef struct _webrtc_gst_slot_s {
        int media_types;    /* values of media_type_e combined with bitwise 'or' */
        int mlines[2];      /* index 0 for audio, 1 for video */
        media_format_h media_format;
+       webrtc_callbacks_s buffer_state_changed_cb;
 
        webrtc_display_s *display;
 } webrtc_gst_slot_s;
@@ -331,6 +332,8 @@ int _gst_pipeline_set_state(webrtc_s *webrtc, GstState state);
 int _add_media_source(webrtc_s *webrtc, webrtc_media_source_type_e type, unsigned int *source_id);
 int _remove_media_source(webrtc_s *webrtc, unsigned int source_id);
 int _set_media_format(webrtc_s *webrtc, unsigned int source_id, media_format_h format);
+bool _check_if_format_is_set_to_packet_sources(webrtc_s *webrtc);
+int _push_media_packet(webrtc_s *webrtc, unsigned int source_id, media_packet_h packet);
 int _get_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction);
 int _set_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction);
 void _post_state_in_idle(webrtc_s *webrtc, webrtc_state_e new_state);
index b1b1bcfcd9138b9872d0b0c56afcc7e1036d1991..105313e96c40eff1dcb699a508aea8feaf7f76ef 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.1.75
+Version:    0.1.76
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index a09aa211b299ec3c3ed73c36e3e99983d78981ff..8c2c0b34ea0160406749e3af4a8c0f77fbf03ac9 100644 (file)
@@ -174,6 +174,7 @@ int webrtc_start(webrtc_h webrtc)
        RET_VAL_WITH_UNLOCK_IF(_webrtc->ice_candidate_cb.callback == NULL, WEBRTC_ERROR_INVALID_OPERATION, &_webrtc->mutex, "the ice candidate callback should be set");
        RET_VAL_WITH_UNLOCK_IF(_webrtc->state != WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should be IDLE");
        RET_VAL_WITH_UNLOCK_IF(_webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, &_webrtc->mutex, "webrtcbin is NULL");
+       RET_VAL_WITH_UNLOCK_IF(!_check_if_format_is_set_to_packet_sources(_webrtc), WEBRTC_ERROR_INVALID_OPERATION, &_webrtc->mutex, "the media format should be set");
 
        _gst_pipeline_set_state(webrtc, GST_STATE_PLAYING);
        _webrtc->pend_state = WEBRTC_STATE_NEGOTIATING;
@@ -193,7 +194,7 @@ int webrtc_stop(webrtc_h webrtc)
 
        g_mutex_lock(&_webrtc->mutex);
 
-       RET_VAL_WITH_UNLOCK_IF(_webrtc->state == WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should not be IDLE");
+       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_NULL);
 
@@ -267,6 +268,100 @@ int webrtc_remove_media_source(webrtc_h webrtc, unsigned int source_id)
        return ret;
 }
 
+int webrtc_media_packet_source_set_buffer_state_changed_cb(webrtc_h webrtc, unsigned int source_id, webrtc_media_packet_source_buffer_state_changed_cb callback, void *user_data)
+{
+       webrtc_s *_webrtc = (webrtc_s*)webrtc;
+       webrtc_gst_slot_s *source;
+
+       RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0");
+       RET_VAL_IF(callback == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "callback is NULL");
+
+       g_mutex_lock(&_webrtc->mutex);
+
+       RET_VAL_WITH_UNLOCK_IF((source = _get_slot_by_id(_webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER,
+               &_webrtc->mutex, "source is NULL");
+       RET_VAL_WITH_UNLOCK_IF(source->type != WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET, WEBRTC_ERROR_INVALID_PARAMETER, &_webrtc->mutex,
+               "source is not media packet type");
+
+       source->buffer_state_changed_cb.callback = callback;
+       source->buffer_state_changed_cb.user_data = user_data;
+
+       LOG_INFO("callback[%p] user_data[%p]", callback, user_data);
+
+       g_mutex_unlock(&_webrtc->mutex);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_media_packet_source_unset_buffer_state_changed_cb(webrtc_h webrtc, unsigned int source_id)
+{
+       webrtc_s *_webrtc = (webrtc_s*)webrtc;
+       webrtc_gst_slot_s *source;
+
+       RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0");
+
+       g_mutex_lock(&_webrtc->mutex);
+
+       RET_VAL_WITH_UNLOCK_IF((source = _get_slot_by_id(_webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER,
+               &_webrtc->mutex, "source is NULL");
+       RET_VAL_WITH_UNLOCK_IF(source->type != WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET, WEBRTC_ERROR_INVALID_PARAMETER, &_webrtc->mutex,
+               "source is not media packet type");
+       RET_VAL_WITH_UNLOCK_IF(source->buffer_state_changed_cb.callback == NULL, WEBRTC_ERROR_INVALID_OPERATION, &_webrtc->mutex,\
+               "callback was not set");
+
+       LOG_INFO("callback[%p] user_data[%p] is reset to NULL",
+               source->buffer_state_changed_cb.callback, source->buffer_state_changed_cb.user_data);
+
+       source->buffer_state_changed_cb.callback = NULL;
+       source->buffer_state_changed_cb.user_data = NULL;
+
+       g_mutex_unlock(&_webrtc->mutex);
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int webrtc_media_packet_source_set_format(webrtc_h webrtc, unsigned int source_id, media_format_h format)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       webrtc_s *_webrtc = (webrtc_s*)webrtc;
+
+       RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(format == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "format is NULL");
+
+       g_mutex_lock(&_webrtc->mutex);
+
+       RET_VAL_WITH_UNLOCK_IF(_webrtc->state != WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should be IDLE");
+
+       ret = _set_media_format(_webrtc, source_id, format);
+       if (ret == WEBRTC_ERROR_NONE)
+               LOG_INFO("source_id[%u] format[%p]", source_id, format);
+
+       g_mutex_unlock(&_webrtc->mutex);
+
+       return ret;
+}
+
+int webrtc_media_packet_source_push_packet(webrtc_h webrtc, unsigned int source_id, media_packet_h packet)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       webrtc_s *_webrtc = (webrtc_s*)webrtc;
+
+       RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(packet == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "packet is NULL");
+
+       g_mutex_lock(&_webrtc->mutex);
+
+       RET_VAL_WITH_UNLOCK_IF(_webrtc->state == WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should NOT be IDLE");
+
+       ret = _push_media_packet(webrtc, source_id, packet);
+
+       g_mutex_unlock(&_webrtc->mutex);
+
+       return ret;
+}
+
 int webrtc_get_transceiver_direction(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction)
 {
        int ret = WEBRTC_ERROR_NONE;
@@ -470,7 +565,7 @@ int webrtc_set_track_added_cb(webrtc_h webrtc, webrtc_track_added_cb callback, v
 
        g_mutex_lock(&_webrtc->mutex);
 
-       RET_VAL_WITH_UNLOCK_IF(_webrtc->state == WEBRTC_STATE_PLAYING, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should not be PLAYING");
+       RET_VAL_WITH_UNLOCK_IF(_webrtc->state == WEBRTC_STATE_PLAYING, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should NOT be PLAYING");
 
        _webrtc->track_added_cb.callback = callback;
        _webrtc->track_added_cb.user_data = user_data;
index 176c8c0b1adc47394a89eff3f0a4e375082c432f..51ceeed1a1c098724ac272648eb94414ae5652ce 100644 (file)
@@ -16,6 +16,7 @@
 
 #include "webrtc.h"
 #include "webrtc_private.h"
+#include <tbm_surface_internal.h>
 
 #define GST_KLASS_NAME_ENCODER_AUDIO   "Codec/Encoder/Audio"
 #define GST_KLASS_NAME_ENCODER_VIDEO   "Codec/Encoder/Video"
@@ -809,6 +810,17 @@ static void _appsrc_need_data_cb(GstElement *appsrc, guint size, gpointer data)
        RET_IF(source == NULL, "source is NULL");
 
        LOG_INFO("appsrc[%s] size[%u] source[%p, idx:%u]", GST_ELEMENT_NAME(appsrc), size, source, source->id);
+
+       if (source->buffer_state_changed_cb.callback == NULL) {
+               LOG_DEBUG("buffer state changed callback is NULL");
+               return;
+       }
+
+       LOG_DEBUG(">>> invoke buffer_state_changed_cb[%p] for UNDERFLOW, user_data[%p]",
+               source->buffer_state_changed_cb.callback, source->buffer_state_changed_cb.user_data);
+       ((webrtc_media_packet_source_buffer_state_changed_cb)(source->buffer_state_changed_cb.callback))
+               (source->id, WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_UNDERFLOW, source->buffer_state_changed_cb.user_data);
+       LOG_DEBUG("<<< end of the callback");
 }
 
 static void _appsrc_enough_data_cb(GstElement *appsrc, gpointer data)
@@ -818,6 +830,17 @@ static void _appsrc_enough_data_cb(GstElement *appsrc, gpointer data)
        RET_IF(source == NULL, "source is NULL");
 
        LOG_INFO("appsrc[%s] source[%p, idx:%u]", GST_ELEMENT_NAME(appsrc), source, source->id);
+
+       if (source->buffer_state_changed_cb.callback == NULL) {
+               LOG_DEBUG("buffer state changed callback is NULL");
+               return;
+       }
+
+       LOG_DEBUG(">>> invoke buffer_state_changed_cb[%p] for OVERFLOW, user_data[%p]",
+               source->buffer_state_changed_cb.callback, source->buffer_state_changed_cb.user_data);
+       ((webrtc_media_packet_source_buffer_state_changed_cb)(source->buffer_state_changed_cb.callback))
+               (source->id, WEBRTC_MEDIA_PACKET_SOURCE_BUFFER_STATE_OVERFLOW, source->buffer_state_changed_cb.user_data);
+       LOG_DEBUG("<<< end of the callback");
 }
 
 static int __build_mediapacketsrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
@@ -832,7 +855,8 @@ static int __build_mediapacketsrc(webrtc_s *webrtc, webrtc_gst_slot_s *source)
                LOG_ERROR("failed to create appsrc");
                return WEBRTC_ERROR_INVALID_OPERATION;
        }
-       g_object_set(G_OBJECT(appsrc), "emit-signals", TRUE, "is-live", TRUE, NULL);
+
+       g_object_set(G_OBJECT(appsrc), "emit-signals", TRUE, "is-live", TRUE, "format", 3, NULL); /* format 3 for time format of the segment events and seek */
 
        _connect_and_append_signal(&source->signals, G_OBJECT(appsrc), "need-data", G_CALLBACK(_appsrc_need_data_cb), source);
        _connect_and_append_signal(&source->signals, G_OBJECT(appsrc), "enough-data", G_CALLBACK(_appsrc_enough_data_cb), source);
@@ -1198,5 +1222,163 @@ int _set_media_format(webrtc_s *webrtc, unsigned int source_id, media_format_h f
                return ret;
        }
 
+       return WEBRTC_ERROR_NONE;
+}
+
+static gboolean __check_format_is_not_set_cb(gpointer key, gpointer value, gpointer user_data)
+{
+       webrtc_gst_slot_s *source = value;
+
+       if (source->type == GPOINTER_TO_UINT(user_data)) {
+               LOG_INFO("found media packet source[%p, id:%u, media_format:%p]", source, source->id, source->media_format);
+               if (!source->media_format)
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+bool _check_if_format_is_set_to_packet_sources(webrtc_s *webrtc)
+{
+       webrtc_gst_slot_s *source;
+
+       RET_VAL_IF(webrtc == NULL, false, "webrtc is NULL");
+
+       source = g_hash_table_find(webrtc->gst.source_slots, __check_format_is_not_set_cb, GUINT_TO_POINTER(WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET));
+       if (source) {
+               LOG_ERROR("media format is not set to the media packet source[%u]", source->id);
+               return false;
+       }
+
+       return true;
+}
+
+static int __fill_gst_buffer_mapped_data_from_packet(GstBuffer *buffer, media_packet_h packet)
+{
+       bool has_tbm_surface = false;
+       tbm_surface_info_s ts_info;
+       guint64 size = 0;
+       GstMapInfo buff_info = GST_MAP_INFO_INIT;
+
+       RET_VAL_IF(buffer == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "buffer is NULL");
+       RET_VAL_IF(packet == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "packet is NULL");
+
+       media_packet_get_buffer_size(packet, &size);
+       media_packet_has_tbm_surface_buffer(packet, &has_tbm_surface);
+
+       if (has_tbm_surface) {
+               int ret = TBM_SURFACE_ERROR_NONE;
+               tbm_surface_h ts;
+
+               media_packet_get_tbm_surface(packet, &ts);
+               ret = tbm_surface_get_info(ts, &ts_info);
+               if (ret != TBM_SURFACE_ERROR_NONE) {
+                       LOG_ERROR("failed to tbm_surface_get_info()");
+                       return WEBRTC_ERROR_INVALID_OPERATION;
+               }
+
+               LOG_DEBUG("tbm surface[%p, %ux%u, size:%u, format:%u, num_planes:%u] found",
+                       ts, ts_info.width, ts_info.height, ts_info.size, ts_info.format, ts_info.num_planes);
+       }
+
+       if (gst_buffer_map(buffer, &buff_info, GST_MAP_READWRITE)) {
+               if (has_tbm_surface) {
+                       int i;
+                       guint8 *ptr = buff_info.data;
+                       for (i = 0; i < ts_info.num_planes; i++) {
+                               LOG_DEBUG("plane[%d][ptr:%p size:%u]", i, ts_info.planes[i].ptr, ts_info.planes[i].size);
+                               memcpy(ptr, ts_info.planes[i].ptr, ts_info.planes[i].size);
+                               ptr += ts_info.planes[i].size;
+                       }
+
+               } else {
+                       guchar *data_ptr;
+                       media_packet_get_buffer_data_ptr(packet, (void **)&data_ptr);
+                       if (data_ptr == NULL) {
+                               LOG_ERROR("invalid packet, data_ptr is NULL");
+                               gst_buffer_unmap(buffer, &buff_info);
+                               return WEBRTC_ERROR_INVALID_OPERATION;
+                       }
+                       memcpy(buff_info.data, data_ptr, size);
+               }
+
+               buff_info.size = size;
+
+               LOG_DEBUG("buffer[%p], buff_info[data:%p, size:%u]", buffer, buff_info.data, buff_info.size);
+
+               gst_buffer_unmap(buffer, &buff_info);
+       }
+
+       return WEBRTC_ERROR_NONE;
+}
+
+int _push_media_packet(webrtc_s *webrtc, unsigned int source_id, media_packet_h packet)
+{
+       int ret = WEBRTC_ERROR_NONE;
+       webrtc_gst_slot_s *source;
+       guchar *data_ptr;
+       GstElement *appsrc;
+       GstBuffer *new_buffer;
+       guint64 pts = 0;
+       guint64 duration = 0;
+       guint64 size = 0;
+       GstFlowReturn gst_ret = GST_FLOW_OK;
+
+       RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0");
+       RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "could not find source");
+       RET_VAL_IF(source->media_format == NULL, WEBRTC_ERROR_INVALID_OPERATION, "media_format is NULL");
+
+       appsrc = __find_element_in_bin(source->bin, "appsrc");
+       if (appsrc == NULL) {
+               LOG_ERROR("source_id[%u] is not for media packet source", source_id);
+               return WEBRTC_ERROR_INVALID_PARAMETER;
+       }
+
+       if (packet == NULL) {
+               LOG_INFO("packet is NULL, emit EOS signal");
+               g_signal_emit_by_name(G_OBJECT(appsrc), "end-of-stream", &gst_ret, NULL);
+               if (gst_ret != GST_FLOW_OK) {
+                       LOG_ERROR("failed to 'end-of-stream', gst_ret[0x%x]", gst_ret);
+                       return WEBRTC_ERROR_INVALID_OPERATION;
+               }
+               return WEBRTC_ERROR_NONE;
+       }
+
+       media_packet_get_buffer_data_ptr(packet, (void **)&data_ptr);
+       if (data_ptr == NULL) {
+               LOG_ERROR("invalid packet, data_ptr is NULL");
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       media_packet_get_buffer_size(packet, &size);
+
+       new_buffer = gst_buffer_new_and_alloc(size);
+       if (!new_buffer) {
+               LOG_ERROR("failed to gst_buffer_new_and_alloc()");
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+       ret = __fill_gst_buffer_mapped_data_from_packet(new_buffer, packet);
+       if (ret != WEBRTC_ERROR_NONE) {
+               LOG_ERROR("failed to __fill_gst_buffer_mapped_data_from_packet()");
+               return ret;
+       }
+
+       media_packet_get_pts(packet, &pts);
+       GST_BUFFER_PTS(new_buffer) = pts;
+
+       media_packet_get_duration(packet, &duration);
+       GST_BUFFER_DURATION(new_buffer) = duration;
+
+       LOG_DEBUG("new gst buffer[%p, pts:%llu, duration:%llu]", new_buffer, pts, duration);
+
+       g_signal_emit_by_name(G_OBJECT(appsrc), "push-buffer", new_buffer, &gst_ret, NULL);
+       gst_buffer_unref(new_buffer);
+
+       if (gst_ret != GST_FLOW_OK) {
+               LOG_ERROR("failed to 'push-buffer', gst_ret[0x%x]", gst_ret);
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
        return WEBRTC_ERROR_NONE;
 }
\ No newline at end of file