Blame gst-libs/gst/rtp/gstrtcpbuffer.c

Packit 971217
/* GStreamer
Packit 971217
 * Copyright (C) <2007> Wim Taymans <wim@fluendo.com>
Packit 971217
 *
Packit 971217
 * gstrtcpbuffer.h: various helper functions to manipulate buffers
Packit 971217
 *     with RTCP payload.
Packit 971217
 *
Packit 971217
 * This library is free software; you can redistribute it and/or
Packit 971217
 * modify it under the terms of the GNU Library General Public
Packit 971217
 * License as published by the Free Software Foundation; either
Packit 971217
 * version 2 of the License, or (at your option) any later version.
Packit 971217
 *
Packit 971217
 * This library is distributed in the hope that it will be useful,
Packit 971217
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 971217
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 971217
 * Library General Public License for more details.
Packit 971217
 *
Packit 971217
 * You should have received a copy of the GNU Library General Public
Packit 971217
 * License along with this library; if not, write to the
Packit 971217
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 971217
 * Boston, MA 02110-1301, USA.
Packit 971217
 */
Packit 971217
Packit 971217
/**
Packit 971217
 * SECTION:gstrtcpbuffer
Packit 971217
 * @title: GstRTCPBuffer
Packit 971217
 * @short_description: Helper methods for dealing with RTCP buffers
Packit 971217
 * @see_also: #GstRTPBasePayload, #GstRTPBaseDepayload, #gstrtpbuffer
Packit 971217
 *
Packit 971217
 * Note: The API in this module is not yet declared stable.
Packit 971217
 *
Packit 971217
 * The GstRTPCBuffer helper functions makes it easy to parse and create regular
Packit 971217
 * #GstBuffer objects that contain compound RTCP packets. These buffers are typically
Packit 971217
 * of 'application/x-rtcp' #GstCaps.
Packit 971217
 *
Packit 971217
 * An RTCP buffer consists of 1 or more #GstRTCPPacket structures that you can
Packit 971217
 * retrieve with gst_rtcp_buffer_get_first_packet(). #GstRTCPPacket acts as a pointer
Packit 971217
 * into the RTCP buffer; you can move to the next packet with
Packit 971217
 * gst_rtcp_packet_move_to_next().
Packit 971217
 *
Packit 971217
 */
Packit 971217
Packit 971217
#include <string.h>
Packit 971217
Packit 971217
#include "gstrtcpbuffer.h"
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_new_take_data:
Packit 971217
 * @data: (array length=len) (element-type guint8): data for the new buffer
Packit 971217
 * @len: the length of data
Packit 971217
 *
Packit 971217
 * Create a new buffer and set the data and size of the buffer to @data and @len
Packit 971217
 * respectively. @data will be freed when the buffer is unreffed, so this
Packit 971217
 * function transfers ownership of @data to the new buffer.
Packit 971217
 *
