[1.0.11] add rtsp receiver ut 31/284931/2
authorEunhye Choi <eunhae1.choi@samsung.com>
Thu, 1 Dec 2022 05:53:55 +0000 (14:53 +0900)
committerEunhye Choi <eunhae1.choi@samsung.com>
Thu, 1 Dec 2022 05:56:52 +0000 (14:56 +0900)
- add rtsp receiver ut
- fix rtsp sender crash by unexpected server unref
- fix server resource leak at ut_rtsp_sender_to_server
- use once_flag to avoid duplicated setting of promise value
  at dataPacketCb

Change-Id: I2d2e2f016f5e13ca718155ed25b9e9a0d90a9592

packaging/capi-media-transporter.spec
src/MediaTransporterSenderRtsp.cpp
unittest/CMakeLists.txt
unittest/ut_rist_receiver.cpp
unittest/ut_rtsp_receiver.cpp [new file with mode: 0644]
unittest/ut_rtsp_sender_to_server.cpp
unittest/ut_srt_receiver.cpp

index 0e12abba07c22622e7822c962178730ab551e012..278b5ea5b559ded9484cca78032ab7898066d588 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-transporter
 Summary:    A Media Transporter library in Tizen Native API
-Version:    1.0.10
+Version:    1.0.11
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 9cb118cc1d054ec973095150119c598ba86e43ff..5a62024cd44dea41136f6d019b56b6bf26297b01 100644 (file)
@@ -200,9 +200,7 @@ void MediaTransporterSenderRtsp::stopRtspServer()
                g_source_remove(_sourceId);
        _sourceId = 0;
 
-       guint ref_cnt = GST_OBJECT_REFCOUNT_VALUE(server);
-       for (guint i = 0; i < ref_cnt; i++)
-               gst_object_unref(server);
+       gst_object_unref(server);
 
        _rtspServer = NULL;
        _rtspMountPoint.clear();
@@ -245,7 +243,6 @@ void MediaTransporterSenderRtsp::_mediaPreparedCb(GstRTSPMedia* media, gpointer
                g_signal_connect(session, "on-sender-ssrc-active",
                                                G_CALLBACK(_onSenderSsrcActive), media);
        }
-
        /* REF: pipeline ref count +1, it will be unref at stopPipeline() */
        handle->_rtspPipeline = gst_rtsp_media_get_pipeline(media);
 
