From 9193219cc03bd69ede8090a6b2694ba12a6783df Mon Sep 17 00:00:00 2001 From: Eunhye Choi Date: Wed, 31 Aug 2022 18:35:50 +0900 Subject: [PATCH 02/12] [0.0.1] add mtpr initial code Change-Id: I2bc2cd29d9a0e8cc708fe9d3e0415757db3944b8 --- CMakeLists.txt | 118 +++ LICENSE.APLv2 | 204 ++++ NOTICE | 3 + capi-media-transporter.pc.in | 14 + doc/media_transporter_doc.h | 147 +++ include/MediaSourceBinAudioTest.h | 70 ++ include/MediaSourceBinBase.h | 65 ++ include/MediaSourceBinCamera.h | 69 ++ include/MediaSourceBinFactory.h | 38 + include/MediaSourceBinMic.h | 73 ++ include/MediaSourceBinVideoTest.h | 69 ++ include/MediaTransporter.h | 32 + include/MediaTransporterBase.h | 102 ++ include/MediaTransporterCallback.h | 119 +++ include/MediaTransporterDisplay.h | 72 ++ include/MediaTransporterException.h | 44 + include/MediaTransporterFactory.h | 37 + include/MediaTransporterGst.h | 129 +++ include/MediaTransporterLog.h | 147 +++ include/MediaTransporterObserver.h | 68 ++ include/MediaTransporterParseIni.h | 194 ++++ include/MediaTransporterReceiver.h | 97 ++ include/MediaTransporterReceiverRist.h | 62 ++ include/MediaTransporterReceiverSrt.h | 62 ++ include/MediaTransporterResource.h | 66 ++ include/MediaTransporterSender.h | 51 + include/MediaTransporterSenderRist.h | 69 ++ include/MediaTransporterSenderRtsp.h | 63 ++ include/MediaTransporterSenderSrt.h | 86 ++ include/MediaTransporterSenderToServerRtsp.h | 58 ++ include/MediaTransporterUtil.h | 45 + include/mtpr.h | 803 ++++++++++++++++ include/mtpr_internal.h | 190 ++++ packaging/capi-media-transporter.manifest | 8 + packaging/capi-media-transporter.spec | 135 +++ src/MediaSourceBinAudioTest.cpp | 197 ++++ src/MediaSourceBinBase.cpp | 201 ++++ src/MediaSourceBinCamera.cpp | 213 +++++ src/MediaSourceBinFactory.cpp | 40 + src/MediaSourceBinMic.cpp | 242 +++++ src/MediaSourceBinVideoTest.cpp | 211 +++++ src/MediaTransporter.cpp | 624 +++++++++++++ src/MediaTransporterBase.cpp | 244 +++++ src/MediaTransporterCallback.cpp | 89 ++ src/MediaTransporterDisplay.cpp | 129 +++ src/MediaTransporterFactory.cpp | 47 + src/MediaTransporterGst.cpp | 743 +++++++++++++++ src/MediaTransporterObserver.cpp | 45 + src/MediaTransporterParseIni.cpp | 305 ++++++ src/MediaTransporterReceiver.cpp | 618 +++++++++++++ src/MediaTransporterReceiverRist.cpp | 142 +++ src/MediaTransporterReceiverSrt.cpp | 139 +++ src/MediaTransporterResource.cpp | 174 ++++ src/MediaTransporterSender.cpp | 54 ++ src/MediaTransporterSenderRist.cpp | 239 +++++ src/MediaTransporterSenderRtsp.cpp | 317 +++++++ src/MediaTransporterSenderSrt.cpp | 271 ++++++ src/MediaTransporterSenderToServerRtsp.cpp | 133 +++ src/MediaTransporterUtil.cpp | 92 ++ test/CMakeLists.txt | 25 + test/mtpr_rtsp_test.c | 65 ++ test/mtpr_test.c | 1284 ++++++++++++++++++++++++++ unittest/CMakeLists.txt | 67 ++ unittest/testbase.hpp | 51 + unittest/ut_main.cpp | 28 + unittest/ut_srt_sender.cpp | 99 ++ 66 files changed, 10737 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 LICENSE.APLv2 create mode 100644 NOTICE create mode 100644 capi-media-transporter.pc.in create mode 100644 doc/media_transporter_doc.h create mode 100644 include/MediaSourceBinAudioTest.h create mode 100644 include/MediaSourceBinBase.h create mode 100644 include/MediaSourceBinCamera.h create mode 100644 include/MediaSourceBinFactory.h create mode 100644 include/MediaSourceBinMic.h create mode 100644 include/MediaSourceBinVideoTest.h create mode 100644 include/MediaTransporter.h create mode 100644 include/MediaTransporterBase.h create mode 100644 include/MediaTransporterCallback.h create mode 100644 include/MediaTransporterDisplay.h create mode 100644 include/MediaTransporterException.h create mode 100644 include/MediaTransporterFactory.h create mode 100644 include/MediaTransporterGst.h create mode 100644 include/MediaTransporterLog.h create mode 100644 include/MediaTransporterObserver.h create mode 100644 include/MediaTransporterParseIni.h create mode 100644 include/MediaTransporterReceiver.h create mode 100644 include/MediaTransporterReceiverRist.h create mode 100644 include/MediaTransporterReceiverSrt.h create mode 100644 include/MediaTransporterResource.h create mode 100644 include/MediaTransporterSender.h create mode 100644 include/MediaTransporterSenderRist.h create mode 100644 include/MediaTransporterSenderRtsp.h create mode 100644 include/MediaTransporterSenderSrt.h create mode 100644 include/MediaTransporterSenderToServerRtsp.h create mode 100644 include/MediaTransporterUtil.h create mode 100644 include/mtpr.h create mode 100644 include/mtpr_internal.h create mode 100644 packaging/capi-media-transporter.manifest create mode 100644 packaging/capi-media-transporter.spec create mode 100644 src/MediaSourceBinAudioTest.cpp create mode 100644 src/MediaSourceBinBase.cpp create mode 100644 src/MediaSourceBinCamera.cpp create mode 100644 src/MediaSourceBinFactory.cpp create mode 100644 src/MediaSourceBinMic.cpp create mode 100644 src/MediaSourceBinVideoTest.cpp create mode 100644 src/MediaTransporter.cpp create mode 100644 src/MediaTransporterBase.cpp create mode 100644 src/MediaTransporterCallback.cpp create mode 100644 src/MediaTransporterDisplay.cpp create mode 100644 src/MediaTransporterFactory.cpp create mode 100644 src/MediaTransporterGst.cpp create mode 100644 src/MediaTransporterObserver.cpp create mode 100644 src/MediaTransporterParseIni.cpp create mode 100644 src/MediaTransporterReceiver.cpp create mode 100644 src/MediaTransporterReceiverRist.cpp create mode 100644 src/MediaTransporterReceiverSrt.cpp create mode 100644 src/MediaTransporterResource.cpp create mode 100644 src/MediaTransporterSender.cpp create mode 100644 src/MediaTransporterSenderRist.cpp create mode 100644 src/MediaTransporterSenderRtsp.cpp create mode 100644 src/MediaTransporterSenderSrt.cpp create mode 100644 src/MediaTransporterSenderToServerRtsp.cpp create mode 100644 src/MediaTransporterUtil.cpp create mode 100644 test/CMakeLists.txt create mode 100644 test/mtpr_rtsp_test.c create mode 100644 test/mtpr_test.c create mode 100644 unittest/CMakeLists.txt create mode 100644 unittest/testbase.hpp create mode 100644 unittest/ut_main.cpp create mode 100644 unittest/ut_srt_sender.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..3c611cb --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,118 @@ + +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_name "capi-media-transporter") + +PROJECT(${fw_name}) + +SET(CMAKE_INSTALL_PREFIX /usr) +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) + +SET(INC_DIR include) +INCLUDE_DIRECTORIES(${INC_DIR}) + +SET(dependents "dlog glib-2.0 gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 \ + json-glib-1.0 iniparser mm-common capi-media-tool mm-display-interface \ + cynara-client libsmack capi-system-info bundle capi-media-sound-manager \ + gstreamer-rtsp-server-1.0 libpulse") + +IF(NOT TIZEN_PROFILE_TV) + SET(dependents "${dependents} mm-resource-manager") +ELSE() + ADD_DEFINITIONS("-DTIZEN_TV") +ENDIF() + +SET(pc_dependents "capi-base-common capi-media-sound-manager capi-media-tool bundle") + +INCLUDE(FindPkgConfig) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +FOREACH(flag ${${fw_name}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -fPIC -Wall -Wshadow -Wsign-compare -Wmissing-field-initializers -Wcast-function-type -Werror") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -std=c++17") +SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") + +IF("${ARCH}" STREQUAL "arm") + ADD_DEFINITIONS("-DTARGET") +ENDIF("${ARCH}" STREQUAL "arm") + +ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"") + +SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--as-needed -Wl,--rpath=${LIB_INSTALL_DIR}") + +AUX_SOURCE_DIRECTORY (src MAIN_SRC) + +LIST (APPEND SOURCES + ${MAIN_SRC} +) + +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_INSTALL_DIR}) +INSTALL( + DIRECTORY ${INC_DIR}/ DESTINATION include/media + FILES_MATCHING + PATTERN "mtpr_*.h" EXCLUDE + PATTERN "${INC_DIR}/*.h" +) + + +SET(PC_NAME ${fw_name}) +SET(PC_REQUIRED ${pc_dependents}) +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_INSTALL_DIR}/pkgconfig) + +ADD_SUBDIRECTORY(test) + +OPTION(MTPR_UNITTEST "Build mtpr unittest code" OFF) +IF(MTPR_UNITTEST) +ADD_SUBDIRECTORY(unittest) +ENDIF(MTPR_UNITTEST) + +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..7d4506d --- /dev/null +++ b/LICENSE.APLv2 @@ -0,0 +1,204 @@ +Copyright (c) 2000 - 2022 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/NOTICE b/NOTICE new file mode 100644 index 0000000..ccdad52 --- /dev/null +++ b/NOTICE @@ -0,0 +1,3 @@ +Copyright (c) Samsung Electronics Co., Ltd. All rights reserved. +Except as noted, this software is licensed under Apache License, Version 2. +Please, see the LICENSE file for Apache License terms and conditions. diff --git a/capi-media-transporter.pc.in b/capi-media-transporter.pc.in new file mode 100644 index 0000000..8cb4d53 --- /dev/null +++ b/capi-media-transporter.pc.in @@ -0,0 +1,14 @@ +# Package Information for pkg-config + +prefix=@PREFIX@ +exec_prefix=/usr +libdir=@LIB_INSTALL_DIR@ +includedir=@INCLUDE_INSTALL_DIR@/media + +Name: @PC_NAME@ +Description: @PACKAGE_DESCRIPTION@ +Version: @VERSION@ +Requires: @PC_REQUIRED@ +Libs: -L${libdir} @PC_LDFLAGS@ +Cflags: -I${includedir} + diff --git a/doc/media_transporter_doc.h b/doc/media_transporter_doc.h new file mode 100644 index 0000000..0a1776b --- /dev/null +++ b/doc/media_transporter_doc.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_DOC_H__ +#define __TIZEN_MEDIA_TRANSPORTER_DOC_H__ + + +/** + * @file media_transporter_doc.h + * @brief This file contains high level documentation of the MediaTransporter API. + */ + +/** + * @ingroup CAPI_MEDIA_FRAMEWORK + * @defgroup CAPI_MEDIA_TRANSPORTER_MODULE MediaTransporter + * @brief The @ref CAPI_MEDIA_TRANSPORTER_MODULE API provides functions for real-time audio/video communication between peers. It supports various protocols as a native API based on GStreamer multimedia framework. + * + * @section CAPI_MEDIA_TRANSPORTER_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_TRANSPORTER_OVERVIEW Overview + * The MediaTransporter API provides functions to communicate with the peer using multimedia sources and generic data. + * The multimedia sources include audio/video stream from microphone, camera. + * The generic data includes string or byte data.\n + * This API set allows you to: + * - add/remove the media source + * - create/destroy data channel and send/receive data via the channel + * - start/stop the state of the handle + * - get notified about various changes via callbacks + * + * @subsection CAPI_MEDIA_TRANSPORTER_LIFE_CYCLE_STATE_TRANSITIONS State Transitions + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
FUNCTIONPRE-STATEPOST-STATESYNC TYPE
mtpr_create() NONE IDLE SYNC
mtpr_destroy() IDLE/PLAYING NONE SYNC
mtpr_start() IDLE PLAYING ASYNC
mtpr_stop() PLAYING IDLE ASYNC
+ * + * @subsection CAPI_MEDIA_TRANSPORTER_LIFE_CYCLE_CALLBACK_OPERATIONS Callback(Event) Operations + * The callback mechanism is used to notify the application about significant MediaTransporter events. + *
+ * + * + * + * + * + * + * + * + * + * + * + * + *
REGISTERUNREGISTERCALLBACKDESCRIPTION
mtpr_set_error_cb()mtpr_unset_error_cb()mtpr_error_cb()This callback is used to notify that an error has occurred
+ * + * @section CAPI_MEDIA_TRANSPORTER_MODULE_FEATURE Related Features + * This API is related with the following features:\n + * - %http://tizen.org/feature/network.wifi\n + * - %http://tizen.org/feature/network.telephony\n + * - %http://tizen.org/feature/network.ethernet\n + * + * It is recommended to design feature related codes in your application for reliability.\n + * You can check if a device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n + * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n + * More details on featuring your application can be found from Feature Element. + * + */ + +/** + * @ingroup CAPI_MEDIA_TRANSPORTER_MODULE + * @defgroup CAPI_MEDIA_TRANSPORTER_SENDER_MODULE Media Transporter Sender + * @brief The @ref CAPI_MEDIA_TRANSPORTER_SENDER_MODULE API provides functions to manage media sources to communicate with the peer. + * @section CAPI_MEDIA_TRANSPORTER_SENDER_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_TRANSPORTER_SENDER_MODULE_OVERVIEW Overview + * The MediaTransporter Sender API allows you to: + * - add/remove the media source (camera, mic, videotest, audiotest) + * - set/get the media source params (video resolution, video framerate, etc) + * + * @section CAPI_MEDIA_TRANSPORTER_SENDER_MODULE_FEATURE Related Features + * This API is related with the following features:\n + * - %http://tizen.org/feature/microphone\n + * - %http://tizen.org/feature/camera + * + * It is recommended to design feature related codes in your application for reliability.\n + * You can check if a device supports the related features for this API by using @ref CAPI_SYSTEM_SYSTEM_INFO_MODULE, thereby controlling the procedure of your application.\n + * To ensure your application is only running on the device with specific features, please define the features in your manifest file using the manifest editor in the SDK.\n + * More details on featuring your application can be found from Feature Element. + * +*/ + +/** + * @ingroup CAPI_MEDIA_TRANSPORTER_MODULE + * @defgroup CAPI_MEDIA_TRANSPORTER_RECEIVER_MODULE Media Transporter Receiver + * @brief The @ref CAPI_MEDIA_TRANSPORTER_RECEIVER_MODULE API provides functions to export received audio or video stream. + * @section CAPI_MEDIA_TRANSPORTER_RECEIVER_MODULE_HEADER Required Header + * \#include + * + * @section CAPI_MEDIA_TRANSPORTER_RECEIVER_MODULE_OVERVIEW Overview + * The MediaTransporter Receiver API allows you to: + * - set media track added callback to get notified about detected track information + * - set media data callback to get received audio and video data from peer + * +*/ + +#endif /* __TIZEN_MEDIA_TRANSPORTER_DOC_H__ */ diff --git a/include/MediaSourceBinAudioTest.h b/include/MediaSourceBinAudioTest.h new file mode 100644 index 0000000..11245a1 --- /dev/null +++ b/include/MediaSourceBinAudioTest.h @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2022 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_MEDIA_SOURCE_BIN_AUDIO_TEST_H__ +#define __TIZEN_MEDIA_SOURCE_BIN_AUDIO_TEST_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include +#include +#include "MediaSourceBinBase.h" +#include "MediaTransporterGst.h" + +namespace tizen_media_transporter { + +#define RESOURCE_TYPE_MAX MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER + 1 +const std::string DEFAULT_ELEMENT_AUDIO_TEST = "audiotestsrc"; + +class MediaSourceBinAudioTest : public MediaSourceBinBase +{ +public: + MediaSourceBinAudioTest(bundle* params); + ~MediaSourceBinAudioTest() = default; + + MediaSourceBinInfo generate() override; + +private: + struct audioInfo { + int channel = -1; + int rate = -1; + std::string format = ""; + }; + + struct encodingInfo { + int bitrate = 0; + }; + + void parseSourceParam(bundle* params); + GstElement* createMicSource(); + void setEncoderParam(gst::GstElements& elements); + void setSourceParam(gst::GstElements& elements); + void replaceCapsWithAudioInfo(GstElement* element); + void replaceEncCapsWithAudioInfo(GstElement* element); + audioInfo _audioInfo; + encodingInfo _encInfo; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_SOURCE_BIN_AUDIO_TEST_H__ diff --git a/include/MediaSourceBinBase.h b/include/MediaSourceBinBase.h new file mode 100644 index 0000000..c1e17f7 --- /dev/null +++ b/include/MediaSourceBinBase.h @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2022 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_MEDIA_SOURCE_BIN_BASE_H__ +#define __TIZEN_MEDIA_SOURCE_BIN_BASE_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "MediaTransporterParseIni.h" +#include + +namespace tizen_media_transporter { + +using MediaSourceBinInfo = std::tuple; + +const std::string ELEMENT_NAME_SRC_CAPSFILTER = "srcCapsfilter"; +const std::string ELEMENT_NAME_ENCODE_CAPSFILTER = "encCapsfilter"; + +class IMediaSourceBin +{ +public: + virtual ~IMediaSourceBin() {} + virtual MediaSourceBinInfo generate() = 0; +}; + +class MediaSourceBinBase : public IMediaSourceBin +{ +public: + MediaSourceBinBase() = default; + ~MediaSourceBinBase() = default; + +protected: + std::vector createVideoRestOfElements(const MtprMediaSourceIni& ini); + std::vector createAudioRestOfElements(const MtprMediaSourceIni& ini); +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_SOURCE_BIN_BASE_H__ diff --git a/include/MediaSourceBinCamera.h b/include/MediaSourceBinCamera.h new file mode 100644 index 0000000..927ad3a --- /dev/null +++ b/include/MediaSourceBinCamera.h @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2022 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_MEDIA_SOURCE_BIN_CAMERA_H__ +#define __TIZEN_MEDIA_SOURCE_BIN_CAMERA_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include +#include +#include "MediaSourceBinBase.h" +#include "MediaTransporterGst.h" + +namespace tizen_media_transporter { + +const std::string DEFAULT_ELEMENT_CAMERASRC = "v4l2src"; + +class MediaSourceBinCamera : public MediaSourceBinBase +{ +public: + MediaSourceBinCamera(bundle* params); + ~MediaSourceBinCamera() = default; + + MediaSourceBinInfo generate() override; + +private: + struct videoInfo { + int width = -1; + int height = -1; + int frameRate = -1; + }; + + struct encodingInfo { + int bitrate = 0; + }; + + void parseSourceParam(bundle* params); + GstElement* createCameraSource(); + void setEncoderParam(gst::GstElements& elements); + void setSourceParam(gst::GstElements& elements); + void replaceCapsWithVideoInfo(GstElement* element); + void replaceEncCapsWithVideoInfo(GstElement* element); + videoInfo _videoInfo; + encodingInfo _encInfo; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_SOURCE_BIN_CAMERA_H__ diff --git a/include/MediaSourceBinFactory.h b/include/MediaSourceBinFactory.h new file mode 100644 index 0000000..e90d67c --- /dev/null +++ b/include/MediaSourceBinFactory.h @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2022 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_MEDIA_SOURCE_BIN_FACTORY_H__ +#define __TIZEN_MEDIA_SOURCE_BIN_FACTORY_H__ + +#ifdef __cplusplus + +#include "MediaSourceBinBase.h" +#include +#include +#include + +namespace tizen_media_transporter { + +class MediaSourceBinFactory +{ +public: + static IMediaSourceBin* create(mtprSourceType type, bundle* param_list); +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_SOURCE_BIN_FACTORY_H__ diff --git a/include/MediaSourceBinMic.h b/include/MediaSourceBinMic.h new file mode 100644 index 0000000..f65a4c3 --- /dev/null +++ b/include/MediaSourceBinMic.h @@ -0,0 +1,73 @@ +/** + * Copyright (c) 2022 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_MEDIA_SOURCE_BIN_MIC_H__ +#define __TIZEN_MEDIA_SOURCE_BIN_MIC_H__ + +#ifdef __cplusplus + + +#include +#include +#include +#include +#include +#include +#include + +#include "MediaTransporter.h" +#include "MediaSourceBinBase.h" +#include "MediaTransporterGst.h" + +namespace tizen_media_transporter { + +const std::string DEFAULT_ELEMENT_MICSRC = "pulsesrc"; + +class MediaSourceBinMic : public MediaSourceBinBase +{ +public: + MediaSourceBinMic(bundle* params); + ~MediaSourceBinMic() = default; + + MediaSourceBinInfo generate() override; + void setSoundStreamInfo(sound_stream_info_h streamInfo); + +private: + struct audioInfo { + int channel = -1; + int rate = -1; + std::string format = ""; + }; + + struct encodingInfo { + int bitrate = 0; + }; + + void parseSourceParam(bundle* params); + GstElement* createMicSource(); + void setEncoderParam(gst::GstElements& elements); + void setSourceParam(gst::GstElements& elements); + void replaceCapsWithAudioInfo(GstElement* element); + void replaceEncCapsWithAudioInfo(GstElement* element); + audioInfo _audioInfo; + encodingInfo _encInfo; + std::string _streamInfo = ""; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_SOURCE_BIN_CAMERA_H__ diff --git a/include/MediaSourceBinVideoTest.h b/include/MediaSourceBinVideoTest.h new file mode 100644 index 0000000..0de1cbc --- /dev/null +++ b/include/MediaSourceBinVideoTest.h @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2022 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_MEDIA_SOURCE_BIN_VIDEO_TEST_SRC_H__ +#define __TIZEN_MEDIA_SOURCE_BIN_VIDEO_TEST_SRC_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include +#include +#include "MediaSourceBinBase.h" +#include "MediaTransporterGst.h" + +namespace tizen_media_transporter { + +const std::string DEFAULT_ELEMENT_VIDEO_TEST = "videotestsrc"; + +class MediaSourceBinVideoTest : public MediaSourceBinBase +{ +public: + MediaSourceBinVideoTest(bundle* params); + ~MediaSourceBinVideoTest() = default; + + MediaSourceBinInfo generate() override; + +private: + struct videoInfo { + int width = -1; + int height = -1; + int frameRate = -1; + }; + + struct encodingInfo { + int bitrate = 0; + }; + + void parseSourceParam(bundle* params); + GstElement* createVideoTestSource(); + void setEncoderParam(gst::GstElements& elements); + void setSourceParam(gst::GstElements& elements); + void replaceCapsWithVideoInfo(GstElement* element); + void replaceEncCapsWithVideoInfo(GstElement* element); + videoInfo _videoInfo; + encodingInfo _encInfo; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_SOURCE_BIN_VIDEO_TEST_SRC_H__ diff --git a/include/MediaTransporter.h b/include/MediaTransporter.h new file mode 100644 index 0000000..202ef28 --- /dev/null +++ b/include/MediaTransporter.h @@ -0,0 +1,32 @@ +#ifndef __TIZEN_MEDIA_TRANSPORTER_CPP_H__ +#define __TIZEN_MEDIA_TRANSPORTER_CPP_H__ + +#ifdef __cplusplus + +#include "mtpr.h" +#include "mtpr_internal.h" + +#include +#include + +namespace tizen_media_transporter { + +using ResourceSet = std::set; + +using mtprConnectionType = mtpr_connection_type_e; +using mtprSourceType = mtpr_source_type_e; +using mtprMediaType = mtpr_media_type_e; +using mtprState = mtpr_state_e; +using mtprTrackAddedCallback = mtpr_track_added_cb; +using mtprNoMoreTrackCallback = mtpr_no_more_track_cb; +using mtprPacketCallback = mtpr_encoded_frame_cb; +using mtprErrorCallback = mtpr_error_cb; +using mtprError = mtpr_error_e; + +using mtprDisplayType = mtpr_display_type_e; +using mtprDisplayMode = mtpr_display_mode_e; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_CPP_H__ diff --git a/include/MediaTransporterBase.h b/include/MediaTransporterBase.h new file mode 100644 index 0000000..b29483d --- /dev/null +++ b/include/MediaTransporterBase.h @@ -0,0 +1,102 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_BASE_H__ +#define __TIZEN_MEDIA_TRANSPORTER_BASE_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "MediaTransporterParseIni.h" +#include "MediaTransporterCallback.h" +#include "MediaTransporterObserver.h" +#include "MediaTransporterResource.h" + +namespace tizen_media_transporter { + +struct mtprGstreamer { + GstElement *pipeline; + GstBus *bus; + guint bus_watcher; + GList *signals; // mtprSignal +}; + +class MediaTransporterBase : public IObserver +{ +public: + MediaTransporterBase() = default; + virtual ~MediaTransporterBase() = default; + + void create(); + ResourceSet build(); + void destroy(); + + void start(); + void stop(); + + mtprState state(); + + void setErrorCallback(void* handle, mtprErrorCallback callback, void* userData); + void unsetErrorCallback(); + + virtual void setSenderAddress(std::string address); + virtual std::string getSenderAddress(); + + virtual void setReceiverAddress(std::string address); + virtual std::string getReceiverAddress(); + + virtual mtprConnectionType type() = 0; + + virtual void setConnection(std::string name, std::string value) = 0; + virtual void setConnection(bundle* params) = 0; + virtual void getConnection(bundle* params) = 0; + + void setResourceManager(std::shared_ptr resourceManager); + void changed() override; // resource interrupted + +protected: + mtprGstreamer _gst {}; + std::unique_ptr _errorCallback; + std::shared_ptr _resourceManager; + +private: + void makePipeline(); + void stopInternal(); + + virtual ResourceSet buildPipeline() = 0; + virtual void startPipeline() = 0; + virtual void stopPipeline() = 0; + + static gboolean __busWatchCb(GstBus *bus, GstMessage *message, gpointer user_data); + + std::mutex _mutex; + mtprState _state { MTPR_STATE_IDLE }; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_BASE_H__ diff --git a/include/MediaTransporterCallback.h b/include/MediaTransporterCallback.h new file mode 100644 index 0000000..24d4ee9 --- /dev/null +++ b/include/MediaTransporterCallback.h @@ -0,0 +1,119 @@ +/* +* Copyright (c) 2022 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_MEDIA_TRANSPORTER_CALLBACK_H__ +#define __TIZEN_MEDIA_TRANSPORTER_CALLBACK_H__ + +#include +#include + +#include +#include +#include + +#include +#include "MediaTransporter.h" + +#ifdef __cplusplus +extern "C" { +#endif + +namespace tizen_media_transporter { + +using VariantData = std::variant; + +class IInvokable +{ +public: + virtual ~IInvokable() = default; + + virtual void invoke() = 0; + virtual void invoke(VariantData data) = 0; + virtual void invoke(VariantData data1, VariantData data2) = 0; +}; + +class AbstractCallback : public IInvokable +{ +public: + AbstractCallback(void* handle, void* userdata) : + _handle(handle), _userdata(userdata) {} + virtual ~AbstractCallback() = default; + + void invoke() override {} + void invoke(VariantData data) override {} + void invoke(VariantData data1, VariantData data2) override {} + +protected: + void* _handle; + void* _userdata; +}; + +class TrackAddedCallback : public AbstractCallback +{ +public: + TrackAddedCallback(void* handle, mtprTrackAddedCallback cb, void* userdata); + virtual ~TrackAddedCallback() = default; + + void invoke(VariantData data1, VariantData data2) override; + +private: + mtprTrackAddedCallback _callback; +}; + +class NoMoreTrackCallback : public AbstractCallback +{ +public: + NoMoreTrackCallback(void* handle, mtprNoMoreTrackCallback cb, void* userdata); + virtual ~NoMoreTrackCallback() = default; + + void invoke() override; + +private: + mtprNoMoreTrackCallback _callback; +}; + +class PacketCallback : public AbstractCallback +{ +public: + PacketCallback(void* handle, mtprMediaType type, mtprPacketCallback cb, void* userdata); + virtual ~PacketCallback() = default; + + void invoke(VariantData data1, VariantData data2) override; + +private: + mtprMediaType _type; + mtprPacketCallback _callback; +}; + +class ErrorCallback : public AbstractCallback +{ +public: + ErrorCallback(void* handle, mtprErrorCallback cb, void* userdata); + virtual ~ErrorCallback() = default; + + void invoke(VariantData data) override; + +private: + mtprErrorCallback _callback; +}; + +} // namespace + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_TRANSPORTER_CALLBACK_H__ */ diff --git a/include/MediaTransporterDisplay.h b/include/MediaTransporterDisplay.h new file mode 100644 index 0000000..9eff6ca --- /dev/null +++ b/include/MediaTransporterDisplay.h @@ -0,0 +1,72 @@ +/* +* Copyright (c) 2022 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_MEDIA_TRANSPORTER_DISPLAY_H__ +#define __TIZEN_MEDIA_TRANSPORTER_DISPLAY_H__ + +#include +#include +#include +#include + +#include "MediaTransporter.h" +#include "MediaTransporterObserver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +namespace tizen_media_transporter { + +class MediaTransporterDisplay +{ +public: + MediaTransporterDisplay(mtprDisplayType type, void *surface); + ~MediaTransporterDisplay(); + + GstElement* videoSink(); + + mtprDisplayType getType() { return _type; }; + + void setVisible(bool visible); + bool getVisible() { return _visible; }; + + void setMode(mtprDisplayMode mode); + mtprDisplayMode getMode() { return _mode; }; + +private: + void applyVisibleProperty(); + void applyModeProperty(); + + mtprDisplayType _type; + void* _surface; + + bool _visible { true }; + mtprDisplayMode _mode { MTPR_DISPLAY_MODE_LETTER_BOX }; + + std::mutex _mutex; + mm_display_interface_h _mmDisplay { nullptr }; + + GstElement* _sinkElement { nullptr }; +}; + +} // namespace tizen_media_transporter + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_TRANSPORTER_DISPLAY_H__ */ diff --git a/include/MediaTransporterException.h b/include/MediaTransporterException.h new file mode 100644 index 0000000..1408b8e --- /dev/null +++ b/include/MediaTransporterException.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_EXCEPTION_H__ +#define __TIZEN_MEDIA_TRANSPORTER_EXCEPTION_H__ + +#include +#include + +#include + +namespace tizen_media_transporter { + +class MediaTransporterException : public std::exception +{ +public: + MediaTransporterException(int error, std::string msg) : + _error(error), _msg(msg) {} + ~MediaTransporterException() final = default; + + const char* what() const noexcept override { return _msg.c_str(); } + int error() const { return _error; } + +private: + int _error; + std::string _msg; +}; + +}; // tizen_media_transporter + +#endif // __TIZEN_MEDIA_TRANSPORTER_EXCEPTION_H__ diff --git a/include/MediaTransporterFactory.h b/include/MediaTransporterFactory.h new file mode 100644 index 0000000..df0825e --- /dev/null +++ b/include/MediaTransporterFactory.h @@ -0,0 +1,37 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_FACTORY_H__ +#define __TIZEN_MEDIA_TRANSPORTER_FACTORY_H__ + +#ifdef __cplusplus + +#include "MediaTransporterBase.h" +#include +#include + +namespace tizen_media_transporter { + +class MediaTransporterFactory +{ +public: + static MediaTransporterBase* create(mtprConnectionType type); +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_FACTORY_H__ diff --git a/include/MediaTransporterGst.h b/include/MediaTransporterGst.h new file mode 100644 index 0000000..79acaa4 --- /dev/null +++ b/include/MediaTransporterGst.h @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_GST_H__ +#define __TIZEN_MEDIA_TRANSPORTER_GST_H__ + +#ifdef __cplusplus +#include +#include +#include +#include + +namespace tizen_media_transporter { +namespace gst { + +const std::string DEFAULT_ELEMENT_FAKESINK = "fakesink"; +const std::string DEFAULT_ELEMENT_AUDIOCONVERT = "audioconvert"; +const std::string DEFAULT_ELEMENT_AUDIORESAMPLE = "audioresample"; +const std::string DEFAULT_ELEMENT_VIDEOCONVERT = "videoconvert"; +const std::string DEFAULT_ELEMENT_CAPSFILTER = "capsfilter"; +const std::string DEFAULT_ELEMENT_TSMUX = "mpegtsmux"; +const std::string DEFAULT_ELEMENT_TSDEMUX = "tsdemux"; +const std::string DEFAULT_ELEMENT_H264_PARSER = "h264parse"; +const std::string DEFAULT_ELEMENT_MPEG4_PARSER = "mpeg4videoparse"; +const std::string DEFAULT_ELEMENT_APPSRC = "appsrc"; +const std::string DEFAULT_ELEMENT_QUEUE = "queue"; + + +const std::string DEFAULT_ELEMENT_RISTSRC = "ristsrc"; +const std::string DEFAULT_ELEMENT_RISTSINK = "ristsink"; +const std::string DEFAULT_ELEMENT_SRTSRC = "srtsrc"; +const std::string DEFAULT_ELEMENT_SRTSINK = "srtsink"; +const std::string DEFAULT_ELEMENT_RTSPSINK = "rtspclientsink"; + +const std::string DEFAULT_VIDEO_SINK_ELEMENT = "tizenwlsink"; +const std::string DEFAULT_AUDIO_SINK_ELEMENT = "pulsesink"; + +const std::string MEDIA_TYPE_AUDIO_RAW = "audio/x-raw"; +const std::string MEDIA_TYPE_AUDIO_MULAW = "audio/x-mulaw"; +const std::string MEDIA_TYPE_AUDIO_ALAW = "audio/x-alaw"; +const std::string MEDIA_TYPE_AUDIO_OPUS = "audio/x-opus"; +const std::string MEDIA_TYPE_AUDIO_VORBIS = "audio/x-vorbis"; +const std::string MEDIA_TYPE_AUDIO_AAC = "audio/mpeg"; +const std::string MEDIA_TYPE_VIDEO_RAW = "video/x-raw"; +const std::string MEDIA_TYPE_VIDEO_VP8 = "video/x-vp8"; +const std::string MEDIA_TYPE_VIDEO_VP9 = "video/x-vp9"; +const std::string MEDIA_TYPE_VIDEO_THEORA = "video/x-theora"; +const std::string MEDIA_TYPE_VIDEO_H264 = "video/x-h264"; +const std::string MEDIA_TYPE_VIDEO_H265 = "video/x-h265"; +const std::string MEDIA_TYPE_VIDEO_JPEG = "image/jpeg"; +const std::string MEDIA_TYPE_VIDEO_MPEG = "video/mpeg"; + +const std::string DEFAULT_DOT_FILE_NAME_PREFIX = "mtpr"; + +struct mtprSignal { + GObject* obj; + gulong signal_id; +}; + +struct elementInfo { + const gchar* klass_name; + GstCaps* srcCaps; + GstCaps* sinkCaps; + std::vector excludedElements; +}; + +using GstElements = std::vector; + +void _gstInit(); + +void _clearElements(GstElements& elements); +void _removeElement(GstElements& elements, GstElement* removeElement); +GstElement*_createElement(std::string factory_name, std::string name =""); +void _connectAndAppendSignal(GList** signals, GObject* obj, const char* sig_name, GCallback cb, gpointer user_data); +void _disconnectSignal(gpointer data); +bool _addNoTargetGhostpad(GstBin* bin, GstPad** new_pad, bool is_src); +bool _setGhostpadTarget(GstPad* ghost_pad, GstElement* target_element, bool is_src); +unsigned int _getUnoccupiedSourceId(GHashTable* slots); + +void _setElementProperties(GstElement* element, std::vector key_value_pairs); +void _applyStreamInfo(GstElement* element, std::string streamInfo); +void _addElementsToBin(GstBin* bin, GstElements elements); +void _removeElementsFromBin(GstBin* bin, GstElements& elements); +GstElement* _findEncoderElement(GstElements& elements); +bool _containHwEncoderElement(GstElements& elements); +GstElement* _findElementByName(GstElements& elements, const std::string& nameToFind); + +void _linkElements(GstElements& elements); +void _syncElementsStateWithParent(GstElements& elements); + +std::string _getMimeTypeFromPad(GstPad* pad); + +void _generateDot(GstElement* pipeline, std::string name); +void _dumpPipelineState(GstElement* pipeline); +void _setPipelineState(GstElement* pipeline, GstState state, int timeout); + +GstAudioFormat _getAudioFormatFromString(std::string format); +std::string _getVideoMediaType(std::string codec_name); +std::string _getAudioMediaType(std::string codec_name); +GstCaps* _getCapsFromEncodedVideoMediaType(std::string media_type, int width, int height); +GstCaps* _getCapsFromEncodedAudioMediaType(std::string media_type, int channels, int samplerate); +GstCaps* _makeCapsForCapsfilter(GstPad *pad); +GstElement* _createElementFromRegistry(std::string klassName, GstCaps* sinkCaps, GstCaps* srcCaps, const std::vector& excludedElements); + +void _setPipelineState(GstElement* pipeline, GstState state, int timeoutSec); + +void _destroyElementFromParent(GstElement* element); + +void _printCaps(GstCaps* caps, std::string prefix); + +}; // gst + +} // tizen_media_transporter + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_GST_H__ diff --git a/include/MediaTransporterLog.h b/include/MediaTransporterLog.h new file mode 100644 index 0000000..19a8103 --- /dev/null +++ b/include/MediaTransporterLog.h @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_LOG_H__ +#define __TIZEN_MEDIA_TRANSPORTER_LOG_H__ + +#include +#include +#include "MediaTransporterParseIni.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef LOG_TAG +#undef LOG_TAG +#endif + +#define LOG_TAG "TIZEN_N_MTPR" + +#define FONT_COLOR_RESET "\033[0m" +#define FONT_COLOR_RED "\033[31m" +#define FONT_COLOR_GREEN "\033[32m" +#define FONT_COLOR_YELLOW "\033[33m" +#define FONT_COLOR_BLUE "\033[34m" +#define FONT_COLOR_PURPLE "\033[35m" +#define FONT_COLOR_CYAN "\033[36m" +#define FONT_COLOR_GRAY "\033[37m" + +#define SECURE_LOG_DEBUG(fmt, arg...) \ +do { \ + SECURE_LOGD(FONT_COLOR_RESET fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define SECURE_LOG_INFO(fmt, arg...) \ +do { \ + SECURE_LOGI(FONT_COLOR_GREEN fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define SECURE_LOG_WARNING(fmt, arg...) \ +do { \ + SECURE_LOGW(FONT_COLOR_YELLOW fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define SECURE_LOG_ERROR(fmt, arg...) \ +do { \ + SECURE_LOGE(FONT_COLOR_RED fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define LOG_VERBOSE(fmt, arg...) \ +do { \ + if (MediaTransporterIni::get().general().verboseLog) \ + LOGD(FONT_COLOR_RESET fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define LOG_DEBUG(fmt, arg...) \ +do { \ + LOGD(FONT_COLOR_RESET fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define LOG_INFO(fmt, arg...) \ +do { \ + LOGI(FONT_COLOR_GREEN fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define LOG_WARNING(fmt, arg...) \ +do { \ + LOGW(FONT_COLOR_YELLOW fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define LOG_ERROR(fmt, arg...) \ +do { \ + LOGE(FONT_COLOR_RED fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define LOG_ERROR_IF_REACHED(fmt, arg...) \ +do { \ + LOGE(FONT_COLOR_RED "should not be reached here." fmt FONT_COLOR_RESET, ##arg); \ +} while (0) + +#define LOG_DEBUG_ENTER() \ +do { \ + LOGD(FONT_COLOR_PURPLE "" FONT_COLOR_RESET); \ +} while (0) + +#define LOG_DEBUG_LEAVE() \ +do { \ + LOGD(FONT_COLOR_PURPLE "" FONT_COLOR_RESET); \ +} while (0) + +#define LOG_WARNING_IF_CALLBACK_EXISTS(x_callback) \ +do { \ + if (x_callback.callback) \ + LOG_WARNING("previous callback[%p] user_data[%p]", x_callback.callback, x_callback.user_data); \ +} while (0) + +#define RET_IF(expr, fmt, arg...) \ +do { \ + if ((expr)) { \ + LOG_ERROR(fmt , ##arg); \ + return; \ + } \ +} while (0) + +#define RET_VAL_IF(expr, val, fmt, arg...) \ +do { \ + if ((expr)) { \ + LOG_ERROR(fmt , ##arg); \ + return (val);\ + } \ +} while (0) + +#define RET_ERR_IF_INVALID_INSTANCE(arg) \ + RET_VAL_IF(!(arg), MTPR_ERROR_INVALID_PARAMETER, "mtpr is null") + +#define RET_ERR_IF_NULL_ARG(arg) \ + RET_VAL_IF(!(arg), MTPR_ERROR_INVALID_PARAMETER, "arg is null") + +#define RET_ERR_IF_INVALID_RANGE_ARG(arg, min, max) \ +do { \ + RET_VAL_IF(((arg) < (min)), MTPR_ERROR_INVALID_PARAMETER, "arg is less than min"); \ + RET_VAL_IF(((arg) > (max)), MTPR_ERROR_INVALID_PARAMETER, "arg is over max"); \ +} while (0) + +#define MTPR_FENTER(); LOG_DEBUG(""); +#define MTPR_FLEAVE(); LOG_DEBUG(""); + +#define SAFE_STR(str) (str) ? str : "null" + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_TRANSPORTER_LOG_H__ */ diff --git a/include/MediaTransporterObserver.h b/include/MediaTransporterObserver.h new file mode 100644 index 0000000..f90ce2c --- /dev/null +++ b/include/MediaTransporterObserver.h @@ -0,0 +1,68 @@ +/* +* Copyright (c) 2022 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_MEDIA_TRANSPORTER_OBSERVER_H__ +#define __TIZEN_MEDIA_TRANSPORTER_OBSERVER_H__ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +namespace tizen_media_transporter { + +class IObserver +{ +public: + virtual ~IObserver() = default; + virtual void changed() = 0; +}; + +class IObservable +{ +public: + virtual ~IObservable() {} + + virtual void subscribe(IObserver *observer) = 0; + virtual void unsubscribe(IObserver *observer) = 0; + virtual void notify() = 0; +}; + +class ObservableBase : public IObservable +{ +public: + ObservableBase() = default; + ~ObservableBase() override = default; + + void subscribe(IObserver *observer); + void unsubscribe(IObserver *observer); + void notify(); + +private: + std::vector _observers; +}; + +} // namespace + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_TRANSPORTER_OBSERVER_H__ */ + diff --git a/include/MediaTransporterParseIni.h b/include/MediaTransporterParseIni.h new file mode 100644 index 0000000..744cc46 --- /dev/null +++ b/include/MediaTransporterParseIni.h @@ -0,0 +1,194 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_PARSE_INI_H__ +#define __TIZEN_MEDIA_TRANSPORTER_PARSE_INI_H__ + +#ifdef __cplusplus + +#include +#include +#include +#include "mtpr.h" + +namespace tizen_media_transporter { + +#define MTPR_INI_PATH SYSCONFDIR"/multimedia/mmfw_media_transporter.ini" + +/* categories */ +#define INI_CATEGORY_GENERAL "general" +#define INI_CATEGORY_CONNECTION "connection" +#define INI_CATEGORY_MEDIA_SOURCE "media source" +#define INI_CATEGORY_SOURCE_CAMERA "source camera" +#define INI_CATEGORY_SOURCE_MIC "source mic" +#define INI_CATEGORY_SOURCE_AUDIOTEST "source audiotest" +#define INI_CATEGORY_SOURCE_VIDEOTEST "source videotest" +#define INI_CATEGORY_RENDERING_SINK "rendering sink" + +/* items for general */ +#define INI_ITEM_DOT_GENERATE "generate dot" +#define INI_ITEM_DOT_PATH "dot path" +#define INI_ITEM_VERBOSE_LOG "verbose log" +#define INI_ITEM_GST_ARGS "gstreamer arguments" +#define INI_ITEM_GST_EXCLUDED_ELEMENTS "gstreamer excluded elements" +#define INI_ITEM_GST_STATE_CHANGE_TIMEOUT "timeout" + +#define DEFAULT_GENERATE_DOT true +#define DEFAULT_DOT_PATH "/tmp/" +#define DEFAULT_VERBOSE_LOG false +#define DEFAULT_STATE_CHANGE_TIMEOUT 10 + +/* items for connection */ +#define INI_ITEM_RTSP_SERVER_IP "rtsp server ip" +#define INI_ITEM_RTSP_SERVER_PORT "rtsp server port" +#define INI_ITEM_RTSP_SERVER_MOUNT_POINT "rtsp server mount point" + +#define DEFAULT_RTSP_SERVER_IP "127.0.0.1" +#define DEFAULT_RTSP_SERVER_PORT "8554" +#define DEFAULT_RTSP_SERVER_MOUNT_POINT "/mtpr_server/tmp" + +/* items for media source */ +#define INI_ITEM_SOURCE_ELEMENT "source element" +#define INI_ITEM_SOURCE_ELEMENT_PROPERTIES "source element properties" +#define INI_ITEM_VIDEO_RAW_FORMAT "video raw format" +#define INI_ITEM_VIDEO_WIDTH "video width" +#define INI_ITEM_VIDEO_HEIGHT "video height" +#define INI_ITEM_VIDEO_FRAMERATE "video framerate" +#define INI_ITEM_VIDEO_DRC_SUPPORT "video drc support" /* source element supports dynamic resolution change */ +#define INI_ITEM_VIDEO_ENCODED_FMT_SUPPORT "video encoded format support" /* source element supports encoded format */ +#define INI_ITEM_VIDEO_CODEC "video codec" +#define INI_ITEM_VIDEO_HW_ENCODER_ELEMENT "video hw encoder element" +#define INI_ITEM_AUDIO_RAW_FORMAT "audio raw format" +#define INI_ITEM_AUDIO_SAMPLERATE "audio samplerate" +#define INI_ITEM_AUDIO_CHANNELS "audio channels" +#define INI_ITEM_AUDIO_CODEC "audio codec" +#define INI_ITEM_AUDIO_HW_ENCODER_ELEMENT "audio hw encoder element" + +#define DEFAULT_VIDEO_RAW_FORMAT "I420" +#define DEFAULT_VIDEO_WIDTH 320 +#define DEFAULT_VIDEO_HEIGHT 240 +#define DEFAULT_VIDEO_FRAMERATE 30 +#define DEFAULT_VIDEO_DRC_SUPPORT false +#define DEFAULT_VIDEO_ENCODED_FMT_SUPPORT false +#define DEFAULT_AUDIO_RAW_FORMAT "F32LE" +#define DEFAULT_AUDIO_SAMPLERATE 8000 +#define DEFAULT_AUDIO_CHANNELS 1 + +#define DEFAULT_VIDEO_CODEC "mpeg" +#define DEFAULT_AUDIO_CODEC "aac" + +/* items for rendering sink */ +#define INI_ITEM_AUDIO_SINK_ELEMENT "audio sink element" +#define INI_ITEM_VIDEO_SINK_ELEMENT "video sink element" +#define INI_ITEM_AUDIO_HW_DECODER_ELEMENTS "audio hw decoder elements" +#define INI_ITEM_VIDEO_HW_DECODER_ELEMENTS "video hw decoder elements" + +struct MtprGeneralIni { + bool generateDot; + std::string dotPath; + bool verboseLog; + std::vector gstArgs; + std::vector gstExcludedElements; + int timeout; +}; + +struct MtprRtspConnectionIni { + std::string rtsp_ip; + std::string rtsp_port; + std::string rtsp_mount_point; +}; + +struct MtprRenderingSinkIni { + std::string audioSinkElement; + std::string videoSinkElement; + std::vector audioHWDecoderElements; + std::vector videoHWDecoderElements; + bool v_overlay_resource_required; +}; + +struct MtprMediaSourceIni { + std::string sourceElement; + std::vector sourceElementProperties; + /* video source pipeline */ + std::string videoRawFormat; + int videoWidth; + int videoHeight; + int videoFramerate; + std::string videoCodec; + std::string videoHWEncoderElement; + bool videoDRCSupport; + bool videoEncodedFMTSupport; + /* audio source pipeline */ + std::string audioRawFormat; + int audioSamplerate; + int audioChannels; + std::string audioCodec; + std::string audioHWEncoderElement; +}; + +struct MtprIni { + MtprGeneralIni general; + MtprMediaSourceIni mediaSourceDefault; + MtprRenderingSinkIni renderingSink; + std::vector mediaSources; +}; + +class IReadable +{ +public: + virtual ~IReadable() = default; + + virtual const MtprGeneralIni& general() = 0; + virtual const MtprMediaSourceIni& mediaSource(int source = -1) = 0; + virtual const MtprRenderingSinkIni& renderingSink() = 0; +}; + +class MediaTransporterIni : public IReadable +{ +public: + static MediaTransporterIni& get(); + + MediaTransporterIni(MediaTransporterIni const&) = delete; + MediaTransporterIni(MediaTransporterIni&&) = delete; + MediaTransporterIni& operator=(MediaTransporterIni const&) = delete; + MediaTransporterIni& operator=(MediaTransporterIni &&) = delete; + + const MtprGeneralIni& general() override; + const MtprMediaSourceIni& mediaSource(int type = -1) override; + const MtprRenderingSinkIni& renderingSink() override; + +private: + MediaTransporterIni(); + + void load(); + void dumpIni(); + + void dumpItemsOfGeneral(); + void dumpItemsOfRenderingSink(); + void dumpItemsOfMediaSource(MtprMediaSourceIni& source); + + void applyGeneralSetting(dictionary* dict); + void applyRenderingSink(dictionary* dict); + void applyMediaSourceDefault(dictionary* dict, std::string category); + void applyMediaSource(dictionary* dict, MtprMediaSourceIni& source, std::string category); + + MtprIni _ini; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_PARSE_INI_H__ diff --git a/include/MediaTransporterReceiver.h b/include/MediaTransporterReceiver.h new file mode 100644 index 0000000..6713755 --- /dev/null +++ b/include/MediaTransporterReceiver.h @@ -0,0 +1,97 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_RECEIVER_H__ +#define __TIZEN_MEDIA_TRANSPORTER_RECEIVER_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include +#include +#include "MediaTransporterBase.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterCallback.h" +#include "MediaTransporterDisplay.h" + +namespace tizen_media_transporter { + +#define DEFAULT_QUEUE_MAX_SIZE_BUFFERS 500 +#define DEFAULT_QUEUE_MAX_SIZE_BYTES 1024 * 1024 * 10 +#define DEFAULT_QUEUE_MAX_SIZE_TIME 5 * GST_SECOND + +class MediaTransporterReceiver : public MediaTransporterBase +{ +public: + MediaTransporterReceiver() = default; + virtual ~MediaTransporterReceiver() = default; + + void setTrackAddedCallback(void* handle, mtprTrackAddedCallback callback, void* userData); + void unsetTrackAddedCallback(); + + void setNoMoreTrackCallback(void* handle, mtprNoMoreTrackCallback callback, void* userData); + void unsetNoMoreTrackCallback(); + + void setVideoPacketCallback(void* handle, mtprPacketCallback callback, void* userData); + void setAudioPacketCallback(void* handle, mtprPacketCallback callback, void* userData); + void unsetVideoPacketCallback(); + void unsetAudioPacketCallback(); + + void setDisplay(std::shared_ptr display); + + void setSoundStreamInfo(sound_stream_info_h streamInfo); + +protected: + std::unique_ptr _trackAddedCallback; + std::unique_ptr _noMoreTrackCallback; + + struct mtprCallback { + std::unique_ptr _callback; + media_format_h mediaFormat { nullptr }; // FIXME : this should be A/V separated!!! + }; + mtprCallback _videoCallback {}; + mtprCallback _audioCallback {}; + + std::shared_ptr _display; + std::string _streamInfo; + + int _buildForwardingElements(GstElement* demux, GstPad* pad, GCallback callback); + void _buildForwardingSink(gst::GstElements& elements, GstPad* pad, GCallback callback); + + int _buildAudioRenderingElements(GstElement* demux, GstPad* pad); + int _buildVideoRenderingElements(GstElement* demux, GstPad* pad); + + static void _streamAddedCallback(GstPad* pad, gpointer data); + static void _noMoreStreamCallback(gpointer data); + static void _encodedAudioStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data); + static void _encodedVideoStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data); + +private: + static media_packet_h _makeMediaPacket(GstBuffer* buffer, GstPad* pad, media_format_h* format); + void _buildAudioRenderingSink(gst::GstElements& elements); + void _buildVideoRenderingSink(gst::GstElements& elements); +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_RECEIVER_H__ + diff --git a/include/MediaTransporterReceiverRist.h b/include/MediaTransporterReceiverRist.h new file mode 100644 index 0000000..54dff45 --- /dev/null +++ b/include/MediaTransporterReceiverRist.h @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_RECEIVER_RIST_H__ +#define __TIZEN_MEDIA_TRANSPORTER_RECEIVER_RIST_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include "MediaTransporterBase.h" +#include "MediaTransporterReceiver.h" + +namespace tizen_media_transporter { + +class MediaTransporterReceiverRist : public MediaTransporterReceiver +{ +public: + MediaTransporterReceiverRist() = default; + ~MediaTransporterReceiverRist() = default; + + ResourceSet buildPipeline() override; + void startPipeline() override; + void stopPipeline() override; + + void setConnection(std::string name, std::string value) override {} + void setConnection(bundle* params) override {} + void getConnection(bundle* params) override {} + + void setReceiverAddress(std::string address) override; + std::string getReceiverAddress() override { return _receiverAddress; } + + mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_RIST_RECEIVER; } + +private: + static void _demuxPadAddedCallback(GstElement *demux, GstPad *new_pad, gpointer userData); + static void _demuxNoMorePadsCallback(GstElement *demux, gpointer userData); + + std::string _receiverAddress; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_RECEIVER_RIST_H__ diff --git a/include/MediaTransporterReceiverSrt.h b/include/MediaTransporterReceiverSrt.h new file mode 100644 index 0000000..64626cd --- /dev/null +++ b/include/MediaTransporterReceiverSrt.h @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_RECEIVER_SRT_H__ +#define __TIZEN_MEDIA_TRANSPORTER_RECEIVER_SRT_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include "MediaTransporterBase.h" +#include "MediaTransporterReceiver.h" + +namespace tizen_media_transporter { + +class MediaTransporterReceiverSrt : public MediaTransporterReceiver +{ +public: + MediaTransporterReceiverSrt() = default; + ~MediaTransporterReceiverSrt() = default; + + ResourceSet buildPipeline() override; + void startPipeline() override; + void stopPipeline() override; + + void setConnection(std::string name, std::string value) override {} + void setConnection(bundle* params) override {} + void getConnection(bundle* params) override {} + + void setSenderAddress(std::string address) override; + std::string getSenderAddress() override { return _senderAddress; } + + mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_SRT_RECEIVER; } + +private: + static void _demuxPadAddedCallback(GstElement *demux, GstPad *new_pad, gpointer userData); + static void _demuxNoMorePadsCallback(GstElement *demux, gpointer userData); + + std::string _senderAddress; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_RECEIVER_SRT_H__ diff --git a/include/MediaTransporterResource.h b/include/MediaTransporterResource.h new file mode 100644 index 0000000..8237dd3 --- /dev/null +++ b/include/MediaTransporterResource.h @@ -0,0 +1,66 @@ +/* +* Copyright (c) 2022 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_MEDIA_TRANSPORTER_RESOURCE_H__ +#define __TIZEN_MEDIA_TRANSPORTER_RESOURCE_H__ + +#include +#include + +#include + +#include "MediaTransporter.h" +#include "MediaTransporterObserver.h" + +#ifdef __cplusplus +extern "C" { +#endif + +namespace tizen_media_transporter { + +class MediaTransporterResource : public ObservableBase +{ +public: + MediaTransporterResource() { create(); } + ~MediaTransporterResource() override { destroy(); } + + int acquire(ResourceSet resourceSet); + int acquire(mm_resource_manager_res_type_e type); + int releaseAll(); + + static int _resourceReleaseCallback(mm_resource_manager_h mgr, mm_resource_manager_res_h res, void *user_data); + +private: + int create(); + int destroy(); + int acquireInternal(mm_resource_manager_res_type_e type); + + bool resourceReleased(mm_resource_manager_res_h res); + mm_resource_manager_h _mgr { nullptr }; + std::map _resources; + bool _onReleaseCallback { false }; + + std::mutex _mutex; +}; + +} // namespace + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_TRANSPORTER_RESOURCE_H__ */ + diff --git a/include/MediaTransporterSender.h b/include/MediaTransporterSender.h new file mode 100644 index 0000000..fd351fd --- /dev/null +++ b/include/MediaTransporterSender.h @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_SENDER_H__ +#define __TIZEN_MEDIA_TRANSPORTER_SENDER_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include "MediaTransporterBase.h" +#include "MediaSourceBinBase.h" +#include + +namespace tizen_media_transporter { + +class MediaTransporterSender : public MediaTransporterBase +{ +public: + MediaTransporterSender() = default; + virtual ~MediaTransporterSender(); + + int addMediaSource(IMediaSourceBin* sourceBin); + void removeMediaSource(int id); + IMediaSourceBin* getMediaSource(int id); + +protected: + std::map> _mediaSources; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_SENDER_H__ diff --git a/include/MediaTransporterSenderRist.h b/include/MediaTransporterSenderRist.h new file mode 100644 index 0000000..68994a7 --- /dev/null +++ b/include/MediaTransporterSenderRist.h @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_SENDER_RIST_H__ +#define __TIZEN_MEDIA_TRANSPORTER_SENDER_RIST_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include "MediaTransporterSender.h" + +namespace tizen_media_transporter { + +#define RESOURCE_TYPE_MAX MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER + 1 + +class MediaTransporterSenderRist : public MediaTransporterSender +{ +public: + MediaTransporterSenderRist() = default; + ~MediaTransporterSenderRist() = default; + + ResourceSet buildPipeline() override; + void startPipeline() override; + void stopPipeline() override; + + void setConnection(std::string name, std::string value) override; + void setConnection(bundle* params) override; + void getConnection(bundle* params) override; + + void setReceiverAddress(std::string address) override; + std::string getReceiverAddress() override { return _receiverAddress; } + + mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_RIST_SENDER; } + +private: + struct MtprConnectionParamRist { + std::string bondingAddress; + double maxRtcpBandwidth { -1 }; + unsigned int minRtcpInterval { UINT_MAX }; + unsigned int senderBuffer { UINT_MAX }; + }; + MtprConnectionParamRist _connectionParam; + + std::string _receiverAddress; + + GstElement* _ristSink { nullptr }; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_SENDER_RIST_H__ diff --git a/include/MediaTransporterSenderRtsp.h b/include/MediaTransporterSenderRtsp.h new file mode 100644 index 0000000..772db4b --- /dev/null +++ b/include/MediaTransporterSenderRtsp.h @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_SENDER_RTSP_H__ +#define __TIZEN_MEDIA_TRANSPORTER_SENDER_RTSP_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include "MediaTransporterSender.h" + +namespace tizen_media_transporter { + +class MediaTransporterSenderRtsp : public MediaTransporterSender +{ +public: + MediaTransporterSenderRtsp() = default; + ~MediaTransporterSenderRtsp() = default; + + ResourceSet buildPipeline() override; + void startPipeline() override; + void stopPipeline() override; + + void setConnection(std::string name, std::string value) override {} + void setConnection(bundle* params) override {} + void getConnection(bundle* params) override {} + + void setSenderAddress(std::string address) override; + std::string getSenderAddress() override { return _senderAddress; } + + mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_RTSP_SENDER; } + +private: + void startRtspServer(); + void stopRtspServer(); + + std::string _senderAddress; // rtsp server ip, port + mount path + + std::string _rtspMountPoint; + void* _rtspServer { nullptr }; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_SENDER_RTSP_H__ diff --git a/include/MediaTransporterSenderSrt.h b/include/MediaTransporterSenderSrt.h new file mode 100644 index 0000000..1c5d96e --- /dev/null +++ b/include/MediaTransporterSenderSrt.h @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_SENDER_SRT_H__ +#define __TIZEN_MEDIA_TRANSPORTER_SENDER_SRT_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include +#include "MediaTransporterSender.h" + +namespace tizen_media_transporter { + +class MediaTransporterSenderSrt : public MediaTransporterSender +{ +public: + MediaTransporterSenderSrt() = default; + ~MediaTransporterSenderSrt() = default; + + ResourceSet buildPipeline() override; + void startPipeline() override; + void stopPipeline() override; + + void setConnection(std::string name, std::string value) override; + void setConnection(bundle* params) override; + void getConnection(bundle* params) override; + + void setSenderAddress(std::string address) override; + std::string getSenderAddress() override { return _senderAddress; } + + mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_SRT_SENDER; } + +private: + bool _isValidKeyLength(int val); + + enum connectionMode { + MTPR_CONNECTION_SRT_MODE_NONE = 0, /**< not connected, default type */ + MTPR_CONNECTION_SRT_MODE_CALLER, /**< The mode to send the connection request like a client (default) */ + MTPR_CONNECTION_SRT_MODE_LISTENER, /**< The mode to wait for being connected by peer caller */ + MTPR_CONNECTION_SRT_MODE_RENDEZVOUS, /**< The mode to support one-to-one only connection */ + }; + + enum connectionKeyLength { + MTPR_CONNECTION_SRT_NO_KEY = 0, /**< no encryption, default value */ + MTPR_CONNECTION_SRT_KEY_LEN_0 = 0, /**< no encryption */ + MTPR_CONNECTION_SRT_KEY_LEN_16 = 16, /**< 16 bytes (128-bit) length */ + MTPR_CONNECTION_SRT_KEY_LEN_24 = 24, /**< 24 bytes (192-bit) length */ + MTPR_CONNECTION_SRT_KEY_LEN_32 = 32, /**< 32 bytes (256-bit) length */ + }; + + struct MtprConnectionParamSrt { + connectionMode mode = MTPR_CONNECTION_SRT_MODE_NONE; + std::string streamId; + std::string passPhrase; + connectionKeyLength pbKeyLen = MTPR_CONNECTION_SRT_NO_KEY; + }; + + MtprConnectionParamSrt _connectionParam; + + std::string _senderAddress; + + GstElement* _srtSink { nullptr }; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_SENDER_SRT_H__ diff --git a/include/MediaTransporterSenderToServerRtsp.h b/include/MediaTransporterSenderToServerRtsp.h new file mode 100644 index 0000000..b6b2bd0 --- /dev/null +++ b/include/MediaTransporterSenderToServerRtsp.h @@ -0,0 +1,58 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_SENDER_TO_SERVER_RTSP_H__ +#define __TIZEN_MEDIA_TRANSPORTER_SENDER_TO_SERVER_RTSP_H__ + +#ifdef __cplusplus + + +#include "MediaTransporter.h" +#include +#include +#include +#include "MediaTransporterSender.h" + +namespace tizen_media_transporter { + +class MediaTransporterSenderToServerRtsp : public MediaTransporterSender +{ +public: + MediaTransporterSenderToServerRtsp() = default; + ~MediaTransporterSenderToServerRtsp() = default; + + ResourceSet buildPipeline() override; + void startPipeline() override; + void stopPipeline() override; + + void setConnection(std::string name, std::string value) override {} + void setConnection(bundle* params) override {} + void getConnection(bundle* params) override {} + + void setReceiverAddress(std::string address) override; + std::string getReceiverAddress() override { return _receiverAddress; } + + mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_RTSP_SENDER_TO_SERVER; } + +private: + std::string _receiverAddress; // rtsp server address to upload data + GstElement* _rtspSink { nullptr }; +}; + +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_SENDER_TO_SERVER_RTSP_H__ diff --git a/include/MediaTransporterUtil.h b/include/MediaTransporterUtil.h new file mode 100644 index 0000000..f59b4b3 --- /dev/null +++ b/include/MediaTransporterUtil.h @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_UTIL_H__ +#define __TIZEN_MEDIA_TRANSPORTER_UTIL_H__ + +#ifdef __cplusplus + +#include + +namespace tizen_media_transporter { +namespace util { + +const std::string MTPR_FEATURE_NETWORK_WIFI = "http://tizen.org/feature/network.wifi"; +const std::string MTPR_FEATURE_NETWORK_TELE = "http://tizen.org/feature/network.telephony"; +const std::string MTPR_FEATURE_NETWORK_ETH = "http://tizen.org/feature/network.ethernet"; +const std::string MTPR_FEATURE_CAMERA = "http://tizen.org/feature/camera"; +const std::string MTPR_FEATURE_MICROPHONE = "http://tizen.org/feature/microphone"; + +const std::string MTPR_PRIVILEGE_INTERNET = "http://tizen.org/privilege/internet"; +const std::string MTPR_PRIVILEGE_CAMERA = "http://tizen.org/privilege/camera"; +const std::string MTPR_PRIVILEGE_RECORDER = "http://tizen.org/privilege/recorder"; + +void throw_if_not_privileged(const std::string& privilege); +void throw_if_feature_not_supported(const std::string& feature); +void throw_if_network_features_not_supported(); + +} // util +} // namespace + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_UTIL_H__ diff --git a/include/mtpr.h b/include/mtpr.h new file mode 100644 index 0000000..9d3dd91 --- /dev/null +++ b/include/mtpr.h @@ -0,0 +1,803 @@ +/* + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_H__ +#define __TIZEN_MEDIA_TRANSPORTER_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** +* @file media_transporter.h +* @brief This file contains the Media Transporter API. +*/ + +/* TEMP Define ***********************************************/ +/* FIXME: this definition have to be applied + at core/api/common pkg, include/tizen_error.h file */ +#define TIZEN_ERROR_MEDIA_TRANSPORTER -0x01A30000 +/*************************************************************/ + +/** +* @addtogroup CAPI_MEDIA_TRANSPORTER_MODULE +* @{ +*/ + +/** + * @brief Media Transporter handle type. + * @since_tizen 7.0 + */ +typedef void *mtpr_h; + +/** + * @brief Enumeration for Media Transporter connection type. + * @since_tizen 7.0 + */ +typedef enum { + MTPR_CONNECTION_TYPE_RIST_SENDER, + MTPR_CONNECTION_TYPE_RIST_RECEIVER, + MTPR_CONNECTION_TYPE_SRT_SENDER, + MTPR_CONNECTION_TYPE_SRT_RECEIVER, + MTPR_CONNECTION_TYPE_RTSP_SENDER, + MTPR_CONNECTION_TYPE_RTSP_SENDER_TO_SERVER +} mtpr_connection_type_e; + +/** + * @brief Enumeration for Media Transporter error. + * @since_tizen 7.0 + */ +typedef enum { + MTPR_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ + MTPR_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< Not supported */ + MTPR_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ + MTPR_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + MTPR_ERROR_INVALID_OPERATION = TIZEN_ERROR_INVALID_OPERATION, /**< Invalid operation */ + MTPR_ERROR_INVALID_STATE = TIZEN_ERROR_MEDIA_TRANSPORTER | 0x01, /**< Invalid state */ + MTPR_ERROR_CONNECTION_FAILED = TIZEN_ERROR_MEDIA_TRANSPORTER | 0x02, /**< Connection failed */ + MTPR_ERROR_RESOURCE_FAILED = TIZEN_ERROR_MEDIA_TRANSPORTER | 0x03, /**< Resource failed */ + MTPR_ERROR_RESOURCE_CONFLICT = TIZEN_ERROR_MEDIA_TRANSPORTER | 0x04, /**< Resource conflict */ +} mtpr_error_e; + +/** + * @brief Enumeration for Media Transporter state. + * @since_tizen 7.0 + */ +typedef enum { + MTPR_STATE_IDLE, /**< Created but not prepared */ +// MTPR_STATE_READY, /**< Ready to start */ + MTPR_STATE_PLAYING, /**< Started */ + MTPR_STATE_PAUSED, /**< Paused while starting */ +} mtpr_state_e; + +/** + * @brief Enumeration for Media Transporter media type. + * @since_tizen 7.0 + */ +typedef enum { + MTPR_MEDIA_TYPE_AUDIO, /**< Audio */ + MTPR_MEDIA_TYPE_VIDEO, /**< Video */ +} mtpr_media_type_e; + +/** + * @brief Enumeration for Media Transporter source type. + * @since_tizen 7.0 + */ +typedef enum { + MTPR_SOURCE_TYPE_CAMERA, /**< Camera preview */ + MTPR_SOURCE_TYPE_MIC, /**< Audio from microphone */ + MTPR_SOURCE_TYPE_VIDEOTEST, /**< Video test */ + MTPR_SOURCE_TYPE_AUDIOTEST, /**< Audio test */ +} mtpr_source_type_e; + +/** + * @brief Definition for mode parameter of SRT. + * @details The connection mode of SRT.\n + 0: not connected.\n + 1: caller mode to send the connection request like a client. (default)\n + 2: listener mode to wait for being connected by peer caller.\n + 3: rendezvous mode to support one-to-one only connection. + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_SRT_MODE "mode" + +/** + * @brief Definition for streamid parameter of SRT. + * @details The streamid for the SRT access control. + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_SRT_STREAMID "streamid" + +/** + * @brief Definition for password parameter of SRT. + * @details The password for the encrypted transmission of SRT. + * @since_tizen 7.0 + * @remarks This is write only parameter. + * @see mtpr_set_connection_params() + */ +#define MTPR_CONNECTION_PARAM_SRT_PASSPHRASE "passphrase" + +/** + * @brief Definition for crypto key length of SRT. + * @details The crypto key length in bytes of SRT.\n + 0: no encryption. (default)\n + 16: 16 bytes (128-bit) length.\n + 24: 24 bytes (192-bit) length.\n + 32: 32 bytes (256-bit) length. + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_SRT_PBKEYLEN "pbkeylen" + +/** + * @brief Definition for bonding addresses of RIST + * @details Bonding address to send packets to (IPv4 or IPv6).\n + Comma (,) separated list of
: to send to + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_RIST_BONDING_ADDRESS "bonding-address" + +/** + * @brief Definition for max rtcp bandwidth fraction of RIST + * @details The maximum bandwidth used for RTCP as a fraction of RTP bandwidth of RIST + Range: 0 ~ 0.05 + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_RIST_MAX_RTCP_BANDWIDTH "max-rtcp-bandwidth" + +/** + * @brief Definition for min rtcp interval for of RIST + * @details The minimum interval (in ms) between two regular successive RTCP packets.\n + Range: 0 ~ 100 (ms) + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_RIST_MIN_RTCP_INTERVAL "min-rtcp-interval" + +/** + * @brief Definition for size of retransmission queue for RIST + * @details Size of the retransmission queue (in ms). + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_RIST_SENDER_BUFFER "sender-buffer" + +/** + * @brief Definition for IP to configure RTSP server + * @details IP address where the RTSP server will listen on. + * @remarks The default value is localhost (0.0.0.0 / 127.0.0.1). + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_RTSP_SERVER_IP "server-ip" + +/** + * @brief Definition for port of RTSP server + * @details String containing port number bewteen 1 and 65535\n + where the RTSP server will listen on. + * @remarks The default value is '8554'. + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_RTSP_SERVER_PORT "server-port" + +/** + * @brief Definition for mount point of RTSP server + * @remarks The default value is '/mtpr_server/tmp'. + * @since_tizen 7.0 + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + */ +#define MTPR_CONNECTION_PARAM_RTSP_SERVER_MOUNT_POINT "mount-point" + +/** + * @brief Definition for video source width + * @remarks The default value 320 + * @since_tizen 7.0 + * @see mtpr_add_media_source() + */ +#define MTPR_SOURCE_PARAM_VIDEO_WIDTH "video-width" + +/** + * @brief Definition for video source height + * @remarks The default value 240 + * @since_tizen 7.0 + * @see mtpr_add_media_source() + */ +#define MTPR_SOURCE_PARAM_VIDEO_HEIGHT "video-height" + +/** + * @brief Definition for video source framerate + * @remarks The default value 30 + * @since_tizen 7.0 + * @see mtpr_add_media_source() + */ +#define MTPR_SOURCE_PARAM_VIDEO_FRAMERATE "video-framerate" + +/** + * @brief Definition for audio source channel + * @remarks The default value 1 + * @since_tizen 7.0 + * @see mtpr_add_media_source() + */ +#define MTPR_SOURCE_PARAM_AUDIO_CHANNEL "audio-channel" + +/** + * @brief Definition for audio source samplerate + * @remarks The default value 48000 + * @since_tizen 7.0 + * @see mtpr_add_media_source() + */ +#define MTPR_SOURCE_PARAM_AUDIO_RATE "audio-rate" + +/** + * @brief Definition for audio source format + * @remarks The default value F32LE + * @since_tizen 7.0 + * @see mtpr_add_media_source() + */ +#define MTPR_SOURCE_PARAM_AUDIO_FORMAT "audio-format" + +/** + * @brief Definition for bitrate for encoder + * @details encoding bitrate (kbits/s)\n + If not set encoding parm,\n + bitrate is controlled by the encoder according to width and height. + * @since_tizen 7.0 + * @see mtpr_add_media_source() + */ +#define MTPR_ENCODING_PARAM_BITRATE "target-bitrate" + + +/** + * @brief Called when an error occurs. + * @details The following error codes can be received:\n + * #MTPR_ERROR_INVALID_OPERATION\n + * #MTPR_ERROR_CONNECTION_FAILED\n + * #MTPR_ERROR_RESOURCE_FAILED\n + * #MTPR_ERROR_RESOURCE_CONFLICT + * @since_tizen 7.0 + * @remarks The @a mtpr is the same object for which the callback was set.\n + * The @a mtpr should not be released. + * @param[in] mtpr Media Transporter handle + * @param[in] error The error code + * @param[in] user_data The user data passed from the callback registration function + * @see mtpr_set_error_cb() + * @see mtpr_unset_error_cb() + */ +typedef void (*mtpr_error_cb)(mtpr_h mtpr, mtpr_error_e error, void *user_data); + +/** + * @brief Called when a new track is added to the receiver. + * @since_tizen 7.0 + * @remarks The @a mtpr is the same object for which the callback was set.\n + * The @a mtpr should not be released. + * @param[in] mtpr Media Transporter handle + * @param[in] type The media type + * @param[in] track_id The track id + * @param[in] user_data The user data passed from the callback registration function + * @see mtpr_set_track_added_cb() + * @see mtpr_unset_track_added_cb() + */ +typedef void (*mtpr_track_added_cb)(mtpr_h mtpr, mtpr_media_type_e type, unsigned int track_id, void *user_data); + +/** + * @brief Called when all the track is parsed and prerolled. + * @since_tizen 7.0 + * @remarks The @a mtpr is the same object for which the callback was set.\n + * The @a mtpr should not be released.\n + * @param[in] mtpr Media Transporter handle + * @param[in] user_data The user data passed from the callback registration function + * @see mtpr_set_no_more_track_cb() + * @see mtpr_unset_no_more_track_cb() + */ +typedef void (*mtpr_no_more_track_cb)(mtpr_h mtpr, void *user_data); + +/** + * @brief Called when each audio or video frame is ready to be rendered via the Media Transporter pipeline after the negotiation. + * @since_tizen 7.0 + * @remarks The @a mtpr is the same object for which the callback was set.\n + * The @a mtpr should not be released.\n + * Use media_packet_get_buffer_data_ptr() with @a packet to get the Gstreamer buffer pointer.\n + * The @a packet should be released using media_packet_destroy(). + * @param[in] mtpr Media Transporter handle + * @param[in] type The media type + * @param[in] track_id The track id + * @param[in] packet The media packet which has a frame data + * @param[in] user_data The user data passed from the callback registration function + * @see mtpr_set_audio_packet_cb() + * @see mtpr_unset_audio_packet_cb() + * @see mtpr_set_video_packet_cb() + * @see mtpr_unset_video_packet_cb() + * @see media_packet_get_buffer_data_ptr() + */ +typedef void (*mtpr_encoded_frame_cb)(mtpr_h mtpr, mtpr_media_type_e type, unsigned int track_id, media_packet_h packet, void *user_data); + +/** + * @brief Creates an instance of Media Transporter. + * @since_tizen 7.0 + * @privlevel public + * @privilege %http://tizen.org/privilege/internet + * @remarks A signaling channel not addressed in this API should be established to send SDP or ICE candidate messages to each other.\n + * The @a mtpr should be released using mtpr_destroy(). + * @param[in] type The connection type + * @param[out] mtpr Media Transporter handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_NOT_SUPPORTED Not supported + * @retval #MTPR_ERROR_PERMISSION_DENIED Permission denied + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @post @a mtpr state will be #MTPR_STATE_IDLE. + * @see mtpr_destroy() + */ +int mtpr_create(mtpr_connection_type_e type, mtpr_h *mtpr); + +/** + * @brief Destroys the Media Transporter. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_create() + */ +int mtpr_destroy(mtpr_h mtpr); + +/** + * @brief Starts the Media Transporter. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @retval #MTPR_ERROR_RESOURCE_FAILED Resource failed + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @post @a mtpr state will be #MTPR_STATE_PLAYING. // FIXME + * @see mtpr_create() + * @see mtpr_stop() + */ +int mtpr_start(mtpr_h mtpr); + +/** + * @brief Stops the Media Transporter. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @retval #MTPR_ERROR_RESOURCE_FAILED Resource failed + * @pre @a mtpr state must be set to #MTPR_STATE_PLAYING. // FIXME + * @post @a mtpr state will be #MTPR_STATE_IDLE. + * @see mtpr_create() + * @see mtpr_start() + */ +int mtpr_stop(mtpr_h mtpr); + +/** + * @brief Gets the Media Transporter state. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[out] state Media Transporter state + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + */ +int mtpr_get_state(mtpr_h mtpr, mtpr_state_e *state); + +/** + * @brief Gets the connection type. + * @since_tizen 7.0 + * @remarks The default value is #MTPR_CONNECTION_TYPE_RIST. + * @param[in] mtpr Media Transporter handle + * @param[out] type The connection type + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + */ +int mtpr_get_connection_type(mtpr_h mtpr, mtpr_connection_type_e *type); + +/** + * @brief Sets the sender address + * @since_tizen 7.0 + * @remarks It should set when mtpr connection type is \n + * (#MTPR_CONNECTION_TYPE_SRT_SENDER, #MTPR_CONNECTION_TYPE_SRT_RECEIVER, #MTPR_CONNECTION_TYPE_RTSP_SENDER) + * @param[in] mtpr Media Transporter handle + * @param[in] address The connection address + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @see mtpr_get_connection_address() + */ +int mtpr_set_sender_address(mtpr_h mtpr, const char *address); + +/** + * @brief Gets the sender address + * @since_tizen 7.0 + * @remarks The @a address should be released using free(). + * @param[in] mtpr Media Transporter handle + * @param[out] address The sender address + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @see mtpr_set_sender_address() + */ +int mtpr_get_sender_address(mtpr_h mtpr, char **address); + +/** + * @brief Sets the receiver address + * @since_tizen 7.0 + * @remarks It should set when mtpr connection type is \n + * (#MTPR_CONNECTION_TYPE_RIST_SENDER, #MTPR_CONNECTION_TYPE_RIST_RECEIVER, #MTPR_CONNECTION_TYPE_RTSP_SENDER_TO_SERVER + * @param[in] mtpr Media Transporter handle + * @param[in] address The connection address + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @see mtpr_get_receiver_address() + */ +int mtpr_set_receiver_address(mtpr_h mtpr, const char *address); + +/** + * @brief Gets the receiver address + * @since_tizen 7.0 + * @remarks The @a address should be released using free(). + * @param[in] mtpr Media Transporter handle + * @param[out] address The receiver address + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @see mtpr_set_receiver_address() + */ +int mtpr_get_receiver_address(mtpr_h mtpr, char **address); + +/** + * @brief Sets connection parameter list. + * @details The parameters are key and value pairs. \n + The key is defined in this header file and the value data type must be string. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] param_name connection parameter nam + * @param[in] param_value connection parameter value + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @see mtpr_set_connection_params() + * @see mtpr_get_connection_params() + * @see #bundle + */ +int mtpr_set_connection_param(mtpr_h mtpr, const char *param_name, const char *param_value); + +/** + * @brief Sets connection parameter list. + * @details Many connection parameters can be set at one time all together by using bundle. \n + The parameters are key and value pairs. \n + The key is defined in this header file and the value data type must be string. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] param_list Key value array of connection parameters + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @see mtpr_get_connection_params() + * @see #bundle + */ +int mtpr_set_connection_params(mtpr_h mtpr, bundle *param_list); + +/** + * @brief Gets connection parameter list. + * @since_tizen 7.0 + * @remarks The @a param_list should be released using bundle_free().\n + * @param[in] mtpr Media Transporter handle + * @param[out] param_list Key value array of connection parameters + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_set_connection_params() + * @see #bundle + */ +int mtpr_get_connection_params(mtpr_h mtpr, bundle **param_list); + +/** + * @brief Adds a media source. + * @since_tizen 7.0 + * @remarks The camera privilege(%http://tizen.org/privilege/camera) should be added if @a type is #MTPR_MEDIA_SOURCE_TYPE_CAMERA.\n + * The recorder privilege(%http://tizen.org/privilege/recorder) should be added if @a type is #MTPR_MEDIA_SOURCE_TYPE_MIC. + * @param[in] mtpr Media Transporter handle + * @param[in] mtpr The media source type to be added + * @param[in] param_list Key value array of connection/encoding parameters + * @param[out] source_id The media source id + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_NOT_SUPPORTED Not supported + * @retval #MTPR_ERROR_PERMISSION_DENIED Permission denied + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @see mtpr_remove_media_source() + * @see mtpr_media_source_set_video_resolution() + * @see mtpr_media_source_get_video_resolution() + * @see mtpr_media_source_set_video_framerate() + * @see mtpr_media_source_get_video_framerate() + */ +int mtpr_add_media_source(mtpr_h mtpr, mtpr_source_type_e type, bundle* param_list, unsigned int *source_id); + +/** + * @brief Removes the media source. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] source_id The media source id to be removed + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre Add media source to @a mtpr to get @a source_id by calling mtpr_add_media_source(). + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @see mtpr_add_media_source() + */ +int mtpr_remove_media_source(mtpr_h mtpr, unsigned int source_id); + +/** + * @brief Sets the mic source's sound manager stream information. + * @details If @a source_id is not a media source of #MTPR_SOURCE_TYPE_MIC, this function will return #MTPR_ERROR_INVALID_PARAMETER. + * @since_tizen 7.0 + * @remarks You can set sound stream information including audio routing.\n + * The following sound stream types can be used to create the @a stream_info :\n + * #SOUND_STREAM_TYPE_MEDIA\n + * #SOUND_STREAM_TYPE_VOICE_RECOGNITION\n + * #SOUND_STREAM_TYPE_VOIP\n + * #SOUND_STREAM_TYPE_MEDIA_EXTERNAL_ONLY\n + * For more details, please refer to @ref CAPI_MEDIA_SOUND_MANAGER_MODULE. + * @param[in] mtpr Media Transporter handle + * @param[in] source_id The mic source id + * @param[in] stream_info The sound stream information + * @return @c 0 on success, otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @see #sound_stream_info_h + * @see sound_manager_create_stream_information() + * @see sound_manager_destroy_stream_information() + */ +int mtpr_mic_source_set_sound_stream_info(mtpr_h mtpr, unsigned int source_id, sound_stream_info_h stream_info); + +/** + * @brief Sets a callback function to be invoked when an asynchronous operation error occurs. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] callback Callback function pointer + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @post mtpr_error_cb() will be invoked. + * @see mtpr_unset_error_cb() + * @see mtpr_error_cb() + */ +int mtpr_set_error_cb(mtpr_h mtpr, mtpr_error_cb callback, void *user_data); + +/** + * @brief Unsets the error callback function. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_set_error_cb() + */ +int mtpr_unset_error_cb(mtpr_h mtpr); + +/** + * @brief Sets a track added callback function to be invoked when a new track is added to the receiver. + * @since_tizen 7.0 + * @remarks The registered callback will be invoked in an internal thread of the media transporter. + * @param[in] mtpr Media Transporter handle + * @param[in] callback Callback function pointer + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @post mtpr_track_added_cb() will be invoked. + * @see mtpr_unset_track_added_cb() + * @see mtpr_track_added_cb() + */ +int mtpr_set_track_added_cb(mtpr_h mtpr, mtpr_track_added_cb callback, void *user_data); + +/** + * @brief Unsets the track added callback function. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_set_track_added_cb() + */ +int mtpr_unset_track_added_cb(mtpr_h mtpr); + +/** + * @brief Sets a no more track callback function to be invoked when all the tracks are added to the receiver. + * @since_tizen 7.0 + * @remarks The registered callback will be invoked in an internal thread of the media transporter. + * @param[in] mtpr Media Transporter handle + * @param[in] callback Callback function pointer + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @post mtpr_no_more_track_cb() will be invoked. + * @see mtpr_unset_no_more_track_cb() + * @see mtpr_no_more_track_cb() + */ +int mtpr_set_no_more_track_cb(mtpr_h mtpr, mtpr_no_more_track_cb callback, void* user_data); + +/** + * @brief Unsets the no more track callback function. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_set_no_more_track_cb() + */ +int mtpr_unset_no_more_track_cb(mtpr_h mtpr); + +/** + * @brief Sets an encoded audio frame callback function to be invoked when each audio frame is ready to be rendered. + * @since_tizen 7.0 + * @remarks If @a callback is set, audio data from the remote peer will be forwarded to @a callback without being rendered by itself.\n + * The registered callback will be invoked in an internal thread of the media transporter. + * @param[in] mtpr Media Transporter handle + * @param[in] callback Callback function pointer + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @post mtpr_encoded_frame_cb() will be invoked. + * @see mtpr_unset_audio_packet_cb() + * @see mtpr_encoded_frame_cb() + */ +int mtpr_set_audio_packet_cb(mtpr_h mtpr, mtpr_encoded_frame_cb callback, void *user_data); + +/** + * @brief Unsets the encoded audio frame callback function. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @see mtpr_set_audio_packet_cb() + */ +int mtpr_unset_audio_packet_cb(mtpr_h mtpr); + +/** + * @brief Sets an encoded video frame callback function to be invoked when each video frame is ready to be rendered. + * @since_tizen 7.0 + * @remarks If @a callback is set, video data from the remote peer will be forwarded to @a callback without being rendered by itself.\n + * The registered callback will be invoked in an internal thread of the media transporter. + * @param[in] mtpr Media Transporter handle + * @param[in] callback Callback function pointer + * @param[in] user_data The user data to be passed to the callback function + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @post mtpr_encoded_frame_cb() will be invoked. + * @see mtpr_unset_video_packet_cb() + * @see mtpr_encoded_frame_cb() + */ +int mtpr_set_video_packet_cb(mtpr_h mtpr, mtpr_encoded_frame_cb callback, void *user_data); + +/** + * @brief Unsets the encoded video frame callback function. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @retval #MTPR_ERROR_INVALID_STATE Invalid state + * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. + * @see mtpr_set_video_packet_cb() + */ +int mtpr_unset_video_packet_cb(mtpr_h mtpr); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_TRANSPORTER_H__ */ + diff --git a/include/mtpr_internal.h b/include/mtpr_internal.h new file mode 100644 index 0000000..4ce0612 --- /dev/null +++ b/include/mtpr_internal.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_INTERNAL_H__ +#define __TIZEN_MEDIA_TRANSPORTER_INTERNAL_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** +* @file mtpr_internal.h +* @brief This file contains the Media Transporter internal API. +*/ + +/** + * @brief Media Transporter display handle type. + * @since_tizen 7.0 + * @remarks The pointer of this handle can be obtained from EFL UI API.\n + * For example, in case of #MTPR_DISPLAY_TYPE_OVERLAY, elm_win_add() can be used to get the window handle.\n + * In case of #MTPR_DISPLAY_TYPE_EVAS, evas_object_image_add() can be used to get the renderable image handle.\n + * For more details, please refer to https://docs.tizen.org/application/native/guides/ui/efl/. + */ +typedef void *mtpr_display_h; + + +/** + * @brief Enumeration for Media Transporter display type. + * @since_tizen 7.0 + */ +typedef enum { + MTPR_DISPLAY_TYPE_OVERLAY, /**< Overlay */ + MTPR_DISPLAY_TYPE_EVAS, /**< Evas image object */ +} mtpr_display_type_e; + +/** + * @brief Enumeration for Media Transporter display mode. + * @since_tizen 7.0 + */ +typedef enum { + MTPR_DISPLAY_MODE_LETTER_BOX, /**< Letter box */ + MTPR_DISPLAY_MODE_ORIGIN_SIZE, /**< Origin size */ + MTPR_DISPLAY_MODE_FULL, /**< Full screen */ +} mtpr_display_mode_e; + + +/** + * @brief Sets a display to the video track to be rendered. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] type The display type + * @param[in] display The display handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_set_display_mode() + * @see mtpr_get_display_mode() + * @see mtpr_set_display_visible() + * @see mtpr_get_display_visible() + */ +int mtpr_set_display(mtpr_h mtpr, mtpr_display_type_e type, mtpr_display_h display); + +/** + * @brief Sets the display mode of the video track. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] mode The display mode + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_get_display_mode() + */ +int mtpr_set_display_mode(mtpr_h mtpr, mtpr_display_mode_e mode); + +/** + * @brief Gets the display mode of the video track. + * @since_tizen 7.0 + * @remarks The default value is #MTPR_DISPLAY_MODE_LETTER_BOX. + * @param[in] mtpr Media Transporter handle + * @param[out] mode The display mode + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_set_display_mode() + */ +int mtpr_get_display_mode(mtpr_h mtpr, mtpr_display_mode_e *mode); + +/** + * @brief Sets the display visibleness of the video track. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] visible The display visibleness + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_get_display_visible() + */ +int mtpr_set_display_visible(mtpr_h mtpr, bool visible); + +/** + * @brief Gets the display visibleness of the video track. + * @since_tizen 7.0 + * @remarks The default value is @c true. + * @param[in] mtpr Media Transporter handle + * @param[out] visible The display visibleness + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_set_display_visible() + */ +int mtpr_get_display_visible(mtpr_h mtpr, bool *visible); + + +/** + * @brief Sets a video loopback to render the video frames of the media source. + * @details The following media source types are available for this function:\n + * #MTPR_SOURCE_TYPE_CAMERA\n + * #MTPR_SOURCE_TYPE_VIDEOTEST + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] source_id The video source id + * @param[in] type The display type + * @param[in] display The display handle + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @pre Add media source to @a mtpr to get @a source_id by calling mtpr_add_media_source(). + * @see mtpr_source_unset_video_loopback() + */ +int mtpr_source_set_video_loopback(mtpr_h mtpr, unsigned int source_id, mtpr_display_type_e type, mtpr_display_h display); + +/** + * @brief Unsets the video loopback. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] source_id The video source id + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + * @see mtpr_source_set_video_loopback() + */ +int mtpr_source_unset_video_loopback(mtpr_h mtpr, unsigned int source_id); + +/** + * @brief Sets a sound manager stream information to be rendered. + * @since_tizen 7.0 + * @param[in] mtpr Media Transporter handle + * @param[in] stream_info The sound stream information + * @return @c 0 on success, + * otherwise a negative error value + * @retval #MTPR_ERROR_NONE Successful + * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation + */ +int mtpr_set_sound_stream_info(mtpr_h mtpr, sound_stream_info_h stream_info); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TIZEN_MEDIA_TRANSPORTER_INTERNAL_H__ */ diff --git a/packaging/capi-media-transporter.manifest b/packaging/capi-media-transporter.manifest new file mode 100644 index 0000000..50f645f --- /dev/null +++ b/packaging/capi-media-transporter.manifest @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec new file mode 100644 index 0000000..5299603 --- /dev/null +++ b/packaging/capi-media-transporter.spec @@ -0,0 +1,135 @@ +Name: capi-media-transporter +Summary: A Media Transporter library in Tizen Native API +Version: 0.0.1 +Release: 0 +Group: Multimedia/API +License: Apache-2.0 +URL: http://source.tizen.org +Source0: %{name}-%{version}.tar.gz +Source1001: capi-media-transporter.manifest +BuildRequires: cmake +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(capi-base-common) +BuildRequires: pkgconfig(capi-media-tool) +BuildRequires: pkgconfig(gstreamer-1.0) +BuildRequires: pkgconfig(gstreamer-video-1.0) +BuildRequires: pkgconfig(gstreamer-audio-1.0) +BuildRequires: pkgconfig(gstreamer-rtsp-server-1.0) +BuildRequires: pkgconfig(libpulse) +BuildRequires: pkgconfig(appcore-efl) +BuildRequires: pkgconfig(elementary) +BuildRequires: pkgconfig(json-glib-1.0) +BuildRequires: pkgconfig(iniparser) +BuildRequires: pkgconfig(bundle) +BuildRequires: pkgconfig(mm-display-interface) +BuildRequires: pkgconfig(mm-common) +BuildRequires: pkgconfig(cynara-client) +BuildRequires: pkgconfig(libsmack) +BuildRequires: pkgconfig(capi-system-info) +BuildRequires: pkgconfig(capi-media-sound-manager) +BuildRequires: pkgconfig(mm-display-interface) +BuildRequires: pkgconfig(esplusplayer) +BuildRequires: pkgconfig(mm-resource-manager) +%if 0%{?gtests:1} +BuildRequires: pkgconfig(gmock) +%endif + +%description +A Media Transporter library in Tizen Native API. + +%package devel +Summary: Multimedia Media Transporter Library in Tizen Native API (Development) +Group: Multimedia/Development +Requires: %{name} = %{version}-%{release} + +%description devel +Media Transporter Library in Tizen Native API (DEV). + +%package tool +Summary: Tizen Media Transporter API testsuite +Requires: %{name} = %{version}-%{release} + +%description tool +Tizen Media Transporter API testsuite. + +%if 0%{?gcov:1} +%package gcov +Summary: Line Coverage files +Group: Development/Multimedia + +%description gcov +Collection of files related to line coverage using gcov. +%endif + +%prep +%setup -q +cp %{SOURCE1001} . + +%build +export CFLAGS+=" -DSYSCONFDIR=\\\"%{_hal_sysconfdir}\\\"" +export CXXFLAGS+=" -DSYSCONFDIR=\\\"%{_hal_sysconfdir}\\\"" + +%if 0%{?gcov:1} +export CFLAGS+=" -fprofile-arcs -ftest-coverage" +export CXXFLAGS+=" -fprofile-arcs -ftest-coverage" +export LDFLAGS+=" -lgcov" +%endif + +MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'` +%cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} -DFULLVER=%{version} -DMAJORVER=${MAJORVER} \ +%if "%{tizen_profile_name}" == "tv" +-DTIZEN_PROFILE_TV=on \ +%else +-DTIZEN_PROFILE_TV=off \ +%endif +%if 0%{?gtests:1} +-DMTPR_UNITTEST=ON +%endif + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +mkdir -p %{buildroot}%{_bindir} +mkdir -p %{buildroot}%{_hal_datadir} +cp test/mtpr_test %{buildroot}%{_bindir} +cp test/mtpr_rtsp_test %{buildroot}%{_bindir} + +%make_install +mkdir -p %{buildroot}%{_hal_sysconfdir}/multimedia + +%if 0%{?gcov:1} +builddir=$(basename $PWD) +gcno_obj_dir=%{buildroot}%{_datadir}/gcov/obj/%{name}/"$builddir" +mkdir -p "$gcno_obj_dir" +find . -name '*.gcno' -exec cp --parents '{}' "$gcno_obj_dir" ';' +%endif + +%post +/sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%manifest %{name}.manifest +%{_libdir}/lib%{name}.so.* +%license LICENSE.APLv2 + +%files devel +%{_includedir}/media/*.h +%{_libdir}/pkgconfig/*.pc +%{_libdir}/lib%{name}.so + +%files tool +%defattr(-,root,root,-) +%{_bindir}/mtpr_test +%{_bindir}/mtpr_rtsp_test +%if 0%{?gtests:1} +%{_bindir}/mtpr_ut +%endif + +%if 0%{?gcov:1} +%files gcov +%{_datadir}/gcov/obj/* +%endif diff --git a/src/MediaSourceBinAudioTest.cpp b/src/MediaSourceBinAudioTest.cpp new file mode 100644 index 0000000..145aad0 --- /dev/null +++ b/src/MediaSourceBinAudioTest.cpp @@ -0,0 +1,197 @@ +/** + * Copyright (c) 2022 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 "MediaSourceBinAudioTest.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterException.h" +#include "MediaTransporterParseIni.h" + +#include + +using namespace std; +using namespace tizen_media_transporter; + +MediaSourceBinAudioTest::MediaSourceBinAudioTest(bundle* params) +{ + // privilege check + parseSourceParam(params); +} + +void MediaSourceBinAudioTest::parseSourceParam(bundle* params) +{ + int written_count = 0; + char* string_val = NULL; + + RET_IF(!params, "input param is NULL"); + + /* Will be move to mic/audiotest bin */ + if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_CHANNEL, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _audioInfo.channel = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param audio channel %u", _audioInfo.channel); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_RATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _audioInfo.rate = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param audio rate %u", _audioInfo.rate); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_FORMAT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _audioInfo.format = string_val; + LOG_DEBUG("Source param audio format %s", _audioInfo.format.c_str()); + written_count++; + } + + if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _encInfo.bitrate = (guint)strtoul(string_val, NULL, 10); + LOG_DEBUG("Encoder target bitrate %u", _encInfo.bitrate); + written_count++; + } + + if (written_count == 0) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); +} + +GstElement* MediaSourceBinAudioTest::createMicSource() +{ + GstElement* audioSrc = nullptr; + + auto& ini = MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_AUDIOTEST)); + if (ini.sourceElement.empty()) { + audioSrc = gst::_createElement(DEFAULT_ELEMENT_AUDIO_TEST, "audioSrc"); + } else { + audioSrc = gst::_createElement(ini.sourceElement, "audioSrc"); + } + gst::_setElementProperties(audioSrc, ini.sourceElementProperties); + + return audioSrc; +} + +void MediaSourceBinAudioTest::setEncoderParam(gst::GstElements& elements) +{ + GstElement* encoder = gst::_findEncoderElement(elements); + if (!encoder) + return; + + if (_encInfo.bitrate) { + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), "bitrate")) + g_object_set(G_OBJECT(encoder), "bitrate", _encInfo.bitrate * 1000, NULL); + else + LOG_WARNING("%s element doesn't contain bitrate property", GST_ELEMENT_NAME(encoder)); + } +} + +void MediaSourceBinAudioTest::replaceCapsWithAudioInfo(GstElement* element) +{ + GstCaps* oldCaps; + auto& ini = MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_AUDIOTEST)); + GstAudioFormat format; + if (!_audioInfo.format.empty()) + format = gst::_getAudioFormatFromString(_audioInfo.format); + else + format = gst::_getAudioFormatFromString(ini.audioRawFormat); + + RET_IF(format == GST_AUDIO_FORMAT_UNKNOWN, "not supported raw format"); + + GstAudioInfo info; + int rate = _audioInfo.rate != -1 ? _audioInfo.rate : ini.audioSamplerate; + int channel = _audioInfo.channel != -1 ? _audioInfo.channel : ini.audioChannels; + gst_audio_info_set_format(&info, format, rate, channel, NULL); + GstCaps* newCaps = gst_audio_info_to_caps(&info); + + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + if (!gst_caps_is_equal(oldCaps, newCaps)) + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + + gst_caps_unref(newCaps); +} + +void MediaSourceBinAudioTest::replaceEncCapsWithAudioInfo(GstElement* element) +{ + GstCaps* oldCaps; + + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + RET_IF(!oldCaps, "capsfilter has no caps"); + + GstCaps* newCaps = gst_caps_copy(oldCaps); + + if (_audioInfo.channel != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _audioInfo.channel); + gst_caps_set_value(newCaps, "channels", &value); + } + + if (_audioInfo.rate != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _audioInfo.rate); + gst_caps_set_value(newCaps, "rate", &value); + } + + if (!gst_caps_is_equal(oldCaps, newCaps)) + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + + gst_caps_unref(newCaps); +} + +void MediaSourceBinAudioTest::setSourceParam(gst::GstElements& elements) +{ + GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); + if (srcCapsfilter) + replaceCapsWithAudioInfo(srcCapsfilter); + + GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); + if (encCapsfilter) + replaceEncCapsWithAudioInfo(encCapsfilter); +} + +MediaSourceBinInfo MediaSourceBinAudioTest::generate() +{ + gst::GstElements elements; + + try { + elements.push_back(createMicSource()); + elements.push_back(gst::_createElement("volume")); + + auto created = createAudioRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_AUDIOTEST))); + std::copy(created.begin(), created.end(), std::back_inserter(elements)); + + setSourceParam(elements); + setEncoderParam(elements); + } catch (const MediaTransporterException& e) { + gst::_clearElements(elements); + throw; + } + + GstBin* bin = GST_BIN(gst_bin_new("auditestbin")); + + try { + gst::_addElementsToBin(bin, elements); + gst::_linkElements(elements); + } catch (const MediaTransporterException& e) { + // FIXME: handle error nicely here + if (std::string { e.what() } == "Failed to link elements") + gst::_removeElementsFromBin(bin, elements); + + g_object_unref(bin); + + throw; + } + + return std::make_tuple(MTPR_SOURCE_TYPE_AUDIOTEST, bin, ResourceSet()); +} diff --git a/src/MediaSourceBinBase.cpp b/src/MediaSourceBinBase.cpp new file mode 100644 index 0000000..9bd3f13 --- /dev/null +++ b/src/MediaSourceBinBase.cpp @@ -0,0 +1,201 @@ +/** + * Copyright (c) 2022 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 "MediaSourceBinBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterParseIni.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif +#include "iniparser.h" +#ifdef __cplusplus +} +#endif + +using namespace tizen_media_transporter; + +static GstCaps *__makeVideoDefaultRawCaps(const MtprMediaSourceIni& ini) +{ + return gst_caps_new_simple(gst::MEDIA_TYPE_VIDEO_RAW.c_str(), + "format", G_TYPE_STRING, ini.videoRawFormat.c_str(), + "width", G_TYPE_INT, ini.videoWidth, + "height", G_TYPE_INT, ini.videoHeight, + NULL); +} + +static GstCaps *__makeAudioDefaultRawCaps(const MtprMediaSourceIni& ini) +{ + GstAudioFormat format = gst::_getAudioFormatFromString(ini.audioRawFormat); + RET_VAL_IF(format == GST_AUDIO_FORMAT_UNKNOWN, NULL, "not supported raw format"); + + GstAudioInfo info; + gst_audio_info_set_format(&info, format, ini.audioSamplerate, ini.audioChannels, NULL); + return gst_audio_info_to_caps(&info); +} + +static GstCaps *__makeVideoDefaultEncodedCaps(const MtprMediaSourceIni& ini) +{ + return gst::_getCapsFromEncodedVideoMediaType(gst::_getVideoMediaType(ini.videoCodec), + ini.videoWidth, ini.videoHeight); +} + +static GstCaps *__makeAudioDefaultEncodedCaps(const MtprMediaSourceIni& ini) +{ + return gst::_getCapsFromEncodedAudioMediaType(gst::_getAudioMediaType(ini.audioCodec), + ini.audioChannels, ini.audioSamplerate); +} + +static GstElement * _prepareVideoEncoder(const MtprMediaSourceIni& ini) +{ + if (!ini.videoHWEncoderElement.empty()) + return gst::_createElement(ini.videoHWEncoderElement); + + LOG_DEBUG("create sw encoder based on caps information"); + + return gst::_createElementFromRegistry("Codec/Encoder/Video", + __makeVideoDefaultRawCaps(ini), + __makeVideoDefaultEncodedCaps(ini), + MediaTransporterIni::get().general().gstExcludedElements); +} + +static GstElement * _prepareAudioEncoder(const MtprMediaSourceIni& ini) +{ + if (!ini.audioHWEncoderElement.empty()) + return gst::_createElement(ini.audioHWEncoderElement); + + LOG_DEBUG("create sw encoder based on caps information"); + return gst::_createElementFromRegistry("Codec/Encoder/Audio", + __makeAudioDefaultRawCaps(ini), + __makeAudioDefaultEncodedCaps(ini), + MediaTransporterIni::get().general().gstExcludedElements); +} + +std::vector MediaSourceBinBase::createVideoRestOfElements(const MtprMediaSourceIni& ini) +{ + std::vector elements; + + // FIXME: make this simple + + try { + // capsfilter + GstElement *capsfilter = gst::_createElement("capsfilter", ELEMENT_NAME_SRC_CAPSFILTER); + + GstCaps *sinkCaps = NULL; + if ((sinkCaps = __makeVideoDefaultRawCaps(ini))) { + gst::_printCaps(sinkCaps, ELEMENT_NAME_SRC_CAPSFILTER); + g_object_set(G_OBJECT(capsfilter), "caps", sinkCaps, NULL); + // source->render[idx].appsrc_caps = gst_caps_copy(sinkCaps); + gst_caps_unref(sinkCaps); + } + elements.push_back(capsfilter); + + // video convert + elements.push_back(gst::_createElement("videoconvert")); + + // encoder + GstElement *encoder = _prepareVideoEncoder(ini); + elements.push_back(encoder); + + // parser from encoder + std::string factory_name = GST_OBJECT_NAME(gst_element_get_factory(encoder)); + GstElement *parser = nullptr; + + if (factory_name.find("h264") != std::string::npos) + parser = gst::_createElement("h264parse"); + else if (factory_name.find("mpeg4") != std::string::npos) + parser = gst::_createElement("mpeg4videoparse"); + + if (parser) { + g_object_set(G_OBJECT(parser), "config-interval", -1, NULL); + elements.push_back(parser); + } + + // capsfilter2 + GstElement *capsfilter2 = gst::_createElement("capsfilter", ELEMENT_NAME_ENCODE_CAPSFILTER); + + sinkCaps = __makeVideoDefaultEncodedCaps(ini); + if (sinkCaps) { + gst::_printCaps(sinkCaps, ELEMENT_NAME_ENCODE_CAPSFILTER); + g_object_set(G_OBJECT(capsfilter2), "caps", sinkCaps, NULL); + gst_caps_unref(sinkCaps); + } + + elements.push_back(capsfilter2); + + // queue + GstElement *queue = gst::_createElement("queue", "srcQueue"); + g_object_set(G_OBJECT(queue), "max-size-buffers", 1, NULL); + elements.push_back(queue); + } catch (const MediaTransporterException& e) { + gst::_clearElements(elements); + throw; + } + + return elements; +} + +gst::GstElements MediaSourceBinBase::createAudioRestOfElements(const MtprMediaSourceIni& ini) +{ + gst::GstElements elements; + + // FIXME: make this simple + + try { + // capsfilter + GstElement* capsfilter = gst::_createElement("capsfilter", ELEMENT_NAME_SRC_CAPSFILTER); + + GstCaps* sinkCaps = NULL; + if ((sinkCaps = __makeAudioDefaultRawCaps(ini))) { + g_object_set(G_OBJECT(capsfilter), "caps", sinkCaps, NULL); + // source->render[idx].appsrc_caps = gst_caps_copy(sinkCaps); + gst_caps_unref(sinkCaps); + } + elements.push_back(capsfilter); + + // audio convert + elements.push_back(gst::_createElement("audioconvert")); + + // encoder + GstElement *encoder = _prepareAudioEncoder(ini); + elements.push_back(encoder); + + // capsfilter2 + GstElement *capsfilter2 = gst::_createElement("capsfilter", ELEMENT_NAME_ENCODE_CAPSFILTER); + + sinkCaps = __makeAudioDefaultEncodedCaps(ini); + if (sinkCaps) { + g_object_set(G_OBJECT(capsfilter2), "caps", sinkCaps, NULL); + gst_caps_unref(sinkCaps); + } + + elements.push_back(capsfilter2); + + // queue + GstElement *queue = gst::_createElement("queue", "srcQueue"); + g_object_set(G_OBJECT(queue), "max-size-buffers", 1, NULL); + elements.push_back(queue); + } catch (const MediaTransporterException& e) { + gst::_clearElements(elements); + throw; + } + + return elements; +} diff --git a/src/MediaSourceBinCamera.cpp b/src/MediaSourceBinCamera.cpp new file mode 100644 index 0000000..1143a5b --- /dev/null +++ b/src/MediaSourceBinCamera.cpp @@ -0,0 +1,213 @@ +/** + * Copyright (c) 2022 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 "MediaSourceBinCamera.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterException.h" +#include "MediaTransporterParseIni.h" + +#include + +using namespace std; +using namespace tizen_media_transporter; + +MediaSourceBinCamera::MediaSourceBinCamera(bundle* params) +{ + // privilege check + parseSourceParam(params); +} + +void MediaSourceBinCamera::parseSourceParam(bundle* params) +{ + int written_count = 0; + char* string_val = NULL; + + RET_IF(!params, "input param is NULL"); + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_WIDTH, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _videoInfo.width = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param video width %u", _videoInfo.width); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_HEIGHT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _videoInfo.height = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param video height %u", _videoInfo.height); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_FRAMERATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _videoInfo.frameRate = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param video framerate %u", _videoInfo.frameRate); + written_count++; + } + + if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _encInfo.bitrate = (guint)strtoul(string_val, NULL, 10); + LOG_DEBUG("Encoder target bitrate %u", _encInfo.bitrate); + written_count++; + } + + if (written_count == 0) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); +} + +GstElement* MediaSourceBinCamera::createCameraSource() +{ + GstElement* camerasrc = nullptr; + + auto& ini = MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_CAMERA)); + if (ini.sourceElement.empty()) { + camerasrc = gst::_createElement(DEFAULT_ELEMENT_CAMERASRC, "videoSrc"); + } else { + camerasrc = gst::_createElement(ini.sourceElement, "videoSrc"); + } + gst::_setElementProperties(camerasrc, ini.sourceElementProperties); + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(camerasrc)), "empty-buffer-timeout")) + g_object_set(G_OBJECT(camerasrc), "empty-buffer-timeout", 0, NULL); + + return camerasrc; +} + +void MediaSourceBinCamera::setEncoderParam(gst::GstElements& elements) +{ + GstElement* encoder = gst::_findEncoderElement(elements); + if (!encoder) + return; + + if (_encInfo.bitrate) { + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), "bitrate")) + g_object_set(G_OBJECT(encoder), "bitrate", _encInfo.bitrate * 1000, NULL); + else + LOG_WARNING("%s element doesn't contain bitrate property", GST_ELEMENT_NAME(encoder)); + } +} + +void MediaSourceBinCamera::replaceCapsWithVideoInfo(GstElement* element) +{ + GstCaps* oldCaps; + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + RET_IF(!oldCaps, "capsfilter has no caps"); + + GstCaps* newCaps = gst_caps_copy(oldCaps); + + if (_videoInfo.width != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _videoInfo.width); + gst_caps_set_value(newCaps, "width", &value); + } + + if (_videoInfo.height != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _videoInfo.height); + gst_caps_set_value(newCaps, "height", &value); + } + + if (_videoInfo.frameRate != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, GST_TYPE_FRACTION); + gst_value_set_fraction(&value, _videoInfo.frameRate, 1); + gst_caps_set_value(newCaps, "framerate", &value); + } + + if (!gst_caps_is_equal(oldCaps, newCaps)) { + gst::_printCaps(newCaps, "newCaps"); + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + } + + gst_caps_unref(newCaps); +} + +void MediaSourceBinCamera::replaceEncCapsWithVideoInfo(GstElement* element) +{ + GstCaps* oldCaps; + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + RET_IF(!oldCaps, "capsfilter has no caps"); + + GstCaps* newCaps = gst_caps_copy(oldCaps); + + if (_videoInfo.width != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _videoInfo.width); + gst_caps_set_value(newCaps, "width", &value); + } + + if (_videoInfo.height != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _videoInfo.height); + gst_caps_set_value(newCaps, "height", &value); + } + + if (!gst_caps_is_equal(oldCaps, newCaps)) { + gst::_printCaps(newCaps, "Change newCaps"); + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + } + + gst_caps_unref(newCaps); +} + +void MediaSourceBinCamera::setSourceParam(gst::GstElements& elements) +{ + GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); + if (srcCapsfilter) + replaceCapsWithVideoInfo(srcCapsfilter); + + GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); + if (encCapsfilter) + replaceEncCapsWithVideoInfo(encCapsfilter); +} + +MediaSourceBinInfo MediaSourceBinCamera::generate() +{ + gst::GstElements elements; + + try { + elements.push_back(createCameraSource()); + + auto created = createVideoRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_CAMERA))); // FIXME + std::copy(created.begin(), created.end(), std::back_inserter(elements)); + + setSourceParam(elements); + setEncoderParam(elements); + } catch (const MediaTransporterException& e) { + gst::_clearElements(elements); + throw; + } + + GstBin* bin = GST_BIN(gst_bin_new("camerabin")); + + try { + gst::_addElementsToBin(bin, elements); + gst::_linkElements(elements); + } catch (const MediaTransporterException& e) { + // FIXME: handle error nicely here + if (std::string { e.what() } == "Failed to link elements") + gst::_removeElementsFromBin(bin, elements); + + g_object_unref(bin); + throw; + } + + ResourceSet resourceRequired = { MM_RESOURCE_MANAGER_RES_TYPE_CAMERA }; + if (gst::_containHwEncoderElement(elements)) + resourceRequired.insert(MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER); + + return std::make_tuple(MTPR_SOURCE_TYPE_CAMERA, bin, resourceRequired); +} diff --git a/src/MediaSourceBinFactory.cpp b/src/MediaSourceBinFactory.cpp new file mode 100644 index 0000000..d51b8e6 --- /dev/null +++ b/src/MediaSourceBinFactory.cpp @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2022 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 "MediaSourceBinFactory.h" +#include "MediaSourceBinCamera.h" +#include "MediaSourceBinMic.h" +#include "MediaSourceBinVideoTest.h" +#include "MediaSourceBinAudioTest.h" + +using namespace tizen_media_transporter; + +IMediaSourceBin* MediaSourceBinFactory::create(mtprSourceType type, bundle* params) +{ + switch (type) + { + case MTPR_SOURCE_TYPE_CAMERA: + return static_cast(new MediaSourceBinCamera(params)); + case MTPR_SOURCE_TYPE_MIC: + return static_cast(new MediaSourceBinMic(params)); + case MTPR_SOURCE_TYPE_VIDEOTEST: + return static_cast(new MediaSourceBinVideoTest(params)); + case MTPR_SOURCE_TYPE_AUDIOTEST: + return static_cast(new MediaSourceBinAudioTest(params)); + default: + return NULL; + } +} diff --git a/src/MediaSourceBinMic.cpp b/src/MediaSourceBinMic.cpp new file mode 100644 index 0000000..45bfa91 --- /dev/null +++ b/src/MediaSourceBinMic.cpp @@ -0,0 +1,242 @@ +/** + * Copyright (c) 2022 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 "MediaSourceBinMic.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterException.h" +#include "MediaTransporterParseIni.h" + +#include +#include +#include +#include + +using namespace std; +using namespace tizen_media_transporter; + +MediaSourceBinMic::MediaSourceBinMic(bundle* params) +{ + // privilege check + parseSourceParam(params); +} + +void MediaSourceBinMic::parseSourceParam(bundle* params) +{ + int written_count = 0; + char* string_val = NULL; + + RET_IF(!params, "input param is NULL"); + + /* Will be move to mic/audiotest bin */ + if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_CHANNEL, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _audioInfo.channel = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param audio channel %u", _audioInfo.channel); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_RATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _audioInfo.rate = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param audio rate %u", _audioInfo.rate); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_FORMAT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _audioInfo.format = string_val; + LOG_DEBUG("Source param audio format %s", _audioInfo.format.c_str()); + written_count++; + } + + if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _encInfo.bitrate = (guint)strtoul(string_val, NULL, 10); + LOG_DEBUG("Encoder target bitrate %u", _encInfo.bitrate); + written_count++; + } + + if (written_count == 0) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); +} + +GstElement* MediaSourceBinMic::createMicSource() +{ + GstElement* audioSrc = nullptr; + + auto& ini = MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_MIC)); + if (ini.sourceElement.empty()) { + audioSrc = gst::_createElement(DEFAULT_ELEMENT_MICSRC, "audioSrc"); + } else { + audioSrc = gst::_createElement(ini.sourceElement, "audioSrc"); + } + gst::_setElementProperties(audioSrc, ini.sourceElementProperties); + + return audioSrc; +} + +void MediaSourceBinMic::setEncoderParam(gst::GstElements& elements) +{ + GstElement* encoder = gst::_findEncoderElement(elements); + if (!encoder) + return; + + if (_encInfo.bitrate) { + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), "bitrate")) + g_object_set(G_OBJECT(encoder), "bitrate", _encInfo.bitrate * 1000, NULL); + else + LOG_WARNING("%s element doesn't contain bitrate property", GST_ELEMENT_NAME(encoder)); + } +} + +void MediaSourceBinMic::replaceCapsWithAudioInfo(GstElement* element) +{ + GstCaps* oldCaps; + auto& ini = MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_MIC)); + GstAudioFormat format; + if (!_audioInfo.format.empty()) + format = gst::_getAudioFormatFromString(_audioInfo.format); + else + format = gst::_getAudioFormatFromString(ini.audioRawFormat); + + RET_IF(format == GST_AUDIO_FORMAT_UNKNOWN, "not supported raw format"); + + GstAudioInfo info; + int rate = _audioInfo.rate != -1 ? _audioInfo.rate : ini.audioSamplerate; + int channel = _audioInfo.channel != -1 ? _audioInfo.channel : ini.audioChannels; + gst_audio_info_set_format(&info, format, rate, channel, NULL); + GstCaps* newCaps = gst_audio_info_to_caps(&info); + + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + if (!gst_caps_is_equal(oldCaps, newCaps)) + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + + gst_caps_unref(newCaps); +} + +void MediaSourceBinMic::replaceEncCapsWithAudioInfo(GstElement* element) +{ + GstCaps* oldCaps; + + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + RET_IF(!oldCaps, "capsfilter has no caps"); + + GstCaps* newCaps = gst_caps_copy(oldCaps); + + if (_audioInfo.channel != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _audioInfo.channel); + gst_caps_set_value(newCaps, "channels", &value); + } + + if (_audioInfo.rate != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _audioInfo.rate); + gst_caps_set_value(newCaps, "rate", &value); + } + + if (!gst_caps_is_equal(oldCaps, newCaps)) + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + + gst_caps_unref(newCaps); +} + +void MediaSourceBinMic::setSourceParam(gst::GstElements& elements) +{ + GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); + if (srcCapsfilter) + replaceCapsWithAudioInfo(srcCapsfilter); + + GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); + if (encCapsfilter) + replaceEncCapsWithAudioInfo(encCapsfilter); +} + +MediaSourceBinInfo MediaSourceBinMic::generate() +{ + gst::GstElements elements; + + try { + GstElement* micSrcElement = createMicSource(); + gst::_applyStreamInfo(micSrcElement, _streamInfo); + elements.push_back(micSrcElement); + elements.push_back(gst::_createElement("volume")); + + auto created = createAudioRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_MIC))); + std::copy(created.begin(), created.end(), std::back_inserter(elements)); + + setSourceParam(elements); + setEncoderParam(elements); + } catch (const MediaTransporterException& e) { + gst::_clearElements(elements); + throw; + } + + GstBin* bin = GST_BIN(gst_bin_new("micbin")); + + try { + gst::_addElementsToBin(bin, elements); + gst::_linkElements(elements); + } catch (const MediaTransporterException& e) { + // FIXME: handle error nicely here + if (std::string { e.what() } == "Failed to link elements") + gst::_removeElementsFromBin(bin, elements); + + g_object_unref(bin); + + throw; + } + + return std::make_tuple(MTPR_SOURCE_TYPE_MIC, bin, ResourceSet()); +} + +void MediaSourceBinMic::setSoundStreamInfo(sound_stream_info_h streamInfo) +{ + char *stream_type; + int stream_index; + int aec_ref_device_id = 0; + // bool available = false; + + RET_IF(!streamInfo, "streamInfo is NULL"); + + sound_manager_get_type_from_stream_information(streamInfo, &stream_type); + sound_manager_get_index_from_stream_information(streamInfo, &stream_index); + sound_manager_get_echo_cancel_reference_device(streamInfo, &aec_ref_device_id); + + /* FIXEME: need to add NATIVE_API_MEDIATRANSPORTER in sound-manager */ + // ret = sound_manager_is_available_stream_information(stream_info, NATIVE_API_MEDIATRANSPORTER, &available); + // if (ret != SOUND_MANAGER_ERROR_NONE) { + // LOG_ERROR("failed to sound_manager_is_available_stream_information()"); + // return MTPR_ERROR_INVALID_OPERATION; + // } + + // if (!available) { + // LOG_ERROR("this stream info[%p, type:%s, index:%d] is not allowed to this framework", stream_info, stream_type, stream_index); + // return MTPR_ERROR_INVALID_PARAMETER; + // } + + RET_IF(!stream_type, "stream_type is NULL"); + + LOG_INFO("stream_info[%p, type:%s, index:%d, aec_ref_device_id:%d]", + streamInfo, stream_type, stream_index, aec_ref_device_id); + + ostringstream stringStream; + stringStream << "props," << PA_PROP_MEDIA_ROLE << "=" << + stream_type << ", " << PA_PROP_MEDIA_PARENT_ID << "=" << stream_index; + if (aec_ref_device_id != SOUND_MANAGER_STREAM_NO_REFERENCE_DEVICE) + stringStream << ", " << PA_PROP_MEDIA_ECHO_CANCEL_METHOD << "default, " + << PA_PROP_MEDIA_ECHO_CANCEL_REFERENCE_DEVICE << aec_ref_device_id; + + _streamInfo = stringStream.str(); +} diff --git a/src/MediaSourceBinVideoTest.cpp b/src/MediaSourceBinVideoTest.cpp new file mode 100644 index 0000000..972775c --- /dev/null +++ b/src/MediaSourceBinVideoTest.cpp @@ -0,0 +1,211 @@ +/** + * Copyright (c) 2022 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 "MediaSourceBinVideoTest.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterException.h" +#include "MediaTransporterParseIni.h" + +#include + +using namespace std; +using namespace tizen_media_transporter; + +MediaSourceBinVideoTest::MediaSourceBinVideoTest(bundle* params) +{ + // privilege check + parseSourceParam(params); +} + +void MediaSourceBinVideoTest::parseSourceParam(bundle* params) +{ + int written_count = 0; + char* string_val = NULL; + + RET_IF(!params, "input param is NULL"); + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_WIDTH, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _videoInfo.width = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param video width %u", _videoInfo.width); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_HEIGHT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _videoInfo.height = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param video height %u", _videoInfo.height); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_FRAMERATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _videoInfo.frameRate = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param video framerate %u", _videoInfo.frameRate); + written_count++; + } + + if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _encInfo.bitrate = (guint)strtoul(string_val, NULL, 10); + LOG_DEBUG("Encoder target bitrate %u", _encInfo.bitrate); + written_count++; + } + + if (written_count == 0) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); +} + +GstElement* MediaSourceBinVideoTest::createVideoTestSource() +{ + GstElement* videotestsrc = nullptr; + + auto& ini = MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_VIDEOTEST)); + if (ini.sourceElement.empty()) { + videotestsrc = gst::_createElement(DEFAULT_ELEMENT_VIDEO_TEST, "videoSrc"); + } else { + videotestsrc = gst::_createElement(ini.sourceElement, "videoSrc"); + } + gst::_setElementProperties(videotestsrc, ini.sourceElementProperties); + + return videotestsrc; +} + +void MediaSourceBinVideoTest::setEncoderParam(gst::GstElements& elements) +{ + GstElement* encoder = gst::_findEncoderElement(elements); + if (!encoder) + return; + + if (_encInfo.bitrate) { + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), "bitrate")) + g_object_set(G_OBJECT(encoder), "bitrate", _encInfo.bitrate * 1000, NULL); + else + LOG_WARNING("%s element doesn't contain bitrate property", GST_ELEMENT_NAME(encoder)); + } +} + +void MediaSourceBinVideoTest::replaceCapsWithVideoInfo(GstElement* element) +{ + GstCaps* oldCaps; + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + RET_IF(!oldCaps, "capsfilter has no caps"); + + GstCaps* newCaps = gst_caps_copy(oldCaps); + + if (_videoInfo.width != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _videoInfo.width); + gst_caps_set_value(newCaps, "width", &value); + } + + if (_videoInfo.height != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _videoInfo.height); + gst_caps_set_value(newCaps, "height", &value); + } + + if (_videoInfo.frameRate != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, GST_TYPE_FRACTION); + gst_value_set_fraction(&value, _videoInfo.frameRate, 1); + gst_caps_set_value(newCaps, "framerate", &value); + } + + if (!gst_caps_is_equal(oldCaps, newCaps)) { + gst::_printCaps(newCaps, "Change newCaps"); + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + } + + gst_caps_unref(newCaps); +} + +void MediaSourceBinVideoTest::replaceEncCapsWithVideoInfo(GstElement* element) +{ + GstCaps* oldCaps; + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + RET_IF(!oldCaps, "capsfilter has no caps"); + + GstCaps* newCaps = gst_caps_copy(oldCaps); + + if (_videoInfo.width != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _videoInfo.width); + gst_caps_set_value(newCaps, "width", &value); + } + + if (_videoInfo.height != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, _videoInfo.height); + gst_caps_set_value(newCaps, "height", &value); + } + + if (!gst_caps_is_equal(oldCaps, newCaps)) { + gst::_printCaps(newCaps, "Change newCaps"); + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + } + + gst_caps_unref(newCaps); +} + +void MediaSourceBinVideoTest::setSourceParam(gst::GstElements& elements) +{ + GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); + if (srcCapsfilter) + replaceCapsWithVideoInfo(srcCapsfilter); + + GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); + if (encCapsfilter) + replaceEncCapsWithVideoInfo(encCapsfilter); +} + +MediaSourceBinInfo MediaSourceBinVideoTest::generate() +{ + gst::GstElements elements; + + try { + elements.push_back(createVideoTestSource()); + + auto created = createVideoRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_VIDEOTEST))); // FIXME + std::copy(created.begin(), created.end(), std::back_inserter(elements)); + + setSourceParam(elements); + setEncoderParam(elements); + } catch (const MediaTransporterException& e) { + gst::_clearElements(elements); + throw; + } + + GstBin* bin = GST_BIN(gst_bin_new("videotestbin")); + + try { + gst::_addElementsToBin(bin, elements); + gst::_linkElements(elements); + } catch (const MediaTransporterException& e) { + // FIXME: handle error nicely here + if (std::string { e.what() } == "Failed to link elements") + gst::_removeElementsFromBin(bin, elements); + + g_object_unref(bin); + throw; + } + + ResourceSet resourceRequired; + if (gst::_containHwEncoderElement(elements)) + resourceRequired.insert(MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER); + + return std::make_tuple(MTPR_SOURCE_TYPE_VIDEOTEST, bin, resourceRequired); +} diff --git a/src/MediaTransporter.cpp b/src/MediaTransporter.cpp new file mode 100644 index 0000000..123c820 --- /dev/null +++ b/src/MediaTransporter.cpp @@ -0,0 +1,624 @@ + +#include "MediaTransporter.h" + +#include "MediaTransporterLog.h" +#include "MediaTransporterFactory.h" +#include "MediaSourceBinFactory.h" +#include "MediaTransporterException.h" +#include "MediaTransporterSender.h" +#include "MediaTransporterReceiver.h" +#include "MediaSourceBinMic.h" + +#include +#include + +using namespace tizen_media_transporter; + +typedef struct { + std::unique_ptr base; + std::shared_ptr resourceManager; + std::shared_ptr display; +} media_transporter_s; + +int mtpr_create(mtpr_connection_type_e type, mtpr_h* mtpr) +{ + auto handle = new media_transporter_s; + RET_VAL_IF(!handle, MTPR_ERROR_INVALID_OPERATION, "Failed to allocate handle!!!"); + + try { + handle->base = std::unique_ptr( + MediaTransporterFactory::create(static_cast(type))); + RET_ERR_IF_INVALID_INSTANCE(handle->base); + + handle->base->create(); + LOG_INFO("base instance %p created", handle->base.get()); + + handle->resourceManager = std::make_shared(); + handle->base->setResourceManager(handle->resourceManager); + + *mtpr = handle; + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to create!!! : %s", e.what()); + delete handle; + return e.error(); + } + return MTPR_ERROR_NONE; +} + +int mtpr_destroy(mtpr_h mtpr) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + handle->base->destroy(); + delete handle; + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to destroy!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_start(mtpr_h mtpr) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + assert(handle->resourceManager); + + try { + ResourceSet rs = handle->base->build(); + handle->resourceManager->acquire(rs); + handle->base->start(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to start!!! : %s", e.what()); + handle->resourceManager->releaseAll(); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_stop(mtpr_h mtpr) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + handle->base->stop(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to stop!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_get_state(mtpr_h mtpr, mtpr_state_e *state) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + *state = handle->base->state(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to stop!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_get_connection_type(mtpr_h mtpr, mtpr_connection_type_e *type) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + *type = handle->base->type(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to create!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_sender_address(mtpr_h mtpr, const char *address) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + handle->base->setSenderAddress(address); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to set sender address!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_get_sender_address(mtpr_h mtpr, char **address) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(address); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + std::string senderAddress = handle->base->getSenderAddress(); + if (senderAddress.empty()) { + *address = NULL; + return MTPR_ERROR_INVALID_OPERATION; + } + *address = strdup(senderAddress.c_str()); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to set sender address!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_receiver_address(mtpr_h mtpr, const char *address) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + handle->base->setReceiverAddress(address); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to set sender address!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_get_receiver_address(mtpr_h mtpr, char **address) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(address); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + std::string receiverAddress = handle->base->getReceiverAddress(); + if (receiverAddress.empty()) { + *address = NULL; + return MTPR_ERROR_INVALID_OPERATION; + } + *address = strdup(receiverAddress.c_str()); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to set sender address!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_connection_param(mtpr_h mtpr, const char *param_name, const char *param_value) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + handle->base->setConnection(param_name, param_value); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to set connection param!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_connection_params(mtpr_h mtpr, bundle *param_list) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + handle->base->setConnection(param_list); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to set connection params!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_get_connection_params(mtpr_h mtpr, bundle **param_list) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + bundle *params = NULL; + try { + auto handle = static_cast(mtpr); + assert(handle->base); + params = bundle_create(); + RET_VAL_IF(!params, MTPR_ERROR_INVALID_OPERATION, "created param_list is NULL!!!"); + handle->base->getConnection(params); + *param_list = params; + } catch (const MediaTransporterException& e) { + if (params) + bundle_free(params); + LOG_ERROR("Failed to get connection params!!! : %s", e.what()); + return e.error(); + } + return MTPR_ERROR_NONE; +} + +int mtpr_add_media_source(mtpr_h mtpr, mtpr_source_type_e type, bundle* param_list, unsigned int *source_id) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_VAL_IF(!source_id, MTPR_ERROR_INVALID_PARAMETER, "invalid id ptr"); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterSender* sender = dynamic_cast(handle->base.get()); + RET_VAL_IF(!sender, MTPR_ERROR_INVALID_OPERATION, "only sender support this api!!!"); + + try { + *source_id = sender->addMediaSource(MediaSourceBinFactory::create(type, param_list)); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to add media source!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_remove_media_source(mtpr_h mtpr, unsigned int source_id) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterSender* sender = dynamic_cast(handle->base.get()); + RET_VAL_IF(!sender, MTPR_ERROR_INVALID_OPERATION, "only sender support this api!!!"); + + try { + sender->removeMediaSource(static_cast(source_id)); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to remove media source!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_mic_source_set_sound_stream_info(mtpr_h mtpr, unsigned int source_id, sound_stream_info_h stream_info) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + try { + MediaTransporterSender* sender = dynamic_cast(handle->base.get()); + RET_VAL_IF(!sender, MTPR_ERROR_INVALID_OPERATION, "only sender support this api!!!"); + + MediaSourceBinMic* micSourceBin = dynamic_cast(sender->getMediaSource(source_id)); + RET_VAL_IF(!micSourceBin, MTPR_ERROR_INVALID_PARAMETER, "Invalid source id"); + + micSourceBin->setSoundStreamInfo(stream_info); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to mic set sound stream info!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_error_cb(mtpr_h mtpr, mtpr_error_cb callback, void *user_data) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + handle->base->setErrorCallback(mtpr, callback, user_data); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to setErrorCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_unset_error_cb(mtpr_h mtpr) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + try { + auto handle = static_cast(mtpr); + assert(handle->base); + handle->base->unsetErrorCallback(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to unsetErrorCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_track_added_cb(mtpr_h mtpr, mtpr_track_added_cb callback, void* user_data) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + receiver->setTrackAddedCallback(mtpr, callback, user_data); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to setNoMoreTrackCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_unset_track_added_cb(mtpr_h mtpr) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + receiver->unsetTrackAddedCallback(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to unsetNoMoreTrackCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_no_more_track_cb(mtpr_h mtpr, mtpr_no_more_track_cb callback, void* user_data) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + receiver->setNoMoreTrackCallback(mtpr, callback, user_data); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to setNoMoreTrackCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_unset_no_more_track_cb(mtpr_h mtpr) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + receiver->unsetNoMoreTrackCallback(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to unsetNoMoreTrackCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_audio_packet_cb(mtpr_h mtpr, mtpr_encoded_frame_cb callback, void* user_data) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + receiver->setAudioPacketCallback(mtpr, callback, user_data);//__internal_audio_packet_cb, static_cast(handle)); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to setAudioPacketCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_unset_audio_packet_cb(mtpr_h mtpr) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + receiver->unsetAudioPacketCallback(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to unsetAudioPacketCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_video_packet_cb(mtpr_h mtpr, mtpr_encoded_frame_cb callback, void* user_data) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + receiver->setVideoPacketCallback(mtpr, callback, user_data); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to setVideoPacketCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_unset_video_packet_cb(mtpr_h mtpr) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + receiver->unsetVideoPacketCallback(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to unsetVideoPacketCallback!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_display(mtpr_h mtpr, mtpr_display_type_e type, mtpr_display_h display) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + handle->display = std::make_shared(type, display); + receiver->setDisplay(handle->display); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to mtpr_set_display!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_display_mode(mtpr_h mtpr, mtpr_display_mode_e mode) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + RET_VAL_IF(!handle->display, MTPR_ERROR_INVALID_OPERATION, "display is not set yet!!!"); + + try { + handle->display->setMode(mode); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to set modeq!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_get_display_mode(mtpr_h mtpr, mtpr_display_mode_e *mode) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + RET_VAL_IF(!handle->display, MTPR_ERROR_INVALID_OPERATION, "display is not set yet!!!"); + + try { + *mode = handle->display->getMode(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to get Mode!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_display_visible(mtpr_h mtpr, bool visible) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + RET_VAL_IF(!handle->display, MTPR_ERROR_INVALID_OPERATION, "display is not set yet!!!"); + + try { + handle->display->setVisible(visible); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to set visible!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_get_display_visible(mtpr_h mtpr, bool *visible) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + RET_VAL_IF(!handle->display, MTPR_ERROR_INVALID_OPERATION, "display is not set yet!!!"); + + try { + *visible = handle->display->getVisible(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to get visible!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} + +int mtpr_set_sound_stream_info(mtpr_h mtpr, sound_stream_info_h stream_info) +{ + RET_ERR_IF_INVALID_INSTANCE(mtpr); + + auto handle = static_cast(mtpr); + assert(handle->base); + + MediaTransporterReceiver* receiver = dynamic_cast(handle->base.get()); + RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!"); + + try { + receiver->setSoundStreamInfo(stream_info); + } catch (const MediaTransporterException& e) { + LOG_ERROR("Failed to setSoundStreamInfo!!! : %s", e.what()); + return e.error(); + } + + return MTPR_ERROR_NONE; +} diff --git a/src/MediaTransporterBase.cpp b/src/MediaTransporterBase.cpp new file mode 100644 index 0000000..681a805 --- /dev/null +++ b/src/MediaTransporterBase.cpp @@ -0,0 +1,244 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterGst.h" + +using namespace tizen_media_transporter; + +gboolean MediaTransporterBase::__busWatchCb(GstBus *bus, GstMessage *message, gpointer user_data) +{ + auto base = static_cast(user_data); + RET_VAL_IF(!base, FALSE, "base is NULL"); + + GError* err = NULL; + GstState gst_state_old = GST_STATE_VOID_PENDING; + GstState gst_state_new = GST_STATE_VOID_PENDING; + GstState gst_state_pending = GST_STATE_VOID_PENDING; + + RET_VAL_IF(!base->_gst.pipeline, FALSE, "pipeline is NULL"); + + if (!message) { + LOG_DEBUG("message is null"); + return TRUE; + } + + switch (GST_MESSAGE_TYPE(message)) { + case GST_MESSAGE_ERROR: { + mtpr_error_e error = MTPR_ERROR_INVALID_OPERATION; + gst_message_parse_error(message, &err, NULL); + + LOG_ERROR("Error[from %s]: message[%s], code[%d]", + GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC(message)))), err->message, err->code); + + // FIXME : convert err -> error + if (base->_errorCallback) + base->_errorCallback->invoke(VariantData{error}); + + g_error_free(err); + break; + } + + case GST_MESSAGE_STATE_CHANGED: + if (GST_MESSAGE_SRC(message) != GST_OBJECT(base->_gst.pipeline)) + return TRUE; + + gst_message_parse_state_changed(message, &gst_state_old, &gst_state_new, &gst_state_pending); + LOG_INFO("GST_MESSAGE_STATE_CHANGED : Old[GST_STATE_%s] New[GST_STATE_%s] Pending[GST_STATE_%s]", + gst_element_state_get_name(gst_state_old), + gst_element_state_get_name(gst_state_new), + gst_element_state_get_name(gst_state_pending)); + break; + + case GST_MESSAGE_ASYNC_DONE: + if (GST_MESSAGE_SRC(message) != GST_OBJECT(base->_gst.pipeline)) + return TRUE; + + LOG_INFO("GST_MESSAGE_ASYNC_DONE"); + break; + + case GST_MESSAGE_EOS: + LOG_INFO("GST_MESSAGE_EOS end-of-stream"); + break; + + default: + break; + } + + return TRUE; +} + +void MediaTransporterBase::makePipeline() +{ + MTPR_FENTER(); + _gst.pipeline = gst_pipeline_new("mtpr-pipeline"); + if (!(_gst.bus = gst_pipeline_get_bus(GST_PIPELINE(_gst.pipeline)))) { + LOG_ERROR("failed to gst_pipeline_get_bus()"); + return; + } + + if ((_gst.bus_watcher = gst_bus_add_watch(_gst.bus, __busWatchCb, this)) == 0) { + LOG_ERROR("failed to gst_bus_add_watch()"); + return; + } + MTPR_FLEAVE(); +} + +void MediaTransporterBase::create() +{ + gst::_gstInit(); + makePipeline(); + + _state = MTPR_STATE_IDLE; +} + +ResourceSet MediaTransporterBase::build() +{ + std::lock_guard mutex(_mutex); + + if (_state != MTPR_STATE_IDLE) + throw MediaTransporterException(MTPR_ERROR_INVALID_STATE, "state must be IDLE"); + + return buildPipeline(); +} + +void MediaTransporterBase::start() +{ + std::lock_guard mutex(_mutex); + + if (_state != MTPR_STATE_IDLE) + throw MediaTransporterException(MTPR_ERROR_INVALID_STATE, "state must be IDLE"); + + startPipeline(); + _state = MTPR_STATE_PLAYING; +} + +void MediaTransporterBase::stopInternal() +{ + try { + stopPipeline(); + _state = MTPR_STATE_IDLE; + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + throw; + } +} + +void MediaTransporterBase::stop() +{ + std::lock_guard mutex(_mutex); + + if (_state != MTPR_STATE_PLAYING) + throw MediaTransporterException(MTPR_ERROR_INVALID_STATE, "state must be PLAYING"); + + stopInternal(); +} + +void MediaTransporterBase::destroy() +{ + stopInternal(); + + try { + if (_gst.bus_watcher > 0) { + gst_bus_remove_watch(_gst.bus); + _gst.bus_watcher = 0; + } + + if (_gst.bus) { + gst_object_unref(_gst.bus); + _gst.bus = NULL; + } + + if (_gst.signals) { + g_list_free_full(_gst.signals, gst::_disconnectSignal); + _gst.signals = NULL; + } + + if (_gst.pipeline) { + gst_object_unref(_gst.pipeline); + _gst.pipeline = NULL; + } + + _resourceManager->unsubscribe(this); + + // _mtpr_destroy_resource_manager(); + // _mtpr_release_connection_params(); + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + throw; + } +} + +mtprState MediaTransporterBase::state() +{ + return _state; +} + +void MediaTransporterBase::setSenderAddress(std::string address) +{ + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, + "not supported, set receiver address instead!"); +} + +void MediaTransporterBase::setReceiverAddress(std::string address) +{ + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, + "not supported, set sender address instead!"); +} + +std::string MediaTransporterBase::getSenderAddress() +{ + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, + "not supported, get receiver address instead!"); +} + +std::string MediaTransporterBase::getReceiverAddress() +{ + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, + "not supported, get sender address instead!"); +} + +void MediaTransporterBase::setErrorCallback(void* handle, mtprErrorCallback callback, void* userData) +{ + _errorCallback = std::unique_ptr(new ErrorCallback(handle, callback, userData)); +} + +void MediaTransporterBase::unsetErrorCallback() +{ + _errorCallback = nullptr; +} + +void MediaTransporterBase::setResourceManager(std::shared_ptr resourceManager) +{ + _resourceManager = resourceManager; + _resourceManager->subscribe(this); +} + +void MediaTransporterBase::changed() +{ + try { + stopInternal(); + if (_errorCallback) + _errorCallback->invoke(VariantData{MTPR_ERROR_RESOURCE_CONFLICT}); + } catch (const MediaTransporterException& e) { + LOG_ERROR("error : %s", e.what()); + //return false; + } + + //return true; +} diff --git a/src/MediaTransporterCallback.cpp b/src/MediaTransporterCallback.cpp new file mode 100644 index 0000000..9df9feb --- /dev/null +++ b/src/MediaTransporterCallback.cpp @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterCallback.h" +#include "MediaTransporterLog.h" + +using namespace tizen_media_transporter; + +TrackAddedCallback::TrackAddedCallback(void* handle, mtprTrackAddedCallback cb, void* userdata) + : AbstractCallback(handle, userdata), _callback(cb) +{ + LOG_DEBUG(">>> callback[%p], handle[%p], user_data[%p] registered", + cb, handle, userdata); +} + +void TrackAddedCallback::invoke(VariantData data1, VariantData data2) +{ + auto mediaType = std::get(data1); + auto trackId = std::get(data2); + + LOG_DEBUG(">>> callback[%p], mediaType[%d], trackId[%u], handle[%p], user_data[%p]", + _callback, mediaType, trackId, _handle, _userdata); + + _callback(_handle, mediaType, trackId, _userdata); +} + +NoMoreTrackCallback::NoMoreTrackCallback(void* handle, mtprNoMoreTrackCallback cb, void* userdata) + : AbstractCallback(handle, userdata), _callback(cb) +{ + LOG_DEBUG(">>> callback[%p], handle[%p], user_data[%p] registered", + cb, handle, userdata); +} + +void NoMoreTrackCallback::invoke() +{ + LOG_DEBUG(">>> callback[%p], handle[%p], user_data[%p]", + _callback, _handle, _userdata); + + _callback(_handle, _userdata); +} + +PacketCallback::PacketCallback(void* handle, mtprMediaType type, mtprPacketCallback cb, void* userdata) + : AbstractCallback(handle, userdata), _type(type), _callback(cb) +{ + LOG_DEBUG(">>> callback[%p], handle[%p], user_data[%p] registered", + cb, handle, userdata); +} + +void PacketCallback::invoke(VariantData data1, VariantData data2) +{ + auto trackId = std::get(data1); + auto packet = std::get(data2); + + LOG_VERBOSE(">>> callback[%p], handle[%p], type[%d], id[%d], packet[%p], user_data[%p]", + _callback, _handle, _type, trackId, packet, _userdata); + + _callback(_handle, _type, trackId, packet, _userdata); +} + +ErrorCallback::ErrorCallback(void* handle, mtprErrorCallback cb, void* userdata) + : AbstractCallback(handle, userdata), _callback(cb) +{ + LOG_DEBUG(">>> callback[%p], handle[%p], user_data[%p] registered", + cb, handle, userdata); +} + +void ErrorCallback::invoke(VariantData data) +{ + auto error = std::get(data); + + LOG_DEBUG(">>> callback[%p], handle[%p], error[%d], user_data[%p]", + _callback, _handle, error, _userdata); + + _callback(_handle, error, _userdata); +} \ No newline at end of file diff --git a/src/MediaTransporterDisplay.cpp b/src/MediaTransporterDisplay.cpp new file mode 100644 index 0000000..04fc8ad --- /dev/null +++ b/src/MediaTransporterDisplay.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2022 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 "MediaTransporter.h" +#include "MediaTransporterDisplay.h" +#include "MediaTransporterException.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterParseIni.h" +#include "MediaTransporterGst.h" + +using namespace tizen_media_transporter; + +MediaTransporterDisplay::MediaTransporterDisplay(mtprDisplayType type, void *surface) + : _type(type), _surface(surface) +{ + if (!surface) + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "surface is NULL"); + + if (mm_display_interface_init(&_mmDisplay) != MM_ERROR_NONE) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to mm_display_interface_init()"); + + LOG_INFO("display[type:%d, surface:%p]", _type, _surface); + LOG_DEBUG("alloc display[mmDisplay:%p, mode:%u, visible:%u]", _mmDisplay, _mode, _visible); +} + +MediaTransporterDisplay::~MediaTransporterDisplay() +{ + LOG_DEBUG("mmDisplay[%p]", _mmDisplay); + + if (mm_display_interface_deinit(_mmDisplay) != MM_ERROR_NONE) + LOG_WARNING("failed to mm_display_interface_deinit()"); + + if (_sinkElement) { + gst_object_unref(_sinkElement); + _sinkElement = nullptr; + } +} + +GstElement* MediaTransporterDisplay::videoSink() +{ + std::lock_guard mutex(_mutex); + + try { + switch (_type) { + case MTPR_DISPLAY_TYPE_OVERLAY: + LOG_INFO("it's OVERLAY type"); + break; + default: + LOG_ERROR_IF_REACHED("type(%d)", _type); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "_display is NULL"); + break; + } + + std::string videoSinkName = MediaTransporterIni::get().renderingSink().videoSinkElement; + _sinkElement = gst::_createElement(videoSinkName); + applyModeProperty(); + applyVisibleProperty(); + + int overlaySurfaceId = -1; + if (mm_display_interface_set_display_mainloop_sync(_mmDisplay, MM_DISPLAY_TYPE_OVERLAY, _surface, &overlaySurfaceId) != MM_ERROR_NONE) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to mm_display_interface_set_display_mainloop_sync()"); + + LOG_INFO("surface[%p], got overlaySurfaceId[%d]", _surface, overlaySurfaceId); + gst_video_overlay_set_wl_window_wl_surface_id(GST_VIDEO_OVERLAY(_sinkElement), overlaySurfaceId); + + return GST_ELEMENT(gst_object_ref(_sinkElement)); + } catch (const MediaTransporterException& e) { + if (_sinkElement) { + gst_object_unref(_sinkElement); + _sinkElement = nullptr; + } + + throw; + } +} + +void MediaTransporterDisplay::setVisible(bool visible) +{ + std::lock_guard mutex(_mutex); + + _visible = visible; + + if (_sinkElement) + applyVisibleProperty(); +} + +void MediaTransporterDisplay::setMode(mtprDisplayMode mode) +{ + std::lock_guard mutex(_mutex); + + _mode = mode; + + if (_sinkElement) + applyModeProperty(); +} + +void MediaTransporterDisplay::applyVisibleProperty() +{ + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(_sinkElement)), "visible")) + g_object_set(G_OBJECT(_sinkElement), + "visible", _visible, NULL); +} + +void MediaTransporterDisplay::applyModeProperty() +{ + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(_sinkElement)), "display-geometry-method")) + g_object_set(G_OBJECT(_sinkElement), + "display-geometry-method", (gint)_mode, /* 0: letter box, 1: origin size, 2: full screen */ + NULL); +} \ No newline at end of file diff --git a/src/MediaTransporterFactory.cpp b/src/MediaTransporterFactory.cpp new file mode 100644 index 0000000..27cdfee --- /dev/null +++ b/src/MediaTransporterFactory.cpp @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterFactory.h" +#include "MediaTransporterSenderRist.h" +#include "MediaTransporterSenderSrt.h" +#include "MediaTransporterSenderRtsp.h" +#include "MediaTransporterSenderToServerRtsp.h" +#include "MediaTransporterReceiverRist.h" +#include "MediaTransporterReceiverSrt.h" + +using namespace tizen_media_transporter; + +MediaTransporterBase* MediaTransporterFactory::create(mtprConnectionType type) +{ + switch (type) + { + case MTPR_CONNECTION_TYPE_RIST_SENDER: + return static_cast(new MediaTransporterSenderRist()); + case MTPR_CONNECTION_TYPE_RIST_RECEIVER: + return static_cast(new MediaTransporterReceiverRist()); + case MTPR_CONNECTION_TYPE_SRT_SENDER: + return static_cast(new MediaTransporterSenderSrt()); + case MTPR_CONNECTION_TYPE_SRT_RECEIVER: + return static_cast(new MediaTransporterReceiverSrt()); + case MTPR_CONNECTION_TYPE_RTSP_SENDER: + return static_cast(new MediaTransporterSenderRtsp()); + case MTPR_CONNECTION_TYPE_RTSP_SENDER_TO_SERVER: + return static_cast(new MediaTransporterSenderToServerRtsp()); + default: + return NULL; + } + return NULL; +} diff --git a/src/MediaTransporterGst.cpp b/src/MediaTransporterGst.cpp new file mode 100644 index 0000000..5929c7a --- /dev/null +++ b/src/MediaTransporterGst.cpp @@ -0,0 +1,743 @@ +/* + * Copyright (c) 2022 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 "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterException.h" +#include "MediaTransporterParseIni.h" + +using namespace tizen_media_transporter; + +void gst::_clearElements(GstElements& elements) +{ + std::for_each(elements.begin(), elements.end(), + [](GstElement*element){ gst_object_unref(element); }); +} + +void gst::_removeElement(GstElements& elements, GstElement* removeElement) +{ + auto it = std::find_if(elements.begin(), elements.end(), + [&removeElement](GstElement* element) { + return (element == removeElement) ? true : false; + }); + elements.erase(it); +} + +GstElement* gst::_createElement(std::string factory_name, std::string name) +{ + GstElement* element = gst_element_factory_make(factory_name.c_str(), name.empty() ? NULL : name.c_str()); + if (!element) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to create element"); + + LOG_INFO("created element[%p, %s, %s]", + element, factory_name.c_str(), name.c_str()); + + return element; +} + +void gst::_connectAndAppendSignal(GList** signals, GObject* obj, const char* sig_name, GCallback cb, gpointer user_data) +{ + auto sig_data = static_cast(g_malloc0(sizeof(gst::mtprSignal))); + sig_data->obj = obj; + sig_data->signal_id = g_signal_connect(sig_data->obj, sig_name, cb, user_data); + if (sig_data->signal_id == 0) { + LOG_ERROR("failed to g_signal_connect(), [%s] for object [%s]", + sig_name, GST_OBJECT_NAME(obj)); + g_free(sig_data); + return; + } + + *signals = g_list_append(*signals, sig_data); + + LOG_DEBUG("signal [%s] with id[%lu] is connected to object [%s]", + sig_name, sig_data->signal_id, GST_OBJECT_NAME(sig_data->obj)); +} + +void gst::_disconnectSignal(gpointer data) +{ + auto sig_data = static_cast(data); + + RET_IF(!sig_data, "sig_data is NULL"); + + if (g_signal_handler_is_connected(sig_data->obj, sig_data->signal_id)) { + g_signal_handler_disconnect(sig_data->obj, sig_data->signal_id); + LOG_DEBUG("signal with id[%lu] is disconnected from object [%s]", + sig_data->signal_id, GST_OBJECT_NAME(sig_data->obj)); + } + + g_free(sig_data); +} + +bool gst::_addNoTargetGhostpad(GstBin* bin, GstPad** new_pad, bool is_src) +{ + RET_VAL_IF(!bin, false, "bin is NULL"); + RET_VAL_IF(!new_pad, false, "new_pad is NULL"); + + GstPad* ghost_pad = gst_ghost_pad_new_no_target(NULL, is_src ? GST_PAD_SRC : GST_PAD_SINK); + if (!ghost_pad) { + LOG_ERROR("failed to gst_ghost_pad_new_no_target()"); + return false; + } + + gchar* bin_name = gst_element_get_name(bin); + if (!gst_element_add_pad(GST_ELEMENT(bin), ghost_pad)) { + LOG_ERROR("failed to add empty [%s] ghostpad into [%s]", GST_PAD_NAME(ghost_pad), bin_name); + g_object_unref(ghost_pad); + g_free(bin_name); + return false; + } + + gst_pad_set_active(ghost_pad, TRUE); + LOG_DEBUG("added [%s] empty ghostpad into [%s]", GST_PAD_NAME(ghost_pad), bin_name); + g_free(bin_name); + + *new_pad = ghost_pad; + + return true; +} + +bool gst::_setGhostpadTarget(GstPad* ghost_pad, GstElement* target_element, bool is_src) +{ + RET_VAL_IF(!ghost_pad, false, "ghost_pad is NULL"); + RET_VAL_IF(!target_element, false, "target_element is NULL"); + + GstPad* target_pad = gst_element_get_static_pad(target_element, is_src ? "src" : "sink"); + + if (!target_pad) { + LOG_ERROR("failed to gst_element_get_static_pad() of [%s]", + GST_ELEMENT_NAME(target_element)); + return false; + } + if (!gst_ghost_pad_set_target(GST_GHOST_PAD(ghost_pad), target_pad)) { + LOG_ERROR("failed to gst_ghost_pad_set_target(), ghostpad[%s] -> targetpad[%s]", + GST_PAD_NAME(ghost_pad), GST_PAD_NAME(target_pad)); + gst_object_unref(target_pad); + return false; + } + + LOG_DEBUG("ghostpad[%s] -> target[%s:%s]", + GST_PAD_NAME(ghost_pad), GST_ELEMENT_NAME(target_element), GST_PAD_NAME(target_pad)); + + gst_object_unref(target_pad); + + return true; +} + +void gst::_removeElementsFromBin(GstBin* bin, GstElements& elements) +{ + for (auto element : elements) + if (!gst_bin_remove(bin, element)) + return; + + LOG_DEBUG("%zu elements are removed from bin[%s]", elements.size(), GST_ELEMENT_NAME(bin)); +} + +void gst::_addElementsToBin(GstBin* bin, GstElements elements) +{ + GstElements addedElements; + + for (auto iter = elements.begin(); iter != elements.end(); iter++) { + GstElement* element = *iter; + if (!gst_bin_add(bin, element)) { + LOG_ERROR("failed to gst_bin_add(), bin[%s], element[%s]", + GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(element)); + + _removeElementsFromBin(bin, addedElements); + + /* rest of elements on the list should be unreferenced */ + for_each(iter, elements.end(), [](GstElement*e) { gst_object_unref(e); }); + + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to add element to bin"); + } + addedElements.push_back(element); + } + + LOG_DEBUG("%zu elements are added to bin[%s]", addedElements.size(), GST_ELEMENT_NAME(bin)); +} + +void gst::_linkElements(GstElements& elements) +{ + GstElement* prev = nullptr; + + for (auto element : elements) { + if (prev && !gst_element_link(prev, element)) { + LOG_ERROR("Failed to link %s - %s", GST_ELEMENT_NAME(prev), GST_ELEMENT_NAME(element)); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, + "Failed to link elements"); + } + prev = element; + } + + LOG_DEBUG("%zu elements are linked", elements.size()); +} + +static void __parse_type_and_set_value(GType type, GstElement* element, gchar** key_value_pair) +{ + RET_IF(!element, "element is NULL"); + RET_IF(!key_value_pair, "key_value_pairs is NULL"); + RET_IF(!key_value_pair[0], "key is NULL"); + RET_IF(!key_value_pair[1], "value is NULL"); + + switch (type) { + case G_TYPE_STRING: + g_object_set(G_OBJECT(element), key_value_pair[0], key_value_pair[1], NULL); + break; + case G_TYPE_INT: + case G_TYPE_INT64: + case G_TYPE_ENUM: { + gint64 value = g_ascii_strtoll((const gchar*)key_value_pair[1], NULL, 10); + g_object_set(G_OBJECT(element), key_value_pair[0], value, NULL); + break; + } + case G_TYPE_UINT: + case G_TYPE_UINT64: { + guint64 value = g_ascii_strtoll((const gchar*)key_value_pair[1], NULL, 10); + g_object_set(G_OBJECT(element), key_value_pair[0], value, NULL); + break; + } + case G_TYPE_BOOLEAN: { + gboolean value = FALSE; + static const gchar* true_names[] = { + "1", "yes", "on", "true", "TRUE", NULL + }; + + if (g_strv_contains (true_names, (const gchar*)key_value_pair[1])) + value = TRUE; + + g_object_set(G_OBJECT(element), key_value_pair[0], value, NULL); + break; + } + case G_TYPE_FLOAT: + case G_TYPE_DOUBLE: { + gdouble value = g_ascii_strtod((const gchar*)key_value_pair[1], NULL); + g_object_set(G_OBJECT(element), key_value_pair[0], value, NULL); + break; + } + default: + LOG_DEBUG("not supported type(0x%x) exactly, but try it with int64 type", (unsigned int)type); /* e.g.) custom enum type falls through here */ + gint64 value = g_ascii_strtoll((const gchar*)key_value_pair[1], NULL, 10); + g_object_set(G_OBJECT(element), key_value_pair[0], value, NULL); + break; + } + + LOG_DEBUG("element[%s] property[%s] value[type:0x%x, %s]", GST_ELEMENT_NAME(element), key_value_pair[0], (unsigned int)type, key_value_pair[1]); +} + +void gst::_setElementProperties(GstElement* element, std::vector key_value_pairs) +{ + RET_IF(!element, "element is NULL"); + + for (auto& kv : key_value_pairs) { + // FIXME: remove g_strsplit later + gchar** key_value_pair = g_strsplit(kv.c_str(), "=", 2); + + if (!g_strcmp0(key_value_pair[0], "") || + !g_strcmp0(key_value_pair[1], "")) { + LOG_ERROR("invalid key_value_pair, key[%s], value[%s]", + key_value_pair[0], key_value_pair[1]); + g_strfreev(key_value_pair); + continue; + } + + GParamSpec* param_spec = g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(element)), g_strstrip(key_value_pair[0]));; + if (param_spec) + __parse_type_and_set_value(param_spec->value_type, element, key_value_pair); + else + LOG_ERROR("element[%s] does not have this property[%s]", GST_ELEMENT_NAME(element), key_value_pair[0]); + + g_strfreev(key_value_pair); + } +} + +void gst::_applyStreamInfo(GstElement* element, std::string streamInfo) +{ + RET_IF(!element, "element is NULL"); + if (!g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(element)), "stream-properties")) { + LOG_WARNING("%s element does not have 'stream-properties", GST_ELEMENT_NAME(element)); + return; + } + + RET_IF(streamInfo.empty(), "input streamInfo is NULL"); + GstStructure *structure = gst_structure_from_string(streamInfo.c_str(), NULL); + RET_IF(!structure, "failed to gst_structure_from_string()"); + LOG_INFO("stream-properties[%s]", streamInfo.c_str()); + + g_object_set(G_OBJECT(element), "stream-properties", structure, NULL); + gst_structure_free(structure); +} + +void gst::_syncElementsStateWithParent(GstElements& elements) +{ + for (auto element : elements) { + if (!gst_element_sync_state_with_parent(element)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, + "Failed to _syncElementsStateWithParent"); + } + + LOG_DEBUG("_syncElementsStateWithParent done"); +} + +std::string gst::_getMimeTypeFromPad(GstPad* pad) +{ + RET_VAL_IF(!pad, NULL, "pad is NULL"); + + GstCaps* caps = gst_pad_has_current_caps(pad) ? gst_pad_get_current_caps(pad) : gst_pad_query_caps(pad, NULL); + RET_VAL_IF(!caps, NULL, "caps is NULL"); + + std::string mimeType = gst_structure_get_name(gst_caps_get_structure(caps, 0)); + LOG_DEBUG("mimeType [%s]", mimeType.c_str()); + + gst_caps_unref(caps); + + return mimeType; +} + +void gst::_generateDot(GstElement* pipeline, std::string name) +{ + std::string dotName = gst::DEFAULT_DOT_FILE_NAME_PREFIX + "." + name; + + GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, dotName.c_str()); + + LOG_WARNING("dot file[%s] is generated", dotName.c_str()); +} + +GstAudioFormat gst::_getAudioFormatFromString(std::string format) +{ + if (format == "S16LE") + return GST_AUDIO_FORMAT_S16LE; + if (format == "F32LE") + return GST_AUDIO_FORMAT_F32LE; + + LOG_ERROR("not supported raw format(%s)", format.c_str()); + + return GST_AUDIO_FORMAT_UNKNOWN; +} + +std::string gst::_getVideoMediaType(std::string codec_name) +{ + if (codec_name == "mpeg") + return MEDIA_TYPE_VIDEO_MPEG; + if (codec_name == "vp8" || codec_name == "VP8") + return MEDIA_TYPE_VIDEO_VP8; + if (codec_name == "vp9" || codec_name == "VP9") + return MEDIA_TYPE_VIDEO_VP9; + if (codec_name == "theora" || codec_name == "THEORA") + return MEDIA_TYPE_VIDEO_THEORA; + if (codec_name == "h264" || codec_name == "H264") + return MEDIA_TYPE_VIDEO_H264; + if (codec_name == "h265" || codec_name == "H265") + return MEDIA_TYPE_VIDEO_H265; + if (codec_name == "jpeg" || codec_name == "JPEG" || codec_name == "mjpeg" || codec_name == "MJPEG") + return MEDIA_TYPE_VIDEO_JPEG; + + LOG_ERROR("not supported video codec_name[%s]", codec_name.c_str()); + + return ""; +} + +std::string gst::_getAudioMediaType(std::string codec_name) +{ + if (codec_name == "aac") + return MEDIA_TYPE_AUDIO_AAC; + if (codec_name == "pcmu" || codec_name == "PCMU") + return MEDIA_TYPE_AUDIO_MULAW; + if (codec_name == "pcma" || codec_name == "PCMA") + return MEDIA_TYPE_AUDIO_ALAW; + if (codec_name == "opus" || codec_name == "OPUS") + return MEDIA_TYPE_AUDIO_OPUS; + if (codec_name == "vorbis" || codec_name == "VORBIS") + return MEDIA_TYPE_AUDIO_VORBIS; + + LOG_ERROR("not supported audio codec_name[%s]", codec_name.c_str()); + + return ""; +} + +GstCaps* gst::_getCapsFromEncodedVideoMediaType(std::string media_type, int width, int height) +{ + if (media_type == MEDIA_TYPE_VIDEO_MPEG) + return gst_caps_new_simple(media_type.c_str(), + "mpegversion", G_TYPE_INT, 4, + "systemstream", G_TYPE_BOOLEAN, FALSE, + NULL); + + if (media_type == MEDIA_TYPE_VIDEO_H264 || + media_type == MEDIA_TYPE_VIDEO_H265) + return gst_caps_new_simple(media_type.c_str(), + "stream-format", G_TYPE_STRING, "byte-stream", + "alignment", G_TYPE_STRING, "au", + "level", G_TYPE_STRING, "3", + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + NULL); + + if (media_type == MEDIA_TYPE_VIDEO_VP8 || + media_type == MEDIA_TYPE_VIDEO_VP9 || + media_type == MEDIA_TYPE_VIDEO_THEORA) + return gst_caps_new_simple(media_type.c_str(), NULL, NULL); /* NOTE: need to verify these codecs */ + + if (media_type == MEDIA_TYPE_VIDEO_JPEG) + return gst_caps_new_simple(media_type.c_str(), + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + NULL); + + LOG_ERROR_IF_REACHED("invalid media_type(%s)", media_type.c_str()); + + return NULL; +} + +GstCaps* gst::_getCapsFromEncodedAudioMediaType(std::string media_type, int channels, int samplerate) +{ + if (media_type == MEDIA_TYPE_AUDIO_AAC) + return gst_caps_new_simple(media_type.c_str(), + "channels", G_TYPE_INT, channels, + "rate", G_TYPE_INT, samplerate, + "mpegversion", G_TYPE_INT, 4, + "base-profile", G_TYPE_STRING, "lc", + NULL); + + if (media_type == MEDIA_TYPE_AUDIO_MULAW || + media_type == MEDIA_TYPE_AUDIO_ALAW) + return gst_caps_new_simple(media_type.c_str(), + "rate", G_TYPE_INT, samplerate, + "channels", G_TYPE_INT, channels, + NULL); + + if (media_type == MEDIA_TYPE_AUDIO_OPUS || + media_type == MEDIA_TYPE_AUDIO_VORBIS) + return gst_caps_new_simple(media_type.c_str(), NULL, NULL); + + LOG_ERROR_IF_REACHED("invalid media_type(%s)", media_type.c_str()); + + return NULL; +} + +static gboolean __elementFilter(GstPluginFeature* feature, gpointer data) +{ + gst::elementInfo* elem_info = static_cast(data); + gboolean src_can_accept = FALSE; + gboolean sink_can_accept = FALSE; + + if (!GST_IS_ELEMENT_FACTORY(feature)) + return FALSE; + + GstElementFactory* factory = GST_ELEMENT_FACTORY(feature); + gchar* factory_name = GST_OBJECT_NAME(factory); + const gchar* factory_klass = gst_element_factory_get_klass(factory); + + if (!elem_info || !g_strrstr(factory_klass, elem_info->klass_name)) + return FALSE; + + auto it = std::find_if(elem_info->excludedElements.begin(), elem_info->excludedElements.end(), + [&factory_name](std::string& element) { + return element.find(factory_name) != std::string::npos; + }); + if (it != elem_info->excludedElements.end()) { + LOG_WARNING("this element[%s] is an item of excluded element list in ini file, skip it", factory_name); + return FALSE; + } + + if (GST_IS_CAPS(elem_info->srcCaps)) + src_can_accept = gst_element_factory_can_src_any_caps(factory, elem_info->srcCaps); + + if (GST_IS_CAPS(elem_info->sinkCaps)) + sink_can_accept = gst_element_factory_can_sink_any_caps(factory, elem_info->sinkCaps); + + if (GST_IS_CAPS(elem_info->srcCaps) && GST_IS_CAPS(elem_info->sinkCaps)) { + if (src_can_accept && sink_can_accept) { + LOG_DEBUG("found compatible factory [%s] for klass [%s]", factory_name, factory_klass); + return TRUE; + } + return FALSE; + } + + if (src_can_accept || sink_can_accept) { + LOG_DEBUG("found compatible factory [%s] for klass [%s]", factory_name, factory_klass); + return TRUE; + } + + return FALSE; +} + +static int __rankCompare(GstPluginFeature* first, GstPluginFeature* second) +{ + guint first_rank = gst_plugin_feature_get_rank(first); + guint second_rank = gst_plugin_feature_get_rank(second); + + LOG_DEBUG("second[%s]_rank(%d) - first[%s]_rank(%d) = (%d)", + GST_OBJECT_NAME(GST_ELEMENT_FACTORY(second)), second_rank, + GST_OBJECT_NAME(GST_ELEMENT_FACTORY(first)), first_rank, second_rank - first_rank); + + return second_rank - first_rank; +} + +GstElement* gst::_createElementFromRegistry(std::string klassName, GstCaps* sinkCaps, GstCaps* srcCaps, const std::vector& excludedElements) +{ + elementInfo info { klassName.c_str(), srcCaps, sinkCaps, excludedElements }; + + GList* factories = gst_registry_feature_filter(gst_registry_get(), __elementFilter, FALSE, &info); + factories = g_list_sort(factories, (GCompareFunc) __rankCompare); + + if (!factories) { + LOG_DEBUG("could not find any compatible element for klass_name[%s]", klassName.c_str()); + if (srcCaps) + gst_caps_unref(srcCaps); + if (sinkCaps) + gst_caps_unref(sinkCaps); + gst_plugin_list_free(factories); + + return nullptr; + } + + GstElementFactory* factory = GST_ELEMENT_FACTORY(factories->data); + LOG_INFO("sorted result element is [%s]", GST_OBJECT_NAME(factory)); + + GstElement* element = _createElement(GST_OBJECT_NAME(factory)); + + /* FIXME error handling */ + if (srcCaps) + gst_caps_unref(srcCaps); + + if (sinkCaps) + gst_caps_unref(sinkCaps); + + gst_plugin_list_free(factories); + + return element; +} + +GstElement* gst::_findEncoderElement(GstElements& elements) +{ + auto it = std::find_if(elements.begin(), elements.end(), + [](GstElement* element) { + return gst_element_factory_list_is_type( + gst_element_get_factory(element), + GST_ELEMENT_FACTORY_TYPE_ENCODER); + }); + + return (it != elements.end()) ? *it : nullptr; +} + +bool gst::_containHwEncoderElement(GstElements& elements) +{ + return std::find_if(elements.begin(), elements.end(), + [](GstElement* element) { + GstElementFactory* factory = gst_element_get_factory(element); + return (gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_ENCODER) && + gst_element_factory_list_is_type(factory, GST_ELEMENT_FACTORY_TYPE_HARDWARE)); + }) != elements.end(); +} + +GstElement* gst::_findElementByName(GstElements& elements, const std::string& nameToFind) +{ + auto it = std::find_if(elements.begin(), elements.end(), + [&nameToFind](GstElement* element) { + return nameToFind.compare(GST_ELEMENT_NAME(element)) == 0; + }); + + return (it != elements.end()) ? *it : nullptr; +} + +void gst::_gstInit() +{ + auto& gstArgs = MediaTransporterIni::get().general().gstArgs; + int argc = gstArgs.size() + 1; + char** argv = static_cast(g_malloc0(sizeof(char *) * argc)); + + argv[0] = g_strdup("capi-media-transporter"); + + int i = 1; + for (auto& arg : gstArgs) { + LOG_DEBUG("adding [%s] is added", arg.c_str()); + argv[i++] = g_strdup(arg.c_str()); + } + + GError* err = NULL; + if (!gst_init_check(&argc, &argv, &err)) { + LOG_ERROR("failed to gst_init_check(), err[%s]", err->message); + g_clear_error(&err); + } + + for (i = 0; i < argc; i++) { + g_free(argv[i]); + argv[i] = NULL; + } + g_free(argv); +} + +void gst::_dumpPipelineState(GstElement* pipeline) +{ + gboolean done = FALSE; + + GValue item = G_VALUE_INIT; + GstElement* element = NULL; + GstElementFactory* factory = NULL; + + GstState state = GST_STATE_VOID_PENDING; + GstState pending = GST_STATE_VOID_PENDING; + GstClockTime time = 200 * GST_MSECOND; + + GstIterator* iter = gst_bin_iterate_recurse(GST_BIN(pipeline)); + + if (iter) { + while (!done) { + switch (gst_iterator_next(iter, &item)) { + case GST_ITERATOR_OK: + element = static_cast(g_value_get_object(&item)); + if (element) { + gst_element_get_state(element, &state, &pending, time); + + factory = gst_element_get_factory(element) ; + if (factory) + LOG_ERROR("%s:%s : From:%s To:%s refcount : %d", GST_OBJECT_NAME(factory) , GST_ELEMENT_NAME(element) , + gst_element_state_get_name(state), gst_element_state_get_name(pending) , GST_OBJECT_REFCOUNT_VALUE(element)); + } + g_value_reset(&item); + break; + case GST_ITERATOR_RESYNC: + gst_iterator_resync(iter); + break; + case GST_ITERATOR_ERROR: + done = TRUE; + break; + case GST_ITERATOR_DONE: + done = TRUE; + break; + } + } + } + + element = GST_ELEMENT(pipeline); + + gst_element_get_state(element, &state, &pending, time); + + factory = gst_element_get_factory(element) ; + + if (factory) { + LOG_ERROR("%s:%s : From:%s To:%s refcount : %d", + GST_OBJECT_NAME(factory), + GST_ELEMENT_NAME(element), + gst_element_state_get_name(state), + gst_element_state_get_name(pending), + GST_OBJECT_REFCOUNT_VALUE(element)); + } + + g_value_unset(&item); + + if (iter) + gst_iterator_free(iter); +} + +void gst::_setPipelineState(GstElement *pipeline, GstState state, int timeout) +{ + GstState element_state = GST_STATE_VOID_PENDING; + GstState element_pending_state = GST_STATE_VOID_PENDING; + + if (!pipeline) { + LOG_ERROR("pipeline is null"); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "pipeline is null"); + } + + GstStateChangeReturn ret = gst_element_set_state(pipeline, state); + if (ret == GST_STATE_CHANGE_FAILURE) { + LOG_ERROR("failed to change [%s] element state to [%s]", + GST_ELEMENT_NAME(pipeline), gst_element_state_get_name(state)); + + _dumpPipelineState(pipeline); + + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to set state!!"); + } + + /* wait for state transition */ + ret = gst_element_get_state(pipeline, &element_state, &element_pending_state, timeout * GST_SECOND); + if (ret == GST_STATE_CHANGE_FAILURE || (state != element_state)) { + LOG_ERROR("failed to change [%s] element state to [%s] within %d sec", + GST_ELEMENT_NAME(pipeline), gst_element_state_get_name(state), timeout); + + LOG_ERROR(" [%s] state : %s pending : %s", + GST_ELEMENT_NAME(pipeline), + gst_element_state_get_name(element_state), + gst_element_state_get_name(element_pending_state)); + + _dumpPipelineState(pipeline); + + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get state!!"); + } + + std::string dotName = std::string { GST_ELEMENT_NAME(pipeline) } + "." + std::string { gst_element_state_get_name(state) }; + _generateDot(pipeline, dotName); +} + +GstCaps* gst::_makeCapsForCapsfilter(GstPad *pad) +{ + gint mpegversion = 0; + GstCaps* new_caps = NULL; + + RET_VAL_IF(!pad, NULL, "pad is NULL"); + + GstCaps* caps = gst_pad_has_current_caps(pad) ? gst_pad_get_current_caps(pad) + : gst_pad_query_caps(pad, NULL); + + // PRINT_CAPS(caps, "pad"); + GstStructure* structure = gst_caps_get_structure(caps, 0); + std::string mediaType = gst_structure_get_name(structure); + gst_structure_get_int(structure, "mpegversion", &mpegversion); + + if ((mediaType.find(MEDIA_TYPE_VIDEO_H264) != std::string::npos) + || mediaType.find(MEDIA_TYPE_VIDEO_H265) != std::string::npos) { + /* FIXME: get value of stream-format, alignment from ini file */ + new_caps = gst_caps_new_simple(mediaType.c_str(), + "stream-format", G_TYPE_STRING, "byte-stream", + "alignment", G_TYPE_STRING, "au", + NULL); + } else if ((mediaType.find(MEDIA_TYPE_AUDIO_AAC) != std::string::npos) + && (mpegversion == 2 || mpegversion == 4)) { + new_caps = gst_caps_new_simple(mediaType.c_str(), + "mpegversion", G_TYPE_INT, mpegversion, + "stream-format", G_TYPE_STRING, "adts", + NULL); + } + + gst_caps_unref(caps); + return new_caps; +} + +void gst::_destroyElementFromParent(GstElement* element) +{ + if (!element) + return; + + GstElement* parent = GST_ELEMENT_CAST(gst_element_get_parent(element)); + if (parent) { + gst_bin_remove(GST_BIN(parent), element); + gst_object_unref(parent); + } else { + gst_object_unref(GST_OBJECT(element)); + } +} + +void gst::_printCaps(GstCaps* caps, std::string prefix) +{ + if (!caps) + return; + + std::string caps_str = gst_caps_to_string(caps); + LOG_DEBUG("%s caps[%s]", prefix.c_str(), caps_str.c_str()); +} diff --git a/src/MediaTransporterObserver.cpp b/src/MediaTransporterObserver.cpp new file mode 100644 index 0000000..f909568 --- /dev/null +++ b/src/MediaTransporterObserver.cpp @@ -0,0 +1,45 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterObserver.h" +#include "MediaTransporterLog.h" +#include + +using namespace tizen_media_transporter; + +void ObservableBase::subscribe(IObserver * observer) +{ + _observers.push_back(observer); +} + +void ObservableBase::notify() +{ + std::vector::iterator iter = _observers.begin(); + for (; iter != _observers.end(); iter++) { + IObserver *observer = *iter; + observer->changed(); + } +} + +void ObservableBase::unsubscribe(IObserver *observer) +{ + std::vector::iterator iter; + iter = std::find(_observers.begin(), _observers.end(), observer); + if (iter != _observers.end()) { + _observers.erase(iter); + } +} diff --git a/src/MediaTransporterParseIni.cpp b/src/MediaTransporterParseIni.cpp new file mode 100644 index 0000000..a8008a6 --- /dev/null +++ b/src/MediaTransporterParseIni.cpp @@ -0,0 +1,305 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterGst.h" +#include "MediaTransporterParseIni.h" +#include "MediaTransporterLog.h" + +using namespace tizen_media_transporter; + +static void dumpItem(const char* prefix_str, bool item) +{ + LOG_INFO("- %-19s = %s", prefix_str, item ? "yes" : "no"); +} + +static void dumpItem(const char* prefix_str, int item) +{ + LOG_INFO("- %-19s = %d", prefix_str, item); +} + +static void dumpItem(const char* prefix_str, std::string& item) +{ + LOG_INFO("- %-19s = %s", prefix_str, item.c_str()); +} + +static void dumpItem(const char* prefix_str, std::vector& item) +{ + std::string joined = std::accumulate(item.begin(), item.end(), std::string("|")); + + LOG_INFO("- %-19s = %s", prefix_str, joined.c_str()); +} + +static std::vector iniReadList(dictionary* dict, std::string category, std::string item, char delimeters) +{ + std::vector strings; + + if (!dict) + return strings; + + std::string key = category + ":" + item; + + const char *str = iniparser_getstring(dict, key.c_str(), NULL); + if (str && strlen(str) > 0) { + g_autofree gchar* strtmp = g_strdup(str); + g_strstrip(strtmp); + + std::string tmp { strtmp }; + std::stringstream ss(tmp); + tmp.clear(); + + while (getline(ss, tmp, delimeters)) + strings.push_back(tmp); + } + + return strings; +} + +static std::string iniGetString(dictionary* dict, std::string category, std::string item, std::string default_value) +{ + if (!dict) + return default_value; + + std::string key = category + ":" + item; + + const char *str = iniparser_getstring(dict, key.c_str(), default_value.c_str()); + return str; +} + +static int iniGetInt(dictionary* dict, std::string category, std::string item, int default_value) +{ + if (!dict) + return default_value; + + std::string key = category + ":" + item; + + return iniparser_getint(dict, key.c_str(), default_value); +} + +static bool iniGetBoolean(dictionary* dict, std::string category, std::string item, bool default_value) +{ + if (!dict) + return default_value; + + std::string key = category + ":" + item; + + return static_cast(iniparser_getboolean(dict, key.c_str(), static_cast(default_value))); +} + +void MediaTransporterIni::dumpItemsOfGeneral() +{ + dumpItem(INI_ITEM_DOT_GENERATE, _ini.general.generateDot); + dumpItem(INI_ITEM_DOT_PATH, _ini.general.dotPath); + dumpItem(INI_ITEM_VERBOSE_LOG, _ini.general.verboseLog); + dumpItem(INI_ITEM_GST_ARGS, _ini.general.gstArgs); + dumpItem(INI_ITEM_GST_EXCLUDED_ELEMENTS, _ini.general.gstExcludedElements); + dumpItem(INI_ITEM_GST_STATE_CHANGE_TIMEOUT, _ini.general.timeout); +} + +#if 0 +void MediaTransporterIni::dumpItemsOfRtspConnection() +{ + dumpItem(INI_ITEM_RTSP_SERVER_IP, connection->rtsp_ip); + dumpItem(INI_ITEM_RTSP_SERVER_PORT, connection->rtsp_port); + dumpItem(INI_ITEM_RTSP_SERVER_MOUNT_POINT, connection->rtsp_mount_point); +} +#endif + +void MediaTransporterIni::dumpItemsOfRenderingSink() +{ + dumpItem(INI_ITEM_AUDIO_SINK_ELEMENT, _ini.renderingSink.audioSinkElement); + dumpItem(INI_ITEM_VIDEO_SINK_ELEMENT, _ini.renderingSink.videoSinkElement); + dumpItem(INI_ITEM_AUDIO_HW_DECODER_ELEMENTS, _ini.renderingSink.audioHWDecoderElements); + dumpItem(INI_ITEM_VIDEO_HW_DECODER_ELEMENTS, _ini.renderingSink.videoHWDecoderElements); +} + +void MediaTransporterIni::dumpItemsOfMediaSource(MtprMediaSourceIni& source) +{ + dumpItem(INI_ITEM_SOURCE_ELEMENT, source.sourceElement); + dumpItem(INI_ITEM_SOURCE_ELEMENT_PROPERTIES, source.sourceElementProperties); + dumpItem(INI_ITEM_VIDEO_RAW_FORMAT, source.videoRawFormat); + dumpItem(INI_ITEM_VIDEO_WIDTH, source.videoWidth); + dumpItem(INI_ITEM_VIDEO_HEIGHT, source.videoHeight); + dumpItem(INI_ITEM_VIDEO_FRAMERATE, source.videoFramerate); + dumpItem(INI_ITEM_VIDEO_DRC_SUPPORT, source.videoDRCSupport); + dumpItem(INI_ITEM_VIDEO_ENCODED_FMT_SUPPORT, source.videoEncodedFMTSupport); + dumpItem(INI_ITEM_VIDEO_CODEC, source.videoCodec); + dumpItem(INI_ITEM_VIDEO_HW_ENCODER_ELEMENT, source.videoHWEncoderElement); + dumpItem(INI_ITEM_AUDIO_RAW_FORMAT, source.audioRawFormat); + dumpItem(INI_ITEM_AUDIO_SAMPLERATE, source.audioSamplerate); + dumpItem(INI_ITEM_AUDIO_CHANNELS, source.audioChannels); + dumpItem(INI_ITEM_AUDIO_CODEC, source.audioCodec); + dumpItem(INI_ITEM_AUDIO_HW_ENCODER_ELEMENT, source.audioHWEncoderElement); +} + +void MediaTransporterIni::applyGeneralSetting(dictionary* dict) +{ + /* general */ + _ini.general.generateDot = iniGetBoolean(dict, INI_CATEGORY_GENERAL, INI_ITEM_DOT_GENERATE, DEFAULT_GENERATE_DOT); + _ini.general.dotPath = iniGetString(dict, INI_CATEGORY_GENERAL, INI_ITEM_DOT_PATH, DEFAULT_DOT_PATH); + if (_ini.general.generateDot) { + LOG_INFO("dot file will be stored in [%s]", _ini.general.dotPath.c_str()); + g_setenv("GST_DEBUG_DUMP_DOT_DIR", _ini.general.dotPath.c_str(), FALSE); + } + + _ini.general.verboseLog = iniGetBoolean(dict, INI_CATEGORY_GENERAL, INI_ITEM_VERBOSE_LOG, DEFAULT_VERBOSE_LOG); + _ini.general.gstArgs = iniReadList(dict, INI_CATEGORY_GENERAL, INI_ITEM_GST_ARGS, '|'); + _ini.general.gstExcludedElements = iniReadList(dict, INI_CATEGORY_GENERAL, INI_ITEM_GST_EXCLUDED_ELEMENTS, ','); + _ini.general.timeout = iniGetInt(dict, INI_CATEGORY_GENERAL, INI_ITEM_GST_STATE_CHANGE_TIMEOUT, DEFAULT_STATE_CHANGE_TIMEOUT); +} + +#if 0 +void MediaTransporterIni::applyRtspConnection(dictionary* dict, MtprRtspConnectionIni* connection) +{ + connection->rtsp_ip = iniGetString(dict, INI_CATEGORY_CONNECTION, INI_ITEM_RTSP_SERVER_IP, DEFAULT_RTSP_SERVER_IP); + connection->rtsp_port = iniGetString(dict, INI_CATEGORY_CONNECTION, INI_ITEM_RTSP_SERVER_PORT, DEFAULT_RTSP_SERVER_PORT); + connection->rtsp_mount_point = iniGetString(dict, INI_CATEGORY_CONNECTION, INI_ITEM_RTSP_SERVER_MOUNT_POINT, DEFAULT_RTSP_SERVER_MOUNT_POINT); +} +#endif + +void MediaTransporterIni::applyRenderingSink(dictionary* dict) +{ + _ini.renderingSink.audioSinkElement = iniGetString(dict, INI_CATEGORY_RENDERING_SINK, INI_ITEM_AUDIO_SINK_ELEMENT, gst::DEFAULT_AUDIO_SINK_ELEMENT); + _ini.renderingSink.videoSinkElement = iniGetString(dict, INI_CATEGORY_RENDERING_SINK, INI_ITEM_VIDEO_SINK_ELEMENT, gst::DEFAULT_VIDEO_SINK_ELEMENT); + _ini.renderingSink.audioHWDecoderElements = iniReadList(dict, INI_CATEGORY_RENDERING_SINK, INI_ITEM_AUDIO_HW_DECODER_ELEMENTS, ','); + _ini.renderingSink.videoHWDecoderElements = iniReadList(dict, INI_CATEGORY_RENDERING_SINK, INI_ITEM_VIDEO_HW_DECODER_ELEMENTS, ','); +} + +void MediaTransporterIni::applyMediaSourceDefault(dictionary* dict, std::string category) +{ + _ini.mediaSourceDefault.videoRawFormat = iniGetString(dict, category, INI_ITEM_VIDEO_RAW_FORMAT, DEFAULT_VIDEO_RAW_FORMAT); + _ini.mediaSourceDefault.videoWidth = iniGetInt(dict, category, INI_ITEM_VIDEO_WIDTH, DEFAULT_VIDEO_WIDTH); + _ini.mediaSourceDefault.videoHeight = iniGetInt(dict, category, INI_ITEM_VIDEO_HEIGHT, DEFAULT_VIDEO_HEIGHT); + _ini.mediaSourceDefault.videoFramerate = iniGetInt(dict, category, INI_ITEM_VIDEO_FRAMERATE, DEFAULT_VIDEO_FRAMERATE); + _ini.mediaSourceDefault.videoDRCSupport = iniGetBoolean(dict, category, INI_ITEM_VIDEO_DRC_SUPPORT, DEFAULT_VIDEO_DRC_SUPPORT); + _ini.mediaSourceDefault.videoEncodedFMTSupport = iniGetBoolean(dict, category, INI_ITEM_VIDEO_ENCODED_FMT_SUPPORT, DEFAULT_VIDEO_ENCODED_FMT_SUPPORT); + _ini.mediaSourceDefault.videoCodec = iniGetString(dict, category, INI_ITEM_VIDEO_CODEC, DEFAULT_VIDEO_CODEC); + _ini.mediaSourceDefault.videoHWEncoderElement = iniGetString(dict, category, INI_ITEM_VIDEO_HW_ENCODER_ELEMENT, ""); + _ini.mediaSourceDefault.audioRawFormat = iniGetString(dict, category, INI_ITEM_AUDIO_RAW_FORMAT, DEFAULT_AUDIO_RAW_FORMAT); + _ini.mediaSourceDefault.audioSamplerate = iniGetInt(dict, category, INI_ITEM_AUDIO_SAMPLERATE, DEFAULT_AUDIO_SAMPLERATE); + _ini.mediaSourceDefault.audioChannels = iniGetInt(dict, category, INI_ITEM_AUDIO_CHANNELS, DEFAULT_AUDIO_CHANNELS); + _ini.mediaSourceDefault.audioCodec = iniGetString(dict, category, INI_ITEM_AUDIO_CODEC, DEFAULT_AUDIO_CODEC); + _ini.mediaSourceDefault.audioHWEncoderElement = iniGetString(dict, category, INI_ITEM_AUDIO_HW_ENCODER_ELEMENT, ""); +} + +void MediaTransporterIni::applyMediaSource(dictionary* dict, MtprMediaSourceIni& source, std::string category) +{ + source.sourceElement = iniGetString(dict, category, INI_ITEM_SOURCE_ELEMENT, ""); + source.sourceElementProperties = iniReadList(dict, category, INI_ITEM_SOURCE_ELEMENT_PROPERTIES, ','); + + source.videoRawFormat = iniGetString(dict, category, INI_ITEM_VIDEO_RAW_FORMAT, _ini.mediaSourceDefault.videoRawFormat); + source.videoWidth = iniGetInt(dict, category, INI_ITEM_VIDEO_WIDTH, _ini.mediaSourceDefault.videoWidth); + source.videoHeight = iniGetInt(dict, category, INI_ITEM_VIDEO_HEIGHT, _ini.mediaSourceDefault.videoHeight); + source.videoFramerate = iniGetInt(dict, category, INI_ITEM_VIDEO_FRAMERATE, _ini.mediaSourceDefault.videoFramerate); + source.videoDRCSupport = iniGetBoolean(dict, category, INI_ITEM_VIDEO_DRC_SUPPORT, _ini.mediaSourceDefault.videoDRCSupport); + source.videoEncodedFMTSupport = iniGetBoolean(dict, category, INI_ITEM_VIDEO_ENCODED_FMT_SUPPORT, _ini.mediaSourceDefault.videoEncodedFMTSupport); + source.videoCodec = iniGetString(dict, category, INI_ITEM_VIDEO_CODEC, _ini.mediaSourceDefault.videoCodec); + source.videoHWEncoderElement = iniGetString(dict, category, INI_ITEM_VIDEO_HW_ENCODER_ELEMENT, _ini.mediaSourceDefault.videoHWEncoderElement); + source.audioRawFormat = iniGetString(dict, category, INI_ITEM_AUDIO_RAW_FORMAT, _ini.mediaSourceDefault.audioRawFormat); + source.audioSamplerate = iniGetInt(dict, category, INI_ITEM_AUDIO_SAMPLERATE, _ini.mediaSourceDefault.audioSamplerate); + source.audioChannels = iniGetInt(dict, category, INI_ITEM_AUDIO_CHANNELS, _ini.mediaSourceDefault.audioChannels); + source.audioCodec = iniGetString(dict, category, INI_ITEM_AUDIO_CODEC, _ini.mediaSourceDefault.audioCodec); + source.audioHWEncoderElement = iniGetString(dict, category, INI_ITEM_AUDIO_HW_ENCODER_ELEMENT, _ini.mediaSourceDefault.audioHWEncoderElement); +} + + +static const char* category_source_names[] = { + [MTPR_SOURCE_TYPE_CAMERA] = INI_CATEGORY_SOURCE_CAMERA, + [MTPR_SOURCE_TYPE_MIC] = INI_CATEGORY_SOURCE_MIC, + [MTPR_SOURCE_TYPE_VIDEOTEST] = INI_CATEGORY_SOURCE_VIDEOTEST, + [MTPR_SOURCE_TYPE_AUDIOTEST] = INI_CATEGORY_SOURCE_AUDIOTEST, + [MTPR_SOURCE_TYPE_AUDIOTEST + 1] = NULL, +}; + +void MediaTransporterIni::dumpIni() +{ + LOG_INFO("[%s]", INI_CATEGORY_GENERAL); + dumpItemsOfGeneral(); + + LOG_INFO("[%s]", INI_CATEGORY_MEDIA_SOURCE); + dumpItemsOfMediaSource(_ini.mediaSourceDefault); + + for (int i = 0; category_source_names[i]; i++) { + LOG_INFO("[%s]", category_source_names[i]); + dumpItemsOfMediaSource(_ini.mediaSources[i]); + } + + LOG_INFO("[%s]", INI_CATEGORY_RENDERING_SINK); + dumpItemsOfRenderingSink(); +} + + +MediaTransporterIni::MediaTransporterIni() +{ + load(); +} + +MediaTransporterIni& MediaTransporterIni::get() +{ + static MediaTransporterIni ini; + return ini; +} + +const MtprGeneralIni& MediaTransporterIni::general() +{ + return _ini.general; +} + +const MtprMediaSourceIni& MediaTransporterIni::mediaSource(int type) +{ + return (type == -1) ? _ini.mediaSourceDefault : _ini.mediaSources.at(type); +} + +const MtprRenderingSinkIni& MediaTransporterIni::renderingSink() +{ + return _ini.renderingSink; +} + +void MediaTransporterIni::load() +{ + dictionary* dict = iniparser_load(MTPR_INI_PATH); + if (!dict) { + LOG_ERROR("could not open ini[%s], use default values", MTPR_INI_PATH); + return; + } + applyGeneralSetting(dict); + + /* default setting for a media source */ + applyMediaSourceDefault(dict, INI_CATEGORY_MEDIA_SOURCE); + + /* it overrides the default values above */ + for (int i = 0; category_source_names[i] != NULL; i++) { + if (iniparser_getsecnkeys(dict, category_source_names[i]) > 0) { + MtprMediaSourceIni source; + applyMediaSource(dict, source, category_source_names[i]); + + _ini.mediaSources.push_back(source); + } + } + + applyRenderingSink(dict); + + dumpIni(); + + if (dict) { + iniparser_freedict(dict); + LOG_DEBUG("ini instance[%p] is freed", dict); + dict = NULL; + } +} \ No newline at end of file diff --git a/src/MediaTransporterReceiver.cpp b/src/MediaTransporterReceiver.cpp new file mode 100644 index 0000000..1bd0ef2 --- /dev/null +++ b/src/MediaTransporterReceiver.cpp @@ -0,0 +1,618 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterReceiver.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterUtil.h" +#include "MediaTransporterParseIni.h" + +#include +#include +#include +#include + +using namespace tizen_media_transporter; + +void MediaTransporterReceiver::setTrackAddedCallback(void* handle, mtprTrackAddedCallback callback, void* userData) +{ + _trackAddedCallback = std::unique_ptr(new TrackAddedCallback(handle, callback, userData)); +} + +void MediaTransporterReceiver::unsetTrackAddedCallback() +{ + _trackAddedCallback = nullptr; +} + +void MediaTransporterReceiver::setNoMoreTrackCallback(void* handle, mtprNoMoreTrackCallback callback, void* userData) +{ + _noMoreTrackCallback = std::unique_ptr(new NoMoreTrackCallback(handle, callback, userData)); +} + +void MediaTransporterReceiver::unsetNoMoreTrackCallback() +{ + _noMoreTrackCallback = nullptr; +} + +void MediaTransporterReceiver::setVideoPacketCallback(void* handle, mtprPacketCallback callback, void* userData) +{ + _videoCallback._callback = std::unique_ptr(new PacketCallback(handle, MTPR_MEDIA_TYPE_VIDEO, callback, userData)); +} + +void MediaTransporterReceiver::setAudioPacketCallback(void* handle, mtprPacketCallback callback, void* userData) +{ + _audioCallback._callback = std::unique_ptr(new PacketCallback(handle, MTPR_MEDIA_TYPE_AUDIO, callback, userData)); +} + +void MediaTransporterReceiver::unsetVideoPacketCallback() +{ + _videoCallback._callback = nullptr; +} + +void MediaTransporterReceiver::unsetAudioPacketCallback() +{ + _audioCallback._callback = nullptr; +} + +static media_format_mimetype_e _getMediaFormatMimeType(std::string mime) +{ + if (mime.find(gst::MEDIA_TYPE_AUDIO_AAC) != std::string::npos) + return MEDIA_FORMAT_AAC; + else if (mime.find(gst::MEDIA_TYPE_AUDIO_OPUS) != std::string::npos) + return MEDIA_FORMAT_OPUS; + else if (mime.find(gst::MEDIA_TYPE_AUDIO_VORBIS) != std::string::npos) + return MEDIA_FORMAT_VORBIS; + else if (mime.find(gst::MEDIA_TYPE_VIDEO_MPEG) != std::string::npos) + return MEDIA_FORMAT_MPEG4_SP; /* FIXME: need to check format , MEDIA_FORMAT_MPEG4_ASP */ + else if (mime.find(gst::MEDIA_TYPE_VIDEO_VP8) != std::string::npos) + return MEDIA_FORMAT_VP8; + else if (mime.find(gst::MEDIA_TYPE_VIDEO_VP9) != std::string::npos) + return MEDIA_FORMAT_VP9; + else if (mime.find(gst::MEDIA_TYPE_VIDEO_H264) != std::string::npos) + return MEDIA_FORMAT_H264_HP; + else if (mime.find(gst::MEDIA_TYPE_VIDEO_JPEG) != std::string::npos) + return MEDIA_FORMAT_MJPEG; + + LOG_ERROR("not supported mime[%s]", mime.c_str()); + return MEDIA_FORMAT_MAX; +} + +static media_format_h _makeMediaFormat(GstPad* pad) +{ + int ret; + + RET_VAL_IF(!pad, NULL, "pad is NULL"); + + media_format_h format; + RET_VAL_IF(media_format_create(&format) != MEDIA_FORMAT_ERROR_NONE, NULL, + "failed to media_format_create()"); + + GstCaps* caps = gst_pad_get_current_caps(pad); + GstStructure* structure = gst_caps_get_structure(caps, 0); + std::string mime = gst_structure_get_name(structure); + + media_format_mimetype_e mimetype = _getMediaFormatMimeType(mime); + LOG_INFO("media format mimetype[0x%x]", mimetype); + + if (mimetype & MEDIA_FORMAT_VIDEO) { + gint width = 0; + gint height = 0; + gint fps_n = 0; + gint fps_d = 0; + + ret = media_format_set_video_mime(format, mimetype); + if (ret != MEDIA_FORMAT_ERROR_NONE) { + LOG_ERROR("failed to media_format_set_video_mime()"); + goto ERROR; + } + + /* FIXME: We also need to get width/height in case of H26x with not this way. */ + gst_structure_get_int(structure, "width", &width); + gst_structure_get_int(structure, "height", &height); + if (width > 0 && height > 0) { + ret |= media_format_set_video_width(format, width); + ret |= media_format_set_video_height(format, height); + if (ret != MEDIA_FORMAT_ERROR_NONE) { + LOG_ERROR("failed to media_format_set_video_width/height()"); + goto ERROR; + } + } + + gst_structure_get_fraction(structure, "framerate", &fps_n, &fps_d); + if (fps_n > 0 && fps_d > 0) + media_format_set_video_frame_rate(format, fps_n / fps_d); + } else if (mimetype & MEDIA_FORMAT_AUDIO) { + gint channels = 0; + gint rate = 0; + + ret = media_format_set_audio_mime(format, mimetype); + if (ret != MEDIA_FORMAT_ERROR_NONE) { + LOG_ERROR("failed to media_format_set_audio_mime()"); + goto ERROR; + } + + gst_structure_get_int(structure, "channels", &channels); + gst_structure_get_int(structure, "rate", &rate); + if (channels > 0 && rate > 0) { + ret |= media_format_set_audio_channel(format, channels); + ret |= media_format_set_audio_samplerate(format, rate); + if (ret != MEDIA_FORMAT_ERROR_NONE) { + LOG_ERROR("failed to media_format_set_audio_channel/samplerate()"); + goto ERROR; + } + } + } else { + LOG_ERROR("Error on _getMediaFormatMimeType"); + } + + gst_caps_unref(caps); + return format; + +ERROR: + gst_caps_unref(caps); + media_format_unref(format); + return NULL; +} + +static void _setCodecDataIfExist(media_packet_h packet, GstPad* pad) +{ + GstCaps* caps = gst_pad_get_current_caps(pad); + + const GValue* codec_data_value = gst_structure_get_value(gst_caps_get_structure(caps, 0), "codec_data"); + if (codec_data_value) { + GstBuffer* codec_data = gst_value_get_buffer(codec_data_value); + + GstMapInfo buff_info; + gst_buffer_map(codec_data, &buff_info, GST_MAP_READ); + + int ret = media_packet_set_codec_data(packet, buff_info.data, buff_info.size); + if (ret != MEDIA_PACKET_ERROR_NONE) + LOG_ERROR("failed to media_packet_set_codec_data()"); + else + LOG_DEBUG("codec_data[%p, size:%" G_GSIZE_FORMAT "] is set to the media packet[%p]", + buff_info.data, buff_info.size, packet); + + gst_buffer_unmap(codec_data, &buff_info); + } + + gst_caps_unref(caps); +} + +/* userData should not be handle */ +static int __mediaPacketFinalizeCallBack(media_packet_h packet, int error_code, void* userData) +{ + GstBuffer* buffer = NULL; + if (media_packet_get_extra(packet, (void**)&buffer) == MEDIA_PACKET_ERROR_NONE) + gst_buffer_unref(buffer); + + LOG_VERBOSE("this[%p], packet[%p], buffer[%p]", userData, packet, buffer); + + return MEDIA_PACKET_FINALIZE; +} + +media_packet_h MediaTransporterReceiver::_makeMediaPacket(GstBuffer* buffer, GstPad* pad, media_format_h* format) +{ + int ret; + media_packet_h packet = NULL; + GstMapInfo info = GST_MAP_INFO_INIT; + + RET_VAL_IF(!buffer, NULL, "buffer is NULL"); + RET_VAL_IF(!pad, NULL, "pad is NULL"); + + if (!(*format)) + *format = _makeMediaFormat(pad); + + gst_buffer_ref(buffer); + + if (!gst_buffer_map(buffer, &info, GST_MAP_READ)) { + LOG_ERROR("failed to gst_buffer_map()"); + goto ERROR; + } + + ret = media_packet_create_from_external_memory(*format, info.data, gst_buffer_get_size(buffer), __mediaPacketFinalizeCallBack, nullptr, &packet); + gst_buffer_unmap(buffer, &info); + if (ret != MEDIA_PACKET_ERROR_NONE) { + LOG_ERROR("failed to media_packet_create_from_external_memory()"); + goto ERROR; + } + + ret |= media_packet_set_pts(packet, GST_BUFFER_PTS(buffer)); + ret |= media_packet_set_dts(packet, GST_BUFFER_DTS(buffer)); + ret |= media_packet_set_duration(packet, GST_BUFFER_DURATION(buffer)); + + /* FIXME: We put the gstbuffer to extra field of media packet. It does not guarantee the validity of the gstbuffer + * after destroying this media packet. Currently, the gstbuffer must be used before destroying the packet. */ + ret |= media_packet_set_extra(packet, (void*)buffer); + if (ret != MEDIA_PACKET_ERROR_NONE) { + LOG_ERROR("failed to media_packet_set_*()"); + goto ERROR; + } + + if (!GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT)) { + /* key frame */ + _setCodecDataIfExist(packet, pad); + // if (ret != MTPR_ERROR_NONE) + // goto ERROR; + } + + LOG_VERBOSE("packet[%p], buffer[%p, pts:%" G_GUINT64_FORMAT ", dts:%" G_GUINT64_FORMAT ", duration:%" G_GUINT64_FORMAT "]", + packet, buffer, GST_BUFFER_PTS(buffer), GST_BUFFER_DTS(buffer), GST_BUFFER_DURATION(buffer)); + + return packet; + +ERROR: + if (packet) + media_packet_destroy(packet); + gst_buffer_unref(buffer); + media_format_unref(*format); + *format = NULL; + + return NULL; +} + +static unsigned int _get_id_from_name(std::string name) +{ + auto pos = name.rfind("_"); + return (strtoul(name.substr(pos + 1).c_str(), NULL, 10) + 1); +} + +void MediaTransporterReceiver::_streamAddedCallback(GstPad* pad, gpointer data) +{ + mtprMediaType type; + auto mtprReceiver = static_cast(data); + RET_IF(!mtprReceiver, "mtprReceiver is NULL"); + + auto id = _get_id_from_name(GST_PAD_NAME(pad)); + + std::string mediaType = gst::_getMimeTypeFromPad(pad); + if (mediaType.find("audio") != std::string::npos) { + type = MTPR_MEDIA_TYPE_AUDIO; + } else if (mediaType.find("video") != std::string::npos) { + type = MTPR_MEDIA_TYPE_VIDEO; + } else { + LOG_INFO("not supported track %s", mediaType.c_str()); + return; + } + + LOG_INFO("pad [%p][%s:%s], type %s, id %u", pad, GST_DEBUG_PAD_NAME(pad), mediaType.c_str(), id); + + if (mtprReceiver->_trackAddedCallback) + mtprReceiver->_trackAddedCallback->invoke(VariantData{type}, VariantData{id}); +} + +void MediaTransporterReceiver::_noMoreStreamCallback(gpointer data) +{ + auto mtprReceiver = static_cast(data); + RET_IF(!mtprReceiver, "mtprReceiver is NULL"); + + if (mtprReceiver->_noMoreTrackCallback) + mtprReceiver->_noMoreTrackCallback->invoke(); +} + +/* handoff signal handler */ +void MediaTransporterReceiver::_encodedAudioStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data) +{ + auto mtprReceiver = static_cast(data); + RET_IF(!mtprReceiver, "mtprReceiver is NULL"); + + LOG_VERBOSE("object[%p] buffer[%p] pad[%p]", object, buffer, pad); + + // FIXME : extract common method for callback invoke + + auto id = _get_id_from_name(GST_ELEMENT_NAME(object)); + media_packet_h packet = _makeMediaPacket(buffer, pad, &mtprReceiver->_audioCallback.mediaFormat); + RET_IF(!packet, "packet is NULL"); + + if (mtprReceiver->_audioCallback._callback) + mtprReceiver->_audioCallback._callback->invoke(VariantData{id}, VariantData{packet}); +} + +void MediaTransporterReceiver::_encodedVideoStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data) +{ + auto mtprReceiver = static_cast(data); + RET_IF(!mtprReceiver, "mtprReceiver is NULL"); + + LOG_VERBOSE("object[%p] buffer[%p] pad[%p]", object, buffer, pad); + + auto id = _get_id_from_name(GST_ELEMENT_NAME(object)); + media_packet_h packet = _makeMediaPacket(buffer, pad, &mtprReceiver->_videoCallback.mediaFormat); + RET_IF(!packet, "packet is NULL"); + + if (mtprReceiver->_videoCallback._callback) + mtprReceiver->_videoCallback._callback->invoke(VariantData{id}, VariantData{packet}); +} + +void MediaTransporterReceiver::_buildForwardingSink(gst::GstElements& elements, GstPad* pad, GCallback callback) +{ + GstElement* capsfilter = gst::_createElement(gst::DEFAULT_ELEMENT_CAPSFILTER); + GstCaps* sink_caps = gst::_makeCapsForCapsfilter(pad); + if (sink_caps) { + gst::_printCaps(sink_caps, "capsfilter"); + g_object_set(G_OBJECT(capsfilter), "caps", sink_caps, NULL); + gst_caps_unref(sink_caps); + } + elements.push_back(capsfilter); + + auto id = _get_id_from_name(GST_PAD_NAME(pad)); + std::string name = "fakesink_" + std::to_string(id); + LOG_INFO("pad %s:%s, sink name = %s", GST_DEBUG_PAD_NAME(pad), name.c_str()); + + GstElement* fakesink = gst::_createElement(gst::DEFAULT_ELEMENT_FAKESINK, name); + g_object_set(G_OBJECT(fakesink), "signal-handoffs", TRUE, NULL); + elements.push_back(fakesink); + + gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(fakesink), "handoff", callback, this); +} + +// FIXME : exception handling +int MediaTransporterReceiver::_buildForwardingElements(GstElement* demux, GstPad* pad, GCallback callback) +{ + gst::GstElements elements; + + RET_VAL_IF(!demux, MTPR_ERROR_INVALID_PARAMETER, "demux element is NULL"); + RET_VAL_IF(!pad, MTPR_ERROR_INVALID_PARAMETER, "pad is NULL"); + + GstElement* queue = gst::_createElement(gst::DEFAULT_ELEMENT_QUEUE); + /* FIXME: need to check queue size */ + g_object_set(G_OBJECT(queue), + "max-size-buffers", DEFAULT_QUEUE_MAX_SIZE_BUFFERS, + "max-size-bytes", DEFAULT_QUEUE_MAX_SIZE_BYTES, + "max-size-time", DEFAULT_QUEUE_MAX_SIZE_TIME, + NULL); + elements.push_back(queue); + + GstElement* parser = gst::_createElementFromRegistry("Parser", gst_pad_get_current_caps(pad), NULL, + MediaTransporterIni::get().general().gstExcludedElements); + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(parser)), "config-interval")) { + g_object_set(G_OBJECT(parser), "config-interval", -1, NULL); + LOG_DEBUG("[%s] set config-interval -1", GST_ELEMENT_NAME(parser) ); + } + elements.push_back(parser); + + _buildForwardingSink(elements, pad, callback); + + gst::_addElementsToBin(GST_BIN(_gst.pipeline), elements); + + if (!gst_element_link_pads(GST_ELEMENT(demux), + GST_PAD_NAME(pad), + GST_ELEMENT(queue), + "sink")) { + LOG_ERROR("failed to link demuxer and queue"); + } + + gst::_linkElements(elements); + gst::_syncElementsStateWithParent(elements); + + return MTPR_ERROR_NONE; +} + +void MediaTransporterReceiver::_buildAudioRenderingSink(gst::GstElements& elements) +{ + if (_streamInfo.empty()) { + LOG_WARNING("Not set streaminfo, link fakesink"); + elements.push_back(gst::_createElement(gst::DEFAULT_ELEMENT_FAKESINK)); + return; + } + + GstElement* converter = nullptr; + GstElement* resample = nullptr; + GstElement* sink = nullptr; + + try { + // display RM acquire + converter = gst::_createElement(gst::DEFAULT_ELEMENT_AUDIOCONVERT); + elements.push_back(converter); + + resample = gst::_createElement(gst::DEFAULT_ELEMENT_AUDIORESAMPLE); + elements.push_back(resample); + + std::string audioSinkName = MediaTransporterIni::get().renderingSink().audioSinkElement; + sink = gst::_createElement(audioSinkName); + gst::_applyStreamInfo(sink, _streamInfo); + elements.push_back(sink); + } catch (const MediaTransporterException& e) { + if (converter) { + gst::_removeElement(elements, converter); + gst_object_unref(converter); + } + if (resample) { + gst::_removeElement(elements, resample); + gst_object_unref(resample); + } + if (sink) { + gst::_removeElement(elements, sink); + gst_object_unref(sink); + } + throw; + } +} + +void MediaTransporterReceiver::_buildVideoRenderingSink(gst::GstElements& elements) +{ + if (!_display) { + LOG_WARNING("Not set display, link fakesink"); + elements.push_back(gst::_createElement(gst::DEFAULT_ELEMENT_FAKESINK)); + return; + } + + GstElement* converter = nullptr; + GstElement* sink = nullptr; + + try { + // display RM acquire + _resourceManager->acquire(MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_OVERLAY); + converter = gst::_createElement(gst::DEFAULT_ELEMENT_VIDEOCONVERT); + elements.push_back(converter); + sink = _display->videoSink(); + elements.push_back(sink); + } catch (const MediaTransporterException& e) { + if (converter) { + gst::_removeElement(elements, converter); + gst_object_unref(converter); + } + if (sink) { + gst::_removeElement(elements, sink); + gst_object_unref(sink); + } + throw; + } +} + +int MediaTransporterReceiver::_buildAudioRenderingElements(GstElement* demux, GstPad* pad) +{ + gst::GstElements elements; + + RET_VAL_IF(!demux, MTPR_ERROR_INVALID_PARAMETER, "demux element is NULL"); + RET_VAL_IF(!pad, MTPR_ERROR_INVALID_PARAMETER, "pad is NULL"); + + GstElement* queue = gst::_createElement(gst::DEFAULT_ELEMENT_QUEUE); + /* FIXME: need to check queue size */ + g_object_set(G_OBJECT(queue), + "max-size-buffers", DEFAULT_QUEUE_MAX_SIZE_BUFFERS, + "max-size-bytes", DEFAULT_QUEUE_MAX_SIZE_BYTES, + "max-size-time", DEFAULT_QUEUE_MAX_SIZE_TIME, + NULL); + elements.push_back(queue); + + GstElement* parser = gst::_createElementFromRegistry("Parser", gst_pad_get_current_caps(pad), NULL, + MediaTransporterIni::get().general().gstExcludedElements); + GstPad* srcPad; + if (parser) { + srcPad = gst_element_get_static_pad(parser, "src"); + elements.push_back(parser); + } else { + srcPad = gst_element_get_static_pad(queue, "src"); + } + + GstCaps* caps = gst_pad_has_current_caps(srcPad) ? gst_pad_get_current_caps(srcPad) + : gst_pad_query_caps(srcPad, NULL); + GstElement* decoder = gst::_createElementFromRegistry("Codec/Decoder/Audio", caps, NULL, + MediaTransporterIni::get().general().gstExcludedElements); + elements.push_back(decoder); + g_object_unref(srcPad); + + _buildAudioRenderingSink(elements); + + gst::_addElementsToBin(GST_BIN(_gst.pipeline), elements); + + if (!gst_element_link_pads(GST_ELEMENT(demux), + GST_PAD_NAME(pad), + GST_ELEMENT(queue), + "sink")) { + LOG_ERROR("failed to link demuxer and queue"); + } + + gst::_linkElements(elements); + gst::_syncElementsStateWithParent(elements); + + return MTPR_ERROR_NONE; +} + +int MediaTransporterReceiver::_buildVideoRenderingElements(GstElement* demux, GstPad* pad) +{ + gst::GstElements elements; + + RET_VAL_IF(!demux, MTPR_ERROR_INVALID_PARAMETER, "demux element is NULL"); + RET_VAL_IF(!pad, MTPR_ERROR_INVALID_PARAMETER, "pad is NULL"); + + GstElement* queue = gst::_createElement(gst::DEFAULT_ELEMENT_QUEUE); + /* FIXME: need to check queue size */ + g_object_set(G_OBJECT(queue), + "max-size-buffers", DEFAULT_QUEUE_MAX_SIZE_BUFFERS, + "max-size-bytes", DEFAULT_QUEUE_MAX_SIZE_BYTES, + "max-size-time", DEFAULT_QUEUE_MAX_SIZE_TIME, + NULL); + elements.push_back(queue); + + GstElement* parser = gst::_createElementFromRegistry("Parser", gst_pad_get_current_caps(pad), NULL, + MediaTransporterIni::get().general().gstExcludedElements); + GstPad* srcPad; + if (parser) { + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(parser)), "config-interval")) { + g_object_set(G_OBJECT(parser), "config-interval", -1, NULL); + LOG_DEBUG("[%s] set config-interval -1", GST_ELEMENT_NAME(parser) ); + } + srcPad = gst_element_get_static_pad(parser, "src"); + elements.push_back(parser); + } else { + srcPad = gst_element_get_static_pad(queue, "src"); + } + + GstCaps* caps = gst_pad_has_current_caps(srcPad) ? gst_pad_get_current_caps(srcPad) + : gst_pad_query_caps(srcPad, NULL); + GstElement* decoder = gst::_createElementFromRegistry("Codec/Decoder/Video", caps, NULL, + MediaTransporterIni::get().general().gstExcludedElements); + elements.push_back(decoder); + g_object_unref(srcPad); + + _buildVideoRenderingSink(elements); + + gst::_addElementsToBin(GST_BIN(_gst.pipeline), elements); + + if (!gst_element_link_pads(GST_ELEMENT(demux), + GST_PAD_NAME(pad), + GST_ELEMENT(queue), + "sink")) { + LOG_ERROR("failed to link demuxer and queue"); + } + + gst::_linkElements(elements); + gst::_syncElementsStateWithParent(elements); + + return MTPR_ERROR_NONE; +} + +void MediaTransporterReceiver::setDisplay(std::shared_ptr display) +{ + _display = display; +} + +void MediaTransporterReceiver::setSoundStreamInfo(sound_stream_info_h streamInfo) +{ + char *stream_type; + int stream_index; + // bool available = false; + + RET_IF(!streamInfo, "streamInfo is NULL"); + + sound_manager_get_type_from_stream_information(streamInfo, &stream_type); + sound_manager_get_index_from_stream_information(streamInfo, &stream_index); + + /* FIXEME: need to add NATIVE_API_MEDIATRANSPORTER in sound-manager */ + // ret = sound_manager_is_available_stream_information(stream_info, NATIVE_API_MEDIATRANSPORTER, &available); + // if (ret != SOUND_MANAGER_ERROR_NONE) { + // LOG_ERROR("failed to sound_manager_is_available_stream_information()"); + // return MTPR_ERROR_INVALID_OPERATION; + // } + + // if (!available) { + // LOG_ERROR("this stream info[%p, type:%s, index:%d] is not allowed to this framework", stream_info, stream_type, stream_index); + // return MTPR_ERROR_INVALID_PARAMETER; + // } + + RET_IF(!stream_type, "stream_type is NULL"); + + LOG_INFO("stream_info[%p, type:%s, index:%d", + streamInfo, stream_type, stream_index); + + std::ostringstream stringStream; + stringStream << "props," << PA_PROP_MEDIA_ROLE << "=" << + stream_type << ", " << PA_PROP_MEDIA_PARENT_ID << "=" << stream_index; + + _streamInfo = stringStream.str(); +} diff --git a/src/MediaTransporterReceiverRist.cpp b/src/MediaTransporterReceiverRist.cpp new file mode 100644 index 0000000..5282ba0 --- /dev/null +++ b/src/MediaTransporterReceiverRist.cpp @@ -0,0 +1,142 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterReceiverRist.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterUtil.h" +#include + +using namespace tizen_media_transporter; + +static bool _isSupportedMediaType(std::string mediaType) +{ + if ((mediaType.find("audio") == std::string::npos) && + (mediaType.find("video") == std::string::npos)) { + LOG_ERROR("not supported media type [%s]", mediaType.c_str()); + return false; + } + + return true; +} + +static bool _isAudioMediaType(std::string mediaType) +{ + return mediaType.find("audio") != std::string::npos; +} + +void MediaTransporterReceiverRist::_demuxNoMorePadsCallback(GstElement *demux, gpointer userData) +{ + MediaTransporterReceiverRist* rist = static_cast(userData); + std::string dotName = std::string { GST_ELEMENT_NAME(rist->_gst.pipeline) } + ".complete"; + gst::_generateDot(rist->_gst.pipeline, dotName); + + _noMoreStreamCallback(userData); +} + +void MediaTransporterReceiverRist::_demuxPadAddedCallback(GstElement *demux, GstPad *new_pad, gpointer userData) +{ + if (GST_PAD_DIRECTION(new_pad) != GST_PAD_SRC) + return; + + std::string mediaType = gst::_getMimeTypeFromPad(new_pad); + + if (!_isSupportedMediaType(mediaType)) + return; + + LOG_INFO("new_pad[%s] media_type[%s]", GST_PAD_NAME(new_pad), mediaType.c_str()); + + auto rist = static_cast(userData); + assert(rist); + if (_isAudioMediaType(mediaType)) { + if (rist->_audioCallback._callback) + rist->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedAudioStreamCallback)); + else + rist->_buildAudioRenderingElements(demux, new_pad); + } else { + if (rist->_videoCallback._callback) + rist->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedVideoStreamCallback)); + else + rist->_buildVideoRenderingElements(demux, new_pad); + } + + _streamAddedCallback(new_pad, userData); +} + +ResourceSet MediaTransporterReceiverRist::buildPipeline() +{ + GstElement* src = NULL; + GstElement* rtpmp2tdepay = NULL; + GstElement* queue = NULL; + GstElement* tsdemux = NULL; + + ResourceSet allResourceRequired; + + MTPR_FENTER(); + + /* create mux to sink */ + try { + src = gst::_createElement(gst::DEFAULT_ELEMENT_RISTSRC); + g_object_set(G_OBJECT(src), "bonding-addresses", _receiverAddress.c_str(), + "receiver-buffer", 0, NULL); + + rtpmp2tdepay = gst::_createElement("rtpmp2tdepay"); + + queue = gst::_createElement(gst::DEFAULT_ELEMENT_QUEUE); + + tsdemux = gst::_createElement(gst::DEFAULT_ELEMENT_TSDEMUX); + g_object_set(G_OBJECT(tsdemux), "latency", 0, NULL); + + gst_bin_add_many(GST_BIN(_gst.pipeline), src, rtpmp2tdepay, queue, tsdemux, NULL); + + if (!gst_element_link_many (src, rtpmp2tdepay, queue, tsdemux, NULL)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to link elements"); + + gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "pad-added", G_CALLBACK(_demuxPadAddedCallback), this); + gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "no-more-pads", G_CALLBACK(_demuxNoMorePadsCallback), this); + LOG_INFO("linked mux and sink"); + + return allResourceRequired; + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + + gst::_destroyElementFromParent(src); + gst::_destroyElementFromParent(rtpmp2tdepay); + gst::_destroyElementFromParent(queue); + gst::_destroyElementFromParent(tsdemux); + + throw; + } +} + +void MediaTransporterReceiverRist::startPipeline() +{ + gst::_setPipelineState(_gst.pipeline, GST_STATE_PLAYING, + MediaTransporterIni::get().general().timeout); +} + +void MediaTransporterReceiverRist::stopPipeline() +{ + gst::_setPipelineState(_gst.pipeline, GST_STATE_NULL, + MediaTransporterIni::get().general().timeout); +} + +void MediaTransporterReceiverRist::setReceiverAddress(std::string address) +{ + _receiverAddress = address; +} diff --git a/src/MediaTransporterReceiverSrt.cpp b/src/MediaTransporterReceiverSrt.cpp new file mode 100644 index 0000000..9d3bdfb --- /dev/null +++ b/src/MediaTransporterReceiverSrt.cpp @@ -0,0 +1,139 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterReceiverSrt.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterUtil.h" +#include + +using namespace tizen_media_transporter; + +static bool _isSupportedMediaType(std::string mediaType) +{ + if ((mediaType.find("audio") == std::string::npos) && + (mediaType.find("video") == std::string::npos)) { + LOG_ERROR("not supported media type [%s]", mediaType.c_str()); + return false; + } + + return true; +} + +static bool _isAudioMediaType(std::string mediaType) +{ + return mediaType.find("audio") != std::string::npos; +} + +void MediaTransporterReceiverSrt::_demuxNoMorePadsCallback(GstElement *demux, gpointer userData) +{ + MediaTransporterReceiverSrt* srt = static_cast(userData); + std::string dotName = std::string { GST_ELEMENT_NAME(srt->_gst.pipeline) } + ".complete"; + gst::_generateDot(srt->_gst.pipeline, dotName); + + _noMoreStreamCallback(userData); +} + +void MediaTransporterReceiverSrt::_demuxPadAddedCallback(GstElement *demux, GstPad *new_pad, gpointer userData) +{ + if (GST_PAD_DIRECTION(new_pad) != GST_PAD_SRC) + return; + + std::string mediaType = gst::_getMimeTypeFromPad(new_pad); + + if (!_isSupportedMediaType(mediaType)) + return; + + LOG_INFO("new_pad[%s] media_type[%s]", GST_PAD_NAME(new_pad), mediaType.c_str()); + + auto srt = static_cast(userData); + assert(srt); + if (_isAudioMediaType(mediaType)) { + if (srt->_audioCallback._callback) + srt->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedAudioStreamCallback)); + else + srt->_buildAudioRenderingElements(demux, new_pad); + } else { + if (srt->_videoCallback._callback) + srt->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedVideoStreamCallback)); + else + srt->_buildVideoRenderingElements(demux, new_pad); + } + + _streamAddedCallback(new_pad, userData); +} + +ResourceSet MediaTransporterReceiverSrt::buildPipeline() +{ + GstElement* src = NULL; + GstElement* queue = NULL; + GstElement* tsdemux = NULL; + + ResourceSet allResourceRequired; + + MTPR_FENTER(); + + /* create mux to sink */ + try { + src = gst::_createElement(gst::DEFAULT_ELEMENT_SRTSRC); + g_object_set(G_OBJECT(src), "uri", _senderAddress.c_str(), "latency", 10, NULL); + + queue = gst::_createElement(gst::DEFAULT_ELEMENT_QUEUE); + + tsdemux = gst::_createElement(gst::DEFAULT_ELEMENT_TSDEMUX); + g_object_set(G_OBJECT(tsdemux), "latency", 0, NULL); + + gst_bin_add_many(GST_BIN(_gst.pipeline), src, queue, tsdemux, NULL); + + if (!gst_element_link_many (src, queue, tsdemux, NULL)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to link elements"); + + gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "pad-added", G_CALLBACK(_demuxPadAddedCallback), this); + gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "no-more-pads", G_CALLBACK(_demuxNoMorePadsCallback), this); + LOG_INFO("linked mux and sink"); + + return allResourceRequired; + + // return MTPR_ERROR_NONE; + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + + gst::_destroyElementFromParent(src); + gst::_destroyElementFromParent(queue); + gst::_destroyElementFromParent(tsdemux); + + throw; + } +} + +void MediaTransporterReceiverSrt::startPipeline() +{ + gst::_setPipelineState(_gst.pipeline, GST_STATE_PLAYING, + MediaTransporterIni::get().general().timeout); +} + +void MediaTransporterReceiverSrt::stopPipeline() +{ + gst::_setPipelineState(_gst.pipeline, GST_STATE_NULL, + MediaTransporterIni::get().general().timeout); +} + +void MediaTransporterReceiverSrt::setSenderAddress(std::string address) +{ + _senderAddress = address; +} diff --git a/src/MediaTransporterResource.cpp b/src/MediaTransporterResource.cpp new file mode 100644 index 0000000..ab1649a --- /dev/null +++ b/src/MediaTransporterResource.cpp @@ -0,0 +1,174 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterResource.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterBase.h" +#include + +using namespace tizen_media_transporter; + +int MediaTransporterResource::_resourceReleaseCallback(mm_resource_manager_h mgr, + mm_resource_manager_res_h res, + void *user_data) +{ + auto resourceClass = static_cast(user_data); + RET_VAL_IF(!resourceClass, FALSE, "mtpr is NULL"); + + return resourceClass->resourceReleased(res); +} + +bool MediaTransporterResource::resourceReleased(mm_resource_manager_res_h res) +{ + std::lock_guard mutex(_mutex); + + bool interrupted = false; + + _onReleaseCallback = true; + + for (auto& [ type, handle ] : _resources) { + if (res == handle) { + LOG_INFO("type[%d] resource was released by resource manager", static_cast(type)); + _resources.erase(type); + interrupted = true; + } + } + + if (interrupted) + notify(); + + _onReleaseCallback = false; + + return true; +} + +int MediaTransporterResource::create() +{ + std::lock_guard mutex(_mutex); + + if (mm_resource_manager_create(MM_RESOURCE_MANAGER_APP_CLASS_MEDIA, + _resourceReleaseCallback, this, &_mgr) != MM_RESOURCE_MANAGER_ERROR_NONE) { + LOG_ERROR("failed to create resource manager"); + return MTPR_ERROR_RESOURCE_FAILED; + } + + return MTPR_ERROR_NONE; +} + +int MediaTransporterResource::acquireInternal(mm_resource_manager_res_type_e type) +{ + int ret = MM_RESOURCE_MANAGER_ERROR_NONE; + mm_resource_manager_res_h handle; + + if (!_mgr) + return MTPR_ERROR_NONE; + + if (_resources.find(type) != _resources.end()) { + LOG_ERROR("type[%d] resource was already acquired", type); + return MTPR_ERROR_RESOURCE_FAILED; + } + + LOG_DEBUG("mark for acquire type[%d] resource", type); + ret = mm_resource_manager_mark_for_acquire(_mgr, type, + MM_RESOURCE_MANAGER_RES_VOLUME_FULL, &handle); + if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { + LOG_ERROR("failed to mark resource for acquire, ret[0x%x]", ret); + return MTPR_ERROR_RESOURCE_FAILED; + } + + LOG_DEBUG("commit type[%d] resource", type); + ret = mm_resource_manager_commit(_mgr); + if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { + LOG_ERROR("failed to commit of resource, ret([0x%x]", ret); + return MTPR_ERROR_RESOURCE_FAILED; + } + + _resources[type] = handle; + + return MTPR_ERROR_NONE; +} + +int MediaTransporterResource::acquire(mm_resource_manager_res_type_e type) +{ + std::lock_guard mutex(_mutex); + + return acquireInternal(type); +} + +int MediaTransporterResource::acquire(ResourceSet resourceSet) +{ + std::lock_guard mutex(_mutex); + + int ret = MTPR_ERROR_NONE; + + for (auto& resource : resourceSet) { + if ((ret = acquireInternal(resource)) != MTPR_ERROR_NONE) + return ret; + } + + return ret; +} + +int MediaTransporterResource::releaseAll() +{ + std::lock_guard mutex(_mutex); + + int ret = MM_RESOURCE_MANAGER_ERROR_NONE; + + if (!_mgr) + return MTPR_ERROR_NONE; + + if (_onReleaseCallback) { + LOG_INFO("__resource_release_cb is calling, so skip"); + return MTPR_ERROR_NONE; + } + + ret = mm_resource_manager_mark_all_for_release(_mgr); + if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { + LOG_ERROR("failed to mark all for release, ret[0x%x]", ret); + return MTPR_ERROR_RESOURCE_FAILED; + } + ret = mm_resource_manager_commit(_mgr); + if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { + LOG_ERROR("failed to commit resource, ret[0x%x]", ret); + return MTPR_ERROR_RESOURCE_FAILED; + } + LOG_DEBUG("all resources were released by resource manager"); + + return MTPR_ERROR_NONE; +} + + +int MediaTransporterResource::destroy() +{ + std::lock_guard mutex(_mutex); + + if (!_mgr) + return MTPR_ERROR_NONE; + + int ret = mm_resource_manager_destroy(_mgr); + if (ret != MM_RESOURCE_MANAGER_ERROR_NONE) { + LOG_ERROR("failed to destroy resource manager, ret[0x%x]", ret); + return MTPR_ERROR_RESOURCE_FAILED; + } + + _mgr = nullptr; + LOG_DEBUG("destroyed resource manager"); + + return MTPR_ERROR_NONE; +} + diff --git a/src/MediaTransporterSender.cpp b/src/MediaTransporterSender.cpp new file mode 100644 index 0000000..ff79058 --- /dev/null +++ b/src/MediaTransporterSender.cpp @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterSender.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterUtil.h" + +using namespace tizen_media_transporter; + +MediaTransporterSender::~MediaTransporterSender() +{ +} + +int MediaTransporterSender::addMediaSource(IMediaSourceBin* sourceBin) +{ + static int id = 0; + _mediaSources.insert(std::make_pair(id, std::unique_ptr(sourceBin))); + LOG_INFO("media source id:%d has been added bin:%p", id, sourceBin); + return id++; +} + +void MediaTransporterSender::removeMediaSource(int id) +{ + if (_mediaSources.erase(id) != 1) + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid id to remove"); + + LOG_INFO("media source id:%d has been removed", id); +} + +IMediaSourceBin* MediaTransporterSender::getMediaSource(int id) +{ + try { + return _mediaSources.at(id).get(); + } catch (...) { + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid id to get Source"); + } +} \ No newline at end of file diff --git a/src/MediaTransporterSenderRist.cpp b/src/MediaTransporterSenderRist.cpp new file mode 100644 index 0000000..490d1a1 --- /dev/null +++ b/src/MediaTransporterSenderRist.cpp @@ -0,0 +1,239 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterSenderRist.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterUtil.h" +#include "MediaTransporterParseIni.h" + +#define RTCP_BANDWIDTH_PARAM_MIN 0 +#define RTCP_BANDWIDTH_PARAM_MAX 0.05 +#define RTCP_INTERVAL_PARAM_MIN 0 +#define RTCP_INTERVAL_PARAM_MAX 100 + +using namespace tizen_media_transporter; + +static GstPad* _getGhostPadFromBin(GstBin* bin) +{ + GstElement* queue = gst_bin_get_by_name(bin, "srcQueue"); + if (!queue) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get srcQueue"); + + GstPad* srcPad = nullptr; + + if (!gst::_addNoTargetGhostpad(bin, &srcPad, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _addNoTargetGhostpad"); + + if (!gst::_setGhostpadTarget(srcPad, queue, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _setGhostpadTarget"); + + return srcPad; +} + +ResourceSet MediaTransporterSenderRist::buildPipeline() +{ + GstElement* mux = NULL; + GstElement* sink = NULL; + GstElement* pay = NULL; + GstPad* sinkPad = NULL; + + ResourceSet allResourceRequired; + + /* create mux to sink */ + try { + mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); + g_object_set(G_OBJECT(mux), "alignment", 7, NULL); + + sink = gst::_createElement(gst::DEFAULT_ELEMENT_RISTSINK); + g_object_set(G_OBJECT(sink), "bonding-addresses", _receiverAddress.c_str(), NULL); + + if (_connectionParam.maxRtcpBandwidth > 0 && _connectionParam.maxRtcpBandwidth <= 0.05) + g_object_set(G_OBJECT(sink), "max-rtcp-bandwidth", _connectionParam.maxRtcpBandwidth, NULL); + + if (_connectionParam.minRtcpInterval != UINT_MAX && _connectionParam.minRtcpInterval <= 100) + g_object_set(G_OBJECT(sink), "min-rtcp-interval", _connectionParam.minRtcpInterval, NULL); + + if (_connectionParam.senderBuffer != UINT_MAX) + g_object_set(G_OBJECT(sink), "sender-buffer", _connectionParam.senderBuffer, NULL); + + SECURE_LOG_INFO("max-rtcp-bandwidth %f, min-rtcp-interval %u, sender-buffer %u", + _connectionParam.maxRtcpBandwidth, _connectionParam.minRtcpInterval, _connectionParam.senderBuffer); + + pay = gst::_createElement("rtpmp2tpay"); + + gst_bin_add_many(GST_BIN(_gst.pipeline), mux, pay, sink, NULL); + if (!gst_element_link_many(mux, pay, sink, NULL)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to gst_element_link()"); + + LOG_ERROR("pp %s, ref %d", + GST_ELEMENT_NAME(_gst.pipeline), GST_OBJECT_REFCOUNT_VALUE(_gst.pipeline)); + + /* link each element */ + for (auto& [id, mediaSource] : _mediaSources) { + auto[ type, bin, resourceRequired ] = mediaSource->generate(); + + LOG_INFO("mediaSource(type:%d, bin:%p, resourceRequired:%zu) generated", + static_cast(type), bin, resourceRequired.size()); + + allResourceRequired.insert(resourceRequired.begin(), resourceRequired.end()); + + gst_bin_add(GST_BIN(_gst.pipeline), GST_ELEMENT(bin)); + + GstPad* srcPad = _getGhostPadFromBin(bin); + if (gst_pad_is_linked(srcPad)) { + LOG_ERROR("pad %s:%s is already linked", GST_DEBUG_PAD_NAME(srcPad)); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "already linked"); + } + + sinkPad = gst_element_request_pad_simple(mux, "sink_%d"); + if (!sinkPad) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); + + GstPadLinkReturn res = gst_pad_link(srcPad, sinkPad); + if (GST_PAD_LINK_FAILED(res)) { + LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", + GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to link pads"); + } + LOG_INFO("pad is linked %s:%s - %s:%s", GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + } + + _ristSink = sink; + LOG_INFO("linked mux and sink"); + + return allResourceRequired; + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + + if (sinkPad) { + gst_element_release_request_pad(mux, sinkPad); + g_object_unref(sinkPad); + } + + gst::_destroyElementFromParent(mux); + gst::_destroyElementFromParent(pay); + gst::_destroyElementFromParent(sink); + + throw; + } +} + +void MediaTransporterSenderRist::startPipeline() +{ + gst::_setPipelineState(_gst.pipeline, GST_STATE_PLAYING, + MediaTransporterIni::get().general().timeout); +} + +void MediaTransporterSenderRist::stopPipeline() +{ + _ristSink = NULL; + gst::_setPipelineState(_gst.pipeline, GST_STATE_NULL, + MediaTransporterIni::get().general().timeout); +} + +void MediaTransporterSenderRist::setConnection(std::string name, std::string string_val) +{ + SECURE_LOG_INFO("%s : %s", name.c_str(), string_val.c_str()); + + try { + if (name.compare(MTPR_CONNECTION_PARAM_RIST_BONDING_ADDRESS) == 0) { + _connectionParam.bondingAddress = string_val; + + } else if (name.compare(MTPR_CONNECTION_PARAM_RIST_MAX_RTCP_BANDWIDTH) == 0) { + size_t size; + double val = stod(string_val, &size); + if ((string_val.size() != size) || + (val < RTCP_BANDWIDTH_PARAM_MIN) || (val > RTCP_BANDWIDTH_PARAM_MAX)) { + LOG_ERROR("invalid rtcp bandwidth value %s", string_val.c_str()); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid rtcp bandwidth value"); + } + _connectionParam.maxRtcpBandwidth = val; + + } else if (name.compare(MTPR_CONNECTION_PARAM_RIST_MIN_RTCP_INTERVAL) == 0) { + size_t size; + int val = stoi(string_val, &size); + if ((string_val.size() != size) || + (val < RTCP_INTERVAL_PARAM_MIN) || (val > RTCP_INTERVAL_PARAM_MAX)) { + LOG_ERROR("invalid rtcp interval value %s", string_val.c_str()); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid rtcp interval value"); + } + _connectionParam.minRtcpInterval = val; + + } else if (name.compare(MTPR_CONNECTION_PARAM_RIST_SENDER_BUFFER) == 0) { + size_t size; + int val = stoi(string_val, &size); + if (string_val.size() != size) { + LOG_ERROR("invalid sender buffer value %s", string_val.c_str()); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid sender buffer value"); + } + _connectionParam.senderBuffer = val; + + } else { + LOG_ERROR("invalid param name %s", name.c_str()); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid param name"); + } + } catch (const std::exception& e) { + LOG_ERROR("error : %s, throw invalid param", e.what()); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid parameter"); + } +} + +void MediaTransporterSenderRist::setConnection(bundle* params) +{ + char* string_val = NULL; + + if (bundle_get_str(params, MTPR_CONNECTION_PARAM_RIST_BONDING_ADDRESS, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) + _connectionParam.bondingAddress = string_val; + + if (bundle_get_str(params, MTPR_CONNECTION_PARAM_RIST_MAX_RTCP_BANDWIDTH, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) + setConnection(MTPR_CONNECTION_PARAM_RIST_MAX_RTCP_BANDWIDTH, string_val); + + if (bundle_get_str(params, MTPR_CONNECTION_PARAM_RIST_MIN_RTCP_INTERVAL, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) + setConnection(MTPR_CONNECTION_PARAM_RIST_MIN_RTCP_INTERVAL, string_val); + + if (bundle_get_str(params, MTPR_CONNECTION_PARAM_RIST_SENDER_BUFFER, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) + setConnection(MTPR_CONNECTION_PARAM_RIST_SENDER_BUFFER, string_val); +} + +void MediaTransporterSenderRist::getConnection(bundle* params) +{ + if (!_connectionParam.bondingAddress.empty()) + bundle_add_str(params, MTPR_CONNECTION_PARAM_RIST_BONDING_ADDRESS, _connectionParam.bondingAddress.c_str()); + + if (_connectionParam.maxRtcpBandwidth > -1) + bundle_add_str(params, + MTPR_CONNECTION_PARAM_RIST_MAX_RTCP_BANDWIDTH, + std::to_string(_connectionParam.maxRtcpBandwidth).c_str()); + + if (_connectionParam.minRtcpInterval != UINT_MAX) + bundle_add_str(params, + MTPR_CONNECTION_PARAM_RIST_MIN_RTCP_INTERVAL, + std::to_string(_connectionParam.minRtcpInterval).c_str()); + + if (_connectionParam.senderBuffer != UINT_MAX) + bundle_add_str(params, + MTPR_CONNECTION_PARAM_RIST_SENDER_BUFFER, + std::to_string(_connectionParam.senderBuffer).c_str()); +} + +void MediaTransporterSenderRist::setReceiverAddress(std::string address) +{ + _receiverAddress = address; +} diff --git a/src/MediaTransporterSenderRtsp.cpp b/src/MediaTransporterSenderRtsp.cpp new file mode 100644 index 0000000..eea9f5b --- /dev/null +++ b/src/MediaTransporterSenderRtsp.cpp @@ -0,0 +1,317 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterSenderRtsp.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterUtil.h" + +using namespace tizen_media_transporter; + +#define ADDR_PORT_DELIM ":" +#define ADDR_PATH_DELIM "/" +#define ADDR_RTSP_PREFIX "rtsp://" + +static GstPad* _getGhostPadFromBin(GstBin* bin) +{ + GstElement* queue = gst_bin_get_by_name(bin, "srcQueue"); + if (!queue) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get srcQueue"); + + GstPad* srcPad = nullptr; + + if (!gst::_addNoTargetGhostpad(bin, &srcPad, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _addNoTargetGhostpad"); + + if (!gst::_setGhostpadTarget(srcPad, queue, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _setGhostpadTarget"); + + return srcPad; +} + +static GstRTSPFilterResult +__clientFilter(GstRTSPServer *server, GstRTSPClient *client, gpointer userData) +{ + /* Simple filter that shuts down all clients. */ + return GST_RTSP_FILTER_REMOVE; +} + +ResourceSet MediaTransporterSenderRtsp::buildPipeline() +{ + GstElement* mux = NULL; + GstElement* pay = NULL; + GstPad* sinkPad = NULL; + + ResourceSet allResourceRequired; + + try { + /* create mux and pay */ + mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); + g_object_set(G_OBJECT(mux), "alignment", 7, NULL); + + /* pay element name have to be "pay0" */ + pay = gst::_createElement("rtpmp2tpay", "pay0"); + gst_bin_add_many(GST_BIN(_gst.pipeline), mux, pay, NULL); + if (!gst_element_link(mux, pay)) { + LOG_ERROR("failed to gst_element_link()"); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to gst_element_link()"); + } + + LOG_ERROR("pp %s, ref %d", + GST_ELEMENT_NAME(_gst.pipeline), GST_OBJECT_REFCOUNT_VALUE(_gst.pipeline)); + + /* create sources and link elements */ + for (auto& [id, mediaSource] : _mediaSources) { + auto[ type, bin, resourceRequired ] = mediaSource->generate(); + + LOG_INFO("mediaSource(type:%d, bin:%p, resourceRequired:%zu) generated", + static_cast(type), bin, resourceRequired.size()); + + allResourceRequired.insert(resourceRequired.begin(), resourceRequired.end()); + + gst_bin_add(GST_BIN(_gst.pipeline), GST_ELEMENT(bin)); + + GstPad* srcPad = _getGhostPadFromBin(bin); + if (gst_pad_is_linked(srcPad)) { + LOG_ERROR("pad %s:%s is already linked", GST_DEBUG_PAD_NAME(srcPad)); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "already linked"); + } + + sinkPad = gst_element_request_pad_simple(mux, "sink_%d"); + if (!sinkPad) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); + + GstPadLinkReturn res = gst_pad_link(srcPad, sinkPad); + if (GST_PAD_LINK_FAILED(res)) { + LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", + GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); + } + LOG_INFO("pad is linked %s:%s - %s:%s", GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + } + + LOG_INFO("linked mux and pay"); + + return allResourceRequired; + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + + if (sinkPad) { + gst_element_release_request_pad(mux, sinkPad); + g_object_unref(sinkPad); + } + + gst::_destroyElementFromParent(mux); + gst::_destroyElementFromParent(pay); + + throw; + } +} + +void MediaTransporterSenderRtsp::startPipeline() +{ + startRtspServer(); +} + +void MediaTransporterSenderRtsp::stopPipeline() +{ + stopRtspServer(); +} + +void MediaTransporterSenderRtsp::setSenderAddress(std::string address) +{ + _senderAddress = address; // rtsp server addr +} + +static void __clientConnectedCb(GstRTSPServer* server, GstRTSPClient* client) +{ + LOG_DEBUG("client connected %p", client); +} + +static void __mediaConstructedCb(GstRTSPMediaFactory* factory, GstRTSPMedia* media, gpointer userData) +{ + LOG_DEBUG("media %p is constructed and has %u streams", media, gst_rtsp_media_n_streams(media)); +} + +static void __onSsrcActive(GObject* session, GObject* source, GstRTSPMedia* media) +{ + GstStructure* stats; + + LOG_DEBUG("source %p in session %p is active", source, session); + + g_object_get(source, "stats", &stats, NULL); + if (stats) { + gchar* sstr; + + sstr = gst_structure_to_string(stats); + LOG_DEBUG("structure: %s", sstr); + g_free(sstr); + + gst_structure_free(stats); + } +} + +static void __onSenderSsrcActive(GObject* session, GObject* source, GstRTSPMedia* media) +{ + GstStructure* stats; + + LOG_DEBUG("source %p in session %p is active", source, session); + + g_object_get(source, "stats", &stats, NULL); + if (stats) { + gchar* sstr; + + sstr = gst_structure_to_string(stats); + LOG_DEBUG("Sender stats:\nstructure: %s", sstr); + g_free(sstr); + + gst_structure_free(stats); + } +} + +static void __mediaPreparedCb(GstRTSPMedia* media) +{ + guint i, n_streams; + + n_streams = gst_rtsp_media_n_streams(media); + + LOG_DEBUG("media %p is prepared and has %u streams", media, n_streams); + + for (i = 0; i < n_streams; i++) { + GstRTSPStream *stream; + GObject *session; + + stream = gst_rtsp_media_get_stream(media, i); + if (!stream) + continue; + + session = gst_rtsp_stream_get_rtpsession(stream); + LOG_DEBUG("watching session %p on stream %u", session, i); + + g_signal_connect(session, "on-ssrc-active", + G_CALLBACK(__onSsrcActive), media); + g_signal_connect(session, "on-sender-ssrc-active", + G_CALLBACK(__onSenderSsrcActive), media); + } +} + +static void __mediaConfigureCb(GstRTSPMediaFactory* factory, GstRTSPMedia* media) +{ + LOG_DEBUG("media %p is prepared and has %u streams", media, gst_rtsp_media_n_streams(media)); + g_signal_connect(media, "prepared", G_CALLBACK(__mediaPreparedCb), factory); +} + +void MediaTransporterSenderRtsp::startRtspServer() +{ + GstRTSPMountPoints *mounts; + GstRTSPMediaFactoryMTPR *factoryMtpr; + GstRTSPServer *server = NULL; + std::string rtspPrefix("rtsp://"); + std::string address; + std::string ipAddr; + std::string portNum; + std::string mountPoint; + + try { + server = gst_rtsp_server_new(); + if (!server) { + LOG_ERROR("Failed to create rtsp server"); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to create rtsp server"); + } + + /* addr format "rtsp://{ip address}:{port number}/{mount_point}" */ + if (_senderAddress.find(ADDR_RTSP_PREFIX) == 0) { + address = _senderAddress.substr(rtspPrefix.size()); + } else { + address = _senderAddress; + } + + if ((address.find(ADDR_PORT_DELIM) == std::string::npos) && + (address.find(ADDR_PATH_DELIM) == std::string::npos)) { + SECURE_LOG_ERROR("invalid address %s", address.c_str()); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "invalid sender address"); + } + + auto portPos = address.find(ADDR_PORT_DELIM); + ipAddr = address.substr(0, portPos); + auto mountPos = address.find(ADDR_PATH_DELIM); + portPos++; + portNum = address.substr(portPos, mountPos - portPos); + mountPoint = address.substr(mountPos); + + gst_rtsp_server_set_address(GST_RTSP_SERVER(server), ipAddr.c_str()); + gst_rtsp_server_set_service(GST_RTSP_SERVER(server), portNum.c_str()); + + g_signal_connect(server, "client-connected", G_CALLBACK(__clientConnectedCb), NULL); + + mounts = gst_rtsp_server_get_mount_points(server); + factoryMtpr = gst_rtsp_media_factory_mtpr_new(); + g_object_ref(_gst.pipeline); + gst_rtsp_media_factory_mtpr_set_custom_element(factoryMtpr, GST_ELEMENT(_gst.pipeline)); + gst::_generateDot(_gst.pipeline, "rtsp-sender"); + + gst_rtsp_mount_points_add_factory(mounts, mountPoint.c_str(), GST_RTSP_MEDIA_FACTORY(factoryMtpr)); + g_object_unref(mounts); + + g_signal_connect(GST_RTSP_MEDIA_FACTORY(factoryMtpr), "media-constructed", G_CALLBACK(__mediaConstructedCb), NULL); + g_signal_connect(GST_RTSP_MEDIA_FACTORY(factoryMtpr), "media-configure", G_CALLBACK(__mediaConfigureCb), NULL); + + if (gst_rtsp_server_attach(server, NULL) == 0) { + LOG_ERROR("failed to attach server to default context"); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to attach server"); + } + + SECURE_LOG_DEBUG("stream ready at rtsp://%s:%s%s", ipAddr.c_str(), portNum.c_str(), mountPoint.c_str()); + + _rtspServer = static_cast(server); + _rtspMountPoint = mountPoint; + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + if (server) { + mounts = gst_rtsp_server_get_mount_points(server); + gst_rtsp_mount_points_remove_factory(mounts, mountPoint.c_str()); + g_object_unref(mounts); + gst_object_unref(server); + } + throw; + } +} + +void MediaTransporterSenderRtsp::stopRtspServer() +{ + guint ref_cnt = 0; + GstRTSPMountPoints* mounts = NULL; + GstRTSPServer* server = static_cast(_rtspServer); + + mounts = gst_rtsp_server_get_mount_points(server); + gst_rtsp_mount_points_remove_factory(mounts, _rtspMountPoint.c_str()); + g_object_unref(mounts); + + gst_rtsp_server_client_filter(server, __clientFilter, NULL); + + ref_cnt = GST_OBJECT_REFCOUNT_VALUE(server); + for (guint i = 0; i < ref_cnt; i++) + gst_object_unref(server); + + _rtspServer = NULL; + _rtspMountPoint.clear(); +} diff --git a/src/MediaTransporterSenderSrt.cpp b/src/MediaTransporterSenderSrt.cpp new file mode 100644 index 0000000..a3ebdb3 --- /dev/null +++ b/src/MediaTransporterSenderSrt.cpp @@ -0,0 +1,271 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterSenderSrt.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterUtil.h" +#include "MediaTransporterParseIni.h" + +using namespace tizen_media_transporter; + +static GstPad* _getGhostPadFromBin(GstBin* bin) +{ + GstElement* queue = gst_bin_get_by_name(bin, "srcQueue"); + if (!queue) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get srcQueue"); + + GstPad* srcPad = nullptr; + + if (!gst::_addNoTargetGhostpad(bin, &srcPad, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _addNoTargetGhostpad"); + + if (!gst::_setGhostpadTarget(srcPad, queue, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _setGhostpadTarget"); + + return srcPad; +} + +static void __callerAddedCb(GstElement* element, gint socket, GSocketAddress* address, gpointer userData) +{ + LOG_INFO("socket %d, address %s", socket, + g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)address))); +} + +static void __callerRemovedCb(GstElement* element, gint socket, GSocketAddress* address, gpointer userData) +{ + LOG_INFO("socket %d, address %s", socket, + g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)address))); +} + +static void __callerRejectedCb(GstElement* element, GSocketAddress* peerAddress, const gchar* stream_id, gpointer userData) +{ + LOG_INFO("stream_id %s, peer_address %s", stream_id, + g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)peerAddress))); +} + +static void __callerConnectingCb(GstElement* element, GSocketAddress* peerAddress, const gchar* stream_id, gpointer userData) +{ + LOG_INFO("stream_id %s, peer_address %s", stream_id, + g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)peerAddress))); +} + +ResourceSet MediaTransporterSenderSrt::buildPipeline() +{ + GstElement* mux = NULL; + GstElement* sink = NULL; + GstPad* sinkPad = NULL; + + ResourceSet allResourceRequired; + + /* create mux to sink */ + try { + mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); + g_object_set(G_OBJECT(mux), "alignment", 7, NULL); + + sink = gst::_createElement(gst::DEFAULT_ELEMENT_SRTSINK); + g_object_set(G_OBJECT(sink), "uri", _senderAddress.c_str(), "wait-for-connection", FALSE, "sync", FALSE, "latency", 10, NULL); + + gst_bin_add_many(GST_BIN(_gst.pipeline), mux, sink, NULL); + if (!gst_element_link(mux, sink)) { + LOG_ERROR("failed to gst_element_link()"); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to gst_element_link()"); + } + if (_connectionParam.mode != MTPR_CONNECTION_SRT_MODE_NONE) + g_object_set(G_OBJECT(sink), + "mode", static_cast(_connectionParam.mode), NULL); + + if (!_connectionParam.pbKeyLen != MTPR_CONNECTION_SRT_NO_KEY) + g_object_set(G_OBJECT(sink), + "pbkeylen", static_cast(_connectionParam.pbKeyLen), NULL); + + if (!_connectionParam.passPhrase.empty()) + g_object_set(G_OBJECT(sink), + "passphrase", _connectionParam.passPhrase.c_str(), NULL); + + if (!_connectionParam.streamId.empty()) + g_object_set(G_OBJECT(sink), + "streamid", _connectionParam.streamId.c_str(), NULL); + + gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(sink), "caller-added", G_CALLBACK(__callerAddedCb), &_gst); + gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(sink), "caller-removed", G_CALLBACK(__callerRemovedCb), &_gst); + gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(sink), "caller-rejected", G_CALLBACK(__callerRejectedCb), &_gst); + gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(sink), "caller-connecting", G_CALLBACK(__callerConnectingCb), &_gst); + + LOG_ERROR("pp %s, ref %d", + GST_ELEMENT_NAME(_gst.pipeline), GST_OBJECT_REFCOUNT_VALUE(_gst.pipeline)); + + /* link each element */ + for (auto& [id, mediaSource] : _mediaSources) { + auto[ type, bin, resourceRequired ] = mediaSource->generate(); + + LOG_INFO("mediaSource(type:%d, bin:%p, resourceRequired:%zu) generated", + static_cast(type), bin, resourceRequired.size()); + + allResourceRequired.insert(resourceRequired.begin(), resourceRequired.end()); + + gst_bin_add(GST_BIN(_gst.pipeline), GST_ELEMENT(bin)); + + GstPad* srcPad = _getGhostPadFromBin(bin); + if (gst_pad_is_linked(srcPad)) { + LOG_ERROR("pad %s:%s is already linked", GST_DEBUG_PAD_NAME(srcPad)); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "already linked"); + } + + sinkPad = gst_element_request_pad_simple(mux, "sink_%d"); + if (!sinkPad) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); + + GstPadLinkReturn res = gst_pad_link(srcPad, sinkPad); + if (GST_PAD_LINK_FAILED(res)) { + LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", + GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); + } + LOG_INFO("pad is linked %s:%s - %s:%s", GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + } + + _srtSink = sink; + LOG_INFO("linked mux and sink"); + + return allResourceRequired; + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + + if (sinkPad) { + gst_element_release_request_pad(mux, sinkPad); + g_object_unref(sinkPad); + } + + gst::_destroyElementFromParent(mux); + gst::_destroyElementFromParent(sink); + + throw; + } +} + +void MediaTransporterSenderSrt::startPipeline() +{ + gst::_setPipelineState(_gst.pipeline, GST_STATE_PLAYING, + MediaTransporterIni::get().general().timeout); +} + +void MediaTransporterSenderSrt::stopPipeline() +{ + _srtSink = NULL; + gst::_setPipelineState(_gst.pipeline, GST_STATE_NULL, + MediaTransporterIni::get().general().timeout); +} + +bool MediaTransporterSenderSrt::_isValidKeyLength(int val) +{ + switch(val) + { + case MTPR_CONNECTION_SRT_NO_KEY: + case MTPR_CONNECTION_SRT_KEY_LEN_16: + case MTPR_CONNECTION_SRT_KEY_LEN_24: + case MTPR_CONNECTION_SRT_KEY_LEN_32: + return true; + default: + return false; + } +} + +void MediaTransporterSenderSrt::setConnection(std::string name, std::string string_val) +{ + SECURE_LOG_INFO("%s : %s", name.c_str(), string_val.c_str()); + + try { + if (name.compare(MTPR_CONNECTION_PARAM_SRT_MODE) == 0) { + size_t size; + int val = stoi(string_val, &size); + if ((string_val.size() != size) || + (val < MTPR_CONNECTION_SRT_MODE_NONE) || (val > MTPR_CONNECTION_SRT_MODE_RENDEZVOUS)) { + LOG_ERROR("invalid srt mode value %d", val); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid srt mode value"); + } + _connectionParam.mode = static_cast(val); + + } else if (name.compare(MTPR_CONNECTION_PARAM_SRT_STREAMID) == 0) { + _connectionParam.streamId = string_val; + + } else if (name.compare(MTPR_CONNECTION_PARAM_SRT_PASSPHRASE) == 0) { + _connectionParam.passPhrase = string_val; + + } else if (name.compare(MTPR_CONNECTION_PARAM_SRT_PBKEYLEN) == 0) { + size_t size; + int val = stoi(string_val, &size); + if (string_val.size() != size || !_isValidKeyLength(val)) { + LOG_ERROR("invalid pbkeylen value %d", val); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid pbkeylen value"); + } + _connectionParam.pbKeyLen = static_cast(val); + + } else { + LOG_ERROR("invalid param name %s", name.c_str()); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid param name"); + } + } catch (const std::exception& e) { + LOG_ERROR("error : %s, throw invalid param", e.what()); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid parameter"); + } +} + +void MediaTransporterSenderSrt::setConnection(bundle* params) +{ + char* string_val = NULL; + + if (bundle_get_str(params, MTPR_CONNECTION_PARAM_SRT_MODE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + setConnection(MTPR_CONNECTION_PARAM_SRT_MODE, string_val); + } + + if (bundle_get_str(params, MTPR_CONNECTION_PARAM_SRT_STREAMID, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _connectionParam.streamId = std::string {string_val}; + } + + if (bundle_get_str(params, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + _connectionParam.passPhrase = std::string {string_val}; + } + + if (bundle_get_str(params, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + setConnection(MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, string_val); + } +} + +void MediaTransporterSenderSrt::getConnection(bundle* params) +{ + bundle_add_str(params, + MTPR_CONNECTION_PARAM_SRT_MODE, + std::to_string(static_cast(_connectionParam.mode)).c_str()); + + if (!_connectionParam.streamId.empty()) + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_STREAMID, _connectionParam.streamId.c_str()); + + if (!_connectionParam.passPhrase.empty()) + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, _connectionParam.passPhrase.c_str()); + + bundle_add_str(params, + MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, + std::to_string(static_cast(_connectionParam.pbKeyLen)).c_str()); +} + +void MediaTransporterSenderSrt::setSenderAddress(std::string address) +{ + _senderAddress = address; +} diff --git a/src/MediaTransporterSenderToServerRtsp.cpp b/src/MediaTransporterSenderToServerRtsp.cpp new file mode 100644 index 0000000..1c267d3 --- /dev/null +++ b/src/MediaTransporterSenderToServerRtsp.cpp @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterBase.h" +#include "MediaTransporterException.h" +#include "MediaTransporterSenderToServerRtsp.h" +#include "MediaTransporterGst.h" +#include "MediaTransporterLog.h" +#include "MediaTransporterUtil.h" +#include "MediaTransporterParseIni.h" + +using namespace tizen_media_transporter; + +static GstPad* _getGhostPadFromBin(GstBin* bin) +{ + GstElement* queue = gst_bin_get_by_name(bin, "srcQueue"); + if (!queue) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get srcQueue"); + + GstPad* srcPad = nullptr; + + if (!gst::_addNoTargetGhostpad(bin, &srcPad, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _addNoTargetGhostpad"); + + if (!gst::_setGhostpadTarget(srcPad, queue, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _setGhostpadTarget"); + + return srcPad; +} + +ResourceSet MediaTransporterSenderToServerRtsp::buildPipeline() +{ + GstElement *mux = NULL; + GstElement *sink = NULL; + GstPad* sinkPad = NULL; + + ResourceSet allResourceRequired; + + /* create mux to sink */ + try { + mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); + g_object_set(G_OBJECT(mux), "alignment", 7, NULL); + + sink = gst::_createElement(gst::DEFAULT_ELEMENT_RTSPSINK); + g_object_set(G_OBJECT(sink), "location", _receiverAddress.c_str(), NULL); + + gst_bin_add_many(GST_BIN(_gst.pipeline), mux, sink, NULL); + if (!gst_element_link(mux, sink)) { + LOG_ERROR("failed to gst_element_link()"); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to gst_element_link()"); + } + + LOG_ERROR("pp %s, ref %d", + GST_ELEMENT_NAME(_gst.pipeline), GST_OBJECT_REFCOUNT_VALUE(_gst.pipeline)); + + /* link each element */ + for (auto& [id, mediaSource] : _mediaSources) { + auto[ type, bin, resourceRequired ] = mediaSource->generate(); + + LOG_INFO("mediaSource(type:%d, bin:%p, resourceRequired:%zu) generated", + static_cast(type), bin, resourceRequired.size()); + + gst_bin_add(GST_BIN(_gst.pipeline), GST_ELEMENT(bin)); + + GstPad* srcPad = _getGhostPadFromBin(bin); + if (gst_pad_is_linked(srcPad)) { + LOG_ERROR("pad %s:%s is already linked", GST_DEBUG_PAD_NAME(srcPad)); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "already linked"); + } + + sinkPad = gst_element_request_pad_simple(mux, "sink_%d"); + if (!sinkPad) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); + + GstPadLinkReturn res = gst_pad_link(srcPad, sinkPad); + if (GST_PAD_LINK_FAILED(res)) { + LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", + GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); + } + LOG_INFO("pad is linked %s:%s - %s:%s", GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + } + + _rtspSink = sink; + LOG_INFO("linked mux and sink"); + + return allResourceRequired; + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + + if (sinkPad) { + gst_element_release_request_pad(mux, sinkPad); + g_object_unref(sinkPad); + } + + gst::_destroyElementFromParent(mux); + gst::_destroyElementFromParent(sink); + + throw; + } +} + +void MediaTransporterSenderToServerRtsp::startPipeline() +{ + gst::_setPipelineState(_gst.pipeline, GST_STATE_PLAYING, + MediaTransporterIni::get().general().timeout); +} + +void MediaTransporterSenderToServerRtsp::stopPipeline() +{ + _rtspSink = NULL; + gst::_setPipelineState(_gst.pipeline, GST_STATE_NULL, + MediaTransporterIni::get().general().timeout); +} + +void MediaTransporterSenderToServerRtsp::setReceiverAddress(std::string address) +{ + _receiverAddress = address; +} diff --git a/src/MediaTransporterUtil.cpp b/src/MediaTransporterUtil.cpp new file mode 100644 index 0000000..cc103df --- /dev/null +++ b/src/MediaTransporterUtil.cpp @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2022 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 "MediaTransporterUtil.h" +#include "MediaTransporterException.h" + +#include +#include +#include +#include +#include +#include + +using namespace tizen_media_transporter; + +void util::throw_if_not_privileged(const std::string& privilege) +{ + // int ret = MTPR_ERROR_NONE; + cynara *cynara_h; + char *smack_label = nullptr; + + try { + if (cynara_initialize(&cynara_h, NULL) != CYNARA_API_SUCCESS) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, + "failed to cynara_initialize()"); + + if (smack_new_label_from_self(&smack_label) == -1) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, + "failed to smack_new_label_from_self()"); + + char uid[10]; + snprintf(uid, sizeof(uid), "%d", getuid()); + //LOG_DEBUG("smack_label[%s] uid[%s]\n", smack_label, uid); + + int cynara_ret = cynara_check(cynara_h, smack_label, "", uid, privilege.c_str()); + if (cynara_ret != CYNARA_API_ACCESS_ALLOWED) { + //LOG_ERROR("NOT ALLOWED, privilege[%s], cynara_ret[%d]", privilege, cynara_ret); + throw MediaTransporterException(MTPR_ERROR_PERMISSION_DENIED, + "[" + privilege + "] is NOT ALLOWED"); + } + + //LOG_INFO("ALLOWED, privilege[%s]", privilege); + } catch (const MediaTransporterException& e) { + free(smack_label); + if (cynara_h) + cynara_finish(cynara_h); + throw; + } + + free(smack_label); + cynara_finish(cynara_h); +} + +void util::throw_if_feature_not_supported(const std::string& feature) +{ + bool supported = false; + + if (system_info_get_platform_bool(feature.c_str(), &supported) != SYSTEM_INFO_ERROR_NONE) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, + "failed to system_info_get_platform_bool(" + feature + ")"); + + if (!supported) + throw MediaTransporterException(MTPR_ERROR_NOT_SUPPORTED, + "[" + feature + "] is not supported"); + + //LOG_INFO("feature[%s] is supported", feature); +} + +void util::throw_if_network_features_not_supported() +{ + try { + throw_if_feature_not_supported(MTPR_FEATURE_NETWORK_WIFI); + throw_if_feature_not_supported(MTPR_FEATURE_NETWORK_TELE); + throw_if_feature_not_supported(MTPR_FEATURE_NETWORK_ETH); + } catch (const MediaTransporterException& e) { + throw MediaTransporterException(MTPR_ERROR_NOT_SUPPORTED, e.what()); + } +} + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000..cba788f --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,25 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +SET(fw_test "${fw_name}-test") + +INCLUDE_DIRECTORIES(../include) + +link_directories(${CMAKE_SOURCE_DIR}/../) + +INCLUDE(FindPkgConfig) + pkg_check_modules(${fw_test} REQUIRED glib-2.0 appcore-efl elementary esplusplayer) + +FOREACH(flag ${${fw_test}_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -pie -Wall -Werror") + +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} capi-media-transporter ${${fw_test}_LDFLAGS}) + INSTALL(TARGETS ${src_name} DESTINATION bin) +ENDFOREACH() diff --git a/test/mtpr_rtsp_test.c b/test/mtpr_rtsp_test.c new file mode 100644 index 0000000..3e54417 --- /dev/null +++ b/test/mtpr_rtsp_test.c @@ -0,0 +1,65 @@ +/* +* Copyright (c) 2022 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 + +#ifdef PACKAGE +#undef PACKAGE +#endif +#define PACKAGE "mtpr_rtsp_test" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "MTPR_TEST" + +#define DEFAULT_RTSP_PORT "8554" + +int main(int argc, char *argv[]) +{ + GMainLoop *loop; + GstRTSPServer *server; + GstRTSPMountPoints *mounts; + GstRTSPMediaFactory *factory; + + if (argc < 2) { + g_print("Enter launch cmd : \"( decodebin name=depay0 ! videoconvert ! tizenwlsink )\"\n"); + return 1; + } + + gst_init(NULL, NULL); + loop = g_main_loop_new(NULL, FALSE); + + server = gst_rtsp_server_new(); + g_object_set(server, "service", DEFAULT_RTSP_PORT, NULL); + + mounts = gst_rtsp_server_get_mount_points(server); + + factory = gst_rtsp_media_factory_new(); + gst_rtsp_media_factory_set_transport_mode(factory, GST_RTSP_TRANSPORT_MODE_RECORD); + gst_rtsp_media_factory_set_launch(factory, argv[1]); + + gst_rtsp_mount_points_add_factory(mounts, "/test", factory); + g_object_unref(mounts); + + gst_rtsp_server_attach(server, NULL); + + g_print("stream ready at rtsp://127.0.0.1:%s/test\n", DEFAULT_RTSP_PORT); + g_main_loop_run(loop); + + return 0; +} diff --git a/test/mtpr_test.c b/test/mtpr_test.c new file mode 100644 index 0000000..a05a2e5 --- /dev/null +++ b/test/mtpr_test.c @@ -0,0 +1,1284 @@ +/* +* Copyright (c) 2022 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 + +#ifdef PACKAGE +#undef PACKAGE +#endif +#define PACKAGE "mtpr_test" + +#ifdef LOG_TAG +#undef LOG_TAG +#endif +#define LOG_TAG "MTPR_TEST" + +#define MAX_STRING_LEN 512 + +enum { + CURRENT_STATUS_MAINMENU, + CURRENT_STATUS_CONNECTION_TYPE, + CURRENT_STATUS_SENDER_ADDRESS, + CURRENT_STATUS_RECEIVER_ADDRESS, + CURRENT_STATUS_CONNECTION_SRT_MODE, + CURRENT_STATUS_CONNECTION_SRT_STREAMID, + CURRENT_STATUS_CONNECTION_SRT_PASSPHRASE, + CURRENT_STATUS_CONNECTION_SRT_PBKEYLEN, + CURRENT_STATUS_CONNECTION_RIST_BONDING_ADDRESS, + CURRENT_STATUS_CONNECTION_RIST_MAX_RTCP_BANDWIDTH, + CURRENT_STATUS_CONNECTION_RIST_MIN_RTCP_INTERVAL, + CURRENT_STATUS_CONNECTION_RIST_SENDER_BUFFER, + CURRENT_STATUS_CONNECTION_RTSP_SERVER_IP, + CURRENT_STATUS_CONNECTION_RTSP_SERVER_PORT, + CURRENT_STATUS_CONNECTION_RTSP_SERVER_MOUNT_POINT, + CURRENT_STATUS_ADD_MEDIA_SOURCE, + CURRENT_STATUS_SOURCE_VIDEO_WIDTH, + CURRENT_STATUS_SOURCE_VIDEO_HEIGHT, + CURRENT_STATUS_SOURCE_VIDEO_FRAMERATE, + CURRENT_STATUS_SOURCE_AUDIO_CHANNEL, + CURRENT_STATUS_SOURCE_AUDIO_RATE, + CURRENT_STATUS_SOURCE_AUDIO_FORMAT, + CURRENT_STATUS_ENCODING_BITRATE, + CURRENT_STATUS_REMOVE_MEDIA_SOURCE, + CURRENT_STATUS_SET_DISPLAY, + CURRENT_STATUS_SET_DISPLAY_MODE, + CURRENT_STATUS_SET_DISPLAY_VISIBLE, + CURRENT_STATUS_SET_SOUND_STREAM_INFO, +}; + +/* for video display */ +static Evas_Object *g_eo; +static Evas_Object *g_win_id; +static Evas_Object *g_selected_win_id; + +typedef struct { + Evas_Object *win; + Evas_Object *layout_main; +} appdata; + +static appdata g_ad; +static mtpr_h g_mtpr; +static bundle *g_connection_param; +static bundle *g_source_param; +static mtpr_source_type_e g_source_type; + +static bool g_dump_data = false; + +static FILE* video_dump = NULL; +static FILE* audio_dump = NULL; + +int g_menu_state = CURRENT_STATUS_MAINMENU; +sound_stream_info_h g_mic_stream_info = NULL; +sound_stream_info_h g_stream_info = NULL; + +static void _mtpr_test_unset_track_cb(); +static void _mtpr_test_unset_encoded_audio_frame_cb(); +static void _mtpr_test_unset_encoded_video_frame_cb(); + +static void win_del(void *data, Evas_Object *obj, void *event) +{ + elm_exit(); +} + +static Evas_Object *create_win(const char *name) +{ + Evas_Object *eo = NULL; + int w = 0; + int h = 0; + + g_print("[%s][%d] name=%s\n", __func__, __LINE__, name); + + eo = elm_win_add(NULL, name, ELM_WIN_BASIC); + if (eo) { + elm_win_title_set(eo, name); + elm_win_borderless_set(eo, EINA_TRUE); + evas_object_smart_callback_add(eo, "delete,request", win_del, NULL); + elm_win_screen_size_get(eo, NULL, NULL, &w, &h); + g_print("window size :%d,%d", w, h); + evas_object_resize(eo, w, h); + elm_win_autodel_set(eo, EINA_TRUE); + elm_win_alpha_set(eo, EINA_TRUE); + } + return eo; +} + +static Evas_Object *create_image_object(Evas_Object *eo_parent) +{ + if (!eo_parent) + return NULL; + + Evas *evas = evas_object_evas_get(eo_parent); + Evas_Object *eo = NULL; + + eo = evas_object_image_add(evas); + + return eo; +} + +void create_render_rect_and_bg(Evas_Object *win) +{ + if (!win) { + g_print("no win"); + return; + } + Evas_Object *bg, *rect; + + bg = elm_bg_add(win); + elm_win_resize_object_add(win, bg); + evas_object_size_hint_weight_set(bg, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(bg); + + rect = evas_object_rectangle_add(evas_object_evas_get(win)); + if (!rect) { + g_print("no rect"); + return; + } + evas_object_color_set(rect, 0, 0, 0, 0); + evas_object_render_op_set(rect, EVAS_RENDER_COPY); + + elm_win_resize_object_add(win, rect); + evas_object_size_hint_weight_set(rect, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND); + evas_object_show(rect); + evas_object_show(win); +} + +static int app_create(void *data) +{ + appdata *ad = data; + Evas_Object *win = NULL; + + /* use gl backend */ + elm_config_accel_preference_set("opengl"); + + /* create window */ + win = create_win(PACKAGE); + if (win == NULL) + return -1; + ad->win = win; + g_win_id = win; + g_selected_win_id = g_win_id; + create_render_rect_and_bg(ad->win); + /* Create evas image object for EVAS surface */ + g_eo = create_image_object(ad->win); + evas_object_image_size_set(g_eo, 500, 500); + evas_object_image_fill_set(g_eo, 0, 0, 500, 500); + evas_object_resize(g_eo, 500, 500); + + elm_win_activate(win); + evas_object_show(win); + + return 0; +} + +static int app_terminate(void *data) +{ + appdata *ad = data; + + if (g_eo) { + evas_object_del(g_eo); + g_eo = NULL; + } + + if (g_win_id) { + evas_object_del(g_win_id); + g_win_id = NULL; + } + + ad->win = NULL; + g_selected_win_id = NULL; + + return 0; +} + +struct appcore_ops ops = { + .create = app_create, + .terminate = app_terminate, +}; + +static void __error_cb(mtpr_h mtpr, mtpr_error_e error, void *user_data) +{ + g_print(" => [ERROR_CB] mtpr[%p], error[0x%x], user_data[%p]\n", + mtpr, error, user_data); +} + +static void __track_added_cb(mtpr_h mtpr, mtpr_media_type_e type, unsigned int id, void *user_data) +{ + g_print(" => [TRACK ADDED CB] mtpr[%p], type[0x%x], id[%u], use_data[%p]\n", + mtpr, type, id, user_data); +} + +static void __no_more_track_cb(mtpr_h mtpr, void *user_data) +{ + g_print(" => [NO MORE TRACK CB] mtpr[%p], use_data[%p]\n", mtpr, user_data); +} + +static void __encoded_frame_cb(mtpr_h mtpr, mtpr_media_type_e type, unsigned int id, media_packet_h packet, void *user_data) +{ + uint64_t gst_pts; + void *temp; + uint64_t buf_size; + FILE *fp; + + if (!packet) { + g_print("encoded_frame packet is NULL\n"); + return; + } + + /* FIXME: dump file have to be created for each id */ + + if (g_dump_data) { + media_packet_get_buffer_data_ptr(packet, &temp); + media_packet_get_buffer_size(packet, &buf_size); + + fp = (type == MTPR_MEDIA_TYPE_AUDIO) ? audio_dump : video_dump; + fwrite(temp, (int)buf_size, 1, fp); + } + + media_packet_get_pts(packet, &gst_pts); + g_print("[%s][%u] frame [%llu ms]\n", (type == MTPR_MEDIA_TYPE_AUDIO) ? "Audio" : "Video", id, (unsigned long long)(gst_pts / 1000)); + + media_packet_destroy(packet); +} + +static void _mtpr_test_set_error_cb() +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_error_cb(g_mtpr, __error_cb, g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_error_cb()\n"); + else + g_print(" => mtpr_set_error_cb() success\n"); +} + +static void _mtpr_test_unset_error_cb() +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_unset_error_cb(g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_unset_error_cb()\n"); + else + g_print(" => mtpr_unset_error_cb() success\n"); +} + +static void _mtpr_test_destroy() +{ + int ret = MTPR_ERROR_NONE; + + if (!g_mtpr) { + g_print(" => failed to _mtpr_test_destroy(), g_mtpr is NULL\n"); + return; + } + + _mtpr_test_unset_error_cb(); + _mtpr_test_unset_track_cb(); + _mtpr_test_unset_encoded_audio_frame_cb(); + _mtpr_test_unset_encoded_video_frame_cb(); + + ret = mtpr_destroy(g_mtpr); + if (ret != MTPR_ERROR_NONE) { + g_print(" => failed to mtpr_destroy() returned [0x%x]\n", ret); + } else { + g_print(" => mtpr_destroy() success\n"); + g_mtpr = NULL; + } + + if (g_mic_stream_info) { + sound_manager_destroy_stream_information(g_mic_stream_info); + g_mic_stream_info = NULL; + } + if (g_stream_info) { + sound_manager_destroy_stream_information(g_stream_info); + g_stream_info = NULL; + } +} + +static void _mtpr_test_start() +{ + int ret = MTPR_ERROR_NONE; + + if (!g_mtpr) { + g_print(" => failed to _mtpr_test_start(), g_mtpr is NULL\n"); + return; + } + + ret = mtpr_start(g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_start() returned [0x%x]\n", ret); + else + g_print(" => mtpr_start() success\n"); +} + +static void _mtpr_test_stop() +{ + int ret = MTPR_ERROR_NONE; + + if (!g_mtpr) { + g_print(" => failed to _mtpr_test_stop(), g_mtpr is NULL\n"); + return; + } + + ret = mtpr_stop(g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_stop() returned [0x%x]\n", ret); + else + g_print(" => mtpr_stop() success\n"); + +} + +static void _mtpr_test_set_display(unsigned int type) +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_display(g_mtpr, (mtpr_display_type_e)type, g_win_id); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_display() returned [0x%x]\n", ret); + else + g_print(" => mtpr_set_display() success\n"); +} + +static void _mtpr_test_set_display_mode(unsigned int mode) +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_display_mode(g_mtpr, (mtpr_display_mode_e)mode); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_display_mode() returned [0x%x]\n", ret); + else + g_print(" => mtpr_set_display_mode() success\n"); +} + +static void _mtpr_test_set_display_visible(unsigned int visible) +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_display_visible(g_mtpr, (bool)visible); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_display_visible() returned [0x%x]\n", ret); + else + g_print(" => mtpr_set_display_visible() success\n"); +} + +static void _mtpr_test_create(int type) +{ + int ret = MTPR_ERROR_NONE; + + if (g_mtpr) { + g_print(" => failed to _mtpr_test_create(), already created\n"); + return; + } + + ret = mtpr_create(type, &g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_create(), ret[0x%x]\n", ret); + else + g_print(" => mtpr_create(type(%d)) success\n", type); +} + +static void _mtpr_test_get_connection_type() +{ + int ret = MTPR_ERROR_NONE; + mtpr_connection_type_e type = MTPR_CONNECTION_TYPE_RIST_SENDER; + + ret = mtpr_get_connection_type(g_mtpr, &type); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_get_connection_type() returned [0x%x]\n", ret); + else + g_print(" => type: [%d]\n", type); +} + +static void _mtpr_test_set_sender_address(char *address) +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_sender_address(g_mtpr, address); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_sender_address(), ret[0x%x]\n", ret); + else + g_print(" => mtpr_set_sender_address() success\n"); +} + +static void _mtpr_test_set_receiver_address(char *address) +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_receiver_address(g_mtpr, address); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_receiver_address(), ret[0x%x]\n", ret); + else + g_print(" => mtpr_set_receiver_address() success\n"); +} + +static void _mtpr_test_get_sender_address() +{ + int ret = MTPR_ERROR_NONE; + char *address = NULL; + + ret = mtpr_get_sender_address(g_mtpr, &address); + if (ret != MTPR_ERROR_NONE) { + g_print(" => failed to mtpr_get_sender_address(), ret[0x%x]\n", ret); + } else { + g_print(" => sender address (%s)\n", address); + } + + if (address) + free(address); +} + +static void _mtpr_test_get_receiver_address() +{ + int ret = MTPR_ERROR_NONE; + char *address = NULL; + + ret = mtpr_get_receiver_address(g_mtpr, &address); + if (ret != MTPR_ERROR_NONE) { + g_print(" => failed to mtpr_get_receiver_address(), ret[0x%x]\n", ret); + } else { + g_print(" => receiver address (%s)\n", address); + } + + if (address) + free(address); +} + +static void __set_aec_reference_device(sound_stream_info_h stream_info) +{ + int ret; + sound_device_list_h device_list = NULL; + sound_device_h device; + sound_device_type_e cur_playback_device_type; + bool found = false; + + if(stream_info == NULL) { + g_printerr("stream_info is NULL\n"); + return; + } + + ret = sound_manager_get_current_media_playback_device_type(&cur_playback_device_type); + if (ret != SOUND_MANAGER_ERROR_NONE) { + g_printerr("failed to sound_manager_get_current_media_playback_device_type()\n"); + return; + } + + ret = sound_manager_get_device_list(SOUND_DEVICE_IO_DIRECTION_OUT_MASK, &device_list); + if (ret != SOUND_MANAGER_ERROR_NONE && ret != SOUND_MANAGER_ERROR_NO_DATA) { + g_printerr("failed to sound_manager_get_device_list()\n"); + return; + } + + while (sound_manager_get_next_device(device_list, &device) == SOUND_MANAGER_ERROR_NONE) { + sound_device_type_e device_type; + int device_id; + + ret = sound_manager_get_device_type(device, &device_type); + if (ret != SOUND_MANAGER_ERROR_NONE) { + g_printerr("failed to sound_manager_get_device_type()\n"); + break; + } + + if (cur_playback_device_type != device_type) + continue; + + ret = sound_manager_get_device_id(device, &device_id); + if (ret != SOUND_MANAGER_ERROR_NONE) { + g_printerr("failed to sound_manager_get_device_id()\n"); + break; + } + + found = true; + + ret = sound_manager_set_echo_cancel_reference_device(stream_info, device); + if (ret != SOUND_MANAGER_ERROR_NONE) { + g_printerr("failed to sound_manager_set_echo_cancel_reference_device()\n"); + } else { + g_print("set a reference device[type:%u, id:%d]\n", device_type, device_id); + break; + } + } + + sound_manager_free_device_list(device_list); + + if (!found) + g_printerr("could not find a candidate for reference device\n"); +} + +static int __get_mic_sound_stream_info(bool aec, sound_stream_info_h *stream_info) +{ + int ret; + sound_device_list_h device_list = NULL; + sound_stream_info_h _stream_info = NULL; + + if (!stream_info) { + g_printerr("stream_info is NULL\n"); + return -1; + } + + ret = sound_manager_get_device_list(SOUND_DEVICE_IO_DIRECTION_IN_MASK | SOUND_DEVICE_TYPE_EXTERNAL_MASK, &device_list); + if (ret != SOUND_MANAGER_ERROR_NONE && ret != SOUND_MANAGER_ERROR_NO_DATA) { + g_printerr("failed to sound_manager_get_device_list()\n"); + return -1; + } + + if (ret == SOUND_MANAGER_ERROR_NO_DATA) { + ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA, NULL, NULL, &_stream_info); + if (ret != SOUND_MANAGER_ERROR_NONE) { + g_printerr("failed to sound_manager_create_stream_information()\n"); + goto error; + } + + } else { + sound_device_h device; + char *device_name = NULL; + ret = sound_manager_create_stream_information(SOUND_STREAM_TYPE_MEDIA_EXTERNAL_ONLY, NULL, NULL, &_stream_info); + if (ret != SOUND_MANAGER_ERROR_NONE) { + g_printerr("failed to sound_manager_create_stream_information()\n"); + goto error; + } + ret = sound_manager_get_next_device(device_list, &device); + if (ret != SOUND_MANAGER_ERROR_NONE) { + g_printerr("failed to get device\n"); + goto error; + } + ret |= sound_manager_add_device_for_stream_routing(_stream_info, device); + ret |= sound_manager_apply_stream_routing(_stream_info); + if (ret != SOUND_MANAGER_ERROR_NONE) { + g_printerr("failed to apply stream routing\n"); + goto error; + } + sound_manager_get_device_name(device, &device_name); + g_print("device[%s] is applied.\n", device_name); + } + + sound_manager_free_device_list(device_list); + + *stream_info = _stream_info; + + if (aec) + __set_aec_reference_device(*stream_info); + + return 0; + +error: + if (device_list) + sound_manager_free_device_list(device_list); + if (_stream_info) + sound_manager_destroy_stream_information(_stream_info); + return -1; +} + +static void _mtpr_test_add_media_source(int type) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + int param_len = 0; + + param_len = bundle_get_count(g_source_param); + g_print(" => num of source param : %d", param_len); + if (param_len > 1) + ret = mtpr_add_media_source(g_mtpr, (mtpr_source_type_e)type, g_source_param, &source_id); + else + ret = mtpr_add_media_source(g_mtpr, (mtpr_source_type_e)type, NULL, &source_id); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_add_media_source(), ret[0x%x]\n", ret); + else + g_print(" => mtpr_add_media_source() success, source_id[%d]\n", source_id); + + if (type == MTPR_SOURCE_TYPE_CAMERA || type == MTPR_SOURCE_TYPE_VIDEOTEST) { + // mtpr_source_set_video_loopback(g_mtpr, source_id, MTPR_DISPLAY_TYPE_OVERLAY, g_win_id); + } else if (type == MTPR_SOURCE_TYPE_MIC) { + if (__get_mic_sound_stream_info(false, &g_mic_stream_info) < 0) { + g_print("failed to __get_mic_sound_stream_info()\n"); + } else { + mtpr_mic_source_set_sound_stream_info(g_mtpr, source_id, g_mic_stream_info); + } + } +} + +static void _mtpr_test_remove_media_source(unsigned int source_id) +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_remove_media_source(g_mtpr, source_id); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_remove_media_source(), source_id[%d], ret[0x%x]\n", source_id, ret); + else + g_print(" => mtpr_remove_media_source() success, source_id[%d]\n", source_id); +} + +static void _mtpr_test_get_state() +{ + int ret = MTPR_ERROR_NONE; + mtpr_state_e state = MTPR_STATE_IDLE; + + ret = mtpr_get_state(g_mtpr, &state); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_get_state() returned [0x%x]\n", ret); + else + g_print(" => state: [%d]\n", state); +} + +static void _mtpr_test_set_connection_params() +{ + int ret = MTPR_ERROR_NONE; + int param_len = 0; + + param_len = bundle_get_count(g_connection_param); + g_print(" => num of connection param : %d\n", param_len); + if (param_len > 0) + ret = mtpr_set_connection_params(g_mtpr, g_connection_param); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_connection_params() returned [0x%x]\n", ret); + bundle_free(g_connection_param); + g_connection_param = NULL; +} + +static void __bundle_iter_cb(const char *key, const int type, const bundle_keyval_t *kv, void *user_data) +{ + void *val = NULL; + size_t size = 0; + + bundle_keyval_get_basic_val((bundle_keyval_t *)kv, &val, &size); + + g_print(" => key : %s, size : %zu,\t val : %s\n", key, size, (char *)val); +} + +static void _mtpr_test_get_connection_params() +{ + int ret = MTPR_ERROR_NONE; + bundle *param = NULL; + int param_len = 0; + + ret = mtpr_get_connection_params(g_mtpr, ¶m); + if (ret != MTPR_ERROR_NONE) { + g_print(" => failed to mtpr_get_connection_params() returned [0x%x]\n", ret); + return; + } + + param_len = bundle_get_count(param); + g_print(" => num of connection param : %d\n", param_len); + + bundle_foreach(param, __bundle_iter_cb, NULL); + bundle_free(param); +} + +static void _mtpr_test_set_track_cb() +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_track_added_cb(g_mtpr, __track_added_cb, g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_track_added_cb()\n"); + else + g_print(" => mtpr_set_track_added_cb() success\n"); + + ret = mtpr_set_no_more_track_cb(g_mtpr, __no_more_track_cb, g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_no_more_track_cb()\n"); + else + g_print(" => mtpr_set_no_more_track_cb() success\n"); +} + +static void _mtpr_test_unset_track_cb() +{ + mtpr_unset_track_added_cb(g_mtpr); + mtpr_unset_no_more_track_cb(g_mtpr); +} + +static void _mtpr_test_set_encoded_audio_frame_cb() +{ + int ret = MTPR_ERROR_NONE; + if (g_dump_data) + audio_dump = fopen ("/tmp/audio_encoded.dump", "w+"); + + ret = mtpr_set_audio_packet_cb(g_mtpr, __encoded_frame_cb, g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_audio_packet_cb()\n"); + else + g_print(" => mtpr_set_audio_packet_cb() success\n"); +} + +static void _mtpr_test_unset_encoded_audio_frame_cb() +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_unset_audio_packet_cb(g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_unset_audio_packet_cb()\n"); + else + g_print(" => mtpr_unset_audio_packet_cb() success\n"); + + if (g_dump_data && audio_dump) { + fclose (audio_dump); + audio_dump = NULL; + } +} + +static void _mtpr_test_set_encoded_video_frame_cb() +{ + int ret = MTPR_ERROR_NONE; + + if (g_dump_data) + video_dump = fopen ("/tmp/video_encoded.dump", "w+"); + + ret = mtpr_set_video_packet_cb(g_mtpr, __encoded_frame_cb, g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_set_video_packet_cb()\n"); + else + g_print(" => mtpr_set_video_packet_cb() success\n"); +} + +static void _mtpr_test_unset_encoded_video_frame_cb() +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_unset_video_packet_cb(g_mtpr); + if (ret != MTPR_ERROR_NONE) + g_print(" => failed to mtpr_unset_video_packet_cb()\n"); + else + g_print(" => mtpr_unset_video_packet_cb() success\n"); + + if (g_dump_data && video_dump) { + fclose (video_dump); + video_dump = NULL; + } +} + +static void _mtpr_test_set_sound_stream_info(int type) +{ + sound_device_list_h device_list = NULL; + int ret = SOUND_MANAGER_ERROR_NONE; + + if (g_stream_info) { + g_print("stream information is already set, please destroy handle and try again\n"); + return; + } + if (sound_manager_create_stream_information(type, NULL, NULL, &g_stream_info)) { + g_print("failed to create stream_information()\n"); + return; + } + /* In case of MEDIA_EXTERNAL_ONLY, we need to set external device manually */ + if (type == (int)SOUND_STREAM_TYPE_MEDIA_EXTERNAL_ONLY) { + sound_device_h device = NULL; + sound_device_type_e device_type; + + if ((ret = sound_manager_get_device_list(SOUND_DEVICE_ALL_MASK, &device_list))) { + g_print("failed to sound_manager_get_device_list(), ret(0x%x)\n", ret); + goto END; + } + while (!(ret = sound_manager_get_next_device(device_list, &device))) { + if ((ret = sound_manager_get_device_type(device, &device_type))) { + g_print("failed to sound_manager_get_device_type(), ret(0x%x)\n", ret); + goto END; + } + if (device_type == SOUND_DEVICE_BLUETOOTH_MEDIA || device_type == SOUND_DEVICE_USB_AUDIO) { + if ((ret = sound_manager_add_device_for_stream_routing(g_stream_info, device))) { + g_print("failed to sound_manager_add_device_for_stream_routing(), ret(0x%x)\n", ret); + goto END; + } + if ((ret = sound_manager_apply_stream_routing(g_stream_info))) { + g_print("failed to sound_manager_apply_stream_routing(), ret(0x%x)\n", ret); + goto END; + } + break; + } + } + if (ret != SOUND_MANAGER_ERROR_NONE) { + g_print("failed to sound_manager_get_next_device(), ret(0x%x)\n", ret); + goto END; + } + } + + if (mtpr_set_sound_stream_info(g_mtpr, g_stream_info) != MTPR_ERROR_NONE) + g_print("failed to set sound stream information(%p)\n", g_stream_info); + else + g_print("set stream information(%p) success", g_stream_info); + +END: + if (device_list) + sound_manager_free_device_list(device_list); + return; +} + +void quit_program() +{ + if (g_mtpr != NULL) { + _mtpr_test_stop(); + _mtpr_test_destroy(); + } + + g_print(" => EXIT\n"); + elm_exit(); +} + +void _interpret_main_menu(char *cmd) +{ + int len = strlen(cmd); + if (len == 1) { + if (strncmp(cmd, "c", 1) == 0) { + g_menu_state = CURRENT_STATUS_CONNECTION_TYPE; + } else if (strncmp(cmd, "d", 1) == 0) { + _mtpr_test_destroy(); + } else if (strncmp(cmd, "s", 1) == 0) { + _mtpr_test_start(); + } else if (strncmp(cmd, "t", 1) == 0) { + _mtpr_test_stop(); + } else if (strncmp(cmd, "a", 1) == 0) { + g_menu_state = CURRENT_STATUS_ADD_MEDIA_SOURCE; + } else if (strncmp(cmd, "r", 1) == 0) { + g_menu_state = CURRENT_STATUS_REMOVE_MEDIA_SOURCE; + } else if (strncmp(cmd, "g", 1) == 0) { + _mtpr_test_get_state(); + } else if (strncmp(cmd, "q", 1) == 0) { + quit_program(); + } else { + g_print("unknown menu \n"); + } + } else if (len == 2) { + if (strncmp(cmd, "se", 2) == 0) { + _mtpr_test_set_error_cb(); + } else if (strncmp(cmd, "cs", 2) == 0) { + g_menu_state = CURRENT_STATUS_CONNECTION_SRT_MODE; + } else if (strncmp(cmd, "cr", 2) == 0) { + g_menu_state = CURRENT_STATUS_CONNECTION_RIST_BONDING_ADDRESS; + } else if (strncmp(cmd, "cg", 2) == 0) { + _mtpr_test_get_connection_params(); + } else if (strncmp(cmd, "ds", 2) == 0) { + g_menu_state = CURRENT_STATUS_SET_DISPLAY; + } else if (strncmp(cmd, "dm", 2) == 0) { + g_menu_state = CURRENT_STATUS_SET_DISPLAY_MODE; + } else if (strncmp(cmd, "dv", 2) == 0) { + g_menu_state = CURRENT_STATUS_SET_DISPLAY_VISIBLE; + } else if (strncmp(cmd, "ea", 2) == 0) { + _mtpr_test_set_encoded_audio_frame_cb(); + } else if (strncmp(cmd, "ev", 2) == 0) { + _mtpr_test_set_encoded_video_frame_cb(); + } else if (strncmp(cmd, "ed", 2) == 0) { + g_dump_data = true; + } else if (strncmp(cmd, "et", 2) == 0) { + _mtpr_test_set_track_cb(); + } else if (strncmp(cmd, "rs", 2) == 0) { + g_menu_state = CURRENT_STATUS_SET_SOUND_STREAM_INFO; + } else { + g_print("unknown menu \n"); + } + } else if (len == 3) { + if (strncmp(cmd, "cgt", 3) == 0) { + _mtpr_test_get_connection_type(); + } else if (strncmp(cmd, "csa", 3) == 0) { + g_menu_state = CURRENT_STATUS_SENDER_ADDRESS; + } else if (strncmp(cmd, "cra", 3) == 0) { + g_menu_state = CURRENT_STATUS_RECEIVER_ADDRESS; + } else if (strncmp(cmd, "crs", 3) == 0) { + g_menu_state = CURRENT_STATUS_CONNECTION_RTSP_SERVER_IP; + } else if (strncmp(cmd, "cgs", 3) == 0) { + _mtpr_test_get_sender_address(); + } else if (strncmp(cmd, "cgr", 3) == 0) { + _mtpr_test_get_receiver_address(); + } else { + g_print("unknown menu \n"); + } + } else { + g_print("unknown menu \n"); + } +} + +void display_sub_basic() +{ + g_print("\n"); + g_print("=========================================================================================\n"); + g_print(" Media Transporter Test (press q to quit) \n"); + g_print("-----------------------------------------------------------------------------------------\n"); + + g_print("c. Create\t"); + g_print("d. Destroy\n"); + g_print("se. Set error callback\t"); + g_print("s. Start\t"); + g_print("t. Stop\n"); + g_print("g. Get state\n\n"); + + g_print("-- << Connection Info >> ----------------------------------------------------------------\n"); + + g_print("csa. set sender address\t\t"); + g_print("cra. set receiver address\n"); + g_print("cgs. get sender address\t\t"); + g_print("cgr. get receiver address\n"); + g_print("cs. set SRT params\t"); + g_print("cr. set RIST params\t"); + g_print("crs. set RTSP sender params\n"); + g_print("cgt. get connection type\t"); + g_print("cg. get connection params\n\n"); + + g_print("-- << Sender source >> ------------------------------------------------------------------\n"); + + g_print("a. Add media source\t"); + g_print("r. Remove media source\n\n"); + + g_print("-- << Receiver sink >> ------------------------------------------------------------------\n"); + g_print("ds. set display \t"); + g_print("dm. set display mode \t"); + g_print("dv. set display visible \n"); + g_print("rs. set sound stream info \t"); + g_print("ed. dump frame data \n"); + g_print("ea. set audio frame cb \t"); + g_print("ev. set video frame cb \t"); + g_print("et. set track added & no more track cb \n\n"); + + g_print("=========================================================================================\n"); +} + +static void displaymenu() +{ + if (g_menu_state == CURRENT_STATUS_MAINMENU) { + display_sub_basic(); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_TYPE) { + g_print("*** Input connection type.\n\ + (1:RIST_SENDER, 2:RIST_RECEIVER, 3:SRT_SENDER, 4:SRT_RECEIVER, 5:RTSP_SENDER, 6:RTSP_SENDER_TO_SERVER)\n"); + } else if (g_menu_state == CURRENT_STATUS_SENDER_ADDRESS) { + g_print("*** Input sender address:\n"); + } else if (g_menu_state == CURRENT_STATUS_RECEIVER_ADDRESS) { + g_print("*** Input receiver address:\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_SRT_MODE) { + g_print("*** Input SRT mode:\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_SRT_STREAMID) { + g_print("*** Input SRT streamid:\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_SRT_PASSPHRASE) { + g_print("*** Input SRT passphrase:\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_SRT_PBKEYLEN) { + g_print("*** Input SRT crypto key len (0, 16, 24, 32):\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_RIST_BONDING_ADDRESS) { + g_print("*** Input RIST bonding address(Comma(,) separated)\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_RIST_MAX_RTCP_BANDWIDTH) { + g_print("*** Input RIST max rtcp bandwidth (0 ~ 0.05)(default: 0.05)\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_RIST_MIN_RTCP_INTERVAL) { + g_print("*** Input RIST min RTCP interval (0 ~ 100ms)(default:100)\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_RIST_SENDER_BUFFER) { + g_print("*** Input RIST sender buffer size (default:1200)\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_RTSP_SERVER_IP) { + g_print("*** Input RTSP server ip\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_RTSP_SERVER_PORT) { + g_print("*** Input RTSP server port\n"); + } else if (g_menu_state == CURRENT_STATUS_CONNECTION_RTSP_SERVER_MOUNT_POINT) { + g_print("*** Input RTSP mount point\n"); + } else if (g_menu_state == CURRENT_STATUS_ADD_MEDIA_SOURCE) { + g_print("*** Input media source type.(1:camera, 2:mic, 3:videotest, 4:audiotest)\n"); + } else if (g_menu_state == CURRENT_STATUS_SOURCE_VIDEO_WIDTH) { + g_print("*** Input source video width\n"); + } else if (g_menu_state == CURRENT_STATUS_SOURCE_VIDEO_HEIGHT) { + g_print("*** Input source video height\n"); + } else if (g_menu_state == CURRENT_STATUS_SOURCE_VIDEO_FRAMERATE) { + g_print("*** Input source video framerate\n"); + } else if (g_menu_state == CURRENT_STATUS_SOURCE_AUDIO_CHANNEL) { + g_print("*** Input source audio channel\n"); + } else if (g_menu_state == CURRENT_STATUS_SOURCE_AUDIO_RATE) { + g_print("*** Input source audio rate\n"); + } else if (g_menu_state == CURRENT_STATUS_SOURCE_AUDIO_FORMAT) { + g_print("*** Input source audio format (ex, F32LE)\n"); + } else if (g_menu_state == CURRENT_STATUS_ENCODING_BITRATE) { + g_print("*** Input encoding bitrate: (bits/s)\n"); + } else if (g_menu_state == CURRENT_STATUS_REMOVE_MEDIA_SOURCE) { + g_print("*** Input media source id to remove.\n"); + } else if (g_menu_state == CURRENT_STATUS_SET_DISPLAY) { + g_print("*** Input display surface type. (0:overlay, 1:evas)\n"); + } else if (g_menu_state == CURRENT_STATUS_SET_DISPLAY_MODE) { + g_print("*** Input display surface type. (0:Letter box, 1:Origin size, 2:Full mode)\n"); + } else if (g_menu_state == CURRENT_STATUS_SET_DISPLAY_VISIBLE) { + g_print("*** Input display surface type. (0:invisible, 1:visible)\n"); + } else if (g_menu_state == CURRENT_STATUS_SET_SOUND_STREAM_INFO) { + g_print("*** input sound stream type.(0:MEDIA 1:SYSTEM 2:ALARM 3:NOTIFICATION 4:EMERGENCY 5:VOICE_INFORMATION 9:MEDIA_EXT_ONLY)\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) +{ + int value = 0; + double value_d = 0; + + switch (g_menu_state) { + case CURRENT_STATUS_MAINMENU: + _interpret_main_menu(cmd); + break; + case CURRENT_STATUS_CONNECTION_TYPE: { + value = atoi(cmd); + _mtpr_test_create(value - 1); + reset_menu_state(); + break; + } + case CURRENT_STATUS_SENDER_ADDRESS: { + _mtpr_test_set_sender_address(cmd); + reset_menu_state(); + break; + } + case CURRENT_STATUS_RECEIVER_ADDRESS: { + _mtpr_test_set_receiver_address(cmd); + reset_menu_state(); + break; + } + case CURRENT_STATUS_CONNECTION_SRT_MODE: { + if (g_connection_param != NULL) + bundle_free(g_connection_param); + g_connection_param = bundle_create(); + value = atoi(cmd); + if (value > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_SRT_MODE, g_strdup_printf("%u", (guint)value)); + g_menu_state = CURRENT_STATUS_CONNECTION_SRT_STREAMID; + break; + } + case CURRENT_STATUS_CONNECTION_SRT_STREAMID: { + if (strlen(cmd) > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_SRT_STREAMID, strdup(cmd)); + g_menu_state = CURRENT_STATUS_CONNECTION_SRT_PASSPHRASE; + break; + } + case CURRENT_STATUS_CONNECTION_SRT_PASSPHRASE: { + if (strlen(cmd) > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, strdup(cmd)); + g_menu_state = CURRENT_STATUS_CONNECTION_SRT_PBKEYLEN; + break; + } + case CURRENT_STATUS_CONNECTION_SRT_PBKEYLEN: { + value = atoi(cmd); + if (value > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, g_strdup_printf("%u", (guint)value)); + _mtpr_test_set_connection_params(); + reset_menu_state(); + break; + } + case CURRENT_STATUS_CONNECTION_RIST_BONDING_ADDRESS: { + if (g_connection_param != NULL) + bundle_free(g_connection_param); + g_connection_param = bundle_create(); + if (strlen(cmd) > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_RIST_BONDING_ADDRESS, strdup(cmd)); + g_menu_state = CURRENT_STATUS_CONNECTION_RIST_MAX_RTCP_BANDWIDTH; + break; + } + case CURRENT_STATUS_CONNECTION_RIST_MAX_RTCP_BANDWIDTH: { + value_d = atof(cmd); + if (value_d >= 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_RIST_MAX_RTCP_BANDWIDTH, g_strdup_printf("%f", (gdouble)value_d)); + g_menu_state = CURRENT_STATUS_CONNECTION_RIST_MIN_RTCP_INTERVAL; + break; + } + case CURRENT_STATUS_CONNECTION_RIST_MIN_RTCP_INTERVAL: { + value = atoi(cmd); + if (value > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_RIST_MIN_RTCP_INTERVAL, g_strdup_printf("%u", (guint)value)); + g_menu_state = CURRENT_STATUS_CONNECTION_RIST_SENDER_BUFFER; + break; + } + case CURRENT_STATUS_CONNECTION_RIST_SENDER_BUFFER: { + value = atoi(cmd); + if (value > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_RIST_SENDER_BUFFER, g_strdup_printf("%u", (guint)value)); + _mtpr_test_set_connection_params(); + reset_menu_state(); + break; + } + case CURRENT_STATUS_CONNECTION_RTSP_SERVER_IP: { + if (g_connection_param != NULL) + bundle_free(g_connection_param); + g_connection_param = bundle_create(); + if (strlen(cmd) > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_RTSP_SERVER_IP, strdup(cmd)); + g_menu_state = CURRENT_STATUS_CONNECTION_RTSP_SERVER_PORT; + break; + } + case CURRENT_STATUS_CONNECTION_RTSP_SERVER_PORT: { + if (strlen(cmd) > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_RTSP_SERVER_PORT, strdup(cmd)); + g_menu_state = CURRENT_STATUS_CONNECTION_RTSP_SERVER_MOUNT_POINT; + break; + } + case CURRENT_STATUS_CONNECTION_RTSP_SERVER_MOUNT_POINT: { + if (strlen(cmd) > 0) + bundle_add_str(g_connection_param, MTPR_CONNECTION_PARAM_RTSP_SERVER_MOUNT_POINT, strdup(cmd)); + _mtpr_test_set_connection_params(); + reset_menu_state(); + break; + } + case CURRENT_STATUS_ADD_MEDIA_SOURCE: { + value = atoi(cmd); + g_source_type = (mtpr_source_type_e) value - 1; + switch (g_source_type) + { + case MTPR_SOURCE_TYPE_CAMERA: + case MTPR_SOURCE_TYPE_VIDEOTEST: + g_menu_state = CURRENT_STATUS_SOURCE_VIDEO_WIDTH; + break; + case MTPR_SOURCE_TYPE_MIC: + case MTPR_SOURCE_TYPE_AUDIOTEST: + g_menu_state = CURRENT_STATUS_SOURCE_AUDIO_CHANNEL; + default: + break; + } + break; + } + case CURRENT_STATUS_SOURCE_VIDEO_WIDTH: { + value = atoi(cmd); + if (g_source_param != NULL) + bundle_free(g_source_param); + g_source_param = bundle_create(); + if (value > 0) + bundle_add_str(g_source_param, MTPR_SOURCE_PARAM_VIDEO_WIDTH, g_strdup_printf("%u", (guint)value)); + g_menu_state = CURRENT_STATUS_SOURCE_VIDEO_HEIGHT; + break; + } + case CURRENT_STATUS_SOURCE_VIDEO_HEIGHT: { + value = atoi(cmd); + if (value > 0) + bundle_add_str(g_source_param, MTPR_SOURCE_PARAM_VIDEO_HEIGHT, g_strdup_printf("%u", (guint)value)); + g_menu_state = CURRENT_STATUS_SOURCE_VIDEO_FRAMERATE; + break; + } + case CURRENT_STATUS_SOURCE_VIDEO_FRAMERATE: { + value = atoi(cmd); + if (value > 0) + bundle_add_str(g_source_param, MTPR_SOURCE_PARAM_VIDEO_FRAMERATE, g_strdup_printf("%u", (guint)value)); + g_menu_state = CURRENT_STATUS_ENCODING_BITRATE; + break; + } + case CURRENT_STATUS_SOURCE_AUDIO_CHANNEL: { + value = atoi(cmd); + if (g_source_param != NULL) + bundle_free(g_source_param); + g_source_param = bundle_create(); + if (value > 0) + bundle_add_str(g_source_param, MTPR_SOURCE_PARAM_AUDIO_CHANNEL, g_strdup_printf("%u", (guint)value)); + g_menu_state = CURRENT_STATUS_SOURCE_AUDIO_RATE; + break; + } + case CURRENT_STATUS_SOURCE_AUDIO_RATE: { + value = atoi(cmd); + if (value > 0) + bundle_add_str(g_source_param, MTPR_SOURCE_PARAM_AUDIO_RATE, g_strdup_printf("%u", (guint)value)); + g_menu_state = CURRENT_STATUS_SOURCE_AUDIO_FORMAT; + break; + } + case CURRENT_STATUS_SOURCE_AUDIO_FORMAT: { + if (strlen(cmd) > 0) + bundle_add_str(g_source_param, MTPR_SOURCE_PARAM_AUDIO_FORMAT, strdup(cmd)); + g_menu_state = CURRENT_STATUS_ENCODING_BITRATE; + break; + } + case CURRENT_STATUS_REMOVE_MEDIA_SOURCE: { + value = atoi(cmd); + _mtpr_test_remove_media_source(value); + reset_menu_state(); + break; + } + case CURRENT_STATUS_SET_DISPLAY:{ + value = atoi(cmd); + _mtpr_test_set_display(value); + reset_menu_state(); + break; + } + case CURRENT_STATUS_SET_DISPLAY_MODE:{ + value = atoi(cmd); + _mtpr_test_set_display_mode(value); + reset_menu_state(); + break; + } + case CURRENT_STATUS_SET_DISPLAY_VISIBLE:{ + value = atoi(cmd); + _mtpr_test_set_display_visible(value); + reset_menu_state(); + break; + } + case CURRENT_STATUS_ENCODING_BITRATE:{ + value = atoi(cmd); + if (value > 0) + bundle_add_str(g_source_param, MTPR_ENCODING_PARAM_BITRATE, g_strdup_printf("%u", (guint)value)); + _mtpr_test_add_media_source(g_source_type); + bundle_free(g_source_param); + g_source_param = NULL; + reset_menu_state(); + break; + } + case CURRENT_STATUS_SET_SOUND_STREAM_INFO:{ + value = atoi(cmd); + _mtpr_test_set_sound_stream_info(value); + reset_menu_state(); + break; + } + default: + break; + } + + g_timeout_add(100, timeout_menu_display, 0); +} + + +static gboolean input(GIOChannel *channel, GIOCondition condition, gpointer data) +{ + gchar buf[MAX_STRING_LEN]; + gsize read; + GIOStatus status; + + status = g_io_channel_read_chars(channel, buf, MAX_STRING_LEN, &read, NULL); + if (status != G_IO_STATUS_NORMAL) { + g_printerr("failed to g_io_channel_read_chars(), status[%d]", status); + return TRUE; + } + + 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); + + displaymenu(); + memset(&g_ad, 0x0, sizeof(appdata)); + ops.data = &g_ad; + + return appcore_efl_main(PACKAGE, &argc, &argv, &ops); +} + diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt new file mode 100644 index 0000000..8a314c3 --- /dev/null +++ b/unittest/CMakeLists.txt @@ -0,0 +1,67 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) +SET(fw_name "mtpr_ut") + +SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) +SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) + +SET(${fw_name}_CXXFLAGS "-Wall -pthread -fPIE -Wl,-z,relro -fstack-protector -fno-delete-null-pointer-checks -DEFL_BETA_API_SUPPORT") + +SET(${fw_name}_LDFLAGS) + +SET(ADD_LIBS + "capi-media-transporter" +) + +SET(dependents + "glib-2.0 gstreamer-base-1.0 gstreamer-app-1.0 dlog" +) + +find_package(GTest REQUIRED) +set(GTEST_LIBRARY gtest) + +INCLUDE(FindPkgConfig) + +IF(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +ELSE(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l) +pkg_check_modules(${fw_name} REQUIRED ${dependents}) +ENDIF(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l) + +FOREACH(flag ${${fw_name}_CFLAGS}) +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}") +ENDFOREACH(flag) +FOREACH(flag ${${fw_name}_CXXFLAGS}) +SET(EXTRA_CXXFLAGS "${EXTRA_CXXFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${EXTRA_CXXFLAGS}") + +INCLUDE_DIRECTORIES( + ${PROJECT_SOURCE_DIR}/src + ${PROJECT_SOURCE_DIR}/include + ${PROJECT_SOURCE_DIR} +) + +SET(UT_SRC + ut_srt_sender.cpp + ut_main.cpp +) + +ADD_EXECUTABLE(${fw_name} ${UT_SRC}) + +LINK_DIRECTORIES(${LIB_INSTALL_DIR}) + +TARGET_LINK_LIBRARIES(${fw_name} + ${GTEST_LIBRARY} + ${CMAKE_THREAD_LIBS_INIT} + ${ADD_LIBS} + ${${fw_name}_LDFLAGS} + "-pie" +) + +INSTALL( + TARGETS ${fw_name} + DESTINATION bin +) diff --git a/unittest/testbase.hpp b/unittest/testbase.hpp new file mode 100644 index 0000000..5e18925 --- /dev/null +++ b/unittest/testbase.hpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gtest/gtest.h" +#include + +#undef LOG_TAG +#define LOG_TAG "MTPR_UT" + +class MediaTransporterTestBase : public ::testing::Test { +public: + MediaTransporterTestBase() : _mtpr(nullptr) {} + + void SetUp() override {} + void TearDown() override {} + + mtpr_h GetHandle() { return _mtpr; } + const std::string& GetSRTSenderPath() { return _srtSenderPath; } + const std::string& GetSRTReceiverPath() { return _srtReceiverPath; } + const std::string& GetRTSPSenderPath() { return _rtspSenderPath; } + +protected: + mtpr_h _mtpr; + +private: + const std::string _srtSenderPath = "srt://:8888"; + const std::string _srtReceiverPath = "srt://127.0.0.1:8888"; + const std::string _rtspSenderPath = "rtsp://127.0.0.1:8554/test"; +}; diff --git a/unittest/ut_main.cpp b/unittest/ut_main.cpp new file mode 100644 index 0000000..d84a5b4 --- /dev/null +++ b/unittest/ut_main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 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" + +int main(int argc, char *argv[]) +{ + try { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + } catch (const std::exception &e) { + std::cout << "caught exception: " << e.what() << std::endl; + return -1; + } +} diff --git a/unittest/ut_srt_sender.cpp b/unittest/ut_srt_sender.cpp new file mode 100644 index 0000000..504680c --- /dev/null +++ b/unittest/ut_srt_sender.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022 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 "testbase.hpp" + +class MediaTransporterSrtSenderTest : public MediaTransporterTestBase { +public: + MediaTransporterSrtSenderTest() {} + + void SetUp() override { + LOGD("Enter"); + + int ret = MTPR_ERROR_NONE; + ret = mtpr_create(MTPR_CONNECTION_TYPE_SRT_SENDER, &_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + LOGD("Leave"); + } + + void TearDown() override { + LOGD("Enter"); + + if (_mtpr) { + int ret = mtpr_destroy(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + } + + LOGD("Leave"); + } +}; + +TEST_F(MediaTransporterSrtSenderTest, set_address) +{ + int ret = MTPR_ERROR_NONE; + char *address = NULL; + + ret = mtpr_set_receiver_address(GetHandle(), GetSRTSenderPath().c_str()); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION); + + ret = mtpr_set_sender_address(GetHandle(), GetSRTSenderPath().c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_get_sender_address(GetHandle(), &address); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_TRUE(address); + + LOGD("sender address : %s", address); + + ASSERT_STREQ(GetSRTSenderPath().c_str(), address); +} + +TEST_F(MediaTransporterSrtSenderTest, get_connection_type) +{ + mtpr_connection_type_e type; + + int ret = mtpr_get_connection_type(GetHandle(), &type); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_EQ(type, MTPR_CONNECTION_TYPE_SRT_SENDER); +} + +TEST_F(MediaTransporterSrtSenderTest, add_media_source) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + + ret = mtpr_add_media_source(GetHandle(), MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_TRUE(source_id >= 0); + + ret = mtpr_add_media_source(GetHandle(), MTPR_SOURCE_TYPE_AUDIOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_TRUE(source_id >= 0); +} + +TEST_F(MediaTransporterSrtSenderTest, remove_media_source) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + + ret = mtpr_add_media_source(GetHandle(), MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_TRUE(source_id >= 0); + + ret = mtpr_remove_media_source(GetHandle(), source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); +} -- 2.7.4 From f9bba8ed41f5872ed60f1ae579455e3221991624 Mon Sep 17 00:00:00 2001 From: Eunhye Choi Date: Thu, 1 Sep 2022 11:41:09 +0900 Subject: [PATCH 03/12] [0.0.2] check empty address - check empty address and return correct error before building pipeline - fix abort Change-Id: I5883de04ebb3a34fd7dabdd691d4c868346d6f89 --- packaging/capi-media-transporter.spec | 2 +- src/MediaTransporterReceiverRist.cpp | 3 +++ src/MediaTransporterReceiverSrt.cpp | 3 +++ src/MediaTransporterSenderRist.cpp | 3 +++ src/MediaTransporterSenderRtsp.cpp | 3 +++ src/MediaTransporterSenderSrt.cpp | 3 +++ src/MediaTransporterSenderToServerRtsp.cpp | 3 +++ 7 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec index 5299603..b94ba41 100644 --- a/packaging/capi-media-transporter.spec +++ b/packaging/capi-media-transporter.spec @@ -1,6 +1,6 @@ Name: capi-media-transporter Summary: A Media Transporter library in Tizen Native API -Version: 0.0.1 +Version: 0.0.2 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/MediaTransporterReceiverRist.cpp b/src/MediaTransporterReceiverRist.cpp index 5282ba0..ee93a54 100644 --- a/src/MediaTransporterReceiverRist.cpp +++ b/src/MediaTransporterReceiverRist.cpp @@ -91,6 +91,9 @@ ResourceSet MediaTransporterReceiverRist::buildPipeline() /* create mux to sink */ try { + if (_receiverAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + src = gst::_createElement(gst::DEFAULT_ELEMENT_RISTSRC); g_object_set(G_OBJECT(src), "bonding-addresses", _receiverAddress.c_str(), "receiver-buffer", 0, NULL); diff --git a/src/MediaTransporterReceiverSrt.cpp b/src/MediaTransporterReceiverSrt.cpp index 9d3bdfb..502f794 100644 --- a/src/MediaTransporterReceiverSrt.cpp +++ b/src/MediaTransporterReceiverSrt.cpp @@ -90,6 +90,9 @@ ResourceSet MediaTransporterReceiverSrt::buildPipeline() /* create mux to sink */ try { + if (_senderAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + src = gst::_createElement(gst::DEFAULT_ELEMENT_SRTSRC); g_object_set(G_OBJECT(src), "uri", _senderAddress.c_str(), "latency", 10, NULL); diff --git a/src/MediaTransporterSenderRist.cpp b/src/MediaTransporterSenderRist.cpp index 490d1a1..5e524a2 100644 --- a/src/MediaTransporterSenderRist.cpp +++ b/src/MediaTransporterSenderRist.cpp @@ -57,6 +57,9 @@ ResourceSet MediaTransporterSenderRist::buildPipeline() /* create mux to sink */ try { + if (_receiverAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); g_object_set(G_OBJECT(mux), "alignment", 7, NULL); diff --git a/src/MediaTransporterSenderRtsp.cpp b/src/MediaTransporterSenderRtsp.cpp index eea9f5b..3678f5f 100644 --- a/src/MediaTransporterSenderRtsp.cpp +++ b/src/MediaTransporterSenderRtsp.cpp @@ -63,6 +63,9 @@ ResourceSet MediaTransporterSenderRtsp::buildPipeline() ResourceSet allResourceRequired; try { + if (_senderAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + /* create mux and pay */ mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); g_object_set(G_OBJECT(mux), "alignment", 7, NULL); diff --git a/src/MediaTransporterSenderSrt.cpp b/src/MediaTransporterSenderSrt.cpp index a3ebdb3..2cd8cd7 100644 --- a/src/MediaTransporterSenderSrt.cpp +++ b/src/MediaTransporterSenderSrt.cpp @@ -75,6 +75,9 @@ ResourceSet MediaTransporterSenderSrt::buildPipeline() /* create mux to sink */ try { + if (_senderAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); g_object_set(G_OBJECT(mux), "alignment", 7, NULL); diff --git a/src/MediaTransporterSenderToServerRtsp.cpp b/src/MediaTransporterSenderToServerRtsp.cpp index 1c267d3..a65dda0 100644 --- a/src/MediaTransporterSenderToServerRtsp.cpp +++ b/src/MediaTransporterSenderToServerRtsp.cpp @@ -51,6 +51,9 @@ ResourceSet MediaTransporterSenderToServerRtsp::buildPipeline() /* create mux to sink */ try { + if (_receiverAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); g_object_set(G_OBJECT(mux), "alignment", 7, NULL); -- 2.7.4 From 7e9107dd7c567fb8762dfbf6fa52d823c2fd72ed Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Thu, 1 Sep 2022 11:47:53 +0900 Subject: [PATCH 04/12] [0.0.3] Revise code - remove CMake version warning - change to define mtpr error enum if not defined - remove unnecessary json-glib dependancy - use uniform initializer for memeber initialization - place class method prior to class member for each access modifier - remove unnecessary header include - use static for global variable on test Change-Id: Ie892d364340a59aa9ce0201725bb9bb4d2da7a57 --- CMakeLists.txt | 4 ++-- include/MediaSourceBinAudioTest.h | 31 ++++++++++++---------------- include/MediaSourceBinBase.h | 20 +++++++----------- include/MediaSourceBinCamera.h | 30 ++++++++++++--------------- include/MediaSourceBinFactory.h | 7 +++---- include/MediaSourceBinMic.h | 27 +++++++++++------------- include/MediaSourceBinVideoTest.h | 30 ++++++++++++--------------- include/MediaTransporterBase.h | 7 ++----- include/MediaTransporterCallback.h | 6 +----- include/MediaTransporterDisplay.h | 1 - include/MediaTransporterFactory.h | 4 +--- include/MediaTransporterGst.h | 1 + include/MediaTransporterObserver.h | 8 +++---- include/MediaTransporterParseIni.h | 1 + include/MediaTransporterReceiver.h | 31 ++++++++++++++-------------- include/MediaTransporterReceiverRist.h | 10 ++++----- include/MediaTransporterReceiverSrt.h | 10 ++++----- include/MediaTransporterResource.h | 3 +-- include/MediaTransporterSender.h | 8 +++---- include/MediaTransporterSenderRist.h | 8 +++---- include/MediaTransporterSenderRtsp.h | 4 +--- include/MediaTransporterSenderSrt.h | 6 ++---- include/MediaTransporterSenderToServerRtsp.h | 5 ++--- include/mtpr.h | 2 ++ packaging/capi-media-transporter.spec | 3 +-- src/MediaSourceBinBase.cpp | 1 - src/MediaTransporterSenderSrt.cpp | 3 ++- test/CMakeLists.txt | 2 +- test/mtpr_test.c | 8 +++---- 29 files changed, 117 insertions(+), 164 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c611cb..11c699f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) SET(fw_name "capi-media-transporter") PROJECT(${fw_name}) @@ -11,7 +11,7 @@ SET(INC_DIR include) INCLUDE_DIRECTORIES(${INC_DIR}) SET(dependents "dlog glib-2.0 gstreamer-1.0 gstreamer-video-1.0 gstreamer-audio-1.0 \ - json-glib-1.0 iniparser mm-common capi-media-tool mm-display-interface \ + iniparser mm-common capi-media-tool mm-display-interface \ cynara-client libsmack capi-system-info bundle capi-media-sound-manager \ gstreamer-rtsp-server-1.0 libpulse") diff --git a/include/MediaSourceBinAudioTest.h b/include/MediaSourceBinAudioTest.h index 11245a1..0cf315c 100644 --- a/include/MediaSourceBinAudioTest.h +++ b/include/MediaSourceBinAudioTest.h @@ -19,20 +19,14 @@ #ifdef __cplusplus +#include #include "MediaTransporter.h" -#include -#include -#include -#include -#include -#include -#include "MediaSourceBinBase.h" #include "MediaTransporterGst.h" +#include "MediaSourceBinBase.h" namespace tizen_media_transporter { -#define RESOURCE_TYPE_MAX MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER + 1 const std::string DEFAULT_ELEMENT_AUDIO_TEST = "audiotestsrc"; class MediaSourceBinAudioTest : public MediaSourceBinBase @@ -44,24 +38,25 @@ public: MediaSourceBinInfo generate() override; private: - struct audioInfo { - int channel = -1; - int rate = -1; - std::string format = ""; - }; - - struct encodingInfo { - int bitrate = 0; - }; - void parseSourceParam(bundle* params); GstElement* createMicSource(); void setEncoderParam(gst::GstElements& elements); void setSourceParam(gst::GstElements& elements); void replaceCapsWithAudioInfo(GstElement* element); void replaceEncCapsWithAudioInfo(GstElement* element); + + struct audioInfo { + int channel { -1 }; + int rate { -1 }; + std::string format; + }; audioInfo _audioInfo; + + struct encodingInfo { + int bitrate = 0; + }; encodingInfo _encInfo; + }; } // namespace diff --git a/include/MediaSourceBinBase.h b/include/MediaSourceBinBase.h index c1e17f7..1fcafb1 100644 --- a/include/MediaSourceBinBase.h +++ b/include/MediaSourceBinBase.h @@ -19,21 +19,15 @@ #ifdef __cplusplus - -#include "MediaTransporter.h" #include #include -#include -#include #include -#include -#include -#include -#include -#include -#include "MediaTransporterParseIni.h" #include +#include "MediaTransporter.h" +#include "MediaTransporterParseIni.h" +#include "MediaTransporterGst.h" + namespace tizen_media_transporter { using MediaSourceBinInfo = std::tuple; @@ -44,7 +38,7 @@ const std::string ELEMENT_NAME_ENCODE_CAPSFILTER = "encCapsfilter"; class IMediaSourceBin { public: - virtual ~IMediaSourceBin() {} + virtual ~IMediaSourceBin() = default; virtual MediaSourceBinInfo generate() = 0; }; @@ -55,8 +49,8 @@ public: ~MediaSourceBinBase() = default; protected: - std::vector createVideoRestOfElements(const MtprMediaSourceIni& ini); - std::vector createAudioRestOfElements(const MtprMediaSourceIni& ini); + gst::GstElements createVideoRestOfElements(const MtprMediaSourceIni& ini); + gst::GstElements createAudioRestOfElements(const MtprMediaSourceIni& ini); }; } // namespace diff --git a/include/MediaSourceBinCamera.h b/include/MediaSourceBinCamera.h index 927ad3a..caddb6c 100644 --- a/include/MediaSourceBinCamera.h +++ b/include/MediaSourceBinCamera.h @@ -19,16 +19,11 @@ #ifdef __cplusplus +#include #include "MediaTransporter.h" -#include -#include -#include -#include -#include -#include -#include "MediaSourceBinBase.h" #include "MediaTransporterGst.h" +#include "MediaSourceBinBase.h" namespace tizen_media_transporter { @@ -43,24 +38,25 @@ public: MediaSourceBinInfo generate() override; private: - struct videoInfo { - int width = -1; - int height = -1; - int frameRate = -1; - }; - - struct encodingInfo { - int bitrate = 0; - }; - void parseSourceParam(bundle* params); GstElement* createCameraSource(); void setEncoderParam(gst::GstElements& elements); void setSourceParam(gst::GstElements& elements); void replaceCapsWithVideoInfo(GstElement* element); void replaceEncCapsWithVideoInfo(GstElement* element); + + struct videoInfo { + int width { -1 }; + int height { -1 }; + int frameRate { -1 }; + }; videoInfo _videoInfo; + + struct encodingInfo { + int bitrate { 0 }; + }; encodingInfo _encInfo; + }; } // namespace diff --git a/include/MediaSourceBinFactory.h b/include/MediaSourceBinFactory.h index e90d67c..610ae81 100644 --- a/include/MediaSourceBinFactory.h +++ b/include/MediaSourceBinFactory.h @@ -19,17 +19,16 @@ #ifdef __cplusplus -#include "MediaSourceBinBase.h" -#include -#include #include +#include "MediaSourceBinBase.h" + namespace tizen_media_transporter { class MediaSourceBinFactory { public: - static IMediaSourceBin* create(mtprSourceType type, bundle* param_list); + static IMediaSourceBin* create(mtprSourceType type, bundle* param_list); }; } // namespace diff --git a/include/MediaSourceBinMic.h b/include/MediaSourceBinMic.h index f65a4c3..2520b1c 100644 --- a/include/MediaSourceBinMic.h +++ b/include/MediaSourceBinMic.h @@ -21,11 +21,7 @@ #include -#include -#include #include -#include -#include #include #include "MediaTransporter.h" @@ -46,25 +42,26 @@ public: void setSoundStreamInfo(sound_stream_info_h streamInfo); private: - struct audioInfo { - int channel = -1; - int rate = -1; - std::string format = ""; - }; - - struct encodingInfo { - int bitrate = 0; - }; - void parseSourceParam(bundle* params); GstElement* createMicSource(); void setEncoderParam(gst::GstElements& elements); void setSourceParam(gst::GstElements& elements); void replaceCapsWithAudioInfo(GstElement* element); void replaceEncCapsWithAudioInfo(GstElement* element); + + struct audioInfo { + int channel { -1 }; + int rate { -1 }; + std::string format; + }; audioInfo _audioInfo; + + struct encodingInfo { + int bitrate { 0 }; + }; encodingInfo _encInfo; - std::string _streamInfo = ""; + + std::string _streamInfo; }; } // namespace diff --git a/include/MediaSourceBinVideoTest.h b/include/MediaSourceBinVideoTest.h index 0de1cbc..b8dbefc 100644 --- a/include/MediaSourceBinVideoTest.h +++ b/include/MediaSourceBinVideoTest.h @@ -19,16 +19,11 @@ #ifdef __cplusplus +#include #include "MediaTransporter.h" -#include -#include -#include -#include -#include -#include -#include "MediaSourceBinBase.h" #include "MediaTransporterGst.h" +#include "MediaSourceBinBase.h" namespace tizen_media_transporter { @@ -43,24 +38,25 @@ public: MediaSourceBinInfo generate() override; private: - struct videoInfo { - int width = -1; - int height = -1; - int frameRate = -1; - }; - - struct encodingInfo { - int bitrate = 0; - }; - void parseSourceParam(bundle* params); GstElement* createVideoTestSource(); void setEncoderParam(gst::GstElements& elements); void setSourceParam(gst::GstElements& elements); void replaceCapsWithVideoInfo(GstElement* element); void replaceEncCapsWithVideoInfo(GstElement* element); + + struct videoInfo { + int width { -1 }; + int height { -1 }; + int frameRate { -1 }; + }; videoInfo _videoInfo; + + struct encodingInfo { + int bitrate { 0 }; + }; encodingInfo _encInfo; + }; } // namespace diff --git a/include/MediaTransporterBase.h b/include/MediaTransporterBase.h index b29483d..e5bf3bb 100644 --- a/include/MediaTransporterBase.h +++ b/include/MediaTransporterBase.h @@ -19,17 +19,14 @@ #ifdef __cplusplus - -#include "MediaTransporter.h" #include -#include -#include #include #include -#include #include #include #include + +#include "MediaTransporter.h" #include "MediaTransporterParseIni.h" #include "MediaTransporterCallback.h" #include "MediaTransporterObserver.h" diff --git a/include/MediaTransporterCallback.h b/include/MediaTransporterCallback.h index 24d4ee9..811b3d7 100644 --- a/include/MediaTransporterCallback.h +++ b/include/MediaTransporterCallback.h @@ -17,14 +17,10 @@ #ifndef __TIZEN_MEDIA_TRANSPORTER_CALLBACK_H__ #define __TIZEN_MEDIA_TRANSPORTER_CALLBACK_H__ -#include -#include - -#include #include #include - #include + #include "MediaTransporter.h" #ifdef __cplusplus diff --git a/include/MediaTransporterDisplay.h b/include/MediaTransporterDisplay.h index 9eff6ca..639d89b 100644 --- a/include/MediaTransporterDisplay.h +++ b/include/MediaTransporterDisplay.h @@ -17,7 +17,6 @@ #ifndef __TIZEN_MEDIA_TRANSPORTER_DISPLAY_H__ #define __TIZEN_MEDIA_TRANSPORTER_DISPLAY_H__ -#include #include #include #include diff --git a/include/MediaTransporterFactory.h b/include/MediaTransporterFactory.h index df0825e..a8721d1 100644 --- a/include/MediaTransporterFactory.h +++ b/include/MediaTransporterFactory.h @@ -20,15 +20,13 @@ #ifdef __cplusplus #include "MediaTransporterBase.h" -#include -#include namespace tizen_media_transporter { class MediaTransporterFactory { public: - static MediaTransporterBase* create(mtprConnectionType type); + static MediaTransporterBase* create(mtprConnectionType type); }; } // namespace diff --git a/include/MediaTransporterGst.h b/include/MediaTransporterGst.h index 79acaa4..72901b4 100644 --- a/include/MediaTransporterGst.h +++ b/include/MediaTransporterGst.h @@ -18,6 +18,7 @@ #define __TIZEN_MEDIA_TRANSPORTER_GST_H__ #ifdef __cplusplus + #include #include #include diff --git a/include/MediaTransporterObserver.h b/include/MediaTransporterObserver.h index f90ce2c..c5e98eb 100644 --- a/include/MediaTransporterObserver.h +++ b/include/MediaTransporterObserver.h @@ -17,8 +17,6 @@ #ifndef __TIZEN_MEDIA_TRANSPORTER_OBSERVER_H__ #define __TIZEN_MEDIA_TRANSPORTER_OBSERVER_H__ -#include -#include #include #ifdef __cplusplus @@ -30,14 +28,14 @@ namespace tizen_media_transporter { class IObserver { public: - virtual ~IObserver() = default; - virtual void changed() = 0; + virtual ~IObserver() = default; + virtual void changed() = 0; }; class IObservable { public: - virtual ~IObservable() {} + virtual ~IObservable() = default; virtual void subscribe(IObserver *observer) = 0; virtual void unsubscribe(IObserver *observer) = 0; diff --git a/include/MediaTransporterParseIni.h b/include/MediaTransporterParseIni.h index 744cc46..9cc5a81 100644 --- a/include/MediaTransporterParseIni.h +++ b/include/MediaTransporterParseIni.h @@ -22,6 +22,7 @@ #include #include #include + #include "mtpr.h" namespace tizen_media_transporter { diff --git a/include/MediaTransporterReceiver.h b/include/MediaTransporterReceiver.h index 6713755..924df8a 100644 --- a/include/MediaTransporterReceiver.h +++ b/include/MediaTransporterReceiver.h @@ -19,14 +19,12 @@ #ifdef __cplusplus - -#include "MediaTransporter.h" #include -#include -#include -#include +#include #include #include + +#include "MediaTransporter.h" #include "MediaTransporterBase.h" #include "MediaTransporterGst.h" #include "MediaTransporterCallback.h" @@ -60,6 +58,17 @@ public: void setSoundStreamInfo(sound_stream_info_h streamInfo); protected: + int _buildForwardingElements(GstElement* demux, GstPad* pad, GCallback callback); + void _buildForwardingSink(gst::GstElements& elements, GstPad* pad, GCallback callback); + + int _buildAudioRenderingElements(GstElement* demux, GstPad* pad); + int _buildVideoRenderingElements(GstElement* demux, GstPad* pad); + + static void _streamAddedCallback(GstPad* pad, gpointer data); + static void _noMoreStreamCallback(gpointer data); + static void _encodedAudioStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data); + static void _encodedVideoStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data); + std::unique_ptr _trackAddedCallback; std::unique_ptr _noMoreTrackCallback; @@ -73,19 +82,9 @@ protected: std::shared_ptr _display; std::string _streamInfo; - int _buildForwardingElements(GstElement* demux, GstPad* pad, GCallback callback); - void _buildForwardingSink(gst::GstElements& elements, GstPad* pad, GCallback callback); - - int _buildAudioRenderingElements(GstElement* demux, GstPad* pad); - int _buildVideoRenderingElements(GstElement* demux, GstPad* pad); - - static void _streamAddedCallback(GstPad* pad, gpointer data); - static void _noMoreStreamCallback(gpointer data); - static void _encodedAudioStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data); - static void _encodedVideoStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data); - private: static media_packet_h _makeMediaPacket(GstBuffer* buffer, GstPad* pad, media_format_h* format); + void _buildAudioRenderingSink(gst::GstElements& elements); void _buildVideoRenderingSink(gst::GstElements& elements); }; diff --git a/include/MediaTransporterReceiverRist.h b/include/MediaTransporterReceiverRist.h index 54dff45..0435b27 100644 --- a/include/MediaTransporterReceiverRist.h +++ b/include/MediaTransporterReceiverRist.h @@ -19,14 +19,12 @@ #ifdef __cplusplus +#include #include "MediaTransporter.h" -#include -#include -#include -#include #include "MediaTransporterBase.h" #include "MediaTransporterReceiver.h" +#include "MediaTransporterGst.h" namespace tizen_media_transporter { @@ -50,8 +48,8 @@ public: mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_RIST_RECEIVER; } private: - static void _demuxPadAddedCallback(GstElement *demux, GstPad *new_pad, gpointer userData); - static void _demuxNoMorePadsCallback(GstElement *demux, gpointer userData); + static void _demuxPadAddedCallback(GstElement* demux, GstPad* new_pad, gpointer userData); + static void _demuxNoMorePadsCallback(GstElement* demux, gpointer userData); std::string _receiverAddress; }; diff --git a/include/MediaTransporterReceiverSrt.h b/include/MediaTransporterReceiverSrt.h index 64626cd..94ae6e5 100644 --- a/include/MediaTransporterReceiverSrt.h +++ b/include/MediaTransporterReceiverSrt.h @@ -19,14 +19,12 @@ #ifdef __cplusplus +#include #include "MediaTransporter.h" -#include -#include -#include -#include #include "MediaTransporterBase.h" #include "MediaTransporterReceiver.h" +#include "MediaTransporterGst.h" namespace tizen_media_transporter { @@ -50,8 +48,8 @@ public: mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_SRT_RECEIVER; } private: - static void _demuxPadAddedCallback(GstElement *demux, GstPad *new_pad, gpointer userData); - static void _demuxNoMorePadsCallback(GstElement *demux, gpointer userData); + static void _demuxPadAddedCallback(GstElement* demux, GstPad* new_pad, gpointer userData); + static void _demuxNoMorePadsCallback(GstElement* demux, gpointer userData); std::string _senderAddress; }; diff --git a/include/MediaTransporterResource.h b/include/MediaTransporterResource.h index 8237dd3..97c53d7 100644 --- a/include/MediaTransporterResource.h +++ b/include/MediaTransporterResource.h @@ -19,7 +19,6 @@ #include #include - #include #include "MediaTransporter.h" @@ -47,8 +46,8 @@ private: int create(); int destroy(); int acquireInternal(mm_resource_manager_res_type_e type); - bool resourceReleased(mm_resource_manager_res_h res); + mm_resource_manager_h _mgr { nullptr }; std::map _resources; bool _onReleaseCallback { false }; diff --git a/include/MediaTransporterSender.h b/include/MediaTransporterSender.h index fd351fd..67a42ae 100644 --- a/include/MediaTransporterSender.h +++ b/include/MediaTransporterSender.h @@ -19,15 +19,12 @@ #ifdef __cplusplus +#include +#include #include "MediaTransporter.h" -#include -#include -#include -#include #include "MediaTransporterBase.h" #include "MediaSourceBinBase.h" -#include namespace tizen_media_transporter { @@ -39,6 +36,7 @@ public: int addMediaSource(IMediaSourceBin* sourceBin); void removeMediaSource(int id); + IMediaSourceBin* getMediaSource(int id); protected: diff --git a/include/MediaTransporterSenderRist.h b/include/MediaTransporterSenderRist.h index 68994a7..884de60 100644 --- a/include/MediaTransporterSenderRist.h +++ b/include/MediaTransporterSenderRist.h @@ -19,17 +19,15 @@ #ifdef __cplusplus - -#include "MediaTransporter.h" #include #include -#include + +#include "MediaTransporter.h" #include "MediaTransporterSender.h" +#include "MediaTransporterGst.h" namespace tizen_media_transporter { -#define RESOURCE_TYPE_MAX MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_ENCODER + 1 - class MediaTransporterSenderRist : public MediaTransporterSender { public: diff --git a/include/MediaTransporterSenderRtsp.h b/include/MediaTransporterSenderRtsp.h index 772db4b..1818a39 100644 --- a/include/MediaTransporterSenderRtsp.h +++ b/include/MediaTransporterSenderRtsp.h @@ -19,11 +19,9 @@ #ifdef __cplusplus +#include #include "MediaTransporter.h" -#include -#include -#include #include "MediaTransporterSender.h" namespace tizen_media_transporter { diff --git a/include/MediaTransporterSenderSrt.h b/include/MediaTransporterSenderSrt.h index 1c5d96e..4b5b155 100644 --- a/include/MediaTransporterSenderSrt.h +++ b/include/MediaTransporterSenderSrt.h @@ -19,13 +19,11 @@ #ifdef __cplusplus +#include #include "MediaTransporter.h" -#include -#include -#include -#include #include "MediaTransporterSender.h" +#include "MediaTransporterGst.h" namespace tizen_media_transporter { diff --git a/include/MediaTransporterSenderToServerRtsp.h b/include/MediaTransporterSenderToServerRtsp.h index b6b2bd0..63ee26f 100644 --- a/include/MediaTransporterSenderToServerRtsp.h +++ b/include/MediaTransporterSenderToServerRtsp.h @@ -19,12 +19,11 @@ #ifdef __cplusplus +#include #include "MediaTransporter.h" -#include -#include -#include #include "MediaTransporterSender.h" +#include "MediaTransporterGst.h" namespace tizen_media_transporter { diff --git a/include/mtpr.h b/include/mtpr.h index 9d3dd91..34de8df 100644 --- a/include/mtpr.h +++ b/include/mtpr.h @@ -35,7 +35,9 @@ extern "C" { /* TEMP Define ***********************************************/ /* FIXME: this definition have to be applied at core/api/common pkg, include/tizen_error.h file */ +#ifndef TIZEN_ERROR_MEDIA_TRANSPORTER #define TIZEN_ERROR_MEDIA_TRANSPORTER -0x01A30000 +#endif /*************************************************************/ /** diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec index b94ba41..a938647 100644 --- a/packaging/capi-media-transporter.spec +++ b/packaging/capi-media-transporter.spec @@ -1,6 +1,6 @@ Name: capi-media-transporter Summary: A Media Transporter library in Tizen Native API -Version: 0.0.2 +Version: 0.0.3 Release: 0 Group: Multimedia/API License: Apache-2.0 @@ -19,7 +19,6 @@ BuildRequires: pkgconfig(gstreamer-rtsp-server-1.0) BuildRequires: pkgconfig(libpulse) BuildRequires: pkgconfig(appcore-efl) BuildRequires: pkgconfig(elementary) -BuildRequires: pkgconfig(json-glib-1.0) BuildRequires: pkgconfig(iniparser) BuildRequires: pkgconfig(bundle) BuildRequires: pkgconfig(mm-display-interface) diff --git a/src/MediaSourceBinBase.cpp b/src/MediaSourceBinBase.cpp index 9bd3f13..bdba563 100644 --- a/src/MediaSourceBinBase.cpp +++ b/src/MediaSourceBinBase.cpp @@ -16,7 +16,6 @@ #include "MediaSourceBinBase.h" #include "MediaTransporterException.h" -#include "MediaTransporterGst.h" #include "MediaTransporterLog.h" #include "MediaTransporterParseIni.h" #include diff --git a/src/MediaTransporterSenderSrt.cpp b/src/MediaTransporterSenderSrt.cpp index 2cd8cd7..5de67bb 100644 --- a/src/MediaTransporterSenderSrt.cpp +++ b/src/MediaTransporterSenderSrt.cpp @@ -14,10 +14,11 @@ * limitations under the License. */ +#include + #include "MediaTransporterBase.h" #include "MediaTransporterException.h" #include "MediaTransporterSenderSrt.h" -#include "MediaTransporterGst.h" #include "MediaTransporterLog.h" #include "MediaTransporterUtil.h" #include "MediaTransporterParseIni.h" diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cba788f..1e85874 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,4 +1,4 @@ -CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +CMAKE_MINIMUM_REQUIRED(VERSION 2.8.12) SET(fw_test "${fw_name}-test") INCLUDE_DIRECTORIES(../include) diff --git a/test/mtpr_test.c b/test/mtpr_test.c index a05a2e5..473c66e 100644 --- a/test/mtpr_test.c +++ b/test/mtpr_test.c @@ -86,9 +86,9 @@ static bool g_dump_data = false; static FILE* video_dump = NULL; static FILE* audio_dump = NULL; -int g_menu_state = CURRENT_STATUS_MAINMENU; -sound_stream_info_h g_mic_stream_info = NULL; -sound_stream_info_h g_stream_info = NULL; +static int g_menu_state = CURRENT_STATUS_MAINMENU; +static sound_stream_info_h g_mic_stream_info = NULL; +static sound_stream_info_h g_stream_info = NULL; static void _mtpr_test_unset_track_cb(); static void _mtpr_test_unset_encoded_audio_frame_cb(); @@ -209,7 +209,7 @@ static int app_terminate(void *data) return 0; } -struct appcore_ops ops = { +static struct appcore_ops ops = { .create = app_create, .terminate = app_terminate, }; -- 2.7.4 From 5e9aa84d991fc4aa143f033c236726902cbd398a Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Thu, 1 Sep 2022 16:49:12 +0900 Subject: [PATCH 05/12] [0.0.4] CMakeLists: Fix exclusion pattern to export header files properly Only mtpr_*.h must be exported. Change-Id: I71371c4e2ffc780189f77c4f5806c0fa20d23484 Signed-off-by: Sangchul Lee --- CMakeLists.txt | 2 +- packaging/capi-media-transporter.spec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11c699f..194edca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ INSTALL(TARGETS ${fw_name} DESTINATION ${LIB_INSTALL_DIR}) INSTALL( DIRECTORY ${INC_DIR}/ DESTINATION include/media FILES_MATCHING - PATTERN "mtpr_*.h" EXCLUDE + PATTERN "Media*.h" EXCLUDE PATTERN "${INC_DIR}/*.h" ) diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec index a938647..1ea299f 100644 --- a/packaging/capi-media-transporter.spec +++ b/packaging/capi-media-transporter.spec @@ -1,6 +1,6 @@ Name: capi-media-transporter Summary: A Media Transporter library in Tizen Native API -Version: 0.0.3 +Version: 0.0.4 Release: 0 Group: Multimedia/API License: Apache-2.0 -- 2.7.4 From a6a2f407fa8357e45484299a3276cfc71a6030c3 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Fri, 2 Sep 2022 03:53:43 +0900 Subject: [PATCH 06/12] [0.0.5] Add required feature and privilege check For MediaTransporterBase: - http://tizen.org/feature/network.wifi - http://tizen.org/feature/network.telephony - http://tizen.org/feature/network.ethernet - http://tizen.org/privilege/internet For MediaSourceBinCamera: - http://tizen.org/feature/camera - http://tizen.org/privilege/camera For MediaSourceBinMic: - http://tizen.org/feature/microphone - http://tizen.org/privilege/recorder Change-Id: Ib3b35ef56fe980bb18ae88cc22356ec11215da85 --- include/MediaTransporterReceiver.h | 3 ++- include/MediaTransporterUtil.h | 6 +++--- packaging/capi-media-transporter.spec | 2 +- src/MediaSourceBinAudioTest.cpp | 1 - src/MediaSourceBinCamera.cpp | 5 ++++- src/MediaSourceBinMic.cpp | 5 ++++- src/MediaSourceBinVideoTest.cpp | 1 - src/MediaTransporter.cpp | 4 ++++ src/MediaTransporterUtil.cpp | 35 ++++++++++++++++------------------- 9 files changed, 34 insertions(+), 28 deletions(-) diff --git a/include/MediaTransporterReceiver.h b/include/MediaTransporterReceiver.h index 924df8a..4aba2ec 100644 --- a/include/MediaTransporterReceiver.h +++ b/include/MediaTransporterReceiver.h @@ -49,8 +49,9 @@ public: void unsetNoMoreTrackCallback(); void setVideoPacketCallback(void* handle, mtprPacketCallback callback, void* userData); - void setAudioPacketCallback(void* handle, mtprPacketCallback callback, void* userData); void unsetVideoPacketCallback(); + + void setAudioPacketCallback(void* handle, mtprPacketCallback callback, void* userData); void unsetAudioPacketCallback(); void setDisplay(std::shared_ptr display); diff --git a/include/MediaTransporterUtil.h b/include/MediaTransporterUtil.h index f59b4b3..838d3ea 100644 --- a/include/MediaTransporterUtil.h +++ b/include/MediaTransporterUtil.h @@ -34,9 +34,9 @@ const std::string MTPR_PRIVILEGE_INTERNET = "http://tizen.org/privilege/internet const std::string MTPR_PRIVILEGE_CAMERA = "http://tizen.org/privilege/camera"; const std::string MTPR_PRIVILEGE_RECORDER = "http://tizen.org/privilege/recorder"; -void throw_if_not_privileged(const std::string& privilege); -void throw_if_feature_not_supported(const std::string& feature); -void throw_if_network_features_not_supported(); +void throwIfNotPrivileged(const std::string& privilege); +void throwIfFeatureNotSupported(const std::string& feature); +void throwIfNetworkFeaturesNotSupported(); } // util } // namespace diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec index 1ea299f..8bff4b8 100644 --- a/packaging/capi-media-transporter.spec +++ b/packaging/capi-media-transporter.spec @@ -1,6 +1,6 @@ Name: capi-media-transporter Summary: A Media Transporter library in Tizen Native API -Version: 0.0.4 +Version: 0.0.5 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/MediaSourceBinAudioTest.cpp b/src/MediaSourceBinAudioTest.cpp index 145aad0..91369d1 100644 --- a/src/MediaSourceBinAudioTest.cpp +++ b/src/MediaSourceBinAudioTest.cpp @@ -26,7 +26,6 @@ using namespace tizen_media_transporter; MediaSourceBinAudioTest::MediaSourceBinAudioTest(bundle* params) { - // privilege check parseSourceParam(params); } diff --git a/src/MediaSourceBinCamera.cpp b/src/MediaSourceBinCamera.cpp index 1143a5b..0d66f1a 100644 --- a/src/MediaSourceBinCamera.cpp +++ b/src/MediaSourceBinCamera.cpp @@ -18,6 +18,7 @@ #include "MediaTransporterLog.h" #include "MediaTransporterException.h" #include "MediaTransporterParseIni.h" +#include "MediaTransporterUtil.h" #include @@ -26,7 +27,9 @@ using namespace tizen_media_transporter; MediaSourceBinCamera::MediaSourceBinCamera(bundle* params) { - // privilege check + util::throwIfFeatureNotSupported(util::MTPR_FEATURE_CAMERA); + util::throwIfNotPrivileged(util::MTPR_PRIVILEGE_CAMERA); + parseSourceParam(params); } diff --git a/src/MediaSourceBinMic.cpp b/src/MediaSourceBinMic.cpp index 45bfa91..4ea6af1 100644 --- a/src/MediaSourceBinMic.cpp +++ b/src/MediaSourceBinMic.cpp @@ -18,6 +18,7 @@ #include "MediaTransporterLog.h" #include "MediaTransporterException.h" #include "MediaTransporterParseIni.h" +#include "MediaTransporterUtil.h" #include #include @@ -29,7 +30,9 @@ using namespace tizen_media_transporter; MediaSourceBinMic::MediaSourceBinMic(bundle* params) { - // privilege check + util::throwIfFeatureNotSupported(util::MTPR_FEATURE_MICROPHONE); + util::throwIfNotPrivileged(util::MTPR_PRIVILEGE_RECORDER); + parseSourceParam(params); } diff --git a/src/MediaSourceBinVideoTest.cpp b/src/MediaSourceBinVideoTest.cpp index 972775c..179d7f6 100644 --- a/src/MediaSourceBinVideoTest.cpp +++ b/src/MediaSourceBinVideoTest.cpp @@ -26,7 +26,6 @@ using namespace tizen_media_transporter; MediaSourceBinVideoTest::MediaSourceBinVideoTest(bundle* params) { - // privilege check parseSourceParam(params); } diff --git a/src/MediaTransporter.cpp b/src/MediaTransporter.cpp index 123c820..87a007a 100644 --- a/src/MediaTransporter.cpp +++ b/src/MediaTransporter.cpp @@ -7,6 +7,7 @@ #include "MediaTransporterException.h" #include "MediaTransporterSender.h" #include "MediaTransporterReceiver.h" +#include "MediaTransporterUtil.h" #include "MediaSourceBinMic.h" #include @@ -26,6 +27,9 @@ int mtpr_create(mtpr_connection_type_e type, mtpr_h* mtpr) RET_VAL_IF(!handle, MTPR_ERROR_INVALID_OPERATION, "Failed to allocate handle!!!"); try { + util::throwIfNetworkFeaturesNotSupported(); + util::throwIfNotPrivileged(util::MTPR_PRIVILEGE_INTERNET); + handle->base = std::unique_ptr( MediaTransporterFactory::create(static_cast(type))); RET_ERR_IF_INVALID_INSTANCE(handle->base); diff --git a/src/MediaTransporterUtil.cpp b/src/MediaTransporterUtil.cpp index cc103df..550460b 100644 --- a/src/MediaTransporterUtil.cpp +++ b/src/MediaTransporterUtil.cpp @@ -16,6 +16,7 @@ #include "MediaTransporterUtil.h" #include "MediaTransporterException.h" +#include "MediaTransporterLog.h" #include #include @@ -23,14 +24,15 @@ #include #include #include +#include + using namespace tizen_media_transporter; -void util::throw_if_not_privileged(const std::string& privilege) +void util::throwIfNotPrivileged(const std::string& privilege) { - // int ret = MTPR_ERROR_NONE; - cynara *cynara_h; - char *smack_label = nullptr; + cynara* cynara_h = nullptr; + g_autofree char* smack_label = nullptr; try { if (cynara_initialize(&cynara_h, NULL) != CYNARA_API_SUCCESS) @@ -43,28 +45,23 @@ void util::throw_if_not_privileged(const std::string& privilege) char uid[10]; snprintf(uid, sizeof(uid), "%d", getuid()); - //LOG_DEBUG("smack_label[%s] uid[%s]\n", smack_label, uid); - int cynara_ret = cynara_check(cynara_h, smack_label, "", uid, privilege.c_str()); - if (cynara_ret != CYNARA_API_ACCESS_ALLOWED) { - //LOG_ERROR("NOT ALLOWED, privilege[%s], cynara_ret[%d]", privilege, cynara_ret); + if (cynara_check(cynara_h, smack_label, "", uid, privilege.c_str()) != CYNARA_API_ACCESS_ALLOWED) throw MediaTransporterException(MTPR_ERROR_PERMISSION_DENIED, "[" + privilege + "] is NOT ALLOWED"); - } - //LOG_INFO("ALLOWED, privilege[%s]", privilege); } catch (const MediaTransporterException& e) { - free(smack_label); if (cynara_h) cynara_finish(cynara_h); throw; } - free(smack_label); cynara_finish(cynara_h); + + LOG_INFO("privilege[%s] allowed", privilege.c_str()); } -void util::throw_if_feature_not_supported(const std::string& feature) +void util::throwIfFeatureNotSupported(const std::string& feature) { bool supported = false; @@ -74,17 +71,17 @@ void util::throw_if_feature_not_supported(const std::string& feature) if (!supported) throw MediaTransporterException(MTPR_ERROR_NOT_SUPPORTED, - "[" + feature + "] is not supported"); + "[" + feature + "] not supported"); - //LOG_INFO("feature[%s] is supported", feature); + LOG_INFO("feature[%s] supported", feature.c_str()); } -void util::throw_if_network_features_not_supported() +void util::throwIfNetworkFeaturesNotSupported() { try { - throw_if_feature_not_supported(MTPR_FEATURE_NETWORK_WIFI); - throw_if_feature_not_supported(MTPR_FEATURE_NETWORK_TELE); - throw_if_feature_not_supported(MTPR_FEATURE_NETWORK_ETH); + throwIfFeatureNotSupported(MTPR_FEATURE_NETWORK_WIFI); + throwIfFeatureNotSupported(MTPR_FEATURE_NETWORK_TELE); + throwIfFeatureNotSupported(MTPR_FEATURE_NETWORK_ETH); } catch (const MediaTransporterException& e) { throw MediaTransporterException(MTPR_ERROR_NOT_SUPPORTED, e.what()); } -- 2.7.4 From 9d54788c9b06f0689f57dbabcbf514c88759ea39 Mon Sep 17 00:00:00 2001 From: Seungbae Shin Date: Fri, 2 Sep 2022 16:31:59 +0900 Subject: [PATCH 07/12] fixup! [0.0.5] Add required feature and privilege check Change-Id: I5da6817d810a39cd90f6b2d0fe2d92ff4b73b0c4 --- src/MediaTransporterUtil.cpp | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/MediaTransporterUtil.cpp b/src/MediaTransporterUtil.cpp index 550460b..14c9f90 100644 --- a/src/MediaTransporterUtil.cpp +++ b/src/MediaTransporterUtil.cpp @@ -61,29 +61,31 @@ void util::throwIfNotPrivileged(const std::string& privilege) LOG_INFO("privilege[%s] allowed", privilege.c_str()); } -void util::throwIfFeatureNotSupported(const std::string& feature) +static bool __isFeatureSupported(const std::string& feature) { bool supported = false; + if (system_info_get_platform_bool(feature.c_str(), &supported) != SYSTEM_INFO_ERROR_NONE) { + LOG_ERROR("failed to system_info_get_platform_bool(%s)", feature.c_str()); + return false; + } - if (system_info_get_platform_bool(feature.c_str(), &supported) != SYSTEM_INFO_ERROR_NONE) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, - "failed to system_info_get_platform_bool(" + feature + ")"); + LOG_INFO("feature[%s] supported[%d]", feature.c_str(), supported); + return supported; +} - if (!supported) +void util::throwIfFeatureNotSupported(const std::string& feature) +{ + if (!__isFeatureSupported(feature)) throw MediaTransporterException(MTPR_ERROR_NOT_SUPPORTED, "[" + feature + "] not supported"); - - LOG_INFO("feature[%s] supported", feature.c_str()); } void util::throwIfNetworkFeaturesNotSupported() { - try { - throwIfFeatureNotSupported(MTPR_FEATURE_NETWORK_WIFI); - throwIfFeatureNotSupported(MTPR_FEATURE_NETWORK_TELE); - throwIfFeatureNotSupported(MTPR_FEATURE_NETWORK_ETH); - } catch (const MediaTransporterException& e) { - throw MediaTransporterException(MTPR_ERROR_NOT_SUPPORTED, e.what()); - } + if (!(__isFeatureSupported(MTPR_FEATURE_NETWORK_WIFI) || + __isFeatureSupported(MTPR_FEATURE_NETWORK_TELE) || + __isFeatureSupported(MTPR_FEATURE_NETWORK_ETH))) + throw MediaTransporterException(MTPR_ERROR_NOT_SUPPORTED, + "One of the network feature (WIFI/TELE/ETH) must be supported"); } -- 2.7.4 From 0f6716eae43ad6f4c14e94b93687d72bfb994441 Mon Sep 17 00:00:00 2001 From: Eunhye Choi Date: Fri, 2 Sep 2022 17:21:36 +0900 Subject: [PATCH 08/12] [0.0.6] add media transporter param - add param to remove duplicated code Change-Id: Idcced37255cb93d51be2f8a959bafc69b9404a7b --- include/MediaSourceBinAudioTest.h | 16 ++---- include/MediaSourceBinCamera.h | 16 ++---- include/MediaSourceBinMic.h | 17 ++----- include/MediaSourceBinVideoTest.h | 16 ++---- include/MediaTransporterParam.h | 51 +++++++++++++++++++ include/mtpr.h | 3 +- packaging/capi-media-transporter.spec | 2 +- src/MediaSourceBinAudioTest.cpp | 39 +------------- src/MediaSourceBinCamera.cpp | 40 ++------------- src/MediaSourceBinMic.cpp | 39 +------------- src/MediaSourceBinVideoTest.cpp | 38 +------------- src/MediaTransporterParam.cpp | 96 +++++++++++++++++++++++++++++++++++ src/MediaTransporterReceiver.cpp | 2 +- test/mtpr_test.c | 4 +- 14 files changed, 175 insertions(+), 204 deletions(-) create mode 100644 include/MediaTransporterParam.h create mode 100644 src/MediaTransporterParam.cpp diff --git a/include/MediaSourceBinAudioTest.h b/include/MediaSourceBinAudioTest.h index 0cf315c..e28c87c 100644 --- a/include/MediaSourceBinAudioTest.h +++ b/include/MediaSourceBinAudioTest.h @@ -23,6 +23,7 @@ #include "MediaTransporter.h" #include "MediaTransporterGst.h" +#include "MediaTransporterParam.h" #include "MediaSourceBinBase.h" namespace tizen_media_transporter { @@ -38,25 +39,14 @@ public: MediaSourceBinInfo generate() override; private: - void parseSourceParam(bundle* params); GstElement* createMicSource(); void setEncoderParam(gst::GstElements& elements); void setSourceParam(gst::GstElements& elements); void replaceCapsWithAudioInfo(GstElement* element); void replaceEncCapsWithAudioInfo(GstElement* element); - struct audioInfo { - int channel { -1 }; - int rate { -1 }; - std::string format; - }; - audioInfo _audioInfo; - - struct encodingInfo { - int bitrate = 0; - }; - encodingInfo _encInfo; - + param::audioInfo _audioInfo; + param::encodingInfo _encInfo; }; } // namespace diff --git a/include/MediaSourceBinCamera.h b/include/MediaSourceBinCamera.h index caddb6c..3256ad5 100644 --- a/include/MediaSourceBinCamera.h +++ b/include/MediaSourceBinCamera.h @@ -23,6 +23,7 @@ #include "MediaTransporter.h" #include "MediaTransporterGst.h" +#include "MediaTransporterParam.h" #include "MediaSourceBinBase.h" namespace tizen_media_transporter { @@ -38,25 +39,14 @@ public: MediaSourceBinInfo generate() override; private: - void parseSourceParam(bundle* params); GstElement* createCameraSource(); void setEncoderParam(gst::GstElements& elements); void setSourceParam(gst::GstElements& elements); void replaceCapsWithVideoInfo(GstElement* element); void replaceEncCapsWithVideoInfo(GstElement* element); - struct videoInfo { - int width { -1 }; - int height { -1 }; - int frameRate { -1 }; - }; - videoInfo _videoInfo; - - struct encodingInfo { - int bitrate { 0 }; - }; - encodingInfo _encInfo; - + param::videoInfo _videoInfo; + param::encodingInfo _encInfo; }; } // namespace diff --git a/include/MediaSourceBinMic.h b/include/MediaSourceBinMic.h index 2520b1c..b5b3b44 100644 --- a/include/MediaSourceBinMic.h +++ b/include/MediaSourceBinMic.h @@ -25,8 +25,9 @@ #include #include "MediaTransporter.h" -#include "MediaSourceBinBase.h" #include "MediaTransporterGst.h" +#include "MediaTransporterParam.h" +#include "MediaSourceBinBase.h" namespace tizen_media_transporter { @@ -42,24 +43,14 @@ public: void setSoundStreamInfo(sound_stream_info_h streamInfo); private: - void parseSourceParam(bundle* params); GstElement* createMicSource(); void setEncoderParam(gst::GstElements& elements); void setSourceParam(gst::GstElements& elements); void replaceCapsWithAudioInfo(GstElement* element); void replaceEncCapsWithAudioInfo(GstElement* element); - struct audioInfo { - int channel { -1 }; - int rate { -1 }; - std::string format; - }; - audioInfo _audioInfo; - - struct encodingInfo { - int bitrate { 0 }; - }; - encodingInfo _encInfo; + param::audioInfo _audioInfo; + param::encodingInfo _encInfo; std::string _streamInfo; }; diff --git a/include/MediaSourceBinVideoTest.h b/include/MediaSourceBinVideoTest.h index b8dbefc..eb6b31f 100644 --- a/include/MediaSourceBinVideoTest.h +++ b/include/MediaSourceBinVideoTest.h @@ -23,6 +23,7 @@ #include "MediaTransporter.h" #include "MediaTransporterGst.h" +#include "MediaTransporterParam.h" #include "MediaSourceBinBase.h" namespace tizen_media_transporter { @@ -38,25 +39,14 @@ public: MediaSourceBinInfo generate() override; private: - void parseSourceParam(bundle* params); GstElement* createVideoTestSource(); void setEncoderParam(gst::GstElements& elements); void setSourceParam(gst::GstElements& elements); void replaceCapsWithVideoInfo(GstElement* element); void replaceEncCapsWithVideoInfo(GstElement* element); - struct videoInfo { - int width { -1 }; - int height { -1 }; - int frameRate { -1 }; - }; - videoInfo _videoInfo; - - struct encodingInfo { - int bitrate { 0 }; - }; - encodingInfo _encInfo; - + param::videoInfo _videoInfo; + param::encodingInfo _encInfo; }; } // namespace diff --git a/include/MediaTransporterParam.h b/include/MediaTransporterParam.h new file mode 100644 index 0000000..2b50853 --- /dev/null +++ b/include/MediaTransporterParam.h @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2022 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_MEDIA_TRANSPORTER_PARAM_H__ +#define __TIZEN_MEDIA_TRANSPORTER_PARAM_H__ + +#ifdef __cplusplus + +#include +#include + +namespace tizen_media_transporter { +namespace param { + +struct videoInfo { + int width { -1 }; + int height { -1 }; + int frameRate { -1 }; +}; + +struct audioInfo { + int channel { -1 }; + int rate { -1 }; + std::string format; +}; + +struct encodingInfo { + int bitrate = 0; +}; + +void parseSourceParam(bundle* params, videoInfo* vInfo, encodingInfo* eInfo); +void parseSourceParam(bundle* params, audioInfo* aInfo, encodingInfo * eInfo); +}; // param + +} // tizen_media_transporter + +#endif // __cplusplus +#endif // __TIZEN_MEDIA_TRANSPORTER_PARAM_H__ diff --git a/include/mtpr.h b/include/mtpr.h index 34de8df..2239968 100644 --- a/include/mtpr.h +++ b/include/mtpr.h @@ -135,7 +135,8 @@ typedef enum { /** * @brief Definition for password parameter of SRT. - * @details The password for the encrypted transmission of SRT. + * @details The password for the encrypted transmission of SRT.\n + * The number of characters must be 10 to 79. * @since_tizen 7.0 * @remarks This is write only parameter. * @see mtpr_set_connection_params() diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec index 8bff4b8..b77dfe5 100644 --- a/packaging/capi-media-transporter.spec +++ b/packaging/capi-media-transporter.spec @@ -1,6 +1,6 @@ Name: capi-media-transporter Summary: A Media Transporter library in Tizen Native API -Version: 0.0.5 +Version: 0.0.6 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/MediaSourceBinAudioTest.cpp b/src/MediaSourceBinAudioTest.cpp index 91369d1..27a49c2 100644 --- a/src/MediaSourceBinAudioTest.cpp +++ b/src/MediaSourceBinAudioTest.cpp @@ -18,6 +18,7 @@ #include "MediaTransporterLog.h" #include "MediaTransporterException.h" #include "MediaTransporterParseIni.h" +#include "MediaTransporterParam.h" #include @@ -26,43 +27,7 @@ using namespace tizen_media_transporter; MediaSourceBinAudioTest::MediaSourceBinAudioTest(bundle* params) { - parseSourceParam(params); -} - -void MediaSourceBinAudioTest::parseSourceParam(bundle* params) -{ - int written_count = 0; - char* string_val = NULL; - - RET_IF(!params, "input param is NULL"); - - /* Will be move to mic/audiotest bin */ - if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_CHANNEL, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _audioInfo.channel = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param audio channel %u", _audioInfo.channel); - written_count++; - } - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_RATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _audioInfo.rate = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param audio rate %u", _audioInfo.rate); - written_count++; - } - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_FORMAT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _audioInfo.format = string_val; - LOG_DEBUG("Source param audio format %s", _audioInfo.format.c_str()); - written_count++; - } - - if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _encInfo.bitrate = (guint)strtoul(string_val, NULL, 10); - LOG_DEBUG("Encoder target bitrate %u", _encInfo.bitrate); - written_count++; - } - - if (written_count == 0) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); + param::parseSourceParam(params, &_audioInfo, &_encInfo); } GstElement* MediaSourceBinAudioTest::createMicSource() diff --git a/src/MediaSourceBinCamera.cpp b/src/MediaSourceBinCamera.cpp index 0d66f1a..b45f448 100644 --- a/src/MediaSourceBinCamera.cpp +++ b/src/MediaSourceBinCamera.cpp @@ -19,6 +19,7 @@ #include "MediaTransporterException.h" #include "MediaTransporterParseIni.h" #include "MediaTransporterUtil.h" +#include "MediaTransporterParam.h" #include @@ -30,42 +31,7 @@ MediaSourceBinCamera::MediaSourceBinCamera(bundle* params) util::throwIfFeatureNotSupported(util::MTPR_FEATURE_CAMERA); util::throwIfNotPrivileged(util::MTPR_PRIVILEGE_CAMERA); - parseSourceParam(params); -} - -void MediaSourceBinCamera::parseSourceParam(bundle* params) -{ - int written_count = 0; - char* string_val = NULL; - - RET_IF(!params, "input param is NULL"); - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_WIDTH, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _videoInfo.width = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param video width %u", _videoInfo.width); - written_count++; - } - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_HEIGHT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _videoInfo.height = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param video height %u", _videoInfo.height); - written_count++; - } - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_FRAMERATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _videoInfo.frameRate = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param video framerate %u", _videoInfo.frameRate); - written_count++; - } - - if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _encInfo.bitrate = (guint)strtoul(string_val, NULL, 10); - LOG_DEBUG("Encoder target bitrate %u", _encInfo.bitrate); - written_count++; - } - - if (written_count == 0) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); + param::parseSourceParam(params, &_videoInfo, &_encInfo); } GstElement* MediaSourceBinCamera::createCameraSource() @@ -184,7 +150,7 @@ MediaSourceBinInfo MediaSourceBinCamera::generate() try { elements.push_back(createCameraSource()); - auto created = createVideoRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_CAMERA))); // FIXME + auto created = createVideoRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_CAMERA))); std::copy(created.begin(), created.end(), std::back_inserter(elements)); setSourceParam(elements); diff --git a/src/MediaSourceBinMic.cpp b/src/MediaSourceBinMic.cpp index 4ea6af1..cd53891 100644 --- a/src/MediaSourceBinMic.cpp +++ b/src/MediaSourceBinMic.cpp @@ -19,6 +19,7 @@ #include "MediaTransporterException.h" #include "MediaTransporterParseIni.h" #include "MediaTransporterUtil.h" +#include "MediaTransporterParam.h" #include #include @@ -33,43 +34,7 @@ MediaSourceBinMic::MediaSourceBinMic(bundle* params) util::throwIfFeatureNotSupported(util::MTPR_FEATURE_MICROPHONE); util::throwIfNotPrivileged(util::MTPR_PRIVILEGE_RECORDER); - parseSourceParam(params); -} - -void MediaSourceBinMic::parseSourceParam(bundle* params) -{ - int written_count = 0; - char* string_val = NULL; - - RET_IF(!params, "input param is NULL"); - - /* Will be move to mic/audiotest bin */ - if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_CHANNEL, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _audioInfo.channel = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param audio channel %u", _audioInfo.channel); - written_count++; - } - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_RATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _audioInfo.rate = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param audio rate %u", _audioInfo.rate); - written_count++; - } - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_FORMAT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _audioInfo.format = string_val; - LOG_DEBUG("Source param audio format %s", _audioInfo.format.c_str()); - written_count++; - } - - if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _encInfo.bitrate = (guint)strtoul(string_val, NULL, 10); - LOG_DEBUG("Encoder target bitrate %u", _encInfo.bitrate); - written_count++; - } - - if (written_count == 0) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); + param::parseSourceParam(params, &_audioInfo, &_encInfo); } GstElement* MediaSourceBinMic::createMicSource() diff --git a/src/MediaSourceBinVideoTest.cpp b/src/MediaSourceBinVideoTest.cpp index 179d7f6..74b0228 100644 --- a/src/MediaSourceBinVideoTest.cpp +++ b/src/MediaSourceBinVideoTest.cpp @@ -18,6 +18,7 @@ #include "MediaTransporterLog.h" #include "MediaTransporterException.h" #include "MediaTransporterParseIni.h" +#include "MediaTransporterParam.h" #include @@ -26,42 +27,7 @@ using namespace tizen_media_transporter; MediaSourceBinVideoTest::MediaSourceBinVideoTest(bundle* params) { - parseSourceParam(params); -} - -void MediaSourceBinVideoTest::parseSourceParam(bundle* params) -{ - int written_count = 0; - char* string_val = NULL; - - RET_IF(!params, "input param is NULL"); - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_WIDTH, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _videoInfo.width = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param video width %u", _videoInfo.width); - written_count++; - } - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_HEIGHT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _videoInfo.height = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param video height %u", _videoInfo.height); - written_count++; - } - - if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_FRAMERATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _videoInfo.frameRate = static_cast(strtoul(string_val, NULL, 10)); - LOG_DEBUG("Source param video framerate %u", _videoInfo.frameRate); - written_count++; - } - - if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _encInfo.bitrate = (guint)strtoul(string_val, NULL, 10); - LOG_DEBUG("Encoder target bitrate %u", _encInfo.bitrate); - written_count++; - } - - if (written_count == 0) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); + param::parseSourceParam(params, &_videoInfo, &_encInfo); } GstElement* MediaSourceBinVideoTest::createVideoTestSource() diff --git a/src/MediaTransporterParam.cpp b/src/MediaTransporterParam.cpp new file mode 100644 index 0000000..b29ae5a --- /dev/null +++ b/src/MediaTransporterParam.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2022 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 "mtpr.h" +#include "MediaTransporterParam.h" +#include "MediaTransporterException.h" +#include "MediaTransporterLog.h" + +using namespace tizen_media_transporter; + +void param::parseSourceParam(bundle* params, param::videoInfo* vInfo, param::encodingInfo* eInfo) +{ + int written_count = 0; + char* string_val = NULL; + + RET_IF(!params, "input param is NULL"); + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_WIDTH, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + vInfo->width = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param video width %u", vInfo->width); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_HEIGHT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + vInfo->height = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param video height %u", vInfo->height); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_FRAMERATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + vInfo->frameRate = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param video framerate %u", vInfo->frameRate); + written_count++; + } + + if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + eInfo->bitrate = (guint)strtoul(string_val, NULL, 10); + LOG_DEBUG("Encoder target bitrate %u", eInfo->bitrate); + written_count++; + } + + if (written_count == 0) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); +} + +void param::parseSourceParam(bundle* params, param::audioInfo* aInfo, param::encodingInfo* eInfo) +{ + int written_count = 0; + char* string_val = NULL; + + RET_IF(!params, "input param is NULL"); + + /* Will be move to mic/audiotest bin */ + if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_CHANNEL, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + aInfo->channel = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param audio channel %u", aInfo->channel); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_RATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + aInfo->rate = static_cast(strtoul(string_val, NULL, 10)); + LOG_DEBUG("Source param audio rate %u", aInfo->rate); + written_count++; + } + + if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_FORMAT, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + aInfo->format = string_val; + LOG_DEBUG("Source param audio format %s", aInfo->format.c_str()); + written_count++; + } + + if (bundle_get_str(params, MTPR_ENCODING_PARAM_BITRATE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { + eInfo->bitrate = (guint)strtoul(string_val, NULL, 10); + LOG_DEBUG("Encoder target bitrate %u", eInfo->bitrate); + written_count++; + } + + if (written_count == 0) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); +} diff --git a/src/MediaTransporterReceiver.cpp b/src/MediaTransporterReceiver.cpp index 1bd0ef2..e24f6e8 100644 --- a/src/MediaTransporterReceiver.cpp +++ b/src/MediaTransporterReceiver.cpp @@ -184,7 +184,7 @@ static void _setCodecDataIfExist(media_packet_h packet, GstPad* pad) if (ret != MEDIA_PACKET_ERROR_NONE) LOG_ERROR("failed to media_packet_set_codec_data()"); else - LOG_DEBUG("codec_data[%p, size:%" G_GSIZE_FORMAT "] is set to the media packet[%p]", + LOG_VERBOSE("codec_data[%p, size:%" G_GSIZE_FORMAT "] is set to the media packet[%p]", buff_info.data, buff_info.size, packet); gst_buffer_unmap(codec_data, &buff_info); diff --git a/test/mtpr_test.c b/test/mtpr_test.c index 473c66e..e10be22 100644 --- a/test/mtpr_test.c +++ b/test/mtpr_test.c @@ -952,7 +952,7 @@ static void displaymenu() display_sub_basic(); } else if (g_menu_state == CURRENT_STATUS_CONNECTION_TYPE) { g_print("*** Input connection type.\n\ - (1:RIST_SENDER, 2:RIST_RECEIVER, 3:SRT_SENDER, 4:SRT_RECEIVER, 5:RTSP_SENDER, 6:RTSP_SENDER_TO_SERVER)\n"); + (0:RIST_SENDER, 1:RIST_RECEIVER, 2:SRT_SENDER, 3:SRT_RECEIVER, 4:RTSP_SENDER, 5:RTSP_SENDER_TO_SERVER)\n"); } else if (g_menu_state == CURRENT_STATUS_SENDER_ADDRESS) { g_print("*** Input sender address:\n"); } else if (g_menu_state == CURRENT_STATUS_RECEIVER_ADDRESS) { @@ -1040,7 +1040,7 @@ static void interpret(char *cmd) break; case CURRENT_STATUS_CONNECTION_TYPE: { value = atoi(cmd); - _mtpr_test_create(value - 1); + _mtpr_test_create(value); reset_menu_state(); break; } -- 2.7.4 From eda4d46bc88e6f3ceebac51f74849705d853d105 Mon Sep 17 00:00:00 2001 From: Gilbok Lee Date: Fri, 2 Sep 2022 16:11:07 +0900 Subject: [PATCH 09/12] [0.0.7] Remove the redundant code - fix wrong log message Change-Id: I8f898fa04fb3cbdec6a08f6bfd3b6c171b4096f7 --- include/MediaSourceBinAudioTest.h | 4 - include/MediaSourceBinBase.h | 3 + include/MediaSourceBinCamera.h | 4 - include/MediaSourceBinMic.h | 4 - include/MediaSourceBinVideoTest.h | 4 - include/MediaTransporterBase.h | 4 +- include/MediaTransporterGst.h | 10 ++ include/MediaTransporterReceiver.h | 9 +- include/MediaTransporterReceiverRist.h | 2 +- include/MediaTransporterReceiverSrt.h | 2 +- include/MediaTransporterSender.h | 1 + include/MediaTransporterSenderRist.h | 2 +- include/MediaTransporterSenderRtsp.h | 2 +- include/MediaTransporterSenderSrt.h | 2 +- include/MediaTransporterSenderToServerRtsp.h | 2 +- packaging/capi-media-transporter.spec | 2 +- src/MediaSourceBinAudioTest.cpp | 84 +--------------- src/MediaSourceBinBase.cpp | 36 +++++++ src/MediaSourceBinCamera.cpp | 97 +------------------ src/MediaSourceBinMic.cpp | 84 +--------------- src/MediaSourceBinVideoTest.cpp | 97 +------------------ src/MediaTransporter.cpp | 47 +++++---- src/MediaTransporterBase.cpp | 4 +- src/MediaTransporterGst.cpp | 139 +++++++++++++++++++++++++++ src/MediaTransporterParam.cpp | 10 +- src/MediaTransporterReceiver.cpp | 78 +++++---------- src/MediaTransporterReceiverRist.cpp | 40 ++------ src/MediaTransporterReceiverSrt.cpp | 42 ++------ src/MediaTransporterSender.cpp | 47 ++++++++- src/MediaTransporterSenderRist.cpp | 60 +----------- src/MediaTransporterSenderRtsp.cpp | 57 +---------- src/MediaTransporterSenderSrt.cpp | 59 +----------- src/MediaTransporterSenderToServerRtsp.cpp | 57 +---------- 33 files changed, 344 insertions(+), 751 deletions(-) diff --git a/include/MediaSourceBinAudioTest.h b/include/MediaSourceBinAudioTest.h index e28c87c..2e137e9 100644 --- a/include/MediaSourceBinAudioTest.h +++ b/include/MediaSourceBinAudioTest.h @@ -40,10 +40,6 @@ public: private: GstElement* createMicSource(); - void setEncoderParam(gst::GstElements& elements); - void setSourceParam(gst::GstElements& elements); - void replaceCapsWithAudioInfo(GstElement* element); - void replaceEncCapsWithAudioInfo(GstElement* element); param::audioInfo _audioInfo; param::encodingInfo _encInfo; diff --git a/include/MediaSourceBinBase.h b/include/MediaSourceBinBase.h index 1fcafb1..132420e 100644 --- a/include/MediaSourceBinBase.h +++ b/include/MediaSourceBinBase.h @@ -51,6 +51,9 @@ public: protected: gst::GstElements createVideoRestOfElements(const MtprMediaSourceIni& ini); gst::GstElements createAudioRestOfElements(const MtprMediaSourceIni& ini); + void setSourceParam(gst::GstElements& elements, const param::audioInfo& aInfo); + void setSourceParam(gst::GstElements& elements, const param::videoInfo& vInfo); + void setEncoderParam(gst::GstElements& elements, const param::encodingInfo& encInfo); }; } // namespace diff --git a/include/MediaSourceBinCamera.h b/include/MediaSourceBinCamera.h index 3256ad5..d706a97 100644 --- a/include/MediaSourceBinCamera.h +++ b/include/MediaSourceBinCamera.h @@ -40,10 +40,6 @@ public: private: GstElement* createCameraSource(); - void setEncoderParam(gst::GstElements& elements); - void setSourceParam(gst::GstElements& elements); - void replaceCapsWithVideoInfo(GstElement* element); - void replaceEncCapsWithVideoInfo(GstElement* element); param::videoInfo _videoInfo; param::encodingInfo _encInfo; diff --git a/include/MediaSourceBinMic.h b/include/MediaSourceBinMic.h index b5b3b44..9ef101c 100644 --- a/include/MediaSourceBinMic.h +++ b/include/MediaSourceBinMic.h @@ -44,10 +44,6 @@ public: private: GstElement* createMicSource(); - void setEncoderParam(gst::GstElements& elements); - void setSourceParam(gst::GstElements& elements); - void replaceCapsWithAudioInfo(GstElement* element); - void replaceEncCapsWithAudioInfo(GstElement* element); param::audioInfo _audioInfo; param::encodingInfo _encInfo; diff --git a/include/MediaSourceBinVideoTest.h b/include/MediaSourceBinVideoTest.h index eb6b31f..01cac96 100644 --- a/include/MediaSourceBinVideoTest.h +++ b/include/MediaSourceBinVideoTest.h @@ -40,10 +40,6 @@ public: private: GstElement* createVideoTestSource(); - void setEncoderParam(gst::GstElements& elements); - void setSourceParam(gst::GstElements& elements); - void replaceCapsWithVideoInfo(GstElement* element); - void replaceEncCapsWithVideoInfo(GstElement* element); param::videoInfo _videoInfo; param::encodingInfo _encInfo; diff --git a/include/MediaTransporterBase.h b/include/MediaTransporterBase.h index e5bf3bb..2b9906a 100644 --- a/include/MediaTransporterBase.h +++ b/include/MediaTransporterBase.h @@ -48,7 +48,7 @@ public: virtual ~MediaTransporterBase() = default; void create(); - ResourceSet build(); + void build(); void destroy(); void start(); @@ -83,7 +83,7 @@ private: void makePipeline(); void stopInternal(); - virtual ResourceSet buildPipeline() = 0; + virtual void buildPipeline() = 0; virtual void startPipeline() = 0; virtual void stopPipeline() = 0; diff --git a/include/MediaTransporterGst.h b/include/MediaTransporterGst.h index 72901b4..b001fc4 100644 --- a/include/MediaTransporterGst.h +++ b/include/MediaTransporterGst.h @@ -24,6 +24,8 @@ #include #include +#include "MediaTransporterParam.h" + namespace tizen_media_transporter { namespace gst { @@ -122,6 +124,14 @@ void _destroyElementFromParent(GstElement* element); void _printCaps(GstCaps* caps, std::string prefix); +GstPad* _getGhostPadFromBin(GstBin* bin); + +void _updateCaps(GstElement* element, const param::videoInfo& vInfo); +void _updateEncCaps(GstElement* element, const param::videoInfo& vInfo); + +void _updateCaps(GstElement* element, const param::audioInfo& aInfo); +void _updateEncCaps(GstElement* element, const param::audioInfo& aInfo); + }; // gst } // tizen_media_transporter diff --git a/include/MediaTransporterReceiver.h b/include/MediaTransporterReceiver.h index 4aba2ec..d74e7970 100644 --- a/include/MediaTransporterReceiver.h +++ b/include/MediaTransporterReceiver.h @@ -60,16 +60,16 @@ public: protected: int _buildForwardingElements(GstElement* demux, GstPad* pad, GCallback callback); - void _buildForwardingSink(gst::GstElements& elements, GstPad* pad, GCallback callback); - - int _buildAudioRenderingElements(GstElement* demux, GstPad* pad); - int _buildVideoRenderingElements(GstElement* demux, GstPad* pad); + int _buildRenderingElements(GstElement* demux, GstPad* pad, bool isAudio); static void _streamAddedCallback(GstPad* pad, gpointer data); static void _noMoreStreamCallback(gpointer data); static void _encodedAudioStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data); static void _encodedVideoStreamCallback(GstElement* object, GstBuffer* buffer, GstPad* pad, gpointer data); + static bool _isSupportedMediaType(std::string mediaType); + static bool _isAudioMediaType(std::string mediaType); + std::unique_ptr _trackAddedCallback; std::unique_ptr _noMoreTrackCallback; @@ -86,6 +86,7 @@ protected: private: static media_packet_h _makeMediaPacket(GstBuffer* buffer, GstPad* pad, media_format_h* format); + void _buildForwardingSink(gst::GstElements& elements, GstPad* pad, GCallback callback); void _buildAudioRenderingSink(gst::GstElements& elements); void _buildVideoRenderingSink(gst::GstElements& elements); }; diff --git a/include/MediaTransporterReceiverRist.h b/include/MediaTransporterReceiverRist.h index 0435b27..c706e67 100644 --- a/include/MediaTransporterReceiverRist.h +++ b/include/MediaTransporterReceiverRist.h @@ -34,7 +34,7 @@ public: MediaTransporterReceiverRist() = default; ~MediaTransporterReceiverRist() = default; - ResourceSet buildPipeline() override; + void buildPipeline() override; void startPipeline() override; void stopPipeline() override; diff --git a/include/MediaTransporterReceiverSrt.h b/include/MediaTransporterReceiverSrt.h index 94ae6e5..fee3326 100644 --- a/include/MediaTransporterReceiverSrt.h +++ b/include/MediaTransporterReceiverSrt.h @@ -34,7 +34,7 @@ public: MediaTransporterReceiverSrt() = default; ~MediaTransporterReceiverSrt() = default; - ResourceSet buildPipeline() override; + void buildPipeline() override; void startPipeline() override; void stopPipeline() override; diff --git a/include/MediaTransporterSender.h b/include/MediaTransporterSender.h index 67a42ae..32bf2c4 100644 --- a/include/MediaTransporterSender.h +++ b/include/MediaTransporterSender.h @@ -40,6 +40,7 @@ public: IMediaSourceBin* getMediaSource(int id); protected: + void linkMediaSourceToMuxer(GstElement* mux); std::map> _mediaSources; }; diff --git a/include/MediaTransporterSenderRist.h b/include/MediaTransporterSenderRist.h index 884de60..d91773c 100644 --- a/include/MediaTransporterSenderRist.h +++ b/include/MediaTransporterSenderRist.h @@ -34,7 +34,7 @@ public: MediaTransporterSenderRist() = default; ~MediaTransporterSenderRist() = default; - ResourceSet buildPipeline() override; + void buildPipeline() override; void startPipeline() override; void stopPipeline() override; diff --git a/include/MediaTransporterSenderRtsp.h b/include/MediaTransporterSenderRtsp.h index 1818a39..3c6504d 100644 --- a/include/MediaTransporterSenderRtsp.h +++ b/include/MediaTransporterSenderRtsp.h @@ -32,7 +32,7 @@ public: MediaTransporterSenderRtsp() = default; ~MediaTransporterSenderRtsp() = default; - ResourceSet buildPipeline() override; + void buildPipeline() override; void startPipeline() override; void stopPipeline() override; diff --git a/include/MediaTransporterSenderSrt.h b/include/MediaTransporterSenderSrt.h index 4b5b155..eec4b55 100644 --- a/include/MediaTransporterSenderSrt.h +++ b/include/MediaTransporterSenderSrt.h @@ -33,7 +33,7 @@ public: MediaTransporterSenderSrt() = default; ~MediaTransporterSenderSrt() = default; - ResourceSet buildPipeline() override; + void buildPipeline() override; void startPipeline() override; void stopPipeline() override; diff --git a/include/MediaTransporterSenderToServerRtsp.h b/include/MediaTransporterSenderToServerRtsp.h index 63ee26f..e042a91 100644 --- a/include/MediaTransporterSenderToServerRtsp.h +++ b/include/MediaTransporterSenderToServerRtsp.h @@ -33,7 +33,7 @@ public: MediaTransporterSenderToServerRtsp() = default; ~MediaTransporterSenderToServerRtsp() = default; - ResourceSet buildPipeline() override; + void buildPipeline() override; void startPipeline() override; void stopPipeline() override; diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec index b77dfe5..47c3c90 100644 --- a/packaging/capi-media-transporter.spec +++ b/packaging/capi-media-transporter.spec @@ -1,6 +1,6 @@ Name: capi-media-transporter Summary: A Media Transporter library in Tizen Native API -Version: 0.0.6 +Version: 0.0.7 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/MediaSourceBinAudioTest.cpp b/src/MediaSourceBinAudioTest.cpp index 27a49c2..f01afda 100644 --- a/src/MediaSourceBinAudioTest.cpp +++ b/src/MediaSourceBinAudioTest.cpp @@ -19,6 +19,7 @@ #include "MediaTransporterException.h" #include "MediaTransporterParseIni.h" #include "MediaTransporterParam.h" +#include "MediaTransporterGst.h" #include @@ -45,85 +46,6 @@ GstElement* MediaSourceBinAudioTest::createMicSource() return audioSrc; } -void MediaSourceBinAudioTest::setEncoderParam(gst::GstElements& elements) -{ - GstElement* encoder = gst::_findEncoderElement(elements); - if (!encoder) - return; - - if (_encInfo.bitrate) { - if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), "bitrate")) - g_object_set(G_OBJECT(encoder), "bitrate", _encInfo.bitrate * 1000, NULL); - else - LOG_WARNING("%s element doesn't contain bitrate property", GST_ELEMENT_NAME(encoder)); - } -} - -void MediaSourceBinAudioTest::replaceCapsWithAudioInfo(GstElement* element) -{ - GstCaps* oldCaps; - auto& ini = MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_AUDIOTEST)); - GstAudioFormat format; - if (!_audioInfo.format.empty()) - format = gst::_getAudioFormatFromString(_audioInfo.format); - else - format = gst::_getAudioFormatFromString(ini.audioRawFormat); - - RET_IF(format == GST_AUDIO_FORMAT_UNKNOWN, "not supported raw format"); - - GstAudioInfo info; - int rate = _audioInfo.rate != -1 ? _audioInfo.rate : ini.audioSamplerate; - int channel = _audioInfo.channel != -1 ? _audioInfo.channel : ini.audioChannels; - gst_audio_info_set_format(&info, format, rate, channel, NULL); - GstCaps* newCaps = gst_audio_info_to_caps(&info); - - g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); - if (!gst_caps_is_equal(oldCaps, newCaps)) - g_object_set(G_OBJECT(element), "caps", newCaps, NULL); - - gst_caps_unref(newCaps); -} - -void MediaSourceBinAudioTest::replaceEncCapsWithAudioInfo(GstElement* element) -{ - GstCaps* oldCaps; - - g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); - RET_IF(!oldCaps, "capsfilter has no caps"); - - GstCaps* newCaps = gst_caps_copy(oldCaps); - - if (_audioInfo.channel != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _audioInfo.channel); - gst_caps_set_value(newCaps, "channels", &value); - } - - if (_audioInfo.rate != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _audioInfo.rate); - gst_caps_set_value(newCaps, "rate", &value); - } - - if (!gst_caps_is_equal(oldCaps, newCaps)) - g_object_set(G_OBJECT(element), "caps", newCaps, NULL); - - gst_caps_unref(newCaps); -} - -void MediaSourceBinAudioTest::setSourceParam(gst::GstElements& elements) -{ - GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); - if (srcCapsfilter) - replaceCapsWithAudioInfo(srcCapsfilter); - - GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); - if (encCapsfilter) - replaceEncCapsWithAudioInfo(encCapsfilter); -} - MediaSourceBinInfo MediaSourceBinAudioTest::generate() { gst::GstElements elements; @@ -135,8 +57,8 @@ MediaSourceBinInfo MediaSourceBinAudioTest::generate() auto created = createAudioRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_AUDIOTEST))); std::copy(created.begin(), created.end(), std::back_inserter(elements)); - setSourceParam(elements); - setEncoderParam(elements); + setSourceParam(elements, _audioInfo); + setEncoderParam(elements, _encInfo); } catch (const MediaTransporterException& e) { gst::_clearElements(elements); throw; diff --git a/src/MediaSourceBinBase.cpp b/src/MediaSourceBinBase.cpp index bdba563..d7fbf44 100644 --- a/src/MediaSourceBinBase.cpp +++ b/src/MediaSourceBinBase.cpp @@ -198,3 +198,39 @@ gst::GstElements MediaSourceBinBase::createAudioRestOfElements(const MtprMediaSo return elements; } + +void MediaSourceBinBase::setEncoderParam(gst::GstElements& elements, const param::encodingInfo& encInfo) +{ + GstElement* encoder = gst::_findEncoderElement(elements); + if (!encoder) + return; + + if (encInfo.bitrate) { + if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), "bitrate")) + g_object_set(G_OBJECT(encoder), "bitrate", encInfo.bitrate * 1000, NULL); + else + LOG_WARNING("%s element doesn't contain bitrate property", GST_ELEMENT_NAME(encoder)); + } +} + +void MediaSourceBinBase::setSourceParam(gst::GstElements& elements, const param::audioInfo& aInfo) +{ + GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); + if (srcCapsfilter) + gst::_updateCaps(srcCapsfilter, aInfo); + + GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); + if (encCapsfilter) + gst::_updateEncCaps(srcCapsfilter, aInfo); +} + +void MediaSourceBinBase::setSourceParam(gst::GstElements& elements, const param::videoInfo& vInfo) +{ + GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); + if (srcCapsfilter) + gst::_updateCaps(srcCapsfilter, vInfo); + + GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); + if (encCapsfilter) + gst::_updateEncCaps(srcCapsfilter, vInfo); +} diff --git a/src/MediaSourceBinCamera.cpp b/src/MediaSourceBinCamera.cpp index b45f448..7618bcc 100644 --- a/src/MediaSourceBinCamera.cpp +++ b/src/MediaSourceBinCamera.cpp @@ -20,6 +20,7 @@ #include "MediaTransporterParseIni.h" #include "MediaTransporterUtil.h" #include "MediaTransporterParam.h" +#include "MediaTransporterGst.h" #include @@ -51,98 +52,6 @@ GstElement* MediaSourceBinCamera::createCameraSource() return camerasrc; } -void MediaSourceBinCamera::setEncoderParam(gst::GstElements& elements) -{ - GstElement* encoder = gst::_findEncoderElement(elements); - if (!encoder) - return; - - if (_encInfo.bitrate) { - if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), "bitrate")) - g_object_set(G_OBJECT(encoder), "bitrate", _encInfo.bitrate * 1000, NULL); - else - LOG_WARNING("%s element doesn't contain bitrate property", GST_ELEMENT_NAME(encoder)); - } -} - -void MediaSourceBinCamera::replaceCapsWithVideoInfo(GstElement* element) -{ - GstCaps* oldCaps; - g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); - RET_IF(!oldCaps, "capsfilter has no caps"); - - GstCaps* newCaps = gst_caps_copy(oldCaps); - - if (_videoInfo.width != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _videoInfo.width); - gst_caps_set_value(newCaps, "width", &value); - } - - if (_videoInfo.height != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _videoInfo.height); - gst_caps_set_value(newCaps, "height", &value); - } - - if (_videoInfo.frameRate != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, GST_TYPE_FRACTION); - gst_value_set_fraction(&value, _videoInfo.frameRate, 1); - gst_caps_set_value(newCaps, "framerate", &value); - } - - if (!gst_caps_is_equal(oldCaps, newCaps)) { - gst::_printCaps(newCaps, "newCaps"); - g_object_set(G_OBJECT(element), "caps", newCaps, NULL); - } - - gst_caps_unref(newCaps); -} - -void MediaSourceBinCamera::replaceEncCapsWithVideoInfo(GstElement* element) -{ - GstCaps* oldCaps; - g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); - RET_IF(!oldCaps, "capsfilter has no caps"); - - GstCaps* newCaps = gst_caps_copy(oldCaps); - - if (_videoInfo.width != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _videoInfo.width); - gst_caps_set_value(newCaps, "width", &value); - } - - if (_videoInfo.height != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _videoInfo.height); - gst_caps_set_value(newCaps, "height", &value); - } - - if (!gst_caps_is_equal(oldCaps, newCaps)) { - gst::_printCaps(newCaps, "Change newCaps"); - g_object_set(G_OBJECT(element), "caps", newCaps, NULL); - } - - gst_caps_unref(newCaps); -} - -void MediaSourceBinCamera::setSourceParam(gst::GstElements& elements) -{ - GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); - if (srcCapsfilter) - replaceCapsWithVideoInfo(srcCapsfilter); - - GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); - if (encCapsfilter) - replaceEncCapsWithVideoInfo(encCapsfilter); -} - MediaSourceBinInfo MediaSourceBinCamera::generate() { gst::GstElements elements; @@ -153,8 +62,8 @@ MediaSourceBinInfo MediaSourceBinCamera::generate() auto created = createVideoRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_CAMERA))); std::copy(created.begin(), created.end(), std::back_inserter(elements)); - setSourceParam(elements); - setEncoderParam(elements); + setSourceParam(elements, _videoInfo); + setEncoderParam(elements, _encInfo); } catch (const MediaTransporterException& e) { gst::_clearElements(elements); throw; diff --git a/src/MediaSourceBinMic.cpp b/src/MediaSourceBinMic.cpp index cd53891..15d2e10 100644 --- a/src/MediaSourceBinMic.cpp +++ b/src/MediaSourceBinMic.cpp @@ -20,6 +20,7 @@ #include "MediaTransporterParseIni.h" #include "MediaTransporterUtil.h" #include "MediaTransporterParam.h" +#include "MediaTransporterGst.h" #include #include @@ -52,85 +53,6 @@ GstElement* MediaSourceBinMic::createMicSource() return audioSrc; } -void MediaSourceBinMic::setEncoderParam(gst::GstElements& elements) -{ - GstElement* encoder = gst::_findEncoderElement(elements); - if (!encoder) - return; - - if (_encInfo.bitrate) { - if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), "bitrate")) - g_object_set(G_OBJECT(encoder), "bitrate", _encInfo.bitrate * 1000, NULL); - else - LOG_WARNING("%s element doesn't contain bitrate property", GST_ELEMENT_NAME(encoder)); - } -} - -void MediaSourceBinMic::replaceCapsWithAudioInfo(GstElement* element) -{ - GstCaps* oldCaps; - auto& ini = MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_MIC)); - GstAudioFormat format; - if (!_audioInfo.format.empty()) - format = gst::_getAudioFormatFromString(_audioInfo.format); - else - format = gst::_getAudioFormatFromString(ini.audioRawFormat); - - RET_IF(format == GST_AUDIO_FORMAT_UNKNOWN, "not supported raw format"); - - GstAudioInfo info; - int rate = _audioInfo.rate != -1 ? _audioInfo.rate : ini.audioSamplerate; - int channel = _audioInfo.channel != -1 ? _audioInfo.channel : ini.audioChannels; - gst_audio_info_set_format(&info, format, rate, channel, NULL); - GstCaps* newCaps = gst_audio_info_to_caps(&info); - - g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); - if (!gst_caps_is_equal(oldCaps, newCaps)) - g_object_set(G_OBJECT(element), "caps", newCaps, NULL); - - gst_caps_unref(newCaps); -} - -void MediaSourceBinMic::replaceEncCapsWithAudioInfo(GstElement* element) -{ - GstCaps* oldCaps; - - g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); - RET_IF(!oldCaps, "capsfilter has no caps"); - - GstCaps* newCaps = gst_caps_copy(oldCaps); - - if (_audioInfo.channel != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _audioInfo.channel); - gst_caps_set_value(newCaps, "channels", &value); - } - - if (_audioInfo.rate != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _audioInfo.rate); - gst_caps_set_value(newCaps, "rate", &value); - } - - if (!gst_caps_is_equal(oldCaps, newCaps)) - g_object_set(G_OBJECT(element), "caps", newCaps, NULL); - - gst_caps_unref(newCaps); -} - -void MediaSourceBinMic::setSourceParam(gst::GstElements& elements) -{ - GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); - if (srcCapsfilter) - replaceCapsWithAudioInfo(srcCapsfilter); - - GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); - if (encCapsfilter) - replaceEncCapsWithAudioInfo(encCapsfilter); -} - MediaSourceBinInfo MediaSourceBinMic::generate() { gst::GstElements elements; @@ -144,8 +66,8 @@ MediaSourceBinInfo MediaSourceBinMic::generate() auto created = createAudioRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_MIC))); std::copy(created.begin(), created.end(), std::back_inserter(elements)); - setSourceParam(elements); - setEncoderParam(elements); + setSourceParam(elements, _audioInfo); + setEncoderParam(elements, _encInfo); } catch (const MediaTransporterException& e) { gst::_clearElements(elements); throw; diff --git a/src/MediaSourceBinVideoTest.cpp b/src/MediaSourceBinVideoTest.cpp index 74b0228..d26d2ab 100644 --- a/src/MediaSourceBinVideoTest.cpp +++ b/src/MediaSourceBinVideoTest.cpp @@ -19,6 +19,7 @@ #include "MediaTransporterException.h" #include "MediaTransporterParseIni.h" #include "MediaTransporterParam.h" +#include "MediaTransporterGst.h" #include @@ -45,98 +46,6 @@ GstElement* MediaSourceBinVideoTest::createVideoTestSource() return videotestsrc; } -void MediaSourceBinVideoTest::setEncoderParam(gst::GstElements& elements) -{ - GstElement* encoder = gst::_findEncoderElement(elements); - if (!encoder) - return; - - if (_encInfo.bitrate) { - if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), "bitrate")) - g_object_set(G_OBJECT(encoder), "bitrate", _encInfo.bitrate * 1000, NULL); - else - LOG_WARNING("%s element doesn't contain bitrate property", GST_ELEMENT_NAME(encoder)); - } -} - -void MediaSourceBinVideoTest::replaceCapsWithVideoInfo(GstElement* element) -{ - GstCaps* oldCaps; - g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); - RET_IF(!oldCaps, "capsfilter has no caps"); - - GstCaps* newCaps = gst_caps_copy(oldCaps); - - if (_videoInfo.width != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _videoInfo.width); - gst_caps_set_value(newCaps, "width", &value); - } - - if (_videoInfo.height != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _videoInfo.height); - gst_caps_set_value(newCaps, "height", &value); - } - - if (_videoInfo.frameRate != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, GST_TYPE_FRACTION); - gst_value_set_fraction(&value, _videoInfo.frameRate, 1); - gst_caps_set_value(newCaps, "framerate", &value); - } - - if (!gst_caps_is_equal(oldCaps, newCaps)) { - gst::_printCaps(newCaps, "Change newCaps"); - g_object_set(G_OBJECT(element), "caps", newCaps, NULL); - } - - gst_caps_unref(newCaps); -} - -void MediaSourceBinVideoTest::replaceEncCapsWithVideoInfo(GstElement* element) -{ - GstCaps* oldCaps; - g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); - RET_IF(!oldCaps, "capsfilter has no caps"); - - GstCaps* newCaps = gst_caps_copy(oldCaps); - - if (_videoInfo.width != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _videoInfo.width); - gst_caps_set_value(newCaps, "width", &value); - } - - if (_videoInfo.height != -1) { - GValue value = G_VALUE_INIT; - g_value_init(&value, G_TYPE_INT); - g_value_set_int(&value, _videoInfo.height); - gst_caps_set_value(newCaps, "height", &value); - } - - if (!gst_caps_is_equal(oldCaps, newCaps)) { - gst::_printCaps(newCaps, "Change newCaps"); - g_object_set(G_OBJECT(element), "caps", newCaps, NULL); - } - - gst_caps_unref(newCaps); -} - -void MediaSourceBinVideoTest::setSourceParam(gst::GstElements& elements) -{ - GstElement* srcCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_SRC_CAPSFILTER); - if (srcCapsfilter) - replaceCapsWithVideoInfo(srcCapsfilter); - - GstElement* encCapsfilter = gst::_findElementByName(elements, ELEMENT_NAME_ENCODE_CAPSFILTER); - if (encCapsfilter) - replaceEncCapsWithVideoInfo(encCapsfilter); -} - MediaSourceBinInfo MediaSourceBinVideoTest::generate() { gst::GstElements elements; @@ -147,8 +56,8 @@ MediaSourceBinInfo MediaSourceBinVideoTest::generate() auto created = createVideoRestOfElements(MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_VIDEOTEST))); // FIXME std::copy(created.begin(), created.end(), std::back_inserter(elements)); - setSourceParam(elements); - setEncoderParam(elements); + setSourceParam(elements, _videoInfo); + setEncoderParam(elements, _encInfo); } catch (const MediaTransporterException& e) { gst::_clearElements(elements); throw; diff --git a/src/MediaTransporter.cpp b/src/MediaTransporter.cpp index 87a007a..dfd5224 100644 --- a/src/MediaTransporter.cpp +++ b/src/MediaTransporter.cpp @@ -74,8 +74,7 @@ int mtpr_start(mtpr_h mtpr) assert(handle->resourceManager); try { - ResourceSet rs = handle->base->build(); - handle->resourceManager->acquire(rs); + handle->base->build(); handle->base->start(); } catch (const MediaTransporterException& e) { LOG_ERROR("Failed to start!!! : %s", e.what()); @@ -111,7 +110,7 @@ int mtpr_get_state(mtpr_h mtpr, mtpr_state_e *state) assert(handle->base); *state = handle->base->state(); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to stop!!! : %s", e.what()); + LOG_ERROR("Failed to get state!!! : %s", e.what()); return e.error(); } @@ -127,7 +126,7 @@ int mtpr_get_connection_type(mtpr_h mtpr, mtpr_connection_type_e *type) assert(handle->base); *type = handle->base->type(); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to create!!! : %s", e.what()); + LOG_ERROR("Failed to get connection type!!! : %s", e.what()); return e.error(); } @@ -165,7 +164,7 @@ int mtpr_get_sender_address(mtpr_h mtpr, char **address) } *address = strdup(senderAddress.c_str()); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to set sender address!!! : %s", e.what()); + LOG_ERROR("Failed to get sender address!!! : %s", e.what()); return e.error(); } @@ -181,7 +180,7 @@ int mtpr_set_receiver_address(mtpr_h mtpr, const char *address) assert(handle->base); handle->base->setReceiverAddress(address); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to set sender address!!! : %s", e.what()); + LOG_ERROR("Failed to set receiver address!!! : %s", e.what()); return e.error(); } @@ -203,7 +202,7 @@ int mtpr_get_receiver_address(mtpr_h mtpr, char **address) } *address = strdup(receiverAddress.c_str()); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to set sender address!!! : %s", e.what()); + LOG_ERROR("Failed to get receiver address!!! : %s", e.what()); return e.error(); } @@ -319,7 +318,7 @@ int mtpr_mic_source_set_sound_stream_info(mtpr_h mtpr, unsigned int source_id, s micSourceBin->setSoundStreamInfo(stream_info); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to mic set sound stream info!!! : %s", e.what()); + LOG_ERROR("Failed to set mic sound stream info!!! : %s", e.what()); return e.error(); } @@ -335,7 +334,7 @@ int mtpr_set_error_cb(mtpr_h mtpr, mtpr_error_cb callback, void *user_data) assert(handle->base); handle->base->setErrorCallback(mtpr, callback, user_data); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to setErrorCallback!!! : %s", e.what()); + LOG_ERROR("Failed to set error callback!!! : %s", e.what()); return e.error(); } @@ -351,7 +350,7 @@ int mtpr_unset_error_cb(mtpr_h mtpr) assert(handle->base); handle->base->unsetErrorCallback(); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to unsetErrorCallback!!! : %s", e.what()); + LOG_ERROR("Failed to unset error callback!!! : %s", e.what()); return e.error(); } @@ -371,7 +370,7 @@ int mtpr_set_track_added_cb(mtpr_h mtpr, mtpr_track_added_cb callback, void* use try { receiver->setTrackAddedCallback(mtpr, callback, user_data); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to setNoMoreTrackCallback!!! : %s", e.what()); + LOG_ERROR("Failed to set track added callback!!! : %s", e.what()); return e.error(); } @@ -391,7 +390,7 @@ int mtpr_unset_track_added_cb(mtpr_h mtpr) try { receiver->unsetTrackAddedCallback(); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to unsetNoMoreTrackCallback!!! : %s", e.what()); + LOG_ERROR("Failed to unset track added callback!!! : %s", e.what()); return e.error(); } @@ -411,7 +410,7 @@ int mtpr_set_no_more_track_cb(mtpr_h mtpr, mtpr_no_more_track_cb callback, void* try { receiver->setNoMoreTrackCallback(mtpr, callback, user_data); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to setNoMoreTrackCallback!!! : %s", e.what()); + LOG_ERROR("Failed to set no more track callback!!! : %s", e.what()); return e.error(); } @@ -431,7 +430,7 @@ int mtpr_unset_no_more_track_cb(mtpr_h mtpr) try { receiver->unsetNoMoreTrackCallback(); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to unsetNoMoreTrackCallback!!! : %s", e.what()); + LOG_ERROR("Failed to unset no more track callback!!! : %s", e.what()); return e.error(); } @@ -451,7 +450,7 @@ int mtpr_set_audio_packet_cb(mtpr_h mtpr, mtpr_encoded_frame_cb callback, void* try { receiver->setAudioPacketCallback(mtpr, callback, user_data);//__internal_audio_packet_cb, static_cast(handle)); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to setAudioPacketCallback!!! : %s", e.what()); + LOG_ERROR("Failed to set audio packet callback!!! : %s", e.what()); return e.error(); } @@ -471,7 +470,7 @@ int mtpr_unset_audio_packet_cb(mtpr_h mtpr) try { receiver->unsetAudioPacketCallback(); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to unsetAudioPacketCallback!!! : %s", e.what()); + LOG_ERROR("Failed to unset audio packet callback!!! : %s", e.what()); return e.error(); } @@ -491,7 +490,7 @@ int mtpr_set_video_packet_cb(mtpr_h mtpr, mtpr_encoded_frame_cb callback, void* try { receiver->setVideoPacketCallback(mtpr, callback, user_data); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to setVideoPacketCallback!!! : %s", e.what()); + LOG_ERROR("Failed to set video packet callback!!! : %s", e.what()); return e.error(); } @@ -511,7 +510,7 @@ int mtpr_unset_video_packet_cb(mtpr_h mtpr) try { receiver->unsetVideoPacketCallback(); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to unsetVideoPacketCallback!!! : %s", e.what()); + LOG_ERROR("Failed to unset video packet callback!!! : %s", e.what()); return e.error(); } @@ -532,7 +531,7 @@ int mtpr_set_display(mtpr_h mtpr, mtpr_display_type_e type, mtpr_display_h displ handle->display = std::make_shared(type, display); receiver->setDisplay(handle->display); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to mtpr_set_display!!! : %s", e.what()); + LOG_ERROR("Failed to set display!!! : %s", e.what()); return e.error(); } @@ -549,7 +548,7 @@ int mtpr_set_display_mode(mtpr_h mtpr, mtpr_display_mode_e mode) try { handle->display->setMode(mode); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to set modeq!!! : %s", e.what()); + LOG_ERROR("Failed to set display mode!!! : %s", e.what()); return e.error(); } @@ -566,7 +565,7 @@ int mtpr_get_display_mode(mtpr_h mtpr, mtpr_display_mode_e *mode) try { *mode = handle->display->getMode(); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to get Mode!!! : %s", e.what()); + LOG_ERROR("Failed to get display mode!!! : %s", e.what()); return e.error(); } @@ -583,7 +582,7 @@ int mtpr_set_display_visible(mtpr_h mtpr, bool visible) try { handle->display->setVisible(visible); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to set visible!!! : %s", e.what()); + LOG_ERROR("Failed to set display visible!!! : %s", e.what()); return e.error(); } @@ -600,7 +599,7 @@ int mtpr_get_display_visible(mtpr_h mtpr, bool *visible) try { *visible = handle->display->getVisible(); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to get visible!!! : %s", e.what()); + LOG_ERROR("Failed to get display visible!!! : %s", e.what()); return e.error(); } @@ -620,7 +619,7 @@ int mtpr_set_sound_stream_info(mtpr_h mtpr, sound_stream_info_h stream_info) try { receiver->setSoundStreamInfo(stream_info); } catch (const MediaTransporterException& e) { - LOG_ERROR("Failed to setSoundStreamInfo!!! : %s", e.what()); + LOG_ERROR("Failed to set sound stream info!!! : %s", e.what()); return e.error(); } diff --git a/src/MediaTransporterBase.cpp b/src/MediaTransporterBase.cpp index 681a805..0bd10f3 100644 --- a/src/MediaTransporterBase.cpp +++ b/src/MediaTransporterBase.cpp @@ -107,14 +107,14 @@ void MediaTransporterBase::create() _state = MTPR_STATE_IDLE; } -ResourceSet MediaTransporterBase::build() +void MediaTransporterBase::build() { std::lock_guard mutex(_mutex); if (_state != MTPR_STATE_IDLE) throw MediaTransporterException(MTPR_ERROR_INVALID_STATE, "state must be IDLE"); - return buildPipeline(); + buildPipeline(); } void MediaTransporterBase::start() diff --git a/src/MediaTransporterGst.cpp b/src/MediaTransporterGst.cpp index 5929c7a..f6d5fc9 100644 --- a/src/MediaTransporterGst.cpp +++ b/src/MediaTransporterGst.cpp @@ -741,3 +741,142 @@ void gst::_printCaps(GstCaps* caps, std::string prefix) std::string caps_str = gst_caps_to_string(caps); LOG_DEBUG("%s caps[%s]", prefix.c_str(), caps_str.c_str()); } + +GstPad* gst::_getGhostPadFromBin(GstBin* bin) +{ + GstElement* queue = gst_bin_get_by_name(bin, "srcQueue"); + if (!queue) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get srcQueue"); + + GstPad* srcPad = nullptr; + + if (!gst::_addNoTargetGhostpad(bin, &srcPad, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _addNoTargetGhostpad"); + + if (!gst::_setGhostpadTarget(srcPad, queue, true)) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _setGhostpadTarget"); + + return srcPad; +} + + +void gst::_updateCaps(GstElement* element, const param::videoInfo& vInfo) +{ + GstCaps* oldCaps; + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + RET_IF(!oldCaps, "capsfilter has no caps"); + + GstCaps* newCaps = gst_caps_copy(oldCaps); + + if (vInfo.width != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, vInfo.width); + gst_caps_set_value(newCaps, "width", &value); + } + + if (vInfo.height != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, vInfo.height); + gst_caps_set_value(newCaps, "height", &value); + } + + if (vInfo.frameRate != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, GST_TYPE_FRACTION); + gst_value_set_fraction(&value, vInfo.frameRate, 1); + gst_caps_set_value(newCaps, "framerate", &value); + } + + if (!gst_caps_is_equal(oldCaps, newCaps)) { + gst::_printCaps(newCaps, "newCaps"); + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + } + + gst_caps_unref(newCaps); +} + +void gst::_updateEncCaps(GstElement* element, const param::videoInfo& vInfo) +{ + GstCaps* oldCaps; + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + RET_IF(!oldCaps, "capsfilter has no caps"); + + GstCaps* newCaps = gst_caps_copy(oldCaps); + + if (vInfo.width != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, vInfo.width); + gst_caps_set_value(newCaps, "width", &value); + } + + if (vInfo.height != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, vInfo.height); + gst_caps_set_value(newCaps, "height", &value); + } + + if (!gst_caps_is_equal(oldCaps, newCaps)) { + gst::_printCaps(newCaps, "Change newCaps"); + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + } + + gst_caps_unref(newCaps); +} + +void gst::_updateCaps(GstElement* element, const param::audioInfo& aInfo) +{ + GstCaps* oldCaps; + auto& ini = MediaTransporterIni::get().mediaSource(static_cast(MTPR_SOURCE_TYPE_MIC)); + GstAudioFormat format; + if (!aInfo.format.empty()) + format = gst::_getAudioFormatFromString(aInfo.format); + else + format = gst::_getAudioFormatFromString(ini.audioRawFormat); + + RET_IF(format == GST_AUDIO_FORMAT_UNKNOWN, "not supported raw format"); + + GstAudioInfo info; + int rate = aInfo.rate != -1 ? aInfo.rate : ini.audioSamplerate; + int channel = aInfo.channel != -1 ? aInfo.channel : ini.audioChannels; + gst_audio_info_set_format(&info, format, rate, channel, NULL); + GstCaps* newCaps = gst_audio_info_to_caps(&info); + + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + if (!gst_caps_is_equal(oldCaps, newCaps)) + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + + gst_caps_unref(newCaps); +} + +void gst::_updateEncCaps(GstElement* element, const param::audioInfo& aInfo) +{ + GstCaps* oldCaps; + + g_object_get(G_OBJECT(element), "caps", &oldCaps, NULL); + RET_IF(!oldCaps, "capsfilter has no caps"); + + GstCaps* newCaps = gst_caps_copy(oldCaps); + + if (aInfo.channel != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, aInfo.channel); + gst_caps_set_value(newCaps, "channels", &value); + } + + if (aInfo.rate != -1) { + GValue value = G_VALUE_INIT; + g_value_init(&value, G_TYPE_INT); + g_value_set_int(&value, aInfo.rate); + gst_caps_set_value(newCaps, "rate", &value); + } + + if (!gst_caps_is_equal(oldCaps, newCaps)) + g_object_set(G_OBJECT(element), "caps", newCaps, NULL); + + gst_caps_unref(newCaps); +} \ No newline at end of file diff --git a/src/MediaTransporterParam.cpp b/src/MediaTransporterParam.cpp index b29ae5a..2d06476 100644 --- a/src/MediaTransporterParam.cpp +++ b/src/MediaTransporterParam.cpp @@ -29,7 +29,10 @@ void param::parseSourceParam(bundle* params, param::videoInfo* vInfo, param::enc int written_count = 0; char* string_val = NULL; - RET_IF(!params, "input param is NULL"); + if (!params) { + LOG_INFO("input param is NULL"); + return; + } if (bundle_get_str(params, MTPR_SOURCE_PARAM_VIDEO_WIDTH, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { vInfo->width = static_cast(strtoul(string_val, NULL, 10)); @@ -64,7 +67,10 @@ void param::parseSourceParam(bundle* params, param::audioInfo* aInfo, param::enc int written_count = 0; char* string_val = NULL; - RET_IF(!params, "input param is NULL"); + if (!params) { + LOG_INFO("input param is NULL"); + return; + } /* Will be move to mic/audiotest bin */ if (bundle_get_str(params, MTPR_SOURCE_PARAM_AUDIO_CHANNEL, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { diff --git a/src/MediaTransporterReceiver.cpp b/src/MediaTransporterReceiver.cpp index e24f6e8..48ef6ab 100644 --- a/src/MediaTransporterReceiver.cpp +++ b/src/MediaTransporterReceiver.cpp @@ -473,57 +473,7 @@ void MediaTransporterReceiver::_buildVideoRenderingSink(gst::GstElements& elemen } } -int MediaTransporterReceiver::_buildAudioRenderingElements(GstElement* demux, GstPad* pad) -{ - gst::GstElements elements; - - RET_VAL_IF(!demux, MTPR_ERROR_INVALID_PARAMETER, "demux element is NULL"); - RET_VAL_IF(!pad, MTPR_ERROR_INVALID_PARAMETER, "pad is NULL"); - - GstElement* queue = gst::_createElement(gst::DEFAULT_ELEMENT_QUEUE); - /* FIXME: need to check queue size */ - g_object_set(G_OBJECT(queue), - "max-size-buffers", DEFAULT_QUEUE_MAX_SIZE_BUFFERS, - "max-size-bytes", DEFAULT_QUEUE_MAX_SIZE_BYTES, - "max-size-time", DEFAULT_QUEUE_MAX_SIZE_TIME, - NULL); - elements.push_back(queue); - - GstElement* parser = gst::_createElementFromRegistry("Parser", gst_pad_get_current_caps(pad), NULL, - MediaTransporterIni::get().general().gstExcludedElements); - GstPad* srcPad; - if (parser) { - srcPad = gst_element_get_static_pad(parser, "src"); - elements.push_back(parser); - } else { - srcPad = gst_element_get_static_pad(queue, "src"); - } - - GstCaps* caps = gst_pad_has_current_caps(srcPad) ? gst_pad_get_current_caps(srcPad) - : gst_pad_query_caps(srcPad, NULL); - GstElement* decoder = gst::_createElementFromRegistry("Codec/Decoder/Audio", caps, NULL, - MediaTransporterIni::get().general().gstExcludedElements); - elements.push_back(decoder); - g_object_unref(srcPad); - - _buildAudioRenderingSink(elements); - - gst::_addElementsToBin(GST_BIN(_gst.pipeline), elements); - - if (!gst_element_link_pads(GST_ELEMENT(demux), - GST_PAD_NAME(pad), - GST_ELEMENT(queue), - "sink")) { - LOG_ERROR("failed to link demuxer and queue"); - } - - gst::_linkElements(elements); - gst::_syncElementsStateWithParent(elements); - - return MTPR_ERROR_NONE; -} - -int MediaTransporterReceiver::_buildVideoRenderingElements(GstElement* demux, GstPad* pad) +int MediaTransporterReceiver::_buildRenderingElements(GstElement* demux, GstPad* pad, bool isAudio) { gst::GstElements elements; @@ -555,12 +505,16 @@ int MediaTransporterReceiver::_buildVideoRenderingElements(GstElement* demux, Gs GstCaps* caps = gst_pad_has_current_caps(srcPad) ? gst_pad_get_current_caps(srcPad) : gst_pad_query_caps(srcPad, NULL); - GstElement* decoder = gst::_createElementFromRegistry("Codec/Decoder/Video", caps, NULL, - MediaTransporterIni::get().general().gstExcludedElements); + GstElement* decoder = gst::_createElementFromRegistry( + isAudio ? "Codec/Decoder/Audio" : "Codec/Decoder/Video", caps, NULL, + MediaTransporterIni::get().general().gstExcludedElements); elements.push_back(decoder); g_object_unref(srcPad); - _buildVideoRenderingSink(elements); + if (isAudio) + _buildAudioRenderingSink(elements); + else + _buildVideoRenderingSink(elements); gst::_addElementsToBin(GST_BIN(_gst.pipeline), elements); @@ -616,3 +570,19 @@ void MediaTransporterReceiver::setSoundStreamInfo(sound_stream_info_h streamInfo _streamInfo = stringStream.str(); } + +bool MediaTransporterReceiver::_isSupportedMediaType(std::string mediaType) +{ + if ((mediaType.find("audio") == std::string::npos) && + (mediaType.find("video") == std::string::npos)) { + LOG_ERROR("not supported media type [%s]", mediaType.c_str()); + return false; + } + + return true; +} + +bool MediaTransporterReceiver::_isAudioMediaType(std::string mediaType) +{ + return mediaType.find("audio") != std::string::npos; +} \ No newline at end of file diff --git a/src/MediaTransporterReceiverRist.cpp b/src/MediaTransporterReceiverRist.cpp index ee93a54..7df1dd2 100644 --- a/src/MediaTransporterReceiverRist.cpp +++ b/src/MediaTransporterReceiverRist.cpp @@ -24,22 +24,6 @@ using namespace tizen_media_transporter; -static bool _isSupportedMediaType(std::string mediaType) -{ - if ((mediaType.find("audio") == std::string::npos) && - (mediaType.find("video") == std::string::npos)) { - LOG_ERROR("not supported media type [%s]", mediaType.c_str()); - return false; - } - - return true; -} - -static bool _isAudioMediaType(std::string mediaType) -{ - return mediaType.find("audio") != std::string::npos; -} - void MediaTransporterReceiverRist::_demuxNoMorePadsCallback(GstElement *demux, gpointer userData) { MediaTransporterReceiverRist* rist = static_cast(userData); @@ -63,30 +47,25 @@ void MediaTransporterReceiverRist::_demuxPadAddedCallback(GstElement *demux, Gst auto rist = static_cast(userData); assert(rist); - if (_isAudioMediaType(mediaType)) { - if (rist->_audioCallback._callback) - rist->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedAudioStreamCallback)); - else - rist->_buildAudioRenderingElements(demux, new_pad); - } else { - if (rist->_videoCallback._callback) - rist->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedVideoStreamCallback)); - else - rist->_buildVideoRenderingElements(demux, new_pad); - } + + bool isAudio = _isAudioMediaType(mediaType); + if (rist->_audioCallback._callback && isAudio) + rist->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedAudioStreamCallback)); + else if (rist->_videoCallback._callback && !isAudio) + rist->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedVideoStreamCallback)); + else + rist->_buildRenderingElements(demux, new_pad, isAudio); _streamAddedCallback(new_pad, userData); } -ResourceSet MediaTransporterReceiverRist::buildPipeline() +void MediaTransporterReceiverRist::buildPipeline() { GstElement* src = NULL; GstElement* rtpmp2tdepay = NULL; GstElement* queue = NULL; GstElement* tsdemux = NULL; - ResourceSet allResourceRequired; - MTPR_FENTER(); /* create mux to sink */ @@ -114,7 +93,6 @@ ResourceSet MediaTransporterReceiverRist::buildPipeline() gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "no-more-pads", G_CALLBACK(_demuxNoMorePadsCallback), this); LOG_INFO("linked mux and sink"); - return allResourceRequired; } catch (const MediaTransporterException& e) { LOG_ERROR("%s", e.what()); diff --git a/src/MediaTransporterReceiverSrt.cpp b/src/MediaTransporterReceiverSrt.cpp index 502f794..fb8cea8 100644 --- a/src/MediaTransporterReceiverSrt.cpp +++ b/src/MediaTransporterReceiverSrt.cpp @@ -24,22 +24,6 @@ using namespace tizen_media_transporter; -static bool _isSupportedMediaType(std::string mediaType) -{ - if ((mediaType.find("audio") == std::string::npos) && - (mediaType.find("video") == std::string::npos)) { - LOG_ERROR("not supported media type [%s]", mediaType.c_str()); - return false; - } - - return true; -} - -static bool _isAudioMediaType(std::string mediaType) -{ - return mediaType.find("audio") != std::string::npos; -} - void MediaTransporterReceiverSrt::_demuxNoMorePadsCallback(GstElement *demux, gpointer userData) { MediaTransporterReceiverSrt* srt = static_cast(userData); @@ -63,29 +47,24 @@ void MediaTransporterReceiverSrt::_demuxPadAddedCallback(GstElement *demux, GstP auto srt = static_cast(userData); assert(srt); - if (_isAudioMediaType(mediaType)) { - if (srt->_audioCallback._callback) - srt->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedAudioStreamCallback)); - else - srt->_buildAudioRenderingElements(demux, new_pad); - } else { - if (srt->_videoCallback._callback) - srt->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedVideoStreamCallback)); - else - srt->_buildVideoRenderingElements(demux, new_pad); - } + + bool isAudio = _isAudioMediaType(mediaType); + if (srt->_audioCallback._callback && isAudio) + srt->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedAudioStreamCallback)); + else if (srt->_videoCallback._callback && !isAudio) + srt->_buildForwardingElements(demux, new_pad, G_CALLBACK(_encodedVideoStreamCallback)); + else + srt->_buildRenderingElements(demux, new_pad, isAudio); _streamAddedCallback(new_pad, userData); } -ResourceSet MediaTransporterReceiverSrt::buildPipeline() +void MediaTransporterReceiverSrt::buildPipeline() { GstElement* src = NULL; GstElement* queue = NULL; GstElement* tsdemux = NULL; - ResourceSet allResourceRequired; - MTPR_FENTER(); /* create mux to sink */ @@ -110,9 +89,6 @@ ResourceSet MediaTransporterReceiverSrt::buildPipeline() gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "no-more-pads", G_CALLBACK(_demuxNoMorePadsCallback), this); LOG_INFO("linked mux and sink"); - return allResourceRequired; - - // return MTPR_ERROR_NONE; } catch (const MediaTransporterException& e) { LOG_ERROR("%s", e.what()); diff --git a/src/MediaTransporterSender.cpp b/src/MediaTransporterSender.cpp index ff79058..0eda02a 100644 --- a/src/MediaTransporterSender.cpp +++ b/src/MediaTransporterSender.cpp @@ -51,4 +51,49 @@ IMediaSourceBin* MediaTransporterSender::getMediaSource(int id) } catch (...) { throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid id to get Source"); } -} \ No newline at end of file +} + +void MediaTransporterSender::linkMediaSourceToMuxer(GstElement* mux) +{ + + GstPad* sinkPad = NULL; + try { + /* link each element */ + for (auto& [id, mediaSource] : _mediaSources) { + auto[ type, bin, resourceRequired ] = mediaSource->generate(); + + LOG_INFO("mediaSource(type:%d, bin:%p, resourceRequired:%zu) generated", + static_cast(type), bin, resourceRequired.size()); + + _resourceManager->acquire(resourceRequired); + + gst_bin_add(GST_BIN(_gst.pipeline), GST_ELEMENT(bin)); + + GstPad* srcPad = gst::_getGhostPadFromBin(bin); + if (gst_pad_is_linked(srcPad)) { + LOG_ERROR("pad %s:%s is already linked", GST_DEBUG_PAD_NAME(srcPad)); + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "already linked"); + } + + sinkPad = gst_element_request_pad_simple(mux, "sink_%d"); + if (!sinkPad) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); + + GstPadLinkReturn res = gst_pad_link(srcPad, sinkPad); + if (GST_PAD_LINK_FAILED(res)) { + LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", + GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to link pads"); + } + LOG_INFO("pad is linked %s:%s - %s:%s", GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); + } + } catch (const MediaTransporterException& e) { + LOG_ERROR("%s", e.what()); + if (sinkPad) { + gst_element_release_request_pad(mux, sinkPad); + g_object_unref(sinkPad); + } + throw; + } +} diff --git a/src/MediaTransporterSenderRist.cpp b/src/MediaTransporterSenderRist.cpp index 5e524a2..403bcf4 100644 --- a/src/MediaTransporterSenderRist.cpp +++ b/src/MediaTransporterSenderRist.cpp @@ -29,31 +29,11 @@ using namespace tizen_media_transporter; -static GstPad* _getGhostPadFromBin(GstBin* bin) -{ - GstElement* queue = gst_bin_get_by_name(bin, "srcQueue"); - if (!queue) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get srcQueue"); - - GstPad* srcPad = nullptr; - - if (!gst::_addNoTargetGhostpad(bin, &srcPad, true)) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _addNoTargetGhostpad"); - - if (!gst::_setGhostpadTarget(srcPad, queue, true)) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _setGhostpadTarget"); - - return srcPad; -} - -ResourceSet MediaTransporterSenderRist::buildPipeline() +void MediaTransporterSenderRist::buildPipeline() { GstElement* mux = NULL; GstElement* sink = NULL; GstElement* pay = NULL; - GstPad* sinkPad = NULL; - - ResourceSet allResourceRequired; /* create mux to sink */ try { @@ -87,49 +67,13 @@ ResourceSet MediaTransporterSenderRist::buildPipeline() LOG_ERROR("pp %s, ref %d", GST_ELEMENT_NAME(_gst.pipeline), GST_OBJECT_REFCOUNT_VALUE(_gst.pipeline)); - /* link each element */ - for (auto& [id, mediaSource] : _mediaSources) { - auto[ type, bin, resourceRequired ] = mediaSource->generate(); - - LOG_INFO("mediaSource(type:%d, bin:%p, resourceRequired:%zu) generated", - static_cast(type), bin, resourceRequired.size()); - - allResourceRequired.insert(resourceRequired.begin(), resourceRequired.end()); - - gst_bin_add(GST_BIN(_gst.pipeline), GST_ELEMENT(bin)); - - GstPad* srcPad = _getGhostPadFromBin(bin); - if (gst_pad_is_linked(srcPad)) { - LOG_ERROR("pad %s:%s is already linked", GST_DEBUG_PAD_NAME(srcPad)); - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "already linked"); - } - - sinkPad = gst_element_request_pad_simple(mux, "sink_%d"); - if (!sinkPad) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); - - GstPadLinkReturn res = gst_pad_link(srcPad, sinkPad); - if (GST_PAD_LINK_FAILED(res)) { - LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", - GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); - - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to link pads"); - } - LOG_INFO("pad is linked %s:%s - %s:%s", GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); - } + linkMediaSourceToMuxer(mux); _ristSink = sink; LOG_INFO("linked mux and sink"); - - return allResourceRequired; } catch (const MediaTransporterException& e) { LOG_ERROR("%s", e.what()); - if (sinkPad) { - gst_element_release_request_pad(mux, sinkPad); - g_object_unref(sinkPad); - } - gst::_destroyElementFromParent(mux); gst::_destroyElementFromParent(pay); gst::_destroyElementFromParent(sink); diff --git a/src/MediaTransporterSenderRtsp.cpp b/src/MediaTransporterSenderRtsp.cpp index 3678f5f..5e0c4ec 100644 --- a/src/MediaTransporterSenderRtsp.cpp +++ b/src/MediaTransporterSenderRtsp.cpp @@ -30,22 +30,7 @@ using namespace tizen_media_transporter; #define ADDR_PATH_DELIM "/" #define ADDR_RTSP_PREFIX "rtsp://" -static GstPad* _getGhostPadFromBin(GstBin* bin) -{ - GstElement* queue = gst_bin_get_by_name(bin, "srcQueue"); - if (!queue) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get srcQueue"); - - GstPad* srcPad = nullptr; - - if (!gst::_addNoTargetGhostpad(bin, &srcPad, true)) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _addNoTargetGhostpad"); - - if (!gst::_setGhostpadTarget(srcPad, queue, true)) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _setGhostpadTarget"); - return srcPad; -} static GstRTSPFilterResult __clientFilter(GstRTSPServer *server, GstRTSPClient *client, gpointer userData) @@ -54,13 +39,10 @@ __clientFilter(GstRTSPServer *server, GstRTSPClient *client, gpointer userData) return GST_RTSP_FILTER_REMOVE; } -ResourceSet MediaTransporterSenderRtsp::buildPipeline() +void MediaTransporterSenderRtsp::buildPipeline() { GstElement* mux = NULL; GstElement* pay = NULL; - GstPad* sinkPad = NULL; - - ResourceSet allResourceRequired; try { if (_senderAddress.empty()) @@ -81,48 +63,13 @@ ResourceSet MediaTransporterSenderRtsp::buildPipeline() LOG_ERROR("pp %s, ref %d", GST_ELEMENT_NAME(_gst.pipeline), GST_OBJECT_REFCOUNT_VALUE(_gst.pipeline)); - /* create sources and link elements */ - for (auto& [id, mediaSource] : _mediaSources) { - auto[ type, bin, resourceRequired ] = mediaSource->generate(); - - LOG_INFO("mediaSource(type:%d, bin:%p, resourceRequired:%zu) generated", - static_cast(type), bin, resourceRequired.size()); - - allResourceRequired.insert(resourceRequired.begin(), resourceRequired.end()); - - gst_bin_add(GST_BIN(_gst.pipeline), GST_ELEMENT(bin)); - - GstPad* srcPad = _getGhostPadFromBin(bin); - if (gst_pad_is_linked(srcPad)) { - LOG_ERROR("pad %s:%s is already linked", GST_DEBUG_PAD_NAME(srcPad)); - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "already linked"); - } - - sinkPad = gst_element_request_pad_simple(mux, "sink_%d"); - if (!sinkPad) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); - - GstPadLinkReturn res = gst_pad_link(srcPad, sinkPad); - if (GST_PAD_LINK_FAILED(res)) { - LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", - GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); - - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); - } - LOG_INFO("pad is linked %s:%s - %s:%s", GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); - } + linkMediaSourceToMuxer(mux); LOG_INFO("linked mux and pay"); - return allResourceRequired; } catch (const MediaTransporterException& e) { LOG_ERROR("%s", e.what()); - if (sinkPad) { - gst_element_release_request_pad(mux, sinkPad); - g_object_unref(sinkPad); - } - gst::_destroyElementFromParent(mux); gst::_destroyElementFromParent(pay); diff --git a/src/MediaTransporterSenderSrt.cpp b/src/MediaTransporterSenderSrt.cpp index 5de67bb..065b579 100644 --- a/src/MediaTransporterSenderSrt.cpp +++ b/src/MediaTransporterSenderSrt.cpp @@ -25,23 +25,6 @@ using namespace tizen_media_transporter; -static GstPad* _getGhostPadFromBin(GstBin* bin) -{ - GstElement* queue = gst_bin_get_by_name(bin, "srcQueue"); - if (!queue) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get srcQueue"); - - GstPad* srcPad = nullptr; - - if (!gst::_addNoTargetGhostpad(bin, &srcPad, true)) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _addNoTargetGhostpad"); - - if (!gst::_setGhostpadTarget(srcPad, queue, true)) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _setGhostpadTarget"); - - return srcPad; -} - static void __callerAddedCb(GstElement* element, gint socket, GSocketAddress* address, gpointer userData) { LOG_INFO("socket %d, address %s", socket, @@ -66,13 +49,10 @@ static void __callerConnectingCb(GstElement* element, GSocketAddress* peerAddres g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)peerAddress))); } -ResourceSet MediaTransporterSenderSrt::buildPipeline() +void MediaTransporterSenderSrt::buildPipeline() { GstElement* mux = NULL; GstElement* sink = NULL; - GstPad* sinkPad = NULL; - - ResourceSet allResourceRequired; /* create mux to sink */ try { @@ -114,49 +94,14 @@ ResourceSet MediaTransporterSenderSrt::buildPipeline() LOG_ERROR("pp %s, ref %d", GST_ELEMENT_NAME(_gst.pipeline), GST_OBJECT_REFCOUNT_VALUE(_gst.pipeline)); - /* link each element */ - for (auto& [id, mediaSource] : _mediaSources) { - auto[ type, bin, resourceRequired ] = mediaSource->generate(); - - LOG_INFO("mediaSource(type:%d, bin:%p, resourceRequired:%zu) generated", - static_cast(type), bin, resourceRequired.size()); - - allResourceRequired.insert(resourceRequired.begin(), resourceRequired.end()); - - gst_bin_add(GST_BIN(_gst.pipeline), GST_ELEMENT(bin)); - - GstPad* srcPad = _getGhostPadFromBin(bin); - if (gst_pad_is_linked(srcPad)) { - LOG_ERROR("pad %s:%s is already linked", GST_DEBUG_PAD_NAME(srcPad)); - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "already linked"); - } - - sinkPad = gst_element_request_pad_simple(mux, "sink_%d"); - if (!sinkPad) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); - - GstPadLinkReturn res = gst_pad_link(srcPad, sinkPad); - if (GST_PAD_LINK_FAILED(res)) { - LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", - GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); - - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); - } - LOG_INFO("pad is linked %s:%s - %s:%s", GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); - } + linkMediaSourceToMuxer(mux); _srtSink = sink; LOG_INFO("linked mux and sink"); - return allResourceRequired; } catch (const MediaTransporterException& e) { LOG_ERROR("%s", e.what()); - if (sinkPad) { - gst_element_release_request_pad(mux, sinkPad); - g_object_unref(sinkPad); - } - gst::_destroyElementFromParent(mux); gst::_destroyElementFromParent(sink); diff --git a/src/MediaTransporterSenderToServerRtsp.cpp b/src/MediaTransporterSenderToServerRtsp.cpp index a65dda0..ff6b1da 100644 --- a/src/MediaTransporterSenderToServerRtsp.cpp +++ b/src/MediaTransporterSenderToServerRtsp.cpp @@ -24,30 +24,10 @@ using namespace tizen_media_transporter; -static GstPad* _getGhostPadFromBin(GstBin* bin) -{ - GstElement* queue = gst_bin_get_by_name(bin, "srcQueue"); - if (!queue) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to get srcQueue"); - - GstPad* srcPad = nullptr; - - if (!gst::_addNoTargetGhostpad(bin, &srcPad, true)) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _addNoTargetGhostpad"); - - if (!gst::_setGhostpadTarget(srcPad, queue, true)) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to _setGhostpadTarget"); - - return srcPad; -} - -ResourceSet MediaTransporterSenderToServerRtsp::buildPipeline() +void MediaTransporterSenderToServerRtsp::buildPipeline() { GstElement *mux = NULL; GstElement *sink = NULL; - GstPad* sinkPad = NULL; - - ResourceSet allResourceRequired; /* create mux to sink */ try { @@ -69,47 +49,14 @@ ResourceSet MediaTransporterSenderToServerRtsp::buildPipeline() LOG_ERROR("pp %s, ref %d", GST_ELEMENT_NAME(_gst.pipeline), GST_OBJECT_REFCOUNT_VALUE(_gst.pipeline)); - /* link each element */ - for (auto& [id, mediaSource] : _mediaSources) { - auto[ type, bin, resourceRequired ] = mediaSource->generate(); - - LOG_INFO("mediaSource(type:%d, bin:%p, resourceRequired:%zu) generated", - static_cast(type), bin, resourceRequired.size()); - - gst_bin_add(GST_BIN(_gst.pipeline), GST_ELEMENT(bin)); - - GstPad* srcPad = _getGhostPadFromBin(bin); - if (gst_pad_is_linked(srcPad)) { - LOG_ERROR("pad %s:%s is already linked", GST_DEBUG_PAD_NAME(srcPad)); - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "already linked"); - } - - sinkPad = gst_element_request_pad_simple(mux, "sink_%d"); - if (!sinkPad) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); - - GstPadLinkReturn res = gst_pad_link(srcPad, sinkPad); - if (GST_PAD_LINK_FAILED(res)) { - LOG_ERROR("failed to link pads, [%s:%s] - [%s:%s]", - GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); - - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to get request pad"); - } - LOG_INFO("pad is linked %s:%s - %s:%s", GST_DEBUG_PAD_NAME(srcPad), GST_DEBUG_PAD_NAME(sinkPad)); - } + linkMediaSourceToMuxer(mux); _rtspSink = sink; LOG_INFO("linked mux and sink"); - return allResourceRequired; } catch (const MediaTransporterException& e) { LOG_ERROR("%s", e.what()); - if (sinkPad) { - gst_element_release_request_pad(mux, sinkPad); - g_object_unref(sinkPad); - } - gst::_destroyElementFromParent(mux); gst::_destroyElementFromParent(sink); -- 2.7.4 From c711316ebc60752a2b19e79c9a63593afb835cb0 Mon Sep 17 00:00:00 2001 From: Eunhye Choi Date: Mon, 5 Sep 2022 12:16:53 +0900 Subject: [PATCH 10/12] [0.0.8] fix coverity issue Change-Id: I68fc8d47523f9839f96c24334f4a6a0720e45f5d --- packaging/capi-media-transporter.spec | 2 +- src/MediaTransporterSenderSrt.cpp | 20 ++++++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec index 47c3c90..50ff5b2 100644 --- a/packaging/capi-media-transporter.spec +++ b/packaging/capi-media-transporter.spec @@ -1,6 +1,6 @@ Name: capi-media-transporter Summary: A Media Transporter library in Tizen Native API -Version: 0.0.7 +Version: 0.0.8 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/MediaTransporterSenderSrt.cpp b/src/MediaTransporterSenderSrt.cpp index 065b579..443b953 100644 --- a/src/MediaTransporterSenderSrt.cpp +++ b/src/MediaTransporterSenderSrt.cpp @@ -27,26 +27,30 @@ using namespace tizen_media_transporter; static void __callerAddedCb(GstElement* element, gint socket, GSocketAddress* address, gpointer userData) { - LOG_INFO("socket %d, address %s", socket, - g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)address))); + g_autofree gchar* ip_addr = g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)address)); + + LOG_INFO("socket %d, address %s", socket, ip_addr); } static void __callerRemovedCb(GstElement* element, gint socket, GSocketAddress* address, gpointer userData) { - LOG_INFO("socket %d, address %s", socket, - g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)address))); + g_autofree gchar* ip_addr = g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)address)); + + LOG_INFO("socket %d, address %s", socket, ip_addr); } static void __callerRejectedCb(GstElement* element, GSocketAddress* peerAddress, const gchar* stream_id, gpointer userData) { - LOG_INFO("stream_id %s, peer_address %s", stream_id, - g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)peerAddress))); + g_autofree gchar* ip_addr = g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)peerAddress)); + + LOG_INFO("stream_id %s, peer_address %s", stream_id, ip_addr); } static void __callerConnectingCb(GstElement* element, GSocketAddress* peerAddress, const gchar* stream_id, gpointer userData) { - LOG_INFO("stream_id %s, peer_address %s", stream_id, - g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)peerAddress))); + g_autofree gchar* ip_addr = g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)peerAddress)); + + LOG_INFO("stream_id %s, peer_address %s", stream_id, ip_addr); } void MediaTransporterSenderSrt::buildPipeline() -- 2.7.4 From cffc551e7fc924d5b8f358f44493bf724201f853 Mon Sep 17 00:00:00 2001 From: Eunhye Choi Date: Mon, 5 Sep 2022 17:22:21 +0900 Subject: [PATCH 11/12] [0.0.9] add srt receiver param - add srt connection param for srtsrc in receiver as srtsink in sender Change-Id: I8b8b828dfc2a2952bd8349b223276812fd5b661b --- include/MediaTransporterParam.h | 45 ++++++++++++++--- include/MediaTransporterReceiverSrt.h | 8 +-- include/MediaTransporterSenderSrt.h | 32 ++---------- packaging/capi-media-transporter.spec | 2 +- src/MediaTransporterParam.cpp | 89 +++++++++++++++++++++++++++++++++ src/MediaTransporterReceiverSrt.cpp | 33 +++++++++++- src/MediaTransporterSenderSrt.cpp | 94 +++-------------------------------- 7 files changed, 177 insertions(+), 126 deletions(-) diff --git a/include/MediaTransporterParam.h b/include/MediaTransporterParam.h index 2b50853..7c16d7d 100644 --- a/include/MediaTransporterParam.h +++ b/include/MediaTransporterParam.h @@ -26,23 +26,54 @@ namespace tizen_media_transporter { namespace param { struct videoInfo { - int width { -1 }; - int height { -1 }; - int frameRate { -1 }; + int width { -1 }; + int height { -1 }; + int frameRate { -1 }; }; struct audioInfo { - int channel { -1 }; - int rate { -1 }; - std::string format; + int channel { -1 }; + int rate { -1 }; + std::string format; }; struct encodingInfo { - int bitrate = 0; + int bitrate { 0 }; }; void parseSourceParam(bundle* params, videoInfo* vInfo, encodingInfo* eInfo); void parseSourceParam(bundle* params, audioInfo* aInfo, encodingInfo * eInfo); + +namespace srt { + +enum connectionMode { + MTPR_CONNECTION_SRT_MODE_NONE = 0, /**< not connected, default type */ + MTPR_CONNECTION_SRT_MODE_CALLER, /**< The mode to send the connection request like a client (default) */ + MTPR_CONNECTION_SRT_MODE_LISTENER, /**< The mode to wait for being connected by peer caller */ + MTPR_CONNECTION_SRT_MODE_RENDEZVOUS, /**< The mode to support one-to-one only connection */ +}; + +enum connectionKeyLength { + MTPR_CONNECTION_SRT_NO_KEY = 0, /**< no encryption, default value */ + MTPR_CONNECTION_SRT_KEY_LEN_0 = 0, /**< no encryption */ + MTPR_CONNECTION_SRT_KEY_LEN_16 = 16, /**< 16 bytes (128-bit) length */ + MTPR_CONNECTION_SRT_KEY_LEN_24 = 24, /**< 24 bytes (192-bit) length */ + MTPR_CONNECTION_SRT_KEY_LEN_32 = 32, /**< 32 bytes (256-bit) length */ +}; + +struct connectionParam { + connectionMode mode { MTPR_CONNECTION_SRT_MODE_NONE }; + std::string streamId; + std::string passPhrase; + connectionKeyLength pbKeyLen { MTPR_CONNECTION_SRT_NO_KEY }; +}; + +bool _isValidKeyLength(int keyLen); +void setConnectionParam(std::string key, std::string value, connectionParam* connectionParam); +void setConnectionParamList(bundle* paramList, connectionParam* connectionParam); +void getConnectionParamList(const connectionParam& connectionParam, bundle* paramList); +}; // srt + }; // param } // tizen_media_transporter diff --git a/include/MediaTransporterReceiverSrt.h b/include/MediaTransporterReceiverSrt.h index fee3326..c766352 100644 --- a/include/MediaTransporterReceiverSrt.h +++ b/include/MediaTransporterReceiverSrt.h @@ -25,6 +25,7 @@ #include "MediaTransporterBase.h" #include "MediaTransporterReceiver.h" #include "MediaTransporterGst.h" +#include "MediaTransporterParam.h" namespace tizen_media_transporter { @@ -38,9 +39,9 @@ public: void startPipeline() override; void stopPipeline() override; - void setConnection(std::string name, std::string value) override {} - void setConnection(bundle* params) override {} - void getConnection(bundle* params) override {} + void setConnection(std::string name, std::string value) override; + void setConnection(bundle* paramList) override; + void getConnection(bundle* paramList) override; void setSenderAddress(std::string address) override; std::string getSenderAddress() override { return _senderAddress; } @@ -51,6 +52,7 @@ private: static void _demuxPadAddedCallback(GstElement* demux, GstPad* new_pad, gpointer userData); static void _demuxNoMorePadsCallback(GstElement* demux, gpointer userData); + param::srt::connectionParam _connectionParam; std::string _senderAddress; }; diff --git a/include/MediaTransporterSenderSrt.h b/include/MediaTransporterSenderSrt.h index eec4b55..08534d7 100644 --- a/include/MediaTransporterSenderSrt.h +++ b/include/MediaTransporterSenderSrt.h @@ -24,6 +24,7 @@ #include "MediaTransporter.h" #include "MediaTransporterSender.h" #include "MediaTransporterGst.h" +#include "MediaTransporterParam.h" namespace tizen_media_transporter { @@ -38,8 +39,8 @@ public: void stopPipeline() override; void setConnection(std::string name, std::string value) override; - void setConnection(bundle* params) override; - void getConnection(bundle* params) override; + void setConnection(bundle* paramList) override; + void getConnection(bundle* paramList) override; void setSenderAddress(std::string address) override; std::string getSenderAddress() override { return _senderAddress; } @@ -47,32 +48,7 @@ public: mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_SRT_SENDER; } private: - bool _isValidKeyLength(int val); - - enum connectionMode { - MTPR_CONNECTION_SRT_MODE_NONE = 0, /**< not connected, default type */ - MTPR_CONNECTION_SRT_MODE_CALLER, /**< The mode to send the connection request like a client (default) */ - MTPR_CONNECTION_SRT_MODE_LISTENER, /**< The mode to wait for being connected by peer caller */ - MTPR_CONNECTION_SRT_MODE_RENDEZVOUS, /**< The mode to support one-to-one only connection */ - }; - - enum connectionKeyLength { - MTPR_CONNECTION_SRT_NO_KEY = 0, /**< no encryption, default value */ - MTPR_CONNECTION_SRT_KEY_LEN_0 = 0, /**< no encryption */ - MTPR_CONNECTION_SRT_KEY_LEN_16 = 16, /**< 16 bytes (128-bit) length */ - MTPR_CONNECTION_SRT_KEY_LEN_24 = 24, /**< 24 bytes (192-bit) length */ - MTPR_CONNECTION_SRT_KEY_LEN_32 = 32, /**< 32 bytes (256-bit) length */ - }; - - struct MtprConnectionParamSrt { - connectionMode mode = MTPR_CONNECTION_SRT_MODE_NONE; - std::string streamId; - std::string passPhrase; - connectionKeyLength pbKeyLen = MTPR_CONNECTION_SRT_NO_KEY; - }; - - MtprConnectionParamSrt _connectionParam; - + param::srt::connectionParam _connectionParam; std::string _senderAddress; GstElement* _srtSink { nullptr }; diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec index 50ff5b2..da6b952 100644 --- a/packaging/capi-media-transporter.spec +++ b/packaging/capi-media-transporter.spec @@ -1,6 +1,6 @@ Name: capi-media-transporter Summary: A Media Transporter library in Tizen Native API -Version: 0.0.8 +Version: 0.0.9 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/MediaTransporterParam.cpp b/src/MediaTransporterParam.cpp index 2d06476..047fc6a 100644 --- a/src/MediaTransporterParam.cpp +++ b/src/MediaTransporterParam.cpp @@ -23,6 +23,7 @@ #include "MediaTransporterLog.h" using namespace tizen_media_transporter; +using namespace tizen_media_transporter::param::srt; void param::parseSourceParam(bundle* params, param::videoInfo* vInfo, param::encodingInfo* eInfo) { @@ -100,3 +101,91 @@ void param::parseSourceParam(bundle* params, param::audioInfo* aInfo, param::enc if (written_count == 0) throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "Failed to parse Source Param"); } + +bool param::srt::_isValidKeyLength(int keyLen) +{ + switch (keyLen) + { + case MTPR_CONNECTION_SRT_NO_KEY: + case MTPR_CONNECTION_SRT_KEY_LEN_16: + case MTPR_CONNECTION_SRT_KEY_LEN_24: + case MTPR_CONNECTION_SRT_KEY_LEN_32: + return true; + default: + return false; + } +} + +void param::srt::setConnectionParam(std::string key, std::string value, param::srt::connectionParam* connectionParam) +{ + SECURE_LOG_INFO("%s : %s", key.c_str(), value.c_str()); + + try { + if (key.compare(MTPR_CONNECTION_PARAM_SRT_MODE) == 0) { + size_t size; + int val = stoi(value, &size); + if ((value.size() != size) || + (val < MTPR_CONNECTION_SRT_MODE_NONE) || (val > MTPR_CONNECTION_SRT_MODE_RENDEZVOUS)) { + LOG_ERROR("invalid srt mode value %d", val); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid srt mode value"); + } + connectionParam->mode = static_cast(val); + + } else if (key.compare(MTPR_CONNECTION_PARAM_SRT_STREAMID) == 0) { + connectionParam->streamId = value; + + } else if (key.compare(MTPR_CONNECTION_PARAM_SRT_PASSPHRASE) == 0) { + connectionParam->passPhrase = value; + + } else if (key.compare(MTPR_CONNECTION_PARAM_SRT_PBKEYLEN) == 0) { + size_t size; + int val = stoi(value, &size); + if (value.size() != size || !_isValidKeyLength(val)) { + LOG_ERROR("invalid pbkeylen value %d", val); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid pbkeylen value"); + } + connectionParam->pbKeyLen = static_cast(val); + + } else { + LOG_ERROR("invalid param name %s", key.c_str()); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid param name"); + } + } catch (const std::exception& e) { + LOG_ERROR("error : %s, throw invalid param", e.what()); + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid parameter"); + } +} + +void param::srt::setConnectionParamList(bundle* paramList, param::srt::connectionParam* connectionParam) +{ + char* string_val = NULL; + + if (bundle_get_str(paramList, MTPR_CONNECTION_PARAM_SRT_MODE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) + setConnectionParam(std::string{MTPR_CONNECTION_PARAM_SRT_MODE}, string_val, connectionParam); + + if (bundle_get_str(paramList, MTPR_CONNECTION_PARAM_SRT_STREAMID, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) + connectionParam->streamId = string_val; + + if (bundle_get_str(paramList, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) + connectionParam->passPhrase = string_val; + + if (bundle_get_str(paramList, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) + setConnectionParam(std::string{MTPR_CONNECTION_PARAM_SRT_PBKEYLEN}, string_val, connectionParam); +} + +void param::srt::getConnectionParamList(const param::srt::connectionParam& connectionParam, bundle *paramList) +{ + bundle_add_str(paramList, + MTPR_CONNECTION_PARAM_SRT_MODE, + std::to_string(static_cast(connectionParam.mode)).c_str()); + + if (!connectionParam.streamId.empty()) + bundle_add_str(paramList, MTPR_CONNECTION_PARAM_SRT_STREAMID, connectionParam.streamId.c_str()); + + if (!connectionParam.passPhrase.empty()) + bundle_add_str(paramList, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, connectionParam.passPhrase.c_str()); + + bundle_add_str(paramList, + MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, + std::to_string(static_cast(connectionParam.pbKeyLen)).c_str()); +} diff --git a/src/MediaTransporterReceiverSrt.cpp b/src/MediaTransporterReceiverSrt.cpp index fb8cea8..7d22924 100644 --- a/src/MediaTransporterReceiverSrt.cpp +++ b/src/MediaTransporterReceiverSrt.cpp @@ -23,6 +23,7 @@ #include using namespace tizen_media_transporter; +using namespace tizen_media_transporter::param::srt; void MediaTransporterReceiverSrt::_demuxNoMorePadsCallback(GstElement *demux, gpointer userData) { @@ -75,6 +76,22 @@ void MediaTransporterReceiverSrt::buildPipeline() src = gst::_createElement(gst::DEFAULT_ELEMENT_SRTSRC); g_object_set(G_OBJECT(src), "uri", _senderAddress.c_str(), "latency", 10, NULL); + if (_connectionParam.mode != MTPR_CONNECTION_SRT_MODE_NONE) + g_object_set(G_OBJECT(src), + "mode", static_cast(_connectionParam.mode), NULL); + + if (_connectionParam.pbKeyLen != MTPR_CONNECTION_SRT_NO_KEY) + g_object_set(G_OBJECT(src), + "pbkeylen", static_cast(_connectionParam.pbKeyLen), NULL); + + if (!_connectionParam.passPhrase.empty()) + g_object_set(G_OBJECT(src), + "passphrase", _connectionParam.passPhrase.c_str(), NULL); + + if (!_connectionParam.streamId.empty()) + g_object_set(G_OBJECT(src), + "streamid", _connectionParam.streamId.c_str(), NULL); + queue = gst::_createElement(gst::DEFAULT_ELEMENT_QUEUE); tsdemux = gst::_createElement(gst::DEFAULT_ELEMENT_TSDEMUX); @@ -88,7 +105,6 @@ void MediaTransporterReceiverSrt::buildPipeline() gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "pad-added", G_CALLBACK(_demuxPadAddedCallback), this); gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(tsdemux), "no-more-pads", G_CALLBACK(_demuxNoMorePadsCallback), this); LOG_INFO("linked mux and sink"); - } catch (const MediaTransporterException& e) { LOG_ERROR("%s", e.what()); @@ -112,6 +128,21 @@ void MediaTransporterReceiverSrt::stopPipeline() MediaTransporterIni::get().general().timeout); } +void MediaTransporterReceiverSrt::setConnection(std::string name, std::string string_val) +{ + setConnectionParam(name, string_val, &_connectionParam); +} + +void MediaTransporterReceiverSrt::setConnection(bundle* paramList) +{ + setConnectionParamList(paramList, &_connectionParam); +} + +void MediaTransporterReceiverSrt::getConnection(bundle* paramList) +{ + getConnectionParamList(_connectionParam, paramList); +} + void MediaTransporterReceiverSrt::setSenderAddress(std::string address) { _senderAddress = address; diff --git a/src/MediaTransporterSenderSrt.cpp b/src/MediaTransporterSenderSrt.cpp index 443b953..ab00a14 100644 --- a/src/MediaTransporterSenderSrt.cpp +++ b/src/MediaTransporterSenderSrt.cpp @@ -24,6 +24,7 @@ #include "MediaTransporterParseIni.h" using namespace tizen_media_transporter; +using namespace tizen_media_transporter::param::srt; static void __callerAddedCb(GstElement* element, gint socket, GSocketAddress* address, gpointer userData) { @@ -74,11 +75,12 @@ void MediaTransporterSenderSrt::buildPipeline() LOG_ERROR("failed to gst_element_link()"); throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "failed to gst_element_link()"); } + if (_connectionParam.mode != MTPR_CONNECTION_SRT_MODE_NONE) g_object_set(G_OBJECT(sink), "mode", static_cast(_connectionParam.mode), NULL); - if (!_connectionParam.pbKeyLen != MTPR_CONNECTION_SRT_NO_KEY) + if (_connectionParam.pbKeyLen != MTPR_CONNECTION_SRT_NO_KEY) g_object_set(G_OBJECT(sink), "pbkeylen", static_cast(_connectionParam.pbKeyLen), NULL); @@ -95,9 +97,6 @@ void MediaTransporterSenderSrt::buildPipeline() gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(sink), "caller-rejected", G_CALLBACK(__callerRejectedCb), &_gst); gst::_connectAndAppendSignal(&_gst.signals, G_OBJECT(sink), "caller-connecting", G_CALLBACK(__callerConnectingCb), &_gst); - LOG_ERROR("pp %s, ref %d", - GST_ELEMENT_NAME(_gst.pipeline), GST_OBJECT_REFCOUNT_VALUE(_gst.pipeline)); - linkMediaSourceToMuxer(mux); _srtSink = sink; @@ -126,96 +125,19 @@ void MediaTransporterSenderSrt::stopPipeline() MediaTransporterIni::get().general().timeout); } -bool MediaTransporterSenderSrt::_isValidKeyLength(int val) -{ - switch(val) - { - case MTPR_CONNECTION_SRT_NO_KEY: - case MTPR_CONNECTION_SRT_KEY_LEN_16: - case MTPR_CONNECTION_SRT_KEY_LEN_24: - case MTPR_CONNECTION_SRT_KEY_LEN_32: - return true; - default: - return false; - } -} - void MediaTransporterSenderSrt::setConnection(std::string name, std::string string_val) { - SECURE_LOG_INFO("%s : %s", name.c_str(), string_val.c_str()); - - try { - if (name.compare(MTPR_CONNECTION_PARAM_SRT_MODE) == 0) { - size_t size; - int val = stoi(string_val, &size); - if ((string_val.size() != size) || - (val < MTPR_CONNECTION_SRT_MODE_NONE) || (val > MTPR_CONNECTION_SRT_MODE_RENDEZVOUS)) { - LOG_ERROR("invalid srt mode value %d", val); - throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid srt mode value"); - } - _connectionParam.mode = static_cast(val); - - } else if (name.compare(MTPR_CONNECTION_PARAM_SRT_STREAMID) == 0) { - _connectionParam.streamId = string_val; - - } else if (name.compare(MTPR_CONNECTION_PARAM_SRT_PASSPHRASE) == 0) { - _connectionParam.passPhrase = string_val; - - } else if (name.compare(MTPR_CONNECTION_PARAM_SRT_PBKEYLEN) == 0) { - size_t size; - int val = stoi(string_val, &size); - if (string_val.size() != size || !_isValidKeyLength(val)) { - LOG_ERROR("invalid pbkeylen value %d", val); - throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid pbkeylen value"); - } - _connectionParam.pbKeyLen = static_cast(val); - - } else { - LOG_ERROR("invalid param name %s", name.c_str()); - throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid param name"); - } - } catch (const std::exception& e) { - LOG_ERROR("error : %s, throw invalid param", e.what()); - throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "invalid parameter"); - } + setConnectionParam(name, string_val, &_connectionParam); } -void MediaTransporterSenderSrt::setConnection(bundle* params) +void MediaTransporterSenderSrt::setConnection(bundle* paramList) { - char* string_val = NULL; - - if (bundle_get_str(params, MTPR_CONNECTION_PARAM_SRT_MODE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - setConnection(MTPR_CONNECTION_PARAM_SRT_MODE, string_val); - } - - if (bundle_get_str(params, MTPR_CONNECTION_PARAM_SRT_STREAMID, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _connectionParam.streamId = std::string {string_val}; - } - - if (bundle_get_str(params, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - _connectionParam.passPhrase = std::string {string_val}; - } - - if (bundle_get_str(params, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) { - setConnection(MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, string_val); - } + setConnectionParamList(paramList, &_connectionParam); } -void MediaTransporterSenderSrt::getConnection(bundle* params) +void MediaTransporterSenderSrt::getConnection(bundle* paramList) { - bundle_add_str(params, - MTPR_CONNECTION_PARAM_SRT_MODE, - std::to_string(static_cast(_connectionParam.mode)).c_str()); - - if (!_connectionParam.streamId.empty()) - bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_STREAMID, _connectionParam.streamId.c_str()); - - if (!_connectionParam.passPhrase.empty()) - bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, _connectionParam.passPhrase.c_str()); - - bundle_add_str(params, - MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, - std::to_string(static_cast(_connectionParam.pbKeyLen)).c_str()); + getConnectionParamList(_connectionParam, paramList); } void MediaTransporterSenderSrt::setSenderAddress(std::string address) -- 2.7.4 From b3f88055b507105a20d8e1ada8811bfcad76677f Mon Sep 17 00:00:00 2001 From: Eunhye Choi Date: Wed, 7 Sep 2022 20:26:43 +0900 Subject: [PATCH 12/12] [0.0.10][ut] add srt sender Change-Id: Ied5c843a3197f10f7fcf2e6c8aee35bb2720bb03 --- include/mtpr.h | 1 - packaging/capi-media-transporter.spec | 2 +- src/MediaTransporter.cpp | 19 + src/MediaTransporterParam.cpp | 12 +- src/MediaTransporterSender.cpp | 1 - src/MediaTransporterSenderRist.cpp | 9 +- src/MediaTransporterSenderRtsp.cpp | 9 +- src/MediaTransporterSenderSrt.cpp | 9 +- src/MediaTransporterSenderToServerRtsp.cpp | 11 +- unittest/{testbase.hpp => ut_base.hpp} | 19 +- unittest/ut_main.cpp | 14 +- unittest/ut_srt_sender.cpp | 558 ++++++++++++++++++++++++++--- 12 files changed, 576 insertions(+), 88 deletions(-) rename unittest/{testbase.hpp => ut_base.hpp} (61%) diff --git a/include/mtpr.h b/include/mtpr.h index 2239968..2906088 100644 --- a/include/mtpr.h +++ b/include/mtpr.h @@ -391,7 +391,6 @@ int mtpr_destroy(mtpr_h mtpr); * @retval #MTPR_ERROR_NONE Successful * @retval #MTPR_ERROR_INVALID_PARAMETER Invalid parameter * @retval #MTPR_ERROR_INVALID_OPERATION Invalid operation - * @retval #MTPR_ERROR_INVALID_STATE Invalid state * @retval #MTPR_ERROR_RESOURCE_FAILED Resource failed * @pre @a mtpr state must be set to #MTPR_STATE_IDLE. * @post @a mtpr state will be #MTPR_STATE_PLAYING. // FIXME diff --git a/packaging/capi-media-transporter.spec b/packaging/capi-media-transporter.spec index da6b952..f2b8d11 100644 --- a/packaging/capi-media-transporter.spec +++ b/packaging/capi-media-transporter.spec @@ -1,6 +1,6 @@ Name: capi-media-transporter Summary: A Media Transporter library in Tizen Native API -Version: 0.0.9 +Version: 0.0.10 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/MediaTransporter.cpp b/src/MediaTransporter.cpp index dfd5224..f044786 100644 --- a/src/MediaTransporter.cpp +++ b/src/MediaTransporter.cpp @@ -23,6 +23,8 @@ typedef struct { int mtpr_create(mtpr_connection_type_e type, mtpr_h* mtpr) { + RET_ERR_IF_NULL_ARG(mtpr); + auto handle = new media_transporter_s; RET_VAL_IF(!handle, MTPR_ERROR_INVALID_OPERATION, "Failed to allocate handle!!!"); @@ -104,6 +106,7 @@ int mtpr_stop(mtpr_h mtpr) int mtpr_get_state(mtpr_h mtpr, mtpr_state_e *state) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(state); try { auto handle = static_cast(mtpr); @@ -120,6 +123,7 @@ int mtpr_get_state(mtpr_h mtpr, mtpr_state_e *state) int mtpr_get_connection_type(mtpr_h mtpr, mtpr_connection_type_e *type) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(type); try { auto handle = static_cast(mtpr); @@ -136,6 +140,7 @@ int mtpr_get_connection_type(mtpr_h mtpr, mtpr_connection_type_e *type) int mtpr_set_sender_address(mtpr_h mtpr, const char *address) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(address); try { auto handle = static_cast(mtpr); @@ -174,6 +179,7 @@ int mtpr_get_sender_address(mtpr_h mtpr, char **address) int mtpr_set_receiver_address(mtpr_h mtpr, const char *address) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(address); try { auto handle = static_cast(mtpr); @@ -212,6 +218,8 @@ int mtpr_get_receiver_address(mtpr_h mtpr, char **address) int mtpr_set_connection_param(mtpr_h mtpr, const char *param_name, const char *param_value) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(param_name); + RET_ERR_IF_NULL_ARG(param_value); try { auto handle = static_cast(mtpr); @@ -228,6 +236,7 @@ int mtpr_set_connection_param(mtpr_h mtpr, const char *param_name, const char *p int mtpr_set_connection_params(mtpr_h mtpr, bundle *param_list) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(param_list); try { auto handle = static_cast(mtpr); @@ -244,6 +253,8 @@ int mtpr_set_connection_params(mtpr_h mtpr, bundle *param_list) int mtpr_get_connection_params(mtpr_h mtpr, bundle **param_list) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(param_list); + bundle *params = NULL; try { auto handle = static_cast(mtpr); @@ -328,6 +339,7 @@ int mtpr_mic_source_set_sound_stream_info(mtpr_h mtpr, unsigned int source_id, s int mtpr_set_error_cb(mtpr_h mtpr, mtpr_error_cb callback, void *user_data) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(callback); try { auto handle = static_cast(mtpr); @@ -360,6 +372,7 @@ int mtpr_unset_error_cb(mtpr_h mtpr) int mtpr_set_track_added_cb(mtpr_h mtpr, mtpr_track_added_cb callback, void* user_data) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(callback); auto handle = static_cast(mtpr); assert(handle->base); @@ -400,6 +413,7 @@ int mtpr_unset_track_added_cb(mtpr_h mtpr) int mtpr_set_no_more_track_cb(mtpr_h mtpr, mtpr_no_more_track_cb callback, void* user_data) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(callback); auto handle = static_cast(mtpr); assert(handle->base); @@ -440,6 +454,7 @@ int mtpr_unset_no_more_track_cb(mtpr_h mtpr) int mtpr_set_audio_packet_cb(mtpr_h mtpr, mtpr_encoded_frame_cb callback, void* user_data) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(callback); auto handle = static_cast(mtpr); assert(handle->base); @@ -480,6 +495,7 @@ int mtpr_unset_audio_packet_cb(mtpr_h mtpr) int mtpr_set_video_packet_cb(mtpr_h mtpr, mtpr_encoded_frame_cb callback, void* user_data) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(callback); auto handle = static_cast(mtpr); assert(handle->base); @@ -520,6 +536,7 @@ int mtpr_unset_video_packet_cb(mtpr_h mtpr) int mtpr_set_display(mtpr_h mtpr, mtpr_display_type_e type, mtpr_display_h display) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(display); auto handle = static_cast(mtpr); assert(handle->base); @@ -558,6 +575,7 @@ int mtpr_set_display_mode(mtpr_h mtpr, mtpr_display_mode_e mode) int mtpr_get_display_mode(mtpr_h mtpr, mtpr_display_mode_e *mode) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(mode); auto handle = static_cast(mtpr); RET_VAL_IF(!handle->display, MTPR_ERROR_INVALID_OPERATION, "display is not set yet!!!"); @@ -592,6 +610,7 @@ int mtpr_set_display_visible(mtpr_h mtpr, bool visible) int mtpr_get_display_visible(mtpr_h mtpr, bool *visible) { RET_ERR_IF_INVALID_INSTANCE(mtpr); + RET_ERR_IF_NULL_ARG(visible); auto handle = static_cast(mtpr); RET_VAL_IF(!handle->display, MTPR_ERROR_INVALID_OPERATION, "display is not set yet!!!"); diff --git a/src/MediaTransporterParam.cpp b/src/MediaTransporterParam.cpp index 047fc6a..7b0b413 100644 --- a/src/MediaTransporterParam.cpp +++ b/src/MediaTransporterParam.cpp @@ -25,6 +25,9 @@ using namespace tizen_media_transporter; using namespace tizen_media_transporter::param::srt; +constexpr size_t SRT_MIN_PASSPHRASE = 10; +constexpr size_t SRT_MAX_PASSPHRASE = 79; + void param::parseSourceParam(bundle* params, param::videoInfo* vInfo, param::encodingInfo* eInfo) { int written_count = 0; @@ -135,8 +138,9 @@ void param::srt::setConnectionParam(std::string key, std::string value, param::s connectionParam->streamId = value; } else if (key.compare(MTPR_CONNECTION_PARAM_SRT_PASSPHRASE) == 0) { + if (value.length() < SRT_MIN_PASSPHRASE || value.length() > SRT_MAX_PASSPHRASE) + throw MediaTransporterException(MTPR_ERROR_INVALID_PARAMETER, "wrong passphrase"); connectionParam->passPhrase = value; - } else if (key.compare(MTPR_CONNECTION_PARAM_SRT_PBKEYLEN) == 0) { size_t size; int val = stoi(value, &size); @@ -161,16 +165,16 @@ void param::srt::setConnectionParamList(bundle* paramList, param::srt::connectio char* string_val = NULL; if (bundle_get_str(paramList, MTPR_CONNECTION_PARAM_SRT_MODE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) - setConnectionParam(std::string{MTPR_CONNECTION_PARAM_SRT_MODE}, string_val, connectionParam); + setConnectionParam(MTPR_CONNECTION_PARAM_SRT_MODE, string_val, connectionParam); if (bundle_get_str(paramList, MTPR_CONNECTION_PARAM_SRT_STREAMID, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) connectionParam->streamId = string_val; if (bundle_get_str(paramList, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) - connectionParam->passPhrase = string_val; + setConnectionParam(MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, string_val, connectionParam); if (bundle_get_str(paramList, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, &string_val) != BUNDLE_ERROR_KEY_NOT_AVAILABLE) - setConnectionParam(std::string{MTPR_CONNECTION_PARAM_SRT_PBKEYLEN}, string_val, connectionParam); + setConnectionParam(MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, string_val, connectionParam); } void param::srt::getConnectionParamList(const param::srt::connectionParam& connectionParam, bundle *paramList) diff --git a/src/MediaTransporterSender.cpp b/src/MediaTransporterSender.cpp index 0eda02a..83fa345 100644 --- a/src/MediaTransporterSender.cpp +++ b/src/MediaTransporterSender.cpp @@ -55,7 +55,6 @@ IMediaSourceBin* MediaTransporterSender::getMediaSource(int id) void MediaTransporterSender::linkMediaSourceToMuxer(GstElement* mux) { - GstPad* sinkPad = NULL; try { /* link each element */ diff --git a/src/MediaTransporterSenderRist.cpp b/src/MediaTransporterSenderRist.cpp index 403bcf4..84da981 100644 --- a/src/MediaTransporterSenderRist.cpp +++ b/src/MediaTransporterSenderRist.cpp @@ -35,11 +35,14 @@ void MediaTransporterSenderRist::buildPipeline() GstElement* sink = NULL; GstElement* pay = NULL; + if (_receiverAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + + if (_mediaSources.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "source is empty"); + /* create mux to sink */ try { - if (_receiverAddress.empty()) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); - mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); g_object_set(G_OBJECT(mux), "alignment", 7, NULL); diff --git a/src/MediaTransporterSenderRtsp.cpp b/src/MediaTransporterSenderRtsp.cpp index 5e0c4ec..6ec0a26 100644 --- a/src/MediaTransporterSenderRtsp.cpp +++ b/src/MediaTransporterSenderRtsp.cpp @@ -44,10 +44,13 @@ void MediaTransporterSenderRtsp::buildPipeline() GstElement* mux = NULL; GstElement* pay = NULL; - try { - if (_senderAddress.empty()) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + if (_senderAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + + if (_mediaSources.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "source is empty"); + try { /* create mux and pay */ mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); g_object_set(G_OBJECT(mux), "alignment", 7, NULL); diff --git a/src/MediaTransporterSenderSrt.cpp b/src/MediaTransporterSenderSrt.cpp index ab00a14..6b058b1 100644 --- a/src/MediaTransporterSenderSrt.cpp +++ b/src/MediaTransporterSenderSrt.cpp @@ -59,11 +59,14 @@ void MediaTransporterSenderSrt::buildPipeline() GstElement* mux = NULL; GstElement* sink = NULL; + if (_senderAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + + if (_mediaSources.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "source is empty"); + /* create mux to sink */ try { - if (_senderAddress.empty()) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); - mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); g_object_set(G_OBJECT(mux), "alignment", 7, NULL); diff --git a/src/MediaTransporterSenderToServerRtsp.cpp b/src/MediaTransporterSenderToServerRtsp.cpp index ff6b1da..7cf6e15 100644 --- a/src/MediaTransporterSenderToServerRtsp.cpp +++ b/src/MediaTransporterSenderToServerRtsp.cpp @@ -29,11 +29,14 @@ void MediaTransporterSenderToServerRtsp::buildPipeline() GstElement *mux = NULL; GstElement *sink = NULL; - /* create mux to sink */ - try { - if (_receiverAddress.empty()) - throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + if (_receiverAddress.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "address is empty"); + + if (_mediaSources.empty()) + throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "source is empty"); + try { + /* create mux to sink */ mux = gst::_createElement(gst::DEFAULT_ELEMENT_TSMUX); g_object_set(G_OBJECT(mux), "alignment", 7, NULL); diff --git a/unittest/testbase.hpp b/unittest/ut_base.hpp similarity index 61% rename from unittest/testbase.hpp rename to unittest/ut_base.hpp index 5e18925..e955570 100644 --- a/unittest/testbase.hpp +++ b/unittest/ut_base.hpp @@ -31,21 +31,12 @@ class MediaTransporterTestBase : public ::testing::Test { public: - MediaTransporterTestBase() : _mtpr(nullptr) {} + MediaTransporterTestBase() = default; + ~MediaTransporterTestBase() = default; - void SetUp() override {} - void TearDown() override {} - - mtpr_h GetHandle() { return _mtpr; } - const std::string& GetSRTSenderPath() { return _srtSenderPath; } - const std::string& GetSRTReceiverPath() { return _srtReceiverPath; } - const std::string& GetRTSPSenderPath() { return _rtspSenderPath; } + void SetUp() override {} + void TearDown() override {} protected: - mtpr_h _mtpr; - -private: - const std::string _srtSenderPath = "srt://:8888"; - const std::string _srtReceiverPath = "srt://127.0.0.1:8888"; - const std::string _rtspSenderPath = "rtsp://127.0.0.1:8554/test"; + mtpr_h _mtpr { nullptr }; }; diff --git a/unittest/ut_main.cpp b/unittest/ut_main.cpp index d84a5b4..8695359 100644 --- a/unittest/ut_main.cpp +++ b/unittest/ut_main.cpp @@ -18,11 +18,11 @@ int main(int argc, char *argv[]) { - try { - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); - } catch (const std::exception &e) { - std::cout << "caught exception: " << e.what() << std::endl; - return -1; - } + try { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + } catch (const std::exception &e) { + std::cout << "caught exception: " << e.what() << std::endl; + return -1; + } } diff --git a/unittest/ut_srt_sender.cpp b/unittest/ut_srt_sender.cpp index 504680c..7f01fad 100644 --- a/unittest/ut_srt_sender.cpp +++ b/unittest/ut_srt_sender.cpp @@ -14,86 +14,550 @@ * limitations under the License. */ -#include "testbase.hpp" +#include "ut_base.hpp" class MediaTransporterSrtSenderTest : public MediaTransporterTestBase { public: - MediaTransporterSrtSenderTest() {} + MediaTransporterSrtSenderTest() = default; + ~MediaTransporterSrtSenderTest() = default; - void SetUp() override { - LOGD("Enter"); + void SetUp() override { + LOGD("Enter"); - int ret = MTPR_ERROR_NONE; - ret = mtpr_create(MTPR_CONNECTION_TYPE_SRT_SENDER, &_mtpr); - ASSERT_EQ(ret, MTPR_ERROR_NONE); + int ret = MTPR_ERROR_NONE; + ret = mtpr_create(MTPR_CONNECTION_TYPE_SRT_SENDER, &_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); - LOGD("Leave"); - } + LOGD("Leave"); + } - void TearDown() override { - LOGD("Enter"); + void TearDown() override { + int ret = MTPR_ERROR_NONE; + mtpr_state_e state = MTPR_STATE_IDLE; + LOGD("Enter"); - if (_mtpr) { - int ret = mtpr_destroy(_mtpr); - ASSERT_EQ(ret, MTPR_ERROR_NONE); - } + if (_mtpr) { + ret = mtpr_get_state(_mtpr, &state); + ASSERT_EQ(ret, MTPR_ERROR_NONE); - LOGD("Leave"); - } + if (state != MTPR_STATE_IDLE) { + ret = mtpr_stop(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + } + ret = mtpr_destroy(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + } + LOGD("Leave"); + } + +protected: + const std::string _srtSenderPath = "srt://:8888"; }; -TEST_F(MediaTransporterSrtSenderTest, set_address) +TEST_F(MediaTransporterSrtSenderTest, set_address_p) +{ + int ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); +} + +TEST_F(MediaTransporterSrtSenderTest, set_address_n1) +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_sender_address(NULL, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_set_sender_address(_mtpr, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_set_sender_address(NULL, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, set_address_n2) +{ + int ret = mtpr_set_receiver_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION); +} + +TEST_F(MediaTransporterSrtSenderTest, get_address_p) { - int ret = MTPR_ERROR_NONE; + int ret = MTPR_ERROR_NONE; char *address = NULL; - ret = mtpr_set_receiver_address(GetHandle(), GetSRTSenderPath().c_str()); - ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION); + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); - ret = mtpr_set_sender_address(GetHandle(), GetSRTSenderPath().c_str()); - ASSERT_EQ(ret, MTPR_ERROR_NONE); + ret = mtpr_get_sender_address(_mtpr, &address); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_TRUE(address); + ASSERT_STREQ(_srtSenderPath.c_str(), address); +} + +TEST_F(MediaTransporterSrtSenderTest, get_address_n1) +{ + int ret = MTPR_ERROR_NONE; + char *address = NULL; + + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_get_sender_address(NULL, &address); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); - ret = mtpr_get_sender_address(GetHandle(), &address); - ASSERT_EQ(ret, MTPR_ERROR_NONE); - ASSERT_TRUE(address); + ret = mtpr_get_sender_address(_mtpr, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); - LOGD("sender address : %s", address); + ret = mtpr_get_sender_address(NULL, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, get_address_n2) +{ + char *address = NULL; - ASSERT_STREQ(GetSRTSenderPath().c_str(), address); + int ret = mtpr_get_sender_address(_mtpr, &address); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION); } -TEST_F(MediaTransporterSrtSenderTest, get_connection_type) +TEST_F(MediaTransporterSrtSenderTest, get_address_n3) { + int ret = MTPR_ERROR_NONE; + char *address = NULL; + + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_get_receiver_address(_mtpr, &address); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION); +} + +TEST_F(MediaTransporterSrtSenderTest, get_connection_type_p) +{ + mtpr_connection_type_e type; + + int ret = mtpr_get_connection_type(_mtpr, &type); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_EQ(type, MTPR_CONNECTION_TYPE_SRT_SENDER); +} + +TEST_F(MediaTransporterSrtSenderTest, get_connection_type_n1) +{ + int ret = MTPR_ERROR_NONE; mtpr_connection_type_e type; - int ret = mtpr_get_connection_type(GetHandle(), &type); - ASSERT_EQ(ret, MTPR_ERROR_NONE); - ASSERT_EQ(type, MTPR_CONNECTION_TYPE_SRT_SENDER); + ret = mtpr_get_connection_type(NULL, &type); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_get_connection_type(_mtpr, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_get_connection_type(NULL, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, add_media_source_p) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_GE(source_id, 0); + + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_AUDIOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_GE(source_id, 0); } -TEST_F(MediaTransporterSrtSenderTest, add_media_source) +TEST_F(MediaTransporterSrtSenderTest, add_media_source_n1) { - int ret = MTPR_ERROR_NONE; + int ret = MTPR_ERROR_NONE; unsigned int source_id = 0; - ret = mtpr_add_media_source(GetHandle(), MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); - ASSERT_EQ(ret, MTPR_ERROR_NONE); - ASSERT_TRUE(source_id >= 0); + ret = mtpr_add_media_source(NULL, MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); - ret = mtpr_add_media_source(GetHandle(), MTPR_SOURCE_TYPE_AUDIOTEST, NULL, &source_id); - ASSERT_EQ(ret, MTPR_ERROR_NONE); - ASSERT_TRUE(source_id >= 0); + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_AUDIOTEST, NULL, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); } -TEST_F(MediaTransporterSrtSenderTest, remove_media_source) +TEST_F(MediaTransporterSrtSenderTest, start_p) { - int ret = MTPR_ERROR_NONE; + int ret = MTPR_ERROR_NONE; unsigned int source_id = 0; - ret = mtpr_add_media_source(GetHandle(), MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); - ASSERT_EQ(ret, MTPR_ERROR_NONE); - ASSERT_TRUE(source_id >= 0); + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_GE(source_id, 0); + + + ret = mtpr_start(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); +} + +TEST_F(MediaTransporterSrtSenderTest, start_n1) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_GE(source_id, 0); + + ret = mtpr_start(NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, start_n2) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_GE(source_id, 0); + + ret = mtpr_start(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION); +} + +TEST_F(MediaTransporterSrtSenderTest, start_n3) +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_start(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION); +} + +TEST_F(MediaTransporterSrtSenderTest, stop_p) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_GE(source_id, 0); + + ret = mtpr_start(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_stop(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); +} + +TEST_F(MediaTransporterSrtSenderTest, stop_n1) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_GE(source_id, 0); + + ret = mtpr_start(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_stop(NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, stop_n2) +{ + int ret = mtpr_stop(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_STATE); +} + +TEST_F(MediaTransporterSrtSenderTest, get_state_p1) +{ + mtpr_state_e state = MTPR_STATE_IDLE; + + int ret = mtpr_get_state(_mtpr, &state); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_EQ(state, MTPR_STATE_IDLE); +} + +TEST_F(MediaTransporterSrtSenderTest, get_state_p2) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + mtpr_state_e state = MTPR_STATE_IDLE; + + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_GE(source_id, 0); + + ret = mtpr_start(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_get_state(_mtpr, &state); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_EQ(state, MTPR_STATE_PLAYING); +} + +TEST_F(MediaTransporterSrtSenderTest, get_state_p3) +{ + int ret = MTPR_ERROR_NONE; + unsigned int source_id = 0; + mtpr_state_e state = MTPR_STATE_IDLE; + + ret = mtpr_set_sender_address(_mtpr, _srtSenderPath.c_str()); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, NULL, &source_id); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_GE(source_id, 0); + + ret = mtpr_start(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_stop(_mtpr); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_get_state(_mtpr, &state); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_EQ(state, MTPR_STATE_IDLE); +} + +TEST_F(MediaTransporterSrtSenderTest, get_state_n) +{ + int ret = MTPR_ERROR_NONE; + mtpr_state_e state = MTPR_STATE_IDLE; + + ret = mtpr_get_state(NULL, &state); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_get_state(_mtpr, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_get_state(NULL, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_mode_p) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_MODE, "2"); + ASSERT_EQ(ret, MTPR_ERROR_NONE); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_mode_n1) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_MODE, "4"); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_mode_n2) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_MODE, "test"); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_streamid_p) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_STREAMID, "testid"); + ASSERT_EQ(ret, MTPR_ERROR_NONE); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_passphrase_p) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, "testpassphrase"); + ASSERT_EQ(ret, MTPR_ERROR_NONE); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_passphrase_n) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, "testpwd"); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_pbkeylen_p) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, "16"); + ASSERT_EQ(ret, MTPR_ERROR_NONE); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_pbkeylen_n1) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, "20"); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_pbkeylen_n2) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, "16test"); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_pbkeylen_n3) +{ + int ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, "test"); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_param_n) +{ + int ret = MTPR_ERROR_NONE; + + ret = mtpr_set_connection_param(NULL, MTPR_CONNECTION_PARAM_SRT_MODE, "2"); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_set_connection_param(_mtpr, NULL, "2"); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_set_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_MODE, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_params_p1) +{ + int ret = MTPR_ERROR_NONE; + bundle* params = bundle_create(); + + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_MODE, "2"); + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_STREAMID, "testid"); + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, "testpassphrase"); + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, "24"); + + ret = mtpr_set_connection_params(_mtpr, params); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + bundle_free(params); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_params_p2) +{ + int ret = MTPR_ERROR_NONE; + bundle* params = bundle_create(); + + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_MODE, "2"); + ret = mtpr_set_connection_params(_mtpr, params); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_STREAMID, "testid"); + ret = mtpr_set_connection_params(_mtpr, params); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, "testpassphrase"); + ret = mtpr_set_connection_params(_mtpr, params); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, "24"); + ret = mtpr_set_connection_params(_mtpr, params); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + bundle_free(params); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_params_n1) +{ + int ret = MTPR_ERROR_NONE; + bundle* params = bundle_create(); + + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_MODE, "7"); + + ret = mtpr_set_connection_params(_mtpr, params); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + bundle_free(params); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_params_n2) +{ + int ret = MTPR_ERROR_NONE; + bundle* params = bundle_create(); + + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, "testwd"); + + ret = mtpr_set_connection_params(_mtpr, params); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + bundle_free(params); +} + +TEST_F(MediaTransporterSrtSenderTest, set_connection_params_n3) +{ + int ret = MTPR_ERROR_NONE; + bundle* params = bundle_create(); + + bundle_add_str(params, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, "30"); + + ret = mtpr_set_connection_params(_mtpr, params); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + bundle_free(params); +} + +TEST_F(MediaTransporterSrtSenderTest, get_connection_params_p) +{ + int ret = MTPR_ERROR_NONE; + bundle* in = bundle_create(); + bundle* out = bundle_create(); + char* out_val = NULL; + + bundle_add_str(in, MTPR_CONNECTION_PARAM_SRT_MODE, "2"); + bundle_add_str(in, MTPR_CONNECTION_PARAM_SRT_STREAMID, "testid"); + bundle_add_str(in, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, "testpassphrase"); + bundle_add_str(in, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, "24"); + int len = bundle_get_count(in); + ret = mtpr_set_connection_params(_mtpr, in); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + + ret = mtpr_get_connection_params(_mtpr, &out); + ASSERT_EQ(ret, MTPR_ERROR_NONE); + ASSERT_EQ(len, bundle_get_count(out)); + + int bundle_ret = BUNDLE_ERROR_NONE; + bundle_ret = bundle_get_str(out, MTPR_CONNECTION_PARAM_SRT_MODE, &out_val); + ASSERT_EQ(bundle_ret, BUNDLE_ERROR_NONE); + ASSERT_STREQ(out_val, "2"); + + bundle_ret = bundle_get_str(out, MTPR_CONNECTION_PARAM_SRT_STREAMID, &out_val); + ASSERT_EQ(bundle_ret, BUNDLE_ERROR_NONE); + ASSERT_STREQ(out_val, "testid"); + + bundle_ret = bundle_get_str(out, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, &out_val); + ASSERT_EQ(bundle_ret, BUNDLE_ERROR_NONE); + ASSERT_STREQ(out_val, "testpassphrase"); + + bundle_ret = bundle_get_str(out, MTPR_CONNECTION_PARAM_SRT_PBKEYLEN, &out_val); + ASSERT_EQ(bundle_ret, BUNDLE_ERROR_NONE); + ASSERT_STREQ(out_val, "24"); + + bundle_free(in); + bundle_free(out); +} + +TEST_F(MediaTransporterSrtSenderTest, get_connection_params_n) +{ + int ret = MTPR_ERROR_NONE; + bundle* out = bundle_create(); + + ret = mtpr_get_connection_params(NULL, &out); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_get_connection_params(_mtpr, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); + + ret = mtpr_get_connection_params(NULL, NULL); + ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER); - ret = mtpr_remove_media_source(GetHandle(), source_id); - ASSERT_EQ(ret, MTPR_ERROR_NONE); + bundle_free(out); } -- 2.7.4