From e80f13f7e477027275dc4671b987dbc08e390640 Mon Sep 17 00:00:00 2001 From: Oleksandr Popov Date: Mon, 5 Dec 2016 18:35:48 +0200 Subject: [PATCH 01/16] Added implementation of interruption by resource manager Signed-off-by: Oleksandr Popov Change-Id: I213f1aa51bf6e051baf0a435f268c2798124d558 (cherry picked from commit c252c62a3ea4e82a304a8b32c53d8ab9a1fd5afa) --- CMakeLists.txt | 4 +- include/media_streamer_gst.h | 4 +- include/media_streamer_node.h | 3 + include/media_streamer_node_resources.h | 36 +++ include/media_streamer_priv.h | 9 + include/media_streamer_resource.h | 84 +++++ include/media_streamer_util.h | 33 +- packaging/capi-media-streamer.spec | 2 + src/media_streamer.c | 35 ++ src/media_streamer_gst.c | 45 ++- src/media_streamer_node.c | 202 ++++++++++-- src/media_streamer_node_resources.c | 268 ++++++++++++++++ src/media_streamer_priv.c | 183 ++++++++++- src/media_streamer_resource.c | 550 ++++++++++++++++++++++++++++++++ src/media_streamer_util.c | 43 +++ test/media_streamer_test.c | 16 +- 16 files changed, 1453 insertions(+), 64 deletions(-) create mode 100644 include/media_streamer_node_resources.h create mode 100644 include/media_streamer_resource.h create mode 100644 src/media_streamer_node_resources.c create mode 100644 src/media_streamer_resource.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 01c0703..0c7e7c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary") -SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary") +SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib") +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${dependents}) diff --git a/include/media_streamer_gst.h b/include/media_streamer_gst.h index 37f2b2b..11b1da8 100644 --- a/include/media_streamer_gst.h +++ b/include/media_streamer_gst.h @@ -182,14 +182,14 @@ GstElement *__ms_combine_next_element(GstElement *previous_element, GstPad *prev * * @since_tizen 3.0 */ -void __ms_element_lock_state(const GValue *item, gpointer user_data); +gboolean __ms_element_lock_state(const GValue *item, GValue *ret, gpointer user_data); /** * @brief Unlocks gst_element being contained in GValue data. * * @since_tizen 3.0 */ -void __ms_element_unlock_state(const GValue *item, gpointer user_data); +gboolean __ms_element_unlock_state(const GValue *item, GValue *ret, gpointer user_data); /** * @brief Creates pipeline, bus and src/sink/topology bins. diff --git a/include/media_streamer_node.h b/include/media_streamer_node.h index eb89d8c..f79f9e5 100644 --- a/include/media_streamer_node.h +++ b/include/media_streamer_node.h @@ -128,3 +128,6 @@ int __ms_node_set_param_value(media_streamer_node_s *ms_node, param_s *param, co * @since_tizen 3.0 */ int __ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, media_format_h fmt); + +gboolean _ms_node_resouces_acquire_iter(const GValue *item, GValue *ret, gpointer user_data); +gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointer user_data); diff --git a/include/media_streamer_node_resources.h b/include/media_streamer_node_resources.h new file mode 100644 index 0000000..2f4dd12 --- /dev/null +++ b/include/media_streamer_node_resources.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2015-2016 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. + */ + +#ifndef __MEDIA_STREAMER_NODE_RESOURCE_H__ +#define __MEDIA_STREAMER_NODE_RESOURCE_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int __ms_node_resouces_init(media_streamer_node_s *node); +int __ms_node_resouces_deinit(media_streamer_node_s *node); +int _ms_node_resource_aquire(media_streamer_node_s *node); +int _ms_node_resource_release(media_streamer_node_s *node); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEDIA_STREAMER_NODE_RESOURCE_H__ */ diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h index 8ffe1c4..14a45f7 100755 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -27,6 +27,7 @@ extern "C" { #include #include +#include struct media_streamer_node_s; @@ -110,6 +111,10 @@ typedef struct { media_streamer_callback_s error_cb; media_streamer_callback_s state_changed_cb; media_streamer_callback_s seek_done_cb; + media_streamer_callback_s interrupted_cb; + + gboolean is_interrupted; + media_streamer_resource_manager_s resource_manager; } media_streamer_s; /** @@ -130,6 +135,8 @@ typedef struct { GList *sig_list; void *callbacks_structure; + + media_streamer_resource_manager_s resource_manager; } media_streamer_node_s; typedef struct _media_streamer_wl_info_s { @@ -185,6 +192,8 @@ int __ms_create(media_streamer_s *ms_streamer); */ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e state); +int __ms_release_resources(media_streamer_s *ms_streamer); + #ifdef __cplusplus } diff --git a/include/media_streamer_resource.h b/include/media_streamer_resource.h new file mode 100644 index 0000000..27da5ca --- /dev/null +++ b/include/media_streamer_resource.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2015-2016 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. + */ + +#ifndef __MEDIA_STREAMER_RESOURCE_H__ +#define __MEDIA_STREAMER_RESOURCE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MEDIA_STREAMER_RESOURCE_TIMEOUT 5 + +#define MEDIA_STREAMER_GET_RESOURCE_LOCK(rm) (&((media_streamer_resource_manager_s *)rm)->lock) +#define MEDIA_STREAMER_RESOURCE_LOCK(rm) (g_mutex_lock(MEDIA_STREAMER_GET_RESOURCE_LOCK(rm))) +#define MEDIA_STREAMER_RESOURCE_UNLOCK(rm) (g_mutex_unlock(MEDIA_STREAMER_GET_RESOURCE_LOCK(rm))) + +#define MEDIA_STREAMER_GET_RESOURCE_COND(rm) (&((media_streamer_resource_manager_s *)rm)->cond) +#define MEDIA_STREAMER_RESOURCE_WAIT(rm) g_cond_wait(MEDIA_STREAMER_GET_RESOURCE_COND(rm), MEDIA_STREAMER_GET_RESOURCE_LOCK(rm) +#define MEDIA_STREAMER_RESOURCE_WAIT_UNTIL(rm, end_time) \ + g_cond_wait_until(MEDIA_STREAMER_GET_RESOURCE_COND(rm), MEDIA_STREAMER_GET_RESOURCE_LOCK(rm), end_time) +#define MEDIA_STREAMER_RESOURCE_SIGNAL(rm) g_cond_signal(MEDIA_STREAMER_GET_RESOURCE_COND(rm)); + +typedef enum { + RESOURCE_TYPE_NONE, + RESOURCE_TYPE_VIDEO_DECODER, + RESOURCE_TYPE_CAMERA, + RESOURCE_TYPE_VIDEO_OVERLAY, +} media_streamer_resource_type_e; + +typedef enum { + RESOURCE_STATE_ERROR = -1, + RESOURCE_STATE_NONE, + RESOURCE_STATE_INITIALIZED, + RESOURCE_STATE_PREPARED, + RESOURCE_STATE_ACQUIRED, + RESOURCE_STATE_MAX, +} media_streamer_resource_state_e; + +typedef struct _media_streamer_resource_manager_s media_streamer_resource_manager_s; +typedef gboolean (*resource_relese_cb) (media_streamer_resource_manager_s *resource_manager, void *user_data); + +struct _media_streamer_resource_manager_s { + mrp_mainloop_t *mloop; + mrp_res_context_t *context; + mrp_res_resource_set_t *rset; + media_streamer_resource_state_e state; + bool is_connected; + void *user_data; + bool by_rm_cb; + GCond cond; + GMutex lock; + + /* Release cb */ + resource_relese_cb release_cb; +}; + +int _ms_resource_manager_init(media_streamer_resource_manager_s *resource_manager, resource_relese_cb release_cb, void *user_data); +int _ms_resource_manager_prepare(media_streamer_resource_manager_s *resource_manager, media_streamer_resource_type_e resource_type); +int _ms_resource_manager_acquire(media_streamer_resource_manager_s *resource_manager); +int _ms_resource_manager_release(media_streamer_resource_manager_s *resource_manager); +int _ms_resource_manager_unprepare(media_streamer_resource_manager_s *resource_manager); +int _ms_resource_manager_deinit(media_streamer_resource_manager_s *resource_manager); +int _ms_resource_manager_get_state(media_streamer_resource_manager_s *resource_manager, media_streamer_resource_state_e *state); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEDIA_STREAMER_RESOURCE_H__ */ diff --git a/include/media_streamer_util.h b/include/media_streamer_util.h index b4b8625..2b44cdf 100644 --- a/include/media_streamer_util.h +++ b/include/media_streamer_util.h @@ -17,6 +17,8 @@ #ifndef __MEDIA_STREAMER_UTIL_H__ #define __MEDIA_STREAMER_UTIL_H__ +#include + #include #include #include @@ -45,33 +47,33 @@ extern "C" { #define ms_debug(fmt, arg...) \ do { \ - LOGD(FONT_COLOR_RESET""fmt"", ##arg); \ + LOGD(FONT_COLOR_RESET""fmt""FONT_COLOR_RESET, ##arg); \ } while (0) #define ms_info(fmt, arg...) \ do { \ - LOGI(FONT_COLOR_GREEN""fmt"", ##arg); \ + LOGI(FONT_COLOR_GREEN""fmt""FONT_COLOR_RESET, ##arg); \ } while (0) #define ms_error(fmt, arg...) \ do { \ - LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET, ##arg); \ } while (0) #define ms_debug_fenter() \ do { \ - LOGD(FONT_COLOR_YELLOW""); \ + LOGD(FONT_COLOR_YELLOW""FONT_COLOR_RESET); \ } while (0) #define ms_debug_fleave() \ do { \ - LOGD(FONT_COLOR_PURPLE""); \ + LOGD(FONT_COLOR_PURPLE""FONT_COLOR_RESET); \ } while (0) #define ms_retm_if(expr, fmt, arg...) \ do { \ if (expr) { \ - LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET, ##arg); \ return; \ } \ } while (0) @@ -79,7 +81,7 @@ extern "C" { #define ms_retvm_if(expr, val, fmt, arg...) \ do { \ if (expr) { \ - LOGE(FONT_COLOR_RED""fmt"", ##arg); \ + LOGE(FONT_COLOR_RED""fmt""FONT_COLOR_RESET, ##arg); \ return(val); \ } \ } while (0) @@ -109,8 +111,8 @@ typedef struct __media_streamer_ini { gboolean generate_dot; gboolean use_decodebin; gchar **exclude_elem_names; + gchar **resource_required_elem_names; gchar **gst_args; - } media_streamer_ini_t; /** @@ -215,14 +217,6 @@ typedef struct { #define MEDIA_STREAMER_DEFAULT_DOT_DIR "/tmp" -#define MS_BIN_FOREACH_ELEMENTS(bin, fn, streamer) \ - do { \ - GstIterator *iter = gst_bin_iterate_elements(GST_BIN(bin)); \ - if (gst_iterator_foreach(iter, fn, streamer) != GST_ITERATOR_DONE) \ - ms_error("Error while iterating elements in bin [%s]!", GST_ELEMENT_NAME(bin)); \ - gst_iterator_free(iter); \ - } while (0) - #define MS_BIN_UNPREPARE(bin) \ if (!__ms_bin_remove_elements(ms_streamer, bin)) {\ ms_debug("Got a few errors during unprepare [%s] bin.", GST_ELEMENT_NAME(bin));\ @@ -340,6 +334,13 @@ void __ms_param_value_destroy(gpointer data); */ int __ms_node_uri_path_check(const char *file_uri); +/** + * @brief Iterates func over all elements contained within a bin. + * + * @since_tizen 3.0 + */ +int __ms_bin_foreach_elements(GstBin *bin, GstIteratorFoldFunction func, void *user_data); + #ifdef __cplusplus } #endif diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 716fcb8..7443f3b 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -29,6 +29,8 @@ BuildRequires: pkgconfig(ecore) BuildRequires: pkgconfig(evas) BuildRequires: pkgconfig(ecore-wayland) BuildRequires: pkgconfig(appcore-efl) +BuildRequires: pkgconfig(murphy-resource) +BuildRequires: pkgconfig(murphy-glib) %description A MediaStreamer library in Tizen Native API. diff --git a/src/media_streamer.c b/src/media_streamer.c index 8bd592f..73ba7dc 100644 --- a/src/media_streamer.c +++ b/src/media_streamer.c @@ -251,6 +251,8 @@ int media_streamer_create(media_streamer_h *streamer) /* create streamer lock */ g_mutex_init(&ms_streamer->mutex_lock); + g_mutex_lock(&ms_streamer->mutex_lock); + ret = __ms_create(ms_streamer); if (ret != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error creating Media Streamer"); @@ -263,6 +265,8 @@ int media_streamer_create(media_streamer_h *streamer) ret = __ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE); *streamer = ms_streamer; + g_mutex_unlock(&ms_streamer->mutex_lock); + ms_info("Media Streamer created successfully"); return ret; } @@ -712,3 +716,34 @@ int media_streamer_node_get_param(media_streamer_node_h node, const char *param_ return ret; } + +int media_streamer_set_interrupted_cb(media_streamer_h streamer, media_streamer_interrupted_cb callback, void *user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(callback == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Callback is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + ms_streamer->interrupted_cb.callback = callback; + ms_streamer->interrupted_cb.user_data = user_data; + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int media_streamer_unset_interrupted_cb(media_streamer_h streamer) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) streamer; + ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + g_mutex_lock(&ms_streamer->mutex_lock); + + ms_streamer->interrupted_cb.callback = NULL; + ms_streamer->interrupted_cb.user_data = NULL; + + g_mutex_unlock(&ms_streamer->mutex_lock); + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 39a1a14..f3961d4 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -465,6 +465,28 @@ static gint __decodebin_autoplug_select_cb(GstElement * bin, GstPad * pad, GstCa } + if (ms_streamer->ini.resource_required_elem_names) { + /* Try to acuire resources before adding element */ + int index = 0; + for ( ; ms_streamer->ini.resource_required_elem_names[index]; ++index) { + if (g_strrstr(factory_name, ms_streamer->ini.resource_required_elem_names[index])) { + ms_debug("Decodebin: trying to acquire resource for [%s] element", factory_name); + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_prepare(&ms_streamer->resource_manager, RESOURCE_TYPE_VIDEO_DECODER)) { + ms_error("Failed to prepare resources for [%s] element", factory_name); + return GST_AUTOPLUG_SELECT_SKIP; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_acquire(&ms_streamer->resource_manager)) { + ms_error("Failed to acquire resources for [%s] element", factory_name); + return GST_AUTOPLUG_SELECT_SKIP; + } + } + } + } + return result; } @@ -979,6 +1001,7 @@ GstElement *__ms_node_element_create(node_plug_s *plug_info, media_streamer_node GstElement *gst_element = NULL; const gchar *src_type, *sink_type; + MS_GET_CAPS_TYPE(plug_info->src_caps, src_type); MS_GET_CAPS_TYPE(plug_info->sink_caps, sink_type); @@ -1474,15 +1497,16 @@ static GstPadProbeReturn __ms_element_event_probe(GstPad * pad, GstPadProbeInfo return GST_PAD_PROBE_PASS; } -void __ms_element_lock_state(const GValue *item, gpointer user_data) +gboolean __ms_element_lock_state(const GValue *item, GValue *ret, gpointer user_data) { GstElement *sink_element = GST_ELEMENT(g_value_get_object(item)); - ms_retm_if(!sink_element, "Handle is NULL"); + g_value_set_boolean(ret, FALSE); + ms_retvm_if(!sink_element, FALSE, "Handle is NULL"); GstPad *sink_pad = gst_element_get_static_pad(sink_element, "sink"); if (!sink_pad) { ms_info("Failed to get static pad of element [%s]", GST_ELEMENT_NAME(sink_element)); - return; + return FALSE; } if (!gst_pad_is_blocked(sink_pad)) { int probe_id = gst_pad_add_probe(sink_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, __ms_element_event_probe, NULL, NULL); @@ -1492,19 +1516,24 @@ void __ms_element_lock_state(const GValue *item, gpointer user_data) ms_info("Pad [%s] of element [%s] is already locked", GST_PAD_NAME(sink_pad), GST_ELEMENT_NAME(sink_element)); } MS_SAFE_UNREF(sink_pad); + + g_value_set_boolean(ret, TRUE); + + return TRUE; } -void __ms_element_unlock_state(const GValue *item, gpointer user_data) +gboolean __ms_element_unlock_state(const GValue *item, GValue *ret, gpointer user_data) { GstElement *sink_element = GST_ELEMENT(g_value_get_object(item)); - ms_retm_if(!sink_element, "Handle is NULL"); + g_value_set_boolean(ret, FALSE); + ms_retvm_if(!sink_element, FALSE, "Handle is NULL"); GValue *val = (GValue *) g_object_get_data(G_OBJECT(sink_element), "pad_sink"); if (val) { GstPad *sink_pad = gst_element_get_static_pad(sink_element, "sink"); if (!sink_pad) { ms_info("Failed to get static pad of element [%s]", GST_ELEMENT_NAME(sink_element)); - return; + return FALSE; } if (gst_pad_is_blocked(sink_pad)) { ms_info("Removing locking probe [%d] ID on [%s] pad of [%s] element", g_value_get_int(val), GST_PAD_NAME(sink_pad), GST_ELEMENT_NAME(sink_element)); @@ -1514,6 +1543,10 @@ void __ms_element_unlock_state(const GValue *item, gpointer user_data) } MS_SAFE_UNREF(sink_pad); } + + g_value_set_boolean(ret, TRUE); + + return TRUE; } static gboolean __ms_bus_cb(GstBus *bus, GstMessage *message, gpointer userdata) diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 874afa9..a87724f 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -15,6 +15,7 @@ */ #include +#include #include #include #include @@ -240,6 +241,7 @@ int __ms_node_create(media_streamer_node_s *node, media_format_h in_fmt, media_f GstCaps *src_caps = out_fmt ? __ms_create_caps_from_fmt(out_fmt) : NULL; node_plug_s plug_info = {&(nodes_info[node->type]), src_caps, sink_caps, NULL}; + ms_info("Creating node with info: klass_name[%s]; default[%s]", plug_info.info->klass_name, plug_info.info->default_name); @@ -247,13 +249,19 @@ int __ms_node_create(media_streamer_node_s *node, media_format_h in_fmt, media_f if (node->gst_element) node->name = gst_element_get_name(node->gst_element); else - ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; if (src_caps) - gst_caps_unref(src_caps); + gst_caps_unref(src_caps); if (sink_caps) - gst_caps_unref(sink_caps); + gst_caps_unref(sink_caps); + + ret = __ms_node_resouces_init(node); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to init resources for node [%s]", node->name); + return ret; + } return ret; } @@ -310,7 +318,7 @@ static int __ms_node_check_priveleges(media_streamer_node_s *node) privilege = "http://tizen.org/privilege/camera"; break; default: - ms_info("For current Src Node [%s] subtype [%d] privileges are not needed", node->name, node->subtype); + ms_info(" [%s] subtype [%d] privileges are not needed", node->name, node->subtype); break; } } @@ -446,7 +454,7 @@ static int __ms_node_check_feature(media_streamer_node_s *node) ret = MEDIA_STREAMER_ERROR_NOT_SUPPORTED; break; default: - ms_info("For current Src Node [%s] subtype [%d] privileges are not needed", node->name, node->subtype); + ms_info("For current Src Node subtype [%d] privileges are not needed", node->subtype); break; } } @@ -483,7 +491,7 @@ static int __ms_node_check_feature(media_streamer_node_s *node) ret = MEDIA_STREAMER_ERROR_NOT_SUPPORTED; break; default: - ms_info("For current Sink Node [%s] subtype [%d] privileges are not needed", node->name, node->subtype); + ms_info("For current Sink Node subtype [%d] privileges are not needed", node->subtype); break; } } @@ -560,11 +568,15 @@ int __ms_src_node_create(media_streamer_node_s *node) MS_SAFE_FREE(plugin_name); - if (ret == MEDIA_STREAMER_ERROR_NONE) { - if (node->gst_element == NULL) - ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; - else - node->name = gst_element_get_name(node->gst_element); + if (node->gst_element == NULL) + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + else + node->name = gst_element_get_name(node->gst_element); + + ret = __ms_node_resouces_init(node); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to init resources for node [%s]", node->name); + return ret; } return ret; @@ -670,10 +682,16 @@ int __ms_sink_node_create(media_streamer_node_s *node) MS_SAFE_FREE(plugin_name); if (node->gst_element == NULL) - ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; else node->name = gst_element_get_name(node->gst_element); + ret = __ms_node_resouces_init(node); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to init resources for node [%s]", node->name); + return ret; + } + return ret; } @@ -684,6 +702,10 @@ void __ms_node_destroy(media_streamer_node_s *node) /* Disconnects and clean all node signals */ g_list_free_full(node->sig_list, __ms_signal_destroy); + /* Deinitialize resource manager */ + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_deinit(node)) + ms_error("Failed to deinitialize resource manager"); + MS_SAFE_UNREF(node->gst_element); MS_SAFE_FREE(node->name); MS_SAFE_FREE(node->callbacks_structure); @@ -751,24 +773,29 @@ node_info_s * __ms_node_get_klass_by_its_type(media_streamer_node_type_e element return &nodes_info[it_klass]; } -static void _src_node_prepare(const GValue *item, gpointer user_data) +static gboolean _src_node_prepare(const GValue *item, GValue *ret, gpointer user_data) { media_streamer_s *ms_streamer = (media_streamer_s *) user_data; GstElement *src_element = GST_ELEMENT(g_value_get_object(item)); g_object_ref(src_element); + g_value_set_boolean(ret, FALSE); media_streamer_node_s *found_node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, GST_ELEMENT_NAME(src_element)); - if (!found_node) - return; + if (!found_node) { + /* If we fail to found corresonding node inside streamer + then apprently this element doesn't require resources. */ + ms_debug("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(src_element)); + g_value_set_boolean(ret, TRUE); + return TRUE; + } - ms_retm_if(!ms_streamer || !src_element, "Handle is NULL"); ms_debug("Autoplug: found src element [%s]", GST_ELEMENT_NAME(src_element)); GstPad *src_pad = gst_element_get_static_pad(src_element, "src"); GstElement *found_element = NULL; if (__ms_src_need_typefind(src_pad)) { - __ms_find_type(ms_streamer,src_element); + __ms_find_type(ms_streamer, src_element); MS_SAFE_UNREF(src_element); } else { /* Check the source element`s pad type */ @@ -777,7 +804,8 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) if (gst_pad_is_linked(src_pad)) { MS_SAFE_UNREF(src_pad); MS_SAFE_UNREF(src_element); - return; + g_value_set_boolean(ret, TRUE); + return TRUE; } /* It is media streamer Server part */ if (MS_ELEMENT_IS_VIDEO(new_pad_type) || MS_ELEMENT_IS_IMAGE(new_pad_type)) { @@ -799,9 +827,19 @@ static void _src_node_prepare(const GValue *item, gpointer user_data) MS_SAFE_UNREF(found_element); } MS_SAFE_UNREF(src_pad); + + g_value_set_boolean(ret, TRUE); + + return TRUE; } -static gboolean demux_find(gpointer key, gpointer value, gpointer user_data) { +static gboolean _sink_node_prepare(const GValue *item, GValue *ret, gpointer user_data) +{ + return __ms_element_lock_state(item, ret, user_data); +} + +static gboolean demux_find(gpointer key, gpointer value, gpointer user_data) +{ return g_strrstr((char *)key, "demux") != NULL; } @@ -816,7 +854,9 @@ int __ms_pipeline_prepare(media_streamer_s *ms_streamer) if (rtp_node) { ret = __ms_rtp_element_prepare(rtp_node) ? MEDIA_STREAMER_ERROR_NONE : MEDIA_STREAMER_ERROR_INVALID_PARAMETER; } else if (demux) { - ret = __ms_demux_element_prepare(ms_streamer, demux) ? MEDIA_STREAMER_ERROR_NONE : MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + ret = __ms_demux_element_prepare(ms_streamer, demux); + if (MEDIA_STREAMER_ERROR_NONE != ret) + ms_error("Failed to prepare demux element"); } else { GstBin *nodes_bin = GST_BIN(ms_streamer->src_bin); if (nodes_bin->numchildren == 0) { @@ -831,21 +871,36 @@ int __ms_pipeline_prepare(media_streamer_s *ms_streamer) } if (adaptive_src) { - if (GST_BIN(ms_streamer->topology_bin)->numchildren == 0) { + if (GST_BIN(ms_streamer->topology_bin)->numchildren == 0) ret = __ms_adaptive_element_prepare(adaptive_src, true); - } else { + else ret = __ms_adaptive_element_prepare(adaptive_src, false); - } } - MS_BIN_FOREACH_ELEMENTS(ms_streamer->sink_bin, __ms_element_lock_state, ms_streamer); - MS_BIN_FOREACH_ELEMENTS(ms_streamer->src_bin, _src_node_prepare, ms_streamer); + if (ret != MEDIA_STREAMER_ERROR_NONE) + goto prepare_fail; + + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), _sink_node_prepare, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to prepare nodes within sink bin"); + goto prepare_fail; + } + + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), _src_node_prepare, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to prepare nodes within src bin"); + goto prepare_fail; + } ret = __ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_READY); if (ret != MEDIA_STREAMER_ERROR_NONE) - __ms_pipeline_unprepare(ms_streamer); + goto prepare_fail; return ret; + +prepare_fail: + __ms_pipeline_unprepare(ms_streamer); + return ret; } static gboolean __ms_bin_remove_elements(media_streamer_s *ms_streamer, GstElement *bin) @@ -881,6 +936,7 @@ static gboolean __ms_bin_remove_elements(media_streamer_s *ms_streamer, GstEleme it_res = gst_iterator_next(bin_iterator, &element); } } + g_value_unset(&element); gst_iterator_free(bin_iterator); @@ -898,11 +954,37 @@ int __ms_pipeline_unprepare(media_streamer_s *ms_streamer) ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); int ret = MEDIA_STREAMER_ERROR_NONE; - __ms_element_set_state(ms_streamer->pipeline, GST_STATE_NULL); - ms_streamer->state = MEDIA_STREAMER_STATE_IDLE; - ms_streamer->pend_state = ms_streamer->state; + ret = __ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_IDLE); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to unprepare pipeline"); + + if (!ms_streamer->is_interrupted) { + media_streamer_resource_state_e res_state = RESOURCE_STATE_ERROR; + ret = _ms_resource_manager_get_state(&ms_streamer->resource_manager, + &res_state); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to get state of resource manager"); + + if (RESOURCE_STATE_ACQUIRED == res_state) { + ret = _ms_resource_manager_release(&ms_streamer->resource_manager); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to release resources"); + } - MS_BIN_FOREACH_ELEMENTS(ms_streamer->sink_bin, __ms_element_unlock_state, ms_streamer); + ret = _ms_resource_manager_get_state(&ms_streamer->resource_manager, + &res_state); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to get state of resource manager"); + + if (RESOURCE_STATE_PREPARED == res_state) { + ret = _ms_resource_manager_unprepare(&ms_streamer->resource_manager); + if (ret != MEDIA_STREAMER_ERROR_NONE) + ms_error("Failed to unprepare resources"); + } + + /* Unprepare resources in case of failure */ + __ms_release_resources(ms_streamer); + } /* Disconnects and clean all autoplug signals */ g_list_free_full(ms_streamer->autoplug_sig_list, __ms_signal_destroy); @@ -1456,3 +1538,63 @@ int __ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, return ret; } + +gboolean _ms_node_resouces_acquire_iter(const GValue *item, GValue *ret, gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) user_data; + media_streamer_node_s *node = NULL; + GstElement *element = NULL; + g_value_set_boolean(ret, FALSE); + + element = GST_ELEMENT(g_value_get_object(item)); + g_object_ref(element); + + node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, + GST_ELEMENT_NAME(element)); + if (!node) { + /* If we fail to found corresonding node inside streamer + then apprently this element doesn't require resources */ + ms_info("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); + g_value_set_boolean(ret, TRUE); + return TRUE; + } + + if (MEDIA_STREAMER_ERROR_NONE != _ms_node_resource_aquire(node)) { + ms_error("Failed to acquire resource for node [%s]", node->name); + return FALSE; + } + + g_value_set_boolean(ret, TRUE); + + return TRUE; +} + +gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) user_data; + media_streamer_node_s *node = NULL; + GstElement *element = NULL; + g_value_set_boolean(ret, FALSE); + + element = GST_ELEMENT(g_value_get_object(item)); + g_object_ref(element); + + node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, + GST_ELEMENT_NAME(element)); + if (!node) { + /* If we fail to found corresonding node inside streamer + then apprently this element doesn't require resources. */ + ms_debug("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); + g_value_set_boolean(ret, TRUE); + return TRUE; + } + + if (MEDIA_STREAMER_ERROR_NONE != _ms_node_resource_release(node)) { + ms_error("Failed to release resource for node [%s]", node->name); + return FALSE; + } + + g_value_set_boolean(ret, TRUE); + + return TRUE; +} diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c new file mode 100644 index 0000000..5dabe15 --- /dev/null +++ b/src/media_streamer_node_resources.c @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2015 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 + +#include +#include +#include +#include +#include + +static gboolean __ms_resource_relese_cb( + media_streamer_resource_manager_s *resource_manager, + void *user_data) +{ + ms_retvm_if(user_data == NULL, FALSE, "user_data is NULL"); + + media_streamer_node_s *node = (media_streamer_node_s *) user_data; + media_streamer_s *streamer = (media_streamer_s *) node->parent_streamer; + ms_info("Received resource_release_cb from node [%s]", node->name); + + /* Here we perform action to release resources relases that + were previoursly acquired. Basically what we need to do is + to unprepare media streamer. Whithout calling release function + on every acquired resource. */ + g_mutex_lock(&streamer->mutex_lock); + streamer->is_interrupted = TRUE; + if (MEDIA_STREAMER_ERROR_NONE != + __ms_pipeline_unprepare(streamer)) { + ms_error("Failed to unprepare streamer"); + streamer->is_interrupted = FALSE; + g_mutex_unlock(&streamer->mutex_lock); + return FALSE; + } + streamer->is_interrupted = FALSE; + + /* Call interrupted_cb with appropriate code */ + media_streamer_interrupted_cb interrupted_cb = + (media_streamer_interrupted_cb) streamer->interrupted_cb.callback; + if (interrupted_cb) { + interrupted_cb(MEDIA_STREAMER_INTERRUPTED_BY_RESOURCE_CONFLICT, + streamer->interrupted_cb.user_data); + } else { + ms_info("Interuption will not be handled because interrupted_cb is NULL"); + } + g_mutex_unlock(&streamer->mutex_lock); + + return TRUE; +} + +static void __ms_node_get_resources_needed(media_streamer_node_s *node, + media_streamer_resource_type_e *resource) { + media_streamer_node_type_e type = node->type; + int subtype = node->subtype; + + ms_debug("Checking resources for node type %d, subtype %d", type, subtype); + + /* Check for node types */ + switch (type) { + case MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER: + break; + case MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER: + *resource = RESOURCE_TYPE_VIDEO_DECODER; + break; + case MEDIA_STREAMER_NODE_TYPE_SRC: + if (MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA == subtype) + *resource = RESOURCE_TYPE_CAMERA; + break; + case MEDIA_STREAMER_NODE_TYPE_SINK: + if (MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY == subtype) + *resource = RESOURCE_TYPE_VIDEO_OVERLAY; + break; + default: + break; + } +} + +int __ms_node_resouces_init(media_streamer_node_s *node) +{ + media_streamer_resource_type_e resource = RESOURCE_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Check if node require resource manager */ + __ms_node_get_resources_needed(node, &resource); + if (RESOURCE_TYPE_NONE == resource) { + ms_info("No resource is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + /* Initialize resource manager */ + ret = _ms_resource_manager_init(&node->resource_manager, + __ms_resource_relese_cb, node); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Failed to initialize resource manager for Node"); + return ret; + } + + return ret; +} + +int __ms_node_resouces_deinit(media_streamer_node_s *node) +{ + media_streamer_resource_type_e resource = RESOURCE_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Check if node require resource manager */ + __ms_node_get_resources_needed(node, &resource); + if (RESOURCE_TYPE_NONE == resource) { + ms_info("No resource is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + /* Deinitialize resource manager */ + ret = _ms_resource_manager_deinit(&node->resource_manager); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Failed to deinitialize resource manager for Src Node"); + return ret; + } + + return ret; +} + +int __ms_node_resouces_prepare(media_streamer_node_s *node, media_streamer_resource_type_e resource) +{ + media_streamer_resource_state_e resource_state = RESOURCE_STATE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + ret = _ms_resource_manager_get_state(&node->resource_manager, &resource_state); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Failed to get state from resource menager"); + return ret; + } else { + if (RESOURCE_STATE_NONE == resource_state || + RESOURCE_STATE_ERROR == resource_state) { + ms_error("Wrong resource manager state %d", resource_state); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else if (RESOURCE_STATE_INITIALIZED == resource_state) { + /* For every node we should call resource manager function to resource */ + ret = _ms_resource_manager_prepare(&node->resource_manager, resource); + } else { + ms_info("Resource state is %d. No need to prepare", resource_state); + return MEDIA_STREAMER_ERROR_NONE; + } + } + + return ret; +} + +int __ms_node_resouces_unprepare(media_streamer_node_s *node, media_streamer_resource_type_e resource) +{ + media_streamer_resource_state_e resource_state = RESOURCE_STATE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + ret = _ms_resource_manager_get_state(&node->resource_manager, &resource_state); + if (ret != MEDIA_STREAMER_ERROR_NONE) { + ms_error("Failed to get state from resource menager"); + return ret; + } else { + if (RESOURCE_STATE_PREPARED == resource_state) { + /* For every node we should call resource manager function to resource */ + ret = _ms_resource_manager_unprepare(&node->resource_manager); + } else { + ms_error("Wrong resource manager state %d", resource_state); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + + return ret; +} + +int _ms_node_resource_aquire(media_streamer_node_s *node) +{ + media_streamer_resource_state_e resource_state = RESOURCE_STATE_NONE; + media_streamer_resource_type_e resource = RESOURCE_TYPE_NONE; + + /* Check if node require resource manager */ + __ms_node_get_resources_needed(node, &resource); + if (RESOURCE_TYPE_NONE == resource) { + ms_info("No resource is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_prepare(node, resource)) { + ms_error("Failed to prepare resources for Node [%p]", node); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_get_state(&node->resource_manager, &resource_state)) { + ms_error("Failed to get state from resource menager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + ms_debug("Resource manager state %d", resource_state); + } + + ms_debug("Acquire resource for node [%s]", node->name); + + if (RESOURCE_STATE_PREPARED != resource_state) { + ms_debug("Resources were not prepared %d. Skipping...", resource_state); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_acquire(&node->resource_manager)) { + ms_error("Failed to acquire resources for node [%s]", node->name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int _ms_node_resource_release(media_streamer_node_s *node) +{ + media_streamer_resource_state_e resource_state = RESOURCE_STATE_NONE; + media_streamer_resource_type_e resource = RESOURCE_TYPE_NONE; + + /* Check if node require resource manager */ + __ms_node_get_resources_needed(node, &resource); + if (RESOURCE_TYPE_NONE == resource) { + ms_info("No resource is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_get_state(&node->resource_manager, &resource_state)) { + ms_error("Failed to get state from resource menager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + ms_debug("Resource manager state %d", resource_state); + } + + ms_debug("Release resources for node [%s]", node->name); + + if (RESOURCE_STATE_ACQUIRED != resource_state) { + ms_debug("Resources were not acquired %d. Skipping...", resource_state); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_release(&node->resource_manager)) { + ms_error("Failed to release resources for node [%s]", node->name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_unprepare(node, resource)) { + ms_error("Failed to unprepare resources for Node [%p]", node); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_priv.c b/src/media_streamer_priv.c index 47dd4bb..3fe8485 100644 --- a/src/media_streamer_priv.c +++ b/src/media_streamer_priv.c @@ -18,9 +18,13 @@ #include "media_streamer_util.h" #include "media_streamer_node.h" #include "media_streamer_gst.h" +#include "media_streamer_resource.h" #define GST_TIME_TO_MSEC(t) (t == GST_CLOCK_TIME_NONE ? t : (int)(((GstClockTime)(t)) / GST_MSECOND)) +int __ms_change_resources_state(media_streamer_s *ms_streamer, media_streamer_state_e state); +static gboolean media_streamer_resource_relese_cb(media_streamer_resource_manager_s *resource_manager, void *user_data); + int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e state) { int ret = MEDIA_STREAMER_ERROR_NONE; @@ -28,6 +32,14 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); ms_retvm_if(ms_streamer->state == state, MEDIA_STREAMER_ERROR_NONE, "Media streamer already in this state"); + if (!ms_streamer->is_interrupted) { + ret = __ms_change_resources_state(ms_streamer, state); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to change resources state for streamer %p", ms_streamer); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + switch (state) { case MEDIA_STREAMER_STATE_NONE: /* @@ -43,9 +55,10 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat * Unlink all gst_elements, set pipeline into state NULL */ ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_NULL); - MS_BIN_FOREACH_ELEMENTS(ms_streamer->sink_bin, __ms_element_unlock_state, ms_streamer); - ms_streamer->pend_state = MEDIA_STREAMER_STATE_NONE; + __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), __ms_element_unlock_state, ms_streamer); + ms_streamer->pend_state = MEDIA_STREAMER_STATE_IDLE; ms_streamer->state = state; + break; case MEDIA_STREAMER_STATE_READY: ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED); @@ -53,7 +66,7 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat break; case MEDIA_STREAMER_STATE_PLAYING: ret = __ms_element_set_state(ms_streamer->pipeline, GST_STATE_PLAYING); - MS_BIN_FOREACH_ELEMENTS(ms_streamer->sink_bin, __ms_element_unlock_state, ms_streamer); + __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), __ms_element_unlock_state, ms_streamer); ms_streamer->pend_state = MEDIA_STREAMER_STATE_PLAYING; break; case MEDIA_STREAMER_STATE_PAUSED: @@ -77,6 +90,14 @@ int __ms_create(media_streamer_s *ms_streamer) ms_streamer->nodes_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, __ms_node_remove_from_table); ms_retvm_if(ms_streamer->nodes_table == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating hash table"); + if (MEDIA_STREAMER_ERROR_NONE != _ms_resource_manager_init( + &ms_streamer->resource_manager, + media_streamer_resource_relese_cb, + ms_streamer)) { + ms_error("Failed to init resource manager for media streamer"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + return __ms_pipeline_create(ms_streamer); } @@ -155,9 +176,165 @@ int __ms_streamer_destroy(media_streamer_s *ms_streamer) if (ms_streamer->ini.exclude_elem_names) g_strfreev(ms_streamer->ini.exclude_elem_names); + /* Clean up resource required elements list */ + if (ms_streamer->ini.resource_required_elem_names) + g_strfreev(ms_streamer->ini.resource_required_elem_names); + + if (MEDIA_STREAMER_ERROR_NONE != + _ms_resource_manager_deinit(&ms_streamer->resource_manager)) { + ms_error("Failed to deinit resource manager for media streamer"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + g_mutex_unlock(&ms_streamer->mutex_lock); g_mutex_clear(&ms_streamer->mutex_lock); MS_SAFE_FREE(ms_streamer); return ret; } + +int __ms_aquire_resources(media_streamer_s *ms_streamer) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Acquire resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), + _ms_node_resouces_acquire_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to acquire resources for src bin"); + return ret; + } + + /* Acquire resources for topology bin. If user doesn't + add nodes explicitly they will be acquired later. + For example when decodebin is used resources are quired + when 'autoplug-select' signal is triggered for new GstElement. */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->topology_bin), + _ms_node_resouces_acquire_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to acquire resources for topology bin"); + return ret; + } + + /* Acquire resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), + _ms_node_resouces_acquire_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to acquire resources for sink bin"); + return ret; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_release_resources(media_streamer_s *ms_streamer) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Release resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), + _ms_node_resouces_release_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to release resources for src bin"); + return ret; + } + + /* Release resources for topology bin. Here we also consider + nodes that were not added by user explicitly (e.g. decodebin + was used). */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->topology_bin), + _ms_node_resouces_release_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to release resources for topology bin"); + return ret; + } + + /* Release resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), + _ms_node_resouces_release_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to release resources for sink bin"); + return ret; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_change_resources_state(media_streamer_s *ms_streamer, media_streamer_state_e state) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* According to state graph we need to handle only this two states + * and different transotions into them */ + if (state == MEDIA_STREAMER_STATE_IDLE) { + switch (ms_streamer->pend_state) { + case MEDIA_STREAMER_STATE_READY: + case MEDIA_STREAMER_STATE_PAUSED: + case MEDIA_STREAMER_STATE_PLAYING: + /* After unprepare function call */ + ret = __ms_release_resources(ms_streamer); + break; + case MEDIA_STREAMER_STATE_NONE: + case MEDIA_STREAMER_STATE_IDLE: + /* We do not considering double unprepare */ + case MEDIA_STREAMER_STATE_SEEKING: + default: + break; + } + } else if (state == MEDIA_STREAMER_STATE_READY) { + switch (ms_streamer->pend_state) { + case MEDIA_STREAMER_STATE_IDLE: + /* After prepare function */ + ret = __ms_aquire_resources(ms_streamer); + break; + case MEDIA_STREAMER_STATE_PAUSED: + case MEDIA_STREAMER_STATE_PLAYING: + case MEDIA_STREAMER_STATE_NONE: + case MEDIA_STREAMER_STATE_SEEKING: + default: + break; + } + } else { + ms_debug("Ignoring state for resource managements"); + } + + return ret; +} + +static gboolean media_streamer_resource_relese_cb( + media_streamer_resource_manager_s *resource_manager, + void *user_data) +{ + ms_retvm_if(user_data == NULL, FALSE, "user_data is NULL"); + + media_streamer_s *streamer = (media_streamer_s *) user_data; + ms_info("Reseived release_cb for streamer %p", streamer); + + /* Here we perform action to release resources relases that + were previoursly acquired (dynamically created case). + Basically what we need to do is to unprepare media streamer. + Whithout calling release function on every acquired resource. */ + g_mutex_lock(&streamer->mutex_lock); + streamer->is_interrupted = TRUE; + if (MEDIA_STREAMER_ERROR_NONE != + __ms_pipeline_unprepare(streamer)) { + ms_error("Failed to unprepare streamer"); + streamer->is_interrupted = FALSE; + g_mutex_unlock(&streamer->mutex_lock); + return FALSE; + } + streamer->is_interrupted = FALSE; + + /* Call interrupted_cb with appropriate code */ + media_streamer_interrupted_cb interrupted_cb = + (media_streamer_interrupted_cb) streamer->interrupted_cb.callback; + if (interrupted_cb) { + interrupted_cb(MEDIA_STREAMER_INTERRUPTED_BY_RESOURCE_CONFLICT, + streamer->interrupted_cb.user_data); + } else { + ms_info("Interuption will not be handled because interrupted_cb is NULL"); + } + g_mutex_unlock(&streamer->mutex_lock); + + return TRUE; +} diff --git a/src/media_streamer_resource.c b/src/media_streamer_resource.c new file mode 100644 index 0000000..4d84082 --- /dev/null +++ b/src/media_streamer_resource.c @@ -0,0 +1,550 @@ +/* + * Copyright (c) 2016 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 "media_streamer_util.h" +#include "media_streamer_resource.h" +#include "media_streamer_priv.h" +#include + +#define MRP_APP_CLASS_FOR_MSTREAMER "media" +#define MRP_RESOURCE_TYPE_MANDATORY TRUE +#define MRP_RESOURCE_TYPE_EXCLUSIVE FALSE + +enum { + MRP_RESOURCE_FOR_VIDEO_OVERLAY, + MRP_RESOURCE_FOR_CAMERA, + MRP_RESOURCE_FOR_VIDEO_DECODER, + MRP_RESOURCE_MAX, +}; +const char* resource_str[MRP_RESOURCE_MAX] = { + "video_overlay", + "camera", + "video_decoder", +}; + +#define MEDIA_STREAMER_WAIT_CONNECTION_TIMEOUT 5 + +#define MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(x_ms_resource_manager) \ +do { \ + if (!x_ms_resource_manager) { \ + ms_error("no resource manager instance");\ + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; \ + } \ +} while (0); + +static int __ms_resource_manager_wait_connection(media_streamer_resource_manager_s *resource_manager) +{ + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (resource_manager->is_connected) { + ms_debug("Already connected to resource server"); + } else { + gint64 end_time = g_get_monotonic_time() + MEDIA_STREAMER_RESOURCE_TIMEOUT*G_TIME_SPAN_SECOND; + + ms_debug("Not connected to resource server yet. Waiting..."); + + if (!g_cond_wait_until(&resource_manager->cond, + &resource_manager->lock, end_time)) { + ms_error("Could not connect to resource server"); + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + if (resource_manager->is_connected) + ms_debug("Successfully connected to resource server!"); + else { + ms_error("Failed to connect to resource server"); + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + } + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + return MEDIA_STREAMER_ERROR_NONE; +} + +static char *state_to_str(mrp_res_resource_state_t st) +{ + char *state = "unknown"; + switch (st) { + case MRP_RES_RESOURCE_ACQUIRED: + state = "acquired"; + break; + case MRP_RES_RESOURCE_LOST: + state = "lost"; + break; + case MRP_RES_RESOURCE_AVAILABLE: + state = "available"; + break; + case MRP_RES_RESOURCE_PENDING: + state = "pending"; + break; + case MRP_RES_RESOURCE_ABOUT_TO_LOOSE: + state = "about to loose"; + break; + } + return state; +} + +static void mrp_state_callback(mrp_res_context_t *context, mrp_res_error_t err, void *user_data) +{ + int i = 0; + const mrp_res_resource_set_t *rset; + mrp_res_resource_t *resource; + media_streamer_resource_manager_s* resource_manager = NULL; + + if (user_data == NULL) { + ms_error(" - user data is null"); + return; + } + resource_manager = (media_streamer_resource_manager_s *) user_data; + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (err != MRP_RES_ERROR_NONE) { + ms_error(" - error message received from Murphy, err(0x%x)", err); + g_cond_signal(&resource_manager->cond); + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + return; + } + + switch (context->state) { + case MRP_RES_CONNECTED: + ms_debug(" - connected to Murphy"); + if ((rset = mrp_res_list_resources(context)) != NULL) { + mrp_res_string_array_t *resource_names; + resource_names = mrp_res_list_resource_names(rset); + if (!resource_names) { + ms_error(" - no resources available"); + return; + } + for (i = 0; i < resource_names->num_strings; i++) { + resource = mrp_res_get_resource_by_name(rset, resource_names->strings[i]); + if (resource) + ms_debug(" - available resource: %s", resource->name); + } + mrp_res_free_string_array(resource_names); + } + resource_manager->is_connected = TRUE; + g_cond_signal(&resource_manager->cond); + break; + case MRP_RES_DISCONNECTED: + ms_debug(" - disconnected from Murphy"); + if (resource_manager->rset) { + mrp_res_delete_resource_set(resource_manager->rset); + resource_manager->rset = NULL; + } + mrp_res_destroy(resource_manager->context); + resource_manager->context = NULL; + resource_manager->is_connected = FALSE; + g_cond_signal(&resource_manager->cond); + break; + } + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + + return; +} + +static void mrp_rset_state_callback(mrp_res_context_t *cx, const mrp_res_resource_set_t *rs, void *user_data) +{ + int i = 0; + media_streamer_resource_manager_s *resource_manager = (media_streamer_resource_manager_s *)user_data; + mrp_res_resource_t *res; + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (!mrp_res_equal_resource_set(rs, resource_manager->rset)) { + ms_info("- resource set(%p) is not same as this resource_manager handle's(%p)", rs, resource_manager->rset); + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + return; + } + + ms_debug(" - resource set state of resource_manager(%p) is changed to [%s]", resource_manager, state_to_str(rs->state)); + for (i = 0; i < MRP_RESOURCE_MAX; i++) { + res = mrp_res_get_resource_by_name(rs, resource_str[i]); + if (res == NULL) + ms_info(" -- %s not present in resource set", resource_str[i]); + else + ms_info(" -- resource name [%s] -> [%s]'", res->name, state_to_str(res->state)); + } + + mrp_res_delete_resource_set(resource_manager->rset); + resource_manager->rset = mrp_res_copy_resource_set(rs); + + if (rs->state == MRP_RES_RESOURCE_ACQUIRED) { + ms_debug(" - resource set is acquired"); + resource_manager->state = RESOURCE_STATE_ACQUIRED; + MEDIA_STREAMER_RESOURCE_SIGNAL(resource_manager); + } else if ((resource_manager->state >= RESOURCE_STATE_ACQUIRED) && + (rs->state == MRP_RES_RESOURCE_AVAILABLE)) { + ms_debug(" - resource set is released"); + resource_manager->state = RESOURCE_STATE_PREPARED; + MEDIA_STREAMER_RESOURCE_SIGNAL(resource_manager); + } + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); +} + + +static void mrp_resource_release_cb(mrp_res_context_t *cx, const mrp_res_resource_set_t *rs, void *user_data) +{ + int i = 0; + media_streamer_resource_manager_s *resource_manager = NULL; + mrp_res_resource_t *res; + + if (user_data == NULL) { + ms_error("- user_data is null"); + return; + } + resource_manager = (media_streamer_resource_manager_s *) user_data; + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (!mrp_res_equal_resource_set(rs, resource_manager->rset)) { + ms_info("- resource set(%p) is not same as this resource_manager handle's(%p)", + rs, resource_manager->rset); + return; + } + + ms_debug(" - resource set state of resource manager (%p) is changed to [%s]", + resource_manager, state_to_str(rs->state)); + for (i = 0; i < MRP_RESOURCE_MAX; i++) { + res = mrp_res_get_resource_by_name(rs, resource_str[i]); + if (res == NULL) + ms_info(" -- %s not present in resource set", resource_str[i]); + else + ms_debug(" -- resource name [%s] -> [%s] %d'", res->name, + state_to_str(res->state), res->state); + } + + if (resource_manager->release_cb) { + if (!resource_manager->release_cb(resource_manager, resource_manager->user_data)) { + ms_error("release_cb failed"); + } else { + ms_info("release_cb is fine"); + } + } else { + ms_error("release cb is NULL. Something wrong happens..."); + } + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + + return; +} + +static int create_rset(media_streamer_resource_manager_s *resource_manager) +{ + if (resource_manager->rset) { + ms_error(" - resource set was already created"); + return MEDIA_STREAMER_ERROR_INVALID_STATE; + } + + resource_manager->rset = + mrp_res_create_resource_set(resource_manager->context, + MRP_APP_CLASS_FOR_MSTREAMER, + mrp_rset_state_callback, + (void*)resource_manager); + if (resource_manager->rset == NULL) { + ms_error(" - could not create resource set"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if (!mrp_res_set_autorelease(TRUE, resource_manager->rset)) + ms_info(" - could not set autorelease flag!"); + + return MEDIA_STREAMER_ERROR_NONE; +} + +static int include_resource(media_streamer_resource_manager_s *resource_manager, const char *resource_name) +{ + mrp_res_resource_t *resource = NULL; + resource = mrp_res_create_resource(resource_manager->rset, + resource_name, + MRP_RESOURCE_TYPE_MANDATORY, + MRP_RESOURCE_TYPE_EXCLUSIVE); + if (resource == NULL) { + ms_error(" - could not include resource[%s]", resource_name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + ms_debug(" - include resource[%s]", resource_name); + + return MEDIA_STREAMER_ERROR_NONE; +} + +static int set_resource_release_cb(media_streamer_resource_manager_s *resource_manager) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + bool mrp_ret = FALSE; + + if (resource_manager->rset) { + if (MRP_RES_RESOURCE_PENDING == resource_manager->rset->state) { + /* FIXME: This workarond is only temporary solution. + When resource set is acquired again after lost the state is 'available' + and no 'pending'. Thus we skip setting reelease callback as it already + was set. */ + mrp_ret = mrp_res_set_release_callback(resource_manager->rset, mrp_resource_release_cb, resource_manager); + if (!mrp_ret) { + ms_error(" - could not set release callback"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + } else { + ms_error(" - resource set is null"); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } + + return ret; +} + +int _ms_resource_manager_init(media_streamer_resource_manager_s *resource_manager, + resource_relese_cb release_cb, void *user_data) +{ + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + ms_retvm_if(release_cb == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "release_cb is NULL"); + + g_mutex_init(&resource_manager->lock); + g_cond_init(&resource_manager->cond); + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + GMainContext *mrp_ctx = g_main_context_new(); + if (!mrp_ctx) { + ms_error("- could not create main context for resource manager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + GMainLoop *mrp_loop = g_main_loop_new(mrp_ctx, TRUE); + g_main_context_unref(mrp_ctx); + if (!mrp_loop) { + ms_error("- could not create glib mainloop for resource manager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + resource_manager->mloop = mrp_mainloop_glib_get(mrp_loop); + g_main_loop_unref(mrp_loop); + if (resource_manager->mloop) { + resource_manager->context = mrp_res_create(resource_manager->mloop, + mrp_state_callback, resource_manager); + + if (resource_manager->context == NULL) { + ms_error(" - could not get context for resource manager"); + mrp_mainloop_destroy(resource_manager->mloop); + resource_manager->mloop = NULL; + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + resource_manager->user_data = user_data; + } else { + ms_error("- could not get mainloop for resource manager"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + resource_manager->release_cb = release_cb; + resource_manager->state = RESOURCE_STATE_INITIALIZED; + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int _ms_resource_manager_prepare(media_streamer_resource_manager_s *resource_manager, media_streamer_resource_type_e resource_type) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + if (!resource_manager->rset) + ret = create_rset(resource_manager); + + if (ret == MEDIA_STREAMER_ERROR_NONE) { + switch (resource_type) { + case RESOURCE_TYPE_VIDEO_OVERLAY: + ret = include_resource(resource_manager, resource_str[MRP_RESOURCE_FOR_VIDEO_OVERLAY]); + break; + case RESOURCE_TYPE_VIDEO_DECODER: + ret = include_resource(resource_manager, resource_str[MRP_RESOURCE_FOR_VIDEO_DECODER]); + break; + case RESOURCE_TYPE_CAMERA: + ret = include_resource(resource_manager, resource_str[MRP_RESOURCE_FOR_CAMERA]); + break; + case RESOURCE_TYPE_NONE: + default: + ms_error("Wrong resource type %d", resource_type); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + break; + } + } + + if (MEDIA_STREAMER_ERROR_NONE == ret) { + resource_manager->state = RESOURCE_STATE_PREPARED; + } else { + resource_manager->state = RESOURCE_STATE_ERROR; + } + + return ret; +} + +int _ms_resource_manager_acquire(media_streamer_resource_manager_s *resource_manager) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + if (resource_manager->rset == NULL) { + ms_error("- could not acquire resource, resource set is null"); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } else { + ret = set_resource_release_cb(resource_manager); + if (ret) { + ms_error("- could not set resource release cb, ret(%d)", ret); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + ret = mrp_res_acquire_resource_set(resource_manager->rset); + if (ret) { + ms_error("- could not acquire resource, ret(%d)", ret); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + gint64 end_time = g_get_monotonic_time() + MEDIA_STREAMER_RESOURCE_TIMEOUT*G_TIME_SPAN_SECOND; + + ms_debug("- acquire resource waiting..%p till %lld", resource_manager, end_time); + if (!MEDIA_STREAMER_RESOURCE_WAIT_UNTIL(resource_manager, end_time)) { + ms_error("- could not acquire resource"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + ms_debug("- resources are acquired"); + } + } + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + } + } + + return ret; +} + +int _ms_resource_manager_release(media_streamer_resource_manager_s *resource_manager) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + if (resource_manager->rset == NULL) { + ms_error("- could not release resource, resource set is null"); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } else { + if (resource_manager->rset->state != MRP_RES_RESOURCE_ACQUIRED) { + ms_error("- could not release resource, resource set state is [%s]", state_to_str(resource_manager->rset->state)); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } else { + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + ret = mrp_res_release_resource_set(resource_manager->rset); + if (ret) { + ms_error("- could not release resource, ret(%d)", ret); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + gint64 end_time = g_get_monotonic_time() + MEDIA_STREAMER_RESOURCE_TIMEOUT*G_TIME_SPAN_SECOND; + + ms_debug("- release resource waiting..%p till %lld", resource_manager, end_time); + if (!MEDIA_STREAMER_RESOURCE_WAIT_UNTIL(resource_manager, end_time)) { + ms_info("- could not release resource in time"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } else { + ms_debug("- resources are released"); + } + } + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + } + } + + return ret; +} + +int _ms_resource_manager_unprepare(media_streamer_resource_manager_s *resource_manager) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + if (resource_manager->rset == NULL) { + ms_error("- could not unprepare for resource_manager, _ms_resource_manager_prepare() first"); + ret = MEDIA_STREAMER_ERROR_INVALID_STATE; + } else { + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + mrp_res_delete_resource_set(resource_manager->rset); + resource_manager->rset = NULL; + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + } + + resource_manager->state = RESOURCE_STATE_INITIALIZED; + + return ret; +} + +int _ms_resource_manager_deinit(media_streamer_resource_manager_s *resource_manager) +{ + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + __ms_resource_manager_wait_connection(resource_manager); + + MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + + if (resource_manager->rset) { + if (resource_manager->rset->state == MRP_RES_RESOURCE_ACQUIRED) { + if (mrp_res_release_resource_set(resource_manager->rset)) + ms_error("- could not release resource"); + } + mrp_res_delete_resource_set(resource_manager->rset); + resource_manager->rset = NULL; + } + + if (resource_manager->context) { + mrp_res_destroy(resource_manager->context); + resource_manager->context = NULL; + } + + if (resource_manager->mloop) { + mrp_mainloop_destroy(resource_manager->mloop); + resource_manager->mloop = NULL; + } + + resource_manager->release_cb = NULL; + + resource_manager->state = RESOURCE_STATE_NONE; + + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); + + g_mutex_clear(&resource_manager->lock); + g_cond_clear(&resource_manager->cond); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int _ms_resource_manager_get_state(media_streamer_resource_manager_s *resource_manager, media_streamer_resource_state_e *state) +{ + MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); + ms_retvm_if(state == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, + "state is NULL"); + + ms_debug("resource_state is %d", resource_manager->state); + + *state = resource_manager->state; + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_util.c b/src/media_streamer_util.c index 8272f50..4ea599f 100644 --- a/src/media_streamer_util.c +++ b/src/media_streamer_util.c @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -160,6 +161,8 @@ void __ms_load_ini_settings(media_streamer_ini_t *ini) /* Read exclude elements list */ __ms_ini_read_list("general:exclude elements", &ini->exclude_elem_names); + /* Read resource require elements list */ + __ms_ini_read_list("general:resource elements", &ini->resource_required_elem_names); /* Read gstreamer arguments list */ __ms_ini_read_list("general:gstreamer arguments", &ini->gst_args); @@ -327,3 +330,43 @@ int __ms_node_uri_path_check(const char *file_uri) return MEDIA_STREAMER_ERROR_NONE; } + +int __ms_bin_foreach_elements(GstBin *bin, GstIteratorFoldFunction func, void *user_data) +{ + media_streamer_s *streamer = (media_streamer_s *) user_data; + + if (!GST_BIN_NUMCHILDREN(bin)) { + ms_debug("No elements were added to bin [%s]. Skipping... ", + GST_ELEMENT_NAME(bin)); + return MEDIA_STREAMER_STATE_NONE; + } + + GstIterator *iter = gst_bin_iterate_recurse(bin); + GValue ret = G_VALUE_INIT; + GstIteratorResult result = GST_ITERATOR_DONE; + + g_value_init(&ret, G_TYPE_BOOLEAN); + result = gst_iterator_fold(iter, func, &ret, streamer); + gst_iterator_free(iter); + + switch (result) { + case GST_ITERATOR_RESYNC: + case GST_ITERATOR_ERROR: + ms_error("Error while iterating elements in bin [%s]!", + GST_ELEMENT_NAME(bin)); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + break; + case GST_ITERATOR_DONE: + case GST_ITERATOR_OK: + /* Check for last return value */ + if (!g_value_get_boolean(&ret)) { + ms_error("Failed to prepare one of nodes"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + break; + default: + break; + } + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index 309a134..3c8d834 100644 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -182,7 +182,12 @@ static void streamer_seek_cb(void *user_data) static void streamer_changed_cb(media_streamer_h streamer, media_streamer_state_e previous_state, media_streamer_state_e current_state, void *user_data) { - g_print("Media Streamer State changed [%d] -> [%d]", previous_state, current_state); + g_print("Media Streamer State changed [%d] -> [%d]\n", previous_state, current_state); +} + +static void streamer_interrubted_cb(media_streamer_interrupted_code_e code, void *user_data) +{ + g_print("Media Streamer was interrupted with code [%d]\n", code); } static void _create(media_streamer_h *streamer) @@ -215,6 +220,7 @@ static void _prepare(void) } media_streamer_set_state_change_cb(current_media_streamer, streamer_changed_cb, NULL); + media_streamer_set_interrupted_cb(current_media_streamer, streamer_interrubted_cb, NULL); g_print("== success prepare \n"); } @@ -290,13 +296,13 @@ static void _destroy(media_streamer_h streamer) int ret = MEDIA_STREAMER_ERROR_NONE; if (streamer == NULL) { - g_print("media streamer already destroyed"); + g_print("media streamer already destroyed\n"); return; } ret = media_streamer_destroy(streamer); if (ret != MEDIA_STREAMER_ERROR_NONE) { - g_print("Fail to destroy media streamer"); + g_print("Fail to destroy media streamer\n"); return; } @@ -313,7 +319,7 @@ static void _destroy(media_streamer_h streamer) static void create_formats(void) { if (!vfmt_raw || !vfmt_encoded || !afmt_raw) - g_print("Formats already created!"); + g_print("Formats already created!\n"); /* Define video raw format */ media_format_create(&vfmt_raw); @@ -1551,7 +1557,7 @@ void _interpret_getting_uri_menu(char *cmd) return; } - g_print("_interpret_getting_uri_menu %d %d %d", g_menu_state, g_sub_menu_state, g_scenario_mode); + g_print("_interpret_getting_uri_menu %d %d %d\n", g_menu_state, g_sub_menu_state, g_scenario_mode); if (g_menu_state == MENU_STATE_PLAYING_MENU) { if (g_scenario_mode == SCENARIO_MODE_FILE_SUBTITLE_VIDEO_AUDIO) { g_sub_menu_state = SUBMENU_STATE_GETTING_SUBFILE_URI; -- 2.7.4 From b79012ad96b65afc7f54debd6e5fb6ce1788b43a Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Thu, 8 Dec 2016 13:48:09 +0200 Subject: [PATCH 02/16] Implement DPM requests for camera and mic Change-Id: Ic1e57ca37017a0aac694a457e5b62b00ba0cf55b Signed-off-by: Volodymyr Brynza --- CMakeLists.txt | 4 +- include/media_streamer_node.h | 1 + include/media_streamer_node_policy.h | 40 +++++++ include/media_streamer_priv.h | 3 + packaging/capi-media-streamer.spec | 1 + src/media_streamer_node.c | 41 +++++++ src/media_streamer_node_policy.c | 204 +++++++++++++++++++++++++++++++++++ src/media_streamer_node_resources.c | 2 +- src/media_streamer_priv.c | 47 ++++++++ 9 files changed, 340 insertions(+), 3 deletions(-) create mode 100644 include/media_streamer_node_policy.h create mode 100644 src/media_streamer_node_policy.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c7e7c5..04a307d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib") -SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib") +SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib dpm") +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib dpm") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${dependents}) diff --git a/include/media_streamer_node.h b/include/media_streamer_node.h index f79f9e5..add8a37 100644 --- a/include/media_streamer_node.h +++ b/include/media_streamer_node.h @@ -131,3 +131,4 @@ int __ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, gboolean _ms_node_resouces_acquire_iter(const GValue *item, GValue *ret, gpointer user_data); gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointer user_data); +gboolean _ms_node_policy_check_iter(const GValue *item, GValue *ret, gpointer user_data); diff --git a/include/media_streamer_node_policy.h b/include/media_streamer_node_policy.h new file mode 100644 index 0000000..5f9adef --- /dev/null +++ b/include/media_streamer_node_policy.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015-2016 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. + */ + +#ifndef __MEDIA_STREAMER_NODE_POLICY_H__ +#define __MEDIA_STREAMER_NODE_POLICY_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + POLICY_TYPE_NONE, + POLICY_TYPE_CAMERA, + POLICY_TYPE_MIC, +} media_streamer_policy_type_e; + +int __ms_node_policy_init(media_streamer_node_s *node); +int __ms_node_policy_deinit(media_streamer_node_s *node); +int _ms_node_policy_check(media_streamer_node_s *node); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEDIA_STREAMER_NODE_POLICY_H__ */ diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h index 14a45f7..bbfd37b 100755 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -24,6 +24,7 @@ extern "C" { #include #include +#include #include #include @@ -137,6 +138,8 @@ typedef struct { void *callbacks_structure; media_streamer_resource_manager_s resource_manager; + device_policy_manager_h dpm_handle; + int policy_changed_cb_id; } media_streamer_node_s; typedef struct _media_streamer_wl_info_s { diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 7443f3b..317b737 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -31,6 +31,7 @@ BuildRequires: pkgconfig(ecore-wayland) BuildRequires: pkgconfig(appcore-efl) BuildRequires: pkgconfig(murphy-resource) BuildRequires: pkgconfig(murphy-glib) +BuildRequires: pkgconfig(dpm) %description A MediaStreamer library in Tizen Native API. diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index a87724f..ced5323 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -579,6 +580,12 @@ int __ms_src_node_create(media_streamer_node_s *node) return ret; } + ret = __ms_node_policy_init(node); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to init policy for node [%s]", node->name); + return ret; + } + return ret; } @@ -702,6 +709,10 @@ void __ms_node_destroy(media_streamer_node_s *node) /* Disconnects and clean all node signals */ g_list_free_full(node->sig_list, __ms_signal_destroy); + /* Deinitialize policy manager */ + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_policy_deinit(node)) + ms_error("Failed to deinitialize policy manager"); + /* Deinitialize resource manager */ if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_deinit(node)) ms_error("Failed to deinitialize resource manager"); @@ -1598,3 +1609,33 @@ gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointe return TRUE; } + +gboolean _ms_node_policy_check_iter(const GValue *item, GValue *ret, gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) user_data; + media_streamer_node_s *node = NULL; + GstElement *element = NULL; + g_value_set_boolean(ret, FALSE); + + element = GST_ELEMENT(g_value_get_object(item)); + g_object_ref(element); + + node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, + GST_ELEMENT_NAME(element)); + if (!node) { + /* If we fail to found corresonding node inside streamer + then apprently this element doesn't require resources */ + ms_info("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); + g_value_set_boolean(ret, TRUE); + return TRUE; + } + + if (MEDIA_STREAMER_ERROR_NONE != _ms_node_policy_check(node)) { + ms_error("Failed to check policy for node [%s]", node->name); + return FALSE; + } + + g_value_set_boolean(ret, TRUE); + + return TRUE; +} diff --git a/src/media_streamer_node_policy.c b/src/media_streamer_node_policy.c new file mode 100644 index 0000000..90628b9 --- /dev/null +++ b/src/media_streamer_node_policy.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2016 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 +#include + +#include +#include +#include +#include + +#define DPM_ALLOWED 1 +#define DPM_DISALLOWED 0 + +enum { + DPM_POLICY_FOR_CAMERA, + DPM_POLICY_FOR_MIC, + DPM_POLICY_MAX, +}; +const char* policy_str[DPM_POLICY_MAX] = { + "camera", + "microphone", +}; + +static void __ms_node_get_dpm_check_needed(media_streamer_node_s *node, + media_streamer_policy_type_e *policy) { + int subtype = node->subtype; + + ms_debug("Checking policy for node type %d, subtype %d", node->type, subtype); + + /* Check for node types */ + switch (subtype) { + case MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA: + case MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_CAPTURE: + *policy = POLICY_TYPE_CAMERA; + break; + case MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE: + *policy = POLICY_TYPE_MIC; + break; + default: + break; + } +} + +static void __ms_node_policy_changed_cb(const char *name, const char *value, void *user_data) +{ + if (user_data == NULL) + return; + + media_streamer_node_s *node = (media_streamer_node_s *) user_data; + media_streamer_s *streamer = (media_streamer_s *) node->parent_streamer; + ms_info("Received policy_changed_cb from node [%s]", node->name); + + /* Here we perform action to release resources relases that + were previoursly acquired. Basically what we need to do is + to unprepare media streamer.*/ + g_mutex_lock(&streamer->mutex_lock); + streamer->is_interrupted = TRUE; + if (MEDIA_STREAMER_ERROR_NONE != + __ms_pipeline_unprepare(streamer)) { + ms_error("Failed to unprepare streamer"); + streamer->is_interrupted = FALSE; + g_mutex_unlock(&streamer->mutex_lock); + return; + } + streamer->is_interrupted = FALSE; + + /* Call interrupted_cb with appropriate code */ + media_streamer_interrupted_cb interrupted_cb = + (media_streamer_interrupted_cb) streamer->interrupted_cb.callback; + if (interrupted_cb) { + interrupted_cb(MEDIA_STREAMER_INTERRUPTED_BY_SECURITY, + streamer->interrupted_cb.user_data); + } else { + ms_info("Interuption will not be handled because interrupted_cb is NULL"); + } + g_mutex_unlock(&streamer->mutex_lock); +} + +int __ms_node_policy_init(media_streamer_node_s *node) +{ + media_streamer_policy_type_e policy = POLICY_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + const char *policy_name = NULL; + + /* Check if node require policy manager */ + __ms_node_get_dpm_check_needed(node, &policy); + if (POLICY_TYPE_NONE == policy) { + ms_info("No policy is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + switch (policy) { + case POLICY_TYPE_CAMERA: + policy_name = policy_str[DPM_POLICY_FOR_CAMERA]; + break; + case POLICY_TYPE_MIC: + policy_name = policy_str[DPM_POLICY_FOR_MIC]; + break; + default: + break; + } + /* Initialize policy manager */ + node->dpm_handle = dpm_manager_create(); + if (node->dpm_handle) { + int dpm_ret = DPM_ERROR_NONE; + dpm_ret = dpm_add_policy_changed_cb(node->dpm_handle, policy_name, + __ms_node_policy_changed_cb, (void *)node, &node->policy_changed_cb_id); + + if (dpm_ret != DPM_ERROR_NONE) { + ms_error("add DPM changed cb failed, keep going"); + node->policy_changed_cb_id = 0; + } + ms_debug("DPM initialized"); + } + + return ret; +} + +int __ms_node_policy_deinit(media_streamer_node_s *node) +{ + media_streamer_policy_type_e policy = POLICY_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Check if node require policy manager */ + __ms_node_get_dpm_check_needed(node, &policy); + if (POLICY_TYPE_NONE == policy) { + ms_info("No policy is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (node->dpm_handle) { + if (node->policy_changed_cb_id > 0) { + dpm_remove_policy_changed_cb(node->dpm_handle, node->policy_changed_cb_id); + } else { + ms_info("invalid dpm cb id"); + } + ms_debug("DPM released"); + } + + dpm_manager_destroy(node->dpm_handle); + node->dpm_handle = NULL; + + return ret; +} + +int _ms_node_policy_check(media_streamer_node_s *node) +{ + media_streamer_policy_type_e policy = POLICY_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + int dpm_state = DPM_ALLOWED; + int dpm_ret = DPM_ERROR_NONE; + + /* Check if node require policy manager */ + __ms_node_get_dpm_check_needed(node, &policy); + if (POLICY_TYPE_NONE == policy) { + ms_info("No policy is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (node->dpm_handle == NULL) { + ms_error("DPM manager handle is NULL"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + switch (policy) { + case POLICY_TYPE_CAMERA: + dpm_ret = dpm_restriction_get_camera_state(node->dpm_handle, &dpm_state); + break; + case POLICY_TYPE_MIC: + dpm_ret = dpm_restriction_get_microphone_state(node->dpm_handle, &dpm_state); + break; + default: + break; + } + + if (dpm_ret == DPM_ERROR_NONE) { + ms_info("DPM state - %d", dpm_state); + if (dpm_state == DPM_DISALLOWED) { + ms_error("Policy disallowed by DPM"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } else { + ms_info("get DPM state failed, continue too work"); + } + + return ret; +} diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c index 5dabe15..3c1545a 100644 --- a/src/media_streamer_node_resources.c +++ b/src/media_streamer_node_resources.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 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. diff --git a/src/media_streamer_priv.c b/src/media_streamer_priv.c index 3fe8485..a6b995d 100644 --- a/src/media_streamer_priv.c +++ b/src/media_streamer_priv.c @@ -23,6 +23,7 @@ #define GST_TIME_TO_MSEC(t) (t == GST_CLOCK_TIME_NONE ? t : (int)(((GstClockTime)(t)) / GST_MSECOND)) int __ms_change_resources_state(media_streamer_s *ms_streamer, media_streamer_state_e state); +int __ms_change_policy_state(media_streamer_s *ms_streamer, media_streamer_state_e state); static gboolean media_streamer_resource_relese_cb(media_streamer_resource_manager_s *resource_manager, void *user_data); int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e state) @@ -33,6 +34,11 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat ms_retvm_if(ms_streamer->state == state, MEDIA_STREAMER_ERROR_NONE, "Media streamer already in this state"); if (!ms_streamer->is_interrupted) { + ret = __ms_change_policy_state(ms_streamer, state); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to change policy state for streamer %p", ms_streamer); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } ret = __ms_change_resources_state(ms_streamer, state); if (MEDIA_STREAMER_ERROR_NONE != ret) { ms_error("Failed to change resources state for streamer %p", ms_streamer); @@ -338,3 +344,44 @@ static gboolean media_streamer_resource_relese_cb( return TRUE; } + +int __ms_check_policy(media_streamer_s *ms_streamer) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Acquire resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), + _ms_node_policy_check_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to check policies for src bin"); + return ret; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_change_policy_state(media_streamer_s *ms_streamer, media_streamer_state_e state) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* According to state graph we need to handle only this state + * and different transotions into them */ + if (state == MEDIA_STREAMER_STATE_READY) { + switch (ms_streamer->pend_state) { + case MEDIA_STREAMER_STATE_IDLE: + /* After prepare function */ + ret = __ms_check_policy(ms_streamer); + break; + case MEDIA_STREAMER_STATE_PAUSED: + case MEDIA_STREAMER_STATE_PLAYING: + case MEDIA_STREAMER_STATE_NONE: + case MEDIA_STREAMER_STATE_SEEKING: + default: + break; + } + } else { + ms_debug("Ignoring state for policy managements"); + } + + return ret; +} -- 2.7.4 From 73a6be599b809791ca3f094cc2902a789c168751 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Thu, 8 Dec 2016 13:48:09 +0200 Subject: [PATCH 03/16] Implement DPM requests for camera and mic Change-Id: Ic1e57ca37017a0aac694a457e5b62b00ba0cf55b Signed-off-by: Volodymyr Brynza (cherry picked from commit b79012ad96b65afc7f54debd6e5fb6ce1788b43a) --- CMakeLists.txt | 4 +- include/media_streamer_node.h | 1 + include/media_streamer_node_policy.h | 40 +++++++ include/media_streamer_priv.h | 3 + packaging/capi-media-streamer.spec | 1 + src/media_streamer_node.c | 41 +++++++ src/media_streamer_node_policy.c | 204 +++++++++++++++++++++++++++++++++++ src/media_streamer_node_resources.c | 2 +- src/media_streamer_priv.c | 47 ++++++++ 9 files changed, 340 insertions(+), 3 deletions(-) create mode 100644 include/media_streamer_node_policy.h create mode 100644 src/media_streamer_node_policy.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 0c7e7c5..04a307d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib") -SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib") +SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib dpm") +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib dpm") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${dependents}) diff --git a/include/media_streamer_node.h b/include/media_streamer_node.h index f79f9e5..add8a37 100644 --- a/include/media_streamer_node.h +++ b/include/media_streamer_node.h @@ -131,3 +131,4 @@ int __ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, gboolean _ms_node_resouces_acquire_iter(const GValue *item, GValue *ret, gpointer user_data); gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointer user_data); +gboolean _ms_node_policy_check_iter(const GValue *item, GValue *ret, gpointer user_data); diff --git a/include/media_streamer_node_policy.h b/include/media_streamer_node_policy.h new file mode 100644 index 0000000..5f9adef --- /dev/null +++ b/include/media_streamer_node_policy.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2015-2016 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. + */ + +#ifndef __MEDIA_STREAMER_NODE_POLICY_H__ +#define __MEDIA_STREAMER_NODE_POLICY_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + POLICY_TYPE_NONE, + POLICY_TYPE_CAMERA, + POLICY_TYPE_MIC, +} media_streamer_policy_type_e; + +int __ms_node_policy_init(media_streamer_node_s *node); +int __ms_node_policy_deinit(media_streamer_node_s *node); +int _ms_node_policy_check(media_streamer_node_s *node); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEDIA_STREAMER_NODE_POLICY_H__ */ diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h index 14a45f7..bbfd37b 100755 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -24,6 +24,7 @@ extern "C" { #include #include +#include #include #include @@ -137,6 +138,8 @@ typedef struct { void *callbacks_structure; media_streamer_resource_manager_s resource_manager; + device_policy_manager_h dpm_handle; + int policy_changed_cb_id; } media_streamer_node_s; typedef struct _media_streamer_wl_info_s { diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 7443f3b..317b737 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -31,6 +31,7 @@ BuildRequires: pkgconfig(ecore-wayland) BuildRequires: pkgconfig(appcore-efl) BuildRequires: pkgconfig(murphy-resource) BuildRequires: pkgconfig(murphy-glib) +BuildRequires: pkgconfig(dpm) %description A MediaStreamer library in Tizen Native API. diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index a87724f..ced5323 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -16,6 +16,7 @@ #include #include +#include #include #include #include @@ -579,6 +580,12 @@ int __ms_src_node_create(media_streamer_node_s *node) return ret; } + ret = __ms_node_policy_init(node); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to init policy for node [%s]", node->name); + return ret; + } + return ret; } @@ -702,6 +709,10 @@ void __ms_node_destroy(media_streamer_node_s *node) /* Disconnects and clean all node signals */ g_list_free_full(node->sig_list, __ms_signal_destroy); + /* Deinitialize policy manager */ + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_policy_deinit(node)) + ms_error("Failed to deinitialize policy manager"); + /* Deinitialize resource manager */ if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_deinit(node)) ms_error("Failed to deinitialize resource manager"); @@ -1598,3 +1609,33 @@ gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointe return TRUE; } + +gboolean _ms_node_policy_check_iter(const GValue *item, GValue *ret, gpointer user_data) +{ + media_streamer_s *ms_streamer = (media_streamer_s *) user_data; + media_streamer_node_s *node = NULL; + GstElement *element = NULL; + g_value_set_boolean(ret, FALSE); + + element = GST_ELEMENT(g_value_get_object(item)); + g_object_ref(element); + + node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, + GST_ELEMENT_NAME(element)); + if (!node) { + /* If we fail to found corresonding node inside streamer + then apprently this element doesn't require resources */ + ms_info("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); + g_value_set_boolean(ret, TRUE); + return TRUE; + } + + if (MEDIA_STREAMER_ERROR_NONE != _ms_node_policy_check(node)) { + ms_error("Failed to check policy for node [%s]", node->name); + return FALSE; + } + + g_value_set_boolean(ret, TRUE); + + return TRUE; +} diff --git a/src/media_streamer_node_policy.c b/src/media_streamer_node_policy.c new file mode 100644 index 0000000..90628b9 --- /dev/null +++ b/src/media_streamer_node_policy.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2016 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 +#include + +#include +#include +#include +#include + +#define DPM_ALLOWED 1 +#define DPM_DISALLOWED 0 + +enum { + DPM_POLICY_FOR_CAMERA, + DPM_POLICY_FOR_MIC, + DPM_POLICY_MAX, +}; +const char* policy_str[DPM_POLICY_MAX] = { + "camera", + "microphone", +}; + +static void __ms_node_get_dpm_check_needed(media_streamer_node_s *node, + media_streamer_policy_type_e *policy) { + int subtype = node->subtype; + + ms_debug("Checking policy for node type %d, subtype %d", node->type, subtype); + + /* Check for node types */ + switch (subtype) { + case MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA: + case MEDIA_STREAMER_NODE_SRC_TYPE_VIDEO_CAPTURE: + *policy = POLICY_TYPE_CAMERA; + break; + case MEDIA_STREAMER_NODE_SRC_TYPE_AUDIO_CAPTURE: + *policy = POLICY_TYPE_MIC; + break; + default: + break; + } +} + +static void __ms_node_policy_changed_cb(const char *name, const char *value, void *user_data) +{ + if (user_data == NULL) + return; + + media_streamer_node_s *node = (media_streamer_node_s *) user_data; + media_streamer_s *streamer = (media_streamer_s *) node->parent_streamer; + ms_info("Received policy_changed_cb from node [%s]", node->name); + + /* Here we perform action to release resources relases that + were previoursly acquired. Basically what we need to do is + to unprepare media streamer.*/ + g_mutex_lock(&streamer->mutex_lock); + streamer->is_interrupted = TRUE; + if (MEDIA_STREAMER_ERROR_NONE != + __ms_pipeline_unprepare(streamer)) { + ms_error("Failed to unprepare streamer"); + streamer->is_interrupted = FALSE; + g_mutex_unlock(&streamer->mutex_lock); + return; + } + streamer->is_interrupted = FALSE; + + /* Call interrupted_cb with appropriate code */ + media_streamer_interrupted_cb interrupted_cb = + (media_streamer_interrupted_cb) streamer->interrupted_cb.callback; + if (interrupted_cb) { + interrupted_cb(MEDIA_STREAMER_INTERRUPTED_BY_SECURITY, + streamer->interrupted_cb.user_data); + } else { + ms_info("Interuption will not be handled because interrupted_cb is NULL"); + } + g_mutex_unlock(&streamer->mutex_lock); +} + +int __ms_node_policy_init(media_streamer_node_s *node) +{ + media_streamer_policy_type_e policy = POLICY_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + const char *policy_name = NULL; + + /* Check if node require policy manager */ + __ms_node_get_dpm_check_needed(node, &policy); + if (POLICY_TYPE_NONE == policy) { + ms_info("No policy is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + switch (policy) { + case POLICY_TYPE_CAMERA: + policy_name = policy_str[DPM_POLICY_FOR_CAMERA]; + break; + case POLICY_TYPE_MIC: + policy_name = policy_str[DPM_POLICY_FOR_MIC]; + break; + default: + break; + } + /* Initialize policy manager */ + node->dpm_handle = dpm_manager_create(); + if (node->dpm_handle) { + int dpm_ret = DPM_ERROR_NONE; + dpm_ret = dpm_add_policy_changed_cb(node->dpm_handle, policy_name, + __ms_node_policy_changed_cb, (void *)node, &node->policy_changed_cb_id); + + if (dpm_ret != DPM_ERROR_NONE) { + ms_error("add DPM changed cb failed, keep going"); + node->policy_changed_cb_id = 0; + } + ms_debug("DPM initialized"); + } + + return ret; +} + +int __ms_node_policy_deinit(media_streamer_node_s *node) +{ + media_streamer_policy_type_e policy = POLICY_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Check if node require policy manager */ + __ms_node_get_dpm_check_needed(node, &policy); + if (POLICY_TYPE_NONE == policy) { + ms_info("No policy is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (node->dpm_handle) { + if (node->policy_changed_cb_id > 0) { + dpm_remove_policy_changed_cb(node->dpm_handle, node->policy_changed_cb_id); + } else { + ms_info("invalid dpm cb id"); + } + ms_debug("DPM released"); + } + + dpm_manager_destroy(node->dpm_handle); + node->dpm_handle = NULL; + + return ret; +} + +int _ms_node_policy_check(media_streamer_node_s *node) +{ + media_streamer_policy_type_e policy = POLICY_TYPE_NONE; + int ret = MEDIA_STREAMER_ERROR_NONE; + int dpm_state = DPM_ALLOWED; + int dpm_ret = DPM_ERROR_NONE; + + /* Check if node require policy manager */ + __ms_node_get_dpm_check_needed(node, &policy); + if (POLICY_TYPE_NONE == policy) { + ms_info("No policy is needed for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + + if (node->dpm_handle == NULL) { + ms_error("DPM manager handle is NULL"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + switch (policy) { + case POLICY_TYPE_CAMERA: + dpm_ret = dpm_restriction_get_camera_state(node->dpm_handle, &dpm_state); + break; + case POLICY_TYPE_MIC: + dpm_ret = dpm_restriction_get_microphone_state(node->dpm_handle, &dpm_state); + break; + default: + break; + } + + if (dpm_ret == DPM_ERROR_NONE) { + ms_info("DPM state - %d", dpm_state); + if (dpm_state == DPM_DISALLOWED) { + ms_error("Policy disallowed by DPM"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } else { + ms_info("get DPM state failed, continue too work"); + } + + return ret; +} diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c index 5dabe15..3c1545a 100644 --- a/src/media_streamer_node_resources.c +++ b/src/media_streamer_node_resources.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2016 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. diff --git a/src/media_streamer_priv.c b/src/media_streamer_priv.c index 3fe8485..a6b995d 100644 --- a/src/media_streamer_priv.c +++ b/src/media_streamer_priv.c @@ -23,6 +23,7 @@ #define GST_TIME_TO_MSEC(t) (t == GST_CLOCK_TIME_NONE ? t : (int)(((GstClockTime)(t)) / GST_MSECOND)) int __ms_change_resources_state(media_streamer_s *ms_streamer, media_streamer_state_e state); +int __ms_change_policy_state(media_streamer_s *ms_streamer, media_streamer_state_e state); static gboolean media_streamer_resource_relese_cb(media_streamer_resource_manager_s *resource_manager, void *user_data); int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e state) @@ -33,6 +34,11 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat ms_retvm_if(ms_streamer->state == state, MEDIA_STREAMER_ERROR_NONE, "Media streamer already in this state"); if (!ms_streamer->is_interrupted) { + ret = __ms_change_policy_state(ms_streamer, state); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to change policy state for streamer %p", ms_streamer); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } ret = __ms_change_resources_state(ms_streamer, state); if (MEDIA_STREAMER_ERROR_NONE != ret) { ms_error("Failed to change resources state for streamer %p", ms_streamer); @@ -338,3 +344,44 @@ static gboolean media_streamer_resource_relese_cb( return TRUE; } + +int __ms_check_policy(media_streamer_s *ms_streamer) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* Acquire resources for src bin */ + ret = __ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), + _ms_node_policy_check_iter, ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != ret) { + ms_error("Failed to check policies for src bin"); + return ret; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_change_policy_state(media_streamer_s *ms_streamer, media_streamer_state_e state) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + + /* According to state graph we need to handle only this state + * and different transotions into them */ + if (state == MEDIA_STREAMER_STATE_READY) { + switch (ms_streamer->pend_state) { + case MEDIA_STREAMER_STATE_IDLE: + /* After prepare function */ + ret = __ms_check_policy(ms_streamer); + break; + case MEDIA_STREAMER_STATE_PAUSED: + case MEDIA_STREAMER_STATE_PLAYING: + case MEDIA_STREAMER_STATE_NONE: + case MEDIA_STREAMER_STATE_SEEKING: + default: + break; + } + } else { + ms_debug("Ignoring state for policy managements"); + } + + return ret; +} -- 2.7.4 From 7c16b0bd37214f99f2bb3dd1a46d67bd87961484 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Mon, 19 Dec 2016 22:31:44 +0200 Subject: [PATCH 04/16] Add Murphy loop quit to prevent polling after destroy Change-Id: I789b032fced4b95a767b4efcda92c54fb5c2cd12 Signed-off-by: Volodymyr Brynza --- src/media_streamer_resource.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/media_streamer_resource.c b/src/media_streamer_resource.c index 4d84082..6f99048 100644 --- a/src/media_streamer_resource.c +++ b/src/media_streamer_resource.c @@ -520,6 +520,7 @@ int _ms_resource_manager_deinit(media_streamer_resource_manager_s *resource_mana } if (resource_manager->mloop) { + mrp_mainloop_quit(resource_manager->mloop, 0); mrp_mainloop_destroy(resource_manager->mloop); resource_manager->mloop = NULL; } -- 2.7.4 From 526c4fde1380d5fcdfa70a0a8c320c10af3094c8 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Mon, 19 Dec 2016 22:31:44 +0200 Subject: [PATCH 05/16] Add Murphy loop quit to prevent polling after destroy Change-Id: I789b032fced4b95a767b4efcda92c54fb5c2cd12 Signed-off-by: Volodymyr Brynza (cherry picked from commit 7c16b0bd37214f99f2bb3dd1a46d67bd87961484) --- src/media_streamer_resource.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/media_streamer_resource.c b/src/media_streamer_resource.c index 4d84082..6f99048 100644 --- a/src/media_streamer_resource.c +++ b/src/media_streamer_resource.c @@ -520,6 +520,7 @@ int _ms_resource_manager_deinit(media_streamer_resource_manager_s *resource_mana } if (resource_manager->mloop) { + mrp_mainloop_quit(resource_manager->mloop, 0); mrp_mainloop_destroy(resource_manager->mloop); resource_manager->mloop = NULL; } -- 2.7.4 From 6fceb7b1aa3d798c22ffc7b1cb13403976b1c034 Mon Sep 17 00:00:00 2001 From: Oleksandr Popov Date: Tue, 27 Dec 2016 19:00:21 +0200 Subject: [PATCH 06/16] Add platform check before resource manager initialization Change-Id: I001fbd14fe4589db030a69e6fd985a32460ac6da Signed-off-by: Oleksandr Popov --- include/media_streamer_resource.h | 2 +- src/media_streamer_node_resources.c | 58 +++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/include/media_streamer_resource.h b/include/media_streamer_resource.h index 27da5ca..2cefdc8 100644 --- a/include/media_streamer_resource.h +++ b/include/media_streamer_resource.h @@ -52,7 +52,7 @@ typedef enum { } media_streamer_resource_state_e; typedef struct _media_streamer_resource_manager_s media_streamer_resource_manager_s; -typedef gboolean (*resource_relese_cb) (media_streamer_resource_manager_s *resource_manager, void *user_data); +typedef gboolean (*resource_relese_cb)(media_streamer_resource_manager_s *resource_manager, void *user_data); struct _media_streamer_resource_manager_s { mrp_mainloop_t *mloop; diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c index 3c1545a..5e96813 100644 --- a/src/media_streamer_node_resources.c +++ b/src/media_streamer_node_resources.c @@ -16,6 +16,8 @@ #include +#include + #include #include #include @@ -61,6 +63,41 @@ static gboolean __ms_resource_relese_cb( return TRUE; } +static gboolean __ms_node_resources_is_needed_by_platform(media_streamer_node_s *node) +{ + media_streamer_node_type_e type = node->type; + int subtype = node->subtype; + char *model_name, *platform_processor; + gboolean ret = FALSE; + + /* Checking for model_name and processor because some resources + are platform dependent */ + system_info_get_platform_string("http://tizen.org/system/model_name", &model_name); + system_info_get_platform_string("http://tizen.org/system/platform.processor", &platform_processor); + ms_info("Check for resources for model_name %s, platform.processor %s", model_name, platform_processor); + + switch (type) { + case MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER: + case MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER: + if (!g_strcmp0(model_name, "Emulator") || + !g_strcmp0(platform_processor, "Emulator")) + ret = FALSE; + break; + case MEDIA_STREAMER_NODE_TYPE_SRC: + if (MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA == subtype) + ret = TRUE; + break; + case MEDIA_STREAMER_NODE_TYPE_SINK: + if (MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY == subtype) + ret = TRUE; + break; + default: + break; + } + + return ret; +} + static void __ms_node_get_resources_needed(media_streamer_node_s *node, media_streamer_resource_type_e *resource) { media_streamer_node_type_e type = node->type; @@ -101,6 +138,13 @@ int __ms_node_resouces_init(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } + /* Check if platform requires resource (e.g. Emulator) */ + if (!__ms_node_resources_is_needed_by_platform(node)) { + ms_info("Platform doesn't require resource for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + /* Initialize resource manager */ ret = _ms_resource_manager_init(&node->resource_manager, __ms_resource_relese_cb, node); @@ -125,6 +169,13 @@ int __ms_node_resouces_deinit(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } + /* Check if platform requires resource (e.g. Emulator) */ + if (!__ms_node_resources_is_needed_by_platform(node)) { + ms_info("Platform doesn't require resource for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + /* Deinitialize resource manager */ ret = _ms_resource_manager_deinit(&node->resource_manager); if (ret != MEDIA_STREAMER_ERROR_NONE) { @@ -196,6 +247,13 @@ int _ms_node_resource_aquire(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } + /* Check if platform requires resource (e.g. Emulator) */ + if (!__ms_node_resources_is_needed_by_platform(node)) { + ms_info("Platform doesn't require resource for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_prepare(node, resource)) { ms_error("Failed to prepare resources for Node [%p]", node); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; -- 2.7.4 From 81d4e447b82db4346069405ecfcfaeaf1fc0b388 Mon Sep 17 00:00:00 2001 From: Oleksandr Popov Date: Tue, 27 Dec 2016 19:00:21 +0200 Subject: [PATCH 07/16] Add platform check before resource manager initialization Change-Id: I001fbd14fe4589db030a69e6fd985a32460ac6da Signed-off-by: Oleksandr Popov --- include/media_streamer_resource.h | 2 +- src/media_streamer_node_resources.c | 58 +++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/include/media_streamer_resource.h b/include/media_streamer_resource.h index 27da5ca..2cefdc8 100644 --- a/include/media_streamer_resource.h +++ b/include/media_streamer_resource.h @@ -52,7 +52,7 @@ typedef enum { } media_streamer_resource_state_e; typedef struct _media_streamer_resource_manager_s media_streamer_resource_manager_s; -typedef gboolean (*resource_relese_cb) (media_streamer_resource_manager_s *resource_manager, void *user_data); +typedef gboolean (*resource_relese_cb)(media_streamer_resource_manager_s *resource_manager, void *user_data); struct _media_streamer_resource_manager_s { mrp_mainloop_t *mloop; diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c index 3c1545a..5e96813 100644 --- a/src/media_streamer_node_resources.c +++ b/src/media_streamer_node_resources.c @@ -16,6 +16,8 @@ #include +#include + #include #include #include @@ -61,6 +63,41 @@ static gboolean __ms_resource_relese_cb( return TRUE; } +static gboolean __ms_node_resources_is_needed_by_platform(media_streamer_node_s *node) +{ + media_streamer_node_type_e type = node->type; + int subtype = node->subtype; + char *model_name, *platform_processor; + gboolean ret = FALSE; + + /* Checking for model_name and processor because some resources + are platform dependent */ + system_info_get_platform_string("http://tizen.org/system/model_name", &model_name); + system_info_get_platform_string("http://tizen.org/system/platform.processor", &platform_processor); + ms_info("Check for resources for model_name %s, platform.processor %s", model_name, platform_processor); + + switch (type) { + case MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER: + case MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER: + if (!g_strcmp0(model_name, "Emulator") || + !g_strcmp0(platform_processor, "Emulator")) + ret = FALSE; + break; + case MEDIA_STREAMER_NODE_TYPE_SRC: + if (MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA == subtype) + ret = TRUE; + break; + case MEDIA_STREAMER_NODE_TYPE_SINK: + if (MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY == subtype) + ret = TRUE; + break; + default: + break; + } + + return ret; +} + static void __ms_node_get_resources_needed(media_streamer_node_s *node, media_streamer_resource_type_e *resource) { media_streamer_node_type_e type = node->type; @@ -101,6 +138,13 @@ int __ms_node_resouces_init(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } + /* Check if platform requires resource (e.g. Emulator) */ + if (!__ms_node_resources_is_needed_by_platform(node)) { + ms_info("Platform doesn't require resource for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + /* Initialize resource manager */ ret = _ms_resource_manager_init(&node->resource_manager, __ms_resource_relese_cb, node); @@ -125,6 +169,13 @@ int __ms_node_resouces_deinit(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } + /* Check if platform requires resource (e.g. Emulator) */ + if (!__ms_node_resources_is_needed_by_platform(node)) { + ms_info("Platform doesn't require resource for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + /* Deinitialize resource manager */ ret = _ms_resource_manager_deinit(&node->resource_manager); if (ret != MEDIA_STREAMER_ERROR_NONE) { @@ -196,6 +247,13 @@ int _ms_node_resource_aquire(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } + /* Check if platform requires resource (e.g. Emulator) */ + if (!__ms_node_resources_is_needed_by_platform(node)) { + ms_info("Platform doesn't require resource for %p node type [%d] subtype [%d]", + node, node->type, node->subtype); + return MEDIA_STREAMER_ERROR_NONE; + } + if (MEDIA_STREAMER_ERROR_NONE != __ms_node_resouces_prepare(node, resource)) { ms_error("Failed to prepare resources for Node [%p]", node); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; -- 2.7.4 From 0a187c0051812dbe8e6c2f12c189cac7c2b239ae Mon Sep 17 00:00:00 2001 From: Oleksandr Popov Date: Tue, 27 Dec 2016 19:39:48 +0200 Subject: [PATCH 08/16] Added missing condition for resource management check Signed-off-by: Oleksandr Popov Change-Id: I700bad3752224583d04762081689b48188a5ec74 --- src/media_streamer_node_resources.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c index 5e96813..2f69001 100644 --- a/src/media_streamer_node_resources.c +++ b/src/media_streamer_node_resources.c @@ -82,6 +82,8 @@ static gboolean __ms_node_resources_is_needed_by_platform(media_streamer_node_s if (!g_strcmp0(model_name, "Emulator") || !g_strcmp0(platform_processor, "Emulator")) ret = FALSE; + else + ret = TRUE; break; case MEDIA_STREAMER_NODE_TYPE_SRC: if (MEDIA_STREAMER_NODE_SRC_TYPE_CAMERA == subtype) -- 2.7.4 From 4b988c903016df04335ca09a98ed9ddf9cf544a1 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Mon, 9 Jan 2017 21:52:24 +0900 Subject: [PATCH 09/16] [v0.1.12] init mrp after create pipeline and add missed unlock Change-Id: Icd662f3ce720ed2863a05dc0045b52459ff90717 (cherry picked from commit 1603f61104ec15d3adb42edfc4a694c21e1788d7) --- packaging/capi-media-streamer.spec | 2 +- src/media_streamer.c | 1 + src/media_streamer_gst.c | 10 +++++----- src/media_streamer_node_policy.c | 16 ++++++++-------- src/media_streamer_priv.c | 6 +++++- src/media_streamer_resource.c | 34 ++++++++++++++++++++-------------- 6 files changed, 40 insertions(+), 29 deletions(-) diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 317b737..89c0c35 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.11 +Version: 0.1.12 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer.c b/src/media_streamer.c index 73ba7dc..a17c699 100644 --- a/src/media_streamer.c +++ b/src/media_streamer.c @@ -256,6 +256,7 @@ int media_streamer_create(media_streamer_h *streamer) ret = __ms_create(ms_streamer); if (ret != MEDIA_STREAMER_ERROR_NONE) { ms_error("Error creating Media Streamer"); + g_mutex_unlock(&ms_streamer->mutex_lock); __ms_streamer_destroy(ms_streamer); return ret; diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index f3961d4..c592087 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -2068,15 +2068,15 @@ static void __demux_nomore_pads_combine(GstPad *src_pad, media_streamer_s *ms_st { GstElement *found_element = gst_pad_get_parent_element(src_pad); const gchar *new_pad_type = __ms_get_pad_type(src_pad); - if (MS_ELEMENT_IS_VIDEO(new_pad_type)) { + if (MS_ELEMENT_IS_VIDEO(new_pad_type)) found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER); - } else if (MS_ELEMENT_IS_AUDIO(new_pad_type)) { + else if (MS_ELEMENT_IS_AUDIO(new_pad_type)) found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER); - } else if (MS_ELEMENT_IS_TEXT(new_pad_type)) { + else if (MS_ELEMENT_IS_TEXT(new_pad_type)) found_element = __ms_combine_next_element(found_element, src_pad, ms_streamer->topology_bin, MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY); - } else { + else ms_error("Unsupported pad type [%s]!", new_pad_type); - } + __ms_generate_dots(ms_streamer->pipeline, "after_demux_linked"); gst_object_unref(found_element); } diff --git a/src/media_streamer_node_policy.c b/src/media_streamer_node_policy.c index 90628b9..3c4f6ec 100644 --- a/src/media_streamer_node_policy.c +++ b/src/media_streamer_node_policy.c @@ -145,11 +145,11 @@ int __ms_node_policy_deinit(media_streamer_node_s *node) } if (node->dpm_handle) { - if (node->policy_changed_cb_id > 0) { + if (node->policy_changed_cb_id > 0) dpm_remove_policy_changed_cb(node->dpm_handle, node->policy_changed_cb_id); - } else { + else ms_info("invalid dpm cb id"); - } + ms_debug("DPM released"); } @@ -191,11 +191,11 @@ int _ms_node_policy_check(media_streamer_node_s *node) } if (dpm_ret == DPM_ERROR_NONE) { - ms_info("DPM state - %d", dpm_state); - if (dpm_state == DPM_DISALLOWED) { - ms_error("Policy disallowed by DPM"); - return MEDIA_STREAMER_ERROR_INVALID_OPERATION; - } + ms_info("DPM state - %d", dpm_state); + if (dpm_state == DPM_DISALLOWED) { + ms_error("Policy disallowed by DPM"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } } else { ms_info("get DPM state failed, continue too work"); } diff --git a/src/media_streamer_priv.c b/src/media_streamer_priv.c index a6b995d..c3825dc 100644 --- a/src/media_streamer_priv.c +++ b/src/media_streamer_priv.c @@ -91,11 +91,14 @@ int __ms_state_change(media_streamer_s *ms_streamer, media_streamer_state_e stat int __ms_create(media_streamer_s *ms_streamer) { + int ret = MEDIA_STREAMER_ERROR_NONE; __ms_load_ini_settings(&ms_streamer->ini); ms_streamer->nodes_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, __ms_node_remove_from_table); ms_retvm_if(ms_streamer->nodes_table == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating hash table"); + ret = __ms_pipeline_create(ms_streamer); + if (MEDIA_STREAMER_ERROR_NONE != _ms_resource_manager_init( &ms_streamer->resource_manager, media_streamer_resource_relese_cb, @@ -104,7 +107,7 @@ int __ms_create(media_streamer_s *ms_streamer) return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } - return __ms_pipeline_create(ms_streamer); + return ret; } int __ms_get_position(media_streamer_s *ms_streamer, int *time) @@ -189,6 +192,7 @@ int __ms_streamer_destroy(media_streamer_s *ms_streamer) if (MEDIA_STREAMER_ERROR_NONE != _ms_resource_manager_deinit(&ms_streamer->resource_manager)) { ms_error("Failed to deinit resource manager for media streamer"); + g_mutex_unlock(&ms_streamer->mutex_lock); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } diff --git a/src/media_streamer_resource.c b/src/media_streamer_resource.c index 6f99048..bce054d 100644 --- a/src/media_streamer_resource.c +++ b/src/media_streamer_resource.c @@ -64,9 +64,9 @@ static int __ms_resource_manager_wait_connection(media_streamer_resource_manager MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } else { - if (resource_manager->is_connected) + if (resource_manager->is_connected) { ms_debug("Successfully connected to resource server!"); - else { + } else { ms_error("Failed to connect to resource server"); MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; @@ -119,7 +119,7 @@ static void mrp_state_callback(mrp_res_context_t *context, mrp_res_error_t err, if (err != MRP_RES_ERROR_NONE) { ms_error(" - error message received from Murphy, err(0x%x)", err); g_cond_signal(&resource_manager->cond); - MEDIA_STREAMER_RESOURCE_LOCK(resource_manager); + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); return; } @@ -131,6 +131,7 @@ static void mrp_state_callback(mrp_res_context_t *context, mrp_res_error_t err, resource_names = mrp_res_list_resource_names(rset); if (!resource_names) { ms_error(" - no resources available"); + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); return; } for (i = 0; i < resource_names->num_strings; i++) { @@ -219,6 +220,7 @@ static void mrp_resource_release_cb(mrp_res_context_t *cx, const mrp_res_resourc if (!mrp_res_equal_resource_set(rs, resource_manager->rset)) { ms_info("- resource set(%p) is not same as this resource_manager handle's(%p)", rs, resource_manager->rset); + MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); return; } @@ -234,11 +236,10 @@ static void mrp_resource_release_cb(mrp_res_context_t *cx, const mrp_res_resourc } if (resource_manager->release_cb) { - if (!resource_manager->release_cb(resource_manager, resource_manager->user_data)) { + if (!resource_manager->release_cb(resource_manager, resource_manager->user_data)) ms_error("release_cb failed"); - } else { + else ms_info("release_cb is fine"); - } } else { ms_error("release cb is NULL. Something wrong happens..."); } @@ -316,6 +317,7 @@ static int set_resource_release_cb(media_streamer_resource_manager_s *resource_m int _ms_resource_manager_init(media_streamer_resource_manager_s *resource_manager, resource_relese_cb release_cb, void *user_data) { + int ret = MEDIA_STREAMER_ERROR_NONE; MEDIA_STREAMER_CHECK_RESOURCE_MANAGER_INSTANCE(resource_manager); ms_retvm_if(release_cb == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "release_cb is NULL"); @@ -328,14 +330,16 @@ int _ms_resource_manager_init(media_streamer_resource_manager_s *resource_manage GMainContext *mrp_ctx = g_main_context_new(); if (!mrp_ctx) { ms_error("- could not create main context for resource manager"); - return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto EXIT; } GMainLoop *mrp_loop = g_main_loop_new(mrp_ctx, TRUE); g_main_context_unref(mrp_ctx); if (!mrp_loop) { ms_error("- could not create glib mainloop for resource manager"); - return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto EXIT; } resource_manager->mloop = mrp_mainloop_glib_get(mrp_loop); @@ -348,20 +352,23 @@ int _ms_resource_manager_init(media_streamer_resource_manager_s *resource_manage ms_error(" - could not get context for resource manager"); mrp_mainloop_destroy(resource_manager->mloop); resource_manager->mloop = NULL; - return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto EXIT; } resource_manager->user_data = user_data; } else { ms_error("- could not get mainloop for resource manager"); - return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto EXIT; } resource_manager->release_cb = release_cb; resource_manager->state = RESOURCE_STATE_INITIALIZED; +EXIT: MEDIA_STREAMER_RESOURCE_UNLOCK(resource_manager); - return MEDIA_STREAMER_ERROR_NONE; + return ret; } int _ms_resource_manager_prepare(media_streamer_resource_manager_s *resource_manager, media_streamer_resource_type_e resource_type) @@ -392,11 +399,10 @@ int _ms_resource_manager_prepare(media_streamer_resource_manager_s *resource_man } } - if (MEDIA_STREAMER_ERROR_NONE == ret) { + if (MEDIA_STREAMER_ERROR_NONE == ret) resource_manager->state = RESOURCE_STATE_PREPARED; - } else { + else resource_manager->state = RESOURCE_STATE_ERROR; - } return ret; } -- 2.7.4 From f0f288ba44517a92a4a27603e708ff01203d8b96 Mon Sep 17 00:00:00 2001 From: Volodymyr Brynza Date: Thu, 2 Feb 2017 13:26:20 +0200 Subject: [PATCH 10/16] fix memory leak Change-Id: I4687b9f4949ecaac16e44bdd210a5ed4d1964b6a Signed-off-by: Volodymyr Brynza --- packaging/capi-media-streamer.spec | 2 +- src/media_streamer_gst.c | 5 ++++- src/media_streamer_node.c | 13 +++++++++++++ src/media_streamer_node_resources.c | 9 +++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 89c0c35..646ff93 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.12 +Version: 0.1.13 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index c592087..3ac83fc 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -1172,6 +1172,7 @@ GstElement *__ms_video_decoder_element_create(node_plug_s *plug_info, media_stre GstElement *__ms_audio_encoder_element_create(node_plug_s *plug_info, media_streamer_node_type_e type) { GstCaps *enc_caps = plug_info->src_caps; + gchar *encoder_name = NULL; if (!enc_caps) { enc_caps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT); ms_debug("No Audio encoding format is set! Deafault will be: [%s]", MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT); @@ -1192,8 +1193,10 @@ GstElement *__ms_audio_encoder_element_create(node_plug_s *plug_info, media_stre if (!audio_encoder) audio_encoder = __ms_element_create_by_registry(&plug_info_encoder, type); - if (g_strrstr(gst_element_get_name(audio_encoder), "aac")) + encoder_name = gst_element_get_name(audio_encoder); + if (encoder_name && g_strrstr(encoder_name, "aac")) g_object_set(audio_encoder, "compliance", -2, NULL); + MS_SAFE_GFREE(encoder_name); /* Creating bin - Audio Encoder */ GstElement *audio_enc_bin = gst_bin_new("audio_encoder"); diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index ced5323..0f69deb 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -657,6 +657,7 @@ int __ms_sink_node_create(media_streamer_node_s *node) case MEDIA_STREAMER_NODE_SINK_TYPE_OVERLAY: plugin_name = __ms_ini_get_string("node type 2:overlay", DEFAULT_VIDEO_SINK); node->gst_element = __ms_element_create(plugin_name, NULL); + g_object_set(node->gst_element, "use-tbm", FALSE, NULL); break; case MEDIA_STREAMER_NODE_SINK_TYPE_FAKE: plugin_name = __ms_ini_get_string("node type 2:fake", DEFAULT_FAKE_SINK); @@ -1567,16 +1568,20 @@ gboolean _ms_node_resouces_acquire_iter(const GValue *item, GValue *ret, gpointe then apprently this element doesn't require resources */ ms_info("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); g_value_set_boolean(ret, TRUE); + g_object_unref(element); return TRUE; } if (MEDIA_STREAMER_ERROR_NONE != _ms_node_resource_aquire(node)) { ms_error("Failed to acquire resource for node [%s]", node->name); + g_object_unref(element); return FALSE; } g_value_set_boolean(ret, TRUE); + g_object_unref(element); + return TRUE; } @@ -1597,16 +1602,20 @@ gboolean _ms_node_resouces_release_iter(const GValue *item, GValue *ret, gpointe then apprently this element doesn't require resources. */ ms_debug("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); g_value_set_boolean(ret, TRUE); + g_object_unref(element); return TRUE; } if (MEDIA_STREAMER_ERROR_NONE != _ms_node_resource_release(node)) { ms_error("Failed to release resource for node [%s]", node->name); + g_object_unref(element); return FALSE; } g_value_set_boolean(ret, TRUE); + g_object_unref(element); + return TRUE; } @@ -1627,15 +1636,19 @@ gboolean _ms_node_policy_check_iter(const GValue *item, GValue *ret, gpointer us then apprently this element doesn't require resources */ ms_info("Failed to found corresonding node [%s] inside streamer", GST_ELEMENT_NAME(element)); g_value_set_boolean(ret, TRUE); + g_object_unref(element); return TRUE; } if (MEDIA_STREAMER_ERROR_NONE != _ms_node_policy_check(node)) { ms_error("Failed to check policy for node [%s]", node->name); + g_object_unref(element); return FALSE; } g_value_set_boolean(ret, TRUE); + g_object_unref(element); + return TRUE; } diff --git a/src/media_streamer_node_resources.c b/src/media_streamer_node_resources.c index 2f69001..dbf8c54 100644 --- a/src/media_streamer_node_resources.c +++ b/src/media_streamer_node_resources.c @@ -74,6 +74,12 @@ static gboolean __ms_node_resources_is_needed_by_platform(media_streamer_node_s are platform dependent */ system_info_get_platform_string("http://tizen.org/system/model_name", &model_name); system_info_get_platform_string("http://tizen.org/system/platform.processor", &platform_processor); + if (!model_name || ! platform_processor) { + ms_error("Failed to get information about platform check resources"); + MS_SAFE_FREE(model_name); + MS_SAFE_FREE(platform_processor); + return TRUE; + } ms_info("Check for resources for model_name %s, platform.processor %s", model_name, platform_processor); switch (type) { @@ -97,6 +103,9 @@ static gboolean __ms_node_resources_is_needed_by_platform(media_streamer_node_s break; } + MS_SAFE_FREE(model_name); + MS_SAFE_FREE(platform_processor); + return ret; } -- 2.7.4 From 9094f0c3465c389223ddc8f930ea296fb46e3a9a Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Thu, 16 Feb 2017 19:45:43 +0900 Subject: [PATCH 11/16] [0.1.14] fix svace issue Change-Id: I7e05d5b5cb6dab7fb21bda14b2988ef0f9b7db9d (cherry picked from commit 74dc3e6ba4dade3c52216587d31c3e984dac3f7a) --- packaging/capi-media-streamer.spec | 2 +- src/media_streamer_gst.c | 22 +++++++++++++++++----- src/media_streamer_node.c | 2 +- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index 646ff93..cab5a44 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.13 +Version: 0.1.14 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index 3ac83fc..d10c954 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -817,11 +817,22 @@ static GstElement *__ms_manifest_src_create(media_streamer_node_s *ms_node) } } g_free(protocol); - ms_retvm_if(manifest_src_name == NULL, NULL, - "Error empty manifest source name for adaprive source"); + + if (manifest_src_name == NULL) { + LOGE("Error empty manifest source name for adaptive source"); + g_free(location); + return NULL; + } + manifest_src = gst_element_factory_make(manifest_src_name, NULL); - ms_retvm_if(manifest_src == NULL, NULL, - "Error creating manifest source for adaptive source"); + g_free(manifest_src_name); + + if (manifest_src == NULL) { + LOGE("Error creating manifest source for adaptive source"); + g_free(location); + return NULL; + } + g_object_set(manifest_src, "location", location, NULL); g_free(location); @@ -843,8 +854,9 @@ int __ms_adaptive_element_prepare(media_streamer_node_s *ms_node, bool auto_plug ms_retvm_if(plugin_name == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Error empty plugin name for adaprive source"); ms_info("Creating [%s] element", plugin_name); plugin_elem = gst_element_factory_make(plugin_name, NULL); + g_free(plugin_name); ms_retvm_if(plugin_elem == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, - "Error creating element [%s] for adaptive source", plugin_name); + "Error creating element for adaptive source"); res = gst_bin_add(GST_BIN(ms_node->gst_element), plugin_elem); ms_retvm_if(res == FALSE, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 0f69deb..ddc60e5 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -343,7 +343,7 @@ static int __ms_node_check_priveleges(media_streamer_node_s *node) char smackLabel[SMACK_LABEL_LEN + 1]; char uid[10]; - cynara *cynara_h; + cynara *cynara_h = NULL; if (CYNARA_API_SUCCESS != cynara_initialize(&cynara_h, NULL)) { ms_error("Failed to initialize cynara structure\n"); -- 2.7.4 From 340e505a7c067e5c68ecc5324856e874348ea0a9 Mon Sep 17 00:00:00 2001 From: Oleksandr Popov Date: Mon, 20 Feb 2017 18:08:39 +0000 Subject: [PATCH 12/16] Added http server feature Change-Id: I286acf360eae667868d1ee17372e4930f82e719f Signed-off-by: Oleksandr Popov --- CMakeLists.txt | 4 +- include/media_streamer_http_server.h | 42 ++++++ include/media_streamer_net_util.h | 31 +++++ include/media_streamer_priv.h | 3 + include/media_streamer_util.h | 2 +- packaging/capi-media-streamer.spec | 7 +- src/media_streamer.c | 4 + src/media_streamer_gst.c | 4 +- src/media_streamer_http_server.c | 262 +++++++++++++++++++++++++++++++++++ src/media_streamer_net_util.c | 49 +++++++ src/media_streamer_node.c | 40 +++++- src/media_streamer_util.c | 4 +- test/media_streamer_test.c | 2 +- 13 files changed, 443 insertions(+), 11 deletions(-) create mode 100644 include/media_streamer_http_server.h create mode 100644 include/media_streamer_net_util.h mode change 100755 => 100644 include/media_streamer_priv.h create mode 100644 src/media_streamer_http_server.c create mode 100644 src/media_streamer_net_util.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 04a307d..2a05d39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,8 +10,8 @@ SET(PREFIX ${CMAKE_INSTALL_PREFIX}) SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) -SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib dpm") -SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib dpm") +SET(dependents "dlog glib-2.0 mm-common capi-media-tool iniparser bundle libtbm gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore elementary murphy-resource murphy-glib dpm capi-network-connection capi-content-mime-type libsoup-2.4") +SET(pc_dependents "capi-base-common capi-media-tool gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-app-1.0 gstreamer-video-1.0 cynara-client capi-system-info ecore evas elementary murphy-resource murphy-glib dpm capi-system-info capi-network-connection capi-content-mime-type libsoup-2.4") INCLUDE(FindPkgConfig) pkg_check_modules(${fw_name} REQUIRED ${dependents}) diff --git a/include/media_streamer_http_server.h b/include/media_streamer_http_server.h new file mode 100644 index 0000000..29c565c --- /dev/null +++ b/include/media_streamer_http_server.h @@ -0,0 +1,42 @@ + +/* + * Copyright (c) 2015 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. + */ + +#ifndef __MEDIA_STREAMER_HTTP_H__ +#define __MEDIA_STREAMER_HTTP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void *media_streamer_http_server_h; + +int __ms_http_server_create(media_streamer_http_server_h *server, char *ip_address, char *port); +int __ms_http_server_destroy(media_streamer_http_server_h server); + +int __ms_http_server_start(media_streamer_http_server_h server); +int __ms_http_server_stop(media_streamer_http_server_h server); + +int __ms_http_server_register_uri(media_streamer_http_server_h server, char *uri, char *file_path); +int __ms_http_server_unregister_uri(media_streamer_http_server_h server, char *uri); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEDIA_STREAMER_HTTP_H__ */ diff --git a/include/media_streamer_net_util.h b/include/media_streamer_net_util.h new file mode 100644 index 0000000..76f72e9 --- /dev/null +++ b/include/media_streamer_net_util.h @@ -0,0 +1,31 @@ + +/* + * Copyright (c) 2015 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. + */ + +#ifndef __MEDIA_STREAMER_NET_UTIL_H__ +#define __MEDIA_STREAMER_NET_UTIL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +int __ms_get_local_network_address(char **ip_address); + +#ifdef __cplusplus +} +#endif + +#endif /* __MEDIA_STREAMER_NET_UTIL_H__ */ diff --git a/include/media_streamer_priv.h b/include/media_streamer_priv.h old mode 100755 new mode 100644 index bbfd37b..9ba66a0 --- a/include/media_streamer_priv.h +++ b/include/media_streamer_priv.h @@ -29,6 +29,7 @@ extern "C" { #include #include #include +#include struct media_streamer_node_s; @@ -116,6 +117,8 @@ typedef struct { gboolean is_interrupted; media_streamer_resource_manager_s resource_manager; + + media_streamer_http_server_h http_server; } media_streamer_s; /** diff --git a/include/media_streamer_util.h b/include/media_streamer_util.h index 2b44cdf..5c85853 100644 --- a/include/media_streamer_util.h +++ b/include/media_streamer_util.h @@ -332,7 +332,7 @@ void __ms_param_value_destroy(gpointer data); * * @since_tizen 3.0 */ -int __ms_node_uri_path_check(const char *file_uri); +int __ms_util_uri_path_check(const char *file_uri); /** * @brief Iterates func over all elements contained within a bin. diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index cab5a44..d413ffb 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.14 +Version: 0.1.15 Release: 0 Group: Multimedia/API License: Apache-2.0 @@ -32,6 +32,9 @@ BuildRequires: pkgconfig(appcore-efl) BuildRequires: pkgconfig(murphy-resource) BuildRequires: pkgconfig(murphy-glib) BuildRequires: pkgconfig(dpm) +BuildRequires: pkgconfig(capi-network-connection) +BuildRequires: pkgconfig(libsoup-2.4) +BuildRequires: pkgconfig(capi-content-mime-type) %description A MediaStreamer library in Tizen Native API. @@ -51,7 +54,7 @@ cp %{SOURCE1001} . %define ini_path %{_sysconfdir}/multimedia/mmfw_media_streamer.ini %build -flags="-DMEDIA_STREAMER_INI_PATH=\\\"%{ini_path}\\\"" +flags="-DMEDIA_STREAMER_INI_PATH=\\\"%{ini_path}\\\" -D_FILE_OFFSET_BITS=64" %if 0%{?sec_build_binary_debug_enable} flags="$flags -DTIZEN_DEBUG_ENABLE" diff --git a/src/media_streamer.c b/src/media_streamer.c index a17c699..a2eb3ff 100644 --- a/src/media_streamer.c +++ b/src/media_streamer.c @@ -213,6 +213,8 @@ int media_streamer_unprepare(media_streamer_h streamer) ret = __ms_pipeline_unprepare(ms_streamer); + __ms_http_server_destroy(ms_streamer->http_server); + __ms_generate_dots(ms_streamer->pipeline, "after_unprepare"); g_mutex_unlock(&ms_streamer->mutex_lock); @@ -477,6 +479,8 @@ int media_streamer_stop(media_streamer_h streamer) else ret = __ms_state_change(ms_streamer, MEDIA_STREAMER_STATE_PAUSED); + __ms_http_server_stop(ms_streamer->http_server); + g_mutex_unlock(&ms_streamer->mutex_lock); __ms_get_state(ms_streamer); diff --git a/src/media_streamer_gst.c b/src/media_streamer_gst.c index d10c954..5171d3d 100644 --- a/src/media_streamer_gst.c +++ b/src/media_streamer_gst.c @@ -752,7 +752,7 @@ static int __ms_adaptive_sink_prepare(media_streamer_s * ms_streamer) {"Codec/Muxer", "mpegtsmux"}, /* MEDIA_STREAMER_NODE_TYPE_MUXER */ }; - GstCaps *video_enc_src_caps = gst_caps_new_empty_simple("video/mpeg"); + GstCaps *video_enc_src_caps = gst_caps_new_simple("video/mpeg", "mpegversion", G_TYPE_INT, 4, NULL); GstCaps *video_enc_sink_caps = gst_caps_new_empty_simple("video/x-raw"); node_plug_s video_enc_plug_info = {&(nodes_info[0]), video_enc_src_caps, video_enc_sink_caps, NULL}; GstElement *video_enc = __ms_node_element_create(&video_enc_plug_info, MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER); @@ -807,7 +807,7 @@ static GstElement *__ms_manifest_src_create(media_streamer_node_s *ms_node) location = gst_uri_get_location(uri); } else { ms_error("Unsupported URI protocol... Check URI is file path"); - if (__ms_node_uri_path_check(uri) == MEDIA_STREAMER_ERROR_NONE) { + if (__ms_util_uri_path_check(uri) == MEDIA_STREAMER_ERROR_NONE) { manifest_src_name = __ms_ini_get_string("node type 1:file", DEFAULT_FILE_SOURCE); location = g_strdup(uri); } else { diff --git a/src/media_streamer_http_server.c b/src/media_streamer_http_server.c new file mode 100644 index 0000000..0179559 --- /dev/null +++ b/src/media_streamer_http_server.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2015 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 +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#define HTTP_SERVER_LOG_LEVEL AD_LOG_DEBUG + +typedef struct { + SoupServer *server; /* Soup HTTP server */ + + GHashTable *uri_table; +} _ms_http_server_s; + +static int __ms_http_server_file_read_contents(const char *file_path, char **content, gsize *size); +static void __ms_http_server_connection_handle_cb(SoupServer *server, SoupMessage *msg, + const char *path, GHashTable *query, SoupClientContext *client, gpointer user_data); + +int __ms_http_server_create(media_streamer_http_server_h *server, char *ip_address, char *port) +{ + ms_retvm_if(server == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + //ms_retvm_if(ip_address == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "IP address is NULL"); + ms_retvm_if(port == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Port is NULL"); + + _ms_http_server_s *ms_server = (_ms_http_server_s *) calloc(1, sizeof(_ms_http_server_s)); + ms_retvm_if(ms_server == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error allocation memory"); + + const int iport = atoi(port); + ms_server->server = soup_server_new(SOUP_SERVER_PORT, iport, NULL); + + if (!ms_server->server) { + ms_error("Failed to create http server"); + __ms_http_server_destroy(ms_server); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + /* Create hash table for URIs */ + ms_server->uri_table = g_hash_table_new(g_str_hash, g_str_equal); + if (!ms_server->uri_table) { + ms_error("Failed to URIs hash table"); + __ms_http_server_destroy(ms_server); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + *server = ms_server; + + ms_info("http server created successfully"); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_http_server_destroy(media_streamer_http_server_h server) +{ + ms_retvm_if(server == NULL, MEDIA_STREAMER_ERROR_NONE, "Handle is NULL"); + _ms_http_server_s *hserver = (_ms_http_server_s *) server; + + /* Stop server first */ + __ms_http_server_stop(server); + + /* Destroy URIs hash table */ + g_hash_table_destroy(hserver->uri_table); + + if (hserver->server) + g_object_unref(hserver->server); + + MS_SAFE_GFREE(hserver); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_http_server_start(media_streamer_http_server_h server) +{ + ms_retvm_if(server == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + + _ms_http_server_s *hserver = (_ms_http_server_s *) server; + + soup_server_add_handler(hserver->server, NULL, + __ms_http_server_connection_handle_cb, hserver, NULL); + + soup_server_run_async(hserver->server); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_http_server_stop(media_streamer_http_server_h server) +{ + ms_retvm_if(server == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + _ms_http_server_s *hserver = (_ms_http_server_s *) server; + + soup_server_disconnect(hserver->server); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_http_server_register_uri(media_streamer_http_server_h server, char *uri, char *file_path) +{ + ms_retvm_if(server == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(uri == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "URI address is NULL"); + ms_retvm_if(file_path == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "File path is NULL"); + + _ms_http_server_s *hserver = (_ms_http_server_s *) server; + + if (!hserver->uri_table) { + ms_error("Failed to register URI. Table is NULL"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + g_hash_table_insert(hserver->uri_table, uri, file_path); + + return MEDIA_STREAMER_ERROR_NONE; +} + +int __ms_http_server_unregister_uri(media_streamer_http_server_h server, char *uri) +{ + ms_retvm_if(server == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); + ms_retvm_if(uri == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "URI address is NULL"); + + _ms_http_server_s *hserver = (_ms_http_server_s *) server; + + if (!hserver->uri_table) { + ms_error("Failed to unregister URI. Table is NULL"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + /* Return if URI is not registered */ + if (!g_hash_table_contains(hserver->uri_table, uri)) + return MEDIA_STREAMER_ERROR_NONE; + + if (!g_hash_table_remove(hserver->uri_table, uri)) { + ms_error("Failed to remove URI %s from table", uri); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + return MEDIA_STREAMER_ERROR_NONE; +} + +static const char *get_filename_ext(const char *file_path) +{ + const char *dot = strrchr(file_path, '.'); + + if (!dot || dot == file_path) return ""; + return dot + 1; +} + +static int __ms_http_server_file_read_contents(const char *file_path, char **content, gsize *size) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + struct stat stat_results = {0, }; + int file_open = 0; + + if (!file_path || !strlen(file_path)) + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + + ret = __ms_util_uri_path_check(file_path); + if (MEDIA_STREAMER_ERROR_NONE != ret) + return ret; + + file_open = open(file_path, O_RDONLY); + if (file_open < 0) { + char mes_error[256]; + strerror_r(errno, mes_error, sizeof(mes_error)); + ms_error("Couldn`t open file [%s] according to [%s]. Error N [%d]", file_path, mes_error, errno); + + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + } + + if (fstat(file_open, &stat_results) < 0) { + ms_error("Couldn`t get status of the file [%s]", file_path); + } else if (stat_results.st_size == 0) { + ms_error("The size of file is 0"); + close(file_open); + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + } else { + ms_debug("Size of file [%lld] bytes", (long long)stat_results.st_size); + } + + *content = malloc((size_t)stat_results.st_size); + if (read(file_open, *content, (size_t)stat_results.st_size) < (size_t)stat_results.st_size) + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + *size = (gsize)stat_results.st_size; + + close(file_open); + + return MEDIA_STREAMER_ERROR_NONE; +} + +static void __ms_http_server_connection_handle_cb(SoupServer *server, SoupMessage *msg, + const char *path, GHashTable *query, SoupClientContext *client, gpointer user_data) +{ + _ms_http_server_s *hserver = (_ms_http_server_s *) user_data; + + /* Close connetion if handle is NULL */ + ms_retm_if(hserver == NULL, "Handle is NULL"); + + SoupMessageHeadersIter iter; + const char *name, *value; + + ms_debug("%s %s HTTP/1.%d", msg->method, path, + soup_message_get_http_version(msg)); + soup_message_headers_iter_init(&iter, msg->request_headers); + while (soup_message_headers_iter_next(&iter, &name, &value)) + ms_debug("%s: %s", name, value); + if (msg->request_body->length) + ms_debug("%s", msg->request_body->data); + + if (msg->method == SOUP_METHOD_GET || msg->method == SOUP_METHOD_HEAD) { + ms_info("Received read event"); + + /* Extract file path with URI. First symbol is '/' */ + char *fs_dir = (char *)g_hash_table_lookup(hserver->uri_table, "adaptive_path"); + char *file_path = g_strjoin(NULL, fs_dir, path+1, NULL); + const char *extension = get_filename_ext(path+1); + char *content = NULL; + gsize size = 0; + char *mime_type = NULL; + + mime_type_get_mime_type(extension, &mime_type); + + ms_info("Recieved URI %s", path + 1); + ms_info("mime-type: %s", mime_type); + + if (MEDIA_STREAMER_ERROR_NONE != + __ms_http_server_file_read_contents(file_path, &content, &size)) { + + soup_message_set_status(msg, SOUP_STATUS_BAD_REQUEST); + } else { + ms_info("Sending response"); + soup_message_set_response(msg, mime_type, SOUP_MEMORY_TAKE, content, size); + soup_message_set_status(msg, SOUP_STATUS_OK); + } + + g_free(file_path); + g_free(mime_type); + } else { + soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED); + soup_message_set_status(msg, SOUP_STATUS_OK); + } +} diff --git a/src/media_streamer_net_util.c b/src/media_streamer_net_util.c new file mode 100644 index 0000000..71a92e0 --- /dev/null +++ b/src/media_streamer_net_util.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015 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 +#include +#include + +#include + +int __ms_get_local_network_address(char **ip_address) +{ + connection_h conn = NULL; + connection_type_e conn_type = CONNECTION_TYPE_DISCONNECTED; + + if (CONNECTION_ERROR_NONE != connection_create(&conn)) { + ms_error("Failed to create connection"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if (CONNECTION_ERROR_NONE != connection_get_type(conn, &conn_type)) { + ms_error("Failed to acquire connection type"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if (conn_type != CONNECTION_TYPE_WIFI) { + ms_error("Wrong connection type"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + if (CONNECTION_ERROR_NONE != connection_get_ip_address(conn, CONNECTION_ADDRESS_FAMILY_IPV4, ip_address)) { + ms_error("Failed to acquire connection ip address"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + + return MEDIA_STREAMER_ERROR_NONE; +} diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index ddc60e5..5bd70c1 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #define SMACK_LABEL_LEN 255 #define DEFAULT_URI_SCHEME_LENGTH 10 +#define DEFAULT_HTTP_PORT "8888" param_s param_table[] = { {MEDIA_STREAMER_PARAM_CAMERA_ID, "camera-id"}, @@ -855,6 +857,38 @@ static gboolean demux_find(gpointer key, gpointer value, gpointer user_data) return g_strrstr((char *)key, "demux") != NULL; } +static int __ms_adaptive_sink_http_server_prepare(media_streamer_s * ms_streamer, media_streamer_node_s *node) +{ + int err_code = MEDIA_STREAMER_ERROR_NONE; + char *playlist_location = NULL; + char *playlist_dir = NULL; + char *split = NULL; + + /* Create and start http server */ + err_code = __ms_http_server_create(&ms_streamer->http_server, NULL, DEFAULT_HTTP_PORT); + if (MEDIA_STREAMER_ERROR_NONE != err_code) { + ms_error("Failed to create http server during prepare"); + } else { + ms_info("Starting http server"); + /* FIXME: find out how to set default port */ + err_code = __ms_http_server_start(ms_streamer->http_server); + if (MEDIA_STREAMER_ERROR_NONE != err_code) { + ms_error("Failed to start http server during prepare. Destroying http server"); + __ms_http_server_destroy(ms_streamer->http_server); + } + } + + g_object_get(node->gst_element, MEDIA_STREAMER_PARAM_PLAYLIST_LOCATION, &playlist_location, NULL); + split = strrchr(playlist_location, '/'); + playlist_dir = g_strndup(playlist_location, split - playlist_location + 1); + + __ms_http_server_register_uri(ms_streamer->http_server, "adaptive_path", playlist_dir); + + MS_SAFE_GFREE(playlist_location); + + return err_code; +} + int __ms_pipeline_prepare(media_streamer_s *ms_streamer) { ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL"); @@ -863,6 +897,7 @@ int __ms_pipeline_prepare(media_streamer_s *ms_streamer) media_streamer_node_s *rtp_node = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "rtp_container"); media_streamer_node_s *demux = (media_streamer_node_s *)g_hash_table_find(ms_streamer->nodes_table, (GHRFunc)demux_find, NULL); media_streamer_node_s *adaptive_src = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "adaptive_src"); + media_streamer_node_s *adaptive_sink = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "adaptive_sink"); if (rtp_node) { ret = __ms_rtp_element_prepare(rtp_node) ? MEDIA_STREAMER_ERROR_NONE : MEDIA_STREAMER_ERROR_INVALID_PARAMETER; } else if (demux) { @@ -889,6 +924,9 @@ int __ms_pipeline_prepare(media_streamer_s *ms_streamer) ret = __ms_adaptive_element_prepare(adaptive_src, false); } + if (adaptive_sink) + __ms_adaptive_sink_http_server_prepare(ms_streamer, adaptive_sink); + if (ret != MEDIA_STREAMER_ERROR_NONE) goto prepare_fail; @@ -1477,7 +1515,7 @@ int __ms_node_set_param_value(media_streamer_node_s *ms_node, param_s *param, co else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_IS_LIVE_STREAM)) g_object_set(ms_node->gst_element, param->origin_name, !g_ascii_strcasecmp(param_value, "true"), NULL); else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_URI)) { - ret = __ms_node_uri_path_check(param_value); + ret = __ms_util_uri_path_check(param_value); if (ret == MEDIA_STREAMER_ERROR_NONE) g_object_set(ms_node->gst_element, param->origin_name, param_value, NULL); } else if (!g_strcmp0(param->param_name, MEDIA_STREAMER_PARAM_USER_AGENT)) diff --git a/src/media_streamer_util.c b/src/media_streamer_util.c index 4ea599f..7f55672 100644 --- a/src/media_streamer_util.c +++ b/src/media_streamer_util.c @@ -296,7 +296,7 @@ void __ms_param_value_destroy(gpointer data) MS_SAFE_GFREE(val); } -int __ms_node_uri_path_check(const char *file_uri) +int __ms_util_uri_path_check(const char *file_uri) { struct stat stat_results = {0, }; int file_open = 0; @@ -308,7 +308,7 @@ int __ms_node_uri_path_check(const char *file_uri) if (file_open < 0) { char mes_error[256]; strerror_r(errno, mes_error, sizeof(mes_error)); - ms_error("Couldn`t open file according to [%s]. Error N [%d]", mes_error, errno); + ms_error("Couldn`t open file [%s] according to [%s]. Error N [%d]", file_uri, mes_error, errno); if (EACCES == errno) return MEDIA_STREAMER_ERROR_PERMISSION_DENIED; diff --git a/test/media_streamer_test.c b/test/media_streamer_test.c index 3c8d834..11eafcc 100644 --- a/test/media_streamer_test.c +++ b/test/media_streamer_test.c @@ -1557,7 +1557,7 @@ void _interpret_getting_uri_menu(char *cmd) return; } - g_print("_interpret_getting_uri_menu %d %d %d\n", g_menu_state, g_sub_menu_state, g_scenario_mode); + g_print("_interpret_getting_uri_menu %d %d %d", g_menu_state, g_sub_menu_state, g_scenario_mode); if (g_menu_state == MENU_STATE_PLAYING_MENU) { if (g_scenario_mode == SCENARIO_MODE_FILE_SUBTITLE_VIDEO_AUDIO) { g_sub_menu_state = SUBMENU_STATE_GETTING_SUBFILE_URI; -- 2.7.4 From 7fcbd1e606a124ae6ee1c24e4f88a52b5bc1bb49 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Wed, 22 Mar 2017 19:21:06 +0900 Subject: [PATCH 13/16] [0.1.15] Use %license macro to copy license Change-Id: I292746121fab2da101ba4a2f9c226565c368ecc7 --- packaging/capi-media-streamer.spec | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index d413ffb..e30cddc 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -71,10 +71,8 @@ make %{?jobs:-j%jobs} %install rm -rf %{buildroot} -mkdir -p %{buildroot}%{_datadir}/license -mkdir -p %{buildroot}/usr/bin -cp LICENSE.APLv2 %{buildroot}%{_datadir}/license/%{name} -cp test/media_streamer_test %{buildroot}/usr/bin +mkdir -p %{buildroot}%{_bindir} +cp test/media_streamer_test %{buildroot}%{_bindir} mkdir -p %{buildroot}/usr/etc @@ -90,7 +88,7 @@ mkdir -p %{buildroot}/usr/etc %manifest %{name}.manifest %license LICENSE.APLv2 %{_libdir}/lib%{name}.so.* -%{_datadir}/license/%{name} +%license LICENSE.APLv2 %{_bindir}/* %files devel -- 2.7.4 From a8fe84c312f9607a87ec2fb38593465b2d38d2e4 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Wed, 5 Apr 2017 16:41:03 +0900 Subject: [PATCH 14/16] doc: update featuring doc path Change-Id: Icb0a69d20fe0f71b9dc8dc9b8da62d889b48a1e1 (cherry picked from commit 5431cd6d88366f21e0b44c8748f4edf923bc5930) --- doc/mediastreamer_doc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mediastreamer_doc.h b/doc/mediastreamer_doc.h index 117e05b..289d684 100755 --- a/doc/mediastreamer_doc.h +++ b/doc/mediastreamer_doc.h @@ -53,7 +53,7 @@ * It is recommended to design feature related codes in your application for reliability.\n * You can check if a device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n - * More details on featuring your application can be found from Feature Element. + * More details on featuring your application can be found from Feature List. * */ -- 2.7.4 From 56c3360271da3de3478d3968b4aca3112c75e847 Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Mon, 17 Apr 2017 16:46:40 +0900 Subject: [PATCH 15/16] [0.1.16] fix svace issue Change-Id: I71289af8dae084733fd99b98429adc75da1bc211 --- LICENSE.APLv2 => LICENSE.Apache-2.0 | 0 packaging/capi-media-streamer.spec | 5 ++--- src/media_streamer_http_server.c | 4 +++- src/media_streamer_node.c | 27 +++++++++++++++++++-------- 4 files changed, 24 insertions(+), 12 deletions(-) rename LICENSE.APLv2 => LICENSE.Apache-2.0 (100%) mode change 100755 => 100644 diff --git a/LICENSE.APLv2 b/LICENSE.Apache-2.0 old mode 100755 new mode 100644 similarity index 100% rename from LICENSE.APLv2 rename to LICENSE.Apache-2.0 diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index e30cddc..9e8832c 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.15 +Version: 0.1.16 Release: 0 Group: Multimedia/API License: Apache-2.0 @@ -86,9 +86,8 @@ mkdir -p %{buildroot}/usr/etc %files %manifest %{name}.manifest -%license LICENSE.APLv2 +%license LICENSE.Apache-2.0 %{_libdir}/lib%{name}.so.* -%license LICENSE.APLv2 %{_bindir}/* %files devel diff --git a/src/media_streamer_http_server.c b/src/media_streamer_http_server.c index 0179559..5d35bc2 100644 --- a/src/media_streamer_http_server.c +++ b/src/media_streamer_http_server.c @@ -199,8 +199,10 @@ static int __ms_http_server_file_read_contents(const char *file_path, char **con } *content = malloc((size_t)stat_results.st_size); - if (read(file_open, *content, (size_t)stat_results.st_size) < (size_t)stat_results.st_size) + if (read(file_open, *content, (size_t)stat_results.st_size) < (size_t)stat_results.st_size) { + close(file_open); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } *size = (gsize)stat_results.st_size; close(file_open); diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 5bd70c1..33afa5b 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -868,17 +868,26 @@ static int __ms_adaptive_sink_http_server_prepare(media_streamer_s * ms_streamer err_code = __ms_http_server_create(&ms_streamer->http_server, NULL, DEFAULT_HTTP_PORT); if (MEDIA_STREAMER_ERROR_NONE != err_code) { ms_error("Failed to create http server during prepare"); - } else { - ms_info("Starting http server"); - /* FIXME: find out how to set default port */ - err_code = __ms_http_server_start(ms_streamer->http_server); - if (MEDIA_STREAMER_ERROR_NONE != err_code) { - ms_error("Failed to start http server during prepare. Destroying http server"); - __ms_http_server_destroy(ms_streamer->http_server); - } + goto _DONE; + } + + ms_info("Starting http server"); + /* FIXME: find out how to set default port */ + err_code = __ms_http_server_start(ms_streamer->http_server); + if (MEDIA_STREAMER_ERROR_NONE != err_code) { + ms_error("Failed to start http server during prepare. Destroying http server"); + __ms_http_server_destroy(ms_streamer->http_server); + goto _DONE; } g_object_get(node->gst_element, MEDIA_STREAMER_PARAM_PLAYLIST_LOCATION, &playlist_location, NULL); + if (!playlist_location) { + err_code = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + ms_error("Failed to get playlist location"); + __ms_http_server_destroy(ms_streamer->http_server); + goto _DONE; + } + split = strrchr(playlist_location, '/'); playlist_dir = g_strndup(playlist_location, split - playlist_location + 1); @@ -886,6 +895,8 @@ static int __ms_adaptive_sink_http_server_prepare(media_streamer_s * ms_streamer MS_SAFE_GFREE(playlist_location); +_DONE: + return err_code; } -- 2.7.4 From c41e5f861f18cd4c844e7a73fef331764b70649b Mon Sep 17 00:00:00 2001 From: Eunhae Choi Date: Mon, 22 May 2017 20:01:53 +0900 Subject: [PATCH 16/16] [0.1.16] modify doc Change-Id: I53bd6ea1e8714432ff1f721444a3b31a8d4231ef --- doc/mediastreamer_doc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/mediastreamer_doc.h b/doc/mediastreamer_doc.h index 289d684..e97184c 100755 --- a/doc/mediastreamer_doc.h +++ b/doc/mediastreamer_doc.h @@ -53,7 +53,7 @@ * It is recommended to design feature related codes in your application for reliability.\n * You can check if a device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n - * More details on featuring your application can be found from Feature List. + * More details on featuring your application can be found from Feature Element. * */ -- 2.7.4