} \
} 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; \
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 */
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));
}
}
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;
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;
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);
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");
__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));
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");
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;
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;
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;
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);
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;