Add statistics API 77/272177/13
authorSangchul Lee <sc11.lee@samsung.com>
Wed, 16 Mar 2022 04:13:43 +0000 (13:13 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Fri, 25 Mar 2022 01:19:04 +0000 (10:19 +0900)
For now, only 'codec' statistics type is exported.
Other types will be supported with the following patches.

Function is added to get all the properties per statistics type.
 - webrtc_foreach_stats()

Callback function prototype is added as below.
 - typedef bool (*webrtc_stats_cb)(webrtc_stats_type_e type,
                                   webrtc_stats_prop_info_s *prop_info,
                                   void *user_data);

Enum is added as below for statistics type.
 - WEBRTC_STATS_TYPE_CODEC

Struct is added to be used as a parameter of the callback function.
 - webrtc_stats_prop_info_s

Enums are added as below for statisics property
 - WEBRTC_STATS_PROP_TIMESTAMP
 - WEBRTC_STATS_PROP_ID
 - WEBRTC_STATS_PROP_PAYLOAD_TYPE
 - WEBRTC_STATS_PROP_CLOCK_RATE
 - WEBRTC_STATS_PROP_CHANNELS
 - WEBRTC_STATS_PROP_MIME_TYPE
 - WEBRTC_STATS_PROP_CODEC_TYPE
 - WEBRTC_STATS_PROP_SDP_FMTP_LINE

Enums are added as below for statistics property data type
 - WEBRTC_STATS_PROP_TYPE_BOOL
 - WEBRTC_STATS_PROP_TYPE_INT
 - WEBRTC_STATS_PROP_TYPE_UINT
 - WEBRTC_STATS_PROP_TYPE_INT64
 - WEBRTC_STATS_PROP_TYPE_UINT64
 - WEBRTC_STATS_PROP_TYPE_FLOAT
 - WEBRTC_STATS_PROP_TYPE_DOUBLE
 - WEBRTC_STATS_PROP_TYPE_STRING

[Version] 0.3.69
[Issue Type] API

Change-Id: I52bbe25d6c03c4db1b0e0ffbf7c8f293da0b62a0
Signed-off-by: Sangchul Lee <sc11.lee@samsung.com>
include/webrtc.h
packaging/capi-media-webrtc.spec
src/webrtc.c
src/webrtc_stats.c
test/webrtc_test.c

index 19f4c0ba7b19df70f254cbd9b70f1a01c3325de4..852d0ce445129fb7cc8fc92a4c7d8c99ca58e874 100644 (file)
@@ -264,6 +264,97 @@ typedef enum {
        WEBRTC_DATA_CHANNEL_TYPE_BYTES,   /**<  Bytes data */
 } webrtc_data_channel_type_e;
 
+/**
+ * @}
+ */
+
+/**
+* @addtogroup CAPI_MEDIA_WEBRTC_STATISTICS_MODULE
+* @{
+*/
+
+/**
+ * @brief Enumeration for WebRTC statistics type.
+ * @since_tizen 7.0
+ */
+typedef enum {
+       WEBRTC_STATS_TYPE_CODEC                = 0x0001,   /**< Codec */
+} webrtc_stats_type_e;
+
+/**
+ * @brief Definition for all the supported statistics types mask.
+ * @since_tizen 7.0
+ * @see webrtc_foreach_stats()
+ */
+#define WEBRTC_STATS_TYPE_ALL  WEBRTC_STATS_TYPE_CODEC
+
+/**
+ * @brief Definition for mask value used by #webrtc_stats_prop_e that represents properties of rtc stats.
+ * @since_tizen 7.0
+ * @remarks It corresponds with the values described in https://www.w3.org/TR/webrtc-stats/#dom-rtcstats.
+ * @see webrtc_stats_prop_e
+ */
+#define WEBRTC_STATS_COMMON    0x00000100
+
+/**
+ * @brief Definition for mask value used by #webrtc_stats_prop_e that represents properties of rtc codec stats.
+ * @since_tizen 7.0
+ * @remarks It corresponds with the values described in https://www.w3.org/TR/webrtc-stats/#dom-rtccodecstats.
+ * @see webrtc_stats_prop_e
+ */
+#define WEBRTC_STATS_CODEC     0x00000200
+
+/**
+ * @brief Enumeration for WebRTC statistics property.
+ * @since_tizen 7.0
+ */
+typedef enum {
+       WEBRTC_STATS_PROP_TIMESTAMP        = WEBRTC_STATS_COMMON | 0x01,  /**< Timestamp */
+       WEBRTC_STATS_PROP_ID               = WEBRTC_STATS_COMMON | 0x02,  /**< Id */
+       WEBRTC_STATS_PROP_PAYLOAD_TYPE     = WEBRTC_STATS_CODEC | 0x01,   /**< Payload type */
+       WEBRTC_STATS_PROP_CLOCK_RATE       = WEBRTC_STATS_CODEC | 0x02,   /**< Clock rate */
+       WEBRTC_STATS_PROP_CHANNELS         = WEBRTC_STATS_CODEC | 0x03,   /**< Channels */
+       WEBRTC_STATS_PROP_MIME_TYPE        = WEBRTC_STATS_CODEC | 0x04,   /**< MIME type */
+       WEBRTC_STATS_PROP_CODEC_TYPE       = WEBRTC_STATS_CODEC | 0x05,   /**< Codec type */
+       WEBRTC_STATS_PROP_SDP_FMTP_LINE    = WEBRTC_STATS_CODEC | 0x06,   /**< SDP FMTP line */
+} webrtc_stats_prop_e;
+
+/**
+ * @brief Enumeration for statistics property data type.
+ * @since_tizen 7.0
+ */
+typedef enum {
+       WEBRTC_STATS_PROP_TYPE_BOOL,    /**< Boolean type */
+       WEBRTC_STATS_PROP_TYPE_INT,     /**< Signed integer type */
+       WEBRTC_STATS_PROP_TYPE_UINT,    /**< Unsigned integer type */
+       WEBRTC_STATS_PROP_TYPE_INT64,   /**< 64-bit signed integer type */
+       WEBRTC_STATS_PROP_TYPE_UINT64,  /**< 64-bit unsigned integer type */
+       WEBRTC_STATS_PROP_TYPE_FLOAT,   /**< Float type */
+       WEBRTC_STATS_PROP_TYPE_DOUBLE,  /**< Double type */
+       WEBRTC_STATS_PROP_TYPE_STRING,  /**< String type */
+} webrtc_stats_prop_type_e;
+
+/**
+ * @brief The structure type for statistics property information.
+ * @since_tizen 7.0
+ */
+typedef struct {
+       const char *name;               /**< The property name */
+       webrtc_stats_prop_e prop;       /**< The property enum */
+       webrtc_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 */
+       };
+} webrtc_stats_prop_info_s;
+
 /**
  * @}
  */
