diff --git a/ChangeLog b/ChangeLog index 2173925421..7aff43528d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,39 @@ +2007-03-29 Wim Taymans + + * docs/libs/gst-plugins-base-libs-docs.sgml: + * docs/libs/gst-plugins-base-libs-sections.txt: + * gst-libs/gst/rtp/gstbasertpaudiopayload.c: + (gst_base_rtp_audio_payload_get_adapter): + Add RTCP docs. + Fix some more docs. + + * gst-libs/gst/rtp/Makefile.am: + * gst-libs/gst/rtp/gstrtcpbuffer.c: + (gst_rtcp_buffer_new_take_data), (gst_rtcp_buffer_new_copy_data), + (gst_rtcp_buffer_validate_data), (gst_rtcp_buffer_validate), + (gst_rtcp_buffer_get_packet_count), (read_packet_header), + (gst_rtcp_buffer_get_first_packet), (gst_rtcp_packet_move_to_next), + (gst_rtcp_buffer_add_packet), (gst_rtcp_packet_remove), + (gst_rtcp_packet_get_padding), (gst_rtcp_packet_get_type), + (gst_rtcp_packet_get_count), (gst_rtcp_packet_get_length), + (gst_rtcp_packet_sr_get_sender_info), + (gst_rtcp_packet_sr_set_sender_info), + (gst_rtcp_packet_rr_get_ssrc), (gst_rtcp_packet_rr_set_ssrc), + (gst_rtcp_packet_get_rb_count), (gst_rtcp_packet_get_rb), + (gst_rtcp_packet_add_rb), (gst_rtcp_packet_set_rb), + (gst_rtcp_packet_sdes_get_chunk_count), + (gst_rtcp_packet_sdes_first_chunk), + (gst_rtcp_packet_sdes_next_chunk), (gst_rtcp_packet_sdes_get_ssrc), + (gst_rtcp_packet_sdes_first_item), + (gst_rtcp_packet_sdes_next_item), (gst_rtcp_packet_sdes_get_item), + (gst_rtcp_packet_bye_get_ssrc_count), + (gst_rtcp_packet_bye_get_nth_ssrc), (gst_rtcp_packet_bye_add_ssrc), + (gst_rtcp_packet_bye_add_ssrcs), (get_reason_offset), + (gst_rtcp_packet_bye_get_reason_len), + (gst_rtcp_packet_bye_get_reason), (gst_rtcp_packet_bye_set_reason): + * gst-libs/gst/rtp/gstrtcpbuffer.h: + Add new helper object for parsing and creating RTCP messages. + 2007-03-29 Sebastian Dröge * gst-libs/gst/riff/riff-media.c: (gst_riff_create_audio_caps): diff --git a/docs/libs/gst-plugins-base-libs-docs.sgml b/docs/libs/gst-plugins-base-libs-docs.sgml index 1ef1fedf70..6f3ce40840 100644 --- a/docs/libs/gst-plugins-base-libs-docs.sgml +++ b/docs/libs/gst-plugins-base-libs-docs.sgml @@ -41,6 +41,7 @@ + @@ -164,6 +165,7 @@ &GstBaseRtpDepayload; &GstBaseRtpPayload; &GstRtpBuffer; + &GstRtcpBuffer; diff --git a/docs/libs/gst-plugins-base-libs-sections.txt b/docs/libs/gst-plugins-base-libs-sections.txt index fdca573cab..ec065b0921 100644 --- a/docs/libs/gst-plugins-base-libs-sections.txt +++ b/docs/libs/gst-plugins-base-libs-sections.txt @@ -93,6 +93,7 @@ GST_AUDIO_SRC_GET_CLASS gst/audio/gstbaseaudiosink.h GstBaseAudioSink GstBaseAudioSinkClass +GstBaseAudioSinkSlaveMethod GST_BASE_AUDIO_SINK_CLOCK GST_BASE_AUDIO_SINK_PAD @@ -105,6 +106,7 @@ gst_base_audio_sink_get_type GST_BASE_AUDIO_SINK_CLASS GST_IS_BASE_AUDIO_SINK_CLASS GST_BASE_AUDIO_SINK_GET_CLASS +GstBaseAudioSinkPrivate
@@ -745,6 +747,8 @@ gst_base_rtp_audio_payload_set_frame_based gst_base_rtp_audio_payload_set_frame_options gst_base_rtp_audio_payload_set_sample_based gst_base_rtp_audio_payload_set_sample_options +gst_base_rtp_audio_payload_get_adapter +gst_base_rtp_audio_payload_push GST_TYPE_BASE_RTP_AUDIO_PAYLOAD GST_BASE_RTP_AUDIO_PAYLOAD @@ -752,6 +756,7 @@ GST_BASE_RTP_AUDIO_PAYLOAD_CLASS GST_IS_BASE_RTP_AUDIO_PAYLOAD GST_IS_BASE_RTP_AUDIO_PAYLOAD_CLASS gst_base_rtp_audio_payload_get_type +GstBaseRTPAudioPayloadPrivate
@@ -763,7 +768,11 @@ GstBaseRTPDepayloadClass GST_BASE_RTP_DEPAYLOAD_SINKPAD GST_BASE_RTP_DEPAYLOAD_SRCPAD +gst_base_rtp_depayload_push +gst_base_rtp_depayload_push_ts + +GstBaseRTPDepayloadPrivate GST_TYPE_BASE_RTP_DEPAYLOAD GST_BASE_RTP_DEPAYLOAD GST_BASE_RTP_DEPAYLOAD_CLASS @@ -798,6 +807,58 @@ GST_IS_BASE_RTP_PAYLOAD_CLASS gst_basertppayload_get_type
+
+gstrtcpbuffer +gst/rtp/gstrtcpbuffer.h + +GST_RTCP_VERSION + +GST_RTCP_MAX_SDES +GST_RTCP_VALID_MASK +GST_RTCP_VALID_VALUE + +GstRTCPType +GstRTCPPacket +GstRTCPSDESType + +gst_rtcp_buffer_add_packet +gst_rtcp_buffer_get_first_packet +gst_rtcp_buffer_get_packet_count +gst_rtcp_buffer_new_copy_data +gst_rtcp_buffer_new_take_data +gst_rtcp_buffer_validate +gst_rtcp_buffer_validate_data +gst_rtcp_packet_add_rb +gst_rtcp_packet_bye_add_ssrc +gst_rtcp_packet_bye_add_ssrcs +gst_rtcp_packet_bye_get_nth_ssrc +gst_rtcp_packet_bye_get_reason +gst_rtcp_packet_bye_get_reason_len +gst_rtcp_packet_bye_get_ssrc_count +gst_rtcp_packet_bye_set_reason +gst_rtcp_packet_get_count +gst_rtcp_packet_get_length +gst_rtcp_packet_get_padding +gst_rtcp_packet_get_rb +gst_rtcp_packet_get_rb_count +gst_rtcp_packet_get_type +gst_rtcp_packet_move_to_next +gst_rtcp_packet_remove +gst_rtcp_packet_rr_get_ssrc +gst_rtcp_packet_rr_set_ssrc +gst_rtcp_packet_sdes_first_chunk +gst_rtcp_packet_sdes_first_item +gst_rtcp_packet_sdes_get_chunk_count +gst_rtcp_packet_sdes_get_item +gst_rtcp_packet_sdes_get_ssrc +gst_rtcp_packet_sdes_next_chunk +gst_rtcp_packet_sdes_next_item +gst_rtcp_packet_set_rb +gst_rtcp_packet_sr_get_sender_info +gst_rtcp_packet_sr_set_sender_info + +
+
gstrtpbuffer gst/rtp/gstrtpbuffer.h @@ -809,6 +870,7 @@ gst_rtp_buffer_allocate_data gst_rtp_buffer_calc_header_len gst_rtp_buffer_calc_packet_len gst_rtp_buffer_calc_payload_len +gst_rtp_buffer_default_clock_rate gst_rtp_buffer_get_csrc gst_rtp_buffer_get_csrc_count gst_rtp_buffer_get_extension @@ -857,6 +919,26 @@ GST_RTP_PAYLOAD_PCMA_STRING GST_RTP_PAYLOAD_PCMU_STRING GST_RTP_PAYLOAD_TS41_STRING GST_RTP_PAYLOAD_TS48_STRING +GST_RTP_PAYLOAD_1016_STRING +GST_RTP_PAYLOAD_CELLB_STRING +GST_RTP_PAYLOAD_CN_STRING +GST_RTP_PAYLOAD_DVI4_11025_STRING +GST_RTP_PAYLOAD_DVI4_16000_STRING +GST_RTP_PAYLOAD_DVI4_22050_STRING +GST_RTP_PAYLOAD_DVI4_8000_STRING +GST_RTP_PAYLOAD_G721_STRING +GST_RTP_PAYLOAD_G722_STRING +GST_RTP_PAYLOAD_G723_53 +GST_RTP_PAYLOAD_G723_63 +GST_RTP_PAYLOAD_G723_STRING +GST_RTP_PAYLOAD_H261_STRING +GST_RTP_PAYLOAD_JPEG_STRING +GST_RTP_PAYLOAD_LPC_STRING +GST_RTP_PAYLOAD_MP2T_STRING +GST_RTP_PAYLOAD_NV_STRING +GST_RTP_PAYLOAD_QCELP_STRING +GST_RTP_PAYLOAD_TS41 +GST_RTP_PAYLOAD_TS48
# tag diff --git a/gst-libs/gst/rtp/Makefile.am b/gst-libs/gst/rtp/Makefile.am index e0d9d602f6..32d642c9ca 100644 --- a/gst-libs/gst/rtp/Makefile.am +++ b/gst-libs/gst/rtp/Makefile.am @@ -1,6 +1,7 @@ libgstrtpincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtp libgstrtpinclude_HEADERS = gstrtpbuffer.h \ + gstrtcpbuffer.h \ gstbasertpaudiopayload.h \ gstbasertppayload.h \ gstbasertpdepayload.h @@ -8,6 +9,7 @@ libgstrtpinclude_HEADERS = gstrtpbuffer.h \ lib_LTLIBRARIES = libgstrtp-@GST_MAJORMINOR@.la libgstrtp_@GST_MAJORMINOR@_la_SOURCES = gstrtpbuffer.c \ + gstrtcpbuffer.c \ gstbasertpaudiopayload.c \ gstbasertppayload.c \ gstbasertpdepayload.c diff --git a/gst-libs/gst/rtp/gstbasertpaudiopayload.c b/gst-libs/gst/rtp/gstbasertpaudiopayload.c index f683b0c832..14ec4aa30c 100644 --- a/gst-libs/gst/rtp/gstbasertpaudiopayload.c +++ b/gst-libs/gst/rtp/gstbasertpaudiopayload.c @@ -598,6 +598,19 @@ gst_base_rtp_audio_payload_handle_sample_based_buffer (GstBaseRTPPayload * return ret; } +/** + * gst_base_rtp_audio_payload_push: + * @basepayload: a #GstBaseRTPPayload + * @data: data to set as payload + * @payload_len: length of payload + * @timestamp: a #GstClockTime + * + * Create an RTP buffer and store @payload_len bytes of @data as the + * payload. Set the timestamp on the new buffer to @timestamp before pushing + * the buffer downstream. + * + * Returns: a #GstFlowReturn + */ GstFlowReturn gst_base_rtp_audio_payload_push (GstBaseRTPPayload * basepayload, const guint8 * data, guint payload_len, GstClockTime timestamp) @@ -712,14 +725,22 @@ gst_base_rtp_payload_audio_handle_event (GstPad * pad, GstEvent * event, return res; } +/** + * gst_base_rtp_audio_payload_get_adapter: + * @basertpaudiopayload: a #GstBaseRTPAudioPayload + * + * Gets the internal adapter used by the depayloader. + * + * Returns: a #GstAdapter. + */ GstAdapter * gst_base_rtp_audio_payload_get_adapter (GstBaseRTPAudioPayload * basertpaudiopayload) { - if (basertpaudiopayload->priv->adapter == NULL) { - return NULL; - } + GstAdapter *adapter; - g_object_ref (G_OBJECT (basertpaudiopayload->priv->adapter)); - return basertpaudiopayload->priv->adapter; + if ((adapter = basertpaudiopayload->priv->adapter)) + g_object_ref (adapter); + + return adapter; } diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.c b/gst-libs/gst/rtp/gstrtcpbuffer.c new file mode 100644 index 0000000000..e3b6c0faa3 --- /dev/null +++ b/gst-libs/gst/rtp/gstrtcpbuffer.c @@ -0,0 +1,1182 @@ +/* GStreamer + * Copyright (C) <2007> Wim Taymans + * + * gstrtcpbuffer.h: various helper functions to manipulate buffers + * with RTCP payload. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:gstrtcpbuffer + * @short_description: Helper methods for dealing with RTCP buffers + * @see_also: gstbasertppayload, gstbasertpdepayload + * + * Note: The API in this module is not yet declared stable. + * + * + * + * The GstRTPCBuffer helper functions makes it easy to parse and create regular + * #GstBuffer objects that contain compound RTCP packets. These buffers are typically + * of 'application/x-rtcp' #GstCaps. + * + * + * An RTCP buffer consists of 1 or more #GstRTCPPacket structures that you can + * retrieve with gst_rtcp_buffer_get_first_packet(). #GstRTCPPacket acts as a pointer + * into the RTCP buffer; you can move to the next packet with + * gst_rtcp_packet_move_to_next(). + * + * + * + * Since: 0.10.13 + * + * Last reviewed on 2007-03-26 (0.10.13) + */ + +#include "gstrtcpbuffer.h" + +/** + * gst_rtcp_buffer_new_take_data: + * @data: data for the new buffer + * @len: the length of data + * + * Create a new buffer and set the data and size of the buffer to @data and @len + * respectively. @data will be freed when the buffer is unreffed, so this + * function transfers ownership of @data to the new buffer. + * + * Returns: A newly allocated buffer with @data and of size @len. + */ +GstBuffer * +gst_rtcp_buffer_new_take_data (gpointer data, guint len) +{ + GstBuffer *result; + + g_return_val_if_fail (data != NULL, NULL); + g_return_val_if_fail (len > 0, NULL); + + result = gst_buffer_new (); + + GST_BUFFER_MALLOCDATA (result) = data; + GST_BUFFER_DATA (result) = data; + GST_BUFFER_SIZE (result) = len; + + return result; +} + +/** + * gst_rtcp_buffer_new_copy_data: + * @data: data for the new buffer + * @len: the length of data + * + * Create a new buffer and set the data to a copy of @len + * bytes of @data and the size to @len. The data will be freed when the buffer + * is freed. + * + * Returns: A newly allocated buffer with a copy of @data and of size @len. + */ +GstBuffer * +gst_rtcp_buffer_new_copy_data (gpointer data, guint len) +{ + return gst_rtcp_buffer_new_take_data (g_memdup (data, len), len); +} + +/** + * gst_rtcp_buffer_validate_data: + * @data: the data to validate + * @len: the length of @data to validate + * + * Check if the @data and @size point to the data of a valid RTCP (compound) + * packet. + * Use this function to validate a packet before using the other functions in + * this module. + * + * Returns: TRUE if the data points to a valid RTCP packet. + */ +gboolean +gst_rtcp_buffer_validate_data (guint8 * data, guint len) +{ + guint16 header_mask; + guint16 header_len; + guint8 version; + guint data_len; + gboolean padding; + guint8 pad_bytes; + + g_return_val_if_fail (data != NULL, FALSE); + + /* we need 4 bytes for the type and length */ + if (G_UNLIKELY (len < 4)) + goto wrong_length; + + /* first packet must be RR or SR and version must be 2 */ + header_mask = ((data[0] << 8) | data[1]) & GST_RTCP_VALID_MASK; + if (G_UNLIKELY (header_mask != GST_RTCP_VALID_VALUE)) + goto wrong_mask; + + /* no padding when mask succeeds */ + padding = FALSE; + + /* store len */ + data_len = len; + + while (TRUE) { + /* get packet length */ + header_len = (((data[2] << 8) | data[3]) + 1) << 2; + if (data_len < header_len) + goto wrong_length; + + /* move to next compount packet */ + data += header_len; + data_len -= header_len; + + /* we are at the end now */ + if (data_len < 4) + break; + + /* check version of new packet */ + version = data[0] & 0xc0; + if (version != (GST_RTCP_VERSION << 6)) + goto wrong_version; + + /* padding only allowed on last packet */ + if ((padding = data[0] & 0x20)) + break; + } + if (data_len > 0) { + /* some leftover bytes, check padding */ + if (!padding) + goto wrong_length; + + /* get padding */ + pad_bytes = data[len - 1]; + if (data_len != pad_bytes) + goto wrong_padding; + } + return TRUE; + + /* ERRORS */ +wrong_length: + { + GST_DEBUG ("len check failed"); + return FALSE; + } +wrong_mask: + { + GST_DEBUG ("mask check failed (%04x != %04x)", header_mask, + GST_RTCP_VALID_VALUE); + return FALSE; + } +wrong_version: + { + GST_DEBUG ("wrong version (%d < 2)", version >> 6); + return FALSE; + } +wrong_padding: + { + GST_DEBUG ("padding check failed"); + return FALSE; + } +} + +/** + * gst_rtcp_buffer_validate: + * @buffer: the buffer to validate + * + * Check if the data pointed to by @buffer is a valid RTCP packet using + * gst_rtcp_buffer_validate_data(). + * + * Returns: TRUE if @buffer is a valid RTCP packet. + */ +gboolean +gst_rtcp_buffer_validate (GstBuffer * buffer) +{ + guint8 *data; + guint len; + + g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); + + data = GST_BUFFER_DATA (buffer); + len = GST_BUFFER_SIZE (buffer); + + return gst_rtcp_buffer_validate_data (data, len); +} + +/** + * gst_rtcp_buffer_get_packet_count: + * @buffer: a valid RTCP buffer + * + * Get the number of RTCP packets in @buffer. + * + * Returns: the number of RTCP packets in @buffer. + */ +guint +gst_rtcp_buffer_get_packet_count (GstBuffer * buffer) +{ + GstRTCPPacket packet; + guint count; + + g_return_val_if_fail (GST_IS_BUFFER (buffer), 0); + + count = gst_rtcp_buffer_get_first_packet (buffer, &packet); + while (gst_rtcp_packet_move_to_next (&packet)) + count++; + + return count; +} + +/** + * read_packet_header: + * @packet: a packet + * + * Read the packet headers for the packet pointed to by @packet. + * + * Returns: TRUE if @packet pointed to a valid header. + */ +static gboolean +read_packet_header (GstRTCPPacket * packet) +{ + guint8 *data; + guint size; + guint offset; + + g_return_val_if_fail (packet != NULL, FALSE); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); + + data = GST_BUFFER_DATA (packet->buffer); + size = GST_BUFFER_SIZE (packet->buffer); + + offset = packet->offset; + + /* check if we are at the end of the buffer, we add 4 because we also want to + * ensure we can read the header. */ + if (offset + 4 > size) + return FALSE; + + if ((data[offset] & 0xc0) != (GST_RTCP_VERSION << 6)) + return FALSE; + + /* read count, type and length */ + packet->padding = (data[offset] & 0x20) == 0x20; + packet->count = data[offset] & 0x1f; + packet->type = data[offset + 1]; + packet->length = (data[offset + 2] << 8) | data[offset + 3]; + packet->chunk_offset = 4; + packet->item_offset = 4; + + return TRUE; +} + +/** + * gst_rtcp_buffer_get_first_packet: + * @buffer: a valid RTCP buffer + * @packet: a #GstRTCPPacket + * + * Initialize a new #GstRTCPPacket pointer that points to the first packet in + * @buffer. + * + * Returns: TRUE if the packet existed in @buffer. + */ +gboolean +gst_rtcp_buffer_get_first_packet (GstBuffer * buffer, GstRTCPPacket * packet) +{ + g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); + g_return_val_if_fail (packet != NULL, FALSE); + + /* init to 0 */ + packet->buffer = buffer; + packet->offset = 0; + packet->type = GST_RTCP_TYPE_INVALID; + + if (!read_packet_header (packet)) + return FALSE; + + return TRUE; +} + +/** + * gst_rtcp_packet_move_to_next: + * @packet: a #GstRTCPPacket + * + * Move the packet pointer @packet to the next packet in the payload. + * Use gst_rtcp_buffer_get_first_packet() to initialize @packet. + * + * Returns: TRUE if @packet is pointing to a valid packet after calling this + * function. + */ +gboolean +gst_rtcp_packet_move_to_next (GstRTCPPacket * packet) +{ + g_return_val_if_fail (packet != NULL, FALSE); + g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); + + /* if we have a padding packet, it must be the last, set pointer to end of + * buffer and return FALSE */ + if (packet->padding) + goto end; + + /* move to next packet. Add 4 because the header is not included in length */ + packet->offset += (packet->length << 2) + 4; + + /* try to read new header */ + if (!read_packet_header (packet)) + goto end; + + return TRUE; + + /* ERRORS */ +end: + { + packet->type = GST_RTCP_TYPE_INVALID; + packet->offset = GST_BUFFER_SIZE (packet->buffer); + return FALSE; + } +} + +/** + * gst_rtcp_buffer_add_packet: + * @buffer: a valid RTCP buffer + * @type: the #GstRTCPType of the new packet + * @packet: pointer to new packet + * + * Add a new packet of @type to @buffer. @packet will point to the newly created + * packet. + * + * Note: Not implemented. + */ +void +gst_rtcp_buffer_add_packet (GstBuffer * buffer, GstRTCPType type, + GstRTCPPacket * packet) +{ + g_return_if_fail (GST_IS_BUFFER (buffer)); + g_return_if_fail (type != GST_RTCP_TYPE_INVALID); + g_return_if_fail (packet != NULL); + + g_warning ("not implemented"); +} + +/** + * gst_rtcp_packet_remove: + * @packet: a #GstRTCPPacket + * + * Removes the packet pointed to by @packet. + * + * Note: Not implemented. + */ +void +gst_rtcp_packet_remove (GstRTCPPacket * packet) +{ + g_return_if_fail (packet != NULL); + g_return_if_fail (packet->type != GST_RTCP_TYPE_INVALID); + + g_warning ("not implemented"); +} + +/** + * gst_rtcp_packet_get_padding: + * @packet: a valid #GstRTCPPacket + * + * Get the packet padding of the packet pointed to by @packet. + * + * Returns: If the packet has the padding bit set. + */ +gboolean +gst_rtcp_packet_get_padding (GstRTCPPacket * packet) +{ + g_return_val_if_fail (packet != NULL, FALSE); + g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE); + + return packet->padding; +} + +/** + * gst_rtcp_packet_get_type: + * @packet: a valid #GstRTCPPacket + * + * Get the packet type of the packet pointed to by @packet. + * + * Returns: The packet type. + */ +GstRTCPType +gst_rtcp_packet_get_type (GstRTCPPacket * packet) +{ + g_return_val_if_fail (packet != NULL, GST_RTCP_TYPE_INVALID); + g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, + GST_RTCP_TYPE_INVALID); + + return packet->type; +} + +/** + * gst_rtcp_packet_get_count: + * @packet: a valid #GstRTCPPacket + * + * Get the count field in @packet. + * + * Returns: The count field in @packet or -1 if @packet does not point to a + * valid packet. + */ +guint8 +gst_rtcp_packet_get_count (GstRTCPPacket * packet) +{ + g_return_val_if_fail (packet != NULL, -1); + g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, -1); + + return packet->count; +} + +/** + * gst_rtcp_packet_get_length: + * @packet: a valid #GstRTCPPacket + * + * Get the length field of @packet. This is the length of the packet in + * 32-bit words minus one. + * + * Returns: The length field of @packet. + */ +guint16 +gst_rtcp_packet_get_length (GstRTCPPacket * packet) +{ + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, 0); + + return packet->length; +} + +/** + * gst_rtcp_packet_sr_get_sender_info: + * @packet: a valid SR #GstRTCPPacket + * @ssrc: result SSRC + * @ntptime: result NTP time + * @rtptime: result RTP time + * @packet_count: result packet count + * @octet_count: result octect count + * + * Parse the SR sender info and store the values. + */ +void +gst_rtcp_packet_sr_get_sender_info (GstRTCPPacket * packet, guint32 * ssrc, + guint64 * ntptime, guint32 * rtptime, guint32 * packet_count, + guint32 * octet_count) +{ + guint8 *data; + + g_return_if_fail (packet != NULL); + g_return_if_fail (packet->type == GST_RTCP_TYPE_SR); + g_return_if_fail (GST_IS_BUFFER (packet->buffer)); + + data = GST_BUFFER_DATA (packet->buffer); + + /* skip header */ + data += packet->offset + 4; + if (ssrc) + *ssrc = GST_READ_UINT32_BE (data); + data += 4; + if (ntptime) + *ntptime = GST_READ_UINT64_BE (data); + data += 8; + if (rtptime) + *rtptime = GST_READ_UINT32_BE (data); + data += 4; + if (packet_count) + *packet_count = GST_READ_UINT32_BE (data); + data += 4; + if (octet_count) + *octet_count = GST_READ_UINT32_BE (data); +} + +/** + * gst_rtcp_packet_sr_set_sender_info: + * @packet: a valid SR #GstRTCPPacket + * @ssrc: the SSRC + * @ntptime: the NTP time + * @rtptime: the RTP time + * @packet_count: the packet count + * @octet_count: the octect count + * + * Set the given values in the SR packet @packet. + * + * Note: Not implemented. + */ +void +gst_rtcp_packet_sr_set_sender_info (GstRTCPPacket * packet, guint32 ssrc, + guint64 ntptime, guint32 rtptime, guint32 packet_count, guint32 octet_count) +{ + g_return_if_fail (packet != NULL); + g_return_if_fail (packet->type == GST_RTCP_TYPE_SR); + g_return_if_fail (GST_IS_BUFFER (packet->buffer)); + + g_warning ("not implemented"); +} + +/** + * gst_rtcp_packet_rr_get_ssrc: + * @packet: a valid RR #GstRTCPPacket + * + * Get the ssrc field of the RR @packet. + * + * Returns: the ssrc. + */ +guint32 +gst_rtcp_packet_rr_get_ssrc (GstRTCPPacket * packet) +{ + guint8 *data; + guint32 ssrc; + + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + data = GST_BUFFER_DATA (packet->buffer); + + /* skip header */ + data += packet->offset + 4; + ssrc = GST_READ_UINT32_BE (data); + + return ssrc; +} + +/** + * gst_rtcp_packet_rr_set_ssrc: + * @packet: a valid RR #GstRTCPPacket + * @ssrc: the SSRC to set + * + * Set the ssrc field of the RR @packet. + * + * Note: Not implemented. + */ +void +gst_rtcp_packet_rr_set_ssrc (GstRTCPPacket * packet, guint32 ssrc) +{ + g_return_if_fail (packet != NULL); + g_return_if_fail (packet->type == GST_RTCP_TYPE_RR); + g_return_if_fail (GST_IS_BUFFER (packet->buffer)); + + g_warning ("not implemented"); +} + +/** + * gst_rtcp_packet_get_rb_count: + * @packet: a valid SR or RR #GstRTCPPacket + * + * Get the number of report blocks in @packet. + * + * Returns: The number of report blocks in @packet. + */ +guint +gst_rtcp_packet_get_rb_count (GstRTCPPacket * packet) +{ + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR || + packet->type == GST_RTCP_TYPE_SR, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + return packet->count; +} + +/** + * gst_rtcp_packet_get_rb: + * @packet: a valid SR or RR #GstRTCPPacket + * @nth: the nth report block in @packet + * @ssrc: result for data source being reported + * @fractionlost: result for fraction lost since last SR/RR + * @packetslost: result for the cumululative number of packets lost + * @exthighestseq: result for the extended last sequence number received + * @jitter: result for the interarrival jitter + * @lsr: result for the last SR packet from this source + * @dlsr: result for the delay since last SR packet + * + * Parse the values of the @nth report block in @packet and store the result in + * the values. + */ +void +gst_rtcp_packet_get_rb (GstRTCPPacket * packet, guint nth, guint32 * ssrc, + guint8 * fractionlost, gint32 * packetslost, guint32 * exthighestseq, + guint32 * jitter, guint32 * lsr, guint32 * dlsr) +{ + guint8 *data; + guint32 tmp; + + g_return_if_fail (packet != NULL); + g_return_if_fail (packet->type == GST_RTCP_TYPE_RR || + packet->type == GST_RTCP_TYPE_SR); + g_return_if_fail (GST_IS_BUFFER (packet->buffer)); + + data = GST_BUFFER_DATA (packet->buffer); + + /* skip header */ + data += packet->offset + 4; + if (packet->type == GST_RTCP_TYPE_RR) + data += 4; + else + data += 36; + + /* move to requested index */ + data += (nth * 36); + + if (ssrc) + *ssrc = GST_READ_UINT32_BE (data); + data += 4; + tmp = GST_READ_UINT32_BE (data); + data += 4; + if (fractionlost) + *fractionlost = (tmp >> 24); + if (packetslost) { + /* sign extend */ + if (tmp & 0x00800000) + tmp |= 0xff000000; + else + tmp &= 0x00ffffff; + *packetslost = (gint32) tmp; + } + data += 4; + if (exthighestseq) + *exthighestseq = GST_READ_UINT32_BE (data); + data += 4; + if (jitter) + *jitter = GST_READ_UINT32_BE (data); + data += 4; + if (lsr) + *lsr = GST_READ_UINT32_BE (data); + data += 4; + if (dlsr) + *dlsr = GST_READ_UINT32_BE (data); +} + +/** + * gst_rtcp_packet_add_rb: + * @packet: a valid SR or RR #GstRTCPPacket + * @ssrc: data source being reported + * @fractionlost: fraction lost since last SR/RR + * @packetslost: the cumululative number of packets lost + * @exthighestseq: the extended last sequence number received + * @jitter: the interarrival jitter + * @lsr: the last SR packet from this source + * @dlsr: the delay since last SR packet + * + * Add a new report block to @packet with the given values. + * + * Note: Not implemented. + */ +void +gst_rtcp_packet_add_rb (GstRTCPPacket * packet, guint32 ssrc, + guint8 fractionlost, gint32 packetslost, guint32 exthighestseq, + guint32 jitter, guint32 lsr, guint32 dlsr) +{ + g_return_if_fail (packet != NULL); + g_return_if_fail (packet->type == GST_RTCP_TYPE_RR || + packet->type == GST_RTCP_TYPE_SR); + g_return_if_fail (GST_IS_BUFFER (packet->buffer)); + + g_warning ("not implemented"); +} + +/** + * gst_rtcp_packet_set_rb: + * @packet: a valid SR or RR #GstRTCPPacket + * @nth: the nth report block to set + * @ssrc: data source being reported + * @fractionlost: fraction lost since last SR/RR + * @packetslost: the cumululative number of packets lost + * @exthighestseq: the extended last sequence number received + * @jitter: the interarrival jitter + * @lsr: the last SR packet from this source + * @dlsr: the delay since last SR packet + * + * Set the @nth new report block in @packet with the given values. + * + * Note: Not implemented. + */ +void +gst_rtcp_packet_set_rb (GstRTCPPacket * packet, guint nth, guint32 ssrc, + guint8 fractionlost, gint32 packetslost, guint32 exthighestseq, + guint32 jitter, guint32 lsr, guint32 dlsr) +{ + g_return_if_fail (packet != NULL); + g_return_if_fail (packet->type == GST_RTCP_TYPE_RR || + packet->type == GST_RTCP_TYPE_SR); + g_return_if_fail (GST_IS_BUFFER (packet->buffer)); + + g_warning ("not implemented"); +} + + +/** + * gst_rtcp_packet_sdes_get_chunk_count: + * @packet: a valid SDES #GstRTCPPacket + * + * Get the number of chunks in the SDES packet @packet. + * + * Returns: The number of chunks in @packet. + */ +guint +gst_rtcp_packet_sdes_get_chunk_count (GstRTCPPacket * packet) +{ + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + return packet->count; +} + +/** + * gst_rtcp_packet_sdes_first_chunk: + * @packet: a valid SDES #GstRTCPPacket + * + * Move to the first SDES chunk in @packet. + * + * Returns: TRUE if there was a first chunk. + */ +gboolean +gst_rtcp_packet_sdes_first_chunk (GstRTCPPacket * packet) +{ + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + if (packet->count == 0) + return FALSE; + + packet->chunk_offset = 4; + packet->item_offset = 4; + + return TRUE; +} + +/** + * gst_rtcp_packet_sdes_next_chunk: + * @packet: a valid SDES #GstRTCPPacket + * + * Move to the next SDES chunk in @packet. + * + * Returns: TRUE if there was a next chunk. + */ +gboolean +gst_rtcp_packet_sdes_next_chunk (GstRTCPPacket * packet) +{ + guint8 *data; + guint offset; + guint len; + + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + /* move to SDES */ + data = GST_BUFFER_DATA (packet->buffer); + data += packet->offset; + /* move to chunk */ + offset = packet->chunk_offset; + /* skip SSRC */ + offset += 4; + + /* don't overrun */ + len = (packet->length << 2); + + while (offset < len) { + if (data[offset] == 0) { + /* end of list, round to next 32-bit word */ + offset = (offset + 3) & ~3; + break; + } + offset += data[offset + 1] + 2; + } + if (offset >= len) + return FALSE; + + packet->chunk_offset = offset; + packet->item_offset = 4; + + return TRUE; +} + +/** + * gst_rtcp_packet_sdes_get_ssrc: + * @packet: a valid SDES #GstRTCPPacket + * + * Get the SSRC of the current SDES chunk. + * + * Returns: the SSRC of the current chunk. + */ +guint32 +gst_rtcp_packet_sdes_get_ssrc (GstRTCPPacket * packet) +{ + guint32 ssrc; + guint8 *data; + + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + /* move to SDES */ + data = GST_BUFFER_DATA (packet->buffer); + data += packet->offset; + /* move to chunk */ + data += packet->chunk_offset; + + ssrc = GST_READ_UINT32_BE (data); + + return ssrc; +} + +/** + * gst_rtcp_packet_sdes_first_item: + * @packet: a valid SDES #GstRTCPPacket + * + * Move to the first SDES item in the current chunk. + * + * Returns: TRUE if there was a first item. + */ +gboolean +gst_rtcp_packet_sdes_first_item (GstRTCPPacket * packet) +{ + guint8 *data; + guint len, offset; + + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + /* move to SDES */ + data = GST_BUFFER_DATA (packet->buffer); + data += packet->offset; + /* move to chunk */ + offset = packet->chunk_offset; + /* skip SSRC */ + offset += 4; + + /* don't overrun */ + len = (packet->length << 2); + if (offset >= len) + return FALSE; + + if (data[offset] == 0) + return FALSE; + + packet->item_offset = 4; + + return TRUE; +} + +/** + * gst_rtcp_packet_sdes_next_item: + * @packet: a valid SDES #GstRTCPPacket + * + * Move to the next SDES item in the current chunk. + * + * Returns: TRUE if there was a next item. + */ +gboolean +gst_rtcp_packet_sdes_next_item (GstRTCPPacket * packet) +{ + guint8 *data; + guint len, offset, item_len; + + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + /* move to SDES */ + data = GST_BUFFER_DATA (packet->buffer); + data += packet->offset; + /* move to chunk */ + offset = packet->chunk_offset; + /* move to item */ + offset += packet->item_offset; + + item_len = data[offset + 1] + 2; + /* skip item */ + offset += item_len; + + /* don't overrun */ + len = (packet->length << 2); + if (offset >= len) + return FALSE; + + /* check for end of list */ + if (data[offset] == 0) + return FALSE; + + packet->item_offset += item_len; + + return TRUE; +} + +/** + * gst_rtcp_packet_sdes_get_item: + * @packet: a valid SDES #GstRTCPPacket + * @type: result of the item type + * @len: result length of the item data + * @data: result item data + * + * Get the data of the current SDES chunk item. + * + * Returns: TRUE if there was valid data. + */ +gboolean +gst_rtcp_packet_sdes_get_item (GstRTCPPacket * packet, + GstRTCPSDESType * type, guint8 * len, gchar ** data) +{ + guint8 *bdata; + guint offset; + + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + /* move to SDES */ + bdata = GST_BUFFER_DATA (packet->buffer); + bdata += packet->offset; + /* move to chunk */ + offset = packet->chunk_offset; + /* move to item */ + offset += packet->item_offset; + + if (bdata[offset] == 0) + return FALSE; + + if (type) + *type = bdata[offset]; + if (len) + *len = bdata[offset + 1]; + if (data) + *data = g_strndup ((const gchar *) &bdata[offset + 2], bdata[offset + 1]); + + return TRUE; +} + +/** + * gst_rtcp_packet_bye_get_ssrc_count: + * @packet: a valid BYE #GstRTCPPacket + * + * Get the number of SSRC fields in @packet. + * + * Returns: The number of SSRC fields in @packet. + */ +guint +gst_rtcp_packet_bye_get_ssrc_count (GstRTCPPacket * packet) +{ + g_return_val_if_fail (packet != NULL, -1); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, -1); + + return packet->count; +} + +/** + * gst_rtcp_packet_bye_get_nth_ssrc: + * @packet: a valid BYE #GstRTCPPacket + * @nth: the nth SSRC to get + * + * Get the @nth SSRC of the BYE @packet. + * + * Returns: The @nth SSRC of @packet. + */ +guint32 +gst_rtcp_packet_bye_get_nth_ssrc (GstRTCPPacket * packet, guint nth) +{ + guint8 *data; + guint offset; + guint32 ssrc; + guint8 sc; + + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + /* get amount of sources and check that we don't read too much */ + sc = packet->count; + if (nth >= sc) + return 0; + + /* get offset in 32-bits words into packet, skip the header */ + offset = 1 + nth; + /* check that we don't go past the packet length */ + if (offset > packet->length) + return 0; + + /* scale to bytes */ + offset <<= 2; + offset += packet->offset; + + /* check if the packet is valid */ + if (offset + 4 > GST_BUFFER_SIZE (packet->buffer)) + return 0; + + data = GST_BUFFER_DATA (packet->buffer); + data += offset; + + ssrc = GST_READ_UINT32_BE (data); + + return ssrc; +} + +/** + * gst_rtcp_packet_bye_add_ssrc: + * @packet: a valid BYE #GstRTCPPacket + * @ssrc: an SSRC to add + * + * Add @ssrc to the BYE @packet. + * + * Note: Not implemented. + */ +void +gst_rtcp_packet_bye_add_ssrc (GstRTCPPacket * packet, guint32 ssrc) +{ + g_return_if_fail (packet != NULL); + g_return_if_fail (packet->type == GST_RTCP_TYPE_BYE); + g_return_if_fail (GST_IS_BUFFER (packet->buffer)); + + g_warning ("not implemented"); +} + +/** + * gst_rtcp_packet_bye_add_ssrcs: + * @packet: a valid BYE #GstRTCPPacket + * @ssrc: an array of SSRCs to add + * @len: number of elements in @ssrc + * + * Adds @len SSRCs in @ssrc to BYE @packet. + * + * Note: Not implemented. + */ +void +gst_rtcp_packet_bye_add_ssrcs (GstRTCPPacket * packet, guint32 * ssrc, + guint len) +{ + g_return_if_fail (packet != NULL); + g_return_if_fail (packet->type == GST_RTCP_TYPE_BYE); + g_return_if_fail (GST_IS_BUFFER (packet->buffer)); + + g_warning ("not implemented"); +} + +/* get the offset in packet of the reason length */ +static guint +get_reason_offset (GstRTCPPacket * packet) +{ + guint sc; + guint offset; + + /* get amount of sources */ + sc = packet->count; + + offset = 1 + sc; + /* check that we don't go past the packet length */ + if (offset > packet->length) + return 0; + + /* scale to bytes */ + offset <<= 2; + offset += packet->offset; + + /* check if the packet is valid */ + if (offset + 1 > GST_BUFFER_SIZE (packet->buffer)) + return 0; + + return offset; +} + +/** + * gst_rtcp_packet_bye_get_reason_len: + * @packet: a valid BYE #GstRTCPPacket + * + * Get the length of the reason string. + * + * Returns: The length of the reason string or 0 when there is no reason string + * present. + */ +guint8 +gst_rtcp_packet_bye_get_reason_len (GstRTCPPacket * packet) +{ + guint8 *data; + guint roffset; + + g_return_val_if_fail (packet != NULL, 0); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); + + roffset = get_reason_offset (packet); + if (roffset == 0) + return 0; + + data = GST_BUFFER_DATA (packet->buffer); + + return data[roffset]; +} + +/** + * gst_rtcp_packet_bye_get_reason: + * @packet: a valid BYE #GstRTCPPacket + * + * Get the reason in @packet. + * + * Returns: The reason for the BYE @packet or NULL if the packet did not contain + * a reason string. The string must be freed with g_free() after usage. + */ +gchar * +gst_rtcp_packet_bye_get_reason (GstRTCPPacket * packet) +{ + guint8 *data; + guint roffset; + guint8 len; + + g_return_val_if_fail (packet != NULL, NULL); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), NULL); + + roffset = get_reason_offset (packet); + if (roffset == 0) + return NULL; + + data = GST_BUFFER_DATA (packet->buffer); + + /* get length of reason string */ + len = data[roffset]; + if (len == 0) + return NULL; + + /* move to string */ + roffset += 1; + + /* check if enough data to copy */ + if (roffset + len > GST_BUFFER_SIZE (packet->buffer)) + return NULL; + + return g_strndup ((gconstpointer) (data + roffset), len); +} + +/** + * gst_rtcp_packet_bye_set_reason: + * @packet: a valid BYE #GstRTCPPacket + * @reason: a reason string + * + * Set the reason string to @reason in @packet. + * + * Returns: TRUE if the string could be set. + * + * Note: Not implemented. + */ +gboolean +gst_rtcp_packet_bye_set_reason (GstRTCPPacket * packet, const gchar * reason) +{ + g_return_val_if_fail (packet != NULL, FALSE); + g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE); + g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); + + g_warning ("not implemented"); + + return FALSE; +} diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.h b/gst-libs/gst/rtp/gstrtcpbuffer.h new file mode 100644 index 0000000000..4989a2e166 --- /dev/null +++ b/gst-libs/gst/rtp/gstrtcpbuffer.h @@ -0,0 +1,206 @@ +/* GStreamer + * Copyright (C) <2007> Wim Taymans + * + * gstrtcpbuffer.h: various helper functions to manipulate buffers + * with RTCP payload. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_RTCPBUFFER_H__ +#define __GST_RTCPBUFFER_H__ + +#include + +G_BEGIN_DECLS + +/** + * GST_RTCP_VERSION: + * + * The supported RTCP version 2. + */ +#define GST_RTCP_VERSION 2 + +/** + * GstRTCPType: + * @GST_RTCP_TYPE_INVALID: Invalid type + * @GST_RTCP_TYPE_SR: Sender report + * @GST_RTCP_TYPE_RR: Receiver report + * @GST_RTCP_TYPE_SDES: Source description + * @GST_RTCP_TYPE_BYE: Goodbye + * @GST_RTCP_TYPE_APP: Application defined + * + * Different RTCP packet types. + */ +typedef enum +{ + GST_RTCP_TYPE_INVALID = 0, + GST_RTCP_TYPE_SR = 200, + GST_RTCP_TYPE_RR = 201, + GST_RTCP_TYPE_SDES = 202, + GST_RTCP_TYPE_BYE = 203, + GST_RTCP_TYPE_APP = 204 +} GstRTCPType; + +/** + * GstRTCPSDESType: + * @GST_RTCP_SDES_INVALID: Invalid SDES entry + * @GST_RTCP_SDES_END: End of SDES list + * @GST_RTCP_SDES_CNAME: Canonical name + * @GST_RTCP_SDES_NAME: User name + * @GST_RTCP_SDES_EMAIL: User's electronic mail address + * @GST_RTCP_SDES_PHONE: User's phone number + * @GST_RTCP_SDES_LOC: Geographic user location + * @GST_RTCP_SDES_TOOL: Name of application or tool + * @GST_RTCP_SDES_NOTE: Notice about the source + * @GST_RTCP_SDES_PRIV: Private extensions + * + * Different types of SDES content. + */ +typedef enum +{ + GST_RTCP_SDES_INVALID = -1, + GST_RTCP_SDES_END = 0, + GST_RTCP_SDES_CNAME = 1, + GST_RTCP_SDES_NAME = 2, + GST_RTCP_SDES_EMAIL = 3, + GST_RTCP_SDES_PHONE = 4, + GST_RTCP_SDES_LOC = 5, + GST_RTCP_SDES_TOOL = 6, + GST_RTCP_SDES_NOTE = 7, + GST_RTCP_SDES_PRIV = 8 +} GstRTCPSDESType; + +/** + * GST_RTCP_MAX_SDES: + * + * The maximum text length for an SDES item. + */ +#define GST_RTCP_MAX_SDES 255 + +/** + * GST_RTCP_VALID_MASK: + * + * Mask for version, padding bit and packet type pair + */ +#define GST_RTCP_VALID_MASK (0xc000 | 0x2000 | 0xfe) +/** + * GST_RTCP_VALID_VALUE: + * + * Valid value for the first two bytes of an RTCP packet after applying + * #GST_RTCP_VALID_MASK to them. + */ +#define GST_RTCP_VALID_VALUE ((GST_RTCP_VERSION << 14) | GST_RTCP_TYPE_SR) + +typedef struct _GstRTCPPacket GstRTCPPacket; + +/** + * GstRTCPPacket: + * @buffer: pointer to RTCP buffer + * @offset: offset of packet in buffer data + * + * Data structure that points to a packet at @offset in @buffer. + * The size of the structure is made public to allow stack allocations. + */ +struct _GstRTCPPacket +{ + GstBuffer *buffer; + guint offset; + + /*< private >*/ + gboolean padding; /* padding field of current packet */ + guint8 count; /* count field of current packet */ + GstRTCPType type; /* type of current packet */ + guint16 length; /* length of current packet in 32-bits words */ + + guint chunk_offset; /* current chunk offset for navigating SDES */ + guint item_offset; /* current item offset for navigating SDE */ +}; + +/* creating buffers */ +GstBuffer* gst_rtcp_buffer_new_take_data (gpointer data, guint len); +GstBuffer* gst_rtcp_buffer_new_copy_data (gpointer data, guint len); + +gboolean gst_rtcp_buffer_validate_data (guint8 *data, guint len); +gboolean gst_rtcp_buffer_validate (GstBuffer *buffer); + +/* adding/retrieving packets */ +guint gst_rtcp_buffer_get_packet_count (GstBuffer *buffer); +gboolean gst_rtcp_buffer_get_first_packet (GstBuffer *buffer, GstRTCPPacket *packet); +gboolean gst_rtcp_packet_move_to_next (GstRTCPPacket *packet); + +void gst_rtcp_buffer_add_packet (GstBuffer *buffer, GstRTCPType type, + GstRTCPPacket *packet); +void gst_rtcp_packet_remove (GstRTCPPacket *packet); + +/* working with packets */ +gboolean gst_rtcp_packet_get_padding (GstRTCPPacket *packet); +guint8 gst_rtcp_packet_get_count (GstRTCPPacket *packet); +GstRTCPType gst_rtcp_packet_get_type (GstRTCPPacket *packet); +guint16 gst_rtcp_packet_get_length (GstRTCPPacket *packet); + + +/* sender reports */ +void gst_rtcp_packet_sr_get_sender_info (GstRTCPPacket *packet, guint32 *ssrc, + guint64 *ntptime, guint32 *rtptime, + guint32 *packet_count, guint32 *octet_count); +void gst_rtcp_packet_sr_set_sender_info (GstRTCPPacket *packet, guint32 ssrc, + guint64 ntptime, guint32 rtptime, + guint32 packet_count, guint32 octet_count); +/* receiver reports */ +guint32 gst_rtcp_packet_rr_get_ssrc (GstRTCPPacket *packet); +void gst_rtcp_packet_rr_set_ssrc (GstRTCPPacket *packet, guint32 ssrc); + + +/* report blocks for SR and RR */ +guint gst_rtcp_packet_get_rb_count (GstRTCPPacket *packet); +void gst_rtcp_packet_get_rb (GstRTCPPacket *packet, guint nth, guint32 *ssrc, + guint8 *fractionlost, gint32 *packetslost, + guint32 *exthighestseq, guint32 *jitter, + guint32 *lsr, guint32 *dlsr); +void gst_rtcp_packet_add_rb (GstRTCPPacket *packet, guint32 ssrc, + guint8 fractionlost, gint32 packetslost, + guint32 exthighestseq, guint32 jitter, + guint32 lsr, guint32 dlsr); +void gst_rtcp_packet_set_rb (GstRTCPPacket *packet, guint nth, guint32 ssrc, + guint8 fractionlost, gint32 packetslost, + guint32 exthighestseq, guint32 jitter, + guint32 lsr, guint32 dlsr); + +/* source description packet */ +guint gst_rtcp_packet_sdes_get_chunk_count (GstRTCPPacket *packet); +gboolean gst_rtcp_packet_sdes_first_chunk (GstRTCPPacket *packet); +gboolean gst_rtcp_packet_sdes_next_chunk (GstRTCPPacket *packet); +guint32 gst_rtcp_packet_sdes_get_ssrc (GstRTCPPacket *packet); +gboolean gst_rtcp_packet_sdes_first_item (GstRTCPPacket *packet); +gboolean gst_rtcp_packet_sdes_next_item (GstRTCPPacket *packet); +gboolean gst_rtcp_packet_sdes_get_item (GstRTCPPacket *packet, + GstRTCPSDESType *type, guint8 *len, + gchar **data); + +/* bye packet */ +guint gst_rtcp_packet_bye_get_ssrc_count (GstRTCPPacket *packet); +guint32 gst_rtcp_packet_bye_get_nth_ssrc (GstRTCPPacket *packet, guint nth); +void gst_rtcp_packet_bye_add_ssrc (GstRTCPPacket *packet, guint32 ssrc); +void gst_rtcp_packet_bye_add_ssrcs (GstRTCPPacket *packet, guint32 *ssrc, guint len); +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); + +G_END_DECLS + +#endif /* __GST_RTCPBUFFER_H__ */ +