From: Sangchul Lee Date: Wed, 16 Dec 2020 08:30:18 +0000 (+0900) Subject: Add new API set for media packet source X-Git-Tag: submit/tizen/20210729.023123~165 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F15%2F249715%2F12;p=platform%2Fcore%2Fapi%2Fwebrtc.git Add new API set for media packet source 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 --- diff --git a/include/webrtc.h b/include/webrtc.h index aa700fd0..b2e5f25c 100644 --- a/include/webrtc.h +++ b/include/webrtc.h @@ -18,6 +18,8 @@ #define __TIZEN_MEDIA_WEBRTC_H__ #include +#include +#include #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 diff --git a/include/webrtc_private.h b/include/webrtc_private.h index c53acdbd..96580831 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -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); diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index b1b1bcfc..105313e9 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.75 +Version: 0.1.76 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc.c b/src/webrtc.c index a09aa211..8c2c0b34 100644 --- a/src/webrtc.c +++ b/src/webrtc.c @@ -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; diff --git a/src/webrtc_source.c b/src/webrtc_source.c index 176c8c0b..51ceeed1 100644 --- a/src/webrtc_source.c +++ b/src/webrtc_source.c @@ -16,6 +16,7 @@ #include "webrtc.h" #include "webrtc_private.h" +#include #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