[1.0.27] Add ConnectionStats abstraction 20/291420/9
authorSeungbae Shin <seungbae.shin@samsung.com>
Fri, 14 Apr 2023 10:40:16 +0000 (19:40 +0900)
committerSeungbae Shin <seungbae.shin@samsung.com>
Thu, 17 Aug 2023 07:47:59 +0000 (16:47 +0900)
Change-Id: Ie344b5e65a2d04db09214b5509b7ef6a9724a364

include/MediaTransporterCallback.h
include/MediaTransporterConnectionStats.h [new file with mode: 0644]
include/MediaTransporterReceiverSrt.h
include/MediaTransporterSenderSrt.h
packaging/capi-media-transporter.spec
src/MediaTransporterCallback.cpp
src/MediaTransporterConnectionStats.cpp [new file with mode: 0644]
src/MediaTransporterReceiverSrt.cpp
src/MediaTransporterSenderSrt.cpp

index 420a87d..41d72e7 100644 (file)
@@ -32,8 +32,9 @@ extern "C" {
 
 namespace tizen_media_transporter {
 
-using VariantData = std::variant<mtprError, media_packet_h, unsigned int, mtprMediaType,
-       mtprPacketSourceBufferState, std::string, const GValue*, std::map<std::string, mtprConnectionStatsProp>>;
+using VariantData = std::variant<mtprError, media_packet_h, unsigned int,
+                                                               mtprMediaType, mtprPacketSourceBufferState,
+                                                               mtprConnectionStatsPropInfo>;
 
 class IInvokable
 {
@@ -43,7 +44,7 @@ public:
        virtual void invoke() = 0;
        virtual void invoke(VariantData data) = 0;
        virtual void invoke(VariantData data1, VariantData data2) = 0;
-       virtual bool invoke(VariantData data1, VariantData data2, VariantData data3) = 0;
+       virtual bool invokeReturn(VariantData data) = 0;
 };
 
 class AbstractCallback : public IInvokable
@@ -56,7 +57,7 @@ public:
        void invoke() override {}
        void invoke(VariantData data) override {}
        void invoke(VariantData data1, VariantData data2) override {}
-       bool invoke(VariantData data1, VariantData data2, VariantData data3) override { return TRUE; }
+       bool invokeReturn(VariantData data) override { return false; }
 
 protected:
        void* _handle;
@@ -142,7 +143,7 @@ public:
        ConnectionStatsCallback(void* handle, mtprConnectionStatsCallback cb, void* userdata);
        virtual ~ConnectionStatsCallback() = default;
 
-       bool invoke(VariantData data1, VariantData data2, VariantData data3) override;
+       bool invokeReturn(VariantData data) override;
 
 private:
        mtprConnectionStatsCallback _callback;
diff --git a/include/MediaTransporterConnectionStats.h b/include/MediaTransporterConnectionStats.h
new file mode 100644 (file)
index 0000000..39b07bd
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+* Copyright (c) 2023 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_CONNECTION_STATS_H__
+#define __TIZEN_MEDIA_TRANSPORTER_CONNECTION_STATS_H__
+
+#include <variant>
+#include <memory>
+#include <map>
+#include <glib-object.h>
+
+#include "MediaTransporter.h"
+#include "MediaTransporterCallback.h"
+#include "MediaTransporterGst.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+namespace tizen_media_transporter {
+
+using ConnectionStatPropMap = std::map<std::string, mtprConnectionStatsProp>;
+
+class IForeachable
+{
+public:
+       virtual ~IForeachable() = default;
+
+       virtual void foreach() = 0;
+};
+
+class AbstractConnectionStats : public IForeachable
+{
+public:
+       AbstractConnectionStats(const GstElement* element, InvokablePtr callback, const ConnectionStatPropMap& prop)
+               : _element(element),  _callback(std::move(callback)), _prop(prop) {}
+       virtual ~AbstractConnectionStats() = default;
+
+protected:
+       const GstStructure* stats();
+
+       static gboolean _statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData);
+       static std::optional<mtprConnectionStatsPropInfo> translateGvalue(const GValue* val,
+                                                                                                                                       const ConnectionStatPropMap& propList,
+                                                                                                                                       const std::string& fieldName);
+
+       const GstElement* _element { nullptr };
+       InvokablePtr _callback;
+       ConnectionStatPropMap _prop;
+};
+
+using ForeachablePtr = std::unique_ptr<IForeachable>;
+
+struct ConnectionStatsFactory
+{
+       static ForeachablePtr createReceiverSrtConnectionStats(const GstElement* element, InvokablePtr callback);
+       static ForeachablePtr createSenderSrtConnectionStats(const GstElement* element, InvokablePtr callback);
+};
+
+class ReceiverSrtConnectionStats : public AbstractConnectionStats
+{
+public:
+       ReceiverSrtConnectionStats(const GstElement* element, InvokablePtr callback);
+       virtual ~ReceiverSrtConnectionStats() = default;
+
+       void foreach() override;
+};
+
+class SenderSrtConnectionStats : public AbstractConnectionStats
+{
+public:
+       SenderSrtConnectionStats(const GstElement* element, InvokablePtr callback);
+       virtual ~SenderSrtConnectionStats() = default;
+
+       void foreach() override;
+};
+
+} // namespace
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIA_TRANSPORTER_CONNECTION_STATS_H__ */
\ No newline at end of file
index a0d1d3a..741e5c8 100644 (file)
@@ -51,7 +51,6 @@ public:
 private:
        static void _demuxPadAddedCallback(GstElement* demux, GstPad* new_pad, gpointer userData);
        static void _demuxNoMorePadsCallback(GstElement* demux, gpointer userData);
