diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c index 75908c00e6..3c26e3467c 100644 --- a/gst/rtpmanager/rtpsession.c +++ b/gst/rtpmanager/rtpsession.c @@ -47,6 +47,7 @@ enum SIGNAL_ON_TIMEOUT, SIGNAL_ON_SENDER_TIMEOUT, SIGNAL_ON_SENDING_RTCP, + SIGNAL_ON_APP_RTCP, SIGNAL_ON_FEEDBACK_RTCP, SIGNAL_SEND_RTCP, SIGNAL_SEND_RTCP_FULL, @@ -296,6 +297,23 @@ rtp_session_class_init (RTPSessionClass * klass) accumulate_trues, NULL, g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 2, GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, G_TYPE_BOOLEAN); + /** + * RTPSession::on-app-rtcp: + * @session: the object which received the signal + * @subtype: The subtype of the packet + * @ssrc: The SSRC/CSRC of the packet + * @name: The name of the packet + * @data: a #GstBuffer with the application-dependant data or %NULL if + * there was no data + * + * Notify that a RTCP APP packet has been received + */ + rtp_session_signals[SIGNAL_ON_APP_RTCP] = + g_signal_new ("on-app-rtcp", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_app_rtcp), + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 4, + G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING, GST_TYPE_BUFFER); + /** * RTPSession::on-feedback-rtcp: * @session: the object which received the signal @@ -2517,6 +2535,33 @@ rtp_session_process_app (RTPSession * sess, GstRTCPPacket * packet, RTPPacketInfo * pinfo) { GST_DEBUG ("received APP"); + + if (g_signal_has_handler_pending (sess, + rtp_session_signals[SIGNAL_ON_APP_RTCP], 0, TRUE)) { + GstBuffer *data_buffer = NULL; + guint16 data_length; + gchar name[5]; + + data_length = gst_rtcp_packet_app_get_data_length (packet) * 4; + if (data_length > 0) { + guint8 *data = gst_rtcp_packet_app_get_data (packet); + data_buffer = gst_buffer_copy_region (packet->rtcp->buffer, + GST_BUFFER_COPY_MEMORY, data - packet->rtcp->map.data, data_length); + GST_BUFFER_PTS (data_buffer) = pinfo->running_time; + } + + memcpy (name, gst_rtcp_packet_app_get_name (packet), 4); + name[4] = '\0'; + + RTP_SESSION_UNLOCK (sess); + g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_APP_RTCP], 0, + gst_rtcp_packet_app_get_subtype (packet), + gst_rtcp_packet_app_get_ssrc (packet), name, data_buffer); + RTP_SESSION_LOCK (sess); + + if (data_buffer) + gst_buffer_unref (data_buffer); + } } static gboolean diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h index 3d99359059..9fa9327c70 100644 --- a/gst/rtpmanager/rtpsession.h +++ b/gst/rtpmanager/rtpsession.h @@ -309,6 +309,8 @@ struct _RTPSessionClass { void (*on_sender_timeout) (RTPSession *sess, RTPSource *source); gboolean (*on_sending_rtcp) (RTPSession *sess, GstBuffer *buffer, gboolean early); + void (*on_app_rtcp) (RTPSession *sess, guint subtype, guint ssrc, + const gchar *name, GstBuffer *data); void (*on_feedback_rtcp) (RTPSession *sess, guint type, guint fbtype, guint sender_ssrc, guint media_ssrc, GstBuffer *fci); gboolean (*send_rtcp) (RTPSession *sess, GstClockTime max_delay); diff --git a/tests/check/elements/rtpsession.c b/tests/check/elements/rtpsession.c index f7c1bdf815..296b958a9c 100644 --- a/tests/check/elements/rtpsession.c +++ b/tests/check/elements/rtpsession.c @@ -21,6 +21,7 @@ * Boston, MA 02110-1301, USA. */ +#include #include #include @@ -576,6 +577,87 @@ GST_START_TEST (test_internal_sources_timeout) GST_END_TEST; +typedef struct +{ + guint8 subtype; + guint32 ssrc; + gchar *name; + GstBuffer *data; +} RTCPAppResult; + +static void +on_app_rtcp_cb (GObject * session, guint subtype, guint ssrc, + const gchar * name, GstBuffer * data, RTCPAppResult * result) +{ + result->subtype = subtype; + result->ssrc = ssrc; + result->name = g_strdup (name); + result->data = data ? gst_buffer_ref (data) : NULL; +} + +GST_START_TEST (test_receive_rtcp_app_packet) +{ + GstHarness *h; + GstBuffer *buffer; + GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT; + GstRTCPPacket packet; + RTCPAppResult result = { 0 }; + GstElement *internal_session; + guint8 data[] = { 0x11, 0x22, 0x33, 0x44 }; + + h = gst_harness_new_with_padnames ("rtpsession", "recv_rtcp_sink", NULL); + g_object_get (h->element, "internal-session", &internal_session, NULL); + + g_signal_connect (internal_session, "on-app-rtcp", + G_CALLBACK (on_app_rtcp_cb), &result); + + /* Push APP buffer with no data */ + buffer = gst_rtcp_buffer_new (1000); + fail_unless (gst_rtcp_buffer_map (buffer, GST_MAP_READWRITE, &rtcp)); + fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_APP, &packet)); + gst_rtcp_packet_app_set_subtype (&packet, 21); + gst_rtcp_packet_app_set_ssrc (&packet, 0x11111111); + gst_rtcp_packet_app_set_name (&packet, "Test"); + gst_rtcp_buffer_unmap (&rtcp); + + gst_harness_set_src_caps_str (h, "application/x-rtcp"); + fail_unless_equals_int (gst_harness_push (h, buffer), GST_FLOW_OK); + + fail_unless_equals_int (result.subtype, 21); + fail_unless_equals_int (result.ssrc, 0x11111111); + fail_unless_equals_string (result.name, "Test"); + fail_unless_equals_pointer (result.data, NULL); + + g_free (result.name); + + /* Push APP buffer with data */ + memset (&result, 0, sizeof (result)); + buffer = gst_rtcp_buffer_new (1000); + fail_unless (gst_rtcp_buffer_map (buffer, GST_MAP_READWRITE, &rtcp)); + fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_APP, &packet)); + gst_rtcp_packet_app_set_subtype (&packet, 22); + gst_rtcp_packet_app_set_ssrc (&packet, 0x22222222); + gst_rtcp_packet_app_set_name (&packet, "Test"); + gst_rtcp_packet_app_set_data_length (&packet, sizeof (data) / 4); + memcpy (gst_rtcp_packet_app_get_data (&packet), data, sizeof (data)); + gst_rtcp_buffer_unmap (&rtcp); + + fail_unless_equals_int (gst_harness_push (h, buffer), GST_FLOW_OK); + + fail_unless_equals_int (result.subtype, 22); + fail_unless_equals_int (result.ssrc, 0x22222222); + fail_unless_equals_string (result.name, "Test"); + fail_unless (gst_buffer_memcmp (result.data, 0, data, sizeof (data)) == 0); + + g_free (result.name); + gst_buffer_unref (result.data); + + gst_object_unref (internal_session); + gst_harness_teardown (h); +} + +GST_END_TEST; + static Suite * rtpsession_suite (void) { @@ -586,6 +668,7 @@ rtpsession_suite (void) tcase_add_test (tc_chain, test_multiple_ssrc_rr); tcase_add_test (tc_chain, test_multiple_senders_roundrobin_rbs); tcase_add_test (tc_chain, test_internal_sources_timeout); + tcase_add_test (tc_chain, test_receive_rtcp_app_packet); return s; }