webrtc: produce stats for all relevant streams
authorMatthew Waters <matthew@centricular.com>
Mon, 21 Feb 2022 03:02:52 +0000 (14:02 +1100)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Tue, 29 Mar 2022 23:55:41 +0000 (23:55 +0000)
Instead of only using the last ssrc that was pushed into a sink pad.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1664>

subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.c
subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcbin.h
subprojects/gst-plugins-bad/ext/webrtc/gstwebrtcstats.c

index 10d617f..0584e08 100644 (file)
@@ -441,37 +441,6 @@ gst_webrtc_bin_pad_init (GstWebRTCBinPad * pad)
 {
 }
 
-static GstPadProbeReturn
-webrtc_bin_pad_buffer_cb (GstPad * pad, GstPadProbeInfo * info,
-    gpointer user_data)
-{
-  GstWebRTCBinPad *wpad;
-  GstBuffer *buf;
-  GstRTPBuffer rtpbuf = GST_RTP_BUFFER_INIT;
-
-  if (info->type & GST_PAD_PROBE_TYPE_BUFFER) {
-    buf = GST_PAD_PROBE_INFO_BUFFER (info);
-  } else {
-    GstBufferList *list;
-
-    list = GST_PAD_PROBE_INFO_BUFFER_LIST (info);
-    buf = gst_buffer_list_get (list, 0);
-  }
-
-  if (buf == NULL)
-    return GST_PAD_PROBE_OK;
-
-  if (!gst_rtp_buffer_map (buf, GST_MAP_READ, &rtpbuf))
-    return GST_PAD_PROBE_OK;
-
-  wpad = GST_WEBRTC_BIN_PAD (pad);
-  wpad->last_ssrc = gst_rtp_buffer_get_ssrc (&rtpbuf);
-
-  gst_rtp_buffer_unmap (&rtpbuf);
-
-  return GST_PAD_PROBE_OK;
-}
-
 static GstWebRTCBinPad *
 gst_webrtc_bin_pad_new (const gchar * name, GstPadDirection direction)
 {
@@ -493,9 +462,6 @@ gst_webrtc_bin_pad_new (const gchar * name, GstPadDirection direction)
   gst_pad_set_event_function (GST_PAD (pad), gst_webrtcbin_sink_event);
   gst_pad_set_query_function (GST_PAD (pad), gst_webrtcbin_sink_query);
 
-  gst_pad_add_probe (GST_PAD (pad), GST_PAD_PROBE_TYPE_BUFFER |
-      GST_PAD_PROBE_TYPE_BUFFER_LIST, webrtc_bin_pad_buffer_cb, NULL, NULL);
-
   GST_DEBUG_OBJECT (pad, "new visible pad with direction %s",
       direction == GST_PAD_SRC ? "src" : "sink");
   return pad;
index 232bb45..06f12ed 100644 (file)
@@ -46,8 +46,6 @@ struct _GstWebRTCBinPad
   GstWebRTCRTPTransceiver *trans;
   gulong                block_id;
 
-  guint32               last_ssrc;
-
   GstCaps              *received_caps;
 };
 
index 1d0dfb1..4931a42 100644 (file)
@@ -697,72 +697,6 @@ _get_stats_from_dtls_transport (GstWebRTCBin * webrtc,
   return id;
 }
 
-static void
-_get_stats_from_transport_channel (GstWebRTCBin * webrtc,
-    TransportStream * stream, const gchar * codec_id, guint ssrc,
-    guint clock_rate, GstStructure * s)
-{
-  GstWebRTCDTLSTransport *transport;
-  GObject *rtp_session;
-  GObject *gst_rtp_session;
-  GstStructure *rtp_stats, *twcc_stats;
-  GValueArray *source_stats;
-  gchar *transport_id;
-  double ts;
-  int i;
-
-  gst_structure_get_double (s, "timestamp", &ts);
-
-  transport = stream->transport;
-  if (!transport)
-    return;
-
-  g_signal_emit_by_name (webrtc->rtpbin, "get-internal-session",
-      stream->session_id, &rtp_session);
-  g_object_get (rtp_session, "stats", &rtp_stats, NULL);
-  g_signal_emit_by_name (webrtc->rtpbin, "get-session",
-      stream->session_id, &gst_rtp_session);
-  g_object_get (gst_rtp_session, "twcc-stats", &twcc_stats, NULL);
-
-  gst_structure_get (rtp_stats, "source-stats", G_TYPE_VALUE_ARRAY,
-      &source_stats, NULL);
-
-  GST_DEBUG_OBJECT (webrtc, "retrieving rtp stream stats from transport %"
-      GST_PTR_FORMAT " rtp session %" GST_PTR_FORMAT " with %u rtp sources, "
-      "transport %" GST_PTR_FORMAT, stream, rtp_session, source_stats->n_values,
-      transport);
-
-  transport_id =
-      _get_stats_from_dtls_transport (webrtc, transport, twcc_stats, s);
-
-  /* construct stats objects */
-  for (i = 0; i < source_stats->n_values; i++) {
-    const GstStructure *stats;
-    const GValue *val = g_value_array_get_nth (source_stats, i);
-    guint stats_ssrc = 0;
-
-    stats = gst_value_get_structure (val);
-
-    /* skip foreign sources */
-    if (gst_structure_get_uint (stats, "ssrc", &stats_ssrc) &&
-        ssrc == stats_ssrc)
-      _get_stats_from_rtp_source_stats (webrtc, stream, stats, codec_id,
-          transport_id, s);
-    else if (gst_structure_get_uint (stats, "rb-ssrc", &stats_ssrc) &&
-        ssrc == stats_ssrc)
-      _get_stats_from_remote_rtp_source_stats (webrtc, stream, stats, ssrc,
-          clock_rate, codec_id, transport_id, s);
-  }
-
-  g_object_unref (rtp_session);
-  g_object_unref (gst_rtp_session);
-  gst_structure_free (rtp_stats);
-  if (twcc_stats)
-    gst_structure_free (twcc_stats);
-  g_value_array_free (source_stats);
-  g_free (transport_id);
-}
-
 /* https://www.w3.org/TR/webrtc-stats/#codec-dict* */
 static gboolean
 _get_codec_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad,
