From ec06268ed8ec5a6e4a07542ca7b5147df6ef8f90 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 27 Mar 2019 16:19:15 -0400 Subject: [PATCH] rtpsession: Allow overriding NACK packet creation This introduce a new signal on RTSession, on-sending-nacks is emited right before the list of seqnums to be nacked are processed and transformed into FB Nack. This allow implementing custom nacks handling through another mechanism with APP feedback. --- gst/rtpmanager/rtpsession.c | 59 +++++++++++++++++++++++++++++++++++-- gst/rtpmanager/rtpsession.h | 2 ++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index b7354c10b0..bc952c2131 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -54,6 +54,7 @@ enum SIGNAL_ON_RECEIVING_RTCP, SIGNAL_ON_NEW_SENDER_SSRC, SIGNAL_ON_SENDER_SSRC_ACTIVE, + SIGNAL_ON_SENDING_NACKS, LAST_SIGNAL }; @@ -422,6 +423,39 @@ rtp_session_class_init (RTPSessionClass * klass) on_sender_ssrc_active), NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, RTP_TYPE_SOURCE); + /** + * RTPSession::on-sending-nack + * @session: the object which received the signal + * @sender_ssrc: the sender ssrc + * @media_ssrc: the media ssrc + * @nacks: (element-type guint16): the list of seqnum to be nacked + * @buffer: the #GstBuffer containing the RTCP packet about to be sent + * + * This signal is emitted before NACK packets are added into the RTCP + * packet. This signal can be used to override the conversion of the NACK + * seqnum array into packets. This can be used if your protocol uses + * different type of NACK (e.g. based on RTCP APP). + * + * The handler should transform the seqnum from @nacks array into packets. + * @nacks seqnum must be consumed from the start. The remaining will be + * rescheduled for later base on bandwidth. Only one handler will be + * signalled. + * + * A handler may return 0 to signal that generic NACKs should be created + * for this set. This can be useful if the signal is used for other purpose + * or if the other type of NACK would use more space. + * + * Returns: the number of NACK seqnum that was consumed from @nacks. + * + * Since: 1.16 + */ + rtp_session_signals[SIGNAL_ON_SENDING_NACKS] = + g_signal_new ("on-sending-nacks", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_sending_nacks), + g_signal_accumulator_first_wins, NULL, g_cclosure_marshal_generic, + G_TYPE_UINT, 4, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_ARRAY, + GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE); + g_object_class_install_property (gobject_class, PROP_INTERNAL_SSRC, g_param_spec_uint ("internal-ssrc", "Internal SSRC", "The internal SSRC used for the session (deprecated)", @@ -3607,6 +3641,7 @@ session_pli (const gchar * key, RTPSource * source, ReportData * data) static void session_nack (const gchar * key, RTPSource * source, ReportData * data) { + RTPSession *sess = data->sess; GstRTCPBuffer *rtcp = &data->rtcpbuf; GstRTCPPacket *packet = &data->packet; guint16 *nacks; @@ -3639,6 +3674,23 @@ session_nack (const gchar * key, RTPSource * source, ReportData * data) return; } + /* allow overriding NACK to packet conversion */ + if (g_signal_has_handler_pending (sess, + rtp_session_signals[SIGNAL_ON_SENDING_NACKS], 0, TRUE)) { + /* this is needed as it will actually resize the buffer */ + gst_rtcp_buffer_unmap (rtcp); + + g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SENDING_NACKS], 0, + data->source->ssrc, source->ssrc, source->nacks, data->rtcp, + &nacked_seqnums); + + /* and now remap for the remaining work */ + gst_rtcp_buffer_map (data->rtcp, GST_MAP_READWRITE, rtcp); + + if (nacked_seqnums > 0) + goto done; + } + if (!gst_rtcp_buffer_add_packet (rtcp, GST_RTCP_TYPE_RTPFB, packet)) /* exit because the packet is full, will put next request in a * further packet */ @@ -3682,12 +3734,13 @@ session_nack (const gchar * key, RTPSource * source, ReportData * data) fci_data += 4; } + GST_DEBUG ("Sent %u seqnums into %u FB NACKs", nacked_seqnums, n_fb_nacks); + source->stats.sent_nack_count += n_fb_nacks; + +done: data->nacked_seqnums += nacked_seqnums; rtp_source_clear_nacks (source, nacked_seqnums); data->may_suppress = FALSE; - source->stats.sent_nack_count += n_fb_nacks; - - GST_DEBUG ("Sent %u seqnums into %u FB NACKs", nacked_seqnums, n_fb_nacks); } /* perform cleanup of sources that timed out */ diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h index 9158f48669..7ab229ad56 100644 --- a/gst/rtpmanager/rtpsession.h +++ b/gst/rtpmanager/rtpsession.h @@ -330,6 +330,8 @@ struct _RTPSessionClass { void (*on_receiving_rtcp) (RTPSession *sess, GstBuffer *buffer); void (*on_new_sender_ssrc) (RTPSession *sess, RTPSource *source); void (*on_sender_ssrc_active) (RTPSession *sess, RTPSource *source); + guint (*on_sending_nacks) (RTPSession *sess, guint sender_ssrc, + guint media_ssrc, GArray *nacks, GstBuffer *buffer); }; GType rtp_session_get_type (void);