From fd5f8de0f35e3f60965da40ea23e12a04cb1abe6 Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Thu, 4 Jul 2024 17:15:37 +0900 Subject: [PATCH] webrtc_internal: Add webrtc_null_source_set_media_type() If this function is called to the particular null source(recvonly), then all of available codecs which defined in ini file are set to the transceiver. Therefore offer or answer description will represents various codec information via rtpmap attributes. [Version] 1.1.10 [Issue Type] Internal API Change-Id: Ifba9314b2eb769ae67a5dbdd8d9aab402ce28257 Signed-off-by: Sangchul Lee --- include/webrtc_internal.h | 17 ++++++ include/webrtc_private.h | 5 ++ packaging/capi-media-webrtc.spec | 2 +- src/webrtc_internal.c | 49 +++++++++++++++++ src/webrtc_source.c | 8 ++- src/webrtc_source_private.c | 1 - src/webrtc_transceiver.c | 90 ++++++++++++++++++++++++++++---- 7 files changed, 160 insertions(+), 12 deletions(-) diff --git a/include/webrtc_internal.h b/include/webrtc_internal.h index 1ff986e8..b3b7be9a 100644 --- a/include/webrtc_internal.h +++ b/include/webrtc_internal.h @@ -468,6 +468,23 @@ int webrtc_media_source_get_transceiver_recv_drop(webrtc_h webrtc, unsigned int */ int webrtc_media_source_get_type(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e *media_type); +/** + * @internal + * @brief Sets the media type to the null source. + * @since_tizen 9.0 + * @remarks If @a source_id is not a media source of #WEBRTC_MEDIA_SOURCE_TYPE_NULL, this function will return #WEBRTC_ERROR_INVALID_PARAMETER. + * @param[in] webrtc WebRTC handle + * @param[in] source_id The null source id + * @param[in] media_type The media type + * @return @c 0 on success, + * otherwise a negative error value + * @retval #WEBRTC_ERROR_NONE Successful + * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation + * @pre Add media source of #WEBRTC_MEDIA_SOURCE_TYPE_NULL to @a webrtc to get @a source_id by calling webrtc_add_media_source(). + */ +int webrtc_null_source_set_media_type(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type); + /** * @internal * @brief Gets the local session description. diff --git a/include/webrtc_private.h b/include/webrtc_private.h index 0dc8f253..97b322db 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -604,6 +604,11 @@ typedef struct _webrtc_gst_slot_s { unsigned int pt; bool pt_set_by_api; GHashTable *encodings; + struct { + const char *codec; + unsigned int pt; + } multiple_codecs[MAX_MLINE_NUM]; + int num_of_codecs; struct { unsigned int track_id; bool need_decoding; diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index dcd697cc..f6fa44d3 100644 --- a/packaging/capi-media-webrtc.spec +++ b/packaging/capi-media-webrtc.spec @@ -1,6 +1,6 @@ Name: capi-media-webrtc Summary: A WebRTC library in Tizen Native API -Version: 1.1.9 +Version: 1.1.10 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc_internal.c b/src/webrtc_internal.c index 4b319a76..31e98060 100644 --- a/src/webrtc_internal.c +++ b/src/webrtc_internal.c @@ -16,6 +16,7 @@ #include "webrtc_internal.h" #include "webrtc_private.h" +#include "webrtc_source_private.h" //LCOV_EXCL_START int webrtc_set_ecore_wl_display(webrtc_h webrtc, unsigned int track_id, void *ecore_wl_window) @@ -375,6 +376,54 @@ int webrtc_media_source_get_type(webrtc_h webrtc, unsigned int source_id, webrtc return WEBRTC_ERROR_NONE; } +int webrtc_null_source_set_media_type(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type) +{ + webrtc_s *_webrtc = (webrtc_s *)webrtc; + webrtc_gst_slot_s *source; + g_autoptr(GMutexLocker) locker = NULL; + int av_idx = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? AV_IDX_AUDIO : AV_IDX_VIDEO; + int av_opposite_idx = (av_idx == AV_IDX_AUDIO) ? AV_IDX_VIDEO : AV_IDX_AUDIO; + const ini_item_media_source_s *ini_source; + int ret; + g_autofree gchar *joined_str_codecs = NULL; + int i; + + RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + RET_VAL_IF(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0"); + + locker = g_mutex_locker_new(&_webrtc->mutex); + + RET_VAL_IF((source = _get_slot_by_id(_webrtc->gst.source_slots, source_id)) == NULL, + WEBRTC_ERROR_INVALID_PARAMETER, "could not find source"); + RET_VAL_IF(source->type != WEBRTC_MEDIA_SOURCE_TYPE_NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source type is not WEBRTC_MEDIA_SOURCE_TYPE_NULL"); + RET_VAL_IF(source->av[av_idx].codec, WEBRTC_ERROR_INVALID_OPERATION, "codec[%s] was already set", source->av[av_idx].codec); + RET_VAL_IF(source->av[av_opposite_idx].codec, WEBRTC_ERROR_INVALID_OPERATION, "codec[%s] was already set", source->av[av_opposite_idx].codec); + + ret = _build_src_check_params_and_get_ini_source(webrtc, source, &ini_source); + RET_VAL_IF(ret != WEBRTC_ERROR_NONE, ret, "failed to _build_src_check_params_and_get_ini_source()"); + + /* clean up the other side */ + for (i = 0; i < source->av[av_opposite_idx].num_of_codecs; i++) { + source->av[av_opposite_idx].multiple_codecs[i].codec = NULL; + source->av[av_opposite_idx].multiple_codecs[i].pt = 0; + } + + GStrv codecs = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? ini_source->a_codecs : ini_source->v_codecs; + source->av[av_idx].num_of_codecs = g_strv_length(codecs); + for (i = 0; i < source->av[av_idx].num_of_codecs; i++) { + source->av[av_idx].multiple_codecs[i].codec = codecs[i]; + } + + source->media_types = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO; + + LOG_INFO("webrtc[%p] source_id[%u] media_type[%d]", _webrtc, source_id, media_type); + + joined_str_codecs = g_strjoinv(" ", codecs); + LOG_INFO(" - codecs: %s", joined_str_codecs); + + return WEBRTC_ERROR_NONE; +} + int webrtc_get_local_description(webrtc_h webrtc, char **description) { g_autoptr(GMutexLocker) locker = NULL; diff --git a/src/webrtc_source.c b/src/webrtc_source.c index 4898a889..5716abe6 100644 --- a/src/webrtc_source.c +++ b/src/webrtc_source.c @@ -663,6 +663,7 @@ void _source_slot_destroy_cb(gpointer data) { webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)data; int i; + int j; RET_IF(source == NULL, "source is NULL"); @@ -695,6 +696,11 @@ void _source_slot_destroy_cb(gpointer data) g_hash_table_destroy(source->av[i].encodings); g_free(source->av[i].payloader_factory_name); + + for (j = 0; j < source->av[i].num_of_codecs; j++) { + if (source->av[i].multiple_codecs[j].pt > 0) + _return_payload_type(source->webrtc, source->av[i].multiple_codecs[j].pt); + } } if (source->bin) { @@ -1171,7 +1177,7 @@ static gboolean __check_codec_is_not_set_cb(gpointer key, gpointer value, gpoint if (source->type == GPOINTER_TO_INT(user_data)) { LOG_INFO("found media null source[%p, id:%u]", source, source->id); for (i = 0; i < AV_IDX_MAX; i++) { - if (source->av[i].codec) + if (source->av[i].codec || source->av[i].num_of_codecs > 0) return FALSE; } return TRUE; diff --git a/src/webrtc_source_private.c b/src/webrtc_source_private.c index cdd4bfbc..fc61ee6b 100644 --- a/src/webrtc_source_private.c +++ b/src/webrtc_source_private.c @@ -24,7 +24,6 @@ int _build_src_check_params_and_get_ini_source(webrtc_s *webrtc, webrtc_gst_slot RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL"); RET_VAL_IF(ini_source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "ini_source is NULL"); - RET_VAL_IF(source->bin == NULL, WEBRTC_ERROR_INVALID_OPERATION, "bin is NULL"); if (!(*ini_source = _ini_get_source_by_type(&webrtc->ini, source->type))) { LOG_ERROR("ini_source is NULL"); diff --git a/src/webrtc_transceiver.c b/src/webrtc_transceiver.c index e162b6a9..df4c3006 100644 --- a/src/webrtc_transceiver.c +++ b/src/webrtc_transceiver.c @@ -423,6 +423,70 @@ static int __add_transceiver_for_simulcast(webrtc_gst_slot_s *source, webrtc_med return WEBRTC_ERROR_NONE; } +int __add_transceiver_with_multiple_codecs(webrtc_gst_slot_s *source, webrtc_media_type_e media_type) +{ + int i; + GstWebRTCRTPTransceiver *trans; + GstCaps *caps = NULL; + GstCaps *_caps; + int av_idx = (media_type == WEBRTC_MEDIA_TYPE_AUDIO) ? AV_IDX_AUDIO : AV_IDX_VIDEO; + rtp_payload_info_s *payload_info = NULL; + int pt; + + ASSERT(source); + + for (i = 0; i < source->av[av_idx].num_of_codecs; i++) { + if (!(payload_info = __get_payload_info_by_encoding_name(source->av[av_idx].multiple_codecs[i].codec))) + return WEBRTC_ERROR_INVALID_OPERATION; + + if ((pt = __get_available_payload_type(source->webrtc)) == -1) + return WEBRTC_ERROR_INVALID_OPERATION; + + source->av[av_idx].multiple_codecs[i].pt = pt; + + _caps = 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, pt, + NULL); + if (payload_info->codec == WEBRTC_TRANSCEIVER_CODEC_OPUS) + gst_caps_set_simple(_caps, + "encoding-params", G_TYPE_STRING, "2", + NULL); + else if (payload_info->codec == WEBRTC_TRANSCEIVER_CODEC_H264) + gst_caps_set_simple(_caps, + "level-asymmetry-allowed", G_TYPE_STRING, "1", + "packetization-mode", G_TYPE_STRING, "1", + "profile-level-id", G_TYPE_STRING, "42e01f", + NULL); + + if (i == 0) + caps = _caps; + else + gst_caps_append(caps, _caps); + } + + ASSERT(caps); + 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]", + source->webrtc, source->id, payload_info->media_type, source->av[av_idx].transceiver); + + return WEBRTC_ERROR_NONE; +} + int _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source) { rtp_payload_info_s *payload_info = NULL; @@ -433,12 +497,17 @@ int _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source) for (i = AV_IDX_AUDIO; i < AV_IDX_MAX; i++) { media_type = (i == AV_IDX_AUDIO) ? WEBRTC_MEDIA_TYPE_AUDIO : WEBRTC_MEDIA_TYPE_VIDEO; - if (source->av[i].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[i].codec) { - if (g_hash_table_size(source->av[i].encodings) > 0) - __add_transceiver_for_simulcast(source, media_type); - else if (!(payload_info = __get_payload_info_by_encoding_name(source->av[i].codec))) - return WEBRTC_ERROR_INVALID_OPERATION; - _add_transceiver(source, media_type, payload_info); + if (source->av[i].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY) { + if (source->av[i].codec) { + if (g_hash_table_size(source->av[i].encodings) > 0) + __add_transceiver_for_simulcast(source, media_type); + else if (!(payload_info = __get_payload_info_by_encoding_name(source->av[i].codec))) + return WEBRTC_ERROR_INVALID_OPERATION; + _add_transceiver(source, media_type, payload_info); + + } else if (source->av[i].num_of_codecs > 0) { + __add_transceiver_with_multiple_codecs(source, media_type); + } } } return WEBRTC_ERROR_NONE; @@ -470,8 +539,8 @@ int _add_transceiver(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, 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"); + ASSERT(source); + ASSERT(payload_info); caps = __make_transceiver_caps(payload_info); PRINT_CAPS(caps, "transceiver"); @@ -712,13 +781,16 @@ int _set_transceiver_codec(webrtc_s *webrtc, unsigned int source_id, webrtc_medi /* 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; + 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; + /* clean up multiple codecs */ + source->av[av_idx].num_of_codecs = 0; + /* 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); -- 2.34.1