From: Oleksandr Popov Date: Mon, 5 Dec 2016 16:35:48 +0000 (+0200) Subject: Added implementation of interruption by resource manager X-Git-Tag: submit/tizen/20161213.083228~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F05%2F102405%2F2;p=platform%2Fcore%2Fapi%2Fmediastreamer.git Added implementation of interruption by resource manager Signed-off-by: Oleksandr Popov Change-Id: I213f1aa51bf6e051baf0a435f268c2798124d558 --- 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;