mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-25 16:48:11 +00:00
webrtc: produce stats for all relevant streams
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>
This commit is contained in:
parent
04de1a161f
commit
041eee6c2e
3 changed files with 88 additions and 113 deletions
|
@ -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 *
|
static GstWebRTCBinPad *
|
||||||
gst_webrtc_bin_pad_new (const gchar * name, GstPadDirection direction)
|
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_event_function (GST_PAD (pad), gst_webrtcbin_sink_event);
|
||||||
gst_pad_set_query_function (GST_PAD (pad), gst_webrtcbin_sink_query);
|
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",
|
GST_DEBUG_OBJECT (pad, "new visible pad with direction %s",
|
||||||
direction == GST_PAD_SRC ? "src" : "sink");
|
direction == GST_PAD_SRC ? "src" : "sink");
|
||||||
return pad;
|
return pad;
|
||||||
|
|
|
@ -46,8 +46,6 @@ struct _GstWebRTCBinPad
|
||||||
GstWebRTCRTPTransceiver *trans;
|
GstWebRTCRTPTransceiver *trans;
|
||||||
gulong block_id;
|
gulong block_id;
|
||||||
|
|
||||||
guint32 last_ssrc;
|
|
||||||
|
|
||||||
GstCaps *received_caps;
|
GstCaps *received_caps;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -697,72 +697,6 @@ _get_stats_from_dtls_transport (GstWebRTCBin * webrtc,
|
||||||
return id;
|
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* */
|
/* https://www.w3.org/TR/webrtc-stats/#codec-dict* */
|
||||||
static gboolean
|
static gboolean
|
||||||
_get_codec_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad,
|
_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;
|
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
|
static gboolean
|
||||||
_get_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad, GstStructure * s)
|
_get_stats_from_pad (GstWebRTCBin * webrtc, GstPad * pad, GstStructure * s)
|
||||||
{
|
{
|
||||||
GstWebRTCBinPad *wpad = GST_WEBRTC_BIN_PAD (pad);
|
GstWebRTCBinPad *wpad = GST_WEBRTC_BIN_PAD (pad);
|
||||||
TransportStream *stream;
|
struct transport_stream_stats ts_stats = { NULL, };
|
||||||
gchar *codec_id;
|
|
||||||
guint ssrc, clock_rate;
|
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);
|
&clock_rate);
|
||||||
|
|
||||||
if (!wpad->trans)
|
if (!wpad->trans)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
stream = WEBRTC_TRANSCEIVER (wpad->trans)->stream;
|
ts_stats.stream = WEBRTC_TRANSCEIVER (wpad->trans)->stream;
|
||||||
if (!stream)
|
if (!ts_stats.stream)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (!has_caps_ssrc)
|
if (wpad->trans->mline == G_MAXUINT)
|
||||||
ssrc = wpad->last_ssrc;
|
goto out;
|
||||||
|
|
||||||
_get_stats_from_transport_channel (webrtc, stream, codec_id, ssrc,
|
if (!ts_stats.stream->transport)
|
||||||
clock_rate, s);
|
goto out;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
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:
|
out:
|
||||||
g_free (codec_id);
|
g_clear_pointer (&ts_stats.codec_id, g_free);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue