Use g_memdup2() where available and add fallback for older GLib versions
[platform/upstream/gstreamer.git] / gst-libs / gst / rtp / gstrtcpbuffer.c
1 /* GStreamer
2  * Copyright (C) <2007> Wim Taymans <wim@fluendo.com>
3  *
4  * gstrtcpbuffer.h: various helper functions to manipulate buffers
5  *     with RTCP payload.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 /**
24  * SECTION:gstrtcpbuffer
25  * @title: GstRTCPBuffer
26  * @short_description: Helper methods for dealing with RTCP buffers
27  * @see_also: #GstRTPBasePayload, #GstRTPBaseDepayload, #gstrtpbuffer
28  *
29  * Note: The API in this module is not yet declared stable.
30  *
31  * The GstRTPCBuffer helper functions makes it easy to parse and create regular
32  * #GstBuffer objects that contain compound RTCP packets. These buffers are typically
33  * of 'application/x-rtcp' #GstCaps.
34  *
35  * An RTCP buffer consists of 1 or more #GstRTCPPacket structures that you can
36  * retrieve with gst_rtcp_buffer_get_first_packet(). #GstRTCPPacket acts as a pointer
37  * into the RTCP buffer; you can move to the next packet with
38  * gst_rtcp_packet_move_to_next().
39  *
40  */
41 #ifdef HAVE_CONFIG_H
42 #include "config.h"
43 #endif
44
45 #include <string.h>
46
47 #include "gstrtcpbuffer.h"
48
49 /**
50  * gst_rtcp_buffer_new_take_data:
51  * @data: (array length=len) (element-type guint8): data for the new buffer
52  * @len: the length of data
53  *
54  * Create a new buffer and set the data and size of the buffer to @data and @len
55  * respectively. @data will be freed when the buffer is unreffed, so this
56  * function transfers ownership of @data to the new buffer.
57  *
58  * Returns: A newly allocated buffer with @data and of size @len.
59  */
60 GstBuffer *
61 gst_rtcp_buffer_new_take_data (gpointer data, guint len)
62 {
63   GstBuffer *result;
64
65   g_return_val_if_fail (data != NULL, NULL);
66   g_return_val_if_fail (len > 0, NULL);
67
68   result = gst_buffer_new_wrapped (data, len);
69
70   return result;
71 }
72
73 /**
74  * gst_rtcp_buffer_new_copy_data:
75  * @data: (array length=len) (element-type guint8): data for the new buffer
76  * @len: the length of data
77  *
78  * Create a new buffer and set the data to a copy of @len
79  * bytes of @data and the size to @len. The data will be freed when the buffer
80  * is freed.
81  *
82  * Returns: A newly allocated buffer with a copy of @data and of size @len.
83  */
84 GstBuffer *
85 gst_rtcp_buffer_new_copy_data (gconstpointer data, guint len)
86 {
87   return gst_rtcp_buffer_new_take_data (g_memdup2 (data, len), len);
88 }
89
90 static gboolean
91 gst_rtcp_buffer_validate_data_internal (guint8 * data, guint len,
92     guint16 valid_mask)
93 {
94   guint16 header_mask;
95   guint header_len;
96   guint8 version;
97   guint data_len;
98   gboolean padding;
99   guint8 pad_bytes;
100
101   g_return_val_if_fail (data != NULL, FALSE);
102
103   /* we need 4 bytes for the type and length */
104   if (G_UNLIKELY (len < 4))
105     goto wrong_length;
106
107   /* first packet must be RR or SR  and version must be 2 */
108   header_mask = ((data[0] << 8) | data[1]) & valid_mask;
109   if (G_UNLIKELY (header_mask != GST_RTCP_VALID_VALUE))
110     goto wrong_mask;
111
112   /* no padding when mask succeeds */
113   padding = FALSE;
114
115   /* store len */
116   data_len = len;
117
118   while (TRUE) {
119     /* get packet length */
120     header_len = (((data[2] << 8) | data[3]) + 1) << 2;
121     if (data_len < header_len)
122       goto wrong_length;
123
124     /* move to next compound packet */
125     data += header_len;
126     data_len -= header_len;
127
128     /* we are at the end now */
129     if (data_len < 4)
130       break;
131
132     /* padding only allowed on last packet */
133     if (padding)
134       break;
135
136     /* check version of new packet */
137     version = data[0] & 0xc0;
138     if (version != (GST_RTCP_VERSION << 6))
139       goto wrong_version;
140
141     /* check padding of new packet */
142     if (data[0] & 0x20) {
143       padding = TRUE;
144       /* last byte of padding contains the number of padded bytes including
145        * itself. must be a multiple of 4, but cannot be 0. */
146       pad_bytes = data[data_len - 1];
147       if (pad_bytes == 0 || (pad_bytes & 0x3))
148         goto wrong_padding;
149     }
150   }
151   if (data_len != 0) {
152     /* some leftover bytes */
153     goto wrong_length;
154   }
155   return TRUE;
156
157   /* ERRORS */
158 wrong_length:
159   {
160     GST_DEBUG ("len check failed");
161     return FALSE;
162   }
163 wrong_mask:
164   {
165     GST_DEBUG ("mask check failed (%04x != %04x)", header_mask, valid_mask);
166     return FALSE;
167   }
168 wrong_version:
169   {
170     GST_DEBUG ("wrong version (%d < 2)", version >> 6);
171     return FALSE;
172   }
173 wrong_padding:
174   {
175     GST_DEBUG ("padding check failed");
176     return FALSE;
177   }
178 }
179
180 /**
181  * gst_rtcp_buffer_validate_data_reduced:
182  * @data: (array length=len): the data to validate
183  * @len: the length of @data to validate
184  *
185  * Check if the @data and @size point to the data of a valid RTCP packet.
186  * Use this function to validate a packet before using the other functions in
187  * this module.
188  *
189  * This function is updated to support reduced size rtcp packets according to
190  * RFC 5506 and will validate full compound RTCP packets as well as reduced
191  * size RTCP packets.
192  *
193  * Returns: TRUE if the data points to a valid RTCP packet.
194  *
195  * Since: 1.6
196  */
197 gboolean
198 gst_rtcp_buffer_validate_data_reduced (guint8 * data, guint len)
199 {
200   return gst_rtcp_buffer_validate_data_internal (data, len,
201       GST_RTCP_REDUCED_SIZE_VALID_MASK);
202 }
203
204 /**
205  * gst_rtcp_buffer_validate_data:
206  * @data: (array length=len): the data to validate
207  * @len: the length of @data to validate
208  *
209  * Check if the @data and @size point to the data of a valid compound,
210  * non-reduced size RTCP packet.
211  * Use this function to validate a packet before using the other functions in
212  * this module.
213  *
214  * Returns: TRUE if the data points to a valid RTCP packet.
215  */
216 gboolean
217 gst_rtcp_buffer_validate_data (guint8 * data, guint len)
218 {
219   return gst_rtcp_buffer_validate_data_internal (data, len,
220       GST_RTCP_VALID_MASK);
221 }
222
223 /**
224  * gst_rtcp_buffer_validate_reduced:
225  * @buffer: the buffer to validate
226  *
227  * Check if the data pointed to by @buffer is a valid RTCP packet using
228  * gst_rtcp_buffer_validate_reduced().
229  *
230  * Returns: TRUE if @buffer is a valid RTCP packet.
231  *
232  * Since: 1.6
233  */
234 gboolean
235 gst_rtcp_buffer_validate_reduced (GstBuffer * buffer)
236 {
237   gboolean res;
238   GstMapInfo map;
239
240   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
241
242   gst_buffer_map (buffer, &map, GST_MAP_READ);
243   res = gst_rtcp_buffer_validate_data_reduced (map.data, map.size);
244   gst_buffer_unmap (buffer, &map);
245
246   return res;
247 }
248
249 /**
250  * gst_rtcp_buffer_validate:
251  * @buffer: the buffer to validate
252  *
253  * Check if the data pointed to by @buffer is a valid RTCP packet using
254  * gst_rtcp_buffer_validate_data().
255  *
256  * Returns: TRUE if @buffer is a valid RTCP packet.
257  */
258 gboolean
259 gst_rtcp_buffer_validate (GstBuffer * buffer)
260 {
261   gboolean res;
262   GstMapInfo map;
263
264   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
265
266   gst_buffer_map (buffer, &map, GST_MAP_READ);
267   res = gst_rtcp_buffer_validate_data (map.data, map.size);
268   gst_buffer_unmap (buffer, &map);
269
270   return res;
271 }
272
273 /**
274  * gst_rtcp_buffer_new:
275  * @mtu: the maximum mtu size.
276  *
277  * Create a new buffer for constructing RTCP packets. The packet will have a
278  * maximum size of @mtu.
279  *
280  * Returns: A newly allocated buffer.
281  */
282 GstBuffer *
283 gst_rtcp_buffer_new (guint mtu)
284 {
285   GstBuffer *result;
286   guint8 *data;
287
288   g_return_val_if_fail (mtu > 0, NULL);
289
290   data = g_malloc0 (mtu);
291
292   result = gst_buffer_new_wrapped_full (0, data, mtu, 0, 0, data, g_free);
293
294   return result;
295 }
296
297 /**
298  * gst_rtcp_buffer_map:
299  * @buffer: a buffer with an RTCP packet
300  * @flags: flags for the mapping
301  * @rtcp: resulting #GstRTCPBuffer
302  *
303  * Open @buffer for reading or writing, depending on @flags. The resulting RTCP
304  * buffer state is stored in @rtcp.
305  */
306 gboolean
307 gst_rtcp_buffer_map (GstBuffer * buffer, GstMapFlags flags,
308     GstRTCPBuffer * rtcp)
309 {
310   g_return_val_if_fail (rtcp != NULL, FALSE);
311   g_return_val_if_fail (rtcp->buffer == NULL, FALSE);
312   g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
313   g_return_val_if_fail (flags & GST_MAP_READ, FALSE);
314
315   rtcp->buffer = buffer;
316   gst_buffer_map (buffer, &rtcp->map, flags);
317
318   return TRUE;
319 }
320
321 /**
322  * gst_rtcp_buffer_unmap:
323  * @rtcp: a buffer with an RTCP packet
324  *
325  * Finish @rtcp after being constructed. This function is usually called
326  * after gst_rtcp_buffer_map() and after adding the RTCP items to the new buffer.
327  *
328  * The function adjusts the size of @rtcp with the total length of all the
329  * added packets.
330  */
331 gboolean
332 gst_rtcp_buffer_unmap (GstRTCPBuffer * rtcp)
333 {
334   g_return_val_if_fail (rtcp != NULL, FALSE);
335   g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), FALSE);
336
337   if (rtcp->map.flags & GST_MAP_WRITE) {
338     /* shrink size */
339     gst_buffer_resize (rtcp->buffer, 0, rtcp->map.size);
340   }
341
342   gst_buffer_unmap (rtcp->buffer, &rtcp->map);
343   rtcp->buffer = NULL;
344
345   return TRUE;
346 }
347
348 /**
349  * gst_rtcp_buffer_get_packet_count:
350  * @rtcp: a valid RTCP buffer
351  *
352  * Get the number of RTCP packets in @rtcp.
353  *
354  * Returns: the number of RTCP packets in @rtcp.
355  */
356 guint
357 gst_rtcp_buffer_get_packet_count (GstRTCPBuffer * rtcp)
358 {
359   GstRTCPPacket packet;
360   guint count;
361
362   g_return_val_if_fail (rtcp != NULL, 0);
363   g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), 0);
364   g_return_val_if_fail (rtcp != NULL, 0);
365   g_return_val_if_fail (rtcp->map.flags & GST_MAP_READ, 0);
366
367   count = 0;
368   if (gst_rtcp_buffer_get_first_packet (rtcp, &packet)) {
369     do {
370       count++;
371     } while (gst_rtcp_packet_move_to_next (&packet));
372   }
373
374   return count;
375 }
376
377 static gint
378 rtcp_packet_min_length (GstRTCPType type)
379 {
380   switch (type) {
381     case GST_RTCP_TYPE_SR:
382       return 28;
383     case GST_RTCP_TYPE_RR:
384       return 8;
385     case GST_RTCP_TYPE_SDES:
386       return 4;
387     case GST_RTCP_TYPE_BYE:
388       return 4;
389     case GST_RTCP_TYPE_APP:
390       return 12;
391     case GST_RTCP_TYPE_RTPFB:
392       return 12;
393     case GST_RTCP_TYPE_PSFB:
394       return 12;
395     case GST_RTCP_TYPE_XR:
396       return 8;
397     default:
398       return -1;
399   }
400 }
401
402 /**
403  * read_packet_header:
404  * @packet: a packet
405  *
406  * Read the packet headers for the packet pointed to by @packet.
407  *
408  * Returns: TRUE if @packet pointed to a valid header.
409  */
410 static gboolean
411 read_packet_header (GstRTCPPacket * packet)
412 {
413   guint8 *data;
414   gsize maxsize;
415   guint offset;
416   gint minsize;
417   guint minlength;
418
419   g_return_val_if_fail (packet != NULL, FALSE);
420
421   data = packet->rtcp->map.data;
422   maxsize = packet->rtcp->map.size;
423
424   offset = packet->offset;
425
426   /* check if we are at the end of the buffer, we add 4 because we also want to
427    * ensure we can read the header. */
428   if (offset + 4 > maxsize)
429     return FALSE;
430
431   if ((data[offset] & 0xc0) != (GST_RTCP_VERSION << 6))
432     return FALSE;
433
434   /* read count, type and length */
435   packet->padding = (data[offset] & 0x20) == 0x20;
436   packet->count = data[offset] & 0x1f;
437   packet->type = data[offset + 1];
438   packet->length = (data[offset + 2] << 8) | data[offset + 3];
439   packet->item_offset = 4;
440   packet->item_count = 0;
441   packet->entry_offset = 4;
442
443   /* Ensure no overread from the claimed data size. The packet length
444      is expressed in multiple of 32 bits, to make things obvious. */
445   if (offset + 4 + packet->length * 4 > maxsize)
446     return FALSE;
447
448   minsize = rtcp_packet_min_length (packet->type);
449   if (minsize == -1)
450     minsize = 0;
451   minlength = (minsize - 4) >> 2;
452
453   /* Validate the size */
454   if (packet->length < minlength)
455     return FALSE;
456
457   return TRUE;
458 }
459
460 /**
461  * gst_rtcp_buffer_get_first_packet:
462  * @rtcp: a valid RTCP buffer
463  * @packet: a #GstRTCPPacket
464  *
465  * Initialize a new #GstRTCPPacket pointer that points to the first packet in
466  * @rtcp.
467  *
468  * Returns: TRUE if the packet existed in @rtcp.
469  */
470 gboolean
471 gst_rtcp_buffer_get_first_packet (GstRTCPBuffer * rtcp, GstRTCPPacket * packet)
472 {
473   g_return_val_if_fail (rtcp != NULL, FALSE);
474   g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), FALSE);
475   g_return_val_if_fail (packet != NULL, FALSE);
476   g_return_val_if_fail (rtcp != NULL, 0);
477   g_return_val_if_fail (rtcp->map.flags & GST_MAP_READ, 0);
478
479   /* init to 0 */
480   packet->rtcp = rtcp;
481   packet->offset = 0;
482   packet->type = GST_RTCP_TYPE_INVALID;
483
484   if (!read_packet_header (packet))
485     return FALSE;
486
487   return TRUE;
488 }
489
490 /**
491  * gst_rtcp_packet_move_to_next:
492  * @packet: a #GstRTCPPacket
493  *
494  * Move the packet pointer @packet to the next packet in the payload.
495  * Use gst_rtcp_buffer_get_first_packet() to initialize @packet.
496  *
497  * Returns: TRUE if @packet is pointing to a valid packet after calling this
498  * function.
499  */
500 gboolean
501 gst_rtcp_packet_move_to_next (GstRTCPPacket * packet)
502 {
503   g_return_val_if_fail (packet != NULL, FALSE);
504   g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE);
505   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
506   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
507
508   /* if we have a padding or invalid packet, it must be the last,
509    * return FALSE */
510   if (packet->type == GST_RTCP_TYPE_INVALID || packet->padding)
511     goto end;
512
513   /* move to next packet. Add 4 because the header is not included in length */
514   packet->offset += (packet->length << 2) + 4;
515
516   /* try to read new header */
517   if (!read_packet_header (packet))
518     goto end;
519
520   return TRUE;
521
522   /* ERRORS */
523 end:
524   {
525     packet->type = GST_RTCP_TYPE_INVALID;
526     return FALSE;
527   }
528 }
529
530 /**
531  * gst_rtcp_buffer_add_packet:
532  * @rtcp: a valid RTCP buffer
533  * @type: the #GstRTCPType of the new packet
534  * @packet: pointer to new packet
535  *
536  * Add a new packet of @type to @rtcp. @packet will point to the newly created
537  * packet.
538  *
539  * Returns: %TRUE if the packet could be created. This function returns %FALSE
540  * if the max mtu is exceeded for the buffer.
541  */
542 gboolean
543 gst_rtcp_buffer_add_packet (GstRTCPBuffer * rtcp, GstRTCPType type,
544     GstRTCPPacket * packet)
545 {
546   guint len;
547   gsize maxsize;
548   guint8 *data;
549   gboolean result;
550
551   g_return_val_if_fail (rtcp != NULL, FALSE);
552   g_return_val_if_fail (GST_IS_BUFFER (rtcp->buffer), FALSE);
553   g_return_val_if_fail (type != GST_RTCP_TYPE_INVALID, FALSE);
554   g_return_val_if_fail (packet != NULL, FALSE);
555   g_return_val_if_fail (rtcp->map.flags & GST_MAP_WRITE, FALSE);
556
557   /* find free space */
558   if (gst_rtcp_buffer_get_first_packet (rtcp, packet)) {
559     while (gst_rtcp_packet_move_to_next (packet));
560
561     if (packet->padding) {
562       /* Last packet is a padding packet. Let's not replace it silently  */
563       /* and let the application know that it could not be added because */
564       /* it would involve replacing a packet */
565       return FALSE;
566     }
567   }
568
569   maxsize = rtcp->map.maxsize;
570
571   /* packet->offset is now pointing to the next free offset in the buffer to
572    * start a compound packet. Next we figure out if we have enough free space in
573    * the buffer to continue. */
574   len = rtcp_packet_min_length (type);
575   if (len == -1)
576     goto unknown_type;
577   if (packet->offset + len >= maxsize)
578     goto no_space;
579
580   rtcp->map.size += len;
581
582   data = rtcp->map.data + packet->offset;
583
584   data[0] = (GST_RTCP_VERSION << 6);
585   data[1] = type;
586   /* length is stored in multiples of 32 bit words minus the length of the
587    * header */
588   len = (len - 4) >> 2;
589   data[2] = len >> 8;
590   data[3] = len & 0xff;
591
592   /* now try to position to the packet */
593   result = read_packet_header (packet);
594
595   return result;
596
597   /* ERRORS */
598 unknown_type:
599   {
600     g_warning ("unknown type %d", type);
601     return FALSE;
602   }
603 no_space:
604   {
605     return FALSE;
606   }
607 }
608
609 /**
610  * gst_rtcp_packet_remove:
611  * @packet: a #GstRTCPPacket
612  *
613  * Removes the packet pointed to by @packet and moves pointer to the next one
614  *
615  * Returns: TRUE if @packet is pointing to a valid packet after calling this
616  * function.
617  */
618 gboolean
619 gst_rtcp_packet_remove (GstRTCPPacket * packet)
620 {
621   gboolean ret = FALSE;
622   guint offset = 0;
623
624   g_return_val_if_fail (packet != NULL, FALSE);
625   g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE);
626   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
627   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
628
629   /* The next packet starts at offset + length + 4 (the header) */
630   offset = packet->offset + (packet->length << 2) + 4;
631
632   /* Overwrite this packet with the rest of the data */
633   memmove (packet->rtcp->map.data + packet->offset,
634       packet->rtcp->map.data + offset, packet->rtcp->map.size - offset);
635
636   packet->rtcp->map.size -= offset - packet->offset;
637
638   /* try to read next header */
639   ret = read_packet_header (packet);
640   if (!ret)
641     packet->type = GST_RTCP_TYPE_INVALID;
642
643   return ret;
644 }
645
646 /**
647  * gst_rtcp_packet_get_padding:
648  * @packet: a valid #GstRTCPPacket
649  *
650  * Get the packet padding of the packet pointed to by @packet.
651  *
652  * Returns: If the packet has the padding bit set.
653  */
654 gboolean
655 gst_rtcp_packet_get_padding (GstRTCPPacket * packet)
656 {
657   g_return_val_if_fail (packet != NULL, FALSE);
658   g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE);
659
660   return packet->padding;
661 }
662
663 /**
664  * gst_rtcp_packet_get_type:
665  * @packet: a valid #GstRTCPPacket
666  *
667  * Get the packet type of the packet pointed to by @packet.
668  *
669  * Returns: The packet type or GST_RTCP_TYPE_INVALID when @packet is not
670  * pointing to a valid packet.
671  */
672 GstRTCPType
673 gst_rtcp_packet_get_type (GstRTCPPacket * packet)
674 {
675   g_return_val_if_fail (packet != NULL, GST_RTCP_TYPE_INVALID);
676
677   return packet->type;
678 }
679
680 /**
681  * gst_rtcp_packet_get_count:
682  * @packet: a valid #GstRTCPPacket
683  *
684  * Get the count field in @packet.
685  *
686  * Returns: The count field in @packet or -1 if @packet does not point to a
687  * valid packet.
688  */
689 guint8
690 gst_rtcp_packet_get_count (GstRTCPPacket * packet)
691 {
692   g_return_val_if_fail (packet != NULL, -1);
693   g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, -1);
694
695   return packet->count;
696 }
697
698 /**
699  * gst_rtcp_packet_get_length:
700  * @packet: a valid #GstRTCPPacket
701  *
702  * Get the length field of @packet. This is the length of the packet in
703  * 32-bit words minus one.
704  *
705  * Returns: The length field of @packet.
706  */
707 guint16
708 gst_rtcp_packet_get_length (GstRTCPPacket * packet)
709 {
710   g_return_val_if_fail (packet != NULL, 0);
711   g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, 0);
712
713   return packet->length;
714 }
715
716 /**
717  * gst_rtcp_packet_sr_get_sender_info:
718  * @packet: a valid SR #GstRTCPPacket
719  * @ssrc: (out): result SSRC
720  * @ntptime: (out): result NTP time
721  * @rtptime: (out): result RTP time
722  * @packet_count: (out): result packet count
723  * @octet_count: (out): result octet count
724  *
725  * Parse the SR sender info and store the values.
726  */
727 void
728 gst_rtcp_packet_sr_get_sender_info (GstRTCPPacket * packet, guint32 * ssrc,
729     guint64 * ntptime, guint32 * rtptime, guint32 * packet_count,
730     guint32 * octet_count)
731 {
732   guint8 *data;
733
734   g_return_if_fail (packet != NULL);
735   g_return_if_fail (packet->type == GST_RTCP_TYPE_SR);
736   g_return_if_fail (packet->rtcp != NULL);
737   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_READ);
738
739   data = packet->rtcp->map.data;
740
741   /* skip header */
742   data += packet->offset + 4;
743   if (ssrc)
744     *ssrc = GST_READ_UINT32_BE (data);
745   data += 4;
746   if (ntptime)
747     *ntptime = GST_READ_UINT64_BE (data);
748   data += 8;
749   if (rtptime)
750     *rtptime = GST_READ_UINT32_BE (data);
751   data += 4;
752   if (packet_count)
753     *packet_count = GST_READ_UINT32_BE (data);
754   data += 4;
755   if (octet_count)
756     *octet_count = GST_READ_UINT32_BE (data);
757 }
758
759 /**
760  * gst_rtcp_packet_sr_set_sender_info:
761  * @packet: a valid SR #GstRTCPPacket
762  * @ssrc: the SSRC
763  * @ntptime: the NTP time
764  * @rtptime: the RTP time
765  * @packet_count: the packet count
766  * @octet_count: the octet count
767  *
768  * Set the given values in the SR packet @packet.
769  */
770 void
771 gst_rtcp_packet_sr_set_sender_info (GstRTCPPacket * packet, guint32 ssrc,
772     guint64 ntptime, guint32 rtptime, guint32 packet_count, guint32 octet_count)
773 {
774   guint8 *data;
775
776   g_return_if_fail (packet != NULL);
777   g_return_if_fail (packet->type == GST_RTCP_TYPE_SR);
778   g_return_if_fail (packet->rtcp != NULL);
779   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
780
781   data = packet->rtcp->map.data;
782
783   /* skip header */
784   data += packet->offset + 4;
785   GST_WRITE_UINT32_BE (data, ssrc);
786   data += 4;
787   GST_WRITE_UINT64_BE (data, ntptime);
788   data += 8;
789   GST_WRITE_UINT32_BE (data, rtptime);
790   data += 4;
791   GST_WRITE_UINT32_BE (data, packet_count);
792   data += 4;
793   GST_WRITE_UINT32_BE (data, octet_count);
794 }
795
796 /**
797  * gst_rtcp_packet_rr_get_ssrc:
798  * @packet: a valid RR #GstRTCPPacket
799  *
800  * Get the ssrc field of the RR @packet.
801  *
802  * Returns: the ssrc.
803  */
804 guint32
805 gst_rtcp_packet_rr_get_ssrc (GstRTCPPacket * packet)
806 {
807   guint8 *data;
808   guint32 ssrc;
809
810   g_return_val_if_fail (packet != NULL, 0);
811   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR, 0);
812   g_return_val_if_fail (packet->rtcp != NULL, 0);
813   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
814
815   data = packet->rtcp->map.data;
816
817   /* skip header */
818   data += packet->offset + 4;
819   ssrc = GST_READ_UINT32_BE (data);
820
821   return ssrc;
822 }
823
824 /**
825  * gst_rtcp_packet_rr_set_ssrc:
826  * @packet: a valid RR #GstRTCPPacket
827  * @ssrc: the SSRC to set
828  *
829  * Set the ssrc field of the RR @packet.
830  */
831 void
832 gst_rtcp_packet_rr_set_ssrc (GstRTCPPacket * packet, guint32 ssrc)
833 {
834   guint8 *data;
835
836   g_return_if_fail (packet != NULL);
837   g_return_if_fail (packet->type == GST_RTCP_TYPE_RR);
838   g_return_if_fail (packet->rtcp != NULL);
839   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
840
841   data = packet->rtcp->map.data;
842
843   /* skip header */
844   data += packet->offset + 4;
845   GST_WRITE_UINT32_BE (data, ssrc);
846 }
847
848 /**
849  * gst_rtcp_packet_get_rb_count:
850  * @packet: a valid SR or RR #GstRTCPPacket
851  *
852  * Get the number of report blocks in @packet.
853  *
854  * Returns: The number of report blocks in @packet.
855  */
856 guint
857 gst_rtcp_packet_get_rb_count (GstRTCPPacket * packet)
858 {
859   g_return_val_if_fail (packet != NULL, 0);
860   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
861       packet->type == GST_RTCP_TYPE_SR, 0);
862   g_return_val_if_fail (packet->rtcp != NULL, 0);
863   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
864
865   return packet->count;
866 }
867
868 /**
869  * gst_rtcp_packet_get_rb:
870  * @packet: a valid SR or RR #GstRTCPPacket
871  * @nth: the nth report block in @packet
872  * @ssrc: (out): result for data source being reported
873  * @fractionlost: (out): result for fraction lost since last SR/RR
874  * @packetslost: (out): result for the cumululative number of packets lost
875  * @exthighestseq: (out): result for the extended last sequence number received
876  * @jitter: (out): result for the interarrival jitter
877  * @lsr: (out): result for the last SR packet from this source
878  * @dlsr: (out): result for the delay since last SR packet
879  *
880  * Parse the values of the @nth report block in @packet and store the result in
881  * the values.
882  */
883 void
884 gst_rtcp_packet_get_rb (GstRTCPPacket * packet, guint nth, guint32 * ssrc,
885     guint8 * fractionlost, gint32 * packetslost, guint32 * exthighestseq,
886     guint32 * jitter, guint32 * lsr, guint32 * dlsr)
887 {
888   guint offset;
889   guint8 *data;
890   guint32 tmp;
891
892   g_return_if_fail (packet != NULL);
893   g_return_if_fail (packet->type == GST_RTCP_TYPE_RR ||
894       packet->type == GST_RTCP_TYPE_SR);
895   g_return_if_fail (packet->rtcp != NULL);
896   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_READ);
897   g_return_if_fail (nth < packet->count);
898
899   /* get offset in 32-bits words into packet, skip the header */
900   if (packet->type == GST_RTCP_TYPE_RR)
901     offset = 2;
902   else
903     offset = 7;
904
905   /* move to requested index */
906   offset += (nth * 6);
907
908   /* check that we don't go past the packet length */
909   if (offset > packet->length)
910     return;
911
912   /* scale to bytes */
913   offset <<= 2;
914   offset += packet->offset;
915
916   /* check if the packet is valid */
917   if (offset + 24 > packet->rtcp->map.size)
918     return;
919
920   data = packet->rtcp->map.data;
921   data += offset;
922
923   if (ssrc)
924     *ssrc = GST_READ_UINT32_BE (data);
925   data += 4;
926   tmp = GST_READ_UINT32_BE (data);
927   if (fractionlost)
928     *fractionlost = (tmp >> 24);
929   if (packetslost) {
930     /* sign extend */
931     if (tmp & 0x00800000)
932       tmp |= 0xff000000;
933     else
934       tmp &= 0x00ffffff;
935     *packetslost = (gint32) tmp;
936   }
937   data += 4;
938   if (exthighestseq)
939     *exthighestseq = GST_READ_UINT32_BE (data);
940   data += 4;
941   if (jitter)
942     *jitter = GST_READ_UINT32_BE (data);
943   data += 4;
944   if (lsr)
945     *lsr = GST_READ_UINT32_BE (data);
946   data += 4;
947   if (dlsr)
948     *dlsr = GST_READ_UINT32_BE (data);
949 }
950
951 /**
952  * gst_rtcp_packet_add_rb:
953  * @packet: a valid SR or RR #GstRTCPPacket
954  * @ssrc: data source being reported
955  * @fractionlost: fraction lost since last SR/RR
956  * @packetslost: the cumululative number of packets lost
957  * @exthighestseq: the extended last sequence number received
958  * @jitter: the interarrival jitter
959  * @lsr: the last SR packet from this source
960  * @dlsr: the delay since last SR packet
961  *
962  * Add a new report block to @packet with the given values.
963  *
964  * Returns: %TRUE if the packet was created. This function can return %FALSE if
965  * the max MTU is exceeded or the number of report blocks is greater than
966  * #GST_RTCP_MAX_RB_COUNT.
967  */
968 gboolean
969 gst_rtcp_packet_add_rb (GstRTCPPacket * packet, guint32 ssrc,
970     guint8 fractionlost, gint32 packetslost, guint32 exthighestseq,
971     guint32 jitter, guint32 lsr, guint32 dlsr)
972 {
973   guint8 *data;
974   guint maxsize, offset;
975
976   g_return_val_if_fail (packet != NULL, FALSE);
977   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
978       packet->type == GST_RTCP_TYPE_SR, FALSE);
979   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
980   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
981   /* if profile-specific extension is added, fail for now!? */
982   g_return_val_if_fail (gst_rtcp_packet_get_profile_specific_ext_length (packet)
983       == 0, FALSE);
984
985   if (packet->count >= GST_RTCP_MAX_RB_COUNT)
986     goto no_space;
987
988   data = packet->rtcp->map.data;
989   maxsize = packet->rtcp->map.maxsize;
990
991   /* skip header */
992   offset = packet->offset + 4;
993   if (packet->type == GST_RTCP_TYPE_RR)
994     offset += 4;
995   else
996     offset += 24;
997
998   /* move to current index */
999   offset += (packet->count * 24);
1000
1001   /* we need 24 free bytes now */
1002   if (offset + 24 >= maxsize)
1003     goto no_space;
1004
1005   /* increment packet count and length */
1006   packet->count++;
1007   data[packet->offset]++;
1008   packet->length += 6;
1009   data[packet->offset + 2] = (packet->length) >> 8;
1010   data[packet->offset + 3] = (packet->length) & 0xff;
1011   packet->rtcp->map.size += 6 * 4;
1012
1013   /* move to new report block offset */
1014   data += offset;
1015
1016   GST_WRITE_UINT32_BE (data, ssrc);
1017   data += 4;
1018   GST_WRITE_UINT32_BE (data,
1019       ((guint32) fractionlost << 24) | (packetslost & 0xffffff));
1020   data += 4;
1021   GST_WRITE_UINT32_BE (data, exthighestseq);
1022   data += 4;
1023   GST_WRITE_UINT32_BE (data, jitter);
1024   data += 4;
1025   GST_WRITE_UINT32_BE (data, lsr);
1026   data += 4;
1027   GST_WRITE_UINT32_BE (data, dlsr);
1028
1029   return TRUE;
1030
1031 no_space:
1032   {
1033     return FALSE;
1034   }
1035 }
1036
1037 /**
1038  * gst_rtcp_packet_set_rb:
1039  * @packet: a valid SR or RR #GstRTCPPacket
1040  * @nth: the nth report block to set
1041  * @ssrc: data source being reported
1042  * @fractionlost: fraction lost since last SR/RR
1043  * @packetslost: the cumululative number of packets lost
1044  * @exthighestseq: the extended last sequence number received
1045  * @jitter: the interarrival jitter
1046  * @lsr: the last SR packet from this source
1047  * @dlsr: the delay since last SR packet
1048  *
1049  * Set the @nth new report block in @packet with the given values.
1050  *
1051  * Note: Not implemented.
1052  */
1053 void
1054 gst_rtcp_packet_set_rb (GstRTCPPacket * packet, guint nth, guint32 ssrc,
1055     guint8 fractionlost, gint32 packetslost, guint32 exthighestseq,
1056     guint32 jitter, guint32 lsr, guint32 dlsr)
1057 {
1058   g_return_if_fail (packet != NULL);
1059   g_return_if_fail (packet->type == GST_RTCP_TYPE_RR ||
1060       packet->type == GST_RTCP_TYPE_SR);
1061   g_return_if_fail (packet->rtcp != NULL);
1062   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
1063
1064   g_warning ("not implemented");
1065 }
1066
1067
1068 /**
1069  * gst_rtcp_packet_add_profile_specific_ext:
1070  * @packet: a valid SR or RR #GstRTCPPacket
1071  * @data: (array length=len) (transfer none): profile-specific data
1072  * @len: length of the profile-specific data in bytes
1073  *
1074  * Add profile-specific extension @data to @packet. If @packet already
1075  * contains profile-specific extension @data will be appended to the existing
1076  * extension.
1077  *
1078  * Returns: %TRUE if the profile specific extension data was added.
1079  *
1080  * Since: 1.10
1081  */
1082 gboolean
1083 gst_rtcp_packet_add_profile_specific_ext (GstRTCPPacket * packet,
1084     const guint8 * data, guint len)
1085 {
1086   guint8 *bdata;
1087   guint maxsize, offset;
1088
1089   g_return_val_if_fail (packet != NULL, FALSE);
1090   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
1091       packet->type == GST_RTCP_TYPE_SR, FALSE);
1092   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1093   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
1094   g_return_val_if_fail ((len & 0x03) == 0, FALSE);
1095
1096   bdata = packet->rtcp->map.data;
1097   maxsize = packet->rtcp->map.maxsize;
1098
1099   /* skip to the end of the packet */
1100   offset = packet->offset + (packet->length << 2) + 4;
1101
1102   /* we need 'len' free bytes now */
1103   if (G_UNLIKELY (offset + len > maxsize))
1104     return FALSE;
1105
1106   memcpy (&bdata[offset], data, len);
1107   packet->length += len >> 2;
1108   bdata[packet->offset + 2] = (packet->length) >> 8;
1109   bdata[packet->offset + 3] = (packet->length) & 0xff;
1110   packet->rtcp->map.size += len;
1111
1112   return TRUE;
1113 }
1114
1115 /**
1116  * gst_rtcp_packet_get_profile_specific_ext_length:
1117  * @packet: a valid SR or RR #GstRTCPPacket
1118  *
1119  * Returns: The number of 32-bit words containing profile-specific extension
1120  *          data from @packet.
1121  *
1122  * Since: 1.10
1123  */
1124 guint16
1125 gst_rtcp_packet_get_profile_specific_ext_length (GstRTCPPacket * packet)
1126 {
1127   guint pse_offset = 2;
1128
1129   g_return_val_if_fail (packet != NULL, 0);
1130   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
1131       packet->type == GST_RTCP_TYPE_SR, 0);
1132   g_return_val_if_fail (packet->rtcp != NULL, 0);
1133   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
1134
1135   if (packet->type == GST_RTCP_TYPE_SR)
1136     pse_offset += 5;
1137   pse_offset += (packet->count * 6);
1138
1139   if (pse_offset <= (packet->length + 1))
1140     return packet->length + 1 - pse_offset;
1141
1142   /* This means that the packet is invalid! */
1143   return 0;
1144 }
1145
1146 /**
1147  * gst_rtcp_packet_get_profile_specific_ext:
1148  * @packet: a valid SR or RR #GstRTCPPacket
1149  * @data: (out) (array length=len) (transfer none): result profile-specific data
1150  * @len: (out): result length of the profile-specific data
1151  *
1152  * Returns: %TRUE if there was valid data.
1153  *
1154  * Since: 1.10
1155  */
1156 gboolean
1157 gst_rtcp_packet_get_profile_specific_ext (GstRTCPPacket * packet,
1158     guint8 ** data, guint * len)
1159 {
1160   guint16 pse_len;
1161
1162   g_return_val_if_fail (packet != NULL, FALSE);
1163   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
1164       packet->type == GST_RTCP_TYPE_SR, FALSE);
1165   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1166   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
1167
1168   pse_len = gst_rtcp_packet_get_profile_specific_ext_length (packet);
1169   if (pse_len > 0) {
1170     if (len != NULL)
1171       *len = pse_len * sizeof (guint32);
1172     if (data != NULL) {
1173       *data = packet->rtcp->map.data;
1174       *data += packet->offset;
1175       *data += ((packet->length + 1 - pse_len) * sizeof (guint32));
1176     }
1177
1178     return TRUE;
1179   }
1180
1181   return FALSE;
1182 }
1183
1184 /**
1185  * gst_rtcp_packet_copy_profile_specific_ext:
1186  * @packet: a valid SR or RR #GstRTCPPacket
1187  * @data: (out) (array length=len): result profile-specific data
1188  * @len: (out): length of the profile-specific extension data
1189  *
1190  * The profile-specific extension data is copied into a new allocated
1191  * memory area @data. This must be freed with g_free() after usage.
1192  *
1193  * Returns: %TRUE if there was valid data.
1194  *
1195  * Since: 1.10
1196  */
1197 gboolean
1198 gst_rtcp_packet_copy_profile_specific_ext (GstRTCPPacket * packet,
1199     guint8 ** data, guint * len)
1200 {
1201   guint16 pse_len;
1202
1203   g_return_val_if_fail (packet != NULL, FALSE);
1204   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR ||
1205       packet->type == GST_RTCP_TYPE_SR, FALSE);
1206   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1207   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
1208
1209   pse_len = gst_rtcp_packet_get_profile_specific_ext_length (packet);
1210   if (pse_len > 0) {
1211     if (len != NULL)
1212       *len = pse_len * sizeof (guint32);
1213     if (data != NULL) {
1214       guint8 *ptr = packet->rtcp->map.data + packet->offset;
1215       ptr += ((packet->length + 1 - pse_len) * sizeof (guint32));
1216       *data = g_memdup2 (ptr, pse_len * sizeof (guint32));
1217     }
1218
1219     return TRUE;
1220   }
1221
1222   return FALSE;
1223 }
1224
1225
1226 /**
1227  * gst_rtcp_packet_sdes_get_item_count:
1228  * @packet: a valid SDES #GstRTCPPacket
1229  *
1230  * Get the number of items in the SDES packet @packet.
1231  *
1232  * Returns: The number of items in @packet.
1233  */
1234 guint
1235 gst_rtcp_packet_sdes_get_item_count (GstRTCPPacket * packet)
1236 {
1237   g_return_val_if_fail (packet != NULL, 0);
1238   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
1239
1240   return packet->count;
1241 }
1242
1243 /**
1244  * gst_rtcp_packet_sdes_first_item:
1245  * @packet: a valid SDES #GstRTCPPacket
1246  *
1247  * Move to the first SDES item in @packet.
1248  *
1249  * Returns: TRUE if there was a first item.
1250  */
1251 gboolean
1252 gst_rtcp_packet_sdes_first_item (GstRTCPPacket * packet)
1253 {
1254   g_return_val_if_fail (packet != NULL, FALSE);
1255   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
1256
1257   packet->item_offset = 4;
1258   packet->item_count = 0;
1259   packet->entry_offset = 4;
1260
1261   if (packet->count == 0)
1262     return FALSE;
1263
1264   return TRUE;
1265 }
1266
1267 /**
1268  * gst_rtcp_packet_sdes_next_item:
1269  * @packet: a valid SDES #GstRTCPPacket
1270  *
1271  * Move to the next SDES item in @packet.
1272  *
1273  * Returns: TRUE if there was a next item.
1274  */
1275 gboolean
1276 gst_rtcp_packet_sdes_next_item (GstRTCPPacket * packet)
1277 {
1278   guint8 *data;
1279   guint offset;
1280   guint len;
1281
1282   g_return_val_if_fail (packet != NULL, FALSE);
1283   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
1284   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1285   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
1286
1287   /* if we are at the last item, we are done */
1288   if (packet->item_count == packet->count)
1289     return FALSE;
1290
1291   /* move to SDES */
1292   data = packet->rtcp->map.data;
1293   data += packet->offset;
1294   /* move to item */
1295   offset = packet->item_offset;
1296   /* skip SSRC */
1297   offset += 4;
1298
1299   /* don't overrun */
1300   len = (packet->length << 2);
1301
1302   while (offset < len) {
1303     if (data[offset] == 0) {
1304       /* end of list, round to next 32-bit word */
1305       offset = (offset + 4) & ~3;
1306       break;
1307     }
1308     offset += data[offset + 1] + 2;
1309   }
1310   if (offset >= len)
1311     return FALSE;
1312
1313   packet->item_offset = offset;
1314   packet->item_count++;
1315   packet->entry_offset = 4;
1316
1317   return TRUE;
1318 }
1319
1320 /**
1321  * gst_rtcp_packet_sdes_get_ssrc:
1322  * @packet: a valid SDES #GstRTCPPacket
1323  *
1324  * Get the SSRC of the current SDES item.
1325  *
1326  * Returns: the SSRC of the current item.
1327  */
1328 guint32
1329 gst_rtcp_packet_sdes_get_ssrc (GstRTCPPacket * packet)
1330 {
1331   guint32 ssrc;
1332   guint8 *data;
1333
1334   g_return_val_if_fail (packet != NULL, 0);
1335   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0);
1336   g_return_val_if_fail (packet->rtcp != NULL, 0);
1337   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
1338
1339   /* move to SDES */
1340   data = packet->rtcp->map.data;
1341   data += packet->offset;
1342   /* move to item */
1343   data += packet->item_offset;
1344
1345   ssrc = GST_READ_UINT32_BE (data);
1346
1347   return ssrc;
1348 }
1349
1350 /**
1351  * gst_rtcp_packet_sdes_first_entry:
1352  * @packet: a valid SDES #GstRTCPPacket
1353  *
1354  * Move to the first SDES entry in the current item.
1355  *
1356  * Returns: %TRUE if there was a first entry.
1357  */
1358 gboolean
1359 gst_rtcp_packet_sdes_first_entry (GstRTCPPacket * packet)
1360 {
1361   guint8 *data;
1362   guint len, offset;
1363
1364   g_return_val_if_fail (packet != NULL, FALSE);
1365   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
1366   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1367   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
1368
1369   /* move to SDES */
1370   data = packet->rtcp->map.data;
1371   data += packet->offset;
1372   /* move to item */
1373   offset = packet->item_offset;
1374   /* skip SSRC */
1375   offset += 4;
1376
1377   packet->entry_offset = 4;
1378
1379   /* don't overrun */
1380   len = (packet->length << 2);
1381   if (offset >= len)
1382     return FALSE;
1383
1384   if (data[offset] == 0)
1385     return FALSE;
1386
1387   return TRUE;
1388 }
1389
1390 /**
1391  * gst_rtcp_packet_sdes_next_entry:
1392  * @packet: a valid SDES #GstRTCPPacket
1393  *
1394  * Move to the next SDES entry in the current item.
1395  *
1396  * Returns: %TRUE if there was a next entry.
1397  */
1398 gboolean
1399 gst_rtcp_packet_sdes_next_entry (GstRTCPPacket * packet)
1400 {
1401   guint8 *data;
1402   guint len, offset, item_len;
1403
1404   g_return_val_if_fail (packet != NULL, FALSE);
1405   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
1406   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1407   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
1408
1409   /* move to SDES */
1410   data = packet->rtcp->map.data;
1411   data += packet->offset;
1412   /* move to item */
1413   offset = packet->item_offset;
1414   /* move to entry */
1415   offset += packet->entry_offset;
1416
1417   item_len = data[offset + 1] + 2;
1418   /* skip item */
1419   offset += item_len;
1420
1421   /* don't overrun */
1422   len = (packet->length << 2);
1423   if (offset >= len)
1424     return FALSE;
1425
1426   packet->entry_offset += item_len;
1427
1428   /* check for end of list */
1429   if (data[offset] == 0)
1430     return FALSE;
1431
1432   return TRUE;
1433 }
1434
1435 /**
1436  * gst_rtcp_packet_sdes_get_entry:
1437  * @packet: a valid SDES #GstRTCPPacket
1438  * @type: result of the entry type
1439  * @len: (out): result length of the entry data
1440  * @data: (out) (array length=len) (transfer none): result entry data
1441  *
1442  * Get the data of the current SDES item entry. @type (when not NULL) will
1443  * contain the type of the entry. @data (when not NULL) will point to @len
1444  * bytes.
1445  *
1446  * When @type refers to a text item, @data will point to a UTF8 string. Note
1447  * that this UTF8 string is NOT null-terminated. Use
1448  * gst_rtcp_packet_sdes_copy_entry() to get a null-terminated copy of the entry.
1449  *
1450  * Returns: %TRUE if there was valid data.
1451  */
1452 gboolean
1453 gst_rtcp_packet_sdes_get_entry (GstRTCPPacket * packet,
1454     GstRTCPSDESType * type, guint8 * len, guint8 ** data)
1455 {
1456   guint8 *bdata;
1457   guint offset;
1458
1459   g_return_val_if_fail (packet != NULL, FALSE);
1460   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
1461   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1462   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
1463
1464   /* move to SDES */
1465   bdata = packet->rtcp->map.data;
1466   bdata += packet->offset;
1467   /* move to item */
1468   offset = packet->item_offset;
1469   /* move to entry */
1470   offset += packet->entry_offset;
1471
1472   if (bdata[offset] == 0)
1473     return FALSE;
1474
1475   if (type)
1476     *type = bdata[offset];
1477   if (len)
1478     *len = bdata[offset + 1];
1479   if (data)
1480     *data = &bdata[offset + 2];
1481
1482   return TRUE;
1483 }
1484
1485 /**
1486  * gst_rtcp_packet_sdes_copy_entry:
1487  * @packet: a valid SDES #GstRTCPPacket
1488  * @type: result of the entry type
1489  * @len: (out): result length of the entry data
1490  * @data: (out) (array length=len): result entry data
1491  *
1492  * This function is like gst_rtcp_packet_sdes_get_entry() but it returns a
1493  * null-terminated copy of the data instead. use g_free() after usage.
1494  *
1495  * Returns: %TRUE if there was valid data.
1496  */
1497 gboolean
1498 gst_rtcp_packet_sdes_copy_entry (GstRTCPPacket * packet,
1499     GstRTCPSDESType * type, guint8 * len, guint8 ** data)
1500 {
1501   guint8 *tdata;
1502   guint8 tlen;
1503
1504   g_return_val_if_fail (packet != NULL, FALSE);
1505   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
1506   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1507   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
1508
1509   if (!gst_rtcp_packet_sdes_get_entry (packet, type, &tlen, &tdata))
1510     return FALSE;
1511
1512   if (len)
1513     *len = tlen;
1514   if (data)
1515     *data = (guint8 *) g_strndup ((gchar *) tdata, tlen);
1516
1517   return TRUE;
1518 }
1519
1520 /**
1521  * gst_rtcp_packet_sdes_add_item:
1522  * @packet: a valid SDES #GstRTCPPacket
1523  * @ssrc: the SSRC of the new item to add
1524  *
1525  * Add a new SDES item for @ssrc to @packet.
1526  *
1527  * Returns: %TRUE if the item could be added, %FALSE if the maximum amount of
1528  * items has been exceeded for the SDES packet or the MTU has been reached.
1529  */
1530 gboolean
1531 gst_rtcp_packet_sdes_add_item (GstRTCPPacket * packet, guint32 ssrc)
1532 {
1533   guint8 *data;
1534   guint offset;
1535   gsize maxsize;
1536
1537   g_return_val_if_fail (packet != NULL, FALSE);
1538   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
1539   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1540   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
1541
1542   /* increment item count when possible */
1543   if (packet->count >= GST_RTCP_MAX_SDES_ITEM_COUNT)
1544     goto no_space;
1545
1546   /* pretend there is a next packet for the next call */
1547   packet->count++;
1548
1549   /* jump over current item */
1550   gst_rtcp_packet_sdes_next_item (packet);
1551
1552   /* move to SDES */
1553   data = packet->rtcp->map.data;
1554   maxsize = packet->rtcp->map.maxsize;
1555   data += packet->offset;
1556   /* move to current item */
1557   offset = packet->item_offset;
1558
1559   /* we need 2 free words now */
1560   if (offset + 8 >= maxsize)
1561     goto no_next;
1562
1563   /* write SSRC */
1564   GST_WRITE_UINT32_BE (&data[offset], ssrc);
1565   /* write 0 entry with padding */
1566   GST_WRITE_UINT32_BE (&data[offset + 4], 0);
1567
1568   /* update count */
1569   data[0] = (data[0] & 0xe0) | packet->count;
1570   /* update length, we added 2 words */
1571   packet->length += 2;
1572   data[2] = (packet->length) >> 8;
1573   data[3] = (packet->length) & 0xff;
1574
1575   packet->rtcp->map.size += 8;
1576
1577   return TRUE;
1578
1579   /* ERRORS */
1580 no_space:
1581   {
1582     return FALSE;
1583   }
1584 no_next:
1585   {
1586     packet->count--;
1587     return FALSE;
1588   }
1589 }
1590
1591 /**
1592  * gst_rtcp_packet_sdes_add_entry:
1593  * @packet: a valid SDES #GstRTCPPacket
1594  * @type: the #GstRTCPSDESType of the SDES entry
1595  * @len: the data length
1596  * @data: (array length=len): the data
1597  *
1598  * Add a new SDES entry to the current item in @packet.
1599  *
1600  * Returns: %TRUE if the item could be added, %FALSE if the MTU has been
1601  * reached.
1602  */
1603 gboolean
1604 gst_rtcp_packet_sdes_add_entry (GstRTCPPacket * packet, GstRTCPSDESType type,
1605     guint8 len, const guint8 * data)
1606 {
1607   guint8 *bdata;
1608   guint offset, padded;
1609   gsize maxsize;
1610
1611   g_return_val_if_fail (packet != NULL, FALSE);
1612   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE);
1613   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1614   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
1615
1616   /* move to SDES */
1617   bdata = packet->rtcp->map.data;
1618   maxsize = packet->rtcp->map.maxsize;
1619   bdata += packet->offset;
1620   /* move to item */
1621   offset = packet->item_offset;
1622   /* move to entry */
1623   offset += packet->entry_offset;
1624
1625   /* add 1 byte end and up to 3 bytes padding to fill a full 32 bit word */
1626   padded = (offset + 2 + len + 1 + 3) & ~3;
1627
1628   /* we need enough space for type, len, data and padding */
1629   if (packet->offset + padded >= maxsize)
1630     goto no_space;
1631
1632   packet->rtcp->map.size = packet->offset + padded;
1633
1634   bdata[offset] = type;
1635   bdata[offset + 1] = len;
1636   memcpy (&bdata[offset + 2], data, len);
1637   bdata[offset + 2 + len] = 0;
1638
1639   /* calculate new packet length */
1640   packet->length = (padded - 4) >> 2;
1641   bdata[2] = (packet->length) >> 8;
1642   bdata[3] = (packet->length) & 0xff;
1643
1644   /* position to new next entry */
1645   packet->entry_offset += 2 + len;
1646
1647   return TRUE;
1648
1649   /* ERRORS */
1650 no_space:
1651   {
1652     return FALSE;
1653   }
1654 }
1655
1656 /**
1657  * gst_rtcp_packet_bye_get_ssrc_count:
1658  * @packet: a valid BYE #GstRTCPPacket
1659  *
1660  * Get the number of SSRC fields in @packet.
1661  *
1662  * Returns: The number of SSRC fields in @packet.
1663  */
1664 guint
1665 gst_rtcp_packet_bye_get_ssrc_count (GstRTCPPacket * packet)
1666 {
1667   g_return_val_if_fail (packet != NULL, -1);
1668   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, -1);
1669
1670   return packet->count;
1671 }
1672
1673 /**
1674  * gst_rtcp_packet_bye_get_nth_ssrc:
1675  * @packet: a valid BYE #GstRTCPPacket
1676  * @nth: the nth SSRC to get
1677  *
1678  * Get the @nth SSRC of the BYE @packet.
1679  *
1680  * Returns: The @nth SSRC of @packet.
1681  */
1682 guint32
1683 gst_rtcp_packet_bye_get_nth_ssrc (GstRTCPPacket * packet, guint nth)
1684 {
1685   guint8 *data;
1686   guint offset;
1687   guint32 ssrc;
1688
1689   g_return_val_if_fail (packet != NULL, 0);
1690   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0);
1691   g_return_val_if_fail (packet->rtcp != NULL, 0);
1692   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
1693   g_return_val_if_fail (nth < packet->count, 0);
1694
1695   /* get offset in 32-bits words into packet, skip the header */
1696   offset = 1 + nth;
1697   /* check that we don't go past the packet length */
1698   if (offset > packet->length)
1699     return 0;
1700
1701   /* scale to bytes */
1702   offset <<= 2;
1703   offset += packet->offset;
1704
1705   /* check if the packet is valid */
1706   if (offset + 4 > packet->rtcp->map.size)
1707     return 0;
1708
1709   data = packet->rtcp->map.data;
1710   data += offset;
1711
1712   ssrc = GST_READ_UINT32_BE (data);
1713
1714   return ssrc;
1715 }
1716
1717 /**
1718  * gst_rtcp_packet_bye_add_ssrc:
1719  * @packet: a valid BYE #GstRTCPPacket
1720  * @ssrc: an SSRC to add
1721  *
1722  * Add @ssrc to the BYE @packet.
1723  *
1724  * Returns: %TRUE if the ssrc was added. This function can return %FALSE if
1725  * the max MTU is exceeded or the number of sources blocks is greater than
1726  * #GST_RTCP_MAX_BYE_SSRC_COUNT.
1727  */
1728 gboolean
1729 gst_rtcp_packet_bye_add_ssrc (GstRTCPPacket * packet, guint32 ssrc)
1730 {
1731   guint8 *data;
1732   gsize maxsize;
1733   guint offset;
1734
1735   g_return_val_if_fail (packet != NULL, FALSE);
1736   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
1737   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1738   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
1739
1740   if (packet->count >= GST_RTCP_MAX_BYE_SSRC_COUNT)
1741     goto no_space;
1742
1743   data = packet->rtcp->map.data;
1744   maxsize = packet->rtcp->map.maxsize;
1745
1746   /* skip header */
1747   offset = packet->offset + 4;
1748
1749   /* move to current index */
1750   offset += (packet->count * 4);
1751
1752   if (offset + 4 >= maxsize)
1753     goto no_space;
1754
1755   /* increment packet count and length */
1756   packet->count++;
1757   data[packet->offset]++;
1758   packet->length += 1;
1759   data[packet->offset + 2] = (packet->length) >> 8;
1760   data[packet->offset + 3] = (packet->length) & 0xff;
1761
1762   packet->rtcp->map.size += 4;
1763
1764   /* move to new SSRC offset and write ssrc */
1765   data += offset;
1766   GST_WRITE_UINT32_BE (data, ssrc);
1767
1768   return TRUE;
1769
1770   /* ERRORS */
1771 no_space:
1772   {
1773     return FALSE;
1774   }
1775 }
1776
1777 /**
1778  * gst_rtcp_packet_bye_add_ssrcs:
1779  * @packet: a valid BYE #GstRTCPPacket
1780  * @ssrc: (array length=len) (transfer none): an array of SSRCs to add
1781  * @len: number of elements in @ssrc
1782  *
1783  * Adds @len SSRCs in @ssrc to BYE @packet.
1784  *
1785  * Returns: %TRUE if the all the SSRCs were added. This function can return %FALSE if
1786  * the max MTU is exceeded or the number of sources blocks is greater than
1787  * #GST_RTCP_MAX_BYE_SSRC_COUNT.
1788  */
1789 gboolean
1790 gst_rtcp_packet_bye_add_ssrcs (GstRTCPPacket * packet, guint32 * ssrc,
1791     guint len)
1792 {
1793   guint i;
1794   gboolean res;
1795
1796   g_return_val_if_fail (packet != NULL, FALSE);
1797   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
1798   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1799   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
1800
1801   res = TRUE;
1802   for (i = 0; i < len && res; i++) {
1803     res = gst_rtcp_packet_bye_add_ssrc (packet, ssrc[i]);
1804   }
1805   return res;
1806 }
1807
1808 /* get the offset in packet of the reason length */
1809 static guint
1810 get_reason_offset (GstRTCPPacket * packet)
1811 {
1812   guint offset;
1813
1814   /* get amount of sources plus header */
1815   offset = 1 + packet->count;
1816
1817   /* check that we don't go past the packet length */
1818   if (offset > packet->length)
1819     return 0;
1820
1821   /* scale to bytes */
1822   offset <<= 2;
1823   offset += packet->offset;
1824
1825   /* check if the packet is valid */
1826   if (offset + 1 > packet->rtcp->map.size)
1827     return 0;
1828
1829   return offset;
1830 }
1831
1832 /**
1833  * gst_rtcp_packet_bye_get_reason_len:
1834  * @packet: a valid BYE #GstRTCPPacket
1835  *
1836  * Get the length of the reason string.
1837  *
1838  * Returns: The length of the reason string or 0 when there is no reason string
1839  * present.
1840  */
1841 guint8
1842 gst_rtcp_packet_bye_get_reason_len (GstRTCPPacket * packet)
1843 {
1844   guint8 *data;
1845   guint roffset;
1846
1847   g_return_val_if_fail (packet != NULL, 0);
1848   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0);
1849   g_return_val_if_fail (packet->rtcp != NULL, 0);
1850   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
1851
1852   roffset = get_reason_offset (packet);
1853   if (roffset == 0)
1854     return 0;
1855
1856   data = packet->rtcp->map.data;
1857
1858   return data[roffset];
1859 }
1860
1861 /**
1862  * gst_rtcp_packet_bye_get_reason:
1863  * @packet: a valid BYE #GstRTCPPacket
1864  *
1865  * Get the reason in @packet.
1866  *
1867  * Returns: The reason for the BYE @packet or NULL if the packet did not contain
1868  * a reason string. The string must be freed with g_free() after usage.
1869  */
1870 gchar *
1871 gst_rtcp_packet_bye_get_reason (GstRTCPPacket * packet)
1872 {
1873   guint8 *data;
1874   guint roffset;
1875   guint8 len;
1876
1877   g_return_val_if_fail (packet != NULL, NULL);
1878   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, NULL);
1879   g_return_val_if_fail (packet->rtcp != NULL, NULL);
1880   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
1881
1882   roffset = get_reason_offset (packet);
1883   if (roffset == 0)
1884     return NULL;
1885
1886   data = packet->rtcp->map.data;
1887
1888   /* get length of reason string */
1889   len = data[roffset];
1890   if (len == 0)
1891     return NULL;
1892
1893   /* move to string */
1894   roffset += 1;
1895
1896   /* check if enough data to copy */
1897   if (roffset + len > packet->rtcp->map.size)
1898     return NULL;
1899
1900   return g_strndup ((gconstpointer) (data + roffset), len);
1901 }
1902
1903 /**
1904  * gst_rtcp_packet_bye_set_reason:
1905  * @packet: a valid BYE #GstRTCPPacket
1906  * @reason: a reason string
1907  *
1908  * Set the reason string to @reason in @packet.
1909  *
1910  * Returns: TRUE if the string could be set.
1911  */
1912 gboolean
1913 gst_rtcp_packet_bye_set_reason (GstRTCPPacket * packet, const gchar * reason)
1914 {
1915   guint8 *data;
1916   guint roffset;
1917   gsize maxsize;
1918   guint8 len, padded;
1919
1920   g_return_val_if_fail (packet != NULL, FALSE);
1921   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE);
1922   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
1923   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
1924
1925   if (reason == NULL)
1926     return TRUE;
1927
1928   len = strlen (reason);
1929   if (len == 0)
1930     return TRUE;
1931
1932   /* make room for the string before we get the offset */
1933   packet->length++;
1934
1935   roffset = get_reason_offset (packet);
1936   if (roffset == 0)
1937     goto no_space;
1938
1939   data = packet->rtcp->map.data;
1940   maxsize = packet->rtcp->map.maxsize;
1941
1942   /* we have 1 byte length and we need to pad to 4 bytes */
1943   padded = ((len + 1) + 3) & ~3;
1944
1945   /* we need enough space for the padded length */
1946   if (roffset + padded >= maxsize)
1947     goto no_space;
1948
1949   data[roffset] = len;
1950   memcpy (&data[roffset + 1], reason, len);
1951
1952   /* update packet length, we made room for 1 double word already */
1953   packet->length += (padded >> 2) - 1;
1954   data[packet->offset + 2] = (packet->length) >> 8;
1955   data[packet->offset + 3] = (packet->length) & 0xff;
1956
1957   packet->rtcp->map.size += padded;
1958
1959   return TRUE;
1960
1961   /* ERRORS */
1962 no_space:
1963   {
1964     packet->length--;
1965     return FALSE;
1966   }
1967 }
1968
1969 /**
1970  * gst_rtcp_packet_fb_get_sender_ssrc:
1971  * @packet: a valid RTPFB or PSFB #GstRTCPPacket
1972  *
1973  * Get the sender SSRC field of the RTPFB or PSFB @packet.
1974  *
1975  * Returns: the sender SSRC.
1976  */
1977 guint32
1978 gst_rtcp_packet_fb_get_sender_ssrc (GstRTCPPacket * packet)
1979 {
1980   guint8 *data;
1981   guint32 ssrc;
1982
1983   g_return_val_if_fail (packet != NULL, 0);
1984   g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
1985           packet->type == GST_RTCP_TYPE_PSFB), 0);
1986   g_return_val_if_fail (packet->rtcp != NULL, 0);
1987   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
1988
1989   data = packet->rtcp->map.data;
1990
1991   /* skip header */
1992   data += packet->offset + 4;
1993   ssrc = GST_READ_UINT32_BE (data);
1994
1995   return ssrc;
1996 }
1997
1998 /**
1999  * gst_rtcp_packet_fb_set_sender_ssrc:
2000  * @packet: a valid RTPFB or PSFB #GstRTCPPacket
2001  * @ssrc: a sender SSRC
2002  *
2003  * Set the sender SSRC field of the RTPFB or PSFB @packet.
2004  */
2005 void
2006 gst_rtcp_packet_fb_set_sender_ssrc (GstRTCPPacket * packet, guint32 ssrc)
2007 {
2008   guint8 *data;
2009
2010   g_return_if_fail (packet != NULL);
2011   g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
2012       packet->type == GST_RTCP_TYPE_PSFB);
2013   g_return_if_fail (packet->rtcp != NULL);
2014   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_READ);
2015
2016   data = packet->rtcp->map.data;
2017
2018   /* skip header */
2019   data += packet->offset + 4;
2020   GST_WRITE_UINT32_BE (data, ssrc);
2021 }
2022
2023 /**
2024  * gst_rtcp_packet_fb_get_media_ssrc:
2025  * @packet: a valid RTPFB or PSFB #GstRTCPPacket
2026  *
2027  * Get the media SSRC field of the RTPFB or PSFB @packet.
2028  *
2029  * Returns: the media SSRC.
2030  */
2031 guint32
2032 gst_rtcp_packet_fb_get_media_ssrc (GstRTCPPacket * packet)
2033 {
2034   guint8 *data;
2035   guint32 ssrc;
2036
2037   g_return_val_if_fail (packet != NULL, 0);
2038   g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
2039           packet->type == GST_RTCP_TYPE_PSFB), 0);
2040   g_return_val_if_fail (packet->rtcp != NULL, 0);
2041   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
2042
2043   data = packet->rtcp->map.data;
2044
2045   /* skip header and sender ssrc */
2046   data += packet->offset + 8;
2047   ssrc = GST_READ_UINT32_BE (data);
2048
2049   return ssrc;
2050 }
2051
2052 /**
2053  * gst_rtcp_packet_fb_set_media_ssrc:
2054  * @packet: a valid RTPFB or PSFB #GstRTCPPacket
2055  * @ssrc: a media SSRC
2056  *
2057  * Set the media SSRC field of the RTPFB or PSFB @packet.
2058  */
2059 void
2060 gst_rtcp_packet_fb_set_media_ssrc (GstRTCPPacket * packet, guint32 ssrc)
2061 {
2062   guint8 *data;
2063
2064   g_return_if_fail (packet != NULL);
2065   g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
2066       packet->type == GST_RTCP_TYPE_PSFB);
2067   g_return_if_fail (packet->rtcp != NULL);
2068   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
2069
2070   data = packet->rtcp->map.data;
2071
2072   /* skip header and sender ssrc */
2073   data += packet->offset + 8;
2074   GST_WRITE_UINT32_BE (data, ssrc);
2075 }
2076
2077 /**
2078  * gst_rtcp_packet_fb_get_type:
2079  * @packet: a valid RTPFB or PSFB #GstRTCPPacket
2080  *
2081  * Get the feedback message type of the FB @packet.
2082  *
2083  * Returns: The feedback message type.
2084  */
2085 GstRTCPFBType
2086 gst_rtcp_packet_fb_get_type (GstRTCPPacket * packet)
2087 {
2088   g_return_val_if_fail (packet != NULL, GST_RTCP_FB_TYPE_INVALID);
2089   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
2090       packet->type == GST_RTCP_TYPE_PSFB, GST_RTCP_FB_TYPE_INVALID);
2091
2092   return packet->count;
2093 }
2094
2095 /**
2096  * gst_rtcp_packet_fb_set_type:
2097  * @packet: a valid RTPFB or PSFB #GstRTCPPacket
2098  * @type: the #GstRTCPFBType to set
2099  *
2100  * Set the feedback message type of the FB @packet.
2101  */
2102 void
2103 gst_rtcp_packet_fb_set_type (GstRTCPPacket * packet, GstRTCPFBType type)
2104 {
2105   guint8 *data;
2106
2107   g_return_if_fail (packet != NULL);
2108   g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
2109       packet->type == GST_RTCP_TYPE_PSFB);
2110   g_return_if_fail (packet->rtcp != NULL);
2111   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
2112
2113   data = packet->rtcp->map.data;
2114
2115   data[packet->offset] = (data[packet->offset] & 0xe0) | type;
2116   packet->count = type;
2117 }
2118
2119 /**
2120  * gst_rtcp_ntp_to_unix:
2121  * @ntptime: an NTP timestamp
2122  *
2123  * Converts an NTP time to UNIX nanoseconds. @ntptime can typically be
2124  * the NTP time of an SR RTCP message and contains, in the upper 32 bits, the
2125  * number of seconds since 1900 and, in the lower 32 bits, the fractional
2126  * seconds. The resulting value will be the number of nanoseconds since 1970.
2127  *
2128  * Returns: the UNIX time for @ntptime in nanoseconds.
2129  */
2130 guint64
2131 gst_rtcp_ntp_to_unix (guint64 ntptime)
2132 {
2133   guint64 unixtime;
2134
2135   /* conversion from NTP timestamp (seconds since 1900) to seconds since
2136    * 1970. */
2137   unixtime = ntptime - (G_GUINT64_CONSTANT (2208988800) << 32);
2138   /* conversion to nanoseconds */
2139   unixtime =
2140       gst_util_uint64_scale (unixtime, GST_SECOND,
2141       (G_GINT64_CONSTANT (1) << 32));
2142
2143   return unixtime;
2144 }
2145
2146 /**
2147  * gst_rtcp_unix_to_ntp:
2148  * @unixtime: an UNIX timestamp in nanoseconds
2149  *
2150  * Converts a UNIX timestamp in nanoseconds to an NTP time. The caller should
2151  * pass a value with nanoseconds since 1970. The NTP time will, in the upper
2152  * 32 bits, contain the number of seconds since 1900 and, in the lower 32
2153  * bits, the fractional seconds. The resulting value can be used as an ntptime
2154  * for constructing SR RTCP packets.
2155  *
2156  * Returns: the NTP time for @unixtime.
2157  */
2158 guint64
2159 gst_rtcp_unix_to_ntp (guint64 unixtime)
2160 {
2161   guint64 ntptime;
2162
2163   /* convert clock time to NTP time. upper 32 bits should contain the seconds
2164    * and the lower 32 bits, the fractions of a second. */
2165   ntptime =
2166       gst_util_uint64_scale (unixtime, (G_GINT64_CONSTANT (1) << 32),
2167       GST_SECOND);
2168   /* conversion from UNIX timestamp (seconds since 1970) to NTP (seconds
2169    * since 1900). */
2170   ntptime += (G_GUINT64_CONSTANT (2208988800) << 32);
2171
2172   return ntptime;
2173 }
2174
2175 /**
2176  * gst_rtcp_sdes_type_to_name:
2177  * @type: a #GstRTCPSDESType
2178  *
2179  * Converts @type to the string equivalent. The string is typically used as a
2180  * key in a #GstStructure containing SDES items.
2181  *
2182  * Returns: the string equivalent of @type
2183  */
2184 const gchar *
2185 gst_rtcp_sdes_type_to_name (GstRTCPSDESType type)
2186 {
2187   const gchar *result;
2188
2189   switch (type) {
2190     case GST_RTCP_SDES_CNAME:
2191       result = "cname";
2192       break;
2193     case GST_RTCP_SDES_NAME:
2194       result = "name";
2195       break;
2196     case GST_RTCP_SDES_EMAIL:
2197       result = "email";
2198       break;
2199     case GST_RTCP_SDES_PHONE:
2200       result = "phone";
2201       break;
2202     case GST_RTCP_SDES_LOC:
2203       result = "location";
2204       break;
2205     case GST_RTCP_SDES_TOOL:
2206       result = "tool";
2207       break;
2208     case GST_RTCP_SDES_NOTE:
2209       result = "note";
2210       break;
2211     case GST_RTCP_SDES_PRIV:
2212       result = "priv";
2213       break;
2214     default:
2215       result = NULL;
2216       break;
2217   }
2218   return result;
2219 }
2220
2221 /**
2222  * gst_rtcp_sdes_name_to_type:
2223  * @name: a SDES name
2224  *
2225  * Convert @name into a @GstRTCPSDESType. @name is typically a key in a
2226  * #GstStructure containing SDES items.
2227  *
2228  * Returns: the #GstRTCPSDESType for @name or #GST_RTCP_SDES_PRIV when @name
2229  * is a private sdes item.
2230  */
2231 GstRTCPSDESType
2232 gst_rtcp_sdes_name_to_type (const gchar * name)
2233 {
2234   if (name == NULL || strlen (name) == 0)
2235     return GST_RTCP_SDES_INVALID;
2236
2237   if (strcmp ("cname", name) == 0)
2238     return GST_RTCP_SDES_CNAME;
2239
2240   if (strcmp ("name", name) == 0)
2241     return GST_RTCP_SDES_NAME;
2242
2243   if (strcmp ("email", name) == 0)
2244     return GST_RTCP_SDES_EMAIL;
2245
2246   if (strcmp ("phone", name) == 0)
2247     return GST_RTCP_SDES_PHONE;
2248
2249   if (strcmp ("location", name) == 0)
2250     return GST_RTCP_SDES_LOC;
2251
2252   if (strcmp ("tool", name) == 0)
2253     return GST_RTCP_SDES_TOOL;
2254
2255   if (strcmp ("note", name) == 0)
2256     return GST_RTCP_SDES_NOTE;
2257
2258   return GST_RTCP_SDES_PRIV;
2259 }
2260
2261 /**
2262  * gst_rtcp_packet_fb_get_fci_length:
2263  * @packet: a valid RTPFB or PSFB #GstRTCPPacket
2264  *
2265  * Get the length of the Feedback Control Information attached to a
2266  * RTPFB or PSFB @packet.
2267  *
2268  * Returns: The length of the FCI in 32-bit words.
2269  */
2270 guint16
2271 gst_rtcp_packet_fb_get_fci_length (GstRTCPPacket * packet)
2272 {
2273   guint8 *data;
2274
2275   g_return_val_if_fail (packet != NULL, 0);
2276   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
2277       packet->type == GST_RTCP_TYPE_PSFB, 0);
2278   g_return_val_if_fail (packet->rtcp != NULL, 0);
2279   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
2280
2281   data = packet->rtcp->map.data + packet->offset + 2;
2282
2283   return GST_READ_UINT16_BE (data) - 2;
2284 }
2285
2286 /**
2287  * gst_rtcp_packet_fb_set_fci_length:
2288  * @packet: a valid RTPFB or PSFB #GstRTCPPacket
2289  * @wordlen: Length of the FCI in 32-bit words
2290  *
2291  * Set the length of the Feedback Control Information attached to a
2292  * RTPFB or PSFB @packet.
2293  *
2294  * Returns: %TRUE if there was enough space in the packet to add this much FCI
2295  */
2296 gboolean
2297 gst_rtcp_packet_fb_set_fci_length (GstRTCPPacket * packet, guint16 wordlen)
2298 {
2299   guint8 *data;
2300
2301   g_return_val_if_fail (packet != NULL, FALSE);
2302   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
2303       packet->type == GST_RTCP_TYPE_PSFB, FALSE);
2304   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
2305   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
2306
2307   if (packet->rtcp->map.maxsize < packet->offset + ((wordlen + 3) * 4))
2308     return FALSE;
2309
2310   data = packet->rtcp->map.data + packet->offset + 2;
2311   wordlen += 2;
2312   GST_WRITE_UINT16_BE (data, wordlen);
2313
2314   packet->rtcp->map.size = packet->offset + ((wordlen + 1) * 4);
2315
2316   return TRUE;
2317 }
2318
2319 /**
2320  * gst_rtcp_packet_fb_get_fci:
2321  * @packet: a valid RTPFB or PSFB #GstRTCPPacket
2322  *
2323  * Get the Feedback Control Information attached to a RTPFB or PSFB @packet.
2324  *
2325  * Returns: a pointer to the FCI
2326  */
2327 guint8 *
2328 gst_rtcp_packet_fb_get_fci (GstRTCPPacket * packet)
2329 {
2330   guint8 *data;
2331
2332   g_return_val_if_fail (packet != NULL, NULL);
2333   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
2334       packet->type == GST_RTCP_TYPE_PSFB, NULL);
2335   g_return_val_if_fail (packet->rtcp != NULL, NULL);
2336   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
2337
2338   data = packet->rtcp->map.data + packet->offset;
2339
2340   if (GST_READ_UINT16_BE (data + 2) <= 2)
2341     return NULL;
2342
2343   return data + 12;
2344 }
2345
2346 /**
2347  * gst_rtcp_packet_app_set_subtype:
2348  * @packet: a valid APP #GstRTCPPacket
2349  * @subtype: subtype of the packet
2350  *
2351  * Set the subtype field of the APP @packet.
2352  *
2353  * Since: 1.10
2354  **/
2355 void
2356 gst_rtcp_packet_app_set_subtype (GstRTCPPacket * packet, guint8 subtype)
2357 {
2358   guint8 *data;
2359
2360   g_return_if_fail (packet != NULL);
2361   g_return_if_fail (packet->type == GST_RTCP_TYPE_APP);
2362   g_return_if_fail (packet->rtcp != NULL);
2363   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
2364
2365   data = packet->rtcp->map.data + packet->offset;
2366   data[0] = (data[0] & 0xe0) | subtype;
2367 }
2368
2369 /**
2370  * gst_rtcp_packet_app_get_subtype:
2371  * @packet: a valid APP #GstRTCPPacket
2372  *
2373  * Get the subtype field of the APP @packet.
2374  *
2375  * Returns: The subtype.
2376  *
2377  * Since: 1.10
2378  */
2379 guint8
2380 gst_rtcp_packet_app_get_subtype (GstRTCPPacket * packet)
2381 {
2382   guint8 *data;
2383
2384   g_return_val_if_fail (packet != NULL, 0);
2385   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, 0);
2386   g_return_val_if_fail (packet->rtcp != NULL, 0);
2387   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
2388
2389   data = packet->rtcp->map.data + packet->offset;
2390
2391   return data[0] & 0x1f;
2392 }
2393
2394 /**
2395  * gst_rtcp_packet_app_set_ssrc:
2396  * @packet: a valid APP #GstRTCPPacket
2397  * @ssrc: SSRC/CSRC of the packet
2398  *
2399  * Set the SSRC/CSRC field of the APP @packet.
2400  *
2401  * Since: 1.10
2402  */
2403 void
2404 gst_rtcp_packet_app_set_ssrc (GstRTCPPacket * packet, guint32 ssrc)
2405 {
2406   guint8 *data;
2407
2408   g_return_if_fail (packet != NULL);
2409   g_return_if_fail (packet->type == GST_RTCP_TYPE_APP);
2410   g_return_if_fail (packet->rtcp != NULL);
2411   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
2412
2413   data = packet->rtcp->map.data + packet->offset + 4;
2414   GST_WRITE_UINT32_BE (data, ssrc);
2415 }
2416
2417 /**
2418  * gst_rtcp_packet_app_get_ssrc:
2419  * @packet: a valid APP #GstRTCPPacket
2420  *
2421  * Get the SSRC/CSRC field of the APP @packet.
2422  *
2423  * Returns: The SSRC/CSRC.
2424  *
2425  * Since: 1.10
2426  */
2427 guint32
2428 gst_rtcp_packet_app_get_ssrc (GstRTCPPacket * packet)
2429 {
2430   guint8 *data;
2431
2432   g_return_val_if_fail (packet != NULL, 0);
2433   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, 0);
2434   g_return_val_if_fail (packet->rtcp != NULL, 0);
2435   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
2436
2437   data = packet->rtcp->map.data + packet->offset + 4;
2438
2439   return GST_READ_UINT32_BE (data);
2440 }
2441
2442 /**
2443  * gst_rtcp_packet_app_set_name:
2444  * @packet: a valid APP #GstRTCPPacket
2445  * @name: 4-byte ASCII name
2446  *
2447  * Set the name field of the APP @packet.
2448  *
2449  * Since: 1.10
2450  */
2451 void
2452 gst_rtcp_packet_app_set_name (GstRTCPPacket * packet, const gchar * name)
2453 {
2454   guint8 *data;
2455
2456   g_return_if_fail (packet != NULL);
2457   g_return_if_fail (packet->type == GST_RTCP_TYPE_APP);
2458   g_return_if_fail (packet->rtcp != NULL);
2459   g_return_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE);
2460
2461   data = packet->rtcp->map.data + packet->offset + 8;
2462   memcpy (data, name, 4);
2463 }
2464
2465 /**
2466  * gst_rtcp_packet_app_get_name:
2467  * @packet: a valid APP #GstRTCPPacket
2468  *
2469  * Get the name field of the APP @packet.
2470  *
2471  * Returns: The 4-byte name field, not zero-terminated.
2472  *
2473  * Since: 1.10
2474  */
2475 const gchar *
2476 gst_rtcp_packet_app_get_name (GstRTCPPacket * packet)
2477 {
2478   g_return_val_if_fail (packet != NULL, NULL);
2479   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, NULL);
2480   g_return_val_if_fail (packet->rtcp != NULL, NULL);
2481   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
2482
2483   return (const gchar *) &packet->rtcp->map.data[packet->offset + 8];
2484 }
2485
2486 /**
2487  * gst_rtcp_packet_app_get_data_length:
2488  * @packet: a valid APP #GstRTCPPacket
2489  *
2490  * Get the length of the application-dependent data attached to an APP
2491  * @packet.
2492  *
2493  * Returns: The length of data in 32-bit words.
2494  *
2495  * Since: 1.10
2496  */
2497 guint16
2498 gst_rtcp_packet_app_get_data_length (GstRTCPPacket * packet)
2499 {
2500   guint8 *data;
2501
2502   g_return_val_if_fail (packet != NULL, 0);
2503   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, 0);
2504   g_return_val_if_fail (packet->rtcp != NULL, 0);
2505   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
2506
2507   data = packet->rtcp->map.data + packet->offset + 2;
2508
2509   return GST_READ_UINT16_BE (data) - 2;
2510 }
2511
2512 /**
2513  * gst_rtcp_packet_app_set_data_length:
2514  * @packet: a valid APP #GstRTCPPacket
2515  * @wordlen: Length of the data in 32-bit words
2516  *
2517  * Set the length of the application-dependent data attached to an APP
2518  * @packet.
2519  *
2520  * Returns: %TRUE if there was enough space in the packet to add this much
2521  * data.
2522  *
2523  * Since: 1.10
2524  */
2525 gboolean
2526 gst_rtcp_packet_app_set_data_length (GstRTCPPacket * packet, guint16 wordlen)
2527 {
2528   guint8 *data;
2529
2530   g_return_val_if_fail (packet != NULL, FALSE);
2531   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, FALSE);
2532   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
2533   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_WRITE, FALSE);
2534
2535   if (packet->rtcp->map.maxsize < packet->offset + ((wordlen + 3) * 4))
2536     return FALSE;
2537
2538   data = packet->rtcp->map.data + packet->offset + 2;
2539   wordlen += 2;
2540   GST_WRITE_UINT16_BE (data, wordlen);
2541
2542   packet->rtcp->map.size = packet->offset + ((wordlen + 1) * 4);
2543
2544   return TRUE;
2545 }
2546
2547 /**
2548  * gst_rtcp_packet_app_get_data:
2549  * @packet: a valid APP #GstRTCPPacket
2550  *
2551  * Get the application-dependent data attached to a RTPFB or PSFB @packet.
2552  *
2553  * Returns: A pointer to the data
2554  *
2555  * Since: 1.10
2556  */
2557 guint8 *
2558 gst_rtcp_packet_app_get_data (GstRTCPPacket * packet)
2559 {
2560   guint8 *data;
2561
2562   g_return_val_if_fail (packet != NULL, NULL);
2563   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_APP, NULL);
2564   g_return_val_if_fail (packet->rtcp != NULL, NULL);
2565   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, NULL);
2566
2567   data = packet->rtcp->map.data + packet->offset;
2568
2569   if (GST_READ_UINT16_BE (data + 2) <= 2)
2570     return NULL;
2571
2572   return data + 12;
2573 }
2574
2575 /**
2576  * gst_rtcp_packet_xr_get_ssrc:
2577  * @packet: a valid XR #GstRTCPPacket
2578  *
2579  * Get the ssrc field of the XR @packet.
2580  *
2581  * Returns: the ssrc.
2582  *
2583  * Since: 1.16
2584  */
2585 guint32
2586 gst_rtcp_packet_xr_get_ssrc (GstRTCPPacket * packet)
2587 {
2588   guint8 *data;
2589   guint32 ssrc;
2590
2591   g_return_val_if_fail (packet != NULL, 0);
2592   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR, 0);
2593   g_return_val_if_fail (packet->rtcp != NULL, 0);
2594   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
2595
2596   data = packet->rtcp->map.data;
2597
2598   /* skip header */
2599   data += packet->offset + 4;
2600   ssrc = GST_READ_UINT32_BE (data);
2601
2602   return ssrc;
2603 }
2604
2605 /**
2606  * gst_rtcp_packet_xr_first_rb:
2607  * @packet: a valid XR #GstRTCPPacket
2608  *
2609  * Move to the first extended report block in XR @packet.
2610  *
2611  * Returns: TRUE if there was a first extended report block.
2612  *
2613  * Since: 1.16
2614  */
2615 gboolean
2616 gst_rtcp_packet_xr_first_rb (GstRTCPPacket * packet)
2617 {
2618   guint16 block_len;
2619   guint offset, len;
2620
2621   g_return_val_if_fail (packet != NULL, FALSE);
2622   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR, FALSE);
2623
2624   if (packet->length < 2)
2625     return FALSE;
2626
2627   /* skip header + ssrc */
2628   packet->item_offset = 8;
2629
2630   /* Validate the block's length */
2631   block_len = gst_rtcp_packet_xr_get_block_length (packet);
2632   offset = 8 + (block_len * 1) + 4;
2633
2634   len = packet->length << 2;
2635
2636   if (offset >= len) {
2637     packet->item_offset = 0;
2638     return FALSE;
2639   }
2640
2641   return TRUE;
2642 }
2643
2644 /**
2645  * gst_rtcp_packet_xr_next_rb:
2646  * @packet: a valid XR #GstRTCPPacket
2647  *
2648  * Move to the next extended report block in XR @packet.
2649  *
2650  * Returns: TRUE if there was a next extended report block.
2651  *
2652  * Since: 1.16
2653  */
2654 gboolean
2655 gst_rtcp_packet_xr_next_rb (GstRTCPPacket * packet)
2656 {
2657   guint16 block_len;
2658   guint offset;
2659   guint len;
2660
2661   g_return_val_if_fail (packet != NULL, FALSE);
2662   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR, FALSE);
2663   g_return_val_if_fail (packet->rtcp != NULL, FALSE);
2664   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, FALSE);
2665
2666   block_len = gst_rtcp_packet_xr_get_block_length (packet);
2667
2668   offset = packet->item_offset;
2669   offset += (block_len + 1) * 4;
2670
2671   /* don't overrun */
2672   len = (packet->length << 2);
2673
2674   if (offset >= len)
2675     return FALSE;
2676
2677   packet->item_offset = offset;
2678
2679   return TRUE;
2680 }
2681
2682 /**
2683  * gst_rtcp_packet_xr_get_block_type:
2684  * @packet: a valid XR #GstRTCPPacket
2685  *
2686  * Get the extended report block type of the XR @packet.
2687  *
2688  * Returns: The extended report block type.
2689  *
2690  * Since: 1.16
2691  */
2692 GstRTCPXRType
2693 gst_rtcp_packet_xr_get_block_type (GstRTCPPacket * packet)
2694 {
2695   guint8 *data;
2696   guint8 type;
2697   GstRTCPXRType xr_type = GST_RTCP_XR_TYPE_INVALID;
2698
2699   g_return_val_if_fail (packet != NULL, GST_RTCP_XR_TYPE_INVALID);
2700   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR,
2701       GST_RTCP_XR_TYPE_INVALID);
2702   g_return_val_if_fail (packet->rtcp != NULL, GST_RTCP_XR_TYPE_INVALID);
2703   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ,
2704       GST_RTCP_XR_TYPE_INVALID);
2705   g_return_val_if_fail (packet->length >= (packet->item_offset >> 2),
2706       GST_RTCP_XR_TYPE_INVALID);
2707
2708   data = packet->rtcp->map.data;
2709
2710   /* skip header + current item offset */
2711   data += packet->offset + packet->item_offset;
2712
2713   /* XR block type can be defined more than described in RFC3611.
2714    * If undefined type is detected, user might want to know. */
2715   type = GST_READ_UINT8 (data);
2716   switch (type) {
2717     case GST_RTCP_XR_TYPE_LRLE:
2718     case GST_RTCP_XR_TYPE_DRLE:
2719     case GST_RTCP_XR_TYPE_PRT:
2720     case GST_RTCP_XR_TYPE_RRT:
2721     case GST_RTCP_XR_TYPE_DLRR:
2722     case GST_RTCP_XR_TYPE_SSUMM:
2723     case GST_RTCP_XR_TYPE_VOIP_METRICS:
2724       xr_type = type;
2725       break;
2726     default:
2727       GST_DEBUG ("got 0x%x type, but that might be out of scope of RFC3611",
2728           type);
2729       break;
2730   }
2731
2732   return xr_type;
2733 }
2734
2735 /**
2736  * gst_rtcp_packet_xr_get_block_length:
2737  * @packet: a valid XR #GstRTCPPacket
2738  *
2739  * Returns: The number of 32-bit words containing type-specific block
2740  *          data from @packet.
2741  *
2742  * Since: 1.16
2743  */
2744 guint16
2745 gst_rtcp_packet_xr_get_block_length (GstRTCPPacket * packet)
2746 {
2747   guint8 *data;
2748   guint16 len;
2749
2750   g_return_val_if_fail (packet != NULL, 0);
2751   g_return_val_if_fail (packet->type == GST_RTCP_TYPE_XR, 0);
2752   g_return_val_if_fail (packet->rtcp != NULL, 0);
2753   g_return_val_if_fail (packet->rtcp->map.flags & GST_MAP_READ, 0);
2754   g_return_val_if_fail (packet->length >= (packet->item_offset >> 2), 0);
2755
2756   data = packet->rtcp->map.data;
2757   data += packet->offset + packet->item_offset + 2;
2758
2759   len = GST_READ_UINT16_BE (data);
2760
2761   return len;
2762 }
2763
2764 /**
2765  * gst_rtcp_packet_xr_get_rle_info:
2766  * @packet: a valid XR #GstRTCPPacket which is Loss RLE or Duplicate RLE report.
2767  * @ssrc: the SSRC of the RTP data packet source being reported upon by this report block.
2768  * @thinning: the amount of thinning performed on the sequence number space.
2769  * @begin_seq: the first sequence number that this block reports on.
2770  * @end_seq: the last sequence number that this block reports on plus one.
2771  * @chunk_count: the number of chunks calculated by block length.
2772  *
2773  * Parse the extended report block for Loss RLE and Duplicated LRE block type.
2774  *
2775  * Returns: %TRUE if the report block is correctly parsed.
2776  *
2777  * Since: 1.16
2778  */
2779 gboolean
2780 gst_rtcp_packet_xr_get_rle_info (GstRTCPPacket * packet, guint32 * ssrc,
2781     guint8 * thinning, guint16 * begin_seq, guint16 * end_seq,
2782     guint32 * chunk_count)
2783 {
2784   guint8 *data;
2785   guint16 block_len;
2786
2787   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
2788       GST_RTCP_XR_TYPE_LRLE
2789       || gst_rtcp_packet_xr_get_block_type (packet) == GST_RTCP_XR_TYPE_DRLE,
2790       FALSE);
2791
2792   block_len = gst_rtcp_packet_xr_get_block_length (packet);
2793   if (block_len < 3)
2794     return FALSE;
2795
2796   if (chunk_count)
2797     *chunk_count = (block_len - 2) * 2;
2798
2799   data = packet->rtcp->map.data;
2800   /* skip header + current item offset */
2801   data += packet->offset + packet->item_offset;
2802
2803   if (thinning)
2804     *thinning = data[1] & 0x0f;
2805
2806   /* go to ssrc */
2807   data += 4;
2808   if (ssrc)
2809     *ssrc = GST_READ_UINT32_BE (data);
2810   /* go to begin_seq */
2811   data += 4;
2812   if (begin_seq)
2813     *begin_seq = ((data[0] << 8) | data[1]);
2814   /* go to end_seq */
2815   data += 2;
2816   if (end_seq)
2817     *end_seq = ((data[0] << 8) | data[1]);
2818
2819   return TRUE;
2820 }
2821
2822 /**
2823  * gst_rtcp_packet_xr_get_rle_nth_chunk:
2824  * @packet: a valid XR #GstRTCPPacket which is Loss RLE or Duplicate RLE report.
2825  * @nth: the index of chunk to retrieve.
2826  * @chunk: the @nth chunk.
2827  *
2828  * Retrieve actual chunk data.
2829  *
2830  * Returns: %TRUE if the report block returns chunk correctly.
2831  *
2832  * Since: 1.16
2833  */
2834 gboolean
2835 gst_rtcp_packet_xr_get_rle_nth_chunk (GstRTCPPacket * packet,
2836     guint nth, guint16 * chunk)
2837 {
2838   guint32 chunk_count;
2839   guint8 *data;
2840
2841   if (!gst_rtcp_packet_xr_get_rle_info (packet, NULL, NULL, NULL, NULL,
2842           &chunk_count))
2843     g_return_val_if_reached (FALSE);
2844
2845   if (nth >= chunk_count)
2846     return FALSE;
2847
2848   data = packet->rtcp->map.data;
2849   /* skip header + current item offset */
2850   data += packet->offset + packet->item_offset;
2851
2852   /* skip ssrc, {begin,end}_seq */
2853   data += 12;
2854
2855   /* goto nth chunk */
2856   data += nth * 2;
2857   if (chunk)
2858     *chunk = ((data[0] << 8) | data[1]);
2859
2860   return TRUE;
2861 }
2862
2863 /**
2864  * gst_rtcp_packet_xr_get_prt_info:
2865  * @packet: a valid XR #GstRTCPPacket which has a Packet Receipt Times Report Block
2866  * @ssrc: the SSRC of the RTP data packet source being reported upon by this report block.
2867  * @thinning: the amount of thinning performed on the sequence number space.
2868  * @begin_seq: the first sequence number that this block reports on.
2869  * @end_seq: the last sequence number that this block reports on plus one.
2870  *
2871  * Parse the Packet Recept Times Report Block from a XR @packet
2872  *
2873  * Returns: %TRUE if the report block is correctly parsed.
2874  *
2875  * Since: 1.16
2876  */
2877 gboolean
2878 gst_rtcp_packet_xr_get_prt_info (GstRTCPPacket * packet,
2879     guint32 * ssrc, guint8 * thinning, guint16 * begin_seq, guint16 * end_seq)
2880 {
2881   guint8 *data;
2882   guint16 block_len;
2883
2884   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
2885       GST_RTCP_XR_TYPE_PRT, FALSE);
2886
2887   block_len = gst_rtcp_packet_xr_get_block_length (packet);
2888   if (block_len < 3)
2889     return FALSE;
2890
2891   data = packet->rtcp->map.data;
2892   /* skip header + current item offset */
2893   data += packet->offset + packet->item_offset;
2894
2895   if (thinning)
2896     *thinning = data[1] & 0x0f;
2897
2898   /* go to ssrc */
2899   data += 4;
2900   if (ssrc)
2901     *ssrc = GST_READ_UINT32_BE (data);
2902
2903   /* go to begin_seq */
2904   data += 4;
2905   if (begin_seq)
2906     *begin_seq = ((data[0] << 8) | data[1]);
2907   /* go to end_seq */
2908   data += 2;
2909   if (end_seq)
2910     *end_seq = ((data[0] << 8) | data[1]);
2911
2912   return TRUE;
2913 }
2914
2915 /**
2916  * gst_rtcp_packet_xr_get_prt_by_seq:
2917  * @packet: a valid XR #GstRTCPPacket which has the Packet Recept Times Report Block.
2918  * @seq: the sequence to retrieve the time.
2919  * @receipt_time: the packet receipt time of @seq.
2920  *
2921  * Retrieve the packet receipt time of @seq which ranges in [begin_seq, end_seq).
2922  *
2923  * Returns: %TRUE if the report block returns the receipt time correctly.
2924  *
2925  * Since: 1.16
2926  */
2927 gboolean
2928 gst_rtcp_packet_xr_get_prt_by_seq (GstRTCPPacket * packet,
2929     guint16 seq, guint32 * receipt_time)
2930 {
2931   guint16 begin_seq, end_seq;
2932   guint8 *data;
2933
2934   if (!gst_rtcp_packet_xr_get_prt_info (packet, NULL, NULL, &begin_seq,
2935           &end_seq))
2936     g_return_val_if_reached (FALSE);
2937
2938   if (seq >= end_seq || seq < begin_seq)
2939     return FALSE;
2940
2941   data = packet->rtcp->map.data;
2942   /* skip header + current item offset */
2943   data += packet->offset + packet->item_offset;
2944
2945   /* skip ssrc, {begin,end}_seq */
2946   data += 12;
2947
2948   data += (seq - begin_seq) * 4;
2949
2950   if (receipt_time)
2951     *receipt_time = GST_READ_UINT32_BE (data);
2952
2953   return TRUE;
2954 }
2955
2956 /**
2957  * gst_rtcp_packet_xr_get_rrt:
2958  * @packet: a valid XR #GstRTCPPacket which has the Receiver Reference Time.
2959  * @timestamp: NTP timestamp
2960  *
2961  * Returns: %TRUE if the report block returns the reference time correctly.
2962  *
2963  * Since: 1.16
2964  */
2965 gboolean
2966 gst_rtcp_packet_xr_get_rrt (GstRTCPPacket * packet, guint64 * timestamp)
2967 {
2968   guint8 *data;
2969
2970   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
2971       GST_RTCP_XR_TYPE_RRT, FALSE);
2972
2973   if (gst_rtcp_packet_xr_get_block_length (packet) != 2)
2974     return FALSE;
2975
2976   data = packet->rtcp->map.data;
2977   /* skip header + current item offset */
2978   data += packet->offset + packet->item_offset;
2979
2980   /* skip block header */
2981   data += 4;
2982   if (timestamp)
2983     *timestamp = GST_READ_UINT64_BE (data);
2984
2985   return TRUE;
2986 }
2987
2988 /**
2989  * gst_rtcp_packet_xr_get_dlrr_block:
2990  * @packet: a valid XR #GstRTCPPacket which has DLRR Report Block.
2991  * @nth: the index of sub-block to retrieve.
2992  * @ssrc: the SSRC of the receiver.
2993  * @last_rr: the last receiver reference timestamp of @ssrc.
2994  * @delay: the delay since @last_rr.
2995  *
2996  * Parse the extended report block for DLRR report block type.
2997  *
2998  * Returns: %TRUE if the report block is correctly parsed.
2999  *
3000  * Since: 1.16
3001  */
3002 gboolean
3003 gst_rtcp_packet_xr_get_dlrr_block (GstRTCPPacket * packet,
3004     guint nth, guint32 * ssrc, guint32 * last_rr, guint32 * delay)
3005 {
3006   guint8 *data;
3007   guint16 block_len;
3008
3009   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3010       GST_RTCP_XR_TYPE_DLRR, FALSE);
3011
3012   block_len = gst_rtcp_packet_xr_get_block_length (packet);
3013
3014   if (nth * 3 >= block_len)
3015     return FALSE;
3016
3017   data = packet->rtcp->map.data;
3018   /* skip header + current item offset */
3019   data += packet->offset + packet->item_offset;
3020   /* skip block header */
3021   data += 4;
3022   data += nth * 3 * 4;
3023
3024   if (ssrc)
3025     *ssrc = GST_READ_UINT32_BE (data);
3026
3027   data += 4;
3028   if (last_rr)
3029     *last_rr = GST_READ_UINT32_BE (data);
3030
3031   data += 4;
3032   if (delay)
3033     *delay = GST_READ_UINT32_BE (data);
3034
3035   return TRUE;
3036 }
3037
3038 /**
3039  * gst_rtcp_packet_xr_get_summary_info:
3040  * @packet: a valid XR #GstRTCPPacket which has Statics Summary Report Block.
3041  * @ssrc: the SSRC of the source.
3042  * @begin_seq: the first sequence number that this block reports on.
3043  * @end_seq: the last sequence number that this block reports on plus one.
3044  *
3045  * Extract a basic information from static summary report block of XR @packet.
3046  *
3047  * Returns: %TRUE if the report block is correctly parsed.
3048  *
3049  * Since: 1.16
3050  */
3051 gboolean
3052 gst_rtcp_packet_xr_get_summary_info (GstRTCPPacket * packet, guint32 * ssrc,
3053     guint16 * begin_seq, guint16 * end_seq)
3054 {
3055   guint8 *data;
3056
3057   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3058       GST_RTCP_XR_TYPE_SSUMM, FALSE);
3059
3060   if (gst_rtcp_packet_xr_get_block_length (packet) != 9)
3061     return FALSE;
3062
3063   data = packet->rtcp->map.data;
3064   /* skip header + current item offset */
3065   data += packet->offset + packet->item_offset;
3066   /* skip block header */
3067   data += 4;
3068
3069   if (ssrc)
3070     *ssrc = GST_READ_UINT32_BE (data);
3071
3072   /* go to begin_seq */
3073   data += 4;
3074   if (begin_seq)
3075     *begin_seq = ((data[0] << 8) | data[1]);
3076   /* go to end_seq */
3077   data += 2;
3078   if (end_seq)
3079     *end_seq = ((data[0] << 8) | data[1]);
3080
3081   return TRUE;
3082 }
3083
3084 /**
3085  * gst_rtcp_packet_xr_get_summary_pkt:
3086  * @packet: a valid XR #GstRTCPPacket which has Statics Summary Report Block.
3087  * @lost_packets: the number of lost packets between begin_seq and end_seq.
3088  * @dup_packets: the number of duplicate packets between begin_seq and end_seq.
3089  *
3090  * Get the number of lost or duplicate packets. If the flag in a block header
3091  * is set as zero, @lost_packets or @dup_packets will be zero.
3092  *
3093  * Returns: %TRUE if the report block is correctly parsed.
3094  *
3095  * Since: 1.16
3096  */
3097 gboolean
3098 gst_rtcp_packet_xr_get_summary_pkt (GstRTCPPacket * packet,
3099     guint32 * lost_packets, guint32 * dup_packets)
3100 {
3101   guint8 *data;
3102   guint8 flags;
3103
3104   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3105       GST_RTCP_XR_TYPE_SSUMM, FALSE);
3106   if (gst_rtcp_packet_xr_get_block_length (packet) != 9)
3107     return FALSE;
3108
3109   data = packet->rtcp->map.data;
3110   /* skip header + current item offset */
3111   data += packet->offset + packet->item_offset;
3112   flags = data[1];
3113   /* skip block header,ssrc, {begin,end}_seq */
3114   data += 12;
3115
3116   if (lost_packets) {
3117     if (!(flags & 0x80))
3118       *lost_packets = 0;
3119     else
3120       *lost_packets = GST_READ_UINT32_BE (data);
3121   }
3122
3123   data += 4;
3124   if (dup_packets) {
3125     if (!(flags & 0x40))
3126       *dup_packets = 0;
3127     else
3128       *dup_packets = GST_READ_UINT32_BE (data);
3129   }
3130
3131   return TRUE;
3132 }
3133
3134 /**
3135  * gst_rtcp_packet_xr_get_summary_jitter:
3136  * @packet: a valid XR #GstRTCPPacket which has Statics Summary Report Block.
3137  * @min_jitter: the minimum relative transit time between two sequences.
3138  * @max_jitter: the maximum relative transit time between two sequences.
3139  * @mean_jitter: the mean relative transit time between two sequences.
3140  * @dev_jitter: the standard deviation of the relative transit time between two sequences.
3141  *
3142  * Extract jitter information from the statistics summary. If the jitter flag in
3143  * a block header is set as zero, all of jitters will be zero.
3144  *
3145  * Returns: %TRUE if the report block is correctly parsed.
3146  *
3147  * Since: 1.16
3148  */
3149 gboolean
3150 gst_rtcp_packet_xr_get_summary_jitter (GstRTCPPacket * packet,
3151     guint32 * min_jitter, guint32 * max_jitter,
3152     guint32 * mean_jitter, guint32 * dev_jitter)
3153 {
3154   guint8 *data;
3155   guint8 flags;
3156
3157   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3158       GST_RTCP_XR_TYPE_SSUMM, FALSE);
3159
3160   if (gst_rtcp_packet_xr_get_block_length (packet) != 9)
3161     return FALSE;
3162
3163   data = packet->rtcp->map.data;
3164   /* skip header + current item offset */
3165   data += packet->offset + packet->item_offset;
3166   flags = data[1];
3167
3168   if (!(flags & 0x20)) {
3169     if (min_jitter)
3170       *min_jitter = 0;
3171     if (max_jitter)
3172       *max_jitter = 0;
3173     if (mean_jitter)
3174       *mean_jitter = 0;
3175     if (dev_jitter)
3176       *dev_jitter = 0;
3177
3178     return TRUE;
3179   }
3180
3181   /* skip block header,ssrc, {begin,end}_seq, packets */
3182   data += 20;
3183   if (min_jitter)
3184     *min_jitter = GST_READ_UINT32_BE (data);
3185
3186   data += 4;
3187   if (max_jitter)
3188     *max_jitter = GST_READ_UINT32_BE (data);
3189
3190   data += 4;
3191   if (mean_jitter)
3192     *mean_jitter = GST_READ_UINT32_BE (data);
3193
3194   data += 4;
3195   if (dev_jitter)
3196     *dev_jitter = GST_READ_UINT32_BE (data);
3197
3198   return TRUE;
3199 }
3200
3201 /**
3202  * gst_rtcp_packet_xr_get_summary_ttl:
3203  * @packet: a valid XR #GstRTCPPacket which has Statics Summary Report Block.
3204  * @is_ipv4: the flag to indicate that the return values are ipv4 ttl or ipv6 hop limits.
3205  * @min_ttl: the minimum TTL or Hop Limit value of data packets between two sequences.
3206  * @max_ttl: the maximum TTL or Hop Limit value of data packets between two sequences.
3207  * @mean_ttl: the mean TTL or Hop Limit value of data packets between two sequences.
3208  * @dev_ttl: the standard deviation of the TTL or Hop Limit value of data packets between two sequences.
3209  *
3210  * Extract the value of ttl for ipv4, or hop limit for ipv6.
3211  *
3212  * Returns: %TRUE if the report block is correctly parsed.
3213  *
3214  * Since: 1.16
3215  */
3216 gboolean
3217 gst_rtcp_packet_xr_get_summary_ttl (GstRTCPPacket * packet,
3218     gboolean * is_ipv4, guint8 * min_ttl, guint8 * max_ttl, guint8 * mean_ttl,
3219     guint8 * dev_ttl)
3220 {
3221   guint8 *data;
3222   guint8 flags;
3223
3224   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3225       GST_RTCP_XR_TYPE_SSUMM, FALSE);
3226
3227   if (gst_rtcp_packet_xr_get_block_length (packet) != 9)
3228     return FALSE;
3229
3230   data = packet->rtcp->map.data;
3231   /* skip header + current item offset */
3232   data += packet->offset + packet->item_offset;
3233   flags = (data[1] & 0x18) >> 3;
3234
3235   if (flags > 2)
3236     return FALSE;
3237
3238   if (is_ipv4)
3239     *is_ipv4 = (flags == 1);
3240
3241   /* skip block header,ssrc, {begin,end}_seq, packets, jitters */
3242   data += 36;
3243   if (min_ttl)
3244     *min_ttl = data[0];
3245
3246   if (max_ttl)
3247     *max_ttl = data[1];
3248
3249   if (mean_ttl)
3250     *mean_ttl = data[2];
3251
3252   if (dev_ttl)
3253     *dev_ttl = data[3];
3254
3255   return TRUE;
3256 }
3257
3258 /**
3259  * gst_rtcp_packet_xr_get_voip_metrics_ssrc:
3260  * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
3261  * @ssrc: the SSRC of source
3262  *
3263  * Returns: %TRUE if the report block is correctly parsed.
3264  *
3265  * Since: 1.16
3266  */
3267 gboolean
3268 gst_rtcp_packet_xr_get_voip_metrics_ssrc (GstRTCPPacket * packet,
3269     guint32 * ssrc)
3270 {
3271   guint8 *data;
3272
3273   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3274       GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
3275
3276   if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
3277     return FALSE;
3278
3279   data = packet->rtcp->map.data;
3280   /* skip header + current item offset */
3281   data += packet->offset + packet->item_offset;
3282
3283   /* skip block header */
3284   data += 4;
3285   if (ssrc)
3286     *ssrc = GST_READ_UINT32_BE (data);
3287
3288   return TRUE;
3289 }
3290
3291 /**
3292  * gst_rtcp_packet_xr_get_voip_packet_metrics:
3293  * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
3294  * @loss_rate: the fraction of RTP data packets from the source lost.
3295  * @discard_rate: the fraction of RTP data packets from the source that have been discarded.
3296  *
3297  * Returns: %TRUE if the report block is correctly parsed.
3298  *
3299  * Since: 1.16
3300  */
3301 gboolean
3302 gst_rtcp_packet_xr_get_voip_packet_metrics (GstRTCPPacket * packet,
3303     guint8 * loss_rate, guint8 * discard_rate)
3304 {
3305   guint8 *data;
3306
3307   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3308       GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
3309
3310   if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
3311     return FALSE;
3312
3313   data = packet->rtcp->map.data;
3314   /* skip header + current item offset */
3315   data += packet->offset + packet->item_offset;
3316
3317   /* skip block header, ssrc */
3318   data += 8;
3319   if (loss_rate)
3320     *loss_rate = data[0];
3321
3322   if (discard_rate)
3323     *discard_rate = data[1];
3324
3325   return TRUE;
3326 }
3327
3328 /**
3329  * gst_rtcp_packet_xr_get_voip_burst_metrics:
3330  * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
3331  * @burst_density: the fraction of RTP data packets within burst periods.
3332  * @gap_density: the fraction of RTP data packets within inter-burst gaps.
3333  * @burst_duration: the mean duration(ms) of the burst periods.
3334  * @gap_duration: the mean duration(ms) of the gap periods.
3335  *
3336  * Returns: %TRUE if the report block is correctly parsed.
3337  *
3338  * Since: 1.16
3339  */
3340 gboolean
3341 gst_rtcp_packet_xr_get_voip_burst_metrics (GstRTCPPacket * packet,
3342     guint8 * burst_density, guint8 * gap_density, guint16 * burst_duration,
3343     guint16 * gap_duration)
3344 {
3345   guint8 *data;
3346
3347   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3348       GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
3349
3350   if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
3351     return FALSE;
3352
3353   data = packet->rtcp->map.data;
3354   /* skip header + current item offset */
3355   data += packet->offset + packet->item_offset;
3356
3357   /* skip block header, ssrc, packet metrics */
3358   data += 10;
3359   if (burst_density)
3360     *burst_density = data[0];
3361
3362   if (gap_density)
3363     *gap_density = data[1];
3364
3365   data += 2;
3366   if (burst_duration)
3367     *burst_duration = GST_READ_UINT16_BE (data);
3368
3369   data += 2;
3370   if (gap_duration)
3371     *gap_duration = GST_READ_UINT16_BE (data);
3372
3373   return TRUE;
3374 }
3375
3376 /**
3377  * gst_rtcp_packet_xr_get_voip_delay_metrics:
3378  * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
3379  * @roundtrip_delay: the most recently calculated round trip time between RTP interfaces(ms)
3380  * @end_system_delay: the most recently estimated end system delay(ms)
3381  *
3382  * Returns: %TRUE if the report block is correctly parsed.
3383  *
3384  * Since: 1.16
3385  */
3386 gboolean
3387 gst_rtcp_packet_xr_get_voip_delay_metrics (GstRTCPPacket * packet,
3388     guint16 * roundtrip_delay, guint16 * end_system_delay)
3389 {
3390   guint8 *data;
3391
3392   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3393       GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
3394
3395   if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
3396     return FALSE;
3397
3398   data = packet->rtcp->map.data;
3399   /* skip header + current item offset */
3400   data += packet->offset + packet->item_offset;
3401
3402   /* skip block header, ssrc, packet metrics, burst metrics */
3403   data += 16;
3404   if (roundtrip_delay)
3405     *roundtrip_delay = GST_READ_UINT16_BE (data);
3406
3407   data += 2;
3408   if (end_system_delay)
3409     *end_system_delay = GST_READ_UINT16_BE (data);
3410
3411   return TRUE;
3412 }
3413
3414 /**
3415  * gst_rtcp_packet_xr_get_voip_signal_metrics:
3416  * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
3417  * @signal_level: the ratio of the signal level to a 0 dBm reference.
3418  * @noise_level: the ratio of the silent period background noise level to a 0 dBm reference.
3419  * @rerl: the residual echo return loss value.
3420  * @gmin: the gap threshold.
3421  *
3422  * Returns: %TRUE if the report block is correctly parsed.
3423  *
3424  * Since: 1.16
3425  */
3426 gboolean
3427 gst_rtcp_packet_xr_get_voip_signal_metrics (GstRTCPPacket * packet,
3428     guint8 * signal_level, guint8 * noise_level, guint8 * rerl, guint8 * gmin)
3429 {
3430   guint8 *data;
3431
3432   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3433       GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
3434
3435   if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
3436     return FALSE;
3437
3438   data = packet->rtcp->map.data;
3439   /* skip header + current item offset */
3440   data += packet->offset + packet->item_offset;
3441
3442   /* skip block header, ssrc, packet metrics, burst metrics,
3443    * delay metrics */
3444   data += 20;
3445   if (signal_level)
3446     *signal_level = data[0];
3447
3448   if (noise_level)
3449     *noise_level = data[1];
3450
3451   if (rerl)
3452     *rerl = data[2];
3453
3454   if (gmin)
3455     *gmin = data[3];
3456
3457   return TRUE;
3458 }
3459
3460 /**
3461  * gst_rtcp_packet_xr_get_voip_quality_metrics:
3462  * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
3463  * @r_factor: the R factor is a voice quality metric describing the segment of the call.
3464  * @ext_r_factor: the external R factor is a voice quality metric.
3465  * @mos_lq: the estimated mean opinion score for listening quality.
3466  * @mos_cq: the estimated mean opinion score for conversational quality.
3467  *
3468  * Returns: %TRUE if the report block is correctly parsed.
3469  *
3470  * Since: 1.16
3471  */
3472 gboolean
3473 gst_rtcp_packet_xr_get_voip_quality_metrics (GstRTCPPacket * packet,
3474     guint8 * r_factor, guint8 * ext_r_factor, guint8 * mos_lq, guint8 * mos_cq)
3475 {
3476   guint8 *data;
3477
3478   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3479       GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
3480
3481   if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
3482     return FALSE;
3483
3484   data = packet->rtcp->map.data;
3485   /* skip header + current item offset */
3486   data += packet->offset + packet->item_offset;
3487
3488   /* skip block header, ssrc, packet metrics, burst metrics,
3489    * delay metrics, signal metrics */
3490   data += 24;
3491   if (r_factor)
3492     *r_factor = data[0];
3493
3494   if (ext_r_factor)
3495     *ext_r_factor = data[1];
3496
3497   if (mos_lq)
3498     *mos_lq = data[2];
3499
3500   if (mos_cq)
3501     *mos_cq = data[3];
3502
3503   return TRUE;
3504 }
3505
3506 /**
3507  * gst_rtcp_packet_xr_get_voip_configuration_params:
3508  * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
3509  * @gmin: the gap threshold.
3510  * @rx_config: the receiver configuration byte.
3511  *
3512  * Returns: %TRUE if the report block is correctly parsed.
3513  *
3514  * Since: 1.16
3515  */
3516 gboolean
3517 gst_rtcp_packet_xr_get_voip_configuration_params (GstRTCPPacket * packet,
3518     guint8 * gmin, guint8 * rx_config)
3519 {
3520   guint8 *data;
3521
3522   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3523       GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
3524
3525   if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
3526     return FALSE;
3527
3528   data = packet->rtcp->map.data;
3529   /* skip header + current item offset */
3530   data += packet->offset + packet->item_offset;
3531
3532   if (gmin)
3533     *gmin = data[23];
3534
3535   if (rx_config)
3536     *rx_config = data[28];
3537
3538   return TRUE;
3539 }
3540
3541 /**
3542  * gst_rtcp_packet_xr_get_voip_jitter_buffer_params:
3543  * @packet: a valid XR #GstRTCPPacket which has VoIP Metrics Report Block.
3544  * @jb_nominal: the current nominal jitter buffer delay(ms)
3545  * @jb_maximum: the current maximum jitter buffer delay(ms)
3546  * @jb_abs_max: the absolute maximum delay(ms)
3547  *
3548  * Returns: %TRUE if the report block is correctly parsed.
3549  *
3550  * Since: 1.16
3551  */
3552 gboolean
3553 gst_rtcp_packet_xr_get_voip_jitter_buffer_params (GstRTCPPacket * packet,
3554     guint16 * jb_nominal, guint16 * jb_maximum, guint16 * jb_abs_max)
3555 {
3556   guint8 *data;
3557
3558   g_return_val_if_fail (gst_rtcp_packet_xr_get_block_type (packet) ==
3559       GST_RTCP_XR_TYPE_VOIP_METRICS, FALSE);
3560
3561   if (gst_rtcp_packet_xr_get_block_length (packet) != 8)
3562     return FALSE;
3563
3564   data = packet->rtcp->map.data;
3565   /* skip header + current item offset */
3566   data += packet->offset + packet->item_offset;
3567
3568   /* skip block header, ssrc, packet metrics, burst metrics,
3569    * delay metrics, signal metrics, config */
3570   data += 30;
3571
3572   if (jb_nominal)
3573     *jb_nominal = GST_READ_UINT16_BE (data);
3574
3575   data += 2;
3576   if (jb_maximum)
3577     *jb_maximum = GST_READ_UINT16_BE (data);
3578
3579   data += 2;
3580   if (jb_abs_max)
3581     *jb_abs_max = GST_READ_UINT16_BE (data);
3582
3583   return TRUE;
3584 }