webrtc_stats: Add user callback parameters to _webrtcbin_get_stats() 02/272402/2 accepted/tizen/unified/20220321.141206 submit/tizen/20220321.030714
authorSangchul Lee <sc11.lee@samsung.com>
Wed, 16 Mar 2022 02:23:40 +0000 (11:23 +0900)
committerSangchul Lee <sc11.lee@samsung.com>
Wed, 16 Mar 2022 03:59:13 +0000 (12:59 +0900)
Some improvements are also applied
 : Use gst_promise_new_with_change_func()'s notify parameter to free userdata
 : Rename __gststructure_foreach_cb() to __stats_field_foreach_cb()
 : Separate user data structure for __stats_field_foreach_cb()

[Version] 0.3.67
[Issue Type] Improvement

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

index bf03fd7813481cc87cc413a807b7b4de93d5b380..e0b1ef13dd8780fbd108dac53a0dcbe834e6252f 100644 (file)
@@ -475,8 +475,6 @@ typedef struct _webrtc_s {
        webrtc_callbacks_s encoded_video_frame_cb;
        webrtc_callbacks_s data_channel_cb;
 
-       webrtc_callbacks_s stats_cb;
-
        webrtc_negotiation_states_s negotiation_states;
 #ifndef TIZEN_TV
        webrtc_resource_s resource;
@@ -713,7 +711,7 @@ int _destroy_data_channel(webrtc_data_channel_s *channel);
 int _data_channel_send_string(webrtc_data_channel_s *channel, const char *string);
 int _data_channel_send_bytes(webrtc_data_channel_s *channel, const char *data, unsigned int size);
 
-void _webrtcbin_get_stats(webrtc_s *webrtc, int type_mask);
+void _webrtcbin_get_stats(webrtc_s *webrtc, int type_mask, void *callback, void *user_data);
 void _set_stats_timer(webrtc_s *webrtc);
 void _unset_stats_timer(webrtc_s *webrtc);
 void _init_stats_all_fields_list(void);
index fdd1fd375bf38023acaa368d44ae78811a64c4a1..625332eeab407bef4a5260a604e8b2eba415b830 100644 (file)
@@ -1,6 +1,6 @@
 Name:       capi-media-webrtc
 Summary:    A WebRTC library in Tizen Native API
-Version:    0.3.66
+Version:    0.3.67
 Release:    0
 Group:      Multimedia/API
 License:    Apache-2.0
index c2c4f755476637863c7f0e2db03b9f38d2738f51..271e8636feb78abb31e55f265e05015ccc559951 100644 (file)
@@ -256,19 +256,45 @@ static stats_field_s *__stats_transport_fields_list[] = {
        NULL
 };
 
-typedef struct _stats_userdata_s {
+/* 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;
+       webrtc_callbacks_s stats_cb;
+} promise_userdata_s;
+
+typedef struct _stats_userdata_s {
+       promise_userdata_s *p_userdata;
+       stats_type_mask_e type;
        stats_field_s **fields_list;
 } stats_userdata_s;
 
-static gboolean __gststructure_foreach_cb(GQuark field_id, const GValue *val, gpointer user_data)
+static gboolean __stats_field_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->p_userdata == NULL, FALSE, "p_userdata is NULL");
+       RET_VAL_IF(stats->p_userdata->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 */
@@ -334,17 +360,20 @@ invoke_cb:
        return TRUE;
 }
 
-static void __stats_codec_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
+
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_inbound_rtp_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        GstStructure *rtpjitterbuffer_stats;
        GstStructure *rtpsource_stats;
 
@@ -352,160 +381,153 @@ static void __stats_inbound_rtp_invoke_callback(const GstStructure *s, stats_use
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 
        gst_structure_get(s,
                "gst-rtpjitterbuffer-stats", GST_TYPE_STRUCTURE, &rtpjitterbuffer_stats,
                "gst-rtpsource-stats", GST_TYPE_STRUCTURE, &rtpsource_stats,
                NULL);
        LOG_DEBUG("gst-rtpjitterbuffer-stats ---> ");
-       gst_structure_foreach(rtpjitterbuffer_stats, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(rtpjitterbuffer_stats, __stats_field_foreach_cb, &stats_userdata);
        LOG_DEBUG("gst-rtpsource-stats ---> ");
-       gst_structure_foreach(rtpsource_stats, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(rtpsource_stats, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_outbound_rtp_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        GstStructure *rtpsource_stats;
 
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 
        gst_structure_get(s, "gst-rtpsource-stats", GST_TYPE_STRUCTURE, &rtpsource_stats, NULL);
        LOG_DEBUG("gst-rtpsource-stats ---> ");
-       gst_structure_foreach(rtpsource_stats, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(rtpsource_stats, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_remote_inbound_rtp_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
        /* FIXME: type of 'packets-lost(int)' should be fixed.*/
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_remote_outbound_rtp_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_csrc_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
        /* not implemented */
 }
 
-static void __stats_peer_connection_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_data_channel_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
        /* not implemented */
 }
 
-static void __stats_stream_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
        /* not implemented */
 }
 
-static void __stats_transport_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
 }
 
-static void __stats_candidate_pair_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
        /* not implemented */
 }
 
-static void __stats_local_candidate_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
        /* not implemented */
 }
 
-static void __stats_remote_candidate_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
        /* not implemented */
 }
 