@@ -860,33 +794,110 @@ _get_codec_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad,
   return has_caps_ssrc;
 }
 
+struct transport_stream_stats
+{
+  GstWebRTCBin *webrtc;
+  TransportStream *stream;
+  char *transport_id;
+  char *codec_id;
+  guint clock_rate;
+  GValueArray *source_stats;
+  GstStructure *s;
+};
+
+static gboolean
+webrtc_stats_get_from_transport (SsrcMapItem * entry,
+    struct transport_stream_stats *ts_stats)
+{
+  double ts;
+  int i;
+
+  gst_structure_get_double (ts_stats->s, "timestamp", &ts);
+
+  /* construct stats objects */
+  for (i = 0; i < ts_stats->source_stats->n_values; i++) {
+    const GstStructure *stats;
+    const GValue *val = g_value_array_get_nth (ts_stats->source_stats, i);
+    guint stats_ssrc = 0;
+
+    stats = gst_value_get_structure (val);
+
+    /* skip foreign sources */
+    if (gst_structure_get_uint (stats, "ssrc", &stats_ssrc) &&
+        entry->ssrc == stats_ssrc)
+      _get_stats_from_rtp_source_stats (ts_stats->webrtc, ts_stats->stream,
+          stats, ts_stats->codec_id, ts_stats->transport_id, ts_stats->s);
+    else if (gst_structure_get_uint (stats, "rb-ssrc", &stats_ssrc) &&
+        entry->ssrc == stats_ssrc)
+      _get_stats_from_remote_rtp_source_stats (ts_stats->webrtc,
+          ts_stats->stream, stats, entry->ssrc, ts_stats->clock_rate,
+          ts_stats->codec_id, ts_stats->transport_id, ts_stats->s);
+  }
+
+  /* we want to look at all the entries */
+  return FALSE;
+}
+
 static gboolean
 _get_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad, GstStructure * s)
 {
   GstWebRTCBinPad *wpad = GST_WEBRTC_BIN_PAD (pad);
-  TransportStream *stream;
-  gchar *codec_id;
+  struct transport_stream_stats ts_stats = { NULL, };
   guint ssrc, clock_rate;
-  gboolean has_caps_ssrc;
+  GObject *rtp_session;
+  GObject *gst_rtp_session;
+  GstStructure *rtp_stats, *twcc_stats;
 
-  has_caps_ssrc = _get_codec_stats_from_pad (webrtc, pad, s, &codec_id, &ssrc,
+  _get_codec_stats_from_pad (webrtc, pad, s, &ts_stats.codec_id, &ssrc,
       &clock_rate);
 
   if (!wpad->trans)
     goto out;
 
-  stream = WEBRTC_TRANSCEIVER (wpad->trans)->stream;
-  if (!stream)
+  ts_stats.stream = WEBRTC_TRANSCEIVER (wpad->trans)->stream;
+  if (!ts_stats.stream)
+    goto out;
+
+  if (wpad->trans->mline == G_MAXUINT)
+    goto out;
+
+  if (!ts_stats.stream->transport)
     goto out;
 
-  if (!has_caps_ssrc)
-    ssrc = wpad->last_ssrc;
+  g_signal_emit_by_name (webrtc->rtpbin, "get-internal-session",
+      ts_stats.stream->session_id, &rtp_session);
+  g_object_get (rtp_session, "stats", &rtp_stats, NULL);
+  g_signal_emit_by_name (webrtc->rtpbin, "get-session",
+      ts_stats.stream->session_id, &gst_rtp_session);
+  g_object_get (gst_rtp_session, "twcc-stats", &twcc_stats, NULL);
+
+  gst_structure_get (rtp_stats, "source-stats", G_TYPE_VALUE_ARRAY,
+      &ts_stats.source_stats, NULL);
+
+  ts_stats.transport_id =
+      _get_stats_from_dtls_transport (webrtc, ts_stats.stream->transport,
+      twcc_stats, s);
+
+  GST_DEBUG_OBJECT (webrtc, "retrieving rtp stream stats from transport %"
+      GST_PTR_FORMAT " rtp session %" GST_PTR_FORMAT " with %u rtp sources, "
+      "transport %" GST_PTR_FORMAT, ts_stats.stream, rtp_session,
+      ts_stats.source_stats->n_values, ts_stats.stream->transport);
+
+  ts_stats.s = s;
+
+  transport_stream_find_ssrc_map_item (ts_stats.stream, &ts_stats,
+      (FindSsrcMapFunc) webrtc_stats_get_from_transport);
 
-  _get_stats_from_transport_channel (webrtc, stream, codec_id, ssrc,
-      clock_rate, s);
+  g_clear_object (&rtp_session);
+  g_clear_object (&gst_rtp_session);
+  gst_clear_structure (&rtp_stats);
+  gst_clear_structure (&twcc_stats);
+  g_value_array_free (ts_stats.source_stats);
+  ts_stats.source_stats = NULL;
+  g_clear_pointer (&ts_stats.transport_id, g_free);
 
 out:
-  g_free (codec_id);
+  g_clear_pointer (&ts_stats.codec_id, g_free);
   return TRUE;
 }