return data + 12;
}
+
+/**
+ * gst_rtcp_packet_app_set_subtype:
+ * @packet: a valid APP #GstRTCPPacket
+ * @subtype: subtype of the packet
+ *
+ * Set the subtype field of the APP @packet.
+ *
+ * Since: 1.8
+ **/
+void
+gst_rtcp_packet_app_set_subtype (GstRTCPPacket * packet, guint8 subtype)
+{
+ guint8 *data;
+
+ g_return_if_fail (packet != NULL);
+ g_return_if_fail (packet->type == GST_RTCP_TYPE_APP);
+ g_return_if_fail (packet->rtcp != NULL);
+ g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
+
+ data = packet->rtcp->map.data + packet->offset;
+ data[0] = (data[0] & 0xe0) | subtype;
+}
+
+/**
+ * gst_rtcp_packet_app_get_subtype:
+ * @packet: a valid APP #GstRTCPPacket
+ *
+ * Get the subtype field of the APP @packet.
+ *
+ * Returns: The subtype.
+ *
+ * Since: 1.8
+ */
+guint8
+gst_rtcp_packet_app_get_subtype (GstRTCPPacket * packet)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (packet != NULL, 0);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, 0);
+ g_return_val_if_fail (packet->rtcp != NULL, 0);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
+
+ data = packet->rtcp->map.data + packet->offset;
+
+ return data[0] & 0x1f;
+}
+
+/**
+ * gst_rtcp_packet_app_set_ssrc:
+ * @packet: a valid APP #GstRTCPPacket
+ * @ssrc: SSRC/CSRC of the packet
+ *
+ * Set the SSRC/CSRC field of the APP @packet.
+ *
+ * Since: 1.8
+ **/
+void
+gst_rtcp_packet_app_set_ssrc (GstRTCPPacket * packet, guint32 ssrc)
+{
+ guint8 *data;
+
+ g_return_if_fail (packet != NULL);
+ g_return_if_fail (packet->type == GST_RTCP_TYPE_APP);
+ g_return_if_fail (packet->rtcp != NULL);
+ g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
+
+ data = packet->rtcp->map.data + packet->offset + 4;
+ GST_WRITE_UINT32_BE (data, ssrc);
+}
+
+/**
+ * gst_rtcp_packet_app_get_ssrc:
+ * @packet: a valid APP #GstRTCPPacket
+ *
+ * Get the SSRC/CSRC field of the APP @packet.
+ *
+ * Returns: The SSRC/CSRC.
+ *
+ * Since: 1.8
+ **/
+guint32
+gst_rtcp_packet_app_get_ssrc (GstRTCPPacket * packet)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (packet != NULL, 0);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, 0);
+ g_return_val_if_fail (packet->rtcp != NULL, 0);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
+
+ data = packet->rtcp->map.data + packet->offset + 4;
+
+ return GST_READ_UINT32_BE (data);
+}
+
+/**
+ * gst_rtcp_packet_app_set_name:
+ * @packet: a valid APP #GstRTCPPacket
+ * @name: 4-byte ASCII name
+ *
+ * Set the name field of the APP @packet.
+ *
+ * Since: 1.8
+ **/
+void
+gst_rtcp_packet_app_set_name (GstRTCPPacket * packet, const gchar * name)
+{
+ guint8 *data;
+
+ g_return_if_fail (packet != NULL);
+ g_return_if_fail (packet->type == GST_RTCP_TYPE_APP);
+ g_return_if_fail (packet->rtcp != NULL);
+ g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
+
+ data = packet->rtcp->map.data + packet->offset + 8;
+ memcpy (data, name, 4);
+}
+
+/**
+ * gst_rtcp_packet_app_get_name:
+ * @packet: a valid APP #GstRTCPPacket
+ *
+ * Get the name field of the APP @packet.
+ *
+ * Returns: The 4-byte name field, not zero-terminated.
+ *
+ * Since: 1.8
+ **/
+const gchar *
+gst_rtcp_packet_app_get_name (GstRTCPPacket * packet)
+{
+ g_return_val_if_fail (packet != NULL, NULL);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, NULL);
+ g_return_val_if_fail (packet->rtcp != NULL, NULL);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
+
+ return (const gchar *)&packet->rtcp->map.data[packet->offset + 8];
+}
+
+/**
+ * gst_rtcp_packet_app_get_data_length:
+ * @packet: a valid APP #GstRTCPPacket
+ *
+ * Get the length of the application-dependent data attached to an APP
+ * @packet.
+ *
+ * Returns: The length of data in 32-bit words.
+ *
+ * Since: 1.8
+ **/
+guint16
+gst_rtcp_packet_app_get_data_length (GstRTCPPacket * packet)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (packet != NULL, 0);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, 0);
+ g_return_val_if_fail (packet->rtcp != NULL, 0);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
+
+ data = packet->rtcp->map.data + packet->offset + 2;
+
+ return GST_READ_UINT16_BE (data) - 2;
+}
+
+/**
+ * gst_rtcp_packet_app_set_data_length:
+ * @packet: a valid APP #GstRTCPPacket
+ * @wordlen: Length of the data in 32-bit words
+ *
+ * Set the length of the application-dependent data attached to an APP
+ * @packet.
+ *
+ * Returns: %TRUE if there was enough space in the packet to add this much
+ * data.
+ *
+ * Since: 1.8
+ */
+gboolean
+gst_rtcp_packet_app_set_data_length (GstRTCPPacket * packet, guint16 wordlen)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (packet != NULL, FALSE);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, FALSE);
+ g_return_val_if_fail (packet->rtcp != NULL, FALSE);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
+
+ if (packet->rtcp->map.maxsize < packet->offset + ((wordlen + 3) * 4))
+ return FALSE;
+
+ data = packet->rtcp->map.data + packet->offset + 2;
+ wordlen += 2;
+ GST_WRITE_UINT16_BE (data, wordlen);
+
+ packet->rtcp->map.size = packet->offset + ((wordlen + 1) * 4);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_app_get_data:
+ * @packet: a valid APP #GstRTCPPacket
+ *
+ * Get the application-dependent data attached to a RTPFB or PSFB @packet.
+ *
+ * Returns: A pointer to the data
+ *
+ * Since: 1.8
+ */
+guint8 *
+gst_rtcp_packet_app_get_data (GstRTCPPacket * packet)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (packet != NULL, NULL);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, NULL);
+ g_return_val_if_fail (packet->rtcp != NULL, NULL);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
+
+ data = packet->rtcp->map.data + packet->offset;
+
+ if (GST_READ_UINT16_BE (data + 2) <= 2)
+ return NULL;
+
+ return data + 12;
+}
}
GST_END_TEST;
+GST_START_TEST (test_rtcp_buffer_app)
+{
+ GstBuffer *buf;
+ GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+ GstRTCPPacket packet;
+ guint mtu = 1000;
+ const guint8 data[] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 };
+ guint max_data_length = (mtu - 12) / 4;
+ guint8 *data_ptr;
+
+ fail_unless ((buf = gst_rtcp_buffer_new (mtu)) != NULL);
+ gst_rtcp_buffer_map (buf, GST_MAP_READWRITE, &rtcp);
+
+ /* Not a valid packet yet */
+ fail_if (gst_rtcp_buffer_validate (buf));
+ fail_if (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+ fail_unless_equals_int (gst_rtcp_buffer_get_packet_count (&rtcp), 0);
+
+ /* Add APP packet */
+ fail_unless (gst_rtcp_buffer_add_packet (&rtcp, GST_RTCP_TYPE_APP, &packet));
+ gst_rtcp_packet_app_set_subtype (&packet, 0x15);
+ gst_rtcp_packet_app_set_ssrc (&packet, 0x01234567);
+ gst_rtcp_packet_app_set_name (&packet, "Test");
+
+ /* Check maximum allowed data */
+ fail_if (gst_rtcp_packet_app_set_data_length (&packet, max_data_length + 1));
+ fail_unless (gst_rtcp_packet_app_set_data_length (&packet, max_data_length));
+
+ /* Add data */
+ fail_unless (gst_rtcp_packet_app_set_data_length (&packet, (sizeof (data) + 3) / 4));
+ fail_unless_equals_int (gst_rtcp_packet_app_get_data_length (&packet), 2);
+ fail_unless ((data_ptr = gst_rtcp_packet_app_get_data (&packet)));
+ memcpy (data_ptr, data, sizeof (data));
+
+ gst_rtcp_buffer_unmap (&rtcp);
+
+ /* Map again with only the READ flag and check fields */
+ gst_rtcp_buffer_map (buf, GST_MAP_READ, &rtcp);
+ fail_unless_equals_int (gst_rtcp_packet_app_get_subtype (&packet), 0x15);
+ fail_unless_equals_int (gst_rtcp_packet_app_get_ssrc (&packet), 0x01234567);
+ fail_unless (memcmp (gst_rtcp_packet_app_get_name (&packet), "Test", 4) == 0);
+ fail_unless_equals_int (gst_rtcp_packet_app_get_data_length (&packet), 2);
+ fail_unless ((data_ptr = gst_rtcp_packet_app_get_data (&packet)));
+ fail_unless (memcmp (data_ptr, data, sizeof (data)) == 0);
+ gst_rtcp_buffer_unmap (&rtcp);
+
+ gst_buffer_unref (buf);
+}
+GST_END_TEST;
+
GST_START_TEST (test_rtp_ntp64_extension)
{
GstBuffer *buf;
tcase_add_test (tc_chain, test_rtcp_validate_reduced_without_padding);
tcase_add_test (tc_chain, test_rtcp_validate_reduced_with_padding);
tcase_add_test (tc_chain, test_rtcp_buffer_profile_specific_extension);
+ tcase_add_test (tc_chain, test_rtcp_buffer_app);
tcase_add_test (tc_chain, test_rtp_ntp64_extension);
tcase_add_test (tc_chain, test_rtp_ntp56_extension);