-static void __stats_certificate_invoke_callback(const GstStructure *s, stats_userdata_s *user_data)
+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)
 {
+       stats_userdata_s stats_userdata = { .p_userdata = user_data, .type = type_mask, .fields_list = fields_list };
        RET_IF(user_data == NULL, "user_data is NULL");
 
        LOG_DEBUG_ENTER();
 
-       gst_structure_foreach(s, __gststructure_foreach_cb, user_data);
+       gst_structure_foreach(s, __stats_field_foreach_cb, &stats_userdata);
        /* not implemented */
 }
 
-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 {
-       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 void (*stats_func)(const GstStructure *s, stats_type_mask_e type_mask, stats_field_s **fields_list, promise_userdata_s *user_data);
 
 typedef struct {
        stats_func func;
@@ -546,11 +568,11 @@ static parse_stats_s parse_stats[] = {
 
 static gboolean __webrtcbin_stats_cb(GQuark field_id, const GValue *value, gpointer user_data)
 {
-       stats_userdata_s *stats_userdata = (stats_userdata_s *)user_data;
+       promise_userdata_s *userdata = (promise_userdata_s *)user_data;
        const GstStructure *s;
        GstWebRTCStatsType type;
 
-       RET_VAL_IF(stats_userdata == NULL, TRUE, "stats_userdata is NULL");
+       RET_VAL_IF(userdata == NULL, TRUE, "userdata is NULL");
 
        if (GST_VALUE_HOLDS_STRUCTURE(value)) {
                s = gst_value_get_structure(value);
@@ -559,13 +581,12 @@ static gboolean __webrtcbin_stats_cb(GQuark field_id, const GValue *value, gpoin
                RET_VAL_IF((type < GST_WEBRTC_STATS_CODEC || type > GST_WEBRTC_STATS_CERTIFICATE),
                        TRUE, "invalid type(%u)", type);
 
-               if (!(stats_userdata->type_mask & parse_stats[type].type_mask)) {
-                       LOG_DEBUG("skip this type[%u], type_mask[0x%x]", type, stats_userdata->type_mask);
+               if (!(userdata->type_mask & parse_stats[type].type_mask)) {
+                       LOG_DEBUG("skip this type[%u], type_mask[0x%x]", type, userdata->type_mask);
                        return TRUE;
                }
 
-               stats_userdata->fields_list = parse_stats[type].fields_list;
-               parse_stats[type].func(s, stats_userdata);
+               parse_stats[type].func(s, parse_stats[type].type_mask, parse_stats[type].fields_list, userdata);
 
        } else {
                LOG_ERROR("unknown field \'%s\' value type: \'%s\'",
@@ -586,23 +607,25 @@ static void __webrtcbin_get_stats_cb(GstPromise *promise, gpointer user_data)
        RET_IF(stats == NULL, "failed to gst_promise_get_reply()");
 
        gst_structure_foreach(stats, __webrtcbin_stats_cb, user_data);
-
-       g_free(user_data);
 }
 
-void _webrtcbin_get_stats(webrtc_s *webrtc, int type_mask)
+void _webrtcbin_get_stats(webrtc_s *webrtc, int type_mask, void *callback, void *user_data)
 {
        GstPromise *promise;
-       stats_userdata_s *stats_userdata;
+       promise_userdata_s *userdata;
 
        RET_IF(webrtc == NULL, "webrtc is NULL");
        RET_IF(webrtc->gst.webrtcbin == NULL, "webrtcbin is NULL");
 
-       stats_userdata = g_new0(stats_userdata_s, 1);
-       stats_userdata->webrtc = webrtc;
-       stats_userdata->type_mask = type_mask;
+       userdata = g_new0(promise_userdata_s, 1);
+       userdata->webrtc = webrtc;
+       userdata->type_mask = type_mask;
+       if (callback) {
+               userdata->stats_cb.callback = callback;
+               userdata->stats_cb.user_data = user_data;
+       }
 
-       promise = gst_promise_new_with_change_func((GstPromiseChangeFunc)__webrtcbin_get_stats_cb, stats_userdata, NULL);
+       promise = gst_promise_new_with_change_func((GstPromiseChangeFunc)__webrtcbin_get_stats_cb, userdata, g_free);
 
        g_signal_emit_by_name(webrtc->gst.webrtcbin, "get-stats", NULL, promise);
        LOG_DEBUG("emitting 'get-stats' on %p", webrtc->gst.webrtcbin);
@@ -615,7 +638,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);
+               _webrtcbin_get_stats(webrtc, STATS_TYPE_ALL_MASK, NULL, NULL);
 
        return G_SOURCE_CONTINUE;
 }
@@ -657,4 +680,4 @@ void _init_stats_all_fields_list(void)
                        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
+//LCOV_EXCL_STOP