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