#include "webrtc.h"
#include "webrtc_private.h"
+#define GST_KLASS_NAME_ENCODER_AUDIO "Codec/Encoder/Audio"
+#define GST_KLASS_NAME_ENCODER_VIDEO "Codec/Encoder/Video"
+#define GST_KLASS_NAME_DECODER_AUDIO "Codec/Decoder/Audio"
+#define GST_KLASS_NAME_DECODER_VIDEO "Codec/Decoder/Video"
+#define GST_KLASS_NAME_PAYLOADER_RTP "Codec/Payloader/Network/RTP"
+#define GST_KLASS_NAME_DEPAYLOADER_RTP "Codec/Depayloader/Network/RTP"
+#define GST_KLASS_NAME_CONVERTER_AUDIO "Filter/Converter/Audio"
+#define GST_KLASS_NAME_CONVERTER_VIDEO "Filter/Converter/Video"
+
+#define DEFAULT_ELEMENT_CAMERASRC "camerasrc"
+#define DEFAULT_ELEMENT_AUDIOSRC "pulsesrc"
+#define DEFAULT_ELEMENT_VIDEOTESTSRC "videotestsrc"
+#define DEFAULT_ELEMENT_AUDIOTESTSRC "audiotestsrc"
+#define DEFAULT_ELEMENT_CAPSFILTER "capsfilter"
+#define DEFAULT_ELEMENT_QUEUE "queue"
+
+#define DEFAULT_VIDEO_ENCODED_MEDIA_TYPE "video/x-vp8"
+#define DEFAULT_VIDEO_RAW_MEDIA_TYPE "video/x-raw"
+#define DEFAULT_VIDEO_RAW_FORMAT "I420"
+#define DEFAULT_VIDEO_WIDTH 352
+#define DEFAULT_VIDEO_HEIGHT 288
+
+#define DEFAULT_AUDIO_ENCODED_MEDIA_TYPE "audio/x-opus"
+#define DEFAULT_AUDIO_RAW_MEDIA_TYPE "audio/x-raw"
+#define DEFAULT_AUDIO_RAW_FORMAT "S16LE"
+#define DEFAULT_AUDIO_CHANNELS 1
+#define DEFAULT_AUDIO_SAMPLERATE 8000
+
+#define CREATE_ELEMENT_FROM_REGISTRY(x_elem_info, x_klass_name, x_sink_caps, x_src_caps, x_element) \
+do { \
+ x_elem_info.klass_name = x_klass_name; \
+ x_elem_info.sink_caps = x_sink_caps; \
+ x_elem_info.src_caps = x_src_caps; \
+ x_element = __create_element_from_registry(&x_elem_info); \
+ if (x_elem_info.sink_caps) \
+ gst_caps_unref(x_elem_info.sink_caps); \
+ if (x_elem_info.src_caps) \
+ gst_caps_unref(x_elem_info.src_caps); \
+ if (!x_element) { \
+ LOG_ERROR("failed to create element of [%s]", x_klass_name); \
+ return WEBRTC_ERROR_INVALID_OPERATION; \
+ } \
+} while (0)
+
static gboolean __meet_gst_state(webrtc_state_e state, GstState gst_state)
{
if (state == WEBRTC_STATE_IDLE && gst_state == GST_STATE_READY)
return TRUE;
}
-static GstElement *__element_create(const char *factory_name, const char *name)
+static GstElement *__create_element(const char *factory_name, const char *name)
{
GstElement *element = NULL;
return element;
}
+static gboolean __element_filter(GstPluginFeature *feature, gpointer data)
+{
+ element_info_s *elem_info = (element_info_s *)data;
+ gboolean src_can_accept = FALSE;
+ gboolean sink_can_accept = FALSE;
+ GstElementFactory *factory = NULL;
+ const gchar *factory_klass = NULL;
+
+ if (!GST_IS_ELEMENT_FACTORY(feature))
+ return FALSE;
+
+ factory = GST_ELEMENT_FACTORY(feature);
+ factory_klass = gst_element_factory_get_klass(factory);
+
+ if (!elem_info || !g_strrstr(factory_klass, elem_info->klass_name))
+ return FALSE;
+
+ if (GST_IS_CAPS(elem_info->src_caps))
+ src_can_accept = gst_element_factory_can_src_any_caps(factory, elem_info->src_caps);
+
+ if (GST_IS_CAPS(elem_info->sink_caps))
+ sink_can_accept = gst_element_factory_can_sink_any_caps(factory, elem_info->sink_caps);
+
+ if (GST_IS_CAPS(elem_info->src_caps) && GST_IS_CAPS(elem_info->sink_caps)) {
+ if (src_can_accept && sink_can_accept) {
+ LOG_INFO("found compatible factory [%s] for klass [%s]", GST_OBJECT_NAME(factory), factory_klass);
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ if (src_can_accept || sink_can_accept) {
+ LOG_INFO("found compatible factory [%s] for klass [%s]", GST_OBJECT_NAME(factory), factory_klass);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int __rank_compare(GstPluginFeature *first, GstPluginFeature *second)
+{
+ guint first_rank = 0, second_rank = 0;
+
+ first_rank = gst_plugin_feature_get_rank(first);
+ second_rank = gst_plugin_feature_get_rank(second);
+ LOG_DEBUG("second[%s]_rank(%d) - first[%s]_rank(%d) = (%d)",
+ GST_OBJECT_NAME(GST_ELEMENT_FACTORY(second)), second_rank,
+ GST_OBJECT_NAME(GST_ELEMENT_FACTORY(first)), first_rank, second_rank - first_rank);
+
+ return second_rank - first_rank;
+}
+
+static GstElement *__create_element_from_registry(element_info_s *elem_info)
+{
+ GstElement *element = NULL;
+ GList *factories = NULL;
+ GstElementFactory *factory = NULL;
+
+ RET_VAL_IF(elem_info == NULL, NULL, "elem_info is NULL");
+
+ factories = gst_registry_feature_filter(gst_registry_get(), __element_filter, FALSE, elem_info);
+ factories = g_list_sort(factories, (GCompareFunc) __rank_compare);
+
+ if (factories) {
+ factory = GST_ELEMENT_FACTORY(factories->data);
+ LOG_DEBUG("sorted result element is [%s]", GST_OBJECT_NAME(factory));
+ element = __create_element(GST_OBJECT_NAME(factory), NULL);
+ } else {
+ LOG_DEBUG("could not find any compatible element for klass_name[%s]", elem_info->klass_name);
+ }
+
+ gst_plugin_list_free(factories);
+
+ return element;
+}
+
static void __value_destroy_cb(gpointer data)
{
webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)data;
+
RET_IF(data == NULL, "data is NULL");
LOG_DEBUG("[%s, type:%u, id:%u] is removed", GST_ELEMENT_NAME(source->bin), source->type, source->id);
{
RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
- webrtc->gst.pipeline = gst_pipeline_new("native-webrtc-pipeline");
+ webrtc->gst.pipeline = gst_pipeline_new("webrtc-pipeline");
RET_VAL_IF(webrtc->gst.pipeline == NULL, WEBRTC_ERROR_INVALID_OPERATION, "pipeline is NULL");
if (!(webrtc->gst.bus = gst_pipeline_get_bus(GST_PIPELINE(webrtc->gst.pipeline)))) {
goto error;
}
- if (!(webrtc->gst.webrtcbin = __element_create("webrtcbin", NULL))) {
+ if (!(webrtc->gst.webrtcbin = __create_element("webrtcbin", NULL))) {
LOG_ERROR("failed to create webrtcbin");
goto error;
}
if (!webrtc)
return;
+ if (webrtc->gst.source_slots) {
+ g_hash_table_destroy(webrtc->gst.source_slots);
+ webrtc->gst.source_slots = NULL;
+ }
if (webrtc->gst.bus_watcher > 0) {
gst_bus_remove_watch(webrtc->gst.bus);
webrtc->gst.bus_watcher = 0;
gst_object_unref(webrtc->gst.pipeline);
webrtc->gst.pipeline = NULL;
}
- if (webrtc->gst.source_slots) {
- g_hash_table_unref(webrtc->gst.source_slots);
- webrtc->gst.source_slots = NULL;
- }
}
int _gst_pipeline_set_state(webrtc_s *webrtc, GstState state)
return WEBRTC_ERROR_NONE;
}
+static GstCaps *__make_default_raw_caps(webrtc_media_source_type_e type)
+{
+ GstCaps *caps = NULL;
+
+ switch (type) {
+ case WEBRTC_MEDIA_SOURCE_TYPE_CAMERA:
+ case WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST:
+ /* FIXME: get default value from ini */
+ caps = gst_caps_new_simple(DEFAULT_VIDEO_RAW_MEDIA_TYPE,
+ "format", G_TYPE_STRING, DEFAULT_VIDEO_RAW_FORMAT,
+ "width", G_TYPE_INT, DEFAULT_VIDEO_WIDTH,
+ "height", G_TYPE_INT, DEFAULT_VIDEO_HEIGHT,
+ NULL);
+ break;
+
+ case WEBRTC_MEDIA_SOURCE_TYPE_MIC:
+ case WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST:
+ /* FIXME: get default value from ini */
+ caps = gst_caps_new_simple(DEFAULT_AUDIO_RAW_MEDIA_TYPE,
+ "format", G_TYPE_STRING, DEFAULT_AUDIO_RAW_FORMAT,
+ "channels", G_TYPE_INT, DEFAULT_AUDIO_CHANNELS,
+ "rate", G_TYPE_INT, DEFAULT_AUDIO_SAMPLERATE,
+ NULL);
+ break;
+
+ default:
+ LOG_ERROR("should not be reached here");
+ break;
+ }
+
+ return caps;
+}
+
+static GstCaps *__make_default_encoded_caps(webrtc_media_source_type_e type)
+{
+ GstCaps *caps = NULL;
+
+ switch (type) {
+ case WEBRTC_MEDIA_SOURCE_TYPE_CAMERA:
+ case WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST:
+ /* FIXME: get default value from ini */
+ caps = gst_caps_new_simple(DEFAULT_VIDEO_ENCODED_MEDIA_TYPE,
+ "width", G_TYPE_INT, DEFAULT_VIDEO_WIDTH,
+ "height", G_TYPE_INT, DEFAULT_VIDEO_HEIGHT,
+ NULL);
+ break;
+
+ case WEBRTC_MEDIA_SOURCE_TYPE_MIC:
+ case WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST:
+ /* FIXME: get default value from ini */
+ caps = gst_caps_new_simple(DEFAULT_AUDIO_ENCODED_MEDIA_TYPE,
+ "channels", G_TYPE_INT, DEFAULT_AUDIO_CHANNELS,
+ "rate", G_TYPE_INT, DEFAULT_AUDIO_SAMPLERATE,
+ NULL);
+ break;
+
+ default:
+ LOG_ERROR("should not be reached here");
+ break;
+ }
+
+ return caps;
+}
+
+static int __set_ghost_pad_target(GstPad *ghost_pad, GstElement *target_element, gboolean is_src)
+{
+ GstPad *target_pad;
+
+ RET_VAL_IF(ghost_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_pad is NULL");
+ RET_VAL_IF(target_element == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "target_element is NULL");
+
+ if (!(target_pad = gst_element_get_static_pad(target_element, is_src ? "src" : "sink"))) {
+ LOG_ERROR("failed to gst_element_get_static_pad()");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ if (!gst_ghost_pad_set_target(GST_GHOST_PAD(ghost_pad), target_pad)) {
+ LOG_ERROR("failed to gst_ghost_pad_set_target(), ghostpad[%s] -> targetpad[%s]", GST_PAD_NAME(ghost_pad), GST_PAD_NAME(target_pad));
+ gst_object_unref(target_pad);
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ gst_object_unref(target_pad);
+
+ LOG_DEBUG("ghostpad[%s] -> target[%s:%s]", GST_PAD_NAME(ghost_pad), GST_ELEMENT_NAME(target_element), GST_PAD_NAME(target_pad));
+
+ return WEBRTC_ERROR_NONE;
+}
+
+static int __create_rest_of_elements(webrtc_media_source_type_e type, GstElement **capsfilter, GstElement **encoder, GstElement **payloader, GstElement **queue)
+{
+ GstCaps *sink_caps;
+ element_info_s elem_info;
+ const gchar *encoder_klass_name;
+
+ RET_VAL_IF(capsfilter == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "capsfilter is NULL");
+ RET_VAL_IF(encoder == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "encoder is NULL");
+ RET_VAL_IF(payloader == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payloader is NULL");
+ RET_VAL_IF(queue == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "queue is NULL");
+
+ if (!(*capsfilter = __create_element(DEFAULT_ELEMENT_CAPSFILTER, NULL))) {
+ LOG_ERROR("failed to create capsfilter");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+ if ((sink_caps = __make_default_raw_caps(type))) {
+ g_object_set(G_OBJECT(*capsfilter), "caps", sink_caps, NULL);
+ gst_caps_unref(sink_caps);
+ }
+
+ if (type == WEBRTC_MEDIA_SOURCE_TYPE_CAMERA || type == WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST)
+ encoder_klass_name = GST_KLASS_NAME_ENCODER_VIDEO;
+ else
+ encoder_klass_name = GST_KLASS_NAME_ENCODER_AUDIO;
+
+ CREATE_ELEMENT_FROM_REGISTRY(elem_info, encoder_klass_name,
+ __make_default_raw_caps(type),
+ __make_default_encoded_caps(type),
+ *encoder);
+
+ CREATE_ELEMENT_FROM_REGISTRY(elem_info, GST_KLASS_NAME_PAYLOADER_RTP,
+ __make_default_encoded_caps(type),
+ NULL,
+ *payloader);
+
+ if (!(*queue = __create_element(DEFAULT_ELEMENT_QUEUE, NULL))) {
+ LOG_ERROR("failed to create queue");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ return WEBRTC_ERROR_NONE;
+}
+
+static int __build_camerasrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ GstElement *camerasrc;
+ GstElement *capsfilter;
+ GstElement *videoenc;
+ GstElement *videopay;
+ GstElement *queue;
+
+ RET_VAL_IF(bin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bin is NULL");
+ RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL");
+
+ /* FIXME: get factory name from ini */
+ if (!(camerasrc = __create_element(DEFAULT_ELEMENT_CAMERASRC, NULL))) {
+ LOG_ERROR("failed to create camerasrc");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+ /* FIXME: set camera default setting from ini */
+
+ if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue)) != WEBRTC_ERROR_NONE)
+ return ret;
+
+ gst_bin_add_many(GST_BIN(bin), camerasrc, capsfilter, videoenc, videopay, queue, NULL);
+ if (!gst_element_link_many(camerasrc, capsfilter, videoenc, videopay, queue, NULL)) {
+ LOG_ERROR("failed to gst_element_link_many()");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+}
+
+static int __build_audiosrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ GstElement *audiosrc;
+ GstElement *capsfilter;
+ GstElement *audioenc;
+ GstElement *audiopay;
+ GstElement *queue;
+
+ RET_VAL_IF(bin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bin is NULL");
+ RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL");
+
+ if (!(audiosrc = __create_element(DEFAULT_ELEMENT_AUDIOSRC, NULL))) {
+ LOG_ERROR("failed to create audiosrc");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue)) != WEBRTC_ERROR_NONE)
+ return ret;
+
+ gst_bin_add_many(GST_BIN(bin), audiosrc, capsfilter, audioenc, audiopay, queue, NULL);
+ if (!gst_element_link_many(audiosrc, capsfilter, audioenc, audiopay, queue, NULL)) {
+ LOG_ERROR("failed to gst_element_link_many()");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+}
+
+static int __build_videotestsrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ GstElement *videotestsrc;
+ GstElement *capsfilter;
+ GstElement *videoenc;
+ GstElement *videopay;
+ GstElement *queue;
+
+ RET_VAL_IF(bin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bin is NULL");
+ RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL");
+
+ if (!(videotestsrc = __create_element(DEFAULT_ELEMENT_VIDEOTESTSRC, NULL))) {
+ LOG_ERROR("failed to create videotestsrc");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+ g_object_set(G_OBJECT(videotestsrc), "is-live", TRUE, NULL);
+
+ if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue)) != WEBRTC_ERROR_NONE)
+ return ret;
+
+ gst_bin_add_many(GST_BIN(bin), videotestsrc, capsfilter, videoenc, videopay, queue, NULL);
+ if (!gst_element_link_many(videotestsrc, capsfilter, videoenc, videopay, queue, NULL)) {
+ LOG_ERROR("failed to gst_element_link_many()");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+}
+
+static int __build_audiotestsrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
+{
+ int ret = WEBRTC_ERROR_NONE;
+ GstElement *audiotestsrc;
+ GstElement *capsfilter;
+ GstElement *audioenc;
+ GstElement *audiopay;
+ GstElement *queue;
+
+ RET_VAL_IF(bin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bin is NULL");
+ RET_VAL_IF(ghost_src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ghost_src_pad is NULL");
+
+ if (!(audiotestsrc = __create_element(DEFAULT_ELEMENT_AUDIOTESTSRC, NULL))) {
+ LOG_ERROR("failed to create audiotestsrc");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+ g_object_set(G_OBJECT(audiotestsrc), "is-live", TRUE, NULL);
+
+ if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue)) != WEBRTC_ERROR_NONE)
+ return ret;
+
+ gst_bin_add_many(GST_BIN(bin), audiotestsrc, capsfilter, audioenc, audiopay, queue, NULL);
+ if (!gst_element_link_many(audiotestsrc, capsfilter, audioenc, audiopay, queue, NULL)) {
+ LOG_ERROR("failed to gst_element_link_many()");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+}
+
+static GstPad* __add_no_target_ghostpad(GstElement *bin, const char *pad_name)
+{
+ gchar *bin_name = NULL;
+ GstPad *ghost_pad = NULL;
+
+ RET_VAL_IF(bin == NULL, NULL, "bin is NULL");
+ RET_VAL_IF(pad_name == NULL, NULL, "pad_name is NULL");
+
+ if (!(ghost_pad = gst_ghost_pad_new_no_target(pad_name, GST_PAD_SRC))) {
+ LOG_ERROR("failed to gst_ghost_pad_new_no_target()");
+ return NULL;
+ }
+
+ bin_name = gst_element_get_name(bin);
+ if (gst_element_add_pad(GST_ELEMENT(bin), ghost_pad)) {
+ gst_pad_set_active(ghost_pad, TRUE);
+ LOG_DEBUG("added [%s] empty ghostpad into [%s]", pad_name, bin_name);
+ } else {
+ LOG_ERROR("failed to add empty [%s] ghostpad into [%s]", pad_name, bin_name);
+ g_object_unref(ghost_pad);
+ ghost_pad = NULL;
+ }
+
+ g_free(bin_name);
+
+ return ghost_pad;
+}
+
+static int __build_source_bin(webrtc_gst_slot_s *source)
+{
+ GstPad *src_pad = NULL;
+ gchar *pad_name;
+
+ RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+ RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "bin is NULL");
+
+ pad_name = g_strdup_printf("src_%u", source->id);
+ if (!(src_pad =__add_no_target_ghostpad(source->bin, pad_name))) {
+ LOG_ERROR("failed to add new ghost source pad for source bin");
+ g_free(pad_name);
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+ g_free(pad_name);
+
+ switch (source->type) {
+ case WEBRTC_MEDIA_SOURCE_TYPE_CAMERA:
+ return __build_camerasrc(source->bin, source->type, src_pad);
+
+ case WEBRTC_MEDIA_SOURCE_TYPE_MIC:
+ return __build_audiosrc(source->bin, source->type, src_pad);
+
+ case WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST:
+ return __build_videotestsrc(source->bin, source->type, src_pad);
+
+ case WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST:
+ return __build_audiotestsrc(source->bin, source->type, src_pad);
+
+ default:
+ LOG_ERROR("should not be reached here");
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+ }
+
+ return WEBRTC_ERROR_NONE;
+}
+
int _add_media_source(webrtc_s *webrtc, webrtc_media_source_type_e type, unsigned int *source_id)
{
+ int ret = WEBRTC_ERROR_NONE;
static unsigned int id = 0;
webrtc_gst_slot_s *source = NULL;
gchar *bin_name = NULL;
+ GstPad *webrtc_sinkpad;
+ gchar *webrtc_sinkpad_name;
+ gchar *bin_srcpad_name = NULL;
RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
RET_VAL_IF(source_id == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is NULL");
- /* key/value will be freed by function set via g_hash_table_new_full() */
- bin_name = g_strdup_printf("media_source_%u", ++id); /* key */
- source = g_new0(webrtc_gst_slot_s, 1); /* value */
+ /* bin_name/source will be freed by function which is set to g_hash_table_new_full() */
+ bin_name = g_strdup_printf("media_source_%u", ++id);
+ source = g_new0(webrtc_gst_slot_s, 1);
source->type = type;
source->id = id;
source->bin = gst_bin_new(bin_name);
- /* FIXME: add proper elements to the bin according to the type */
+ ret = __build_source_bin(source);
+ if (ret != WEBRTC_ERROR_NONE) {
+ LOG_ERROR("failed to __build_source_bin()");
+ goto error_before_insert;
+ }
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));
- g_free(bin_name);
- g_free(source);
- return WEBRTC_ERROR_INVALID_OPERATION;
+ goto error_before_insert;
+ }
+
+ 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;
+ }
+ if (!(webrtc_sinkpad_name = gst_pad_get_name(webrtc_sinkpad))) {
+ LOG_ERROR("failed to gst_pad_get_name()");
+ goto error_before_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;
}
+ 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;
}
LOG_INFO("type[%d] source_id[%u] source[%p]", type, *source_id, source);
+ g_free(bin_srcpad_name);
+
return WEBRTC_ERROR_NONE;
+
+error_before_insert:
+ g_free(bin_name);
+ g_free(bin_srcpad_name);
+ g_free(source);
+
+ return WEBRTC_ERROR_INVALID_OPERATION;
}
int _remove_media_source(webrtc_s *webrtc, unsigned int source_id)
{
+ int ret = WEBRTC_ERROR_NONE;
gchar *bin_name = NULL;
RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
if (!g_hash_table_remove(webrtc->gst.source_slots, (gpointer)bin_name)) {
LOG_ERROR("failed to find media source by id[%u]", source_id);
- g_free(bin_name);
- return WEBRTC_ERROR_INVALID_PARAMETER;
+ ret = WEBRTC_ERROR_INVALID_PARAMETER;
}
g_free(bin_name);
- return WEBRTC_ERROR_NONE;
+ return ret;
}