|
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., 59 Temple Place - Suite 330, |
|
20 * Boston, MA 02111-1307, USA. |
|
21 */ |
|
22 |
|
23 /** |
|
24 * SECTION:gstrtcpbuffer |
|
25 * @short_description: Helper methods for dealing with RTCP buffers |
|
26 * @see_also: #GstBaseRTPPayload, #GstBaseRTPDepayload, #gstrtpbuffer |
|
27 * |
|
28 * Note: The API in this module is not yet declared stable. |
|
29 * |
|
30 * <refsect2> |
|
31 * <para> |
|
32 * The GstRTPCBuffer helper functions makes it easy to parse and create regular |
|
33 * #GstBuffer objects that contain compound RTCP packets. These buffers are typically |
|
34 * of 'application/x-rtcp' #GstCaps. |
|
35 * </para> |
|
36 * <para> |
|
37 * An RTCP buffer consists of 1 or more #GstRTCPPacket structures that you can |
|
38 * retrieve with gst_rtcp_buffer_get_first_packet(). #GstRTCPPacket acts as a pointer |
|
39 * into the RTCP buffer; you can move to the next packet with |
|
40 * gst_rtcp_packet_move_to_next(). |
|
41 * </para> |
|
42 * </refsect2> |
|
43 * |
|
44 * Since: 0.10.13 |
|
45 * |
|
46 * Last reviewed on 2007-03-26 (0.10.13) |
|
47 */ |
|
48 |
|
49 #include <string.h> |
|
50 |
|
51 #include "gstrtcpbuffer.h" |
|
52 |
|
53 /** |
|
54 * gst_rtcp_buffer_new_take_data: |
|
55 * @data: data for the new buffer |
|
56 * @len: the length of data |
|
57 * |
|
58 * Create a new buffer and set the data and size of the buffer to @data and @len |
|
59 * respectively. @data will be freed when the buffer is unreffed, so this |
|
60 * function transfers ownership of @data to the new buffer. |
|
61 * |
|
62 * Returns: A newly allocated buffer with @data and of size @len. |
|
63 */ |
|
64 #ifdef __SYMBIAN32__ |
|
65 EXPORT_C |
|
66 #endif |
|
67 |
|
68 GstBuffer * |
|
69 gst_rtcp_buffer_new_take_data (gpointer data, guint len) |
|
70 { |
|
71 GstBuffer *result; |
|
72 |
|
73 g_return_val_if_fail (data != NULL, NULL); |
|
74 g_return_val_if_fail (len > 0, NULL); |
|
75 |
|
76 result = gst_buffer_new (); |
|
77 |
|
78 GST_BUFFER_MALLOCDATA (result) = data; |
|
79 GST_BUFFER_DATA (result) = data; |
|
80 GST_BUFFER_SIZE (result) = len; |
|
81 |
|
82 return result; |
|
83 } |
|
84 |
|
85 /** |
|
86 * gst_rtcp_buffer_new_copy_data: |
|
87 * @data: data for the new buffer |
|
88 * @len: the length of data |
|
89 * |
|
90 * Create a new buffer and set the data to a copy of @len |
|
91 * bytes of @data and the size to @len. The data will be freed when the buffer |
|
92 * is freed. |
|
93 * |
|
94 * Returns: A newly allocated buffer with a copy of @data and of size @len. |
|
95 */ |
|
96 #ifdef __SYMBIAN32__ |
|
97 EXPORT_C |
|
98 #endif |
|
99 |
|
100 GstBuffer * |
|
101 gst_rtcp_buffer_new_copy_data (gpointer data, guint len) |
|
102 { |
|
103 return gst_rtcp_buffer_new_take_data (g_memdup (data, len), len); |
|
104 } |
|
105 |
|
106 /** |
|
107 * gst_rtcp_buffer_validate_data: |
|
108 * @data: the data to validate |
|
109 * @len: the length of @data to validate |
|
110 * |
|
111 * Check if the @data and @size point to the data of a valid RTCP (compound) |
|
112 * packet. |
|
113 * Use this function to validate a packet before using the other functions in |
|
114 * this module. |
|
115 * |
|
116 * Returns: TRUE if the data points to a valid RTCP packet. |
|
117 */ |
|
118 #ifdef __SYMBIAN32__ |
|
119 EXPORT_C |
|
120 #endif |
|
121 |
|
122 gboolean |
|
123 gst_rtcp_buffer_validate_data (guint8 * data, guint len) |
|
124 { |
|
125 guint16 header_mask; |
|
126 guint16 header_len; |
|
127 guint8 version; |
|
128 guint data_len; |
|
129 gboolean padding; |
|
130 guint8 pad_bytes; |
|
131 |
|
132 g_return_val_if_fail (data != NULL, FALSE); |
|
133 |
|
134 /* we need 4 bytes for the type and length */ |
|
135 if (G_UNLIKELY (len < 4)) |
|
136 goto wrong_length; |
|
137 |
|
138 /* first packet must be RR or SR and version must be 2 */ |
|
139 header_mask = ((data[0] << 8) | data[1]) & GST_RTCP_VALID_MASK; |
|
140 if (G_UNLIKELY (header_mask != GST_RTCP_VALID_VALUE)) |
|
141 goto wrong_mask; |
|
142 |
|
143 /* no padding when mask succeeds */ |
|
144 padding = FALSE; |
|
145 |
|
146 /* store len */ |
|
147 data_len = len; |
|
148 |
|
149 while (TRUE) { |
|
150 /* get packet length */ |
|
151 header_len = (((data[2] << 8) | data[3]) + 1) << 2; |
|
152 if (data_len < header_len) |
|
153 goto wrong_length; |
|
154 |
|
155 /* move to next compount packet */ |
|
156 data += header_len; |
|
157 data_len -= header_len; |
|
158 |
|
159 /* we are at the end now */ |
|
160 if (data_len < 4) |
|
161 break; |
|
162 |
|
163 /* check version of new packet */ |
|
164 version = data[0] & 0xc0; |
|
165 if (version != (GST_RTCP_VERSION << 6)) |
|
166 goto wrong_version; |
|
167 |
|
168 /* padding only allowed on last packet */ |
|
169 if ((padding = data[0] & 0x20)) |
|
170 break; |
|
171 } |
|
172 if (data_len > 0) { |
|
173 /* some leftover bytes, check padding */ |
|
174 if (!padding) |
|
175 goto wrong_length; |
|
176 |
|
177 /* get padding */ |
|
178 pad_bytes = data[len - 1]; |
|
179 if (data_len != pad_bytes) |
|
180 goto wrong_padding; |
|
181 } |
|
182 return TRUE; |
|
183 |
|
184 /* ERRORS */ |
|
185 wrong_length: |
|
186 { |
|
187 GST_DEBUG ("len check failed"); |
|
188 return FALSE; |
|
189 } |
|
190 wrong_mask: |
|
191 { |
|
192 GST_DEBUG ("mask check failed (%04x != %04x)", header_mask, |
|
193 GST_RTCP_VALID_VALUE); |
|
194 return FALSE; |
|
195 } |
|
196 wrong_version: |
|
197 { |
|
198 GST_DEBUG ("wrong version (%d < 2)", version >> 6); |
|
199 return FALSE; |
|
200 } |
|
201 wrong_padding: |
|
202 { |
|
203 GST_DEBUG ("padding check failed"); |
|
204 return FALSE; |
|
205 } |
|
206 } |
|
207 |
|
208 /** |
|
209 * gst_rtcp_buffer_validate: |
|
210 * @buffer: the buffer to validate |
|
211 * |
|
212 * Check if the data pointed to by @buffer is a valid RTCP packet using |
|
213 * gst_rtcp_buffer_validate_data(). |
|
214 * |
|
215 * Returns: TRUE if @buffer is a valid RTCP packet. |
|
216 */ |
|
217 #ifdef __SYMBIAN32__ |
|
218 EXPORT_C |
|
219 #endif |
|
220 |
|
221 gboolean |
|
222 gst_rtcp_buffer_validate (GstBuffer * buffer) |
|
223 { |
|
224 guint8 *data; |
|
225 guint len; |
|
226 |
|
227 g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); |
|
228 |
|
229 data = GST_BUFFER_DATA (buffer); |
|
230 len = GST_BUFFER_SIZE (buffer); |
|
231 |
|
232 return gst_rtcp_buffer_validate_data (data, len); |
|
233 } |
|
234 |
|
235 /** |
|
236 * gst_rtcp_buffer_new: |
|
237 * @mtu: the maximum mtu size. |
|
238 * |
|
239 * Create a new buffer for constructing RTCP packets. The packet will have a |
|
240 * maximum size of @mtu. |
|
241 * |
|
242 * Returns: A newly allocated buffer. |
|
243 */ |
|
244 #ifdef __SYMBIAN32__ |
|
245 EXPORT_C |
|
246 #endif |
|
247 |
|
248 GstBuffer * |
|
249 gst_rtcp_buffer_new (guint mtu) |
|
250 { |
|
251 GstBuffer *result; |
|
252 |
|
253 g_return_val_if_fail (mtu > 0, NULL); |
|
254 |
|
255 result = gst_buffer_new (); |
|
256 GST_BUFFER_MALLOCDATA (result) = g_malloc0 (mtu); |
|
257 GST_BUFFER_DATA (result) = GST_BUFFER_MALLOCDATA (result); |
|
258 GST_BUFFER_SIZE (result) = mtu; |
|
259 |
|
260 return result; |
|
261 } |
|
262 |
|
263 /** |
|
264 * gst_rtcp_buffer_end: |
|
265 * @buffer: a buffer with an RTCP packet |
|
266 * |
|
267 * Finish @buffer after being constructured. This function is usually called |
|
268 * after gst_rtcp_buffer_new() and after adding the RTCP items to the new buffer. |
|
269 * |
|
270 * The function adjusts the size of @buffer with the total length of all the |
|
271 * added packets. |
|
272 */ |
|
273 #ifdef __SYMBIAN32__ |
|
274 EXPORT_C |
|
275 #endif |
|
276 |
|
277 void |
|
278 gst_rtcp_buffer_end (GstBuffer * buffer) |
|
279 { |
|
280 GstRTCPPacket packet; |
|
281 |
|
282 g_return_if_fail (GST_IS_BUFFER (buffer)); |
|
283 |
|
284 /* move to the first free space */ |
|
285 if (gst_rtcp_buffer_get_first_packet (buffer, &packet)) |
|
286 while (gst_rtcp_packet_move_to_next (&packet)); |
|
287 |
|
288 /* shrink size */ |
|
289 GST_BUFFER_SIZE (buffer) = packet.offset; |
|
290 } |
|
291 |
|
292 /** |
|
293 * gst_rtcp_buffer_get_packet_count: |
|
294 * @buffer: a valid RTCP buffer |
|
295 * |
|
296 * Get the number of RTCP packets in @buffer. |
|
297 * |
|
298 * Returns: the number of RTCP packets in @buffer. |
|
299 */ |
|
300 #ifdef __SYMBIAN32__ |
|
301 EXPORT_C |
|
302 #endif |
|
303 |
|
304 guint |
|
305 gst_rtcp_buffer_get_packet_count (GstBuffer * buffer) |
|
306 { |
|
307 GstRTCPPacket packet; |
|
308 guint count; |
|
309 |
|
310 g_return_val_if_fail (GST_IS_BUFFER (buffer), 0); |
|
311 |
|
312 count = 0; |
|
313 if (gst_rtcp_buffer_get_first_packet (buffer, &packet)) { |
|
314 do { |
|
315 count++; |
|
316 } while (gst_rtcp_packet_move_to_next (&packet)); |
|
317 } |
|
318 |
|
319 return count; |
|
320 } |
|
321 |
|
322 /** |
|
323 * read_packet_header: |
|
324 * @packet: a packet |
|
325 * |
|
326 * Read the packet headers for the packet pointed to by @packet. |
|
327 * |
|
328 * Returns: TRUE if @packet pointed to a valid header. |
|
329 */ |
|
330 static gboolean |
|
331 read_packet_header (GstRTCPPacket * packet) |
|
332 { |
|
333 guint8 *data; |
|
334 guint size; |
|
335 guint offset; |
|
336 |
|
337 g_return_val_if_fail (packet != NULL, FALSE); |
|
338 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
339 |
|
340 data = GST_BUFFER_DATA (packet->buffer); |
|
341 size = GST_BUFFER_SIZE (packet->buffer); |
|
342 |
|
343 offset = packet->offset; |
|
344 |
|
345 /* check if we are at the end of the buffer, we add 4 because we also want to |
|
346 * ensure we can read the header. */ |
|
347 if (offset + 4 > size) |
|
348 return FALSE; |
|
349 |
|
350 if ((data[offset] & 0xc0) != (GST_RTCP_VERSION << 6)) |
|
351 return FALSE; |
|
352 |
|
353 /* read count, type and length */ |
|
354 packet->padding = (data[offset] & 0x20) == 0x20; |
|
355 packet->count = data[offset] & 0x1f; |
|
356 packet->type = data[offset + 1]; |
|
357 packet->length = (data[offset + 2] << 8) | data[offset + 3]; |
|
358 packet->item_offset = 4; |
|
359 packet->item_count = 0; |
|
360 packet->entry_offset = 4; |
|
361 |
|
362 return TRUE; |
|
363 } |
|
364 |
|
365 /** |
|
366 * gst_rtcp_buffer_get_first_packet: |
|
367 * @buffer: a valid RTCP buffer |
|
368 * @packet: a #GstRTCPPacket |
|
369 * |
|
370 * Initialize a new #GstRTCPPacket pointer that points to the first packet in |
|
371 * @buffer. |
|
372 * |
|
373 * Returns: TRUE if the packet existed in @buffer. |
|
374 */ |
|
375 #ifdef __SYMBIAN32__ |
|
376 EXPORT_C |
|
377 #endif |
|
378 |
|
379 gboolean |
|
380 gst_rtcp_buffer_get_first_packet (GstBuffer * buffer, GstRTCPPacket * packet) |
|
381 { |
|
382 g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); |
|
383 g_return_val_if_fail (packet != NULL, FALSE); |
|
384 |
|
385 /* init to 0 */ |
|
386 packet->buffer = buffer; |
|
387 packet->offset = 0; |
|
388 packet->type = GST_RTCP_TYPE_INVALID; |
|
389 |
|
390 if (!read_packet_header (packet)) |
|
391 return FALSE; |
|
392 |
|
393 return TRUE; |
|
394 } |
|
395 |
|
396 /** |
|
397 * gst_rtcp_packet_move_to_next: |
|
398 * @packet: a #GstRTCPPacket |
|
399 * |
|
400 * Move the packet pointer @packet to the next packet in the payload. |
|
401 * Use gst_rtcp_buffer_get_first_packet() to initialize @packet. |
|
402 * |
|
403 * Returns: TRUE if @packet is pointing to a valid packet after calling this |
|
404 * function. |
|
405 */ |
|
406 #ifdef __SYMBIAN32__ |
|
407 EXPORT_C |
|
408 #endif |
|
409 gboolean |
|
410 gst_rtcp_packet_move_to_next (GstRTCPPacket * packet) |
|
411 { |
|
412 g_return_val_if_fail (packet != NULL, FALSE); |
|
413 g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE); |
|
414 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
415 |
|
416 /* if we have a padding or invalid packet, it must be the last, |
|
417 * return FALSE */ |
|
418 if (packet->type == GST_RTCP_TYPE_INVALID || packet->padding) |
|
419 goto end; |
|
420 |
|
421 /* move to next packet. Add 4 because the header is not included in length */ |
|
422 packet->offset += (packet->length << 2) + 4; |
|
423 |
|
424 /* try to read new header */ |
|
425 if (!read_packet_header (packet)) |
|
426 goto end; |
|
427 |
|
428 return TRUE; |
|
429 |
|
430 /* ERRORS */ |
|
431 end: |
|
432 { |
|
433 packet->type = GST_RTCP_TYPE_INVALID; |
|
434 return FALSE; |
|
435 } |
|
436 } |
|
437 |
|
438 /** |
|
439 * gst_rtcp_buffer_add_packet: |
|
440 * @buffer: a valid RTCP buffer |
|
441 * @type: the #GstRTCPType of the new packet |
|
442 * @packet: pointer to new packet |
|
443 * |
|
444 * Add a new packet of @type to @buffer. @packet will point to the newly created |
|
445 * packet. |
|
446 * |
|
447 * Returns: %TRUE if the packet could be created. This function returns %FALSE |
|
448 * if the max mtu is exceeded for the buffer. |
|
449 */ |
|
450 #ifdef __SYMBIAN32__ |
|
451 EXPORT_C |
|
452 #endif |
|
453 |
|
454 gboolean |
|
455 gst_rtcp_buffer_add_packet (GstBuffer * buffer, GstRTCPType type, |
|
456 GstRTCPPacket * packet) |
|
457 { |
|
458 guint len, size; |
|
459 guint8 *data; |
|
460 gboolean result; |
|
461 |
|
462 g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE); |
|
463 g_return_val_if_fail (type != GST_RTCP_TYPE_INVALID, FALSE); |
|
464 g_return_val_if_fail (packet != NULL, FALSE); |
|
465 |
|
466 /* find free space */ |
|
467 if (gst_rtcp_buffer_get_first_packet (buffer, packet)) |
|
468 while (gst_rtcp_packet_move_to_next (packet)); |
|
469 |
|
470 size = GST_BUFFER_SIZE (buffer); |
|
471 |
|
472 /* packet->offset is now pointing to the next free offset in the buffer to |
|
473 * start a compount packet. Next we figure out if we have enough free space in |
|
474 * the buffer to continue. */ |
|
475 switch (type) { |
|
476 case GST_RTCP_TYPE_SR: |
|
477 len = 28; |
|
478 break; |
|
479 case GST_RTCP_TYPE_RR: |
|
480 len = 8; |
|
481 break; |
|
482 case GST_RTCP_TYPE_SDES: |
|
483 len = 4; |
|
484 break; |
|
485 case GST_RTCP_TYPE_BYE: |
|
486 len = 4; |
|
487 break; |
|
488 case GST_RTCP_TYPE_APP: |
|
489 len = 12; |
|
490 break; |
|
491 default: |
|
492 goto unknown_type; |
|
493 } |
|
494 if (packet->offset + len >= size) |
|
495 goto no_space; |
|
496 |
|
497 data = GST_BUFFER_DATA (buffer) + packet->offset; |
|
498 |
|
499 data[0] = (GST_RTCP_VERSION << 6); |
|
500 data[1] = type; |
|
501 /* length is stored in multiples of 32 bit words minus the length of the |
|
502 * header */ |
|
503 len = (len - 4) >> 2; |
|
504 data[2] = len >> 8; |
|
505 data[3] = len & 0xff; |
|
506 |
|
507 /* now try to position to the packet */ |
|
508 result = read_packet_header (packet); |
|
509 |
|
510 return result; |
|
511 |
|
512 /* ERRORS */ |
|
513 unknown_type: |
|
514 { |
|
515 g_warning ("unknown type %d", type); |
|
516 return FALSE; |
|
517 } |
|
518 no_space: |
|
519 { |
|
520 return FALSE; |
|
521 } |
|
522 } |
|
523 |
|
524 /** |
|
525 * gst_rtcp_packet_remove: |
|
526 * @packet: a #GstRTCPPacket |
|
527 * |
|
528 * Removes the packet pointed to by @packet. |
|
529 * |
|
530 * Note: Not implemented. |
|
531 */ |
|
532 #ifdef __SYMBIAN32__ |
|
533 EXPORT_C |
|
534 #endif |
|
535 |
|
536 void |
|
537 gst_rtcp_packet_remove (GstRTCPPacket * packet) |
|
538 { |
|
539 g_return_if_fail (packet != NULL); |
|
540 g_return_if_fail (packet->type != GST_RTCP_TYPE_INVALID); |
|
541 |
|
542 g_warning ("not implemented"); |
|
543 } |
|
544 |
|
545 /** |
|
546 * gst_rtcp_packet_get_padding: |
|
547 * @packet: a valid #GstRTCPPacket |
|
548 * |
|
549 * Get the packet padding of the packet pointed to by @packet. |
|
550 * |
|
551 * Returns: If the packet has the padding bit set. |
|
552 */ |
|
553 #ifdef __SYMBIAN32__ |
|
554 EXPORT_C |
|
555 #endif |
|
556 |
|
557 gboolean |
|
558 gst_rtcp_packet_get_padding (GstRTCPPacket * packet) |
|
559 { |
|
560 g_return_val_if_fail (packet != NULL, FALSE); |
|
561 g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, FALSE); |
|
562 |
|
563 return packet->padding; |
|
564 } |
|
565 |
|
566 /** |
|
567 * gst_rtcp_packet_get_type: |
|
568 * @packet: a valid #GstRTCPPacket |
|
569 * |
|
570 * Get the packet type of the packet pointed to by @packet. |
|
571 * |
|
572 * Returns: The packet type. |
|
573 */ |
|
574 #ifdef __SYMBIAN32__ |
|
575 EXPORT_C |
|
576 #endif |
|
577 |
|
578 GstRTCPType |
|
579 gst_rtcp_packet_get_type (GstRTCPPacket * packet) |
|
580 { |
|
581 g_return_val_if_fail (packet != NULL, GST_RTCP_TYPE_INVALID); |
|
582 g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, |
|
583 GST_RTCP_TYPE_INVALID); |
|
584 |
|
585 return packet->type; |
|
586 } |
|
587 |
|
588 /** |
|
589 * gst_rtcp_packet_get_count: |
|
590 * @packet: a valid #GstRTCPPacket |
|
591 * |
|
592 * Get the count field in @packet. |
|
593 * |
|
594 * Returns: The count field in @packet or -1 if @packet does not point to a |
|
595 * valid packet. |
|
596 */ |
|
597 #ifdef __SYMBIAN32__ |
|
598 EXPORT_C |
|
599 #endif |
|
600 |
|
601 guint8 |
|
602 gst_rtcp_packet_get_count (GstRTCPPacket * packet) |
|
603 { |
|
604 g_return_val_if_fail (packet != NULL, -1); |
|
605 g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, -1); |
|
606 |
|
607 return packet->count; |
|
608 } |
|
609 |
|
610 /** |
|
611 * gst_rtcp_packet_get_length: |
|
612 * @packet: a valid #GstRTCPPacket |
|
613 * |
|
614 * Get the length field of @packet. This is the length of the packet in |
|
615 * 32-bit words minus one. |
|
616 * |
|
617 * Returns: The length field of @packet. |
|
618 */ |
|
619 #ifdef __SYMBIAN32__ |
|
620 EXPORT_C |
|
621 #endif |
|
622 |
|
623 guint16 |
|
624 gst_rtcp_packet_get_length (GstRTCPPacket * packet) |
|
625 { |
|
626 g_return_val_if_fail (packet != NULL, 0); |
|
627 g_return_val_if_fail (packet->type != GST_RTCP_TYPE_INVALID, 0); |
|
628 |
|
629 return packet->length; |
|
630 } |
|
631 |
|
632 /** |
|
633 * gst_rtcp_packet_sr_get_sender_info: |
|
634 * @packet: a valid SR #GstRTCPPacket |
|
635 * @ssrc: result SSRC |
|
636 * @ntptime: result NTP time |
|
637 * @rtptime: result RTP time |
|
638 * @packet_count: result packet count |
|
639 * @octet_count: result octect count |
|
640 * |
|
641 * Parse the SR sender info and store the values. |
|
642 */ |
|
643 #ifdef __SYMBIAN32__ |
|
644 EXPORT_C |
|
645 #endif |
|
646 |
|
647 void |
|
648 gst_rtcp_packet_sr_get_sender_info (GstRTCPPacket * packet, guint32 * ssrc, |
|
649 guint64 * ntptime, guint32 * rtptime, guint32 * packet_count, |
|
650 guint32 * octet_count) |
|
651 { |
|
652 guint8 *data; |
|
653 |
|
654 g_return_if_fail (packet != NULL); |
|
655 g_return_if_fail (packet->type == GST_RTCP_TYPE_SR); |
|
656 g_return_if_fail (GST_IS_BUFFER (packet->buffer)); |
|
657 |
|
658 data = GST_BUFFER_DATA (packet->buffer); |
|
659 |
|
660 /* skip header */ |
|
661 data += packet->offset + 4; |
|
662 if (ssrc) |
|
663 *ssrc = GST_READ_UINT32_BE (data); |
|
664 data += 4; |
|
665 if (ntptime) |
|
666 *ntptime = GST_READ_UINT64_BE (data); |
|
667 data += 8; |
|
668 if (rtptime) |
|
669 *rtptime = GST_READ_UINT32_BE (data); |
|
670 data += 4; |
|
671 if (packet_count) |
|
672 *packet_count = GST_READ_UINT32_BE (data); |
|
673 data += 4; |
|
674 if (octet_count) |
|
675 *octet_count = GST_READ_UINT32_BE (data); |
|
676 } |
|
677 |
|
678 /** |
|
679 * gst_rtcp_packet_sr_set_sender_info: |
|
680 * @packet: a valid SR #GstRTCPPacket |
|
681 * @ssrc: the SSRC |
|
682 * @ntptime: the NTP time |
|
683 * @rtptime: the RTP time |
|
684 * @packet_count: the packet count |
|
685 * @octet_count: the octect count |
|
686 * |
|
687 * Set the given values in the SR packet @packet. |
|
688 */ |
|
689 #ifdef __SYMBIAN32__ |
|
690 EXPORT_C |
|
691 #endif |
|
692 |
|
693 void |
|
694 gst_rtcp_packet_sr_set_sender_info (GstRTCPPacket * packet, guint32 ssrc, |
|
695 guint64 ntptime, guint32 rtptime, guint32 packet_count, guint32 octet_count) |
|
696 { |
|
697 guint8 *data; |
|
698 |
|
699 g_return_if_fail (packet != NULL); |
|
700 g_return_if_fail (packet->type == GST_RTCP_TYPE_SR); |
|
701 g_return_if_fail (GST_IS_BUFFER (packet->buffer)); |
|
702 |
|
703 data = GST_BUFFER_DATA (packet->buffer); |
|
704 |
|
705 /* skip header */ |
|
706 data += packet->offset + 4; |
|
707 GST_WRITE_UINT32_BE (data, ssrc); |
|
708 data += 4; |
|
709 GST_WRITE_UINT64_BE (data, ntptime); |
|
710 data += 8; |
|
711 GST_WRITE_UINT32_BE (data, rtptime); |
|
712 data += 4; |
|
713 GST_WRITE_UINT32_BE (data, packet_count); |
|
714 data += 4; |
|
715 GST_WRITE_UINT32_BE (data, octet_count); |
|
716 } |
|
717 |
|
718 /** |
|
719 * gst_rtcp_packet_rr_get_ssrc: |
|
720 * @packet: a valid RR #GstRTCPPacket |
|
721 * |
|
722 * Get the ssrc field of the RR @packet. |
|
723 * |
|
724 * Returns: the ssrc. |
|
725 */ |
|
726 #ifdef __SYMBIAN32__ |
|
727 EXPORT_C |
|
728 #endif |
|
729 |
|
730 guint32 |
|
731 gst_rtcp_packet_rr_get_ssrc (GstRTCPPacket * packet) |
|
732 { |
|
733 guint8 *data; |
|
734 guint32 ssrc; |
|
735 |
|
736 g_return_val_if_fail (packet != NULL, 0); |
|
737 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR, 0); |
|
738 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); |
|
739 |
|
740 data = GST_BUFFER_DATA (packet->buffer); |
|
741 |
|
742 /* skip header */ |
|
743 data += packet->offset + 4; |
|
744 ssrc = GST_READ_UINT32_BE (data); |
|
745 |
|
746 return ssrc; |
|
747 } |
|
748 |
|
749 /** |
|
750 * gst_rtcp_packet_rr_set_ssrc: |
|
751 * @packet: a valid RR #GstRTCPPacket |
|
752 * @ssrc: the SSRC to set |
|
753 * |
|
754 * Set the ssrc field of the RR @packet. |
|
755 */ |
|
756 #ifdef __SYMBIAN32__ |
|
757 EXPORT_C |
|
758 #endif |
|
759 |
|
760 void |
|
761 gst_rtcp_packet_rr_set_ssrc (GstRTCPPacket * packet, guint32 ssrc) |
|
762 { |
|
763 guint8 *data; |
|
764 |
|
765 g_return_if_fail (packet != NULL); |
|
766 g_return_if_fail (packet->type == GST_RTCP_TYPE_RR); |
|
767 g_return_if_fail (GST_IS_BUFFER (packet->buffer)); |
|
768 |
|
769 data = GST_BUFFER_DATA (packet->buffer); |
|
770 |
|
771 /* skip header */ |
|
772 data += packet->offset + 4; |
|
773 GST_WRITE_UINT32_BE (data, ssrc); |
|
774 } |
|
775 |
|
776 /** |
|
777 * gst_rtcp_packet_get_rb_count: |
|
778 * @packet: a valid SR or RR #GstRTCPPacket |
|
779 * |
|
780 * Get the number of report blocks in @packet. |
|
781 * |
|
782 * Returns: The number of report blocks in @packet. |
|
783 */ |
|
784 #ifdef __SYMBIAN32__ |
|
785 EXPORT_C |
|
786 #endif |
|
787 |
|
788 guint |
|
789 gst_rtcp_packet_get_rb_count (GstRTCPPacket * packet) |
|
790 { |
|
791 g_return_val_if_fail (packet != NULL, 0); |
|
792 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR || |
|
793 packet->type == GST_RTCP_TYPE_SR, 0); |
|
794 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); |
|
795 |
|
796 return packet->count; |
|
797 } |
|
798 |
|
799 /** |
|
800 * gst_rtcp_packet_get_rb: |
|
801 * @packet: a valid SR or RR #GstRTCPPacket |
|
802 * @nth: the nth report block in @packet |
|
803 * @ssrc: result for data source being reported |
|
804 * @fractionlost: result for fraction lost since last SR/RR |
|
805 * @packetslost: result for the cumululative number of packets lost |
|
806 * @exthighestseq: result for the extended last sequence number received |
|
807 * @jitter: result for the interarrival jitter |
|
808 * @lsr: result for the last SR packet from this source |
|
809 * @dlsr: result for the delay since last SR packet |
|
810 * |
|
811 * Parse the values of the @nth report block in @packet and store the result in |
|
812 * the values. |
|
813 */ |
|
814 #ifdef __SYMBIAN32__ |
|
815 EXPORT_C |
|
816 #endif |
|
817 |
|
818 void |
|
819 gst_rtcp_packet_get_rb (GstRTCPPacket * packet, guint nth, guint32 * ssrc, |
|
820 guint8 * fractionlost, gint32 * packetslost, guint32 * exthighestseq, |
|
821 guint32 * jitter, guint32 * lsr, guint32 * dlsr) |
|
822 { |
|
823 guint8 *data; |
|
824 guint32 tmp; |
|
825 |
|
826 g_return_if_fail (packet != NULL); |
|
827 g_return_if_fail (packet->type == GST_RTCP_TYPE_RR || |
|
828 packet->type == GST_RTCP_TYPE_SR); |
|
829 g_return_if_fail (GST_IS_BUFFER (packet->buffer)); |
|
830 |
|
831 data = GST_BUFFER_DATA (packet->buffer); |
|
832 |
|
833 /* skip header */ |
|
834 data += packet->offset + 4; |
|
835 if (packet->type == GST_RTCP_TYPE_RR) |
|
836 data += 4; |
|
837 else |
|
838 data += 24; |
|
839 |
|
840 /* move to requested index */ |
|
841 data += (nth * 24); |
|
842 |
|
843 if (ssrc) |
|
844 *ssrc = GST_READ_UINT32_BE (data); |
|
845 data += 4; |
|
846 tmp = GST_READ_UINT32_BE (data); |
|
847 if (fractionlost) |
|
848 *fractionlost = (tmp >> 24); |
|
849 if (packetslost) { |
|
850 /* sign extend */ |
|
851 if (tmp & 0x00800000) |
|
852 tmp |= 0xff000000; |
|
853 else |
|
854 tmp &= 0x00ffffff; |
|
855 *packetslost = (gint32) tmp; |
|
856 } |
|
857 data += 4; |
|
858 if (exthighestseq) |
|
859 *exthighestseq = GST_READ_UINT32_BE (data); |
|
860 data += 4; |
|
861 if (jitter) |
|
862 *jitter = GST_READ_UINT32_BE (data); |
|
863 data += 4; |
|
864 if (lsr) |
|
865 *lsr = GST_READ_UINT32_BE (data); |
|
866 data += 4; |
|
867 if (dlsr) |
|
868 *dlsr = GST_READ_UINT32_BE (data); |
|
869 } |
|
870 |
|
871 /** |
|
872 * gst_rtcp_packet_add_rb: |
|
873 * @packet: a valid SR or RR #GstRTCPPacket |
|
874 * @ssrc: data source being reported |
|
875 * @fractionlost: fraction lost since last SR/RR |
|
876 * @packetslost: the cumululative number of packets lost |
|
877 * @exthighestseq: the extended last sequence number received |
|
878 * @jitter: the interarrival jitter |
|
879 * @lsr: the last SR packet from this source |
|
880 * @dlsr: the delay since last SR packet |
|
881 * |
|
882 * Add a new report block to @packet with the given values. |
|
883 * |
|
884 * Returns: %TRUE if the packet was created. This function can return %FALSE if |
|
885 * the max MTU is exceeded or the number of report blocks is greater than |
|
886 * #GST_RTCP_MAX_RB_COUNT. |
|
887 */ |
|
888 #ifdef __SYMBIAN32__ |
|
889 EXPORT_C |
|
890 #endif |
|
891 |
|
892 gboolean |
|
893 gst_rtcp_packet_add_rb (GstRTCPPacket * packet, guint32 ssrc, |
|
894 guint8 fractionlost, gint32 packetslost, guint32 exthighestseq, |
|
895 guint32 jitter, guint32 lsr, guint32 dlsr) |
|
896 { |
|
897 guint8 *data; |
|
898 guint size, offset; |
|
899 |
|
900 g_return_val_if_fail (packet != NULL, FALSE); |
|
901 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_RR || |
|
902 packet->type == GST_RTCP_TYPE_SR, FALSE); |
|
903 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
904 |
|
905 if (packet->count >= GST_RTCP_MAX_RB_COUNT) |
|
906 goto no_space; |
|
907 |
|
908 data = GST_BUFFER_DATA (packet->buffer); |
|
909 size = GST_BUFFER_SIZE (packet->buffer); |
|
910 |
|
911 /* skip header */ |
|
912 offset = packet->offset + 4; |
|
913 if (packet->type == GST_RTCP_TYPE_RR) |
|
914 offset += 4; |
|
915 else |
|
916 offset += 24; |
|
917 |
|
918 /* move to current index */ |
|
919 offset += (packet->count * 24); |
|
920 |
|
921 /* we need 24 free bytes now */ |
|
922 if (offset + 24 >= size) |
|
923 goto no_space; |
|
924 |
|
925 /* increment packet count and length */ |
|
926 packet->count++; |
|
927 data[packet->offset]++; |
|
928 packet->length += 6; |
|
929 data[packet->offset + 2] = (packet->length) >> 8; |
|
930 data[packet->offset + 3] = (packet->length) & 0xff; |
|
931 |
|
932 /* move to new report block offset */ |
|
933 data += offset; |
|
934 |
|
935 GST_WRITE_UINT32_BE (data, ssrc); |
|
936 data += 4; |
|
937 GST_WRITE_UINT32_BE (data, (fractionlost << 24) | (packetslost & 0xffffff)); |
|
938 data += 4; |
|
939 GST_WRITE_UINT32_BE (data, exthighestseq); |
|
940 data += 4; |
|
941 GST_WRITE_UINT32_BE (data, jitter); |
|
942 data += 4; |
|
943 GST_WRITE_UINT32_BE (data, lsr); |
|
944 data += 4; |
|
945 GST_WRITE_UINT32_BE (data, dlsr); |
|
946 |
|
947 return TRUE; |
|
948 |
|
949 no_space: |
|
950 { |
|
951 return FALSE; |
|
952 } |
|
953 } |
|
954 |
|
955 /** |
|
956 * gst_rtcp_packet_set_rb: |
|
957 * @packet: a valid SR or RR #GstRTCPPacket |
|
958 * @nth: the nth report block to set |
|
959 * @ssrc: data source being reported |
|
960 * @fractionlost: fraction lost since last SR/RR |
|
961 * @packetslost: the cumululative number of packets lost |
|
962 * @exthighestseq: the extended last sequence number received |
|
963 * @jitter: the interarrival jitter |
|
964 * @lsr: the last SR packet from this source |
|
965 * @dlsr: the delay since last SR packet |
|
966 * |
|
967 * Set the @nth new report block in @packet with the given values. |
|
968 * |
|
969 * Note: Not implemented. |
|
970 */ |
|
971 #ifdef __SYMBIAN32__ |
|
972 EXPORT_C |
|
973 #endif |
|
974 |
|
975 void |
|
976 gst_rtcp_packet_set_rb (GstRTCPPacket * packet, guint nth, guint32 ssrc, |
|
977 guint8 fractionlost, gint32 packetslost, guint32 exthighestseq, |
|
978 guint32 jitter, guint32 lsr, guint32 dlsr) |
|
979 { |
|
980 g_return_if_fail (packet != NULL); |
|
981 g_return_if_fail (packet->type == GST_RTCP_TYPE_RR || |
|
982 packet->type == GST_RTCP_TYPE_SR); |
|
983 g_return_if_fail (GST_IS_BUFFER (packet->buffer)); |
|
984 |
|
985 g_warning ("not implemented"); |
|
986 } |
|
987 |
|
988 |
|
989 /** |
|
990 * gst_rtcp_packet_sdes_get_item_count: |
|
991 * @packet: a valid SDES #GstRTCPPacket |
|
992 * |
|
993 * Get the number of items in the SDES packet @packet. |
|
994 * |
|
995 * Returns: The number of items in @packet. |
|
996 */ |
|
997 #ifdef __SYMBIAN32__ |
|
998 EXPORT_C |
|
999 #endif |
|
1000 |
|
1001 guint |
|
1002 gst_rtcp_packet_sdes_get_item_count (GstRTCPPacket * packet) |
|
1003 { |
|
1004 g_return_val_if_fail (packet != NULL, 0); |
|
1005 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0); |
|
1006 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); |
|
1007 |
|
1008 return packet->count; |
|
1009 } |
|
1010 |
|
1011 /** |
|
1012 * gst_rtcp_packet_sdes_first_item: |
|
1013 * @packet: a valid SDES #GstRTCPPacket |
|
1014 * |
|
1015 * Move to the first SDES item in @packet. |
|
1016 * |
|
1017 * Returns: TRUE if there was a first item. |
|
1018 */ |
|
1019 #ifdef __SYMBIAN32__ |
|
1020 EXPORT_C |
|
1021 #endif |
|
1022 |
|
1023 gboolean |
|
1024 gst_rtcp_packet_sdes_first_item (GstRTCPPacket * packet) |
|
1025 { |
|
1026 g_return_val_if_fail (packet != NULL, FALSE); |
|
1027 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE); |
|
1028 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1029 |
|
1030 packet->item_offset = 4; |
|
1031 packet->item_count = 0; |
|
1032 packet->entry_offset = 4; |
|
1033 |
|
1034 if (packet->count == 0) |
|
1035 return FALSE; |
|
1036 |
|
1037 return TRUE; |
|
1038 } |
|
1039 |
|
1040 /** |
|
1041 * gst_rtcp_packet_sdes_next_item: |
|
1042 * @packet: a valid SDES #GstRTCPPacket |
|
1043 * |
|
1044 * Move to the next SDES item in @packet. |
|
1045 * |
|
1046 * Returns: TRUE if there was a next item. |
|
1047 */ |
|
1048 #ifdef __SYMBIAN32__ |
|
1049 EXPORT_C |
|
1050 #endif |
|
1051 |
|
1052 gboolean |
|
1053 gst_rtcp_packet_sdes_next_item (GstRTCPPacket * packet) |
|
1054 { |
|
1055 guint8 *data; |
|
1056 guint offset; |
|
1057 guint len; |
|
1058 |
|
1059 g_return_val_if_fail (packet != NULL, FALSE); |
|
1060 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE); |
|
1061 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1062 |
|
1063 /* if we are at the last item, we are done */ |
|
1064 if (packet->item_count == packet->count) |
|
1065 return FALSE; |
|
1066 |
|
1067 /* move to SDES */ |
|
1068 data = GST_BUFFER_DATA (packet->buffer); |
|
1069 data += packet->offset; |
|
1070 /* move to item */ |
|
1071 offset = packet->item_offset; |
|
1072 /* skip SSRC */ |
|
1073 offset += 4; |
|
1074 |
|
1075 /* don't overrun */ |
|
1076 len = (packet->length << 2); |
|
1077 |
|
1078 while (offset < len) { |
|
1079 if (data[offset] == 0) { |
|
1080 /* end of list, round to next 32-bit word */ |
|
1081 offset = (offset + 3) & ~3; |
|
1082 break; |
|
1083 } |
|
1084 offset += data[offset + 1] + 2; |
|
1085 } |
|
1086 if (offset >= len) |
|
1087 return FALSE; |
|
1088 |
|
1089 packet->item_offset = offset; |
|
1090 packet->item_count++; |
|
1091 packet->entry_offset = 4; |
|
1092 |
|
1093 return TRUE; |
|
1094 } |
|
1095 |
|
1096 /** |
|
1097 * gst_rtcp_packet_sdes_get_ssrc: |
|
1098 * @packet: a valid SDES #GstRTCPPacket |
|
1099 * |
|
1100 * Get the SSRC of the current SDES item. |
|
1101 * |
|
1102 * Returns: the SSRC of the current item. |
|
1103 */ |
|
1104 #ifdef __SYMBIAN32__ |
|
1105 EXPORT_C |
|
1106 #endif |
|
1107 |
|
1108 guint32 |
|
1109 gst_rtcp_packet_sdes_get_ssrc (GstRTCPPacket * packet) |
|
1110 { |
|
1111 guint32 ssrc; |
|
1112 guint8 *data; |
|
1113 |
|
1114 g_return_val_if_fail (packet != NULL, 0); |
|
1115 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, 0); |
|
1116 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); |
|
1117 |
|
1118 /* move to SDES */ |
|
1119 data = GST_BUFFER_DATA (packet->buffer); |
|
1120 data += packet->offset; |
|
1121 /* move to item */ |
|
1122 data += packet->item_offset; |
|
1123 |
|
1124 ssrc = GST_READ_UINT32_BE (data); |
|
1125 |
|
1126 return ssrc; |
|
1127 } |
|
1128 |
|
1129 /** |
|
1130 * gst_rtcp_packet_sdes_first_entry: |
|
1131 * @packet: a valid SDES #GstRTCPPacket |
|
1132 * |
|
1133 * Move to the first SDES entry in the current item. |
|
1134 * |
|
1135 * Returns: %TRUE if there was a first entry. |
|
1136 */ |
|
1137 #ifdef __SYMBIAN32__ |
|
1138 EXPORT_C |
|
1139 #endif |
|
1140 |
|
1141 gboolean |
|
1142 gst_rtcp_packet_sdes_first_entry (GstRTCPPacket * packet) |
|
1143 { |
|
1144 guint8 *data; |
|
1145 guint len, offset; |
|
1146 |
|
1147 g_return_val_if_fail (packet != NULL, FALSE); |
|
1148 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE); |
|
1149 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1150 |
|
1151 /* move to SDES */ |
|
1152 data = GST_BUFFER_DATA (packet->buffer); |
|
1153 data += packet->offset; |
|
1154 /* move to item */ |
|
1155 offset = packet->item_offset; |
|
1156 /* skip SSRC */ |
|
1157 offset += 4; |
|
1158 |
|
1159 packet->entry_offset = 4; |
|
1160 |
|
1161 /* don't overrun */ |
|
1162 len = (packet->length << 2); |
|
1163 if (offset >= len) |
|
1164 return FALSE; |
|
1165 |
|
1166 if (data[offset] == 0) |
|
1167 return FALSE; |
|
1168 |
|
1169 return TRUE; |
|
1170 } |
|
1171 |
|
1172 /** |
|
1173 * gst_rtcp_packet_sdes_next_entry: |
|
1174 * @packet: a valid SDES #GstRTCPPacket |
|
1175 * |
|
1176 * Move to the next SDES entry in the current item. |
|
1177 * |
|
1178 * Returns: %TRUE if there was a next entry. |
|
1179 */ |
|
1180 #ifdef __SYMBIAN32__ |
|
1181 EXPORT_C |
|
1182 #endif |
|
1183 |
|
1184 gboolean |
|
1185 gst_rtcp_packet_sdes_next_entry (GstRTCPPacket * packet) |
|
1186 { |
|
1187 guint8 *data; |
|
1188 guint len, offset, item_len; |
|
1189 |
|
1190 g_return_val_if_fail (packet != NULL, FALSE); |
|
1191 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE); |
|
1192 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1193 |
|
1194 /* move to SDES */ |
|
1195 data = GST_BUFFER_DATA (packet->buffer); |
|
1196 data += packet->offset; |
|
1197 /* move to item */ |
|
1198 offset = packet->item_offset; |
|
1199 /* move to entry */ |
|
1200 offset += packet->entry_offset; |
|
1201 |
|
1202 item_len = data[offset + 1] + 2; |
|
1203 /* skip item */ |
|
1204 offset += item_len; |
|
1205 |
|
1206 /* don't overrun */ |
|
1207 len = (packet->length << 2); |
|
1208 if (offset >= len) |
|
1209 return FALSE; |
|
1210 |
|
1211 packet->entry_offset += item_len; |
|
1212 |
|
1213 /* check for end of list */ |
|
1214 if (data[offset] == 0) |
|
1215 return FALSE; |
|
1216 |
|
1217 return TRUE; |
|
1218 } |
|
1219 |
|
1220 /** |
|
1221 * gst_rtcp_packet_sdes_get_entry: |
|
1222 * @packet: a valid SDES #GstRTCPPacket |
|
1223 * @type: result of the entry type |
|
1224 * @len: result length of the entry data |
|
1225 * @data: result entry data |
|
1226 * |
|
1227 * Get the data of the current SDES item entry. @type (when not NULL) will |
|
1228 * contain the type of the entry. @data (when not NULL) will point to @len |
|
1229 * bytes. |
|
1230 * |
|
1231 * When @type refers to a text item, @data will point to a UTF8 string. Note |
|
1232 * that this UTF8 string is NOT null-terminated. Use |
|
1233 * gst_rtcp_packet_sdes_copy_entry() to get a null-termined copy of the entry. |
|
1234 * |
|
1235 * Returns: %TRUE if there was valid data. |
|
1236 */ |
|
1237 #ifdef __SYMBIAN32__ |
|
1238 EXPORT_C |
|
1239 #endif |
|
1240 |
|
1241 gboolean |
|
1242 gst_rtcp_packet_sdes_get_entry (GstRTCPPacket * packet, |
|
1243 GstRTCPSDESType * type, guint8 * len, guint8 ** data) |
|
1244 { |
|
1245 guint8 *bdata; |
|
1246 guint offset; |
|
1247 |
|
1248 g_return_val_if_fail (packet != NULL, FALSE); |
|
1249 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE); |
|
1250 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1251 |
|
1252 /* move to SDES */ |
|
1253 bdata = GST_BUFFER_DATA (packet->buffer); |
|
1254 bdata += packet->offset; |
|
1255 /* move to item */ |
|
1256 offset = packet->item_offset; |
|
1257 /* move to entry */ |
|
1258 offset += packet->entry_offset; |
|
1259 |
|
1260 if (bdata[offset] == 0) |
|
1261 return FALSE; |
|
1262 |
|
1263 if (type) |
|
1264 *type = bdata[offset]; |
|
1265 if (len) |
|
1266 *len = bdata[offset + 1]; |
|
1267 if (data) |
|
1268 *data = &bdata[offset + 2]; |
|
1269 |
|
1270 return TRUE; |
|
1271 } |
|
1272 |
|
1273 /** |
|
1274 * gst_rtcp_packet_sdes_copy_entry: |
|
1275 * @packet: a valid SDES #GstRTCPPacket |
|
1276 * @type: result of the entry type |
|
1277 * @len: result length of the entry data |
|
1278 * @data: result entry data |
|
1279 * |
|
1280 * This function is like gst_rtcp_packet_sdes_get_entry() but it returns a |
|
1281 * null-terminated copy of the data instead. use g_free() after usage. |
|
1282 * |
|
1283 * Returns: %TRUE if there was valid data. |
|
1284 */ |
|
1285 #ifdef __SYMBIAN32__ |
|
1286 EXPORT_C |
|
1287 #endif |
|
1288 |
|
1289 gboolean |
|
1290 gst_rtcp_packet_sdes_copy_entry (GstRTCPPacket * packet, |
|
1291 GstRTCPSDESType * type, guint8 * len, guint8 ** data) |
|
1292 { |
|
1293 guint8 *tdata; |
|
1294 guint8 tlen; |
|
1295 |
|
1296 g_return_val_if_fail (packet != NULL, FALSE); |
|
1297 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE); |
|
1298 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1299 |
|
1300 if (!gst_rtcp_packet_sdes_get_entry (packet, type, &tlen, &tdata)) |
|
1301 return FALSE; |
|
1302 |
|
1303 if (len) |
|
1304 *len = tlen; |
|
1305 if (data) |
|
1306 *data = (guint8 *) g_strndup ((gchar *) tdata, tlen); |
|
1307 |
|
1308 return TRUE; |
|
1309 } |
|
1310 |
|
1311 /** |
|
1312 * gst_rtcp_packet_sdes_add_item: |
|
1313 * @packet: a valid SDES #GstRTCPPacket |
|
1314 * @ssrc: the SSRC of the new item to add |
|
1315 * |
|
1316 * Add a new SDES item for @ssrc to @packet. |
|
1317 * |
|
1318 * Returns: %TRUE if the item could be added, %FALSE if the maximum amount of |
|
1319 * items has been exceeded for the SDES packet or the MTU has been reached. |
|
1320 */ |
|
1321 #ifdef __SYMBIAN32__ |
|
1322 EXPORT_C |
|
1323 #endif |
|
1324 |
|
1325 gboolean |
|
1326 gst_rtcp_packet_sdes_add_item (GstRTCPPacket * packet, guint32 ssrc) |
|
1327 { |
|
1328 guint8 *data; |
|
1329 guint offset, size; |
|
1330 |
|
1331 g_return_val_if_fail (packet != NULL, FALSE); |
|
1332 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE); |
|
1333 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1334 |
|
1335 /* increment item count when possible */ |
|
1336 if (packet->count >= GST_RTCP_MAX_SDES_ITEM_COUNT) |
|
1337 goto no_space; |
|
1338 |
|
1339 /* pretend there is a next packet for the next call */ |
|
1340 packet->count++; |
|
1341 |
|
1342 /* jump over current item */ |
|
1343 gst_rtcp_packet_sdes_next_item (packet); |
|
1344 |
|
1345 /* move to SDES */ |
|
1346 data = GST_BUFFER_DATA (packet->buffer); |
|
1347 size = GST_BUFFER_SIZE (packet->buffer); |
|
1348 data += packet->offset; |
|
1349 /* move to current item */ |
|
1350 offset = packet->item_offset; |
|
1351 |
|
1352 /* we need 2 free words now */ |
|
1353 if (offset + 8 >= size) |
|
1354 goto no_next; |
|
1355 |
|
1356 /* write SSRC */ |
|
1357 GST_WRITE_UINT32_BE (&data[offset], ssrc); |
|
1358 /* write 0 entry with padding */ |
|
1359 GST_WRITE_UINT32_BE (&data[offset + 4], 0); |
|
1360 |
|
1361 /* update count */ |
|
1362 data[0] = (data[0] & 0xe0) | packet->count; |
|
1363 /* update length, we added 2 words */ |
|
1364 packet->length += 2; |
|
1365 data[2] = (packet->length) >> 8; |
|
1366 data[3] = (packet->length) & 0xff; |
|
1367 |
|
1368 return TRUE; |
|
1369 |
|
1370 /* ERRORS */ |
|
1371 no_space: |
|
1372 { |
|
1373 return FALSE; |
|
1374 } |
|
1375 no_next: |
|
1376 { |
|
1377 packet->count--; |
|
1378 return FALSE; |
|
1379 } |
|
1380 } |
|
1381 |
|
1382 /** |
|
1383 * gst_rtcp_packet_sdes_add_entry: |
|
1384 * @packet: a valid SDES #GstRTCPPacket |
|
1385 * @type: the #GstRTCPSDESType of the SDES entry |
|
1386 * @len: the data length |
|
1387 * @data: the data |
|
1388 * |
|
1389 * Add a new SDES entry to the current item in @packet. |
|
1390 * |
|
1391 * Returns: %TRUE if the item could be added, %FALSE if the MTU has been |
|
1392 * reached. |
|
1393 */ |
|
1394 #ifdef __SYMBIAN32__ |
|
1395 EXPORT_C |
|
1396 #endif |
|
1397 |
|
1398 gboolean |
|
1399 gst_rtcp_packet_sdes_add_entry (GstRTCPPacket * packet, GstRTCPSDESType type, |
|
1400 guint8 len, const guint8 * data) |
|
1401 { |
|
1402 guint8 *bdata; |
|
1403 guint offset, size, padded; |
|
1404 |
|
1405 g_return_val_if_fail (packet != NULL, FALSE); |
|
1406 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_SDES, FALSE); |
|
1407 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1408 |
|
1409 /* move to SDES */ |
|
1410 bdata = GST_BUFFER_DATA (packet->buffer); |
|
1411 size = GST_BUFFER_SIZE (packet->buffer); |
|
1412 bdata += packet->offset; |
|
1413 /* move to item */ |
|
1414 offset = packet->item_offset; |
|
1415 /* move to entry */ |
|
1416 offset += packet->entry_offset; |
|
1417 |
|
1418 /* add 1 byte end and up to 3 bytes padding to fill a full 32 bit word */ |
|
1419 padded = (offset + 2 + len + 1 + 3) & ~3; |
|
1420 |
|
1421 /* we need enough space for type, len, data and padding */ |
|
1422 if (packet->offset + padded >= size) |
|
1423 goto no_space; |
|
1424 |
|
1425 bdata[offset] = type; |
|
1426 bdata[offset + 1] = len; |
|
1427 memcpy (&bdata[offset + 2], data, len); |
|
1428 bdata[offset + 2 + len] = 0; |
|
1429 |
|
1430 /* calculate new packet length */ |
|
1431 packet->length = (padded - 4) >> 2; |
|
1432 bdata[2] = (packet->length) >> 8; |
|
1433 bdata[3] = (packet->length) & 0xff; |
|
1434 |
|
1435 /* position to new next entry */ |
|
1436 packet->entry_offset += 2 + len; |
|
1437 |
|
1438 return TRUE; |
|
1439 |
|
1440 /* ERRORS */ |
|
1441 no_space: |
|
1442 { |
|
1443 return FALSE; |
|
1444 } |
|
1445 } |
|
1446 |
|
1447 /** |
|
1448 * gst_rtcp_packet_bye_get_ssrc_count: |
|
1449 * @packet: a valid BYE #GstRTCPPacket |
|
1450 * |
|
1451 * Get the number of SSRC fields in @packet. |
|
1452 * |
|
1453 * Returns: The number of SSRC fields in @packet. |
|
1454 */ |
|
1455 #ifdef __SYMBIAN32__ |
|
1456 EXPORT_C |
|
1457 #endif |
|
1458 |
|
1459 guint |
|
1460 gst_rtcp_packet_bye_get_ssrc_count (GstRTCPPacket * packet) |
|
1461 { |
|
1462 g_return_val_if_fail (packet != NULL, -1); |
|
1463 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, -1); |
|
1464 |
|
1465 return packet->count; |
|
1466 } |
|
1467 |
|
1468 /** |
|
1469 * gst_rtcp_packet_bye_get_nth_ssrc: |
|
1470 * @packet: a valid BYE #GstRTCPPacket |
|
1471 * @nth: the nth SSRC to get |
|
1472 * |
|
1473 * Get the @nth SSRC of the BYE @packet. |
|
1474 * |
|
1475 * Returns: The @nth SSRC of @packet. |
|
1476 */ |
|
1477 #ifdef __SYMBIAN32__ |
|
1478 EXPORT_C |
|
1479 #endif |
|
1480 |
|
1481 guint32 |
|
1482 gst_rtcp_packet_bye_get_nth_ssrc (GstRTCPPacket * packet, guint nth) |
|
1483 { |
|
1484 guint8 *data; |
|
1485 guint offset; |
|
1486 guint32 ssrc; |
|
1487 guint8 sc; |
|
1488 |
|
1489 g_return_val_if_fail (packet != NULL, 0); |
|
1490 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0); |
|
1491 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); |
|
1492 |
|
1493 /* get amount of sources and check that we don't read too much */ |
|
1494 sc = packet->count; |
|
1495 if (nth >= sc) |
|
1496 return 0; |
|
1497 |
|
1498 /* get offset in 32-bits words into packet, skip the header */ |
|
1499 offset = 1 + nth; |
|
1500 /* check that we don't go past the packet length */ |
|
1501 if (offset > packet->length) |
|
1502 return 0; |
|
1503 |
|
1504 /* scale to bytes */ |
|
1505 offset <<= 2; |
|
1506 offset += packet->offset; |
|
1507 |
|
1508 /* check if the packet is valid */ |
|
1509 if (offset + 4 > GST_BUFFER_SIZE (packet->buffer)) |
|
1510 return 0; |
|
1511 |
|
1512 data = GST_BUFFER_DATA (packet->buffer); |
|
1513 data += offset; |
|
1514 |
|
1515 ssrc = GST_READ_UINT32_BE (data); |
|
1516 |
|
1517 return ssrc; |
|
1518 } |
|
1519 |
|
1520 /** |
|
1521 * gst_rtcp_packet_bye_add_ssrc: |
|
1522 * @packet: a valid BYE #GstRTCPPacket |
|
1523 * @ssrc: an SSRC to add |
|
1524 * |
|
1525 * Add @ssrc to the BYE @packet. |
|
1526 * |
|
1527 * Returns: %TRUE if the ssrc was added. This function can return %FALSE if |
|
1528 * the max MTU is exceeded or the number of sources blocks is greater than |
|
1529 * #GST_RTCP_MAX_BYE_SSRC_COUNT. |
|
1530 */ |
|
1531 #ifdef __SYMBIAN32__ |
|
1532 EXPORT_C |
|
1533 #endif |
|
1534 |
|
1535 gboolean |
|
1536 gst_rtcp_packet_bye_add_ssrc (GstRTCPPacket * packet, guint32 ssrc) |
|
1537 { |
|
1538 guint8 *data; |
|
1539 guint size, offset; |
|
1540 |
|
1541 g_return_val_if_fail (packet != NULL, FALSE); |
|
1542 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE); |
|
1543 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1544 |
|
1545 if (packet->count >= GST_RTCP_MAX_BYE_SSRC_COUNT) |
|
1546 goto no_space; |
|
1547 |
|
1548 data = GST_BUFFER_DATA (packet->buffer); |
|
1549 size = GST_BUFFER_SIZE (packet->buffer); |
|
1550 |
|
1551 /* skip header */ |
|
1552 offset = packet->offset + 4; |
|
1553 |
|
1554 /* move to current index */ |
|
1555 offset += (packet->count * 4); |
|
1556 |
|
1557 if (offset + 4 >= size) |
|
1558 goto no_space; |
|
1559 |
|
1560 /* increment packet count and length */ |
|
1561 packet->count++; |
|
1562 data[packet->offset]++; |
|
1563 packet->length += 1; |
|
1564 data[packet->offset + 2] = (packet->length) >> 8; |
|
1565 data[packet->offset + 3] = (packet->length) & 0xff; |
|
1566 |
|
1567 /* move to new SSRC offset and write ssrc */ |
|
1568 data += offset; |
|
1569 GST_WRITE_UINT32_BE (data, ssrc); |
|
1570 |
|
1571 return TRUE; |
|
1572 |
|
1573 /* ERRORS */ |
|
1574 no_space: |
|
1575 { |
|
1576 return FALSE; |
|
1577 } |
|
1578 } |
|
1579 |
|
1580 /** |
|
1581 * gst_rtcp_packet_bye_add_ssrcs: |
|
1582 * @packet: a valid BYE #GstRTCPPacket |
|
1583 * @ssrc: an array of SSRCs to add |
|
1584 * @len: number of elements in @ssrc |
|
1585 * |
|
1586 * Adds @len SSRCs in @ssrc to BYE @packet. |
|
1587 * |
|
1588 * Returns: %TRUE if the all the SSRCs were added. This function can return %FALSE if |
|
1589 * the max MTU is exceeded or the number of sources blocks is greater than |
|
1590 * #GST_RTCP_MAX_BYE_SSRC_COUNT. |
|
1591 */ |
|
1592 #ifdef __SYMBIAN32__ |
|
1593 EXPORT_C |
|
1594 #endif |
|
1595 |
|
1596 gboolean |
|
1597 gst_rtcp_packet_bye_add_ssrcs (GstRTCPPacket * packet, guint32 * ssrc, |
|
1598 guint len) |
|
1599 { |
|
1600 guint i; |
|
1601 gboolean res; |
|
1602 |
|
1603 g_return_val_if_fail (packet != NULL, FALSE); |
|
1604 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE); |
|
1605 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1606 |
|
1607 res = TRUE; |
|
1608 for (i = 0; i < len && res; i++) { |
|
1609 res = gst_rtcp_packet_bye_add_ssrc (packet, ssrc[i]); |
|
1610 } |
|
1611 return res; |
|
1612 } |
|
1613 |
|
1614 /* get the offset in packet of the reason length */ |
|
1615 static guint |
|
1616 get_reason_offset (GstRTCPPacket * packet) |
|
1617 { |
|
1618 guint offset; |
|
1619 |
|
1620 /* get amount of sources plus header */ |
|
1621 offset = 1 + packet->count; |
|
1622 |
|
1623 /* check that we don't go past the packet length */ |
|
1624 if (offset > packet->length) |
|
1625 return 0; |
|
1626 |
|
1627 /* scale to bytes */ |
|
1628 offset <<= 2; |
|
1629 offset += packet->offset; |
|
1630 |
|
1631 /* check if the packet is valid */ |
|
1632 if (offset + 1 > GST_BUFFER_SIZE (packet->buffer)) |
|
1633 return 0; |
|
1634 |
|
1635 return offset; |
|
1636 } |
|
1637 |
|
1638 /** |
|
1639 * gst_rtcp_packet_bye_get_reason_len: |
|
1640 * @packet: a valid BYE #GstRTCPPacket |
|
1641 * |
|
1642 * Get the length of the reason string. |
|
1643 * |
|
1644 * Returns: The length of the reason string or 0 when there is no reason string |
|
1645 * present. |
|
1646 */ |
|
1647 #ifdef __SYMBIAN32__ |
|
1648 EXPORT_C |
|
1649 #endif |
|
1650 |
|
1651 guint8 |
|
1652 gst_rtcp_packet_bye_get_reason_len (GstRTCPPacket * packet) |
|
1653 { |
|
1654 guint8 *data; |
|
1655 guint roffset; |
|
1656 |
|
1657 g_return_val_if_fail (packet != NULL, 0); |
|
1658 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, 0); |
|
1659 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0); |
|
1660 |
|
1661 roffset = get_reason_offset (packet); |
|
1662 if (roffset == 0) |
|
1663 return 0; |
|
1664 |
|
1665 data = GST_BUFFER_DATA (packet->buffer); |
|
1666 |
|
1667 return data[roffset]; |
|
1668 } |
|
1669 |
|
1670 /** |
|
1671 * gst_rtcp_packet_bye_get_reason: |
|
1672 * @packet: a valid BYE #GstRTCPPacket |
|
1673 * |
|
1674 * Get the reason in @packet. |
|
1675 * |
|
1676 * Returns: The reason for the BYE @packet or NULL if the packet did not contain |
|
1677 * a reason string. The string must be freed with g_free() after usage. |
|
1678 */ |
|
1679 #ifdef __SYMBIAN32__ |
|
1680 EXPORT_C |
|
1681 #endif |
|
1682 |
|
1683 gchar * |
|
1684 gst_rtcp_packet_bye_get_reason (GstRTCPPacket * packet) |
|
1685 { |
|
1686 guint8 *data; |
|
1687 guint roffset; |
|
1688 guint8 len; |
|
1689 |
|
1690 g_return_val_if_fail (packet != NULL, NULL); |
|
1691 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, NULL); |
|
1692 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), NULL); |
|
1693 |
|
1694 roffset = get_reason_offset (packet); |
|
1695 if (roffset == 0) |
|
1696 return NULL; |
|
1697 |
|
1698 data = GST_BUFFER_DATA (packet->buffer); |
|
1699 |
|
1700 /* get length of reason string */ |
|
1701 len = data[roffset]; |
|
1702 if (len == 0) |
|
1703 return NULL; |
|
1704 |
|
1705 /* move to string */ |
|
1706 roffset += 1; |
|
1707 |
|
1708 /* check if enough data to copy */ |
|
1709 if (roffset + len > GST_BUFFER_SIZE (packet->buffer)) |
|
1710 return NULL; |
|
1711 |
|
1712 return g_strndup ((gconstpointer) (data + roffset), len); |
|
1713 } |
|
1714 |
|
1715 /** |
|
1716 * gst_rtcp_packet_bye_set_reason: |
|
1717 * @packet: a valid BYE #GstRTCPPacket |
|
1718 * @reason: a reason string |
|
1719 * |
|
1720 * Set the reason string to @reason in @packet. |
|
1721 * |
|
1722 * Returns: TRUE if the string could be set. |
|
1723 */ |
|
1724 #ifdef __SYMBIAN32__ |
|
1725 EXPORT_C |
|
1726 #endif |
|
1727 |
|
1728 gboolean |
|
1729 gst_rtcp_packet_bye_set_reason (GstRTCPPacket * packet, const gchar * reason) |
|
1730 { |
|
1731 guint8 *data; |
|
1732 guint roffset, size; |
|
1733 guint8 len, padded; |
|
1734 |
|
1735 g_return_val_if_fail (packet != NULL, FALSE); |
|
1736 g_return_val_if_fail (packet->type == GST_RTCP_TYPE_BYE, FALSE); |
|
1737 g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), FALSE); |
|
1738 |
|
1739 if (reason == NULL) |
|
1740 return TRUE; |
|
1741 |
|
1742 len = strlen (reason); |
|
1743 if (len == 0) |
|
1744 return TRUE; |
|
1745 |
|
1746 /* make room for the string before we get the offset */ |
|
1747 packet->length++; |
|
1748 |
|
1749 roffset = get_reason_offset (packet); |
|
1750 if (roffset == 0) |
|
1751 goto no_space; |
|
1752 |
|
1753 data = GST_BUFFER_DATA (packet->buffer); |
|
1754 size = GST_BUFFER_SIZE (packet->buffer); |
|
1755 |
|
1756 /* we have 1 byte length and we need to pad to 4 bytes */ |
|
1757 padded = ((len + 1) + 3) & ~3; |
|
1758 |
|
1759 /* we need enough space for the padded length */ |
|
1760 if (roffset + padded >= size) |
|
1761 goto no_space; |
|
1762 |
|
1763 data[roffset] = len; |
|
1764 memcpy (&data[roffset + 1], reason, len); |
|
1765 |
|
1766 /* update packet length, we made room for 1 double word already */ |
|
1767 packet->length += (padded >> 2) - 1; |
|
1768 data[packet->offset + 2] = (packet->length) >> 8; |
|
1769 data[packet->offset + 3] = (packet->length) & 0xff; |
|
1770 |
|
1771 return TRUE; |
|
1772 |
|
1773 /* ERRORS */ |
|
1774 no_space: |
|
1775 { |
|
1776 packet->length--; |
|
1777 return FALSE; |
|
1778 } |
|
1779 } |
|
1780 |
|
1781 /** |
|
1782 * gst_rtcp_ntp_to_unix: |
|
1783 * @ntptime: an NTP timestamp |
|
1784 * |
|
1785 * Converts an NTP time to UNIX nanoseconds. @ntptime can typically be |
|
1786 * the NTP time of an SR RTCP message and contains, in the upper 32 bits, the |
|
1787 * number of seconds since 1900 and, in the lower 32 bits, the fractional |
|
1788 * seconds. The resulting value will be the number of nanoseconds since 1970. |
|
1789 * |
|
1790 * Returns: the UNIX time for @ntptime in nanoseconds. |
|
1791 */ |
|
1792 #ifdef __SYMBIAN32__ |
|
1793 EXPORT_C |
|
1794 #endif |
|
1795 |
|
1796 guint64 |
|
1797 gst_rtcp_ntp_to_unix (guint64 ntptime) |
|
1798 { |
|
1799 guint64 unixtime; |
|
1800 |
|
1801 /* conversion from NTP timestamp (seconds since 1900) to seconds since |
|
1802 * 1970. */ |
|
1803 unixtime = ntptime - (G_GUINT64_CONSTANT (2208988800) << 32); |
|
1804 /* conversion to nanoseconds */ |
|
1805 unixtime = |
|
1806 gst_util_uint64_scale (unixtime, GST_SECOND, |
|
1807 (G_GINT64_CONSTANT (1) << 32)); |
|
1808 |
|
1809 return unixtime; |
|
1810 } |
|
1811 |
|
1812 /** |
|
1813 * gst_rtcp_unix_to_ntp: |
|
1814 * @unixtime: an UNIX timestamp in nanoseconds |
|
1815 * |
|
1816 * Converts a UNIX timestamp in nanoseconds to an NTP time. The caller should |
|
1817 * pass a value with nanoseconds since 1970. The NTP time will, in the upper |
|
1818 * 32 bits, contain the number of seconds since 1900 and, in the lower 32 |
|
1819 * bits, the fractional seconds. The resulting value can be used as an ntptime |
|
1820 * for constructing SR RTCP packets. |
|
1821 * |
|
1822 * Returns: the NTP time for @gsttime. |
|
1823 */ |
|
1824 #ifdef __SYMBIAN32__ |
|
1825 EXPORT_C |
|
1826 #endif |
|
1827 |
|
1828 guint64 |
|
1829 gst_rtcp_unix_to_ntp (guint64 unixtime) |
|
1830 { |
|
1831 guint64 ntptime; |
|
1832 |
|
1833 /* convert clock time to NTP time. upper 32 bits should contain the seconds |
|
1834 * and the lower 32 bits, the fractions of a second. */ |
|
1835 ntptime = |
|
1836 gst_util_uint64_scale (unixtime, (G_GINT64_CONSTANT (1) << 32), |
|
1837 GST_SECOND); |
|
1838 /* conversion from UNIX timestamp (seconds since 1970) to NTP (seconds |
|
1839 * since 1900). */ |
|
1840 ntptime += (G_GUINT64_CONSTANT (2208988800) << 32); |
|
1841 |
|
1842 return ntptime; |
|
1843 } |