#define MEDIA_TYPE_VIDEO_JPEG "image/jpeg"
#define WEBRTC_DISPLAY_TYPE_ECORE_WL 2
-#define PAYLOAD_TYPE_BITS 32 /* 96 ~ 127 */
+#define MIN_DYNAMIC_PAYLOAD_TYPE 96
+#define MAX_DYNAMIC_PAYLOAD_TYPE 127
+#define PAYLOAD_TYPE_BITS MAX_DYNAMIC_PAYLOAD_TYPE - MIN_DYNAMIC_PAYLOAD_TYPE + 1
#define TRACK_ID_THRESHOLD_OF_LOOPBACK 100
#define MAX_MLINE_NUM 32
#define MAX_SOURCE_NUM 32
GstWebRTCRTPTransceiverDirection gst;
} direction_info_s;
+typedef struct {
+ webrtc_transceiver_codec_e codec;
+ const char *gst_media_type;
+ const char *media_type;
+ const char *encoding_name;
+ int clock_rate;
+} rtp_payload_info_s;
+
typedef struct _webrtc_signal_s {
GObject *obj;
gulong signal_id;
const char *_get_hw_encoder_from_ini(webrtc_ini_s *ini, int src_type, media_type_e media_type);
GStrv _get_supported_codecs_from_ini(webrtc_ini_s *ini, int src_type, media_type_e media_type);
+/* transceiver */
+void _webrtcbin_on_new_transceiver_cb(GstElement *webrtcbin, GstWebRTCRTPTransceiver *transceiver, gpointer user_data);
+void _update_transceivers_fec(webrtc_s *webrtc, bool is_offer);
+void _update_transceivers_for_offer(webrtc_s *webrtc);
+int _set_payload_type(webrtc_s *webrtc, webrtc_gst_slot_s *source, int av_idx, const gchar *media_type);
+int _get_fixed_payload_type(const gchar *media_type);
+void _return_payload_type(webrtc_s *webrtc, unsigned int payload_type);
+void _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source);
+int _add_transceiver(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, rtp_payload_info_s *payload_info);
+int _set_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction);
+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_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_codec_e codec);
+int _get_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_codec_e *codec);
+int _foreach_supported_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_media_source_supported_transceiver_codec_cb callback, void *user_data);
+
/* file source */
int _gst_filesrc_pipeline_set_state(webrtc_s *webrtc, GstState state);
int _set_filesrc_looping(webrtc_s *webrtc, unsigned int source_id, bool looping);
int _complete_sources(webrtc_s *webrtc);
const char *_get_audio_media_type(const char *codec_name);
const char *_get_video_media_type(const char *codec_name);
-int _get_fixed_payload_type(const gchar *media_type);
-void _update_transceivers_for_offer(webrtc_s *webrtc);
void _source_slot_destroy_cb(gpointer data);
int _add_media_source(webrtc_s *webrtc, int type, unsigned int *source_id);
int _add_media_source_internal(webrtc_s *webrtc, int type, unsigned int *source_id);
int _remove_media_source(webrtc_s *webrtc, unsigned int source_id);
-int _set_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction);
-int _get_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction);
-direction_info_s *_convert_transceiver_direction(webrtc_transceiver_direction_e direction);
-int _set_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_codec_e codec);
-int _get_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_codec_e *codec);
-int _foreach_supported_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_media_source_supported_transceiver_codec_cb callback, void *user_data);
bool _check_if_codec_is_set_to_null_sources(webrtc_s *webrtc);
bool _check_if_path_is_set_to_file_sources(webrtc_s *webrtc);
bool _check_if_format_is_set_to_packet_sources(webrtc_s *webrtc);
ELEMENT_FAKESINK
} gst_element_e;
-typedef struct {
- webrtc_transceiver_codec_e codec;
- const char *gst_media_type;
- const char *media_type;
- const char *encoding_name;
- int clock_rate;
-} rtp_payload_info_s;
-
const char *_get_audio_format_name(media_format_mimetype_e mime_type);
const char *_get_video_format_name(media_format_mimetype_e mime_type, bool zerocopy_enabled);
const char *_get_source_element(webrtc_s *webrtc, int type);
GstCaps *_get_caps_from_encoded_video_media_type(const char *media_type, int width, int height);
GstCaps *_make_rtp_caps(const gchar *media_type, unsigned int payload_type, webrtc_gst_slot_s *source, GstElement *encoder);
const char *_get_element_name(int av_idx, gst_element_e element);
-int _set_payload_type(webrtc_s *webrtc, webrtc_gst_slot_s *source, int av_idx, const gchar *media_type);
GstPadProbeReturn _payloaded_data_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
void _add_probe_to_pad_for_pause(webrtc_gst_slot_s *source, unsigned int idx, GstPad *pad, void *probe_cb);
void _remove_probe_from_pad_for_pause(webrtc_gst_slot_s *source, unsigned int idx);
GstPadProbeReturn _source_data_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data);
void _add_probe_to_pad_for_render(webrtc_gst_slot_s *source, unsigned int idx, GstPad *pad, void *probe_cb);
void _remove_probe_from_pad_for_render(webrtc_gst_slot_s *source, unsigned int idx);
-rtp_payload_info_s * _get_payload_info(webrtc_transceiver_codec_e codec);
-rtp_payload_info_s * _get_payload_info_by_encoding_name(const char *encoding_name);
-int _add_transceiver(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, rtp_payload_info_s *payload_info);
-int _update_transceiver_with_pt(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, rtp_payload_info_s *payload_info);
int _link_source_with_webrtcbin(webrtc_gst_slot_s *source, GstElement *webrtcbin);
int _create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool need_capsfilter, GList **element_list, bool is_audio);
int _set_encoder_element_bitrate(GstElement *encoder, int target_bitrate);
Name: capi-media-webrtc
Summary: A WebRTC library in Tizen Native API
-Version: 0.3.227
+Version: 0.3.228
Release: 0
Group: Multimedia/API
License: Apache-2.0
return WEBRTC_ERROR_NONE;
}
-static void __webrtcbin_transceiver_set_ulpfec_red(webrtc_s *webrtc, GstWebRTCRTPTransceiver *transceiver)
-{
- GstElement *rtpbin;
-
- RET_IF(webrtc == NULL, "webrtc is NULL");
- RET_IF(transceiver == NULL, "transceiver is NULL");
-
- if (!(rtpbin = gst_bin_get_by_name(GST_BIN(webrtc->gst.webrtcbin), "rtpbin"))) {
- LOG_ERROR("failed to get rtpbin");
- return;
- }
-
- g_object_set(transceiver, "fec-type", GST_WEBRTC_FEC_TYPE_ULP_RED, NULL);
- LOG_INFO("set ULPFEC/RED to transceiver[%p]", transceiver);
-
- g_object_set(G_OBJECT(rtpbin), "do-lost", TRUE, NULL);
- LOG_DEBUG("set do-lost to rtpbin[%p], ULPFEC recovers a lost packet when do-lost event occurs", rtpbin);
-
- gst_object_unref(rtpbin);
-}
-
-static void __webrtcbin_transceiver_set_fec_percentage(webrtc_s *webrtc, GstWebRTCRTPTransceiver *transceiver, unsigned int fec_percentage)
-{
- RET_IF(webrtc == NULL, "webrtc is NULL");
- RET_IF(transceiver == NULL, "transceiver is NULL");
-
- g_object_set(transceiver, "fec-percentage", fec_percentage, NULL);
-
- LOG_INFO("set fec-percentage[%u] to transceiver[%p]", fec_percentage, transceiver);
-}
-
//LCOV_EXCL_START
gchar * _get_media_type_from_pad(GstPad *pad)
{
}
//LCOV_EXCL_STOP
-static void __webrtcbin_on_new_transceiver_cb(GstElement *webrtcbin, GstWebRTCRTPTransceiver *transceiver, gpointer user_data)
-{
- webrtc_s *webrtc = (webrtc_s *)user_data;
- webrtc_gst_slot_s *source;
- int i, j;
- guint mlineindex;
- gchar *mid;
- GstWebRTCRTPTransceiverDirection direction;
- GstWebRTCKind kind;
- GstCaps *caps;
-
- RET_IF(webrtcbin == NULL, "webrtcbin is NULL");
- RET_IF(transceiver == NULL, "transceiver is NULL");
- RET_IF(webrtc == NULL, "webrtc is NULL");
-
- g_object_get(G_OBJECT(transceiver),
- "mlineindex", &mlineindex,
- "mid", &mid,
- "direction", &direction,
- "kind", &kind,
- "codec-preferences", &caps,
- NULL);
-
- LOG_DEBUG("webrtc[%p] new transceiver[%p, mlineindex:%u, mid:%s, direction:%d, kind:%d] user_data[%p]",
- webrtc, transceiver, mlineindex, mid, direction, kind, user_data);
- PRINT_CAPS(caps, "codec preferences");
-
- /* Code below is for the scenario of an answerer without any added media sources. */
- if (g_hash_table_size(webrtc->gst.source_slots) == 0) {
- if (mlineindex >= MAX_MLINE_NUM) {
- LOG_ERROR("mlineindex[%u] exceeds the max value", mlineindex);
- return;
- }
- if (webrtc->data_recovery_types[mlineindex].red &&
- webrtc->data_recovery_types[mlineindex].ulpfec)
- __webrtcbin_transceiver_set_ulpfec_red(webrtc, transceiver);
- return;
- }
-
- for (i = 0; i < MAX_SOURCE_NUM; i++) {
- if (!(source = webrtc->gst.sources[i]))
- continue;
- for (j = AV_IDX_AUDIO; j < AV_IDX_MAX; j++) {
- if (!(source->media_types & (j == AV_IDX_AUDIO ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO)))
- continue;
- if (source->av[j].transceiver)
- continue;
-
- source->av[j].transceiver = gst_object_ref(transceiver);
- g_object_set(G_OBJECT(transceiver), "direction", _convert_transceiver_direction(source->av[j].direction)->gst, NULL);
-
- LOG_INFO("source->id[%u] transceiver[%p for %s, direction:%s]",
- source->id, source->av[j].transceiver, j == AV_IDX_AUDIO ? "AUDIO" : "VIDEO",
- _convert_transceiver_direction(source->av[j].direction)->str);
- return;
- }
- }
-}
-
-void _update_transceivers_fec(webrtc_s *webrtc, bool is_offer)
-{
- GstWebRTCRTPTransceiver *transceiver;
- webrtc_gst_slot_s *source;
- int i, j;
- GstWebRTCRTPTransceiverDirection direction;
-
- RET_IF(webrtc == NULL, "webrtc is NULL");
-
- for (i = 0; i < MAX_SOURCE_NUM; i++) {
- if (!(source = webrtc->gst.sources[i]))
- continue;
- for (j = AV_IDX_AUDIO; j < AV_IDX_MAX; j++) {
- if (!(source->media_types & (j == AV_IDX_AUDIO ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO)))
- continue;
- if (!(transceiver = source->av[j].transceiver))
- continue;
-
- g_object_get(G_OBJECT(transceiver), "direction", &direction, NULL);
-
- if (is_offer) {
- bool use_ulpfec_red;
- _get_use_ulpfec_red_from_ini(&webrtc->ini, source->type, &use_ulpfec_red);
-
- if (!use_ulpfec_red)
- continue;
-
- __webrtcbin_transceiver_set_ulpfec_red(webrtc, transceiver);
- } else {
- if (!webrtc->data_recovery_types[i].red ||
- !webrtc->data_recovery_types[i].ulpfec)
- continue;
- __webrtcbin_transceiver_set_ulpfec_red(webrtc, transceiver);
- }
-
- if (direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY ||
- direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV)
- __webrtcbin_transceiver_set_fec_percentage(webrtc, transceiver, _get_fec_percentage_from_ini(&webrtc->ini, source->type));
- }
- }
-}
-
int _gst_build_pipeline(webrtc_s *webrtc)
{
gchar *webrtcbin_name;
_connect_and_append_signal(&webrtc->signals, (GObject *)webrtc->gst.webrtcbin, "notify::ice-connection-state", G_CALLBACK(__webrtcbin_ice_connection_state_cb), webrtc);
_connect_and_append_signal(&webrtc->signals, (GObject *)webrtc->gst.webrtcbin, "pad-added", G_CALLBACK(__webrtcbin_pad_added_cb), webrtc);
_connect_and_append_signal(&webrtc->signals, (GObject *)webrtc->gst.webrtcbin, "no-more-pads", G_CALLBACK(__webrtcbin_no_more_pads_cb), webrtc);
- _connect_and_append_signal(&webrtc->signals, (GObject *)webrtc->gst.webrtcbin, "on-new-transceiver", G_CALLBACK(__webrtcbin_on_new_transceiver_cb), webrtc);
+ _connect_and_append_signal(&webrtc->signals, (GObject *)webrtc->gst.webrtcbin, "on-new-transceiver", G_CALLBACK(_webrtcbin_on_new_transceiver_cb), webrtc);
_connect_and_append_signal(&webrtc->signals, (GObject *)webrtc->gst.webrtcbin, "on-data-channel", G_CALLBACK(_webrtcbin_on_data_channel_cb), webrtc);
if (!gst_bin_add(GST_BIN(webrtc->gst.pipeline), webrtc->gst.webrtcbin)) {
#include <tbm_surface_internal.h>
#include <sound_manager_internal.h>
-#define MIN_DYNAMIC_PAYLOAD_TYPE 96
-#define MAX_DYNAMIC_PAYLOAD_TYPE 127
-
-static direction_info_s __direction_info[] = {
- [WEBRTC_TRANSCEIVER_DIRECTION_SENDONLY] = { "SENDONLY", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY },
- [WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY] = { "RECVONLY", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY },
- [WEBRTC_TRANSCEIVER_DIRECTION_SENDRECV] = { "SENDRECV", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV }
-};
-
static GstPadProbeReturn __camerasrc_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data);
static GstCaps *__make_video_raw_caps_with_framerate(webrtc_gst_slot_s *source, webrtc_ini_s *ini, int framerate)
return caps;
}
-static void __return_payload_type(webrtc_s *webrtc, unsigned int payload_type)
-{
- int i;
- int bitmask = 0x1;
-
- RET_IF(webrtc == NULL, "webrtc is NULL");
- RET_IF(payload_type < MIN_DYNAMIC_PAYLOAD_TYPE || payload_type > MAX_DYNAMIC_PAYLOAD_TYPE, "invalid payload_type(%u)", payload_type);
-
- i = payload_type - MIN_DYNAMIC_PAYLOAD_TYPE;
-
- while (i-- > 0)
- bitmask <<= 1;
-
- webrtc->payload_types ^= bitmask;
-}
-
static bool __link_switch_srcs(GstElement *switch_element, GList *switch_src_list)
{
GstElement *element;
return WEBRTC_ERROR_INVALID_OPERATION;
}
-static void __check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source)
-{
- rtp_payload_info_s *payload_info = NULL;
-
- RET_IF(source == NULL, "source is NULL");
-
- if (source->av[AV_IDX_AUDIO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_AUDIO].codec) {
- if ((payload_info = _get_payload_info_by_encoding_name(source->av[AV_IDX_AUDIO].codec)))
- _add_transceiver(source, WEBRTC_MEDIA_TYPE_AUDIO, payload_info);
- }
-
- if (source->av[AV_IDX_VIDEO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_VIDEO].codec) {
- if ((payload_info = _get_payload_info_by_encoding_name(source->av[AV_IDX_VIDEO].codec)))
- _add_transceiver(source, WEBRTC_MEDIA_TYPE_VIDEO, payload_info);
- }
-}
-
-static void __check_and_update_transceiver(webrtc_gst_slot_s *source)
-{
- rtp_payload_info_s *payload_info = NULL;
-
- RET_IF(source == NULL, "source is NULL");
-
- if (source->av[AV_IDX_AUDIO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_AUDIO].codec) {
- if ((payload_info = _get_payload_info_by_encoding_name(source->av[AV_IDX_AUDIO].codec)))
- _update_transceiver_with_pt(source, WEBRTC_MEDIA_TYPE_AUDIO, payload_info);
- }
-
- if (source->av[AV_IDX_VIDEO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_VIDEO].codec) {
- if ((payload_info = _get_payload_info_by_encoding_name(source->av[AV_IDX_VIDEO].codec)))
- _update_transceiver_with_pt(source, WEBRTC_MEDIA_TYPE_VIDEO, payload_info);
- }
-}
-
-void _update_transceivers_for_offer(webrtc_s *webrtc)
-{
- int i;
- webrtc_gst_slot_s *source;
- RET_IF(webrtc == NULL, "webrtc is NULL");
-
- for (i = 0; i < MAX_SOURCE_NUM; i++) {
- if (!(source = webrtc->gst.sources[i]))
- continue;
-
- if (source->type != WEBRTC_MEDIA_SOURCE_TYPE_NULL)
- continue;
-
- LOG_DEBUG("source[id:%u, type:%d, media_types:0x%x]", source->id, source->type, source->media_types);
-
- __check_and_update_transceiver(source);
- }
-}
-
-int _get_fixed_payload_type(const gchar *media_type)
-{
- RET_VAL_IF(media_type == NULL, -1, "media_type is NULL");
-
- if (!g_strcmp0(media_type, MEDIA_TYPE_AUDIO_MULAW))
- return 0;
- if (!g_strcmp0(media_type, MEDIA_TYPE_AUDIO_ALAW))
- return 8;
-
- LOG_DEBUG("%s might need to use dynamic id", media_type);
-
- return -1;
-}
-
int _complete_sources(webrtc_s *webrtc)
{
int i;
__complete_rest_of_videosrc(webrtc, source);
add_transceiver:
- __check_and_add_recvonly_transceiver(source);
+ _check_and_add_recvonly_transceiver(source);
}
return WEBRTC_ERROR_NONE;
_remove_probe_from_pad_for_render(source, i);
if (source->av[i].pt > 0)
- __return_payload_type(source->webrtc, source->av[i].pt);
+ _return_payload_type(source->webrtc, source->av[i].pt);
if (source->av[i].render.pipeline) {
gst_element_set_state(source->av[i].render.pipeline, GST_STATE_NULL);
return ret;
}
-direction_info_s* _convert_transceiver_direction(webrtc_transceiver_direction_e direction)
-{
- return &__direction_info[direction];
-}
-
-int _set_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction)
-{
- webrtc_gst_slot_s *source;
- GstWebRTCRTPTransceiver *trans;
-
- RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
- RET_VAL_IF(direction > WEBRTC_TRANSCEIVER_DIRECTION_SENDRECV, WEBRTC_ERROR_INVALID_PARAMETER, "invalid direction");
- RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
- RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
- RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
- RET_VAL_IF(source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL && direction != WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY,
- WEBRTC_ERROR_INVALID_PARAMETER, "null source only allow RECVONLY direction");
-
- if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) {
- trans = source->av[AV_IDX_AUDIO].transceiver;
- source->av[AV_IDX_AUDIO].direction = direction;
-
- } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) {
- trans = source->av[AV_IDX_VIDEO].transceiver;
- source->av[AV_IDX_VIDEO].direction = direction;
-
- } else {
- LOG_ERROR("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id);
- return WEBRTC_ERROR_INVALID_PARAMETER;
- }
-
- if (trans)
- g_object_set(G_OBJECT(trans), "direction", __direction_info[direction].gst, NULL);
-
- LOG_INFO("webrtc[%p] source_id[%u] media_type[%d] transceiver[%p, direction:%s]",
- webrtc, source_id, media_type, trans, __direction_info[direction].str);
-
- return WEBRTC_ERROR_NONE;
-}
-
-int _get_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction)
-{
- const webrtc_gst_slot_s *source;
-
- RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
- RET_VAL_IF(direction == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "direction is NULL");
- RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
- RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
- RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
-
- if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) {
- *direction = source->av[AV_IDX_AUDIO].direction;
-
- } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) {
- *direction = source->av[AV_IDX_VIDEO].direction;
-
- } else {
- LOG_ERROR("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id);
- return WEBRTC_ERROR_INVALID_PARAMETER;
- }
-
- LOG_INFO("webrtc[%p] source_id[%u] media_type[%d] direction[%s]",
- webrtc, source_id, media_type, __direction_info[*direction].str);
-
- return WEBRTC_ERROR_NONE;
-}
-
-static int __convert_audio_codec(const char *codec_name, webrtc_transceiver_codec_e *codec)
-{
- RET_VAL_IF(codec_name == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec_name is NULL");
- RET_VAL_IF(codec == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec is NULL");
-
- if (!strcmp(codec_name, "pcmu") || !strcmp(codec_name, "PCMU")) {
- *codec = WEBRTC_TRANSCEIVER_CODEC_PCMU;
- return WEBRTC_ERROR_NONE;
- }
- if (!strcmp(codec_name, "pcma") || !strcmp(codec_name, "PCMA")) {
- *codec = WEBRTC_TRANSCEIVER_CODEC_PCMA;
- return WEBRTC_ERROR_NONE;
- }
- if (!strcmp(codec_name, "opus") || !strcmp(codec_name, "OPUS")) {
- *codec = WEBRTC_TRANSCEIVER_CODEC_OPUS;
- return WEBRTC_ERROR_NONE;
- }
-
- LOG_ERROR("not supported audio codec_name[%s]", codec_name);
-
- return WEBRTC_ERROR_INVALID_PARAMETER;
-}
-
-static int __convert_video_codec(const char *codec_name, webrtc_transceiver_codec_e *codec)
-{
- RET_VAL_IF(codec_name == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec_name is NULL");
- RET_VAL_IF(codec == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec is NULL");
-
- if (!strcmp(codec_name, "vp8") || !strcmp(codec_name, "VP8")) {
- *codec = WEBRTC_TRANSCEIVER_CODEC_VP8;
- return WEBRTC_ERROR_NONE;
- }
- if (!strcmp(codec_name, "vp9") || !strcmp(codec_name, "VP9")) {
- *codec = WEBRTC_TRANSCEIVER_CODEC_VP9;
- return WEBRTC_ERROR_NONE;
- }
- if (!strcmp(codec_name, "h264") || !strcmp(codec_name, "H264")) {
- *codec = WEBRTC_TRANSCEIVER_CODEC_H264;
- return WEBRTC_ERROR_NONE;
- }
-
- LOG_ERROR("not supported video codec_name[%s]", codec_name);
-
- return WEBRTC_ERROR_INVALID_PARAMETER;
-}
-
-typedef int (*convert_codec_func)(const char *codec_name, webrtc_transceiver_codec_e *codec);
-
-static convert_codec_func convert_codec_funcs[] = {
- [WEBRTC_MEDIA_TYPE_AUDIO] = __convert_audio_codec,
- [WEBRTC_MEDIA_TYPE_VIDEO] = __convert_video_codec,
-};
-
-int _foreach_supported_transceiver_codec(webrtc_s *webrtc, webrtc_media_source_type_e source_type, webrtc_media_type_e media_type, webrtc_media_source_supported_transceiver_codec_cb callback, void *user_data)
-{
- int ret;
- webrtc_transceiver_codec_e codec;
- GStrv codecs;
- guint i;
-
- RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
- RET_VAL_IF(callback == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "callback is NULL");
- RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
- RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
- RET_VAL_IF((source_type == WEBRTC_MEDIA_SOURCE_TYPE_FILE), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the file source");
- RET_VAL_IF((source_type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the media packet source");
- RET_VAL_IF((source_type > WEBRTC_MEDIA_SOURCE_TYPE_NULL), WEBRTC_ERROR_INVALID_PARAMETER, "invalid source_type");
-
- if (media_type == WEBRTC_MEDIA_TYPE_AUDIO &&
- (source_type == WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST ||
- source_type == WEBRTC_MEDIA_SOURCE_TYPE_MIC ||
- source_type == WEBRTC_MEDIA_SOURCE_TYPE_NULL)) {
- codecs = _get_supported_codecs_from_ini(&webrtc->ini, source_type, MEDIA_TYPE_AUDIO);
-
- } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO &&
- (source_type == WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST ||
- source_type == WEBRTC_MEDIA_SOURCE_TYPE_CAMERA ||
- source_type == WEBRTC_MEDIA_SOURCE_TYPE_SCREEN ||
- source_type == WEBRTC_MEDIA_SOURCE_TYPE_NULL)) {
- codecs = _get_supported_codecs_from_ini(&webrtc->ini, source_type, MEDIA_TYPE_VIDEO);
-
- } else {
- LOG_ERROR("invalid media_type[%d] for source_type[%u]", media_type, source_type);
- return WEBRTC_ERROR_INVALID_PARAMETER;
- }
-
- LOG_INFO("webrtc[%p] source_type[%u] media_type[%d] callback[%p] user_data[%p]", webrtc, source_type, media_type, callback, user_data);
-
- for (i = 0; i < g_strv_length(codecs); i++) {
- if ((ret = convert_codec_funcs[media_type](codecs[i], &codec)) != WEBRTC_ERROR_NONE)
- return ret;
- LOG_INFO(" - supported %s codec: %s", media_type == WEBRTC_MEDIA_TYPE_AUDIO ? "audio" : "video", codecs[i]);
- if (!callback(codec, user_data)) {
- LOG_DEBUG("stop foreach callback");
- break;
- }
- }
-
- return WEBRTC_ERROR_NONE;
-}
-
-static int __validate_codec(webrtc_s *webrtc, webrtc_gst_slot_s *source, webrtc_media_type_e media_type, webrtc_transceiver_codec_e codec)
-{
- int ret;
- GStrv codecs;
- webrtc_transceiver_codec_e _codec;
- guint i;
-
- RET_VAL_IF(webrtc == NULL, FALSE, "webrtc is NULL");
- RET_VAL_IF(source == NULL, FALSE, "source is NULL");
-
- if (media_type == WEBRTC_MEDIA_TYPE_AUDIO &&
- source->media_types & MEDIA_TYPE_AUDIO &&
- codec & CODEC_TYPE_AUDIO) {
- codecs = _get_supported_codecs_from_ini(&webrtc->ini, source->type, MEDIA_TYPE_AUDIO);
-
- } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO &&
- source->media_types & MEDIA_TYPE_VIDEO &&
- codec & CODEC_TYPE_VIDEO) {
- codecs = _get_supported_codecs_from_ini(&webrtc->ini, source->type, MEDIA_TYPE_VIDEO);
-
- } else {
- LOG_ERROR("invalid media_type[%d], codec[0x%x] for source[media_types:0x%x, id:%u]",
- media_type, codec, source->media_types, source->id);
- return WEBRTC_ERROR_INVALID_PARAMETER;
- }
-
- for (i = 0; i < g_strv_length(codecs); i++) {
- if ((ret = convert_codec_funcs[media_type](codecs[i], &_codec)) != WEBRTC_ERROR_NONE)
- return ret;
- if (_codec == codec) {
- LOG_DEBUG("codec[0x%x] is supported", codec);
- return WEBRTC_ERROR_NONE;
- }
- }
-
- LOG_ERROR("webrtc[%p] codec[0x%x] is not supported for this source type[%d]", webrtc, codec, source->type);
-
- return WEBRTC_ERROR_INVALID_PARAMETER;
-}
-
-int _set_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_codec_e codec)
-{
- int ret;
- webrtc_gst_slot_s *source;
- int av_idx = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? AV_IDX_AUDIO : AV_IDX_VIDEO;
- rtp_payload_info_s *payload_info = NULL;
-
- RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
- RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
- RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
- RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
- RET_VAL_IF((source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the file source");
- RET_VAL_IF((source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the media packet source");
-
- payload_info = _get_payload_info(codec);
- RET_VAL_IF(payload_info == NULL, WEBRTC_ERROR_INVALID_OPERATION, "could not find payload_info");
-
- /* NOTE: for null source, set media_types here exceptionally. */
- if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL)
- source->media_types |= (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO;
-
- if ((ret = __validate_codec(webrtc, source, media_type, codec)) != WEBRTC_ERROR_NONE)
- return ret;
-
- source->av[av_idx].codec = payload_info->encoding_name;
-
- if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL) {
- if (source->av[av_idx].pt >= MIN_DYNAMIC_PAYLOAD_TYPE)
- __return_payload_type(webrtc, source->av[av_idx].pt);
-
- if ((ret = _set_payload_type(webrtc, source, av_idx, payload_info->gst_media_type)) != WEBRTC_ERROR_NONE)
- return ret;
- }
-
- /* FIXME: to utilize 'codec-preferences' of trans object, we need to re-create and re-link elements again */
- LOG_INFO("webrtc[%p] source_id[%u] media_type[%d] codec[%s]", webrtc, source_id, media_type, payload_info->encoding_name);
-
- return WEBRTC_ERROR_NONE;
-}
-
-int _get_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_codec_e *codec)
-{
- int ret;
- webrtc_gst_slot_s *source;
- const char *codec_str;
- webrtc_transceiver_codec_e _codec;
-
- RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
- RET_VAL_IF(codec == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec is NULL");
- RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
- RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
- RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
-
- if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) {
- codec_str = source->av[AV_IDX_AUDIO].codec;
-
- } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) {
- codec_str = source->av[AV_IDX_VIDEO].codec;
-
- } else {
- LOG_ERROR("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id);
- return WEBRTC_ERROR_INVALID_PARAMETER;
- }
-
- if ((ret = convert_codec_funcs[media_type](codec_str, &_codec)) != WEBRTC_ERROR_NONE)
- return ret;
-
- *codec = _codec;
-
- LOG_INFO("webrtc[%p] source_id[%u] media_type[%d] codec[%s]", webrtc, source_id, media_type, codec_str);
-
- return WEBRTC_ERROR_NONE;
-}
-
int _set_pause(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, bool pause)
{
webrtc_gst_slot_s *source;
_remove_filesrc_pad_block_probe(source, av_idx);
if (source->av[av_idx].pt > 0)
- __return_payload_type(source->webrtc, source->av[av_idx].pt);
+ _return_payload_type(source->webrtc, source->av[av_idx].pt);
if (source->av[av_idx].render.pipeline) {
gst_element_set_state(source->av[av_idx].render.pipeline, GST_STATE_NULL);
#include "webrtc_private.h"
#include "webrtc_source_private.h"
-static rtp_payload_info_s __payload_info[] = {
- { WEBRTC_TRANSCEIVER_CODEC_PCMU, MEDIA_TYPE_AUDIO_MULAW, "audio", "PCMU", 8000 },
- { WEBRTC_TRANSCEIVER_CODEC_PCMA, MEDIA_TYPE_AUDIO_ALAW, "audio", "PCMA", 8000 },
- { WEBRTC_TRANSCEIVER_CODEC_OPUS, MEDIA_TYPE_AUDIO_OPUS, "audio", "OPUS", 48000 },
- { WEBRTC_TRANSCEIVER_CODEC_VP8, MEDIA_TYPE_VIDEO_VP8, "video", "VP8", 90000 },
- { WEBRTC_TRANSCEIVER_CODEC_VP9, MEDIA_TYPE_VIDEO_VP9, "video", "VP9", 90000 },
- { WEBRTC_TRANSCEIVER_CODEC_H264, MEDIA_TYPE_VIDEO_H264, "video", "H264", 90000 },
- { 0 /* TBD */, MEDIA_TYPE_AUDIO_VORBIS, "audio", "VORBIS", 8000 },
- { 0 /* TBD */, MEDIA_TYPE_VIDEO_JPEG, "video", "JPEG", 90000 },
- { 0, NULL, NULL, NULL, 0 }
-};
-
const char *_get_audio_format_name(media_format_mimetype_e mime_type)
{
switch (mime_type) {
return _av_element_tbl[av_idx][element];
}
-static int __get_available_payload_type(webrtc_s *webrtc)
-{
- int bitmask = 0x1;
- int count = 0;
-
- RET_VAL_IF(webrtc == NULL, 0, "webrtc is NULL");
-
- while (count++ < PAYLOAD_TYPE_BITS) {
- if (webrtc->payload_types & bitmask) {
- bitmask <<= 1;
- continue;
- }
- webrtc->payload_types |= bitmask;
- LOG_DEBUG("found available payload type[%d]", count + 95);
- return count + 95; /* 96 ~ 127 */
- }
-
- LOG_ERROR("could not assign payload type");
-
- return -1;
-}
-
-int _set_payload_type(webrtc_s *webrtc, webrtc_gst_slot_s *source, int av_idx, const gchar *media_type)
-{
- int payload_type = -1;
-
- RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
- RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
-
- if (source->av[av_idx].pt_set_by_api) {
- LOG_INFO("current pt[%u] might be set by api, skip it", source->av[av_idx].pt);
- return WEBRTC_ERROR_NONE;
- }
-
- if (media_type)
- if ((payload_type = _get_fixed_payload_type(media_type)) != -1)
- goto out;
-
- if ((payload_type = __get_available_payload_type(webrtc)) == -1)
- return WEBRTC_ERROR_INVALID_OPERATION;
-
-out:
- source->av[av_idx].pt = payload_type;
-
- return WEBRTC_ERROR_NONE;
-}
-
GstPadProbeReturn _payloaded_data_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
{
probe_userdata_s *probe_data = (probe_userdata_s *)user_data;
_unset_caps_for_render(source, idx);
}
-rtp_payload_info_s * _get_payload_info(webrtc_transceiver_codec_e codec)
-{
- int i = 0;
-
- for (i = 0; i != (int)__payload_info[i].codec; i++) {
- if (__payload_info[i].codec == codec)
- return &__payload_info[i];
- }
-
- LOG_ERROR("could not find payload_info. codec[%d]", codec);
-
- return NULL;
-}
-
-rtp_payload_info_s * _get_payload_info_by_encoding_name(const char *encoding_name)
-{
- int i = 0;
- size_t n = 0;
-
- RET_VAL_IF(encoding_name == NULL, NULL, "encoding_name is NULL");
-
- n = ARRAY_SIZE(__payload_info);
-
- for (i = 0; i < (int)n; i++) {
- if ((__payload_info[i].encoding_name) && !strcasecmp(__payload_info[i].encoding_name, encoding_name))
- return &__payload_info[i];
- }
-
- LOG_ERROR("could not find payload_info. encoding_name[%s]", encoding_name);
-
- return NULL;
-}
-
-static GstCaps *__make_transceiver_caps(rtp_payload_info_s *payload_info)
-{
- RET_VAL_IF(payload_info == NULL, NULL, "payload_info is NULL");
-
- return gst_caps_new_simple("application/x-rtp",
- "media", G_TYPE_STRING, payload_info->media_type,
- "encoding-name", G_TYPE_STRING, payload_info->encoding_name,
- "clock-rate", G_TYPE_INT, payload_info->clock_rate,
- NULL);
-}
-
-static GstCaps *__make_transceiver_caps_with_pt(rtp_payload_info_s *payload_info, int payload_type)
-{
- RET_VAL_IF(payload_info == NULL, NULL, "payload_info is NULL");
-
- return gst_caps_new_simple("application/x-rtp",
- "media", G_TYPE_STRING, payload_info->media_type,
- "encoding-name", G_TYPE_STRING, payload_info->encoding_name,
- "clock-rate", G_TYPE_INT, payload_info->clock_rate,
- "payload", G_TYPE_INT, payload_type,
- NULL);
-}
-
-int _add_transceiver(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, rtp_payload_info_s *payload_info)
-{
- GstWebRTCRTPTransceiver *trans;
- GstCaps *caps;
- int av_idx = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? AV_IDX_AUDIO : AV_IDX_VIDEO;
-
- RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
- RET_VAL_IF(payload_info == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payload_info is NULL");
-
- caps = __make_transceiver_caps(payload_info);
- PRINT_CAPS(caps, "transceiver");
-
- if (!source->av[av_idx].transceiver) {
- g_signal_emit_by_name(source->webrtc->gst.webrtcbin, "add-transceiver",
- GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY, caps, &trans, NULL);
- gst_object_unref(trans);
- } else {
- g_object_set(G_OBJECT(source->av[av_idx].transceiver), "codec-preferences", caps, NULL);
- }
-
- gst_caps_unref(caps);
-
- LOG_DEBUG("webrtc[%p] source_id[%u] [%s] transceiver[%p] codec[%s]",
- source->webrtc, source->id, payload_info->media_type, source->av[av_idx].transceiver, payload_info->encoding_name);
-
- return WEBRTC_ERROR_NONE;
-}
-
-int _update_transceiver_with_pt(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, rtp_payload_info_s *payload_info)
-{
- GstCaps *caps;
- int av_idx = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? AV_IDX_AUDIO : AV_IDX_VIDEO;
-
- RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
- RET_VAL_IF(payload_info == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payload_info is NULL");
- RET_VAL_IF(source->av[av_idx].transceiver == NULL, WEBRTC_ERROR_INVALID_OPERATION, "transceiver is NULL");
-
- caps = __make_transceiver_caps_with_pt(payload_info, source->av[av_idx].pt);
- PRINT_CAPS(caps, "transceiver");
-
- g_object_set(G_OBJECT(source->av[av_idx].transceiver), "codec-preferences", caps, NULL);
-
- gst_caps_unref(caps);
-
- LOG_DEBUG("webrtc[%p] source_id[%u] [%s] transceiver[%p] codec[%s]",
- source->webrtc, source->id, payload_info->media_type, source->av[av_idx].transceiver, payload_info->encoding_name);
-
- return WEBRTC_ERROR_NONE;
-}
-
static bool __is_linked_pad(webrtc_gst_slot_s *source, const char *pad_name)
{
GstIterator *iter = NULL;
--- /dev/null
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "webrtc_private.h"
+
+static direction_info_s __direction_info[] = {
+ [WEBRTC_TRANSCEIVER_DIRECTION_SENDONLY] = { "SENDONLY", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY },
+ [WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY] = { "RECVONLY", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY },
+ [WEBRTC_TRANSCEIVER_DIRECTION_SENDRECV] = { "SENDRECV", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV }
+};
+
+static direction_info_s* __convert_transceiver_direction(webrtc_transceiver_direction_e direction)
+{
+ return &__direction_info[direction];
+}
+
+static rtp_payload_info_s __payload_info[] = {
+ { WEBRTC_TRANSCEIVER_CODEC_PCMU, MEDIA_TYPE_AUDIO_MULAW, "audio", "PCMU", 8000 },
+ { WEBRTC_TRANSCEIVER_CODEC_PCMA, MEDIA_TYPE_AUDIO_ALAW, "audio", "PCMA", 8000 },
+ { WEBRTC_TRANSCEIVER_CODEC_OPUS, MEDIA_TYPE_AUDIO_OPUS, "audio", "OPUS", 48000 },
+ { WEBRTC_TRANSCEIVER_CODEC_VP8, MEDIA_TYPE_VIDEO_VP8, "video", "VP8", 90000 },
+ { WEBRTC_TRANSCEIVER_CODEC_VP9, MEDIA_TYPE_VIDEO_VP9, "video", "VP9", 90000 },
+ { WEBRTC_TRANSCEIVER_CODEC_H264, MEDIA_TYPE_VIDEO_H264, "video", "H264", 90000 },
+ { 0 /* TBD */, MEDIA_TYPE_AUDIO_VORBIS, "audio", "VORBIS", 8000 },
+ { 0 /* TBD */, MEDIA_TYPE_VIDEO_JPEG, "video", "JPEG", 90000 },
+ { 0, NULL, NULL, NULL, 0 }
+};
+
+static void __webrtcbin_transceiver_set_ulpfec_red(webrtc_s *webrtc, GstWebRTCRTPTransceiver *transceiver)
+{
+ GstElement *rtpbin;
+
+ RET_IF(webrtc == NULL, "webrtc is NULL");
+ RET_IF(transceiver == NULL, "transceiver is NULL");
+
+ if (!(rtpbin = gst_bin_get_by_name(GST_BIN(webrtc->gst.webrtcbin), "rtpbin"))) {
+ LOG_ERROR("failed to get rtpbin");
+ return;
+ }
+
+ g_object_set(transceiver, "fec-type", GST_WEBRTC_FEC_TYPE_ULP_RED, NULL);
+ LOG_INFO("set ULPFEC/RED to transceiver[%p]", transceiver);
+
+ g_object_set(G_OBJECT(rtpbin), "do-lost", TRUE, NULL);
+ LOG_DEBUG("set do-lost to rtpbin[%p], ULPFEC recovers a lost packet when do-lost event occurs", rtpbin);
+
+ gst_object_unref(rtpbin);
+}
+
+static void __webrtcbin_transceiver_set_fec_percentage(webrtc_s *webrtc, GstWebRTCRTPTransceiver *transceiver, unsigned int fec_percentage)
+{
+ RET_IF(webrtc == NULL, "webrtc is NULL");
+ RET_IF(transceiver == NULL, "transceiver is NULL");
+
+ g_object_set(transceiver, "fec-percentage", fec_percentage, NULL);
+
+ LOG_INFO("set fec-percentage[%u] to transceiver[%p]", fec_percentage, transceiver);
+}
+
+
+void _webrtcbin_on_new_transceiver_cb(GstElement *webrtcbin, GstWebRTCRTPTransceiver *transceiver, gpointer user_data)
+{
+ webrtc_s *webrtc = (webrtc_s *)user_data;
+ webrtc_gst_slot_s *source;
+ int i, j;
+ guint mlineindex;
+ gchar *mid;
+ GstWebRTCRTPTransceiverDirection direction;
+ GstWebRTCKind kind;
+ GstCaps *caps;
+
+ RET_IF(webrtcbin == NULL, "webrtcbin is NULL");
+ RET_IF(transceiver == NULL, "transceiver is NULL");
+ RET_IF(webrtc == NULL, "webrtc is NULL");
+
+ g_object_get(G_OBJECT(transceiver),
+ "mlineindex", &mlineindex,
+ "mid", &mid,
+ "direction", &direction,
+ "kind", &kind,
+ "codec-preferences", &caps,
+ NULL);
+
+ LOG_DEBUG("webrtc[%p] new transceiver[%p, mlineindex:%u, mid:%s, direction:%d, kind:%d] user_data[%p]",
+ webrtc, transceiver, mlineindex, mid, direction, kind, user_data);
+ PRINT_CAPS(caps, "codec preferences");
+
+ /* Code below is for the scenario of an answerer without any added media sources. */
+ if (g_hash_table_size(webrtc->gst.source_slots) == 0) {
+ if (mlineindex >= MAX_MLINE_NUM) {
+ LOG_ERROR("mlineindex[%u] exceeds the max value", mlineindex);
+ return;
+ }
+ if (webrtc->data_recovery_types[mlineindex].red &&
+ webrtc->data_recovery_types[mlineindex].ulpfec)
+ __webrtcbin_transceiver_set_ulpfec_red(webrtc, transceiver);
+ return;
+ }
+
+ for (i = 0; i < MAX_SOURCE_NUM; i++) {
+ if (!(source = webrtc->gst.sources[i]))
+ continue;
+ for (j = AV_IDX_AUDIO; j < AV_IDX_MAX; j++) {
+ if (!(source->media_types & (j == AV_IDX_AUDIO ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO)))
+ continue;
+ if (source->av[j].transceiver)
+ continue;
+
+ source->av[j].transceiver = gst_object_ref(transceiver);
+ g_object_set(G_OBJECT(transceiver), "direction", __convert_transceiver_direction(source->av[j].direction)->gst, NULL);
+
+ LOG_INFO("source->id[%u] transceiver[%p for %s, direction:%s]",
+ source->id, source->av[j].transceiver, j == AV_IDX_AUDIO ? "AUDIO" : "VIDEO",
+ __convert_transceiver_direction(source->av[j].direction)->str);
+ return;
+ }
+ }
+}
+
+void _update_transceivers_fec(webrtc_s *webrtc, bool is_offer)
+{
+ GstWebRTCRTPTransceiver *transceiver;
+ webrtc_gst_slot_s *source;
+ int i, j;
+ GstWebRTCRTPTransceiverDirection direction;
+
+ RET_IF(webrtc == NULL, "webrtc is NULL");
+
+ for (i = 0; i < MAX_SOURCE_NUM; i++) {
+ if (!(source = webrtc->gst.sources[i]))
+ continue;
+ for (j = AV_IDX_AUDIO; j < AV_IDX_MAX; j++) {
+ if (!(source->media_types & (j == AV_IDX_AUDIO ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO)))
+ continue;
+ if (!(transceiver = source->av[j].transceiver))
+ continue;
+
+ g_object_get(G_OBJECT(transceiver), "direction", &direction, NULL);
+
+ if (is_offer) {
+ bool use_ulpfec_red;
+ _get_use_ulpfec_red_from_ini(&webrtc->ini, source->type, &use_ulpfec_red);
+
+ if (!use_ulpfec_red)
+ continue;
+
+ __webrtcbin_transceiver_set_ulpfec_red(webrtc, transceiver);
+ } else {
+ if (!webrtc->data_recovery_types[i].red ||
+ !webrtc->data_recovery_types[i].ulpfec)
+ continue;
+ __webrtcbin_transceiver_set_ulpfec_red(webrtc, transceiver);
+ }
+
+ if (direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDONLY ||
+ direction == GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV)
+ __webrtcbin_transceiver_set_fec_percentage(webrtc, transceiver, _get_fec_percentage_from_ini(&webrtc->ini, source->type));
+ }
+ }
+}
+
+static GstCaps *__make_transceiver_caps_with_pt(rtp_payload_info_s *payload_info, int payload_type)
+{
+ RET_VAL_IF(payload_info == NULL, NULL, "payload_info is NULL");
+
+ return gst_caps_new_simple("application/x-rtp",
+ "media", G_TYPE_STRING, payload_info->media_type,
+ "encoding-name", G_TYPE_STRING, payload_info->encoding_name,
+ "clock-rate", G_TYPE_INT, payload_info->clock_rate,
+ "payload", G_TYPE_INT, payload_type,
+ NULL);
+}
+
+static int __update_transceiver_with_pt(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, rtp_payload_info_s *payload_info)
+{
+ GstCaps *caps;
+ int av_idx = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? AV_IDX_AUDIO : AV_IDX_VIDEO;
+
+ RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+ RET_VAL_IF(payload_info == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payload_info is NULL");
+ RET_VAL_IF(source->av[av_idx].transceiver == NULL, WEBRTC_ERROR_INVALID_OPERATION, "transceiver is NULL");
+
+ caps = __make_transceiver_caps_with_pt(payload_info, source->av[av_idx].pt);
+ PRINT_CAPS(caps, "transceiver");
+
+ g_object_set(G_OBJECT(source->av[av_idx].transceiver), "codec-preferences", caps, NULL);
+
+ gst_caps_unref(caps);
+
+ LOG_DEBUG("webrtc[%p] source_id[%u] [%s] transceiver[%p] codec[%s]",
+ source->webrtc, source->id, payload_info->media_type, source->av[av_idx].transceiver, payload_info->encoding_name);
+
+ return WEBRTC_ERROR_NONE;
+}
+
+static rtp_payload_info_s * __get_payload_info_by_encoding_name(const char *encoding_name)
+{
+ int i = 0;
+ size_t n = 0;
+
+ RET_VAL_IF(encoding_name == NULL, NULL, "encoding_name is NULL");
+
+ n = ARRAY_SIZE(__payload_info);
+
+ for (i = 0; i < (int)n; i++) {
+ if ((__payload_info[i].encoding_name) && !strcasecmp(__payload_info[i].encoding_name, encoding_name))
+ return &__payload_info[i];
+ }
+
+ LOG_ERROR("could not find payload_info. encoding_name[%s]", encoding_name);
+
+ return NULL;
+}
+
+static void __check_and_update_transceiver(webrtc_gst_slot_s *source)
+{
+ rtp_payload_info_s *payload_info = NULL;
+
+ RET_IF(source == NULL, "source is NULL");
+
+ if (source->av[AV_IDX_AUDIO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_AUDIO].codec) {
+ if ((payload_info = __get_payload_info_by_encoding_name(source->av[AV_IDX_AUDIO].codec)))
+ __update_transceiver_with_pt(source, WEBRTC_MEDIA_TYPE_AUDIO, payload_info);
+ }
+
+ if (source->av[AV_IDX_VIDEO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_VIDEO].codec) {
+ if ((payload_info = __get_payload_info_by_encoding_name(source->av[AV_IDX_VIDEO].codec)))
+ __update_transceiver_with_pt(source, WEBRTC_MEDIA_TYPE_VIDEO, payload_info);
+ }
+}
+
+void _update_transceivers_for_offer(webrtc_s *webrtc)
+{
+ int i;
+ webrtc_gst_slot_s *source;
+ RET_IF(webrtc == NULL, "webrtc is NULL");
+
+ for (i = 0; i < MAX_SOURCE_NUM; i++) {
+ if (!(source = webrtc->gst.sources[i]))
+ continue;
+
+ if (source->type != WEBRTC_MEDIA_SOURCE_TYPE_NULL)
+ continue;
+
+ LOG_DEBUG("source[id:%u, type:%d, media_types:0x%x]", source->id, source->type, source->media_types);
+
+ __check_and_update_transceiver(source);
+ }
+}
+
+static rtp_payload_info_s * __get_payload_info(webrtc_transceiver_codec_e codec)
+{
+ int i = 0;
+
+ for (i = 0; i != (int)__payload_info[i].codec; i++) {
+ if (__payload_info[i].codec == codec)
+ return &__payload_info[i];
+ }
+
+ LOG_ERROR("could not find payload_info. codec[%d]", codec);
+
+ return NULL;
+}
+
+static int __get_available_payload_type(webrtc_s *webrtc)
+{
+ int bitmask = 0x1;
+ int count = 0;
+
+ RET_VAL_IF(webrtc == NULL, 0, "webrtc is NULL");
+
+ while (count++ < PAYLOAD_TYPE_BITS) {
+ if (webrtc->payload_types & bitmask) {
+ bitmask <<= 1;
+ continue;
+ }
+ webrtc->payload_types |= bitmask;
+ LOG_DEBUG("found available payload type[%d]", count + 95);
+ return count + 95; /* 96 ~ 127 */
+ }
+
+ LOG_ERROR("could not assign payload type");
+
+ return -1;
+}
+
+int _set_payload_type(webrtc_s *webrtc, webrtc_gst_slot_s *source, int av_idx, const gchar *media_type)
+{
+ int payload_type = -1;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+
+ if (source->av[av_idx].pt_set_by_api) {
+ LOG_INFO("current pt[%u] might be set by api, skip it", source->av[av_idx].pt);
+ return WEBRTC_ERROR_NONE;
+ }
+
+ if (media_type)
+ if ((payload_type = _get_fixed_payload_type(media_type)) != -1)
+ goto out;
+
+ if ((payload_type = __get_available_payload_type(webrtc)) == -1)
+ return WEBRTC_ERROR_INVALID_OPERATION;
+
+out:
+ source->av[av_idx].pt = payload_type;
+
+ return WEBRTC_ERROR_NONE;
+}
+
+int _get_fixed_payload_type(const gchar *media_type)
+{
+ RET_VAL_IF(media_type == NULL, -1, "media_type is NULL");
+
+ if (!g_strcmp0(media_type, MEDIA_TYPE_AUDIO_MULAW))
+ return 0;
+ if (!g_strcmp0(media_type, MEDIA_TYPE_AUDIO_ALAW))
+ return 8;
+
+ LOG_DEBUG("%s might need to use dynamic id", media_type);
+
+ return -1;
+}
+
+void _return_payload_type(webrtc_s *webrtc, unsigned int payload_type)
+{
+ int i;
+ int bitmask = 0x1;
+
+ RET_IF(webrtc == NULL, "webrtc is NULL");
+ RET_IF(payload_type < MIN_DYNAMIC_PAYLOAD_TYPE || payload_type > MAX_DYNAMIC_PAYLOAD_TYPE, "invalid payload_type(%u)", payload_type);
+
+ i = payload_type - MIN_DYNAMIC_PAYLOAD_TYPE;
+
+ while (i-- > 0)
+ bitmask <<= 1;
+
+ webrtc->payload_types ^= bitmask;
+}
+
+void _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source)
+{
+ rtp_payload_info_s *payload_info = NULL;
+
+ RET_IF(source == NULL, "source is NULL");
+
+ if (source->av[AV_IDX_AUDIO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_AUDIO].codec) {
+ if ((payload_info = __get_payload_info_by_encoding_name(source->av[AV_IDX_AUDIO].codec)))
+ _add_transceiver(source, WEBRTC_MEDIA_TYPE_AUDIO, payload_info);
+ }
+
+ if (source->av[AV_IDX_VIDEO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_VIDEO].codec) {
+ if ((payload_info = __get_payload_info_by_encoding_name(source->av[AV_IDX_VIDEO].codec)))
+ _add_transceiver(source, WEBRTC_MEDIA_TYPE_VIDEO, payload_info);
+ }
+}
+
+static GstCaps *__make_transceiver_caps(rtp_payload_info_s *payload_info)
+{
+ RET_VAL_IF(payload_info == NULL, NULL, "payload_info is NULL");
+
+ return gst_caps_new_simple("application/x-rtp",
+ "media", G_TYPE_STRING, payload_info->media_type,
+ "encoding-name", G_TYPE_STRING, payload_info->encoding_name,
+ "clock-rate", G_TYPE_INT, payload_info->clock_rate,
+ NULL);
+}
+
+int _add_transceiver(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, rtp_payload_info_s *payload_info)
+{
+ GstWebRTCRTPTransceiver *trans;
+ GstCaps *caps;
+ int av_idx = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? AV_IDX_AUDIO : AV_IDX_VIDEO;
+
+ RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+ RET_VAL_IF(payload_info == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payload_info is NULL");
+
+ caps = __make_transceiver_caps(payload_info);
+ PRINT_CAPS(caps, "transceiver");
+
+ if (!source->av[av_idx].transceiver) {
+ g_signal_emit_by_name(source->webrtc->gst.webrtcbin, "add-transceiver",
+ GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY, caps, &trans, NULL);
+ gst_object_unref(trans);
+ } else {
+ g_object_set(G_OBJECT(source->av[av_idx].transceiver), "codec-preferences", caps, NULL);
+ }
+
+ gst_caps_unref(caps);
+
+ LOG_DEBUG("webrtc[%p] source_id[%u] [%s] transceiver[%p] codec[%s]",
+ source->webrtc, source->id, payload_info->media_type, source->av[av_idx].transceiver, payload_info->encoding_name);
+
+ return WEBRTC_ERROR_NONE;
+}
+
+int _set_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e direction)
+{
+ webrtc_gst_slot_s *source;
+ GstWebRTCRTPTransceiver *trans;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(direction > WEBRTC_TRANSCEIVER_DIRECTION_SENDRECV, WEBRTC_ERROR_INVALID_PARAMETER, "invalid direction");
+ RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
+ RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
+ RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+ RET_VAL_IF(source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL && direction != WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY,
+ WEBRTC_ERROR_INVALID_PARAMETER, "null source only allow RECVONLY direction");
+
+ if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) {
+ trans = source->av[AV_IDX_AUDIO].transceiver;
+ source->av[AV_IDX_AUDIO].direction = direction;
+
+ } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) {
+ trans = source->av[AV_IDX_VIDEO].transceiver;
+ source->av[AV_IDX_VIDEO].direction = direction;
+
+ } else {
+ LOG_ERROR("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id);
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+ }
+
+ if (trans)
+ g_object_set(G_OBJECT(trans), "direction", __direction_info[direction].gst, NULL);
+
+ LOG_INFO("webrtc[%p] source_id[%u] media_type[%d] transceiver[%p, direction:%s]",
+ webrtc, source_id, media_type, trans, __direction_info[direction].str);
+
+ return WEBRTC_ERROR_NONE;
+}
+
+int _get_transceiver_direction(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_direction_e *direction)
+{
+ const webrtc_gst_slot_s *source;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(direction == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "direction is NULL");
+ RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
+ RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
+ RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+
+ if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) {
+ *direction = source->av[AV_IDX_AUDIO].direction;
+
+ } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) {
+ *direction = source->av[AV_IDX_VIDEO].direction;
+
+ } else {
+ LOG_ERROR("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id);
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+ }
+
+ LOG_INFO("webrtc[%p] source_id[%u] media_type[%d] direction[%s]",
+ webrtc, source_id, media_type, __direction_info[*direction].str);
+
+ return WEBRTC_ERROR_NONE;
+}
+
+static int __convert_audio_codec(const char *codec_name, webrtc_transceiver_codec_e *codec)
+{
+ RET_VAL_IF(codec_name == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec_name is NULL");
+ RET_VAL_IF(codec == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec is NULL");
+
+ if (!strcmp(codec_name, "pcmu") || !strcmp(codec_name, "PCMU")) {
+ *codec = WEBRTC_TRANSCEIVER_CODEC_PCMU;
+ return WEBRTC_ERROR_NONE;
+ }
+ if (!strcmp(codec_name, "pcma") || !strcmp(codec_name, "PCMA")) {
+ *codec = WEBRTC_TRANSCEIVER_CODEC_PCMA;
+ return WEBRTC_ERROR_NONE;
+ }
+ if (!strcmp(codec_name, "opus") || !strcmp(codec_name, "OPUS")) {
+ *codec = WEBRTC_TRANSCEIVER_CODEC_OPUS;
+ return WEBRTC_ERROR_NONE;
+ }
+
+ LOG_ERROR("not supported audio codec_name[%s]", codec_name);
+
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+}
+
+static int __convert_video_codec(const char *codec_name, webrtc_transceiver_codec_e *codec)
+{
+ RET_VAL_IF(codec_name == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec_name is NULL");
+ RET_VAL_IF(codec == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec is NULL");
+
+ if (!strcmp(codec_name, "vp8") || !strcmp(codec_name, "VP8")) {
+ *codec = WEBRTC_TRANSCEIVER_CODEC_VP8;
+ return WEBRTC_ERROR_NONE;
+ }
+ if (!strcmp(codec_name, "vp9") || !strcmp(codec_name, "VP9")) {
+ *codec = WEBRTC_TRANSCEIVER_CODEC_VP9;
+ return WEBRTC_ERROR_NONE;
+ }
+ if (!strcmp(codec_name, "h264") || !strcmp(codec_name, "H264")) {
+ *codec = WEBRTC_TRANSCEIVER_CODEC_H264;
+ return WEBRTC_ERROR_NONE;
+ }
+
+ LOG_ERROR("not supported video codec_name[%s]", codec_name);
+
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+}
+
+typedef int (*convert_codec_func)(const char *codec_name, webrtc_transceiver_codec_e *codec);
+
+static convert_codec_func convert_codec_funcs[] = {
+ [WEBRTC_MEDIA_TYPE_AUDIO] = __convert_audio_codec,
+ [WEBRTC_MEDIA_TYPE_VIDEO] = __convert_video_codec,
+};
+
+int _foreach_supported_transceiver_codec(webrtc_s *webrtc, webrtc_media_source_type_e source_type, webrtc_media_type_e media_type, webrtc_media_source_supported_transceiver_codec_cb callback, void *user_data)
+{
+ int ret;
+ webrtc_transceiver_codec_e codec;
+ GStrv codecs;
+ guint i;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(callback == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "callback is NULL");
+ RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
+ RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
+ RET_VAL_IF((source_type == WEBRTC_MEDIA_SOURCE_TYPE_FILE), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the file source");
+ RET_VAL_IF((source_type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the media packet source");
+ RET_VAL_IF((source_type > WEBRTC_MEDIA_SOURCE_TYPE_NULL), WEBRTC_ERROR_INVALID_PARAMETER, "invalid source_type");
+
+ if (media_type == WEBRTC_MEDIA_TYPE_AUDIO &&
+ (source_type == WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST ||
+ source_type == WEBRTC_MEDIA_SOURCE_TYPE_MIC ||
+ source_type == WEBRTC_MEDIA_SOURCE_TYPE_NULL)) {
+ codecs = _get_supported_codecs_from_ini(&webrtc->ini, source_type, MEDIA_TYPE_AUDIO);
+
+ } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO &&
+ (source_type == WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST ||
+ source_type == WEBRTC_MEDIA_SOURCE_TYPE_CAMERA ||
+ source_type == WEBRTC_MEDIA_SOURCE_TYPE_SCREEN ||
+ source_type == WEBRTC_MEDIA_SOURCE_TYPE_NULL)) {
+ codecs = _get_supported_codecs_from_ini(&webrtc->ini, source_type, MEDIA_TYPE_VIDEO);
+
+ } else {
+ LOG_ERROR("invalid media_type[%d] for source_type[%u]", media_type, source_type);
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+ }
+
+ LOG_INFO("webrtc[%p] source_type[%u] media_type[%d] callback[%p] user_data[%p]", webrtc, source_type, media_type, callback, user_data);
+
+ for (i = 0; i < g_strv_length(codecs); i++) {
+ if ((ret = convert_codec_funcs[media_type](codecs[i], &codec)) != WEBRTC_ERROR_NONE)
+ return ret;
+ LOG_INFO(" - supported %s codec: %s", media_type == WEBRTC_MEDIA_TYPE_AUDIO ? "audio" : "video", codecs[i]);
+ if (!callback(codec, user_data)) {
+ LOG_DEBUG("stop foreach callback");
+ break;
+ }
+ }
+
+ return WEBRTC_ERROR_NONE;
+}
+
+static int __validate_codec(webrtc_s *webrtc, webrtc_gst_slot_s *source, webrtc_media_type_e media_type, webrtc_transceiver_codec_e codec)
+{
+ int ret;
+ GStrv codecs;
+ webrtc_transceiver_codec_e _codec;
+ guint i;
+
+ RET_VAL_IF(webrtc == NULL, FALSE, "webrtc is NULL");
+ RET_VAL_IF(source == NULL, FALSE, "source is NULL");
+
+ if (media_type == WEBRTC_MEDIA_TYPE_AUDIO &&
+ source->media_types & MEDIA_TYPE_AUDIO &&
+ codec & CODEC_TYPE_AUDIO) {
+ codecs = _get_supported_codecs_from_ini(&webrtc->ini, source->type, MEDIA_TYPE_AUDIO);
+
+ } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO &&
+ source->media_types & MEDIA_TYPE_VIDEO &&
+ codec & CODEC_TYPE_VIDEO) {
+ codecs = _get_supported_codecs_from_ini(&webrtc->ini, source->type, MEDIA_TYPE_VIDEO);
+
+ } else {
+ LOG_ERROR("invalid media_type[%d], codec[0x%x] for source[media_types:0x%x, id:%u]",
+ media_type, codec, source->media_types, source->id);
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+ }
+
+ for (i = 0; i < g_strv_length(codecs); i++) {
+ if ((ret = convert_codec_funcs[media_type](codecs[i], &_codec)) != WEBRTC_ERROR_NONE)
+ return ret;
+ if (_codec == codec) {
+ LOG_DEBUG("codec[0x%x] is supported", codec);
+ return WEBRTC_ERROR_NONE;
+ }
+ }
+
+ LOG_ERROR("webrtc[%p] codec[0x%x] is not supported for this source type[%d]", webrtc, codec, source->type);
+
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+}
+
+int _set_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_codec_e codec)
+{
+ int ret;
+ webrtc_gst_slot_s *source;
+ int av_idx = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? AV_IDX_AUDIO : AV_IDX_VIDEO;
+ rtp_payload_info_s *payload_info = NULL;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
+ RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
+ RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+ RET_VAL_IF((source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the file source");
+ RET_VAL_IF((source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the media packet source");
+
+ payload_info = __get_payload_info(codec);
+ RET_VAL_IF(payload_info == NULL, WEBRTC_ERROR_INVALID_OPERATION, "could not find payload_info");
+
+ /* NOTE: for null source, set media_types here exceptionally. */
+ if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL)
+ source->media_types |= (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO;
+
+ if ((ret = __validate_codec(webrtc, source, media_type, codec)) != WEBRTC_ERROR_NONE)
+ return ret;
+
+ source->av[av_idx].codec = payload_info->encoding_name;
+
+ if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL) {
+ if (source->av[av_idx].pt >= MIN_DYNAMIC_PAYLOAD_TYPE)
+ _return_payload_type(webrtc, source->av[av_idx].pt);
+
+ if ((ret = _set_payload_type(webrtc, source, av_idx, payload_info->gst_media_type)) != WEBRTC_ERROR_NONE)
+ return ret;
+ }
+
+ /* FIXME: to utilize 'codec-preferences' of trans object, we need to re-create and re-link elements again */
+ LOG_INFO("webrtc[%p] source_id[%u] media_type[%d] codec[%s]", webrtc, source_id, media_type, payload_info->encoding_name);
+
+ return WEBRTC_ERROR_NONE;
+}
+
+int _get_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_transceiver_codec_e *codec)
+{
+ int ret;
+ webrtc_gst_slot_s *source;
+ const char *codec_str;
+ webrtc_transceiver_codec_e _codec;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(codec == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "codec is NULL");
+ RET_VAL_IF(webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "webrtcbin is NULL");
+ RET_VAL_IF(webrtc->gst.source_slots == NULL, WEBRTC_ERROR_INVALID_OPERATION, "source_slots is NULL");
+ RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+
+ if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) {
+ codec_str = source->av[AV_IDX_AUDIO].codec;
+
+ } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) {
+ codec_str = source->av[AV_IDX_VIDEO].codec;
+
+ } else {
+ LOG_ERROR("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id);
+ return WEBRTC_ERROR_INVALID_PARAMETER;
+ }
+
+ if ((ret = convert_codec_funcs[media_type](codec_str, &_codec)) != WEBRTC_ERROR_NONE)
+ return ret;
+
+ *codec = _codec;
+
+ LOG_INFO("webrtc[%p] source_id[%u] media_type[%d] codec[%s]", webrtc, source_id, media_type, codec_str);
+
+ return WEBRTC_ERROR_NONE;
+}
\ No newline at end of file