--- /dev/null
+
+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)
+
--- /dev/null
+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.
+
--- /dev/null
+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.
--- /dev/null
+# 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}
+
--- /dev/null
+/*
+ * 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 <mtpr.h>
+ *
+ * @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
+ * <div><table class="doxtable">
+ * <tr>
+ * <th><b>FUNCTION</b></th>
+ * <th><b>PRE-STATE</b></th>
+ * <th><b>POST-STATE</b></th>
+ * <th><b>SYNC TYPE</b></th>
+ * </tr>
+ * <tr>
+ * <td> mtpr_create() </td>
+ * <td> NONE </td>
+ * <td> IDLE </td>
+ * <td> SYNC </td>
+ * </tr>
+ * <tr>
+ * <td> mtpr_destroy() </td>
+ * <td> IDLE/PLAYING </td>
+ * <td> NONE </td>
+ * <td> SYNC </td>
+ * </tr>
+ * <tr>
+ * <td> mtpr_start() </td>
+ * <td> IDLE </td>
+ * <td> PLAYING </td>
+ * <td> ASYNC </td>
+ * </tr>
+ * <tr>
+ * <td> mtpr_stop() </td>
+ * <td> PLAYING </td>
+ * <td> IDLE </td>
+ * <td> ASYNC </td>
+ * </tr>
+ * </table></div>
+ *
+ * @subsection CAPI_MEDIA_TRANSPORTER_LIFE_CYCLE_CALLBACK_OPERATIONS Callback(Event) Operations
+ * The callback mechanism is used to notify the application about significant MediaTransporter events.
+ * <div><table class="doxtable">
+ * <tr>
+ * <th><b>REGISTER</b></th>
+ * <th><b>UNREGISTER</b></th>
+ * <th><b>CALLBACK</b></th>
+ * <th><b>DESCRIPTION</b></th>
+ * </tr>
+ * <tr>
+ * <td>mtpr_set_error_cb()</td>
+ * <td>mtpr_unset_error_cb()</td>
+ * <td>mtpr_error_cb()</td>
+ * <td>This callback is used to notify that an error has occurred</td>
+ * </tr>
+ * </table></div>
+ *
+ * @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 <a href="https://docs.tizen.org/application/tizen-studio/native-tools/manifest-text-editor#feature-element"><b>Feature Element</b>.</a>
+ *
+ */
+
+/**
+ * @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 <mtpr.h>
+ *
+ * @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 <a href="https://docs.tizen.org/application/tizen-studio/native-tools/manifest-text-editor#feature-element"><b>Feature Element</b>.</a>
+ *
+*/
+
+/**
+ * @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 <mtpr.h>
+ *
+ * @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__ */
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <mutex>
+#include <glib.h>
+#include <iniparser.h>
+#include <mm_resource_manager.h>
+#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__
--- /dev/null
+/**
+ * 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 <string>
+#include <vector>
+#include <map>
+#include <set>
+#include <mutex>
+#include <glib.h>
+#include <gst/gst.h>
+#include <iniparser.h>
+#include <bundle.h>
+#include <mm_resource_manager.h>
+#include "MediaTransporterParseIni.h"
+#include <tuple>
+
+namespace tizen_media_transporter {
+
+using MediaSourceBinInfo = std::tuple<mtprSourceType, GstBin*, ResourceSet>;
+
+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<GstElement*> createVideoRestOfElements(const MtprMediaSourceIni& ini);
+ std::vector<GstElement*> createAudioRestOfElements(const MtprMediaSourceIni& ini);
+};
+
+} // namespace
+
+#endif // __cplusplus
+#endif // __TIZEN_MEDIA_SOURCE_BIN_BASE_H__
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <mutex>
+#include <glib.h>
+#include <iniparser.h>
+#include <mm_resource_manager.h>
+#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__
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <bundle.h>
+
+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__
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <mutex>
+#include <glib.h>
+#include <iniparser.h>
+#include <mm_resource_manager.h>
+#include <sound_manager.h>
+
+#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__
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <mutex>
+#include <glib.h>
+#include <iniparser.h>
+#include <mm_resource_manager.h>
+#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__
--- /dev/null
+#ifndef __TIZEN_MEDIA_TRANSPORTER_CPP_H__
+#define __TIZEN_MEDIA_TRANSPORTER_CPP_H__
+
+#ifdef __cplusplus
+
+#include "mtpr.h"
+#include "mtpr_internal.h"
+
+#include <set>
+#include <mm_resource_manager.h>
+
+namespace tizen_media_transporter {
+
+using ResourceSet = std::set<mm_resource_manager_res_type_e>;
+
+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__
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <set>
+#include <mutex>
+#include <glib.h>
+#include <iniparser.h>
+#include <mm_resource_manager.h>
+#include <gst/gst.h>
+#include <bundle.h>
+#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<MediaTransporterResource> resourceManager);
+ void changed() override; // resource interrupted
+
+protected:
+ mtprGstreamer _gst {};
+ std::unique_ptr<IInvokable> _errorCallback;
+ std::shared_ptr<MediaTransporterResource> _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__
--- /dev/null
+/*
+* 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 <stdio.h>
+#include <dlog.h>
+
+#include <map>
+#include <variant>
+#include <memory>
+
+#include <media_packet.h>
+#include "MediaTransporter.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+namespace tizen_media_transporter {
+
+using VariantData = std::variant<mtprError, media_packet_h, unsigned int, mtprMediaType>;
+
+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__ */
--- /dev/null
+/*
+* 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 <stdio.h>
+#include <mutex>
+#include <mm_display_interface.h>
+#include <gst/gst.h>
+
+#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__ */
--- /dev/null
+/**
+ * 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 <exception>
+#include <string>
+
+#include <MediaTransporter.h>
+
+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__
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+
+namespace tizen_media_transporter {
+
+class MediaTransporterFactory
+{
+public:
+ static MediaTransporterBase* create(mtprConnectionType type);
+};
+
+} // namespace
+
+#endif // __cplusplus
+#endif // __TIZEN_MEDIA_TRANSPORTER_FACTORY_H__
--- /dev/null
+/**
+ * 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 <glib.h>
+#include <gst/gst.h>
+#include <gst/audio/audio.h>
+#include <vector>
+
+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<std::string> excludedElements;
+};
+
+using GstElements = std::vector<GstElement*>;
+
+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<std::string> 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<std::string>& 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__
--- /dev/null
+/*
+ * 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 <stdio.h>
+#include <dlog.h>
+#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 "<Enter>" FONT_COLOR_RESET); \
+} while (0)
+
+#define LOG_DEBUG_LEAVE() \
+do { \
+ LOGD(FONT_COLOR_PURPLE "<Leave>" 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("<ENTER>");
+#define MTPR_FLEAVE(); LOG_DEBUG("<LEAVE>");
+
+#define SAFE_STR(str) (str) ? str : "null"
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIA_TRANSPORTER_LOG_H__ */
--- /dev/null
+/*
+* 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 <stdio.h>
+#include <dlog.h>
+#include <vector>
+
+#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<IObserver*> _observers;
+};
+
+} // namespace
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIA_TRANSPORTER_OBSERVER_H__ */
+
--- /dev/null
+/**
+ * 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 <string>
+#include <vector>
+#include <iniparser.h>
+#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<std::string> gstArgs;
+ std::vector<std::string> 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<std::string> audioHWDecoderElements;
+ std::vector<std::string> videoHWDecoderElements;
+ bool v_overlay_resource_required;
+};
+
+struct MtprMediaSourceIni {
+ std::string sourceElement;
+ std::vector<std::string> 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<MtprMediaSourceIni> 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__
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <climits>
+#include <gst/gst.h>
+#include <media_format.h>
+#include <sound_manager_internal.h>
+#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<MediaTransporterDisplay> display);
+
+ void setSoundStreamInfo(sound_stream_info_h streamInfo);
+
+protected:
+ std::unique_ptr<IInvokable> _trackAddedCallback;
+ std::unique_ptr<IInvokable> _noMoreTrackCallback;
+
+ struct mtprCallback {
+ std::unique_ptr<IInvokable> _callback;
+ media_format_h mediaFormat { nullptr }; // FIXME : this should be A/V separated!!!
+ };
+ mtprCallback _videoCallback {};
+ mtprCallback _audioCallback {};
+
+ std::shared_ptr<MediaTransporterDisplay> _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__
+
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <climits>
+#include <gst/gst.h>
+#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__
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <climits>
+#include <gst/gst.h>
+#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__
--- /dev/null
+/*
+* 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 <mutex>
+#include <map>
+
+#include <mm_resource_manager.h>
+
+#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<mm_resource_manager_res_type_e, mm_resource_manager_res_h> _resources;
+ bool _onReleaseCallback { false };
+
+ std::mutex _mutex;
+};
+
+} // namespace
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIA_TRANSPORTER_RESOURCE_H__ */
+
--- /dev/null
+/**
+ * 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 <string>
+#include <map>
+#include <climits>
+#include <gst/gst.h>
+#include "MediaTransporterBase.h"
+#include "MediaSourceBinBase.h"
+#include <memory>
+
+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<int, std::unique_ptr<IMediaSourceBin>> _mediaSources;
+};
+
+} // namespace
+
+#endif // __cplusplus
+#endif // __TIZEN_MEDIA_TRANSPORTER_SENDER_H__
--- /dev/null
+/**
+ * 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 <string>
+#include <climits>
+#include <gst/gst.h>
+#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__
--- /dev/null
+/**
+ * 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 <string>
+#include <climits>
+#include <gst/gst.h>
+#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__
--- /dev/null
+/**
+ * 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 <string>
+#include <climits>
+#include <gio/gio.h>
+#include <gst/gst.h>
+#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__
--- /dev/null
+/**
+ * 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 <string>
+#include <climits>
+#include <gst/gst.h>
+#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__
--- /dev/null
+/**
+ * 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 <string>
+
+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__
--- /dev/null
+/*
+ * 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 <tizen.h>
+#include <bundle.h>
+#include <media_format.h>
+#include <media_packet.h>
+#include <sound_manager.h>
+
+#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 <address>:<port> 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__ */
+
--- /dev/null
+/*
+ * 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 <mtpr.h>
+
+#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__ */
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_" />
+ </request>
+ <assign>
+ <filesystem path="/usr/bin/mtpr_test" label="_" exec_label="none" />
+ </assign>
+</manifest>
--- /dev/null
+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
--- /dev/null
+/**
+ * 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 <algorithm>
+
+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<int>(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<int>(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<int>(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<int>(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<int>(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());
+}
--- /dev/null
+/**
+ * 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 <sstream>
+#include <algorithm>
+
+#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<GstElement*> MediaSourceBinBase::createVideoRestOfElements(const MtprMediaSourceIni& ini)
+{
+ std::vector<GstElement*> 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;
+}
--- /dev/null
+/**
+ * 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 <algorithm>
+
+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<int>(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<int>(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<int>(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<int>(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<int>(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);
+}
--- /dev/null
+/**
+ * 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<IMediaSourceBin*>(new MediaSourceBinCamera(params));
+ case MTPR_SOURCE_TYPE_MIC:
+ return static_cast<IMediaSourceBin*>(new MediaSourceBinMic(params));
+ case MTPR_SOURCE_TYPE_VIDEOTEST:
+ return static_cast<IMediaSourceBin*>(new MediaSourceBinVideoTest(params));
+ case MTPR_SOURCE_TYPE_AUDIOTEST:
+ return static_cast<IMediaSourceBin*>(new MediaSourceBinAudioTest(params));
+ default:
+ return NULL;
+ }
+}
--- /dev/null
+/**
+ * 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 <sound_manager_internal.h>
+#include <pulse/proplist.h>
+#include <algorithm>
+#include <sstream>
+
+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<int>(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<int>(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<int>(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<int>(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<int>(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();
+}
--- /dev/null
+/**
+ * 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 <algorithm>
+
+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<int>(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<int>(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<int>(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<int>(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<int>(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);
+}
--- /dev/null
+
+#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 <cassert>
+#include <memory>
+
+using namespace tizen_media_transporter;
+
+typedef struct {
+ std::unique_ptr<MediaTransporterBase> base;
+ std::shared_ptr<MediaTransporterResource> resourceManager;
+ std::shared_ptr<MediaTransporterDisplay> 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<MediaTransporterBase>(
+ MediaTransporterFactory::create(static_cast<mtprConnectionType>(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<MediaTransporterResource>();
+ 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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterSender* sender = dynamic_cast<MediaTransporterSender*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterSender* sender = dynamic_cast<MediaTransporterSender*>(handle->base.get());
+ RET_VAL_IF(!sender, MTPR_ERROR_INVALID_OPERATION, "only sender support this api!!!");
+
+ try {
+ sender->removeMediaSource(static_cast<int>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ try {
+ MediaTransporterSender* sender = dynamic_cast<MediaTransporterSender*>(handle->base.get());
+ RET_VAL_IF(!sender, MTPR_ERROR_INVALID_OPERATION, "only sender support this api!!!");
+
+ MediaSourceBinMic* micSourceBin = dynamic_cast<MediaSourceBinMic*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(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<void*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(handle->base.get());
+ RET_VAL_IF(!receiver, MTPR_ERROR_INVALID_OPERATION, "only receiver support this api!!!");
+
+ try {
+ handle->display = std::make_shared<MediaTransporterDisplay>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(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<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ MediaTransporterReceiver* receiver = dynamic_cast<MediaTransporterReceiver*>(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;
+}
--- /dev/null
+/**
+ * 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<MediaTransporterBase*>(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<std::mutex> 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<std::mutex> 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<std::mutex> 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<IInvokable>(new ErrorCallback(handle, callback, userData));
+}
+
+void MediaTransporterBase::unsetErrorCallback()
+{
+ _errorCallback = nullptr;
+}
+
+void MediaTransporterBase::setResourceManager(std::shared_ptr<MediaTransporterResource> 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;
+}
--- /dev/null
+/**
+ * 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<mtprMediaType>(data1);
+ auto trackId = std::get<unsigned int>(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<unsigned int>(data1);
+ auto packet = std::get<media_packet_h>(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<mtprError>(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
--- /dev/null
+/*
+ * 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 <iostream>
+#include <string>
+#include <algorithm>
+#include <mm_error.h>
+#include <gst/video/videooverlay.h>
+
+#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<std::mutex> 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<std::mutex> mutex(_mutex);
+
+ _visible = visible;
+
+ if (_sinkElement)
+ applyVisibleProperty();
+}
+
+void MediaTransporterDisplay::setMode(mtprDisplayMode mode)
+{
+ std::lock_guard<std::mutex> 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
--- /dev/null
+/**
+ * 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<MediaTransporterBase*>(new MediaTransporterSenderRist());
+ case MTPR_CONNECTION_TYPE_RIST_RECEIVER:
+ return static_cast<MediaTransporterBase*>(new MediaTransporterReceiverRist());
+ case MTPR_CONNECTION_TYPE_SRT_SENDER:
+ return static_cast<MediaTransporterBase*>(new MediaTransporterSenderSrt());
+ case MTPR_CONNECTION_TYPE_SRT_RECEIVER:
+ return static_cast<MediaTransporterBase*>(new MediaTransporterReceiverSrt());
+ case MTPR_CONNECTION_TYPE_RTSP_SENDER:
+ return static_cast<MediaTransporterBase*>(new MediaTransporterSenderRtsp());
+ case MTPR_CONNECTION_TYPE_RTSP_SENDER_TO_SERVER:
+ return static_cast<MediaTransporterBase*>(new MediaTransporterSenderToServerRtsp());
+ default:
+ return NULL;
+ }
+ return NULL;
+}
--- /dev/null
+/*
+ * 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 <iostream>
+#include <string>
+#include <algorithm>
+#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<gst::mtprSignal*>(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<gst::mtprSignal*>(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<std::string> 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<gst::elementInfo*>(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<std::string>& 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<char**>(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<GstElement*>(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());
+}
--- /dev/null
+/**
+ * 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 <algorithm>
+
+using namespace tizen_media_transporter;
+
+void ObservableBase::subscribe(IObserver * observer)
+{
+ _observers.push_back(observer);
+}
+
+void ObservableBase::notify()
+{
+ std::vector<IObserver *>::iterator iter = _observers.begin();
+ for (; iter != _observers.end(); iter++) {
+ IObserver *observer = *iter;
+ observer->changed();
+ }
+}
+
+void ObservableBase::unsubscribe(IObserver *observer)
+{
+ std::vector<IObserver *>::iterator iter;
+ iter = std::find(_observers.begin(), _observers.end(), observer);
+ if (iter != _observers.end()) {
+ _observers.erase(iter);
+ }
+}
--- /dev/null
+/**
+ * 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 <numeric>
+#include <sstream>
+#include <algorithm>
+#include <glib.h>
+#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<std::string>& item)
+{
+ std::string joined = std::accumulate(item.begin(), item.end(), std::string("|"));
+
+ LOG_INFO("- %-19s = %s", prefix_str, joined.c_str());
+}
+
+static std::vector<std::string> iniReadList(dictionary* dict, std::string category, std::string item, char delimeters)
+{
+ std::vector<std::string> 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<bool>(iniparser_getboolean(dict, key.c_str(), static_cast<int>(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
--- /dev/null
+/**
+ * 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 <media_packet_internal.h>
+#include <sound_manager_internal.h>
+#include <pulse/proplist.h>
+#include <sstream>
+
+using namespace tizen_media_transporter;
+
+void MediaTransporterReceiver::setTrackAddedCallback(void* handle, mtprTrackAddedCallback callback, void* userData)
+{
+ _trackAddedCallback = std::unique_ptr<IInvokable>(new TrackAddedCallback(handle, callback, userData));
+}
+
+void MediaTransporterReceiver::unsetTrackAddedCallback()
+{
+ _trackAddedCallback = nullptr;
+}
+
+void MediaTransporterReceiver::setNoMoreTrackCallback(void* handle, mtprNoMoreTrackCallback callback, void* userData)
+{
+ _noMoreTrackCallback = std::unique_ptr<IInvokable>(new NoMoreTrackCallback(handle, callback, userData));
+}
+
+void MediaTransporterReceiver::unsetNoMoreTrackCallback()
+{
+ _noMoreTrackCallback = nullptr;
+}
+
+void MediaTransporterReceiver::setVideoPacketCallback(void* handle, mtprPacketCallback callback, void* userData)
+{
+ _videoCallback._callback = std::unique_ptr<IInvokable>(new PacketCallback(handle, MTPR_MEDIA_TYPE_VIDEO, callback, userData));
+}
+
+void MediaTransporterReceiver::setAudioPacketCallback(void* handle, mtprPacketCallback callback, void* userData)
+{
+ _audioCallback._callback = std::unique_ptr<IInvokable>(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<MediaTransporterReceiver*>(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<MediaTransporterReceiver*>(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<MediaTransporterReceiver*>(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<MediaTransporterReceiver*>(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<MediaTransporterDisplay> 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();
+}
--- /dev/null
+/**
+ * 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 <cassert>
+
+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<MediaTransporterReceiverRist*>(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<MediaTransporterReceiverRist*>(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;
+}
--- /dev/null
+/**
+ * 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 <cassert>
+
+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<MediaTransporterReceiverSrt*>(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<MediaTransporterReceiverSrt*>(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;
+}
--- /dev/null
+/**
+ * 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 <algorithm>
+
+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<MediaTransporterResource*>(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<std::mutex> 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<int>(type));
+ _resources.erase(type);
+ interrupted = true;
+ }
+ }
+
+ if (interrupted)
+ notify();
+
+ _onReleaseCallback = false;
+
+ return true;
+}
+
+int MediaTransporterResource::create()
+{
+ std::lock_guard<std::mutex> 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<std::mutex> mutex(_mutex);
+
+ return acquireInternal(type);
+}
+
+int MediaTransporterResource::acquire(ResourceSet resourceSet)
+{
+ std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> 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;
+}
+
--- /dev/null
+/**
+ * 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 <map>
+#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<IMediaSourceBin>(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
--- /dev/null
+/**
+ * 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<int>(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;
+}
--- /dev/null
+/**
+ * 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 <string>
+#include <gst/rtsp-server/rtsp-server.h>
+#include <gst/rtsp-server/rtsp-media-factory-mtpr.h>
+
+#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<int>(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<void*>(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<GstRTSPServer*>(_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();
+}
--- /dev/null
+/**
+ * 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<int>(_connectionParam.mode), NULL);
+
+ if (!_connectionParam.pbKeyLen != MTPR_CONNECTION_SRT_NO_KEY)
+ g_object_set(G_OBJECT(sink),
+ "pbkeylen", static_cast<int>(_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<int>(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<connectionMode>(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<connectionKeyLength>(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<int>(_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<int>(_connectionParam.pbKeyLen)).c_str());
+}
+
+void MediaTransporterSenderSrt::setSenderAddress(std::string address)
+{
+ _senderAddress = address;
+}
--- /dev/null
+/**
+ * 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<int>(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;
+}
--- /dev/null
+/**
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <cynara-client.h>
+#include <sys/smack.h>
+#include <system_info.h>
+
+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());
+ }
+}
+
--- /dev/null
+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()
--- /dev/null
+/*
+* 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 <gst/gst.h>
+#include <gst/rtsp-server/rtsp-server.h>
+
+#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;
+}
--- /dev/null
+/*
+* 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 <mtpr_internal.h>
+
+#include <appcore-efl.h>
+#include <Elementary.h>
+#include <glib.h>
+#include <bundle.h>
+#include <sound_manager_internal.h>
+
+#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);
+}
+
--- /dev/null
+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
+)
--- /dev/null
+/*
+ * 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 <chrono>
+#include <iostream>
+#include <memory>
+#include <string>
+#include <thread>
+#include <malloc.h>
+#include <dlog.h>
+#include <glib.h>
+
+#include "gtest/gtest.h"
+#include <mtpr.h>
+
+#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";
+};
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+}