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