Packit 971217
 * Returns: A newly allocated buffer with @data and of size @len.
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_rtcp_buffer_new_take_data (gpointer data, guint len)
Packit 971217
{
Packit 971217
  GstBuffer *result;
Packit 971217
Packit 971217
  g_return_val_if_fail (data != NULL, NULL);
Packit 971217
  g_return_val_if_fail (len > 0, NULL);
Packit 971217
Packit 971217
  result = gst_buffer_new_wrapped (data, len);
Packit 971217
Packit 971217
  return result;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_new_copy_data:
Packit 971217
 * @data: (array length=len) (element-type guint8): data for the new buffer
Packit 971217
 * @len: the length of data
Packit 971217
 *
Packit 971217
 * Create a new buffer and set the data to a copy of @len
Packit 971217
 * bytes of @data and the size to @len. The data will be freed when the buffer
Packit 971217
 * is freed.
Packit 971217
 *
Packit 971217
 * Returns: A newly allocated buffer with a copy of @data and of size @len.
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_rtcp_buffer_new_copy_data (gconstpointer data, guint len)
Packit 971217
{
Packit 971217
  return gst_rtcp_buffer_new_take_data (g_memdup (data, len), len);
Packit 971217
}
Packit 971217
Packit 971217
static gboolean
Packit 971217
gst_rtcp_buffer_validate_data_internal (guint8 * data, guint len,
Packit 971217
    guint16 valid_mask)
Packit 971217
{
Packit 971217
  guint16 header_mask;
Packit 971217
  guint header_len;
Packit 971217
  guint8 version;
Packit 971217
  guint data_len;
Packit 971217
  gboolean padding;
Packit 971217
  guint8 pad_bytes;
Packit 971217
Packit 971217
  g_return_val_if_fail (data != NULL, FALSE);
Packit 971217
Packit 971217
  /* we need 4 bytes for the type and length */
Packit 971217
  if (G_UNLIKELY (len < 4))
Packit 971217
    goto wrong_length;
Packit 971217
Packit 971217
  /* first packet must be RR or SR  and version must be 2 */
Packit 971217
  header_mask = ((data[0] << 8) | data[1]) & valid_mask;
Packit 971217
  if (G_UNLIKELY (header_mask != GST_RTCP_VALID_VALUE))
Packit 971217
    goto wrong_mask;
Packit 971217
Packit 971217
  /* no padding when mask succeeds */
Packit 971217
  padding = FALSE;
Packit 971217
Packit 971217
  /* store len */
Packit 971217
  data_len = len;
Packit 971217
Packit 971217
  while (TRUE) {
Packit 971217
    /* get packet length */
Packit 971217
    header_len = (((data[2] << 8) | data[3]) + 1) << 2;
Packit 971217
    if (data_len < header_len)
Packit 971217
      goto wrong_length;
Packit 971217
Packit 971217
    /* move to next compount packet */
Packit 971217
    data += header_len;
Packit 971217
    data_len -= header_len;
Packit 971217
Packit 971217
    /* we are at the end now */
Packit 971217
    if (data_len < 4)
Packit 971217
      break;
Packit 971217
Packit 971217
    /* padding only allowed on last packet */
Packit 971217
    if (padding)
Packit 971217
      break;
Packit 971217
Packit 971217
    /* check version of new packet */
Packit 971217
    version = data[0] & 0xc0;
Packit 971217
    if (version != (GST_RTCP_VERSION << 6))
Packit 971217
      goto wrong_version;
Packit 971217
Packit 971217
    /* check padding of new packet */
Packit 971217
    if (data[0] & 0x20) {
Packit 971217
      padding = TRUE;
Packit 971217
      /* last byte of padding contains the number of padded bytes including
Packit 971217
       * itself. must be a multiple of 4, but cannot be 0. */
Packit 971217
      pad_bytes = data[data_len - 1];
Packit 971217
      if (pad_bytes == 0 || (pad_bytes & 0x3))
Packit 971217
        goto wrong_padding;
Packit 971217
    }
Packit 971217
  }
Packit 971217
  if (data_len != 0) {
Packit 971217
    /* some leftover bytes */
Packit 971217
    goto wrong_length;
Packit 971217
  }
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
wrong_length:
Packit 971217
  {
Packit 971217
    GST_DEBUG ("len check failed");
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
wrong_mask:
Packit 971217
  {
Packit 971217
    GST_DEBUG ("mask check failed (%04x != %04x)", header_mask, valid_mask);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
wrong_version:
Packit 971217
  {
Packit 971217
    GST_DEBUG ("wrong version (%d < 2)", version >> 6);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
wrong_padding:
Packit 971217
  {
Packit 971217
    GST_DEBUG ("padding check failed");
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_validate_data_reduced:
Packit 971217
 * @data: (array length=len): the data to validate
Packit 971217
 * @len: the length of @data to validate
Packit 971217
 *
Packit 971217
 * Check if the @data and @size point to the data of a valid RTCP packet.
Packit 971217
 * Use this function to validate a packet before using the other functions in
Packit 971217
 * this module.
Packit 971217
 *
Packit 971217
 * This function is updated to support reduced size rtcp packets according to
Packit 971217
 * RFC 5506 and will validate full compound RTCP packets as well as reduced
Packit 971217
 * size RTCP packets.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if the data points to a valid RTCP packet.
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_buffer_validate_data_reduced (guint8 * data, guint len)
Packit 971217
{
Packit 971217
  return gst_rtcp_buffer_validate_data_internal (data, len,
Packit 971217
      GST_RTCP_REDUCED_SIZE_VALID_MASK);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_validate_data:
Packit 971217
 * @data: (array length=len): the data to validate
Packit 971217
 * @len: the length of @data to validate
Packit 971217
 *
Packit 971217
 * Check if the @data and @size point to the data of a valid compound,
Packit 971217
 * non-reduced size RTCP packet.
Packit 971217
 * Use this function to validate a packet before using the other functions in
Packit 971217
 * this module.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if the data points to a valid RTCP packet.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_buffer_validate_data (guint8 * data, guint len)
Packit 971217
{
Packit 971217
  return gst_rtcp_buffer_validate_data_internal (data, len,
Packit 971217
      GST_RTCP_VALID_MASK);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_validate_reduced:
Packit 971217
 * @buffer: the buffer to validate
Packit 971217
 *
Packit 971217
 * Check if the data pointed to by @buffer is a valid RTCP packet using
Packit 971217
 * gst_rtcp_buffer_validate_reduced().
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @buffer is a valid RTCP packet.
Packit 971217
 *
Packit 971217
 * Since: 1.6
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_buffer_validate_reduced (GstBuffer * buffer)
Packit 971217
{
Packit 971217
  gboolean res;
Packit 971217
  GstMapInfo map;
Packit 971217
Packit 971217
  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
Packit 971217
Packit 971217
  gst_buffer_map (buffer, &map, GST_MAP_READ);
Packit 971217
  res = gst_rtcp_buffer_validate_data_reduced (map.data, map.size);
Packit 971217
  gst_buffer_unmap (buffer, &map);
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_validate:
Packit 971217
 * @buffer: the buffer to validate
Packit 971217
 *
Packit 971217
 * Check if the data pointed to by @buffer is a valid RTCP packet using
Packit 971217
 * gst_rtcp_buffer_validate_data().
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @buffer is a valid RTCP packet.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_buffer_validate (GstBuffer * buffer)
Packit 971217
{
Packit 971217
  gboolean res;
Packit 971217
  GstMapInfo map;
Packit 971217
Packit 971217
  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
Packit 971217
Packit 971217
  gst_buffer_map (buffer, &map, GST_MAP_READ);
Packit 971217
  res = gst_rtcp_buffer_validate_data (map.data, map.size);
Packit 971217
  gst_buffer_unmap (buffer, &map);
Packit 971217
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_new:
Packit 971217
 * @mtu: the maximum mtu size.
Packit 971217
 *
Packit 971217
 * Create a new buffer for constructing RTCP packets. The packet will have a
Packit 971217
 * maximum size of @mtu.
Packit 971217
 *
Packit 971217
 * Returns: A newly allocated buffer.
Packit 971217
 */
Packit 971217
GstBuffer *
Packit 971217
gst_rtcp_buffer_new (guint mtu)
Packit 971217
{
Packit 971217
  GstBuffer *result;
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (mtu > 0, NULL);
Packit 971217
Packit 971217
  data = g_malloc0 (mtu);
Packit 971217
Packit 971217
  result = gst_buffer_new_wrapped_full (0, data, mtu, 0, 0, data, g_free);
Packit 971217
Packit 971217
  return result;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_map:
Packit 971217
 * @buffer: a buffer with an RTCP packet
Packit 971217
 * @flags: flags for the mapping
Packit 971217
 * @rtcp: resulting #GstRTCPBuffer
Packit 971217
 *
Packit 971217
 * Open @buffer for reading or writing, depending on @flags. The resulting RTCP
Packit 971217
 * buffer state is stored in @rtcp.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_buffer_map (GstBuffer * buffer, GstMapFlags flags,
Packit 971217
    GstRTCPBuffer * rtcp)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (rtcp->buffer == NULL, FALSE);
Packit 971217
  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
Packit 971217
  g_return_val_if_fail (flags & GST_MAP_READ, FALSE);
Packit 971217
Packit 971217
  rtcp->buffer = buffer;
Packit 971217
  gst_buffer_map (buffer, &rtcp->map, flags);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_unmap:
Packit 971217
 * @rtcp: a buffer with an RTCP packet
Packit 971217
 *
Packit 971217
 * Finish @rtcp after being constructed. This function is usually called
Packit 971217
 * after gst_rtcp_buffer_map() and after adding the RTCP items to the new buffer.
Packit 971217
 *
Packit 971217
 * The function adjusts the size of @rtcp with the total length of all the
Packit 971217
 * added packets.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_buffer_unmap (GstRTCPBuffer * rtcp)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), FALSE);
Packit 971217
Packit 971217
  if (rtcp->map.flags & GST_MAP_WRITE) {
Packit 971217
    /* shrink size */
Packit 971217
    gst_buffer_resize (rtcp->buffer, 0, rtcp->map.size);
Packit 971217
  }
Packit 971217
Packit 971217
  gst_buffer_unmap (rtcp->buffer, &rtcp->map);
Packit 971217
  rtcp->buffer = NULL;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_get_packet_count:
Packit 971217
 * @rtcp: a valid RTCP buffer
Packit 971217
 *
Packit 971217
 * Get the number of RTCP packets in @rtcp.
Packit 971217
 *
Packit 971217
 * Returns: the number of RTCP packets in @rtcp.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtcp_buffer_get_packet_count (GstRTCPBuffer * rtcp)
Packit 971217
{
Packit 971217
  GstRTCPPacket packet;
Packit 971217
  guint count;
Packit 971217
Packit 971217
  g_return_val_if_fail (rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), 0);
Packit 971217
  g_return_val_if_fail (rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  count = 0;
Packit 971217
  if (gst_rtcp_buffer_get_first_packet (rtcp, &packet)) {
Packit 971217
    do {
Packit 971217
      count++;
Packit 971217
    } while (gst_rtcp_packet_move_to_next (&packet));
Packit 971217
  }
Packit 971217
Packit 971217
  return count;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * read_packet_header:
Packit 971217
 * @packet: a packet
Packit 971217
 *
Packit 971217
 * Read the packet headers for the packet pointed to by @packet.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @packet pointed to a valid header.
Packit 971217
 */
Packit 971217
static gboolean
Packit 971217
read_packet_header (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  gsize maxsize;
Packit 971217
  guint offset;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  maxsize = packet->rtcp->map.size;
Packit 971217
Packit 971217
  offset = packet->offset;
Packit 971217
Packit 971217
  /* check if we are at the end of the buffer, we add 4 because we also want to
Packit 971217
   * ensure we can read the header. */
Packit 971217
  if (offset + 4 > maxsize)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if ((data[offset] & 0xc0) != (GST_RTCP_VERSION << 6))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  /* read count, type and length */
Packit 971217
  packet->padding = (data[offset] & 0x20) == 0x20;
Packit 971217
  packet->count = data[offset] & 0x1f;
Packit 971217
  packet->type = data[offset + 1];
Packit 971217
  packet->length = (data[offset + 2] << 8) | data[offset + 3];
Packit 971217
  packet->item_offset = 4;
Packit 971217
  packet->item_count = 0;
Packit 971217
  packet->entry_offset = 4;
Packit 971217
Packit 971217
  /* Ensure no overread from the claimed data size. The packet length
Packit 971217
     is expressed in multiple of 32 bits, to make things obvious. */
Packit 971217
  if (offset + 4 + packet->length * 4 > maxsize)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_get_first_packet:
Packit 971217
 * @rtcp: a valid RTCP buffer
Packit 971217
 * @packet: a #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Initialize a new #GstRTCPPacket pointer that points to the first packet in
Packit 971217
 * @rtcp.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if the packet existed in @rtcp.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_buffer_get_first_packet (GstRTCPBuffer * rtcp, GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), FALSE);
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  /* init to 0 */
Packit 971217
  packet->rtcp = rtcp;
Packit 971217
  packet->offset = 0;
Packit 971217
  packet->type = GST_RTCP_TYPE_INVALID;
Packit 971217
Packit 971217
  if (!read_packet_header (packet))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_move_to_next:
Packit 971217
 * @packet: a #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Move the packet pointer @packet to the next packet in the payload.
Packit 971217
 * Use gst_rtcp_buffer_get_first_packet() to initialize @packet.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @packet is pointing to a valid packet after calling this
Packit 971217
 * function.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_move_to_next (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
Packit 971217
Packit 971217
  /* if we have a padding or invalid packet, it must be the last, 
Packit 971217
   * return FALSE */
Packit 971217
  if (packet->type == GST_RTCP_TYPE_INVALID || packet->padding)
Packit 971217
    goto end;
Packit 971217
Packit 971217
  /* move to next packet. Add 4 because the header is not included in length */
Packit 971217
  packet->offset += (packet->length << 2) + 4;
Packit 971217
Packit 971217
  /* try to read new header */
Packit 971217
  if (!read_packet_header (packet))
Packit 971217
    goto end;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
end:
Packit 971217
  {
Packit 971217
    packet->type = GST_RTCP_TYPE_INVALID;
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_buffer_add_packet:
Packit 971217
 * @rtcp: a valid RTCP buffer
Packit 971217
 * @type: the #GstRTCPType of the new packet
Packit 971217
 * @packet: pointer to new packet
Packit 971217
 *
Packit 971217
 * Add a new packet of @type to @rtcp. @packet will point to the newly created
Packit 971217
 * packet.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if the packet could be created. This function returns %FALSE
Packit 971217
 * if the max mtu is exceeded for the buffer.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_buffer_add_packet (GstRTCPBuffer * rtcp, GstRTCPType type,
Packit 971217
    GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint len;
Packit 971217
  gsize maxsize;
Packit 971217
  guint8 *data;
Packit 971217
  gboolean result;
Packit 971217
Packit 971217
  g_return_val_if_fail (rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), FALSE);
Packit 971217
  g_return_val_if_fail (type != GST_RTCP_TYPE_INVALID, FALSE);
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
Packit 971217
  /* find free space */
Packit 971217
  if (gst_rtcp_buffer_get_first_packet (rtcp, packet))
Packit 971217
    while (gst_rtcp_packet_move_to_next (packet));
Packit 971217
Packit 971217
  maxsize = rtcp->map.maxsize;
Packit 971217
Packit 971217
  /* packet->offset is now pointing to the next free offset in the buffer to
Packit 971217
   * start a compount packet. Next we figure out if we have enough free space in
Packit 971217
   * the buffer to continue. */
Packit 971217
  switch (type) {
Packit 971217
    case GST_RTCP_TYPE_SR:
Packit 971217
      len = 28;
Packit 971217
      break;
Packit 971217
    case GST_RTCP_TYPE_RR:
Packit 971217
      len = 8;
Packit 971217
      break;
Packit 971217
    case GST_RTCP_TYPE_SDES:
Packit 971217
      len = 4;
Packit 971217
      break;
Packit 971217
    case GST_RTCP_TYPE_BYE:
Packit 971217
      len = 4;
Packit 971217
      break;
Packit 971217
    case GST_RTCP_TYPE_APP:
Packit 971217
      len = 12;
Packit 971217
      break;
Packit 971217
    case GST_RTCP_TYPE_RTPFB:
Packit 971217
      len = 12;
Packit 971217
      break;
Packit 971217
    case GST_RTCP_TYPE_PSFB:
Packit 971217
      len = 12;
Packit 971217
      break;
Packit 971217
    case GST_RTCP_TYPE_XR:
Packit 971217
      len = 4;
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      goto unknown_type;
Packit 971217
  }
Packit 971217
  if (packet->offset + len >= maxsize)
Packit 971217
    goto no_space;
Packit 971217
Packit 971217
  rtcp->map.size += len;
Packit 971217
Packit 971217
  data = rtcp->map.data + packet->offset;
Packit 971217
Packit 971217
  data[0] = (GST_RTCP_VERSION << 6);
Packit 971217
  data[1] = type;
Packit 971217
  /* length is stored in multiples of 32 bit words minus the length of the
Packit 971217
   * header */
Packit 971217
  len = (len - 4) >> 2;
Packit 971217
  data[2] = len >> 8;
Packit 971217
  data[3] = len & 0xff;
Packit 971217
Packit 971217
  /* now try to position to the packet */
Packit 971217
  result = read_packet_header (packet);
Packit 971217
Packit 971217
  return result;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
unknown_type:
Packit 971217
  {
Packit 971217
    g_warning ("unknown type %d", type);
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
no_space:
Packit 971217
  {
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_remove:
Packit 971217
 * @packet: a #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Removes the packet pointed to by @packet and moves pointer to the next one
Packit 971217
 *
Packit 971217
 * Returns: TRUE if @packet is pointing to a valid packet after calling this
Packit 971217
 * function.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_remove (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  gboolean ret = FALSE;
Packit 971217
  guint offset = 0;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
Packit 971217
  /* The next packet starts at offset + length + 4 (the header) */
Packit 971217
  offset = packet->offset + (packet->length << 2) + 4;
Packit 971217
Packit 971217
  /* Overwrite this packet with the rest of the data */
Packit 971217
  memmove (packet->rtcp->map.data + packet->offset,
Packit 971217
      packet->rtcp->map.data + offset, packet->rtcp->map.size - offset);
Packit 971217
Packit 971217
  packet->rtcp->map.size -= offset - packet->offset;
Packit 971217
Packit 971217
  /* try to read next header */
Packit 971217
  ret = read_packet_header (packet);
Packit 971217
  if (!ret)
Packit 971217
    packet->type = GST_RTCP_TYPE_INVALID;
Packit 971217
Packit 971217
  return ret;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_get_padding:
Packit 971217
 * @packet: a valid #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the packet padding of the packet pointed to by @packet.
Packit 971217
 *
Packit 971217
 * Returns: If the packet has the padding bit set.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_get_padding (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE);
Packit 971217
Packit 971217
  return packet->padding;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_get_type:
Packit 971217
 * @packet: a valid #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the packet type of the packet pointed to by @packet.
Packit 971217
 *
Packit 971217
 * Returns: The packet type or GST_RTCP_TYPE_INVALID when @packet is not
Packit 971217
 * pointing to a valid packet.
Packit 971217
 */
Packit 971217
GstRTCPType
Packit 971217
gst_rtcp_packet_get_type (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, GST_RTCP_TYPE_INVALID);
Packit 971217
Packit 971217
  return packet->type;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_get_count:
Packit 971217
 * @packet: a valid #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the count field in @packet.
Packit 971217
 *
Packit 971217
 * Returns: The count field in @packet or -1 if @packet does not point to a
Packit 971217
 * valid packet.
Packit 971217
 */
Packit 971217
guint8
Packit 971217
gst_rtcp_packet_get_count (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, -1);
Packit 971217
  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, -1);
Packit 971217
Packit 971217
  return packet->count;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_get_length:
Packit 971217
 * @packet: a valid #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the length field of @packet. This is the length of the packet in
Packit 971217
 * 32-bit words minus one.
Packit 971217
 *
Packit 971217
 * Returns: The length field of @packet.
Packit 971217
 */
Packit 971217
guint16
Packit 971217
gst_rtcp_packet_get_length (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, 0);
Packit 971217
Packit 971217
  return packet->length;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sr_get_sender_info:
Packit 971217
 * @packet: a valid SR #GstRTCPPacket
Packit 971217
 * @ssrc: (out): result SSRC
Packit 971217
 * @ntptime: (out): result NTP time
Packit 971217
 * @rtptime: (out): result RTP time
Packit 971217
 * @packet_count: (out): result packet count
Packit 971217
 * @octet_count: (out): result octet count
Packit 971217
 *
Packit 971217
 * Parse the SR sender info and store the values.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_sr_get_sender_info (GstRTCPPacket * packet, guint32 * ssrc,
Packit 971217
    guint64 * ntptime, guint32 * rtptime, guint32 * packet_count,
Packit 971217
    guint32 * octet_count)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_SR);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_READ);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  /* skip header */
Packit 971217
  data += packet->offset + 4;
Packit 971217
  if (ssrc)
Packit 971217
    *ssrc = GST_READ_UINT32_BE (data);
Packit 971217
  data += 4;
Packit 971217
  if (ntptime)
Packit 971217
    *ntptime = GST_READ_UINT64_BE (data);
Packit 971217
  data += 8;
Packit 971217
  if (rtptime)
Packit 971217
    *rtptime = GST_READ_UINT32_BE (data);
Packit 971217
  data += 4;
Packit 971217
  if (packet_count)
Packit 971217
    *packet_count = GST_READ_UINT32_BE (data);
Packit 971217
  data += 4;
Packit 971217
  if (octet_count)
Packit 971217
    *octet_count = GST_READ_UINT32_BE (data);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sr_set_sender_info:
Packit 971217
 * @packet: a valid SR #GstRTCPPacket
Packit 971217
 * @ssrc: the SSRC
Packit 971217
 * @ntptime: the NTP time
Packit 971217
 * @rtptime: the RTP time
Packit 971217
 * @packet_count: the packet count
Packit 971217
 * @octet_count: the octet count
Packit 971217
 *
Packit 971217
 * Set the given values in the SR packet @packet.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_sr_set_sender_info (GstRTCPPacket * packet, guint32 ssrc,
Packit 971217
    guint64 ntptime, guint32 rtptime, guint32 packet_count, guint32 octet_count)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_SR);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  /* skip header */
Packit 971217
  data += packet->offset + 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, ssrc);
Packit 971217
  data += 4;
Packit 971217
  GST_WRITE_UINT64_BE (data, ntptime);
Packit 971217
  data += 8;
Packit 971217
  GST_WRITE_UINT32_BE (data, rtptime);
Packit 971217
  data += 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, packet_count);
Packit 971217
  data += 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, octet_count);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_rr_get_ssrc:
Packit 971217
 * @packet: a valid RR #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the ssrc field of the RR @packet.
Packit 971217
 *
Packit 971217
 * Returns: the ssrc.
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtcp_packet_rr_get_ssrc (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint32 ssrc;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  /* skip header */
Packit 971217
  data += packet->offset + 4;
Packit 971217
  ssrc = GST_READ_UINT32_BE (data);
Packit 971217
Packit 971217
  return ssrc;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_rr_set_ssrc:
Packit 971217
 * @packet: a valid RR #GstRTCPPacket
Packit 971217
 * @ssrc: the SSRC to set
Packit 971217
 *
Packit 971217
 * Set the ssrc field of the RR @packet.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_rr_set_ssrc (GstRTCPPacket * packet, guint32 ssrc)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_RR);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  /* skip header */
Packit 971217
  data += packet->offset + 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, ssrc);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_get_rb_count:
Packit 971217
 * @packet: a valid SR or RR #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the number of report blocks in @packet.
Packit 971217
 *
Packit 971217
 * Returns: The number of report blocks in @packet.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtcp_packet_get_rb_count (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
Packit 971217
      packet->type == GST_RTCP_TYPE_SR, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  return packet->count;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_get_rb:
Packit 971217
 * @packet: a valid SR or RR #GstRTCPPacket
Packit 971217
 * @nth: the nth report block in @packet
Packit 971217
 * @ssrc: (out): result for data source being reported
Packit 971217
 * @fractionlost: (out): result for fraction lost since last SR/RR
Packit 971217
 * @packetslost: (out): result for the cumululative number of packets lost
Packit 971217
 * @exthighestseq: (out): result for the extended last sequence number received
Packit 971217
 * @jitter: (out): result for the interarrival jitter
Packit 971217
 * @lsr: (out): result for the last SR packet from this source
Packit 971217
 * @dlsr: (out): result for the delay since last SR packet
Packit 971217
 *
Packit 971217
 * Parse the values of the @nth report block in @packet and store the result in
Packit 971217
 * the values.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_get_rb (GstRTCPPacket * packet, guint nth, guint32 * ssrc,
Packit 971217
    guint8 * fractionlost, gint32 * packetslost, guint32 * exthighestseq,
Packit 971217
    guint32 * jitter, guint32 * lsr, guint32 * dlsr)
Packit 971217
{
Packit 971217
  guint offset;
Packit 971217
  guint8 *data;
Packit 971217
  guint32 tmp;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_RR ||
Packit 971217
      packet->type == GST_RTCP_TYPE_SR);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_READ);
Packit 971217
  g_return_if_fail (nth < packet->count);
Packit 971217
Packit 971217
  /* get offset in 32-bits words into packet, skip the header */
Packit 971217
  if (packet->type == GST_RTCP_TYPE_RR)
Packit 971217
    offset = 2;
Packit 971217
  else
Packit 971217
    offset = 7;
Packit 971217
Packit 971217
  /* move to requested index */
Packit 971217
  offset += (nth * 6);
Packit 971217
Packit 971217
  /* check that we don't go past the packet length */
Packit 971217
  if (offset > packet->length)
Packit 971217
    return;
Packit 971217
Packit 971217
  /* scale to bytes */
Packit 971217
  offset <<= 2;
Packit 971217
  offset += packet->offset;
Packit 971217
Packit 971217
  /* check if the packet is valid */
Packit 971217
  if (offset + 24 > packet->rtcp->map.size)
Packit 971217
    return;
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  data += offset;
Packit 971217
Packit 971217
  if (ssrc)
Packit 971217
    *ssrc = GST_READ_UINT32_BE (data);
Packit 971217
  data += 4;
Packit 971217
  tmp = GST_READ_UINT32_BE (data);
Packit 971217
  if (fractionlost)
Packit 971217
    *fractionlost = (tmp >> 24);
Packit 971217
  if (packetslost) {
Packit 971217
    /* sign extend */
Packit 971217
    if (tmp & 0x00800000)
Packit 971217
      tmp |= 0xff000000;
Packit 971217
    else
Packit 971217
      tmp &= 0x00ffffff;
Packit 971217
    *packetslost = (gint32) tmp;
Packit 971217
  }
Packit 971217
  data += 4;
Packit 971217
  if (exthighestseq)
Packit 971217
    *exthighestseq = GST_READ_UINT32_BE (data);
Packit 971217
  data += 4;
Packit 971217
  if (jitter)
Packit 971217
    *jitter = GST_READ_UINT32_BE (data);
Packit 971217
  data += 4;
Packit 971217
  if (lsr)
Packit 971217
    *lsr = GST_READ_UINT32_BE (data);
Packit 971217
  data += 4;
Packit 971217
  if (dlsr)
Packit 971217
    *dlsr = GST_READ_UINT32_BE (data);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_add_rb:
Packit 971217
 * @packet: a valid SR or RR #GstRTCPPacket
Packit 971217
 * @ssrc: data source being reported
Packit 971217
 * @fractionlost: fraction lost since last SR/RR
Packit 971217
 * @packetslost: the cumululative number of packets lost
Packit 971217
 * @exthighestseq: the extended last sequence number received
Packit 971217
 * @jitter: the interarrival jitter
Packit 971217
 * @lsr: the last SR packet from this source
Packit 971217
 * @dlsr: the delay since last SR packet
Packit 971217
 *
Packit 971217
 * Add a new report block to @packet with the given values.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if the packet was created. This function can return %FALSE if
Packit 971217
 * the max MTU is exceeded or the number of report blocks is greater than
Packit 971217
 * #GST_RTCP_MAX_RB_COUNT.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_add_rb (GstRTCPPacket * packet, guint32 ssrc,
Packit 971217
    guint8 fractionlost, gint32 packetslost, guint32 exthighestseq,
Packit 971217
    guint32 jitter, guint32 lsr, guint32 dlsr)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint maxsize, offset;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
Packit 971217
      packet->type == GST_RTCP_TYPE_SR, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
  /* if profile-specific extension is added, fail for now!? */
Packit 971217
  g_return_val_if_fail (gst_rtcp_packet_get_profile_specific_ext_length (packet)
Packit 971217
      == 0, FALSE);
Packit 971217
Packit 971217
  if (packet->count >= GST_RTCP_MAX_RB_COUNT)
Packit 971217
    goto no_space;
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  maxsize = packet->rtcp->map.maxsize;
Packit 971217
Packit 971217
  /* skip header */
Packit 971217
  offset = packet->offset + 4;
Packit 971217
  if (packet->type == GST_RTCP_TYPE_RR)
Packit 971217
    offset += 4;
Packit 971217
  else
Packit 971217
    offset += 24;
Packit 971217
Packit 971217
  /* move to current index */
Packit 971217
  offset += (packet->count * 24);
Packit 971217
Packit 971217
  /* we need 24 free bytes now */
Packit 971217
  if (offset + 24 >= maxsize)
Packit 971217
    goto no_space;
Packit 971217
Packit 971217
  /* increment packet count and length */
Packit 971217
  packet->count++;
Packit 971217
  data[packet->offset]++;
Packit 971217
  packet->length += 6;
Packit 971217
  data[packet->offset + 2] = (packet->length) >> 8;
Packit 971217
  data[packet->offset + 3] = (packet->length) & 0xff;
Packit 971217
  packet->rtcp->map.size += 6 * 4;
Packit 971217
Packit 971217
  /* move to new report block offset */
Packit 971217
  data += offset;
Packit 971217
Packit 971217
  GST_WRITE_UINT32_BE (data, ssrc);
Packit 971217
  data += 4;
Packit 971217
  GST_WRITE_UINT32_BE (data,
Packit 971217
      ((guint32) fractionlost << 24) | (packetslost & 0xffffff));
Packit 971217
  data += 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, exthighestseq);
Packit 971217
  data += 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, jitter);
Packit 971217
  data += 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, lsr);
Packit 971217
  data += 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, dlsr);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
no_space:
Packit 971217
  {
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_set_rb:
Packit 971217
 * @packet: a valid SR or RR #GstRTCPPacket
Packit 971217
 * @nth: the nth report block to set
Packit 971217
 * @ssrc: data source being reported
Packit 971217
 * @fractionlost: fraction lost since last SR/RR
Packit 971217
 * @packetslost: the cumululative number of packets lost
Packit 971217
 * @exthighestseq: the extended last sequence number received
Packit 971217
 * @jitter: the interarrival jitter
Packit 971217
 * @lsr: the last SR packet from this source
Packit 971217
 * @dlsr: the delay since last SR packet
Packit 971217
 *
Packit 971217
 * Set the @nth new report block in @packet with the given values.
Packit 971217
 *
Packit 971217
 * Note: Not implemented.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_set_rb (GstRTCPPacket * packet, guint nth, guint32 ssrc,
Packit 971217
    guint8 fractionlost, gint32 packetslost, guint32 exthighestseq,
Packit 971217
    guint32 jitter, guint32 lsr, guint32 dlsr)
Packit 971217
{
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_RR ||
Packit 971217
      packet->type == GST_RTCP_TYPE_SR);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
Packit 971217
Packit 971217
  g_warning ("not implemented");
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_add_profile_specific_ext:
Packit 971217
 * @packet: a valid SR or RR #GstRTCPPacket
Packit 971217
 * @data: (array length=len) (transfer none): profile-specific data
Packit 971217
 * @len: length of the profile-specific data in bytes
Packit 971217
 *
Packit 971217
 * Add profile-specific extension @data to @packet. If @packet already
Packit 971217
 * contains profile-specific extension @data will be appended to the existing
Packit 971217
 * extension.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if the profile specific extension data was added.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_add_profile_specific_ext (GstRTCPPacket * packet,
Packit 971217
    const guint8 * data, guint len)
Packit 971217
{
Packit 971217
  guint8 *bdata;
Packit 971217
  guint maxsize, offset;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
Packit 971217
      packet->type == GST_RTCP_TYPE_SR, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
  g_return_val_if_fail ((len & 0x03) == 0, FALSE);
Packit 971217
Packit 971217
  bdata = packet->rtcp->map.data;
Packit 971217
  maxsize = packet->rtcp->map.maxsize;
Packit 971217
Packit 971217
  /* skip to the end of the packet */
Packit 971217
  offset = packet->offset + (packet->length << 2) + 4;
Packit 971217
Packit 971217
  /* we need 'len' free bytes now */
Packit 971217
  if (G_UNLIKELY (offset + len > maxsize))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  memcpy (&bdata[offset], data, len);
Packit 971217
  packet->length += len >> 2;
Packit 971217
  bdata[packet->offset + 2] = (packet->length) >> 8;
Packit 971217
  bdata[packet->offset + 3] = (packet->length) & 0xff;
Packit 971217
  packet->rtcp->map.size += len;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_get_profile_specific_ext_length:
Packit 971217
 * @packet: a valid SR or RR #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Returns: The number of 32-bit words containing profile-specific extension
Packit 971217
 *          data from @packet.
Packit 971217
 */
Packit 971217
guint16
Packit 971217
gst_rtcp_packet_get_profile_specific_ext_length (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint pse_offset = 2;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
Packit 971217
      packet->type == GST_RTCP_TYPE_SR, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  if (packet->type == GST_RTCP_TYPE_SR)
Packit 971217
    pse_offset += 5;
Packit 971217
  pse_offset += (packet->count * 6);
Packit 971217
Packit 971217
  if (pse_offset <= (packet->length + 1))
Packit 971217
    return packet->length + 1 - pse_offset;
Packit 971217
Packit 971217
  /* This means that the packet is invalid! */
Packit 971217
  return 0;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_get_profile_specific_ext:
Packit 971217
 * @packet: a valid SR or RR #GstRTCPPacket
Packit 971217
 * @data: (out) (array length=len) (transfer none): result profile-specific data
Packit 971217
 * @len: (out): result length of the profile-specific data
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if there was valid data.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_get_profile_specific_ext (GstRTCPPacket * packet,
Packit 971217
    guint8 ** data, guint * len)
Packit 971217
{
Packit 971217
  guint16 pse_len;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
Packit 971217
      packet->type == GST_RTCP_TYPE_SR, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
Packit 971217
Packit 971217
  pse_len = gst_rtcp_packet_get_profile_specific_ext_length (packet);
Packit 971217
  if (pse_len > 0) {
Packit 971217
    if (len != NULL)
Packit 971217
      *len = pse_len * sizeof (guint32);
Packit 971217
    if (data != NULL) {
Packit 971217
      *data = packet->rtcp->map.data;
Packit 971217
      *data += packet->offset;
Packit 971217
      *data += ((packet->length + 1 - pse_len) * sizeof (guint32));
Packit 971217
    }
Packit 971217
Packit 971217
    return TRUE;
Packit 971217
  }
Packit 971217
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_copy_profile_specific_ext:
Packit 971217
 * @packet: a valid SR or RR #GstRTCPPacket
Packit 971217
 * @data: (out) (array length=len): result profile-specific data
Packit 971217
 * @len: (out): length of the profile-specific extension data
Packit 971217
 *
Packit 971217
 * The profile-specific extension data is copied into a new allocated
Packit 971217
 * memory area @data. This must be freed with g_free() after usage.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if there was valid data.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_copy_profile_specific_ext (GstRTCPPacket * packet,
Packit 971217
    guint8 ** data, guint * len)
Packit 971217
{
Packit 971217
  guint16 pse_len;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
Packit 971217
      packet->type == GST_RTCP_TYPE_SR, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
Packit 971217
Packit 971217
  pse_len = gst_rtcp_packet_get_profile_specific_ext_length (packet);
Packit 971217
  if (pse_len > 0) {
Packit 971217
    if (len != NULL)
Packit 971217
      *len = pse_len * sizeof (guint32);
Packit 971217
    if (data != NULL) {
Packit 971217
      guint8 *ptr = packet->rtcp->map.data + packet->offset;
Packit 971217
      ptr += ((packet->length + 1 - pse_len) * sizeof (guint32));
Packit 971217
      *data = g_memdup (ptr, pse_len * sizeof (guint32));
Packit 971217
    }
Packit 971217
Packit 971217
    return TRUE;
Packit 971217
  }
Packit 971217
Packit 971217
  return FALSE;
Packit 971217
}
Packit 971217
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_get_item_count:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the number of items in the SDES packet @packet.
Packit 971217
 *
Packit 971217
 * Returns: The number of items in @packet.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtcp_packet_sdes_get_item_count (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
Packit 971217
Packit 971217
  return packet->count;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_first_item:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Move to the first SDES item in @packet.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if there was a first item.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_sdes_first_item (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
Packit 971217
Packit 971217
  packet->item_offset = 4;
Packit 971217
  packet->item_count = 0;
Packit 971217
  packet->entry_offset = 4;
Packit 971217
Packit 971217
  if (packet->count == 0)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_next_item:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Move to the next SDES item in @packet.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if there was a next item.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_sdes_next_item (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint offset;
Packit 971217
  guint len;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
Packit 971217
Packit 971217
  /* if we are at the last item, we are done */
Packit 971217
  if (packet->item_count == packet->count)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  /* move to SDES */
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  data += packet->offset;
Packit 971217
  /* move to item */
Packit 971217
  offset = packet->item_offset;
Packit 971217
  /* skip SSRC */
Packit 971217
  offset += 4;
Packit 971217
Packit 971217
  /* don't overrun */
Packit 971217
  len = (packet->length << 2);
Packit 971217
Packit 971217
  while (offset < len) {
Packit 971217
    if (data[offset] == 0) {
Packit 971217
      /* end of list, round to next 32-bit word */
Packit 971217
      offset = (offset + 4) & ~3;
Packit 971217
      break;
Packit 971217
    }
Packit 971217
    offset += data[offset + 1] + 2;
Packit 971217
  }
Packit 971217
  if (offset >= len)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  packet->item_offset = offset;
Packit 971217
  packet->item_count++;
Packit 971217
  packet->entry_offset = 4;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_get_ssrc:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the SSRC of the current SDES item.
Packit 971217
 *
Packit 971217
 * Returns: the SSRC of the current item.
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtcp_packet_sdes_get_ssrc (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint32 ssrc;
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  /* move to SDES */
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  data += packet->offset;
Packit 971217
  /* move to item */
Packit 971217
  data += packet->item_offset;
Packit 971217
Packit 971217
  ssrc = GST_READ_UINT32_BE (data);
Packit 971217
Packit 971217
  return ssrc;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_first_entry:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Move to the first SDES entry in the current item.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if there was a first entry.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_sdes_first_entry (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint len, offset;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
Packit 971217
Packit 971217
  /* move to SDES */
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  data += packet->offset;
Packit 971217
  /* move to item */
Packit 971217
  offset = packet->item_offset;
Packit 971217
  /* skip SSRC */
Packit 971217
  offset += 4;
Packit 971217
Packit 971217
  packet->entry_offset = 4;
Packit 971217
Packit 971217
  /* don't overrun */
Packit 971217
  len = (packet->length << 2);
Packit 971217
  if (offset >= len)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if (data[offset] == 0)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_next_entry:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Move to the next SDES entry in the current item.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if there was a next entry.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_sdes_next_entry (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint len, offset, item_len;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
Packit 971217
Packit 971217
  /* move to SDES */
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  data += packet->offset;
Packit 971217
  /* move to item */
Packit 971217
  offset = packet->item_offset;
Packit 971217
  /* move to entry */
Packit 971217
  offset += packet->entry_offset;
Packit 971217
Packit 971217
  item_len = data[offset + 1] + 2;
Packit 971217
  /* skip item */
Packit 971217
  offset += item_len;
Packit 971217
Packit 971217
  /* don't overrun */
Packit 971217
  len = (packet->length << 2);
Packit 971217
  if (offset >= len)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  packet->entry_offset += item_len;
Packit 971217
Packit 971217
  /* check for end of list */
Packit 971217
  if (data[offset] == 0)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_get_entry:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 * @type: result of the entry type
Packit 971217
 * @len: (out): result length of the entry data
Packit 971217
 * @data: (out) (array length=len) (transfer none): result entry data
Packit 971217
 *
Packit 971217
 * Get the data of the current SDES item entry. @type (when not NULL) will
Packit 971217
 * contain the type of the entry. @data (when not NULL) will point to @len
Packit 971217
 * bytes.
Packit 971217
 *
Packit 971217
 * When @type refers to a text item, @data will point to a UTF8 string. Note
Packit 971217
 * that this UTF8 string is NOT null-terminated. Use
Packit 971217
 * gst_rtcp_packet_sdes_copy_entry() to get a null-terminated copy of the entry.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if there was valid data.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_sdes_get_entry (GstRTCPPacket * packet,
Packit 971217
    GstRTCPSDESType * type, guint8 * len, guint8 ** data)
Packit 971217
{
Packit 971217
  guint8 *bdata;
Packit 971217
  guint offset;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
Packit 971217
Packit 971217
  /* move to SDES */
Packit 971217
  bdata = packet->rtcp->map.data;
Packit 971217
  bdata += packet->offset;
Packit 971217
  /* move to item */
Packit 971217
  offset = packet->item_offset;
Packit 971217
  /* move to entry */
Packit 971217
  offset += packet->entry_offset;
Packit 971217
Packit 971217
  if (bdata[offset] == 0)
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if (type)
Packit 971217
    *type = bdata[offset];
Packit 971217
  if (len)
Packit 971217
    *len = bdata[offset + 1];
Packit 971217
  if (data)
Packit 971217
    *data = &bdata[offset + 2];
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_copy_entry:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 * @type: result of the entry type
Packit 971217
 * @len: (out): result length of the entry data
Packit 971217
 * @data: (out) (array length=len): result entry data
Packit 971217
 *
Packit 971217
 * This function is like gst_rtcp_packet_sdes_get_entry() but it returns a
Packit 971217
 * null-terminated copy of the data instead. use g_free() after usage.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if there was valid data.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_sdes_copy_entry (GstRTCPPacket * packet,
Packit 971217
    GstRTCPSDESType * type, guint8 * len, guint8 ** data)
Packit 971217
{
Packit 971217
  guint8 *tdata;
Packit 971217
  guint8 tlen;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
Packit 971217
Packit 971217
  if (!gst_rtcp_packet_sdes_get_entry (packet, type, &tlen, &tdata))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  if (len)
Packit 971217
    *len = tlen;
Packit 971217
  if (data)
Packit 971217
    *data = (guint8 *) g_strndup ((gchar *) tdata, tlen);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_add_item:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 * @ssrc: the SSRC of the new item to add
Packit 971217
 *
Packit 971217
 * Add a new SDES item for @ssrc to @packet.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if the item could be added, %FALSE if the maximum amount of
Packit 971217
 * items has been exceeded for the SDES packet or the MTU has been reached.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_sdes_add_item (GstRTCPPacket * packet, guint32 ssrc)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint offset;
Packit 971217
  gsize maxsize;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
Packit 971217
  /* increment item count when possible */
Packit 971217
  if (packet->count >= GST_RTCP_MAX_SDES_ITEM_COUNT)
Packit 971217
    goto no_space;
Packit 971217
Packit 971217
  /* pretend there is a next packet for the next call */
Packit 971217
  packet->count++;
Packit 971217
Packit 971217
  /* jump over current item */
Packit 971217
  gst_rtcp_packet_sdes_next_item (packet);
Packit 971217
Packit 971217
  /* move to SDES */
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  maxsize = packet->rtcp->map.maxsize;
Packit 971217
  data += packet->offset;
Packit 971217
  /* move to current item */
Packit 971217
  offset = packet->item_offset;
Packit 971217
Packit 971217
  /* we need 2 free words now */
Packit 971217
  if (offset + 8 >= maxsize)
Packit 971217
    goto no_next;
Packit 971217
Packit 971217
  /* write SSRC */
Packit 971217
  GST_WRITE_UINT32_BE (&data[offset], ssrc);
Packit 971217
  /* write 0 entry with padding */
Packit 971217
  GST_WRITE_UINT32_BE (&data[offset + 4], 0);
Packit 971217
Packit 971217
  /* update count */
Packit 971217
  data[0] = (data[0] & 0xe0) | packet->count;
Packit 971217
  /* update length, we added 2 words */
Packit 971217
  packet->length += 2;
Packit 971217
  data[2] = (packet->length) >> 8;
Packit 971217
  data[3] = (packet->length) & 0xff;
Packit 971217
Packit 971217
  packet->rtcp->map.size += 8;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
no_space:
Packit 971217
  {
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
no_next:
Packit 971217
  {
Packit 971217
    packet->count--;
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_sdes_add_entry:
Packit 971217
 * @packet: a valid SDES #GstRTCPPacket
Packit 971217
 * @type: the #GstRTCPSDESType of the SDES entry
Packit 971217
 * @len: the data length
Packit 971217
 * @data: (array length=len): the data
Packit 971217
 *
Packit 971217
 * Add a new SDES entry to the current item in @packet.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if the item could be added, %FALSE if the MTU has been
Packit 971217
 * reached.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_sdes_add_entry (GstRTCPPacket * packet, GstRTCPSDESType type,
Packit 971217
    guint8 len, const guint8 * data)
Packit 971217
{
Packit 971217
  guint8 *bdata;
Packit 971217
  guint offset, padded;
Packit 971217
  gsize maxsize;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
Packit 971217
  /* move to SDES */
Packit 971217
  bdata = packet->rtcp->map.data;
Packit 971217
  maxsize = packet->rtcp->map.maxsize;
Packit 971217
  bdata += packet->offset;
Packit 971217
  /* move to item */
Packit 971217
  offset = packet->item_offset;
Packit 971217
  /* move to entry */
Packit 971217
  offset += packet->entry_offset;
Packit 971217
Packit 971217
  /* add 1 byte end and up to 3 bytes padding to fill a full 32 bit word */
Packit 971217
  padded = (offset + 2 + len + 1 + 3) & ~3;
Packit 971217
Packit 971217
  /* we need enough space for type, len, data and padding */
Packit 971217
  if (packet->offset + padded >= maxsize)
Packit 971217
    goto no_space;
Packit 971217
Packit 971217
  packet->rtcp->map.size = packet->offset + padded;
Packit 971217
Packit 971217
  bdata[offset] = type;
Packit 971217
  bdata[offset + 1] = len;
Packit 971217
  memcpy (&bdata[offset + 2], data, len);
Packit 971217
  bdata[offset + 2 + len] = 0;
Packit 971217
Packit 971217
  /* calculate new packet length */
Packit 971217
  packet->length = (padded - 4) >> 2;
Packit 971217
  bdata[2] = (packet->length) >> 8;
Packit 971217
  bdata[3] = (packet->length) & 0xff;
Packit 971217
Packit 971217
  /* position to new next entry */
Packit 971217
  packet->entry_offset += 2 + len;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
no_space:
Packit 971217
  {
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_bye_get_ssrc_count:
Packit 971217
 * @packet: a valid BYE #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the number of SSRC fields in @packet.
Packit 971217
 *
Packit 971217
 * Returns: The number of SSRC fields in @packet.
Packit 971217
 */
Packit 971217
guint
Packit 971217
gst_rtcp_packet_bye_get_ssrc_count (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, -1);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, -1);
Packit 971217
Packit 971217
  return packet->count;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_bye_get_nth_ssrc:
Packit 971217
 * @packet: a valid BYE #GstRTCPPacket
Packit 971217
 * @nth: the nth SSRC to get
Packit 971217
 *
Packit 971217
 * Get the @nth SSRC of the BYE @packet.
Packit 971217
 *
Packit 971217
 * Returns: The @nth SSRC of @packet.
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtcp_packet_bye_get_nth_ssrc (GstRTCPPacket * packet, guint nth)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint offset;
Packit 971217
  guint32 ssrc;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
  g_return_val_if_fail (nth < packet->count, 0);
Packit 971217
Packit 971217
  /* get offset in 32-bits words into packet, skip the header */
Packit 971217
  offset = 1 + nth;
Packit 971217
  /* check that we don't go past the packet length */
Packit 971217
  if (offset > packet->length)
Packit 971217
    return 0;
Packit 971217
Packit 971217
  /* scale to bytes */
Packit 971217
  offset <<= 2;
Packit 971217
  offset += packet->offset;
Packit 971217
Packit 971217
  /* check if the packet is valid */
Packit 971217
  if (offset + 4 > packet->rtcp->map.size)
Packit 971217
    return 0;
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  data += offset;
Packit 971217
Packit 971217
  ssrc = GST_READ_UINT32_BE (data);
Packit 971217
Packit 971217
  return ssrc;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_bye_add_ssrc:
Packit 971217
 * @packet: a valid BYE #GstRTCPPacket
Packit 971217
 * @ssrc: an SSRC to add
Packit 971217
 *
Packit 971217
 * Add @ssrc to the BYE @packet.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if the ssrc was added. This function can return %FALSE if
Packit 971217
 * the max MTU is exceeded or the number of sources blocks is greater than
Packit 971217
 * #GST_RTCP_MAX_BYE_SSRC_COUNT.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_bye_add_ssrc (GstRTCPPacket * packet, guint32 ssrc)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  gsize maxsize;
Packit 971217
  guint offset;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
Packit 971217
  if (packet->count >= GST_RTCP_MAX_BYE_SSRC_COUNT)
Packit 971217
    goto no_space;
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  maxsize = packet->rtcp->map.maxsize;
Packit 971217
Packit 971217
  /* skip header */
Packit 971217
  offset = packet->offset + 4;
Packit 971217
Packit 971217
  /* move to current index */
Packit 971217
  offset += (packet->count * 4);
Packit 971217
Packit 971217
  if (offset + 4 >= maxsize)
Packit 971217
    goto no_space;
Packit 971217
Packit 971217
  /* increment packet count and length */
Packit 971217
  packet->count++;
Packit 971217
  data[packet->offset]++;
Packit 971217
  packet->length += 1;
Packit 971217
  data[packet->offset + 2] = (packet->length) >> 8;
Packit 971217
  data[packet->offset + 3] = (packet->length) & 0xff;
Packit 971217
Packit 971217
  packet->rtcp->map.size += 4;
Packit 971217
Packit 971217
  /* move to new SSRC offset and write ssrc */
Packit 971217
  data += offset;
Packit 971217
  GST_WRITE_UINT32_BE (data, ssrc);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
no_space:
Packit 971217
  {
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_bye_add_ssrcs:
Packit 971217
 * @packet: a valid BYE #GstRTCPPacket
Packit 971217
 * @ssrc: (array length=len) (transfer none): an array of SSRCs to add
Packit 971217
 * @len: number of elements in @ssrc
Packit 971217
 *
Packit 971217
 * Adds @len SSRCs in @ssrc to BYE @packet.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if the all the SSRCs were added. This function can return %FALSE if
Packit 971217
 * the max MTU is exceeded or the number of sources blocks is greater than
Packit 971217
 * #GST_RTCP_MAX_BYE_SSRC_COUNT.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_bye_add_ssrcs (GstRTCPPacket * packet, guint32 * ssrc,
Packit 971217
    guint len)
Packit 971217
{
Packit 971217
  guint i;
Packit 971217
  gboolean res;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
Packit 971217
  res = TRUE;
Packit 971217
  for (i = 0; i < len && res; i++) {
Packit 971217
    res = gst_rtcp_packet_bye_add_ssrc (packet, ssrc[i]);
Packit 971217
  }
Packit 971217
  return res;
Packit 971217
}
Packit 971217
Packit 971217
/* get the offset in packet of the reason length */
Packit 971217
static guint
Packit 971217
get_reason_offset (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint offset;
Packit 971217
Packit 971217
  /* get amount of sources plus header */
Packit 971217
  offset = 1 + packet->count;
Packit 971217
Packit 971217
  /* check that we don't go past the packet length */
Packit 971217
  if (offset > packet->length)
Packit 971217
    return 0;
Packit 971217
Packit 971217
  /* scale to bytes */
Packit 971217
  offset <<= 2;
Packit 971217
  offset += packet->offset;
Packit 971217
Packit 971217
  /* check if the packet is valid */
Packit 971217
  if (offset + 1 > packet->rtcp->map.size)
Packit 971217
    return 0;
Packit 971217
Packit 971217
  return offset;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_bye_get_reason_len:
Packit 971217
 * @packet: a valid BYE #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the length of the reason string.
Packit 971217
 *
Packit 971217
 * Returns: The length of the reason string or 0 when there is no reason string
Packit 971217
 * present.
Packit 971217
 */
Packit 971217
guint8
Packit 971217
gst_rtcp_packet_bye_get_reason_len (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint roffset;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  roffset = get_reason_offset (packet);
Packit 971217
  if (roffset == 0)
Packit 971217
    return 0;
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  return data[roffset];
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_bye_get_reason:
Packit 971217
 * @packet: a valid BYE #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the reason in @packet.
Packit 971217
 *
Packit 971217
 * Returns: The reason for the BYE @packet or NULL if the packet did not contain
Packit 971217
 * a reason string. The string must be freed with g_free() after usage.
Packit 971217
 */
Packit 971217
gchar *
Packit 971217
gst_rtcp_packet_bye_get_reason (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint roffset;
Packit 971217
  guint8 len;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, NULL);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, NULL);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, NULL);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
Packit 971217
Packit 971217
  roffset = get_reason_offset (packet);
Packit 971217
  if (roffset == 0)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  /* get length of reason string */
Packit 971217
  len = data[roffset];
Packit 971217
  if (len == 0)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  /* move to string */
Packit 971217
  roffset += 1;
Packit 971217
Packit 971217
  /* check if enough data to copy */
Packit 971217
  if (roffset + len > packet->rtcp->map.size)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  return g_strndup ((gconstpointer) (data + roffset), len);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_bye_set_reason:
Packit 971217
 * @packet: a valid BYE #GstRTCPPacket
Packit 971217
 * @reason: a reason string
Packit 971217
 *
Packit 971217
 * Set the reason string to @reason in @packet.
Packit 971217
 *
Packit 971217
 * Returns: TRUE if the string could be set.
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_bye_set_reason (GstRTCPPacket * packet, const gchar * reason)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint roffset;
Packit 971217
  gsize maxsize;
Packit 971217
  guint8 len, padded;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
Packit 971217
  if (reason == NULL)
Packit 971217
    return TRUE;
Packit 971217
Packit 971217
  len = strlen (reason);
Packit 971217
  if (len == 0)
Packit 971217
    return TRUE;
Packit 971217
Packit 971217
  /* make room for the string before we get the offset */
Packit 971217
  packet->length++;
Packit 971217
Packit 971217
  roffset = get_reason_offset (packet);
Packit 971217
  if (roffset == 0)
Packit 971217
    goto no_space;
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
  maxsize = packet->rtcp->map.maxsize;
Packit 971217
Packit 971217
  /* we have 1 byte length and we need to pad to 4 bytes */
Packit 971217
  padded = ((len + 1) + 3) & ~3;
Packit 971217
Packit 971217
  /* we need enough space for the padded length */
Packit 971217
  if (roffset + padded >= maxsize)
Packit 971217
    goto no_space;
Packit 971217
Packit 971217
  data[roffset] = len;
Packit 971217
  memcpy (&data[roffset + 1], reason, len);
Packit 971217
Packit 971217
  /* update packet length, we made room for 1 double word already */
Packit 971217
  packet->length += (padded >> 2) - 1;
Packit 971217
  data[packet->offset + 2] = (packet->length) >> 8;
Packit 971217
  data[packet->offset + 3] = (packet->length) & 0xff;
Packit 971217
Packit 971217
  packet->rtcp->map.size += padded;
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
Packit 971217
  /* ERRORS */
Packit 971217
no_space:
Packit 971217
  {
Packit 971217
    packet->length--;
Packit 971217
    return FALSE;
Packit 971217
  }
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_fb_get_sender_ssrc:
Packit 971217
 * @packet: a valid RTPFB or PSFB #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the sender SSRC field of the RTPFB or PSFB @packet.
Packit 971217
 *
Packit 971217
 * Returns: the sender SSRC.
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtcp_packet_fb_get_sender_ssrc (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint32 ssrc;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
Packit 971217
          packet->type == GST_RTCP_TYPE_PSFB), 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  /* skip header */
Packit 971217
  data += packet->offset + 4;
Packit 971217
  ssrc = GST_READ_UINT32_BE (data);
Packit 971217
Packit 971217
  return ssrc;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_fb_set_sender_ssrc:
Packit 971217
 * @packet: a valid RTPFB or PSFB #GstRTCPPacket
Packit 971217
 * @ssrc: a sender SSRC
Packit 971217
 *
Packit 971217
 * Set the sender SSRC field of the RTPFB or PSFB @packet.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_fb_set_sender_ssrc (GstRTCPPacket * packet, guint32 ssrc)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
Packit 971217
      packet->type == GST_RTCP_TYPE_PSFB);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_READ);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  /* skip header */
Packit 971217
  data += packet->offset + 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, ssrc);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_fb_get_media_ssrc:
Packit 971217
 * @packet: a valid RTPFB or PSFB #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the media SSRC field of the RTPFB or PSFB @packet.
Packit 971217
 *
Packit 971217
 * Returns: the media SSRC.
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtcp_packet_fb_get_media_ssrc (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
  guint32 ssrc;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
Packit 971217
          packet->type == GST_RTCP_TYPE_PSFB), 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  /* skip header and sender ssrc */
Packit 971217
  data += packet->offset + 8;
Packit 971217
  ssrc = GST_READ_UINT32_BE (data);
Packit 971217
Packit 971217
  return ssrc;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_fb_set_media_ssrc:
Packit 971217
 * @packet: a valid RTPFB or PSFB #GstRTCPPacket
Packit 971217
 * @ssrc: a media SSRC
Packit 971217
 *
Packit 971217
 * Set the media SSRC field of the RTPFB or PSFB @packet.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_fb_set_media_ssrc (GstRTCPPacket * packet, guint32 ssrc)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
Packit 971217
      packet->type == GST_RTCP_TYPE_PSFB);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  /* skip header and sender ssrc */
Packit 971217
  data += packet->offset + 8;
Packit 971217
  GST_WRITE_UINT32_BE (data, ssrc);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_fb_get_type:
Packit 971217
 * @packet: a valid RTPFB or PSFB #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the feedback message type of the FB @packet.
Packit 971217
 *
Packit 971217
 * Returns: The feedback message type.
Packit 971217
 */
Packit 971217
GstRTCPFBType
Packit 971217
gst_rtcp_packet_fb_get_type (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, GST_RTCP_FB_TYPE_INVALID);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
Packit 971217
      packet->type == GST_RTCP_TYPE_PSFB, GST_RTCP_FB_TYPE_INVALID);
Packit 971217
Packit 971217
  return packet->count;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_fb_set_type:
Packit 971217
 * @packet: a valid RTPFB or PSFB #GstRTCPPacket
Packit 971217
 * @type: the #GstRTCPFBType to set
Packit 971217
 *
Packit 971217
 * Set the feedback message type of the FB @packet.
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_fb_set_type (GstRTCPPacket * packet, GstRTCPFBType type)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
Packit 971217
      packet->type == GST_RTCP_TYPE_PSFB);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data;
Packit 971217
Packit 971217
  data[packet->offset] = (data[packet->offset] & 0xe0) | type;
Packit 971217
  packet->count = type;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_ntp_to_unix:
Packit 971217
 * @ntptime: an NTP timestamp
Packit 971217
 *
Packit 971217
 * Converts an NTP time to UNIX nanoseconds. @ntptime can typically be
Packit 971217
 * the NTP time of an SR RTCP message and contains, in the upper 32 bits, the
Packit 971217
 * number of seconds since 1900 and, in the lower 32 bits, the fractional
Packit 971217
 * seconds. The resulting value will be the number of nanoseconds since 1970.
Packit 971217
 *
Packit 971217
 * Returns: the UNIX time for @ntptime in nanoseconds.
Packit 971217
 */
Packit 971217
guint64
Packit 971217
gst_rtcp_ntp_to_unix (guint64 ntptime)
Packit 971217
{
Packit 971217
  guint64 unixtime;
Packit 971217
Packit 971217
  /* conversion from NTP timestamp (seconds since 1900) to seconds since
Packit 971217
   * 1970. */
Packit 971217
  unixtime = ntptime - (G_GUINT64_CONSTANT (2208988800) << 32);
Packit 971217
  /* conversion to nanoseconds */
Packit 971217
  unixtime =
Packit 971217
      gst_util_uint64_scale (unixtime, GST_SECOND,
Packit 971217
      (G_GINT64_CONSTANT (1) << 32));
Packit 971217
Packit 971217
  return unixtime;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_unix_to_ntp:
Packit 971217
 * @unixtime: an UNIX timestamp in nanoseconds
Packit 971217
 *
Packit 971217
 * Converts a UNIX timestamp in nanoseconds to an NTP time. The caller should
Packit 971217
 * pass a value with nanoseconds since 1970. The NTP time will, in the upper
Packit 971217
 * 32 bits, contain the number of seconds since 1900 and, in the lower 32
Packit 971217
 * bits, the fractional seconds. The resulting value can be used as an ntptime
Packit 971217
 * for constructing SR RTCP packets.
Packit 971217
 *
Packit 971217
 * Returns: the NTP time for @unixtime.
Packit 971217
 */
Packit 971217
guint64
Packit 971217
gst_rtcp_unix_to_ntp (guint64 unixtime)
Packit 971217
{
Packit 971217
  guint64 ntptime;
Packit 971217
Packit 971217
  /* convert clock time to NTP time. upper 32 bits should contain the seconds
Packit 971217
   * and the lower 32 bits, the fractions of a second. */
Packit 971217
  ntptime =
Packit 971217
      gst_util_uint64_scale (unixtime, (G_GINT64_CONSTANT (1) << 32),
Packit 971217
      GST_SECOND);
Packit 971217
  /* conversion from UNIX timestamp (seconds since 1970) to NTP (seconds
Packit 971217
   * since 1900). */
Packit 971217
  ntptime += (G_GUINT64_CONSTANT (2208988800) << 32);
Packit 971217
Packit 971217
  return ntptime;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_sdes_type_to_name:
Packit 971217
 * @type: a #GstRTCPSDESType
Packit 971217
 *
Packit 971217
 * Converts @type to the string equivalent. The string is typically used as a
Packit 971217
 * key in a #GstStructure containing SDES items.
Packit 971217
 *
Packit 971217
 * Returns: the string equivalent of @type
Packit 971217
 */
Packit 971217
const gchar *
Packit 971217
gst_rtcp_sdes_type_to_name (GstRTCPSDESType type)
Packit 971217
{
Packit 971217
  const gchar *result;
Packit 971217
Packit 971217
  switch (type) {
Packit 971217
    case GST_RTCP_SDES_CNAME:
Packit 971217
      result = "cname";
Packit 971217
      break;
Packit 971217
    case GST_RTCP_SDES_NAME:
Packit 971217
      result = "name";
Packit 971217
      break;
Packit 971217
    case GST_RTCP_SDES_EMAIL:
Packit 971217
      result = "email";
Packit 971217
      break;
Packit 971217
    case GST_RTCP_SDES_PHONE:
Packit 971217
      result = "phone";
Packit 971217
      break;
Packit 971217
    case GST_RTCP_SDES_LOC:
Packit 971217
      result = "location";
Packit 971217
      break;
Packit 971217
    case GST_RTCP_SDES_TOOL:
Packit 971217
      result = "tool";
Packit 971217
      break;
Packit 971217
    case GST_RTCP_SDES_NOTE:
Packit 971217
      result = "note";
Packit 971217
      break;
Packit 971217
    case GST_RTCP_SDES_PRIV:
Packit 971217
      result = "priv";
Packit 971217
      break;
Packit 971217
    default:
Packit 971217
      result = NULL;
Packit 971217
      break;
Packit 971217
  }
Packit 971217
  return result;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_sdes_name_to_type:
Packit 971217
 * @name: a SDES name
Packit 971217
 *
Packit 971217
 * Convert @name into a @GstRTCPSDESType. @name is typically a key in a
Packit 971217
 * #GstStructure containing SDES items.
Packit 971217
 *
Packit 971217
 * Returns: the #GstRTCPSDESType for @name or #GST_RTCP_SDES_PRIV when @name
Packit 971217
 * is a private sdes item.
Packit 971217
 */
Packit 971217
GstRTCPSDESType
Packit 971217
gst_rtcp_sdes_name_to_type (const gchar * name)
Packit 971217
{
Packit 971217
  if (name == NULL || strlen (name) == 0)
Packit 971217
    return GST_RTCP_SDES_INVALID;
Packit 971217
Packit 971217
  if (strcmp ("cname", name) == 0)
Packit 971217
    return GST_RTCP_SDES_CNAME;
Packit 971217
Packit 971217
  if (strcmp ("name", name) == 0)
Packit 971217
    return GST_RTCP_SDES_NAME;
Packit 971217
Packit 971217
  if (strcmp ("email", name) == 0)
Packit 971217
    return GST_RTCP_SDES_EMAIL;
Packit 971217
Packit 971217
  if (strcmp ("phone", name) == 0)
Packit 971217
    return GST_RTCP_SDES_PHONE;
Packit 971217
Packit 971217
  if (strcmp ("location", name) == 0)
Packit 971217
    return GST_RTCP_SDES_LOC;
Packit 971217
Packit 971217
  if (strcmp ("tool", name) == 0)
Packit 971217
    return GST_RTCP_SDES_TOOL;
Packit 971217
Packit 971217
  if (strcmp ("note", name) == 0)
Packit 971217
    return GST_RTCP_SDES_NOTE;
Packit 971217
Packit 971217
  return GST_RTCP_SDES_PRIV;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_fb_get_fci_length:
Packit 971217
 * @packet: a valid RTPFB or PSFB #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the length of the Feedback Control Information attached to a
Packit 971217
 * RTPFB or PSFB @packet.
Packit 971217
 *
Packit 971217
 * Returns: The length of the FCI in 32-bit words.
Packit 971217
 */
Packit 971217
guint16
Packit 971217
gst_rtcp_packet_fb_get_fci_length (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
Packit 971217
      packet->type == GST_RTCP_TYPE_PSFB, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset + 2;
Packit 971217
Packit 971217
  return GST_READ_UINT16_BE (data) - 2;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_fb_set_fci_length:
Packit 971217
 * @packet: a valid RTPFB or PSFB #GstRTCPPacket
Packit 971217
 * @wordlen: Length of the FCI in 32-bit words
Packit 971217
 *
Packit 971217
 * Set the length of the Feedback Control Information attached to a
Packit 971217
 * RTPFB or PSFB @packet.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if there was enough space in the packet to add this much FCI
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_fb_set_fci_length (GstRTCPPacket * packet, guint16 wordlen)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
Packit 971217
      packet->type == GST_RTCP_TYPE_PSFB, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
Packit 971217
  if (packet->rtcp->map.maxsize < packet->offset + ((wordlen + 3) * 4))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset + 2;
Packit 971217
  wordlen += 2;
Packit 971217
  GST_WRITE_UINT16_BE (data, wordlen);
Packit 971217
Packit 971217
  packet->rtcp->map.size = packet->offset + ((wordlen + 1) * 4);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_fb_get_fci:
Packit 971217
 * @packet: a valid RTPFB or PSFB #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the Feedback Control Information attached to a RTPFB or PSFB @packet.
Packit 971217
 *
Packit 971217
 * Returns: a pointer to the FCI
Packit 971217
 */
Packit 971217
guint8 *
Packit 971217
gst_rtcp_packet_fb_get_fci (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, NULL);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
Packit 971217
      packet->type == GST_RTCP_TYPE_PSFB, NULL);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, NULL);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset;
Packit 971217
Packit 971217
  if (GST_READ_UINT16_BE (data + 2) <= 2)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  return data + 12;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_app_set_subtype:
Packit 971217
 * @packet: a valid APP #GstRTCPPacket
Packit 971217
 * @subtype: subtype of the packet
Packit 971217
 *
Packit 971217
 * Set the subtype field of the APP @packet.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 **/
Packit 971217
void
Packit 971217
gst_rtcp_packet_app_set_subtype (GstRTCPPacket * packet, guint8 subtype)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_APP);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset;
Packit 971217
  data[0] = (data[0] & 0xe0) | subtype;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_app_get_subtype:
Packit 971217
 * @packet: a valid APP #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the subtype field of the APP @packet.
Packit 971217
 *
Packit 971217
 * Returns: The subtype.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
guint8
Packit 971217
gst_rtcp_packet_app_get_subtype (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset;
Packit 971217
Packit 971217
  return data[0] & 0x1f;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_app_set_ssrc:
Packit 971217
 * @packet: a valid APP #GstRTCPPacket
Packit 971217
 * @ssrc: SSRC/CSRC of the packet
Packit 971217
 *
Packit 971217
 * Set the SSRC/CSRC field of the APP @packet.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_app_set_ssrc (GstRTCPPacket * packet, guint32 ssrc)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_APP);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset + 4;
Packit 971217
  GST_WRITE_UINT32_BE (data, ssrc);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_app_get_ssrc:
Packit 971217
 * @packet: a valid APP #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the SSRC/CSRC field of the APP @packet.
Packit 971217
 *
Packit 971217
 * Returns: The SSRC/CSRC.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
guint32
Packit 971217
gst_rtcp_packet_app_get_ssrc (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset + 4;
Packit 971217
Packit 971217
  return GST_READ_UINT32_BE (data);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_app_set_name:
Packit 971217
 * @packet: a valid APP #GstRTCPPacket
Packit 971217
 * @name: 4-byte ASCII name
Packit 971217
 *
Packit 971217
 * Set the name field of the APP @packet.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
void
Packit 971217
gst_rtcp_packet_app_set_name (GstRTCPPacket * packet, const gchar * name)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_if_fail (packet != NULL);
Packit 971217
  g_return_if_fail (packet->type == GST_RTCP_TYPE_APP);
Packit 971217
  g_return_if_fail (packet->rtcp != NULL);
Packit 971217
  g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset + 8;
Packit 971217
  memcpy (data, name, 4);
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_app_get_name:
Packit 971217
 * @packet: a valid APP #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the name field of the APP @packet.
Packit 971217
 *
Packit 971217
 * Returns: The 4-byte name field, not zero-terminated.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
const gchar *
Packit 971217
gst_rtcp_packet_app_get_name (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  g_return_val_if_fail (packet != NULL, NULL);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, NULL);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, NULL);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
Packit 971217
Packit 971217
  return (const gchar *) &packet->rtcp->map.data[packet->offset + 8];
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_app_get_data_length:
Packit 971217
 * @packet: a valid APP #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the length of the application-dependent data attached to an APP
Packit 971217
 * @packet.
Packit 971217
 *
Packit 971217
 * Returns: The length of data in 32-bit words.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
guint16
Packit 971217
gst_rtcp_packet_app_get_data_length (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, 0);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset + 2;
Packit 971217
Packit 971217
  return GST_READ_UINT16_BE (data) - 2;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_app_set_data_length:
Packit 971217
 * @packet: a valid APP #GstRTCPPacket
Packit 971217
 * @wordlen: Length of the data in 32-bit words
Packit 971217
 *
Packit 971217
 * Set the length of the application-dependent data attached to an APP
Packit 971217
 * @packet.
Packit 971217
 *
Packit 971217
 * Returns: %TRUE if there was enough space in the packet to add this much
Packit 971217
 * data.
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
gboolean
Packit 971217
gst_rtcp_packet_app_set_data_length (GstRTCPPacket * packet, guint16 wordlen)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, FALSE);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
Packit 971217
Packit 971217
  if (packet->rtcp->map.maxsize < packet->offset + ((wordlen + 3) * 4))
Packit 971217
    return FALSE;
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset + 2;
Packit 971217
  wordlen += 2;
Packit 971217
  GST_WRITE_UINT16_BE (data, wordlen);
Packit 971217
Packit 971217
  packet->rtcp->map.size = packet->offset + ((wordlen + 1) * 4);
Packit 971217
Packit 971217
  return TRUE;
Packit 971217
}
Packit 971217
Packit 971217
/**
Packit 971217
 * gst_rtcp_packet_app_get_data:
Packit 971217
 * @packet: a valid APP #GstRTCPPacket
Packit 971217
 *
Packit 971217
 * Get the application-dependent data attached to a RTPFB or PSFB @packet.
Packit 971217
 *
Packit 971217
 * Returns: A pointer to the data
Packit 971217
 *
Packit 971217
 * Since: 1.10
Packit 971217
 */
Packit 971217
guint8 *
Packit 971217
gst_rtcp_packet_app_get_data (GstRTCPPacket * packet)
Packit 971217
{
Packit 971217
  guint8 *data;
Packit 971217
Packit 971217
  g_return_val_if_fail (packet != NULL, NULL);
Packit 971217
  g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, NULL);
Packit 971217
  g_return_val_if_fail (packet->rtcp != NULL, NULL);
Packit 971217
  g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
Packit 971217
Packit 971217
  data = packet->rtcp->map.data + packet->offset;
Packit 971217
Packit 971217
  if (GST_READ_UINT16_BE (data + 2) <= 2)
Packit 971217
    return NULL;
Packit 971217
Packit 971217
  return data + 12;
Packit 971217
}