gst_plugins_base/gst-libs/gst/rtp/gstrtcpbuffer.c
changeset 0 0e761a78d257
child 7 567bb019e3e3
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     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 }