2 * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "MediaTransporterConnectionStats.h"
20 #include "MediaTransporterLog.h"
22 using namespace tizen_media_transporter;
24 // AbstractConnectionStats
25 const GstStructure* AbstractConnectionStats::stats()
27 const GstStructure* structure = nullptr;
28 g_object_get(const_cast<GstElement*>(_element), "stats", &structure, NULL);
30 gchar* str = gst_structure_to_string(structure);
31 SECURE_LOG_DEBUG(">>> stats : %s", str);
37 gboolean AbstractConnectionStats::_statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData)
39 std::string fieldName = g_quark_to_string(fieldId);
41 auto [ callback, prop ] = *(static_cast<std::pair<IInvokable*, ConnectionStatPropMap>*>(userData));
43 auto propInfo = translateGvalue(val, prop, fieldName);
45 if (propInfo.has_value()) {
46 if (!callback || !callback->invokeReturn(propInfo.value())) {
47 LOG_WARNING("stop calling stats callback");
55 std::optional<mtprConnectionStatsPropInfo> AbstractConnectionStats::translateGvalue(const GValue* val,
56 const ConnectionStatPropMap& propList,
57 const std::string& fieldName)
59 g_autofree gchar* addr = NULL;
61 if (propList.find(fieldName) == propList.end()) {
62 LOG_DEBUG("not supported [%s]", fieldName.c_str());
66 mtprConnectionStatsProp prop = propList.at(fieldName);
68 switch (G_VALUE_TYPE(val)) {
69 case G_TYPE_BOOLEAN: {
70 gboolean result = g_value_get_boolean(val);
71 LOG_DEBUG("field[%s] GType[%s] value[%u]",
72 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
74 return mtprConnectionStatsPropInfo {
75 fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_BOOL, .v_bool = static_cast<bool>(result)
79 gint result = g_value_get_int(val);
80 LOG_DEBUG("field[%s] GType[%s] value[%d]",
81 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
83 return mtprConnectionStatsPropInfo {
84 fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_INT, .v_int = result
89 guint result = g_value_get_uint(val);
90 LOG_DEBUG("field[%s] GType[%s] value[%u]",
91 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
93 return mtprConnectionStatsPropInfo {
94 fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_UINT, .v_uint = result
98 gint64 result = g_value_get_int64(val);
99 LOG_DEBUG("field[%s] GType[%s] value[%" G_GINT64_FORMAT "]",
100 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
102 return mtprConnectionStatsPropInfo {
103 fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_INT64, .v_int64 = result
106 case G_TYPE_UINT64: {
107 guint64 result = g_value_get_uint64(val);
108 LOG_DEBUG("field[%s] GType[%s] value[%" G_GUINT64_FORMAT "]",
109 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
111 return mtprConnectionStatsPropInfo {
112 fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_UINT64, .v_uint64 = result
116 gfloat result = g_value_get_float(val);
117 LOG_DEBUG("field[%s] GType[%s] value[%f]",
118 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
120 return mtprConnectionStatsPropInfo {
121 fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_FLOAT, .v_float = result
124 case G_TYPE_DOUBLE: {
125 gdouble result = g_value_get_double(val);
126 LOG_DEBUG("field[%s] GType[%s] value[%f]",
127 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
129 return mtprConnectionStatsPropInfo {
130 fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_DOUBLE, .v_double = result
133 case G_TYPE_STRING: {
134 const gchar *result = g_value_get_string(val);
135 LOG_DEBUG("field[%s] GType[%s] value[%s]",
136 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), result);
138 return mtprConnectionStatsPropInfo {
139 fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_STRING, .v_string = result
143 if (G_VALUE_TYPE(val) == G_TYPE_SOCKET_ADDRESS) { /* non-constexpr : g_socket_address_get_type() */
144 addr = g_inet_address_to_string
145 (g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(g_value_get_object(val))));
146 LOG_DEBUG("field[%s] GType[%s] value[%s]",
147 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)), addr);
149 return mtprConnectionStatsPropInfo {
150 fieldName.c_str(), prop, MTPR_CONNECTION_STATS_PROP_TYPE_STRING, .v_string = addr
154 LOG_ERROR("invalid type, field[%s] GType[%s]",
155 fieldName.c_str(), g_type_name(G_VALUE_TYPE(val)));
161 // ConnectionStatsFactory
162 ForeachablePtr ConnectionStatsFactory::createReceiverSrtConnectionStats(const GstElement* element, InvokablePtr callback)
164 return ForeachablePtr(new ReceiverSrtConnectionStats(element, std::move(callback)));
167 ForeachablePtr ConnectionStatsFactory::createSenderSrtConnectionStats(const GstElement* element, InvokablePtr callback)
169 return ForeachablePtr(new SenderSrtConnectionStats(element, std::move(callback)));
172 // ReceiverSrtConnectionStats
173 ReceiverSrtConnectionStats::ReceiverSrtConnectionStats(const GstElement* element, InvokablePtr callback)
174 : AbstractConnectionStats(element, std::move(callback), {
175 { "packets-received", MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED },
176 { "packets-received-lost", MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED_LOST },
177 { "packets-received-rate-mbps", MTPR_CONNECTION_STATS_PROP_RECEIVED_RATE_MBPS },
178 { "negotiated-latency-ms", MTPR_CONNECTION_STATS_PROP_NEGOTIATED_LATENCY_MS },
179 { "bandwidth-mbps", MTPR_CONNECTION_STATS_PROP_BANDWIDTH_MPBS },
180 { "rtt-ms", MTPR_CONNECTION_STATS_PROP_RTT_MS },
181 { "bytes-received-total", MTPR_CONNECTION_STATS_PROP_BYTES_RECEIVED_TOTAL }
186 void ReceiverSrtConnectionStats::foreach()
188 const GstStructure* structure = stats();
189 auto userdata = std::make_pair(_callback.get(), _prop);
191 gst_structure_foreach(structure, _statsForeachCb, &userdata);
194 // SenderSrtConnectionStats
195 SenderSrtConnectionStats::SenderSrtConnectionStats(const GstElement* element, InvokablePtr callback)
196 : AbstractConnectionStats(element, std::move(callback), {
197 { "packets-sent", MTPR_CONNECTION_STATS_PROP_PACKET_SENT },
198 { "packets-sent-lost", MTPR_CONNECTION_STATS_PROP_PACKET_SENT_LOST },
199 { "send-rate-mbps", MTPR_CONNECTION_STATS_PROP_SEND_RATE_MPBS },
200 { "negotiated-latency-ms", MTPR_CONNECTION_STATS_PROP_NEGOTIATED_LATENCY_MS },
201 { "bandwidth-mbps", MTPR_CONNECTION_STATS_PROP_BANDWIDTH_MPBS },
202 { "rtt-ms", MTPR_CONNECTION_STATS_PROP_RTT_MS },
203 { "caller-address", MTPR_CONNECTION_STATS_PROP_CALLER_ADDRESS },
204 { "bytes-sent-total", MTPR_CONNECTION_STATS_PROP_BYTES_SENT_TOTAL }
209 void SenderSrtConnectionStats::foreach()
211 const GstStructure* structure = stats();
212 auto userdata = std::make_pair(_callback.get(), _prop);
213 gboolean ret = FALSE;
215 if (gst_structure_has_field(structure, "callers")) {
216 auto callers = static_cast<GValueArray *>(g_value_get_boxed(
217 gst_structure_get_value(structure, "callers")
220 LOG_DEBUG("SENDER >>> num of callers : %d", callers->n_values);
221 for (int i = 0; i < (int)callers->n_values; i++) {
222 const GstStructure* callerStats = (GstStructure *)g_value_get_boxed(&callers->values[i]);
224 LOG_DEBUG("SENDER >>> caller idx : %d", i);
225 ret = gst_structure_foreach(callerStats, _statsForeachCb, &userdata);
231 if (ret && gst_structure_has_field(structure, "bytes-sent-total")) {
232 auto propInfo = translateGvalue(gst_structure_get_value(structure, "bytes-sent-total"),
233 _prop, "bytes-sent-total");
234 if (propInfo.has_value()) {
235 if (!_callback || !_callback->invokeReturn(propInfo.value())) {
236 LOG_WARNING("stop calling stats callback");