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