2 * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
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.
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.
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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
20 * Unless otherwise indicated, Source Code is licensed under MIT license.
21 * See further explanation attached in License Statement (distributed in the file
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:
31 * The above copyright notice and this permission notice shall be included in all
32 * copies or substantial portions of the Software.
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
44 * SECTION:gstsdpmessage
45 * @short_description: Helper methods for dealing with SDP messages
49 * The GstSDPMessage helper functions makes it easy to parse and create SDP
65 #include <gst/rtp/gstrtppayloads.h>
66 #include "gstsdpmessage.h"
69 #define FREE_STRING(field) g_free (field); (field) = NULL
70 #define REPLACE_STRING(field, val) FREE_STRING(field); (field) = g_strdup (val)
73 free_string (gchar ** str)
78 #define INIT_ARRAY(field, type, init_func) \
82 for(i = 0; i < (field)->len; i++) \
83 init_func (&g_array_index ((field), type, i)); \
84 g_array_set_size ((field), 0); \
87 (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
90 #define FREE_ARRAY(field) \
93 g_array_free ((field), TRUE); \
97 #define DEFINE_STRING_SETTER(field) \
98 GstSDPResult gst_sdp_message_set_##field (GstSDPMessage *msg, const gchar *val) { \
99 g_free (msg->field); \
100 msg->field = g_strdup (val); \
103 #define DEFINE_STRING_GETTER(field) \
104 const gchar* gst_sdp_message_get_##field (const GstSDPMessage *msg) { \
108 #define DEFINE_ARRAY_LEN(field) \
109 guint gst_sdp_message_##field##_len (const GstSDPMessage *msg) { \
110 return msg->field->len; \
112 #define DEFINE_ARRAY_GETTER(method, field, type) \
113 const type * gst_sdp_message_get_##method (const GstSDPMessage *msg, guint idx) { \
114 return &g_array_index (msg->field, type, idx); \
116 #define DEFINE_PTR_ARRAY_GETTER(method, field, type) \
117 const type gst_sdp_message_get_##method (const GstSDPMessage *msg, guint idx) { \
118 return g_array_index (msg->field, type, idx); \
120 #define DEFINE_ARRAY_INSERT(method, field, intype, dup_method, type) \
121 GstSDPResult gst_sdp_message_insert_##method (GstSDPMessage *msg, gint idx, intype val) { \
124 dup_method (v, val); \
126 g_array_append_val (msg->field, vt); \
128 g_array_insert_val (msg->field, idx, vt); \
132 #define DEFINE_ARRAY_REPLACE(method, field, intype, free_method, dup_method, type) \
133 GstSDPResult gst_sdp_message_replace_##method (GstSDPMessage *msg, guint idx, intype val) { \
134 type *v = &g_array_index (msg->field, type, idx); \
136 dup_method (v, val); \
139 #define DEFINE_ARRAY_REMOVE(method, field, type, free_method) \
140 GstSDPResult gst_sdp_message_remove_##method (GstSDPMessage *msg, guint idx) { \
141 type *v = &g_array_index (msg->field, type, idx); \
143 g_array_remove_index (msg->field, idx); \
146 #define DEFINE_ARRAY_ADDER(method, type) \
147 GstSDPResult gst_sdp_message_add_##method (GstSDPMessage *msg, const type val) { \
148 return gst_sdp_message_insert_##method (msg, -1, val); \
151 #define dup_string(v,val) ((*v) = g_strdup (val))
152 #define INIT_STR_ARRAY(field) \
153 INIT_ARRAY (field, gchar *, free_string)
154 #define DEFINE_STR_ARRAY_GETTER(method, field) \
155 DEFINE_PTR_ARRAY_GETTER(method, field, gchar *)
156 #define DEFINE_STR_ARRAY_INSERT(method, field) \
157 DEFINE_ARRAY_INSERT (method, field, const gchar *, dup_string, gchar *)
158 #define DEFINE_STR_ARRAY_ADDER(method, field) \
159 DEFINE_ARRAY_ADDER (method, gchar *)
160 #define DEFINE_STR_ARRAY_REPLACE(method, field) \
161 DEFINE_ARRAY_REPLACE (method, field, const gchar *, free_string, dup_string, gchar *)
162 #define DEFINE_STR_ARRAY_REMOVE(method, field) \
163 DEFINE_ARRAY_REMOVE (method, field, gchar *, free_string)
165 static GstSDPMessage *gst_sdp_message_boxed_copy (GstSDPMessage * orig);
166 static void gst_sdp_message_boxed_free (GstSDPMessage * msg);
168 G_DEFINE_BOXED_TYPE (GstSDPMessage, gst_sdp_message, gst_sdp_message_boxed_copy,
169 gst_sdp_message_boxed_free);
171 static GstSDPMessage *
172 gst_sdp_message_boxed_copy (GstSDPMessage * orig)
176 if (gst_sdp_message_copy (orig, ©) == GST_SDP_OK)
183 gst_sdp_message_boxed_free (GstSDPMessage * msg)
185 gst_sdp_message_free (msg);
189 gst_sdp_origin_init (GstSDPOrigin * origin)
191 FREE_STRING (origin->username);
192 FREE_STRING (origin->sess_id);
193 FREE_STRING (origin->sess_version);
194 FREE_STRING (origin->nettype);
195 FREE_STRING (origin->addrtype);
196 FREE_STRING (origin->addr);
200 gst_sdp_key_init (GstSDPKey * key)
202 FREE_STRING (key->type);
203 FREE_STRING (key->data);
207 * gst_sdp_message_new:
208 * @msg: (out) (transfer full): pointer to new #GstSDPMessage
210 * Allocate a new GstSDPMessage and store the result in @msg.
212 * Returns: a #GstSDPResult.
215 gst_sdp_message_new (GstSDPMessage ** msg)
217 GstSDPMessage *newmsg;
219 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
221 newmsg = g_new0 (GstSDPMessage, 1);
225 return gst_sdp_message_init (newmsg);
229 * gst_sdp_message_init:
230 * @msg: a #GstSDPMessage
232 * Initialize @msg so that its contents are as if it was freshly allocated
233 * with gst_sdp_message_new(). This function is mostly used to initialize a message
234 * allocated on the stack. gst_sdp_message_uninit() undoes this operation.
236 * When this function is invoked on newly allocated data (with malloc or on the
237 * stack), its contents should be set to 0 before calling this function.
239 * Returns: a #GstSDPResult.
242 gst_sdp_message_init (GstSDPMessage * msg)
244 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
246 FREE_STRING (msg->version);
247 gst_sdp_origin_init (&msg->origin);
248 FREE_STRING (msg->session_name);
249 FREE_STRING (msg->information);
250 FREE_STRING (msg->uri);
251 INIT_STR_ARRAY (msg->emails);
252 INIT_STR_ARRAY (msg->phones);
253 gst_sdp_connection_clear (&msg->connection);
254 INIT_ARRAY (msg->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_clear);
255 INIT_ARRAY (msg->times, GstSDPTime, gst_sdp_time_clear);
256 INIT_ARRAY (msg->zones, GstSDPZone, gst_sdp_zone_clear);
257 gst_sdp_key_init (&msg->key);
258 INIT_ARRAY (msg->attributes, GstSDPAttribute, gst_sdp_attribute_clear);
259 INIT_ARRAY (msg->medias, GstSDPMedia, gst_sdp_media_uninit);
265 * gst_sdp_message_uninit:
266 * @msg: a #GstSDPMessage
268 * Free all resources allocated in @msg. @msg should not be used anymore after
269 * this function. This function should be used when @msg was allocated on the
270 * stack and initialized with gst_sdp_message_init().
272 * Returns: a #GstSDPResult.
275 gst_sdp_message_uninit (GstSDPMessage * msg)
277 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
279 gst_sdp_message_init (msg);
281 FREE_ARRAY (msg->emails);
282 FREE_ARRAY (msg->phones);
283 FREE_ARRAY (msg->bandwidths);
284 FREE_ARRAY (msg->times);
285 FREE_ARRAY (msg->zones);
286 FREE_ARRAY (msg->attributes);
287 FREE_ARRAY (msg->medias);
293 * gst_sdp_message_copy:
294 * @msg: a #GstSDPMessage
295 * @copy: (out) (transfer full): pointer to new #GstSDPMessage
297 * Allocate a new copy of @msg and store the result in @copy. The value in
298 * @copy should be release with gst_sdp_message_free function.
300 * Returns: a #GstSDPResult
305 gst_sdp_message_copy (const GstSDPMessage * msg, GstSDPMessage ** copy)
312 return GST_SDP_EINVAL;
314 ret = gst_sdp_message_new (copy);
315 if (ret != GST_SDP_OK)
320 REPLACE_STRING (cp->version, msg->version);
321 gst_sdp_message_set_origin (cp, msg->origin.username, msg->origin.sess_id,
322 msg->origin.sess_version, msg->origin.nettype, msg->origin.addrtype,
324 REPLACE_STRING (cp->session_name, msg->session_name);
325 REPLACE_STRING (cp->information, msg->information);
326 REPLACE_STRING (cp->uri, msg->uri);
328 len = gst_sdp_message_emails_len (msg);
329 for (i = 0; i < len; i++) {
330 gst_sdp_message_add_email (cp, gst_sdp_message_get_email (msg, i));
333 len = gst_sdp_message_phones_len (msg);
334 for (i = 0; i < len; i++) {
335 gst_sdp_message_add_phone (cp, gst_sdp_message_get_phone (msg, i));
338 gst_sdp_message_set_connection (cp, msg->connection.nettype,
339 msg->connection.addrtype, msg->connection.address, msg->connection.ttl,
340 msg->connection.addr_number);
342 len = gst_sdp_message_bandwidths_len (msg);
343 for (i = 0; i < len; i++) {
344 const GstSDPBandwidth *bw = gst_sdp_message_get_bandwidth (msg, i);
345 gst_sdp_message_add_bandwidth (cp, bw->bwtype, bw->bandwidth);
348 len = gst_sdp_message_times_len (msg);
349 for (i = 0; i < len; i++) {
350 const gchar **repeat = NULL;
351 const GstSDPTime *time = gst_sdp_message_get_time (msg, i);
353 if (time->repeat != NULL) {
356 repeat = g_malloc0 ((time->repeat->len + 1) * sizeof (gchar *));
357 for (j = 0; j < time->repeat->len; j++) {
358 repeat[j] = g_array_index (time->repeat, char *, j);
363 gst_sdp_message_add_time (cp, time->start, time->stop, repeat);
368 len = gst_sdp_message_zones_len (msg);
369 for (i = 0; i < len; i++) {
370 const GstSDPZone *zone = gst_sdp_message_get_zone (msg, i);
371 gst_sdp_message_add_zone (cp, zone->time, zone->typed_time);
374 gst_sdp_message_set_key (cp, msg->key.type, msg->key.data);
376 len = gst_sdp_message_attributes_len (msg);
377 for (i = 0; i < len; i++) {
378 const GstSDPAttribute *attr = gst_sdp_message_get_attribute (msg, i);
379 gst_sdp_message_add_attribute (cp, attr->key, attr->value);
382 len = gst_sdp_message_medias_len (msg);
383 for (i = 0; i < len; i++) {
384 GstSDPMedia *media_copy;
385 const GstSDPMedia *media = gst_sdp_message_get_media (msg, i);
387 if (gst_sdp_media_copy (media, &media_copy) == GST_SDP_OK) {
388 gst_sdp_message_add_media (cp, media_copy);
389 gst_sdp_media_free (media_copy);
397 * gst_sdp_message_free:
398 * @msg: a #GstSDPMessage
400 * Free all resources allocated by @msg. @msg should not be used anymore after
401 * this function. This function should be used when @msg was dynamically
402 * allocated with gst_sdp_message_new().
404 * Returns: a #GstSDPResult.
407 gst_sdp_message_free (GstSDPMessage * msg)
409 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
411 gst_sdp_message_uninit (msg);
418 * gst_sdp_address_is_multicast:
419 * @nettype: a network type
420 * @addrtype: an address type
423 * Check if the given @addr is a multicast address.
425 * Returns: TRUE when @addr is multicast.
428 gst_sdp_address_is_multicast (const gchar * nettype, const gchar * addrtype,
431 gboolean ret = FALSE;
434 g_return_val_if_fail (addr, FALSE);
436 /* we only support IN */
437 if (nettype && strcmp (nettype, "IN") != 0)
440 /* guard against parse failures */
441 if ((iaddr = g_inet_address_new_from_string (addr)) == NULL)
444 ret = g_inet_address_get_is_multicast (iaddr);
445 g_object_unref (iaddr);
451 * gst_sdp_message_as_text:
452 * @msg: a #GstSDPMessage
454 * Convert the contents of @msg to a text string.
456 * Returns: A dynamically allocated string representing the SDP description.
459 gst_sdp_message_as_text (const GstSDPMessage * msg)
461 /* change all vars so they match rfc? */
465 g_return_val_if_fail (msg != NULL, NULL);
467 lines = g_string_new ("");
470 g_string_append_printf (lines, "v=%s\r\n", msg->version);
472 if (msg->origin.sess_id && msg->origin.sess_version && msg->origin.nettype &&
473 msg->origin.addrtype && msg->origin.addr)
474 g_string_append_printf (lines, "o=%s %s %s %s %s %s\r\n",
475 msg->origin.username ? msg->origin.username : "-", msg->origin.sess_id,
476 msg->origin.sess_version, msg->origin.nettype, msg->origin.addrtype,
479 if (msg->session_name)
480 g_string_append_printf (lines, "s=%s\r\n", msg->session_name);
482 if (msg->information)
483 g_string_append_printf (lines, "i=%s\r\n", msg->information);
486 g_string_append_printf (lines, "u=%s\r\n", msg->uri);
488 for (i = 0; i < gst_sdp_message_emails_len (msg); i++)
489 g_string_append_printf (lines, "e=%s\r\n",
490 gst_sdp_message_get_email (msg, i));
492 for (i = 0; i < gst_sdp_message_phones_len (msg); i++)
493 g_string_append_printf (lines, "p=%s\r\n",
494 gst_sdp_message_get_phone (msg, i));
496 if (msg->connection.nettype && msg->connection.addrtype &&
497 msg->connection.address) {
498 g_string_append_printf (lines, "c=%s %s %s", msg->connection.nettype,
499 msg->connection.addrtype, msg->connection.address);
500 if (gst_sdp_address_is_multicast (msg->connection.nettype,
501 msg->connection.addrtype, msg->connection.address)) {
502 /* only add ttl for IP4 */
503 if (strcmp (msg->connection.addrtype, "IP4") == 0)
504 g_string_append_printf (lines, "/%u", msg->connection.ttl);
505 if (msg->connection.addr_number > 1)
506 g_string_append_printf (lines, "/%u", msg->connection.addr_number);
508 g_string_append_printf (lines, "\r\n");
511 for (i = 0; i < gst_sdp_message_bandwidths_len (msg); i++) {
512 const GstSDPBandwidth *bandwidth = gst_sdp_message_get_bandwidth (msg, i);
514 g_string_append_printf (lines, "b=%s:%u\r\n", bandwidth->bwtype,
515 bandwidth->bandwidth);
518 if (gst_sdp_message_times_len (msg) == 0) {
519 g_string_append_printf (lines, "t=0 0\r\n");
521 for (i = 0; i < gst_sdp_message_times_len (msg); i++) {
522 const GstSDPTime *times = gst_sdp_message_get_time (msg, i);
524 g_string_append_printf (lines, "t=%s %s\r\n", times->start, times->stop);
526 if (times->repeat != NULL) {
529 g_string_append_printf (lines, "r=%s",
530 g_array_index (times->repeat, gchar *, 0));
531 for (j = 1; j < times->repeat->len; j++)
532 g_string_append_printf (lines, " %s",
533 g_array_index (times->repeat, gchar *, j));
534 g_string_append_printf (lines, "\r\n");
539 if (gst_sdp_message_zones_len (msg) > 0) {
540 const GstSDPZone *zone = gst_sdp_message_get_zone (msg, 0);
542 g_string_append_printf (lines, "z=%s %s", zone->time, zone->typed_time);
543 for (i = 1; i < gst_sdp_message_zones_len (msg); i++) {
544 zone = gst_sdp_message_get_zone (msg, i);
545 g_string_append_printf (lines, " %s %s", zone->time, zone->typed_time);
547 g_string_append_printf (lines, "\r\n");
551 g_string_append_printf (lines, "k=%s", msg->key.type);
553 g_string_append_printf (lines, ":%s", msg->key.data);
554 g_string_append_printf (lines, "\r\n");
557 for (i = 0; i < gst_sdp_message_attributes_len (msg); i++) {
558 const GstSDPAttribute *attr = gst_sdp_message_get_attribute (msg, i);
561 g_string_append_printf (lines, "a=%s", attr->key);
563 g_string_append_printf (lines, ":%s", attr->value);
564 g_string_append_printf (lines, "\r\n");
568 for (i = 0; i < gst_sdp_message_medias_len (msg); i++) {
569 const GstSDPMedia *media = gst_sdp_message_get_media (msg, i);
570 gchar *sdp_media_str;
572 sdp_media_str = gst_sdp_media_as_text (media);
573 g_string_append_printf (lines, "%s", sdp_media_str);
574 g_free (sdp_media_str);
577 return g_string_free (lines, FALSE);
583 return c >= '0' && c <= '9' ? c - '0'
584 : c >= 'A' && c <= 'F' ? c - 'A' + 10
585 : c >= 'a' && c <= 'f' ? c - 'a' + 10 : 0;
589 * gst_sdp_message_parse_uri:
590 * @uri: the start of the uri
591 * @msg: the result #GstSDPMessage
593 * Parse the null-terminated @uri and store the result in @msg.
595 * The uri should be of the form:
597 * scheme://[address[:ttl=ttl][:noa=noa]]/[sessionname]
598 * [#type=value *[&type=value]]
600 * where value is url encoded. This looslely resembles
601 * http://tools.ietf.org/html/draft-fujikawa-sdp-url-01
603 * Returns: #GST_SDP_OK on success.
606 gst_sdp_message_parse_uri (const gchar * uri, GstSDPMessage * msg)
610 const gchar *colon, *slash, *hash, *p;
613 g_return_val_if_fail (uri != NULL, GST_SDP_EINVAL);
614 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
616 colon = strstr (uri, "://");
620 /* FIXME connection info goes here */
622 slash = strstr (colon + 3, "/");
626 /* FIXME session name goes here */
628 hash = strstr (slash + 1, "#");
632 lines = g_string_new ("");
635 for (p = hash + 1; *p; p++) {
637 g_string_append_printf (lines, "\r\n");
639 g_string_append_c (lines, ' ');
640 else if (*p == '%') {
645 g_string_append_c (lines, (hex_to_int (a) << 4) | hex_to_int (b));
652 g_string_append_c (lines, *p);
655 message = g_string_free (lines, FALSE);
657 gst_sdp_message_parse_buffer ((const guint8 *) message, strlen (message),
666 return GST_SDP_EINVAL;
670 return GST_SDP_EINVAL;
674 return GST_SDP_EINVAL;
678 static const guchar acceptable[96] = {
679 /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */
680 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, /* 2X !"#$%&'()*+,-./ */
681 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3X 0123456789:;<=>? */
682 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 4X @ABCDEFGHIJKLMNO */
683 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, /* 5X PQRSTUVWXYZ[\]^_ */
684 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 6X `abcdefghijklmno */
685 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 /* 7X pqrstuvwxyz{|}~DEL */
688 static const gchar hex[16] = "0123456789ABCDEF";
690 #define ACCEPTABLE_CHAR(a) (((guchar)(a))>=32 && ((guchar)(a))<128 && acceptable[(((guchar)a))-32])
693 * gst_sdp_message_as_uri:
694 * @scheme: the uri scheme
695 * @msg: the #GstSDPMessage
697 * Creates a uri from @msg with the given @scheme. The uri has the format:
699 * \@scheme:///[#type=value *[&type=value]]
701 * Where each value is url encoded.
703 * Returns: a uri for @msg.
706 gst_sdp_message_as_uri (const gchar * scheme, const GstSDPMessage * msg)
708 gchar *serialized, *p;
713 g_return_val_if_fail (scheme != NULL, NULL);
714 g_return_val_if_fail (msg != NULL, NULL);
716 p = serialized = gst_sdp_message_as_text (msg);
718 lines = g_string_new ("");
719 g_string_append_printf (lines, "%s:///#", scheme);
723 for (p = serialized; *p; p++) {
725 g_string_append_printf (lines, "%c=", *p);
733 else if (*p == '\n') {
735 g_string_append_c (lines, '&');
737 } else if (*p == ' ')
738 g_string_append_c (lines, '+');
739 else if (ACCEPTABLE_CHAR (*p))
740 g_string_append_c (lines, *p);
743 g_string_append_printf (lines, "%%%c%c", hex[*p >> 4], hex[*p & 0xf]);
747 res = g_string_free (lines, FALSE);
754 * gst_sdp_message_set_version:
755 * @msg: a #GstSDPMessage
756 * @version: the version
758 * Set the version in @msg.
760 * Returns: a #GstSDPResult.
762 DEFINE_STRING_SETTER (version);
764 * gst_sdp_message_get_version:
765 * @msg: a #GstSDPMessage
767 * Get the version in @msg.
769 * Returns: a #GstSDPResult.
771 DEFINE_STRING_GETTER (version);
774 * gst_sdp_message_set_origin:
775 * @msg: a #GstSDPMessage
776 * @username: the user name
777 * @sess_id: a session id
778 * @sess_version: a session version
779 * @nettype: a network type
780 * @addrtype: an address type
783 * Configure the SDP origin in @msg with the given parameters.
785 * Returns: #GST_SDP_OK.
788 gst_sdp_message_set_origin (GstSDPMessage * msg, const gchar * username,
789 const gchar * sess_id, const gchar * sess_version, const gchar * nettype,
790 const gchar * addrtype, const gchar * addr)
792 REPLACE_STRING (msg->origin.username, username);
793 REPLACE_STRING (msg->origin.sess_id, sess_id);
794 REPLACE_STRING (msg->origin.sess_version, sess_version);
795 REPLACE_STRING (msg->origin.nettype, nettype);
796 REPLACE_STRING (msg->origin.addrtype, addrtype);
797 REPLACE_STRING (msg->origin.addr, addr);
803 * gst_sdp_message_get_origin:
804 * @msg: a #GstSDPMessage
806 * Get the origin of @msg.
808 * Returns: a #GstSDPOrigin. The result remains valid as long as @msg is valid.
811 gst_sdp_message_get_origin (const GstSDPMessage * msg)
817 * gst_sdp_message_set_session_name:
818 * @msg: a #GstSDPMessage
819 * @session_name: the session name
821 * Set the session name in @msg.
823 * Returns: a #GstSDPResult.
825 DEFINE_STRING_SETTER (session_name);
827 * gst_sdp_message_get_session_name:
828 * @msg: a #GstSDPMessage
830 * Get the session name in @msg.
832 * Returns: a #GstSDPResult.
834 DEFINE_STRING_GETTER (session_name);
836 * gst_sdp_message_set_information:
837 * @msg: a #GstSDPMessage
838 * @information: the information
840 * Set the information in @msg.
842 * Returns: a #GstSDPResult.
844 DEFINE_STRING_SETTER (information);
846 * gst_sdp_message_get_information:
847 * @msg: a #GstSDPMessage
849 * Get the information in @msg.
851 * Returns: a #GstSDPResult.
853 DEFINE_STRING_GETTER (information);
855 * gst_sdp_message_set_uri:
856 * @msg: a #GstSDPMessage
859 * Set the URI in @msg.
861 * Returns: a #GstSDPResult.
863 DEFINE_STRING_SETTER (uri);
865 * gst_sdp_message_get_uri:
866 * @msg: a #GstSDPMessage
868 * Get the URI in @msg.
870 * Returns: a #GstSDPResult.
872 DEFINE_STRING_GETTER (uri);
875 * gst_sdp_message_emails_len:
876 * @msg: a #GstSDPMessage
878 * Get the number of emails in @msg.
880 * Returns: the number of emails in @msg.
882 DEFINE_ARRAY_LEN (emails);
884 * gst_sdp_message_get_email:
885 * @msg: a #GstSDPMessage
886 * @idx: an email index
888 * Get the email with number @idx from @msg.
890 * Returns: the email at position @idx.
892 DEFINE_STR_ARRAY_GETTER (email, emails);
895 * gst_sdp_message_insert_email:
896 * @msg: a #GstSDPMessage
900 * Insert @email into the array of emails in @msg at index @idx.
901 * When -1 is given as @idx, the email is inserted at the end.
903 * Returns: a #GstSDPResult.
907 DEFINE_STR_ARRAY_INSERT (email, emails);
910 * gst_sdp_message_replace_email:
911 * @msg: a #GstSDPMessage
912 * @idx: an email index
915 * Replace the email in @msg at index @idx with @email.
917 * Returns: a #GstSDPResult.
921 DEFINE_STR_ARRAY_REPLACE (email, emails);
924 * gst_sdp_message_remove_email:
925 * @msg: a #GstSDPMessage
926 * @idx: an email index
928 * Remove the email in @msg at index @idx.
930 * Returns: a #GstSDPResult.
934 DEFINE_STR_ARRAY_REMOVE (email, emails);
937 * gst_sdp_message_add_email:
938 * @msg: a #GstSDPMessage
941 * Add @email to the list of emails in @msg.
943 * Returns: a #GstSDPResult.
945 DEFINE_STR_ARRAY_ADDER (email, emails);
948 * gst_sdp_message_phones_len:
949 * @msg: a #GstSDPMessage
951 * Get the number of phones in @msg.
953 * Returns: the number of phones in @msg.
955 DEFINE_ARRAY_LEN (phones);
957 * gst_sdp_message_get_phone:
958 * @msg: a #GstSDPMessage
959 * @idx: a phone index
961 * Get the phone with number @idx from @msg.
963 * Returns: the phone at position @idx.
965 DEFINE_STR_ARRAY_GETTER (phone, phones);
968 * gst_sdp_message_insert_phone:
969 * @msg: a #GstSDPMessage
970 * @idx: a phone index
973 * Insert @phone into the array of phone numbers in @msg at index @idx.
974 * When -1 is given as @idx, the phone is inserted at the end.
976 * Returns: a #GstSDPResult.
980 DEFINE_STR_ARRAY_INSERT (phone, phones);
983 * gst_sdp_message_replace_phone:
984 * @msg: a #GstSDPMessage
985 * @idx: a phone index
988 * Replace the phone number in @msg at index @idx with @phone.
990 * Returns: a #GstSDPResult.
994 DEFINE_STR_ARRAY_REPLACE (phone, phones);
997 * gst_sdp_message_remove_phone:
998 * @msg: a #GstSDPMessage
999 * @idx: a phone index
1001 * Remove the phone number in @msg at index @idx.
1003 * Returns: a #GstSDPResult.
1007 DEFINE_STR_ARRAY_REMOVE (phone, phones);
1010 * gst_sdp_message_add_phone:
1011 * @msg: a #GstSDPMessage
1014 * Add @phone to the list of phones in @msg.
1016 * Returns: a #GstSDPResult.
1018 DEFINE_STR_ARRAY_ADDER (phone, phones);
1022 * gst_sdp_message_set_connection:
1023 * @msg: a #GstSDPMessage
1024 * @nettype: the type of network. "IN" is defined to have the meaning
1026 * @addrtype: the type of address.
1027 * @address: the address
1028 * @ttl: the time to live of the address
1029 * @addr_number: the number of layers
1031 * Configure the SDP connection in @msg with the given parameters.
1033 * Returns: a #GstSDPResult.
1036 gst_sdp_message_set_connection (GstSDPMessage * msg, const gchar * nettype,
1037 const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
1039 REPLACE_STRING (msg->connection.nettype, nettype);
1040 REPLACE_STRING (msg->connection.addrtype, addrtype);
1041 REPLACE_STRING (msg->connection.address, address);
1042 msg->connection.ttl = ttl;
1043 msg->connection.addr_number = addr_number;
1049 * gst_sdp_message_get_connection:
1050 * @msg: a #GstSDPMessage
1052 * Get the connection of @msg.
1054 * Returns: a #GstSDPConnection. The result remains valid as long as @msg is valid.
1056 const GstSDPConnection *
1057 gst_sdp_message_get_connection (const GstSDPMessage * msg)
1059 return &msg->connection;
1063 * gst_sdp_bandwidth_set:
1064 * @bw: a #GstSDPBandwidth
1065 * @bwtype: the bandwidth modifier type
1066 * @bandwidth: the bandwidth in kilobits per second
1068 * Set bandwidth information in @bw.
1070 * Returns: a #GstSDPResult.
1075 gst_sdp_bandwidth_set (GstSDPBandwidth * bw, const gchar * bwtype,
1078 bw->bwtype = g_strdup (bwtype);
1079 bw->bandwidth = bandwidth;
1084 * gst_sdp_bandwidth_clear:
1085 * @bw: a #GstSDPBandwidth
1087 * Reset the bandwidth information in @bw.
1089 * Returns: a #GstSDPResult.
1094 gst_sdp_bandwidth_clear (GstSDPBandwidth * bw)
1096 FREE_STRING (bw->bwtype);
1102 * gst_sdp_message_bandwidths_len:
1103 * @msg: a #GstSDPMessage
1105 * Get the number of bandwidth information in @msg.
1107 * Returns: the number of bandwidth information in @msg.
1109 DEFINE_ARRAY_LEN (bandwidths);
1111 * gst_sdp_message_get_bandwidth:
1112 * @msg: a #GstSDPMessage
1113 * @idx: the bandwidth index
1115 * Get the bandwidth at index @idx from @msg.
1117 * Returns: a #GstSDPBandwidth.
1119 DEFINE_ARRAY_GETTER (bandwidth, bandwidths, GstSDPBandwidth);
1121 #define DUP_BANDWIDTH(v, val) memcpy (v, val, sizeof (GstSDPBandwidth))
1122 #define FREE_BANDWIDTH(v) gst_sdp_bandwidth_clear(v)
1125 * gst_sdp_message_insert_bandwidth:
1126 * @msg: a #GstSDPMessage
1128 * @bw: the bandwidth
1130 * Insert bandwidth parameters into the array of bandwidths in @msg
1132 * When -1 is given as @idx, the bandwidth is inserted at the end.
1134 * Returns: a #GstSDPResult.
1138 DEFINE_ARRAY_INSERT (bandwidth, bandwidths, GstSDPBandwidth *, DUP_BANDWIDTH,
1142 * gst_sdp_message_replace_bandwidth:
1143 * @msg: a #GstSDPMessage
1144 * @idx: the bandwidth index
1145 * @bw: the bandwidth
1147 * Replace the bandwidth information in @msg at index @idx with @bw.
1149 * Returns: a #GstSDPResult.
1153 DEFINE_ARRAY_REPLACE (bandwidth, bandwidths, GstSDPBandwidth *, FREE_BANDWIDTH,
1154 DUP_BANDWIDTH, GstSDPBandwidth);
1157 * gst_sdp_message_remove_bandwidth:
1158 * @msg: a #GstSDPMessage
1159 * @idx: the bandwidth index
1161 * Remove the bandwidth information in @msg at index @idx.
1163 * Returns: a #GstSDPResult.
1167 DEFINE_ARRAY_REMOVE (bandwidth, bandwidths, GstSDPBandwidth, FREE_BANDWIDTH);
1170 * gst_sdp_message_add_bandwidth:
1171 * @msg: a #GstSDPMessage
1172 * @bwtype: the bandwidth modifier type
1173 * @bandwidth: the bandwidth in kilobits per second
1175 * Add the specified bandwidth information to @msg.
1177 * Returns: a #GstSDPResult.
1180 gst_sdp_message_add_bandwidth (GstSDPMessage * msg, const gchar * bwtype,
1185 gst_sdp_bandwidth_set (&bw, bwtype, bandwidth);
1186 return gst_sdp_message_insert_bandwidth (msg, -1, &bw);
1192 * @start: the start time
1193 * @stop: the stop time
1194 * @repeat: (array zero-terminated=1): the repeat times
1196 * Set time information @start, @stop and @repeat in @t.
1198 * Returns: a #GstSDPResult.
1203 gst_sdp_time_set (GstSDPTime * t, const gchar * start,
1204 const gchar * stop, const gchar ** repeat)
1206 t->start = g_strdup (start);
1207 t->stop = g_strdup (stop);
1209 t->repeat = g_array_new (FALSE, TRUE, sizeof (gchar *));
1210 for (; *repeat; repeat++) {
1211 gchar *r = g_strdup (*repeat);
1213 g_array_append_val (t->repeat, r);
1222 * gst_sdp_time_clear:
1225 * Reset the time information in @t.
1227 * Returns: a #GstSDPResult.
1232 gst_sdp_time_clear (GstSDPTime * t)
1234 FREE_STRING (t->start);
1235 FREE_STRING (t->stop);
1236 INIT_STR_ARRAY (t->repeat);
1237 FREE_ARRAY (t->repeat);
1243 * gst_sdp_message_times_len:
1244 * @msg: a #GstSDPMessage
1246 * Get the number of time information entries in @msg.
1248 * Returns: the number of time information entries in @msg.
1250 DEFINE_ARRAY_LEN (times);
1253 * gst_sdp_message_get_time:
1254 * @msg: a #GstSDPMessage
1255 * @idx: the time index
1257 * Get time information with index @idx from @msg.
1259 * Returns: a #GstSDPTime.
1261 DEFINE_ARRAY_GETTER (time, times, GstSDPTime);
1263 #define DUP_TIME(v, val) memcpy (v, val, sizeof (GstSDPTime))
1264 #define FREE_TIME(v) gst_sdp_time_clear(v)
1267 * gst_sdp_message_insert_time:
1268 * @msg: a #GstSDPMessage
1272 * Insert time parameters into the array of times in @msg
1274 * When -1 is given as @idx, the times are inserted at the end.
1276 * Returns: a #GstSDPResult.
1280 DEFINE_ARRAY_INSERT (time, times, GstSDPTime *, DUP_TIME, GstSDPTime);
1283 * gst_sdp_message_replace_time:
1284 * @msg: a #GstSDPMessage
1288 * Replace the time information in @msg at index @idx with @t.
1290 * Returns: a #GstSDPResult.
1294 DEFINE_ARRAY_REPLACE (time, times, GstSDPTime *, FREE_TIME,
1295 DUP_TIME, GstSDPTime);
1298 * gst_sdp_message_remove_time:
1299 * @msg: a #GstSDPMessage
1302 * Remove the time information in @msg at index @idx.
1304 * Returns: a #GstSDPResult.
1308 DEFINE_ARRAY_REMOVE (time, times, GstSDPTime, FREE_TIME);
1311 * gst_sdp_message_add_time:
1312 * @msg: a #GstSDPMessage
1313 * @start: the start time
1314 * @stop: the stop time
1315 * @repeat: (array zero-terminated=1): the repeat times
1317 * Add time information @start and @stop to @msg.
1319 * Returns: a #GstSDPResult.
1322 gst_sdp_message_add_time (GstSDPMessage * msg, const gchar * start,
1323 const gchar * stop, const gchar ** repeat)
1327 gst_sdp_time_set (×, start, stop, repeat);
1328 g_array_append_val (msg->times, times);
1335 * @zone: a #GstSDPZone
1336 * @adj_time: the NTP time that a time zone adjustment happens
1337 * @typed_time: the offset from the time when the session was first scheduled
1339 * Set zone information in @zone.
1341 * Returns: a #GstSDPResult.
1346 gst_sdp_zone_set (GstSDPZone * zone, const gchar * adj_time,
1347 const gchar * typed_time)
1349 zone->time = g_strdup (adj_time);
1350 zone->typed_time = g_strdup (typed_time);
1355 * gst_sdp_zone_clear:
1356 * @zone: a #GstSDPZone
1358 * Reset the zone information in @zone.
1360 * Returns: a #GstSDPResult.
1365 gst_sdp_zone_clear (GstSDPZone * zone)
1367 FREE_STRING (zone->time);
1368 FREE_STRING (zone->typed_time);
1373 * gst_sdp_message_zones_len:
1374 * @msg: a #GstSDPMessage
1376 * Get the number of time zone information entries in @msg.
1378 * Returns: the number of time zone information entries in @msg.
1380 DEFINE_ARRAY_LEN (zones);
1382 * gst_sdp_message_get_zone:
1383 * @msg: a #GstSDPMessage
1384 * @idx: the zone index
1386 * Get time zone information with index @idx from @msg.
1388 * Returns: a #GstSDPZone.
1390 DEFINE_ARRAY_GETTER (zone, zones, GstSDPZone);
1392 #define DUP_ZONE(v, val) memcpy (v, val, sizeof (GstSDPZone))
1393 #define FREE_ZONE(v) gst_sdp_zone_clear(v)
1396 * gst_sdp_message_insert_zone:
1397 * @msg: a #GstSDPMessage
1399 * @zone a #GstSDPZone
1401 * Insert zone parameters into the array of zones in @msg
1403 * When -1 is given as @idx, the zone is inserted at the end.
1405 * Returns: a #GstSDPResult.
1409 DEFINE_ARRAY_INSERT (zone, zones, GstSDPZone *, DUP_ZONE, GstSDPZone);
1412 * gst_sdp_message_replace_zone:
1413 * @msg: a #GstSDPMessage
1415 * @zone: a #GstSDPZone
1417 * Replace the zone information in @msg at index @idx with @zone.
1419 * Returns: a #GstSDPResult.
1423 DEFINE_ARRAY_REPLACE (zone, zones, GstSDPZone *, FREE_ZONE,
1424 DUP_ZONE, GstSDPZone);
1427 * gst_sdp_message_remove_zone:
1428 * @msg: a #GstSDPMessage
1431 * Remove the zone information in @msg at index @idx.
1433 * Returns: a #GstSDPResult.
1437 DEFINE_ARRAY_REMOVE (zone, zones, GstSDPZone, FREE_ZONE);
1440 * gst_sdp_message_add_zone:
1441 * @msg: a #GstSDPMessage
1442 * @adj_time: the NTP time that a time zone adjustment happens
1443 * @typed_time: the offset from the time when the session was first scheduled
1445 * Add time zone information to @msg.
1447 * Returns: a #GstSDPResult.
1450 gst_sdp_message_add_zone (GstSDPMessage * msg, const gchar * adj_time,
1451 const gchar * typed_time)
1455 gst_sdp_zone_set (&zone, adj_time, typed_time);
1456 g_array_append_val (msg->zones, zone);
1462 * gst_sdp_message_set_key:
1463 * @msg: a #GstSDPMessage
1464 * @type: the encryption type
1465 * @data: the encryption data
1467 * Adds the encryption information to @msg.
1469 * Returns: a #GstSDPResult.
1472 gst_sdp_message_set_key (GstSDPMessage * msg, const gchar * type,
1475 REPLACE_STRING (msg->key.type, type);
1476 REPLACE_STRING (msg->key.data, data);
1482 * gst_sdp_message_get_key:
1483 * @msg: a #GstSDPMessage
1485 * Get the encryption information from @msg.
1487 * Returns: a #GstSDPKey.
1490 gst_sdp_message_get_key (const GstSDPMessage * msg)
1496 * gst_sdp_attribute_set:
1497 * @attr: a #GstSDPAttribute
1501 * Set the attribute with @key and @value.
1503 * Returns: @GST_SDP_OK.
1508 gst_sdp_attribute_set (GstSDPAttribute * attr, const gchar * key,
1509 const gchar * value)
1511 attr->key = g_strdup (key);
1512 attr->value = g_strdup (value);
1517 * gst_sdp_attribute_clear:
1518 * @attr: a #GstSDPAttribute
1520 * Clear the attribute.
1522 * Returns: @GST_SDP_OK.
1527 gst_sdp_attribute_clear (GstSDPAttribute * attr)
1529 FREE_STRING (attr->key);
1530 FREE_STRING (attr->value);
1535 * gst_sdp_message_attributes_len:
1536 * @msg: a #GstSDPMessage
1538 * Get the number of attributes in @msg.
1540 * Returns: the number of attributes in @msg.
1542 DEFINE_ARRAY_LEN (attributes);
1545 * gst_sdp_message_get_attribute:
1546 * @msg: a #GstSDPMessage
1549 * Get the attribute at position @idx in @msg.
1551 * Returns: the #GstSDPAttribute at position @idx.
1553 DEFINE_ARRAY_GETTER (attribute, attributes, GstSDPAttribute);
1556 * gst_sdp_message_get_attribute_val_n:
1557 * @msg: a #GstSDPMessage
1561 * Get the @nth attribute with key @key in @msg.
1563 * Returns: the attribute value of the @nth attribute with @key.
1566 gst_sdp_message_get_attribute_val_n (const GstSDPMessage * msg,
1567 const gchar * key, guint nth)
1571 for (i = 0; i < msg->attributes->len; i++) {
1572 GstSDPAttribute *attr;
1574 attr = &g_array_index (msg->attributes, GstSDPAttribute, i);
1575 if (!strcmp (attr->key, key)) {
1586 * gst_sdp_message_get_attribute_val:
1587 * @msg: a #GstSDPMessage
1590 * Get the first attribute with key @key in @msg.
1592 * Returns: the attribute value of the first attribute with @key.
1595 gst_sdp_message_get_attribute_val (const GstSDPMessage * msg, const gchar * key)
1597 return gst_sdp_message_get_attribute_val_n (msg, key, 0);
1600 #define DUP_ATTRIBUTE(v, val) memcpy (v, val, sizeof (GstSDPAttribute))
1601 #define FREE_ATTRIBUTE(v) gst_sdp_attribute_clear(v)
1604 * gst_sdp_message_insert_attribute:
1605 * @msg: a #GstSDPMessage
1607 * @attr: a #GstSDPAttribute
1609 * Insert attribute into the array of attributes in @msg
1611 * When -1 is given as @idx, the attribute is inserted at the end.
1613 * Returns: a #GstSDPResult.
1617 DEFINE_ARRAY_INSERT (attribute, attributes, GstSDPAttribute *, DUP_ATTRIBUTE,
1621 * gst_sdp_message_replace_attribute:
1622 * @msg: a #GstSDPMessage
1624 * @attr: a #GstSDPAttribute
1626 * Replace the attribute in @msg at index @idx with @attr.
1628 * Returns: a #GstSDPResult.
1632 DEFINE_ARRAY_REPLACE (attribute, attributes, GstSDPAttribute *, FREE_ATTRIBUTE,
1633 DUP_ATTRIBUTE, GstSDPAttribute);
1636 * gst_sdp_message_remove_attribute:
1637 * @msg: a #GstSDPMessage
1640 * Remove the attribute in @msg at index @idx.
1642 * Returns: a #GstSDPResult.
1646 DEFINE_ARRAY_REMOVE (attribute, attributes, GstSDPAttribute, FREE_ATTRIBUTE);
1649 * gst_sdp_message_add_attribute:
1650 * @msg: a #GstSDPMessage
1654 * Add the attribute with @key and @value to @msg.
1656 * Returns: @GST_SDP_OK.
1659 gst_sdp_message_add_attribute (GstSDPMessage * msg, const gchar * key,
1660 const gchar * value)
1662 GstSDPAttribute attr;
1664 gst_sdp_attribute_set (&attr, key, value);
1665 g_array_append_val (msg->attributes, attr);
1671 * gst_sdp_message_medias_len:
1672 * @msg: a #GstSDPMessage
1674 * Get the number of media descriptions in @msg.
1676 * Returns: the number of media descriptions in @msg.
1678 DEFINE_ARRAY_LEN (medias);
1680 * gst_sdp_message_get_media:
1681 * @msg: a #GstSDPMessage
1684 * Get the media description at index @idx in @msg.
1686 * Returns: a #GstSDPMedia.
1688 DEFINE_ARRAY_GETTER (media, medias, GstSDPMedia);
1691 * gst_sdp_message_add_media:
1692 * @msg: a #GstSDPMessage
1693 * @media: a #GstSDPMedia to add
1695 * Adds @media to the array of medias in @msg. This function takes ownership of
1696 * the contents of @media so that @media will have to be reinitialized with
1697 * gst_sdp_media_init() before it can be used again.
1699 * Returns: a #GstSDPResult.
1702 gst_sdp_message_add_media (GstSDPMessage * msg, GstSDPMedia * media)
1705 GstSDPMedia *nmedia;
1707 len = msg->medias->len;
1708 g_array_set_size (msg->medias, len + 1);
1709 nmedia = &g_array_index (msg->medias, GstSDPMedia, len);
1711 memcpy (nmedia, media, sizeof (GstSDPMedia));
1712 memset (media, 0, sizeof (GstSDPMedia));
1720 * gst_sdp_media_new:
1721 * @media: (out) (transfer full): pointer to new #GstSDPMedia
1723 * Allocate a new GstSDPMedia and store the result in @media.
1725 * Returns: a #GstSDPResult.
1728 gst_sdp_media_new (GstSDPMedia ** media)
1730 GstSDPMedia *newmedia;
1732 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1734 newmedia = g_new0 (GstSDPMedia, 1);
1738 return gst_sdp_media_init (newmedia);
1742 * gst_sdp_media_init:
1743 * @media: a #GstSDPMedia
1745 * Initialize @media so that its contents are as if it was freshly allocated
1746 * with gst_sdp_media_new(). This function is mostly used to initialize a media
1747 * allocated on the stack. gst_sdp_media_uninit() undoes this operation.
1749 * When this function is invoked on newly allocated data (with malloc or on the
1750 * stack), its contents should be set to 0 before calling this function.
1752 * Returns: a #GstSDPResult.
1755 gst_sdp_media_init (GstSDPMedia * media)
1757 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1759 FREE_STRING (media->media);
1761 media->num_ports = 0;
1762 FREE_STRING (media->proto);
1763 INIT_STR_ARRAY (media->fmts);
1764 FREE_STRING (media->information);
1765 INIT_ARRAY (media->connections, GstSDPConnection, gst_sdp_connection_clear);
1766 INIT_ARRAY (media->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_clear);
1767 gst_sdp_key_init (&media->key);
1768 INIT_ARRAY (media->attributes, GstSDPAttribute, gst_sdp_attribute_clear);
1774 * gst_sdp_media_uninit:
1775 * @media: a #GstSDPMedia
1777 * Free all resources allocated in @media. @media should not be used anymore after
1778 * this function. This function should be used when @media was allocated on the
1779 * stack and initialized with gst_sdp_media_init().
1781 * Returns: a #GstSDPResult.
1784 gst_sdp_media_uninit (GstSDPMedia * media)
1786 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1788 gst_sdp_media_init (media);
1789 FREE_ARRAY (media->fmts);
1790 FREE_ARRAY (media->connections);
1791 FREE_ARRAY (media->bandwidths);
1792 FREE_ARRAY (media->attributes);
1798 * gst_sdp_media_free:
1799 * @media: a #GstSDPMedia
1801 * Free all resources allocated by @media. @media should not be used anymore after
1802 * this function. This function should be used when @media was dynamically
1803 * allocated with gst_sdp_media_new().
1805 * Returns: a #GstSDPResult.
1808 gst_sdp_media_free (GstSDPMedia * media)
1810 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1812 gst_sdp_media_uninit (media);
1819 * gst_sdp_media_copy:
1820 * @media: a #GstSDPMedia
1821 * @copy: (out) (transfer full): pointer to new #GstSDPMedia
1823 * Allocate a new copy of @media and store the result in @copy. The value in
1824 * @copy should be release with gst_sdp_media_free function.
1826 * Returns: a #GstSDPResult
1831 gst_sdp_media_copy (const GstSDPMedia * media, GstSDPMedia ** copy)
1838 return GST_SDP_EINVAL;
1840 ret = gst_sdp_media_new (copy);
1841 if (ret != GST_SDP_OK)
1846 REPLACE_STRING (cp->media, media->media);
1847 cp->port = media->port;
1848 cp->num_ports = media->num_ports;
1849 REPLACE_STRING (cp->proto, media->proto);
1851 len = gst_sdp_media_formats_len (media);
1852 for (i = 0; i < len; i++) {
1853 gst_sdp_media_add_format (cp, gst_sdp_media_get_format (media, i));
1856 REPLACE_STRING (cp->information, media->information);
1858 len = gst_sdp_media_connections_len (media);
1859 for (i = 0; i < len; i++) {
1860 const GstSDPConnection *connection =
1861 gst_sdp_media_get_connection (media, i);
1862 gst_sdp_media_add_connection (cp, connection->nettype, connection->addrtype,
1863 connection->address, connection->ttl, connection->addr_number);
1866 len = gst_sdp_media_bandwidths_len (media);
1867 for (i = 0; i < len; i++) {
1868 const GstSDPBandwidth *bw = gst_sdp_media_get_bandwidth (media, i);
1869 gst_sdp_media_add_bandwidth (cp, bw->bwtype, bw->bandwidth);
1872 gst_sdp_media_set_key (cp, media->key.type, media->key.data);
1874 len = gst_sdp_media_attributes_len (media);
1875 for (i = 0; i < len; i++) {
1876 const GstSDPAttribute *att = gst_sdp_media_get_attribute (media, i);
1877 gst_sdp_media_add_attribute (cp, att->key, att->value);
1884 * gst_sdp_media_as_text:
1885 * @media: a #GstSDPMedia
1887 * Convert the contents of @media to a text string.
1889 * Returns: A dynamically allocated string representing the media.
1892 gst_sdp_media_as_text (const GstSDPMedia * media)
1897 g_return_val_if_fail (media != NULL, NULL);
1899 lines = g_string_new ("");
1902 g_string_append_printf (lines, "m=%s", media->media);
1904 g_string_append_printf (lines, " %u", media->port);
1906 if (media->num_ports > 1)
1907 g_string_append_printf (lines, "/%u", media->num_ports);
1909 g_string_append_printf (lines, " %s", media->proto);
1911 for (i = 0; i < gst_sdp_media_formats_len (media); i++)
1912 g_string_append_printf (lines, " %s", gst_sdp_media_get_format (media, i));
1913 g_string_append_printf (lines, "\r\n");
1915 if (media->information)
1916 g_string_append_printf (lines, "i=%s", media->information);
1918 for (i = 0; i < gst_sdp_media_connections_len (media); i++) {
1919 const GstSDPConnection *conn = gst_sdp_media_get_connection (media, i);
1921 if (conn->nettype && conn->addrtype && conn->address) {
1922 g_string_append_printf (lines, "c=%s %s %s", conn->nettype,
1923 conn->addrtype, conn->address);
1924 if (gst_sdp_address_is_multicast (conn->nettype, conn->addrtype,
1926 /* only add TTL for IP4 multicast */
1927 if (strcmp (conn->addrtype, "IP4") == 0)
1928 g_string_append_printf (lines, "/%u", conn->ttl);
1929 if (conn->addr_number > 1)
1930 g_string_append_printf (lines, "/%u", conn->addr_number);
1932 g_string_append_printf (lines, "\r\n");
1936 for (i = 0; i < gst_sdp_media_bandwidths_len (media); i++) {
1937 const GstSDPBandwidth *bandwidth = gst_sdp_media_get_bandwidth (media, i);
1939 g_string_append_printf (lines, "b=%s:%u\r\n", bandwidth->bwtype,
1940 bandwidth->bandwidth);
1943 if (media->key.type) {
1944 g_string_append_printf (lines, "k=%s", media->key.type);
1945 if (media->key.data)
1946 g_string_append_printf (lines, ":%s", media->key.data);
1947 g_string_append_printf (lines, "\r\n");
1950 for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
1951 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
1954 g_string_append_printf (lines, "a=%s", attr->key);
1955 if (attr->value && attr->value[0] != '\0')
1956 g_string_append_printf (lines, ":%s", attr->value);
1957 g_string_append_printf (lines, "\r\n");
1961 return g_string_free (lines, FALSE);
1965 * gst_sdp_media_get_media:
1966 * @media: a #GstSDPMedia
1968 * Get the media description of @media.
1970 * Returns: the media description.
1973 gst_sdp_media_get_media (const GstSDPMedia * media)
1975 return media->media;
1979 * gst_sdp_media_set_media:
1980 * @media: a #GstSDPMedia
1981 * @med: the media description
1983 * Set the media description of @media to @med.
1985 * Returns: #GST_SDP_OK.
1988 gst_sdp_media_set_media (GstSDPMedia * media, const gchar * med)
1990 g_free (media->media);
1991 media->media = g_strdup (med);
1997 * gst_sdp_media_get_port:
1998 * @media: a #GstSDPMedia
2000 * Get the port number for @media.
2002 * Returns: the port number of @media.
2005 gst_sdp_media_get_port (const GstSDPMedia * media)
2011 * gst_sdp_media_get_num_ports:
2012 * @media: a #GstSDPMedia
2014 * Get the number of ports for @media.
2016 * Returns: the number of ports for @media.
2019 gst_sdp_media_get_num_ports (const GstSDPMedia * media)
2021 return media->num_ports;
2025 * gst_sdp_media_set_port_info:
2026 * @media: a #GstSDPMedia
2027 * @port: the port number
2028 * @num_ports: the number of ports
2030 * Set the port information in @media.
2032 * Returns: #GST_SDP_OK.
2035 gst_sdp_media_set_port_info (GstSDPMedia * media, guint port, guint num_ports)
2038 media->num_ports = num_ports;
2044 * gst_sdp_media_get_proto:
2045 * @media: a #GstSDPMedia
2047 * Get the transport protocol of @media
2049 * Returns: the transport protocol of @media.
2052 gst_sdp_media_get_proto (const GstSDPMedia * media)
2054 return media->proto;
2058 * gst_sdp_media_set_proto:
2059 * @media: a #GstSDPMedia
2060 * @proto: the media transport protocol
2062 * Set the media transport protocol of @media to @proto.
2064 * Returns: #GST_SDP_OK.
2067 gst_sdp_media_set_proto (GstSDPMedia * media, const gchar * proto)
2069 g_free (media->proto);
2070 media->proto = g_strdup (proto);
2076 * gst_sdp_media_formats_len:
2077 * @media: a #GstSDPMedia
2079 * Get the number of formats in @media.
2081 * Returns: the number of formats in @media.
2084 gst_sdp_media_formats_len (const GstSDPMedia * media)
2086 return media->fmts->len;
2090 * gst_sdp_media_get_format:
2091 * @media: a #GstSDPMedia
2094 * Get the format information at position @idx in @media.
2096 * Returns: the format at position @idx.
2099 gst_sdp_media_get_format (const GstSDPMedia * media, guint idx)
2101 if (idx >= media->fmts->len)
2103 return g_array_index (media->fmts, gchar *, idx);
2107 * gst_sdp_media_insert_format:
2108 * @media: a #GstSDPMedia
2110 * @format: the format
2112 * Insert the format information to @media at @idx. When @idx is -1,
2113 * the format is appended.
2115 * Returns: #GST_SDP_OK.
2120 gst_sdp_media_insert_format (GstSDPMedia * media, gint idx,
2121 const gchar * format)
2125 fmt = g_strdup (format);
2128 g_array_append_val (media->fmts, fmt);
2130 g_array_insert_val (media->fmts, idx, fmt);
2136 * gst_sdp_media_replace_format:
2137 * @media: a #GstSDPMedia
2139 * @format: the format
2141 * Replace the format information in @media at @idx with @format.
2143 * Returns: #GST_SDP_OK.
2148 gst_sdp_media_replace_format (GstSDPMedia * media, guint idx,
2149 const gchar * format)
2153 old = &g_array_index (media->fmts, gchar *, idx);
2155 *old = g_strdup (format);
2161 * gst_sdp_media_remove_format:
2162 * @media: a #GstSDPMedia
2165 * Remove the format information in @media at @idx.
2167 * Returns: #GST_SDP_OK.
2172 gst_sdp_media_remove_format (GstSDPMedia * media, guint idx)
2176 old = &g_array_index (media->fmts, gchar *, idx);
2178 g_array_remove_index (media->fmts, idx);
2184 * gst_sdp_media_add_format:
2185 * @media: a #GstSDPMedia
2186 * @format: the format
2188 * Add the format information to @media.
2190 * Returns: #GST_SDP_OK.
2193 gst_sdp_media_add_format (GstSDPMedia * media, const gchar * format)
2197 fmt = g_strdup (format);
2199 g_array_append_val (media->fmts, fmt);
2205 * gst_sdp_media_get_information:
2206 * @media: a #GstSDPMedia
2208 * Get the information of @media
2210 * Returns: the information of @media.
2213 gst_sdp_media_get_information (const GstSDPMedia * media)
2215 return media->information;
2219 * gst_sdp_media_set_information:
2220 * @media: a #GstSDPMedia
2221 * @information: the media information
2223 * Set the media information of @media to @information.
2225 * Returns: #GST_SDP_OK.
2228 gst_sdp_media_set_information (GstSDPMedia * media, const gchar * information)
2230 g_free (media->information);
2231 media->information = g_strdup (information);
2237 * gst_sdp_connection_set:
2238 * @conn: a #GstSDPConnection
2239 * @nettype: the type of network. "IN" is defined to have the meaning
2241 * @addrtype: the type of address.
2242 * @address: the address
2243 * @ttl: the time to live of the address
2244 * @addr_number: the number of layers
2246 * Set the connection with the given parameters.
2248 * Returns: @GST_SDP_OK.
2253 gst_sdp_connection_set (GstSDPConnection * conn, const gchar * nettype,
2254 const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
2256 conn->nettype = g_strdup (nettype);
2257 conn->addrtype = g_strdup (addrtype);
2258 conn->address = g_strdup (address);
2260 conn->addr_number = addr_number;
2265 * gst_sdp_connection_clear:
2266 * @conn: a #GstSDPConnection
2268 * Clear the connection.
2270 * Returns: @GST_SDP_OK.
2275 gst_sdp_connection_clear (GstSDPConnection * conn)
2277 FREE_STRING (conn->nettype);
2278 FREE_STRING (conn->addrtype);
2279 FREE_STRING (conn->address);
2281 conn->addr_number = 0;
2287 * gst_sdp_media_connections_len:
2288 * @media: a #GstSDPMedia
2290 * Get the number of connection fields in @media.
2292 * Returns: the number of connections in @media.
2295 gst_sdp_media_connections_len (const GstSDPMedia * media)
2297 return media->connections->len;
2301 * gst_sdp_media_get_connection:
2302 * @media: a #GstSDPMedia
2305 * Get the connection at position @idx in @media.
2307 * Returns: the #GstSDPConnection at position @idx.
2309 const GstSDPConnection *
2310 gst_sdp_media_get_connection (const GstSDPMedia * media, guint idx)
2312 return &g_array_index (media->connections, GstSDPConnection, idx);
2316 * gst_sdp_media_insert_connection:
2317 * @media: a #GstSDPMedia
2319 * @conn: a #GstSDPConnection
2321 * Insert the connection information to @media at @idx. When @idx is -1,
2322 * the connection is appended.
2324 * Returns: #GST_SDP_OK.
2329 gst_sdp_media_insert_connection (GstSDPMedia * media, gint idx,
2330 GstSDPConnection * conn)
2333 g_array_append_val (media->connections, *conn);
2335 g_array_insert_val (media->connections, idx, *conn);
2341 * gst_sdp_media_replace_connection:
2342 * @media: a #GstSDPMedia
2344 * @conn: a #GstSDPConnection
2346 * Replace the connection information in @media at @idx with @conn.
2348 * Returns: #GST_SDP_OK.
2353 gst_sdp_media_replace_connection (GstSDPMedia * media, guint idx,
2354 GstSDPConnection * conn)
2356 GstSDPConnection *old;
2358 old = &g_array_index (media->connections, GstSDPConnection, idx);
2359 gst_sdp_connection_clear (old);
2366 * gst_sdp_media_remove_connection:
2367 * @media: a #GstSDPMedia
2370 * Remove the connection information in @media at @idx.
2372 * Returns: #GST_SDP_OK.
2377 gst_sdp_media_remove_connection (GstSDPMedia * media, guint idx)
2379 GstSDPConnection *old;
2381 old = &g_array_index (media->connections, GstSDPConnection, idx);
2382 gst_sdp_connection_clear (old);
2383 g_array_remove_index (media->connections, idx);
2389 * gst_sdp_media_add_connection:
2390 * @media: a #GstSDPMedia
2391 * @nettype: the type of network. "IN" is defined to have the meaning
2393 * @addrtype: the type of address.
2394 * @address: the address
2395 * @ttl: the time to live of the address
2396 * @addr_number: the number of layers
2398 * Add the given connection parameters to @media.
2400 * Returns: a #GstSDPResult.
2403 gst_sdp_media_add_connection (GstSDPMedia * media, const gchar * nettype,
2404 const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
2406 GstSDPConnection conn;
2408 gst_sdp_connection_set (&conn, nettype, addrtype, address, ttl, addr_number);
2409 g_array_append_val (media->connections, conn);
2415 * gst_sdp_media_bandwidths_len:
2416 * @media: a #GstSDPMedia
2418 * Get the number of bandwidth fields in @media.
2420 * Returns: the number of bandwidths in @media.
2423 gst_sdp_media_bandwidths_len (const GstSDPMedia * media)
2425 return media->bandwidths->len;
2429 * gst_sdp_media_get_bandwidth:
2430 * @media: a #GstSDPMedia
2433 * Get the bandwidth at position @idx in @media.
2435 * Returns: the #GstSDPBandwidth at position @idx.
2437 const GstSDPBandwidth *
2438 gst_sdp_media_get_bandwidth (const GstSDPMedia * media, guint idx)
2440 return &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
2444 * gst_sdp_media_insert_bandwidth:
2445 * @media: a #GstSDPMedia
2447 * @bw: a #GstSDPBandwidth
2449 * Insert the bandwidth information to @media at @idx. When @idx is -1,
2450 * the bandwidth is appended.
2452 * Returns: #GST_SDP_OK.
2457 gst_sdp_media_insert_bandwidth (GstSDPMedia * media, gint idx,
2458 GstSDPBandwidth * bw)
2461 g_array_append_val (media->bandwidths, *bw);
2463 g_array_insert_val (media->bandwidths, idx, *bw);
2469 * gst_sdp_media_replace_bandwidth:
2470 * @media: a #GstSDPMedia
2472 * @bw: a #GstSDPBandwidth
2474 * Replace the bandwidth information in @media at @idx with @bw.
2476 * Returns: #GST_SDP_OK.
2481 gst_sdp_media_replace_bandwidth (GstSDPMedia * media, guint idx,
2482 GstSDPBandwidth * bw)
2484 GstSDPBandwidth *old;
2486 old = &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
2487 gst_sdp_bandwidth_clear (old);
2494 * gst_sdp_media_remove_bandwidth:
2495 * @media: a #GstSDPMedia
2498 * Remove the bandwidth information in @media at @idx.
2500 * Returns: #GST_SDP_OK.
2505 gst_sdp_media_remove_bandwidth (GstSDPMedia * media, guint idx)
2507 GstSDPBandwidth *old;
2509 old = &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
2510 gst_sdp_bandwidth_clear (old);
2511 g_array_remove_index (media->bandwidths, idx);
2517 * gst_sdp_media_add_bandwidth:
2518 * @media: a #GstSDPMedia
2519 * @bwtype: the bandwidth modifier type
2520 * @bandwidth: the bandwidth in kilobits per second
2522 * Add the bandwidth information with @bwtype and @bandwidth to @media.
2524 * Returns: #GST_SDP_OK.
2527 gst_sdp_media_add_bandwidth (GstSDPMedia * media, const gchar * bwtype,
2532 gst_sdp_bandwidth_set (&bw, bwtype, bandwidth);
2533 g_array_append_val (media->bandwidths, bw);
2539 * gst_sdp_media_set_key:
2540 * @media: a #GstSDPMedia
2541 * @type: the encryption type
2542 * @data: the encryption data
2544 * Adds the encryption information to @media.
2546 * Returns: a #GstSDPResult.
2549 gst_sdp_media_set_key (GstSDPMedia * media, const gchar * type,
2552 g_free (media->key.type);
2553 media->key.type = g_strdup (type);
2554 g_free (media->key.data);
2555 media->key.data = g_strdup (data);
2561 * gst_sdp_media_get_key:
2562 * @media: a #GstSDPMedia
2564 * Get the encryption information from @media.
2566 * Returns: a #GstSDPKey.
2569 gst_sdp_media_get_key (const GstSDPMedia * media)
2575 * gst_sdp_media_attributes_len:
2576 * @media: a #GstSDPMedia
2578 * Get the number of attribute fields in @media.
2580 * Returns: the number of attributes in @media.
2583 gst_sdp_media_attributes_len (const GstSDPMedia * media)
2585 return media->attributes->len;
2589 * gst_sdp_media_add_attribute:
2590 * @media: a #GstSDPMedia
2594 * Add the attribute with @key and @value to @media.
2596 * Returns: #GST_SDP_OK.
2599 gst_sdp_media_add_attribute (GstSDPMedia * media, const gchar * key,
2600 const gchar * value)
2602 GstSDPAttribute attr;
2604 gst_sdp_attribute_set (&attr, key, value);
2605 g_array_append_val (media->attributes, attr);
2611 * gst_sdp_media_get_attribute:
2612 * @media: a #GstSDPMedia
2615 * Get the attribute at position @idx in @media.
2617 * Returns: the #GstSDPAttribute at position @idx.
2619 const GstSDPAttribute *
2620 gst_sdp_media_get_attribute (const GstSDPMedia * media, guint idx)
2622 return &g_array_index (media->attributes, GstSDPAttribute, idx);
2626 * gst_sdp_media_get_attribute_val_n:
2627 * @media: a #GstSDPMedia
2631 * Get the @nth attribute value for @key in @media.
2633 * Returns: the @nth attribute value.
2636 gst_sdp_media_get_attribute_val_n (const GstSDPMedia * media, const gchar * key,
2641 for (i = 0; i < media->attributes->len; i++) {
2642 GstSDPAttribute *attr;
2644 attr = &g_array_index (media->attributes, GstSDPAttribute, i);
2645 if (!strcmp (attr->key, key)) {
2656 * gst_sdp_media_get_attribute_val:
2657 * @media: a #GstSDPMedia
2660 * Get the first attribute value for @key in @media.
2662 * Returns: the first attribute value for @key.
2665 gst_sdp_media_get_attribute_val (const GstSDPMedia * media, const gchar * key)
2667 return gst_sdp_media_get_attribute_val_n (media, key, 0);
2671 * gst_sdp_media_insert_attribute:
2672 * @media: a #GstSDPMedia
2674 * @attr: a #GstSDPAttribute
2676 * Insert the attribute to @media at @idx. When @idx is -1,
2677 * the attribute is appended.
2679 * Returns: #GST_SDP_OK.
2684 gst_sdp_media_insert_attribute (GstSDPMedia * media, gint idx,
2685 GstSDPAttribute * attr)
2688 g_array_append_val (media->attributes, *attr);
2690 g_array_insert_val (media->attributes, idx, *attr);
2696 * gst_sdp_media_replace_attribute:
2697 * @media: a #GstSDPMedia
2699 * @attr: a #GstSDPAttribute
2701 * Replace the attribute in @media at @idx with @attr.
2703 * Returns: #GST_SDP_OK.
2708 gst_sdp_media_replace_attribute (GstSDPMedia * media, guint idx,
2709 GstSDPAttribute * attr)
2711 GstSDPAttribute *old;
2713 old = &g_array_index (media->attributes, GstSDPAttribute, idx);
2714 gst_sdp_attribute_clear (old);
2721 * gst_sdp_media_remove_attribute:
2722 * @media: a #GstSDPMedia
2725 * Remove the attribute in @media at @idx.
2727 * Returns: #GST_SDP_OK.
2732 gst_sdp_media_remove_attribute (GstSDPMedia * media, guint idx)
2734 GstSDPAttribute *old;
2736 old = &g_array_index (media->attributes, GstSDPAttribute, idx);
2737 gst_sdp_attribute_clear (old);
2738 g_array_remove_index (media->attributes, idx);
2744 read_string (gchar * dest, guint size, gchar ** src)
2750 while (g_ascii_isspace (**src))
2753 while (!g_ascii_isspace (**src) && **src != '\0') {
2755 dest[idx++] = **src;
2763 read_string_del (gchar * dest, guint size, gchar del, gchar ** src)
2769 while (g_ascii_isspace (**src))
2772 while (**src != del && **src != '\0') {
2774 dest[idx++] = **src;
2795 gst_sdp_parse_line (SDPContext * c, gchar type, gchar * buffer)
2800 #define READ_STRING(field) \
2801 do { read_string (str, sizeof (str), &p); REPLACE_STRING (field, str); } while (0)
2802 #define READ_UINT(field) \
2803 do { read_string (str, sizeof (str), &p); field = strtoul (str, NULL, 10); } while (0)
2807 if (buffer[0] != '0')
2808 GST_WARNING ("wrong SDP version");
2809 gst_sdp_message_set_version (c->msg, buffer);
2812 READ_STRING (c->msg->origin.username);
2813 READ_STRING (c->msg->origin.sess_id);
2814 READ_STRING (c->msg->origin.sess_version);
2815 READ_STRING (c->msg->origin.nettype);
2816 READ_STRING (c->msg->origin.addrtype);
2817 READ_STRING (c->msg->origin.addr);
2820 REPLACE_STRING (c->msg->session_name, buffer);
2823 if (c->state == SDP_SESSION) {
2824 REPLACE_STRING (c->msg->information, buffer);
2826 REPLACE_STRING (c->media->information, buffer);
2830 REPLACE_STRING (c->msg->uri, buffer);
2833 gst_sdp_message_add_email (c->msg, buffer);
2836 gst_sdp_message_add_phone (c->msg, buffer);
2840 GstSDPConnection conn;
2843 memset (&conn, 0, sizeof (conn));
2846 while ((str2 = strchr (str2, '/')))
2848 READ_STRING (conn.nettype);
2849 READ_STRING (conn.addrtype);
2850 READ_STRING (conn.address);
2851 /* only read TTL for IP4 */
2852 if (strcmp (conn.addrtype, "IP4") == 0)
2853 READ_UINT (conn.ttl);
2854 READ_UINT (conn.addr_number);
2856 if (c->state == SDP_SESSION) {
2857 gst_sdp_message_set_connection (c->msg, conn.nettype, conn.addrtype,
2858 conn.address, conn.ttl, conn.addr_number);
2860 gst_sdp_media_add_connection (c->media, conn.nettype, conn.addrtype,
2861 conn.address, conn.ttl, conn.addr_number);
2863 gst_sdp_connection_clear (&conn);
2870 read_string_del (str, sizeof (str), ':', &p);
2873 read_string (str2, sizeof (str2), &p);
2874 if (c->state == SDP_SESSION)
2875 gst_sdp_message_add_bandwidth (c->msg, str, atoi (str2));
2877 gst_sdp_media_add_bandwidth (c->media, str, atoi (str2));
2883 read_string_del (str, sizeof (str), ':', &p);
2886 if (c->state == SDP_SESSION)
2887 gst_sdp_message_set_key (c->msg, str, p);
2889 gst_sdp_media_set_key (c->media, str, p);
2892 read_string_del (str, sizeof (str), ':', &p);
2895 if (c->state == SDP_SESSION)
2896 gst_sdp_message_add_attribute (c->msg, str, p);
2898 gst_sdp_media_add_attribute (c->media, str, p);
2905 c->state = SDP_MEDIA;
2906 memset (&nmedia, 0, sizeof (nmedia));
2907 gst_sdp_media_init (&nmedia);
2909 /* m=<media> <port>/<number of ports> <proto> <fmt> ... */
2910 READ_STRING (nmedia.media);
2911 read_string (str, sizeof (str), &p);
2912 slash = g_strrstr (str, "/");
2915 nmedia.port = atoi (str);
2916 nmedia.num_ports = atoi (slash + 1);
2918 nmedia.port = atoi (str);
2919 nmedia.num_ports = 0;
2921 READ_STRING (nmedia.proto);
2923 read_string (str, sizeof (str), &p);
2924 gst_sdp_media_add_format (&nmedia, str);
2925 } while (*p != '\0');
2927 gst_sdp_message_add_media (c->msg, &nmedia);
2929 &g_array_index (c->msg->medias, GstSDPMedia, c->msg->medias->len - 1);
2939 * gst_sdp_message_parse_buffer:
2940 * @data: (array length=size): the start of the buffer
2941 * @size: the size of the buffer
2942 * @msg: the result #GstSDPMessage
2944 * Parse the contents of @size bytes pointed to by @data and store the result in
2947 * Returns: #GST_SDP_OK on success.
2950 gst_sdp_message_parse_buffer (const guint8 * data, guint size,
2951 GstSDPMessage * msg)
2956 gchar *buffer = NULL;
2960 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
2961 g_return_val_if_fail (data != NULL, GST_SDP_EINVAL);
2962 g_return_val_if_fail (size != 0, GST_SDP_EINVAL);
2964 c.state = SDP_SESSION;
2968 #define SIZE_CHECK_GUARD \
2970 if (p - (gchar *) data >= size) \
2976 while (p - (gchar *) data < size && g_ascii_isspace (*p))
2994 while (p - (gchar *) data < size && *p != '\n' && *p != '\r' && *p != '\0')
2998 if (bufsize <= len) {
2999 buffer = g_realloc (buffer, len + 1);
3002 memcpy (buffer, s, len);
3005 gst_sdp_parse_line (&c, type, buffer);
3010 while (p - (gchar *) data < size && *p != '\n' && *p != '\0')
3019 #undef SIZE_CHECK_GUARD
3028 print_media (GstSDPMedia * media)
3030 g_print (" media: '%s'\n", GST_STR_NULL (media->media));
3031 g_print (" port: '%u'\n", media->port);
3032 g_print (" num_ports: '%u'\n", media->num_ports);
3033 g_print (" proto: '%s'\n", GST_STR_NULL (media->proto));
3034 if (media->fmts->len > 0) {
3037 g_print (" formats:\n");
3038 for (i = 0; i < media->fmts->len; i++) {
3039 g_print (" format '%s'\n", g_array_index (media->fmts, gchar *, i));
3042 g_print (" information: '%s'\n", GST_STR_NULL (media->information));
3043 if (media->connections->len > 0) {
3046 g_print (" connections:\n");
3047 for (i = 0; i < media->connections->len; i++) {
3048 GstSDPConnection *conn =
3049 &g_array_index (media->connections, GstSDPConnection, i);
3051 g_print (" nettype: '%s'\n", GST_STR_NULL (conn->nettype));
3052 g_print (" addrtype: '%s'\n", GST_STR_NULL (conn->addrtype));
3053 g_print (" address: '%s'\n", GST_STR_NULL (conn->address));
3054 g_print (" ttl: '%u'\n", conn->ttl);
3055 g_print (" addr_number: '%u'\n", conn->addr_number);
3058 if (media->bandwidths->len > 0) {
3061 g_print (" bandwidths:\n");
3062 for (i = 0; i < media->bandwidths->len; i++) {
3063 GstSDPBandwidth *bw =
3064 &g_array_index (media->bandwidths, GstSDPBandwidth, i);
3066 g_print (" type: '%s'\n", GST_STR_NULL (bw->bwtype));
3067 g_print (" bandwidth: '%u'\n", bw->bandwidth);
3070 g_print (" key:\n");
3071 g_print (" type: '%s'\n", GST_STR_NULL (media->key.type));
3072 g_print (" data: '%s'\n", GST_STR_NULL (media->key.data));
3073 if (media->attributes->len > 0) {
3076 g_print (" attributes:\n");
3077 for (i = 0; i < media->attributes->len; i++) {
3078 GstSDPAttribute *attr =
3079 &g_array_index (media->attributes, GstSDPAttribute, i);
3081 g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
3087 * gst_sdp_message_dump:
3088 * @msg: a #GstSDPMessage
3090 * Dump the parsed contents of @msg to stdout.
3092 * Returns: a #GstSDPResult.
3095 gst_sdp_message_dump (const GstSDPMessage * msg)
3097 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
3099 g_print ("sdp packet %p:\n", msg);
3100 g_print (" version: '%s'\n", GST_STR_NULL (msg->version));
3101 g_print (" origin:\n");
3102 g_print (" username: '%s'\n", GST_STR_NULL (msg->origin.username));
3103 g_print (" sess_id: '%s'\n", GST_STR_NULL (msg->origin.sess_id));
3104 g_print (" sess_version: '%s'\n", GST_STR_NULL (msg->origin.sess_version));
3105 g_print (" nettype: '%s'\n", GST_STR_NULL (msg->origin.nettype));
3106 g_print (" addrtype: '%s'\n", GST_STR_NULL (msg->origin.addrtype));
3107 g_print (" addr: '%s'\n", GST_STR_NULL (msg->origin.addr));
3108 g_print (" session_name: '%s'\n", GST_STR_NULL (msg->session_name));
3109 g_print (" information: '%s'\n", GST_STR_NULL (msg->information));
3110 g_print (" uri: '%s'\n", GST_STR_NULL (msg->uri));
3112 if (msg->emails->len > 0) {
3115 g_print (" emails:\n");
3116 for (i = 0; i < msg->emails->len; i++) {
3117 g_print (" email '%s'\n", g_array_index (msg->emails, gchar *, i));
3120 if (msg->phones->len > 0) {
3123 g_print (" phones:\n");
3124 for (i = 0; i < msg->phones->len; i++) {
3125 g_print (" phone '%s'\n", g_array_index (msg->phones, gchar *, i));
3128 g_print (" connection:\n");
3129 g_print (" nettype: '%s'\n", GST_STR_NULL (msg->connection.nettype));
3130 g_print (" addrtype: '%s'\n", GST_STR_NULL (msg->connection.addrtype));
3131 g_print (" address: '%s'\n", GST_STR_NULL (msg->connection.address));
3132 g_print (" ttl: '%u'\n", msg->connection.ttl);
3133 g_print (" addr_number: '%u'\n", msg->connection.addr_number);
3134 if (msg->bandwidths->len > 0) {
3137 g_print (" bandwidths:\n");
3138 for (i = 0; i < msg->bandwidths->len; i++) {
3139 GstSDPBandwidth *bw =
3140 &g_array_index (msg->bandwidths, GstSDPBandwidth, i);
3142 g_print (" type: '%s'\n", GST_STR_NULL (bw->bwtype));
3143 g_print (" bandwidth: '%u'\n", bw->bandwidth);
3146 g_print (" key:\n");
3147 g_print (" type: '%s'\n", GST_STR_NULL (msg->key.type));
3148 g_print (" data: '%s'\n", GST_STR_NULL (msg->key.data));
3149 if (msg->attributes->len > 0) {
3152 g_print (" attributes:\n");
3153 for (i = 0; i < msg->attributes->len; i++) {
3154 GstSDPAttribute *attr =
3155 &g_array_index (msg->attributes, GstSDPAttribute, i);
3157 g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
3160 if (msg->medias->len > 0) {
3163 g_print (" medias:\n");
3164 for (i = 0; i < msg->medias->len; i++) {
3165 g_print (" media %u:\n", i);
3166 print_media (&g_array_index (msg->medias, GstSDPMedia, i));
3172 static const gchar *
3173 gst_sdp_get_attribute_for_pt (const GstSDPMedia * media, const gchar * name,
3182 if ((attr = gst_sdp_media_get_attribute_val_n (media, name, i)) == NULL)
3185 if (sscanf (attr, "%d ", &val) != 1)
3194 #define PARSE_INT(p, del, res) \
3197 p = strstr (p, del); \
3207 #define PARSE_STRING(p, del, res) \
3210 p = strstr (p, del); \
3222 #define SKIP_SPACES(p) \
3223 while (*p && g_ascii_isspace (*p)) \
3228 * <payload> <encoding_name>/<clock_rate>[/<encoding_params>]
3231 gst_sdp_parse_rtpmap (const gchar * rtpmap, gint * payload, gchar ** name,
3232 gint * rate, gchar ** params)
3236 p = (gchar *) rtpmap;
3238 PARSE_INT (p, " ", *payload);
3246 PARSE_STRING (p, "/", *name);
3247 if (*name == NULL) {
3248 GST_DEBUG ("no rate, name %s", p);
3249 /* no rate, assume -1 then, this is not supposed to happen but RealMedia
3250 * streams seem to omit the rate. */
3257 p = strstr (p, "/");
3275 * gst_sdp_media_get_caps_from_media:
3276 * @media: a #GstSDPMedia
3277 * @pt: a payload type
3279 * Mapping of caps from SDP fields:
3281 * a=rtpmap:(payload) (encoding_name)/(clock_rate)[/(encoding_params)]
3283 * a=framesize:(payload) (width)-(height)
3285 * a=fmtp:(payload) (param)[=(value)];...
3287 * Returns: a #GstCaps, or %NULL if an error happened
3292 gst_sdp_media_get_caps_from_media (const GstSDPMedia * media, gint pt)
3295 const gchar *rtpmap;
3297 const gchar *framesize;
3300 gchar *params = NULL;
3306 /* get and parse rtpmap */
3307 rtpmap = gst_sdp_get_attribute_for_pt (media, "rtpmap", pt);
3310 ret = gst_sdp_parse_rtpmap (rtpmap, &payload, &name, &rate, ¶ms);
3312 GST_ERROR ("error parsing rtpmap, ignoring");
3316 /* dynamic payloads need rtpmap or we fail */
3317 if (rtpmap == NULL && pt >= 96)
3320 /* check if we have a rate, if not, we need to look up the rate from the
3321 * default rates based on the payload types. */
3323 const GstRTPPayloadInfo *info;
3325 if (GST_RTP_PAYLOAD_IS_DYNAMIC (pt)) {
3326 /* dynamic types, use media and encoding_name */
3327 tmp = g_ascii_strdown (media->media, -1);
3328 info = gst_rtp_payload_info_for_name (tmp, name);
3331 /* static types, use payload type */
3332 info = gst_rtp_payload_info_for_pt (pt);
3336 if ((rate = info->clock_rate) == 0)
3339 /* we fail if we cannot find one */
3344 tmp = g_ascii_strdown (media->media, -1);
3345 caps = gst_caps_new_simple ("application/x-unknown",
3346 "media", G_TYPE_STRING, tmp, "payload", G_TYPE_INT, pt, NULL);
3348 s = gst_caps_get_structure (caps, 0);
3350 gst_structure_set (s, "clock-rate", G_TYPE_INT, rate, NULL);
3352 /* encoding name must be upper case */
3354 tmp = g_ascii_strup (name, -1);
3355 gst_structure_set (s, "encoding-name", G_TYPE_STRING, tmp, NULL);
3359 /* params must be lower case */
3360 if (params != NULL) {
3361 tmp = g_ascii_strdown (params, -1);
3362 gst_structure_set (s, "encoding-params", G_TYPE_STRING, tmp, NULL);
3366 /* parse optional fmtp: field */
3367 if ((fmtp = gst_sdp_get_attribute_for_pt (media, "fmtp", pt))) {
3373 /* p is now of the format <payload> <param>[=<value>];... */
3374 PARSE_INT (p, " ", payload);
3375 if (payload != -1 && payload == pt) {
3379 /* <param>[=<value>] are separated with ';' */
3380 pairs = g_strsplit (p, ";", 0);
3381 for (i = 0; pairs[i]; i++) {
3383 const gchar *val, *key;
3385 const gchar *reserved_keys[] =
3386 { "media", "payload", "clock-rate", "encoding-name",
3390 /* the key may not have a '=', the value can have other '='s */
3391 valpos = strstr (pairs[i], "=");
3393 /* we have a '=' and thus a value, remove the '=' with \0 */
3395 /* value is everything between '=' and ';'. We split the pairs at ;
3396 * boundaries so we can take the remainder of the value. Some servers
3397 * put spaces around the value which we strip off here. Alternatively
3398 * we could strip those spaces in the depayloaders should these spaces
3399 * actually carry any meaning in the future. */
3400 val = g_strstrip (valpos + 1);
3402 /* simple <param>;.. is translated into <param>=1;... */
3405 /* strip the key of spaces, convert key to lowercase but not the value. */
3406 key = g_strstrip (pairs[i]);
3408 /* skip keys from the fmtp, which we already use ourselves for the
3409 * caps. Some software is adding random things like clock-rate into
3410 * the fmtp, and we would otherwise here set a string-typed clock-rate
3411 * in the caps... and thus fail to create valid RTP caps
3413 for (j = 0; j < G_N_ELEMENTS (reserved_keys); j++) {
3414 if (g_ascii_strcasecmp (reserved_keys[j], key) == 0) {
3420 if (strlen (key) > 1) {
3421 tmp = g_ascii_strdown (key, -1);
3422 gst_structure_set (s, tmp, G_TYPE_STRING, val, NULL);
3430 /* parse framesize: field */
3431 if ((framesize = gst_sdp_media_get_attribute_val (media, "framesize"))) {
3434 /* p is now of the format <payload> <width>-<height> */
3435 p = (gchar *) framesize;
3437 PARSE_INT (p, " ", payload);
3438 if (payload != -1 && payload == pt) {
3439 gst_structure_set (s, "a-framesize", G_TYPE_STRING, p, NULL);
3448 GST_ERROR ("rtpmap type not given for dynamic payload %d", pt);
3453 GST_ERROR ("rate unknown for payload type %d", pt);
3459 * gst_sdp_media_set_media_from_caps:
3461 * @media: a #GstSDPMedia
3463 * Mapping of caps to SDP fields:
3465 * a=rtpmap:(payload) (encoding_name) or (clock_rate)[or (encoding_params)]
3467 * a=framesize:(payload) (width)-(height)
3469 * a=fmtp:(payload) (param)[=(value)];...
3471 * Returns: a #GstSDPResult.
3476 gst_sdp_media_set_media_from_caps (const GstCaps * caps, GstSDPMedia * media)
3478 const gchar *caps_str, *caps_enc, *caps_params;
3480 gint caps_pt, caps_rate;
3486 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
3487 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
3489 s = gst_caps_get_structure (caps, 0);
3491 GST_ERROR ("ignoring stream without media type");
3495 /* get media type and payload for the m= line */
3496 caps_str = gst_structure_get_string (s, "media");
3497 gst_sdp_media_set_media (media, caps_str);
3499 gst_structure_get_int (s, "payload", &caps_pt);
3500 tmp = g_strdup_printf ("%d", caps_pt);
3501 gst_sdp_media_add_format (media, tmp);
3504 /* get clock-rate, media type and params for the rtpmap attribute */
3505 gst_structure_get_int (s, "clock-rate", &caps_rate);
3506 caps_enc = gst_structure_get_string (s, "encoding-name");
3507 caps_params = gst_structure_get_string (s, "encoding-params");
3511 tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate,
3514 tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate);
3516 gst_sdp_media_add_attribute (media, "rtpmap", tmp);
3520 /* collect all other properties and add them to fmtp or attributes */
3521 fmtp = g_string_new ("");
3522 g_string_append_printf (fmtp, "%d ", caps_pt);
3524 n_fields = gst_structure_n_fields (s);
3525 for (j = 0; j < n_fields; j++) {
3526 const gchar *fname, *fval;
3528 fname = gst_structure_nth_field_name (s, j);
3530 /* filter out standard properties */
3531 if (!strcmp (fname, "media"))
3533 if (!strcmp (fname, "payload"))
3535 if (!strcmp (fname, "clock-rate"))
3537 if (!strcmp (fname, "encoding-name"))
3539 if (!strcmp (fname, "encoding-params"))
3541 if (!strcmp (fname, "ssrc"))
3543 if (!strcmp (fname, "timestamp-offset"))
3545 if (!strcmp (fname, "seqnum-offset"))
3547 if (g_str_has_prefix (fname, "srtp-"))
3549 if (g_str_has_prefix (fname, "srtcp-"))
3552 if (g_str_has_prefix (fname, "x-gst-rtsp-server-rtx-time"))
3555 if (!strcmp (fname, "a-framesize")) {
3556 /* a-framesize attribute */
3557 if ((fval = gst_structure_get_string (s, fname))) {
3558 tmp = g_strdup_printf ("%d %s", caps_pt, fval);
3559 gst_sdp_media_add_attribute (media, fname + 2, tmp);
3565 if (g_str_has_prefix (fname, "a-")) {
3567 if ((fval = gst_structure_get_string (s, fname)))
3568 gst_sdp_media_add_attribute (media, fname + 2, fval);
3571 if (g_str_has_prefix (fname, "x-")) {
3573 if ((fval = gst_structure_get_string (s, fname)))
3574 gst_sdp_media_add_attribute (media, fname, fval);
3578 if ((fval = gst_structure_get_string (s, fname))) {
3579 g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval);
3585 tmp = g_string_free (fmtp, FALSE);
3586 gst_sdp_media_add_attribute (media, "fmtp", tmp);
3589 g_string_free (fmtp, TRUE);
3597 GST_DEBUG ("ignoring stream");
3598 return GST_SDP_EINVAL;
3603 * gst_sdp_make_keymgmt:
3604 * @uri: a #gchar URI
3605 * @base64: a #gchar base64-encoded key data
3607 * Makes key management data
3609 * Returns: (transfer full): a #gchar key-mgmt data,
3614 gst_sdp_make_keymgmt (const gchar * uri, const gchar * base64)
3616 g_return_val_if_fail (uri != NULL, NULL);
3617 g_return_val_if_fail (base64 != NULL, NULL);
3619 return g_strdup_printf ("prot=mikey;uri=\"%s\";data=\"%s\"", uri, base64);
3622 #define AES_128_KEY_LEN 16
3623 #define AES_256_KEY_LEN 32
3624 #define HMAC_32_KEY_LEN 4
3625 #define HMAC_80_KEY_LEN 10
3628 gst_sdp_parse_keymgmt (const gchar * keymgmt, GstCaps * caps)
3630 gboolean res = FALSE;
3633 GstMIKEYMessage *msg;
3634 const GstMIKEYPayload *payload;
3635 const gchar *srtp_cipher;
3636 const gchar *srtp_auth;
3640 p = orig_value = g_strdup (keymgmt);
3644 g_free (orig_value);
3648 PARSE_STRING (p, " ", kmpid);
3649 if (kmpid == NULL || !g_str_equal (kmpid, "mikey")) {
3650 g_free (orig_value);
3653 data = g_base64_decode (p, &size);
3654 g_free (orig_value); /* Don't need this any more */
3659 msg = gst_mikey_message_new_from_data (data, size, NULL, NULL);
3664 srtp_cipher = "aes-128-icm";
3665 srtp_auth = "hmac-sha1-80";
3667 /* check the Security policy if any */
3668 if ((payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_SP, 0))) {
3669 GstMIKEYPayloadSP *p = (GstMIKEYPayloadSP *) payload;
3672 if (p->proto != GST_MIKEY_SEC_PROTO_SRTP)
3675 len = gst_mikey_payload_sp_get_n_params (payload);
3676 for (i = 0; i < len; i++) {
3677 const GstMIKEYPayloadSPParam *param =
3678 gst_mikey_payload_sp_get_param (payload, i);
3680 switch (param->type) {
3681 case GST_MIKEY_SP_SRTP_ENC_ALG:
3682 switch (param->val[0]) {
3684 srtp_cipher = "null";
3688 srtp_cipher = "aes-128-icm";
3694 case GST_MIKEY_SP_SRTP_ENC_KEY_LEN:
3695 switch (param->val[0]) {
3696 case AES_128_KEY_LEN:
3697 srtp_cipher = "aes-128-icm";
3699 case AES_256_KEY_LEN:
3700 srtp_cipher = "aes-256-icm";
3706 case GST_MIKEY_SP_SRTP_AUTH_ALG:
3707 switch (param->val[0]) {
3713 srtp_auth = "hmac-sha1-80";
3719 case GST_MIKEY_SP_SRTP_AUTH_KEY_LEN:
3720 switch (param->val[0]) {
3721 case HMAC_32_KEY_LEN:
3722 srtp_auth = "hmac-sha1-32";
3724 case HMAC_80_KEY_LEN:
3725 srtp_auth = "hmac-sha1-80";
3731 case GST_MIKEY_SP_SRTP_SRTP_ENC:
3733 case GST_MIKEY_SP_SRTP_SRTCP_ENC:
3741 if (!(payload = gst_mikey_message_find_payload (msg, GST_MIKEY_PT_KEMAC, 0)))
3744 GstMIKEYPayloadKEMAC *p = (GstMIKEYPayloadKEMAC *) payload;
3745 const GstMIKEYPayload *sub;
3746 GstMIKEYPayloadKeyData *pkd;
3749 if (p->enc_alg != GST_MIKEY_ENC_NULL || p->mac_alg != GST_MIKEY_MAC_NULL)
3752 if (!(sub = gst_mikey_payload_kemac_get_sub (payload, 0)))
3755 if (sub->type != GST_MIKEY_PT_KEY_DATA)
3758 pkd = (GstMIKEYPayloadKeyData *) sub;
3760 gst_buffer_new_wrapped (g_memdup (pkd->key_data, pkd->key_len),
3762 gst_caps_set_simple (caps, "srtp-key", GST_TYPE_BUFFER, buf, NULL);
3763 gst_buffer_unref (buf);
3766 gst_caps_set_simple (caps,
3767 "srtp-cipher", G_TYPE_STRING, srtp_cipher,
3768 "srtp-auth", G_TYPE_STRING, srtp_auth,
3769 "srtcp-cipher", G_TYPE_STRING, srtp_cipher,
3770 "srtcp-auth", G_TYPE_STRING, srtp_auth, NULL);
3774 gst_mikey_message_unref (msg);
3780 sdp_addtributes_to_caps (GArray * attributes, GstCaps * caps)
3782 if (attributes->len > 0) {
3786 s = gst_caps_get_structure (caps, 0);
3788 for (i = 0; i < attributes->len; i++) {
3789 GstSDPAttribute *attr = &g_array_index (attributes, GstSDPAttribute, i);
3790 gchar *tofree, *key;
3794 /* skip some of the attribute we already handle */
3795 if (!strcmp (key, "fmtp"))
3797 if (!strcmp (key, "rtpmap"))
3799 if (!strcmp (key, "control"))
3801 if (!strcmp (key, "range"))
3803 if (!strcmp (key, "framesize"))
3805 if (g_str_equal (key, "key-mgmt")) {
3806 gst_sdp_parse_keymgmt (attr->value, caps);
3810 /* string must be valid UTF8 */
3811 if (!g_utf8_validate (attr->value, -1, NULL))
3814 if (!g_str_has_prefix (key, "x-"))
3815 tofree = key = g_strdup_printf ("a-%s", key);
3819 GST_DEBUG ("adding caps: %s=%s", key, attr->value);
3820 gst_structure_set (s, key, G_TYPE_STRING, attr->value, NULL);
3829 * gst_sdp_message_attributes_to_caps:
3830 * @msg: a #GstSDPMessage
3833 * Mapping of attributes of #GstSDPMessage to #GstCaps
3835 * Returns: a #GstSDPResult.
3840 gst_sdp_message_attributes_to_caps (const GstSDPMessage * msg, GstCaps * caps)
3842 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
3843 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
3845 return sdp_addtributes_to_caps (msg->attributes, caps);
3849 * gst_sdp_media_attributes_to_caps:
3850 * @media: a #GstSDPMedia
3853 * Mapping of attributes of #GstSDPMedia to #GstCaps
3855 * Returns: a #GstSDPResult.
3860 gst_sdp_media_attributes_to_caps (const GstSDPMedia * media, GstCaps * caps)
3862 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
3863 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
3865 return sdp_addtributes_to_caps (media->attributes, caps);