Add webrtc_start_media_source() function 22/308722/5
authorSangchul Lee <sc11.lee@samsung.com>
Fri, 29 Mar 2024 07:20:44 +0000 (16:20 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Mon, 10 Jun 2024 01:45:46 +0000 (10:45 +0900)
This function will be used after adding a media source during state
of #WEBRTC_STATE_NEGOTIATING or #WEBRTC_STATE_PLAYING.
It has been added for re-negotiation scenario.

[Version] 1.1.0
[Issue Type] API

Change-Id: I0985473ce0c37767c8734072104f9b34132475a5
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
include/webrtc.h
include/webrtc_private.h
packaging/capi-media-webrtc.spec
src/webrtc.c
src/webrtc_internal.c
src/webrtc_source.c
src/webrtc_source_private.c
src/webrtc_transceiver.c

index fff6aee391a1b5f4efe59f44b8d6aefac2750a00..c1b0f8645886aa203f6269600b85e1a726c7c22e 100644 (file)
@@ -1650,6 +1650,24 @@ int webrtc_screen_source_set_crop(webrtc_h webrtc, unsigned int source_id, int x
  */
 int webrtc_screen_source_unset_crop(webrtc_h webrtc, unsigned int source_id);
 
+/**
+ * @brief Starts the media source.
+ * @since_tizen 9.0
+ * @remarks This function will be used after adding a media source during state of #WEBRTC_STATE_NEGOTIATING or #WEBRTC_STATE_PLAYING.\n
+ *          If the state is #WEBRTC_STATE_IDLE, this function will have no effect. Rather webrtc_start() will start media sources later.
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] source_id   The media source id
+ * @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
+ * @see webrtc_add_media_source()
+ * @see webrtc_remove_media_source()
+ * @see webrtc_start()
+ */
+int webrtc_start_media_source(webrtc_h webrtc, unsigned int source_id);
+
 /**
  * @}
  */
index 20fb2a659448812b9e8ef819e69f05411b92fd2b..bbafd1ac6dfe0b39ee7c8441eb4fab6322350f61 100644 (file)
@@ -747,7 +747,7 @@ 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 _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);
@@ -810,6 +810,7 @@ const char *_get_video_media_type(const char *codec_name);
 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 _start_media_source(webrtc_s *webrtc, unsigned int source_id);
 int _remove_media_source(webrtc_s *webrtc, unsigned int source_id);
 bool _check_if_codec_is_set_to_null_sources(webrtc_s *webrtc);
 bool _check_if_format_is_set_to_packet_sources(webrtc_s *webrtc);
index 4ecae43225fbc8da9dbcf9aa0da864a0f3236f5b..0f54ce34b1f608b85df645697a12ff42a8141a6a 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    1.0.5
+Version:    1.1.0
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index be1ebffeab329756a7c86a9ca198b86021977824..71307fb562ee8254a19eceb60ccc6b40c5286f65 100644 (file)
@@ -720,7 +720,6 @@ int webrtc_file_source_get_looping(webrtc_h webrtc, unsigned int source_id, bool
        return _get_filesrc_looping(_webrtc, source_id, looping);
 }
 
-//LCOV_EXCL_START
 int webrtc_screen_source_set_crop(webrtc_h webrtc, unsigned int source_id, int x, int y, int width, int height)
 {
        g_autoptr(GMutexLocker) locker = NULL;
@@ -766,7 +765,24 @@ int webrtc_screen_source_unset_crop(webrtc_h webrtc, unsigned int source_id)
        return WEBRTC_ERROR_INVALID_OPERATION;
 #endif
 }
-//LCOV_EXCL_STOP
+
+int webrtc_start_media_source(webrtc_h webrtc, unsigned int source_id)
+{
+       g_autoptr(GMutexLocker) locker = NULL;
+       webrtc_s *_webrtc = (webrtc_s *)webrtc;
+
+       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);
+
+       if (_webrtc->state == WEBRTC_STATE_IDLE) {
+               LOG_DEBUG("webrtc_start() will take charge of starting media sources");
+               return WEBRTC_ERROR_NONE;
+       }
+
+       return _start_media_source(webrtc, source_id);
+}
 
 int webrtc_set_sound_stream_info(webrtc_h webrtc, unsigned int track_id, sound_stream_info_h stream_info)
 {
index ce6c5effff09008d292d1f1571bf16c09911afcc..b26fc7fc03aa2334ba3492ace6e75611bb1772bc 100644 (file)
@@ -132,7 +132,6 @@ int webrtc_media_source_set_video_loopback_to_ecore_wl(webrtc_h webrtc, unsigned
 
 int webrtc_add_media_source_internal(webrtc_h webrtc, webrtc_media_source_type_internal_e type, unsigned int *source_id)
 {
-       int ret = WEBRTC_ERROR_NONE;
        g_autoptr(GMutexLocker) locker = NULL;
        webrtc_s *_webrtc = (webrtc_s *)webrtc;
 
@@ -141,11 +140,7 @@ int webrtc_add_media_source_internal(webrtc_h webrtc, webrtc_media_source_type_i
 
        locker = g_mutex_locker_new(&_webrtc->mutex);
 
-       ret = _add_media_source_internal(webrtc, type, source_id);
-       if (ret == WEBRTC_ERROR_NONE)
-               LOG_INFO("source_id[%u]", *source_id);
-
-       return ret;
+       return _add_media_source_internal(webrtc, type, source_id);
 }
 
 int webrtc_media_source_set_payload_type(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, unsigned int pt)
index 06055da8eb21b188eafb3acb1382ba8adc384909..53404ca5f3774d535244f60a8753a983f73981a9 100644 (file)
@@ -306,9 +306,39 @@ exit:
        return WEBRTC_ERROR_INVALID_OPERATION;
 }
 
+static int __complete_source(webrtc_s *webrtc, webrtc_gst_slot_s *source)
+{
+       int ret;
+
+       RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
+
+       LOG_DEBUG("source[id:%u, type:%d, media_types:0x%x]", source->id, source->type, source->media_types);
+
+       if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE)
+               return WEBRTC_ERROR_NONE;
+
+       if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET ||
+               source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL)
+               goto add_transceiver;
+
+       ret = (source->media_types == MEDIA_TYPE_AUDIO) ?
+               __complete_rest_of_audiosrc(webrtc, source) : __complete_rest_of_videosrc(webrtc, source);
+       if (ret != WEBRTC_ERROR_NONE)
+               return ret;
+       if (!gst_element_sync_state_with_parent(GST_ELEMENT(source->bin))) {
+               LOG_ERROR("failed to gst_element_sync_state_with_parent() for [%s]", GST_ELEMENT_NAME(source->bin));
+               return WEBRTC_ERROR_INVALID_OPERATION;
+       }
+
+add_transceiver:
+       return _check_and_add_recvonly_transceiver(source);
+}
+
 int _complete_sources(webrtc_s *webrtc)
 {
        int i;
+       int ret;
        webrtc_gst_slot_s *source;
        RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
 
@@ -316,25 +346,64 @@ int _complete_sources(webrtc_s *webrtc)
                if (!(source = webrtc->gst.sources[i]))
                        continue;
 
-               LOG_DEBUG("source[id:%u, type:%d, media_types:0x%x]", source->id, source->type, source->media_types);
+               if ((ret = __complete_source(webrtc, source)) != WEBRTC_ERROR_NONE)
+                       return ret;
+       }
 
