rtcpbuffer: Add API for APP packets

https://bugzilla.gnome.org/show_bug.cgi?id=761944
This commit is contained in:
Stian Selnes 2015-10-06 17:02:03 +02:00 committed by Sebastian Dröge
parent d8e9a711a0
commit 93196092d1
3 changed files with 291 additions and 0 deletions

View file

@ -2311,3 +2311,232 @@ gst_rtcp_packet_fb_get_fci (GstRTCPPacket * packet)
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;
}

View file

@ -315,6 +315,17 @@ guint8 gst_rtcp_packet_bye_get_reason_len (GstRTCPPacket *packet);
gchar* gst_rtcp_packet_bye_get_reason (GstRTCPPacket *packet);
gboolean gst_rtcp_packet_bye_set_reason (GstRTCPPacket *packet, const gchar *reason);
/* app packets */
void gst_rtcp_packet_app_set_subtype (GstRTCPPacket * packet, guint8 subtype);
guint8 gst_rtcp_packet_app_get_subtype (GstRTCPPacket * packet);
void gst_rtcp_packet_app_set_ssrc (GstRTCPPacket * packet, guint32 ssrc);
guint32 gst_rtcp_packet_app_get_ssrc (GstRTCPPacket * packet);
void gst_rtcp_packet_app_set_name (GstRTCPPacket * packet, const gchar *name);
const gchar* gst_rtcp_packet_app_get_name (GstRTCPPacket * packet);
guint16 gst_rtcp_packet_app_get_data_length (GstRTCPPacket * packet);
gboolean gst_rtcp_packet_app_set_data_length (GstRTCPPacket * packet, guint16 wordlen);
guint8* gst_rtcp_packet_app_get_data (GstRTCPPacket * packet);
/* feedback packets */
guint32 gst_rtcp_packet_fb_get_sender_ssrc (GstRTCPPacket *packet);
void gst_rtcp_packet_fb_set_sender_ssrc (GstRTCPPacket *packet, guint32 ssrc);

View file

@ -1080,6 +1080,56 @@ GST_START_TEST (test_rtcp_buffer_profile_specific_extension)
}
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;
@ -1321,6 +1371,7 @@ rtp_suite (void)
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);