#define DEFAULT_AUDIO_CHANNELS 1
#define DEFAULT_AUDIO_SAMPLERATE 8000
+typedef enum {
+ CODEC_TYPE_OPUS,
+ CODEC_TYPE_VORBIS,
+ CODEC_TYPE_VP8,
+ CODEC_TYPE_VP9,
+ CODEC_TYPE_THEORA,
+ CODEC_TYPE_H263,
+ CODEC_TYPE_H264,
+ CODEC_TYPE_H265,
+ CODEC_TYPE_NOT_SUPPORTED,
+} codec_type_e;
+
+typedef struct {
+ const char *encoding_name;
+ const int clock_rate;
+} payload_type_s;
+
+static payload_type_s payload_types[] = {
+ /* AUDIO */
+ [CODEC_TYPE_OPUS] = { "OPUS", 48000 },
+ [CODEC_TYPE_VORBIS] = { "VORBIS", -1 }, /* NOTE: -1 for various clock rate */
+ /* VIDEO */
+ [CODEC_TYPE_VP8] = { "VP8", 90000 },
+ [CODEC_TYPE_VP9] = { "VP9", 90000 },
+ [CODEC_TYPE_THEORA] = { "THEORA", 90000 },
+ [CODEC_TYPE_H263] = { "H263", 90000 },
+ [CODEC_TYPE_H264] = { "H264", 90000 },
+ [CODEC_TYPE_H265] = { "H265", 90000 },
+};
+
#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; \
return caps;
}
-static GstCaps *__make_default_encoded_caps(webrtc_media_source_type_e type)
+/* Use g_free() to free the media_type parameter. */
+static GstCaps *__make_default_encoded_caps(webrtc_media_source_type_e type, gchar **media_type)
{
- GstCaps *caps = NULL;
+ GstCaps *caps;
+ const char *_media_type;
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,
+ _media_type = DEFAULT_VIDEO_ENCODED_MEDIA_TYPE;
+ caps = gst_caps_new_simple(_media_type,
"width", G_TYPE_INT, DEFAULT_VIDEO_WIDTH,
"height", G_TYPE_INT, DEFAULT_VIDEO_HEIGHT,
NULL);
case WEBRTC_MEDIA_SOURCE_TYPE_MIC:
case WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST:
/* FIXME: get default value from ini */
+ _media_type = DEFAULT_AUDIO_ENCODED_MEDIA_TYPE;
caps = gst_caps_new_simple(DEFAULT_AUDIO_ENCODED_MEDIA_TYPE,
"channels", G_TYPE_INT, DEFAULT_AUDIO_CHANNELS,
"rate", G_TYPE_INT, DEFAULT_AUDIO_SAMPLERATE,
default:
LOG_ERROR_IF_REACHED("type(%d)", type);
- break;
+ return NULL;
}
+ if (media_type)
+ *media_type = g_strdup(_media_type);
+
+ return caps;
+}
+
+static codec_type_e __get_codec_type(const gchar *media_type)
+{
+ if (!g_strcmp0(media_type, "audio/x-opus"))
+ return CODEC_TYPE_OPUS;
+ else if (!g_strcmp0(media_type, "audio/x-vorbis"))
+ return CODEC_TYPE_VORBIS;
+ else if (!g_strcmp0(media_type, "video/x-vp8"))
+ return CODEC_TYPE_VP8;
+ else if (!g_strcmp0(media_type, "video/x-vp9"))
+ return CODEC_TYPE_VP9;
+ else if (!g_strcmp0(media_type, "video/x-theora"))
+ return CODEC_TYPE_THEORA;
+ else if (!g_strcmp0(media_type, "video/x-h263"))
+ return CODEC_TYPE_H263;
+ else if (!g_strcmp0(media_type, "video/x-h264"))
+ return CODEC_TYPE_H264;
+ else if (!g_strcmp0(media_type, "video/x-h265"))
+ return CODEC_TYPE_H265;
+ else
+ return CODEC_TYPE_NOT_SUPPORTED;
+}
+
+static GstCaps *__make_rtp_caps(const gchar *media_type)
+{
+ gchar *caps_str;
+ GstCaps *caps;
+ codec_type_e codec_type = __get_codec_type(media_type);
+
+ RET_VAL_IF(codec_type == CODEC_TYPE_NOT_SUPPORTED, NULL, "media_type[%s] is not supported", media_type);
+
+ caps = gst_caps_new_simple("application/x-rtp",
+ "media", G_TYPE_STRING, g_strrstr(media_type, "video") ? "video" : "audio",
+ "clock-rate", G_TYPE_INT, payload_types[codec_type].clock_rate, /* FIXME: support various clock-rate */
+ "encoding-name", G_TYPE_STRING, payload_types[codec_type].encoding_name,
+ "payload", G_TYPE_INT, 96, NULL); /* FIXME: payload identifier should be assigned dynamically */
+
+ caps_str = gst_caps_to_string(caps);
+ LOG_DEBUG("RTP caps is created [%s]", caps_str);
+
+ g_free(caps_str);
+
return caps;
}
return WEBRTC_ERROR_NONE;
}
-static int __create_rest_of_elements(webrtc_media_source_type_e type, GstElement **capsfilter, GstElement **encoder, GstElement **payloader, GstElement **queue)
+static int __create_rest_of_elements(webrtc_media_source_type_e type, GstElement **capsfilter, GstElement **encoder, GstElement **payloader, GstElement **queue, GstElement **capsfilter2)
{
GstCaps *sink_caps;
element_info_s elem_info;
const gchar *encoder_klass_name;
+ gchar *media_type;
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");
+ RET_VAL_IF(capsfilter2 == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "capsfilter2 is NULL");
if (!(*capsfilter = __create_element(DEFAULT_ELEMENT_CAPSFILTER, NULL))) {
LOG_ERROR("failed to create capsfilter");
CREATE_ELEMENT_FROM_REGISTRY(elem_info, encoder_klass_name,
__make_default_raw_caps(type),
- __make_default_encoded_caps(type),
+ __make_default_encoded_caps(type, NULL),
*encoder);
CREATE_ELEMENT_FROM_REGISTRY(elem_info, GST_KLASS_NAME_PAYLOADER_RTP,
- __make_default_encoded_caps(type),
+ __make_default_encoded_caps(type, &media_type),
NULL,
*payloader);
if (!(*queue = __create_element(DEFAULT_ELEMENT_QUEUE, NULL))) {
LOG_ERROR("failed to create queue");
+ g_free(media_type);
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
+ if (!(*capsfilter2 = __create_element(DEFAULT_ELEMENT_CAPSFILTER, NULL))) {
+ LOG_ERROR("failed to create capsfilter");
+ g_free(media_type);
return WEBRTC_ERROR_INVALID_OPERATION;
}
+ if ((sink_caps = __make_rtp_caps(media_type))) {
+ g_object_set(G_OBJECT(*capsfilter2), "caps", sink_caps, NULL);
+ gst_caps_unref(sink_caps);
+ }
+
+ g_free(media_type);
return WEBRTC_ERROR_NONE;
}
GstElement *videoenc;
GstElement *videopay;
GstElement *queue;
+ GstElement *capsfilter2;
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: set camera default setting from ini */
- if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue)) != WEBRTC_ERROR_NONE)
+ if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != 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)) {
+ gst_bin_add_many(GST_BIN(bin), camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
+ if (!gst_element_link_many(camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) {
LOG_ERROR("failed to gst_element_link_many()");
return WEBRTC_ERROR_INVALID_OPERATION;
}
- return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+ return __set_ghost_pad_target(ghost_src_pad, capsfilter2, TRUE);
}
static int __build_audiosrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
GstElement *audioenc;
GstElement *audiopay;
GstElement *queue;
+ GstElement *capsfilter2;
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");
return WEBRTC_ERROR_INVALID_OPERATION;
}
- if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue)) != WEBRTC_ERROR_NONE)
+ if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue, &capsfilter2)) != 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)) {
+ gst_bin_add_many(GST_BIN(bin), audiosrc, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL);
+ if (!gst_element_link_many(audiosrc, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL)) {
LOG_ERROR("failed to gst_element_link_many()");
return WEBRTC_ERROR_INVALID_OPERATION;
}
- return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+ return __set_ghost_pad_target(ghost_src_pad, capsfilter2, TRUE);
}
static int __build_videotestsrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
GstElement *videoenc;
GstElement *videopay;
GstElement *queue;
+ GstElement *capsfilter2;
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");
}
g_object_set(G_OBJECT(videotestsrc), "is-live", TRUE, NULL);
- if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue)) != WEBRTC_ERROR_NONE)
+ if ((ret = __create_rest_of_elements(type, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != 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)) {
+ gst_bin_add_many(GST_BIN(bin), videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL);
+ if (!gst_element_link_many(videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) {
LOG_ERROR("failed to gst_element_link_many()");
return WEBRTC_ERROR_INVALID_OPERATION;
}
- return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+ return __set_ghost_pad_target(ghost_src_pad, capsfilter2, TRUE);
}
static int __build_audiotestsrc(GstElement *bin, webrtc_media_source_type_e type, GstPad *ghost_src_pad)
GstElement *audioenc;
GstElement *audiopay;
GstElement *queue;
+ GstElement *capsfilter2;
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");
}
g_object_set(G_OBJECT(audiotestsrc), "is-live", TRUE, NULL);
- if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue)) != WEBRTC_ERROR_NONE)
+ if ((ret = __create_rest_of_elements(type, &capsfilter, &audioenc, &audiopay, &queue, &capsfilter2)) != 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)) {
+ gst_bin_add_many(GST_BIN(bin), audiotestsrc, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL);
+ if (!gst_element_link_many(audiotestsrc, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL)) {
LOG_ERROR("failed to gst_element_link_many()");
return WEBRTC_ERROR_INVALID_OPERATION;
}
- return __set_ghost_pad_target(ghost_src_pad, queue, TRUE);
+ return __set_ghost_pad_target(ghost_src_pad, capsfilter2, TRUE);
}
static GstPad* __add_no_target_ghostpad(GstElement *bin, const char *pad_name)