@@ -587,6 +678,61 @@ typedef void (*webrtc_data_channel_close_cb)(webrtc_data_channel_h channel, void
  * @see webrtc_data_channel_unset_buffered_amount_low_cb()
  */
 typedef void (*webrtc_data_channel_buffered_amount_low_cb)(webrtc_data_channel_h channel, void *user_data);
+
+/**
+ * @}
+ */
+
+/**
+* @addtogroup CAPI_MEDIA_WEBRTC_STATISTICS_MODULE
+* @{
+*/
+
+/**
+ * @brief Called iteratively to inform about a statistics property.
+ * @since_tizen 7.0
+ * @param[in] type       The statistics type
+ * @param[in] prop_info  The 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 webrtc_foreach_stats()
+ * @par Example
+ * @code
+       bool __stats_cb(webrtc_stats_type_e type, const webrtc_stats_prop_info_s *prop_info, void *user_data)
+       {
+               switch (prop_info->type) {
+               case WEBRTC_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 WEBRTC_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;
+               case WEBRTC_STATS_PROP_TYPE_INT64:
+                       printf("type[0x%x] prop[%s, 0x%08x, value:%"PRId64"]\n", type, prop_info->name, prop_info->prop, prop_info->v_int64);
+                       break;
+               case WEBRTC_STATS_PROP_TYPE_UINT:
+                       printf("type[0x%x] prop[%s, 0x%08x, value:%u]\n", type, prop_info->name, prop_info->prop, prop_info->v_uint);
+                       break;
+               case WEBRTC_STATS_PROP_TYPE_UINT64:
+                       printf("type[0x%x] prop[%s, 0x%08x, value:%"PRIu64"]\n", type, prop_info->name, prop_info->prop, prop_info->v_uint64);
+                       break;
+               case WEBRTC_STATS_PROP_TYPE_FLOAT:
+                       printf("type[0x%x] prop[%s, 0x%08x, value:%f]\n", type, prop_info->name, prop_info->prop, prop_info->v_float);
+                       break;
+               case WEBRTC_STATS_PROP_TYPE_DOUBLE:
+                       printf("type[0x%x] prop[%s, 0x%08x, value:%lf]\n", type, prop_info->name, prop_info->prop, prop_info->v_double);
+                       break;
+               case WEBRTC_STATS_PROP_TYPE_STRING:
+                       printf("type[0x%x] prop[%s, 0x%08x, value:%s]\n", type, prop_info->name, prop_info->prop, prop_info->v_string);
+                       break;
+               }
+               return true;
+       }
+ * @endcode
+ */
+typedef bool (*webrtc_stats_cb)(webrtc_stats_type_e type, const webrtc_stats_prop_info_s *prop_info, void *user_data);
+
 /**
  * @}
  */
@@ -2363,6 +2509,33 @@ int webrtc_data_channel_get_buffered_amount_low_threshold(webrtc_data_channel_h
  */
 int webrtc_data_channel_unset_buffered_amount_low_cb(webrtc_data_channel_h channel);
 
+/**
+ * @}
+ */
+
+/**
+* @addtogroup CAPI_MEDIA_WEBRTC_STATISTICS_MODULE
+* @{
+*/
+
+/**
+ * @brief Retrieves all the statistics properties, asynchronously.
+ * @since_tizen 7.0
+ * @remarks The registered callback will be invoked in an internal thread of the webrtc.
+ * @param[in] webrtc      WebRTC handle
+ * @param[in] type_mask   The mask values of #webrtc_stats_type_e combined with bitwise 'or'
+ * @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 #WEBRTC_ERROR_NONE    Successful
+ * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state
+ * @pre @a webrtc state must be set to #WEBRTC_STATE_PLAYING.
+ * @post webrtc_stats_cb() will be invoked.
+ */
+int webrtc_foreach_stats(webrtc_h webrtc, int type_mask, webrtc_stats_cb callback, void *user_data);
+
 /**
  * @}
  */
index 0776d2e73cbc3e91a80eae26256f8374937979c8..ea5448691c91aa6b5f4120360540a02a1d5e5633 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.3.68
+Version:    0.3.69
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index 986a6aaac68cb1abfefd7953309310198f6222f4..e4eb730506495e86b4d9b90dd04000be2834563b 100644 (file)
@@ -2023,3 +2023,22 @@ int webrtc_data_channel_unset_buffered_amount_low_cb(webrtc_data_channel_h chann
 
        return WEBRTC_ERROR_NONE;
 }
+
+int webrtc_foreach_stats(webrtc_h webrtc, int type_mask, webrtc_stats_cb callback, void *user_data)
+{
+       g_autoptr(GMutexLocker) locker = NULL;
+       webrtc_s *_webrtc = (webrtc_s *)webrtc;
+
+       RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL");
+       RET_VAL_IF(callback == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "callback is NULL");
+
+       locker = g_mutex_locker_new(&_webrtc->mutex);
+
+       RET_VAL_IF(_webrtc->state != WEBRTC_STATE_PLAYING, WEBRTC_ERROR_INVALID_STATE, "the state should be PLAYING");
+
+       _webrtcbin_get_stats(_webrtc, type_mask, callback, user_data);
+
+       LOG_INFO("webrtc[%p] type_mask[0x%x] callback[%p] user_data[%p]", webrtc, type_mask, callback, user_data);
+
+       return WEBRTC_ERROR_NONE;
+}
index 271e8636feb78abb31e55f265e05015ccc559951..1af0128ca0c8d8b58e5b97de60af5f3a63b9be21 100644 (file)
 #include "webrtc_private.h"
 
 //LCOV_EXCL_START
+#define WEBRTC_STATS_TYPE_GST_ALL    0xFFFF /* All statistic types of webrtcbin for debugging */
 
 typedef struct _stats_field_s {
        const gchar *name;
+       webrtc_stats_prop_e prop;
        GQuark id;
 } stats_field_s;
 
@@ -34,10 +36,10 @@ typedef struct _stats_field_s {
  *  "id"                  G_TYPE_STRING               unique identifier
  */
 static stats_field_s __stats_common_fields[] = {
-       { "timestamp", 0 },
-       { "type", 0 },
-       { "id", 0 },
-       { NULL, 0 }
+       { "timestamp", WEBRTC_STATS_PROP_TIMESTAMP, 0 },
+       { "type", 0, 0 },
+       { "id", WEBRTC_STATS_PROP_ID, 0 },
+       { NULL, 0, 0 }
 };
 
 /*
@@ -53,14 +55,14 @@ static stats_field_s __stats_common_fields[] = {
  *  "sdp-fmtp-line"       G_TYPE_STRING               the a=fmtp line in the SDP corresponding to the codec
  */
 static stats_field_s __stats_codec_fields[] = {
-       { "payload-type", 0 },
-       { "clock-rate", 0 },
-       { "ssrc", 0 },
-       { "channels", 0 },
-       { "mime-type", 0 },
-       { "codec-type", 0 },
-       { "sdp-fmtp-line", 0 },
-       { NULL, 0 }
+       { "payload-type", WEBRTC_STATS_PROP_PAYLOAD_TYPE, 0 },
+       { "clock-rate", WEBRTC_STATS_PROP_CLOCK_RATE, 0 },
+       { "ssrc", 0, 0 },
+       { "channels", WEBRTC_STATS_PROP_CHANNELS, 0 },
+       { "mime-type", WEBRTC_STATS_PROP_MIME_TYPE, 0 },
+       { "codec-type", WEBRTC_STATS_PROP_CODEC_TYPE, 0 },
+       { "sdp-fmtp-line", WEBRTC_STATS_PROP_SDP_FMTP_LINE, 0 },
+       { NULL, 0, 0 }
 };
 
 /*
@@ -75,13 +77,13 @@ static stats_field_s __stats_codec_fields[] = {
  *  "nack-count"          G_TYPE_UINT                 NACK requests received by the sender (only for local statistics)
  */
 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 }
+       { "ssrc", 0, 0 },
+       { "transport-id", 0, 0 },
+       { "codec-id", 0, 0 },
+       { "fir-count", 0, 0 },
+       { "pli-count", 0, 0 },
+       { "nack-count", 0, 0 },
+       { NULL, 0, 0 }
 };
 
 /*
@@ -94,12 +96,12 @@ static stats_field_s __stats_rtp_stream_fields[] = {
  *  "jitter"               G_TYPE_DOUBLE              packet jitter measured in seconds
  */
 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 }