index 1b0882d57e03a4be1a535897662de96c32231577..98d4a9178e21162054daf805f201661a29882c3e 100644 (file)
@@ -49,6 +49,7 @@ SET(UT_SRC
   ut_rist_receiver.cpp
   ut_rtsp_sender.cpp
   ut_rtsp_sender_to_server.cpp
+  ut_rtsp_receiver.cpp
   ut_srt_sender.cpp
   ut_srt_receiver.cpp
   ut_main.cpp
index 3b34d352e44fec50b25e21a3c38efcbb77e53352..ca8b5ea2476f80f7e0c75689ff3435d176286b1d 100644 (file)
@@ -47,9 +47,13 @@ static void dataPacketCb(mtpr_h mtpr, mtpr_media_type_e type,
                                                unsigned int id, media_packet_h packet, void *user_data) {
        LOGD("callback is invoked. type: %d, id: %d", type, id);
 
-       auto p = static_cast<std::promise<bool>*>(user_data);
-       assert(p);
-       p->set_value(true);
+       static std::once_flag flag;
+
+       std::call_once(flag, [&](){
+               auto p = static_cast<std::promise<bool>*>(user_data);
+               assert(p);
+               p->set_value(true);
+       });
 }
 
 static bool waitDataPacket(std::future<bool>& f) {
@@ -84,7 +88,6 @@ public:
                mtpr_state_e state = MTPR_STATE_IDLE;
 
                LOGD("Enter");
-               stop_rist_sender();
 
                if (_mtpr) {
                        ret = mtpr_get_state(_mtpr, &state);
@@ -98,6 +101,7 @@ public:
                        ASSERT_EQ(ret, MTPR_ERROR_NONE);
                }
 
+               stop_rist_sender();
                LOGD("Leave");
        }
 
diff --git a/unittest/ut_rtsp_receiver.cpp b/unittest/ut_rtsp_receiver.cpp
new file mode 100644 (file)
index 0000000..3f40f00
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * 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 "ut_base.hpp"
+
+static GMainLoop* mainloop;
+
+using namespace std::chrono_literals;
+
+static void* _run_rtsp_sender(void* ptr) {
+       mtpr_h mtpr;
+       unsigned int src_id = 0;
+       mtpr_create(MTPR_CONNECTION_TYPE_RTSP_SENDER, &mtpr);
+       mtpr_set_sender_address(mtpr, "rtsp://127.0.0.1:8554/test");
+       mtpr_add_media_source(mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, &src_id);
+       mtpr_start(mtpr);
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       LOGD("rtsp sender ready");
+       g_main_loop_run(mainloop);
+
+       LOGD("rtsp sender terminated");
+       g_main_loop_unref(mainloop);
+
+       mtpr_stop(mtpr);
+       mtpr_destroy(mtpr);
+
+       return NULL;
+}
+
+static void dataPacketCb(mtpr_h mtpr, mtpr_media_type_e type,
+                                               unsigned int id, media_packet_h packet, void *user_data) {
+       LOGD("callback is invoked. type: %d, id: %d", type, id);
+
+    static std::once_flag flag;
+
+    std::call_once(flag, [&](){
+        auto p = static_cast<std::promise<bool>*>(user_data);
+        assert(p);
+        p->set_value(true);
+    });
+}
+
+static bool waitDataPacket(std::future<bool>& f) {
+       LOGI("start waiting for packet arrival...");
+
+       if (f.wait_for(10s) != std::future_status::ready) {
+               LOGW("timeout(10s)!!!");
+               return false;
+       }
+
+       LOGI("ready to get the result!");
+       return f.get();
+}
+
+class MediaTransporterTestRtspReceiverWithSender : public MediaTransporterTestBase {
+public:
+       MediaTransporterTestRtspReceiverWithSender() = default;
+       ~MediaTransporterTestRtspReceiverWithSender() = default;
+
+       void SetUp() override {
+               LOGD("Enter");
+               start_rtsp_sender();
+
+               int ret = mtpr_create(MTPR_CONNECTION_TYPE_RTSP_RECEIVER, &_mtpr);
+               ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+               LOGD("Leave");
+       }
+
+       void TearDown() override {
+               int ret = MTPR_ERROR_NONE;
+               mtpr_state_e state = MTPR_STATE_IDLE;
+
+               LOGD("Enter");
+
+               if (_mtpr) {
+                       ret = mtpr_get_state(_mtpr, &state);
+                       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+                       if (state != MTPR_STATE_IDLE) {
+                               ret = mtpr_stop(_mtpr);
+                               ASSERT_EQ(ret, MTPR_ERROR_NONE);
+                       }
+                       ret = mtpr_destroy(_mtpr);
+                       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+               }
+
+               stop_rtsp_sender();
+               LOGD("Leave");
+       }
+
+protected:
+       const std::string _senderPath = "rtsp://127.0.0.1:8554/test";
+
+       void start_rtsp_sender() {
+               _rtspSender = g_thread_try_new("rtsp_sender", _run_rtsp_sender, NULL, NULL);
+               std::this_thread::sleep_for(std::chrono::seconds(1));
+       }
+
+       void stop_rtsp_sender() {
+               if (mainloop)
+                       g_main_loop_quit(mainloop);
+               if (_rtspSender)
+                       g_thread_join(_rtspSender);
+       }
+
+       GThread* _rtspSender {nullptr};
+};
+
+class MediaTransporterTestRtspReceiver : public MediaTransporterTestBase {
+public:
+       MediaTransporterTestRtspReceiver() = default;
+       ~MediaTransporterTestRtspReceiver() = default;
+
+       void SetUp() override {
+               LOGD("Enter");
+
+               int ret = mtpr_create(MTPR_CONNECTION_TYPE_RTSP_RECEIVER, &_mtpr);
+               ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+               LOGD("Leave");
+       }
+
+       void TearDown() override {
+               int ret = MTPR_ERROR_NONE;
+               mtpr_state_e state = MTPR_STATE_IDLE;
+               LOGD("Enter");
+
+               if (_mtpr) {
+                       ret = mtpr_get_state(_mtpr, &state);
+                       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+                       if (state != MTPR_STATE_IDLE) {
+                               ret = mtpr_stop(_mtpr);
+                               ASSERT_EQ(ret, MTPR_ERROR_NONE);
+                       }
+                       ret = mtpr_destroy(_mtpr);
+                       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+               }
+               LOGD("Leave");
+       }
+
+protected:
+       const std::string _senderPath = "rtsp://127.0.0.1:8554/test";
+};
+
+// MediaTransporterTestRtspReceiver
+
+TEST_F(MediaTransporterTestRtspReceiver, set_address_p)
+{
+       int ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, set_address_n1)
+{
+       int ret = MTPR_ERROR_NONE;
+
+       ret = mtpr_set_sender_address(NULL, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+       ret = mtpr_set_sender_address(_mtpr, NULL);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+       ret = mtpr_set_sender_address(NULL, NULL);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, set_address_n2)
+{
+       int ret = mtpr_set_receiver_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, get_address_p)
+{
+       int ret = MTPR_ERROR_NONE;
+       char *address = NULL;
+
+       ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_get_sender_address(_mtpr, &address);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+       ASSERT_TRUE(address);
+       ASSERT_STREQ(_senderPath.c_str(), address);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, get_address_n1)
+{
+       int ret = MTPR_ERROR_NONE;
+       char *address = NULL;
+
+       ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_get_sender_address(NULL, &address);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+       ret = mtpr_get_sender_address(_mtpr, NULL);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+       ret = mtpr_get_sender_address(NULL, NULL);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, get_address_n2)
+{
+       char *address = NULL;
+
+       int ret = mtpr_get_sender_address(_mtpr, &address);
+       ASSERT_EQ(ret, MTPR_ERROR_NO_DATA);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, get_address_n3)
+{
+       int ret = MTPR_ERROR_NONE;
+       char *address = NULL;
+
+       ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_get_receiver_address(_mtpr, &address);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, get_connection_type_p)
+{
+       mtpr_connection_type_e type;
+
+       int ret = mtpr_get_connection_type(_mtpr, &type);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+       ASSERT_EQ(type, MTPR_CONNECTION_TYPE_RTSP_RECEIVER);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, get_connection_type_n1)
+{
+       int ret = MTPR_ERROR_NONE;
+       mtpr_connection_type_e type;
+
+       ret = mtpr_get_connection_type(NULL, &type);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+       ret = mtpr_get_connection_type(_mtpr, NULL);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+       ret = mtpr_get_connection_type(NULL, NULL);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, start_n1)
+{
+       int ret = MTPR_ERROR_NONE;
+
+       ret = mtpr_start(_mtpr);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, start_n2)
+{
+       int ret = MTPR_ERROR_NONE;
+
+       ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_start(NULL);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, stop_n)
+{
+       int ret = mtpr_stop(_mtpr);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_STATE);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, get_state_p)
+{
+       mtpr_state_e state = MTPR_STATE_IDLE;
+
+       int ret = mtpr_get_state(_mtpr, &state);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+       ASSERT_EQ(state, MTPR_STATE_IDLE);
+}
+
+TEST_F(MediaTransporterTestRtspReceiver, get_state_n)
+{
+       int ret = MTPR_ERROR_NONE;
+       mtpr_state_e state = MTPR_STATE_IDLE;
+
+       ret = mtpr_get_state(NULL, &state);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+       ret = mtpr_get_state(_mtpr, NULL);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+       ret = mtpr_get_state(NULL, NULL);
+       ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+}
+
+
+// MediaTransporterTestRtspReceiverWithSender
+
+TEST_F(MediaTransporterTestRtspReceiverWithSender, start_p)
+{
+       int ret = MTPR_ERROR_NONE;
+
+       ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       std::promise<bool> p;
+       std::future<bool> f = p.get_future();
+       ret = mtpr_set_video_packet_cb(_mtpr, dataPacketCb, &p);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_start(_mtpr);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ASSERT_TRUE(waitDataPacket(f));
+
+       ret = mtpr_unset_video_packet_cb(_mtpr);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+}
+
+TEST_F(MediaTransporterTestRtspReceiverWithSender, stop_p)
+{
+       int ret = MTPR_ERROR_NONE;
+
+       ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_start(_mtpr);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       std::this_thread::sleep_for(std::chrono::seconds(1));
+
+       ret = mtpr_stop(_mtpr);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+}
+
+TEST_F(MediaTransporterTestRtspReceiverWithSender, get_state_p1)
+{
+       int ret = MTPR_ERROR_NONE;
+       mtpr_state_e state = MTPR_STATE_IDLE;
+
+       ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_start(_mtpr);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_get_state(_mtpr, &state);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+       ASSERT_EQ(state, MTPR_STATE_PLAYING);
+}
+
+TEST_F(MediaTransporterTestRtspReceiverWithSender, get_state_p2)
+{
+       int ret = MTPR_ERROR_NONE;
+       mtpr_state_e state = MTPR_STATE_IDLE;
+
+       ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_start(_mtpr);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_stop(_mtpr);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+       ret = mtpr_get_state(_mtpr, &state);
+       ASSERT_EQ(ret, MTPR_ERROR_NONE);
+       ASSERT_EQ(state, MTPR_STATE_IDLE);
+}
index bde70f5eaa42cc5206400adee53f36bcf99ac8f0..a3c55de364118a885ff853f2dd9f56737b0a8765 100644 (file)
 #include "ut_base.hpp"
 
 static GMainLoop* _mainloop;
+
+static void _clientConnectedCb(GstRTSPServer* server, GstRTSPClient* client)
+{
+       LOGD("client connected %p", client);
+}
+
 static void* _run_rtsp_server(void* ptr) {
-       GstRTSPServer* server;
-       GstRTSPMountPoints* mounts;
-       GstRTSPMediaFactory* factory;
 
        gst_init(NULL, NULL);
        _mainloop = g_main_loop_new(NULL, FALSE);
 
-       server = gst_rtsp_server_new();
-       g_object_set(server, "service", "8554", NULL);
-
-       mounts = gst_rtsp_server_get_mount_points(server);
+       GstRTSPServer* server = gst_rtsp_server_new();
+       gst_rtsp_server_set_address(server, "127.0.0.1");
+       gst_rtsp_server_set_service(server, "8554");
+       g_signal_connect(server, "client-connected", G_CALLBACK(_clientConnectedCb), NULL);
 
-       factory = gst_rtsp_media_factory_new();
+       GstRTSPMediaFactory* 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, "decodebin name=depay0 ! videoconvert ! tizenwlsink");
 
+       GstRTSPMountPoints* mounts = gst_rtsp_server_get_mount_points(server);
        gst_rtsp_mount_points_add_factory(mounts, "/test", factory);
-       g_object_unref(mounts);
 
-       gst_rtsp_server_attach(server, NULL);
+       unsigned int sourceId = gst_rtsp_server_attach(server, NULL);
 
        LOGD("server ready");
        g_main_loop_run(_mainloop);
@@ -48,6 +51,16 @@ static void* _run_rtsp_server(void* ptr) {
        LOGD("server terminated");
        g_main_loop_unref(_mainloop);
 
+       gst_rtsp_mount_points_remove_factory(mounts, "/test");
+       g_object_unref(mounts);
+
+       gst_rtsp_server_client_filter(server, NULL, NULL);
+
+       if (sourceId > 0)
+               g_source_remove(sourceId);
+
+       gst_object_unref(server);
+
        return NULL;
 }
 
index 612b66f7cea8c5ab085dc59a02d21863dfabd481..b06f7a4aadf8c133a477d289ba556467d7fcbf44 100644 (file)
@@ -47,9 +47,13 @@ static void dataPacketCb(mtpr_h mtpr, mtpr_media_type_e type,
                                                unsigned int id, media_packet_h packet, void *user_data) {
        LOGD("callback is invoked. type: %d, id: %d", type, id);
 
-       auto p = static_cast<std::promise<bool>*>(user_data);
-       assert(p);
-       p->set_value(true);
+       static std::once_flag flag;
+
+       std::call_once(flag, [&](){
+               auto p = static_cast<std::promise<bool>*>(user_data);
+               assert(p);
+               p->set_value(true);
+       });
 }
 
 static bool waitDataPacket(std::future<bool>& f) {
@@ -84,7 +88,6 @@ public:
                mtpr_state_e state = MTPR_STATE_IDLE;
 
                LOGD("Enter");
-               stop_srt_sender();
 
                if (_mtpr) {
                        ret = mtpr_get_state(_mtpr, &state);
@@ -98,6 +101,7 @@ public:
                        ASSERT_EQ(ret, MTPR_ERROR_NONE);
                }
 
+               stop_srt_sender();
                LOGD("Leave");
        }