rtpsession: Add new signal 'on-app-rtcp'
authorStian Selnes <stian@pexip.com>
Tue, 17 Nov 2015 17:17:35 +0000 (18:17 +0100)
committerSebastian Dröge <sebastian@centricular.com>
Wed, 30 Mar 2016 12:42:01 +0000 (15:42 +0300)
Similar to the 'on-feedback-rtcp' signal, but emitted for RTCP APP
packets.

https://bugzilla.gnome.org/show_bug.cgi?id=762217

gst/rtpmanager/rtpsession.c
gst/rtpmanager/rtpsession.h
tests/check/elements/rtpsession.c

index 75908c0..3c26e34 100644 (file)
@@ -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,
@@ -297,6 +298,23 @@ rtp_session_class_init (RTPSessionClass * klass)
       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
    * @type: Type of RTCP packet, will be %GST_RTCP_TYPE_RTPFB or
@@ -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
index 3d99359..9fa9327 100644 (file)
@@ -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);
index f7c1bdf..296b958 100644 (file)
@@ -21,6 +21,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
+#include <gst/check/gstharness.h>
 #include <gst/check/gstcheck.h>
 #include <gst/check/gsttestclock.h>
 
@@ -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;
 }