From: Sangchul Lee Date: Mon, 21 Sep 2020 10:44:46 +0000 (+0900) Subject: Add more members to the slot structure for source/sink X-Git-Tag: submit/tizen/20210729.023123~212 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F41%2F244541%2F6;p=platform%2Fcore%2Fapi%2Fwebrtc.git Add more members to the slot structure for source/sink The mline value is got from the transceiver object via on-new-transceiver callback. It will be used to find the tranceiver object to modify the direction. [Version] 0.1.30 [Issue Type] Improvement Change-Id: I279f7ed5870b228eccbe6d14af1105f1f01b3d2c Signed-off-by: Sangchul Lee --- diff --git a/include/webrtc_private.h b/include/webrtc_private.h index 68e66c53..0f7f4a93 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -112,9 +112,19 @@ typedef struct _webrtc_ini_s { gchar **gst_args; } webrtc_ini_s; +typedef enum { + MEDIA_TYPE_AUDIO = 0x01, + MEDIA_TYPE_VIDEO = 0x02, +} media_type_e; + +#define MLINES_IDX_AUDIO 0 +#define MLINES_IDX_VIDEO 1 + typedef struct _webrtc_gst_slot_s { unsigned int id; GstElement *bin; + int media_types; /* values of media_type_e combined with bitwise 'or' */ + int mlines[2]; /* index 0 for audio, 1 for video */ } webrtc_gst_slot_s; typedef struct _webrtc_gst_s { diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 9320dece..e078c181 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.29 +Version: 0.1.30 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc_private.c b/src/webrtc_private.c index 34225b10..0c1b4272 100644 --- a/src/webrtc_private.c +++ b/src/webrtc_private.c @@ -100,6 +100,15 @@ do { \ } \ } while (0) +#define MALLOC_AND_INIT_SLOT(x_slot, x_id, x_bin_name) \ +do { \ + x_slot = g_new0(webrtc_gst_slot_s, 1); \ + x_slot->id = x_id; \ + x_slot->bin = gst_bin_new(x_bin_name); \ + x_slot->mlines[MLINES_IDX_AUDIO] = -1; \ + x_slot->mlines[MLINES_IDX_VIDEO] = -1; \ +} while (0) + #define GENERATE_DOT(x_webrtc, x_fmt, x_arg...) \ do { \ gchar *dot_name; \ @@ -421,7 +430,8 @@ static void __value_destroy_cb(gpointer data) RET_IF(data == NULL, "data is NULL"); - LOG_DEBUG("[%s, id:%u] is removed", GST_ELEMENT_NAME(source->bin), source->id); + LOG_DEBUG("[%s, id:%u, media_types:0x%x, mlines[AUDIO]:%d, mlines[VIDEO]:%d] is removed", + GST_ELEMENT_NAME(source->bin), source->id, source->media_types, source->mlines[MLINES_IDX_AUDIO], source->mlines[MLINES_IDX_VIDEO]); /* FIXME: do unlink */ @@ -527,7 +537,7 @@ static void __disconnect_signal(gpointer data) if (GST_IS_ELEMENT(sig_data->obj)) { if (g_signal_handler_is_connected(sig_data->obj, sig_data->signal_id)) { g_signal_handler_disconnect(sig_data->obj, sig_data->signal_id); - LOG_DEBUG("signal with id[%lu] is disconnected from object [%s].", sig_data->signal_id, GST_OBJECT_NAME(sig_data->obj)); + LOG_DEBUG("signal with id[%lu] is disconnected from object [%s]", sig_data->signal_id, GST_OBJECT_NAME(sig_data->obj)); } } @@ -757,6 +767,8 @@ static int __build_videosink(webrtc_s *webrtc, GstElement *decodebin, GstPad *sr RET_VAL_IF(sink == NULL, WEBRTC_ERROR_INVALID_OPERATION, "could not find an item by [%s] in sink slots", GST_ELEMENT_NAME(decodebin)); RET_VAL_IF(sink->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL"); + sink->media_types |= MEDIA_TYPE_VIDEO; + if (!(videoconvert = __create_element(DEFAULT_ELEMENT_VIDEOCONVERT, NULL))) { LOG_ERROR("failed to create videoconvert"); return WEBRTC_ERROR_INVALID_OPERATION; @@ -802,6 +814,8 @@ static int __build_audiosink(webrtc_s *webrtc, GstElement *decodebin, GstPad *sr RET_VAL_IF(sink == NULL, WEBRTC_ERROR_INVALID_OPERATION, "could not find an item by [%s] in sink slots", GST_ELEMENT_NAME(decodebin)); RET_VAL_IF(sink->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL"); + sink->media_types |= MEDIA_TYPE_AUDIO; + if (!(audioconvert = __create_element(DEFAULT_ELEMENT_AUDIOCONVERT, NULL))) { LOG_ERROR("failed to create audioconvert"); return WEBRTC_ERROR_INVALID_OPERATION; @@ -1000,9 +1014,8 @@ static int __add_rendering_sink_bin(webrtc_s *webrtc, GstPad *src_pad) bin_name = g_strdup_printf("rendering_sink_%u", id); decodebin_name = g_strdup_printf("%s_decodebin", bin_name); - sink = g_new0(webrtc_gst_slot_s, 1); - sink->id = id; - sink->bin = gst_bin_new(bin_name); + MALLOC_AND_INIT_SLOT(sink, id, bin_name); + g_free(bin_name); decodebin = __create_element("decodebin", decodebin_name); @@ -1083,6 +1096,36 @@ static void __webrtcbin_no_more_pads_cb(GstElement *webrtcbin, gpointer user_dat LOG_DEBUG_LEAVE(); } +static void __webrtcbin_on_new_transceiver_cb(GstElement *webrtcbin, GstWebRTCRTPTransceiver *transceiver, gpointer user_data) +{ + webrtc_s *webrtc = (webrtc_s *)user_data; + GHashTableIter iter; + gpointer key, value; + webrtc_gst_slot_s *source; + int i; + + RET_IF(webrtcbin == NULL, "webrtcbin is NULL"); + RET_IF(transceiver == NULL, "transceiver is NULL"); + RET_IF(webrtc == NULL, "webrtc is NULL"); + + LOG_INFO("new transceiver[%p, mline:%u, mid:%s, direction:%d], user_data[%p]", + transceiver, transceiver->mline, transceiver->mid, transceiver->direction, user_data); + + g_hash_table_iter_init(&iter, webrtc->gst.source_slots); + while (g_hash_table_iter_next(&iter, &key, &value)) { + source = (webrtc_gst_slot_s*)value; + for (i = MLINES_IDX_AUDIO; i <= MLINES_IDX_VIDEO; i++) { + if (!(source->media_types & (i == MLINES_IDX_AUDIO ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO))) + continue; + if (source->mlines[i] == -1) { + source->mlines[i] = transceiver->mline; + LOG_DEBUG("source[%s, id:%u, mline:%d for %s]", + (gchar*)key, source->id, source->mlines[i], i == MLINES_IDX_AUDIO ? "AUDIO" : "VIDEO"); + } + } + } +} + int _gst_build_pipeline(webrtc_s *webrtc) { RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); @@ -1112,6 +1155,7 @@ int _gst_build_pipeline(webrtc_s *webrtc) __connect_and_append_signal(&webrtc->signals, webrtc->gst.webrtcbin, "notify::ice-connection-state", G_CALLBACK(__webrtcbin_ice_connection_state_cb), webrtc); __connect_and_append_signal(&webrtc->signals, webrtc->gst.webrtcbin, "pad-added", G_CALLBACK(__webrtcbin_pad_added_cb), webrtc); __connect_and_append_signal(&webrtc->signals, webrtc->gst.webrtcbin, "no-more-pads", G_CALLBACK(__webrtcbin_no_more_pads_cb), webrtc); + __connect_and_append_signal(&webrtc->signals, webrtc->gst.webrtcbin, "on-new-transceiver", G_CALLBACK(__webrtcbin_on_new_transceiver_cb), webrtc); if (!gst_bin_add(GST_BIN(webrtc->gst.pipeline), webrtc->gst.webrtcbin)) { LOG_ERROR("failed to gst_bin_add(), [%s] -> [%s] pipeline", GST_ELEMENT_NAME(webrtc->gst.webrtcbin), GST_ELEMENT_NAME(webrtc->gst.pipeline)); @@ -1379,6 +1423,8 @@ static int __build_camerasrc(webrtc_gst_slot_s *source, GstPad *ghost_src_pad) RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL"); RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL"); + source->media_types |= MEDIA_TYPE_VIDEO; + /* FIXME: get factory name from ini */ if (!(camerasrc = __create_element(DEFAULT_ELEMENT_CAMERASRC, NULL))) { LOG_ERROR("failed to create camerasrc"); @@ -1412,6 +1458,8 @@ static int __build_audiosrc(webrtc_gst_slot_s *source, GstPad *ghost_src_pad) RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL"); RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL"); + source->media_types |= MEDIA_TYPE_AUDIO; + if (!(audiosrc = __create_element(DEFAULT_ELEMENT_AUDIOSRC, NULL))) { LOG_ERROR("failed to create audiosrc"); return WEBRTC_ERROR_INVALID_OPERATION; @@ -1443,6 +1491,8 @@ static int __build_videotestsrc(webrtc_gst_slot_s *source, GstPad *ghost_src_pad RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL"); RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL"); + source->media_types |= MEDIA_TYPE_VIDEO; + if (!(videotestsrc = __create_element(DEFAULT_ELEMENT_VIDEOTESTSRC, NULL))) { LOG_ERROR("failed to create videotestsrc"); return WEBRTC_ERROR_INVALID_OPERATION; @@ -1475,6 +1525,8 @@ static int __build_audiotestsrc(webrtc_gst_slot_s *source, GstPad *ghost_src_pad RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL"); RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL"); + source->media_types |= MEDIA_TYPE_AUDIO; + if (!(audiotestsrc = __create_element(DEFAULT_ELEMENT_AUDIOTESTSRC, NULL))) { LOG_ERROR("failed to create audiotestsrc"); return WEBRTC_ERROR_INVALID_OPERATION; @@ -1568,45 +1620,45 @@ int _add_media_source(webrtc_s *webrtc, webrtc_media_source_type_e type, unsigne RET_VAL_IF(id == 0, WEBRTC_ERROR_INVALID_OPERATION, "source_slots are full"); bin_name = g_strdup_printf("media_source_%u", id); - source = g_new0(webrtc_gst_slot_s, 1); - source->id = id; - source->bin = gst_bin_new(bin_name); + + MALLOC_AND_INIT_SLOT(source, id, bin_name); ret = __build_source_bin(source, type); if (ret != WEBRTC_ERROR_NONE) { LOG_ERROR("failed to __build_source_bin()"); - goto error_before_insert; + goto error; } if (!gst_bin_add(GST_BIN(webrtc->gst.pipeline), source->bin)) { LOG_ERROR("failed to gst_bin_add(), [%s] -> [%s] pipeline", GST_ELEMENT_NAME(source->bin), GST_ELEMENT_NAME(webrtc->gst.pipeline)); - goto error_before_insert; + goto error; + } + + /* The gst_element_get_request_pad() of webrtcbin will trigger the transciever callback. To update the mline value of + * new transceiver object to the source structure in the callback, hash table inserting should be preceded. */ + if (!g_hash_table_insert(webrtc->gst.source_slots, bin_name, (gpointer)source)) { + LOG_ERROR("should not be reached here, bin_name[%s] already exist, source id[%u] will be removed", bin_name, source->id); + g_hash_table_remove(webrtc->gst.source_slots, bin_name); + return WEBRTC_ERROR_INVALID_OPERATION; } if (!(webrtc_sinkpad = gst_element_get_request_pad(webrtc->gst.webrtcbin, "sink_%u"))) { LOG_ERROR("failed to gst_element_get_request_pad()"); - goto error_before_insert; + goto error_after_insert; } if (!(webrtc_sinkpad_name = gst_pad_get_name(webrtc_sinkpad))) { LOG_ERROR("failed to gst_pad_get_name()"); - goto error_before_insert; + goto error_after_insert; } bin_srcpad_name = g_strdup_printf("src_%u", id); if (!gst_element_link_pads(source->bin, bin_srcpad_name, webrtc->gst.webrtcbin, webrtc_sinkpad_name)) { LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", GST_ELEMENT_NAME(source->bin), bin_srcpad_name, GST_ELEMENT_NAME(webrtc->gst.webrtcbin), webrtc_sinkpad_name); - goto error_before_insert; + goto error_after_insert; } LOG_DEBUG("link pads successfully, [%s:%s] - [%s:%s]", GST_ELEMENT_NAME(source->bin), bin_srcpad_name, GST_ELEMENT_NAME(webrtc->gst.webrtcbin), webrtc_sinkpad_name); - if (!g_hash_table_insert(webrtc->gst.source_slots, bin_name, (gpointer)source)) { - LOG_ERROR("should not be reached here, bin_name[%s] already exist, source id[%u] will be removed", bin_name, source->id); - g_hash_table_remove(webrtc->gst.source_slots, bin_name); - g_free(bin_srcpad_name); - return WEBRTC_ERROR_INVALID_OPERATION; - } - *source_id = id; LOG_INFO("added a source slot[%p, id:%u]", source, source->id); @@ -1615,9 +1667,14 @@ int _add_media_source(webrtc_s *webrtc, webrtc_media_source_type_e type, unsigne return WEBRTC_ERROR_NONE; -error_before_insert: - g_free(bin_name); +error_after_insert: + g_hash_table_remove(webrtc->gst.source_slots, bin_name); g_free(bin_srcpad_name); + + return WEBRTC_ERROR_INVALID_OPERATION; + +error: + g_free(bin_name); g_free(source); return WEBRTC_ERROR_INVALID_OPERATION;