- In case of TV profile, functions are disabled.
[Version] 0.1.89
[Issue Type] New feature
Change-Id: Ida0e5049b667c2cb14756d03dae25d9d757178bf
Signed-off-by: Hyunil <hyunil46.park@samsung.com>
SET(dependents "dlog glib-2.0 gstreamer-1.0 gstreamer-webrtc-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 \
json-glib-1.0 iniparser mm-common mm-display-interface capi-media-tool libtbm libwebsockets \
cynara-client libsmack")
+IF(TIZEN_FEATURE_RESOURCE_MANAGER)
+SET(dependents "${dependents} mm-resource-manager")
+ADD_DEFINITIONS("-DTIZEN_FEATURE_RES_MGR")
+ENDIF()
SET(pc_dependents "capi-base-common" )
LIST (APPEND SOURCES
${MAIN_SRC}
)
+IF(NOT TIZEN_FEATURE_RESOURCE_MANAGER)
+LIST (REMOVE_ITEM SOURCES src/webrtc_resource.c)
+ENDIF()
ADD_LIBRARY(${fw_name} SHARED ${SOURCES})
#endif
#include <iniparser.h>
#include <mm_display_interface.h>
+#ifdef TIZEN_FEATURE_RES_MGR
+#include <mm_resource_manager.h>
+#endif
#include <tbm_bufmgr.h>
#include <libwebsockets.h>
#define MLINES_IDX_AUDIO 0
#define MLINES_IDX_VIDEO 1
+#ifdef TIZEN_FEATURE_RES_MGR
+#define RESOURCE_TYPE_MAX MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER + 1
+
+typedef struct _webrtc_resource_s {
+ mm_resource_manager_h mgr;
+ mm_resource_manager_res_h res[RESOURCE_TYPE_MAX];
+ gboolean need_to_acquire[RESOURCE_TYPE_MAX];
+ gboolean release_cb_is_calling;
+} webrtc_resource_s;
+#endif
+
typedef struct _ini_item_general_s {
bool generate_dot;
const char *dot_path;
const gchar *ice_connection_state;
const gchar *ice_gathering_state;
} internal_states;
+#ifdef TIZEN_FEATURE_RES_MGR
+ webrtc_resource_s resource;
+#endif
} webrtc_s;
typedef struct _webrtc_data_channel_s {
void _unload_ini(webrtc_s *webrtc);
ini_item_media_source_s* _ini_get_source_by_type(webrtc_ini_s *ini, webrtc_media_source_type_e type);
+int _webrtc_stop(webrtc_s *webrtc);
int _gst_init(webrtc_s *webrtc);
int _gst_build_pipeline(webrtc_s *webrtc);
void _gst_destroy_pipeline(webrtc_s *webrtc);
int _apply_display(webrtc_display_s *display);
void _video_stream_decoded_cb(GstElement *object, GstBuffer *buffer, GstPad *pad, gpointer data);
+#ifdef TIZEN_FEATURE_RES_MGR
+int _acquire_resource_if_needed(webrtc_s *webrtc);
+int _create_resource_manager(webrtc_s *webrtc);
+int _destroy_resource_manager(webrtc_s *webrtc);
+int _acquire_resource_for_type(webrtc_s *webrtc, mm_resource_manager_res_type_e type);
+int _release_all_resources(webrtc_s *webrtc);
+#endif
+
webrtc_tbm_s *_alloc_tbm(void);
void _release_tbm(webrtc_tbm_s *tbm);
void _create_tbm_bo_list(webrtc_tbm_s *tbm, int bo_size, int list_length);
Name: capi-media-webrtc
Summary: A WebRTC library in Tizen Native API
-Version: 0.1.88
+Version: 0.1.89
Release: 0
Group: Multimedia/API
License: Apache-2.0
BuildRequires: pkgconfig(libwebsockets)
BuildRequires: pkgconfig(cynara-client)
BuildRequires: pkgconfig(libsmack)
+%if "%{tizen_profile_name}" != "tv"
+BuildRequires: pkgconfig(mm-resource-manager)
+%endif
%description
A WebRTC library in Tizen Native API.
%build
MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
-cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER}
+cmake . -DCMAKE_INSTALL_PREFIX=/usr -DFULLVER=%{version} -DMAJORVER=${MAJORVER} \
+%if "%{tizen_profile_name}" != "tv"
+-DTIZEN_FEATURE_RESOURCE_MANAGER=on
+%else
+-DTIZEN_FEATURE_RESOURCE_MANAGER=off
+%endif
make %{?jobs:-j%jobs}
_webrtc = g_new0(webrtc_s, 1);
+#ifdef TIZEN_FEATURE_RES_MGR
+ ret = _create_resource_manager(_webrtc);
+ if (ret != WEBRTC_ERROR_NONE) {
+ LOG_ERROR("failed to create resource manager");
+ g_free(_webrtc);
+ return ret;
+ }
+#endif
g_mutex_init(&_webrtc->mutex);
g_mutex_lock(&_webrtc->mutex);
_gst_pipeline_set_state(webrtc, GST_STATE_NULL);
+#ifdef TIZEN_FEATURE_RES_MGR
+ if (_destroy_resource_manager(_webrtc) != WEBRTC_ERROR_NONE)
+ LOG_ERROR("failed to destroy webrtc[%p]", webrtc);
+#endif
_webrtc->pend_state = WEBRTC_STATE_IDLE;
_webrtc->state = _webrtc->pend_state;
int webrtc_start(webrtc_h webrtc)
{
+ int ret = WEBRTC_ERROR_NONE;
webrtc_s *_webrtc = (webrtc_s*)webrtc;
RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
RET_VAL_WITH_UNLOCK_IF(_webrtc->gst.webrtcbin == NULL, WEBRTC_ERROR_INVALID_OPERATION, &_webrtc->mutex, "webrtcbin is NULL");
RET_VAL_WITH_UNLOCK_IF(!_check_if_format_is_set_to_packet_sources(_webrtc), WEBRTC_ERROR_INVALID_OPERATION, &_webrtc->mutex, "the media format should be set");
+#ifdef TIZEN_FEATURE_RES_MGR
+ ret = _acquire_resource_if_needed(_webrtc);
+ if (ret != WEBRTC_ERROR_NONE) {
+ LOG_ERROR("failed to acquire resource, webrtc[%p]", _webrtc);
+ g_mutex_unlock(&_webrtc->mutex);
+ return ret;
+ }
+#endif
_gst_pipeline_set_state(webrtc, GST_STATE_PLAYING);
_webrtc->pend_state = WEBRTC_STATE_NEGOTIATING;
g_mutex_unlock(&_webrtc->mutex);
- return WEBRTC_ERROR_NONE;
+ return ret;
}
int webrtc_stop(webrtc_h webrtc)
RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
- g_mutex_lock(&_webrtc->mutex);
-
- RET_VAL_WITH_UNLOCK_IF(_webrtc->state == WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &_webrtc->mutex, "the state should NOT be IDLE");
-
- _gst_pipeline_set_state(_webrtc, GST_STATE_NULL);
-
- _post_state_in_idle(_webrtc, WEBRTC_STATE_IDLE);
-
- LOG_INFO("webrtc[%p] is stopping", webrtc);
-
- g_hash_table_remove_all(_webrtc->gst.sink_slots);
- g_hash_table_remove_all(_webrtc->data_channels);
-
- g_mutex_unlock(&_webrtc->mutex);
-
- return WEBRTC_ERROR_NONE;
+ return _webrtc_stop(_webrtc);
}
int webrtc_get_state(webrtc_h webrtc, webrtc_state_e *state)
LOG_INFO("data[%p] size[%u]", *data, *size);
return WEBRTC_ERROR_NONE;
-}
\ No newline at end of file
+}
return (signaling_state == GST_WEBRTC_SIGNALING_STATE_HAVE_REMOTE_OFFER);
}
+
+int _webrtc_stop(webrtc_s *webrtc)
+{
+ int ret = WEBRTC_ERROR_NONE;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+
+ g_mutex_lock(&webrtc->mutex);
+
+ RET_VAL_WITH_UNLOCK_IF(webrtc->state == WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, &webrtc->mutex, "the state should not be IDLE");
+
+ _gst_pipeline_set_state(webrtc, GST_STATE_NULL);
+
+#ifdef TIZEN_FEATURE_RES_MGR
+ ret = _release_all_resources(webrtc);
+ RET_VAL_WITH_UNLOCK_IF(ret != WEBRTC_ERROR_NONE, ret, &webrtc->mutex, "failed to release all resources");
+#endif
+ _post_state_in_idle(webrtc, WEBRTC_STATE_IDLE);
+
+ LOG_INFO("webrtc[%p] is stopping", webrtc);
+
+ g_mutex_unlock(&webrtc->mutex);
+
+ return ret;
+}
--- /dev/null
+
+/*
+ * Copyright (c) 2021 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.h"
+#include "webrtc_private.h"
+
+int _acquire_resource_if_needed(webrtc_s *webrtc)
+{
+ int i;
+ int ret = WEBRTC_ERROR_NONE;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+
+ for (i = 0; i < RESOURCE_TYPE_MAX; i++) {
+ if (webrtc->resource.need_to_acquire[i] == true) {
+ ret = _acquire_resource_for_type(webrtc, i);
+ if (ret != WEBRTC_ERROR_NONE)
+ return ret;
+ webrtc->resource.need_to_acquire[i] = false;
+ }
+ }
+
+ return ret;
+}
+
+static int __resource_release_cb(mm_resource_manager_h mgr,
+ mm_resource_manager_res_h res, void *user_data)
+{
+ int i;
+ int ret = true;
+ webrtc_s *webrtc = (webrtc_s *)user_data;
+
+ RET_VAL_IF(webrtc == NULL, false, "webrtc is NULL");
+
+ webrtc->resource.release_cb_is_calling = true;
+
+ for (i = 0; i < RESOURCE_TYPE_MAX; i++) {
+ if (webrtc->resource.res[i] == res) {
+ LOG_INFO("type[%d] resource was released by resource manager", i);
+ webrtc->resource.res[i] = NULL;
+ }
+ }
+
+ if (_webrtc_stop(webrtc) != WEBRTC_ERROR_NONE)
+ ret = false;
+
+ webrtc->resource.release_cb_is_calling = false;
+
+ return ret;
+}
+
+int _create_resource_manager(webrtc_s *webrtc)
+{
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+
+ if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA,
+ __resource_release_cb, webrtc,
+ &webrtc->resource.mgr) != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ LOG_ERROR("Failed to init resource manager for media");
+ return WEBRTC_ERROR_RESOURCE_FAILED;
+ }
+
+ return WEBRTC_ERROR_NONE;
+}
+
+static bool __is_valid_resource_type(mm_resource_manager_res_type_e type)
+{
+ if (type < MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER || type >= RESOURCE_TYPE_MAX) {
+ LOG_ERROR("Type[%d] is a invalid resource type", type);
+ return false;
+ }
+ return true;
+}
+
+int _acquire_resource_for_type(webrtc_s *webrtc, mm_resource_manager_res_type_e type)
+{
+ int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(webrtc->resource.mgr == NULL, WEBRTC_ERROR_INVALID_PARAMETER,
+ "resource manager is NULL");
+ RET_VAL_IF(!__is_valid_resource_type(type), WEBRTC_ERROR_INVALID_PARAMETER,
+ "type is wrong");
+
+ if (webrtc->resource.res[type] != NULL) {
+ LOG_ERROR("type[%d] resource was already acquired", type);
+ return WEBRTC_ERROR_RESOURCE_FAILED;
+ }
+
+ LOG_DEBUG("mark for acquire type[%d] resource", type);
+ ret = mm_resource_manager_mark_for_acquire(webrtc->resource.mgr, type,
+ MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &webrtc->resource.res[type]);
+ if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ LOG_ERROR("failed to mark resource for acquire, ret[0x%x]", ret);
+ return WEBRTC_ERROR_RESOURCE_FAILED;
+ }
+
+ LOG_DEBUG("commit type[%d] resource", type);
+ ret = mm_resource_manager_commit(webrtc->resource.mgr);
+ if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ LOG_ERROR("failed to commit of resource, ret([0x%x]", ret);
+ return WEBRTC_ERROR_RESOURCE_FAILED;
+ }
+
+ return WEBRTC_ERROR_NONE;
+}
+
+int _release_all_resources(webrtc_s *webrtc)
+{
+ int i;
+ int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(webrtc->resource.mgr == NULL, WEBRTC_ERROR_INVALID_PARAMETER,
+ "resource manager is NULL");
+
+ if(webrtc->resource.release_cb_is_calling) {
+ LOG_INFO("__resource_release_cb is calling, so skip");
+ return WEBRTC_ERROR_NONE;
+ }
+
+ ret = mm_resource_manager_mark_all_for_release(webrtc->resource.mgr);
+ if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ LOG_ERROR("failed to mark all for release, ret[0x%x]", ret);
+ return WEBRTC_ERROR_RESOURCE_FAILED;
+ }
+ ret = mm_resource_manager_commit(webrtc->resource.mgr);
+ if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ LOG_ERROR("failed to commit resource, ret[0x%x]", ret);
+ return WEBRTC_ERROR_RESOURCE_FAILED;
+ }
+ LOG_DEBUG("all resources were released by resource manager");
+
+ for (i = 0; i < RESOURCE_TYPE_MAX; i++) {
+ webrtc->resource.need_to_acquire[i] = false;
+ webrtc->resource.res[i] = NULL;
+ }
+
+ return WEBRTC_ERROR_NONE;
+}
+
+int _destroy_resource_manager(webrtc_s *webrtc)
+{
+ int ret = MM_RESOURCE_MANAGER_ERROR_NONE;
+
+ RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+ RET_VAL_IF(webrtc->resource.mgr == NULL, WEBRTC_ERROR_INVALID_PARAMETER,
+ "resource manager is NULL");
+
+ ret = mm_resource_manager_destroy(webrtc->resource.mgr);
+ if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) {
+ LOG_ERROR("failed to destroy resource manager, ret[0x%x]", ret);
+ return WEBRTC_ERROR_RESOURCE_FAILED;
+ }
+ webrtc->resource.mgr = NULL;
+ LOG_DEBUG("destroyed resource manager");
+
+ return WEBRTC_ERROR_NONE;
+}
GstElement *videosink;
const char *videosink_factory_name;
bool display_is_set = false;
+ int ret = WEBRTC_ERROR_NONE;
RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
RET_VAL_IF(decodebin == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "decodebin is NULL");
sink->media_types |= MEDIA_TYPE_VIDEO;
- if (!(videoconvert = _create_element(DEFAULT_ELEMENT_VIDEOCONVERT, NULL))) {
- LOG_ERROR("failed to create videoconvert");
- return WEBRTC_ERROR_INVALID_OPERATION;
- }
-
videosink_factory_name = __get_videosink_factory_name(sink->display, DEFAULT_ELEMENT_VIDEOSINK, &display_is_set);
-
+#ifdef TIZEN_FEATURE_RES_MGR
+ if (!g_strcmp0(videosink_factory_name, DEFAULT_ELEMENT_VIDEOSINK)) {
+ webrtc->resource.need_to_acquire[MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY] = true;
+ if ((ret =_acquire_resource_for_type(webrtc, MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY)))
+ return ret;
+ }
+#endif
if (!(videosink = _create_element(videosink_factory_name, NULL))) {
LOG_ERROR("failed to create videosink[%s]", videosink_factory_name);
return WEBRTC_ERROR_INVALID_OPERATION;
}
}
+ if (!(videoconvert = _create_element(DEFAULT_ELEMENT_VIDEOCONVERT, NULL))) {
+ LOG_ERROR("failed to create videoconvert");
+ return WEBRTC_ERROR_INVALID_OPERATION;
+ }
+
gst_bin_add_many(GST_BIN(sink->bin), videoconvert, videosink, NULL);
if (!gst_element_sync_state_with_parent(videoconvert)) {
return WEBRTC_ERROR_INVALID_OPERATION;
}
- return WEBRTC_ERROR_NONE;
+ return ret;
}
static int __build_audiosink(webrtc_s *webrtc, GstElement *decodebin, GstPad *src_pad)
if (str_arr == NULL || !g_strv_contains((const gchar * const *)str_arr, factory_name)) {
LOG_WARNING("this video hw decoder element[%s] is not specified in ini file, skip it", factory_name);
return GST_AUTOPLUG_SELECT_SKIP;
+#ifdef TIZEN_FEATURE_RES_MGR
+ } else {
+ webrtc->resource.need_to_acquire[MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER] = true;
+ if (_acquire_resource_for_type(webrtc, MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER) != WEBRTC_ERROR_NONE)
+ return GST_AUTOPLUG_SELECT_SKIP;
+#endif
}
}
sink->display->object = display;
return _apply_display(sink->display);
-}
\ No newline at end of file
+}
static GstElement *__get_hw_encoder_element(webrtc_s *webrtc, webrtc_media_source_type_e type)
{
ini_item_media_source_s *source;
+ GstElement *encoder = NULL;
RET_VAL_IF(webrtc == NULL, NULL, "webrtc is NULL");
if (type == WEBRTC_MEDIA_SOURCE_TYPE_CAMERA || type == WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST) {
if (source && source->v_hw_encoder_element)
- return _create_element(source->v_hw_encoder_element, NULL);
- if (webrtc->ini.media_source.v_hw_encoder_element)
- return _create_element(webrtc->ini.media_source.v_hw_encoder_element, NULL);
-
+ encoder = _create_element(source->v_hw_encoder_element, NULL);
+ else if (webrtc->ini.media_source.v_hw_encoder_element)
+ encoder = _create_element(webrtc->ini.media_source.v_hw_encoder_element, NULL);
+#ifdef TIZEN_FEATURE_RES_MGR
+ if (encoder)
+ webrtc->resource.need_to_acquire[MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER] = true;
+#endif
+ return encoder;
} else if (type == WEBRTC_MEDIA_SOURCE_TYPE_MIC || type == WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST) {
if (source && source->a_hw_encoder_element)
return _create_element(source->a_hw_encoder_element, NULL);
RET_VAL_IF(source->src_pad == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "src_pad is NULL");
source->media_types = MEDIA_TYPE_VIDEO;
-
+#ifdef TIZEN_FEATURE_RES_MGR
+ webrtc->resource.need_to_acquire[MM_RESOURCE_MANAGER_RES_TYPE_CAMERA] = true;
+#endif
if (!(camerasrc = _create_element(__get_source_element(webrtc, WEBRTC_MEDIA_SOURCE_TYPE_CAMERA), NULL))) {
LOG_ERROR("failed to create camerasrc");
return WEBRTC_ERROR_INVALID_OPERATION;
}
return WEBRTC_ERROR_NONE;
-}
\ No newline at end of file
+}