+       { "packets-received", 0, 0 },
+       { "packets-lost", 0, 0 },
+       { "packets-discarded", 0, 0 },
+       { "packets-repaired", 0, 0 },
+       { "jitter", 0, 0 },
+       { NULL, 0, 0 }
 };
 
 /*
@@ -109,13 +111,13 @@ static stats_field_s __stats_received_rtp_stream_fields[] = {
  *  "remote-id"           G_TYPE_STRING               identifier for the associated RTCRemoteOutboundRTPStreamStats
  */
 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 }
+       { "remote-id", 0, 0 },
+       { "bytes-received", 0, 0 },
+       { "packets-duplicated", 0, 0 },
+       { "fir-count", 0, 0 },
+       { "pli-count", 0, 0 },
+       { "nack-count", 0, 0 },
+       { NULL, 0, 0 }
 };
 
 /*
@@ -126,9 +128,9 @@ static stats_field_s __stats_inbound_rtp_stream_fields[] = {
  *  "bytes-sent"          G_TYPE_UINT64               number of packets sent (only for local outbound)
  */
 static stats_field_s __stats_sent_rtp_stream_fields[] = {
-       { "packets-sent", 0 },
-       { "bytes-sent", 0 },
-       { NULL, 0 }
+       { "packets-sent", 0, 0 },
+       { "bytes-sent", 0, 0 },
+       { NULL, 0, 0 }
 };
 
 /*
@@ -138,8 +140,8 @@ static stats_field_s __stats_sent_rtp_stream_fields[] = {
  *  "remote-id"           G_TYPE_STRING               identifier for the associated RTCRemoteInboundRTPSTreamStats
  */
 static stats_field_s __stats_outbound_rtp_stream_fields[] = {
-       { "remote-id", 0 },
-       { NULL, 0 }
+       { "remote-id", 0, 0 },
+       { NULL, 0, 0 }
 };
 
 /*
@@ -151,10 +153,10 @@ static stats_field_s __stats_outbound_rtp_stream_fields[] = {
  *  "fraction-lost"       G_TYPE_DOUBLE               the fraction packet loss reported for this SSRC
  */
 static stats_field_s __stats_remote_inbound_rtp_stream_fields[] = {
-       { "local-id", 0 },
-       { "round-trip-time", 0 },
-       { "fraction-lost", 0 },
-       { NULL, 0 }
+       { "local-id", 0, 0 },
+       { "round-trip-time", 0, 0 },
+       { "fraction-lost", 0, 0 },
+       { NULL, 0, 0 }
 };
 
 /*
@@ -165,9 +167,9 @@ static stats_field_s __stats_remote_inbound_rtp_stream_fields[] = {
  *  "remote-timestamp"    G_TYPE_DOUBLE               the remote timestamp at which these statistics were sent by the remote endpoint
  */
 static stats_field_s __stats_remote_outbound_rtp_stream_fields[] = {
-       { "local-id", 0 },
-       { "remote-timestamp", 0 },
-       { NULL, 0 }
+       { "local-id", 0, 0 },
+       { "remote-timestamp", 0, 0 },
+       { NULL, 0, 0 }
 };
 
 /*
@@ -180,16 +182,16 @@ static stats_field_s __stats_remote_outbound_rtp_stream_fields[] = {
  *  "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 }
+       { "data-channels-opened", 0, 0 },
+       { "data-channels-closed", 0, 0 },
+       { "data-channels-requested", 0, 0 },
+       { "data-channels-accepted", 0, 0 },
+       { NULL, 0, 0 }
 };
 
 static stats_field_s __stats_transport_fields[] = {
        /* not supported yet */
