sdp: Include winsock2.h after defining WINVER.
[platform/upstream/gstreamer.git] / gst-libs / gst / sdp / gstsdpmessage.c
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 /* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
73  * minwg32 headers check WINVER before allowing the use of these */
74 #ifndef WINVER
75 #define WINVER 0x0501
76 #endif
77 #ifdef _MSC_VER
78 #include <Winsock2.h>
79 #endif
80 #include <ws2tcpip.h>
81 #else
82 #include <sys/socket.h>
83 #include <netdb.h>
84 #include <netinet/in.h>
85 #endif
86
87 #include "gstsdpmessage.h"
88
89 /* FIXME, is currently allocated on the stack */
90 #define MAX_LINE_LEN    1024 * 16
91
92 #define FREE_STRING(field)              g_free (field); (field) = NULL
93 #define REPLACE_STRING(field, val)      FREE_STRING(field); (field) = g_strdup (val)
94
95 #define INIT_ARRAY(field, type, init_func)              \
96 G_STMT_START {                                          \
97   if (field) {                                          \
98     guint i;                                            \
99     for(i = 0; i < (field)->len; i++)                   \
100       init_func (&g_array_index ((field), type, i));    \
101     g_array_set_size ((field), 0);                      \
102   }                                                     \
103   else                                                  \
104     (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
105 } G_STMT_END
106
107 #define FREE_ARRAY(field)         \
108 G_STMT_START {                    \
109   if (field)                      \
110     g_array_free ((field), TRUE); \
111   (field) = NULL;                 \
112 } G_STMT_END
113
114 #define INIT_PTR_ARRAY(field, type, init_func)          \
115 G_STMT_START {                                          \
116   if (field) {                                          \
117     guint i;                                            \
118     for(i = 0; i < (field)->len; i++)                   \
119       init_func (g_array_index ((field), type, i));     \
120     g_array_set_size ((field), 0);                      \
121   }                                                     \
122   else                                                  \
123     (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
124 } G_STMT_END
125
126 #define FREE_PTR_ARRAY(field) FREE_ARRAY(field)
127
128 #define DEFINE_STRING_SETTER(field)                                     \
129 GstSDPResult gst_sdp_message_set_##field (GstSDPMessage *msg, const gchar *val) { \
130   g_free (msg->field);                                                  \
131   msg->field = g_strdup (val);                                          \
132   return GST_SDP_OK;                                                    \
133 }
134 #define DEFINE_STRING_GETTER(field)                                     \
135 const gchar* gst_sdp_message_get_##field (const GstSDPMessage *msg) {   \
136   return msg->field;                                                    \
137 }
138
139 #define DEFINE_ARRAY_LEN(field)                                         \
140 guint gst_sdp_message_##field##_len (const GstSDPMessage *msg) {        \
141   return msg->field->len;                                               \
142 }
143 #define DEFINE_ARRAY_GETTER(method, field, type)                        \
144 type * gst_sdp_message_get_##method (const GstSDPMessage *msg, guint idx) {  \
145   return &g_array_index (msg->field, type, idx);                        \
146 }
147
148 #define DEFINE_PTR_ARRAY_LEN(field) DEFINE_ARRAY_LEN(field)
149 #define DEFINE_PTR_ARRAY_GETTER(method, field, type)                    \
150 type gst_sdp_message_get_##method (const GstSDPMessage *msg, guint idx) {    \
151   return g_array_index (msg->field, type, idx);                         \
152 }
153 #define DEFINE_PTR_ARRAY_ADDER(method, field, type, dup_method)         \
154 GstSDPResult gst_sdp_message_add_##method (GstSDPMessage *msg, type val) {   \
155   type v = dup_method (val);                                            \
156   g_array_append_val (msg->field, v);                                   \
157   return GST_SDP_OK;                                                    \
158 }
159
160 static void
161 gst_sdp_origin_init (GstSDPOrigin * origin)
162 {
163   FREE_STRING (origin->username);
164   FREE_STRING (origin->sess_id);
165   FREE_STRING (origin->sess_version);
166   FREE_STRING (origin->nettype);
167   FREE_STRING (origin->addrtype);
168   FREE_STRING (origin->addr);
169 }
170
171 static void
172 gst_sdp_connection_init (GstSDPConnection * connection)
173 {
174   FREE_STRING (connection->nettype);
175   FREE_STRING (connection->addrtype);
176   FREE_STRING (connection->address);
177   connection->ttl = 0;
178   connection->addr_number = 0;
179 }
180
181 static void
182 gst_sdp_bandwidth_init (GstSDPBandwidth * bandwidth)
183 {
184   FREE_STRING (bandwidth->bwtype);
185   bandwidth->bandwidth = 0;
186 }
187
188 static void
189 gst_sdp_time_init (GstSDPTime * t)
190 {
191   FREE_STRING (t->start);
192   FREE_STRING (t->stop);
193   INIT_PTR_ARRAY (t->repeat, gchar *, g_free);
194   FREE_PTR_ARRAY (t->repeat);
195 }
196
197 static void
198 gst_sdp_zone_init (GstSDPZone * zone)
199 {
200   FREE_STRING (zone->time);
201   FREE_STRING (zone->typed_time);
202 }
203
204 static void
205 gst_sdp_key_init (GstSDPKey * key)
206 {
207   FREE_STRING (key->type);
208   FREE_STRING (key->data);
209 }
210
211 static void
212 gst_sdp_attribute_init (GstSDPAttribute * attr)
213 {
214   FREE_STRING (attr->key);
215   FREE_STRING (attr->value);
216 }
217
218 /**
219  * gst_sdp_message_new:
220  * @msg: pointer to new #GstSDPMessage
221  *
222  * Allocate a new GstSDPMessage and store the result in @msg.
223  *
224  * Returns: a #GstSDPResult.
225  */
226 GstSDPResult
227 gst_sdp_message_new (GstSDPMessage ** msg)
228 {
229   GstSDPMessage *newmsg;
230
231   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
232
233   newmsg = g_new0 (GstSDPMessage, 1);
234
235   *msg = newmsg;
236
237   return gst_sdp_message_init (newmsg);
238 }
239
240 /**
241  * gst_sdp_message_init:
242  * @msg: a #GstSDPMessage
243  *
244  * Initialize @msg so that its contents are as if it was freshly allocated
245  * with gst_sdp_message_new(). This function is mostly used to initialize a message
246  * allocated on the stack. gst_sdp_message_uninit() undoes this operation.
247  *
248  * When this function is invoked on newly allocated data (with malloc or on the
249  * stack), its contents should be set to 0 before calling this function.
250  *
251  * Returns: a #GstSDPResult.
252  */
253 GstSDPResult
254 gst_sdp_message_init (GstSDPMessage * msg)
255 {
256   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
257
258   FREE_STRING (msg->version);
259   gst_sdp_origin_init (&msg->origin);
260   FREE_STRING (msg->session_name);
261   FREE_STRING (msg->information);
262   FREE_STRING (msg->uri);
263   INIT_PTR_ARRAY (msg->emails, gchar *, g_free);
264   INIT_PTR_ARRAY (msg->phones, gchar *, g_free);
265   gst_sdp_connection_init (&msg->connection);
266   INIT_ARRAY (msg->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_init);
267   INIT_ARRAY (msg->times, GstSDPTime, gst_sdp_time_init);
268   INIT_ARRAY (msg->zones, GstSDPZone, gst_sdp_zone_init);
269   gst_sdp_key_init (&msg->key);
270   INIT_ARRAY (msg->attributes, GstSDPAttribute, gst_sdp_attribute_init);
271   INIT_ARRAY (msg->medias, GstSDPMedia, gst_sdp_media_uninit);
272
273   return GST_SDP_OK;
274 }
275
276 /**
277  * gst_sdp_message_uninit:
278  * @msg: a #GstSDPMessage
279  *
280  * Free all resources allocated in @msg. @msg should not be used anymore after
281  * this function. This function should be used when @msg was allocated on the
282  * stack and initialized with gst_sdp_message_init().
283  *
284  * Returns: a #GstSDPResult.
285  */
286 GstSDPResult
287 gst_sdp_message_uninit (GstSDPMessage * msg)
288 {
289   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
290
291   gst_sdp_message_init (msg);
292
293   FREE_PTR_ARRAY (msg->emails);
294   FREE_PTR_ARRAY (msg->phones);
295   FREE_ARRAY (msg->bandwidths);
296   FREE_ARRAY (msg->times);
297   FREE_ARRAY (msg->zones);
298   FREE_ARRAY (msg->attributes);
299   FREE_ARRAY (msg->medias);
300
301   return GST_SDP_OK;
302 }
303
304 /**
305  * gst_sdp_message_free:
306  * @msg: a #GstSDPMessage
307  *
308  * Free all resources allocated by @msg. @msg should not be used anymore after
309  * this function. This function should be used when @msg was dynamically
310  * allocated with gst_sdp_message_new().
311  *
312  * Returns: a #GstSDPResult.
313  */
314 GstSDPResult
315 gst_sdp_message_free (GstSDPMessage * msg)
316 {
317   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
318
319   gst_sdp_message_uninit (msg);
320   g_free (msg);
321
322   return GST_SDP_OK;
323 }
324
325 static gboolean
326 is_multicast_address (const gchar * host_name, guint * family)
327 {
328   struct addrinfo hints;
329   struct addrinfo *ai;
330   struct addrinfo *res;
331   gboolean ret = FALSE;
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 (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     {
1746       GstSDPConnection conn;
1747       gchar *str2;
1748
1749       memset (&conn, 0, sizeof (conn));
1750
1751       str2 = p;
1752       while ((str2 = strchr (str2, '/')))
1753         *str2++ = ' ';
1754       READ_STRING (conn.nettype);
1755       READ_STRING (conn.addrtype);
1756       READ_STRING (conn.address);
1757       READ_UINT (conn.ttl);
1758       READ_UINT (conn.addr_number);
1759
1760       if (c->state == SDP_SESSION) {
1761         gst_sdp_message_set_connection (c->msg, conn.nettype, conn.addrtype,
1762             conn.address, conn.ttl, conn.addr_number);
1763       } else {
1764         gst_sdp_media_add_connection (c->media, conn.nettype, conn.addrtype,
1765             conn.address, conn.ttl, conn.addr_number);
1766       }
1767       gst_sdp_connection_init (&conn);
1768       break;
1769     }
1770     case 'b':
1771     {
1772       gchar str2[MAX_LINE_LEN];
1773
1774       read_string_del (str, sizeof (str), ':', &p);
1775       if (*p != '\0')
1776         p++;
1777       read_string (str2, sizeof (str2), &p);
1778       if (c->state == SDP_SESSION)
1779         gst_sdp_message_add_bandwidth (c->msg, str, atoi (str2));
1780       else
1781         gst_sdp_media_add_bandwidth (c->media, str, atoi (str2));
1782       break;
1783     }
1784     case 't':
1785       break;
1786     case 'k':
1787       break;
1788     case 'a':
1789       read_string_del (str, sizeof (str), ':', &p);
1790       if (*p != '\0')
1791         p++;
1792       if (c->state == SDP_SESSION)
1793         gst_sdp_message_add_attribute (c->msg, str, p);
1794       else
1795         gst_sdp_media_add_attribute (c->media, str, p);
1796       break;
1797     case 'm':
1798     {
1799       gchar *slash;
1800       GstSDPMedia nmedia;
1801
1802       c->state = SDP_MEDIA;
1803       memset (&nmedia, 0, sizeof (nmedia));
1804       gst_sdp_media_init (&nmedia);
1805
1806       /* m=<media> <port>/<number of ports> <proto> <fmt> ... */
1807       READ_STRING (nmedia.media);
1808       read_string (str, sizeof (str), &p);
1809       slash = g_strrstr (str, "/");
1810       if (slash) {
1811         *slash = '\0';
1812         nmedia.port = atoi (str);
1813         nmedia.num_ports = atoi (slash + 1);
1814       } else {
1815         nmedia.port = atoi (str);
1816         nmedia.num_ports = -1;
1817       }
1818       READ_STRING (nmedia.proto);
1819       do {
1820         read_string (str, sizeof (str), &p);
1821         gst_sdp_media_add_format (&nmedia, str);
1822       } while (*p != '\0');
1823
1824       gst_sdp_message_add_media (c->msg, &nmedia);
1825       c->media =
1826           &g_array_index (c->msg->medias, GstSDPMedia, c->msg->medias->len - 1);
1827       break;
1828     }
1829     default:
1830       break;
1831   }
1832   return TRUE;
1833 }
1834
1835 /**
1836  * gst_sdp_message_parse_buffer:
1837  * @data: the start of the buffer
1838  * @size: the size of the buffer
1839  * @msg: the result #GstSDPMessage
1840  *
1841  * Parse the contents of @size bytes pointed to by @data and store the result in
1842  * @msg.
1843  *
1844  * Returns: #GST_SDP_OK on success.
1845  */
1846 GstSDPResult
1847 gst_sdp_message_parse_buffer (const guint8 * data, guint size,
1848     GstSDPMessage * msg)
1849 {
1850   gchar *p;
1851   SDPContext c;
1852   gchar type;
1853   gchar buffer[MAX_LINE_LEN];
1854   guint idx = 0;
1855
1856   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1857   g_return_val_if_fail (data != NULL, GST_SDP_EINVAL);
1858   g_return_val_if_fail (size != 0, GST_SDP_EINVAL);
1859
1860   c.state = SDP_SESSION;
1861   c.msg = msg;
1862   c.media = NULL;
1863
1864   p = (gchar *) data;
1865   while (TRUE) {
1866     while (g_ascii_isspace (*p))
1867       p++;
1868
1869     type = *p++;
1870     if (type == '\0')
1871       break;
1872
1873     if (*p != '=')
1874       goto line_done;
1875     p++;
1876
1877     idx = 0;
1878     while (*p != '\n' && *p != '\r' && *p != '\0') {
1879       if (idx < sizeof (buffer) - 1)
1880         buffer[idx++] = *p;
1881       p++;
1882     }
1883     buffer[idx] = '\0';
1884     gst_sdp_parse_line (&c, type, buffer);
1885
1886   line_done:
1887     while (*p != '\n' && *p != '\0')
1888       p++;
1889     if (*p == '\n')
1890       p++;
1891   }
1892
1893   return GST_SDP_OK;
1894 }
1895
1896 static void
1897 print_media (GstSDPMedia * media)
1898 {
1899   g_print ("   media:       '%s'\n", GST_STR_NULL (media->media));
1900   g_print ("   port:        '%u'\n", media->port);
1901   g_print ("   num_ports:   '%u'\n", media->num_ports);
1902   g_print ("   proto:       '%s'\n", GST_STR_NULL (media->proto));
1903   if (media->fmts->len > 0) {
1904     guint i;
1905
1906     g_print ("   formats:\n");
1907     for (i = 0; i < media->fmts->len; i++) {
1908       g_print ("    format  '%s'\n", g_array_index (media->fmts, gchar *, i));
1909     }
1910   }
1911   g_print ("   information: '%s'\n", GST_STR_NULL (media->information));
1912   if (media->connections->len > 0) {
1913     guint i;
1914
1915     g_print ("   connections:\n");
1916     for (i = 0; i < media->connections->len; i++) {
1917       GstSDPConnection *conn =
1918           &g_array_index (media->connections, GstSDPConnection, i);
1919
1920       g_print ("    nettype:      '%s'\n", GST_STR_NULL (conn->nettype));
1921       g_print ("    addrtype:     '%s'\n", GST_STR_NULL (conn->addrtype));
1922       g_print ("    address:      '%s'\n", GST_STR_NULL (conn->address));
1923       g_print ("    ttl:          '%u'\n", conn->ttl);
1924       g_print ("    addr_number:  '%u'\n", conn->addr_number);
1925     }
1926   }
1927   if (media->bandwidths->len > 0) {
1928     guint i;
1929
1930     g_print ("   bandwidths:\n");
1931     for (i = 0; i < media->bandwidths->len; i++) {
1932       GstSDPBandwidth *bw =
1933           &g_array_index (media->bandwidths, GstSDPBandwidth, i);
1934
1935       g_print ("    type:         '%s'\n", GST_STR_NULL (bw->bwtype));
1936       g_print ("    bandwidth:    '%u'\n", bw->bandwidth);
1937     }
1938   }
1939   g_print ("   key:\n");
1940   g_print ("    type:       '%s'\n", GST_STR_NULL (media->key.type));
1941   g_print ("    data:       '%s'\n", GST_STR_NULL (media->key.data));
1942   if (media->attributes->len > 0) {
1943     guint i;
1944
1945     g_print ("   attributes:\n");
1946     for (i = 0; i < media->attributes->len; i++) {
1947       GstSDPAttribute *attr =
1948           &g_array_index (media->attributes, GstSDPAttribute, i);
1949
1950       g_print ("    attribute '%s' : '%s'\n", attr->key, attr->value);
1951     }
1952   }
1953 }
1954
1955 /**
1956  * gst_sdp_message_dump:
1957  * @msg: a #GstSDPMessage
1958  *
1959  * Dump the parsed contents of @msg to stdout.
1960  *
1961  * Returns: a #GstSDPResult.
1962  */
1963 GstSDPResult
1964 gst_sdp_message_dump (const GstSDPMessage * msg)
1965 {
1966   g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1967
1968   g_print ("sdp packet %p:\n", msg);
1969   g_print (" version:       '%s'\n", GST_STR_NULL (msg->version));
1970   g_print (" origin:\n");
1971   g_print ("  username:     '%s'\n", GST_STR_NULL (msg->origin.username));
1972   g_print ("  sess_id:      '%s'\n", GST_STR_NULL (msg->origin.sess_id));
1973   g_print ("  sess_version: '%s'\n", GST_STR_NULL (msg->origin.sess_version));
1974   g_print ("  nettype:      '%s'\n", GST_STR_NULL (msg->origin.nettype));
1975   g_print ("  addrtype:     '%s'\n", GST_STR_NULL (msg->origin.addrtype));
1976   g_print ("  addr:         '%s'\n", GST_STR_NULL (msg->origin.addr));
1977   g_print (" session_name:  '%s'\n", GST_STR_NULL (msg->session_name));
1978   g_print (" information:   '%s'\n", GST_STR_NULL (msg->information));
1979   g_print (" uri:           '%s'\n", GST_STR_NULL (msg->uri));
1980
1981   if (msg->emails->len > 0) {
1982     guint i;
1983
1984     g_print (" emails:\n");
1985     for (i = 0; i < msg->emails->len; i++) {
1986       g_print ("  email '%s'\n", g_array_index (msg->emails, gchar *, i));
1987     }
1988   }
1989   if (msg->phones->len > 0) {
1990     guint i;
1991
1992     g_print (" phones:\n");
1993     for (i = 0; i < msg->phones->len; i++) {
1994       g_print ("  phone '%s'\n", g_array_index (msg->phones, gchar *, i));
1995     }
1996   }
1997   g_print (" connection:\n");
1998   g_print ("  nettype:      '%s'\n", GST_STR_NULL (msg->connection.nettype));
1999   g_print ("  addrtype:     '%s'\n", GST_STR_NULL (msg->connection.addrtype));
2000   g_print ("  address:      '%s'\n", GST_STR_NULL (msg->connection.address));
2001   g_print ("  ttl:          '%u'\n", msg->connection.ttl);
2002   g_print ("  addr_number:  '%u'\n", msg->connection.addr_number);
2003   if (msg->bandwidths->len > 0) {
2004     guint i;
2005
2006     g_print (" bandwidths:\n");
2007     for (i = 0; i < msg->bandwidths->len; i++) {
2008       GstSDPBandwidth *bw =
2009           &g_array_index (msg->bandwidths, GstSDPBandwidth, i);
2010
2011       g_print ("  type:         '%s'\n", GST_STR_NULL (bw->bwtype));
2012       g_print ("  bandwidth:    '%u'\n", bw->bandwidth);
2013     }
2014   }
2015   g_print (" key:\n");
2016   g_print ("  type:         '%s'\n", GST_STR_NULL (msg->key.type));
2017   g_print ("  data:         '%s'\n", GST_STR_NULL (msg->key.data));
2018   if (msg->attributes->len > 0) {
2019     guint i;
2020
2021     g_print (" attributes:\n");
2022     for (i = 0; i < msg->attributes->len; i++) {
2023       GstSDPAttribute *attr =
2024           &g_array_index (msg->attributes, GstSDPAttribute, i);
2025
2026       g_print ("  attribute '%s' : '%s'\n", attr->key, attr->value);
2027     }
2028   }
2029   if (msg->medias->len > 0) {
2030     guint i;
2031
2032     g_print (" medias:\n");
2033     for (i = 0; i < msg->medias->len; i++) {
2034       g_print ("  media %u:\n", i);
2035       print_media (&g_array_index (msg->medias, GstSDPMedia, i));
2036     }
2037   }
2038   return GST_SDP_OK;
2039 }