From 252ee157f6cd2beea699f18f095679fe173408ca Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Fri, 25 Feb 2022 15:15:14 +0900 Subject: [PATCH] webrtc_stats: Revise to allow pre-defined fields per stats type It is also possible to check easily fields incoming from gstreamer which are not defined in this library yet. [Version] 0.3.63 [Issue Type] Refactoring Change-Id: Ied57fcf1ad4b350588d1456ddca56f6fe4003774 Signed-off-by: Sangchul Lee --- include/webrtc_private.h | 1 + packaging/capi-media-webrtc.spec | 2 +- src/webrtc_private.c | 1 + src/webrtc_stats.c | 583 ++++++++++++++----------------- 4 files changed, 261 insertions(+), 326 deletions(-) diff --git a/include/webrtc_private.h b/include/webrtc_private.h index 47ff2043..b9849576 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -716,6 +716,7 @@ int _data_channel_send_bytes(webrtc_data_channel_s *channel, const char *data, u void _webrtcbin_get_stats(webrtc_s *webrtc, int type_mask); void _set_stats_timer(webrtc_s *webrtc); void _unset_stats_timer(webrtc_s *webrtc); +void _init_stats_all_fields_list(void); typedef int (*_websocket_cb)(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len); webrtc_websocket_s *_alloc_websocket(const int port, const char *ssl_cert_path, const char *ssl_private_key_path, const char *ssl_ca_path, _websocket_cb callback, void *user_data); diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 036245ab..9a532736 100644 --- a/packaging/capi-media-webrtc.spec +++ b/packaging/capi-media-webrtc.spec @@ -1,6 +1,6 @@ Name: capi-media-webrtc Summary: A WebRTC library in Tizen Native API -Version: 0.3.62 +Version: 0.3.63 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc_private.c b/src/webrtc_private.c index cb95b7a9..8fddce3f 100644 --- a/src/webrtc_private.c +++ b/src/webrtc_private.c @@ -378,6 +378,7 @@ void _invoke_state_changed_cb(webrtc_s *webrtc, webrtc_state_e old, webrtc_state } if (new == WEBRTC_STATE_PLAYING) { + _init_stats_all_fields_list(); _set_stats_timer(webrtc); _remove_filesrc_pad_block_probe(webrtc); } diff --git a/src/webrtc_stats.c b/src/webrtc_stats.c index 88051a13..13545ada 100644 --- a/src/webrtc_stats.c +++ b/src/webrtc_stats.c @@ -19,6 +19,11 @@ //LCOV_EXCL_START +typedef struct _stats_field_s { + const gchar *name; + GQuark id; +} stats_field_s; + /* * Description below is extracted from GstWebRTCBin::get-stats: * Each statistics structure contains the following values as defined by @@ -28,11 +33,12 @@ * "type" GST_TYPE_WEBRTC_STATS_TYPE the type of statistics reported * "id" G_TYPE_STRING unique identifier */ -typedef struct _stats_common_s { - gdouble timestamp; - GstWebRTCStatsType type; - gchar *id; -} stats_common_s; +static stats_field_s __stats_common_fields[] = { + { "timestamp", 0 }, + { "type", 0 }, + { "id", 0 }, + { NULL, 0 } +}; /* * Description below is extracted from GstWebRTCBin::get-stats: @@ -41,11 +47,12 @@ typedef struct _stats_common_s { * "payload-type" G_TYPE_UINT the rtp payload number in use * "clock-rate" G_TYPE_UINT the rtp clock-rate */ -typedef struct _stats_codec_s { - guint payload_type; - guint clock_rate; - guint ssrc; -} stats_codec_s; +static stats_field_s __stats_codec_fields[] = { + { "payload-type", 0 }, + { "clock-rate", 0 }, + { "ssrc", 0 }, + { NULL, 0 } +}; /* * Description below is extracted from GstWebRTCBin::get-stats: @@ -58,11 +65,15 @@ typedef struct _stats_codec_s { * "pli-count" G_TYPE_UINT PLI requests received by the sender (only for local statistics) * "nack-count" G_TYPE_UINT NACK requests received by the sender (only for local statistics) */ -typedef struct _stats_rtp_stream_s { - guint ssrc; - gchar *transport_id; - gchar *codec_id; -} stats_rtp_stream_s; +static stats_field_s __stats_rtp_stream_fields[] = { + { "ssrc", 0 }, + { "transport-id", 0 }, + { "codec-id", 0 }, + { "fir-count", 0 }, + { "pli-count", 0 }, + { "nack-count", 0 }, + { NULL, 0 } +}; /* * Description below is extracted from GstWebRTCBin::get-stats: @@ -73,13 +84,14 @@ typedef struct _stats_rtp_stream_s { * "packets-lost" G_TYPE_UINT number of packets lost * "jitter" G_TYPE_DOUBLE packet jitter measured in seconds */ -typedef struct _stats_received_rtp_stream_s { - guint64 packets_received; - guint64 packets_lost; - guint64 packets_discarded; - guint64 packets_repaired; - gdouble jitter; -} stats_received_rtp_stream_s; +static stats_field_s __stats_received_rtp_stream_fields[] = { + { "packets-received", 0 }, + { "packets-lost", 0 }, + { "packets-discarded", 0 }, + { "packets-repaired", 0 }, + { "jitter", 0 }, + { NULL, 0 } +}; /* * Description below is extracted from GstWebRTCBin::get-stats: @@ -87,14 +99,15 @@ typedef struct _stats_received_rtp_stream_s { * * "remote-id" G_TYPE_STRING identifier for the associated RTCRemoteOutboundRTPStreamStats */ -typedef struct _stats_inbound_rtp_stream_s { - gchar *remote_id; - guint64 bytes_received; - guint64 packets_duplicated; - guint fir_count; - guint pli_count; - guint nack_count; -} stats_inbound_rtp_stream_s; +static stats_field_s __stats_inbound_rtp_stream_fields[] = { + { "remote-id", 0 }, + { "bytes-received", 0 }, + { "packets-duplicated", 0 }, + { "fir-count", 0 }, + { "pli-count", 0 }, + { "nack-count", 0 }, + { NULL, 0 } +}; /* * Description below is extracted from GstWebRTCBin::get-stats: @@ -103,10 +116,11 @@ typedef struct _stats_inbound_rtp_stream_s { * "packets-sent" G_TYPE_UINT64 number of packets sent (only for local outbound) * "bytes-sent" G_TYPE_UINT64 number of packets sent (only for local outbound) */ -typedef struct _stats_sent_rtp_stream_s { - guint64 packets_sent; - guint64 bytes_sent; -} stats_sent_rtp_stream_s; +static stats_field_s __stats_sent_rtp_stream_fields[] = { + { "packets-sent", 0 }, + { "bytes-sent", 0 }, + { NULL, 0 } +}; /* * Description below is extracted from GstWebRTCBin::get-stats: @@ -114,12 +128,10 @@ typedef struct _stats_sent_rtp_stream_s { * * "remote-id" G_TYPE_STRING identifier for the associated RTCRemoteInboundRTPSTreamStats */ -typedef struct _stats_outbound_rtp_stream_s { - gchar *remote_id; - guint fir_count; /* FIR/PLI/NACK counts exists here that differ from WebRTC SPEC */ - guint pli_count; - guint nack_count; -} stats_outbound_rtp_stream_s; +static stats_field_s __stats_outbound_rtp_stream_fields[] = { + { "remote-id", 0 }, + { NULL, 0 } +}; /* * Description below is extracted from GstWebRTCBin::get-stats: @@ -128,32 +140,133 @@ typedef struct _stats_outbound_rtp_stream_s { * "local-id" G_TYPE_STRING identifier for the associated RTCOutboundRTPSTreamStats * "round-trip-time" G_TYPE_DOUBLE round trip time of packets measured in seconds */ -typedef struct _stats_remote_inbound_rtp_stream_s { - gchar *local_id; - gdouble round_trip_time; -} stats_remote_inbound_rtp_stream_s; +static stats_field_s __stats_remote_inbound_rtp_stream_fields[] = { + { "local-id", 0 }, + { "round-trip-time", 0 }, + { NULL, 0 } +}; /* * Description below is extracted from GstWebRTCBin::get-stats: * RTCRemoteOutboundRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#remoteoutboundrtpstats-dict*) * * "local-id" G_TYPE_STRING identifier for the associated RTCInboundRTPSTreamStats + * "remote-timestamp" G_TYPE_DOUBLE the remote timestamp at which these statistics were sent by the remote endpoint */ -typedef struct _stats_remote_outbound_rtp_stream_s { - gchar *local_id; - gdouble remote_timestamp; -} stats_remote_outbound_rtp_stream_s; - -typedef struct _stats_peer_connection_s { - guint data_channels_opened; - guint data_channels_closed; - guint data_channels_requested; - guint data_channels_accepted; -} stats_peer_connection_s; - -/* This is for debug purpose to check which fields are actually provided via webrtcbin. */ -static gboolean __gststructure_foreach_cb(GQuark field_id, const GValue *val, gpointer data) +static stats_field_s __stats_remote_outbound_rtp_stream_fields[] = { + { "local-id", 0 }, + { "remote-timestamp", 0 }, + { NULL, 0 } +}; + +/* + * Description below is extracted from GstWebRTCBin::get-stats: + * RTCRemoteOutboundRTPStreamStats supported fields (https://w3c.github.io/webrtc-stats/#pcstats-dict*) + * + * "data-channels-opened" G_TYPE_UINT the number of unique RTCDataChannels that have entered the "open" state during their lifetime + * "data-channels-closed" G_TYPE_UINT the number of unique RTCDataChannels that have left the "open" state during their lifetime + * "data-channels-requested" G_TYPE_UINT the number of unique RTCDataChannels returned from a successful createDataChannel() call on the RTCPeerConnection + * "data-channels-accepted" G_TYPE_UINT the number of unique RTCDataChannels signaled in a ondatachannel event on the RTCPeerConnection + */ +static stats_field_s __stats_peer_connection_fields[] = { + { "data-channels-opened", 0 }, + { "data-channels-closed", 0 }, + { "data-channels-requested", 0 }, + { "data-channels-accepted", 0 }, + { NULL, 0 } +}; + +static stats_field_s *__stats_all_fields_list[] = { + __stats_common_fields, + __stats_codec_fields, + __stats_rtp_stream_fields, + __stats_received_rtp_stream_fields, + __stats_inbound_rtp_stream_fields, + __stats_sent_rtp_stream_fields, + __stats_outbound_rtp_stream_fields, + __stats_remote_inbound_rtp_stream_fields, + __stats_remote_outbound_rtp_stream_fields, + __stats_peer_connection_fields, + NULL +}; + +static stats_field_s *__stats_codec_fields_list[] = { + __stats_common_fields, + __stats_codec_fields, + NULL +}; + +static stats_field_s *__stats_inbound_rtp_fields_list[] = { + __stats_common_fields, + __stats_rtp_stream_fields, + __stats_received_rtp_stream_fields, + __stats_inbound_rtp_stream_fields, + NULL +}; + +static stats_field_s *__stats_outbound_rtp_fields_list[] = { + __stats_common_fields, + __stats_rtp_stream_fields, + __stats_sent_rtp_stream_fields, + __stats_outbound_rtp_stream_fields, + NULL +}; + +/* NOTE: __stats_received_rtp_stream_fields does not exist that differs from WebRTC SPEC. */ +static stats_field_s *__stats_remote_inbound_rtp_fields_list[] = { + __stats_common_fields, + __stats_rtp_stream_fields, + //__stats_received_rtp_stream_fields, + __stats_remote_inbound_rtp_stream_fields, + NULL +}; + +/* NOTE: stats_sent_rtp_stream_s does not exist that differs from WebRTC SPEC. */ +static stats_field_s *__stats_remote_outbound_rtp_fields_list[] = { + __stats_common_fields, + __stats_rtp_stream_fields, + //__stats_sent_rtp_stream_fields, + __stats_remote_outbound_rtp_stream_fields, + NULL +}; + +static stats_field_s *__stats_peer_connection_fields_list[] = { + __stats_common_fields, + __stats_peer_connection_fields, + NULL +}; + +typedef struct _stats_userdata_s { + webrtc_s *webrtc; + int type_mask; + stats_field_s **fields_list; +} stats_userdata_s; + +static gboolean __gststructure_foreach_cb(GQuark field_id, const GValue *val, gpointer user_data) { + stats_userdata_s *stats = (stats_userdata_s *)user_data; + int i, j; + + RET_VAL_IF(user_data == NULL, FALSE, "user_data is NULL"); + RET_VAL_IF(stats->webrtc == NULL, FALSE, "webrtc is NULL"); + RET_VAL_IF(stats->fields_list == NULL, FALSE, "fields_list is NULL"); + + /* Note that it only allow fields pre-defined in list */ + for (i = 0; stats->fields_list[i]; i++) + for (j = 0; stats->fields_list[i][j].name; j++) + if (stats->fields_list[i][j].id == field_id) + goto invoke_cb; + + /* field id below will be skipped here, it should be handled with gst_structure_foreach() */ + if (!g_strcmp0(g_quark_to_string(field_id), "gst-rtpjitterbuffer-stats") || + !g_strcmp0(g_quark_to_string(field_id), "gst-rtpsource-stats")) + return TRUE; + + LOG_WARNING("this field[%s] is not supported", g_quark_to_string(field_id)); + return TRUE; + +invoke_cb: + /* TODO: invoke callback */ switch (G_VALUE_TYPE(val)) { case G_TYPE_BOOLEAN: LOG_DEBUG("field_id[%s] GType[%s] value[%u]", @@ -201,357 +314,157 @@ static gboolean __gststructure_foreach_cb(GQuark field_id, const GValue *val, gp return TRUE; } -static void __get_common_stats(const GstStructure *s, stats_common_s *stats) -{ - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "timestamp", G_TYPE_DOUBLE, &stats->timestamp, - "type", GST_TYPE_WEBRTC_STATS_TYPE, &stats->type, - "id", G_TYPE_STRING, &stats->id, - NULL); - - LOG_DEBUG("timestamp[%lf] type[%u] id[%s]", stats->timestamp, stats->type, stats->id); -} - -static void __get_codec_stats(const GstStructure *s, stats_codec_s *stats) -{ - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "payload-type", G_TYPE_UINT, &stats->payload_type, - "clock-rate", G_TYPE_UINT, &stats->clock_rate, - "ssrc", G_TYPE_UINT, &stats->ssrc, - NULL); - - LOG_DEBUG("payload-type[%u] clock-rate[%u] ssrc[%u]", stats->payload_type, stats->clock_rate, stats->ssrc); -} - -static void __get_rtp_stream_stats(const GstStructure *s, stats_rtp_stream_s *stats) +static void __stats_codec_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "ssrc", G_TYPE_UINT, &stats->ssrc, - "transport-id", G_TYPE_STRING, &stats->transport_id, - "codec-id", G_TYPE_STRING, &stats->codec_id, - NULL); - - LOG_DEBUG("ssrc[%u] transport-id[%s] codec-id[%s] ", stats->ssrc, stats->transport_id, stats->codec_id); -} - -static void __get_received_rtp_stream_stats(const GstStructure *s, stats_received_rtp_stream_s *stats) -{ - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "packets-received", G_TYPE_UINT64, &stats->packets_received, - "packets-lost", G_TYPE_UINT64, &stats->packets_lost, - "packets-discarded", G_TYPE_UINT64, &stats->packets_discarded, - "packets-repaired", G_TYPE_UINT64, &stats->packets_repaired, - "jitter", G_TYPE_DOUBLE, &stats->jitter, - NULL); - - LOG_DEBUG("packet-received[%"G_GUINT64_FORMAT"] packets-lost[%"G_GUINT64_FORMAT"] \ - packets-discarded[%"G_GUINT64_FORMAT"] packets-repaired[%"G_GUINT64_FORMAT"] jitter[%lf]", - stats->packets_received, stats->packets_lost, stats->packets_discarded, stats->packets_repaired, stats->jitter); -} - -static void __get_inbound_rtp_stream_stats(const GstStructure *s, stats_inbound_rtp_stream_s *stats) -{ - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "remote-id", G_TYPE_STRING, &stats->remote_id, - "bytes-received", G_TYPE_UINT64, &stats->bytes_received, - "packets-duplicated", G_TYPE_UINT64, &stats->packets_duplicated, - "fir-count", G_TYPE_UINT, &stats->fir_count, - "pli-count", G_TYPE_UINT, &stats->pli_count, - "nack-count", G_TYPE_UINT, &stats->nack_count, - NULL); - - LOG_DEBUG("remote-id[%s] bytes-received[%"G_GUINT64_FORMAT"] packets-duplicated[%"G_GUINT64_FORMAT"] \ - fir-count[%u] pli-count[%u] nack-count[%u]", stats->remote_id, stats->bytes_received, stats->packets_duplicated, - stats->fir_count, stats->pli_count, stats->nack_count); -} - -static void __get_sent_rtp_stream_stats(const GstStructure *s, stats_sent_rtp_stream_s *stats) -{ - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "packets-sent", G_TYPE_UINT64, &stats->packets_sent, - "bytes-sent", G_TYPE_UINT64, &stats->bytes_sent, - NULL); - - LOG_DEBUG("packet-sent[%"G_GUINT64_FORMAT"] bytes-sent[%"G_GUINT64_FORMAT"]", stats->packets_sent, stats->bytes_sent); -} - -static void __get_outbound_rtp_stream_stats(const GstStructure *s, stats_outbound_rtp_stream_s *stats) -{ - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "remote-id", G_TYPE_STRING, &stats->remote_id, - "fir-count", G_TYPE_UINT, &stats->fir_count, - "pli-count", G_TYPE_UINT, &stats->pli_count, - "nack-count", G_TYPE_UINT, &stats->nack_count, - NULL); - - LOG_DEBUG("remote-id[%s] fir-count[%u] pli-count[%u] nack-count[%u]", - stats->remote_id, stats->fir_count, stats->pli_count, stats->nack_count); -} - -static void __get_remote_inbound_rtp_stream_stats(const GstStructure *s, stats_remote_inbound_rtp_stream_s *stats) -{ - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "local-id", G_TYPE_STRING, &stats->local_id, - "round-trip-time", G_TYPE_DOUBLE, &stats->round_trip_time, - NULL); - /* FIXME: fraction-lost should be added */ - - LOG_DEBUG("local-id[%s] round-trip-time[%lf]", stats->local_id, stats->round_trip_time); -} - -static void __get_remote_outbound_rtp_stream_stats(const GstStructure *s, stats_remote_outbound_rtp_stream_s *stats) -{ - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "local-id", G_TYPE_STRING, &stats->local_id, - "remote-timestamp", G_TYPE_DOUBLE, &stats->remote_timestamp, - NULL); - - LOG_DEBUG("local-id[%s] remote-timestamp[%lf]", stats->local_id, stats->remote_timestamp); -} - -static void __get_peer_connection_stats(const GstStructure *s, stats_peer_connection_s *stats) -{ - RET_IF(s == NULL, "s is NULL"); - RET_IF(stats == NULL, "stats is NULL"); - - gst_structure_get(s, - "data-channels-opened", G_TYPE_UINT, &stats->data_channels_opened, - "data-channels-closed", G_TYPE_UINT, &stats->data_channels_closed, - "data-channels-requested", G_TYPE_UINT, &stats->data_channels_requested, - "data-channels-accepted", G_TYPE_UINT, &stats->data_channels_accepted, - NULL); - - LOG_DEBUG("data-channels-[opened:%u, closed:%u, requested:%u, accepted:%u]", - stats->data_channels_opened, stats->data_channels_closed, stats->data_channels_requested, stats->data_channels_accepted); -} - -static void __parse_codec_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) -{ - stats_common_s common; - stats_codec_s codec; - - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - __get_common_stats(s, &common); - __get_codec_stats(s, &codec); - - /* TODO: invoke callback */ + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); } -static void __parse_inbound_rtp_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_inbound_rtp_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - stats_common_s common; - stats_rtp_stream_s rtp_stream; - stats_received_rtp_stream_s received_rtp_stream; - stats_inbound_rtp_stream_s inbound_rtp_stream; GstStructure *rtpjitterbuffer_stats; GstStructure *rtpsource_stats; - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - __get_common_stats(s, &common); - __get_rtp_stream_stats(s, &rtp_stream); - __get_received_rtp_stream_stats(s, &received_rtp_stream); - __get_inbound_rtp_stream_stats(s, &inbound_rtp_stream); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); gst_structure_get(s, "gst-rtpjitterbuffer-stats", GST_TYPE_STRUCTURE, &rtpjitterbuffer_stats, "gst-rtpsource-stats", GST_TYPE_STRUCTURE, &rtpsource_stats, NULL); - - gst_structure_foreach(rtpjitterbuffer_stats, __gststructure_foreach_cb, NULL); - gst_structure_foreach(rtpsource_stats, __gststructure_foreach_cb, NULL); - - /* TODO: invoke callback */ + gst_structure_foreach(rtpjitterbuffer_stats, __gststructure_foreach_cb, user_data); + gst_structure_foreach(rtpsource_stats, __gststructure_foreach_cb, user_data); } -static void __parse_outbound_rtp_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_outbound_rtp_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - stats_common_s common; - stats_rtp_stream_s rtp_stream; - stats_sent_rtp_stream_s sent_rtp_stream; - stats_outbound_rtp_stream_s outbound_rtp_stream; GstStructure *rtpsource_stats; - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - __get_common_stats(s, &common); - __get_rtp_stream_stats(s, &rtp_stream); - __get_sent_rtp_stream_stats(s, &sent_rtp_stream); - __get_outbound_rtp_stream_stats(s, &outbound_rtp_stream); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); gst_structure_get(s, "gst-rtpsource-stats", GST_TYPE_STRUCTURE, &rtpsource_stats, NULL); - gst_structure_foreach(rtpsource_stats, __gststructure_foreach_cb, NULL); - - /* TODO: invoke callback */ + gst_structure_foreach(rtpsource_stats, __gststructure_foreach_cb, user_data); } -static void __parse_remote_inbound_rtp_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_remote_inbound_rtp_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - stats_common_s common; - stats_rtp_stream_s rtp_stream; - stats_remote_inbound_rtp_stream_s remote_inbound_rtp_stream; - - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - __get_common_stats(s, &common); - __get_rtp_stream_stats(s, &rtp_stream); - /* FIXME: only 'jitter' and 'packet-lost'(int) are available. type of 'packet-lost' should be fixed. - * __get_received_rtp_stream_stats(s, &received_rtp_stream); */ - __get_remote_inbound_rtp_stream_stats(s, &remote_inbound_rtp_stream); - - /* TODO: invoke callback */ + /* FIXME: only 'jitter' and 'packet-lost'(int) are available. type of 'packet-lost' should be fixed.*/ + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); } -static void __parse_remote_outbound_rtp_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_remote_outbound_rtp_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - stats_common_s common; - stats_rtp_stream_s rtp_stream; - stats_remote_outbound_rtp_stream_s remote_outbound_rtp_stream; - /* NOTE: stats_sent_rtp_stream_s does not exist that differs from WebRTC SPEC. */ - - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - __get_common_stats(s, &common); - __get_rtp_stream_stats(s, &rtp_stream); - __get_remote_outbound_rtp_stream_stats(s, &remote_outbound_rtp_stream); - - /* TODO: invoke callback */ + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); } -static void __parse_csrc_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_csrc_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - gst_structure_foreach(s, __gststructure_foreach_cb, NULL); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); /* not implemented */ } -static void __parse_peer_connection_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_peer_connection_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - stats_common_s common; - stats_peer_connection_s peer_connection; - - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - __get_common_stats(s, &common); - __get_peer_connection_stats(s, &peer_connection); - - /* TODO: invoke callback */ + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); } -static void __parse_data_channel_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_data_channel_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - gst_structure_foreach(s, __gststructure_foreach_cb, NULL); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); /* not implemented */ } -static void __parse_stream_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_stream_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - gst_structure_foreach(s, __gststructure_foreach_cb, NULL); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); /* not implemented */ } -static void __parse_transport_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_transport_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - gst_structure_foreach(s, __gststructure_foreach_cb, NULL); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); /* not implemented */ } -static void __parse_candidate_pair_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_candidate_pair_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - gst_structure_foreach(s, __gststructure_foreach_cb, NULL); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); /* not implemented */ } -static void __parse_local_candidate_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_local_candidate_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - gst_structure_foreach(s, __gststructure_foreach_cb, NULL); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); /* not implemented */ } -static void __parse_remote_candidate_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_remote_candidate_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - gst_structure_foreach(s, __gststructure_foreach_cb, NULL); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); /* not implemented */ } -static void __parse_certificate_and_invoke_callback(const GstStructure *s, webrtc_callbacks_s *cb) +static void __stats_certificate_invoke_callback(const GstStructure *s, stats_userdata_s *user_data) { - RET_IF(cb == NULL, "cb is NULL"); + RET_IF(user_data == NULL, "user_data is NULL"); LOG_DEBUG_ENTER(); - gst_structure_foreach(s, __gststructure_foreach_cb, NULL); + gst_structure_foreach(s, __gststructure_foreach_cb, user_data); /* not implemented */ } -typedef void (*stats_func)(const GstStructure *s, webrtc_callbacks_s *cb); +typedef void (*stats_func)(const GstStructure *s, stats_userdata_s *user_data); /* Note that stats_type_mask_e below follows GstWebRTCStatsType of webrtc_fwd.h */ typedef enum { @@ -575,30 +488,40 @@ typedef enum { typedef struct { stats_func func; stats_type_mask_e type_mask; + stats_field_s **fields_list; } parse_stats_s; static parse_stats_s parse_stats[] = { - [GST_WEBRTC_STATS_CODEC] = { __parse_codec_and_invoke_callback, STATS_TYPE_CODEC_MASK }, - [GST_WEBRTC_STATS_INBOUND_RTP] = { __parse_inbound_rtp_and_invoke_callback, STATS_TYPE_INBOUND_RTP_MASK }, - [GST_WEBRTC_STATS_OUTBOUND_RTP] = { __parse_outbound_rtp_and_invoke_callback, STATS_TYPE_OUTBOUND_RTP_MASK }, - [GST_WEBRTC_STATS_REMOTE_INBOUND_RTP] = { __parse_remote_inbound_rtp_and_invoke_callback, STATS_TYPE_REMOTE_INBOUND_RTP_MASK }, - [GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP] = { __parse_remote_outbound_rtp_and_invoke_callback, STATS_TYPE_REMOTE_OUTBOUND_RTP_MASK }, - [GST_WEBRTC_STATS_CSRC] = { __parse_csrc_and_invoke_callback, STATS_TYPE_CSRC_MASK }, - [GST_WEBRTC_STATS_PEER_CONNECTION] = { __parse_peer_connection_and_invoke_callback, STATS_TYPE_PEER_CONNECTION_MASK }, - [GST_WEBRTC_STATS_DATA_CHANNEL] = { __parse_data_channel_and_invoke_callback, STATS_TYPE_DATA_CHANNEL_MASK }, - [GST_WEBRTC_STATS_STREAM] = { __parse_stream_and_invoke_callback, STATS_TYPE_STREAM_MASK }, - [GST_WEBRTC_STATS_TRANSPORT] = { __parse_transport_and_invoke_callback, STATS_TYPE_TRANSPORT_MASK }, - [GST_WEBRTC_STATS_CANDIDATE_PAIR] = { __parse_candidate_pair_and_invoke_callback, STATS_TYPE_CANDIDATE_PAIR_MASK }, - [GST_WEBRTC_STATS_LOCAL_CANDIDATE] = { __parse_local_candidate_and_invoke_callback, STATS_TYPE_LOCAL_CANDIDATE_MASK }, - [GST_WEBRTC_STATS_REMOTE_CANDIDATE] = { __parse_remote_candidate_and_invoke_callback, STATS_TYPE_REMOTE_CANDIDATE_MASK }, - [GST_WEBRTC_STATS_CERTIFICATE] = { __parse_certificate_and_invoke_callback, STATS_TYPE_CERTIFICATE_MASK } + [GST_WEBRTC_STATS_CODEC] = { + __stats_codec_invoke_callback, STATS_TYPE_CODEC_MASK, __stats_codec_fields_list }, + [GST_WEBRTC_STATS_INBOUND_RTP] = { + __stats_inbound_rtp_invoke_callback, STATS_TYPE_INBOUND_RTP_MASK, __stats_inbound_rtp_fields_list }, + [GST_WEBRTC_STATS_OUTBOUND_RTP] = { + __stats_outbound_rtp_invoke_callback, STATS_TYPE_OUTBOUND_RTP_MASK, __stats_outbound_rtp_fields_list }, + [GST_WEBRTC_STATS_REMOTE_INBOUND_RTP] = { + __stats_remote_inbound_rtp_invoke_callback, STATS_TYPE_REMOTE_INBOUND_RTP_MASK, __stats_remote_inbound_rtp_fields_list }, + [GST_WEBRTC_STATS_REMOTE_OUTBOUND_RTP] = { + __stats_remote_outbound_rtp_invoke_callback, STATS_TYPE_REMOTE_OUTBOUND_RTP_MASK, __stats_remote_outbound_rtp_fields_list }, + [GST_WEBRTC_STATS_CSRC] = { + __stats_csrc_invoke_callback, STATS_TYPE_CSRC_MASK, NULL }, + [GST_WEBRTC_STATS_PEER_CONNECTION] = { + __stats_peer_connection_invoke_callback, STATS_TYPE_PEER_CONNECTION_MASK, __stats_peer_connection_fields_list }, + [GST_WEBRTC_STATS_DATA_CHANNEL] = { + __stats_data_channel_invoke_callback, STATS_TYPE_DATA_CHANNEL_MASK, NULL }, + [GST_WEBRTC_STATS_STREAM] = { + __stats_stream_invoke_callback, STATS_TYPE_STREAM_MASK, NULL }, + [GST_WEBRTC_STATS_TRANSPORT] = { + __stats_transport_invoke_callback, STATS_TYPE_TRANSPORT_MASK, NULL }, + [GST_WEBRTC_STATS_CANDIDATE_PAIR] = { + __stats_candidate_pair_invoke_callback, STATS_TYPE_CANDIDATE_PAIR_MASK, NULL }, + [GST_WEBRTC_STATS_LOCAL_CANDIDATE] = { + __stats_local_candidate_invoke_callback, STATS_TYPE_LOCAL_CANDIDATE_MASK, NULL }, + [GST_WEBRTC_STATS_REMOTE_CANDIDATE] = { + __stats_remote_candidate_invoke_callback, STATS_TYPE_REMOTE_CANDIDATE_MASK, NULL }, + [GST_WEBRTC_STATS_CERTIFICATE] = { + __stats_certificate_invoke_callback, STATS_TYPE_CERTIFICATE_MASK, NULL } }; -typedef struct _stats_userdata_s { - webrtc_s *webrtc; - int type_mask; -} stats_userdata_s; - static gboolean __webrtcbin_stats_cb(GQuark field_id, const GValue *value, gpointer user_data) { stats_userdata_s *stats_userdata = (stats_userdata_s *)user_data; @@ -619,7 +542,8 @@ static gboolean __webrtcbin_stats_cb(GQuark field_id, const GValue *value, gpoin return TRUE; } - parse_stats[type].func(s, &stats_userdata->webrtc->stats_cb); + stats_userdata->fields_list = parse_stats[type].fields_list; + parse_stats[type].func(s, stats_userdata); } else { LOG_ERROR("unknown field \'%s\' value type: \'%s\'", @@ -702,4 +626,13 @@ void _unset_stats_timer(webrtc_s *webrtc) LOG_DEBUG("remove stats_timer_src[%u]", webrtc->stats_timer_src); webrtc->stats_timer_src = 0; } + +void _init_stats_all_fields_list(void) +{ + int i, j; + for (i = 0; __stats_all_fields_list[i]; i++) + for (j = 0; __stats_all_fields_list[i][j].name; j++) + if (__stats_all_fields_list[i][j].id == 0) + __stats_all_fields_list[i][j].id = g_quark_from_string(__stats_all_fields_list[i][j].name); +} //LCOV_EXCL_STOP \ No newline at end of file -- 2.34.1