Initial Release 17/312617/6
authorYoungHun Kim <yh8004.kim@samsung.com>
Wed, 12 Jun 2024 10:07:51 +0000 (19:07 +0900)
committerYoungHun Kim <yh8004.kim@samsung.com>
Sun, 28 Jul 2024 23:48:03 +0000 (08:48 +0900)
Change-Id: I984f34cbfad39ab8426766db25740785cc3948c5

29 files changed:
CMakeLists.txt [new file with mode: 0644]
LICENSE.APLv2 [new file with mode: 0644]
include/resource_center.h [new file with mode: 0644]
include/resource_center_internal.h [new file with mode: 0644]
include_internal/resource_center_private.h [new file with mode: 0644]
packaging/resource-center-api.spec [new file with mode: 0644]
resource-center-api.manifest [new file with mode: 0644]
resource-center-api.pc.in [new file with mode: 0644]
resource-center_tomato.manifest [new file with mode: 0644]
src/resource_center.cpp [new file with mode: 0644]
src/resource_center_internal.cpp [new file with mode: 0644]
src/resource_center_private.cpp [new file with mode: 0644]
test/CMakeLists.txt [new file with mode: 0644]
test/resource_center_test.cpp [new file with mode: 0644]
ut/CMakeLists.txt [new file with mode: 0644]
ut/inc/TCApp.h [new file with mode: 0644]
ut/inc/TCPlayer.h [new file with mode: 0644]
ut/inc/TCResource.h [new file with mode: 0644]
ut/inc/tomatoGtest.h [new file with mode: 0644]
ut/inc/ut_log.h [new file with mode: 0644]
ut/inc/ut_util.h [new file with mode: 0644]
ut/src/testcase/TCApp.cpp [new file with mode: 0644]
ut/src/testcase/TCPlayer.cpp [new file with mode: 0644]
ut/src/testcase/TCResource.cpp [new file with mode: 0644]
ut/src/testcase/ut_api.cpp [new file with mode: 0644]
ut/src/testcase/ut_main.cpp [new file with mode: 0644]
ut/src/testcase/ut_util.cpp [new file with mode: 0644]
ut/tc/TCList.dat [new file with mode: 0644]
ut/tc/resource-center.xml [new file with mode: 0644]

diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..ea0f807
--- /dev/null
@@ -0,0 +1,110 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+# project
+SET(prefix "/usr")
+SET(version "0.0.1")
+SET(submodule "resource-center-api")
+
+# for package file
+SET(dependents dlog gio-2.0 glib-2.0 resource-manager resource-information)
+
+SET(fw_name "${submodule}")
+
+PROJECT(${fw_name})
+
+SET(CMAKE_INSTALL_PREFIX ${prefix})
+SET(PREFIX ${CMAKE_INSTALL_PREFIX})
+SET(VERSION ${version})
+
+SET(INC_DIR include)
+SET(INTERNAL_INT_DIR include_internal)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(${fw_name} REQUIRED ${dependents})
+FOREACH(flag ${${fw_name}_CXXFLAGS})
+    SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+INCLUDE_DIRECTORIES(${INC_DIR})
+INCLUDE_DIRECTORIES(${INTERNAL_INT_DIR})
+INCLUDE_DIRECTORIES(${${fw_name}_INCLUDE_DIRS})
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -fPIC -Wall -Werror")
+SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
+
+IF("${ARCH}" STREQUAL "arm")
+    ADD_DEFINITIONS("-DTARGET")
+ENDIF("${ARCH}" STREQUAL "arm")
+
+ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+ADD_DEFINITIONS("-DTIZEN_DEBUG")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/${LIB_DIR}")
+
+aux_source_directory(src SOURCES)
+ADD_LIBRARY(${fw_name} SHARED ${SOURCES})
+
+TARGET_LINK_LIBRARIES(${fw_name} ${${fw_name}_LDFLAGS})
+
+SET_TARGET_PROPERTIES(${fw_name}
+     PROPERTIES
+     VERSION ${FULLVER}
+     SOVERSION ${MAJORVER}
+     CLEAN_DIRECT_OUTPUT 1
+)
+
+INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_DIR})
+INSTALL(
+        DIRECTORY ${INC_DIR}/ DESTINATION include
+        FILES_MATCHING
+        PATTERN "*_private.h" EXCLUDE
+        PATTERN "${INC_DIR}/*.h"
+        PATTERN "${INTERNAL_INT_DIR}/*.h"
+        )
+
+SET(PC_NAME ${fw_name})
+SET(PC_LDFLAGS -l${fw_name})
+
+CONFIGURE_FILE(
+    ${fw_name}.pc.in
+    ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc
+    @ONLY
+)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${fw_name}.pc DESTINATION ${LIB_DIR}/pkgconfig)
+
+ADD_SUBDIRECTORY(test)
+
+IF(TOMATO STREQUAL "y")
+    ADD_SUBDIRECTORY(ut)
+ENDIF(TOMATO STREQUAL "y")
+
+IF(UNIX)
+
+ADD_CUSTOM_TARGET (distclean @echo cleaning for source distribution)
+ADD_CUSTOM_COMMAND(
+        DEPENDS clean
+        COMMENT "distribution clean"
+        COMMAND find
+        ARGS    .
+        -not -name config.cmake -and \(
+        -name tester.c -or
+        -name Testing -or
+        -name CMakeFiles -or
+        -name cmake.depends -or
+        -name cmake.check_depends -or
+        -name CMakeCache.txt -or
+        -name cmake.check_cache -or
+        -name *.cmake -or
+        -name Makefile -or
+        -name core -or
+        -name core.* -or
+        -name gmon.out -or
+        -name install_manifest.txt -or
+        -name *.pc -or
+        -name *~ \)
+        | grep -v TC | xargs rm -rf
+        TARGET  distclean
+        VERBATIM
+)
+
+ENDIF(UNIX)
diff --git a/LICENSE.APLv2 b/LICENSE.APLv2
new file mode 100644 (file)
index 0000000..bbe9d02
--- /dev/null
@@ -0,0 +1,206 @@
+Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.\r
+\r
+                                 Apache License\r
+                           Version 2.0, January 2004\r
+                        http://www.apache.org/licenses/\r
+\r
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\r
+\r
+   1. Definitions.\r
+\r
+      "License" shall mean the terms and conditions for use, reproduction,\r
+      and distribution as defined by Sections 1 through 9 of this document.\r
+\r
+      "Licensor" shall mean the copyright owner or entity authorized by\r
+      the copyright owner that is granting the License.\r
+\r
+      "Legal Entity" shall mean the union of the acting entity and all\r
+      other entities that control, are controlled by, or are under common\r
+      control with that entity. For the purposes of this definition,\r
+      "control" means (i) the power, direct or indirect, to cause the\r
+      direction or management of such entity, whether by contract or\r
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the\r
+      outstanding shares, or (iii) beneficial ownership of such entity.\r
+\r
+      "You" (or "Your") shall mean an individual or Legal Entity\r
+      exercising permissions granted by this License.\r
+\r
+      "Source" form shall mean the preferred form for making modifications,\r
+      including but not limited to software source code, documentation\r
+      source, and configuration files.\r
+\r
+      "Object" form shall mean any form resulting from mechanical\r
+      transformation or translation of a Source form, including but\r
+      not limited to compiled object code, generated documentation,\r
+      and conversions to other media types.\r
+\r
+      "Work" shall mean the work of authorship, whether in Source or\r
+      Object form, made available under the License, as indicated by a\r
+      copyright notice that is included in or attached to the work\r
+      (an example is provided in the Appendix below).\r
+\r
+      "Derivative Works" shall mean any work, whether in Source or Object\r
+      form, that is based on (or derived from) the Work and for which the\r
+      editorial revisions, annotations, elaborations, or other modifications\r
+      represent, as a whole, an original work of authorship. For the purposes\r
+      of this License, Derivative Works shall not include works that remain\r
+      separable from, or merely link (or bind by name) to the interfaces of,\r
+      the Work and Derivative Works thereof.\r
+\r
+      "Contribution" shall mean any work of authorship, including\r
+      the original version of the Work and any modifications or additions\r
+      to that Work or Derivative Works thereof, that is intentionally\r
+      submitted to Licensor for inclusion in the Work by the copyright owner\r
+      or by an individual or Legal Entity authorized to submit on behalf of\r
+      the copyright owner. For the purposes of this definition, "submitted"\r
+      means any form of electronic, verbal, or written communication sent\r
+      to the Licensor or its representatives, including but not limited to\r
+      communication on electronic mailing lists, source code control systems,\r
+      and issue tracking systems that are managed by, or on behalf of, the\r
+      Licensor for the purpose of discussing and improving the Work, but\r
+      excluding communication that is conspicuously marked or otherwise\r
+      designated in writing by the copyright owner as "Not a Contribution."\r
+\r
+      "Contributor" shall mean Licensor and any individual or Legal Entity\r
+      on behalf of whom a Contribution has been received by Licensor and\r
+      subsequently incorporated within the Work.\r
+\r
+   2. Grant of Copyright License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      copyright license to reproduce, prepare Derivative Works of,\r
+      publicly display, publicly perform, sublicense, and distribute the\r
+      Work and such Derivative Works in Source or Object form.\r
+\r
+   3. Grant of Patent License. Subject to the terms and conditions of\r
+      this License, each Contributor hereby grants to You a perpetual,\r
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\r
+      (except as stated in this section) patent license to make, have made,\r
+      use, offer to sell, sell, import, and otherwise transfer the Work,\r
+      where such license applies only to those patent claims licensable\r
+      by such Contributor that are necessarily infringed by their\r
+      Contribution(s) alone or by combination of their Contribution(s)\r
+      with the Work to which such Contribution(s) was submitted. If You\r
+      institute patent litigation against any entity (including a\r
+      cross-claim or counterclaim in a lawsuit) alleging that the Work\r
+      or a Contribution incorporated within the Work constitutes direct\r
+      or contributory patent infringement, then any patent licenses\r
+      granted to You under this License for that Work shall terminate\r
+      as of the date such litigation is filed.\r
+\r
+   4. Redistribution. You may reproduce and distribute copies of the\r
+      Work or Derivative Works thereof in any medium, with or without\r
+      modifications, and in Source or Object form, provided that You\r
+      meet the following conditions:\r
+\r
+      (a) You must give any other recipients of the Work or\r
+          Derivative Works a copy of this License; and\r
+\r
+      (b) You must cause any modified files to carry prominent notices\r
+          stating that You changed the files; and\r
+\r
+      (c) You must retain, in the Source form of any Derivative Works\r
+          that You distribute, all copyright, patent, trademark, and\r
+          attribution notices from the Source form of the Work,\r
+          excluding those notices that do not pertain to any part of\r
+          the Derivative Works; and\r
+\r
+      (d) If the Work includes a "NOTICE" text file as part of its\r
+          distribution, then any Derivative Works that You distribute must\r
+          include a readable copy of the attribution notices contained\r
+          within such NOTICE file, excluding those notices that do not\r
+          pertain to any part of the Derivative Works, in at least one\r
+          of the following places: within a NOTICE text file distributed\r
+          as part of the Derivative Works; within the Source form or\r
+          documentation, if provided along with the Derivative Works; or,\r
+          within a display generated by the Derivative Works, if and\r
+          wherever such third-party notices normally appear. The contents\r
+          of the NOTICE file are for informational purposes only and\r
+          do not modify the License. You may add Your own attribution\r
+          notices within Derivative Works that You distribute, alongside\r
+          or as an addendum to the NOTICE text from the Work, provided\r
+          that such additional attribution notices cannot be construed\r
+          as modifying the License.\r
+\r
+      You may add Your own copyright statement to Your modifications and\r
+      may provide additional or different license terms and conditions\r
+      for use, reproduction, or distribution of Your modifications, or\r
+      for any such Derivative Works as a whole, provided Your use,\r
+      reproduction, and distribution of the Work otherwise complies with\r
+      the conditions stated in this License.\r
+\r
+   5. Submission of Contributions. Unless You explicitly state otherwise,\r
+      any Contribution intentionally submitted for inclusion in the Work\r
+      by You to the Licensor shall be under the terms and conditions of\r
+      this License, without any additional terms or conditions.\r
+      Notwithstanding the above, nothing herein shall supersede or modify\r
+      the terms of any separate license agreement you may have executed\r
+      with Licensor regarding such Contributions.\r
+\r
+   6. Trademarks. This License does not grant permission to use the trade\r
+      names, trademarks, service marks, or product names of the Licensor,\r
+      except as required for reasonable and customary use in describing the\r
+      origin of the Work and reproducing the content of the NOTICE file.\r
+\r
+   7. Disclaimer of Warranty. Unless required by applicable law or\r
+      agreed to in writing, Licensor provides the Work (and each\r
+      Contributor provides its Contributions) on an "AS IS" BASIS,\r
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\r
+      implied, including, without limitation, any warranties or conditions\r
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\r
+      PARTICULAR PURPOSE. You are solely responsible for determining the\r
+      appropriateness of using or redistributing the Work and assume any\r
+      risks associated with Your exercise of permissions under this License.\r
+\r
+   8. Limitation of Liability. In no event and under no legal theory,\r
+      whether in tort (including negligence), contract, or otherwise,\r
+      unless required by applicable law (such as deliberate and grossly\r
+      negligent acts) or agreed to in writing, shall any Contributor be\r
+      liable to You for damages, including any direct, indirect, special,\r
+      incidental, or consequential damages of any character arising as a\r
+      result of this License or out of the use or inability to use the\r
+      Work (including but not limited to damages for loss of goodwill,\r
+      work stoppage, computer failure or malfunction, or any and all\r
+      other commercial damages or losses), even if such Contributor\r
+      has been advised of the possibility of such damages.\r
+\r
+   9. Accepting Warranty or Additional Liability. While redistributing\r
+      the Work or Derivative Works thereof, You may choose to offer,\r
+      and charge a fee for, acceptance of support, warranty, indemnity,\r
+      or other liability obligations and/or rights consistent with this\r
+      License. However, in accepting such obligations, You may act only\r
+      on Your own behalf and on Your sole responsibility, not on behalf\r
+      of any other Contributor, and only if You agree to indemnify,\r
+      defend, and hold each Contributor harmless for any liability\r
+      incurred by, or claims asserted against, such Contributor by reason\r
+      of your accepting any such warranty or additional liability.\r
+\r
+   END OF TERMS AND CONDITIONS\r
+\r
+   APPENDIX: How to apply the Apache License to your work.\r
+\r
+      To apply the Apache License to your work, attach the following\r
+      boilerplate notice, with the fields enclosed by brackets "[]"\r
+      replaced with your own identifying information. (Don't include\r
+      the brackets!)  The text should be enclosed in the appropriate\r
+      comment syntax for the file format. We also recommend that a\r
+      file or class name and description of purpose be included on the\r
+      same "printed page" as the copyright notice for easier\r
+      identification within third-party archives.\r
+\r
+   Copyright [yyyy] [name of copyright owner]\r
+\r
+   Licensed under the Apache License, Version 2.0 (the "License");\r
+   you may not use this file except in compliance with the License.\r
+   You may obtain a copy of the License at\r
+\r
+       http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing, software\r
+   distributed under the License is distributed on an "AS IS" BASIS,\r
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+   See the License for the specific language governing permissions and\r
+   limitations under the License.\r
+\r
+\r
+\r
diff --git a/include/resource_center.h b/include/resource_center.h
new file mode 100644 (file)
index 0000000..b4ed154
--- /dev/null
@@ -0,0 +1,709 @@
+/*
+ * Copyright (c) 2024 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 __TIZEN_RESOURCE_CENTER_H__
+#define __TIZEN_RESOURCE_CENTER_H__
+
+#include <glib.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+* @brief resource policy
+*/
+typedef enum{
+       RC_RSC_POLICY_NORMAL = 0,   /**< normal policy */
+       RC_RSC_POLICY_N_DECODING_MV,/**< N decoding policy in multiview */
+} rc_rsc_policy_e;
+
+/**
+* @brief video resolution
+*/
+typedef enum {
+       RC_RESOLUTION_FHD = 0, /**< Full HD, up to (1920 * 1088) */
+       RC_RESOLUTION_UHD, /**< UHD, up to (4096 * 2160) */
+       RC_RESOLUTION_8K /**< 8K, up to (7680 * 4320) */
+} rc_resolution_e;
+
+/**
+* @brief video framerate
+*/
+typedef enum {
+       RC_FRAMERATE_30P = 0, /**< 30 fps */
+       RC_FRAMERATE_60P, /**< 60 fps */
+       RC_FRAMERATE_120P /**< 120 fps */
+} rc_framerate_e;
+
+/**
+* @brief player's audio out
+*/
+typedef enum {
+       RC_PLAYER_AUDIO_OUT_NONE = 0, /**< audio out none */
+       RC_PLAYER_AUDIO_OUT_MAIN,     /**< audio out main */
+       RC_PLAYER_AUDIO_OUT_SUB       /**< audio out sub */
+} rc_player_audio_out_e;
+
+/**
+* @brief layout state
+*/
+typedef enum {
+       RC_LAYOUT_STATE_CHANGE_START = 0, /**< layout change start */
+       RC_LAYOUT_STATE_CHANGE_DONE       /**< layout change done */
+} rc_layout_state_e;
+
+/**
+ * @brief Called when resource center request audio control.
+ * @param[in] player_id target player's id
+ * @param[in] data The user data passed from the callback registration function
+ * @see rc_register_player_audio_stop_request_callback()
+ * @see rc_register_player_audio_start_request_callback()
+ */
+typedef void (*rc_player_audio_request_cb)(int player_id, void* data);
+
+/**
+ * @brief Called when audio focus is changed.
+ * @param[in] zone_id id of focused zone
+ * @param[in] data The user data passed from the callback registration function
+ * @see rc_register_audio_focus_changed_callback()
+ * @see rc_unregister_audio_focus_changed_callback()
+ */
+typedef void (*rc_audio_focus_changed_cb)(int zone_id, void* data);
+
+
+/**
+ * @brief Called when best quality zone is switched.
+ * @param[in] prev_zone_id previous zone id had best quality
+ * @param[in] cur_zone_id current zone id having best quality
+ * @param[in] result switching result (0 on success, otherwise negative value)
+ * @param[in] data The user data passed from the callback registration function
+ * @see rc_register_best_quality_zone_switched_callback()
+ * @see rc_unregister_best_quality_zone_switched_callback()
+ */
+typedef void (*rc_best_quality_zone_switched_cb)(int prev_zone_id, int cur_zone_id, int result, void* data);
+
+struct rc_zone;
+
+/**
+ * @brief zone list handle.
+ */
+typedef void* rc_zone_list_h;
+
+/**
+ * @brief zone handle.
+ */
+typedef struct rc_zone* rc_zone_h;
+
+/**
+ * @brief Set resource policy.
+ * @param[in] policy resource policy to set.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_set_resource_policy(rc_rsc_policy_e policy);
+
+/**
+ * @brief Get a capable resource category which is dedicated to the application
+ * @param[in] handle player handle which is returned by rm_register()
+ * @param[in] app_id application id
+ * @param[in] category resource category id
+ * @return @c positive value which represents resource category on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ * @remark
+ *       This function returns a resource category id which is dedicated to the application based on current resource policy.
+ *       app_id shall be a valid application id. If not, RI_CATEGORY_NOT_PERMITTED will be returned
+ */
+int rc_get_capable_category_id(int handle, const char* app_id, int category);
+
+/**
+ * @brief Set audio focus.
+ * @param[in] zone_id id of focused zone to set.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_set_audio_focus(int zone_id);
+
+/**
+ * @brief Get audio focus.
+ * @param[out] zone_id id of focused zone.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_get_audio_focus(int* zone_id);
+
+/**
+ * @brief Get last audio focus.
+ * @remarks This API is working only after exit multiview.
+ * @param[out] zone_id id of last focused zone.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_get_last_audio_focus(int* zone_id);
+
+/**
+ * @brief Register changed callback for audio focus.
+ * @param[in] callback Callback function to be called when audio focus is changed.
+ * @param[in] data The user data passed from the callback
+ * @return Callback handle value if function finished succesful, 0 if failed.
+ * @pre None
+ * @post None
+ * @exception None
+ */
+unsigned int rc_register_audio_focus_changed_callback(rc_audio_focus_changed_cb callback, void* data);
+
+/**
+ * @brief Unregister changed callback for audio focus.
+ * @param[in] id Id of handler received from rc_register_audio_focus_changed_callback() function.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ * @return None
+ */
+int rc_unregister_audio_focus_changed_callback(const unsigned int id);
+
+/**
+ * @brief Get max video resolution the application can use in current resource policy
+ * @param[in] app_id application id
+ * @param[out] width max width (in pixel)
+ * @param[out] height max height (in pixel)
+ * @param[out] framerate max framerate (in fps)
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_get_max_video_resolution(const char* app_id, int *width, int *height, int *framerate);
+
+/**
+ * @brief Called when max video resolution to the application is changed
+ * @param[in] app_id The application id
+ * @param[in] width max width (in pixel)
+ * @param[in] height max height (in pixel)
+ * @param[in] framerate max framerate (in pixel)
+ * @param[in] data user data
+ * @pre None
+ * @post None
+ * @remarks
+ */
+typedef void (*max_resolution_change_cb)(const char* app_id, int width, int height, int framerate, void *data);
+
+/**
+ * @brief Register a callback to receive max video resolution change event
+ * @details Once max video resolution to the application is changed, the registered callback will be invoked.
+ * @param[in] app_id the application id id to observe
+ * @param[in] cb The callback function to register
+ * @param[in] data The user data to be passed to the callback function
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_register_max_video_resolution_changed_callback(const char* app_id, max_resolution_change_cb cb, void* data);
+
+/**
+ * @brief Unregister a callback which had been added to observe max video resolution change event
+ * @param[in] app_id the application id to stop to observe
+ * @param[in] cb The callback function to unregister
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_unregister_max_video_resolution_changed_callback(const char* app_id, max_resolution_change_cb cb);
+
+/**
+ * @brief Register changed callback for resource center's request.
+ * @param[in] callback Callback function to be called when resource center request audio stop.
+ * @param[in] data The user data passed from the callback
+ * @return Callback handle value if function finished succesful, 0 if failed.
+ * @pre None
+ * @post None
+ * @exception None
+ */
+unsigned int rc_register_player_audio_stop_request_callback(rc_player_audio_request_cb callback, void* data);
+
+/**
+ * @brief Register changed callback for resource center's request.
+ * @param[in] callback Callback function to be called when resource center request audio start.
+ * @param[in] data The user data passed from the callback
+ * @return Callback handle value if function finished succesful, 0 if failed.
+ * @pre None
+ * @post None
+ * @exception None
+ */
+unsigned int rc_register_player_audio_start_request_callback(rc_player_audio_request_cb callback, void* data);
+
+/**
+ * @brief Register changed callback for resource center's request.
+ * @param[in] callback Callback function to be called when resource center request audio resync.
+ * @param[in] data The user data passed from the callback
+ * @return Callback handle value if function finished succesful, 0 if failed.
+ * @pre None
+ * @post None
+ * @exception None
+ */
+unsigned int rc_register_player_audio_resync_request_callback(rc_player_audio_request_cb callback, void* data);
+
+/**
+ * @brief Unregister changed callback for resource center's request.
+ * @param[in] id Id of handler received from rc_register_player_audio_stop_request_callback() function.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ * @return None
+ */
+int rc_unregister_player_audio_stop_request_callback(const unsigned int id);
+
+/**
+ * @brief Unregister changed callback for resource center's request.
+ * @param[in] id Id of handler received from rc_register_player_audio_start_request_callback() function.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ * @return None
+ */
+int rc_unregister_player_audio_start_request_callback(const unsigned int id);
+
+/**
+ * @brief Unregister changed callback for resource center's request.
+ * @param[in] id Id of handler received from rc_register_player_audio_resync_request_callback() function.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ * @return None
+ */
+int rc_unregister_player_audio_resync_request_callback(const unsigned int id);
+
+/**
+ * @brief Get zone list
+ * @remarks    @a zone_list should be freed using rc_free_zone_list().\n
+ *     Use rc_get_next_zone() to get the first node of the list.
+ * @param[out] zone_list list of zones.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_get_zone_list(rc_zone_list_h* zone_list);
+
+/**
+ * @brief Gets the next zone of the zone list.
+ * @param[in] zone_list list of zones.
+ * @param[out] zone The zone item
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_get_next_zone(rc_zone_list_h zone_list, rc_zone_h *zone);
+
+/**
+ * @brief Gets the prev zone of the zone list.
+ * @param[in] zone_list list of zones.
+ * @param[out] zone The zone item
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_get_prev_zone(rc_zone_list_h zone_list, rc_zone_h *zone);
+
+/**
+ * @brief Gets the prev zone of the zone list.
+ * @param[in] zone The zone item
+ * @param[out] zone_id id of zone.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_get_zone_id(rc_zone_h zone, int* zone_id);
+
+/**
+ * @brief Free zone list
+ * @param[in] zone_list list of zones.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_free_zone_list(rc_zone_list_h zone_list);
+
+/**
+ * @brief Set application's zone info
+ * @remarks This API is only for control app
+ * @param[in] app_id application id
+ * @param[in] zone_id id of zone
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_set_app_zone_info(const char* app_id, int zone_id);
+
+/**
+ * @brief Set application's zone info which pre assigned
+ * @remarks This API is only for control app
+ * @param[in] app_id application id
+ * @param[in] zone_id id of zone
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_set_pre_assigned_app_zone_info(const char* app_id, int zone_id);
+
+/**
+ * @brief Notify that player's audio start is done
+ * @param[in] player_id player id
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_player_audio_start_done(int player_id);
+
+/**
+ * @brief Notify that player's audio stop is done
+ * @param[in] player_id player id
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_player_audio_stop_done(int player_id);
+
+/**
+ * @brief Set zone id which requires best quality video resource
+ * @remarks This API is only for control app
+ * @param[in] app_id application id
+ * @param[in] zone_id id of zone
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_set_best_quality_zone_info(const char* app_id, int zone_id);
+
+/**
+ * @brief Switch zones which require best quality video resource
+ * @remarks This API is only for control app
+ * @param[in] cur_zone_id current zone id having best quality video resource
+ * @param[in] next_zone_id next zone id which will have best quality video resource
+ * @return @c a zone id which is selected as best quality zone on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_switch_best_quality_zone(int cur_zone_id, int next_zone_id);
+
+/**
+ * @brief Restore best quality zone
+ * @remarks This API is only for control app
+ * @return @c 0 in case restore performed, otherwise a negative value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_restore_best_quality_zone(void);
+
+/**
+ * @brief Register callback for best quality zone switching
+ * @remarks This API is only for control app
+ * @param[in] cb Callback function to be called when best quality zone is switched
+ * @param[in] data The user data passed from the callback
+ * @return 0 on success, otherwise negative value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_register_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb, void *data);
+
+/**
+ * @brief Unregister callback for best quality zone switching
+ * @remarks This API is only for control app
+ * @param[in] cb Callback function to unregister
+ * @return 0 on success, otherwise negative value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_unregister_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb);
+
+/**
+ * @brief Check application has audio focus or not
+ * @remarks This API return 0, if application is not assigned specific zone yet.
+ * @param[in] app_id application id
+ * @return @c 0 and positive value on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_is_audio_focused(const char* app_id);
+
+/**
+ * @brief Get focused zone handle
+ * @param[in] zone zone handle
+ * @return @c 0 and positive value on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ * @remarks
+ * \li The returned zone must be freed by rc_zone_free() after use
+ * \li zone id will be 0 in case it's not in multiview mode. The valid zone id starts from 1.
+ * \li The data of zone information can be accessed by the following APIs
+ * \li rc_zone_get_id()
+ * \li rc_zone_get_app_id()
+ * \li rc_zone_get_scaler_id()
+ */
+int rc_get_focused_zone(rc_zone_h *zone);
+
+/**
+ * @brief Get zone id
+ * @param[in] zone zone handle
+ * @return positive zone id value on success, otherwise a negative value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_zone_get_id(rc_zone_h zone);
+
+/**
+ * @brief Get application id allocated to the zone
+ * @param[in] zone zone handle
+ * @return application id on success, otherwise NULL
+ * @pre None
+ * @post None
+ * @exception None
+ * @remarks
+ * \li The returned pointer will be valid until rc_zone_free() is called.
+ */
+const char* rc_zone_get_app_id(rc_zone_h zone);
+
+/**
+ * @brief Get scaler id allocated to the zone
+ * @param[in] zone zone handle
+ * @return positive hw scaler id value on success, otherwise a negative value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_zone_get_scaler_id(rc_zone_h zone);
+
+/**
+ * @brief Free zone handle
+ * @param[in] zone zone handle
+ * @return None
+ * @pre None
+ * @post None
+ * @exception None
+ */
+void rc_zone_free(rc_zone_h zone);
+
+struct rc_resource;
+
+/**
+ * @brief resource handle.
+ */
+typedef struct rc_resource* rc_resource_h;
+
+/**
+ * @brief Get whether max resolution has been changed
+ * @param[in] rsc resource handle
+ * @return true in case rc_resource_change_cb() was invoked by max resolution change, otherwise false
+ * @pre None
+ * @post None
+ * @exception None
+ */
+bool rc_rsc_max_resolution_changed(rc_resource_h rsc);
+
+/**
+ * @brief Get max video resolution allowed to the application.
+ * @param[in] rsc resource handle
+ * @param[out] width max width
+ * @param[out] height max height
+ * @param[out] framerate max framerate
+ * @return 0 on success, otherwise negative value
+ * @pre None
+ * @post None
+ * @exception None
+ * @remarks
+ * \li The values are valid only in case rc_rsc_max_resolution_changed() is true.
+ */
+int rc_rsc_get_video_max_resolution(rc_resource_h rsc, int *width, int *height, int *framerate);
+
+/**
+ * @brief Get whether audio resource shall be changed
+ * @param[in] rsc resource handle
+ * @return true in case rc_resource_change_cb() was invoked by audio resource change, otherwise false
+ * @pre None
+ * @post None
+ * @exception None
+ */
+bool rc_rsc_audio_out_changed(rc_resource_h rsc);
+
+/**
+ * @brief Called when max resolution of application is changed or audio resource shall be reallocated
+ * @param[in] app_id application id of which max resolution was changed or audio resource shall be reallocated
+ * @param[in] rsc resource handle
+ * @param[in] data The user data passed from the callback registration function
+ * @see rc_register_resource_change_callback()
+ * @see rc_unregister_resource_change_callback()
+ * @remarks
+ * \li The passed resource handle can be accessed by below APIs
+ * \li rc_rsc_max_resolution_changed()
+ * \li rc_rsc_audio_out_changed()
+ * \li rc_rsc_get_video_max_resolution()
+ */
+typedef void (*rc_resource_change_cb)(const char* app_id, rc_resource_h rsc, void *data);
+
+/**
+ * @brief Register callback for resource change event
+ * @param[in] app_id application id
+ * @param[in] cb Callback function to be called when max resolution of application is changed or audio resource shall be reallocated
+ * @param[in] data The user data passed from the callback
+ * @return 0 on success, otherwise negative value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_register_resource_change_callback(const char* app_id, rc_resource_change_cb cb, void* data);
+
+/**
+ * @brief Unregister callback for resource change event
+ * @param[in] app_id application id
+ * @param[in] cb Callback function to unregister
+ * @return 0 on success, otherwise negative value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_unregister_resource_change_callback(const char* app_id, rc_resource_change_cb cb);
+
+/**
+ * @brief Get player's audio out
+ * @param[in] player_id player id
+ * @param[out] audio_out player's audio out
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_get_player_audio_out(int player_id, rc_player_audio_out_e* audio_out);
+
+/**
+ * @brief Called when resource center request video control.
+ * @param[in] player_id target player's id
+ * @param[in] data The user data passed from the callback registration function
+ * @see rc_register_player_video_stop_request_callback()
+ * @see rc_register_player_video_start_request_callback()
+ */
+typedef void (*rc_player_video_request_cb)(int player_id, void* data);
+
+/**
+ * @brief Register changed callback for resource center's request.
+ * @param[in] callback Callback function to be called when resource center request video stop.
+ * @param[in] data The user data passed from the callback
+ * @return Callback handle value if function finished succesful, 0 if failed.
+ * @pre None
+ * @post None
+ * @exception None
+ */
+unsigned int rc_register_player_video_stop_request_callback(rc_player_video_request_cb callback, void* data);
+
+/**
+ * @brief Register changed callback for resource center's request.
+ * @param[in] callback Callback function to be called when resource center request video start.
+ * @param[in] data The user data passed from the callback
+ * @return Callback handle value if function finished succesful, 0 if failed.
+ * @pre None
+ * @post None
+ * @exception None
+ */
+unsigned int rc_register_player_video_start_request_callback(rc_player_video_request_cb callback, void* data);
+
+/**
+ * @brief Unregister changed callback for resource center's request.
+ * @param[in] id Id of handler received from rc_register_player_video_stop_request_callback() function.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ * @return None
+ */
+int rc_unregister_player_video_stop_request_callback(const unsigned int id);
+
+/**
+ * @brief Unregister changed callback for resource center's request.
+ * @param[in] id Id of handler received from rc_register_player_video_start_request_callback() function.
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ * @return None
+ */
+int rc_unregister_player_video_start_request_callback(const unsigned int id);
+
+/**
+ * @brief Notify that player's video start is done
+ * @param[in] player_id player id
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_player_video_start_done(int player_id);
+
+/**
+ * @brief Notify that player's video stop is done
+ * @param[in] player_id player id
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_player_video_stop_done(int player_id);
+
+/**
+ * @brief Notify current layout state
+ * @param[in] state layout state
+ * @return @c 0 on success, otherwise a negative error value
+ * @pre None
+ * @post None
+ * @exception None
+ */
+int rc_notify_layout_state(rc_layout_state_e state);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __TIZEN_RESOURCE_CENTER_H__ */
diff --git a/include/resource_center_internal.h b/include/resource_center_internal.h
new file mode 100644 (file)
index 0000000..c489c4c
--- /dev/null
@@ -0,0 +1,109 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef __TIZEN_RESOURCE_CENTER_INTERNAL_H__\r
+#define __TIZEN_RESOURCE_CENTER_INTERNAL_H__\r
+\r
+#ifdef __cplusplus\r
+extern "C"\r
+{\r
+#endif\r
+\r
+typedef enum {\r
+       RC_AUDIO_OUT_MAIN = 1, /**< audio out main */\r
+       RC_AUDIO_OUT_SUB       /**< audio out sub */\r
+} rc_audio_out_e;\r
+\r
+/**\r
+ * @brief Register player\r
+ * @param[in] player_id player id\r
+ * @param[in] resource_id window resource id\r
+ * @return @c 0 on success, otherwise a negative error value\r
+ * @pre None\r
+ * @post None\r
+ * @exception None\r
+ */\r
+int rc_player_register(int player_id, int resource_id);\r
+\r
+/**\r
+ * @brief Request play\r
+ * @param[in] player_id player id\r
+ * @param[out] audio_out player's audio out\r
+ * @return @c 0 on success, otherwise a negative error value\r
+ * @pre None\r
+ * @post None\r
+ * @exception None\r
+ */\r
+int rc_player_request_play(int player_id, rc_audio_out_e* audio_out);\r
+\r
+/**\r
+ * @brief Request stop\r
+ * @param[in] player_id player id\r
+ * @return @c 0 on success, otherwise a negative error value\r
+ * @pre None\r
+ * @post None\r
+ * @exception None\r
+ */\r
+int rc_player_request_stop(int player_id);\r
+\r
+/**\r
+ * @brief Unregister player\r
+ * @param[in] player_id player id\r
+ * @return @c 0 on success, otherwise a negative error value\r
+ * @pre None\r
+ * @post None\r
+ * @exception None\r
+ */\r
+int rc_player_unregister(int player_id);\r
+\r
+/**\r
+ * @brief Register external speaker info\r
+ * @param[in] info external speaker info\r
+ * @param[in] zone_id zone id\r
+ * @return @c 0 on success, otherwise a negative error value\r
+ * @pre None\r
+ * @post None\r
+ * @exception None\r
+ */\r
+int rc_extspk_info_register(const char* info, int zone_id);\r
+\r
+/**\r
+ * @brief Unegister external speaker info\r
+ * @param[in] info external speaker info\r
+ * @param[in] zone_id zone id\r
+ * @return @c 0 on success, otherwise a negative error value\r
+ * @pre None\r
+ * @post None\r
+ * @exception None\r
+ */\r
+int rc_extspk_info_unregister(const char* info, int zone_id);\r
+\r
+/**\r
+ * @brief Register external speaker info\r
+ * @param[in] info external speaker info\r
+ * @param[out] audio_out audio out of external speaker\r
+ * @return @c 0 on success, otherwise a negative error value\r
+ * @pre None\r
+ * @post None\r
+ * @exception None\r
+ */\r
+int rc_get_extspk_info_audio_out(const char* info, int* audio_out);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __TIZEN_RESOURCE_CENTER_INTERNAL_H__ */\r
diff --git a/include_internal/resource_center_private.h b/include_internal/resource_center_private.h
new file mode 100644 (file)
index 0000000..0872da0
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2024 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 __TIZEN_RESOURCE_CENTER_PRIVATE_H__
+#define __TIZEN_RESOURCE_CENTER_PRIVATE_H__
+
+#include <dlog.h>
+#include <resource_center.h>
+#include <resource_center_internal.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "RSC_CENTER_API"
+
+#ifndef RC_LOG_ERR
+#define RC_LOG_ERR(fmt, args...)SLOGE(fmt, ##args)
+#endif
+
+#ifndef RC_LOG_WARN
+#define RC_LOG_WARN(fmt, args...)SLOGW(fmt, ##args)
+#endif
+
+#ifndef RC_LOG_DBG
+#define RC_LOG_DBG(fmt, args...)SLOGD(fmt, ##args)
+#endif
+
+#ifndef RC_LOG_INFO
+#define RC_LOG_INFO(fmt, args...)SLOGI(fmt, ##args)
+#endif
+
+typedef struct {
+       max_resolution_change_cb cb;
+       void* data;
+} rez_change_cb;
+
+typedef struct {
+       rc_resource_change_cb cb;
+       void* data;
+} rsc_change_cb;
+
+struct rc_zone {
+       int id;
+       int scaler_id;
+       char* app_id;
+};
+
+struct rc_resource
+{
+       int max_rsz_changed;
+       int audio_out_changed;
+       int height;
+       int width;
+       int framerate;
+};
+
+int _rc_set_resource_policy(int policy);
+int _rc_get_capable_category_id(const char* app_id, int category);
+int _rc_set_audio_focus(int zone_id);
+int _rc_get_audio_focus(int* zone_id);
+int _rc_get_last_audio_focus(int* zone_id);
+unsigned int _rc_register_audio_focus_changed_callback(rc_audio_focus_changed_cb callback, void* data);
+int _rc_unregister_audio_focus_changed_callback(const unsigned int id);
+int _rc_get_max_video_resolution(const char* app_id, int *width, int *height, int *framerate);
+int _rc_player_register(int player_id, int resource_id);
+int _rc_player_request_play(int player_id, rc_audio_out_e* audio_out);
+int _rc_player_request_stop(int player_id);
+int _rc_player_unregister(int player_id);
+int _rc_extspk_info_register(const char* info, int zone_id);
+int _rc_extspk_info_unregister(const char* info, int zone_id);
+int _rc_get_extspk_info_audio_out(const char* info);
+int _rc_register_max_video_resolution_changed_callback(const char* app_id, max_resolution_change_cb cb, void* data);
+int _rc_unregister_max_video_resolution_changed_callback(const char* app_id, max_resolution_change_cb cb);
+unsigned int _rc_register_player_audio_stop_request_callback(rc_player_audio_request_cb callback, gpointer data);
+unsigned int _rc_register_player_audio_start_request_callback(rc_player_audio_request_cb callback, gpointer data);
+unsigned int _rc_register_player_audio_resync_request_callback(rc_player_audio_request_cb callback, gpointer data);
+int _rc_unregister_player_audio_stop_request_callback(const unsigned int id);
+int _rc_unregister_player_audio_start_request_callback(const unsigned int id);
+int _rc_unregister_player_audio_resync_request_callback(const unsigned int id);
+unsigned int _rc_register_player_video_stop_request_callback(rc_player_video_request_cb callback, gpointer data);
+unsigned int _rc_register_player_video_start_request_callback(rc_player_video_request_cb callback, gpointer data);
+int _rc_unregister_player_video_stop_request_callback(const unsigned int id);
+int _rc_unregister_player_video_start_request_callback(const unsigned int id);
+int _rc_get_zone_list(rc_zone_list_h* zone_list);
+int _rc_get_next_zone(rc_zone_list_h zone_list, rc_zone_h *zone);
+int _rc_get_prev_zone(rc_zone_list_h zone_list, rc_zone_h *zone);
+int _rc_get_zone_id(rc_zone_h zone, int* zone_id);
+int _rc_free_zone_list(rc_zone_list_h zone_list);
+int _rc_set_app_zone_info(const char* app_id, int zone_id);
+int _rc_set_pre_assigned_app_zone_info(const char* app_id, int zone_id);
+bool _rc_is_supported_category(int category);
+int _rc_player_audio_start_done(int player_id);
+int _rc_player_audio_stop_done(int player_id);
+int _rc_player_video_start_done(int player_id);
+int _rc_player_video_stop_done(int player_id);
+int _rc_switch_best_quality_zone_info(int cur_zone_id, int next_zone_id);
+int _rc_register_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb, void *data);
+int _rc_unregister_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb);
+bool _rc_is_normal_mode(void);
+int _rc_is_audio_focused(const char* app_id);
+int _rc_restore_best_quality_zone(void);
+int _rc_get_focused_zone(rc_zone_h *zone);
+int _rc_register_resource_change_callback(const char* app_id, rc_resource_change_cb cb, void *data);
+int _rc_unregister_resource_change_callback(const char* app_id, rc_resource_change_cb cb);
+int _rc_get_player_audio_out(int player_id, rc_player_audio_out_e* audio_out);
+int _rc_notify_layout_state(rc_layout_state_e state);
+
+#endif /* __TIZEN_RESOURCE_CENTER_PRIVATE_H__ */
diff --git a/packaging/resource-center-api.spec b/packaging/resource-center-api.spec
new file mode 100644 (file)
index 0000000..7061372
--- /dev/null
@@ -0,0 +1,82 @@
+Name: resource-center-api
+Summary: resource center library
+Version: 0.1
+Release: 0
+Group:   Multimedia/Libraries
+License: Apache-2.0
+Source0: %{name}-%{version}.tar.gz
+BuildRequires:  cmake
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:  pkgconfig(gio-2.0)
+BuildRequires:  pkgconfig(glib-2.0)
+BuildRequires:  pkgconfig(libtzplatform-config)
+BuildRequires:  pkgconfig(resource-manager)
+BuildRequires:  pkgconfig(resource-information)
+
+%define _install_prefix /usr
+
+Requires(post): /sbin/ldconfig
+Requires(postun): /sbin/ldconfig
+
+%description
+Resource center library in Tizen
+
+%package devel
+Summary: resource center library (Development)
+Group: TO_BE/FILLED_IN
+Requires: %{name} = %{version}-%{release}
+
+%description devel
+Resource center library in Tizen (DEV)
+
+%if ("%{_vd_cfg_licensing}" == "y")
+%{?!TOMATO: %define TOMATO n}
+%else
+%{?!TOMATO: %define TOMATO y}
+%endif
+
+%prep
+%setup -q
+
+%build
+%if (%{TOMATO} == "y")
+export CXXFLAGS="$CXXFLAGS %{?__vd_cxxflags} -Wno-error"
+%endif
+
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+cmake . \
+      -DFULLVER=%{version} \
+      -DMAJORVER=${MAJORVER} \
+      -DLIB_DIR=%{_libdir} \
+      -DCMAKE_INSTALL_PREFIX=%{_install_prefix} \
+      -DTOMATO_BIN=%{_tomatobin}
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%if (%{TOMATO} == "y")
+mkdir -p %{buildroot}%{_tomatodir}
+mkdir -p %{buildroot}%{_tomatodir}/tc
+cp -rf ut/tc/* %{buildroot}%{_tomatodir}/tc
+%endif
+
+%make_install
+
+%clean
+
+%post
+/sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%{_libdir}/libresource-center-api.so.*
+%manifest resource-center-api.manifest
+%license LICENSE.APLv2
+%{_bindir}/resource_center_test
+
+%files devel
+%{_includedir}/resource_center.h
+%{_includedir}/resource_center_internal.h
+%{_libdir}/pkgconfig/*.pc
+%{_libdir}/*.so
diff --git a/resource-center-api.manifest b/resource-center-api.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
diff --git a/resource-center-api.pc.in b/resource-center-api.pc.in
new file mode 100644 (file)
index 0000000..109ba27
--- /dev/null
@@ -0,0 +1,14 @@
+
+# Package Information for pkg-config
+
+prefix=@PREFIX@
+exec_prefix=/usr
+libdir=/usr/@LIB_DIR@
+includedir=/usr/include
+
+Name: @PC_NAME@
+Description: @PACKAGE_DESCRIPTION@
+Version: @VERSION@
+Requires: @PC_REQUIRED@
+Libs: -L${libdir} @PC_LDFLAGS@
+Cflags: -I${includedir}
diff --git a/resource-center_tomato.manifest b/resource-center_tomato.manifest
new file mode 100644 (file)
index 0000000..fb6e646
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+   <request>
+     <domain name="_"/>
+   </request>
+ </manifest>
diff --git a/src/resource_center.cpp b/src/resource_center.cpp
new file mode 100644 (file)
index 0000000..a6e4620
--- /dev/null
@@ -0,0 +1,506 @@
+/*
+ * Copyright (c) 2024 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 <stdlib.h>
+#include <assert.h>
+#include <ri-module-api.h>
+#include "resource_center.h"
+#include "resource_center_private.h"
+
+int rc_set_resource_policy(rc_rsc_policy_e policy)
+{
+       RC_LOG_INFO(">>");
+
+       return _rc_set_resource_policy(policy);
+}
+
+int rc_get_capable_category_id(int handle, const char* app_id, int category)
+{
+       RC_LOG_INFO("app_id(%s), category(%d)", (app_id) ? app_id : "null", category);
+
+       if (!app_id || (category == RI_CATEGORY_NONE)) {
+               bool is_normal_mode = _rc_is_normal_mode();
+               RC_LOG_ERR("invalid param (%d:%d)", is_normal_mode, category);
+               return is_normal_mode? category:RI_CATEGORY_NOT_PERMITTED;
+       }
+
+       return (_rc_is_supported_category(category)) ? _rc_get_capable_category_id(app_id, category) : category;
+}
+
+int rc_set_audio_focus(int zone_id)
+{
+       RC_LOG_INFO(">>");
+
+       return _rc_set_audio_focus(zone_id);
+}
+
+int rc_get_audio_focus(int* zone_id)
+{
+       RC_LOG_INFO(">>");
+
+       if (!zone_id) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       return _rc_get_audio_focus(zone_id);
+}
+
+int rc_get_last_audio_focus(int* zone_id)
+{
+       RC_LOG_INFO(">>");
+
+       if (!zone_id) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       return _rc_get_last_audio_focus(zone_id);
+}
+
+unsigned int rc_register_audio_focus_changed_callback(rc_audio_focus_changed_cb callback, void* data)
+{
+       if (!callback) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_register_audio_focus_changed_callback(callback, data);
+}
+
+int rc_unregister_audio_focus_changed_callback(const unsigned int id)
+{
+       if (!id) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_unregister_audio_focus_changed_callback(id);
+}
+
+int rc_get_max_video_resolution(const char* app_id, int *width, int *height, int *framerate)
+{
+       if (!app_id || !width || !height || !framerate) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       return _rc_get_max_video_resolution(app_id, width, height, framerate);
+}
+
+int rc_register_max_video_resolution_changed_callback(const char* app_id, max_resolution_change_cb cb, void* data)
+{
+       if (!app_id || !cb) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       return _rc_register_max_video_resolution_changed_callback(app_id, cb, data);
+}
+
+int rc_unregister_max_video_resolution_changed_callback(const char* app_id, max_resolution_change_cb cb)
+{
+       if (!app_id || !cb) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       return _rc_unregister_max_video_resolution_changed_callback(app_id, cb);
+}
+
+unsigned int rc_register_player_audio_stop_request_callback(rc_player_audio_request_cb callback, void* data)
+{
+       if (!callback) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_register_player_audio_stop_request_callback(callback, data);
+}
+
+unsigned int rc_register_player_audio_start_request_callback(rc_player_audio_request_cb callback, void* data)
+{
+       if (!callback) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_register_player_audio_start_request_callback(callback, data);
+}
+
+unsigned int rc_register_player_audio_resync_request_callback(rc_player_audio_request_cb callback, void* data)
+{
+       if (!callback) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_register_player_audio_resync_request_callback(callback, data);
+}
+
+int rc_unregister_player_audio_stop_request_callback(const unsigned int id)
+{
+       if (!id) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_unregister_player_audio_stop_request_callback(id);
+}
+
+int rc_unregister_player_audio_start_request_callback(const unsigned int id)
+{
+       if (!id) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_unregister_player_audio_start_request_callback(id);
+}
+
+int rc_unregister_player_audio_resync_request_callback(const unsigned int id)
+{
+       if (!id) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_unregister_player_audio_resync_request_callback(id);
+}
+
+int rc_get_zone_list(rc_zone_list_h* zone_list)
+{
+       if (!zone_list) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       RC_LOG_INFO(">>");
+
+       return _rc_get_zone_list(zone_list);
+}
+
+int rc_get_next_zone(rc_zone_list_h zone_list, rc_zone_h *zone)
+{
+       if (!zone_list || !zone) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       RC_LOG_INFO(">>");
+
+       return _rc_get_next_zone(zone_list, zone);
+}
+
+int rc_get_prev_zone(rc_zone_list_h zone_list, rc_zone_h *zone)
+{
+       if (!zone_list || !zone) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       RC_LOG_INFO(">>");
+
+       return _rc_get_prev_zone(zone_list, zone);
+}
+
+int rc_get_zone_id(rc_zone_h zone, int* zone_id)
+{
+       if (!zone || !zone_id) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       RC_LOG_INFO(">>");
+
+       return _rc_get_zone_id(zone, zone_id);
+}
+
+int rc_free_zone_list(rc_zone_list_h zone_list)
+{
+       if (!zone_list) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       RC_LOG_INFO(">>");
+
+       return _rc_free_zone_list(zone_list);
+}
+
+int rc_set_app_zone_info(const char* app_id, int zone_id)
+{
+       if (!app_id) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       RC_LOG_INFO(">> (%s:%d)", app_id, zone_id);
+
+       return _rc_set_app_zone_info(app_id, zone_id);
+}
+
+int rc_set_pre_assigned_app_zone_info(const char* app_id, int zone_id)
+{
+       if (!app_id) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       RC_LOG_INFO(">>");
+
+       return _rc_set_pre_assigned_app_zone_info(app_id, zone_id);
+}
+
+int rc_player_audio_start_done(int player_id)
+{
+       RC_LOG_INFO(">>");
+
+       return _rc_player_audio_start_done(player_id);
+}
+
+int rc_player_audio_stop_done(int player_id)
+{
+       RC_LOG_INFO(">>");
+
+       return _rc_player_audio_stop_done(player_id);
+}
+
+int rc_set_best_quality_zone_info(const char* app_id, int zone_id)
+{
+       //deprecated
+       return 0;
+}
+
+int rc_switch_best_quality_zone(int cur_zone_id, int next_zone_id)
+{
+       if (cur_zone_id < 0 || next_zone_id < 0) {
+               RC_LOG_ERR("invalid param (%d:%d)", cur_zone_id, next_zone_id);
+               return -1;
+       }
+
+       RC_LOG_INFO(">> (%d:%d)", cur_zone_id, next_zone_id);
+
+       return _rc_switch_best_quality_zone_info(cur_zone_id, next_zone_id);
+}
+
+int rc_register_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb, void *data)
+{
+       RC_LOG_INFO(">>");
+       return _rc_register_best_quality_zone_switched_callback(cb, data);
+}
+
+int rc_unregister_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb)
+{
+       RC_LOG_INFO(">>");
+       return _rc_unregister_best_quality_zone_switched_callback(cb);
+}
+
+int rc_is_audio_focused(const char* app_id)
+{
+       if (!app_id) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       RC_LOG_INFO(">> (%s)", app_id);
+
+       return _rc_is_audio_focused(app_id);
+}
+
+int rc_restore_best_quality_zone(void)
+{
+       return _rc_restore_best_quality_zone();
+}
+
+int rc_get_focused_zone(rc_zone_h *zone)
+{
+       if (!zone) {
+               RC_LOG_ERR("invalid zone");
+               return -1;
+       }
+
+       return _rc_get_focused_zone(zone);
+}
+
+int rc_zone_get_id(rc_zone_h zone)
+{
+       if (!zone) {
+               RC_LOG_ERR("invalid zone");
+               return -1;
+       }
+
+       return zone->id;
+}
+
+const char* rc_zone_get_app_id(rc_zone_h zone)
+{
+       if (!zone) {
+               RC_LOG_ERR("invalid zone");
+               return NULL;
+       }
+
+       RC_LOG_INFO("(%s)", zone->app_id? zone->app_id:"empty");
+       return zone->app_id;
+}
+
+int rc_zone_get_scaler_id(rc_zone_h zone)
+{
+       if (!zone) {
+               RC_LOG_ERR("invalid zone");
+               return -1;
+       }
+
+       return zone->scaler_id;
+}
+
+void rc_zone_free(rc_zone_h zone)
+{
+       if (!zone) {
+               RC_LOG_ERR("invalid zone");
+               return;
+       }
+
+       if (zone->app_id) {
+               free(zone->app_id);
+               zone->app_id = NULL;
+       }
+
+       free(zone);
+       zone = NULL;
+}
+
+int rc_register_resource_change_callback(const char* app_id, rc_resource_change_cb cb, void* data)
+{
+       if (!app_id || !cb) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       return _rc_register_resource_change_callback(app_id, cb, data);
+}
+
+int rc_unregister_resource_change_callback(const char* app_id, rc_resource_change_cb cb)
+{
+       if (!app_id || !cb) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       return _rc_unregister_resource_change_callback(app_id, cb);
+}
+
+bool rc_rsc_max_resolution_changed(rc_resource_h rsc)
+{
+       if (!rsc) {
+               RC_LOG_ERR("invalid param");
+               return false;
+       }
+
+       return rsc->max_rsz_changed;
+}
+
+bool rc_rsc_audio_out_changed(rc_resource_h rsc)
+{
+       if (!rsc) {
+               RC_LOG_ERR("invalid param");
+               return false;
+       }
+
+       return rsc->audio_out_changed;
+}
+
+int rc_rsc_get_video_max_resolution(rc_resource_h rsc, int *width, int *height, int *framerate)
+{
+       if (!rsc || !width || !height || !framerate) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       *width = rsc->width;
+       *height = rsc->height;
+       *framerate = rsc->framerate;
+       return 0;
+}
+
+int rc_get_player_audio_out(int player_id, rc_player_audio_out_e* audio_out)
+{
+       if (!audio_out) {
+               RC_LOG_ERR("invalid param");
+               return -1;
+       }
+
+       return _rc_get_player_audio_out(player_id, audio_out);
+}
+
+unsigned int rc_register_player_video_stop_request_callback(rc_player_video_request_cb callback, void* data)
+{
+       if (!callback) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_register_player_video_stop_request_callback(callback, data);
+}
+
+unsigned int rc_register_player_video_start_request_callback(rc_player_video_request_cb callback, void* data)
+{
+       if (!callback) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_register_player_video_start_request_callback(callback, data);
+}
+
+int rc_unregister_player_video_stop_request_callback(const unsigned int id)
+{
+       if (!id) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_unregister_player_video_stop_request_callback(id);
+}
+
+int rc_unregister_player_video_start_request_callback(const unsigned int id)
+{
+       if (!id) {
+               RC_LOG_ERR("invalid param");
+               return 0;
+       }
+
+       return _rc_unregister_player_video_start_request_callback(id);
+}
+
+int rc_player_video_start_done(int player_id)
+{
+       RC_LOG_INFO(">>");
+
+       return _rc_player_video_start_done(player_id);
+}
+
+int rc_player_video_stop_done(int player_id)
+{
+       RC_LOG_INFO(">>");
+
+       return _rc_player_video_stop_done(player_id);
+}
+
+int rc_notify_layout_state(rc_layout_state_e state)
+{
+       return _rc_notify_layout_state(state);
+}
diff --git a/src/resource_center_internal.cpp b/src/resource_center_internal.cpp
new file mode 100644 (file)
index 0000000..0c9e3bf
--- /dev/null
@@ -0,0 +1,75 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include <stdlib.h>\r
+#include "resource_center_internal.h"\r
+#include "resource_center_private.h"\r
+\r
+int rc_player_register(int player_id, int resource_id)\r
+{\r
+       RC_LOG_INFO(">>");\r
+\r
+       return _rc_player_register(player_id, resource_id);\r
+}\r
+\r
+int rc_player_request_play(int player_id, rc_audio_out_e* audio_out)\r
+{\r
+       RC_LOG_INFO(">>");\r
+\r
+       return _rc_player_request_play(player_id, audio_out);\r
+}\r
+\r
+int rc_player_request_stop(int player_id)\r
+{\r
+       RC_LOG_INFO(">>");\r
+\r
+       return _rc_player_request_stop(player_id);\r
+}\r
+\r
+int rc_player_unregister(int player_id)\r
+{\r
+       RC_LOG_INFO(">>");\r
+\r
+       return _rc_player_unregister(player_id);\r
+}\r
+\r
+int rc_extspk_info_register(const char* info, int zone_id)\r
+{\r
+       RC_LOG_INFO(">>");\r
+\r
+       return _rc_extspk_info_register(info, zone_id);\r
+}\r
+\r
+int rc_extspk_info_unregister(const char* info, int zone_id)\r
+{\r
+       RC_LOG_INFO(">>");\r
+\r
+       return _rc_extspk_info_unregister(info, zone_id);\r
+}\r
+\r
+int rc_get_extspk_info_audio_out(const char* info, int* audio_out)\r
+{\r
+       int ret;\r
+       RC_LOG_INFO(">>");\r
+\r
+       ret = _rc_get_extspk_info_audio_out(info);\r
+\r
+       if (ret < 0)\r
+               return ret;\r
+\r
+       *audio_out = ret;\r
+       return 0;\r
+}
\ No newline at end of file
diff --git a/src/resource_center_private.cpp b/src/resource_center_private.cpp
new file mode 100644 (file)
index 0000000..b0b2a51
--- /dev/null
@@ -0,0 +1,1837 @@
+/*
+ * Copyright (c) 2024 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 <list>
+#include <map>
+#include <glib.h>
+#include <gio/gio.h>
+#include <assert.h>
+
+#include <rm_module_api.h>
+#include <ri-module-api.h>
+#include "resource_center_private.h"
+#include "resource_center.h"
+
+#define RC_DBUS_BUS_NAME "org.tizen.tv.system.resource"
+#define RC_DBUS_OBJ_PATH "/Org/Tizen/TV/System/Resource"
+#define RC_DBUS_INTERFACE_NAME RC_DBUS_BUS_NAME
+#define RC_DBUS_METHOD_NAME_SET_RESOURCE_POLICY "SetResourcePolicy"
+#define RC_DBUS_METHOD_NAME_GET_CAPABLE_CATEGORY_ID "GetCapableCatId"
+#define RC_DBUS_METHOD_NAME_SET_AUDIO_FOCUS "SetAudioFocus"
+#define RC_DBUS_METHOD_NAME_GET_AUDIO_FOCUS "GetAudioFocus"
+#define RC_DBUS_METHOD_NAME_GET_LAST_AUDIO_FOCUS "GetLastAudioFocus"
+#define RC_DBUS_METHOD_NAME_GET_MAX_VIDEO "GetMaxVideo"
+#define RC_DBUS_METHOD_NAME_PLAYER_REGISTER "PlayerRegister"
+#define RC_DBUS_METHOD_NAME_PLAYER_REQUEST_PLAY "PlayerRequestPlay"
+#define RC_DBUS_METHOD_NAME_PLAYER_REQUEST_STOP "PlayerRequestStop"
+#define RC_DBUS_METHOD_NAME_PLAYER_UNREGISTER "PlayerUnregister"
+#define RC_DBUS_METHOD_NAME_EXTSPKINFO_REGISTER "RegisterExtSpkInfo"
+#define RC_DBUS_METHOD_NAME_EXTSPKINFO_UNREGISTER "UnregisterExtSpkInfo"
+#define RC_DBUS_METHOD_NAME_GET_EXTSPKINFO_AUDIO_OUT "GetExtSpkInfoAudioOut"
+#define RC_DBUS_METHOD_NAME_GET_ZONE_LIST "GetMultiviewZoneIds"
+#define RC_DBUS_METHOD_NAME_SET_APP_ZONE_INFO "SetAppToZone"
+#define RC_DBUS_METHOD_NAME_SET_PRE_ASSIGNED_APP_ZONE_INFO "SetPreAssignedAppToZone"
+#define RC_DBUS_METHOD_NAME_MAX_REZ_REG_APP_ID "MaxVideoRegId"
+#define RC_DBUS_METHOD_NAME_MAX_REZ_UNREG_APP_ID "MaxVideoUnRegId"
+#define RC_DBUS_METHOD_NAME_SWITCH_BEST_QUALITY_ZONE "SwitchBestQaulityZone"
+#define RC_DBUS_METHOD_NAME_IS_AUDIO_FOCUSED "IsAudioFocused"
+#define RC_DBUS_METHOD_NAME_RESTORE_BEST_QUALITY_ZONE "RestoreBestQualityZone"
+#define RC_DBUS_METHOD_NAME_GET_FOCUSED_ZONE "GetFocusedZone"
+#define RC_DBUS_METHOD_NAME_RSC_CHANGE_REG_APP_ID "RscChangeRegId"
+#define RC_DBUS_METHOD_NAME_RSC_CHANGE_UNREG_APP_ID "RscChangeUnRegId"
+#define RC_DBUS_METHOD_NAME_GET_PLAYER_AUDIO_OUT "GetPlayerAudioOut"
+#define RC_DBUS_METHOD_NAME_NOTIFY_LAYOUT_STATE "NotifyLayoutState"
+
+#define RC_DBUS_SIGNAL_NAME_PLAYER_STOP_AUDIO "PlayerAudioStop"
+#define RC_DBUS_SIGNAL_NAME_PLAYER_START_AUDIO "PlayerAudioStart"
+#define RC_DBUS_SIGNAL_NAME_PLAYER_RESYNC_AUDIO "PlayerAudioResync"
+#define RC_DBUS_SIGNAL_NAME_PLAYER_AUDIO_STOP_DONE "PlayerAudioStopDone"
+#define RC_DBUS_SIGNAL_NAME_PLAYER_AUDIO_START_DONE "PlayerAudioStartDone"
+#define RC_DBUS_SIGNAL_NAME_AUDIO_FOCUS_CHANGED "AudioFocusChanged"
+
+#define RC_DBUS_SIGNAL_NAME_PLAYER_STOP_VIDEO "PlayerVideoStop"
+#define RC_DBUS_SIGNAL_NAME_PLAYER_START_VIDEO "PlayerVideoStart"
+#define RC_DBUS_SIGNAL_NAME_PLAYER_VIDEO_STOP_DONE "PlayerVideoStopDone"
+#define RC_DBUS_SIGNAL_NAME_PLAYER_VIDEO_START_DONE "PlayerVideoStartDone"
+
+typedef struct rc_player_audio_callback {
+       rc_player_audio_request_cb user_cb;
+       void* user_data;
+} rc_player_audio_callback_t;
+
+typedef struct rc_audio_focus_callback {
+       rc_audio_focus_changed_cb user_cb;
+       void* user_data;
+} rc_audio_focus_callback_t;
+
+typedef struct rc_best_quality_switched_callback {
+       rc_best_quality_zone_switched_cb user_cb;
+       void* user_data;
+} rc_best_quality_switched_callback_t;
+
+typedef struct rc_player_video_callback {
+       rc_player_video_request_cb user_cb;
+       void* user_data;
+} rc_player_video_callback_t;
+
+typedef struct rc_zone_list {
+       int count;
+       GList *list;
+       GList *iter;
+} rc_zone_list_t;
+
+static GDBusConnection* __dbus_get_connection()
+{
+       static GDBusConnection *conn = NULL;
+       GError *err = NULL;
+
+       if (conn)
+               return conn;
+
+       conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+       if (!conn) {
+               RC_LOG_ERR("g_bus_get_sync() error (%s)", err->message);
+               g_error_free(err);
+               return NULL;
+       }
+
+       return conn;
+}
+
+static int __dbus_method_call(const char *method, GVariant *args, GVariant **result)
+{
+       GError *err = NULL;
+       GVariant *reply = NULL;
+       GDBusConnection *conn = NULL;
+
+       RC_LOG_INFO("Method call '%s'", method);
+
+       if (!method) {
+               RC_LOG_ERR("Invalid Argument");
+               g_variant_unref(args);
+               return -1;
+       }
+
+       conn = __dbus_get_connection();
+
+       if (!conn) {
+               g_variant_unref(args);
+               return -1;
+       }
+
+       reply = g_dbus_connection_call_sync(conn, RC_DBUS_BUS_NAME, RC_DBUS_OBJ_PATH, RC_DBUS_INTERFACE_NAME,
+                                                                               method, args, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+
+       if (!reply) {
+               RC_LOG_ERR("Method Call '%s' Failed (%s)", method, err->message);
+               g_error_free(err);
+               return -1;
+       }
+
+       if (result)
+               *result = reply;
+
+       return 0;
+}
+
+static int __dbus_method_call_async_with_no_reply(const char *method, GVariant *args)
+{
+       GDBusConnection *conn = NULL;
+
+       RC_LOG_INFO("Method call '%s'", method);
+
+       if (!method) {
+               RC_LOG_ERR("Invalid Argument");
+               g_variant_unref(args);
+               return -1;
+       }
+
+       conn = __dbus_get_connection();
+
+       if (!conn) {
+               g_variant_unref(args);
+               return -1;
+       }
+
+       g_dbus_connection_call(conn, RC_DBUS_BUS_NAME, RC_DBUS_OBJ_PATH, RC_DBUS_INTERFACE_NAME,
+                                                                               method, args, NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+
+       return 0;
+}
+
+static int _dbus_subscribe_signal(const char *signal_name, GDBusSignalCallback signal_cb, guint *subscribe_id,
+                                                               void *userdata, GDestroyNotify freefunc)
+{
+       guint subs_id = 0;
+       GDBusConnection *conn = NULL;
+
+       if (!signal_name || !signal_cb) {
+               RC_LOG_ERR("Invalid Argument");
+               return -1;
+       }
+
+       conn = __dbus_get_connection();
+
+       if (!conn)
+               return -1;
+
+       RC_LOG_INFO("Dbus subscirbe signal %s", signal_name);
+
+       subs_id = g_dbus_connection_signal_subscribe(conn, NULL, RC_DBUS_INTERFACE_NAME, signal_name, RC_DBUS_OBJ_PATH,
+                                                                                               NULL, G_DBUS_SIGNAL_FLAGS_NONE , signal_cb, userdata, freefunc);
+
+       if (!subs_id) {
+               RC_LOG_ERR("g_dbus_connection_signal_subscribe() failed ");
+               return -1;
+       }
+       if (subscribe_id)
+               *subscribe_id = subs_id;
+
+       return 0;
+}
+
+static int __get_command_id(void)
+{
+       static int pid = -1, count = 0;
+       if (pid == -1)
+               pid = getpid();
+
+       return (pid << 16) | count++;
+}
+
+int _rc_set_resource_policy(int policy)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       int command_id = __get_command_id();
+       GVariant *result = NULL;
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_SET_RESOURCE_POLICY,
+                                                       g_variant_new("(iui)", command_id, policy, getpid()),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for SET_RESOURCE_POLICY is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, dbus_ret);
+       if (dbus_ret)
+               ret = -1;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+bool _rc_is_supported_category(int category)
+{
+       int category_id = rm_unmask_category_options(category);
+
+       if (ri_is_video_decoder_category(category_id))
+               return true;
+       if (ri_is_audio_decoder_category(category_id))
+               return true;
+       if (ri_is_audio_out_category(category_id))
+               return true;
+       if (ri_is_video_scaler_category(category_id))
+               return true;
+       if (ri_is_mjpeg_decoder_category(category_id))
+               return true;
+
+       RC_LOG_INFO("[%d] is not supported category", category);
+
+       return false;
+}
+
+bool _rc_is_normal_mode(void)
+{
+       const char* rsc_event_name = "/tmp/.rsc_policy_activated";
+       //return (LwipcWaitEvent(rsc_event_name, 0) == 0)? false:true;
+
+       return access(rsc_event_name, F_OK) == 0;
+}
+
+static bool _rc_is_resource_center_ready(void)
+{
+       const char* rsc_event_name = "/tmp/.rsc_center_ready";
+       return access(rsc_event_name, F_OK) == 0;
+}
+
+static bool _rc_need_interlaced_capability_check(int category)
+{
+       int unmasked_id = rm_unmask_category_options(category);
+       if (unmasked_id != RM_CATEGORY_VIDEO_DECODER_H264_FHD_8BIT_30P && unmasked_id != RM_CATEGORY_VIDEO_DECODER_H264_FHD_8BIT_60P)
+               return false;
+
+       return ri_is_h264_interlaced_limited_model();
+}
+
+int _rc_get_capable_category_id(const char* app_id, int category)
+{
+       int ret = 0;
+       int category_id = -1;
+       GVariant *result = NULL;
+       pid_t pid = getpid();
+       int command_id = __get_command_id();
+
+       if (!_rc_is_resource_center_ready())
+               return category;
+       if (_rc_is_normal_mode() && !_rc_need_interlaced_capability_check(category))
+               return category;
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_GET_CAPABLE_CATEGORY_ID,
+                                                       g_variant_new("(isii)", command_id, app_id, category, pid),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for GET_CAPABLE_CATEGORY_ID is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &category_id);
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, category_id);
+
+       g_variant_unref(result);
+
+       RC_LOG_INFO("category id %d", category_id);
+
+       return category_id;
+}
+
+int _rc_set_audio_focus(int zone_id)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_SET_AUDIO_FOCUS,
+                                                       g_variant_new("(ii)", command_id, zone_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for SET_AUDIO_FOCUS is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, dbus_ret);
+       if (dbus_ret)
+               ret = -1;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_get_audio_focus(int* zone_id)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_GET_AUDIO_FOCUS,
+                                                       g_variant_new("(i)", command_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for GET_AUDIO_FOCUS is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, dbus_ret);
+       if (!dbus_ret)
+               ret = -1;
+
+       if (dbus_ret)
+               *zone_id = dbus_ret;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_get_last_audio_focus(int* zone_id)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_GET_LAST_AUDIO_FOCUS,
+                                                       g_variant_new("(i)", command_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for GET_LAST_AUDIO_FOCUS is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, dbus_ret);
+       if (!dbus_ret)
+               ret = -1;
+
+       if (dbus_ret)
+               *zone_id = dbus_ret;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+static void audio_focus_cb_data_free_func(gpointer data)
+{
+       rc_audio_focus_callback_t *cb_data = (rc_audio_focus_callback_t *)data;
+
+       g_free(cb_data);
+}
+
+static void _dbus_audio_focus_signal_callback(GDBusConnection *connection, const gchar *sender_name, const gchar *object_path,
+                                                               const gchar *interface_name, const gchar *signal_name, GVariant *params, gpointer userdata)
+{
+       int zone_id;
+       int command_id;
+       rc_audio_focus_callback_t *cb_data = (rc_audio_focus_callback_t *)userdata;
+
+       g_variant_get(params, "(ii)", &command_id, &zone_id);
+
+       RC_LOG_INFO("[%08X] Signal(%s.%s) Received(%d)", command_id, interface_name, signal_name, zone_id);
+
+       (cb_data->user_cb)(zone_id, cb_data->user_data);
+}
+
+unsigned int _rc_register_audio_focus_changed_callback(rc_player_audio_request_cb callback, void* data)
+{
+       int ret = 0;
+       guint id = 0;
+       rc_audio_focus_callback_t *cb_data = (rc_audio_focus_callback_t*)g_malloc0(sizeof(rc_audio_focus_callback_t));
+
+       assert(cb_data);
+
+       cb_data->user_cb = callback;
+       cb_data->user_data = data;
+
+       ret = _dbus_subscribe_signal(RC_DBUS_SIGNAL_NAME_AUDIO_FOCUS_CHANGED, _dbus_audio_focus_signal_callback, &id, cb_data, audio_focus_cb_data_free_func);
+
+       if (ret) {
+               RC_LOG_ERR("(%s) failed", RC_DBUS_SIGNAL_NAME_AUDIO_FOCUS_CHANGED);
+               return -1;
+       }
+
+       RC_LOG_INFO("(%s) success :: (%lu)", RC_DBUS_SIGNAL_NAME_AUDIO_FOCUS_CHANGED, (unsigned long int)id);
+
+       return (unsigned int)id;
+}
+
+int _rc_unregister_audio_focus_changed_callback(const unsigned int id)
+{
+       GDBusConnection *conn = NULL;
+
+       conn = __dbus_get_connection();
+
+       if (!conn)
+               return -1;
+
+       g_dbus_connection_signal_unsubscribe(conn, id);
+
+       return 0;
+}
+
+int _rc_get_max_video_resolution(const char* app_id, int *width, int *height, int *framerate)
+{
+       int ret = 0;
+       int w = 0;
+       int h = 0;
+       int frame = -1;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_GET_MAX_VIDEO,
+                                                       g_variant_new("(is)", command_id, app_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_GET_MAX_VIDEO);
+               return -1;
+       }
+
+       g_variant_get(result, "(iii)", &w, &h, &frame);
+       RC_LOG_INFO("[%08X] (%s) success (%d*%d)-(%d)", command_id, RC_DBUS_METHOD_NAME_GET_MAX_VIDEO, w, h, frame);
+
+       *width = w;
+       *height = h;
+       *framerate = frame;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_player_register(int player_id, int resource_id)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_PLAYER_REGISTER,
+                                                       g_variant_new("(iii)", command_id, player_id, resource_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_PLAYER_REGISTER);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_PLAYER_REGISTER, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_player_request_play(int player_id, rc_audio_out_e* audio_out)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_PLAYER_REQUEST_PLAY,
+                                                       g_variant_new("(ii)", command_id, player_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_PLAYER_REQUEST_PLAY);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+
+       if (ret < 0) {
+               RC_LOG_ERR("[%08X] (%s) failed %d", command_id, RC_DBUS_METHOD_NAME_PLAYER_REQUEST_PLAY, ret);
+               return -1;
+       }
+
+       *audio_out = (rc_audio_out_e)ret;
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_PLAYER_REQUEST_PLAY, ret);
+
+       g_variant_unref(result);
+       return 0;
+}
+
+int _rc_player_request_stop(int player_id)
+{
+       int ret = 0;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call_async_with_no_reply(RC_DBUS_METHOD_NAME_PLAYER_REQUEST_STOP,
+                                                       g_variant_new("(ii)", command_id, player_id));
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_PLAYER_REQUEST_STOP);
+               return -1;
+       }
+
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_PLAYER_REQUEST_STOP, ret);
+
+       return ret;
+}
+
+int _rc_player_unregister(int player_id)
+{
+       int ret = 0;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call_async_with_no_reply(RC_DBUS_METHOD_NAME_PLAYER_UNREGISTER,
+                                                       g_variant_new("(ii)", command_id, player_id));
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_PLAYER_UNREGISTER);
+               return -1;
+       }
+
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_PLAYER_UNREGISTER, ret);
+
+       return ret;
+}
+
+int _rc_extspk_info_register(const char* info, int zone_id)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_EXTSPKINFO_REGISTER,
+                                                       g_variant_new("(isi)", command_id, info, zone_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_EXTSPKINFO_REGISTER);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_EXTSPKINFO_REGISTER, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_extspk_info_unregister(const char* info, int zone_id)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_EXTSPKINFO_UNREGISTER,
+                                                       g_variant_new("(isi)", command_id, info, zone_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_EXTSPKINFO_UNREGISTER);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_EXTSPKINFO_UNREGISTER, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_get_extspk_info_audio_out(const char* info)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_GET_EXTSPKINFO_AUDIO_OUT,
+                                                       g_variant_new("(is)", command_id, info),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_GET_EXTSPKINFO_AUDIO_OUT);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_GET_EXTSPKINFO_AUDIO_OUT, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+static unsigned int rez_change_signal_id = 0;
+std::map<std::string, rez_change_cb*> rez_change_cbs;
+
+static int _rc_add_max_video_resolution_cb(const char* app_id, max_resolution_change_cb cb, void * data)
+{
+       std::string appid(app_id);
+
+       auto it = rez_change_cbs.find(appid);
+       if (it != rez_change_cbs.end()) {
+               RC_LOG_ERR("already registered (%s:0x%08lX)", appid.c_str(), (unsigned long int) cb);
+               return -1;
+       }
+
+       rez_change_cb *cb_item = (rez_change_cb*) calloc(1, sizeof(rez_change_cb));
+       assert(cb_item);
+       cb_item->cb = cb;
+       cb_item->data = data;
+
+       rez_change_cbs.insert(std::pair<std::string, rez_change_cb*>(appid, cb_item));
+
+       RC_LOG_INFO("cb added (%s:0x%08lX)", appid.c_str(), (unsigned long int) cb);
+       return 0;
+}
+
+static int _rc_remove_max_video_resolution_cb(const char* app_id, max_resolution_change_cb cb)
+{
+       std::string appid(app_id);
+
+       auto it = rez_change_cbs.find(appid);
+       if (it == rez_change_cbs.end()) {
+               RC_LOG_ERR("not registered (%s:0x%08lX)", appid.c_str(), (unsigned long int) cb);
+               return -1;
+       }
+
+       rez_change_cb* cb_item = it->second;
+       rez_change_cbs.erase(it);
+
+       if (cb_item) {
+               free(cb_item);
+               cb_item = NULL;
+       }
+
+       RC_LOG_INFO("cb removed (%s:0x%08lX)", appid.c_str(), (unsigned long int) cb);
+
+       return rez_change_cbs.size();
+}
+
+static void onMaxRezChanged(GDBusConnection *conn,
+               const gchar *sender,
+               const gchar *object,
+               const gchar *interface,
+               const gchar *signal,
+               GVariant *parameters,
+               gpointer user_data)
+{
+       char* app_id;
+       int width;
+       int height;
+       int framerate;
+
+       g_variant_get(parameters, "(&siii)", &app_id, &width, &height, &framerate);
+       RC_LOG_INFO("signal (%s) received - (%s:%d:%d:%d)", signal, app_id, width, height, framerate);
+
+       if (rez_change_cbs.size() == 0) {
+               RC_LOG_ERR("empty list");
+               return;
+       }
+
+       std::map<std::string, rez_change_cb*> cb_list;
+       std::copy(rez_change_cbs.begin(), rez_change_cbs.end(), std::inserter(cb_list, cb_list.begin()));
+
+       auto it = cb_list.find(std::string(app_id));
+       if (it == cb_list.end())
+               return;
+
+       rez_change_cb *change_cb = (rez_change_cb *) it->second;
+
+       RC_LOG_INFO("call cb(0x%08lX)", (unsigned long int) change_cb->cb);
+       change_cb->cb(app_id, width, height, framerate, change_cb->data);
+}
+
+int _rc_register_max_video_resolution_changed_callback_app_id(const char* app_id, void *func)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_MAX_REZ_REG_APP_ID,
+                                                       g_variant_new("(islu)", command_id, app_id, (unsigned long int) func),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_MAX_REZ_REG_APP_ID);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_MAX_REZ_REG_APP_ID, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_unregister_max_video_resolution_changed_callback_app_id(const char* app_id, void *func)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_MAX_REZ_UNREG_APP_ID,
+                                                       g_variant_new("(islu)", command_id, app_id, (unsigned long int) func),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_MAX_REZ_UNREG_APP_ID);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_MAX_REZ_UNREG_APP_ID, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_register_max_video_resolution_changed_callback(const char* app_id, max_resolution_change_cb cb, void* data)
+{
+       if (_rc_add_max_video_resolution_cb(app_id, cb, data) < 0)
+               return -1;
+
+       if (_rc_register_max_video_resolution_changed_callback_app_id(app_id, (void*) cb) < 0) {
+               RC_LOG_ERR("failed to register app id(%s:%lu)", app_id, (unsigned long int) cb);
+               _rc_remove_max_video_resolution_cb(app_id, cb);
+               return -1;
+       }
+
+       if (rez_change_signal_id)
+               return 0;
+
+       GError *error = NULL;
+       GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!conn) {
+               RC_LOG_ERR("failed to get connection (%s)", (error)? error->message:"unknown");
+               _rc_remove_max_video_resolution_cb(app_id, cb);
+               return -1;
+       }
+
+       rez_change_signal_id = g_dbus_connection_signal_subscribe(conn,
+                       NULL,
+                       RC_DBUS_INTERFACE_NAME,
+                       "MaxRezChanged",
+                       RC_DBUS_OBJ_PATH,
+                       NULL,
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       onMaxRezChanged,
+                       NULL,
+                       NULL);
+
+       if (rez_change_signal_id == 0) {
+               if (error) {
+                       RC_LOG_ERR("dbus connection close error: %s", error->message);
+                       g_clear_error(&error);
+               }
+               _rc_remove_max_video_resolution_cb(app_id, cb);
+               return -1;
+       }
+
+       RC_LOG_INFO("subscribe max resolution change (%d)", rez_change_signal_id);
+
+       return 0;
+}
+
+int _rc_unregister_max_video_resolution_changed_callback(const char* app_id, max_resolution_change_cb cb)
+{
+       int remain = _rc_remove_max_video_resolution_cb(app_id, cb);
+
+       if (remain < 0)
+               return -1;
+
+       if (_rc_unregister_max_video_resolution_changed_callback_app_id(app_id, (void*) cb) < 0) {
+               RC_LOG_ERR("failed to unregister app id(%s:%lu)", app_id, (unsigned long int) cb);
+       }
+
+       if (remain > 0)
+               return 0;
+
+       GError *error = NULL;
+       GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!conn) {
+               RC_LOG_ERR("failed to get connection (%s)", (error)? error->message:"unknown");
+               return -1;
+       }
+
+       RC_LOG_INFO("unsubscribe max resolution change(%d)", rez_change_signal_id);
+       g_dbus_connection_signal_unsubscribe(conn, rez_change_signal_id);
+       rez_change_signal_id = 0;
+
+       return 0;
+}
+
+static void player_audio_cb_data_free_func(gpointer data)
+{
+       rc_player_audio_callback_t *cb_data = (rc_player_audio_callback_t *)data;
+
+       g_free(cb_data);
+}
+
+static void _dbus_player_audio_signal_callback(GDBusConnection *connection, const gchar *sender_name, const gchar *object_path,
+                                                               const gchar *interface_name, const gchar *signal_name, GVariant *params, gpointer userdata)
+{
+       int command_id;
+       int player_id;
+       rc_player_audio_callback_t *cb_data = (rc_player_audio_callback_t *)userdata;
+
+       g_variant_get(params, "(ii)", &command_id, &player_id);
+
+       RC_LOG_INFO("[%08X] Signal(%s.%s) Received(%d)", command_id, interface_name, signal_name, player_id);
+
+       (cb_data->user_cb)(player_id, cb_data->user_data);
+}
+
+unsigned int _rc_register_player_audio_stop_request_callback(rc_player_audio_request_cb callback, void* data)
+{
+       int ret = 0;
+       guint id = 0;
+
+       rc_player_audio_callback_t *cb_data = (rc_player_audio_callback_t*)g_malloc0(sizeof(rc_player_audio_callback_t));
+       assert(cb_data);
+       cb_data->user_cb = callback;
+       cb_data->user_data = data;
+
+       ret = _dbus_subscribe_signal(RC_DBUS_SIGNAL_NAME_PLAYER_STOP_AUDIO, _dbus_player_audio_signal_callback, &id, cb_data, player_audio_cb_data_free_func);
+
+       if (ret) {
+               RC_LOG_ERR("(%s) failed", RC_DBUS_SIGNAL_NAME_PLAYER_STOP_AUDIO);
+               return -1;
+       }
+
+       RC_LOG_INFO("(%s) success :: (%lu)", RC_DBUS_SIGNAL_NAME_PLAYER_STOP_AUDIO, (unsigned long int)id);
+
+       return (unsigned int)id;
+}
+
+unsigned int _rc_register_player_audio_start_request_callback(rc_player_audio_request_cb callback, void* data)
+{
+       int ret = 0;
+       guint id = 0;
+
+       rc_player_audio_callback_t *cb_data = (rc_player_audio_callback_t*)g_malloc0(sizeof(rc_player_audio_callback_t));
+       assert(cb_data);
+       cb_data->user_cb = callback;
+       cb_data->user_data = data;
+
+       ret = _dbus_subscribe_signal(RC_DBUS_SIGNAL_NAME_PLAYER_START_AUDIO, _dbus_player_audio_signal_callback, &id, cb_data, player_audio_cb_data_free_func);
+
+       if (ret) {
+               RC_LOG_ERR("(%s) failed", RC_DBUS_SIGNAL_NAME_PLAYER_START_AUDIO);
+               return -1;
+       }
+
+       RC_LOG_INFO("(%s) success :: (%lu)", RC_DBUS_SIGNAL_NAME_PLAYER_START_AUDIO, (unsigned long int)id);
+
+       return (unsigned int)id;
+}
+
+unsigned int _rc_register_player_audio_resync_request_callback(rc_player_audio_request_cb callback, void* data)
+{
+       int ret = 0;
+       guint id = 0;
+
+       rc_player_audio_callback_t *cb_data = (rc_player_audio_callback_t*)g_malloc0(sizeof(rc_player_audio_callback_t));
+       assert(cb_data);
+       cb_data->user_cb = callback;
+       cb_data->user_data = data;
+
+       ret = _dbus_subscribe_signal(RC_DBUS_SIGNAL_NAME_PLAYER_RESYNC_AUDIO, _dbus_player_audio_signal_callback, &id, cb_data, player_audio_cb_data_free_func);
+
+       if (ret) {
+               RC_LOG_ERR("(%s) failed", RC_DBUS_SIGNAL_NAME_PLAYER_RESYNC_AUDIO);
+               return -1;
+       }
+
+       RC_LOG_INFO("(%s) success :: (%lx)", RC_DBUS_SIGNAL_NAME_PLAYER_RESYNC_AUDIO, (unsigned long int)id);
+
+       return (unsigned int)id;
+}
+
+int _rc_unregister_player_audio_stop_request_callback(const unsigned int id)
+{
+       GDBusConnection *conn = NULL;
+
+       conn = __dbus_get_connection();
+
+       if (!conn)
+               return -1;
+
+       g_dbus_connection_signal_unsubscribe(conn, id);
+
+       return 0;
+}
+
+int _rc_unregister_player_audio_start_request_callback(const unsigned int id)
+{
+       GDBusConnection *conn = NULL;
+
+       conn = __dbus_get_connection();
+
+       if (!conn)
+               return -1;
+
+       g_dbus_connection_signal_unsubscribe(conn, id);
+
+       return 0;
+}
+
+int _rc_unregister_player_audio_resync_request_callback(const unsigned int id)
+{
+       GDBusConnection *conn = NULL;
+
+       conn = __dbus_get_connection();
+
+       if (!conn)
+               return -1;
+
+       g_dbus_connection_signal_unsubscribe(conn, id);
+
+       return 0;
+}
+
+static void _rc_zone_free(gpointer data)
+{
+       rc_zone *zone = (rc_zone*) data;
+
+       if (!zone)
+               return;
+
+       if (zone->app_id) {
+               free(zone->app_id);
+               zone->app_id = NULL;
+       }
+
+       free(zone);
+       zone = NULL;
+}
+
+int _rc_get_zone_list(rc_zone_list_h* zone_list)
+{
+       int ret = 0;
+       int zone_id;
+       gchar *app_id;
+       GVariant* result = nullptr;
+       GVariantIter* iter;
+       rc_zone_list_t* _zone_list = nullptr;
+       rc_zone *zone = nullptr;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_GET_ZONE_LIST,
+                                                       g_variant_new("(i)", command_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for GET_ZONE_LIST is failed", command_id);
+               return -1;
+       }
+
+       _zone_list = (rc_zone_list_t*)g_malloc0(sizeof(rc_zone_list_t));
+       assert(_zone_list);
+       g_variant_get(result, "(a(is))", &iter);
+
+       if (!iter) {
+               RC_LOG_ERR("[%08X] iter is null", command_id);
+               return -1;
+       }
+
+       while (g_variant_iter_loop(iter, "(is)", &zone_id, &app_id)) {
+               zone = (rc_zone*) calloc(1, sizeof(rc_zone));
+               assert(zone);
+               zone->id = zone_id;
+               zone->app_id = (app_id)? strndup(app_id, strlen(app_id)):nullptr;
+               _zone_list->count++;
+               _zone_list->list = g_list_append(_zone_list->list, zone);
+               RC_LOG_INFO("[%08X] zone %d(%s) is added", command_id, zone->id, (zone->app_id)? zone->app_id:"");
+       }
+       g_variant_iter_free(iter);
+
+       if (!_zone_list->count) {
+               RC_LOG_INFO("[%08X] There is no zones", command_id);
+               g_list_free_full(g_list_first(_zone_list->list), _rc_zone_free);
+               g_free(_zone_list);
+               return -1;
+       }
+
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, _zone_list->count);
+       *zone_list = (rc_zone_list_h)_zone_list;
+       _zone_list->iter = NULL;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_get_next_zone(rc_zone_list_h zone_list, rc_zone_h *zone)
+{
+       rc_zone_list_t* _zone_list = NULL;
+       GList* node = NULL;
+
+       _zone_list = (rc_zone_list_t*)zone_list;
+
+       if (!_zone_list->iter)
+               node = g_list_first(_zone_list->list);
+       else
+               node = g_list_next(_zone_list->iter);
+
+       if (!node) {
+               RC_LOG_INFO("no next zone");
+               return -1;
+       }
+
+       _zone_list->iter = node;
+       *zone = (rc_zone_h) node->data;
+
+       return 0;
+}
+
+int _rc_get_prev_zone(rc_zone_list_h zone_list, rc_zone_h *zone)
+{
+       rc_zone_list_t* _zone_list = NULL;
+       GList* node = NULL;
+
+       _zone_list = (rc_zone_list_t*)zone_list;
+
+       if (!_zone_list->iter) {
+               RC_LOG_INFO("no prev zone");
+               return -1;
+       }
+
+       node = g_list_previous(_zone_list->iter);
+
+       if (!node) {
+               RC_LOG_INFO("no prev zone");
+               return -1;
+       }
+
+       _zone_list->iter = node;
+       *zone = (rc_zone_h) node->data;
+
+       return 0;
+}
+
+int _rc_get_zone_id(rc_zone_h zone, int* zone_id)
+{
+       *zone_id = zone->id;
+       return 0;
+}
+
+int _rc_free_zone_list(rc_zone_list_h zone_list)
+{
+       rc_zone_list_t* _zone_list = (rc_zone_list_t*)zone_list;
+
+       g_list_free_full(_zone_list->list, _rc_zone_free);
+       g_free(_zone_list);
+
+       return 0;
+}
+
+int _rc_set_app_zone_info(const char* app_id, int zone_id)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_SET_APP_ZONE_INFO,
+                                                       g_variant_new("(isu)", command_id, app_id, zone_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08lX] __dbus_method_call() for SET_APP_ZONE_INFO is failed", (unsigned long int) command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08lX] __dbus_method_call() success, method return value is (%i)", (unsigned long int) command_id, dbus_ret);
+       if (dbus_ret)
+               ret = -1;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_set_pre_assigned_app_zone_info(const char* app_id, int zone_id)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_SET_PRE_ASSIGNED_APP_ZONE_INFO,
+                                                       g_variant_new("(isi)", command_id, app_id, zone_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08lX] __dbus_method_call() for SET_PRE_ASSIGNED_APP_ZONE_INFO is failed", (unsigned long int) command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08lX] __dbus_method_call() success, method return value is (%i)", (unsigned long int) command_id, dbus_ret);
+       if (dbus_ret)
+               ret = -1;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_player_audio_start_done(int player_id)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_SIGNAL_NAME_PLAYER_AUDIO_START_DONE,
+                                                       g_variant_new("(ii)", command_id, player_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08lX] (%s) failed", (unsigned long int) command_id, RC_DBUS_SIGNAL_NAME_PLAYER_AUDIO_START_DONE);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_SIGNAL_NAME_PLAYER_AUDIO_START_DONE, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_player_audio_stop_done(int player_id)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_SIGNAL_NAME_PLAYER_AUDIO_STOP_DONE,
+                                                       g_variant_new("(ii)", command_id, player_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_SIGNAL_NAME_PLAYER_AUDIO_STOP_DONE);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_SIGNAL_NAME_PLAYER_AUDIO_STOP_DONE, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_switch_best_quality_zone_info(int cur_zone_id, int next_zone_id)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_SWITCH_BEST_QUALITY_ZONE,
+                                                       g_variant_new("(iii)", command_id, cur_zone_id, next_zone_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for BEST QUALITY ZONE INFO is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, dbus_ret);
+
+       ret = dbus_ret;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+static unsigned int switched_signal_id = 0;
+static std::list<rc_best_quality_switched_callback_t*> switched_cb_list;
+
+static void onBestQualityZoneSwitched(GDBusConnection *conn,
+               const gchar *sender,
+               const gchar *object,
+               const gchar *interface,
+               const gchar *signal,
+               GVariant *parameters,
+               gpointer user_data)
+{
+       int prev_zone_id;
+       int cur_zone_id;
+       int result;
+
+       g_variant_get(parameters, "(iii)", &prev_zone_id, &cur_zone_id, &result);
+       RC_LOG_INFO("signal (%s) received - (%d:%d:%d)", signal, prev_zone_id, cur_zone_id, result);
+
+       std::list<rc_best_quality_switched_callback_t*> copied_cb_list;
+       copied_cb_list.assign(switched_cb_list.begin(), switched_cb_list.end());
+
+       for (auto it = copied_cb_list.begin(); it != copied_cb_list.end(); ++it) {
+               rc_best_quality_switched_callback_t *cb = *it;
+               RC_LOG_INFO("call cb(0x%08lX) - (%d:%d:%d)", (unsigned long int) cb->user_cb, prev_zone_id, cur_zone_id, result);
+               cb->user_cb(prev_zone_id, cur_zone_id, result, cb->user_data);
+       }
+}
+
+static int _rc_add_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb, void *data)
+{
+       for (auto &it : switched_cb_list) {
+               if (it->user_cb == cb) {
+                       RC_LOG_ERR("already registered callback (0x%08lX)", (unsigned long int) cb);
+                       return -1;
+               }
+       }
+       rc_best_quality_switched_callback_t *cb_item = (rc_best_quality_switched_callback_t*) calloc(1, sizeof(rc_best_quality_switched_callback_t));
+
+       assert(cb_item);
+
+       cb_item->user_cb = cb;
+       cb_item->user_data = data;
+
+       switched_cb_list.push_back(cb_item);
+       RC_LOG_INFO("cb added (0x%08lX)", (unsigned long int) cb);
+       return 0;
+}
+
+static int _rc_remove_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb)
+{
+       for (auto it = switched_cb_list.begin(); it != switched_cb_list.end(); ++it) {
+               rc_best_quality_switched_callback_t *cb_item = *it;
+               if (cb_item->user_cb == cb) {
+                       it = switched_cb_list.erase(it);
+                       free(cb_item);
+                       RC_LOG_INFO("cb removed (0x%08lX)", (unsigned long int) cb);
+                       return switched_cb_list.size();
+               }
+       }
+
+       RC_LOG_ERR("not registered cb (0x%08lX)", (unsigned long int) cb);
+       return -1;
+}
+
+int _rc_register_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb, void *data)
+{
+       if (_rc_add_best_quality_zone_switched_callback(cb, data) < 0)
+               return -1;
+
+       if (switched_signal_id)
+               return 0;
+
+       GError *error = NULL;
+       GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!conn) {
+               RC_LOG_ERR("failed to get connection (%s)", (error)? error->message:"unknown");
+               _rc_remove_best_quality_zone_switched_callback(cb);
+               return -1;
+       }
+
+       switched_signal_id = g_dbus_connection_signal_subscribe(conn,
+                       NULL,
+                       RC_DBUS_INTERFACE_NAME,
+                       "BestQualitZoneSwitched",
+                       RC_DBUS_OBJ_PATH,
+                       NULL,
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       onBestQualityZoneSwitched,
+                       NULL,
+                       NULL);
+
+       if (switched_signal_id == 0) {
+               if (error) {
+                       RC_LOG_ERR("dbus connection close error: %s", error->message);
+                       g_clear_error(&error);
+               }
+               _rc_remove_best_quality_zone_switched_callback(cb);
+               return -1;
+       }
+
+       RC_LOG_INFO("subscribe best quality zone switched (%d)", switched_signal_id);
+
+       return 0;
+}
+
+int _rc_unregister_best_quality_zone_switched_callback(rc_best_quality_zone_switched_cb cb)
+{
+       int remain = _rc_remove_best_quality_zone_switched_callback(cb);
+
+       if (remain != 0)
+               return (remain < 0)? -1 : 0;
+
+       GError *error = NULL;
+       GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!conn) {
+               RC_LOG_ERR("failed to get connection (%s)", (error)? error->message:"unknown");
+               return -1;
+       }
+
+       RC_LOG_INFO("unsubscribe best quality zone switched (%d)", switched_signal_id);
+       g_dbus_connection_signal_unsubscribe(conn, switched_signal_id);
+       switched_signal_id = 0;
+
+       return 0;
+}
+
+int _rc_is_audio_focused(const char* app_id)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_IS_AUDIO_FOCUSED,
+                                                       g_variant_new("(is)", command_id, app_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for IS_AUDIO_FOCUSED is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, dbus_ret);
+
+       g_variant_unref(result);
+       return dbus_ret;
+}
+
+int _rc_restore_best_quality_zone(void)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_RESTORE_BEST_QUALITY_ZONE,
+                                                       g_variant_new("(i)", command_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for RESTORE BEST QUALITY ZONE INFO is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, dbus_ret);
+
+       ret = dbus_ret;
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_get_focused_zone(rc_zone_h *zone)
+{
+       int ret = 0;
+       int zone_id = 0;
+       int scaler_id = -1;
+       char* app_id;
+       int command_id = __get_command_id();
+
+       GVariant *result = NULL;
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_GET_FOCUSED_ZONE,
+                                                       g_variant_new("(i)", command_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for GET_FOCUSED_ZONE is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(ii&s)", &zone_id, &scaler_id, &app_id);
+       RC_LOG_INFO("[%08X] focused zone (%d:%d:%s)", command_id, zone_id, scaler_id, (app_id)? app_id:"null");
+
+       rc_zone* z = (rc_zone*) calloc(1, sizeof(rc_zone));
+       assert(z);
+
+       z->id = zone_id;
+       z->scaler_id = scaler_id;
+       if (app_id)
+               z->app_id = strdup(app_id);
+
+       *zone = z;
+       g_variant_unref(result);
+       return ret;
+}
+
+static unsigned int rsc_change_signal_id = 0;
+std::map<std::string, rsc_change_cb*> rsc_change_cbs;
+
+static int _rc_add_resource_change_cb(const char* app_id, rc_resource_change_cb cb, void * data)
+{
+       std::string appid(app_id);
+
+       auto it = rsc_change_cbs.find(appid);
+       if (it != rsc_change_cbs.end()) {
+               RC_LOG_ERR("already registered (%s:0x%08lX)", appid.c_str(), (unsigned long int) cb);
+               return -1;
+       }
+
+       rsc_change_cb *cb_item = (rsc_change_cb*) calloc(1, sizeof(rsc_change_cb));
+       assert(cb_item);
+       cb_item->cb = cb;
+       cb_item->data = data;
+
+       rsc_change_cbs.insert(std::pair<std::string, rsc_change_cb*>(appid, cb_item));
+
+       RC_LOG_INFO("cb added (%s:0x%08lX)", appid.c_str(), (unsigned long int) cb);
+       return 0;
+}
+
+static int _rc_remove_resource_change_cb(const char* app_id, rc_resource_change_cb cb)
+{
+       std::string appid(app_id);
+
+       auto it = rsc_change_cbs.find(appid);
+       if (it == rsc_change_cbs.end()) {
+               RC_LOG_ERR("not registered (%s:0x%08lX)", appid.c_str(), (unsigned long int) cb);
+               return -1;
+       }
+
+       rsc_change_cb* cb_item = it->second;
+       rsc_change_cbs.erase(it);
+
+       if (cb_item) {
+               free(cb_item);
+               cb_item = NULL;
+       }
+
+       RC_LOG_INFO("cb removed (%s:0x%08lX)", appid.c_str(), (unsigned long int) cb);
+
+       return rsc_change_cbs.size();
+}
+
+int _rc_register_resource_change_callback_app_id(const char* app_id, void *func)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_RSC_CHANGE_REG_APP_ID,
+                                                       g_variant_new("(iislu)", command_id, getpid(), app_id, (unsigned long int) func),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_RSC_CHANGE_REG_APP_ID);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_RSC_CHANGE_REG_APP_ID, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_unregister_resource_change_callback_app_id(const char* app_id, void *func)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_RSC_CHANGE_UNREG_APP_ID,
+                                                       g_variant_new("(iislu)", command_id, getpid(), app_id, (unsigned long int) func),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_RSC_CHANGE_UNREG_APP_ID);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_RSC_CHANGE_UNREG_APP_ID, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+static void onRezChanged(GDBusConnection *conn,
+               const gchar *sender,
+               const gchar *object,
+               const gchar *interface,
+               const gchar *signal, GVariant *parameters, gpointer user_data)
+{
+       char* app_id; int max_rsz_changed = 0;
+       int audio_out_changed = 0;
+       int width = 0;
+       int height = 0;
+       int framerate = 0;
+
+       g_variant_get(parameters, "(&siiiii)", &app_id, &max_rsz_changed, &audio_out_changed, &width, &height, &framerate);
+       RC_LOG_INFO("signal (%s) received - (%s:%d:%d:%d:%d:%d)", signal, app_id, max_rsz_changed, audio_out_changed, width, height, framerate);
+
+       if (rsc_change_cbs.size() == 0) {
+               RC_LOG_ERR("empty list");
+               return;
+       }
+
+       std::map<std::string, rsc_change_cb*> cb_list;
+       std::copy(rsc_change_cbs.begin(), rsc_change_cbs.end(), std::inserter(cb_list, cb_list.begin()));
+
+       auto it = cb_list.find(std::string(app_id));
+       if (it == cb_list.end())
+               return;
+
+       rsc_change_cb *change_cb = (rsc_change_cb *) it->second;
+
+       rc_resource rsc;
+       rsc.max_rsz_changed = max_rsz_changed;
+       rsc.audio_out_changed = audio_out_changed;
+       rsc.width = width;
+       rsc.height = height;
+       rsc.framerate = framerate;
+
+       RC_LOG_INFO("call cb(0x%08lX)", (unsigned long int) change_cb->cb);
+       change_cb->cb(app_id, &rsc, change_cb->data);
+}
+
+int _rc_register_resource_change_callback(const char* app_id, rc_resource_change_cb cb, void *data)
+{
+       if (_rc_add_resource_change_cb(app_id, cb, data) < 0)
+               return -1;
+
+       if (_rc_register_resource_change_callback_app_id(app_id, (void*) cb) < 0) {
+               RC_LOG_ERR("failed to register app id(%s:%lu)", app_id, (unsigned long int) cb);
+               _rc_remove_resource_change_cb(app_id, cb);
+               return -1;
+       }
+
+       if (rsc_change_signal_id)
+               return 0;
+
+       GError *error = NULL;
+       GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!conn) {
+               RC_LOG_ERR("failed to get connection (%s)", (error)? error->message:"unknown");
+               _rc_remove_resource_change_cb(app_id, cb);
+               return -1;
+       }
+
+       rsc_change_signal_id = g_dbus_connection_signal_subscribe(conn,
+                       NULL,
+                       RC_DBUS_INTERFACE_NAME,
+                       "AppRscChanged",
+                       RC_DBUS_OBJ_PATH,
+                       NULL,
+                       G_DBUS_SIGNAL_FLAGS_NONE,
+                       onRezChanged,
+                       NULL,
+                       NULL);
+
+       if (rsc_change_signal_id == 0) {
+               if (error) {
+                       RC_LOG_ERR("dbus connection close error: %s", error->message);
+                       g_clear_error(&error);
+               }
+               _rc_remove_resource_change_cb(app_id, cb);
+               return -1;
+       }
+
+       RC_LOG_INFO("subscribe resource change (%d)", rsc_change_signal_id);
+       return 0;
+}
+
+int _rc_unregister_resource_change_callback(const char* app_id, rc_resource_change_cb cb)
+{
+       int remain = _rc_remove_resource_change_cb(app_id, cb);
+
+       if (remain < 0)
+               return -1;
+
+       if (_rc_unregister_resource_change_callback_app_id(app_id, (void*) cb) < 0)
+               RC_LOG_ERR("failed to unregister app id(%s:%lx)", app_id, (unsigned long int) cb);
+
+       if (remain > 0)
+               return 0;
+
+       GError *error = NULL;
+       GDBusConnection *conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+       if (!conn) {
+               RC_LOG_ERR("failed to get connection (%s)", (error)? error->message:"unknown");
+               return -1;
+       }
+
+       RC_LOG_INFO("unsubscribe resource change(%d)", rsc_change_signal_id);
+       g_dbus_connection_signal_unsubscribe(conn, rsc_change_signal_id);
+       rsc_change_signal_id = 0;
+       return 0;
+}
+
+int _rc_get_player_audio_out(int player_id, rc_player_audio_out_e* audio_out)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+       int active_audio_out = 0;
+
+       if (_rc_is_normal_mode()) {
+               active_audio_out = rm_get_active_audio_out(player_id);
+               RC_LOG_INFO("player : %d, active audio out : %d", player_id, active_audio_out);
+
+               if (active_audio_out < 0)
+                       return -1;
+
+               if (active_audio_out & RM_AUDIO_OUT_MAIN)
+                       *audio_out = RC_PLAYER_AUDIO_OUT_MAIN;
+               else if (active_audio_out & RM_AUDIO_OUT_SUB)
+                       *audio_out = RC_PLAYER_AUDIO_OUT_SUB;
+               else
+                       *audio_out = RC_PLAYER_AUDIO_OUT_NONE;
+
+               return 0;
+       }
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_GET_PLAYER_AUDIO_OUT,
+                                                       g_variant_new("(ii)", command_id, player_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_METHOD_NAME_GET_PLAYER_AUDIO_OUT);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       g_variant_unref(result);
+
+       if (ret < 0) {
+               RC_LOG_ERR("[%08X] (%s) failed %d", command_id, RC_DBUS_METHOD_NAME_GET_PLAYER_AUDIO_OUT, ret);
+               return -1;
+       }
+
+       *audio_out = (rc_player_audio_out_e)ret;
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_METHOD_NAME_GET_PLAYER_AUDIO_OUT, ret);
+
+       return 0;
+}
+
+static void _dbus_player_video_signal_callback(GDBusConnection *connection, const gchar *sender_name, const gchar *object_path,
+                                                               const gchar *interface_name, const gchar *signal_name, GVariant *params, gpointer userdata)
+{
+       int command_id;
+       int player_id;
+       rc_player_video_callback_t *cb_data = (rc_player_video_callback_t *)userdata;
+
+       g_variant_get(params, "(ii)", &command_id, &player_id);
+
+       RC_LOG_INFO("[%08X] Signal(%s.%s) Received(%d)", command_id, interface_name, signal_name, player_id);
+
+       (cb_data->user_cb)(player_id, cb_data->user_data);
+}
+
+static void player_video_cb_data_free_func(gpointer data)
+{
+       rc_player_video_callback_t *cb_data = (rc_player_video_callback_t *)data;
+
+       g_free(cb_data);
+}
+
+unsigned int _rc_register_player_video_stop_request_callback(rc_player_video_request_cb callback, void* data)
+{
+       int ret = 0;
+       guint id = 0;
+
+       rc_player_video_callback_t *cb_data = (rc_player_video_callback_t*)g_malloc0(sizeof(rc_player_video_callback_t));
+       assert(cb_data);
+       cb_data->user_cb = callback;
+       cb_data->user_data = data;
+
+       ret = _dbus_subscribe_signal(RC_DBUS_SIGNAL_NAME_PLAYER_STOP_VIDEO, _dbus_player_video_signal_callback, &id, cb_data, player_video_cb_data_free_func);
+
+       if (ret) {
+               RC_LOG_ERR("(%s) failed", RC_DBUS_SIGNAL_NAME_PLAYER_STOP_VIDEO);
+               return -1;
+       }
+
+       RC_LOG_INFO("(%s) success :: (%lu)", RC_DBUS_SIGNAL_NAME_PLAYER_STOP_VIDEO, (unsigned long int)id);
+
+       return (unsigned int)id;
+}
+
+unsigned int _rc_register_player_video_start_request_callback(rc_player_video_request_cb callback, void* data)
+{
+       int ret = 0;
+       guint id = 0;
+
+       rc_player_video_callback_t *cb_data = (rc_player_video_callback_t*)g_malloc0(sizeof(rc_player_video_callback_t));
+       assert(cb_data);
+       cb_data->user_cb = callback;
+       cb_data->user_data = data;
+
+       ret = _dbus_subscribe_signal(RC_DBUS_SIGNAL_NAME_PLAYER_START_VIDEO, _dbus_player_video_signal_callback, &id, cb_data, player_audio_cb_data_free_func);
+
+       if (ret) {
+               RC_LOG_ERR("(%s) failed", RC_DBUS_SIGNAL_NAME_PLAYER_START_VIDEO);
+               return -1;
+       }
+
+       RC_LOG_INFO("(%s) success :: (%lu)", RC_DBUS_SIGNAL_NAME_PLAYER_START_VIDEO, (unsigned long int) id);
+
+       return (unsigned int)id;
+}
+
+int _rc_unregister_player_video_stop_request_callback(const unsigned int id)
+{
+       GDBusConnection *conn = NULL;
+
+       conn = __dbus_get_connection();
+
+       if (!conn)
+               return -1;
+
+       g_dbus_connection_signal_unsubscribe(conn, id);
+
+       return 0;
+}
+
+int _rc_unregister_player_video_start_request_callback(const unsigned int id)
+{
+       GDBusConnection *conn = NULL;
+
+       conn = __dbus_get_connection();
+
+       if (!conn)
+               return -1;
+
+       g_dbus_connection_signal_unsubscribe(conn, id);
+
+       return 0;
+}
+
+int _rc_player_video_start_done(int player_id)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_SIGNAL_NAME_PLAYER_VIDEO_START_DONE,
+                                                       g_variant_new("(ii)", command_id, player_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_SIGNAL_NAME_PLAYER_VIDEO_START_DONE);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_SIGNAL_NAME_PLAYER_VIDEO_START_DONE, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_player_video_stop_done(int player_id)
+{
+       int ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_SIGNAL_NAME_PLAYER_VIDEO_STOP_DONE,
+                                                       g_variant_new("(ii)", command_id, player_id),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] (%s) failed", command_id, RC_DBUS_SIGNAL_NAME_PLAYER_VIDEO_STOP_DONE);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &ret);
+       RC_LOG_INFO("[%08X] (%s) success :: (%d)", command_id, RC_DBUS_SIGNAL_NAME_PLAYER_VIDEO_STOP_DONE, ret);
+
+       g_variant_unref(result);
+       return ret;
+}
+
+int _rc_notify_layout_state(rc_layout_state_e state)
+{
+       int ret = 0;
+       int dbus_ret = 0;
+       GVariant *result = NULL;
+       int command_id = __get_command_id();
+
+       ret = __dbus_method_call(RC_DBUS_METHOD_NAME_NOTIFY_LAYOUT_STATE,
+                                                       g_variant_new("(ii)", command_id, (int)state),
+                                                       &result);
+
+       if (ret) {
+               RC_LOG_ERR("[%08X] __dbus_method_call() for NOTIFY_LAYOUT_STATE is failed", command_id);
+               return -1;
+       }
+
+       g_variant_get(result, "(i)", &dbus_ret);
+       RC_LOG_INFO("[%08X] __dbus_method_call() success, method return value is (%i)", command_id, dbus_ret);
+       if (dbus_ret)
+               ret = -1;
+
+       g_variant_unref(result);
+       return ret;
+}
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..af19206
--- /dev/null
@@ -0,0 +1,19 @@
+SET(fw_test "${fw_name}-test")
+
+INCLUDE(FindPkgConfig)
+FOREACH(flag ${${fw_test}_CXXFLAGS})
+    SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}")
+    MESSAGE(${flag})
+ENDFOREACH()
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS} -Wall -pie")
+
+aux_source_directory(. sources)
+FOREACH(src ${sources})
+    GET_FILENAME_COMPONENT(src_name ${src} NAME_WE)
+    MESSAGE("${src_name}")
+    ADD_EXECUTABLE(${src_name} ${src})
+    TARGET_LINK_LIBRARIES(${src_name} ${fw_name} ${${fw_test}_LDFLAGS})
+ENDFOREACH()
+
+INSTALL(TARGETS resource_center_test DESTINATION bin)
diff --git a/test/resource_center_test.cpp b/test/resource_center_test.cpp
new file mode 100644 (file)
index 0000000..bb4f2a5
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2024 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 <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <glib.h>
+
+#include <resource_center.h>
+#include <resource_center_internal.h>
+
+#define MAX_STRING_LEN 256
+
+enum {
+       CURRENT_STATUS_MAINMENU,
+       CURRENT_STATUS_SET_RESOURCE_POLICY,
+       CURRENT_STATUS_SET_AUDIO_FOCUS,
+       CURRENT_STATUS_GET_AUDIO_FOCUS,
+       CURRENT_STATUS_PLAYER_UNREGISTER,
+       CURRENT_STATUS_REIGSTER_PLAYER_AUDIO_CALLBACK,
+       CURRENT_STATUS_UNREIGSTER_PLAYER_AUDIO_CALLBACK,
+       CURRENT_STATUS_GET_ZONE_LIST,
+       CURRENT_STATUS_FREE_ZONE_LIST,
+       CURRENT_STATUS_SET_APP_ZONE_INFO,
+       CURRENT_STATUS_GET_PLAYER_AUDIO_OUT,
+       CURRENT_STATUS_NOTIFY_LAYOUT_STATE,
+};
+
+static rc_zone_list_h zone_list;
+static int g_menu_state = CURRENT_STATUS_MAINMENU;
+
+GMainLoop* g_loop;
+
+void player_audio_stop_callback(int player_id, void* data)
+{
+       g_print("[%d] stop requested\n", player_id);
+}
+
+void player_audio_start_callback(int player_id, void* data)
+{
+       g_print("[%d] start requested\n", player_id);
+}
+
+void quit_program()
+{
+       g_main_loop_quit(g_loop);
+}
+
+void _interpret_main_menu(char *cmd)
+{
+       if (strncmp(cmd, "rpac", 4) == 0) {
+               g_menu_state = CURRENT_STATUS_REIGSTER_PLAYER_AUDIO_CALLBACK;
+       } else if (strncmp(cmd, "upac", 4) == 0) {
+               g_menu_state = CURRENT_STATUS_UNREIGSTER_PLAYER_AUDIO_CALLBACK;
+       } else if (strncmp(cmd, "srp", 3) == 0) {
+               g_menu_state = CURRENT_STATUS_SET_RESOURCE_POLICY;
+       } else if (strncmp(cmd, "saf", 3) == 0) {
+               g_menu_state = CURRENT_STATUS_SET_AUDIO_FOCUS;
+       } else if (strncmp(cmd, "gaf", 3) == 0) {
+               g_menu_state = CURRENT_STATUS_GET_AUDIO_FOCUS;
+       } else if (strncmp(cmd, "gsl", 3) == 0) {
+               g_menu_state = CURRENT_STATUS_GET_ZONE_LIST;
+       } else if (strncmp(cmd, "fsl", 3) == 0) {
+               g_menu_state = CURRENT_STATUS_FREE_ZONE_LIST;
+       } else if (strncmp(cmd, "pur", 3) == 0) {
+               g_menu_state = CURRENT_STATUS_PLAYER_UNREGISTER;
+       } else if (strncmp(cmd, "saz", 3) == 0) {
+               g_menu_state = CURRENT_STATUS_SET_APP_ZONE_INFO;
+       } else if (strncmp(cmd, "gpa", 3) == 0) {
+               g_menu_state = CURRENT_STATUS_GET_PLAYER_AUDIO_OUT;
+       } else if (strncmp(cmd, "nls", 3) == 0) {
+               g_menu_state = CURRENT_STATUS_NOTIFY_LAYOUT_STATE;
+       } else if (strncmp(cmd, "q", 1) == 0 ) {
+               g_print("closing the test suite\n");
+               quit_program();
+       } else {
+               g_print("unknown menu \n");
+       }
+
+}
+
+void display_sub_basic()
+{
+       g_print("\n");
+       g_print("=========================================================================================\n");
+       g_print("                         Resource Center API Test (press q to quit) \n");
+       g_print("-----------------------------------------------------------------------------------------\n");
+       g_print("srp. Set Resource Policy \n");
+       g_print("saf. Set Audio Focus \t\t\t");
+       g_print("gaf. Get Audio Focus \n");
+       g_print("pur. Unregister Player \n");
+       g_print("rpac. Register Player Audio Start/Stop callbacks \n");
+       g_print("upac. Unregister Player Audio Start/Stop callback \n");
+       g_print("gsl. Get Zone List \t\t\t");
+       g_print("fsl. Free Zone List \n");
+       g_print("saz. Set Application Zone Info \n");
+       g_print("gpa. Get Player AudioOut \n");
+       g_print("nls. Notify Layout State \n");
+       g_print("=========================================================================================\n");
+}
+
+static void displaymenu()
+{
+       if (g_menu_state == CURRENT_STATUS_MAINMENU) {
+               display_sub_basic();
+       } else if (g_menu_state == CURRENT_STATUS_SET_RESOURCE_POLICY) {
+               g_print("*** input the resource policy\n");
+       } else if (g_menu_state == CURRENT_STATUS_SET_AUDIO_FOCUS) {
+               g_print("*** input the focused zone\n");
+       } else if (g_menu_state == CURRENT_STATUS_GET_AUDIO_FOCUS) {
+               g_print("*** Press enter to get audio focus\n");
+       } else if (g_menu_state == CURRENT_STATUS_PLAYER_UNREGISTER) {
+               g_print("*** input the player id\n");
+       } else if (g_menu_state == CURRENT_STATUS_REIGSTER_PLAYER_AUDIO_CALLBACK) {
+               g_print("*** Press enter to register callbacks\n");
+       } else if (g_menu_state == CURRENT_STATUS_UNREIGSTER_PLAYER_AUDIO_CALLBACK) {
+               g_print("*** input the callback id\n");
+       } else if (g_menu_state == CURRENT_STATUS_GET_ZONE_LIST) {
+               g_print("*** Press enter to get zone list\n");
+       } else if (g_menu_state == CURRENT_STATUS_FREE_ZONE_LIST) {
+               g_print("*** Press enter to free zone list\n");
+       } else if (g_menu_state == CURRENT_STATUS_SET_APP_ZONE_INFO) {
+               g_print("*** input tha app id and zone id\n");
+       } else if (g_menu_state == CURRENT_STATUS_GET_PLAYER_AUDIO_OUT) {
+               g_print("*** input the player id\n");
+       } else if (g_menu_state == CURRENT_STATUS_NOTIFY_LAYOUT_STATE) {
+               g_print("*** input the state\n");
+       } else {
+               g_print("*** unknown status\n");
+               quit_program();
+       }
+       g_print(" >>> ");
+}
+
+gboolean timeout_menu_display(void* data)
+{
+       displaymenu();
+       return FALSE;
+}
+
+gboolean timeout_quit_program(void* data)
+{
+       quit_program();
+       return FALSE;
+}
+
+void reset_menu_state(void)
+{
+       g_menu_state = CURRENT_STATUS_MAINMENU;
+}
+
+static void interpret (char *cmd)
+{
+       switch (g_menu_state) {
+               case CURRENT_STATUS_MAINMENU: {
+                       _interpret_main_menu(cmd);
+                       break;
+               }
+               case CURRENT_STATUS_SET_RESOURCE_POLICY: {
+                       int policy = atoi(cmd);
+
+                       if (rc_set_resource_policy((rc_rsc_policy_e) policy) != 0)
+                               g_print("fail to set resource policy\n");
+                       else
+                               g_print("set resource policy success : %d\n", policy);
+
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_SET_AUDIO_FOCUS: {
+                       int zone_id = atoi(cmd);
+
+                       if (rc_set_audio_focus(zone_id) != 0)
+                               g_print("fail to set audio focus\n");
+                       else
+                               g_print("set audio focus success : %d\n", zone_id);
+
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_GET_AUDIO_FOCUS: {
+                       int zone_id = 0;
+
+                       if (rc_get_audio_focus(&zone_id) != 0)
+                               g_print("fail to get audio focus\n");
+                       else
+                               g_print("get audio focus success : %d\n", zone_id);
+
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_PLAYER_UNREGISTER: {
+                       int player_id = atoi(cmd);
+
+                       if (rc_player_unregister(player_id) != 0)
+                               g_print("fail to unregister player\n");
+                       else
+                               g_print("unregister player success : %d\n", player_id);
+
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_REIGSTER_PLAYER_AUDIO_CALLBACK: {
+                       unsigned int ret = rc_register_player_audio_stop_request_callback(player_audio_stop_callback, NULL);
+
+                       if (ret == 0)
+                               g_print("fail to register stop callback\n");
+                       else
+                               g_print("register stop callback success : %u\n", ret);
+
+                       ret = rc_register_player_audio_start_request_callback(player_audio_start_callback, NULL);
+
+                       if (ret == 0)
+                               g_print("fail to register start callback\n");
+                       else
+                               g_print("register start callback success : %u\n", ret);
+
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_UNREIGSTER_PLAYER_AUDIO_CALLBACK: {
+                       unsigned int id = atoi(cmd);
+
+                       if (rc_unregister_player_audio_stop_request_callback(id) != 0)
+                               g_print("fail to unregister callback\n");
+                       else
+                               g_print("unregister callback success : %u\n", id);
+
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_GET_ZONE_LIST: {
+                       int id;
+                       rc_zone_h zone;
+
+                       if (rc_get_zone_list(&zone_list) != 0) {
+                               g_print("fail to get zone list\n");
+                               reset_menu_state();
+                               break;
+                       }
+
+                       g_print("get zone list success : %p\n", zone_list);
+
+                       while (!rc_get_next_zone(zone_list, &zone)) {
+                               rc_get_zone_id(zone, &id);
+                               g_print("Zone(%p) id : %d\n", zone, id);
+                       }
+
+                       g_print("tail of zone list\n");
+
+                       while (!rc_get_prev_zone(zone_list, &zone)) {
+                               rc_get_zone_id(zone, &id);
+                               g_print("Zone(%p) id : %d\n", zone, id);
+                       }
+
+                       g_print("head of zone list\n");
+
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_FREE_ZONE_LIST: {
+                       if (rc_free_zone_list(zone_list) != 0)
+                               g_print("fail to free zone list\n");
+                       else
+                               g_print("free zone list success\n");
+
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_SET_APP_ZONE_INFO: {
+                       static int saz_state = 0;
+                       static char app_id[256];
+                       static int zone_id;
+
+                       if (!saz_state) {
+                               strncpy(app_id, cmd, 255);
+                               app_id[255] = 0;
+                               saz_state++;
+                               break;
+                       }
+
+                       zone_id = atoi(cmd);
+
+                       if (rc_set_app_zone_info(app_id, zone_id) != 0)
+                               g_print("fail to set app zone info\n");
+                       else
+                               g_print("set app zone info success : %s(%d)\n", app_id, zone_id);
+
+                       saz_state = 0;
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_GET_PLAYER_AUDIO_OUT: {
+                       int player_id = atoi(cmd);
+                       rc_player_audio_out_e audio_out = RC_PLAYER_AUDIO_OUT_NONE;
+
+                       if (rc_get_player_audio_out(player_id, &audio_out) != 0)
+                               g_print("fail to get player audio out\n");
+                       else
+                               g_print("get player audio out success : %d(%d)\n", (int)audio_out, player_id);
+
+                       reset_menu_state();
+                       break;
+               }
+               case CURRENT_STATUS_NOTIFY_LAYOUT_STATE: {
+                       int state = atoi(cmd);
+
+                       if (rc_notify_layout_state((rc_layout_state_e)state) != 0)
+                               g_print("fail to notify layout state\n");
+                       else
+                               g_print("notify layout state(%d) success\n", state);
+
+                       reset_menu_state();
+                       break;
+               }
+       }
+       g_timeout_add(100, timeout_menu_display, 0);
+}
+
+gboolean input(GIOChannel *channel, GIOCondition condition, gpointer data)
+{
+       gchar buf[MAX_STRING_LEN];
+       gsize read;
+       GError *error = NULL;
+
+       g_io_channel_read_chars(channel, buf, MAX_STRING_LEN, &read, &error);
+       buf[read] = '\0';
+       g_strstrip(buf);
+       interpret(buf);
+
+       return TRUE;
+}
+
+int main(int argc, char *argv[])
+{
+       GIOChannel *stdin_channel;
+
+       stdin_channel = g_io_channel_unix_new(0);
+       g_io_channel_set_flags(stdin_channel, G_IO_FLAG_NONBLOCK, NULL);
+       g_io_add_watch(stdin_channel, G_IO_IN, (GIOFunc)input, NULL);
+       g_loop = g_main_loop_new(NULL, 1);
+
+       displaymenu();
+       g_main_loop_run(g_loop);
+
+       return 0;
+}
\ No newline at end of file
diff --git a/ut/CMakeLists.txt b/ut/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9e01685
--- /dev/null
@@ -0,0 +1,64 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(${TEST_PKG_NAME} C CXX)
+INCLUDE(FindPkgConfig)
+pkg_check_modules(TOMATO_PKG REQUIRED
+       dlog
+       gio-2.0
+       gtest_gmock
+       resource-manager
+       resource-information
+)
+
+ADD_DEFINITIONS(-DTOMATO)
+
+FOREACH(flag ${TOMATO_PKG_CFLAGS})
+       SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}")
+       SET(EXTRA_CXXFLAGS "${EXTRA_CFLAGS} ${flag}")
+ENDFOREACH(flag)
+
+SET(CMAKE_C_FLAGS "${EXTRA_CFLAGS} -fPIC")
+SET(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
+
+SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=/usr/lib")
+
+SET(INCLUDE_DIR_TO_TEST
+       ${CMAKE_CURRENT_SOURCE_DIR}/inc
+       ${CMAKE_CURRENT_SOURCE_DIR}/../include
+       ${CMAKE_CURRENT_SOURCE_DIR}/../include_internal
+)
+
+SET(SRC_TO_TEST
+       ${CMAKE_CURRENT_SOURCE_DIR}/../src/resource_center_private.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/../src/resource_center.cpp
+)
+
+SET(SRC_TESTCASE
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/testcase/ut_main.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/testcase/ut_api.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/testcase/ut_util.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/testcase/TCPlayer.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/testcase/TCResource.cpp
+       ${CMAKE_CURRENT_SOURCE_DIR}/src/testcase/TCApp.cpp
+)
+
+#FILE(GLOB SRC_TOMATOUTIL "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
+
+SET(TOMATO_TEST ${TEST_PKG_NAME})
+
+INCLUDE_DIRECTORIES(
+       ${INCLUDE_DIR_TO_TEST}
+)
+
+ADD_EXECUTABLE(${TEST_PKG_NAME} ${SRC_TESTCASE} ${SRC_TO_TEST})
+
+FIND_PACKAGE (Threads REQUIRED)
+MESSAGE("TEST_PKG_NAME : " ${TEST_PKG_NAME})
+MESSAGE("CMAKE_THREAD_LIBS_INIT : " ${CMAKE_THREAD_LIBS_INIT})
+MESSAGE("TEST_PKG_NAME : " ${TEST_PKG_NAME} )
+MESSAGE("TOMATO_PKG_LDFLAGS : " ${TOMATO_PKG_LDFLAGS} )
+MESSAGE("glib_pkg_LDFLAGS : " ${glib_pkg_LDFLAGS} )
+MESSAGE("CMAKE_EXE_LINKER_FLAGS : " ${CMAKE_EXE_LINKER_FLAGS} )
+
+TARGET_LINK_LIBRARIES(${TEST_PKG_NAME}  ${CMAKE_THREAD_LIBS_INIT} ${TOMATO_PKG_LDFLAGS} ${glib_pkg_LDFLAGS} ${CMAKE_EXE_LINKER_FLAGS} )
+
+INSTALL(TARGETS ${TEST_PKG_NAME} DESTINATION ${TOMATO_BIN})
diff --git a/ut/inc/TCApp.h b/ut/inc/TCApp.h
new file mode 100644 (file)
index 0000000..b0ebbde
--- /dev/null
@@ -0,0 +1,57 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef __TC_APP_H__\r
+#define __TC_APP_H__\r
+#include <string>\r
+\r
+class TCApp\r
+{\r
+public:\r
+       TCApp(const char* app_id);\r
+       ~TCApp();\r
+\r
+       static void ResourceChangedCb(const char* app_id, rc_resource_h rsc, void *data);\r
+       int RegisterResourceChangeCb(void);\r
+       int UnregisterResourceChangeCb(void);\r
+\r
+       std::string GetAppId(void) { return m_app_id; }\r
+\r
+       void IncreaseCbCount(void) { m_cb_count++; }\r
+       void ResetCbCount(void) { m_cb_count = 0; }\r
+       int GetCbCount(void) { return m_cb_count;}\r
+\r
+       bool IsMaxRszChanged(void) { return m_max_rsz_changed; }\r
+       bool IsAudioRscChanged(void) { return m_audio_rsc_changed; }\r
+\r
+       void SetMaxRszChanged(bool changed) { m_max_rsz_changed = changed; }\r
+       void SetAudioRscChanged(bool changed) { m_audio_rsc_changed = changed; }\r
+       void SetMaxResolution(int w, int h, int f) { m_max_width = w; m_max_height = h; m_max_framerate = f; }\r
+       void GetMaxResolution(int *w, int *h, int *f) { *w = m_max_width, *h = m_max_height, *f = m_max_framerate; }\r
+       void ResetCbData(void) { m_max_width = 0; m_max_height = 0; m_max_framerate = 0; m_max_rsz_changed = false; m_audio_rsc_changed = false; }\r
+\r
+private:\r
+       std::string m_app_id;\r
+       int m_cb_count;\r
+\r
+       int m_max_width = 0;\r
+       int m_max_height = 0;\r
+       int m_max_framerate = 0;\r
+       bool m_max_rsz_changed = false;\r
+       bool m_audio_rsc_changed = false;\r
+};\r
+\r
+#endif //__TC_APP_H__
\ No newline at end of file
diff --git a/ut/inc/TCPlayer.h b/ut/inc/TCPlayer.h
new file mode 100644 (file)
index 0000000..d043430
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef __TC_PLAYER_H__\r
+#define __TC_PLAYER_H__\r
+\r
+#include <string>\r
+#include <map>\r
+#include <rm_api.h>\r
+\r
+class TCResource;\r
+class TCPlayer\r
+{\r
+public:\r
+       TCPlayer();\r
+       TCPlayer(std::string app_id) { m_app_id = app_id; }\r
+       ~TCPlayer();\r
+\r
+       static rm_cb_result ConflictCb(int handle, rm_callback_type event, rm_device_request_s *info, void* data);\r
+       int Register(void);\r
+       int Unregister(void);\r
+\r
+       int SetPriority(int priority);\r
+       int SetAppId(std::string app_id);\r
+       void SetCustomHandle(int handle) { m_handle = handle;}\r
+\r
+       int GetHandle(void) { return m_handle; }\r
+       std::string GetAppId(void) { return m_app_id; }\r
+       int AddResource(int category_id, int state);\r
+       int AddResource(int category_id, int category_option, int state);\r
+       void RemoveResources(void);\r
+       int GetAudioCategory(std::string codec_name, int mixing_mode);\r
+       int GetCapableVideoCategory(std::string codec_name, int h_size, int v_size, int color_depth, int sampling_format, int framerate);\r
+       int GetCapableCategoryIdFromRC(int category_id);\r
+\r
+       int AddQuery(int category_id, int category_option, int state);\r
+       void RemoveQueries(void);\r
+       int Query(int query_type, int *ans);\r
+\r
+       void AddAllocatedResource(int device_id);\r
+       int AllocateResources(void);\r
+       int ReleaseResources(void);\r
+       int ReleaseResource(int index);\r
+       int GetAllocatedResourceId(int index);\r
+       int GetAllocatedResourcesNum(void) { return m_allocated_resources.size(); }\r
+\r
+       void IncreaseConflictNum(void) { m_n_conflict++; }\r
+       int GetConflictNum(void) { return m_n_conflict; }\r
+       void SetConflictedResourcesNum(int n) { m_n_conflicted_rsc = n; }\r
+       int GetConflictedResourcesNum(void) { return m_n_conflicted_rsc; }\r
+\r
+       int GetActiveAudioOut(void);\r
+\r
+private:\r
+       std::map<int, int> m_allocated_resources;\r
+       std::map<int, TCResource*> m_requested_resources;\r
+       std::map<int, TCResource*> m_queries;\r
+\r
+       std::string m_app_id;\r
+       int m_handle;\r
+       int m_rsc_index;\r
+       int m_query_index;\r
+       int m_allocated_rsc_index;\r
+       int m_n_conflict;\r
+       int m_n_conflicted_rsc;\r
+};\r
+\r
+#endif //__TC_PLAYER_H__
\ No newline at end of file
diff --git a/ut/inc/TCResource.h b/ut/inc/TCResource.h
new file mode 100644 (file)
index 0000000..545b5af
--- /dev/null
@@ -0,0 +1,36 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef __TC_RESOURCE_H__\r
+#define __TC_RESOURCE_H__\r
+\r
+class TCResource\r
+{\r
+public:\r
+       TCResource(int category_id, int category_option, int state);\r
+       ~TCResource();\r
+\r
+       int GetCategoryId(void) {return m_category_id;}\r
+       int GetCategoryOption(void) {return m_category_option;}\r
+       int GetState(void) {return m_state;}\r
+\r
+private:\r
+       int m_category_id;\r
+       int m_category_option;\r
+       int m_state;\r
+};\r
+\r
+#endif //__TC_RESOURCE_H__
\ No newline at end of file
diff --git a/ut/inc/tomatoGtest.h b/ut/inc/tomatoGtest.h
new file mode 100644 (file)
index 0000000..2fda25e
--- /dev/null
@@ -0,0 +1,99 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+//invoke Tomato LIB\r
+#ifndef __TOMATO_GTEST_H__\r
+#define __TOMATO_GTEST_H__\r
+\r
+#include "TomatoAPI.h"\r
+\r
+//Set TC-config to tomato via Gtest macro\r
+#undef GTEST_TEST_\r
+#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\\r
+class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\\r
+ public:\\r
+  GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\\r
+ private:\\r
+  virtual void TestBody();\\r
+  virtual void TestBody_();\\r
+  static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\\r
+  GTEST_DISALLOW_COPY_AND_ASSIGN_(\\r
+      GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\\r
+};\\r
+\\r
+::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\\r
+  ::test_info_ =\\r
+    ::testing::internal::MakeAndRegisterTestInfo(\\r
+        #test_case_name, #test_name, NULL, NULL, \\r
+        (parent_id), \\r
+        parent_class::SetUpTestCase, \\r
+        parent_class::TearDownTestCase, \\r
+        new ::testing::internal::TestFactoryImpl<\\r
+            GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\\r
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()\\r
+{\\r
+  CTomatoAPI::BeginTestCase(#test_name);\\r
+  this->TestBody_();\\r
+  CTomatoAPI::EndTestCase();\\r
+}\\r
+void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody_()\r
+\r
+// Re-define Gtest macro for redirecting gtest-report to tomato\r
+/*\r
+       EXPECT_EQ\r
+       ASSERT_EQ\r
+\r
+       @ refer to "gtest_pred_impl.h"\r
+*/\r
+// parvin.kumar\r
+\r
+#undef GTEST_PRED_FORMAT2_\r
+#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\\r
+               GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), v2, on_failure) \\r
+\r
+#undef GTEST_ASSERT_\r
+#define GTEST_ASSERT_(expression, v2, on_failure) \\r
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \\r
+  if (const ::testing::AssertionResult gtest_ar = (expression)) {\\r
+    CTomatoAPI::WriteTestResult( #v2, true , "success"); { \\r
+  else \\r
+    { on_failure(gtest_ar.failure_message()); \\r
+           CTomatoAPI::WriteTestResult( #v2, false , gtest_ar.failure_message()); {\r
+\r
+\r
+/*\r
+       EXPECT_TRUE   : return TRUE   -> PASS\r
+       EXPECT_FALSE  : return FALSE -> PASS\r
+       ASSERT_TRUE\r
+       ASSERT_FALSE\r
+*/\r
+\r
+\r
+// Implements Boolean test assertions such as EXPECT_TRUE. expression can be\r
+// either a boolean expression or an AssertionResult. text is a textual\r
+// representation of expression as it was passed into the EXPECT_TRUE.\r
+#undef GTEST_TEST_BOOLEAN_\r
+#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \\r
+  GTEST_AMBIGUOUS_ELSE_BLOCKER_ \\r
+  if (const ::testing::AssertionResult gtest_ar_ = \\r
+      ::testing::AssertionResult(expression)) {\\r
+         CTomatoAPI::WriteTestResult( text, true , "success"); { \\r
+  else {\\r
+    fail(::testing::internal::GetBoolAssertionFailureMessage(gtest_ar_, text, #actual, #expected).c_str());\\r
+         CTomatoAPI::WriteTestResult( test, false , ::testing::internal::GetBoolAssertionFailureMessage(gtest_ar_, text, #actual, #expected).c_str()); {\r
+\r
+\r
+#endif //__TOMATO_GTEST_H__\r
diff --git a/ut/inc/ut_log.h b/ut/inc/ut_log.h
new file mode 100644 (file)
index 0000000..572fdd4
--- /dev/null
@@ -0,0 +1,31 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef __UT_LOG_H__\r
+#define __UT_LOG_H__\r
+\r
+#include <dlog.h>\r
+\r
+#ifdef LOG_TAG\r
+#undef LOG_TAG\r
+#endif//LOG_TAG\r
+\r
+#define LOG_TAG "RSC_CENTER_TC"\r
+#define RC_TEST_ERR(fmt, ...) LOGE(fmt, ##__VA_ARGS__)\r
+#define RC_TEST_INFO(fmt, ...) LOGI(fmt, ##__VA_ARGS__)\r
+#define RC_TEST_DBG(fmt, ...) LOGD(fmt, ##__VA_ARGS__)\r
+\r
+#endif //__UT_LOG_H__
\ No newline at end of file
diff --git a/ut/inc/ut_util.h b/ut/inc/ut_util.h
new file mode 100644 (file)
index 0000000..40fd3b3
--- /dev/null
@@ -0,0 +1,103 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#ifndef __UT_UTIL_H__\r
+#define __UT_UTIL_H__\r
+#include <glib.h>\r
+#include <rm_api.h>\r
+#include <ri-api.h>\r
+\r
+int AddZoneInfo(int category_id, int zone_id);\r
+\r
+class CResourceManagerAPI\r
+{\r
+public:\r
+\r
+       typedef enum {\r
+               CB_NORMAL = 0,\r
+               CB_COUNT\r
+       } cb_option;\r
+\r
+       static CResourceManagerAPI* GetInstance();\r
+       static gboolean SetAppZoneIdAsync(gpointer data);\r
+       static gboolean SetAudioFocusAsync(gpointer data);\r
+\r
+       void Reset(void);\r
+       int RegisterPlayer(int cb_option, int expected);\r
+       int RegisterPlayer(std::string app_id, int cb_option, int expected);\r
+       int SetAppZoneIdAsync(std::string app_id, int zone_id, int sleep_sec);\r
+       int SetAudioFocusAsync(int zone_id, int sleep_sec);\r
+\r
+private:\r
+       CResourceManagerAPI() = default;\r
+       ~CResourceManagerAPI() = default;\r
+\r
+       rm_resource_cb GetConflictCB(int option);\r
+       static rm_cb_result ConflictCB(int handle, rm_callback_type event, rm_device_request_s *info, void* data);\r
+       static rm_cb_result ConflictCBCount(int handle, rm_callback_type event, rm_device_request_s *info, void* data);\r
+\r
+       static CResourceManagerAPI* m_instance;\r
+       int m_conflict_count;\r
+};\r
+\r
+\r
+class CVideoCategory\r
+{\r
+public:\r
+       CVideoCategory();\r
+       ~CVideoCategory() = default;\r
+\r
+       void SetProperties(std::string name, int width, int height, int framerate, int color_depth, int sampling);\r
+       ri_video_category_option_request_s* Build(void);\r
+       int GetCapableCategoryId(void);\r
+\r
+private:\r
+       void ResetProperties(void);\r
+       ri_video_category_option_request_s m_option;\r
+};\r
+\r
+class CAppInfo{\r
+public:\r
+       CAppInfo() = default;\r
+       ~CAppInfo() = default;\r
+\r
+       void SetAppId(std::string app_id) {m_app_id = app_id;}\r
+       std::string GetAppId(void) {return m_app_id;}\r
+       void SetZoneId(int id) {m_zone_id = id;}\r
+       int GetZoneId(void) {return m_zone_id;}\r
+       void SetSleep(int sec) {m_sleep = sec;}\r
+       int GetSleep(void) {return m_sleep;}\r
+\r
+private:\r
+       std::string m_app_id;\r
+       int m_zone_id;\r
+       int m_sleep;\r
+};\r
+\r
+class CFocusInfo{\r
+public:\r
+       CFocusInfo() = default;\r
+       ~CFocusInfo() = default;\r
+\r
+       void SetZoneId(int id) {m_zone_id = id;}\r
+       int GetZoneId(void) {return m_zone_id;}\r
+       void SetSleep(int sec) {m_sleep = sec;}\r
+       int GetSleep(void) {return m_sleep;}\r
+private:\r
+       int m_sleep;\r
+       int m_zone_id;\r
+};\r
+#endif //__UT_UTIL_H__
\ No newline at end of file
diff --git a/ut/src/testcase/TCApp.cpp b/ut/src/testcase/TCApp.cpp
new file mode 100644 (file)
index 0000000..f00bfd8
--- /dev/null
@@ -0,0 +1,74 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "gtest/gtest.h"\r
+#include <resource_center.h>\r
+#include "TCApp.h"\r
+\r
+TCApp::TCApp(const char* app_id)\r
+{\r
+       if (app_id)\r
+               m_app_id.assign(app_id);\r
+       else\r
+               m_app_id.assign("");\r
+\r
+       m_cb_count = 0;\r
+\r
+       m_max_width = 0;\r
+       m_max_height = 0;\r
+       m_max_framerate = 0;\r
+}\r
+\r
+TCApp::~TCApp()\r
+{\r
+}\r
+\r
+void TCApp::ResourceChangedCb(const char* app_id, rc_resource_h rsc, void *data)\r
+{\r
+       int w;\r
+       int h;\r
+       int f;\r
+\r
+       if (!data)\r
+               return;\r
+\r
+       TCApp* app = (TCApp*) data;\r
+       app->IncreaseCbCount();\r
+\r
+       EXPECT_STREQ(app->GetAppId().c_str(), app_id);\r
+\r
+       if (rc_rsc_max_resolution_changed(rsc))\r
+       {\r
+               EXPECT_EQ(0, rc_rsc_get_video_max_resolution(rsc, &w, &h, &f));\r
+               app->SetMaxResolution(w, h, f);\r
+               app->SetMaxRszChanged(true);\r
+       }\r
+\r
+       if (rc_rsc_audio_out_changed(rsc))\r
+       {\r
+               app->SetAudioRscChanged(true);\r
+       }\r
+}\r
+\r
+int TCApp::RegisterResourceChangeCb(void)\r
+{\r
+       return rc_register_resource_change_callback(m_app_id.c_str(), TCApp::ResourceChangedCb, this);\r
+}\r
+\r
+int TCApp::UnregisterResourceChangeCb(void)\r
+{\r
+       return rc_unregister_resource_change_callback(m_app_id.c_str(), TCApp::ResourceChangedCb);\r
+}
\ No newline at end of file
diff --git a/ut/src/testcase/TCPlayer.cpp b/ut/src/testcase/TCPlayer.cpp
new file mode 100644 (file)
index 0000000..3cb81ae
--- /dev/null
@@ -0,0 +1,284 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "gtest/gtest.h"\r
+#include <rm_api.h>\r
+#include <rm_module_api.h>\r
+#include <ut_log.h>\r
+#include <ri-api.h>\r
+#include <ri-module-api.h>\r
+#include <resource_center.h>\r
+#include "TCResource.h"\r
+#include "TCPlayer.h"\r
+\r
+TCPlayer::TCPlayer()\r
+{\r
+       m_handle = 0;\r
+       m_allocated_rsc_index = 0;\r
+       m_rsc_index = 0;\r
+       m_query_index = 0;\r
+       m_n_conflict = 0;\r
+       m_n_conflicted_rsc = 0;\r
+}\r
+\r
+TCPlayer::~TCPlayer()\r
+{\r
+       Unregister();\r
+}\r
+\r
+rm_cb_result TCPlayer::ConflictCb(int handle, rm_callback_type event, rm_device_request_s *info, void* data)\r
+{\r
+       if (!data)\r
+               return RM_CB_RESULT_ERROR;\r
+\r
+       TCPlayer *player = (TCPlayer*) data;\r
+       player->IncreaseConflictNum();\r
+       player->SetConflictedResourcesNum(info->request_num);\r
+\r
+       rm_deallocate_resources(handle, info);\r
+\r
+       return RM_CB_RESULT_OK;\r
+}\r
+\r
+int TCPlayer::Register(void)\r
+{\r
+       if (m_handle != 0)\r
+               return RM_ERROR;\r
+\r
+       return rm_register(TCPlayer::ConflictCb, this, &m_handle, NULL);\r
+}\r
+\r
+int TCPlayer::Unregister(void)\r
+{\r
+       int result = RM_ERROR;;\r
+\r
+       RemoveResources();\r
+       RemoveQueries();\r
+       m_allocated_resources.clear();\r
+\r
+       result = rm_unregister(m_handle);\r
+       m_handle = 0;\r
+\r
+       return result;\r
+}\r
+\r
+int TCPlayer::SetPriority(int priority)\r
+{\r
+       return rm_set_priority(m_handle, priority);\r
+}\r
+\r
+int TCPlayer::SetAppId(std::string app_id)\r
+{\r
+       m_app_id = app_id;\r
+       return rm_set_app_id(m_handle, (char*) app_id.c_str());\r
+}\r
+\r
+int TCPlayer::AddResource(int category_id, int state)\r
+{\r
+       TCResource* rsc = new TCResource(category_id, 0, state);\r
+       m_rsc_index++;\r
+       m_requested_resources.insert(std::pair<int, TCResource*>(m_rsc_index, rsc));\r
+       return 0;\r
+}\r
+\r
+int TCPlayer::AddResource(int category_id, int category_option, int state)\r
+{\r
+       TCResource* rsc = new TCResource(category_id, category_option, state);\r
+       m_rsc_index++;\r
+       m_requested_resources.insert(std::pair<int, TCResource*>(m_rsc_index, rsc));\r
+       return 0;\r
+}\r
+\r
+int TCPlayer::AddQuery(int category_id, int category_option, int state)\r
+{\r
+       TCResource* rsc = new TCResource(category_id, category_option, state);\r
+       m_query_index++;\r
+       m_queries.insert(std::pair<int, TCResource*>(m_query_index, rsc));\r
+       return 0;\r
+}\r
+\r
+void TCPlayer::RemoveResources(void)\r
+{\r
+       TCResource *rsc = nullptr;\r
+\r
+       for (auto &it : m_requested_resources) {\r
+               rsc = it.second;\r
+               if (rsc)\r
+                       delete rsc;\r
+       }\r
+       m_requested_resources.clear();\r
+       m_rsc_index = 0;\r
+}\r
+\r
+int TCPlayer::GetAudioCategory(std::string codec_name, int mixing_mode)\r
+{\r
+       ri_audio_category_option_request_s audio_option;\r
+       memset(&audio_option, 0, sizeof(ri_audio_category_option_request_s));\r
+\r
+       audio_option.codec_name = codec_name.c_str();\r
+       audio_option.mixing_mode = (ri_audio_mixing_mode) mixing_mode;\r
+\r
+       return ri_get_capable_audio_category_id(&audio_option);\r
+}\r
+\r
+int TCPlayer::GetCapableVideoCategory(std::string codec_name, int h_size, int v_size, int color_depth, int sampling_format, int framerate)\r
+{\r
+       ri_video_category_option_request_s opt;\r
+       memset(&opt, 0, sizeof(ri_video_category_option_request_s));\r
+\r
+       opt.codec_name = strndup(codec_name.c_str(), codec_name.length());\r
+       opt.color_depth = color_depth;\r
+       opt.framerate = framerate;\r
+       opt.h_size = h_size;\r
+       opt.v_size = v_size;\r
+       opt.sampling_format = sampling_format;\r
+\r
+       return ri_get_capable_video_category_id(&opt);\r
+}\r
+\r
+int TCPlayer::GetCapableCategoryIdFromRC(int category_id)\r
+{\r
+       return rc_get_capable_category_id(m_handle, m_app_id.c_str(), category_id);\r
+}\r
+\r
+int TCPlayer::Query(int query_type, int *ans)\r
+{\r
+       rm_category_request_s req;\r
+       memset(&req, 0, sizeof(rm_category_request_s));\r
+\r
+       int i = 0;\r
+       int result = RM_ERROR;\r
+       int answer;\r
+\r
+       req.request_num = m_queries.size();\r
+\r
+       for (auto &it : m_queries) {\r
+               TCResource *rsc = it.second;\r
+               req.category_id[i] = (rm_rsc_category_e) rsc->GetCategoryId();\r
+               req.category_option[i] = rsc->GetCategoryOption();\r
+               req.state[i] = (rm_requests_resource_state_e) rsc->GetState();\r
+               i++;\r
+       }\r
+\r
+       result = rm_query(m_handle, (rm_query_type_e) query_type, &req, &answer);\r
+       *ans = answer;\r
+\r
+       return result;\r
+}\r
+\r
+void TCPlayer::RemoveQueries(void)\r
+{\r
+       TCResource *rsc = nullptr;\r
+\r
+       for (auto &it : m_queries) {\r
+               rsc = it.second;\r
+               if (rsc)\r
+                       delete rsc;\r
+       }\r
+       m_queries.clear();\r
+}\r
+\r
+void TCPlayer::AddAllocatedResource(int device_id)\r
+{\r
+       m_allocated_resources.insert(std::pair<int, int>(++m_allocated_rsc_index, device_id));\r
+}\r
+\r
+int TCPlayer::GetAllocatedResourceId(int index)\r
+{\r
+       auto it = m_allocated_resources.find(index);\r
+\r
+       return (it == m_allocated_resources.end()) ? -1 : it->second;\r
+}\r
+\r
+int TCPlayer::AllocateResources(void)\r
+{\r
+       if (m_requested_resources.size() == 0)\r
+               return RM_ERROR;\r
+\r
+       int i = 0;\r
+       int result = RM_ERROR;\r
+\r
+       rm_category_request_s req;\r
+       memset(&req, 0, sizeof(rm_category_request_s));\r
+\r
+       req.request_num = m_requested_resources.size();\r
+\r
+       for (auto &it : m_requested_resources) {\r
+               TCResource *rsc = it.second;\r
+               req.category_id[i] = (rm_rsc_category_e) rsc->GetCategoryId();\r
+               req.category_option[i] = rsc->GetCategoryOption();\r
+               req.state[i] = (rm_requests_resource_state_e) rsc->GetState();\r
+               i++;\r
+       }\r
+\r
+       rm_device_return_s allocated;\r
+       memset(&allocated, 0, sizeof(allocated));\r
+\r
+       result = rm_allocate_resources(m_handle, &req, &allocated);\r
+\r
+       if (result == RM_OK) {\r
+               for (int j = 0; j < allocated.allocated_num; j++)\r
+                       AddAllocatedResource(allocated.device_id[j]);\r
+       }\r
+\r
+       return result;\r
+}\r
+\r
+int TCPlayer::ReleaseResources(void)\r
+{\r
+       if (m_allocated_resources.size() <= 0)\r
+               return RM_ERROR;\r
+\r
+       int i = 0;\r
+       rm_device_request_s req;\r
+       memset(&req, 0, sizeof(req));\r
+\r
+       req.request_num = m_allocated_resources.size();\r
+\r
+       for (auto &it : m_allocated_resources) {\r
+               req.device_id[i] = it.second;\r
+               i++;\r
+       }\r
+\r
+       m_allocated_resources.clear();\r
+       m_allocated_rsc_index = 0;\r
+\r
+       return rm_deallocate_resources(m_handle, &req);\r
+}\r
+\r
+int TCPlayer::ReleaseResource(int index)\r
+{\r
+       if (m_allocated_resources.size() <= 0)\r
+               return RM_ERROR;\r
+\r
+       auto it = m_allocated_resources.find(index);\r
+       int device_id = (it == m_allocated_resources.end()) ? -1 : it->second;\r
+\r
+       rm_device_request_s req;\r
+       memset(&req, 0, sizeof(req));\r
+\r
+       req.request_num = 1;\r
+       req.device_id[0] = device_id;\r
+\r
+       m_allocated_resources.erase(index);\r
+\r
+       return rm_deallocate_resources(m_handle, &req);\r
+}\r
+\r
+int TCPlayer::GetActiveAudioOut(void)\r
+{\r
+       return rm_get_active_audio_out(m_handle);\r
+}\r
diff --git a/ut/src/testcase/TCResource.cpp b/ut/src/testcase/TCResource.cpp
new file mode 100644 (file)
index 0000000..c149966
--- /dev/null
@@ -0,0 +1,28 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "TCResource.h"\r
+\r
+TCResource::TCResource(int category_id, int category_option, int state)\r
+{\r
+       m_category_id = category_id;\r
+       m_category_option = category_option;\r
+       m_state = state;\r
+}\r
+\r
+TCResource::~TCResource()\r
+{\r
+}\r
diff --git a/ut/src/testcase/ut_api.cpp b/ut/src/testcase/ut_api.cpp
new file mode 100644 (file)
index 0000000..db08e55
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2024 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 "gtest/gtest.h"
+#include <rm_api.h>
+#include <rm_module_api.h>
+#include <ri-api.h>
+#include <ri-module-api.h>
+#include <resource_center.h>
+
+#include <ut_log.h>
+
+#ifdef TOMATO
+#include "tomatoGtest.h"
+#endif//TOMATO
+
+static void _delay(int sec)
+{
+       sleep(sec);
+}
+
+TEST(UT_RSC, rc_set_resource_policy_p1)
+{
+       RC_TEST_INFO("rc_set_resource_policy_p1 start...");
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_NORMAL));
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_N_DECODING_MV));
+       RC_TEST_INFO("rc_set_resource_policy_p1 end...");
+       _delay(1);
+}
+
+TEST(UT_RSC, rc_set_resource_policy_n1)
+{
+
+       RC_TEST_INFO("rc_set_resource_policy_n1 start...");
+       rc_rsc_policy_e val = (rc_rsc_policy_e) -1;
+       EXPECT_NE(0, rc_set_resource_policy(val));
+
+       val = (rc_rsc_policy_e) 100;
+       EXPECT_NE(0, rc_set_resource_policy(val));
+       RC_TEST_INFO("rc_set_resource_policy_n1 end...");
+       _delay(1);
+}
+
+TEST(UT_RSC, rc_get_capable_category_id_p1)
+{
+       /*
+       * Test scenario
+       * App - 3rd party app
+       * Resource policy - Normal
+       * > 1. Set resource policy to Normal
+       * > 2. Get category id of video scaler
+       * > Expected Result
+       *   - The passed value shall be returned
+       */
+       RC_TEST_INFO("rc_get_capable_category_id_p1 start...");
+
+       int category = RM_CATEGORY_SCALER;
+       const char* app_id = "org.tizen.test";
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_NORMAL));
+       EXPECT_EQ(category, rc_get_capable_category_id(100, app_id, category));
+
+       RC_TEST_INFO("rc_get_capable_category_id_p1 end...");
+       _delay(1);
+}
+
+TEST(UT_RSC, rc_get_capable_category_id_p2)
+{
+       // Check return values for the categories not interested in
+       RC_TEST_INFO("rc_get_capable_category_id_p2 start...");
+
+       int category = RM_CATEGORY_TUNER;
+       const char* app_id = "org.tizen.test";
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_N_DECODING_MV));
+
+       EXPECT_EQ(category, rc_get_capable_category_id(100, app_id, category));
+
+       category = RM_CATEGORY_EXT_AUDIO_SRC_HDMI;
+       EXPECT_EQ(category, rc_get_capable_category_id(100, app_id, category));
+
+       category = RM_CATEGORY_VIDEO_ENCODER;
+       EXPECT_EQ(category, rc_get_capable_category_id(100, app_id, category));
+
+       category = RM_CATEGORY_EXT_HDMI_SRC;
+       EXPECT_EQ(category, rc_get_capable_category_id(100, app_id, category));
+
+       RC_TEST_INFO("rc_get_capable_category_id_p2 end...");
+       _delay(1);
+}
+
+TEST(UT_RSC, rc_get_capable_category_id_p3)
+{
+       RC_TEST_INFO("rc_get_capable_category_id_p3 start...");
+
+       const char* app_id = "org.tizen.tv-viewer";
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_NORMAL));
+
+       ri_category_option_request_s req;
+       memset(&req, 0, sizeof(ri_category_option_request_s));
+
+       req.codec_name = RI_CODEC_NAME_HEVC;
+       req.preferred_mode = RI_TVP_VDEC_MODE_SPECIFIC;
+
+       ri_category_option_return_s result;
+       memset(&result, 0, sizeof(ri_category_option_return_s));
+
+       EXPECT_EQ(0, ri_get_video_category_id_by_codec(&req, &result));
+       EXPECT_EQ(RI_CATEGORY_VIDEO_DECODER_HEVC_FHD_8BIT_30P, result.category_option);
+       EXPECT_EQ(result.category_option, rc_get_capable_category_id(100, app_id, result.category_option));
+
+       RC_TEST_INFO("rc_get_capable_category_id_p3 end...");
+       _delay(1);
+}
+
+static void max_rez_change_cb(const char* app_id, int width, int height, int framerate, void* data)
+{
+
+}
+
+TEST(UT_RSC, rc_register_max_video_resolution_changed_callback_p1)
+{
+       RC_TEST_INFO("rc_register_max_video_resolution_changed_callback_p1 start...");
+
+       const char* app_id = "com.samsung.tv.cobalt";
+
+       EXPECT_EQ(0, rc_register_max_video_resolution_changed_callback(app_id, max_rez_change_cb, NULL));
+       EXPECT_EQ(0, rc_unregister_max_video_resolution_changed_callback(app_id, max_rez_change_cb));
+
+       RC_TEST_INFO("rc_register_max_video_resolution_changed_callback_p1 end...");
+}
+
+TEST(UT_RSC, rc_register_max_video_resolution_changed_callback_n1)
+{
+       RC_TEST_INFO("rc_register_max_video_resolution_changed_callback_n1 start...");
+
+       const char* app_id = "com.samsung.tv.cobalt";
+
+       EXPECT_NE(0, rc_unregister_max_video_resolution_changed_callback(app_id, max_rez_change_cb));
+       EXPECT_EQ(0, rc_register_max_video_resolution_changed_callback(app_id, max_rez_change_cb, NULL));
+       EXPECT_EQ(0, rc_unregister_max_video_resolution_changed_callback(app_id, max_rez_change_cb));
+       EXPECT_NE(0, rc_unregister_max_video_resolution_changed_callback(app_id, max_rez_change_cb));
+
+       RC_TEST_INFO("rc_register_max_video_resolution_changed_callback_n1 end...");
+}
+
+TEST(UT_RSC, rc_register_max_video_resolution_changed_callback_n2)
+{
+       RC_TEST_INFO("rc_register_max_video_resolution_changed_callback_n2 start...");
+
+       const char* app_id = "com.samsung.tv.cobalt";
+
+       EXPECT_NE(0, rc_register_max_video_resolution_changed_callback(NULL, max_rez_change_cb, NULL));
+       EXPECT_NE(0, rc_register_max_video_resolution_changed_callback(app_id, NULL, NULL));
+
+       EXPECT_NE(0, rc_unregister_max_video_resolution_changed_callback(NULL, max_rez_change_cb));
+       EXPECT_NE(0, rc_unregister_max_video_resolution_changed_callback(app_id, NULL));
+
+       RC_TEST_INFO("rc_register_max_video_resolution_changed_callback_n2 end...");
+}
+
+TEST(UT_RSC, rc_get_capable_category_id_p4)
+{
+       RC_TEST_INFO("rc_get_capable_category_id_p4 start...");
+
+       const char* app_id = "";
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_N_DECODING_MV));
+
+       // app id shall be a valid application id in N Decoding MV
+       EXPECT_EQ(RI_CATEGORY_NOT_PERMITTED, rc_get_capable_category_id(100, app_id, RI_CATEGORY_VIDEO_DECODER_MPEG1_FHD_8BIT_30P));
+       EXPECT_EQ(RI_CATEGORY_NOT_PERMITTED, rc_get_capable_category_id(100, app_id, RI_CATEGORY_AUDIO_MAIN_OUT));
+       EXPECT_EQ(RI_CATEGORY_NOT_PERMITTED, rc_get_capable_category_id(100, app_id, RI_CATEGORY_AUDIO_DECODER_AC4));
+       EXPECT_EQ(RI_CATEGORY_NOT_PERMITTED, rc_get_capable_category_id(100, app_id, RI_CATEGORY_SCALER));
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_NORMAL));
+
+       RC_TEST_INFO("rc_get_capable_category_id_p4 end...");
+}
+
+TEST(UT_RSC, rc_get_capable_category_id_p5)
+{
+       RC_TEST_INFO("rc_get_capable_category_id_p5 start...");
+
+       const char* app_id = "";
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_NORMAL));
+
+       // In case app id is invalid, return the passed value as it is
+       EXPECT_EQ(RI_CATEGORY_VIDEO_DECODER_MPEG1_FHD_8BIT_30P, rc_get_capable_category_id(100, app_id, RI_CATEGORY_VIDEO_DECODER_MPEG1_FHD_8BIT_30P));
+       EXPECT_EQ(RI_CATEGORY_AUDIO_MAIN_OUT, rc_get_capable_category_id(100, app_id, RI_CATEGORY_AUDIO_MAIN_OUT));
+       EXPECT_EQ(RI_CATEGORY_AUDIO_DECODER_AC4, rc_get_capable_category_id(100, app_id, RI_CATEGORY_AUDIO_DECODER_AC4));
+       EXPECT_EQ(RI_CATEGORY_SCALER, rc_get_capable_category_id(100, app_id, RI_CATEGORY_SCALER));
+
+       RC_TEST_INFO("rc_get_capable_category_id_p5 end...");
+}
+
+TEST(UT_RSC, rc_get_capable_category_id_p6)
+{
+       RC_TEST_INFO("rc_get_capable_category_id_p6 start...");
+
+       const char* app_id = "org.tizen.tv-viewer";
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_NORMAL));
+
+       // In case resource policy is normal, return the passed value as it is
+       EXPECT_EQ(RI_CATEGORY_NONE, rc_get_capable_category_id(100, app_id, RI_CATEGORY_NONE));
+
+       RC_TEST_INFO("rc_get_capable_category_id_p6 end...");
+}
+
+TEST(UT_RSC, rc_get_capable_category_id_p7)
+{
+       RC_TEST_INFO("rc_get_capable_category_id_p7 start...");
+
+       const char* app_id = "org.tizen.tv-viewer";
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_N_DECODING_MV));
+
+       // In case resource policy is n-decoding, return Not permitted value shall be returned
+       EXPECT_EQ(RI_CATEGORY_NOT_PERMITTED, rc_get_capable_category_id(100, app_id, RI_CATEGORY_NONE));
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_NORMAL));
+
+       RC_TEST_INFO("rc_get_capable_category_id_p7 end...");
+}
+
+TEST(UT_RSC, rc_get_focused_zone_info_p1)
+{
+       RC_TEST_INFO("rc_get_focused_zone_info_p1 start...");
+
+       const char* app_id = "org.tizen.rc_test";
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_N_DECODING_MV));
+       EXPECT_EQ(0, rc_set_app_zone_info(app_id, 1));
+       EXPECT_EQ(0, rc_set_audio_focus(1));
+
+       rc_zone_h zone_info;
+       EXPECT_EQ(0, rc_get_focused_zone(&zone_info));
+
+       EXPECT_EQ(1, rc_zone_get_id(zone_info));
+       EXPECT_EQ(-1, rc_zone_get_scaler_id(zone_info));
+       EXPECT_STREQ(app_id, rc_zone_get_app_id(zone_info));
+
+       rc_zone_free(zone_info);
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_NORMAL));
+
+       RC_TEST_INFO("rc_get_focused_zone_info_p1 end...");
+}
+
+TEST(UT_RSC, rc_get_focused_zone_info_n1)
+{
+       RC_TEST_INFO("rc_get_focused_zone_info_n1 start...");
+
+       rc_zone_h zone_info;
+       EXPECT_EQ(0, rc_get_focused_zone(&zone_info));
+
+       EXPECT_EQ(0, rc_zone_get_id(zone_info));
+       EXPECT_EQ(-1, rc_zone_get_scaler_id(zone_info));
+       EXPECT_STREQ("", rc_zone_get_app_id(zone_info));
+
+       rc_zone_free(zone_info);
+
+       EXPECT_EQ(0, rc_set_resource_policy(RC_RSC_POLICY_NORMAL));
+       RC_TEST_INFO("rc_get_focused_zone_info_n1 end...");
+}
+
+static void rsc_change_cb(const char* app_id, rc_resource_h rsc, void* data)
+{
+
+}
+
+TEST(UT_RSC, rc_register_resource_change_callback_p1)
+{
+       RC_TEST_INFO("rc_register_resource_change_callback_p1 start...");
+       const char* app_id = "org.tizen.rc_test";
+       EXPECT_EQ(0, rc_register_resource_change_callback(app_id, rsc_change_cb, NULL));
+       EXPECT_EQ(0, rc_unregister_resource_change_callback(app_id, rsc_change_cb));
+       RC_TEST_INFO("rc_register_resource_change_callback_p1 end...");
+}
diff --git a/ut/src/testcase/ut_main.cpp b/ut/src/testcase/ut_main.cpp
new file mode 100644 (file)
index 0000000..a0075aa
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2024 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 <stdio.h>
+#include <glib.h>
+#include "gtest/gtest.h"
+
+#include <ut_log.h>
+
+#ifdef TOMATO
+#include "tomatoGtest.h"
+#endif//TOMATO
+
+
+static gpointer tc_run_loop(gpointer data)
+{
+       RC_TEST_INFO("Run callback thread");
+       GMainLoop *main_loop = (GMainLoop*) data;
+
+       if (main_loop != NULL) {
+               g_main_loop_run(main_loop);
+       }
+
+       RC_TEST_INFO("callback thread terminated");
+       return NULL;
+}
+
+GTEST_API_ int main(int argc, char **argv)
+{
+       printf("Running main() from ut_main.cpp\n");
+
+       int ret;
+
+       GMainContext *context = g_main_context_new();
+       GMainLoop *main_loop = g_main_loop_new(context, FALSE);
+       GThread *cb_thread = g_thread_new("rc_cb_thread", tc_run_loop, main_loop);
+
+       if (cb_thread == NULL) {
+               g_main_loop_unref(main_loop);
+               RC_TEST_ERR("failed to create the callback thread");
+       }
+
+       testing::InitGoogleTest(&argc, argv);
+
+       ret = RUN_ALL_TESTS();
+
+       return ret;
+}
diff --git a/ut/src/testcase/ut_util.cpp b/ut/src/testcase/ut_util.cpp
new file mode 100644 (file)
index 0000000..4d833dc
--- /dev/null
@@ -0,0 +1,169 @@
+/*\r
+ * Copyright (c) 2024 Samsung Electronics Co., Ltd All Rights Reserved\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "gtest/gtest.h"\r
+#include <rm_api.h>\r
+#include <resource_center.h>\r
+#include <ut_util.h>\r
+\r
+CResourceManagerAPI* CResourceManagerAPI::m_instance = NULL;\r
+\r
+CResourceManagerAPI* CResourceManagerAPI::GetInstance()\r
+{\r
+       if (!m_instance)\r
+               m_instance = new CResourceManagerAPI();\r
+\r
+       return m_instance;\r
+}\r
+\r
+void CResourceManagerAPI::Reset(void)\r
+{\r
+       m_conflict_count = 0;\r
+}\r
+\r
+rm_resource_cb CResourceManagerAPI::GetConflictCB(int option)\r
+{\r
+       if (option == CB_NORMAL)\r
+               return &CResourceManagerAPI::ConflictCB;\r
+\r
+       if (option == CB_COUNT)\r
+               return &CResourceManagerAPI::ConflictCBCount;\r
+\r
+       return &CResourceManagerAPI::ConflictCB;\r
+}\r
+\r
+\r
+rm_cb_result CResourceManagerAPI::ConflictCB(int handle, rm_callback_type event, rm_device_request_s *info, void* data)\r
+{\r
+       rm_unregister(handle);\r
+       return RM_CB_RESULT_OK;\r
+}\r
+\r
+rm_cb_result CResourceManagerAPI::ConflictCBCount(int handle, rm_callback_type event, rm_device_request_s *info, void* data)\r
+{\r
+       CResourceManagerAPI* api = (CResourceManagerAPI*) data;\r
+       api->m_conflict_count++;\r
+       rm_unregister(handle);\r
+       return RM_CB_RESULT_OK;\r
+}\r
+\r
+int CResourceManagerAPI::RegisterPlayer(int option, int expected)\r
+{\r
+       int handle = 0;\r
+\r
+       EXPECT_EQ(expected, rm_register(GetConflictCB(option), this, &handle, NULL));\r
+\r
+       return handle;\r
+}\r
+\r
+int CResourceManagerAPI::RegisterPlayer(std::string app_id, int option, int expected)\r
+{\r
+       return 0;\r
+}\r
+\r
+gboolean CResourceManagerAPI::SetAppZoneIdAsync(gpointer data)\r
+{\r
+       CAppInfo *app_info = (CAppInfo*) data;\r
+       sleep(app_info->GetSleep());\r
+       EXPECT_EQ(0, rc_set_app_zone_info(app_info->GetAppId().c_str(), app_info->GetZoneId()));\r
+       delete app_info;\r
+       return G_SOURCE_REMOVE;\r
+}\r
+\r
+int CResourceManagerAPI::SetAppZoneIdAsync(std::string app_id, int zone_id, int sleep_sec)\r
+{\r
+       CAppInfo *app_info = new CAppInfo();\r
+       app_info->SetAppId(app_id);\r
+       app_info->SetZoneId(zone_id);\r
+       app_info->SetSleep(sleep_sec);\r
+\r
+       g_idle_add(&CResourceManagerAPI::SetAppZoneIdAsync, app_info);\r
+       return 0;\r
+}\r
+\r
+gboolean CResourceManagerAPI::SetAudioFocusAsync(gpointer data)\r
+{\r
+       CFocusInfo *focus_info = (CFocusInfo*) data;\r
+       sleep(focus_info->GetSleep());\r
+       EXPECT_EQ(0, rc_set_audio_focus(focus_info->GetZoneId()));\r
+       delete focus_info;\r
+       return G_SOURCE_REMOVE;\r
+}\r
+\r
+int CResourceManagerAPI::SetAudioFocusAsync(int zone_id, int sleep_sec)\r
+{\r
+       CFocusInfo *focus_info = new CFocusInfo();\r
+       focus_info->SetZoneId(zone_id);\r
+       focus_info->SetSleep(sleep_sec);\r
+\r
+       g_idle_add(&CResourceManagerAPI::SetAudioFocusAsync, focus_info);\r
+       return 0;\r
+}\r
+\r
+CVideoCategory::CVideoCategory()\r
+{\r
+       m_option.codec_name = NULL;\r
+       m_option.h_size = 0;\r
+       m_option.v_size = 0;\r
+       m_option.framerate = 0;\r
+       m_option.color_depth = 0;\r
+       m_option.sampling_format = 0;\r
+}\r
+\r
+void CVideoCategory::SetProperties(std::string codec, int width, int height, int framerate, int color_depth, int sampling)\r
+{\r
+       ResetProperties();\r
+\r
+       m_option.codec_name = strndup(codec.c_str(), codec.length());\r
+       m_option.h_size = width;\r
+       m_option.v_size = height;\r
+       m_option.framerate = framerate;\r
+       m_option.color_depth = color_depth;\r
+       m_option.sampling_format = sampling;\r
+}\r
+\r
+void CVideoCategory::ResetProperties(void)\r
+{\r
+       if (m_option.codec_name) {\r
+               free((void*) m_option.codec_name);\r
+               m_option.codec_name = NULL;\r
+       }\r
+\r
+       m_option.h_size = 0;\r
+       m_option.v_size = 0;\r
+       m_option.framerate = 0;\r
+       m_option.color_depth = 0;\r
+       m_option.sampling_format = 0;\r
+}\r
+\r
+ri_video_category_option_request_s* CVideoCategory::Build(void)\r
+{\r
+       return &m_option;\r
+}\r
+\r
+int CVideoCategory::GetCapableCategoryId(void)\r
+{\r
+       return ri_get_capable_video_category_id(&m_option);\r
+}\r
+\r
+int AddZoneInfo(int category_id, int zone_id)\r
+{\r
+       const int PM_ZONE_ID_OFFSET = 21;\r
+       int zone_info = (zone_id << PM_ZONE_ID_OFFSET);\r
+\r
+       return (category_id | zone_info);\r
+}\r
+\r
diff --git a/ut/tc/TCList.dat b/ut/tc/TCList.dat
new file mode 100644 (file)
index 0000000..02afde8
--- /dev/null
@@ -0,0 +1 @@
+resource-center.xml
\ No newline at end of file
diff --git a/ut/tc/resource-center.xml b/ut/tc/resource-center.xml
new file mode 100644 (file)
index 0000000..b5ab7ac
--- /dev/null
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<TestCase Name="RESOURCE_CENTER_TEST" Description="RESOURCE_CENTER test" LogFilter="RSC_CENTER:* RSC_CENTER_API:* TOMATOCLIENT:*">
+    <Procedure Number="1" Description="resource center test">
+        <Step Name="start resource center package" Type="EXT_TEST_PACKAGE" Dbus="resource_center_tomato_test_pkg" Permission="ROOT" Command="export COVFILE=/opt/data/vdut/resource_center_ut.cov; /opt/usr/apps/tomato/testcase/resource_center_ut/bin/resource_center_ut --gtest_output=xml:/opt/data/vdut/resource_center_ut.xml">
+            <Input Expirytime="2400" />
+            <Output Type="DetectFile" FilePath="/opt/data/vdut/resource_center_ut.xml" />
+        </Step>
+    </Procedure>
+</TestCase>