GstRTCPPacket
GstRTCPSDESType
GstRTCPFBType
+GstRTCPXRType
gst_rtcp_buffer_new_take_data
gst_rtcp_buffer_new_copy_data
gst_rtcp_sdes_name_to_type
gst_rtcp_sdes_type_to_name
+gst_rtcp_packet_xr_first_rb
+gst_rtcp_packet_xr_next_rb
+gst_rtcp_packet_xr_get_ssrc
+gst_rtcp_packet_xr_get_block_length
+gst_rtcp_packet_xr_get_block_type
+
+gst_rtcp_packet_xr_get_dlrr_block
+
+gst_rtcp_packet_xr_get_prt_by_seq
+gst_rtcp_packet_xr_get_prt_info
+
+gst_rtcp_packet_xr_get_rle_info
+gst_rtcp_packet_xr_get_rle_nth_chunk
+
+gst_rtcp_packet_xr_get_rrt
+
+gst_rtcp_packet_xr_get_summary_info
+gst_rtcp_packet_xr_get_summary_jitter
+gst_rtcp_packet_xr_get_summary_pkt
+gst_rtcp_packet_xr_get_summary_ttl
+
+gst_rtcp_packet_xr_get_voip_burst_metrics
+gst_rtcp_packet_xr_get_voip_configuration_params
+gst_rtcp_packet_xr_get_voip_delay_metrics
+gst_rtcp_packet_xr_get_voip_jitter_buffer_params
+gst_rtcp_packet_xr_get_voip_metrics_ssrc
+gst_rtcp_packet_xr_get_voip_packet_metrics
+gst_rtcp_packet_xr_get_voip_quality_metrics
+gst_rtcp_packet_xr_get_voip_signal_metrics
+
<SUBSECTION Standard>
GST_RTCP_RTPFB_TYPE_RCTP_SR_REQ
GST_TYPE_RTCPFB_TYPE
gst_rtcp_type_get_type
gst_rtcpfb_type_get_type
gst_rtcpsdes_type_get_type
+gst_rtcpxr_type_get_type
</SECTION>
<SECTION>
len = 12;
break;
case GST_RTCP_TYPE_XR:
- len = 4;
+ len = 8;
break;
default:
goto unknown_type;
return data + 12;
}
+
+/**
+ * gst_rtcp_packet_xr_get_ssrc:
+ * @packet: a valid XR #GstRTCPPacket
+ *
+ * Get the ssrc field of the XR @packet.
+ *
+ * Returns: the ssrc.
+ *
+ * Since: 1.16
+ */
+guint32
+gst_rtcp_packet_xr_get_ssrc (GstRTCPPacket * packet)
+{
+ guint8 *data;
+ guint32 ssrc;
+
+ g_return_val_if_fail (packet != NULL, 0);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR, 0);
+ g_return_val_if_fail (packet->rtcp != NULL, 0);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
+
+ data = packet->rtcp->map.data;
+
+ /* skip header */
+ data += packet->offset + 4;
+ ssrc = GST_READ_UINT32_BE (data);
+
+ return ssrc;
+}
+
+/**
+ * gst_rtcp_packet_xr_first_rb:
+ * @packet: a valid XR #GstRTCPPacket
+ *
+ * Move to the first extended report block in XR @packet.
+ *
+ * Returns: TRUE if there was a first extended report block.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_first_rb (GstRTCPPacket * packet)
+{
+ guint16 block_len;
+ guint offset, len;
+
+ g_return_val_if_fail (packet != NULL, FALSE);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR, FALSE);
+
+ if (packet->length < 2)
+ return FALSE;
+
+ /* skip header + ssrc */
+ packet->item_offset = 8;
+
+ /* Validate the block's length */
+ block_len = gst_rtcp_packet_xr_get_block_length (packet);
+ offset = 8 + (block_len * 1) + 4;
+
+ len = packet->length << 2;
+
+ if (offset >= len) {
+ packet->item_offset = 0;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_next_rb:
+ * @packet: a valid XR #GstRTCPPacket
+ *
+ * Move to the next extended report block in XR @packet.
+ *
+ * Returns: TRUE if there was a next extended report block.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_next_rb (GstRTCPPacket * packet)
+{
+ guint16 block_len;
+ guint offset;
+ guint len;
+
+ g_return_val_if_fail (packet != NULL, FALSE);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR, FALSE);
+ g_return_val_if_fail (packet->rtcp != NULL, FALSE);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
+
+ block_len = gst_rtcp_packet_xr_get_block_length (packet);
+
+ offset = packet->item_offset;
+ offset += (block_len + 1) * 4;
+
+ /* don't overrun */
+ len = (packet->length << 2);
+
+ if (offset >= len)
+ return FALSE;
+
+ packet->item_offset = offset;
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_block_type:
+ * @packet: a valid XR #GstRTCPPacket
+ *
+ * Get the extended report block type of the XR @packet.
+ *
+ * Returns: The extended report block type.
+ *
+ * Since: 1.16
+ */
+GstRTCPXRType
+gst_rtcp_packet_xr_get_block_type (GstRTCPPacket * packet)
+{
+ guint8 *data;
+ guint8 type;
+ GstRTCPXRType xr_type = GST_RTCP_XR_TYPE_INVALID;
+
+ g_return_val_if_fail (packet != NULL, GST_RTCP_XR_TYPE_INVALID);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR,
+ GST_RTCP_XR_TYPE_INVALID);
+ g_return_val_if_fail (packet->rtcp != NULL, GST_RTCP_XR_TYPE_INVALID);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ,
+ GST_RTCP_XR_TYPE_INVALID);
+ g_return_val_if_fail (packet->length >= (packet->item_offset >> 2),
+ GST_RTCP_XR_TYPE_INVALID);
+
+ data = packet->rtcp->map.data;
+
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* XR block type can be defined more than described in RFC3611.
+ * If undefined type is detected, user might want to know. */
+ type = GST_READ_UINT8 (data);
+ switch (type) {
+ case GST_RTCP_XR_TYPE_LRLE:
+ case GST_RTCP_XR_TYPE_DRLE:
+ case GST_RTCP_XR_TYPE_PRT:
+ case GST_RTCP_XR_TYPE_RRT:
+ case GST_RTCP_XR_TYPE_DLRR:
+ case GST_RTCP_XR_TYPE_SSUMM:
+ case GST_RTCP_XR_TYPE_VOIP_METRICS:
+ xr_type = type;
+ break;
+ default:
+ GST_DEBUG ("got 0x%x type, but that might be out of scope of RFC3611",
+ type);
+ break;
+ }
+
+ return xr_type;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_block_length:
+ * @packet: a valid XR #GstRTCPPacket
+ *
+ * Returns: The number of 32-bit words containing type-specific block
+ * data from @packet.
+ *
+ * Since: 1.16
+ */
+guint16
+gst_rtcp_packet_xr_get_block_length (GstRTCPPacket * packet)
+{
+ guint8 *data;
+ guint16 len;
+
+ g_return_val_if_fail (packet != NULL, 0);
+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR, 0);
+ g_return_val_if_fail (packet->rtcp != NULL, 0);
+ g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
+ g_return_val_if_fail (packet->length >= (packet->item_offset >> 2), 0);
+
+ data = packet->rtcp->map.data;
+ data += packet->offset + packet->item_offset + 2;
+
+ len = GST_READ_UINT16_BE (data);
+
+ return len;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_rle_info:
+ * @packet: a valid XR #GstRTCPPacket which is Loss RLE or Duplicate RLE report.
+ * @ssrc: the SSRC of the RTP data packet source being reported upon by this report block.
+ * @thining: the amount of thinning performed on the sequence number space.
+ * @begin_seq: the first sequence number that this block reports on.
+ * @end_seq: the last sequence number that this block reports on plus one.
+ * @chunk_count: the number of chunks calculated by block length.
+ *
+ * Parse the extended report block for Loss RLE and Duplicated LRE block type.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_rle_info (GstRTCPPacket * packet, guint32 * ssrc,
+ guint8 * thining, guint16 * begin_seq, guint16 * end_seq,
+ guint32 * chunk_count)
+{
+ guint8 *data;
+ guint16 block_len;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_LRLE
+ || gst_rtcp_packet_xr_get_block_type (packet) == GST_RTCP_XR_TYPE_DRLE,
+ FALSE);
+
+ block_len = gst_rtcp_packet_xr_get_block_length (packet);
+ if (block_len < 3)
+ return FALSE;
+
+ if (chunk_count)
+ *chunk_count = (block_len - 2) * 2;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ if (thining)
+ *thining = data[1] & 0x0f;
+
+ /* go to ssrc */
+ data += 4;
+ if (ssrc)
+ *ssrc = GST_READ_UINT32_BE (data);
+ /* go to begin_seq */
+ data += 4;
+ if (begin_seq)
+ *begin_seq = ((data[0] << 8) | data[1]);
+ /* go to end_seq */
+ data += 2;
+ if (end_seq)
+ *end_seq = ((data[0] << 8) | data[1]);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_rle_nth_chunk:
+ * @packet: a valid XR #GstRTCPPacket which is Loss RLE or Duplicate RLE report.
+ * @nth: the index of chunk to retrieve.
+ * @chunk: the @nth chunk.
+ *
+ * Retrieve actual chunk data.
+ *
+ * Returns: %TRUE if the report block returns chunk correctly.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_rle_nth_chunk (GstRTCPPacket * packet,
+ guint nth, guint16 * chunk)
+{
+ guint32 chunk_count;
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_rle_info (packet, NULL, NULL,
+ NULL, NULL, &chunk_count), FALSE);
+
+ if (nth >= chunk_count)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip ssrc, {begin,end}_seq */
+ data += 12;
+
+ /* goto nth chunk */
+ data += nth * 2;
+ if (chunk)
+ *chunk = ((data[0] << 8) | data[1]);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_prt_info:
+ * @packet: a valid XR #GstRTCPPacket which has a Packet Receipt Times Report Block
+ * @ssrc: the SSRC of the RTP data packet source being reported upon by this report block.
+ * @thining: the amount of thinning performed on the sequence number space.
+ * @begin_seq: the first sequence number that this block reports on.
+ * @end_seq: the last sequence number that this block reports on plus one.
+ *
+ * Parse the Packet Recept Times Report Block from a XR @packet
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_prt_info (GstRTCPPacket * packet,
+ guint32 * ssrc, guint8 * thining, guint16 * begin_seq, guint16 * end_seq)
+{
+ guint8 *data;
+ guint16 block_len;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_PRT, FALSE);
+
+ block_len = gst_rtcp_packet_xr_get_block_length (packet);
+ if (block_len < 3)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ if (thining)
+ *thining = data[1] & 0x0f;
+
+ /* go to ssrc */
+ data += 4;
+ if (ssrc)
+ *ssrc = GST_READ_UINT32_BE (data);
+
+ /* go to begin_seq */
+ data += 4;
+ if (begin_seq)
+ *begin_seq = ((data[0] << 8) | data[1]);
+ /* go to end_seq */
+ data += 2;
+ if (end_seq)
+ *end_seq = ((data[0] << 8) | data[1]);
+
+ if (block_len < (end_seq - begin_seq) + 2)
+ return FALSE;
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_prt_by_seq:
+ * @packet: a valid XR #GstRTCPPacket which has the Packet Recept Times Report Block.
+ * @seq: the sequence to retrieve the time.
+ * @receipt_time: the packet receipt time of @seq.
+ *
+ * Retrieve the packet receipt time of @seq which ranges in [begin_seq, end_seq).
+ *
+ * Returns: %TRUE if the report block returns the receipt time correctly.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_prt_by_seq (GstRTCPPacket * packet,
+ guint16 seq, guint32 * receipt_time)
+{
+ guint16 begin_seq, end_seq;
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_prt_info (packet, NULL, NULL,
+ &begin_seq, &end_seq), FALSE);
+
+ if (seq >= end_seq || seq < begin_seq)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip ssrc, {begin,end}_seq */
+ data += 12;
+
+ data += (seq - begin_seq) * 4;
+
+ if (receipt_time)
+ *receipt_time = GST_READ_UINT32_BE (data);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_rrt:
+ * @packet: a valid XR #GstRTCPPacket which has the Receiver Reference Time.
+ * @timestamp: NTP timestamp
+ *
+ * Returns: %TRUE if the report block returns the reference time correctly.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_rrt (GstRTCPPacket * packet, guint64 * timestamp)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_RRT, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 2)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip block header */
+ data += 4;
+ if (timestamp)
+ *timestamp = GST_READ_UINT64_BE (data);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_dlrr_block:
+ * @packet: a valid XR #GstRTCPPacket which has DLRR Report Block.
+ * @nth: the index of sub-block to retrieve.
+ * @ssrc: the SSRC of the receiver.
+ * @last_rr: the last receiver reference timestamp of @ssrc.
+ * @delay: the delay since @last_rr.
+ *
+ * Parse the extended report block for DLRR report block type.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_dlrr_block (GstRTCPPacket * packet,
+ guint nth, guint32 * ssrc, guint32 * last_rr, guint32 * delay)
+{
+ guint8 *data;
+ guint16 block_len;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_DLRR, FALSE);
+
+ block_len = gst_rtcp_packet_xr_get_block_length (packet);
+
+ if (nth * 3 >= block_len)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+ /* skip block header */
+ data += 4;
+ data += nth * 3 * 4;
+
+ if (ssrc)
+ *ssrc = GST_READ_UINT32_BE (data);
+
+ data += 4;
+ if (last_rr)
+ *last_rr = GST_READ_UINT32_BE (data);
+
+ data += 4;
+ if (delay)
+ *delay = GST_READ_UINT32_BE (data);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_summary_info:
+ * @packet: a valid XR #GstRTCPPacket which has Statics Summary Report Block.
+ * @ssrc: the SSRC of the source.
+ * @begin_seq: the first sequence number that this block reports on.
+ * @end_seq: the last sequence number that this block reports on plus one.
+ *
+ * Extract a basic information from static summary report block of XR @packet.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_summary_info (GstRTCPPacket * packet, guint32 * ssrc,
+ guint16 * begin_seq, guint16 * end_seq)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_SSUMM, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 9)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+ /* skip block header */
+ data += 4;
+
+ if (ssrc)
+ *ssrc = GST_READ_UINT32_BE (data);
+
+ /* go to begin_seq */
+ data += 4;
+ if (begin_seq)
+ *begin_seq = ((data[0] << 8) | data[1]);
+ /* go to end_seq */
+ data += 2;
+ if (end_seq)
+ *end_seq = ((data[0] << 8) | data[1]);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_summary_pkt:
+ * @packet: a valid XR #GstRTCPPacket which has Statics Summary Report Block.
+ * @lost_packets: the number of lost packets between begin_seq and end_seq.
+ * @dup_packets: the number of duplicate packets between begin_seq and end_seq.
+ *
+ * Get the number of lost or duplicate packets. If the flag in a block header
+ * is set as zero, @lost_packets or @dup_packets will be zero.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_summary_pkt (GstRTCPPacket * packet,
+ guint32 * lost_packets, guint32 * dup_packets)
+{
+ guint8 *data;
+ guint8 flags;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_SSUMM, FALSE);
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 9)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+ flags = data[1];
+ /* skip block header,ssrc, {begin,end}_seq */
+ data += 12;
+
+ if (lost_packets) {
+ if (!(flags & 0x80))
+ *lost_packets = 0;
+ else
+ *lost_packets = GST_READ_UINT32_BE (data);
+ }
+
+ data += 4;
+ if (dup_packets) {
+ if (!(flags & 0x40))
+ *dup_packets = 0;
+ else
+ *dup_packets = GST_READ_UINT32_BE (data);
+ }
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_summary_jitter:
+ * @packet: a valid XR #GstRTCPPacket which has Statics Summary Report Block.
+ * @min_jitter: the minimum relative transit time between two sequences.
+ * @max_jitter: the maximum relative transit time between two sequences.
+ * @mean_jitter: the mean relative transit time between two sequences.
+ * @dev_jitter: the standard deviation of the relative transit time between two sequences.
+ *
+ * Extract jitter information from the statistics summary. If the jitter flag in
+ * a block header is set as zero, all of jitters will be zero.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_summary_jitter (GstRTCPPacket * packet,
+ guint32 * min_jitter, guint32 * max_jitter,
+ guint32 * mean_jitter, guint32 * dev_jitter)
+{
+ guint8 *data;
+ guint8 flags;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_SSUMM, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 9)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+ flags = data[1];
+
+ if (!(flags & 0x20)) {
+ if (min_jitter)
+ *min_jitter = 0;
+ if (max_jitter)
+ *max_jitter = 0;
+ if (mean_jitter)
+ *mean_jitter = 0;
+ if (dev_jitter)
+ *dev_jitter = 0;
+
+ return TRUE;
+ }
+
+ /* skip block header,ssrc, {begin,end}_seq, packets */
+ data += 20;
+ if (min_jitter)
+ *min_jitter = GST_READ_UINT32_BE (data);
+
+ data += 4;
+ if (max_jitter)
+ *max_jitter = GST_READ_UINT32_BE (data);
+
+ data += 4;
+ if (mean_jitter)
+ *mean_jitter = GST_READ_UINT32_BE (data);
+
+ data += 4;
+ if (dev_jitter)
+ *dev_jitter = GST_READ_UINT32_BE (data);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_summary_ttl:
+ * @packet: a valid XR #GstRTCPPacket which has Statics Summary Report Block.
+ * @is_ipv4: the flag to indicate that the return values are ipv4 ttl or ipv6 hop limits.
+ * @min_ttl: the minimum TTL or Hop Limit value of data packets between two sequences.
+ * @max_ttl: the maximum TTL or Hop Limit value of data packets between two sequences.
+ * @mean_ttl: the mean TTL or Hop Limit value of data packets between two sequences.
+ * @dev_ttl: the standard deviation of the TTL or Hop Limit value of data packets between two sequences.
+ *
+ * Extract the value of ttl for ipv4, or hop limit for ipv6.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_summary_ttl (GstRTCPPacket * packet,
+ gboolean * is_ipv4, guint8 * min_ttl, guint8 * max_ttl, guint8 * mean_ttl,
+ guint8 * dev_ttl)
+{
+ guint8 *data;
+ guint8 flags;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_SSUMM, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 9)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+ flags = (data[1] & 0x18) >> 3;
+
+ if (flags > 2)
+ return FALSE;
+
+ if (is_ipv4)
+ *is_ipv4 = (flags == 1);
+
+ /* skip block header,ssrc, {begin,end}_seq, packets, jitters */
+ data += 36;
+ if (min_ttl)
+ *min_ttl = data[0];
+
+ if (max_ttl)
+ *max_ttl = data[1];
+
+ if (mean_ttl)
+ *mean_ttl = data[2];
+
+ if (dev_ttl)
+ *dev_ttl = data[3];
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_voip_metrics_ssrc:
+ * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
+ * @ssrc: the SSRC of source
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_voip_metrics_ssrc (GstRTCPPacket * packet,
+ guint32 * ssrc)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip block header */
+ data += 4;
+ if (ssrc)
+ *ssrc = GST_READ_UINT32_BE (data);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_voip_packet_metrics:
+ * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
+ * @loss_rate: the fraction of RTP data packets from the source lost.
+ * @discard_rate: the fraction of RTP data packets from the source that have been discarded.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_voip_packet_metrics (GstRTCPPacket * packet,
+ guint8 * loss_rate, guint8 * discard_rate)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip block header, ssrc */
+ data += 8;
+ if (loss_rate)
+ *loss_rate = data[0];
+
+ if (discard_rate)
+ *discard_rate = data[1];
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_voip_burst_metrics:
+ * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
+ * @burst_density: the fraction of RTP data packets within burst periods.
+ * @gap_density: the fraction of RTP data packets within inter-burst gaps.
+ * @burst_duration: the mean duration(ms) of the burst periods.
+ * @gap_duration: the mean duration(ms) of the gap periods.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_voip_burst_metrics (GstRTCPPacket * packet,
+ guint8 * burst_density, guint8 * gap_density, guint16 * burst_duration,
+ guint16 * gap_duration)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip block header, ssrc, packet metrics */
+ data += 10;
+ if (burst_density)
+ *burst_density = data[0];
+
+ if (gap_density)
+ *gap_density = data[1];
+
+ data += 2;
+ if (burst_duration)
+ *burst_duration = GST_READ_UINT16_BE (data);
+
+ data += 2;
+ if (gap_duration)
+ *gap_duration = GST_READ_UINT16_BE (data);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_voip_delay_metrics:
+ * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
+ * @roundtrip_delay: the most recently calculated round trip time between RTP interfaces(ms)
+ * @end_system_delay: the most recently estimated end system delay(ms)
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_voip_delay_metrics (GstRTCPPacket * packet,
+ guint16 * roundtrip_delay, guint16 * end_system_delay)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip block header, ssrc, packet metrics, burst metrics */
+ data += 16;
+ if (roundtrip_delay)
+ *roundtrip_delay = GST_READ_UINT16_BE (data);
+
+ data += 2;
+ if (end_system_delay)
+ *end_system_delay = GST_READ_UINT16_BE (data);
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_voip_signal_metrics:
+ * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
+ * @signal_level: the ratio of the signal level to a 0 dBm reference.
+ * @noise_level: the ratio of the silent period background noise level to a 0 dBm reference.
+ * @rerl: the residual echo return loss value.
+ * @gmin: the gap threshold.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_voip_signal_metrics (GstRTCPPacket * packet,
+ guint8 * signal_level, guint8 * noise_level, guint8 * rerl, guint8 * gmin)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip block header, ssrc, packet metrics, burst metrics,
+ * delay metrics */
+ data += 20;
+ if (signal_level)
+ *signal_level = data[0];
+
+ if (noise_level)
+ *noise_level = data[1];
+
+ if (rerl)
+ *rerl = data[2];
+
+ if (gmin)
+ *gmin = data[3];
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_voip_quality_metrics:
+ * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
+ * @r_factor: the R factor is a voice quality metric describing the segment of the call.
+ * @ext_r_factor: the external R factor is a voice quality metric.
+ * @mos_lq: the estimated mean opinion score for listening quality.
+ * @mos_cq: the estimated mean opinion score for conversational quality.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_voip_quality_metrics (GstRTCPPacket * packet,
+ guint8 * r_factor, guint8 * ext_r_factor, guint8 * mos_lq, guint8 * mos_cq)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip block header, ssrc, packet metrics, burst metrics,
+ * delay metrics, signal metrics */
+ data += 24;
+ if (r_factor)
+ *r_factor = data[0];
+
+ if (ext_r_factor)
+ *ext_r_factor = data[1];
+
+ if (mos_lq)
+ *mos_lq = data[2];
+
+ if (mos_cq)
+ *mos_cq = data[3];
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_voip_configuration_params:
+ * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
+ * @gmin: the gap threshold.
+ * @rx_config: the receiver configuration byte.
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_voip_configuration_params (GstRTCPPacket * packet,
+ guint8 * gmin, guint8 * rx_config)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ if (gmin)
+ *gmin = data[23];
+
+ if (rx_config)
+ *rx_config = data[28];
+
+ return TRUE;
+}
+
+/**
+ * gst_rtcp_packet_xr_get_voip_jitter_buffer_params:
+ * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
+ * @jb_nominal: the current nominal jitter buffer delay(ms)
+ * @jb_maximum: the current maximum jitter buffer delay(ms)
+ * @jb_abs_max: the absolute maximum delay(ms)
+ *
+ * Returns: %TRUE if the report block is correctly parsed.
+ *
+ * Since: 1.16
+ */
+gboolean
+gst_rtcp_packet_xr_get_voip_jitter_buffer_params (GstRTCPPacket * packet,
+ guint16 * jb_nominal, guint16 * jb_maximum, guint16 * jb_abs_max)
+{
+ guint8 *data;
+
+ g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
+ GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
+
+ if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
+ return FALSE;
+
+ data = packet->rtcp->map.data;
+ /* skip header + current item offset */
+ data += packet->offset + packet->item_offset;
+
+ /* skip block header, ssrc, packet metrics, burst metrics,
+ * delay metrics, signal metrics, config */
+ data += 30;
+
+ if (jb_nominal)
+ *jb_nominal = GST_READ_UINT16_BE (data);
+
+ data += 2;
+ if (jb_maximum)
+ *jb_maximum = GST_READ_UINT16_BE (data);
+
+ data += 2;
+ if (jb_abs_max)
+ *jb_abs_max = GST_READ_UINT16_BE (data);
+
+ return TRUE;
+}
} GstRTCPSDESType;
/**
+ * GstRTCPXRType:
+ * @GST_RTCP_XR_TYPE_INVALID: Invalid XR Report Block
+ * @GST_RTCP_XR_TYPE_LRLE: Loss RLE Report Block
+ * @GST_RTCP_XR_TYPE_DRLE: Duplicate RLE Report Block
+ * @GST_RTCP_XR_TYPE_PRT: Packet Receipt Times Report Block
+ * @GST_RTCP_XR_TYPE_RRT: Receiver Reference Time Report Block
+ * @GST_RTCP_XR_TYPE_DLRR: Delay since the last Receiver Report
+ * @GST_RTCP_XR_TYPE_SSUMM: Statistics Summary Report Block
+ * @GST_RTCP_XR_TYPE_VOIP_METRICS: VoIP Metrics Report Block
+ *
+ * Types of RTCP Extended Reports, those are defined in RFC 3611 and other RFCs
+ * according to the [IANA registry](https://www.iana.org/assignments/rtcp-xr-block-types/rtcp-xr-block-types.xhtml).
+ *
+ * Since: 1.16
+ */
+typedef enum
+{
+ GST_RTCP_XR_TYPE_INVALID = -1,
+ GST_RTCP_XR_TYPE_LRLE = 1,
+ GST_RTCP_XR_TYPE_DRLE = 2,
+ GST_RTCP_XR_TYPE_PRT = 3,
+ GST_RTCP_XR_TYPE_RRT = 4,
+ GST_RTCP_XR_TYPE_DLRR = 5,
+ GST_RTCP_XR_TYPE_SSUMM = 6,
+ GST_RTCP_XR_TYPE_VOIP_METRICS = 7
+} GstRTCPXRType;
+
+/**
* GST_RTCP_MAX_SDES:
*
* The maximum text length for an SDES item.
gboolean padding; /* padding field of current packet */
guint8 count; /* count field of current packet */
GstRTCPType type; /* type of current packet */
- guint16 length; /* length of current packet in 32-bits words */
+ guint16 length; /* length of current packet in 32-bits words minus one, this is validated when doing _get_first_packet() and _move_to_next() */
guint item_offset; /* current item offset for navigating SDES */
guint item_count; /* current item count */
GST_RTP_API
GstRTCPSDESType gst_rtcp_sdes_name_to_type (const gchar *name);
+/* extended report */
+
+GST_RTP_API
+guint32 gst_rtcp_packet_xr_get_ssrc (GstRTCPPacket *packet);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_first_rb (GstRTCPPacket *packet);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_next_rb (GstRTCPPacket * packet);
+
+GST_RTP_API
+GstRTCPXRType gst_rtcp_packet_xr_get_block_type (GstRTCPPacket * packet);
+
+GST_RTP_API
+guint16 gst_rtcp_packet_xr_get_block_length (GstRTCPPacket * packet);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_rle_info (GstRTCPPacket * packet,
+ guint32 * ssrc, guint8 * thining,
+ guint16 * begin_seq, guint16 * end_seq,
+ guint32 * chunk_count);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_rle_nth_chunk (GstRTCPPacket * packet, guint nth,
+ guint16 * chunk);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_prt_info (GstRTCPPacket * packet,
+ guint32 * ssrc, guint8 * thining,
+ guint16 * begin_seq, guint16 * end_seq);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_prt_by_seq (GstRTCPPacket * packet, guint16 seq,
+ guint32 * receipt_time);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_rrt (GstRTCPPacket * packet, guint64 * timestamp);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_dlrr_block (GstRTCPPacket * packet,
+ guint nth, guint32 * ssrc,
+ guint32 * last_rr, guint32 * delay);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_summary_info (GstRTCPPacket * packet, guint32 * ssrc,
+ guint16 * begin_seq, guint16 * end_seq);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_summary_pkt (GstRTCPPacket * packet,
+ guint32 * lost_packets, guint32 * dup_packets);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_summary_jitter (GstRTCPPacket * packet,
+ guint32 * min_jitter, guint32 * max_jitter,
+ guint32 * mean_jitter, guint32 * dev_jitter);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_summary_ttl (GstRTCPPacket * packet, gboolean * is_ipv4,
+ guint8 * min_ttl, guint8 * max_ttl,
+ guint8 * mean_ttl, guint8 * dev_ttl);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_voip_metrics_ssrc (GstRTCPPacket * packet, guint32 * ssrc);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_voip_packet_metrics (GstRTCPPacket * packet,
+ guint8 * loss_rate, guint8 * discard_rate);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_voip_burst_metrics (GstRTCPPacket * packet,
+ guint8 * burst_density, guint8 * gap_density,
+ guint16 * burst_duration, guint16 * gap_duration);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_voip_delay_metrics (GstRTCPPacket * packet,
+ guint16 * roundtrip_delay,
+ guint16 * end_system_delay);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_voip_signal_metrics (GstRTCPPacket * packet,
+ guint8 * signal_level, guint8 * noise_level,
+ guint8 * rerl, guint8 * gmin);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_voip_quality_metrics (GstRTCPPacket * packet,
+ guint8 * r_factor, guint8 * ext_r_factor,
+ guint8 * mos_lq, guint8 * mos_cq);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_voip_configuration_params (GstRTCPPacket * packet,
+ guint8 * gmin, guint8 * rx_config);
+
+GST_RTP_API
+gboolean gst_rtcp_packet_xr_get_voip_jitter_buffer_params (GstRTCPPacket * packet,
+ guint16 * jb_nominal,
+ guint16 * jb_maximum,
+ guint16 * jb_abs_max);
+
G_END_DECLS
#endif /* __GST_RTCPBUFFER_H__ */
GST_END_TEST;
+GST_START_TEST (test_rtcp_buffer_xr)
+{
+ GstBuffer *buffer;
+ GstRTCPPacket packet;
+ GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+ guint8 rtcp_pkt[] = {
+ 0x80, 0xCF, 0x00, 0x0e, /* Type XR, length = 14 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x01, 0x00, 0x00, 0x03, /* Loss RLE, No thining, length = 3 */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x00, 0x01, 0x00, 0x02,
+ 0xcf, 0xb7, 0x8f, 0xb7,
+ 0x02, 0x00, 0x00, 0x03, /* Dup RLE, No thining, length = 3 */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x00, 0x01, 0x00, 0x02,
+ 0xcf, 0xb7, 0x8f, 0xb7,
+ 0x03, 0x00, 0x00, 0x04, /* Packet Receipt Times, No thining, length = 4 */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x00, 0x01, 0x00, 0x02,
+ 0x59, 0xf9, 0xdd, 0x7e,
+ 0x59, 0xf9, 0xdd, 0x7e,
+ };
+
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt, sizeof (rtcp_pkt), 0, sizeof (rtcp_pkt), NULL, NULL);
+
+ fail_unless (gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp));
+
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+ fail_unless (gst_rtcp_packet_get_type (&packet) == GST_RTCP_TYPE_XR);
+ fail_unless (gst_rtcp_packet_xr_get_ssrc (&packet) ==
+ GST_READ_UINT32_BE (rtcp_pkt + 12));
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_LRLE);
+ fail_unless (gst_rtcp_packet_xr_next_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_DRLE);
+ fail_unless (gst_rtcp_packet_xr_next_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_PRT);
+
+ fail_if (gst_rtcp_packet_xr_next_rb (&packet));
+
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtcp_buffer_xr_rle)
+{
+ GstBuffer *buffer;
+ GstRTCPPacket packet;
+ guint32 ssrc, chunk_count;
+ guint8 thining;
+ guint16 begin_seq, end_seq, chunk;
+ GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+ guint8 rtcp_pkt[] = {
+ 0x80, 0xCF, 0x00, 0x0a, /* Type XR, length = 10 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x01, 0x00, 0x00, 0x03, /* Loss RLE, No thining, length = 3 */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x00, 0x01, 0x00, 0x02,
+ 0x80, 0x12, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x04, /* Dup RLE, No thining, length = 4 */
+ 0x97, 0x6d, 0x21, 0x7b, /* SSRC of source */
+ 0x00, 0x01, 0x00, 0x04,
+ 0x8f, 0x21, 0x8f, 0x22,
+ 0x8f, 0x23, 0x8f, 0x24
+ };
+ guint8 rtcp_pkt_invalid_pkt_length[] = {
+ 0x80, 0xCF, 0x00, 0x04, /* Type XR, length = 4 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x01, 0x00, 0x00, 0x02, /* Loss RLE, No thining, length = 1 (but really 3) */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x00, 0x01, 0x00, 0x02,
+ };
+
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt, sizeof (rtcp_pkt), 0, sizeof (rtcp_pkt), NULL, NULL);
+ gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+
+ /* check LRLE */
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_LRLE);
+ fail_unless (gst_rtcp_packet_xr_get_rle_info (&packet, &ssrc, &thining,
+ &begin_seq, &end_seq, &chunk_count));
+ fail_unless_equals_int (ssrc, GST_READ_UINT32_BE (rtcp_pkt + 12));
+ fail_unless_equals_int (thining, 0);
+ fail_unless_equals_int (begin_seq, 0x0001);
+ fail_unless_equals_int (end_seq, 0x0002);
+ fail_unless_equals_int (chunk_count, 2);
+
+ gst_rtcp_packet_xr_get_rle_nth_chunk (&packet, 0, &chunk);
+ fail_unless_equals_int (chunk, 0x8012);
+
+ gst_rtcp_packet_xr_get_rle_nth_chunk (&packet, 1, &chunk);
+ fail_unless_equals_int (chunk, 0x0);
+
+ /* check DRLE */
+ fail_unless (gst_rtcp_packet_xr_next_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_DRLE);
+ fail_unless (gst_rtcp_packet_xr_get_rle_info (&packet, &ssrc, &thining,
+ &begin_seq, &end_seq, &chunk_count));
+ fail_unless_equals_int (ssrc, GST_READ_UINT32_BE (rtcp_pkt + 28));
+ fail_unless_equals_int (thining, 0);
+ fail_unless_equals_int (begin_seq, 0x0001);
+ fail_unless_equals_int (end_seq, 0x0004);
+ fail_unless_equals_int (chunk_count, 4);
+
+ gst_rtcp_packet_xr_get_rle_nth_chunk (&packet, 1, &chunk);
+ fail_unless_equals_int (chunk, 0x8f22);
+
+ gst_rtcp_packet_xr_get_rle_nth_chunk (&packet, 2, &chunk);
+ fail_unless_equals_int (chunk, 0x8f23);
+
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+
+ /* Test invalid length */
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt_invalid_pkt_length, sizeof (rtcp_pkt_invalid_pkt_length), 0,
+ sizeof (rtcp_pkt_invalid_pkt_length), NULL, NULL);
+ gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+
+ /* check LRLE (should fail because length is too short) */
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_LRLE);
+ fail_if (gst_rtcp_packet_xr_get_rle_info (&packet, &ssrc, &thining,
+ &begin_seq, &end_seq, &chunk_count));
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtcp_buffer_xr_prt)
+{
+ GstBuffer *buffer;
+ GstRTCPPacket packet;
+ guint32 ssrc, receipt_time;
+ guint8 thining;
+ guint16 begin_seq, end_seq;
+ GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+ guint8 rtcp_pkt[] = {
+ 0x80, 0xCF, 0x00, 0x06, /* Type XR, length = 6 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x03, 0x00, 0x00, 0x04, /* Packet Receipt Times, No thining, length = 4 */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x00, 0x01, 0x00, 0x03,
+ 0x59, 0xf9, 0xdd, 0x7e,
+ 0x59, 0xf9, 0xde, 0x00,
+ };
+ guint8 rtcp_pkt_invalid_pkt_length[] = {
+ 0x80, 0xCF, 0x00, 0x04, /* Type XR, length = 4 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x03, 0x00, 0x00, 0x02, /* Packet Receipt Times, No thining, length = 2 (but should be 4) */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x00, 0x01, 0x00, 0x03,
+ };
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt, sizeof (rtcp_pkt), 0, sizeof (rtcp_pkt), NULL, NULL);
+ gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_PRT);
+
+ fail_unless (gst_rtcp_packet_xr_get_prt_info (&packet, &ssrc, &thining,
+ &begin_seq, &end_seq));
+ fail_unless (gst_rtcp_packet_xr_get_prt_by_seq (&packet, 2, &receipt_time));
+ fail_unless_equals_int_hex (receipt_time, 0x59f9de00L);
+
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+
+ /* Test for invalid length */
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt_invalid_pkt_length, sizeof (rtcp_pkt_invalid_pkt_length), 0,
+ sizeof (rtcp_pkt_invalid_pkt_length), NULL, NULL);
+ gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_PRT);
+
+ fail_if (gst_rtcp_packet_xr_get_prt_info (&packet, &ssrc, &thining,
+ &begin_seq, &end_seq));
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtcp_buffer_xr_rrt)
+{
+ GstBuffer *buffer;
+ GstRTCPPacket packet;
+ guint64 ntptime;
+ GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+ guint8 rtcp_pkt[] = {
+ 0x80, 0xCF, 0x00, 0x04, /* Type XR, length = 4 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x04, 0x00, 0x00, 0x02, /* Receiver Reference Time, length = 2 */
+ 0x01, 0x23, 0x45, 0x67,
+ 0x89, 0x01, 0x23, 0x45
+ };
+ guint8 rtcp_pkt_invalid_pkt_length[] = {
+ 0x80, 0xCF, 0x00, 0x04, /* Type XR, length = 4 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x04, 0x00, 0x00, 0x01, /* Receiver Reference Time, length = 1 */
+ 0x01, 0x23, 0x45, 0x67,
+ 0x89, 0x01, 0x23, 0x45
+ };
+
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt, sizeof (rtcp_pkt), 0, sizeof (rtcp_pkt), NULL, NULL);
+ gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_RRT);
+
+ fail_unless (gst_rtcp_packet_xr_get_rrt (&packet, &ntptime));
+ fail_unless_equals_uint64_hex (ntptime, 0x0123456789012345LL);
+
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+
+ /* Test invalid length */
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt_invalid_pkt_length, sizeof (rtcp_pkt_invalid_pkt_length), 0,
+ sizeof (rtcp_pkt_invalid_pkt_length), NULL, NULL);
+ gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_RRT);
+
+ fail_if (gst_rtcp_packet_xr_get_rrt (&packet, &ntptime));
+
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtcp_buffer_xr_dlrr)
+{
+ GstBuffer *buffer;
+ GstRTCPPacket packet;
+ guint32 ssrc, last_rr, delay;
+ GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+ guint8 rtcp_pkt[] = {
+ 0x80, 0xCF, 0x00, 0x08, /* Type XR, length = 8 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x05, 0x00, 0x00, 0x06, /* DLRR, length = 6 */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x01, 0x23, 0x45, 0x67,
+ 0x89, 0x01, 0x23, 0x45,
+ 0x97, 0x6d, 0x21, 0x6b, /* SSRC of source */
+ 0x01, 0x23, 0x45, 0x67,
+ 0x89, 0x01, 0x23, 0x45
+ };
+
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt, sizeof (rtcp_pkt), 0, sizeof (rtcp_pkt), NULL, NULL);
+ gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_DLRR);
+
+ fail_unless (gst_rtcp_packet_xr_get_dlrr_block (&packet, 0, &ssrc, &last_rr,
+ &delay));
+ fail_unless_equals_int_hex (ssrc, GST_READ_UINT32_BE (rtcp_pkt + 12));
+ fail_unless (gst_rtcp_packet_xr_get_dlrr_block (&packet, 1, &ssrc, &last_rr,
+ &delay));
+ fail_unless_equals_int_hex (ssrc, GST_READ_UINT32_BE (rtcp_pkt + 24));
+
+ /* it has only two sub-blocks. */
+ fail_if (gst_rtcp_packet_xr_get_dlrr_block (&packet, 2, &ssrc, &last_rr,
+ &delay));
+
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtcp_buffer_xr_ssumm)
+{
+ GstBuffer *buffer;
+ GstRTCPPacket packet;
+ guint32 ssrc, lost_packets, dup_packets;
+ guint16 begin_seq, end_seq;
+ guint32 min_jitter, max_jitter, mean_jitter, dev_jitter;
+ guint8 min_ttl, max_ttl, mean_ttl, dev_ttl;
+ gboolean ipv4;
+ GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+ guint8 rtcp_pkt[] = {
+ 0x80, 0xCF, 0x00, 0x0b, /* Type XR, length = 11 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x06, 0xe8, 0x00, 0x09, /* Statistics summary, length = 9 */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x00, 0x01, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x01,
+ 0x00, 0x00, 0x00, 0x02,
+ 0x00, 0x00, 0x00, 0x03,
+ 0x00, 0x00, 0x00, 0x04,
+ 0x00, 0x00, 0x00, 0x05,
+ 0x00, 0x00, 0x00, 0x06,
+ 0x01, 0x80, 0x0f, 0x8f
+ };
+
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt, sizeof (rtcp_pkt), 0, sizeof (rtcp_pkt), NULL, NULL);
+ gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_SSUMM);
+
+ fail_unless (gst_rtcp_packet_xr_get_summary_info (&packet, &ssrc, &begin_seq,
+ &end_seq));
+ fail_unless_equals_int_hex (ssrc, GST_READ_UINT32_BE (rtcp_pkt + 12));
+ fail_unless_equals_int (begin_seq, GST_READ_UINT16_BE (rtcp_pkt + 16));
+ fail_unless_equals_int (end_seq, GST_READ_UINT16_BE (rtcp_pkt + 18));
+
+ fail_unless (gst_rtcp_packet_xr_get_summary_pkt (&packet, &lost_packets,
+ &dup_packets));
+ fail_unless_equals_int (lost_packets, GST_READ_UINT32_BE (rtcp_pkt + 20));
+ fail_unless_equals_int (dup_packets, GST_READ_UINT32_BE (rtcp_pkt + 24));
+
+ fail_unless (gst_rtcp_packet_xr_get_summary_jitter (&packet, &min_jitter,
+ &max_jitter, &mean_jitter, &dev_jitter));
+ fail_unless_equals_int (min_jitter, GST_READ_UINT32_BE (rtcp_pkt + 28));
+ fail_unless_equals_int (max_jitter, GST_READ_UINT32_BE (rtcp_pkt + 32));
+ fail_unless_equals_int (mean_jitter, GST_READ_UINT32_BE (rtcp_pkt + 36));
+ fail_unless_equals_int (dev_jitter, GST_READ_UINT32_BE (rtcp_pkt + 40));
+
+ fail_unless (gst_rtcp_packet_xr_get_summary_ttl (&packet, &ipv4, &min_ttl,
+ &max_ttl, &mean_ttl, &dev_ttl));
+ fail_unless (ipv4);
+ fail_unless_equals_int (min_ttl, rtcp_pkt[44]);
+ fail_unless_equals_int (max_ttl, rtcp_pkt[45]);
+ fail_unless_equals_int (mean_ttl, rtcp_pkt[46]);
+ fail_unless_equals_int (dev_ttl, rtcp_pkt[47]);
+
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_rtcp_buffer_xr_voipmtrx)
+{
+ GstBuffer *buffer;
+ GstRTCPPacket packet;
+ guint32 ssrc;
+ guint8 loss_rate, discard_rate, burst_density, gap_density;
+ guint8 signal_level, noise_level, rerl, gmin;
+ guint8 r_factor, ext_r_factor, mos_lq, mos_cq, rx_config;
+ guint16 burst_duration, gap_duration;
+ guint16 roundtrip_delay, end_system_delay;
+ guint16 jb_nominal, jb_maximum, jb_abs_max;
+ GstRTCPBuffer rtcp = GST_RTCP_BUFFER_INIT;
+ guint8 rtcp_pkt[] = {
+ 0x80, 0xCF, 0x00, 0x0a, /* Type XR, length = 10 */
+ 0x97, 0x6d, 0x21, 0x6a,
+ 0x07, 0x00, 0x00, 0x08, /* VoIP Metrics, length = 8 */
+ 0x97, 0x6d, 0x21, 0x6a, /* SSRC of source */
+ 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14,
+ 0x15, 0x00, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b
+ };
+
+ buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+ rtcp_pkt, sizeof (rtcp_pkt), 0, sizeof (rtcp_pkt), NULL, NULL);
+ gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcp);
+
+ fail_unless (gst_rtcp_buffer_get_first_packet (&rtcp, &packet));
+
+ fail_unless (gst_rtcp_packet_xr_first_rb (&packet));
+ fail_unless (gst_rtcp_packet_xr_get_block_type (&packet) ==
+ GST_RTCP_XR_TYPE_VOIP_METRICS);
+ fail_unless (gst_rtcp_packet_xr_get_voip_metrics_ssrc (&packet, &ssrc));
+ fail_unless_equals_int_hex (ssrc, GST_READ_UINT32_BE (rtcp_pkt + 12));
+
+ fail_unless (gst_rtcp_packet_xr_get_voip_packet_metrics (&packet, &loss_rate,
+ &discard_rate));
+ fail_unless_equals_int (loss_rate, rtcp_pkt[16]);
+ fail_unless_equals_int (discard_rate, rtcp_pkt[17]);
+
+ fail_unless (gst_rtcp_packet_xr_get_voip_burst_metrics (&packet,
+ &burst_density, &gap_density, &burst_duration, &gap_duration));
+ fail_unless_equals_int (burst_density, rtcp_pkt[18]);
+ fail_unless_equals_int (gap_density, rtcp_pkt[19]);
+ fail_unless_equals_int (burst_duration, GST_READ_UINT16_BE (rtcp_pkt + 20));
+ fail_unless_equals_int (gap_duration, GST_READ_UINT16_BE (rtcp_pkt + 22));
+
+ fail_unless (gst_rtcp_packet_xr_get_voip_delay_metrics (&packet,
+ &roundtrip_delay, &end_system_delay));
+ fail_unless_equals_int (roundtrip_delay, GST_READ_UINT16_BE (rtcp_pkt + 24));
+ fail_unless_equals_int (end_system_delay, GST_READ_UINT16_BE (rtcp_pkt + 26));
+
+ fail_unless (gst_rtcp_packet_xr_get_voip_signal_metrics (&packet,
+ &signal_level, &noise_level, &rerl, &gmin));
+ fail_unless_equals_int (signal_level, rtcp_pkt[28]);
+ fail_unless_equals_int (noise_level, rtcp_pkt[29]);
+ fail_unless_equals_int (rerl, rtcp_pkt[30]);
+ fail_unless_equals_int (gmin, rtcp_pkt[31]);
+
+ fail_unless (gst_rtcp_packet_xr_get_voip_quality_metrics (&packet, &r_factor,
+ &ext_r_factor, &mos_lq, &mos_cq));
+ fail_unless_equals_int (r_factor, rtcp_pkt[32]);
+ fail_unless_equals_int (ext_r_factor, rtcp_pkt[33]);
+ fail_unless_equals_int (mos_lq, rtcp_pkt[34]);
+ fail_unless_equals_int (mos_cq, rtcp_pkt[35]);
+
+ fail_unless (gst_rtcp_packet_xr_get_voip_configuration_params (&packet, &gmin,
+ &rx_config));
+ fail_unless_equals_int (gmin, rtcp_pkt[31]);
+ fail_unless_equals_int (rx_config, rtcp_pkt[36]);
+
+ fail_unless (gst_rtcp_packet_xr_get_voip_jitter_buffer_params (&packet,
+ &jb_nominal, &jb_maximum, &jb_abs_max));
+ fail_unless_equals_int (jb_nominal, GST_READ_UINT16_BE (rtcp_pkt + 38));
+ fail_unless_equals_int (jb_maximum, GST_READ_UINT16_BE (rtcp_pkt + 40));
+ fail_unless_equals_int (jb_abs_max, GST_READ_UINT16_BE (rtcp_pkt + 42));
+
+ gst_rtcp_buffer_unmap (&rtcp);
+ gst_buffer_unref (buffer);
+}
+
+GST_END_TEST;
+
GST_START_TEST (test_rtp_ntp64_extension)
{
GstBuffer *buf;
tcase_add_test (tc_chain, test_rtcp_validate_reduced_with_padding);
tcase_add_test (tc_chain, test_rtcp_buffer_profile_specific_extension);
tcase_add_test (tc_chain, test_rtcp_buffer_app);
+ tcase_add_test (tc_chain, test_rtcp_buffer_xr);
+ tcase_add_test (tc_chain, test_rtcp_buffer_xr_rle);
+ tcase_add_test (tc_chain, test_rtcp_buffer_xr_prt);
+ tcase_add_test (tc_chain, test_rtcp_buffer_xr_rrt);
+ tcase_add_test (tc_chain, test_rtcp_buffer_xr_dlrr);
+ tcase_add_test (tc_chain, test_rtcp_buffer_xr_ssumm);
+ tcase_add_test (tc_chain, test_rtcp_buffer_xr_voipmtrx);
tcase_add_test (tc_chain, test_rtp_ntp64_extension);
tcase_add_test (tc_chain, test_rtp_ntp56_extension);