-       { NULL, 0 }
+       { NULL, 0, 0 }
 };
 
 static stats_field_s *__stats_all_fields_list[] = {
@@ -256,25 +258,6 @@ static stats_field_s *__stats_transport_fields_list[] = {
        NULL
 };
 
-/* Note that stats_type_mask_e below follows GstWebRTCStatsType of webrtc_fwd.h */
-typedef enum {
-       STATS_TYPE_ALL_MASK                 = 0xFFFF,
-       STATS_TYPE_CODEC_MASK               = 0x0001,
-       STATS_TYPE_INBOUND_RTP_MASK         = 0x0002,
-       STATS_TYPE_OUTBOUND_RTP_MASK        = 0x0004,
-       STATS_TYPE_REMOTE_INBOUND_RTP_MASK  = 0x0008,
-       STATS_TYPE_REMOTE_OUTBOUND_RTP_MASK = 0x0010,
-       STATS_TYPE_CSRC_MASK                = 0x0020,
-       STATS_TYPE_PEER_CONNECTION_MASK     = 0x0040,
-       STATS_TYPE_DATA_CHANNEL_MASK        = 0x0080,
-       STATS_TYPE_STREAM_MASK              = 0x0100,
-       STATS_TYPE_TRANSPORT_MASK           = 0x0200,
-       STATS_TYPE_CANDIDATE_PAIR_MASK      = 0x0400,
-       STATS_TYPE_LOCAL_CANDIDATE_MASK     = 0x0800,
-       STATS_TYPE_REMOTE_CANDIDATE_MASK    = 0x1000,
-       STATS_TYPE_CERTIFICATE_MASK         = 0x2000,
-} stats_type_mask_e;
-
 typedef struct _promise_userdata_s {
        webrtc_s *webrtc;
        int type_mask;
@@ -283,13 +266,60 @@ typedef struct _promise_userdata_s {
 
 typedef struct _stats_userdata_s {
        promise_userdata_s *p_userdata;
-       stats_type_mask_e type;
+       int type;
        stats_field_s **fields_list;
 } stats_userdata_s;
 
+static gboolean __invoke_stats_cb(int type, const gchar *field_name, webrtc_stats_prop_e prop, webrtc_stats_prop_type_e data_type, void *result, webrtc_callbacks_s *stats_cb)
+{
+       webrtc_stats_prop_info_s prop_info = { .name = field_name, .prop = prop, .type = data_type };
+
+       if (!stats_cb || !stats_cb->callback)
+               return TRUE;
+
+       switch (data_type) {
+       case WEBRTC_STATS_PROP_TYPE_BOOL:
+               prop_info.v_bool = *(bool *)result;
+               break;
+       case WEBRTC_STATS_PROP_TYPE_INT:
+               prop_info.v_int = *(int *)result;
+               break;
+       case WEBRTC_STATS_PROP_TYPE_INT64:
+               prop_info.v_int64 = *(int64_t *)result;
+               break;
+       case WEBRTC_STATS_PROP_TYPE_UINT:
+               prop_info.v_uint = *(unsigned int *)result;
+               break;
+       case WEBRTC_STATS_PROP_TYPE_UINT64:
+               prop_info.v_uint64 = *(uint64_t *)result;
+               break;
+       case WEBRTC_STATS_PROP_TYPE_FLOAT:
+               prop_info.v_float = *(float *)result;
+               break;
+       case WEBRTC_STATS_PROP_TYPE_DOUBLE:
+               prop_info.v_double = *(double *)result;
+               break;
+       case WEBRTC_STATS_PROP_TYPE_STRING:
+               prop_info.v_string = (const char *)result;
+               break;
+       default:
+               LOG_ERROR_IF_REACHED("data_type(%d)", data_type);
+               return TRUE;
+       }
+
+       if (!((webrtc_stats_cb)stats_cb->callback)(type, &prop_info, stats_cb->user_data)) {
+               LOG_DEBUG("stats foreach callback[%p] returns false, stop it", stats_cb->callback);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
 static gboolean __stats_field_foreach_cb(GQuark field_id, const GValue *val, gpointer user_data)
 {
        stats_userdata_s *stats = (stats_userdata_s *)user_data;
+       const gchar *field_name = g_quark_to_string(field_id);
+       webrtc_stats_prop_e prop;
        int i, j;
 
        RET_VAL_IF(user_data == NULL, FALSE, "user_data is NULL");
@@ -300,69 +330,92 @@ static gboolean __stats_field_foreach_cb(GQuark field_id, const GValue *val, gpo
        /* 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)
+                       if (stats->fields_list[i][j].id == field_id) {
+                               prop = stats->fields_list[i][j].prop;
                                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"))
+       if (!g_strcmp0(field_name, "gst-rtpjitterbuffer-stats") ||
+               !g_strcmp0(field_name, "gst-rtpsource-stats"))
                return TRUE;
 
-       LOG_WARNING("this field[%s] is not supported", g_quark_to_string(field_id));
+       LOG_WARNING("this field[%s] is not supported", field_name);
        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]",
-                       g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)), g_value_get_boolean(val));
-               break;
-       case G_TYPE_INT:
-               LOG_DEBUG("field_id[%s] GType[%s] value[%d]",
-                       g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)), g_value_get_int(val));
-               break;
-       case G_TYPE_INT64:
-               LOG_DEBUG("field_id[%s] GType[%s] value[%"G_GINT64_FORMAT"]",
-                       g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)), g_value_get_int64(val));
-               break;
-       case G_TYPE_UINT:
-               LOG_DEBUG("field_id[%s] GType[%s] value[%u]",
-                       g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)), g_value_get_uint(val));
-               break;
-       case G_TYPE_UINT64:
-               LOG_DEBUG("field_id[%s] GType[%s] value[%"G_GUINT64_FORMAT"]",
-                       g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)), g_value_get_uint64(val));
-               break;
-       case G_TYPE_FLOAT:
-               LOG_DEBUG("field_id[%s] GType[%s] value[%f]",
-                       g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)), g_value_get_float(val));
-               break;
-       case G_TYPE_DOUBLE:
-               LOG_DEBUG("field_id[%s] GType[%s] value[%lf]",
-                       g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)), g_value_get_double(val));
-               break;
-       case G_TYPE_STRING:
-               LOG_DEBUG("field_id[%s] GType[%s] value[%s]",
-                       g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)), g_value_get_string(val));
-               break;
+       case G_TYPE_BOOLEAN: {
+               gboolean result = g_value_get_boolean(val);
+               LOG_DEBUG("field[%23s] GType[%18s] value[%21u]",
+                       field_name, g_type_name(G_VALUE_TYPE(val)), result);
+
+               return __invoke_stats_cb(stats->type, field_name, prop, WEBRTC_STATS_PROP_TYPE_BOOL, &result, &stats->p_userdata->stats_cb);
+       }
+       case G_TYPE_INT: {
+               gint result = g_value_get_int(val);
+               LOG_DEBUG("field[%23s] GType[%18s] value[%21d]",
+                       field_name, g_type_name(G_VALUE_TYPE(val)), result);
+
+               return __invoke_stats_cb(stats->type, field_name, prop, WEBRTC_STATS_PROP_TYPE_INT, &result, &stats->p_userdata->stats_cb);
+       }
+       case G_TYPE_INT64: {
+               gint64 result = g_value_get_int64(val);
+               LOG_DEBUG("field[%23s] GType[%18s] value[%21"G_GINT64_FORMAT"]",
+                       field_name, g_type_name(G_VALUE_TYPE(val)), result);
+
+               return __invoke_stats_cb(stats->type, field_name, prop, WEBRTC_STATS_PROP_TYPE_INT64, &result, &stats->p_userdata->stats_cb);
+       }
+       case G_TYPE_UINT: {
+               guint result = g_value_get_uint(val);
+               LOG_DEBUG("field[%23s] GType[%18s] value[%21u]",
+                       field_name, g_type_name(G_VALUE_TYPE(val)), result);
+
+               return __invoke_stats_cb(stats->type, field_name, prop, WEBRTC_STATS_PROP_TYPE_UINT, &result, &stats->p_userdata->stats_cb);
+       }
+       case G_TYPE_UINT64: {
+               guint64 result = g_value_get_uint64(val);
+               LOG_DEBUG("field[%23s] GType[%18s] value[%21"G_GUINT64_FORMAT"]",
+                       field_name, g_type_name(G_VALUE_TYPE(val)), result);
+
+               return __invoke_stats_cb(stats->type, field_name, prop, WEBRTC_STATS_PROP_TYPE_UINT64, &result, &stats->p_userdata->stats_cb);
+       }
+       case G_TYPE_FLOAT: {
+               gfloat result = g_value_get_float(val);
+               LOG_DEBUG("field[%23s] GType[%18s] value[%21f]",
+                       field_name, g_type_name(G_VALUE_TYPE(val)), result);
+
+               return __invoke_stats_cb(stats->type, field_name, prop, WEBRTC_STATS_PROP_TYPE_FLOAT, &result, &stats->p_userdata->stats_cb);
+       }
+       case G_TYPE_DOUBLE: {
+               gdouble result = g_value_get_double(val);
+               LOG_DEBUG("field[%23s] GType[%18s] value[%21lf]",
+                       field_name, g_type_name(G_VALUE_TYPE(val)), result);
+
+               return __invoke_stats_cb(stats->type, field_name, prop, WEBRTC_STATS_PROP_TYPE_DOUBLE, &result, &stats->p_userdata->stats_cb);
+       }
+       case G_TYPE_STRING: {
+               const gchar *result = g_value_get_string(val);
+               LOG_DEBUG("field[%23s] GType[%18s] value[%21s]",
+                       field_name, g_type_name(G_VALUE_TYPE(val)), result);
+
+               return __invoke_stats_cb(stats->type, field_name, prop, WEBRTC_STATS_PROP_TYPE_STRING, (void *)result, &stats->p_userdata->stats_cb);
+       }
        default:
                if (!g_strcmp0(g_type_name(G_VALUE_TYPE(val)), "GstWebRTCStatsType")) {
-                       LOG_DEBUG("field_id[%s] GType[%s] value[%d]",
-                               g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)), g_value_get_enum(val));
+                       LOG_DEBUG("field[%23s] GType[%18s] value[%21d]", field_name, g_type_name(G_VALUE_TYPE(val)), g_value_get_enum(val));
                        break;
                }
-               LOG_ERROR("invalid type, field_id[%s] GType[%s]",
-                       g_quark_to_string(field_id), g_type_name(G_VALUE_TYPE(val)));
+               LOG_ERROR("invalid type, field[%23s] GType[%18s]", field_name, g_type_name(G_VALUE_TYPE(val)));
                break;
        }
 
        return TRUE;
 }
 
-static void __stats_codec_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_codec_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
 
        RET_IF(user_data == NULL, "user_data is NULL");
 
@@ -371,9 +424,9 @@ static void __stats_codec_invoke_callback(const GstStructure *s, stats_type_mask
        gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_inbound_rtp_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_inbound_rtp_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        GstStructure *rtpjitterbuffer_stats;
        GstStructure *rtpsource_stats;
 
@@ -393,9 +446,9 @@ static void __stats_inbound_rtp_invoke_callback(const GstStructure *s, stats_typ
        gst_structure_foreach(rtpsource_stats, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_outbound_rtp_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_outbound_rtp_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        GstStructure *rtpsource_stats;
 
        RET_IF(user_data == NULL, "user_data is NULL");
@@ -409,9 +462,9 @@ static void __stats_outbound_rtp_invoke_callback(const GstStructure *s, stats_ty
        gst_structure_foreach(rtpsource_stats, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_remote_inbound_rtp_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_remote_inbound_rtp_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -420,9 +473,9 @@ static void __stats_remote_inbound_rtp_invoke_callback(const GstStructure *s, st
        gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_remote_outbound_rtp_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_remote_outbound_rtp_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -430,9 +483,9 @@ static void __stats_remote_outbound_rtp_invoke_callback(const GstStructure *s, s
        gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_csrc_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_csrc_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -441,9 +494,9 @@ static void __stats_csrc_invoke_callback(const GstStructure *s, stats_type_mask_
        /* not implemented */
 }
 
-static void __stats_peer_connection_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_peer_connection_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -451,9 +504,9 @@ static void __stats_peer_connection_invoke_callback(const GstStructure *s, stats
        gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_data_channel_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_data_channel_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -462,9 +515,9 @@ static void __stats_data_channel_invoke_callback(const GstStructure *s, stats_ty
        /* not implemented */
 }
 
-static void __stats_stream_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_stream_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -473,9 +526,9 @@ static void __stats_stream_invoke_callback(const GstStructure *s, stats_type_mas
        /* not implemented */
 }
 
-static void __stats_transport_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_transport_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -483,9 +536,9 @@ static void __stats_transport_invoke_callback(const GstStructure *s, stats_type_
        gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_candidate_pair_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_candidate_pair_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -494,9 +547,9 @@ static void __stats_candidate_pair_invoke_callback(const GstStructure *s, stats_
        /* not implemented */
 }
 
-static void __stats_local_candidate_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_local_candidate_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -505,9 +558,9 @@ static void __stats_local_candidate_invoke_callback(const GstStructure *s, stats
        /* not implemented */
 }
 
-static void __stats_remote_candidate_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_remote_candidate_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -516,9 +569,9 @@ static void __stats_remote_candidate_invoke_callback(const GstStructure *s, stat
        /* not implemented */
 }
 
-static void __stats_certificate_invoke_callback(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data)
+static void __stats_certificate_invoke_callback(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data)
 {
-       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
@@ -527,43 +580,59 @@ static void __stats_certificate_invoke_callback(const GstStructure *s, stats_typ
        /* not implemented */
 }
 
-typedef void (*stats_func)(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data);
+typedef void (*stats_func)(const GstStructure *s, webrtc_stats_type_e type, stats_field_s **fields_list, promise_userdata_s *user_data);
 
 typedef struct {
        stats_func func;
-       stats_type_mask_e type_mask;
+       int type_mask;
        stats_field_s **fields_list;
 } parse_stats_s;
 
+/* Definitions below are not exported types due to the incompletion. */
+#define WEBRTC_STATS_TYPE_INBOUND_RTP          0x0002   /**< Inbound RTP */
+#define WEBRTC_STATS_TYPE_OUTBOUND_RTP         0x0004   /**< Outbound RTP */
+#define WEBRTC_STATS_TYPE_REMOTE_INBOUND_RTP   0x0008   /**< Remote Inbound RTP */
+#define WEBRTC_STATS_TYPE_REMOTE_OUTBOUND_RTP  0x000F   /**< Remote Outbound RTP */
+#define WEBRTC_STATS_TYPE_PEER_CONNECTION      0x0010   /**< Peer Connection */
+#define WEBRTC_STATS_TYPE_CSRC                 0x0020   /**< CSRC */
+#define WEBRTC_STATS_TYPE_DATA_CHANNEL         0x0040   /**< Data Channel */
+#define WEBRTC_STATS_TYPE_STREAM               0x0080   /**< Stream */
+#define WEBRTC_STATS_TYPE_TRANSPORT            0x00F0   /**< Transport */
+#define WEBRTC_STATS_TYPE_CANDIDATE_PAIR       0x0100   /**< Candidate Pair */
+#define WEBRTC_STATS_TYPE_LOCAL_CANDIDATE      0x0200   /**< Local Candidate */
+#define WEBRTC_STATS_TYPE_REMOTE_CANDIDATE     0x0400   /**< Remote Candidate */
+#define WEBRTC_STATS_TYPE_CERTIFICATE          0x0800   /**< Certificate */
+
+/* Refer to GstWebRTCStatsType of webrtc_fwd.h */
 static parse_stats_s parse_stats[] = {
        [GST_WEBRTC_STATS_CODEC] = {
-               __stats_codec_invoke_callback, STATS_TYPE_CODEC_MASK, __stats_codec_fields_list },
+               __stats_codec_invoke_callback, WEBRTC_STATS_TYPE_CODEC, __stats_codec_fields_list },
        [GST_WEBRTC_STATS_INBOUND_RTP] = {
-               __stats_inbound_rtp_invoke_callback, STATS_TYPE_INBOUND_RTP_MASK, __stats_inbound_rtp_fields_list },
+               __stats_inbound_rtp_invoke_callback, WEBRTC_STATS_TYPE_INBOUND_RTP, __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 },
+               __stats_outbound_rtp_invoke_callback, WEBRTC_STATS_TYPE_OUTBOUND_RTP, __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 },
+               __stats_remote_inbound_rtp_invoke_callback, WEBRTC_STATS_TYPE_REMOTE_INBOUND_RTP, __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 },
+               __stats_remote_outbound_rtp_invoke_callback, WEBRTC_STATS_TYPE_REMOTE_OUTBOUND_RTP, __stats_remote_outbound_rtp_fields_list },
        [GST_WEBRTC_STATS_CSRC] = {
-               __stats_csrc_invoke_callback, STATS_TYPE_CSRC_MASK, NULL },
+               __stats_csrc_invoke_callback, WEBRTC_STATS_TYPE_CSRC, NULL },
        [GST_WEBRTC_STATS_PEER_CONNECTION] = {
-               __stats_peer_connection_invoke_callback, STATS_TYPE_PEER_CONNECTION_MASK, __stats_peer_connection_fields_list },
+               __stats_peer_connection_invoke_callback, WEBRTC_STATS_TYPE_PEER_CONNECTION, __stats_peer_connection_fields_list },
        [GST_WEBRTC_STATS_DATA_CHANNEL] = {
-               __stats_data_channel_invoke_callback, STATS_TYPE_DATA_CHANNEL_MASK, NULL },
+               __stats_data_channel_invoke_callback, WEBRTC_STATS_TYPE_DATA_CHANNEL, NULL },
        [GST_WEBRTC_STATS_STREAM] = {
-               __stats_stream_invoke_callback, STATS_TYPE_STREAM_MASK, NULL },
+               __stats_stream_invoke_callback, WEBRTC_STATS_TYPE_STREAM, NULL },
        [GST_WEBRTC_STATS_TRANSPORT] = {
-               __stats_transport_invoke_callback, STATS_TYPE_TRANSPORT_MASK, __stats_transport_fields_list },
+               __stats_transport_invoke_callback, WEBRTC_STATS_TYPE_TRANSPORT, __stats_transport_fields_list },
        [GST_WEBRTC_STATS_CANDIDATE_PAIR] = {
-               __stats_candidate_pair_invoke_callback, STATS_TYPE_CANDIDATE_PAIR_MASK, NULL },
+               __stats_candidate_pair_invoke_callback, WEBRTC_STATS_TYPE_CANDIDATE_PAIR, NULL },
        [GST_WEBRTC_STATS_LOCAL_CANDIDATE] = {
-               __stats_local_candidate_invoke_callback, STATS_TYPE_LOCAL_CANDIDATE_MASK, NULL },
+               __stats_local_candidate_invoke_callback, WEBRTC_STATS_TYPE_LOCAL_CANDIDATE, NULL },
        [GST_WEBRTC_STATS_REMOTE_CANDIDATE] = {
-               __stats_remote_candidate_invoke_callback, STATS_TYPE_REMOTE_CANDIDATE_MASK, NULL },
+               __stats_remote_candidate_invoke_callback, WEBRTC_STATS_TYPE_REMOTE_CANDIDATE, NULL },
        [GST_WEBRTC_STATS_CERTIFICATE] = {
-               __stats_certificate_invoke_callback, STATS_TYPE_CERTIFICATE_MASK, NULL }
+               __stats_certificate_invoke_callback, WEBRTC_STATS_TYPE_CERTIFICATE, NULL }
 };
 
 static gboolean __webrtcbin_stats_cb(GQuark field_id, const GValue *value, gpointer user_data)
