using mtprMediaType = mtpr_media_type_e;
using mtprSourceAudioFormat = mtpr_source_audio_format_e;
using mtprState = mtpr_state_e;
+using mtprError = mtpr_error_e;
using mtprPacketSourceBufferState = mtpr_media_packet_source_buffer_state_e;
+using mtprConnectionStatsProp = mtpr_connection_stats_prop_e;
+using mtprConnectionStatsPropInfo = mtpr_connection_stats_prop_info_s;
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 mtprPacketSourceBufferStateCallback = mtpr_media_packet_source_buffer_state_changed_cb;
-using mtprError = mtpr_error_e;
+using mtprConnectionStatsCallback = mtpr_connection_stats_cb;
using mtprDisplayType = mtpr_display_type_e;
using mtprDisplayMode = mtpr_display_mode_e;
virtual void setConnection(std::string name, std::string value);
virtual std::string getConnection(std::string name);
+ virtual void foreachConnectionStats(void* handle, mtprConnectionStatsCallback callback, void* userData);
+
void setResourceManager(std::shared_ptr<MediaTransporterResource> resourceManager);
void changed() override; // resource interrupted
protected:
mtprGstreamer _gst {};
std::unique_ptr<IInvokable> _errorCallback;
+ std::unique_ptr<IInvokable> _connectionStatsCallback;
std::shared_ptr<MediaTransporterResource> _resourceManager;
private:
#include <variant>
#include <memory>
#include <media_packet.h>
+#include <map>
+#include <glib-object.h>
#include "MediaTransporter.h"
namespace tizen_media_transporter {
-using VariantData = std::variant<mtprError, media_packet_h, unsigned int, mtprMediaType, mtprPacketSourceBufferState>;
+using VariantData = std::variant<mtprError, media_packet_h, unsigned int, mtprMediaType,
+ mtprPacketSourceBufferState, std::string, const GValue*, std::map<std::string, mtprConnectionStatsProp>>;
class IInvokable
{
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;
};
class AbstractCallback : public IInvokable
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; }
protected:
void* _handle;
mtprPacketSourceBufferStateCallback _callback;
};
+class ConnectionStatsCallback : public AbstractCallback
+{
+public:
+ ConnectionStatsCallback(void* handle, mtprConnectionStatsCallback cb, void* userdata);
+ virtual ~ConnectionStatsCallback() = default;
+
+ bool invoke(VariantData data1, VariantData data2, VariantData data3) override;
+
+private:
+ mtprConnectionStatsCallback _callback;
+};
+
} // namespace
#ifdef __cplusplus
std::string getSenderAddress() override { return _senderAddress; }
mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_SRT_RECEIVER; }
+ void foreachConnectionStats(void* handle, mtprConnectionStatsCallback callback, void* userData) override;
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;
+ GstElement* _srtSrc { nullptr };
};
} // namespace
mtprConnectionType type() override { return MTPR_CONNECTION_TYPE_SRT_SENDER; }
+ void foreachConnectionStats(void* handle, mtprConnectionStatsCallback callback, void* userData) override;
+
private:
void startStatsMonitoring();
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 };
} mtpr_media_packet_source_buffer_state_e;
/**
+ * @brief Enumeration for Media Transporter connection statistics property.
+ * @since_tizen 7.5
+ */
+typedef enum {
+ /* sender */
+ MTPR_CONNECTION_STATS_PROP_PACKET_SENT,
+ MTPR_CONNECTION_STATS_PROP_PACKET_SENT_LOST,
+ MTPR_CONNECTION_STATS_PROP_SEND_RATE_MPBS,
+ MTPR_CONNECTION_STATS_PROP_CALLER_ADDRESS,
+ MTPR_CONNECTION_STATS_PROP_BYTES_SENT_TOTAL,
+ /* receiver */
+ MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED,
+ MTPR_CONNECTION_STATS_PROP_PACKET_RECEIVED_LOST,
+ MTPR_CONNECTION_STATS_PROP_RECEIVED_RATE_MBPS,
+ MTPR_CONNECTION_STATS_PROP_BYTES_RECEIVED_TOTAL,
+ /* common */
+ MTPR_CONNECTION_STATS_PROP_NEGOTIATED_LATENCY_MS,
+ MTPR_CONNECTION_STATS_PROP_BANDWIDTH_MPBS,
+ MTPR_CONNECTION_STATS_PROP_RTT_MS,
+} mtpr_connection_stats_prop_e;
+
+/**
+ * @brief Enumeration for connection statistics property data type.
+ * @since_tizen 7.5
+ */
+typedef enum {
+ MTPR_CONNECTION_STATS_PROP_TYPE_BOOL, /**< Boolean type */
+ MTPR_CONNECTION_STATS_PROP_TYPE_INT, /**< Signed integer type */
+ MTPR_CONNECTION_STATS_PROP_TYPE_UINT, /**< Unsigned integer type */
+ MTPR_CONNECTION_STATS_PROP_TYPE_INT64, /**< 64-bit signed integer type */
+ MTPR_CONNECTION_STATS_PROP_TYPE_UINT64, /**< 64-bit unsigned integer type */
+ MTPR_CONNECTION_STATS_PROP_TYPE_FLOAT, /**< Float type */
+ MTPR_CONNECTION_STATS_PROP_TYPE_DOUBLE, /**< Double type */
+ MTPR_CONNECTION_STATS_PROP_TYPE_STRING, /**< String type */
+} mtpr_connection_stats_prop_type_e;
+
+/**
+ * @brief The structure type for connection statistics property information.
+ * @since_tizen 7.5
+ */
+typedef struct {
+ const char *name; /**< The property name */
+ mtpr_connection_stats_prop_e prop; /**< The property enum */
+ mtpr_connection_stats_prop_type_e type; /**< The property data type */
+ /** The property value as per the data type above */
+ union {
+ bool v_bool; /**< For boolean */
+ int v_int; /**< For signed integer */
+ unsigned int v_uint; /**< For unsigned integer */
+ int64_t v_int64; /**< For 64-bit signed integer */
+ uint64_t v_uint64; /**< For 64-bit unsigned integer */
+ float v_float; /**< For float */
+ double v_double; /**< For double */
+ const char *v_string; /**< For string */
+ };
+} mtpr_connection_stats_prop_info_s;
+
+/**
* @brief Definition for mode parameter of SRT.
* @details The connection mode of SRT.\n
0: not connected.\n
typedef void (*mtpr_media_packet_source_buffer_state_changed_cb)(unsigned int source_id, mtpr_media_packet_source_buffer_state_e state, void *user_data);
/**
+ * @brief Called iteratively to report the connection statistics properties.
+ * @since_tizen 7.5
+ * @remarks The @a prop_info can be used only in the callback. To use outside, make a copy.
+ * @param[in] mtpr Media Transporter handle
+ * @param[in] prop_info The connection statistics property information
+ * @param[in] user_data The user data passed from the callback registration function
+ * @return @c true to continue with the next iteration of the loop,
+ * otherwise @c false to break out of the loop
+ * @see mtpr_foreach_connection_stats()
+ * @par Example
+ * @code
+ bool __connection_stats_cb(mtpr_h mtpr, const mtpr_connection_stats_prop_info_s *prop_info, void *user_data)
+ {
+ switch (prop_info->type) {
+ case MTPR_CONNECTION_STATS_PROP_TYPE_BOOL:
+ printf("type[0x%x] prop[%s, 0x%08x, value:%d]\n", type, prop_info->name, prop_info->prop, prop_info->v_bool);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_INT:
+ printf("type[0x%x] prop[%s, 0x%08x, value:%d]\n", type, prop_info->name, prop_info->prop, prop_info->v_int);
+ break;
+ default:
+ printf("no need more stats info");
+ return false;
+ }
+ return true;
+ }
+ * @endcode
+ */
+typedef bool (*mtpr_connection_stats_cb)(mtpr_h mtpr, const mtpr_connection_stats_prop_info_s *prop_info, void *user_data);
+
+/**
* @brief Creates an instance of Media Transporter.
* @since_tizen 7.0
* @privlevel public
int mtpr_unset_video_packet_cb(mtpr_h mtpr);
/**
+ * @brief Retrieves the connection statistics properties.
+ * @since_tizen 7.5
+ * @remarks The registered callback will be invoked in an internal thread.
+ * @remarks If current connection type does not support this api,
+ * #MTPR_ERROR_INVALID_OPERATION will be return.
+ * @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_OPERATION Invalid operation
+ * @retval #MTPR_ERROR_INVALID_STATE Invalid state
+ * @pre @a mtpr state must not be set to #MTPR_STATE_IDLE.
+ * @post mtpr_connection_stats_cb() will be invoked.
+ */
+int mtpr_foreach_connection_stats(mtpr_h mtpr, mtpr_connection_stats_cb callback, void *user_data);
+
+/**
* @}
*/
Name: capi-media-transporter
Summary: A Media Transporter library in Tizen Native API
-Version: 1.0.21
+Version: 1.0.22
Release: 0
Group: Multimedia/API
License: Apache-2.0
return MTPR_ERROR_NONE;
}
+
+int mtpr_foreach_connection_stats(mtpr_h mtpr, mtpr_connection_stats_cb callback, void *user_data)
+{
+ RET_ERR_IF_INVALID_INSTANCE(mtpr);
+ RET_ERR_IF_NULL_ARG(callback);
+
+ try {
+ auto handle = static_cast<media_transporter_s*>(mtpr);
+ assert(handle->base);
+
+ if (handle->base->state() == MTPR_STATE_IDLE)
+ throw MediaTransporterException(MTPR_ERROR_INVALID_STATE, "state must not be IDLE");
+
+ handle->base->foreachConnectionStats(mtpr, callback, user_data);
+ } catch (const MediaTransporterException& e) {
+ LOG_ERROR("Failed to foreach connection statistics!!! : %s", e.what());
+ return e.error();
+ }
+
+ return MTPR_ERROR_NONE;
+}
\ No newline at end of file
_errorCallback = nullptr;
}
+void MediaTransporterBase::foreachConnectionStats(void* handle, mtprConnectionStatsCallback callback, void* userData)
+{
+ throw MediaTransporterException(MTPR_ERROR_INVALID_OPERATION, "not supported");
+}
+
void MediaTransporterBase::setResourceManager(std::shared_ptr<MediaTransporterResource> resourceManager)
{
_resourceManager = resourceManager;
* limitations under the License.
*/
+#include <gio/gio.h>
#include "MediaTransporterCallback.h"
#include "MediaTransporterLog.h"
_callback, _handle, sourceId, state, _userdata);
_callback(sourceId, state, _userdata);
+}
+
+ConnectionStatsCallback::ConnectionStatsCallback(void* handle, mtprConnectionStatsCallback cb, void* userdata)
+ : AbstractCallback(handle, userdata), _callback(cb)
+{
+ LOG_DEBUG(">>> callback[%p], handle[%p], user_data[%p] registered",
+ cb, handle, userdata);
+}
+
+bool ConnectionStatsCallback::invoke(VariantData data1, VariantData data2, VariantData data3)
+{
+ 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
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);
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");
+ _srtSrc = src;
} catch (const MediaTransporterException& e) {
LOG_ERROR("%s", e.what());
{
gst::_setPipelineState(_gst.pipeline, GST_STATE_NULL,
MediaTransporterIni::get().general().timeout);
+ _srtSrc = NULL;
}
void MediaTransporterReceiverSrt::setConnection(std::string name, std::string val)
{
_senderAddress = address;
}
+
+gboolean MediaTransporterReceiverSrt::_statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData)
+{
+ MediaTransporterReceiverSrt* srt = static_cast<MediaTransporterReceiverSrt*>(userData);
+ std::string fieldName = g_quark_to_string(fieldId);
+
+ if (!srt->_connectionStatsCallback ||
+ !srt->_connectionStatsCallback->invoke(fieldName, val, __receiverProp)) {
+ LOG_WARNING("stop calling stats callback");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void MediaTransporterReceiverSrt::foreachConnectionStats(void* handle, mtprConnectionStatsCallback callback, void* userData)
+{
+ GstStructure* structure = NULL;
+
+ _connectionStatsCallback = std::unique_ptr<IInvokable>(new ConnectionStatsCallback(handle, callback, userData));
+
+ 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, (gpointer)this);
+
+ _connectionStatsCallback = nullptr;
+}
\ No newline at end of file
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));
return NULL;
}
-
MediaTransporterSenderSrt::MediaTransporterSenderSrt()
{
LOG_DEBUG("ctor: %p", this);
{
_senderAddress = address;
}
+
+gboolean MediaTransporterSenderSrt::_statsForeachCb(GQuark fieldId, const GValue* val, gpointer userData)
+{
+ MediaTransporterSenderSrt* srt = static_cast<MediaTransporterSenderSrt*>(userData);
+ std::string fieldName = g_quark_to_string(fieldId);
+
+ if (!srt->_connectionStatsCallback ||
+ !srt->_connectionStatsCallback->invoke(fieldName, val, __senderProp)) {
+ LOG_WARNING("stop calling stats callback");
+ srt->_connectionStatsCallback = NULL;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void MediaTransporterSenderSrt::foreachConnectionStats(void* handle, mtprConnectionStatsCallback callback, void* userData)
+{
+ const GstStructure* structure = NULL;
+
+ _connectionStatsCallback = std::unique_ptr<IInvokable>(new ConnectionStatsCallback(handle, callback, userData));
+
+ g_object_get(_srtSink, "stats", &structure, NULL);
+ gchar* str = gst_structure_to_string(structure);
+ SECURE_LOG_DEBUG("SENDER >>> stats : %s", str);
+ g_free(str);
+
+ 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);
+ gst_structure_foreach(callerStats, _statsForeachCb, (gpointer)this);
+ }
+ }
+
+ if (_connectionStatsCallback && gst_structure_has_field(structure, "bytes-sent-total"))
+ _connectionStatsCallback->invoke("bytes-sent-total",
+ gst_structure_get_value(structure, "bytes-sent-total"), __senderProp);
+
+ _connectionStatsCallback = nullptr;
+}
media_packet_destroy(packet);
}
+bool __connection_stats_cb(mtpr_h mtpr, const mtpr_connection_stats_prop_info_s *prop_info, void *user_data)
+{
+ if (!prop_info) {
+ g_print(" => [STATS_CB][ERROR] mtpr[%p] invalid prop_info\n", mtpr);
+ return false;
+ }
+
+ switch(prop_info->type) {
+ case MTPR_CONNECTION_STATS_PROP_TYPE_BOOL:
+ g_print(" => [STATS_CB] mtpr[%p], prop[%d], type[%d], %s:%u\n",
+ mtpr, prop_info->prop, prop_info->type, prop_info->name, prop_info->v_bool);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_INT:
+ g_print(" => [STATS_CB] mtpr[%p], prop[%d], type[%d], %s:%d\n",
+ mtpr, prop_info->prop, prop_info->type, prop_info->name, prop_info->v_int);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_UINT:
+ g_print(" => [STATS_CB] mtpr[%p], prop[%d], type[%d], %s:%u\n",
+ mtpr, prop_info->prop, prop_info->type, prop_info->name, prop_info->v_uint);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_INT64:
+ g_print(" => [STATS_CB] mtpr[%p], prop[%d], type[%d], %s:%" G_GINT64_FORMAT "\n",
+ mtpr, prop_info->prop, prop_info->type, prop_info->name, prop_info->v_int64);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_UINT64:
+ g_print(" => [STATS_CB] mtpr[%p], prop[%d], type[%d], %s:%" G_GUINT64_FORMAT "\n",
+ mtpr, prop_info->prop, prop_info->type, prop_info->name, prop_info->v_uint64);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_FLOAT:
+ g_print(" => [STATS_CB] mtpr[%p], prop[%d], type[%d], %s:%f\n",
+ mtpr, prop_info->prop, prop_info->type, prop_info->name, prop_info->v_float);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_DOUBLE:
+ g_print(" => [STATS_CB] mtpr[%p], prop[%d], type[%d], %s:%f\n",
+ mtpr, prop_info->prop, prop_info->type, prop_info->name, prop_info->v_double);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_STRING:
+ g_print(" => [STATS_CB] mtpr[%p], prop[%d], type[%d], %s:%s\n",
+ mtpr, prop_info->prop, prop_info->type, prop_info->name, prop_info->v_string);
+ break;
+ default:
+ g_print(" => [STATS_CB][ERROR] mtpr[%p] invalid type %d\n", mtpr, prop_info->type);
+ break;
+ }
+
+ return true;
+}
+
static void _mtpr_test_set_error_cb()
{
int ret = MTPR_ERROR_NONE;
free(address);
}
+static void _mtpr_test_foreach_connection_stats()
+{
+ int ret = MTPR_ERROR_NONE;
+
+ ret = mtpr_foreach_connection_stats(g_mtpr, __connection_stats_cb, g_mtpr);
+ if (ret != MTPR_ERROR_NONE) {
+ g_print(" => failed to mtpr_foreach_connection_stats(), ret[0x%x]\n", ret);
+ } else {
+ g_print(" => foreach stats done\n");
+ }
+}
+
static void __set_aec_reference_device(sound_stream_info_h stream_info)
{
int ret;
_mtpr_test_set_track_cb();
} else if (strncmp(cmd, "rs", 2) == 0) {
g_menu_state = CURRENT_STATUS_SET_SOUND_STREAM_INFO;
+ } else if (strncmp(cmd, "fs", 2) == 0) {
+ _mtpr_test_foreach_connection_stats();
} else {
g_print("unknown menu \n");
}
g_print("ev. set video frame cb \t");
g_print("et. set track added & no more track cb \n\n");
+ g_print("-- << Connection Stats Info >> ----------------------------------------------------------------\n");
+ g_print("fs. foreach stats\n");
+
g_print("=========================================================================================\n");
}
using namespace std::chrono_literals;
-static void* _run_rist_sender(void* ptr) {
+static bool connectionStatsCb(mtpr_h mtpr,
+ const mtpr_connection_stats_prop_info_s *prop_info, void *user_data)
+{
+ return true;
+}
+
+static void* _run_rist_sender(void* ptr)
+{
mtpr_h mtpr;
unsigned int src_id = 0;
mtpr_create(MTPR_CONNECTION_TYPE_RIST_SENDER, &mtpr);
}
static void dataPacketCb(mtpr_h mtpr, mtpr_media_type_e type,
- unsigned int id, media_packet_h packet, void *user_data) {
+ 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;
});
}
-static bool waitDataPacket(std::future<bool>& f) {
+static bool waitDataPacket(std::future<bool>& f)
+{
LOGI("start waiting for packet arrival...");
if (f.wait_for(1s) != std::future_status::ready) {
ASSERT_TRUE(waitDataPacket(f));
}
+
+TEST_F(MediaTransporterTestRistReceiverWithSender, foreach_connection_stats_n)
+{
+ int ret = MTPR_ERROR_NONE;
+
+ ret = mtpr_set_receiver_address(_mtpr, _receiverPath.c_str());
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_start(_mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_foreach_connection_stats(_mtpr, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION);
+}
\ No newline at end of file
#include "ut_base.hpp"
+static bool connectionStatsCb(mtpr_h mtpr,
+ const mtpr_connection_stats_prop_info_s *prop_info, void *user_data)
+{
+ return true;
+}
+
class MediaTransporterTestRistSender : public MediaTransporterTestBase {
public:
MediaTransporterTestRistSender() = default;
ret = mtpr_get_connection_param(_mtpr, MTPR_CONNECTION_PARAM_RIST_BONDING_ADDRESS, &value);
ASSERT_EQ(ret, MTPR_ERROR_NO_DATA);
}
+
+TEST_F(MediaTransporterTestRistSender, foreach_connection_stats_n)
+{
+ int ret = MTPR_ERROR_NONE;
+ unsigned int source_id = 0;
+
+ ret = mtpr_set_receiver_address(_mtpr, _receiverPath.c_str());
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, &source_id);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+ ASSERT_GE(source_id, 0);
+
+ ret = mtpr_start(_mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_foreach_connection_stats(_mtpr, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION);
+}
using namespace std::chrono_literals;
-static void* _run_rtsp_sender(void* ptr) {
+static bool connectionStatsCb(mtpr_h mtpr,
+ const mtpr_connection_stats_prop_info_s *prop_info, void *user_data)
+{
+ return true;
+}
+
+static void* _run_rtsp_sender(void* ptr)
+{
mtpr_h mtpr;
unsigned int src_id = 0;
mtpr_create(MTPR_CONNECTION_TYPE_RTSP_SENDER, &mtpr);
}
static void dataPacketCb(mtpr_h mtpr, mtpr_media_type_e type,
- unsigned int id, media_packet_h packet, void *user_data) {
+ 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;
});
}
-static bool waitDataPacket(std::future<bool>& f) {
+static bool waitDataPacket(std::future<bool>& f)
+{
LOGI("start waiting for packet arrival...");
if (f.wait_for(10s) != std::future_status::ready) {
ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
}
+TEST_F(MediaTransporterTestRtspReceiver, foreach_connection_stats_n)
+{
+ 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);
+
+ ret = mtpr_foreach_connection_stats(_mtpr, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION);
+}
// MediaTransporterTestRtspReceiverWithSender
#include "ut_base.hpp"
+static bool connectionStatsCb(mtpr_h mtpr,
+ const mtpr_connection_stats_prop_info_s *prop_info, void *user_data)
+{
+ return true;
+}
+
class MediaTransporterTestRtspSender : public MediaTransporterTestBase {
public:
MediaTransporterTestRtspSender() = default;
ret = mtpr_get_connection_param(_mtpr, MTPR_CONNECTION_PARAM_RIST_MAX_RTCP_BANDWIDTH, &value);
ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION);
}
+
+TEST_F(MediaTransporterTestRtspSender, foreach_connection_stats_n)
+{
+ int ret = MTPR_ERROR_NONE;
+ unsigned int source_id = 0;
+
+ ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, &source_id);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+ ASSERT_GE(source_id, 0);
+
+ ret = mtpr_start(_mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_foreach_connection_stats(_mtpr, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION);
+}
static GMainLoop* _mainloop;
+static bool connectionStatsCb(mtpr_h mtpr,
+ const mtpr_connection_stats_prop_info_s *prop_info, void *user_data)
+{
+ return true;
+}
+
static void _clientConnectedCb(GstRTSPServer* server, GstRTSPClient* client)
{
LOGD("client connected %p", client);
ASSERT_EQ(ret, MTPR_ERROR_NONE);
ASSERT_EQ(state, MTPR_STATE_IDLE);
}
+
+TEST_F(MediaTransporterTestRtspSenderToServerRun, foreach_connection_stats_n)
+{
+ int ret = MTPR_ERROR_NONE;
+ unsigned int source_id = 0;
+
+ ret = mtpr_set_receiver_address(_mtpr, _receiverPath.c_str());
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, &source_id);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+ ASSERT_GE(source_id, 0);
+
+ ret = mtpr_start(_mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_foreach_connection_stats(_mtpr, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_OPERATION);
+}
\ No newline at end of file
using namespace std::chrono_literals;
-static void* _run_srt_sender(void* ptr) {
+static void* _run_srt_sender(void* ptr)
+{
mtpr_h mtpr;
unsigned int src_id = 0;
mtpr_create(MTPR_CONNECTION_TYPE_SRT_SENDER, &mtpr);
}
static void dataPacketCb(mtpr_h mtpr, mtpr_media_type_e type,
- unsigned int id, media_packet_h packet, void *user_data) {
+ 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;
});
}
-static bool waitDataPacket(std::future<bool>& f) {
+static bool waitDataPacket(std::future<bool>& f)
+{
LOGI("start waiting for packet arrival...");
if (f.wait_for(1s) != std::future_status::ready) {
return f.get();
}
+static bool connectionStatsCb(mtpr_h mtpr,
+ const mtpr_connection_stats_prop_info_s *prop_info, void *user_data)
+{
+ assert(prop_info);
+
+ switch(prop_info->type) {
+ case MTPR_CONNECTION_STATS_PROP_TYPE_INT:
+ LOGI("> prop[%d], type[%d], %s:%d",
+ prop_info->prop, prop_info->type, prop_info->name, prop_info->v_int);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_INT64:
+ LOGI("> prop[%d], type[%d], %s:%" G_GINT64_FORMAT,
+ prop_info->prop, prop_info->type, prop_info->name, prop_info->v_int64);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
class MediaTransporterTestSrtReceiverWithSender : public MediaTransporterTestBase {
public:
MediaTransporterTestSrtReceiverWithSender() = default;
ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
}
+TEST_F(MediaTransporterTestSrtReceiver, foreach_connection_stats_n1)
+{
+ int ret = MTPR_ERROR_NONE;
+
+ ret = mtpr_foreach_connection_stats(NULL, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+ ret = mtpr_foreach_connection_stats(_mtpr, NULL, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MediaTransporterTestSrtReceiver, foreach_connection_stats_n2)
+{
+ int ret = MTPR_ERROR_NONE;
+
+ ret = mtpr_foreach_connection_stats(_mtpr, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_STATE);
+}
+
TEST_F(MediaTransporterTestSrtReceiver, get_connection_param_n2)
{
int ret = MTPR_ERROR_NONE;
ret = mtpr_unset_video_packet_cb(_mtpr);
ASSERT_EQ(ret, MTPR_ERROR_NONE);
}
+
+TEST_F(MediaTransporterTestSrtReceiverWithSender, foreach_connection_stats_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_foreach_connection_stats(_mtpr, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+}
\ No newline at end of file
#include "ut_base.hpp"
+static bool connectionStatsCb(mtpr_h mtpr,
+ const mtpr_connection_stats_prop_info_s *prop_info, void *user_data)
+{
+ assert(prop_info);
+
+ switch(prop_info->type) {
+ case MTPR_CONNECTION_STATS_PROP_TYPE_INT:
+ LOGI("> prop[%d], type[%d], %s:%d",
+ prop_info->prop, prop_info->type, prop_info->name, prop_info->v_int);
+ break;
+ case MTPR_CONNECTION_STATS_PROP_TYPE_INT64:
+ LOGI("> prop[%d], type[%d], %s:%" G_GINT64_FORMAT,
+ prop_info->prop, prop_info->type, prop_info->name, prop_info->v_int64);
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
class MediaTransporterTestSrtSender : public MediaTransporterTestBase {
public:
MediaTransporterTestSrtSender() = default;
ret = mtpr_get_connection_param(_mtpr, MTPR_CONNECTION_PARAM_SRT_PASSPHRASE, &value);
ASSERT_EQ(ret, MTPR_ERROR_NO_DATA);
}
+
+TEST_F(MediaTransporterTestSrtSender, foreach_connection_stats_p)
+{
+ int ret = MTPR_ERROR_NONE;
+ unsigned int source_id = 0;
+
+ ret = mtpr_set_sender_address(_mtpr, _senderPath.c_str());
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_add_media_source(_mtpr, MTPR_SOURCE_TYPE_VIDEOTEST, &source_id);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+ ASSERT_GE(source_id, 0);
+
+ ret = mtpr_start(_mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+
+ ret = mtpr_foreach_connection_stats(_mtpr, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_NONE);
+}
+
+TEST_F(MediaTransporterTestSrtSender, foreach_connection_stats_n1)
+{
+ int ret = MTPR_ERROR_NONE;
+
+ ret = mtpr_foreach_connection_stats(NULL, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+
+ ret = mtpr_foreach_connection_stats(_mtpr, NULL, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MediaTransporterTestSrtSender, foreach_connection_stats_n2)
+{
+ int ret = MTPR_ERROR_NONE;
+
+ ret = mtpr_foreach_connection_stats(_mtpr, connectionStatsCb, _mtpr);
+ ASSERT_EQ(ret, MTPR_ERROR_INVALID_STATE);
+}
\ No newline at end of file