-       static gboolean _statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData);
 
        param::srt::connectionParam _connectionParam;
        std::string _senderAddress;
index bf9e32e..78d0d9f 100644 (file)
@@ -54,7 +54,6 @@ private:
        void stopStatsMonitoring();
        static gpointer _statsMonitorThread(gpointer userData);
        static gpointer _updateStats(gpointer userData);
-       static gboolean _statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData);
 
        struct stats {
                gint64 packetsSent { 0 };
index 3cf03e4..0d5a0bc 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-transporter
 Summary:    A Media Transporter library in Tizen Native API
-Version:    1.0.26
+Version:    1.0.27
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index aea26ae..fadb499 100644 (file)
@@ -144,128 +144,12 @@ ConnectionStatsCallback::ConnectionStatsCallback(void* handle, mtprConnectionSta
                        cb, handle, userdata);
 }
 
-bool ConnectionStatsCallback::invoke(VariantData data1, VariantData data2, VariantData data3)
+bool ConnectionStatsCallback::invokeReturn(VariantData data)
 {
-       auto fieldName = std::get<std::string>(data1);
-       auto val = std::get<const GValue*>(data2);
-       auto propList = std::get<std::map<std::string, mtprConnectionStatsProp>>(data3);
-       g_autofree gchar* addr = NULL;
-
-       if (propList.find(fieldName) == propList.end()) {
-               LOG_DEBUG("not supported [%s]", fieldName.c_str());
-               return true;
-       }
-
-       mtprConnectionStatsProp prop = propList.at(fieldName);
-
-       switch (G_VALUE_TYPE(val)) {
-       case G_TYPE_BOOLEAN: {
-               gboolean result = g_value_get_boolean(val);
-               LOG_DEBUG("field[%s] GType[%s] value[%u]",
-                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
-
-               mtprConnectionStatsPropInfo propInfo {
-                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_BOOL, .v_bool = static_cast<bool>(result)
-               };
-
-               return _callback(_handle, &propInfo, _userdata);
-       }
-       case G_TYPE_INT: {
-               gint result = g_value_get_int(val);
-               LOG_DEBUG("field[%s] GType[%s] value[%d]",
-                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
-
-               mtprConnectionStatsPropInfo propInfo {
-                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_INT, .v_int = result
-               };
-
-               return _callback(_handle, &propInfo, _userdata);
-       }
-       case G_TYPE_UINT: {
-               guint result = g_value_get_uint(val);
-               LOG_DEBUG("field[%s] GType[%s] value[%u]",
-                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
-
-               mtprConnectionStatsPropInfo propInfo {
-                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_UINT, .v_uint = result
-               };
-
-               return _callback(_handle, &propInfo, _userdata);
-       }
-       case G_TYPE_INT64: {
-               gint64 result = g_value_get_int64(val);
-               LOG_DEBUG("field[%s] GType[%s] value[%" G_GINT64_FORMAT "]",
-                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
-
-               mtprConnectionStatsPropInfo propInfo {
-                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_INT64, .v_int64 = result
-               };
-
-               return _callback(_handle, &propInfo, _userdata);
-       }
-       case G_TYPE_UINT64: {
-               guint64 result = g_value_get_uint64(val);
-               LOG_DEBUG("field[%s] GType[%s] value[%" G_GUINT64_FORMAT "]",
-                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
-
-               mtprConnectionStatsPropInfo propInfo {
-                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_UINT64, .v_uint64 = result
-               };
-
-               return _callback(_handle, &propInfo, _userdata);
-       }
-       case G_TYPE_FLOAT: {
-               gfloat result = g_value_get_float(val);
-               LOG_DEBUG("field[%s] GType[%s] value[%f]",
-                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
-
-               mtprConnectionStatsPropInfo propInfo {
-                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_FLOAT, .v_float = result
-               };
-
-               return _callback(_handle, &propInfo, _userdata);
-       }
-       case G_TYPE_DOUBLE: {
-               gdouble result = g_value_get_double(val);
-               LOG_DEBUG("field[%s] GType[%s] value[%f]",
-                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
-
-               mtprConnectionStatsPropInfo propInfo {
-                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_DOUBLE, .v_double = result
-               };
-
-               return _callback(_handle, &propInfo, _userdata);
-       }
-       case G_TYPE_STRING: {
-               const gchar *result = g_value_get_string(val);
-               LOG_DEBUG("field[%s] GType[%s] value[%s]",
-                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
-
-               mtprConnectionStatsPropInfo propInfo {
-                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_STRING, .v_string = result
-               };
-
-               return _callback(_handle, &propInfo, _userdata);
-       }
-       default:
-               if (G_VALUE_TYPE(val) == G_TYPE_SOCKET_ADDRESS) { /* non-constexpr : g_socket_address_get_type() */
-                       addr = g_inet_address_to_string
-                               (g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(g_value_get_object(val))));
-                       LOG_DEBUG("field[%s] GType[%s] value[%s]",
-                               fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), addr);
-
-                       mtprConnectionStatsPropInfo propInfo {
-                               fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_STRING, .v_string = addr
-                       };
-
-                       return _callback(_handle, &propInfo, _userdata);
-               }
-
-               LOG_ERROR("invalid type, field[%s] GType[%s]",
-                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)));
-
-               break;
-       }
-
-       return true;
-}
\ No newline at end of file
+       auto prop = std::get<mtprConnectionStatsPropInfo>(data);
+
+       LOG_DEBUG(">>> callback[%p], handle[%p], prop[%p], user_data[%p]",
+                       _callback, _handle, &prop, _userdata);
+
+       return _callback(_handle, &prop, _userdata);
+}
diff --git a/src/MediaTransporterConnectionStats.cpp b/src/MediaTransporterConnectionStats.cpp
new file mode 100644 (file)
index 0000000..46964ca
--- /dev/null
@@ -0,0 +1,241 @@
+/**
+ * Copyright (c) 2023 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 <gio/gio.h>
+
+#include "MediaTransporterConnectionStats.h"
+#include "MediaTransporterLog.h"
+
+using namespace tizen_media_transporter;
+
+// AbstractConnectionStats
+const GstStructure* AbstractConnectionStats::stats()
+{
+       const GstStructure* structure = nullptr;
+       g_object_get(const_cast<GstElement*>(_element), "stats", &structure, NULL);
+
+       gchar* str = gst_structure_to_string(structure);
+       SECURE_LOG_DEBUG(">>> stats : %s", str);
+       g_free(str);
+
+       return structure;
+}
+
+gboolean AbstractConnectionStats::_statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData)
+{
+       std::string fieldName = g_quark_to_string(fieldId);
+
+       auto [ callback, prop ] = *(static_cast<std::pair<IInvokable*, ConnectionStatPropMap>*>(userData));
+
+       auto propInfo = translateGvalue(val, prop, fieldName);
+
+       if (propInfo.has_value()) {
+               if (!callback || !callback->invokeReturn(propInfo.value())) {
+                       LOG_WARNING("stop calling stats callback");
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+std::optional<mtprConnectionStatsPropInfo> AbstractConnectionStats::translateGvalue(const GValue* val,
+                                                                                                                                                       const ConnectionStatPropMap& propList,
+                                                                                                                                                       const std::string& fieldName)
+{
+       g_autofree gchar* addr = NULL;
+
+       if (propList.find(fieldName) == propList.end()) {
+               LOG_DEBUG("not supported [%s]", fieldName.c_str());
+               return std::nullopt;
+       }
+
+       mtprConnectionStatsProp prop = propList.at(fieldName);
+
+       switch (G_VALUE_TYPE(val)) {
+       case G_TYPE_BOOLEAN: {
+               gboolean result = g_value_get_boolean(val);
+               LOG_DEBUG("field[%s] GType[%s] value[%u]",
+                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
+
+               return mtprConnectionStatsPropInfo {
+                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_BOOL, .v_bool = static_cast<bool>(result)
+               };
+       }
+       case G_TYPE_INT: {
+               gint result = g_value_get_int(val);
+               LOG_DEBUG("field[%s] GType[%s] value[%d]",
+                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
+
+               return mtprConnectionStatsPropInfo {
+                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_INT, .v_int = result
+               };
+
+       }
+       case G_TYPE_UINT: {
+               guint result = g_value_get_uint(val);
+               LOG_DEBUG("field[%s] GType[%s] value[%u]",
+                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
+
+               return mtprConnectionStatsPropInfo {
+                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_UINT, .v_uint = result
+               };
+       }
+       case G_TYPE_INT64: {
+               gint64 result = g_value_get_int64(val);
+               LOG_DEBUG("field[%s] GType[%s] value[%" G_GINT64_FORMAT "]",
+                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
+
+               return mtprConnectionStatsPropInfo {
+                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_INT64, .v_int64 = result
+               };
+       }
+       case G_TYPE_UINT64: {
+               guint64 result = g_value_get_uint64(val);
+               LOG_DEBUG("field[%s] GType[%s] value[%" G_GUINT64_FORMAT "]",
+                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
+
+               return mtprConnectionStatsPropInfo {
+                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_UINT64, .v_uint64 = result
+               };
+       }
+       case G_TYPE_FLOAT: {
+               gfloat result = g_value_get_float(val);
+               LOG_DEBUG("field[%s] GType[%s] value[%f]",
+                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
+
+               return mtprConnectionStatsPropInfo {
+                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_FLOAT, .v_float = result
+               };
+       }
+       case G_TYPE_DOUBLE: {
+               gdouble result = g_value_get_double(val);
+               LOG_DEBUG("field[%s] GType[%s] value[%f]",
+                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
+
+               return mtprConnectionStatsPropInfo {
+                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_DOUBLE, .v_double = result
+               };
+       }
+       case G_TYPE_STRING: {
+               const gchar *result = g_value_get_string(val);
+               LOG_DEBUG("field[%s] GType[%s] value[%s]",
+                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
+
+               return mtprConnectionStatsPropInfo {
+                       fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_STRING, .v_string = result
+               };
+       }
+       default:
+               if (G_VALUE_TYPE(val) == G_TYPE_SOCKET_ADDRESS) { /* non-constexpr : g_socket_address_get_type() */
+                       addr = g_inet_address_to_string
+                               (g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(g_value_get_object(val))));
+                       LOG_DEBUG("field[%s] GType[%s] value[%s]",
+                               fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), addr);
+
+                       return mtprConnectionStatsPropInfo {
+                               fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_STRING, .v_string = addr
+                       };
+               }
+
+               LOG_ERROR("invalid type, field[%s] GType[%s]",
+                       fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)));
+
+               return std::nullopt;
+       }
+}
+
+// ConnectionStatsFactory
+ForeachablePtr ConnectionStatsFactory::createReceiverSrtConnectionStats(const GstElement* element, InvokablePtr callback)
+{
+       return ForeachablePtr(new ReceiverSrtConnectionStats(element, std::move(callback)));
+}
+
+ForeachablePtr ConnectionStatsFactory::createSenderSrtConnectionStats(const GstElement* element, InvokablePtr callback)
+{
+       return ForeachablePtr(new SenderSrtConnectionStats(element, std::move(callback)));
+}
+
+// ReceiverSrtConnectionStats
+ReceiverSrtConnectionStats::ReceiverSrtConnectionStats(const GstElement* element, InvokablePtr callback)
+       : AbstractConnectionStats(element, std::move(callback), {
+               { "packets-received", MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED },
+               { "packets-received-lost", MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED_LOST },
+               { "packets-received-rate-mbps", MTPR_CONNECTION_STATS_PROP_RECEIVED_RATE_MBPS },
+               { "negotiated-latency-ms", MTPR_CONNECTION_STATS_PROP_NEGOTIATED_LATENCY_MS },
+               { "bandwidth-mbps", MTPR_CONNECTION_STATS_PROP_BANDWIDTH_MPBS },
+               { "rtt-ms", MTPR_CONNECTION_STATS_PROP_RTT_MS },
+               { "bytes-received-total", MTPR_CONNECTION_STATS_PROP_BYTES_RECEIVED_TOTAL }
+       })
+{
+}
+
+void ReceiverSrtConnectionStats::foreach()
+{
+       const GstStructure* structure = stats();
+       auto userdata = std::make_pair(_callback.get(), _prop);
+
+       gst_structure_foreach(structure, _statsForeachCb, &userdata);
+}
+
+// SenderSrtConnectionStats
+SenderSrtConnectionStats::SenderSrtConnectionStats(const GstElement* element, InvokablePtr callback)
+       : AbstractConnectionStats(element, std::move(callback), {
+               { "packets-sent", MTPR_CONNECTION_STATS_PROP_PACKET_SENT },
+               { "packets-sent-lost", MTPR_CONNECTION_STATS_PROP_PACKET_SENT_LOST },
+               { "send-rate-mbps", MTPR_CONNECTION_STATS_PROP_SEND_RATE_MPBS },
+               { "negotiated-latency-ms", MTPR_CONNECTION_STATS_PROP_NEGOTIATED_LATENCY_MS },
+               { "bandwidth-mbps", MTPR_CONNECTION_STATS_PROP_BANDWIDTH_MPBS },
+               { "rtt-ms", MTPR_CONNECTION_STATS_PROP_RTT_MS },
+               { "caller-address", MTPR_CONNECTION_STATS_PROP_CALLER_ADDRESS },
+               { "bytes-sent-total", MTPR_CONNECTION_STATS_PROP_BYTES_SENT_TOTAL }
+       })
+{
+}
+
+void SenderSrtConnectionStats::foreach()
+{
+       const GstStructure* structure = stats();
+       auto userdata = std::make_pair(_callback.get(), _prop);
+       gboolean ret = FALSE;
+
+       if (gst_structure_has_field(structure, "callers")) {
+               auto callers = static_cast<GValueArray *>(g_value_get_boxed(
+                       gst_structure_get_value(structure, "callers")
+               ));
+
+               LOG_DEBUG("SENDER >>> num of callers : %d", callers->n_values);
+               for (int i = 0; i < (int)callers->n_values; i++) {
+                       const GstStructure* callerStats = (GstStructure *)g_value_get_boxed(&callers->values[i]);
+
+                       LOG_DEBUG("SENDER >>> caller idx : %d", i);
+                       ret = gst_structure_foreach(callerStats, _statsForeachCb, &userdata);
+                       if (!ret)
+                               break;
+               }
+       }
+
+       if (ret && gst_structure_has_field(structure, "bytes-sent-total")) {
+               auto propInfo = translateGvalue(gst_structure_get_value(structure, "bytes-sent-total"),
+                                                               _prop, "bytes-sent-total");
+               if (propInfo.has_value()) {
+                       if (!_callback || !_callback->invokeReturn(propInfo.value())) {
+                               LOG_WARNING("stop calling stats callback");
+                               return;
+                       }
+               }
+       }
+}
index 5b61a0c..9ac843b 100644 (file)
 #include "MediaTransporterGst.h"
 #include "MediaTransporterLog.h"
 #include "MediaTransporterUtil.h"
