From: YoungHun Kim Date: Wed, 12 Jun 2024 10:07:51 +0000 (+0900) Subject: Initial Release X-Git-Tag: accepted/tizen/unified/20240801.021611~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b98b0da77d7119b2d678367ad219a82bca2843fa;p=platform%2Fcore%2Fmultimedia%2Fresource-center-api.git Initial Release Change-Id: I984f34cbfad39ab8426766db25740785cc3948c5 --- diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ea0f807 --- /dev/null +++ b/CMakeLists.txt @@ -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 index 0000000..bbe9d02 --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,206 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. + + + diff --git a/include/resource_center.h b/include/resource_center.h new file mode 100644 index 0000000..b4ed154 --- /dev/null +++ b/include/resource_center.h @@ -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 + +#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 index 0000000..c489c4c --- /dev/null +++ b/include/resource_center_internal.h @@ -0,0 +1,109 @@ +/* + * 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_INTERNAL_H__ +#define __TIZEN_RESOURCE_CENTER_INTERNAL_H__ + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef enum { + RC_AUDIO_OUT_MAIN = 1, /**< audio out main */ + RC_AUDIO_OUT_SUB /**< audio out sub */ +} rc_audio_out_e; + +/** + * @brief Register player + * @param[in] player_id player id + * @param[in] resource_id window resource id + * @return @c 0 on success, otherwise a negative error value + * @pre None + * @post None + * @exception None + */ +int rc_player_register(int player_id, int resource_id); + +/** + * @brief Request play + * @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_player_request_play(int player_id, rc_audio_out_e* audio_out); + +/** + * @brief Request stop + * @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_request_stop(int player_id); + +/** + * @brief Unregister player + * @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_unregister(int player_id); + +/** + * @brief Register external speaker info + * @param[in] info external speaker info + * @param[in] zone_id zone id + * @return @c 0 on success, otherwise a negative error value + * @pre None + * @post None + * @exception None + */ +int rc_extspk_info_register(const char* info, int zone_id); + +/** + * @brief Unegister external speaker info + * @param[in] info external speaker info + * @param[in] zone_id zone id + * @return @c 0 on success, otherwise a negative error value + * @pre None + * @post None + * @exception None + */ +int rc_extspk_info_unregister(const char* info, int zone_id); + +/** + * @brief Register external speaker info + * @param[in] info external speaker info + * @param[out] audio_out audio out of external speaker + * @return @c 0 on success, otherwise a negative error value + * @pre None + * @post None + * @exception None + */ +int rc_get_extspk_info_audio_out(const char* info, int* audio_out); + +#ifdef __cplusplus +} +#endif + +#endif /* __TIZEN_RESOURCE_CENTER_INTERNAL_H__ */ diff --git a/include_internal/resource_center_private.h b/include_internal/resource_center_private.h new file mode 100644 index 0000000..0872da0 --- /dev/null +++ b/include_internal/resource_center_private.h @@ -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 +#include +#include + +#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 index 0000000..7061372 --- /dev/null +++ b/packaging/resource-center-api.spec @@ -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 index 0000000..a76fdba --- /dev/null +++ b/resource-center-api.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/resource-center-api.pc.in b/resource-center-api.pc.in new file mode 100644 index 0000000..109ba27 --- /dev/null +++ b/resource-center-api.pc.in @@ -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 index 0000000..fb6e646 --- /dev/null +++ b/resource-center_tomato.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/src/resource_center.cpp b/src/resource_center.cpp new file mode 100644 index 0000000..a6e4620 --- /dev/null +++ b/src/resource_center.cpp @@ -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 +#include +#include +#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 index 0000000..0c9e3bf --- /dev/null +++ b/src/resource_center_internal.cpp @@ -0,0 +1,75 @@ +/* + * 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 +#include "resource_center_internal.h" +#include "resource_center_private.h" + +int rc_player_register(int player_id, int resource_id) +{ + RC_LOG_INFO(">>"); + + return _rc_player_register(player_id, resource_id); +} + +int rc_player_request_play(int player_id, rc_audio_out_e* audio_out) +{ + RC_LOG_INFO(">>"); + + return _rc_player_request_play(player_id, audio_out); +} + +int rc_player_request_stop(int player_id) +{ + RC_LOG_INFO(">>"); + + return _rc_player_request_stop(player_id); +} + +int rc_player_unregister(int player_id) +{ + RC_LOG_INFO(">>"); + + return _rc_player_unregister(player_id); +} + +int rc_extspk_info_register(const char* info, int zone_id) +{ + RC_LOG_INFO(">>"); + + return _rc_extspk_info_register(info, zone_id); +} + +int rc_extspk_info_unregister(const char* info, int zone_id) +{ + RC_LOG_INFO(">>"); + + return _rc_extspk_info_unregister(info, zone_id); +} + +int rc_get_extspk_info_audio_out(const char* info, int* audio_out) +{ + int ret; + RC_LOG_INFO(">>"); + + ret = _rc_get_extspk_info_audio_out(info); + + if (ret < 0) + return ret; + + *audio_out = ret; + return 0; +} \ No newline at end of file diff --git a/src/resource_center_private.cpp b/src/resource_center_private.cpp new file mode 100644 index 0000000..b0b2a51 --- /dev/null +++ b/src/resource_center_private.cpp @@ -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 +#include +#include +#include +#include + +#include +#include +#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 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(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 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 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 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 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(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 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 index 0000000..af19206 --- /dev/null +++ b/test/CMakeLists.txt @@ -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 index 0000000..bb4f2a5 --- /dev/null +++ b/test/resource_center_test.cpp @@ -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 +#include +#include +#include +#include + +#include +#include + +#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 index 0000000..9e01685 --- /dev/null +++ b/ut/CMakeLists.txt @@ -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 index 0000000..b0ebbde --- /dev/null +++ b/ut/inc/TCApp.h @@ -0,0 +1,57 @@ +/* + * 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 __TC_APP_H__ +#define __TC_APP_H__ +#include + +class TCApp +{ +public: + TCApp(const char* app_id); + ~TCApp(); + + static void ResourceChangedCb(const char* app_id, rc_resource_h rsc, void *data); + int RegisterResourceChangeCb(void); + int UnregisterResourceChangeCb(void); + + std::string GetAppId(void) { return m_app_id; } + + void IncreaseCbCount(void) { m_cb_count++; } + void ResetCbCount(void) { m_cb_count = 0; } + int GetCbCount(void) { return m_cb_count;} + + bool IsMaxRszChanged(void) { return m_max_rsz_changed; } + bool IsAudioRscChanged(void) { return m_audio_rsc_changed; } + + void SetMaxRszChanged(bool changed) { m_max_rsz_changed = changed; } + void SetAudioRscChanged(bool changed) { m_audio_rsc_changed = changed; } + void SetMaxResolution(int w, int h, int f) { m_max_width = w; m_max_height = h; m_max_framerate = f; } + void GetMaxResolution(int *w, int *h, int *f) { *w = m_max_width, *h = m_max_height, *f = m_max_framerate; } + 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; } + +private: + std::string m_app_id; + int m_cb_count; + + int m_max_width = 0; + int m_max_height = 0; + int m_max_framerate = 0; + bool m_max_rsz_changed = false; + bool m_audio_rsc_changed = false; +}; + +#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 index 0000000..d043430 --- /dev/null +++ b/ut/inc/TCPlayer.h @@ -0,0 +1,81 @@ +/* + * 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 __TC_PLAYER_H__ +#define __TC_PLAYER_H__ + +#include +#include +#include + +class TCResource; +class TCPlayer +{ +public: + TCPlayer(); + TCPlayer(std::string app_id) { m_app_id = app_id; } + ~TCPlayer(); + + static rm_cb_result ConflictCb(int handle, rm_callback_type event, rm_device_request_s *info, void* data); + int Register(void); + int Unregister(void); + + int SetPriority(int priority); + int SetAppId(std::string app_id); + void SetCustomHandle(int handle) { m_handle = handle;} + + int GetHandle(void) { return m_handle; } + std::string GetAppId(void) { return m_app_id; } + int AddResource(int category_id, int state); + int AddResource(int category_id, int category_option, int state); + void RemoveResources(void); + int GetAudioCategory(std::string codec_name, int mixing_mode); + int GetCapableVideoCategory(std::string codec_name, int h_size, int v_size, int color_depth, int sampling_format, int framerate); + int GetCapableCategoryIdFromRC(int category_id); + + int AddQuery(int category_id, int category_option, int state); + void RemoveQueries(void); + int Query(int query_type, int *ans); + + void AddAllocatedResource(int device_id); + int AllocateResources(void); + int ReleaseResources(void); + int ReleaseResource(int index); + int GetAllocatedResourceId(int index); + int GetAllocatedResourcesNum(void) { return m_allocated_resources.size(); } + + void IncreaseConflictNum(void) { m_n_conflict++; } + int GetConflictNum(void) { return m_n_conflict; } + void SetConflictedResourcesNum(int n) { m_n_conflicted_rsc = n; } + int GetConflictedResourcesNum(void) { return m_n_conflicted_rsc; } + + int GetActiveAudioOut(void); + +private: + std::map m_allocated_resources; + std::map m_requested_resources; + std::map m_queries; + + std::string m_app_id; + int m_handle; + int m_rsc_index; + int m_query_index; + int m_allocated_rsc_index; + int m_n_conflict; + int m_n_conflicted_rsc; +}; + +#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 index 0000000..545b5af --- /dev/null +++ b/ut/inc/TCResource.h @@ -0,0 +1,36 @@ +/* + * 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 __TC_RESOURCE_H__ +#define __TC_RESOURCE_H__ + +class TCResource +{ +public: + TCResource(int category_id, int category_option, int state); + ~TCResource(); + + int GetCategoryId(void) {return m_category_id;} + int GetCategoryOption(void) {return m_category_option;} + int GetState(void) {return m_state;} + +private: + int m_category_id; + int m_category_option; + int m_state; +}; + +#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 index 0000000..2fda25e --- /dev/null +++ b/ut/inc/tomatoGtest.h @@ -0,0 +1,99 @@ +/* + * 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. + */ + +//invoke Tomato LIB +#ifndef __TOMATO_GTEST_H__ +#define __TOMATO_GTEST_H__ + +#include "TomatoAPI.h" + +//Set TC-config to tomato via Gtest macro +#undef GTEST_TEST_ +#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ +class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ + public:\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ + private:\ + virtual void TestBody();\ + virtual void TestBody_();\ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ +};\ +\ +::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ + ::test_info_ =\ + ::testing::internal::MakeAndRegisterTestInfo(\ + #test_case_name, #test_name, NULL, NULL, \ + (parent_id), \ + parent_class::SetUpTestCase, \ + parent_class::TearDownTestCase, \ + new ::testing::internal::TestFactoryImpl<\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ +void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()\ +{\ + CTomatoAPI::BeginTestCase(#test_name);\ + this->TestBody_();\ + CTomatoAPI::EndTestCase();\ +}\ +void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody_() + +// Re-define Gtest macro for redirecting gtest-report to tomato +/* + EXPECT_EQ + ASSERT_EQ + + @ refer to "gtest_pred_impl.h" +*/ +// parvin.kumar + +#undef GTEST_PRED_FORMAT2_ +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), v2, on_failure) \ + +#undef GTEST_ASSERT_ +#define GTEST_ASSERT_(expression, v2, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) {\ + CTomatoAPI::WriteTestResult( #v2, true , "success"); { \ + else \ + { on_failure(gtest_ar.failure_message()); \ + CTomatoAPI::WriteTestResult( #v2, false , gtest_ar.failure_message()); { + + +/* + EXPECT_TRUE : return TRUE -> PASS + EXPECT_FALSE : return FALSE -> PASS + ASSERT_TRUE + ASSERT_FALSE +*/ + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// representation of expression as it was passed into the EXPECT_TRUE. +#undef GTEST_TEST_BOOLEAN_ +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) {\ + CTomatoAPI::WriteTestResult( text, true , "success"); { \ + else {\ + fail(::testing::internal::GetBoolAssertionFailureMessage(gtest_ar_, text, #actual, #expected).c_str());\ + CTomatoAPI::WriteTestResult( test, false , ::testing::internal::GetBoolAssertionFailureMessage(gtest_ar_, text, #actual, #expected).c_str()); { + + +#endif //__TOMATO_GTEST_H__ diff --git a/ut/inc/ut_log.h b/ut/inc/ut_log.h new file mode 100644 index 0000000..572fdd4 --- /dev/null +++ b/ut/inc/ut_log.h @@ -0,0 +1,31 @@ +/* + * 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 __UT_LOG_H__ +#define __UT_LOG_H__ + +#include + +#ifdef LOG_TAG +#undef LOG_TAG +#endif//LOG_TAG + +#define LOG_TAG "RSC_CENTER_TC" +#define RC_TEST_ERR(fmt, ...) LOGE(fmt, ##__VA_ARGS__) +#define RC_TEST_INFO(fmt, ...) LOGI(fmt, ##__VA_ARGS__) +#define RC_TEST_DBG(fmt, ...) LOGD(fmt, ##__VA_ARGS__) + +#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 index 0000000..40fd3b3 --- /dev/null +++ b/ut/inc/ut_util.h @@ -0,0 +1,103 @@ +/* + * 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 __UT_UTIL_H__ +#define __UT_UTIL_H__ +#include +#include +#include + +int AddZoneInfo(int category_id, int zone_id); + +class CResourceManagerAPI +{ +public: + + typedef enum { + CB_NORMAL = 0, + CB_COUNT + } cb_option; + + static CResourceManagerAPI* GetInstance(); + static gboolean SetAppZoneIdAsync(gpointer data); + static gboolean SetAudioFocusAsync(gpointer data); + + void Reset(void); + int RegisterPlayer(int cb_option, int expected); + int RegisterPlayer(std::string app_id, int cb_option, int expected); + int SetAppZoneIdAsync(std::string app_id, int zone_id, int sleep_sec); + int SetAudioFocusAsync(int zone_id, int sleep_sec); + +private: + CResourceManagerAPI() = default; + ~CResourceManagerAPI() = default; + + rm_resource_cb GetConflictCB(int option); + static rm_cb_result ConflictCB(int handle, rm_callback_type event, rm_device_request_s *info, void* data); + static rm_cb_result ConflictCBCount(int handle, rm_callback_type event, rm_device_request_s *info, void* data); + + static CResourceManagerAPI* m_instance; + int m_conflict_count; +}; + + +class CVideoCategory +{ +public: + CVideoCategory(); + ~CVideoCategory() = default; + + void SetProperties(std::string name, int width, int height, int framerate, int color_depth, int sampling); + ri_video_category_option_request_s* Build(void); + int GetCapableCategoryId(void); + +private: + void ResetProperties(void); + ri_video_category_option_request_s m_option; +}; + +class CAppInfo{ +public: + CAppInfo() = default; + ~CAppInfo() = default; + + void SetAppId(std::string app_id) {m_app_id = app_id;} + std::string GetAppId(void) {return m_app_id;} + void SetZoneId(int id) {m_zone_id = id;} + int GetZoneId(void) {return m_zone_id;} + void SetSleep(int sec) {m_sleep = sec;} + int GetSleep(void) {return m_sleep;} + +private: + std::string m_app_id; + int m_zone_id; + int m_sleep; +}; + +class CFocusInfo{ +public: + CFocusInfo() = default; + ~CFocusInfo() = default; + + void SetZoneId(int id) {m_zone_id = id;} + int GetZoneId(void) {return m_zone_id;} + void SetSleep(int sec) {m_sleep = sec;} + int GetSleep(void) {return m_sleep;} +private: + int m_sleep; + int m_zone_id; +}; +#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 index 0000000..f00bfd8 --- /dev/null +++ b/ut/src/testcase/TCApp.cpp @@ -0,0 +1,74 @@ +/* + * 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 +#include "TCApp.h" + +TCApp::TCApp(const char* app_id) +{ + if (app_id) + m_app_id.assign(app_id); + else + m_app_id.assign(""); + + m_cb_count = 0; + + m_max_width = 0; + m_max_height = 0; + m_max_framerate = 0; +} + +TCApp::~TCApp() +{ +} + +void TCApp::ResourceChangedCb(const char* app_id, rc_resource_h rsc, void *data) +{ + int w; + int h; + int f; + + if (!data) + return; + + TCApp* app = (TCApp*) data; + app->IncreaseCbCount(); + + EXPECT_STREQ(app->GetAppId().c_str(), app_id); + + if (rc_rsc_max_resolution_changed(rsc)) + { + EXPECT_EQ(0, rc_rsc_get_video_max_resolution(rsc, &w, &h, &f)); + app->SetMaxResolution(w, h, f); + app->SetMaxRszChanged(true); + } + + if (rc_rsc_audio_out_changed(rsc)) + { + app->SetAudioRscChanged(true); + } +} + +int TCApp::RegisterResourceChangeCb(void) +{ + return rc_register_resource_change_callback(m_app_id.c_str(), TCApp::ResourceChangedCb, this); +} + +int TCApp::UnregisterResourceChangeCb(void) +{ + return rc_unregister_resource_change_callback(m_app_id.c_str(), TCApp::ResourceChangedCb); +} \ No newline at end of file diff --git a/ut/src/testcase/TCPlayer.cpp b/ut/src/testcase/TCPlayer.cpp new file mode 100644 index 0000000..3cb81ae --- /dev/null +++ b/ut/src/testcase/TCPlayer.cpp @@ -0,0 +1,284 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include "TCResource.h" +#include "TCPlayer.h" + +TCPlayer::TCPlayer() +{ + m_handle = 0; + m_allocated_rsc_index = 0; + m_rsc_index = 0; + m_query_index = 0; + m_n_conflict = 0; + m_n_conflicted_rsc = 0; +} + +TCPlayer::~TCPlayer() +{ + Unregister(); +} + +rm_cb_result TCPlayer::ConflictCb(int handle, rm_callback_type event, rm_device_request_s *info, void* data) +{ + if (!data) + return RM_CB_RESULT_ERROR; + + TCPlayer *player = (TCPlayer*) data; + player->IncreaseConflictNum(); + player->SetConflictedResourcesNum(info->request_num); + + rm_deallocate_resources(handle, info); + + return RM_CB_RESULT_OK; +} + +int TCPlayer::Register(void) +{ + if (m_handle != 0) + return RM_ERROR; + + return rm_register(TCPlayer::ConflictCb, this, &m_handle, NULL); +} + +int TCPlayer::Unregister(void) +{ + int result = RM_ERROR;; + + RemoveResources(); + RemoveQueries(); + m_allocated_resources.clear(); + + result = rm_unregister(m_handle); + m_handle = 0; + + return result; +} + +int TCPlayer::SetPriority(int priority) +{ + return rm_set_priority(m_handle, priority); +} + +int TCPlayer::SetAppId(std::string app_id) +{ + m_app_id = app_id; + return rm_set_app_id(m_handle, (char*) app_id.c_str()); +} + +int TCPlayer::AddResource(int category_id, int state) +{ + TCResource* rsc = new TCResource(category_id, 0, state); + m_rsc_index++; + m_requested_resources.insert(std::pair(m_rsc_index, rsc)); + return 0; +} + +int TCPlayer::AddResource(int category_id, int category_option, int state) +{ + TCResource* rsc = new TCResource(category_id, category_option, state); + m_rsc_index++; + m_requested_resources.insert(std::pair(m_rsc_index, rsc)); + return 0; +} + +int TCPlayer::AddQuery(int category_id, int category_option, int state) +{ + TCResource* rsc = new TCResource(category_id, category_option, state); + m_query_index++; + m_queries.insert(std::pair(m_query_index, rsc)); + return 0; +} + +void TCPlayer::RemoveResources(void) +{ + TCResource *rsc = nullptr; + + for (auto &it : m_requested_resources) { + rsc = it.second; + if (rsc) + delete rsc; + } + m_requested_resources.clear(); + m_rsc_index = 0; +} + +int TCPlayer::GetAudioCategory(std::string codec_name, int mixing_mode) +{ + ri_audio_category_option_request_s audio_option; + memset(&audio_option, 0, sizeof(ri_audio_category_option_request_s)); + + audio_option.codec_name = codec_name.c_str(); + audio_option.mixing_mode = (ri_audio_mixing_mode) mixing_mode; + + return ri_get_capable_audio_category_id(&audio_option); +} + +int TCPlayer::GetCapableVideoCategory(std::string codec_name, int h_size, int v_size, int color_depth, int sampling_format, int framerate) +{ + ri_video_category_option_request_s opt; + memset(&opt, 0, sizeof(ri_video_category_option_request_s)); + + opt.codec_name = strndup(codec_name.c_str(), codec_name.length()); + opt.color_depth = color_depth; + opt.framerate = framerate; + opt.h_size = h_size; + opt.v_size = v_size; + opt.sampling_format = sampling_format; + + return ri_get_capable_video_category_id(&opt); +} + +int TCPlayer::GetCapableCategoryIdFromRC(int category_id) +{ + return rc_get_capable_category_id(m_handle, m_app_id.c_str(), category_id); +} + +int TCPlayer::Query(int query_type, int *ans) +{ + rm_category_request_s req; + memset(&req, 0, sizeof(rm_category_request_s)); + + int i = 0; + int result = RM_ERROR; + int answer; + + req.request_num = m_queries.size(); + + for (auto &it : m_queries) { + TCResource *rsc = it.second; + req.category_id[i] = (rm_rsc_category_e) rsc->GetCategoryId(); + req.category_option[i] = rsc->GetCategoryOption(); + req.state[i] = (rm_requests_resource_state_e) rsc->GetState(); + i++; + } + + result = rm_query(m_handle, (rm_query_type_e) query_type, &req, &answer); + *ans = answer; + + return result; +} + +void TCPlayer::RemoveQueries(void) +{ + TCResource *rsc = nullptr; + + for (auto &it : m_queries) { + rsc = it.second; + if (rsc) + delete rsc; + } + m_queries.clear(); +} + +void TCPlayer::AddAllocatedResource(int device_id) +{ + m_allocated_resources.insert(std::pair(++m_allocated_rsc_index, device_id)); +} + +int TCPlayer::GetAllocatedResourceId(int index) +{ + auto it = m_allocated_resources.find(index); + + return (it == m_allocated_resources.end()) ? -1 : it->second; +} + +int TCPlayer::AllocateResources(void) +{ + if (m_requested_resources.size() == 0) + return RM_ERROR; + + int i = 0; + int result = RM_ERROR; + + rm_category_request_s req; + memset(&req, 0, sizeof(rm_category_request_s)); + + req.request_num = m_requested_resources.size(); + + for (auto &it : m_requested_resources) { + TCResource *rsc = it.second; + req.category_id[i] = (rm_rsc_category_e) rsc->GetCategoryId(); + req.category_option[i] = rsc->GetCategoryOption(); + req.state[i] = (rm_requests_resource_state_e) rsc->GetState(); + i++; + } + + rm_device_return_s allocated; + memset(&allocated, 0, sizeof(allocated)); + + result = rm_allocate_resources(m_handle, &req, &allocated); + + if (result == RM_OK) { + for (int j = 0; j < allocated.allocated_num; j++) + AddAllocatedResource(allocated.device_id[j]); + } + + return result; +} + +int TCPlayer::ReleaseResources(void) +{ + if (m_allocated_resources.size() <= 0) + return RM_ERROR; + + int i = 0; + rm_device_request_s req; + memset(&req, 0, sizeof(req)); + + req.request_num = m_allocated_resources.size(); + + for (auto &it : m_allocated_resources) { + req.device_id[i] = it.second; + i++; + } + + m_allocated_resources.clear(); + m_allocated_rsc_index = 0; + + return rm_deallocate_resources(m_handle, &req); +} + +int TCPlayer::ReleaseResource(int index) +{ + if (m_allocated_resources.size() <= 0) + return RM_ERROR; + + auto it = m_allocated_resources.find(index); + int device_id = (it == m_allocated_resources.end()) ? -1 : it->second; + + rm_device_request_s req; + memset(&req, 0, sizeof(req)); + + req.request_num = 1; + req.device_id[0] = device_id; + + m_allocated_resources.erase(index); + + return rm_deallocate_resources(m_handle, &req); +} + +int TCPlayer::GetActiveAudioOut(void) +{ + return rm_get_active_audio_out(m_handle); +} diff --git a/ut/src/testcase/TCResource.cpp b/ut/src/testcase/TCResource.cpp new file mode 100644 index 0000000..c149966 --- /dev/null +++ b/ut/src/testcase/TCResource.cpp @@ -0,0 +1,28 @@ +/* + * 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 "TCResource.h" + +TCResource::TCResource(int category_id, int category_option, int state) +{ + m_category_id = category_id; + m_category_option = category_option; + m_state = state; +} + +TCResource::~TCResource() +{ +} diff --git a/ut/src/testcase/ut_api.cpp b/ut/src/testcase/ut_api.cpp new file mode 100644 index 0000000..db08e55 --- /dev/null +++ b/ut/src/testcase/ut_api.cpp @@ -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 +#include +#include +#include +#include + +#include + +#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 index 0000000..a0075aa --- /dev/null +++ b/ut/src/testcase/ut_main.cpp @@ -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 +#include +#include "gtest/gtest.h" + +#include + +#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 index 0000000..4d833dc --- /dev/null +++ b/ut/src/testcase/ut_util.cpp @@ -0,0 +1,169 @@ +/* + * 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 +#include +#include + +CResourceManagerAPI* CResourceManagerAPI::m_instance = NULL; + +CResourceManagerAPI* CResourceManagerAPI::GetInstance() +{ + if (!m_instance) + m_instance = new CResourceManagerAPI(); + + return m_instance; +} + +void CResourceManagerAPI::Reset(void) +{ + m_conflict_count = 0; +} + +rm_resource_cb CResourceManagerAPI::GetConflictCB(int option) +{ + if (option == CB_NORMAL) + return &CResourceManagerAPI::ConflictCB; + + if (option == CB_COUNT) + return &CResourceManagerAPI::ConflictCBCount; + + return &CResourceManagerAPI::ConflictCB; +} + + +rm_cb_result CResourceManagerAPI::ConflictCB(int handle, rm_callback_type event, rm_device_request_s *info, void* data) +{ + rm_unregister(handle); + return RM_CB_RESULT_OK; +} + +rm_cb_result CResourceManagerAPI::ConflictCBCount(int handle, rm_callback_type event, rm_device_request_s *info, void* data) +{ + CResourceManagerAPI* api = (CResourceManagerAPI*) data; + api->m_conflict_count++; + rm_unregister(handle); + return RM_CB_RESULT_OK; +} + +int CResourceManagerAPI::RegisterPlayer(int option, int expected) +{ + int handle = 0; + + EXPECT_EQ(expected, rm_register(GetConflictCB(option), this, &handle, NULL)); + + return handle; +} + +int CResourceManagerAPI::RegisterPlayer(std::string app_id, int option, int expected) +{ + return 0; +} + +gboolean CResourceManagerAPI::SetAppZoneIdAsync(gpointer data) +{ + CAppInfo *app_info = (CAppInfo*) data; + sleep(app_info->GetSleep()); + EXPECT_EQ(0, rc_set_app_zone_info(app_info->GetAppId().c_str(), app_info->GetZoneId())); + delete app_info; + return G_SOURCE_REMOVE; +} + +int CResourceManagerAPI::SetAppZoneIdAsync(std::string app_id, int zone_id, int sleep_sec) +{ + CAppInfo *app_info = new CAppInfo(); + app_info->SetAppId(app_id); + app_info->SetZoneId(zone_id); + app_info->SetSleep(sleep_sec); + + g_idle_add(&CResourceManagerAPI::SetAppZoneIdAsync, app_info); + return 0; +} + +gboolean CResourceManagerAPI::SetAudioFocusAsync(gpointer data) +{ + CFocusInfo *focus_info = (CFocusInfo*) data; + sleep(focus_info->GetSleep()); + EXPECT_EQ(0, rc_set_audio_focus(focus_info->GetZoneId())); + delete focus_info; + return G_SOURCE_REMOVE; +} + +int CResourceManagerAPI::SetAudioFocusAsync(int zone_id, int sleep_sec) +{ + CFocusInfo *focus_info = new CFocusInfo(); + focus_info->SetZoneId(zone_id); + focus_info->SetSleep(sleep_sec); + + g_idle_add(&CResourceManagerAPI::SetAudioFocusAsync, focus_info); + return 0; +} + +CVideoCategory::CVideoCategory() +{ + m_option.codec_name = NULL; + m_option.h_size = 0; + m_option.v_size = 0; + m_option.framerate = 0; + m_option.color_depth = 0; + m_option.sampling_format = 0; +} + +void CVideoCategory::SetProperties(std::string codec, int width, int height, int framerate, int color_depth, int sampling) +{ + ResetProperties(); + + m_option.codec_name = strndup(codec.c_str(), codec.length()); + m_option.h_size = width; + m_option.v_size = height; + m_option.framerate = framerate; + m_option.color_depth = color_depth; + m_option.sampling_format = sampling; +} + +void CVideoCategory::ResetProperties(void) +{ + if (m_option.codec_name) { + free((void*) m_option.codec_name); + m_option.codec_name = NULL; + } + + m_option.h_size = 0; + m_option.v_size = 0; + m_option.framerate = 0; + m_option.color_depth = 0; + m_option.sampling_format = 0; +} + +ri_video_category_option_request_s* CVideoCategory::Build(void) +{ + return &m_option; +} + +int CVideoCategory::GetCapableCategoryId(void) +{ + return ri_get_capable_video_category_id(&m_option); +} + +int AddZoneInfo(int category_id, int zone_id) +{ + const int PM_ZONE_ID_OFFSET = 21; + int zone_info = (zone_id << PM_ZONE_ID_OFFSET); + + return (category_id | zone_info); +} + diff --git a/ut/tc/TCList.dat b/ut/tc/TCList.dat new file mode 100644 index 0000000..02afde8 --- /dev/null +++ b/ut/tc/TCList.dat @@ -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 index 0000000..b5ab7ac --- /dev/null +++ b/ut/tc/resource-center.xml @@ -0,0 +1,10 @@ + + + + + + + + + +