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