@@ -638,7 +707,7 @@ static gboolean __get_stats_periodically(gpointer user_data)
        webrtc_s *webrtc = (webrtc_s *)user_data;
 
        if (webrtc->state == WEBRTC_STATE_PLAYING)
-               _webrtcbin_get_stats(webrtc, STATS_TYPE_ALL_MASK, NULL, NULL);
+               _webrtcbin_get_stats(webrtc, WEBRTC_STATS_TYPE_GST_ALL, NULL, NULL);
 
        return G_SOURCE_CONTINUE;
 }
index 3ba5a59ab20e6d6affa4f6ee1935fb76b025421c..f4afb4760372b1c1a17d73327124f1db208216ca 100644 (file)
@@ -1830,6 +1830,61 @@ static void _webrtc_data_channel_get_buffered_amount(int index)
        }
 }
 
+static bool __stats_cb(webrtc_stats_type_e type, const webrtc_stats_prop_info_s *prop_info, void *user_data)
+{
+       switch (prop_info->type) {
+       case WEBRTC_STATS_PROP_TYPE_BOOL:
+               g_print("stats type[0x%04x], prop[%23s, 0x%08x, type:%d, value:%21d], user_data[%p]\n",
+                       type, prop_info->name, prop_info->prop, prop_info->type, prop_info->v_bool, user_data);
+               break;
+       case WEBRTC_STATS_PROP_TYPE_INT:
+               g_print("stats type[0x%04x], prop[%23s, 0x%08x, type:%d, value:%21d], user_data[%p]\n",
+                       type, prop_info->name, prop_info->prop, prop_info->type, prop_info->v_int, user_data);
+               break;
+       case WEBRTC_STATS_PROP_TYPE_INT64:
+               g_print("stats type[0x%04x], prop[%23s, 0x%08x, type:%d, value:%21"PRId64"], user_data[%p]\n",
+                       type, prop_info->name, prop_info->prop, prop_info->type, prop_info->v_int64, user_data);
+               break;
+       case WEBRTC_STATS_PROP_TYPE_UINT:
+               g_print("stats type[0x%04x], prop[%23s, 0x%08x, type:%d, value:%21u], user_data[%p]\n",
+                       type, prop_info->name, prop_info->prop, prop_info->type, prop_info->v_uint, user_data);
+               break;
+       case WEBRTC_STATS_PROP_TYPE_UINT64:
+               g_print("stats type[0x%04x], prop[%23s, 0x%08x, type:%d, value:%21"PRIu64"], user_data[%p]\n",
+                       type, prop_info->name, prop_info->prop, prop_info->type, prop_info->v_uint64, user_data);
+               break;
+       case WEBRTC_STATS_PROP_TYPE_FLOAT:
+               g_print("stats type[0x%04x], prop[%23s, 0x%08x, type:%d, value:%21f], user_data[%p]\n",
+                       type, prop_info->name, prop_info->prop, prop_info->type, prop_info->v_float, user_data);
+               break;
+       case WEBRTC_STATS_PROP_TYPE_DOUBLE:
+               g_print("stats type[0x%04x], prop[%23s, 0x%08x, type:%d, value:%21lf], user_data[%p]\n",
+                       type, prop_info->name, prop_info->prop, prop_info->type, prop_info->v_double, user_data);
+               break;
+       case WEBRTC_STATS_PROP_TYPE_STRING:
+               g_print("stats type[0x%04x], prop[%23s, 0x%08x, type:%d, value:%21s], user_data[%p]\n",
+                       type, prop_info->name, prop_info->prop, prop_info->type, prop_info->v_string, user_data);
+               break;
+       default:
+               g_printerr("invalid prop_info->type, stats type[0x%04x], prop[%23s, 0x%08x, type:%d], user_data[%p]\n",
+                       type, prop_info->name, prop_info->prop, prop_info->type, user_data);
+               break;
+       }
+
+       return true;
+}
+
+static void _webrtc_foreach_stats(int index)
+{
+       int ret = WEBRTC_ERROR_NONE;
+
+       ret = webrtc_foreach_stats(g_conns[index].webrtc, WEBRTC_STATS_TYPE_ALL, __stats_cb, NULL);
+       if (ret != WEBRTC_ERROR_NONE)
+               g_print("failed to webrtc_foreach_stats(), index[%d]\n", index);
+       else
+               g_print("webrtc_foreach_stats() success, index[%d]\n", index);
+}
+
 static void __error_cb(webrtc_h webrtc, webrtc_error_e error, webrtc_state_e state, void *user_data)
 {
        g_print("__error_cb() is invoked, webrtc[%p], error[0x%x], state[%d], user_data[%p]\n",
@@ -4467,6 +4522,9 @@ void _interpret_main_menu(char *cmd)
                } else if (strncmp(cmd, "ubc", 3) == 0) {
                        _webrtc_data_channel_unset_buffered_amount_low_cb(0);
 
+               } else if (strncmp(cmd, "sts", 3) == 0) {
+                       _webrtc_foreach_stats(0);
+
                } else {
                        g_print("unknown menu \n");
                }
@@ -4578,6 +4636,8 @@ void display_sub_basic()
        g_print("sbc. Set buffered amount low callback\t");
        g_print("ubc. Unset buffered amount low callback\n");
        g_print("gbt. Get buffered amount low threshold\n");
+       g_print("------------------------------------- Stats ---------------------------------------------\n");
+       g_print("sts. Get stats\n");
        g_print("------------------------------------- Callbacks -----------------------------------------\n");
        g_print("sac. Set all callbacks below (except for the encoded frame callbacks)\n");
        g_print("san. Set all the negotiation state change callbacks\t");