gst_plugins_base/gst-libs/gst/sdp/gstsdpmessage.c
changeset 0 0e761a78d257
child 8 4a7fac7dd34a
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     1 /* GStreamer
       
     2  * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
       
     3  *
       
     4  * This library is free software; you can redistribute it and/or
       
     5  * modify it under the terms of the GNU Library General Public
       
     6  * License as published by the Free Software Foundation; either
       
     7  * version 2 of the License, or (at your option) any later version.
       
     8  *
       
     9  * This library is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    12  * Library General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU Library General Public
       
    15  * License along with this library; if not, write to the
       
    16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    17  * Boston, MA 02111-1307, USA.
       
    18  */
       
    19 /*
       
    20  * Unless otherwise indicated, Source Code is licensed under MIT license.
       
    21  * See further explanation attached in License Statement (distributed in the file
       
    22  * LICENSE).
       
    23  *
       
    24  * Permission is hereby granted, free of charge, to any person obtaining a copy of
       
    25  * this software and associated documentation files (the "Software"), to deal in
       
    26  * the Software without restriction, including without limitation the rights to
       
    27  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
       
    28  * of the Software, and to permit persons to whom the Software is furnished to do
       
    29  * so, subject to the following conditions:
       
    30  *
       
    31  * The above copyright notice and this permission notice shall be included in all
       
    32  * copies or substantial portions of the Software.
       
    33  *
       
    34  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
       
    35  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
       
    36  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
       
    37  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
       
    38  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
       
    39  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
       
    40  * SOFTWARE.
       
    41  */
       
    42 
       
    43 /**
       
    44  * SECTION:gstsdpmessage
       
    45  * @short_description: Helper methods for dealing with SDP messages
       
    46  *
       
    47  * <refsect2>
       
    48  * <para>
       
    49  * The GstSDPMessage helper functions makes it easy to parse and create SDP
       
    50  * messages.
       
    51  * </para>
       
    52  * </refsect2>
       
    53  *
       
    54  * Last reviewed on 2007-07-24 (0.10.14)
       
    55  */
       
    56 
       
    57 #ifdef HAVE_CONFIG_H
       
    58 #include "config.h"
       
    59 #endif
       
    60 
       
    61 #include <stdlib.h>
       
    62 #include <string.h>
       
    63 
       
    64 #ifdef HAVE_SYS_TYPES_H
       
    65 #include <sys/types.h>
       
    66 #endif
       
    67 
       
    68 #include <glib.h>               /* for G_OS_WIN32 */
       
    69 #include <gst/gstinfo.h>        /* For GST_STR_NULL */
       
    70 
       
    71 #ifdef G_OS_WIN32
       
    72 #ifdef _MSC_VER
       
    73 #include <Winsock2.h>
       
    74 #endif
       
    75 #include <ws2tcpip.h>
       
    76 #else
       
    77 #include <sys/socket.h>
       
    78 #include <netdb.h>
       
    79 #include <netinet/in.h>
       
    80 #endif
       
    81 
       
    82 #include "gstsdpmessage.h"
       
    83 
       
    84 /* FIXME, is currently allocated on the stack */
       
    85 #define MAX_LINE_LEN    1024 * 16
       
    86 
       
    87 #define FREE_STRING(field)              g_free (field); (field) = NULL
       
    88 #define REPLACE_STRING(field, val)      FREE_STRING(field); (field) = g_strdup (val)
       
    89 
       
    90 #define INIT_ARRAY(field, type, init_func)              \
       
    91 G_STMT_START {                                          \
       
    92   if (field) {                                          \
       
    93     guint i;                                            \
       
    94     for(i = 0; i < (field)->len; i++)                   \
       
    95       init_func (&g_array_index ((field), type, i));    \
       
    96     g_array_set_size ((field), 0);                      \
       
    97   }                                                     \
       
    98   else                                                  \
       
    99     (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
       
   100 } G_STMT_END
       
   101 
       
   102 #define FREE_ARRAY(field)         \
       
   103 G_STMT_START {                    \
       
   104   if (field)                      \
       
   105     g_array_free ((field), TRUE); \
       
   106   (field) = NULL;                 \
       
   107 } G_STMT_END
       
   108 
       
   109 #define INIT_PTR_ARRAY(field, type, init_func)          \
       
   110 G_STMT_START {                                          \
       
   111   if (field) {                                          \
       
   112     guint i;                                            \
       
   113     for(i = 0; i < (field)->len; i++)                   \
       
   114       init_func (g_array_index ((field), type, i));     \
       
   115     g_array_set_size ((field), 0);                      \
       
   116   }                                                     \
       
   117   else                                                  \
       
   118     (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
       
   119 } G_STMT_END
       
   120 
       
   121 #define FREE_PTR_ARRAY(field) FREE_ARRAY(field)
       
   122 
       
   123 #define DEFINE_STRING_SETTER(field)                                     \
       
   124 GstSDPResult gst_sdp_message_set_##field (GstSDPMessage *msg, const gchar *val) { \
       
   125   g_free (msg->field);                                                  \
       
   126   msg->field = g_strdup (val);                                          \
       
   127   return GST_SDP_OK;                                                    \
       
   128 }
       
   129 #define DEFINE_STRING_GETTER(field)                                     \
       
   130 const gchar* gst_sdp_message_get_##field (const GstSDPMessage *msg) {   \
       
   131   return msg->field;                                                    \
       
   132 }
       
   133 
       
   134 #define DEFINE_ARRAY_LEN(field)                                         \
       
   135 guint gst_sdp_message_##field##_len (const GstSDPMessage *msg) {        \
       
   136   return msg->field->len;                                               \
       
   137 }
       
   138 #define DEFINE_ARRAY_GETTER(method, field, type)                        \
       
   139 type * gst_sdp_message_get_##method (const GstSDPMessage *msg, guint idx) {  \
       
   140   return &g_array_index (msg->field, type, idx);                        \
       
   141 }
       
   142 
       
   143 #define DEFINE_PTR_ARRAY_LEN(field) DEFINE_ARRAY_LEN(field)
       
   144 #define DEFINE_PTR_ARRAY_GETTER(method, field, type)                    \
       
   145 type gst_sdp_message_get_##method (const GstSDPMessage *msg, guint idx) {    \
       
   146   return g_array_index (msg->field, type, idx);                         \
       
   147 }
       
   148 #define DEFINE_PTR_ARRAY_ADDER(method, field, type, dup_method)         \
       
   149 GstSDPResult gst_sdp_message_add_##method (GstSDPMessage *msg, type val) {   \
       
   150   type v = dup_method (val);                                            \
       
   151   g_array_append_val (msg->field, v);                                   \
       
   152   return GST_SDP_OK;                                                    \
       
   153 }
       
   154 #ifdef __SYMBIAN32__
       
   155 EXPORT_C
       
   156 #endif
       
   157 
       
   158 
       
   159 static void
       
   160 gst_sdp_origin_init (GstSDPOrigin * origin)
       
   161 {
       
   162   FREE_STRING (origin->username);
       
   163   FREE_STRING (origin->sess_id);
       
   164   FREE_STRING (origin->sess_version);
       
   165   FREE_STRING (origin->nettype);
       
   166   FREE_STRING (origin->addrtype);
       
   167   FREE_STRING (origin->addr);
       
   168 }
       
   169 
       
   170 static void
       
   171 gst_sdp_connection_init (GstSDPConnection * connection)
       
   172 {
       
   173   FREE_STRING (connection->nettype);
       
   174   FREE_STRING (connection->addrtype);
       
   175   FREE_STRING (connection->address);
       
   176   connection->ttl = 0;
       
   177   connection->addr_number = 0;
       
   178 }
       
   179 
       
   180 static void
       
   181 gst_sdp_bandwidth_init (GstSDPBandwidth * bandwidth)
       
   182 {
       
   183   FREE_STRING (bandwidth->bwtype);
       
   184   bandwidth->bandwidth = 0;
       
   185 }
       
   186 
       
   187 static void
       
   188 gst_sdp_time_init (GstSDPTime * t)
       
   189 {
       
   190   FREE_STRING (t->start);
       
   191   FREE_STRING (t->stop);
       
   192   INIT_PTR_ARRAY (t->repeat, gchar *, g_free);
       
   193   FREE_PTR_ARRAY (t->repeat);
       
   194 }
       
   195 
       
   196 static void
       
   197 gst_sdp_zone_init (GstSDPZone * zone)
       
   198 {
       
   199   FREE_STRING (zone->time);
       
   200   FREE_STRING (zone->typed_time);
       
   201 }
       
   202 
       
   203 static void
       
   204 gst_sdp_key_init (GstSDPKey * key)
       
   205 {
       
   206   FREE_STRING (key->type);
       
   207   FREE_STRING (key->data);
       
   208 }
       
   209 
       
   210 static void
       
   211 gst_sdp_attribute_init (GstSDPAttribute * attr)
       
   212 {
       
   213   FREE_STRING (attr->key);
       
   214   FREE_STRING (attr->value);
       
   215 }
       
   216 
       
   217 /**
       
   218  * gst_sdp_message_new:
       
   219  * @msg: pointer to new #GstSDPMessage
       
   220  *
       
   221  * Allocate a new GstSDPMessage and store the result in @msg.
       
   222  *
       
   223  * Returns: a #GstSDPResult.
       
   224  */
       
   225 GstSDPResult
       
   226 gst_sdp_message_new (GstSDPMessage ** msg)
       
   227 {
       
   228   GstSDPMessage *newmsg;
       
   229 
       
   230   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
       
   231 
       
   232   newmsg = g_new0 (GstSDPMessage, 1);
       
   233 
       
   234   *msg = newmsg;
       
   235 
       
   236   return gst_sdp_message_init (newmsg);
       
   237 }
       
   238 
       
   239 /**
       
   240  * gst_sdp_message_init:
       
   241  * @msg: a #GstSDPMessage
       
   242  *
       
   243  * Initialize @msg so that its contents are as if it was freshly allocated
       
   244  * with gst_sdp_message_new(). This function is mostly used to initialize a message
       
   245  * allocated on the stack. gst_sdp_message_uninit() undoes this operation.
       
   246  *
       
   247  * When this function is invoked on newly allocated data (with malloc or on the
       
   248  * stack), its contents should be set to 0 before calling this function.
       
   249  *
       
   250  * Returns: a #GstSDPResult.
       
   251  */
       
   252 GstSDPResult
       
   253 gst_sdp_message_init (GstSDPMessage * msg)
       
   254 {
       
   255   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
       
   256 
       
   257   FREE_STRING (msg->version);
       
   258   gst_sdp_origin_init (&msg->origin);
       
   259   FREE_STRING (msg->session_name);
       
   260   FREE_STRING (msg->information);
       
   261   FREE_STRING (msg->uri);
       
   262   INIT_PTR_ARRAY (msg->emails, gchar *, g_free);
       
   263   INIT_PTR_ARRAY (msg->phones, gchar *, g_free);
       
   264   gst_sdp_connection_init (&msg->connection);
       
   265   INIT_ARRAY (msg->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_init);
       
   266   INIT_ARRAY (msg->times, GstSDPTime, gst_sdp_time_init);
       
   267   INIT_ARRAY (msg->zones, GstSDPZone, gst_sdp_zone_init);
       
   268   gst_sdp_key_init (&msg->key);
       
   269   INIT_ARRAY (msg->attributes, GstSDPAttribute, gst_sdp_attribute_init);
       
   270   INIT_ARRAY (msg->medias, GstSDPMedia, gst_sdp_media_uninit);
       
   271 
       
   272   return GST_SDP_OK;
       
   273 }
       
   274 
       
   275 /**
       
   276  * gst_sdp_message_uninit:
       
   277  * @msg: a #GstSDPMessage
       
   278  *
       
   279  * Free all resources allocated in @msg. @msg should not be used anymore after
       
   280  * this function. This function should be used when @msg was allocated on the
       
   281  * stack and initialized with gst_sdp_message_init().
       
   282  *
       
   283  * Returns: a #GstSDPResult.
       
   284  */
       
   285 GstSDPResult
       
   286 gst_sdp_message_uninit (GstSDPMessage * msg)
       
   287 {
       
   288   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
       
   289 
       
   290   gst_sdp_message_init (msg);
       
   291 
       
   292   FREE_PTR_ARRAY (msg->emails);
       
   293   FREE_PTR_ARRAY (msg->phones);
       
   294   FREE_ARRAY (msg->bandwidths);
       
   295   FREE_ARRAY (msg->times);
       
   296   FREE_ARRAY (msg->zones);
       
   297   FREE_ARRAY (msg->attributes);
       
   298   FREE_ARRAY (msg->medias);
       
   299 
       
   300   return GST_SDP_OK;
       
   301 }
       
   302 
       
   303 /**
       
   304  * gst_sdp_message_free:
       
   305  * @msg: a #GstSDPMessage
       
   306  *
       
   307  * Free all resources allocated by @msg. @msg should not be used anymore after
       
   308  * this function. This function should be used when @msg was dynamically
       
   309  * allocated with gst_sdp_message_new().
       
   310  *
       
   311  * Returns: a #GstSDPResult.
       
   312  */
       
   313 GstSDPResult
       
   314 gst_sdp_message_free (GstSDPMessage * msg)
       
   315 {
       
   316   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
       
   317 
       
   318   gst_sdp_message_uninit (msg);
       
   319   g_free (msg);
       
   320 
       
   321   return GST_SDP_OK;
       
   322 }
       
   323 
       
   324 static gboolean
       
   325 is_multicast_address (const gchar * host_name, guint * family)
       
   326 {
       
   327   struct addrinfo hints;
       
   328   struct addrinfo *ai;
       
   329   struct addrinfo *res;
       
   330   gboolean ret = FALSE;
       
   331   int err;
       
   332 
       
   333   memset (&hints, 0, sizeof (hints));
       
   334   hints.ai_socktype = SOCK_DGRAM;
       
   335 
       
   336   g_return_val_if_fail (host_name, FALSE);
       
   337 
       
   338   if ((err = getaddrinfo (host_name, NULL, &hints, &res)) < 0)
       
   339     return FALSE;
       
   340 
       
   341   for (ai = res; !ret && ai; ai = ai->ai_next) {
       
   342     if (ai->ai_family == AF_INET)
       
   343       ret =
       
   344           IN_MULTICAST (ntohl (((struct sockaddr_in *) ai->ai_addr)->sin_addr.
       
   345               s_addr));
       
   346     else
       
   347       ret =
       
   348           IN6_IS_ADDR_MULTICAST (&((struct sockaddr_in6 *) ai->ai_addr)->
       
   349           sin6_addr);
       
   350     if (ret && family)
       
   351       *family = ai->ai_family;
       
   352   }
       
   353 
       
   354   freeaddrinfo (res);
       
   355 
       
   356   return ret;
       
   357 }
       
   358 
       
   359 /**
       
   360  * gst_sdp_message_as_text:
       
   361  * @msg: a #GstSDPMessage
       
   362  *
       
   363  * Convert the contents of @msg to a text string.
       
   364  *
       
   365  * Returns: A dynamically allocated string representing the SDP description.
       
   366  */
       
   367 gchar *
       
   368 gst_sdp_message_as_text (const GstSDPMessage * msg)
       
   369 {
       
   370   /* change all vars so they match rfc? */
       
   371   GString *lines;
       
   372   guint i;
       
   373 
       
   374   g_return_val_if_fail (msg != NULL, NULL);
       
   375 
       
   376   lines = g_string_new ("");
       
   377 
       
   378   if (msg->version)
       
   379     g_string_append_printf (lines, "v=%s\r\n", msg->version);
       
   380 
       
   381   if (msg->origin.sess_id && msg->origin.sess_version && msg->origin.nettype &&
       
   382       msg->origin.addrtype && msg->origin.addr)
       
   383     g_string_append_printf (lines, "o=%s %s %s %s %s %s\r\n",
       
   384         msg->origin.username ? msg->origin.username : "-", msg->origin.sess_id,
       
   385         msg->origin.sess_version, msg->origin.nettype, msg->origin.addrtype,
       
   386         msg->origin.addr);
       
   387 
       
   388   if (msg->session_name)
       
   389     g_string_append_printf (lines, "s=%s\r\n", msg->session_name);
       
   390 
       
   391   if (msg->information)
       
   392     g_string_append_printf (lines, "i=%s\r\n", msg->information);
       
   393 
       
   394   if (msg->uri)
       
   395     g_string_append_printf (lines, "u=%s\r\n", msg->uri);
       
   396 
       
   397   for (i = 0; i < gst_sdp_message_emails_len (msg); i++)
       
   398     g_string_append_printf (lines, "e=%s\r\n",
       
   399         gst_sdp_message_get_email (msg, i));
       
   400 
       
   401   for (i = 0; i < gst_sdp_message_phones_len (msg); i++)
       
   402     g_string_append_printf (lines, "p=%s\r\n",
       
   403         gst_sdp_message_get_phone (msg, i));
       
   404 
       
   405   if (gst_sdp_message_emails_len (msg) == 0 &&
       
   406       gst_sdp_message_phones_len (msg) == 0)
       
   407     g_string_append_printf (lines, "e=NONE\r\n");
       
   408 
       
   409   if (msg->connection.nettype && msg->connection.addrtype &&
       
   410       msg->connection.address) {
       
   411     guint family;
       
   412 
       
   413     g_string_append_printf (lines, "c=%s %s %s", msg->connection.nettype,
       
   414         msg->connection.addrtype, msg->connection.address);
       
   415     if (is_multicast_address (msg->connection.address, &family)) {
       
   416       if (family == AF_INET)
       
   417         g_string_append_printf (lines, "/%u", msg->connection.ttl);
       
   418       if (msg->connection.addr_number > 1)
       
   419         g_string_append_printf (lines, "/%u", msg->connection.addr_number);
       
   420     }
       
   421     g_string_append_printf (lines, "\r\n");
       
   422   }
       
   423 
       
   424   for (i = 0; i < gst_sdp_message_bandwidths_len (msg); i++) {
       
   425     const GstSDPBandwidth *bandwidth = gst_sdp_message_get_bandwidth (msg, i);
       
   426 
       
   427     g_string_append_printf (lines, "b=%s:%u\r\n", bandwidth->bwtype,
       
   428         bandwidth->bandwidth);
       
   429   }
       
   430 
       
   431   for (i = 0; i < gst_sdp_message_times_len (msg); i++) {
       
   432     const GstSDPTime *times = gst_sdp_message_get_time (msg, i);
       
   433 
       
   434     g_string_append_printf (lines, "t=%s %s\r\n", times->start, times->stop);
       
   435 
       
   436     if (times->repeat != NULL) {
       
   437       guint j;
       
   438 
       
   439       g_string_append_printf (lines, "r=%s",
       
   440           g_array_index (times->repeat, gchar *, 0));
       
   441       for (j = 1; j < times->repeat->len; j++)
       
   442         g_string_append_printf (lines, " %s",
       
   443             g_array_index (times->repeat, gchar *, j));
       
   444       g_string_append_printf (lines, "\r\n");
       
   445     }
       
   446   }
       
   447 
       
   448   if (gst_sdp_message_zones_len (msg) > 0) {
       
   449     const GstSDPZone *zone = gst_sdp_message_get_zone (msg, 0);
       
   450 
       
   451     g_string_append_printf (lines, "z=%s %s", zone->time, zone->typed_time);
       
   452     for (i = 1; i < gst_sdp_message_zones_len (msg); i++) {
       
   453       zone = gst_sdp_message_get_zone (msg, i);
       
   454       g_string_append_printf (lines, " %s %s", zone->time, zone->typed_time);
       
   455     }
       
   456     g_string_append_printf (lines, "\r\n");
       
   457   }
       
   458 
       
   459   if (msg->key.type) {
       
   460     g_string_append_printf (lines, "k=%s", msg->key.type);
       
   461     if (msg->key.data)
       
   462       g_string_append_printf (lines, ":%s", msg->key.data);
       
   463     g_string_append_printf (lines, "\r\n");
       
   464   }
       
   465 
       
   466   for (i = 0; i < gst_sdp_message_attributes_len (msg); i++) {
       
   467     const GstSDPAttribute *attr = gst_sdp_message_get_attribute (msg, i);
       
   468 
       
   469     if (attr->key) {
       
   470       g_string_append_printf (lines, "a=%s", attr->key);
       
   471       if (attr->value)
       
   472         g_string_append_printf (lines, ":%s", attr->value);
       
   473       g_string_append_printf (lines, "\r\n");
       
   474     }
       
   475   }
       
   476 
       
   477   for (i = 0; i < gst_sdp_message_medias_len (msg); i++) {
       
   478     const GstSDPMedia *media = gst_sdp_message_get_media (msg, i);
       
   479     gchar *sdp_media_str;
       
   480 
       
   481     sdp_media_str = gst_sdp_media_as_text (media);
       
   482     g_string_append_printf (lines, "%s", sdp_media_str);
       
   483     g_free (sdp_media_str);
       
   484   }
       
   485 
       
   486   return g_string_free (lines, FALSE);
       
   487 }
       
   488 
       
   489 /**
       
   490  * gst_sdp_message_set_version:
       
   491  * @msg: a #GstSDPMessage
       
   492  * @version: the version
       
   493  *
       
   494  * Set the version in @msg.
       
   495  *
       
   496  * Returns: a #GstSDPResult.
       
   497  */
       
   498 DEFINE_STRING_SETTER (version);
       
   499 /**
       
   500  * gst_sdp_message_get_version:
       
   501  * @msg: a #GstSDPMessage
       
   502  *
       
   503  * Get the version in @msg.
       
   504  *
       
   505  * Returns: a #GstSDPResult.
       
   506  */
       
   507 DEFINE_STRING_GETTER (version);
       
   508 
       
   509 /**
       
   510  * gst_sdp_message_set_origin:
       
   511  * @msg: a #GstSDPMessage
       
   512  * @username: the user name
       
   513  * @sess_id: a session id
       
   514  * @sess_version: a session version
       
   515  * @nettype: a network type
       
   516  * @addrtype: an address type
       
   517  * @addr: an address
       
   518  *
       
   519  * Configure the SDP origin in @msg with the given parameters.
       
   520  *
       
   521  * Returns: #GST_SDP_OK.
       
   522  */
       
   523 GstSDPResult
       
   524 gst_sdp_message_set_origin (GstSDPMessage * msg, const gchar * username,
       
   525     const gchar * sess_id, const gchar * sess_version, const gchar * nettype,
       
   526     const gchar * addrtype, const gchar * addr)
       
   527 {
       
   528   REPLACE_STRING (msg->origin.username, username);
       
   529   REPLACE_STRING (msg->origin.sess_id, sess_id);
       
   530   REPLACE_STRING (msg->origin.sess_version, sess_version);
       
   531   REPLACE_STRING (msg->origin.nettype, nettype);
       
   532   REPLACE_STRING (msg->origin.addrtype, addrtype);
       
   533   REPLACE_STRING (msg->origin.addr, addr);
       
   534 
       
   535   return GST_SDP_OK;
       
   536 }
       
   537 
       
   538 /**
       
   539  * gst_sdp_message_get_origin:
       
   540  * @msg: a #GstSDPMessage
       
   541  *
       
   542  * Get the origin of @msg.
       
   543  *
       
   544  * Returns: a #GstSDPOrigin. The result remains valid as long as @msg is valid.
       
   545  */
       
   546 const GstSDPOrigin *
       
   547 gst_sdp_message_get_origin (const GstSDPMessage * msg)
       
   548 {
       
   549   return &msg->origin;
       
   550 }
       
   551 
       
   552 /**
       
   553  * gst_sdp_message_set_session_name:
       
   554  * @msg: a #GstSDPMessage
       
   555  * @session_name: the session name
       
   556  *
       
   557  * Set the session name in @msg.
       
   558  *
       
   559  * Returns: a #GstSDPResult.
       
   560  */
       
   561 DEFINE_STRING_SETTER (session_name);
       
   562 /**
       
   563  * gst_sdp_message_get_session_name:
       
   564  * @msg: a #GstSDPMessage
       
   565  *
       
   566  * Get the session name in @msg.
       
   567  *
       
   568  * Returns: a #GstSDPResult.
       
   569  */
       
   570 DEFINE_STRING_GETTER (session_name);
       
   571 /**
       
   572  * gst_sdp_message_set_information:
       
   573  * @msg: a #GstSDPMessage
       
   574  * @information: the information
       
   575  *
       
   576  * Set the information in @msg.
       
   577  *
       
   578  * Returns: a #GstSDPResult.
       
   579  */
       
   580 DEFINE_STRING_SETTER (information);
       
   581 /**
       
   582  * gst_sdp_message_get_information:
       
   583  * @msg: a #GstSDPMessage
       
   584  *
       
   585  * Get the information in @msg.
       
   586  *
       
   587  * Returns: a #GstSDPResult.
       
   588  */
       
   589 DEFINE_STRING_GETTER (information);
       
   590 /**
       
   591  * gst_sdp_message_set_uri:
       
   592  * @msg: a #GstSDPMessage
       
   593  * @uri: the URI
       
   594  *
       
   595  * Set the URI in @msg.
       
   596  *
       
   597  * Returns: a #GstSDPResult.
       
   598  */
       
   599 DEFINE_STRING_SETTER (uri);
       
   600 /**
       
   601  * gst_sdp_message_get_uri:
       
   602  * @msg: a #GstSDPMessage
       
   603  *
       
   604  * Get the URI in @msg.
       
   605  *
       
   606  * Returns: a #GstSDPResult.
       
   607  */
       
   608 DEFINE_STRING_GETTER (uri);
       
   609 
       
   610 /**
       
   611  * gst_sdp_message_emails_len:
       
   612  * @msg: a #GstSDPMessage
       
   613  *
       
   614  * Get the number of emails in @msg.
       
   615  *
       
   616  * Returns: the number of emails in @msg.
       
   617  */
       
   618 DEFINE_ARRAY_LEN (emails);
       
   619 /**
       
   620  * gst_sdp_message_get_email:
       
   621  * @msg: a #GstSDPMessage
       
   622  * @idx: an email index
       
   623  *
       
   624  * Get the email with number @idx from @msg.
       
   625  *
       
   626  * Returns: the email at position @idx.
       
   627  */
       
   628 DEFINE_PTR_ARRAY_GETTER (email, emails, const gchar *);
       
   629 
       
   630 /**
       
   631  * gst_sdp_message_add_email:
       
   632  * @msg: a #GstSDPMessage
       
   633  * @email: an email
       
   634  *
       
   635  * Add @email to the list of emails in @msg.
       
   636  *
       
   637  * Returns: a #GstSDPResult.
       
   638  */
       
   639 DEFINE_PTR_ARRAY_ADDER (email, emails, const gchar *, g_strdup);
       
   640 
       
   641 /**
       
   642  * gst_sdp_message_phones_len:
       
   643  * @msg: a #GstSDPMessage
       
   644  *
       
   645  * Get the number of phones in @msg.
       
   646  *
       
   647  * Returns: the number of phones in @msg.
       
   648  */
       
   649 DEFINE_ARRAY_LEN (phones);
       
   650 /**
       
   651  * gst_sdp_message_get_phone:
       
   652  * @msg: a #GstSDPMessage
       
   653  * @idx: a phone index
       
   654  *
       
   655  * Get the phone with number @idx from @msg.
       
   656  *
       
   657  * Returns: the phone at position @idx.
       
   658  */
       
   659 DEFINE_PTR_ARRAY_GETTER (phone, phones, const gchar *);
       
   660 
       
   661 /**
       
   662  * gst_sdp_message_add_phone:
       
   663  * @msg: a #GstSDPMessage
       
   664  * @phone: a phone
       
   665  *
       
   666  * Add @phone to the list of phones in @msg.
       
   667  *
       
   668  * Returns: a #GstSDPResult.
       
   669  */
       
   670 DEFINE_PTR_ARRAY_ADDER (phone, phones, const gchar *, g_strdup);
       
   671 
       
   672 /**
       
   673  * gst_sdp_message_set_connection:
       
   674  * @msg: a #GstSDPMessage
       
   675  * @nettype: the type of network. "IN" is defined to have the meaning
       
   676  * "Internet".
       
   677  * @addrtype: the type of address.
       
   678  * @address: the address
       
   679  * @ttl: the time to live of the address
       
   680  * @addr_number: the number of layers
       
   681  *
       
   682  * Configure the SDP connection in @msg with the given parameters.
       
   683  *
       
   684  * Returns: a #GstSDPResult.
       
   685  */
       
   686 GstSDPResult
       
   687 gst_sdp_message_set_connection (GstSDPMessage * msg, const gchar * nettype,
       
   688     const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
       
   689 {
       
   690   REPLACE_STRING (msg->connection.nettype, nettype);
       
   691   REPLACE_STRING (msg->connection.addrtype, addrtype);
       
   692   REPLACE_STRING (msg->connection.address, address);
       
   693   msg->connection.ttl = ttl;
       
   694   msg->connection.addr_number = addr_number;
       
   695 
       
   696   return GST_SDP_OK;
       
   697 }
       
   698 
       
   699 /**
       
   700  * gst_sdp_message_get_connection:
       
   701  * @msg: a #GstSDPMessage
       
   702  *
       
   703  * Get the connection of @msg.
       
   704  *
       
   705  * Returns: a #GstSDPConnection. The result remains valid as long as @msg is valid.
       
   706  */
       
   707 const GstSDPConnection *
       
   708 gst_sdp_message_get_connection (const GstSDPMessage * msg)
       
   709 {
       
   710   return &msg->connection;
       
   711 }
       
   712 
       
   713 /**
       
   714  * gst_sdp_message_bandwidths_len:
       
   715  * @msg: a #GstSDPMessage
       
   716  *
       
   717  * Get the number of bandwidth information in @msg.
       
   718  *
       
   719  * Returns: the number of bandwidth information in @msg.
       
   720  */
       
   721 DEFINE_ARRAY_LEN (bandwidths);
       
   722 /**
       
   723  * gst_sdp_message_get_bandwidth:
       
   724  * @msg: a #GstSDPMessage
       
   725  * @idx: the bandwidth index
       
   726  *
       
   727  * Get the bandwidth at index @idx from @msg.
       
   728  *
       
   729  * Returns: a #GstSDPBandwidth.
       
   730  */
       
   731 DEFINE_ARRAY_GETTER (bandwidth, bandwidths, const GstSDPBandwidth);
       
   732 
       
   733 /**
       
   734  * gst_sdp_message_add_bandwidth:
       
   735  * @msg: a #GstSDPMessage
       
   736  * @bwtype: the bandwidth modifier type
       
   737  * @bandwidth: the bandwidth in kilobits per second
       
   738  *
       
   739  * Add the specified bandwidth information to @msg.
       
   740  *
       
   741  * Returns: a #GstSDPResult.
       
   742  */
       
   743 
       
   744 GstSDPResult
       
   745 gst_sdp_message_add_bandwidth (GstSDPMessage * msg, const gchar * bwtype,
       
   746     guint bandwidth)
       
   747 {
       
   748   GstSDPBandwidth bw;
       
   749 
       
   750   bw.bwtype = g_strdup (bwtype);
       
   751   bw.bandwidth = bandwidth;
       
   752 
       
   753   g_array_append_val (msg->bandwidths, bw);
       
   754 
       
   755   return GST_SDP_OK;
       
   756 }
       
   757 
       
   758 /**
       
   759  * gst_sdp_message_times_len:
       
   760  * @msg: a #GstSDPMessage
       
   761  *
       
   762  * Get the number of time information entries in @msg.
       
   763  *
       
   764  * Returns: the number of time information entries in @msg.
       
   765  */
       
   766 DEFINE_ARRAY_LEN (times);
       
   767 
       
   768 /**
       
   769  * gst_sdp_message_get_time:
       
   770  * @msg: a #GstSDPMessage
       
   771  * @idx: the time index
       
   772  *
       
   773  * Get time information with index @idx from @msg.
       
   774  *
       
   775  * Returns: a #GstSDPTime.
       
   776  */
       
   777 DEFINE_ARRAY_GETTER (time, times, const GstSDPTime);
       
   778 
       
   779 /**
       
   780  * gst_sdp_message_add_time:
       
   781  * @msg: a #GstSDPMessage
       
   782  * @start: the start time
       
   783  * @stop: the stop time
       
   784  * @repeat: the repeat times
       
   785  *
       
   786  * Add time information @start and @stop to @msg.
       
   787  *
       
   788  * Returns: a #GstSDPResult.
       
   789  */
       
   790 GstSDPResult
       
   791 gst_sdp_message_add_time (GstSDPMessage * msg, const gchar * start,
       
   792     const gchar * stop, const gchar ** repeat)
       
   793 {
       
   794   GstSDPTime times;
       
   795 
       
   796   times.start = g_strdup (start);
       
   797   times.stop = g_strdup (stop);
       
   798   if (repeat) {
       
   799     times.repeat = g_array_new (FALSE, TRUE, sizeof (gchar *));
       
   800     for (; *repeat; repeat++) {
       
   801       gchar *r = g_strdup (*repeat);
       
   802 
       
   803       g_array_append_val (times.repeat, r);
       
   804     }
       
   805   } else
       
   806     times.repeat = NULL;
       
   807   g_array_append_val (msg->times, times);
       
   808 
       
   809   return GST_SDP_OK;
       
   810 }
       
   811 
       
   812 /**
       
   813  * gst_sdp_message_zones_len:
       
   814  * @msg: a #GstSDPMessage
       
   815  *
       
   816  * Get the number of time zone information entries in @msg.
       
   817  *
       
   818  * Returns: the number of time zone information entries in @msg.
       
   819  */
       
   820 DEFINE_ARRAY_LEN (zones);
       
   821 /**
       
   822  * gst_sdp_message_get_zone:
       
   823  * @msg: a #GstSDPMessage
       
   824  * @idx: the zone index
       
   825  *
       
   826  * Get time zone information with index @idx from @msg.
       
   827  *
       
   828  * Returns: a #GstSDPZone.
       
   829  */
       
   830 DEFINE_ARRAY_GETTER (zone, zones, const GstSDPZone);
       
   831 
       
   832 /**
       
   833  * gst_sdp_message_add_zone:
       
   834  * @msg: a #GstSDPMessage
       
   835  * @adj_time: the NTP time that a time zone adjustment happens
       
   836  * @typed_time: the offset from the time when the session was first scheduled
       
   837  *
       
   838  * Add time zone information to @msg.
       
   839  *
       
   840  * Returns: a #GstSDPResult.
       
   841  */
       
   842 GstSDPResult
       
   843 gst_sdp_message_add_zone (GstSDPMessage * msg, const gchar * adj_time,
       
   844     const gchar * typed_time)
       
   845 {
       
   846   GstSDPZone zone;
       
   847 
       
   848   zone.time = g_strdup (adj_time);
       
   849   zone.typed_time = g_strdup (typed_time);
       
   850 
       
   851   g_array_append_val (msg->zones, zone);
       
   852 
       
   853   return GST_SDP_OK;
       
   854 }
       
   855 
       
   856 /**
       
   857  * gst_sdp_message_set_key:
       
   858  * @msg: a #GstSDPMessage
       
   859  * @type: the encryption type
       
   860  * @data: the encryption data
       
   861  *
       
   862  * Adds the encryption information to @msg.
       
   863  *
       
   864  * Returns: a #GstSDPResult.
       
   865  */
       
   866 GstSDPResult
       
   867 gst_sdp_message_set_key (GstSDPMessage * msg, const gchar * type,
       
   868     const gchar * data)
       
   869 {
       
   870   REPLACE_STRING (msg->key.type, type);
       
   871   REPLACE_STRING (msg->key.data, data);
       
   872 
       
   873   return GST_SDP_OK;
       
   874 }
       
   875 
       
   876 /**
       
   877  * gst_sdp_message_get_key:
       
   878  * @msg: a #GstSDPMessage
       
   879  *
       
   880  * Get the encryption information from @msg.
       
   881  *
       
   882  * Returns: a #GstSDPKey.
       
   883  */
       
   884 const GstSDPKey *
       
   885 gst_sdp_message_get_key (const GstSDPMessage * msg)
       
   886 {
       
   887   return &msg->key;
       
   888 }
       
   889 
       
   890 /**
       
   891  * gst_sdp_message_attributes_len:
       
   892  * @msg: a #GstSDPMessage
       
   893  *
       
   894  * Get the number of attributes in @msg.
       
   895  *
       
   896  * Returns: the number of attributes in @msg.
       
   897  */
       
   898 DEFINE_ARRAY_LEN (attributes);
       
   899 
       
   900 /**
       
   901  * gst_sdp_message_get_attribute:
       
   902  * @msg: a #GstSDPMessage
       
   903  * @idx: the index
       
   904  *
       
   905  * Get the attribute at position @idx in @msg.
       
   906  *
       
   907  * Returns: the #GstSDPAttribute at position @idx.
       
   908  */
       
   909 DEFINE_ARRAY_GETTER (attribute, attributes, const GstSDPAttribute);
       
   910 
       
   911 /**
       
   912  * gst_sdp_message_get_attribute_val_n:
       
   913  * @msg: a #GstSDPMessage
       
   914  * @key: the key
       
   915  * @nth: the index
       
   916  *
       
   917  * Get the @nth attribute with key @key in @msg.
       
   918  *
       
   919  * Returns: the attribute value of the @nth attribute with @key.
       
   920  */
       
   921 const gchar *
       
   922 gst_sdp_message_get_attribute_val_n (const GstSDPMessage * msg,
       
   923     const gchar * key, guint nth)
       
   924 {
       
   925   guint i;
       
   926 
       
   927   for (i = 0; i < msg->attributes->len; i++) {
       
   928     GstSDPAttribute *attr;
       
   929 
       
   930     attr = &g_array_index (msg->attributes, GstSDPAttribute, i);
       
   931     if (!strcmp (attr->key, key)) {
       
   932       if (nth == 0)
       
   933         return attr->value;
       
   934       else
       
   935         nth--;
       
   936     }
       
   937   }
       
   938   return NULL;
       
   939 }
       
   940 
       
   941 /**
       
   942  * gst_sdp_message_get_attribute_val:
       
   943  * @msg: a #GstSDPMessage
       
   944  * @key: the key
       
   945  *
       
   946  * Get the first attribute with key @key in @msg.
       
   947  *
       
   948  * Returns: the attribute value of the first attribute with @key.
       
   949  */
       
   950 const gchar *
       
   951 gst_sdp_message_get_attribute_val (const GstSDPMessage * msg, const gchar * key)
       
   952 {
       
   953   return gst_sdp_message_get_attribute_val_n (msg, key, 0);
       
   954 }
       
   955 
       
   956 /**
       
   957  * gst_sdp_message_add_attribute:
       
   958  * @msg: a #GstSDPMessage
       
   959  * @key: the key
       
   960  * @value: the value
       
   961  *
       
   962  * Add the attribute with @key and @value to @msg.
       
   963  *
       
   964  * Returns: @GST_SDP_OK.
       
   965  */
       
   966 GstSDPResult
       
   967 gst_sdp_message_add_attribute (GstSDPMessage * msg, const gchar * key,
       
   968     const gchar * value)
       
   969 {
       
   970   GstSDPAttribute attr;
       
   971 
       
   972   attr.key = g_strdup (key);
       
   973   attr.value = g_strdup (value);
       
   974 
       
   975   g_array_append_val (msg->attributes, attr);
       
   976 
       
   977   return GST_SDP_OK;
       
   978 }
       
   979 
       
   980 /**
       
   981  * gst_sdp_message_medias_len:
       
   982  * @msg: a #GstSDPMessage
       
   983  *
       
   984  * Get the number of media descriptions in @msg.
       
   985  *
       
   986  * Returns: the number of media descriptions in @msg.
       
   987  */
       
   988 DEFINE_ARRAY_LEN (medias);
       
   989 /**
       
   990  * gst_sdp_message_get_media:
       
   991  * @msg: a #GstSDPMessage
       
   992  * @idx: the index
       
   993  *
       
   994  * Get the media description at index @idx in @msg.
       
   995  *
       
   996  * Returns: a #GstSDPMedia.
       
   997  */
       
   998 DEFINE_ARRAY_GETTER (media, medias, const GstSDPMedia);
       
   999 
       
  1000 /**
       
  1001  * gst_sdp_message_add_media:
       
  1002  * @msg: a #GstSDPMessage
       
  1003  * @media: a #GstSDPMedia to add
       
  1004  *
       
  1005  * Adds @media to the array of medias in @msg. This function takes ownership of
       
  1006  * the contents of @media so that @media will have to be reinitialized with
       
  1007  * gst_media_init() before it can be used again.
       
  1008  *
       
  1009  * Returns: a #GstSDPResult.
       
  1010  */
       
  1011 GstSDPResult
       
  1012 gst_sdp_message_add_media (GstSDPMessage * msg, GstSDPMedia * media)
       
  1013 {
       
  1014   guint len;
       
  1015   GstSDPMedia *nmedia;
       
  1016 
       
  1017   len = msg->medias->len;
       
  1018   g_array_set_size (msg->medias, len + 1);
       
  1019   nmedia = &g_array_index (msg->medias, GstSDPMedia, len);
       
  1020 
       
  1021   memcpy (nmedia, media, sizeof (GstSDPMedia));
       
  1022   memset (media, 0, sizeof (GstSDPMedia));
       
  1023 
       
  1024   return GST_SDP_OK;
       
  1025 }
       
  1026 
       
  1027 /* media access */
       
  1028 
       
  1029 /**
       
  1030  * gst_sdp_media_new:
       
  1031  * @media: pointer to new #GstSDPMedia
       
  1032  *
       
  1033  * Allocate a new GstSDPMedia and store the result in @media.
       
  1034  *
       
  1035  * Returns: a #GstSDPResult.
       
  1036  */
       
  1037 GstSDPResult
       
  1038 gst_sdp_media_new (GstSDPMedia ** media)
       
  1039 {
       
  1040   GstSDPMedia *newmedia;
       
  1041 
       
  1042   g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
       
  1043 
       
  1044   newmedia = g_new0 (GstSDPMedia, 1);
       
  1045 
       
  1046   *media = newmedia;
       
  1047 
       
  1048   return gst_sdp_media_init (newmedia);
       
  1049 }
       
  1050 
       
  1051 /**
       
  1052  * gst_sdp_media_init:
       
  1053  * @media: a #GstSDPMedia
       
  1054  *
       
  1055  * Initialize @media so that its contents are as if it was freshly allocated
       
  1056  * with gst_sdp_media_new(). This function is mostly used to initialize a media
       
  1057  * allocated on the stack. gst_sdp_media_uninit() undoes this operation.
       
  1058  *
       
  1059  * When this function is invoked on newly allocated data (with malloc or on the
       
  1060  * stack), its contents should be set to 0 before calling this function.
       
  1061  *
       
  1062  * Returns: a #GstSDPResult.
       
  1063  */
       
  1064 GstSDPResult
       
  1065 gst_sdp_media_init (GstSDPMedia * media)
       
  1066 {
       
  1067   g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
       
  1068 
       
  1069   FREE_STRING (media->media);
       
  1070   media->port = 0;
       
  1071   media->num_ports = 0;
       
  1072   FREE_STRING (media->proto);
       
  1073   INIT_PTR_ARRAY (media->fmts, gchar *, g_free);
       
  1074   FREE_STRING (media->information);
       
  1075   INIT_ARRAY (media->connections, GstSDPConnection, gst_sdp_connection_init);
       
  1076   INIT_ARRAY (media->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_init);
       
  1077   gst_sdp_key_init (&media->key);
       
  1078   INIT_ARRAY (media->attributes, GstSDPAttribute, gst_sdp_attribute_init);
       
  1079 
       
  1080   return GST_SDP_OK;
       
  1081 }
       
  1082 
       
  1083 /**
       
  1084  * gst_sdp_media_uninit:
       
  1085  * @media: a #GstSDPMedia
       
  1086  *
       
  1087  * Free all resources allocated in @media. @media should not be used anymore after
       
  1088  * this function. This function should be used when @media was allocated on the
       
  1089  * stack and initialized with gst_sdp_media_init().
       
  1090  *
       
  1091  * Returns: a #GstSDPResult.
       
  1092  */
       
  1093 GstSDPResult
       
  1094 gst_sdp_media_uninit (GstSDPMedia * media)
       
  1095 {
       
  1096   g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
       
  1097 
       
  1098   gst_sdp_media_init (media);
       
  1099   FREE_PTR_ARRAY (media->fmts);
       
  1100   FREE_ARRAY (media->connections);
       
  1101   FREE_ARRAY (media->bandwidths);
       
  1102   FREE_ARRAY (media->attributes);
       
  1103 
       
  1104   return GST_SDP_OK;
       
  1105 }
       
  1106 
       
  1107 /**
       
  1108  * gst_sdp_media_free:
       
  1109  * @media: a #GstSDPMedia
       
  1110  *
       
  1111  * Free all resources allocated by @media. @media should not be used anymore after
       
  1112  * this function. This function should be used when @media was dynamically
       
  1113  * allocated with gst_sdp_media_new().
       
  1114  *
       
  1115  * Returns: a #GstSDPResult.
       
  1116  */
       
  1117 GstSDPResult
       
  1118 gst_sdp_media_free (GstSDPMedia * media)
       
  1119 {
       
  1120   g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
       
  1121 
       
  1122   gst_sdp_media_uninit (media);
       
  1123   g_free (media);
       
  1124 
       
  1125   return GST_SDP_OK;
       
  1126 }
       
  1127 
       
  1128 /**
       
  1129  * gst_sdp_media_as_text:
       
  1130  * @media: a #GstSDPMedia
       
  1131  *
       
  1132  * Convert the contents of @media to a text string.
       
  1133  *
       
  1134  * Returns: A dynamically allocated string representing the media.
       
  1135  */
       
  1136 gchar *
       
  1137 gst_sdp_media_as_text (const GstSDPMedia * media)
       
  1138 {
       
  1139   GString *lines;
       
  1140   guint i;
       
  1141 
       
  1142   g_return_val_if_fail (media != NULL, NULL);
       
  1143 
       
  1144   lines = g_string_new ("");
       
  1145 
       
  1146   if (media->media)
       
  1147     g_string_append_printf (lines, "m=%s", media->media);
       
  1148 
       
  1149   g_string_append_printf (lines, " %u", media->port);
       
  1150 
       
  1151   if (media->num_ports > 1)
       
  1152     g_string_append_printf (lines, "/%u", media->num_ports);
       
  1153 
       
  1154   g_string_append_printf (lines, " %s", media->proto);
       
  1155 
       
  1156   for (i = 0; i < gst_sdp_media_formats_len (media); i++)
       
  1157     g_string_append_printf (lines, " %s", gst_sdp_media_get_format (media, i));
       
  1158   g_string_append_printf (lines, "\r\n");
       
  1159 
       
  1160   if (media->information)
       
  1161     g_string_append_printf (lines, "i=%s", media->information);
       
  1162 
       
  1163   for (i = 0; i < gst_sdp_media_connections_len (media); i++) {
       
  1164     const GstSDPConnection *conn = gst_sdp_media_get_connection (media, i);
       
  1165 
       
  1166     if (conn->nettype && conn->addrtype && conn->address) {
       
  1167       guint family;
       
  1168 
       
  1169       g_string_append_printf (lines, "c=%s %s %s", conn->nettype,
       
  1170           conn->addrtype, conn->address);
       
  1171       if (is_multicast_address (conn->address, &family)) {
       
  1172         if (family == AF_INET)
       
  1173           g_string_append_printf (lines, "/%u", conn->ttl);
       
  1174         if (conn->addr_number > 1)
       
  1175           g_string_append_printf (lines, "/%u", conn->addr_number);
       
  1176       }
       
  1177       g_string_append_printf (lines, "\r\n");
       
  1178     }
       
  1179   }
       
  1180 
       
  1181   for (i = 0; i < gst_sdp_media_bandwidths_len (media); i++) {
       
  1182     const GstSDPBandwidth *bandwidth = gst_sdp_media_get_bandwidth (media, i);
       
  1183 
       
  1184     g_string_append_printf (lines, "b=%s:%u\r\n", bandwidth->bwtype,
       
  1185         bandwidth->bandwidth);
       
  1186   }
       
  1187 
       
  1188   if (media->key.type) {
       
  1189     g_string_append_printf (lines, "k=%s", media->key.type);
       
  1190     if (media->key.data)
       
  1191       g_string_append_printf (lines, ":%s", media->key.data);
       
  1192     g_string_append_printf (lines, "\r\n");
       
  1193   }
       
  1194 
       
  1195   for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
       
  1196     const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
       
  1197 
       
  1198     if (attr->key) {
       
  1199       g_string_append_printf (lines, "a=%s", attr->key);
       
  1200       if (attr->value)
       
  1201         g_string_append_printf (lines, ":%s", attr->value);
       
  1202       g_string_append_printf (lines, "\r\n");
       
  1203     }
       
  1204   }
       
  1205 
       
  1206   return g_string_free (lines, FALSE);
       
  1207 }
       
  1208 
       
  1209 /**
       
  1210  * gst_sdp_media_get_media:
       
  1211  * @media: a #GstSDPMedia
       
  1212  *
       
  1213  * Get the media description of @media.
       
  1214  *
       
  1215  * Returns: the media description.
       
  1216  */
       
  1217 const gchar *
       
  1218 gst_sdp_media_get_media (const GstSDPMedia * media)
       
  1219 {
       
  1220   return media->media;
       
  1221 }
       
  1222 
       
  1223 /**
       
  1224  * gst_sdp_media_set_media:
       
  1225  * @media: a #GstSDPMedia
       
  1226  * @med: the media description
       
  1227  *
       
  1228  * Set the media description of @media to @med.
       
  1229  *
       
  1230  * Returns: #GST_SDP_OK.
       
  1231  */
       
  1232 GstSDPResult
       
  1233 gst_sdp_media_set_media (GstSDPMedia * media, const gchar * med)
       
  1234 {
       
  1235   g_free (media->media);
       
  1236   media->media = g_strdup (med);
       
  1237 
       
  1238   return GST_SDP_OK;
       
  1239 }
       
  1240 
       
  1241 /**
       
  1242  * gst_sdp_media_get_port:
       
  1243  * @media: a #GstSDPMedia
       
  1244  *
       
  1245  * Get the port number for @media.
       
  1246  *
       
  1247  * Returns: the port number of @media.
       
  1248  */
       
  1249 guint
       
  1250 gst_sdp_media_get_port (const GstSDPMedia * media)
       
  1251 {
       
  1252   return media->port;
       
  1253 }
       
  1254 
       
  1255 /**
       
  1256  * gst_sdp_media_get_num_ports:
       
  1257  * @media: a #GstSDPMedia
       
  1258  *
       
  1259  * Get the number of ports for @media.
       
  1260  *
       
  1261  * Returns: the number of ports for @media.
       
  1262  */
       
  1263 guint
       
  1264 gst_sdp_media_get_num_ports (const GstSDPMedia * media)
       
  1265 {
       
  1266   return media->num_ports;
       
  1267 }
       
  1268 
       
  1269 /**
       
  1270  * gst_sdp_media_set_port_info:
       
  1271  * @media: a #GstSDPMedia
       
  1272  * @port: the port number
       
  1273  * @num_ports: the number of ports
       
  1274  *
       
  1275  * Set the port information in @media.
       
  1276  *
       
  1277  * Returns: #GST_SDP_OK.
       
  1278  */
       
  1279 GstSDPResult
       
  1280 gst_sdp_media_set_port_info (GstSDPMedia * media, guint port, guint num_ports)
       
  1281 {
       
  1282   media->port = port;
       
  1283   media->num_ports = num_ports;
       
  1284 
       
  1285   return GST_SDP_OK;
       
  1286 }
       
  1287 
       
  1288 /**
       
  1289  * gst_sdp_media_get_proto:
       
  1290  * @media: a #GstSDPMedia
       
  1291  *
       
  1292  * Get the transport protocol of @media
       
  1293  *
       
  1294  * Returns: the transport protocol of @media.
       
  1295  */
       
  1296 const gchar *
       
  1297 gst_sdp_media_get_proto (const GstSDPMedia * media)
       
  1298 {
       
  1299   return media->proto;
       
  1300 }
       
  1301 
       
  1302 /**
       
  1303  * gst_sdp_media_set_proto:
       
  1304  * @media: a #GstSDPMedia
       
  1305  * @proto: the media transport protocol
       
  1306  *
       
  1307  * Set the media transport protocol of @media to @proto.
       
  1308  *
       
  1309  * Returns: #GST_SDP_OK.
       
  1310  */
       
  1311 GstSDPResult
       
  1312 gst_sdp_media_set_proto (GstSDPMedia * media, const gchar * proto)
       
  1313 {
       
  1314   g_free (media->proto);
       
  1315   media->proto = g_strdup (proto);
       
  1316 
       
  1317   return GST_SDP_OK;
       
  1318 }
       
  1319 
       
  1320 /**
       
  1321  * gst_sdp_media_formats_len:
       
  1322  * @media: a #GstSDPMedia
       
  1323  *
       
  1324  * Get the number of formats in @media.
       
  1325  *
       
  1326  * Returns: the number of formats in @media.
       
  1327  */
       
  1328 guint
       
  1329 gst_sdp_media_formats_len (const GstSDPMedia * media)
       
  1330 {
       
  1331   return media->fmts->len;
       
  1332 }
       
  1333 
       
  1334 /**
       
  1335  * gst_sdp_media_get_format:
       
  1336  * @media: a #GstSDPMedia
       
  1337  * @idx: an index
       
  1338  *
       
  1339  * Get the format information at position @idx in @media.
       
  1340  *
       
  1341  * Returns: the format at position @idx.
       
  1342  */
       
  1343 const gchar *
       
  1344 gst_sdp_media_get_format (const GstSDPMedia * media, guint idx)
       
  1345 {
       
  1346   if (idx >= media->fmts->len)
       
  1347     return NULL;
       
  1348   return g_array_index (media->fmts, gchar *, idx);
       
  1349 }
       
  1350 
       
  1351 /**
       
  1352  * gst_sdp_media_add_format:
       
  1353  * @media: a #GstSDPMedia
       
  1354  * @format: the format
       
  1355  *
       
  1356  * Add the format information to @media.
       
  1357  *
       
  1358  * Returns: #GST_SDP_OK.
       
  1359  */
       
  1360 GstSDPResult
       
  1361 gst_sdp_media_add_format (GstSDPMedia * media, const gchar * format)
       
  1362 {
       
  1363   gchar *fmt;
       
  1364 
       
  1365   fmt = g_strdup (format);
       
  1366 
       
  1367   g_array_append_val (media->fmts, fmt);
       
  1368 
       
  1369   return GST_SDP_OK;
       
  1370 }
       
  1371 
       
  1372 /**
       
  1373  * gst_sdp_media_get_information:
       
  1374  * @media: a #GstSDPMedia
       
  1375  *
       
  1376  * Get the information of @media
       
  1377  *
       
  1378  * Returns: the information of @media.
       
  1379  */
       
  1380 const gchar *
       
  1381 gst_sdp_media_get_information (const GstSDPMedia * media)
       
  1382 {
       
  1383   return media->information;
       
  1384 }
       
  1385 
       
  1386 /**
       
  1387  * gst_sdp_media_set_information:
       
  1388  * @media: a #GstSDPMedia
       
  1389  * @information: the media information
       
  1390  *
       
  1391  * Set the media information of @media to @information.
       
  1392  *
       
  1393  * Returns: #GST_SDP_OK.
       
  1394  */
       
  1395 GstSDPResult
       
  1396 gst_sdp_media_set_information (GstSDPMedia * media, const gchar * information)
       
  1397 {
       
  1398   g_free (media->information);
       
  1399   media->information = g_strdup (information);
       
  1400 
       
  1401   return GST_SDP_OK;
       
  1402 }
       
  1403 
       
  1404 /**
       
  1405  * gst_sdp_media_connections_len:
       
  1406  * @media: a #GstSDPMedia
       
  1407  *
       
  1408  * Get the number of connection fields in @media.
       
  1409  *
       
  1410  * Returns: the number of connections in @media.
       
  1411  */
       
  1412 guint
       
  1413 gst_sdp_media_connections_len (const GstSDPMedia * media)
       
  1414 {
       
  1415   return media->connections->len;
       
  1416 }
       
  1417 
       
  1418 /**
       
  1419  * gst_sdp_media_get_connection:
       
  1420  * @media: a #GstSDPMedia
       
  1421  * @idx: an index
       
  1422  *
       
  1423  * Get the connection at position @idx in @media.
       
  1424  *
       
  1425  * Returns: the #GstSDPConnection at position @idx.
       
  1426  */
       
  1427 const GstSDPConnection *
       
  1428 gst_sdp_media_get_connection (const GstSDPMedia * media, guint idx)
       
  1429 {
       
  1430   return &g_array_index (media->connections, GstSDPConnection, idx);
       
  1431 }
       
  1432 
       
  1433 /**
       
  1434  * gst_sdp_media_add_connection:
       
  1435  * @media: a #GstSDPMedia
       
  1436  * @nettype: the type of network. "IN" is defined to have the meaning
       
  1437  * "Internet".
       
  1438  * @addrtype: the type of address.
       
  1439  * @address: the address
       
  1440  * @ttl: the time to live of the address
       
  1441  * @addr_number: the number of layers
       
  1442  *
       
  1443  * Add the given connection parameters to @media.
       
  1444  *
       
  1445  * Returns: a #GstSDPResult.
       
  1446  */
       
  1447 GstSDPResult
       
  1448 gst_sdp_media_add_connection (GstSDPMedia * media, const gchar * nettype,
       
  1449     const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
       
  1450 {
       
  1451   GstSDPConnection conn;
       
  1452 
       
  1453   conn.nettype = g_strdup (nettype);
       
  1454   conn.addrtype = g_strdup (addrtype);
       
  1455   conn.address = g_strdup (address);
       
  1456   conn.ttl = ttl;
       
  1457   conn.addr_number = addr_number;
       
  1458 
       
  1459   g_array_append_val (media->connections, conn);
       
  1460 
       
  1461   return GST_SDP_OK;
       
  1462 }
       
  1463 
       
  1464 /**
       
  1465  * gst_sdp_media_bandwidths_len:
       
  1466  * @media: a #GstSDPMedia
       
  1467  *
       
  1468  * Get the number of bandwidth fields in @media.
       
  1469  *
       
  1470  * Returns: the number of bandwidths in @media.
       
  1471  */
       
  1472 guint
       
  1473 gst_sdp_media_bandwidths_len (const GstSDPMedia * media)
       
  1474 {
       
  1475   return media->bandwidths->len;
       
  1476 }
       
  1477 
       
  1478 /**
       
  1479  * gst_sdp_media_get_bandwidth:
       
  1480  * @media: a #GstSDPMedia
       
  1481  * @idx: an index
       
  1482  *
       
  1483  * Get the bandwidth at position @idx in @media.
       
  1484  *
       
  1485  * Returns: the #GstSDPBandwidth at position @idx.
       
  1486  */
       
  1487 const GstSDPBandwidth *
       
  1488 gst_sdp_media_get_bandwidth (const GstSDPMedia * media, guint idx)
       
  1489 {
       
  1490   return &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
       
  1491 }
       
  1492 
       
  1493 /**
       
  1494  * gst_sdp_media_add_bandwidth:
       
  1495  * @media: a #GstSDPMedia
       
  1496  * @bwtype: the bandwidth modifier type
       
  1497  * @bandwidth: the bandwidth in kilobits per second
       
  1498  *
       
  1499  * Add the bandwidth information with @bwtype and @bandwidth to @media.
       
  1500  *
       
  1501  * Returns: #GST_SDP_OK.
       
  1502  */
       
  1503 GstSDPResult
       
  1504 gst_sdp_media_add_bandwidth (GstSDPMedia * media, const gchar * bwtype,
       
  1505     guint bandwidth)
       
  1506 {
       
  1507   GstSDPBandwidth bw;
       
  1508 
       
  1509   bw.bwtype = g_strdup (bwtype);
       
  1510   bw.bandwidth = bandwidth;
       
  1511 
       
  1512   g_array_append_val (media->bandwidths, bw);
       
  1513 
       
  1514   return GST_SDP_OK;
       
  1515 }
       
  1516 
       
  1517 /**
       
  1518  * gst_sdp_media_set_key:
       
  1519  * @media: a #GstSDPMedia
       
  1520  * @type: the encryption type
       
  1521  * @data: the encryption data
       
  1522  *
       
  1523  * Adds the encryption information to @media.
       
  1524  *
       
  1525  * Returns: a #GstSDPResult.
       
  1526  */
       
  1527 GstSDPResult
       
  1528 gst_sdp_media_set_key (GstSDPMedia * media, const gchar * type,
       
  1529     const gchar * data)
       
  1530 {
       
  1531   g_free (media->key.type);
       
  1532   media->key.type = g_strdup (type);
       
  1533   g_free (media->key.data);
       
  1534   media->key.data = g_strdup (data);
       
  1535 
       
  1536   return GST_SDP_OK;
       
  1537 }
       
  1538 
       
  1539 /**
       
  1540  * gst_sdp_media_get_key:
       
  1541  * @media: a #GstSDPMedia
       
  1542  *
       
  1543  * Get the encryption information from @media.
       
  1544  *
       
  1545  * Returns: a #GstSDPKey.
       
  1546  */
       
  1547 const GstSDPKey *
       
  1548 gst_sdp_media_get_key (const GstSDPMedia * media)
       
  1549 {
       
  1550   return &media->key;
       
  1551 }
       
  1552 
       
  1553 /**
       
  1554  * gst_sdp_media_attributes_len:
       
  1555  * @media: a #GstSDPMedia
       
  1556  *
       
  1557  * Get the number of attribute fields in @media.
       
  1558  *
       
  1559  * Returns: the number of attributes in @media.
       
  1560  */
       
  1561 guint
       
  1562 gst_sdp_media_attributes_len (const GstSDPMedia * media)
       
  1563 {
       
  1564   return media->attributes->len;
       
  1565 }
       
  1566 
       
  1567 /**
       
  1568  * gst_sdp_media_add_attribute:
       
  1569  * @media: a #GstSDPMedia
       
  1570  * @key: a key
       
  1571  * @value: a value
       
  1572  *
       
  1573  * Add the attribute with @key and @value to @media.
       
  1574  *
       
  1575  * Returns: #GST_SDP_OK.
       
  1576  */
       
  1577 GstSDPResult
       
  1578 gst_sdp_media_add_attribute (GstSDPMedia * media, const gchar * key,
       
  1579     const gchar * value)
       
  1580 {
       
  1581   GstSDPAttribute attr;
       
  1582 
       
  1583   attr.key = g_strdup (key);
       
  1584   attr.value = g_strdup (value);
       
  1585 
       
  1586   g_array_append_val (media->attributes, attr);
       
  1587 
       
  1588   return GST_SDP_OK;
       
  1589 }
       
  1590 
       
  1591 /**
       
  1592  * gst_sdp_media_get_attribute:
       
  1593  * @media: a #GstSDPMedia
       
  1594  * @idx: an index
       
  1595  *
       
  1596  * Get the attribute at position @idx in @media.
       
  1597  *
       
  1598  * Returns: the #GstSDPAttribute at position @idx.
       
  1599  */
       
  1600 const GstSDPAttribute *
       
  1601 gst_sdp_media_get_attribute (const GstSDPMedia * media, guint idx)
       
  1602 {
       
  1603   return &g_array_index (media->attributes, GstSDPAttribute, idx);
       
  1604 }
       
  1605 
       
  1606 /**
       
  1607  * gst_sdp_media_get_attribute_val_n:
       
  1608  * @media: a #GstSDPMedia
       
  1609  * @key: a key
       
  1610  * @nth: an index
       
  1611  *
       
  1612  * Get the @nth attribute value for @key in @media.
       
  1613  *
       
  1614  * Returns: the @nth attribute value.
       
  1615  */
       
  1616 const gchar *
       
  1617 gst_sdp_media_get_attribute_val_n (const GstSDPMedia * media, const gchar * key,
       
  1618     guint nth)
       
  1619 {
       
  1620   guint i;
       
  1621 
       
  1622   for (i = 0; i < media->attributes->len; i++) {
       
  1623     GstSDPAttribute *attr;
       
  1624 
       
  1625     attr = &g_array_index (media->attributes, GstSDPAttribute, i);
       
  1626     if (!strcmp (attr->key, key)) {
       
  1627       if (nth == 0)
       
  1628         return attr->value;
       
  1629       else
       
  1630         nth--;
       
  1631     }
       
  1632   }
       
  1633   return NULL;
       
  1634 }
       
  1635 
       
  1636 /**
       
  1637  * gst_sdp_media_get_attribute_val:
       
  1638  * @media: a #GstSDPMedia
       
  1639  * @key: a key
       
  1640  *
       
  1641  * Get the first attribute value for @key in @media.
       
  1642  *
       
  1643  * Returns: the first attribute value for @key.
       
  1644  */
       
  1645 const gchar *
       
  1646 gst_sdp_media_get_attribute_val (const GstSDPMedia * media, const gchar * key)
       
  1647 {
       
  1648   return gst_sdp_media_get_attribute_val_n (media, key, 0);
       
  1649 }
       
  1650 
       
  1651 static void
       
  1652 read_string (gchar * dest, guint size, gchar ** src)
       
  1653 {
       
  1654   guint idx;
       
  1655 
       
  1656   idx = 0;
       
  1657   /* skip spaces */
       
  1658   while (g_ascii_isspace (**src))
       
  1659     (*src)++;
       
  1660 
       
  1661   while (!g_ascii_isspace (**src) && **src != '\0') {
       
  1662     if (idx < size - 1)
       
  1663       dest[idx++] = **src;
       
  1664     (*src)++;
       
  1665   }
       
  1666   if (size > 0)
       
  1667     dest[idx] = '\0';
       
  1668 }
       
  1669 
       
  1670 static void
       
  1671 read_string_del (gchar * dest, guint size, gchar del, gchar ** src)
       
  1672 {
       
  1673   guint idx;
       
  1674 
       
  1675   idx = 0;
       
  1676   /* skip spaces */
       
  1677   while (g_ascii_isspace (**src))
       
  1678     (*src)++;
       
  1679 
       
  1680   while (**src != del && **src != '\0') {
       
  1681     if (idx < size - 1)
       
  1682       dest[idx++] = **src;
       
  1683     (*src)++;
       
  1684   }
       
  1685   if (size > 0)
       
  1686     dest[idx] = '\0';
       
  1687 }
       
  1688 
       
  1689 enum
       
  1690 {
       
  1691   SDP_SESSION,
       
  1692   SDP_MEDIA,
       
  1693 };
       
  1694 
       
  1695 typedef struct
       
  1696 {
       
  1697   guint state;
       
  1698   GstSDPMessage *msg;
       
  1699   GstSDPMedia *media;
       
  1700 } SDPContext;
       
  1701 
       
  1702 static gboolean
       
  1703 gst_sdp_parse_line (SDPContext * c, gchar type, gchar * buffer)
       
  1704 {
       
  1705   gchar str[8192];
       
  1706   gchar *p = buffer;
       
  1707 
       
  1708 #define READ_STRING(field) read_string (str, sizeof (str), &p); REPLACE_STRING (field, str)
       
  1709 #define READ_UINT(field) read_string (str, sizeof (str), &p); field = strtoul (str, NULL, 10)
       
  1710 
       
  1711   switch (type) {
       
  1712     case 'v':
       
  1713       if (buffer[0] != '0')
       
  1714         g_warning ("wrong SDP version");
       
  1715       gst_sdp_message_set_version (c->msg, buffer);
       
  1716       break;
       
  1717     case 'o':
       
  1718       READ_STRING (c->msg->origin.username);
       
  1719       READ_STRING (c->msg->origin.sess_id);
       
  1720       READ_STRING (c->msg->origin.sess_version);
       
  1721       READ_STRING (c->msg->origin.nettype);
       
  1722       READ_STRING (c->msg->origin.addrtype);
       
  1723       READ_STRING (c->msg->origin.addr);
       
  1724       break;
       
  1725     case 's':
       
  1726       REPLACE_STRING (c->msg->session_name, buffer);
       
  1727       break;
       
  1728     case 'i':
       
  1729       if (c->state == SDP_SESSION) {
       
  1730         REPLACE_STRING (c->msg->information, buffer);
       
  1731       } else {
       
  1732         REPLACE_STRING (c->media->information, buffer);
       
  1733       }
       
  1734       break;
       
  1735     case 'u':
       
  1736       REPLACE_STRING (c->msg->uri, buffer);
       
  1737       break;
       
  1738     case 'e':
       
  1739       gst_sdp_message_add_email (c->msg, buffer);
       
  1740       break;
       
  1741     case 'p':
       
  1742       gst_sdp_message_add_phone (c->msg, buffer);
       
  1743       break;
       
  1744     case 'c':
       
  1745       READ_STRING (c->msg->connection.nettype);
       
  1746       READ_STRING (c->msg->connection.addrtype);
       
  1747       READ_STRING (c->msg->connection.address);
       
  1748       READ_UINT (c->msg->connection.ttl);
       
  1749       READ_UINT (c->msg->connection.addr_number);
       
  1750       break;
       
  1751     case 'b':
       
  1752     {
       
  1753       gchar str2[MAX_LINE_LEN];
       
  1754 
       
  1755       read_string_del (str, sizeof (str), ':', &p);
       
  1756       read_string (str2, sizeof (str2), &p);
       
  1757       if (c->state == SDP_SESSION)
       
  1758         gst_sdp_message_add_bandwidth (c->msg, str, atoi (str2));
       
  1759       else
       
  1760         gst_sdp_media_add_bandwidth (c->media, str, atoi (str2));
       
  1761       break;
       
  1762     }
       
  1763     case 't':
       
  1764       break;
       
  1765     case 'k':
       
  1766       break;
       
  1767     case 'a':
       
  1768       read_string_del (str, sizeof (str), ':', &p);
       
  1769       if (*p != '\0')
       
  1770         p++;
       
  1771       if (c->state == SDP_SESSION)
       
  1772         gst_sdp_message_add_attribute (c->msg, str, p);
       
  1773       else
       
  1774         gst_sdp_media_add_attribute (c->media, str, p);
       
  1775       break;
       
  1776     case 'm':
       
  1777     {
       
  1778       gchar *slash;
       
  1779       GstSDPMedia nmedia;
       
  1780 
       
  1781       c->state = SDP_MEDIA;
       
  1782       memset (&nmedia, 0, sizeof (nmedia));
       
  1783       gst_sdp_media_init (&nmedia);
       
  1784 
       
  1785       /* m=<media> <port>/<number of ports> <proto> <fmt> ... */
       
  1786       READ_STRING (nmedia.media);
       
  1787       read_string (str, sizeof (str), &p);
       
  1788       slash = g_strrstr (str, "/");
       
  1789       if (slash) {
       
  1790         *slash = '\0';
       
  1791         nmedia.port = atoi (str);
       
  1792         nmedia.num_ports = atoi (slash + 1);
       
  1793       } else {
       
  1794         nmedia.port = atoi (str);
       
  1795         nmedia.num_ports = -1;
       
  1796       }
       
  1797       READ_STRING (nmedia.proto);
       
  1798       do {
       
  1799         read_string (str, sizeof (str), &p);
       
  1800         gst_sdp_media_add_format (&nmedia, str);
       
  1801       } while (*p != '\0');
       
  1802 
       
  1803       gst_sdp_message_add_media (c->msg, &nmedia);
       
  1804       c->media =
       
  1805           &g_array_index (c->msg->medias, GstSDPMedia, c->msg->medias->len - 1);
       
  1806       break;
       
  1807     }
       
  1808     default:
       
  1809       break;
       
  1810   }
       
  1811   return TRUE;
       
  1812 }
       
  1813 
       
  1814 /**
       
  1815  * gst_sdp_message_parse_buffer:
       
  1816  * @data: the start of the buffer
       
  1817  * @size: the size of the buffer
       
  1818  * @msg: the result #GstSDPMessage
       
  1819  *
       
  1820  * Parse the contents of @size bytes pointed to by @data and store the result in
       
  1821  * @msg.
       
  1822  *
       
  1823  * Returns: #GST_SDP_OK on success.
       
  1824  */
       
  1825 GstSDPResult
       
  1826 gst_sdp_message_parse_buffer (const guint8 * data, guint size,
       
  1827     GstSDPMessage * msg)
       
  1828 {
       
  1829   gchar *p;
       
  1830   SDPContext c;
       
  1831   gchar type;
       
  1832   gchar buffer[MAX_LINE_LEN];
       
  1833   guint idx = 0;
       
  1834 
       
  1835   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
       
  1836   g_return_val_if_fail (data != NULL, GST_SDP_EINVAL);
       
  1837   g_return_val_if_fail (size != 0, GST_SDP_EINVAL);
       
  1838 
       
  1839   c.state = SDP_SESSION;
       
  1840   c.msg = msg;
       
  1841   c.media = NULL;
       
  1842 
       
  1843   p = (gchar *) data;
       
  1844   while (TRUE) {
       
  1845     while (g_ascii_isspace (*p))
       
  1846       p++;
       
  1847 
       
  1848     type = *p++;
       
  1849     if (type == '\0')
       
  1850       break;
       
  1851 
       
  1852     if (*p != '=')
       
  1853       goto line_done;
       
  1854     p++;
       
  1855 
       
  1856     idx = 0;
       
  1857     while (*p != '\n' && *p != '\r' && *p != '\0') {
       
  1858       if (idx < sizeof (buffer) - 1)
       
  1859         buffer[idx++] = *p;
       
  1860       p++;
       
  1861     }
       
  1862     buffer[idx] = '\0';
       
  1863     gst_sdp_parse_line (&c, type, buffer);
       
  1864 
       
  1865   line_done:
       
  1866     while (*p != '\n' && *p != '\0')
       
  1867       p++;
       
  1868     if (*p == '\n')
       
  1869       p++;
       
  1870   }
       
  1871 
       
  1872   return GST_SDP_OK;
       
  1873 }
       
  1874 
       
  1875 static void
       
  1876 print_media (GstSDPMedia * media)
       
  1877 {
       
  1878   g_print ("   media:       '%s'\n", media->media);
       
  1879   g_print ("   port:        '%u'\n", media->port);
       
  1880   g_print ("   num_ports:   '%u'\n", media->num_ports);
       
  1881   g_print ("   proto:       '%s'\n", media->proto);
       
  1882   if (media->fmts->len > 0) {
       
  1883     guint i;
       
  1884 
       
  1885     g_print ("   formats:\n");
       
  1886     for (i = 0; i < media->fmts->len; i++) {
       
  1887       g_print ("    format  '%s'\n", g_array_index (media->fmts, gchar *, i));
       
  1888     }
       
  1889   }
       
  1890   g_print ("   information: '%s'\n", media->information);
       
  1891   g_print ("   key:\n");
       
  1892   g_print ("    type:       '%s'\n", media->key.type);
       
  1893   g_print ("    data:       '%s'\n", media->key.data);
       
  1894   if (media->attributes->len > 0) {
       
  1895     guint i;
       
  1896 
       
  1897     g_print ("   attributes:\n");
       
  1898     for (i = 0; i < media->attributes->len; i++) {
       
  1899       GstSDPAttribute *attr =
       
  1900           &g_array_index (media->attributes, GstSDPAttribute, i);
       
  1901 
       
  1902       g_print ("    attribute '%s' : '%s'\n", attr->key, attr->value);
       
  1903     }
       
  1904   }
       
  1905 }
       
  1906 
       
  1907 /**
       
  1908  * gst_sdp_message_dump:
       
  1909  * @msg: a #GstSDPMessage
       
  1910  *
       
  1911  * Dump the parsed contents of @msg to stdout.
       
  1912  *
       
  1913  * Returns: a #GstSDPResult.
       
  1914  */
       
  1915 GstSDPResult
       
  1916 gst_sdp_message_dump (const GstSDPMessage * msg)
       
  1917 {
       
  1918   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
       
  1919 
       
  1920   g_print ("sdp packet %p:\n", msg);
       
  1921   g_print (" version:       '%s'\n", GST_STR_NULL (msg->version));
       
  1922   g_print (" origin:\n");
       
  1923   g_print ("  username:     '%s'\n", GST_STR_NULL (msg->origin.username));
       
  1924   g_print ("  sess_id:      '%s'\n", GST_STR_NULL (msg->origin.sess_id));
       
  1925   g_print ("  sess_version: '%s'\n", GST_STR_NULL (msg->origin.sess_version));
       
  1926   g_print ("  nettype:      '%s'\n", GST_STR_NULL (msg->origin.nettype));
       
  1927   g_print ("  addrtype:     '%s'\n", GST_STR_NULL (msg->origin.addrtype));
       
  1928   g_print ("  addr:         '%s'\n", GST_STR_NULL (msg->origin.addr));
       
  1929   g_print (" session_name:  '%s'\n", GST_STR_NULL (msg->session_name));
       
  1930   g_print (" information:   '%s'\n", GST_STR_NULL (msg->information));
       
  1931   g_print (" uri:           '%s'\n", GST_STR_NULL (msg->uri));
       
  1932 
       
  1933   if (msg->emails->len > 0) {
       
  1934     guint i;
       
  1935 
       
  1936     g_print (" emails:\n");
       
  1937     for (i = 0; i < msg->emails->len; i++) {
       
  1938       g_print ("  email '%s'\n", g_array_index (msg->emails, gchar *, i));
       
  1939     }
       
  1940   }
       
  1941   if (msg->phones->len > 0) {
       
  1942     guint i;
       
  1943 
       
  1944     g_print (" phones:\n");
       
  1945     for (i = 0; i < msg->phones->len; i++) {
       
  1946       g_print ("  phone '%s'\n", g_array_index (msg->phones, gchar *, i));
       
  1947     }
       
  1948   }
       
  1949   g_print (" connection:\n");
       
  1950   g_print ("  nettype:      '%s'\n", GST_STR_NULL (msg->connection.nettype));
       
  1951   g_print ("  addrtype:     '%s'\n", GST_STR_NULL (msg->connection.addrtype));
       
  1952   g_print ("  address:      '%s'\n", GST_STR_NULL (msg->connection.address));
       
  1953   g_print ("  ttl:          '%u'\n", msg->connection.ttl);
       
  1954   g_print ("  addr_number:  '%u'\n", msg->connection.addr_number);
       
  1955   g_print (" key:\n");
       
  1956   g_print ("  type:         '%s'\n", GST_STR_NULL (msg->key.type));
       
  1957   g_print ("  data:         '%s'\n", GST_STR_NULL (msg->key.data));
       
  1958   if (msg->attributes->len > 0) {
       
  1959     guint i;
       
  1960 
       
  1961     g_print (" attributes:\n");
       
  1962     for (i = 0; i < msg->attributes->len; i++) {
       
  1963       GstSDPAttribute *attr =
       
  1964           &g_array_index (msg->attributes, GstSDPAttribute, i);
       
  1965 
       
  1966       g_print ("  attribute '%s' : '%s'\n", attr->key, attr->value);
       
  1967     }
       
  1968   }
       
  1969   if (msg->medias->len > 0) {
       
  1970     guint i;
       
  1971 
       
  1972     g_print (" medias:\n");
       
  1973     for (i = 0; i < msg->medias->len; i++) {
       
  1974       g_print ("  media %u:\n", i);
       
  1975       print_media (&g_array_index (msg->medias, GstSDPMedia, i));
       
  1976     }
       
  1977   }
       
  1978   return GST_SDP_OK;
       
  1979 }