-               if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE)
-                       continue;
+       return WEBRTC_ERROR_NONE;
+}
 
-               if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET ||
-                       source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL) {
-                       goto add_transceiver;
-               }
+int _start_media_source(webrtc_s *webrtc, unsigned int source_id)
+{
+       int ret;
+       webrtc_gst_slot_s *source;
 
-               if (source->media_types == MEDIA_TYPE_AUDIO)
-                       __complete_rest_of_audiosrc(webrtc, source);
-               else
-                       __complete_rest_of_videosrc(webrtc, source);
+       ASSERT(webrtc);
 
-add_transceiver:
-               _check_and_add_recvonly_transceiver(source);
+       RET_VAL_IF(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0");
+       RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "could not find source");
+
+       switch (source->type) {
+       case WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET:
+               if (!source->media_format) {
+                       LOG_ERROR("media format must be set to the media packet");
+                       return WEBRTC_ERROR_INVALID_OPERATION;
+               }
+               break;
+       case WEBRTC_MEDIA_SOURCE_TYPE_FILE: {
+               gchar *location = NULL;
+               g_object_get(G_OBJECT(gst_bin_get_by_name(GST_BIN(source->filesrc_pipeline), ELEMENT_NAME_FILE_SRC)), "location", &location, NULL);
+               if (!location) {
+                       LOG_ERROR("location must be set to the file source");
+                       return WEBRTC_ERROR_INVALID_OPERATION;
+               }
+               g_free(location);
+               break;
+       }
+       case WEBRTC_MEDIA_SOURCE_TYPE_NULL: {
+               int i;
+               bool found = false;
+               for (i = 0; i < AV_IDX_MAX; i++) {
+                       if (source->av[i].codec) {
+                               found = true;
+                               break;
+                       }
+               }
+               if (!found) {
+                       LOG_ERROR("codec must be set to the null source");
+                       return WEBRTC_ERROR_INVALID_OPERATION;
+               }
+               break;
+       }
        }
 
+       /* TODO: add resource check */
+
+       ret = __complete_source(webrtc, source);
+       RET_VAL_IF(ret != WEBRTC_ERROR_NONE, ret, "failed to complete sources");
+
+       LOG_INFO("webrtc[%p] source[type:%d, id:%u]", webrtc, source->type, source_id);
+
        return WEBRTC_ERROR_NONE;
 }
 