+#include "MediaTransporterConnectionStats.h"
 #include <cassert>
 
 using namespace tizen_media_transporter;
 using namespace tizen_media_transporter::param::srt;
 
-static const std::map<std::string, mtprConnectionStatsProp> __receiverProp = {
-       { "packets-received", MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED },
-       { "packets-received-lost", MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED_LOST },
-       { "packets-received-rate-mbps", MTPR_CONNECTION_STATS_PROP_RECEIVED_RATE_MBPS },
-       { "negotiated-latency-ms", MTPR_CONNECTION_STATS_PROP_NEGOTIATED_LATENCY_MS },
-       { "bandwidth-mbps", MTPR_CONNECTION_STATS_PROP_BANDWIDTH_MPBS },
-       { "rtt-ms", MTPR_CONNECTION_STATS_PROP_RTT_MS },
-       { "bytes-received-total", MTPR_CONNECTION_STATS_PROP_BYTES_RECEIVED_TOTAL }};
-
 MediaTransporterReceiverSrt::MediaTransporterReceiverSrt()
 {
        LOG_DEBUG("ctor: %p", this);
@@ -169,29 +161,7 @@ void MediaTransporterReceiverSrt::setSenderAddress(std::string address)
        _senderAddress = address;
 }
 
-gboolean MediaTransporterReceiverSrt::_statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData)
-{
-       auto callback = static_cast<IInvokable*>(userData);
-       std::string fieldName = g_quark_to_string(fieldId);
-
-       if (!callback ||
-               !callback->invoke(fieldName, val, __receiverProp)) {
-               LOG_WARNING("stop calling stats callback");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
 void MediaTransporterReceiverSrt::foreachConnectionStats(InvokablePtr callback)
 {
-       GstStructure* structure = nullptr;
-
-       g_object_get(_srtSrc, "stats", &structure, NULL);
-
-       gchar* str = gst_structure_to_string(structure);
-       SECURE_LOG_DEBUG("RECEIVER >>> stats : %s", str);
-       g_free(str);
-
-       gst_structure_foreach(structure, _statsForeachCb, callback.get());
+       ConnectionStatsFactory::createReceiverSrtConnectionStats(_srtSrc, std::move(callback))->foreach();
 }
\ No newline at end of file
index e595073..80c815c 100644 (file)
 #include "MediaTransporterLog.h"
 #include "MediaTransporterUtil.h"
 #include "MediaTransporterParseIni.h"
+#include "MediaTransporterConnectionStats.h"
 
 using namespace tizen_media_transporter;
 using namespace tizen_media_transporter::param::srt;
 
 constexpr unsigned int STATS_UPDATE_INTERVAL = 1000;
 
-static const std::map<std::string, mtprConnectionStatsProp> __senderProp = {
-       { "packets-sent", MTPR_CONNECTION_STATS_PROP_PACKET_SENT },
-       { "packets-sent-lost", MTPR_CONNECTION_STATS_PROP_PACKET_SENT_LOST },
-       { "send-rate-mbps", MTPR_CONNECTION_STATS_PROP_SEND_RATE_MPBS },
-       { "negotiated-latency-ms", MTPR_CONNECTION_STATS_PROP_NEGOTIATED_LATENCY_MS },
-       { "bandwidth-mbps", MTPR_CONNECTION_STATS_PROP_BANDWIDTH_MPBS },
-       { "rtt-ms", MTPR_CONNECTION_STATS_PROP_RTT_MS },
-       { "caller-address", MTPR_CONNECTION_STATS_PROP_CALLER_ADDRESS },
-       { "bytes-sent-total", MTPR_CONNECTION_STATS_PROP_BYTES_SENT_TOTAL }};
-
 static void __callerAddedCb(GstElement* element, gint socket, GSocketAddress* address, gpointer userData)
 {
        g_autofree gchar* ip_addr = g_inet_address_to_string(g_inet_socket_address_get_address((GInetSocketAddress*)address));
@@ -240,47 +231,7 @@ void MediaTransporterSenderSrt::setSenderAddress(std::string address)
        _senderAddress = address;
 }
 
-gboolean MediaTransporterSenderSrt::_statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData)
-{
-       auto callback = static_cast<IInvokable*>(userData);
-       std::string fieldName = g_quark_to_string(fieldId);
-
-       if (!callback ||
-               !callback->invoke(fieldName, val, __senderProp)) {
-               LOG_WARNING("stop calling stats callback");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
 void MediaTransporterSenderSrt::foreachConnectionStats(InvokablePtr callback)
 {
-       const GstStructure* structure = NULL;
-
-       g_object_get(_srtSink, "stats", &structure, NULL);
-       gchar* str = gst_structure_to_string(structure);
-       SECURE_LOG_DEBUG("SENDER >>> stats : %s", str);
-       g_free(str);
-
-       gboolean ret = FALSE;
-
-       if (gst_structure_has_field(structure, "callers")) {
-               GValueArray* callers = (GValueArray *)g_value_get_boxed(gst_structure_get_value(structure, "callers"));
-
-               LOG_DEBUG("SENDER >>> num of callers : %d", callers->n_values);
-               for (int i = 0; i < (int)callers->n_values; i++) {
-                       const GstStructure* callerStats = (GstStructure *)g_value_get_boxed(&callers->values[i]);
-
-                       LOG_DEBUG("SENDER >>> caller idx : %d", i);
-                       ret = gst_structure_foreach(callerStats, _statsForeachCb, callback.get());
-                       if (!ret)
-                               break;
-               }
-       }
-
-       if (ret && gst_structure_has_field(structure, "bytes-sent-total"))
-               callback->invoke("bytes-sent-total",
-                               gst_structure_get_value(structure, "bytes-sent-total"), __senderProp);
-
+       ConnectionStatsFactory::createSenderSrtConnectionStats(_srtSink, std::move(callback))->foreach();
 }