index 5df60b4b79da952a9229bb82ff728cf3d12e4f93..c871ba5e3c9986c2bf192eb6a28921b400ac5186 100644 (file)
@@ -1077,6 +1077,7 @@ static gboolean __foreach_src_pad_cb(GstElement *element, GstPad *pad, gpointer
 {
        webrtc_gst_slot_s *source = (webrtc_gst_slot_s *)user_data;
        GstPad *peer = gst_pad_get_peer(pad);
+       GstWebRTCRTPTransceiver *transceiver;
 
        RET_VAL_IF(source == NULL, FALSE, "source is NULL");
        RET_VAL_IF(source->webrtc == NULL, FALSE, "webrtc is NULL");
@@ -1087,6 +1088,17 @@ static gboolean __foreach_src_pad_cb(GstElement *element, GstPad *pad, gpointer
 
        LOG_DEBUG("about to release request pad[%s]", GST_PAD_NAME(peer));
 
+       /* Should it be done manually? */
+       g_object_get(peer, "transceiver", &transceiver, NULL);
+       g_object_set(transceiver, "direction", GST_WEBRTC_RTP_TRANSCEIVER_DIRECTION_INACTIVE, NULL);
+
+       gst_pad_unlink(pad, peer);
+       LOG_DEBUG("unlink pads[%s - %s]", GST_PAD_NAME(pad), GST_PAD_NAME(peer));
+
+       /* FIXME: setting gst state to NULL when WEBRTC_STATE_NEGOTIATING occurs a blocking issue. */
+       if (source->webrtc->state == WEBRTC_STATE_PLAYING)
+               gst_element_set_state(GST_ELEMENT(source->bin), GST_STATE_NULL);
+
        gst_element_release_request_pad(source->webrtc->gst.webrtcbin, peer);
 
        /* Two unrefing here, one for getting request pad, another one for getting peer pad */
index 56d2fd3813407937733f8fb02ddfd93238d2f693..31f708758b18a1dfd83c20da07dde261403f31d7 100644 (file)
@@ -417,25 +417,25 @@ static int __add_transceiver_for_simulcast(webrtc_gst_slot_s *source, webrtc_med
        return WEBRTC_ERROR_NONE;
 }
 
-void _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source)
+int _check_and_add_recvonly_transceiver(webrtc_gst_slot_s *source)
 {
        rtp_payload_info_s *payload_info = NULL;
+       int i;
+       webrtc_media_type_e media_type;
 
-       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 (g_hash_table_size(source->av[AV_IDX_AUDIO].encodings) > 0)
-                       __add_transceiver_for_simulcast(source, WEBRTC_MEDIA_TYPE_AUDIO);
-               else if ((payload_info = __get_payload_info_by_encoding_name(source->av[AV_IDX_AUDIO].codec)))
-                       _add_transceiver(source, WEBRTC_MEDIA_TYPE_AUDIO, payload_info);
-       }
+       RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL");
 
-       if (source->av[AV_IDX_VIDEO].direction == WEBRTC_TRANSCEIVER_DIRECTION_RECVONLY && source->av[AV_IDX_VIDEO].codec) {
-               if (g_hash_table_size(source->av[AV_IDX_VIDEO].encodings) > 0)
-                       __add_transceiver_for_simulcast(source, WEBRTC_MEDIA_TYPE_VIDEO);
-               else if ((payload_info = __get_payload_info_by_encoding_name(source->av[AV_IDX_VIDEO].codec)))
-                       _add_transceiver(source, WEBRTC_MEDIA_TYPE_VIDEO, payload_info);
+       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);
+               }
        }
+       return WEBRTC_ERROR_NONE;
 }
 
 static GstCaps *__make_transceiver_caps(rtp_payload_info_s *payload_info)