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 * @title: GstSDPMessage
46 * @short_description: Helper methods for dealing with SDP messages
48 * The GstSDPMessage helper functions makes it easy to parse and create SDP
63 #include <gst/rtp/gstrtppayloads.h>
64 #include "gstsdpmessage.h"
66 #define FREE_STRING(field) g_free (field); (field) = NULL
67 #define REPLACE_STRING(field, val) FREE_STRING(field); (field) = g_strdup (val)
70 free_string (gchar ** str)
75 #define INIT_ARRAY(field, type, init_func) \
79 for(i = 0; i < (field)->len; i++) \
80 init_func (&g_array_index ((field), type, i)); \
81 g_array_set_size ((field), 0); \
84 (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
87 #define FREE_ARRAY(field) \
90 g_array_free ((field), TRUE); \
94 #define DEFINE_STRING_SETTER(field) \
95 GstSDPResult gst_sdp_message_set_##field (GstSDPMessage *msg, const gchar *val) { \
96 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
97 g_free (msg->field); \
98 msg->field = g_strdup (val); \
101 #define DEFINE_STRING_GETTER(field) \
102 const gchar* gst_sdp_message_get_##field (const GstSDPMessage *msg) { \
103 g_return_val_if_fail (msg != NULL, NULL); \
107 #define DEFINE_ARRAY_LEN(field) \
108 guint gst_sdp_message_##field##_len (const GstSDPMessage *msg) { \
109 g_return_val_if_fail (msg != NULL, 0); \
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 g_return_val_if_fail (msg != NULL, NULL); \
115 return &g_array_index (msg->field, type, idx); \
117 #define DEFINE_PTR_ARRAY_GETTER(method, field, type) \
118 const type gst_sdp_message_get_##method (const GstSDPMessage *msg, guint idx) { \
119 g_return_val_if_fail (msg != NULL, (type) 0); \
120 return g_array_index (msg->field, type, idx); \
122 #define DEFINE_ARRAY_INSERT(method, field, intype, dup_method, type) \
123 GstSDPResult gst_sdp_message_insert_##method (GstSDPMessage *msg, gint idx, intype val) { \
126 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
127 dup_method (v, val); \
129 g_array_append_val (msg->field, vt); \
131 g_array_insert_val (msg->field, idx, vt); \
135 #define DEFINE_ARRAY_REPLACE(method, field, intype, free_method, dup_method, type) \
136 GstSDPResult gst_sdp_message_replace_##method (GstSDPMessage *msg, guint idx, intype val) { \
138 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
139 v = &g_array_index (msg->field, type, idx); \
141 dup_method (v, val); \
144 #define DEFINE_ARRAY_REMOVE(method, field, type, free_method) \
145 GstSDPResult gst_sdp_message_remove_##method (GstSDPMessage *msg, guint idx) { \
147 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
148 v = &g_array_index (msg->field, type, idx); \
150 g_array_remove_index (msg->field, idx); \
153 #define DEFINE_ARRAY_ADDER(method, type) \
154 GstSDPResult gst_sdp_message_add_##method (GstSDPMessage *msg, const type val) { \
155 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
156 return gst_sdp_message_insert_##method (msg, -1, val); \
159 #define dup_string(v,val) ((*v) = g_strdup (val))
160 #define INIT_STR_ARRAY(field) \
161 INIT_ARRAY (field, gchar *, free_string)
162 #define DEFINE_STR_ARRAY_GETTER(method, field) \
163 DEFINE_PTR_ARRAY_GETTER(method, field, gchar *)
164 #define DEFINE_STR_ARRAY_INSERT(method, field) \
165 DEFINE_ARRAY_INSERT (method, field, const gchar *, dup_string, gchar *)
166 #define DEFINE_STR_ARRAY_ADDER(method, field) \
167 DEFINE_ARRAY_ADDER (method, gchar *)
168 #define DEFINE_STR_ARRAY_REPLACE(method, field) \
169 DEFINE_ARRAY_REPLACE (method, field, const gchar *, free_string, dup_string, gchar *)
170 #define DEFINE_STR_ARRAY_REMOVE(method, field) \
171 DEFINE_ARRAY_REMOVE (method, field, gchar *, free_string)
173 static GstSDPMessage *gst_sdp_message_boxed_copy (GstSDPMessage * orig);
174 static void gst_sdp_message_boxed_free (GstSDPMessage * msg);
176 G_DEFINE_BOXED_TYPE (GstSDPMessage, gst_sdp_message, gst_sdp_message_boxed_copy,
177 gst_sdp_message_boxed_free);
179 static GstSDPMessage *
180 gst_sdp_message_boxed_copy (GstSDPMessage * orig)
187 if (gst_sdp_message_copy (orig, ©) == GST_SDP_OK)
194 gst_sdp_message_boxed_free (GstSDPMessage * msg)
196 gst_sdp_message_free (msg);
200 gst_sdp_origin_init (GstSDPOrigin * origin)
202 FREE_STRING (origin->username);
203 FREE_STRING (origin->sess_id);
204 FREE_STRING (origin->sess_version);
205 FREE_STRING (origin->nettype);
206 FREE_STRING (origin->addrtype);
207 FREE_STRING (origin->addr);
211 gst_sdp_key_init (GstSDPKey * key)
213 FREE_STRING (key->type);
214 FREE_STRING (key->data);
218 * gst_sdp_message_new:
219 * @msg: (out) (transfer full): pointer to new #GstSDPMessage
221 * Allocate a new GstSDPMessage and store the result in @msg.
223 * Returns: a #GstSDPResult.
226 gst_sdp_message_new (GstSDPMessage ** msg)
228 GstSDPMessage *newmsg;
230 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
232 newmsg = g_new0 (GstSDPMessage, 1);
236 return gst_sdp_message_init (newmsg);
240 * gst_sdp_message_new_from_text:
241 * @msg: (out) (transfer full): pointer to new #GstSDPMessage
242 * @text: A dynamically allocated string representing the SDP description
244 * Parse @text and create a new SDPMessage from these.
246 * Returns: a #GstSDPResult.
250 gst_sdp_message_new_from_text (const gchar * text, GstSDPMessage ** msg)
254 if ((res = gst_sdp_message_new (msg)) != GST_SDP_OK)
258 gst_sdp_message_parse_buffer ((const guint8 *) text, strlen (text), *msg);
264 * gst_sdp_message_init:
265 * @msg: a #GstSDPMessage
267 * Initialize @msg so that its contents are as if it was freshly allocated
268 * with gst_sdp_message_new(). This function is mostly used to initialize a message
269 * allocated on the stack. gst_sdp_message_uninit() undoes this operation.
271 * When this function is invoked on newly allocated data (with malloc or on the
272 * stack), its contents should be set to 0 before calling this function.
274 * Returns: a #GstSDPResult.
277 gst_sdp_message_init (GstSDPMessage * msg)
279 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
281 FREE_STRING (msg->version);
282 gst_sdp_origin_init (&msg->origin);
283 FREE_STRING (msg->session_name);
284 FREE_STRING (msg->information);
285 FREE_STRING (msg->uri);
286 INIT_STR_ARRAY (msg->emails);
287 INIT_STR_ARRAY (msg->phones);
288 gst_sdp_connection_clear (&msg->connection);
289 INIT_ARRAY (msg->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_clear);
290 INIT_ARRAY (msg->times, GstSDPTime, gst_sdp_time_clear);
291 INIT_ARRAY (msg->zones, GstSDPZone, gst_sdp_zone_clear);
292 gst_sdp_key_init (&msg->key);
293 INIT_ARRAY (msg->attributes, GstSDPAttribute, gst_sdp_attribute_clear);
294 INIT_ARRAY (msg->medias, GstSDPMedia, gst_sdp_media_uninit);
300 * gst_sdp_message_uninit:
301 * @msg: a #GstSDPMessage
303 * Free all resources allocated in @msg. @msg should not be used anymore after
304 * this function. This function should be used when @msg was allocated on the
305 * stack and initialized with gst_sdp_message_init().
307 * Returns: a #GstSDPResult.
310 gst_sdp_message_uninit (GstSDPMessage * msg)
312 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
314 gst_sdp_message_init (msg);
316 FREE_ARRAY (msg->emails);
317 FREE_ARRAY (msg->phones);
318 FREE_ARRAY (msg->bandwidths);
319 FREE_ARRAY (msg->times);
320 FREE_ARRAY (msg->zones);
321 FREE_ARRAY (msg->attributes);
322 FREE_ARRAY (msg->medias);
328 * gst_sdp_message_copy:
329 * @msg: a #GstSDPMessage
330 * @copy: (out) (transfer full): pointer to new #GstSDPMessage
332 * Allocate a new copy of @msg and store the result in @copy. The value in
333 * @copy should be release with gst_sdp_message_free function.
335 * Returns: a #GstSDPResult
340 gst_sdp_message_copy (const GstSDPMessage * msg, GstSDPMessage ** copy)
347 return GST_SDP_EINVAL;
349 ret = gst_sdp_message_new (copy);
350 if (ret != GST_SDP_OK)
355 REPLACE_STRING (cp->version, msg->version);
356 gst_sdp_message_set_origin (cp, msg->origin.username, msg->origin.sess_id,
357 msg->origin.sess_version, msg->origin.nettype, msg->origin.addrtype,
359 REPLACE_STRING (cp->session_name, msg->session_name);
360 REPLACE_STRING (cp->information, msg->information);
361 REPLACE_STRING (cp->uri, msg->uri);
363 len = gst_sdp_message_emails_len (msg);
364 for (i = 0; i < len; i++) {
365 gst_sdp_message_add_email (cp, gst_sdp_message_get_email (msg, i));
368 len = gst_sdp_message_phones_len (msg);
369 for (i = 0; i < len; i++) {
370 gst_sdp_message_add_phone (cp, gst_sdp_message_get_phone (msg, i));
373 gst_sdp_message_set_connection (cp, msg->connection.nettype,
374 msg->connection.addrtype, msg->connection.address, msg->connection.ttl,
375 msg->connection.addr_number);
377 len = gst_sdp_message_bandwidths_len (msg);
378 for (i = 0; i < len; i++) {
379 const GstSDPBandwidth *bw = gst_sdp_message_get_bandwidth (msg, i);
380 gst_sdp_message_add_bandwidth (cp, bw->bwtype, bw->bandwidth);
383 len = gst_sdp_message_times_len (msg);
384 for (i = 0; i < len; i++) {
385 const gchar **repeat = NULL;
386 const GstSDPTime *time = gst_sdp_message_get_time (msg, i);
388 if (time->repeat != NULL) {
391 repeat = g_malloc0 ((time->repeat->len + 1) * sizeof (gchar *));
392 for (j = 0; j < time->repeat->len; j++) {
393 repeat[j] = g_array_index (time->repeat, char *, j);
398 gst_sdp_message_add_time (cp, time->start, time->stop, repeat);
400 g_free ((gchar **) repeat);
403 len = gst_sdp_message_zones_len (msg);
404 for (i = 0; i < len; i++) {
405 const GstSDPZone *zone = gst_sdp_message_get_zone (msg, i);
406 gst_sdp_message_add_zone (cp, zone->time, zone->typed_time);
409 gst_sdp_message_set_key (cp, msg->key.type, msg->key.data);
411 len = gst_sdp_message_attributes_len (msg);
412 for (i = 0; i < len; i++) {
413 const GstSDPAttribute *attr = gst_sdp_message_get_attribute (msg, i);
414 gst_sdp_message_add_attribute (cp, attr->key, attr->value);
417 len = gst_sdp_message_medias_len (msg);
418 for (i = 0; i < len; i++) {
419 GstSDPMedia *media_copy;
420 const GstSDPMedia *media = gst_sdp_message_get_media (msg, i);
422 if (gst_sdp_media_copy (media, &media_copy) == GST_SDP_OK) {
423 gst_sdp_message_add_media (cp, media_copy);
424 gst_sdp_media_free (media_copy);
432 * gst_sdp_message_free:
433 * @msg: a #GstSDPMessage
435 * Free all resources allocated by @msg. @msg should not be used anymore after
436 * this function. This function should be used when @msg was dynamically
437 * allocated with gst_sdp_message_new().
439 * Returns: a #GstSDPResult.
442 gst_sdp_message_free (GstSDPMessage * msg)
444 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
446 gst_sdp_message_uninit (msg);
453 * gst_sdp_address_is_multicast:
454 * @nettype: a network type
455 * @addrtype: an address type
458 * Check if the given @addr is a multicast address.
460 * Returns: TRUE when @addr is multicast.
463 gst_sdp_address_is_multicast (const gchar * nettype, const gchar * addrtype,
466 gboolean ret = FALSE;
469 g_return_val_if_fail (addr, FALSE);
471 /* we only support IN */
472 if (nettype && strcmp (nettype, "IN") != 0)
475 /* guard against parse failures */
476 if ((iaddr = g_inet_address_new_from_string (addr)) == NULL)
479 ret = g_inet_address_get_is_multicast (iaddr);
480 g_object_unref (iaddr);
486 * gst_sdp_message_as_text:
487 * @msg: a #GstSDPMessage
489 * Convert the contents of @msg to a text string.
491 * Returns: A dynamically allocated string representing the SDP description.
494 gst_sdp_message_as_text (const GstSDPMessage * msg)
496 /* change all vars so they match rfc? */
500 g_return_val_if_fail (msg != NULL, NULL);
502 lines = g_string_new ("");
505 g_string_append_printf (lines, "v=%s\r\n", msg->version);
507 if (msg->origin.sess_id && msg->origin.sess_version && msg->origin.nettype &&
508 msg->origin.addrtype && msg->origin.addr)
509 g_string_append_printf (lines, "o=%s %s %s %s %s %s\r\n",
510 msg->origin.username ? msg->origin.username : "-", msg->origin.sess_id,
511 msg->origin.sess_version, msg->origin.nettype, msg->origin.addrtype,
514 if (msg->session_name)
515 g_string_append_printf (lines, "s=%s\r\n", msg->session_name);
517 if (msg->information)
518 g_string_append_printf (lines, "i=%s\r\n", msg->information);
521 g_string_append_printf (lines, "u=%s\r\n", msg->uri);
523 for (i = 0; i < gst_sdp_message_emails_len (msg); i++)
524 g_string_append_printf (lines, "e=%s\r\n",
525 gst_sdp_message_get_email (msg, i));
527 for (i = 0; i < gst_sdp_message_phones_len (msg); i++)
528 g_string_append_printf (lines, "p=%s\r\n",
529 gst_sdp_message_get_phone (msg, i));
531 if (msg->connection.nettype && msg->connection.addrtype &&
532 msg->connection.address) {
533 g_string_append_printf (lines, "c=%s %s %s", msg->connection.nettype,
534 msg->connection.addrtype, msg->connection.address);
535 if (gst_sdp_address_is_multicast (msg->connection.nettype,
536 msg->connection.addrtype, msg->connection.address)) {
537 /* only add ttl for IP4 */
538 if (strcmp (msg->connection.addrtype, "IP4") == 0)
539 g_string_append_printf (lines, "/%u", msg->connection.ttl);
540 if (msg->connection.addr_number > 1)
541 g_string_append_printf (lines, "/%u", msg->connection.addr_number);
543 g_string_append_printf (lines, "\r\n");
546 for (i = 0; i < gst_sdp_message_bandwidths_len (msg); i++) {
547 const GstSDPBandwidth *bandwidth = gst_sdp_message_get_bandwidth (msg, i);
549 g_string_append_printf (lines, "b=%s:%u\r\n", bandwidth->bwtype,
550 bandwidth->bandwidth);
553 if (gst_sdp_message_times_len (msg) == 0) {
554 g_string_append_printf (lines, "t=0 0\r\n");
556 for (i = 0; i < gst_sdp_message_times_len (msg); i++) {
557 const GstSDPTime *times = gst_sdp_message_get_time (msg, i);
559 g_string_append_printf (lines, "t=%s %s\r\n", times->start, times->stop);
561 if (times->repeat != NULL) {
564 g_string_append_printf (lines, "r=%s",
565 g_array_index (times->repeat, gchar *, 0));
566 for (j = 1; j < times->repeat->len; j++)
567 g_string_append_printf (lines, " %s",
568 g_array_index (times->repeat, gchar *, j));
569 g_string_append_printf (lines, "\r\n");
574 if (gst_sdp_message_zones_len (msg) > 0) {
575 const GstSDPZone *zone = gst_sdp_message_get_zone (msg, 0);
577 g_string_append_printf (lines, "z=%s %s", zone->time, zone->typed_time);
578 for (i = 1; i < gst_sdp_message_zones_len (msg); i++) {
579 zone = gst_sdp_message_get_zone (msg, i);
580 g_string_append_printf (lines, " %s %s", zone->time, zone->typed_time);
582 g_string_append_printf (lines, "\r\n");
586 g_string_append_printf (lines, "k=%s", msg->key.type);
588 g_string_append_printf (lines, ":%s", msg->key.data);
589 g_string_append_printf (lines, "\r\n");
592 for (i = 0; i < gst_sdp_message_attributes_len (msg); i++) {
593 const GstSDPAttribute *attr = gst_sdp_message_get_attribute (msg, i);
596 g_string_append_printf (lines, "a=%s", attr->key);
597 if (attr->value && attr->value[0] != '\0')
598 g_string_append_printf (lines, ":%s", attr->value);
599 g_string_append_printf (lines, "\r\n");
603 for (i = 0; i < gst_sdp_message_medias_len (msg); i++) {
604 const GstSDPMedia *media = gst_sdp_message_get_media (msg, i);
605 gchar *sdp_media_str;
607 sdp_media_str = gst_sdp_media_as_text (media);
608 g_string_append_printf (lines, "%s", sdp_media_str);
609 g_free (sdp_media_str);
612 return g_string_free (lines, FALSE);
618 return c >= '0' && c <= '9' ? c - '0'
619 : c >= 'A' && c <= 'F' ? c - 'A' + 10
620 : c >= 'a' && c <= 'f' ? c - 'a' + 10 : 0;
624 * gst_sdp_message_parse_uri:
625 * @uri: the start of the uri
626 * @msg: the result #GstSDPMessage
628 * Parse the null-terminated @uri and store the result in @msg.
630 * The uri should be of the form:
632 * scheme://[address[:ttl=ttl][:noa=noa]]/[sessionname]
633 * [#type=value *[&type=value]]
635 * where value is url encoded. This looslely resembles
636 * http://tools.ietf.org/html/draft-fujikawa-sdp-url-01
638 * Returns: #GST_SDP_OK on success.
641 gst_sdp_message_parse_uri (const gchar * uri, GstSDPMessage * msg)
645 const gchar *colon, *slash, *hash, *p;
648 g_return_val_if_fail (uri != NULL, GST_SDP_EINVAL);
649 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
651 colon = strstr (uri, "://");
655 /* FIXME connection info goes here */
657 slash = strstr (colon + 3, "/");
661 /* FIXME session name goes here */
663 hash = strstr (slash + 1, "#");
667 lines = g_string_new ("");
670 for (p = hash + 1; *p; p++) {
672 g_string_append_printf (lines, "\r\n");
674 g_string_append_c (lines, ' ');
675 else if (*p == '%') {
680 g_string_append_c (lines, (hex_to_int (a) << 4) | hex_to_int (b));
687 g_string_append_c (lines, *p);
690 message = g_string_free (lines, FALSE);
692 gst_sdp_message_parse_buffer ((const guint8 *) message, strlen (message),
701 return GST_SDP_EINVAL;
705 return GST_SDP_EINVAL;
709 return GST_SDP_EINVAL;
713 static const guchar acceptable[96] = {
714 /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */
715 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, /* 2X !"#$%&'()*+,-./ */
716 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3X 0123456789:;<=>? */
717 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 4X @ABCDEFGHIJKLMNO */
718 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, /* 5X PQRSTUVWXYZ[\]^_ */
719 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 6X `abcdefghijklmno */
720 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 /* 7X pqrstuvwxyz{|}~DEL */
723 static const gchar hex[16] = "0123456789ABCDEF";
725 #define ACCEPTABLE_CHAR(a) (((guchar)(a))>=32 && ((guchar)(a))<128 && acceptable[(((guchar)a))-32])
728 * gst_sdp_message_as_uri:
729 * @scheme: the uri scheme
730 * @msg: the #GstSDPMessage
732 * Creates a uri from @msg with the given @scheme. The uri has the format:
734 * \@scheme:///[#type=value *[&type=value]]
736 * Where each value is url encoded.
738 * Returns: a uri for @msg.
741 gst_sdp_message_as_uri (const gchar * scheme, const GstSDPMessage * msg)
743 gchar *serialized, *p;
748 g_return_val_if_fail (scheme != NULL, NULL);
749 g_return_val_if_fail (msg != NULL, NULL);
751 serialized = gst_sdp_message_as_text (msg);
753 lines = g_string_new ("");
754 g_string_append_printf (lines, "%s:///#", scheme);
758 for (p = serialized; *p; p++) {
760 g_string_append_printf (lines, "%c=", *p);
768 else if (*p == '\n') {
770 g_string_append_c (lines, '&');
772 } else if (*p == ' ')
773 g_string_append_c (lines, '+');
774 else if (ACCEPTABLE_CHAR (*p))
775 g_string_append_c (lines, *p);
778 g_string_append_printf (lines, "%%%c%c", hex[*p >> 4], hex[*p & 0xf]);
782 res = g_string_free (lines, FALSE);
789 * gst_sdp_message_set_version:
790 * @msg: a #GstSDPMessage
791 * @version: the version
793 * Set the version in @msg.
795 * Returns: a #GstSDPResult.
797 DEFINE_STRING_SETTER (version);
799 * gst_sdp_message_get_version:
800 * @msg: a #GstSDPMessage
802 * Get the version in @msg.
804 * Returns: a #GstSDPResult.
806 DEFINE_STRING_GETTER (version);
809 * gst_sdp_message_set_origin:
810 * @msg: a #GstSDPMessage
811 * @username: the user name
812 * @sess_id: a session id
813 * @sess_version: a session version
814 * @nettype: a network type
815 * @addrtype: an address type
818 * Configure the SDP origin in @msg with the given parameters.
820 * Returns: #GST_SDP_OK.
823 gst_sdp_message_set_origin (GstSDPMessage * msg, const gchar * username,
824 const gchar * sess_id, const gchar * sess_version, const gchar * nettype,
825 const gchar * addrtype, const gchar * addr)
827 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
829 REPLACE_STRING (msg->origin.username, username);
830 REPLACE_STRING (msg->origin.sess_id, sess_id);
831 REPLACE_STRING (msg->origin.sess_version, sess_version);
832 REPLACE_STRING (msg->origin.nettype, nettype);
833 REPLACE_STRING (msg->origin.addrtype, addrtype);
834 REPLACE_STRING (msg->origin.addr, addr);
840 * gst_sdp_message_get_origin:
841 * @msg: a #GstSDPMessage
843 * Get the origin of @msg.
845 * Returns: a #GstSDPOrigin. The result remains valid as long as @msg is valid.
848 gst_sdp_message_get_origin (const GstSDPMessage * msg)
850 g_return_val_if_fail (msg != NULL, NULL);
856 * gst_sdp_message_set_session_name:
857 * @msg: a #GstSDPMessage
858 * @session_name: the session name
860 * Set the session name in @msg.
862 * Returns: a #GstSDPResult.
864 DEFINE_STRING_SETTER (session_name);
866 * gst_sdp_message_get_session_name:
867 * @msg: a #GstSDPMessage
869 * Get the session name in @msg.
871 * Returns: a #GstSDPResult.
873 DEFINE_STRING_GETTER (session_name);
875 * gst_sdp_message_set_information:
876 * @msg: a #GstSDPMessage
877 * @information: the information
879 * Set the information in @msg.
881 * Returns: a #GstSDPResult.
883 DEFINE_STRING_SETTER (information);
885 * gst_sdp_message_get_information:
886 * @msg: a #GstSDPMessage
888 * Get the information in @msg.
890 * Returns: a #GstSDPResult.
892 DEFINE_STRING_GETTER (information);
894 * gst_sdp_message_set_uri:
895 * @msg: a #GstSDPMessage
898 * Set the URI in @msg.
900 * Returns: a #GstSDPResult.
902 DEFINE_STRING_SETTER (uri);
904 * gst_sdp_message_get_uri:
905 * @msg: a #GstSDPMessage
907 * Get the URI in @msg.
909 * Returns: a #GstSDPResult.
911 DEFINE_STRING_GETTER (uri);
914 * gst_sdp_message_emails_len:
915 * @msg: a #GstSDPMessage
917 * Get the number of emails in @msg.
919 * Returns: the number of emails in @msg.
921 DEFINE_ARRAY_LEN (emails);
923 * gst_sdp_message_get_email:
924 * @msg: a #GstSDPMessage
925 * @idx: an email index
927 * Get the email with number @idx from @msg.
929 * Returns: the email at position @idx.
931 DEFINE_STR_ARRAY_GETTER (email, emails);
934 * gst_sdp_message_insert_email:
935 * @msg: a #GstSDPMessage
939 * Insert @email into the array of emails in @msg at index @idx.
940 * When -1 is given as @idx, the email is inserted at the end.
942 * Returns: a #GstSDPResult.
946 DEFINE_STR_ARRAY_INSERT (email, emails);
949 * gst_sdp_message_replace_email:
950 * @msg: a #GstSDPMessage
951 * @idx: an email index
954 * Replace the email in @msg at index @idx with @email.
956 * Returns: a #GstSDPResult.
960 DEFINE_STR_ARRAY_REPLACE (email, emails);
963 * gst_sdp_message_remove_email:
964 * @msg: a #GstSDPMessage
965 * @idx: an email index
967 * Remove the email in @msg at index @idx.
969 * Returns: a #GstSDPResult.
973 DEFINE_STR_ARRAY_REMOVE (email, emails);
976 * gst_sdp_message_add_email:
977 * @msg: a #GstSDPMessage
980 * Add @email to the list of emails in @msg.
982 * Returns: a #GstSDPResult.
984 DEFINE_STR_ARRAY_ADDER (email, emails);
987 * gst_sdp_message_phones_len:
988 * @msg: a #GstSDPMessage
990 * Get the number of phones in @msg.
992 * Returns: the number of phones in @msg.
994 DEFINE_ARRAY_LEN (phones);
996 * gst_sdp_message_get_phone:
997 * @msg: a #GstSDPMessage
998 * @idx: a phone index
1000 * Get the phone with number @idx from @msg.
1002 * Returns: the phone at position @idx.
1004 DEFINE_STR_ARRAY_GETTER (phone, phones);
1007 * gst_sdp_message_insert_phone:
1008 * @msg: a #GstSDPMessage
1009 * @idx: a phone index
1012 * Insert @phone into the array of phone numbers in @msg at index @idx.
1013 * When -1 is given as @idx, the phone is inserted at the end.
1015 * Returns: a #GstSDPResult.
1019 DEFINE_STR_ARRAY_INSERT (phone, phones);
1022 * gst_sdp_message_replace_phone:
1023 * @msg: a #GstSDPMessage
1024 * @idx: a phone index
1027 * Replace the phone number in @msg at index @idx with @phone.
1029 * Returns: a #GstSDPResult.
1033 DEFINE_STR_ARRAY_REPLACE (phone, phones);
1036 * gst_sdp_message_remove_phone:
1037 * @msg: a #GstSDPMessage
1038 * @idx: a phone index
1040 * Remove the phone number in @msg at index @idx.
1042 * Returns: a #GstSDPResult.
1046 DEFINE_STR_ARRAY_REMOVE (phone, phones);
1049 * gst_sdp_message_add_phone:
1050 * @msg: a #GstSDPMessage
1053 * Add @phone to the list of phones in @msg.
1055 * Returns: a #GstSDPResult.
1057 DEFINE_STR_ARRAY_ADDER (phone, phones);
1061 * gst_sdp_message_set_connection:
1062 * @msg: a #GstSDPMessage
1063 * @nettype: the type of network. "IN" is defined to have the meaning
1065 * @addrtype: the type of address.
1066 * @address: the address
1067 * @ttl: the time to live of the address
1068 * @addr_number: the number of layers
1070 * Configure the SDP connection in @msg with the given parameters.
1072 * Returns: a #GstSDPResult.
1075 gst_sdp_message_set_connection (GstSDPMessage * msg, const gchar * nettype,
1076 const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
1078 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1080 REPLACE_STRING (msg->connection.nettype, nettype);
1081 REPLACE_STRING (msg->connection.addrtype, addrtype);
1082 REPLACE_STRING (msg->connection.address, address);
1083 msg->connection.ttl = ttl;
1084 msg->connection.addr_number = addr_number;
1090 * gst_sdp_message_get_connection:
1091 * @msg: a #GstSDPMessage
1093 * Get the connection of @msg.
1095 * Returns: a #GstSDPConnection. The result remains valid as long as @msg is valid.
1097 const GstSDPConnection *
1098 gst_sdp_message_get_connection (const GstSDPMessage * msg)
1100 g_return_val_if_fail (msg != NULL, NULL);
1102 return &msg->connection;
1106 * gst_sdp_bandwidth_set:
1107 * @bw: a #GstSDPBandwidth
1108 * @bwtype: the bandwidth modifier type
1109 * @bandwidth: the bandwidth in kilobits per second
1111 * Set bandwidth information in @bw.
1113 * Returns: a #GstSDPResult.
1118 gst_sdp_bandwidth_set (GstSDPBandwidth * bw, const gchar * bwtype,
1121 g_return_val_if_fail (bw != NULL, GST_SDP_EINVAL);
1123 bw->bwtype = g_strdup (bwtype);
1124 bw->bandwidth = bandwidth;
1129 * gst_sdp_bandwidth_clear:
1130 * @bw: a #GstSDPBandwidth
1132 * Reset the bandwidth information in @bw.
1134 * Returns: a #GstSDPResult.
1139 gst_sdp_bandwidth_clear (GstSDPBandwidth * bw)
1141 g_return_val_if_fail (bw != NULL, GST_SDP_EINVAL);
1143 FREE_STRING (bw->bwtype);
1149 * gst_sdp_message_bandwidths_len:
1150 * @msg: a #GstSDPMessage
1152 * Get the number of bandwidth information in @msg.
1154 * Returns: the number of bandwidth information in @msg.
1156 DEFINE_ARRAY_LEN (bandwidths);
1158 * gst_sdp_message_get_bandwidth:
1159 * @msg: a #GstSDPMessage
1160 * @idx: the bandwidth index
1162 * Get the bandwidth at index @idx from @msg.
1164 * Returns: a #GstSDPBandwidth.
1166 DEFINE_ARRAY_GETTER (bandwidth, bandwidths, GstSDPBandwidth);
1168 #define DUP_BANDWIDTH(v, val) memcpy (v, val, sizeof (GstSDPBandwidth))
1169 #define FREE_BANDWIDTH(v) gst_sdp_bandwidth_clear(v)
1172 * gst_sdp_message_insert_bandwidth:
1173 * @msg: a #GstSDPMessage
1175 * @bw: the bandwidth
1177 * Insert bandwidth parameters into the array of bandwidths in @msg
1179 * When -1 is given as @idx, the bandwidth is inserted at the end.
1181 * Returns: a #GstSDPResult.
1185 DEFINE_ARRAY_INSERT (bandwidth, bandwidths, GstSDPBandwidth *, DUP_BANDWIDTH,
1189 * gst_sdp_message_replace_bandwidth:
1190 * @msg: a #GstSDPMessage
1191 * @idx: the bandwidth index
1192 * @bw: the bandwidth
1194 * Replace the bandwidth information in @msg at index @idx with @bw.
1196 * Returns: a #GstSDPResult.
1200 DEFINE_ARRAY_REPLACE (bandwidth, bandwidths, GstSDPBandwidth *, FREE_BANDWIDTH,
1201 DUP_BANDWIDTH, GstSDPBandwidth);
1204 * gst_sdp_message_remove_bandwidth:
1205 * @msg: a #GstSDPMessage
1206 * @idx: the bandwidth index
1208 * Remove the bandwidth information in @msg at index @idx.
1210 * Returns: a #GstSDPResult.
1214 DEFINE_ARRAY_REMOVE (bandwidth, bandwidths, GstSDPBandwidth, FREE_BANDWIDTH);
1217 * gst_sdp_message_add_bandwidth:
1218 * @msg: a #GstSDPMessage
1219 * @bwtype: the bandwidth modifier type
1220 * @bandwidth: the bandwidth in kilobits per second
1222 * Add the specified bandwidth information to @msg.
1224 * Returns: a #GstSDPResult.
1227 gst_sdp_message_add_bandwidth (GstSDPMessage * msg, const gchar * bwtype,
1232 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1234 gst_sdp_bandwidth_set (&bw, bwtype, bandwidth);
1235 return gst_sdp_message_insert_bandwidth (msg, -1, &bw);
1241 * @start: the start time
1242 * @stop: the stop time
1243 * @repeat: (array zero-terminated=1): the repeat times
1245 * Set time information @start, @stop and @repeat in @t.
1247 * Returns: a #GstSDPResult.
1252 gst_sdp_time_set (GstSDPTime * t, const gchar * start,
1253 const gchar * stop, const gchar ** repeat)
1255 g_return_val_if_fail (t != NULL, GST_SDP_EINVAL);
1257 t->start = g_strdup (start);
1258 t->stop = g_strdup (stop);
1260 t->repeat = g_array_new (FALSE, TRUE, sizeof (gchar *));
1261 for (; *repeat; repeat++) {
1262 gchar *r = g_strdup (*repeat);
1264 g_array_append_val (t->repeat, r);
1273 * gst_sdp_time_clear:
1276 * Reset the time information in @t.
1278 * Returns: a #GstSDPResult.
1283 gst_sdp_time_clear (GstSDPTime * t)
1285 g_return_val_if_fail (t != NULL, GST_SDP_EINVAL);
1287 FREE_STRING (t->start);
1288 FREE_STRING (t->stop);
1289 INIT_STR_ARRAY (t->repeat);
1290 FREE_ARRAY (t->repeat);
1296 * gst_sdp_message_times_len:
1297 * @msg: a #GstSDPMessage
1299 * Get the number of time information entries in @msg.
1301 * Returns: the number of time information entries in @msg.
1303 DEFINE_ARRAY_LEN (times);
1306 * gst_sdp_message_get_time:
1307 * @msg: a #GstSDPMessage
1308 * @idx: the time index
1310 * Get time information with index @idx from @msg.
1312 * Returns: a #GstSDPTime.
1314 DEFINE_ARRAY_GETTER (time, times, GstSDPTime);
1316 #define DUP_TIME(v, val) memcpy (v, val, sizeof (GstSDPTime))
1317 #define FREE_TIME(v) gst_sdp_time_clear(v)
1320 * gst_sdp_message_insert_time:
1321 * @msg: a #GstSDPMessage
1325 * Insert time parameters into the array of times in @msg
1327 * When -1 is given as @idx, the times are inserted at the end.
1329 * Returns: a #GstSDPResult.
1333 DEFINE_ARRAY_INSERT (time, times, GstSDPTime *, DUP_TIME, GstSDPTime);
1336 * gst_sdp_message_replace_time:
1337 * @msg: a #GstSDPMessage
1341 * Replace the time information in @msg at index @idx with @t.
1343 * Returns: a #GstSDPResult.
1347 DEFINE_ARRAY_REPLACE (time, times, GstSDPTime *, FREE_TIME,
1348 DUP_TIME, GstSDPTime);
1351 * gst_sdp_message_remove_time:
1352 * @msg: a #GstSDPMessage
1355 * Remove the time information in @msg at index @idx.
1357 * Returns: a #GstSDPResult.
1361 DEFINE_ARRAY_REMOVE (time, times, GstSDPTime, FREE_TIME);
1364 * gst_sdp_message_add_time:
1365 * @msg: a #GstSDPMessage
1366 * @start: the start time
1367 * @stop: the stop time
1368 * @repeat: (array zero-terminated=1): the repeat times
1370 * Add time information @start and @stop to @msg.
1372 * Returns: a #GstSDPResult.
1375 gst_sdp_message_add_time (GstSDPMessage * msg, const gchar * start,
1376 const gchar * stop, const gchar ** repeat)
1380 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1382 gst_sdp_time_set (×, start, stop, repeat);
1383 g_array_append_val (msg->times, times);
1390 * @zone: a #GstSDPZone
1391 * @adj_time: the NTP time that a time zone adjustment happens
1392 * @typed_time: the offset from the time when the session was first scheduled
1394 * Set zone information in @zone.
1396 * Returns: a #GstSDPResult.
1401 gst_sdp_zone_set (GstSDPZone * zone, const gchar * adj_time,
1402 const gchar * typed_time)
1404 g_return_val_if_fail (zone != NULL, GST_SDP_EINVAL);
1406 zone->time = g_strdup (adj_time);
1407 zone->typed_time = g_strdup (typed_time);
1412 * gst_sdp_zone_clear:
1413 * @zone: a #GstSDPZone
1415 * Reset the zone information in @zone.
1417 * Returns: a #GstSDPResult.
1422 gst_sdp_zone_clear (GstSDPZone * zone)
1424 g_return_val_if_fail (zone != NULL, GST_SDP_EINVAL);
1426 FREE_STRING (zone->time);
1427 FREE_STRING (zone->typed_time);
1432 * gst_sdp_message_zones_len:
1433 * @msg: a #GstSDPMessage
1435 * Get the number of time zone information entries in @msg.
1437 * Returns: the number of time zone information entries in @msg.
1439 DEFINE_ARRAY_LEN (zones);
1441 * gst_sdp_message_get_zone:
1442 * @msg: a #GstSDPMessage
1443 * @idx: the zone index
1445 * Get time zone information with index @idx from @msg.
1447 * Returns: a #GstSDPZone.
1449 DEFINE_ARRAY_GETTER (zone, zones, GstSDPZone);
1451 #define DUP_ZONE(v, val) memcpy (v, val, sizeof (GstSDPZone))
1452 #define FREE_ZONE(v) gst_sdp_zone_clear(v)
1455 * gst_sdp_message_insert_zone:
1456 * @msg: a #GstSDPMessage
1458 * @zone: a #GstSDPZone
1460 * Insert zone parameters into the array of zones in @msg
1462 * When -1 is given as @idx, the zone is inserted at the end.
1464 * Returns: a #GstSDPResult.
1468 DEFINE_ARRAY_INSERT (zone, zones, GstSDPZone *, DUP_ZONE, GstSDPZone);
1471 * gst_sdp_message_replace_zone:
1472 * @msg: a #GstSDPMessage
1474 * @zone: a #GstSDPZone
1476 * Replace the zone information in @msg at index @idx with @zone.
1478 * Returns: a #GstSDPResult.
1482 DEFINE_ARRAY_REPLACE (zone, zones, GstSDPZone *, FREE_ZONE,
1483 DUP_ZONE, GstSDPZone);
1486 * gst_sdp_message_remove_zone:
1487 * @msg: a #GstSDPMessage
1490 * Remove the zone information in @msg at index @idx.
1492 * Returns: a #GstSDPResult.
1496 DEFINE_ARRAY_REMOVE (zone, zones, GstSDPZone, FREE_ZONE);
1499 * gst_sdp_message_add_zone:
1500 * @msg: a #GstSDPMessage
1501 * @adj_time: the NTP time that a time zone adjustment happens
1502 * @typed_time: the offset from the time when the session was first scheduled
1504 * Add time zone information to @msg.
1506 * Returns: a #GstSDPResult.
1509 gst_sdp_message_add_zone (GstSDPMessage * msg, const gchar * adj_time,
1510 const gchar * typed_time)
1514 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1516 gst_sdp_zone_set (&zone, adj_time, typed_time);
1517 g_array_append_val (msg->zones, zone);
1523 * gst_sdp_message_set_key:
1524 * @msg: a #GstSDPMessage
1525 * @type: the encryption type
1526 * @data: the encryption data
1528 * Adds the encryption information to @msg.
1530 * Returns: a #GstSDPResult.
1533 gst_sdp_message_set_key (GstSDPMessage * msg, const gchar * type,
1536 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1538 REPLACE_STRING (msg->key.type, type);
1539 REPLACE_STRING (msg->key.data, data);
1545 * gst_sdp_message_get_key:
1546 * @msg: a #GstSDPMessage
1548 * Get the encryption information from @msg.
1550 * Returns: a #GstSDPKey.
1553 gst_sdp_message_get_key (const GstSDPMessage * msg)
1555 g_return_val_if_fail (msg != NULL, NULL);
1561 * gst_sdp_attribute_set:
1562 * @attr: a #GstSDPAttribute
1564 * @value: (nullable): the value
1566 * Set the attribute with @key and @value.
1568 * Returns: @GST_SDP_OK.
1573 gst_sdp_attribute_set (GstSDPAttribute * attr, const gchar * key,
1574 const gchar * value)
1576 g_return_val_if_fail (attr != NULL, GST_SDP_EINVAL);
1577 g_return_val_if_fail (key != NULL, GST_SDP_EINVAL);
1579 attr->key = g_strdup (key);
1580 attr->value = g_strdup (value);
1585 * gst_sdp_attribute_clear:
1586 * @attr: a #GstSDPAttribute
1588 * Clear the attribute.
1590 * Returns: @GST_SDP_OK.
1595 gst_sdp_attribute_clear (GstSDPAttribute * attr)
1597 g_return_val_if_fail (attr != NULL, GST_SDP_EINVAL);
1599 FREE_STRING (attr->key);
1600 FREE_STRING (attr->value);
1605 * gst_sdp_message_attributes_len:
1606 * @msg: a #GstSDPMessage
1608 * Get the number of attributes in @msg.
1610 * Returns: the number of attributes in @msg.
1612 DEFINE_ARRAY_LEN (attributes);
1615 * gst_sdp_message_get_attribute:
1616 * @msg: a #GstSDPMessage
1619 * Get the attribute at position @idx in @msg.
1621 * Returns: the #GstSDPAttribute at position @idx.
1623 DEFINE_ARRAY_GETTER (attribute, attributes, GstSDPAttribute);
1626 * gst_sdp_message_get_attribute_val_n:
1627 * @msg: a #GstSDPMessage
1631 * Get the @nth attribute with key @key in @msg.
1633 * Returns: the attribute value of the @nth attribute with @key.
1636 gst_sdp_message_get_attribute_val_n (const GstSDPMessage * msg,
1637 const gchar * key, guint nth)
1641 g_return_val_if_fail (msg != NULL, NULL);
1642 g_return_val_if_fail (key != NULL, NULL);
1644 for (i = 0; i < msg->attributes->len; i++) {
1645 GstSDPAttribute *attr;
1647 attr = &g_array_index (msg->attributes, GstSDPAttribute, i);
1648 if (!strcmp (attr->key, key)) {
1659 * gst_sdp_message_get_attribute_val:
1660 * @msg: a #GstSDPMessage
1663 * Get the first attribute with key @key in @msg.
1665 * Returns: the attribute value of the first attribute with @key.
1668 gst_sdp_message_get_attribute_val (const GstSDPMessage * msg, const gchar * key)
1670 return gst_sdp_message_get_attribute_val_n (msg, key, 0);
1673 #define DUP_ATTRIBUTE(v, val) memcpy (v, val, sizeof (GstSDPAttribute))
1674 #define FREE_ATTRIBUTE(v) gst_sdp_attribute_clear(v)
1677 * gst_sdp_message_insert_attribute:
1678 * @msg: a #GstSDPMessage
1680 * @attr: a #GstSDPAttribute
1682 * Insert attribute into the array of attributes in @msg
1684 * When -1 is given as @idx, the attribute is inserted at the end.
1686 * Returns: a #GstSDPResult.
1690 DEFINE_ARRAY_INSERT (attribute, attributes, GstSDPAttribute *, DUP_ATTRIBUTE,
1694 * gst_sdp_message_replace_attribute:
1695 * @msg: a #GstSDPMessage
1697 * @attr: a #GstSDPAttribute
1699 * Replace the attribute in @msg at index @idx with @attr.
1701 * Returns: a #GstSDPResult.
1705 DEFINE_ARRAY_REPLACE (attribute, attributes, GstSDPAttribute *, FREE_ATTRIBUTE,
1706 DUP_ATTRIBUTE, GstSDPAttribute);
1709 * gst_sdp_message_remove_attribute:
1710 * @msg: a #GstSDPMessage
1713 * Remove the attribute in @msg at index @idx.
1715 * Returns: a #GstSDPResult.
1719 DEFINE_ARRAY_REMOVE (attribute, attributes, GstSDPAttribute, FREE_ATTRIBUTE);
1722 * gst_sdp_message_add_attribute:
1723 * @msg: a #GstSDPMessage
1725 * @value: (nullable): the value
1727 * Add the attribute with @key and @value to @msg.
1729 * Returns: @GST_SDP_OK.
1732 gst_sdp_message_add_attribute (GstSDPMessage * msg, const gchar * key,
1733 const gchar * value)
1735 GstSDPAttribute attr;
1737 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1738 g_return_val_if_fail (key != NULL, GST_SDP_EINVAL);
1740 gst_sdp_attribute_set (&attr, key, value);
1741 g_array_append_val (msg->attributes, attr);
1747 * gst_sdp_message_medias_len:
1748 * @msg: a #GstSDPMessage
1750 * Get the number of media descriptions in @msg.
1752 * Returns: the number of media descriptions in @msg.
1754 DEFINE_ARRAY_LEN (medias);
1756 * gst_sdp_message_get_media:
1757 * @msg: a #GstSDPMessage
1760 * Get the media description at index @idx in @msg.
1762 * Returns: a #GstSDPMedia.
1764 DEFINE_ARRAY_GETTER (media, medias, GstSDPMedia);
1767 * gst_sdp_message_add_media:
1768 * @msg: a #GstSDPMessage
1769 * @media: a #GstSDPMedia to add
1771 * Adds @media to the array of medias in @msg. This function takes ownership of
1772 * the contents of @media so that @media will have to be reinitialized with
1773 * gst_sdp_media_init() before it can be used again.
1775 * Returns: a #GstSDPResult.
1778 gst_sdp_message_add_media (GstSDPMessage * msg, GstSDPMedia * media)
1781 GstSDPMedia *nmedia;
1783 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1784 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1786 len = msg->medias->len;
1787 g_array_set_size (msg->medias, len + 1);
1788 nmedia = &g_array_index (msg->medias, GstSDPMedia, len);
1790 memcpy (nmedia, media, sizeof (GstSDPMedia));
1791 memset (media, 0, sizeof (GstSDPMedia));
1799 * gst_sdp_media_new:
1800 * @media: (out) (transfer full): pointer to new #GstSDPMedia
1802 * Allocate a new GstSDPMedia and store the result in @media.
1804 * Returns: a #GstSDPResult.
1807 gst_sdp_media_new (GstSDPMedia ** media)
1809 GstSDPMedia *newmedia;
1811 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1813 newmedia = g_new0 (GstSDPMedia, 1);
1817 return gst_sdp_media_init (newmedia);
1821 * gst_sdp_media_init:
1822 * @media: a #GstSDPMedia
1824 * Initialize @media so that its contents are as if it was freshly allocated
1825 * with gst_sdp_media_new(). This function is mostly used to initialize a media
1826 * allocated on the stack. gst_sdp_media_uninit() undoes this operation.
1828 * When this function is invoked on newly allocated data (with malloc or on the
1829 * stack), its contents should be set to 0 before calling this function.
1831 * Returns: a #GstSDPResult.
1834 gst_sdp_media_init (GstSDPMedia * media)
1836 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1838 FREE_STRING (media->media);
1840 media->num_ports = 0;
1841 FREE_STRING (media->proto);
1842 INIT_STR_ARRAY (media->fmts);
1843 FREE_STRING (media->information);
1844 INIT_ARRAY (media->connections, GstSDPConnection, gst_sdp_connection_clear);
1845 INIT_ARRAY (media->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_clear);
1846 gst_sdp_key_init (&media->key);
1847 INIT_ARRAY (media->attributes, GstSDPAttribute, gst_sdp_attribute_clear);
1853 * gst_sdp_media_uninit:
1854 * @media: a #GstSDPMedia
1856 * Free all resources allocated in @media. @media should not be used anymore after
1857 * this function. This function should be used when @media was allocated on the
1858 * stack and initialized with gst_sdp_media_init().
1860 * Returns: a #GstSDPResult.
1863 gst_sdp_media_uninit (GstSDPMedia * media)
1865 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1867 gst_sdp_media_init (media);
1868 FREE_ARRAY (media->fmts);
1869 FREE_ARRAY (media->connections);
1870 FREE_ARRAY (media->bandwidths);
1871 FREE_ARRAY (media->attributes);
1877 * gst_sdp_media_free:
1878 * @media: a #GstSDPMedia
1880 * Free all resources allocated by @media. @media should not be used anymore after
1881 * this function. This function should be used when @media was dynamically
1882 * allocated with gst_sdp_media_new().
1884 * Returns: a #GstSDPResult.
1887 gst_sdp_media_free (GstSDPMedia * media)
1889 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1891 gst_sdp_media_uninit (media);
1898 * gst_sdp_media_copy:
1899 * @media: a #GstSDPMedia
1900 * @copy: (out) (transfer full): pointer to new #GstSDPMedia
1902 * Allocate a new copy of @media and store the result in @copy. The value in
1903 * @copy should be release with gst_sdp_media_free function.
1905 * Returns: a #GstSDPResult
1910 gst_sdp_media_copy (const GstSDPMedia * media, GstSDPMedia ** copy)
1917 return GST_SDP_EINVAL;
1919 ret = gst_sdp_media_new (copy);
1920 if (ret != GST_SDP_OK)
1925 REPLACE_STRING (cp->media, media->media);
1926 cp->port = media->port;
1927 cp->num_ports = media->num_ports;
1928 REPLACE_STRING (cp->proto, media->proto);
1930 len = gst_sdp_media_formats_len (media);
1931 for (i = 0; i < len; i++) {
1932 gst_sdp_media_add_format (cp, gst_sdp_media_get_format (media, i));
1935 REPLACE_STRING (cp->information, media->information);
1937 len = gst_sdp_media_connections_len (media);
1938 for (i = 0; i < len; i++) {
1939 const GstSDPConnection *connection =
1940 gst_sdp_media_get_connection (media, i);
1941 gst_sdp_media_add_connection (cp, connection->nettype, connection->addrtype,
1942 connection->address, connection->ttl, connection->addr_number);
1945 len = gst_sdp_media_bandwidths_len (media);
1946 for (i = 0; i < len; i++) {
1947 const GstSDPBandwidth *bw = gst_sdp_media_get_bandwidth (media, i);
1948 gst_sdp_media_add_bandwidth (cp, bw->bwtype, bw->bandwidth);
1951 gst_sdp_media_set_key (cp, media->key.type, media->key.data);
1953 len = gst_sdp_media_attributes_len (media);
1954 for (i = 0; i < len; i++) {
1955 const GstSDPAttribute *att = gst_sdp_media_get_attribute (media, i);
1956 gst_sdp_media_add_attribute (cp, att->key, att->value);
1963 * gst_sdp_media_as_text:
1964 * @media: a #GstSDPMedia
1966 * Convert the contents of @media to a text string.
1968 * Returns: A dynamically allocated string representing the media.
1971 gst_sdp_media_as_text (const GstSDPMedia * media)
1976 g_return_val_if_fail (media != NULL, NULL);
1978 lines = g_string_new ("");
1981 g_string_append_printf (lines, "m=%s", media->media);
1983 g_string_append_printf (lines, " %u", media->port);
1985 if (media->num_ports > 1)
1986 g_string_append_printf (lines, "/%u", media->num_ports);
1988 g_string_append_printf (lines, " %s", media->proto);
1990 for (i = 0; i < gst_sdp_media_formats_len (media); i++)
1991 g_string_append_printf (lines, " %s", gst_sdp_media_get_format (media, i));
1992 g_string_append_printf (lines, "\r\n");
1994 if (media->information)
1995 g_string_append_printf (lines, "i=%s", media->information);
1997 for (i = 0; i < gst_sdp_media_connections_len (media); i++) {
1998 const GstSDPConnection *conn = gst_sdp_media_get_connection (media, i);
2000 if (conn->nettype && conn->addrtype && conn->address) {
2001 g_string_append_printf (lines, "c=%s %s %s", conn->nettype,
2002 conn->addrtype, conn->address);
2003 if (gst_sdp_address_is_multicast (conn->nettype, conn->addrtype,
2005 /* only add TTL for IP4 multicast */
2006 if (strcmp (conn->addrtype, "IP4") == 0)
2007 g_string_append_printf (lines, "/%u", conn->ttl);
2008 if (conn->addr_number > 1)
2009 g_string_append_printf (lines, "/%u", conn->addr_number);
2011 g_string_append_printf (lines, "\r\n");
2015 for (i = 0; i < gst_sdp_media_bandwidths_len (media); i++) {
2016 const GstSDPBandwidth *bandwidth = gst_sdp_media_get_bandwidth (media, i);
2018 g_string_append_printf (lines, "b=%s:%u\r\n", bandwidth->bwtype,
2019 bandwidth->bandwidth);
2022 if (media->key.type) {
2023 g_string_append_printf (lines, "k=%s", media->key.type);
2024 if (media->key.data)
2025 g_string_append_printf (lines, ":%s", media->key.data);
2026 g_string_append_printf (lines, "\r\n");
2029 for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
2030 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
2033 g_string_append_printf (lines, "a=%s", attr->key);
2034 if (attr->value && attr->value[0] != '\0')
2035 g_string_append_printf (lines, ":%s", attr->value);
2036 g_string_append_printf (lines, "\r\n");
2040 return g_string_free (lines, FALSE);
2044 * gst_sdp_media_get_media:
2045 * @media: a #GstSDPMedia
2047 * Get the media description of @media.
2049 * Returns: the media description.
2052 gst_sdp_media_get_media (const GstSDPMedia * media)
2054 g_return_val_if_fail (media != NULL, NULL);
2056 return media->media;
2060 * gst_sdp_media_set_media:
2061 * @media: a #GstSDPMedia
2062 * @med: the media description
2064 * Set the media description of @media to @med.
2066 * Returns: #GST_SDP_OK.
2069 gst_sdp_media_set_media (GstSDPMedia * media, const gchar * med)
2071 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2072 g_return_val_if_fail (med != NULL, GST_SDP_EINVAL);
2074 g_free (media->media);
2075 media->media = g_strdup (med);
2081 * gst_sdp_media_get_port:
2082 * @media: a #GstSDPMedia
2084 * Get the port number for @media.
2086 * Returns: the port number of @media.
2089 gst_sdp_media_get_port (const GstSDPMedia * media)
2091 g_return_val_if_fail (media != NULL, 0);
2097 * gst_sdp_media_get_num_ports:
2098 * @media: a #GstSDPMedia
2100 * Get the number of ports for @media.
2102 * Returns: the number of ports for @media.
2105 gst_sdp_media_get_num_ports (const GstSDPMedia * media)
2107 g_return_val_if_fail (media != NULL, 0);
2109 return media->num_ports;
2113 * gst_sdp_media_set_port_info:
2114 * @media: a #GstSDPMedia
2115 * @port: the port number
2116 * @num_ports: the number of ports
2118 * Set the port information in @media.
2120 * Returns: #GST_SDP_OK.
2123 gst_sdp_media_set_port_info (GstSDPMedia * media, guint port, guint num_ports)
2125 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2128 media->num_ports = num_ports;
2134 * gst_sdp_media_get_proto:
2135 * @media: a #GstSDPMedia
2137 * Get the transport protocol of @media
2139 * Returns: the transport protocol of @media.
2142 gst_sdp_media_get_proto (const GstSDPMedia * media)
2144 g_return_val_if_fail (media != NULL, NULL);
2146 return media->proto;
2150 * gst_sdp_media_set_proto:
2151 * @media: a #GstSDPMedia
2152 * @proto: the media transport protocol
2154 * Set the media transport protocol of @media to @proto.
2156 * Returns: #GST_SDP_OK.
2159 gst_sdp_media_set_proto (GstSDPMedia * media, const gchar * proto)
2161 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2163 g_free (media->proto);
2164 media->proto = g_strdup (proto);
2170 * gst_sdp_media_formats_len:
2171 * @media: a #GstSDPMedia
2173 * Get the number of formats in @media.
2175 * Returns: the number of formats in @media.
2178 gst_sdp_media_formats_len (const GstSDPMedia * media)
2180 g_return_val_if_fail (media != NULL, 0);
2182 return media->fmts->len;
2186 * gst_sdp_media_get_format:
2187 * @media: a #GstSDPMedia
2190 * Get the format information at position @idx in @media.
2192 * Returns: the format at position @idx.
2195 gst_sdp_media_get_format (const GstSDPMedia * media, guint idx)
2197 g_return_val_if_fail (media != NULL, NULL);
2199 if (idx >= media->fmts->len)
2201 return g_array_index (media->fmts, gchar *, idx);
2205 * gst_sdp_media_insert_format:
2206 * @media: a #GstSDPMedia
2208 * @format: the format
2210 * Insert the format information to @media at @idx. When @idx is -1,
2211 * the format is appended.
2213 * Returns: #GST_SDP_OK.
2218 gst_sdp_media_insert_format (GstSDPMedia * media, gint idx,
2219 const gchar * format)
2223 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2224 g_return_val_if_fail (format != NULL, GST_SDP_EINVAL);
2226 fmt = g_strdup (format);
2229 g_array_append_val (media->fmts, fmt);
2231 g_array_insert_val (media->fmts, idx, fmt);
2237 * gst_sdp_media_replace_format:
2238 * @media: a #GstSDPMedia
2240 * @format: the format
2242 * Replace the format information in @media at @idx with @format.
2244 * Returns: #GST_SDP_OK.
2249 gst_sdp_media_replace_format (GstSDPMedia * media, guint idx,
2250 const gchar * format)
2254 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2255 g_return_val_if_fail (format != NULL, GST_SDP_EINVAL);
2257 old = &g_array_index (media->fmts, gchar *, idx);
2259 *old = g_strdup (format);
2265 * gst_sdp_media_remove_format:
2266 * @media: a #GstSDPMedia
2269 * Remove the format information in @media at @idx.
2271 * Returns: #GST_SDP_OK.
2276 gst_sdp_media_remove_format (GstSDPMedia * media, guint idx)
2280 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2282 old = &g_array_index (media->fmts, gchar *, idx);
2284 g_array_remove_index (media->fmts, idx);
2290 * gst_sdp_media_add_format:
2291 * @media: a #GstSDPMedia
2292 * @format: the format
2294 * Add the format information to @media.
2296 * Returns: #GST_SDP_OK.
2299 gst_sdp_media_add_format (GstSDPMedia * media, const gchar * format)
2303 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2304 g_return_val_if_fail (format != NULL, GST_SDP_EINVAL);
2306 fmt = g_strdup (format);
2308 g_array_append_val (media->fmts, fmt);
2314 * gst_sdp_media_get_information:
2315 * @media: a #GstSDPMedia
2317 * Get the information of @media
2319 * Returns: the information of @media.
2322 gst_sdp_media_get_information (const GstSDPMedia * media)
2324 g_return_val_if_fail (media != NULL, NULL);
2326 return media->information;
2330 * gst_sdp_media_set_information:
2331 * @media: a #GstSDPMedia
2332 * @information: the media information
2334 * Set the media information of @media to @information.
2336 * Returns: #GST_SDP_OK.
2339 gst_sdp_media_set_information (GstSDPMedia * media, const gchar * information)
2341 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2343 g_free (media->information);
2344 media->information = g_strdup (information);
2350 * gst_sdp_connection_set:
2351 * @conn: a #GstSDPConnection
2352 * @nettype: the type of network. "IN" is defined to have the meaning
2354 * @addrtype: the type of address.
2355 * @address: the address
2356 * @ttl: the time to live of the address
2357 * @addr_number: the number of layers
2359 * Set the connection with the given parameters.
2361 * Returns: @GST_SDP_OK.
2366 gst_sdp_connection_set (GstSDPConnection * conn, const gchar * nettype,
2367 const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
2369 g_return_val_if_fail (conn != NULL, GST_SDP_EINVAL);
2370 g_return_val_if_fail (nettype != NULL, GST_SDP_EINVAL);
2371 g_return_val_if_fail (addrtype != NULL, GST_SDP_EINVAL);
2372 g_return_val_if_fail (address != NULL, GST_SDP_EINVAL);
2374 conn->nettype = g_strdup (nettype);
2375 conn->addrtype = g_strdup (addrtype);
2376 conn->address = g_strdup (address);
2378 conn->addr_number = addr_number;
2383 * gst_sdp_connection_clear:
2384 * @conn: a #GstSDPConnection
2386 * Clear the connection.
2388 * Returns: @GST_SDP_OK.
2393 gst_sdp_connection_clear (GstSDPConnection * conn)
2395 g_return_val_if_fail (conn != NULL, GST_SDP_EINVAL);
2397 FREE_STRING (conn->nettype);
2398 FREE_STRING (conn->addrtype);
2399 FREE_STRING (conn->address);
2401 conn->addr_number = 0;
2407 * gst_sdp_media_connections_len:
2408 * @media: a #GstSDPMedia
2410 * Get the number of connection fields in @media.
2412 * Returns: the number of connections in @media.
2415 gst_sdp_media_connections_len (const GstSDPMedia * media)
2417 g_return_val_if_fail (media != NULL, 0);
2419 return media->connections->len;
2423 * gst_sdp_media_get_connection:
2424 * @media: a #GstSDPMedia
2427 * Get the connection at position @idx in @media.
2429 * Returns: the #GstSDPConnection at position @idx.
2431 const GstSDPConnection *
2432 gst_sdp_media_get_connection (const GstSDPMedia * media, guint idx)
2434 g_return_val_if_fail (media != NULL, NULL);
2435 g_return_val_if_fail (idx < media->connections->len, NULL);
2437 return &g_array_index (media->connections, GstSDPConnection, idx);
2441 * gst_sdp_media_insert_connection:
2442 * @media: a #GstSDPMedia
2444 * @conn: a #GstSDPConnection
2446 * Insert the connection information to @media at @idx. When @idx is -1,
2447 * the connection is appended.
2449 * Returns: #GST_SDP_OK.
2454 gst_sdp_media_insert_connection (GstSDPMedia * media, gint idx,
2455 GstSDPConnection * conn)
2457 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2458 g_return_val_if_fail (conn != NULL, GST_SDP_EINVAL);
2459 g_return_val_if_fail (idx == -1
2460 || idx < media->connections->len, GST_SDP_EINVAL);
2463 g_array_append_val (media->connections, *conn);
2465 g_array_insert_val (media->connections, idx, *conn);
2471 * gst_sdp_media_replace_connection:
2472 * @media: a #GstSDPMedia
2474 * @conn: a #GstSDPConnection
2476 * Replace the connection information in @media at @idx with @conn.
2478 * Returns: #GST_SDP_OK.
2483 gst_sdp_media_replace_connection (GstSDPMedia * media, guint idx,
2484 GstSDPConnection * conn)
2486 GstSDPConnection *old;
2488 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2489 g_return_val_if_fail (conn != NULL, GST_SDP_EINVAL);
2490 g_return_val_if_fail (idx < media->connections->len, GST_SDP_EINVAL);
2492 old = &g_array_index (media->connections, GstSDPConnection, idx);
2493 gst_sdp_connection_clear (old);
2500 * gst_sdp_media_remove_connection:
2501 * @media: a #GstSDPMedia
2504 * Remove the connection information in @media at @idx.
2506 * Returns: #GST_SDP_OK.
2511 gst_sdp_media_remove_connection (GstSDPMedia * media, guint idx)
2513 GstSDPConnection *old;
2515 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2516 g_return_val_if_fail (idx < media->connections->len, GST_SDP_EINVAL);
2518 old = &g_array_index (media->connections, GstSDPConnection, idx);
2519 gst_sdp_connection_clear (old);
2520 g_array_remove_index (media->connections, idx);
2526 * gst_sdp_media_add_connection:
2527 * @media: a #GstSDPMedia
2528 * @nettype: the type of network. "IN" is defined to have the meaning
2530 * @addrtype: the type of address.
2531 * @address: the address
2532 * @ttl: the time to live of the address
2533 * @addr_number: the number of layers
2535 * Add the given connection parameters to @media.
2537 * Returns: a #GstSDPResult.
2540 gst_sdp_media_add_connection (GstSDPMedia * media, const gchar * nettype,
2541 const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
2543 GstSDPConnection conn;
2545 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2546 g_return_val_if_fail (nettype != NULL, GST_SDP_EINVAL);
2547 g_return_val_if_fail (addrtype != NULL, GST_SDP_EINVAL);
2548 g_return_val_if_fail (address != NULL, GST_SDP_EINVAL);
2550 gst_sdp_connection_set (&conn, nettype, addrtype, address, ttl, addr_number);
2551 g_array_append_val (media->connections, conn);
2557 * gst_sdp_media_bandwidths_len:
2558 * @media: a #GstSDPMedia
2560 * Get the number of bandwidth fields in @media.
2562 * Returns: the number of bandwidths in @media.
2565 gst_sdp_media_bandwidths_len (const GstSDPMedia * media)
2567 g_return_val_if_fail (media != NULL, 0);
2569 return media->bandwidths->len;
2573 * gst_sdp_media_get_bandwidth:
2574 * @media: a #GstSDPMedia
2577 * Get the bandwidth at position @idx in @media.
2579 * Returns: the #GstSDPBandwidth at position @idx.
2581 const GstSDPBandwidth *
2582 gst_sdp_media_get_bandwidth (const GstSDPMedia * media, guint idx)
2584 g_return_val_if_fail (media != NULL, NULL);
2586 return &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
2590 * gst_sdp_media_insert_bandwidth:
2591 * @media: a #GstSDPMedia
2593 * @bw: a #GstSDPBandwidth
2595 * Insert the bandwidth information to @media at @idx. When @idx is -1,
2596 * the bandwidth is appended.
2598 * Returns: #GST_SDP_OK.
2603 gst_sdp_media_insert_bandwidth (GstSDPMedia * media, gint idx,
2604 GstSDPBandwidth * bw)
2606 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2607 g_return_val_if_fail (bw != NULL, GST_SDP_EINVAL);
2608 g_return_val_if_fail (idx == -1
2609 || idx < media->bandwidths->len, GST_SDP_EINVAL);
2612 g_array_append_val (media->bandwidths, *bw);
2614 g_array_insert_val (media->bandwidths, idx, *bw);
2620 * gst_sdp_media_replace_bandwidth:
2621 * @media: a #GstSDPMedia
2623 * @bw: a #GstSDPBandwidth
2625 * Replace the bandwidth information in @media at @idx with @bw.
2627 * Returns: #GST_SDP_OK.
2632 gst_sdp_media_replace_bandwidth (GstSDPMedia * media, guint idx,
2633 GstSDPBandwidth * bw)
2635 GstSDPBandwidth *old;
2636 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2637 g_return_val_if_fail (bw != NULL, GST_SDP_EINVAL);
2638 g_return_val_if_fail (idx < media->bandwidths->len, GST_SDP_EINVAL);
2640 old = &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
2641 gst_sdp_bandwidth_clear (old);
2648 * gst_sdp_media_remove_bandwidth:
2649 * @media: a #GstSDPMedia
2652 * Remove the bandwidth information in @media at @idx.
2654 * Returns: #GST_SDP_OK.
2659 gst_sdp_media_remove_bandwidth (GstSDPMedia * media, guint idx)
2661 GstSDPBandwidth *old;
2663 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2664 g_return_val_if_fail (idx < media->bandwidths->len, GST_SDP_EINVAL);
2666 old = &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
2667 gst_sdp_bandwidth_clear (old);
2668 g_array_remove_index (media->bandwidths, idx);
2674 * gst_sdp_media_add_bandwidth:
2675 * @media: a #GstSDPMedia
2676 * @bwtype: the bandwidth modifier type
2677 * @bandwidth: the bandwidth in kilobits per second
2679 * Add the bandwidth information with @bwtype and @bandwidth to @media.
2681 * Returns: #GST_SDP_OK.
2684 gst_sdp_media_add_bandwidth (GstSDPMedia * media, const gchar * bwtype,
2689 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2690 g_return_val_if_fail (bwtype != NULL, GST_SDP_EINVAL);
2692 gst_sdp_bandwidth_set (&bw, bwtype, bandwidth);
2693 g_array_append_val (media->bandwidths, bw);
2699 * gst_sdp_media_set_key:
2700 * @media: a #GstSDPMedia
2701 * @type: the encryption type
2702 * @data: the encryption data
2704 * Adds the encryption information to @media.
2706 * Returns: a #GstSDPResult.
2709 gst_sdp_media_set_key (GstSDPMedia * media, const gchar * type,
2712 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2714 g_free (media->key.type);
2715 media->key.type = g_strdup (type);
2716 g_free (media->key.data);
2717 media->key.data = g_strdup (data);
2723 * gst_sdp_media_get_key:
2724 * @media: a #GstSDPMedia
2726 * Get the encryption information from @media.
2728 * Returns: a #GstSDPKey.
2731 gst_sdp_media_get_key (const GstSDPMedia * media)
2733 g_return_val_if_fail (media != NULL, NULL);
2739 * gst_sdp_media_attributes_len:
2740 * @media: a #GstSDPMedia
2742 * Get the number of attribute fields in @media.
2744 * Returns: the number of attributes in @media.
2747 gst_sdp_media_attributes_len (const GstSDPMedia * media)
2749 g_return_val_if_fail (media != NULL, 0);
2751 return media->attributes->len;
2755 * gst_sdp_media_add_attribute:
2756 * @media: a #GstSDPMedia
2758 * @value: (nullable): a value
2760 * Add the attribute with @key and @value to @media.
2762 * Returns: #GST_SDP_OK.
2765 gst_sdp_media_add_attribute (GstSDPMedia * media, const gchar * key,
2766 const gchar * value)
2768 GstSDPAttribute attr;
2770 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2771 g_return_val_if_fail (key != NULL, GST_SDP_EINVAL);
2773 gst_sdp_attribute_set (&attr, key, value);
2774 g_array_append_val (media->attributes, attr);
2780 * gst_sdp_media_get_attribute:
2781 * @media: a #GstSDPMedia
2784 * Get the attribute at position @idx in @media.
2786 * Returns: the #GstSDPAttribute at position @idx.
2788 const GstSDPAttribute *
2789 gst_sdp_media_get_attribute (const GstSDPMedia * media, guint idx)
2791 g_return_val_if_fail (media != NULL, NULL);
2792 g_return_val_if_fail (idx < media->attributes->len, NULL);
2794 return &g_array_index (media->attributes, GstSDPAttribute, idx);
2798 * gst_sdp_media_get_attribute_val_n:
2799 * @media: a #GstSDPMedia
2803 * Get the @nth attribute value for @key in @media.
2805 * Returns: the @nth attribute value.
2808 gst_sdp_media_get_attribute_val_n (const GstSDPMedia * media, const gchar * key,
2813 g_return_val_if_fail (media != NULL, NULL);
2814 g_return_val_if_fail (key != NULL, NULL);
2816 for (i = 0; i < media->attributes->len; i++) {
2817 GstSDPAttribute *attr;
2819 attr = &g_array_index (media->attributes, GstSDPAttribute, i);
2820 if (!strcmp (attr->key, key)) {
2831 * gst_sdp_media_get_attribute_val:
2832 * @media: a #GstSDPMedia
2835 * Get the first attribute value for @key in @media.
2837 * Returns: the first attribute value for @key.
2840 gst_sdp_media_get_attribute_val (const GstSDPMedia * media, const gchar * key)
2842 g_return_val_if_fail (media != NULL, NULL);
2843 g_return_val_if_fail (key != NULL, NULL);
2845 return gst_sdp_media_get_attribute_val_n (media, key, 0);
2849 * gst_sdp_media_insert_attribute:
2850 * @media: a #GstSDPMedia
2852 * @attr: a #GstSDPAttribute
2854 * Insert the attribute to @media at @idx. When @idx is -1,
2855 * the attribute is appended.
2857 * Returns: #GST_SDP_OK.
2862 gst_sdp_media_insert_attribute (GstSDPMedia * media, gint idx,
2863 GstSDPAttribute * attr)
2865 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2866 g_return_val_if_fail (attr != NULL, GST_SDP_EINVAL);
2867 g_return_val_if_fail (idx == -1
2868 || idx < media->attributes->len, GST_SDP_EINVAL);
2871 g_array_append_val (media->attributes, *attr);
2873 g_array_insert_val (media->attributes, idx, *attr);
2879 * gst_sdp_media_replace_attribute:
2880 * @media: a #GstSDPMedia
2882 * @attr: a #GstSDPAttribute
2884 * Replace the attribute in @media at @idx with @attr.
2886 * Returns: #GST_SDP_OK.
2891 gst_sdp_media_replace_attribute (GstSDPMedia * media, guint idx,
2892 GstSDPAttribute * attr)
2894 GstSDPAttribute *old;
2896 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2897 g_return_val_if_fail (attr != NULL, GST_SDP_EINVAL);
2898 g_return_val_if_fail (idx < media->attributes->len, GST_SDP_EINVAL);
2900 old = &g_array_index (media->attributes, GstSDPAttribute, idx);
2901 gst_sdp_attribute_clear (old);
2908 * gst_sdp_media_remove_attribute:
2909 * @media: a #GstSDPMedia
2912 * Remove the attribute in @media at @idx.
2914 * Returns: #GST_SDP_OK.
2919 gst_sdp_media_remove_attribute (GstSDPMedia * media, guint idx)
2921 GstSDPAttribute *old;
2922 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2923 g_return_val_if_fail (idx < media->attributes->len, GST_SDP_EINVAL);
2925 old = &g_array_index (media->attributes, GstSDPAttribute, idx);
2926 gst_sdp_attribute_clear (old);
2927 g_array_remove_index (media->attributes, idx);
2933 read_string (gchar * dest, guint size, gchar ** src)
2939 while (g_ascii_isspace (**src))
2942 while (!g_ascii_isspace (**src) && **src != '\0') {
2944 dest[idx++] = **src;
2952 read_string_del (gchar * dest, guint size, gchar del, gchar ** src)
2958 while (g_ascii_isspace (**src))
2961 while (**src != del && **src != '\0') {
2963 dest[idx++] = **src;
2984 gst_sdp_parse_line (SDPContext * c, gchar type, gchar * buffer)
2989 #define READ_STRING(field) \
2990 do { read_string (str, sizeof (str), &p); REPLACE_STRING (field, str); } while (0)
2991 #define READ_UINT(field) \
2992 do { read_string (str, sizeof (str), &p); field = strtoul (str, NULL, 10); } while (0)
2996 if (buffer[0] != '0')
2997 GST_WARNING ("wrong SDP version");
2998 gst_sdp_message_set_version (c->msg, buffer);
3001 READ_STRING (c->msg->origin.username);
3002 READ_STRING (c->msg->origin.sess_id);
3003 READ_STRING (c->msg->origin.sess_version);
3004 READ_STRING (c->msg->origin.nettype);
3005 READ_STRING (c->msg->origin.addrtype);
3006 READ_STRING (c->msg->origin.addr);
3009 REPLACE_STRING (c->msg->session_name, buffer);
3012 if (c->state == SDP_SESSION) {
3013 REPLACE_STRING (c->msg->information, buffer);
3015 REPLACE_STRING (c->media->information, buffer);
3019 REPLACE_STRING (c->msg->uri, buffer);
3022 gst_sdp_message_add_email (c->msg, buffer);
3025 gst_sdp_message_add_phone (c->msg, buffer);
3029 GstSDPConnection conn;
3032 memset (&conn, 0, sizeof (conn));
3035 while ((str2 = strchr (str2, '/')))
3037 READ_STRING (conn.nettype);
3038 READ_STRING (conn.addrtype);
3039 READ_STRING (conn.address);
3040 /* only read TTL for IP4 */
3041 if (strcmp (conn.addrtype, "IP4") == 0)
3042 READ_UINT (conn.ttl);
3043 READ_UINT (conn.addr_number);
3045 if (c->state == SDP_SESSION) {
3046 gst_sdp_message_set_connection (c->msg, conn.nettype, conn.addrtype,
3047 conn.address, conn.ttl, conn.addr_number);
3049 gst_sdp_media_add_connection (c->media, conn.nettype, conn.addrtype,
3050 conn.address, conn.ttl, conn.addr_number);
3052 gst_sdp_connection_clear (&conn);
3059 read_string_del (str, sizeof (str), ':', &p);
3062 read_string (str2, sizeof (str2), &p);
3063 if (c->state == SDP_SESSION)
3064 gst_sdp_message_add_bandwidth (c->msg, str, atoi (str2));
3066 gst_sdp_media_add_bandwidth (c->media, str, atoi (str2));
3072 read_string_del (str, sizeof (str), ':', &p);
3075 if (c->state == SDP_SESSION)
3076 gst_sdp_message_set_key (c->msg, str, p);
3078 gst_sdp_media_set_key (c->media, str, p);
3081 read_string_del (str, sizeof (str), ':', &p);
3084 if (c->state == SDP_SESSION)
3085 gst_sdp_message_add_attribute (c->msg, str, p);
3087 gst_sdp_media_add_attribute (c->media, str, p);
3094 c->state = SDP_MEDIA;
3095 memset (&nmedia, 0, sizeof (nmedia));
3096 gst_sdp_media_init (&nmedia);
3098 /* m=<media> <port>/<number of ports> <proto> <fmt> ... */
3099 READ_STRING (nmedia.media);
3100 read_string (str, sizeof (str), &p);
3101 slash = g_strrstr (str, "/");
3104 nmedia.port = atoi (str);
3105 nmedia.num_ports = atoi (slash + 1);
3107 nmedia.port = atoi (str);
3108 nmedia.num_ports = 0;
3110 READ_STRING (nmedia.proto);
3112 read_string (str, sizeof (str), &p);
3113 gst_sdp_media_add_format (&nmedia, str);
3114 } while (*p != '\0');
3116 gst_sdp_message_add_media (c->msg, &nmedia);
3118 &g_array_index (c->msg->medias, GstSDPMedia, c->msg->medias->len - 1);
3128 * gst_sdp_message_parse_buffer:
3129 * @data: (array length=size): the start of the buffer
3130 * @size: the size of the buffer
3131 * @msg: the result #GstSDPMessage
3133 * Parse the contents of @size bytes pointed to by @data and store the result in
3136 * Returns: #GST_SDP_OK on success.
3139 gst_sdp_message_parse_buffer (const guint8 * data, guint size,
3140 GstSDPMessage * msg)
3145 gchar *buffer = NULL;
3149 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
3150 g_return_val_if_fail (data != NULL, GST_SDP_EINVAL);
3151 g_return_val_if_fail (size != 0, GST_SDP_EINVAL);
3153 c.state = SDP_SESSION;
3157 #define SIZE_CHECK_GUARD \
3159 if (p - (gchar *) data >= size) \
3165 while (p - (gchar *) data < size && g_ascii_isspace (*p))
3183 while (p - (gchar *) data < size && *p != '\n' && *p != '\r' && *p != '\0')
3187 if (bufsize <= len) {
3188 buffer = g_realloc (buffer, len + 1);
3191 memcpy (buffer, s, len);
3194 gst_sdp_parse_line (&c, type, buffer);
3199 while (p - (gchar *) data < size && *p != '\n' && *p != '\0')
3208 #undef SIZE_CHECK_GUARD
3217 print_media (GstSDPMedia * media)
3219 g_print (" media: '%s'\n", GST_STR_NULL (media->media));
3220 g_print (" port: '%u'\n", media->port);
3221 g_print (" num_ports: '%u'\n", media->num_ports);
3222 g_print (" proto: '%s'\n", GST_STR_NULL (media->proto));
3223 if (media->fmts->len > 0) {
3226 g_print (" formats:\n");
3227 for (i = 0; i < media->fmts->len; i++) {
3228 g_print (" format '%s'\n", g_array_index (media->fmts, gchar *, i));
3231 g_print (" information: '%s'\n", GST_STR_NULL (media->information));
3232 if (media->connections->len > 0) {
3235 g_print (" connections:\n");
3236 for (i = 0; i < media->connections->len; i++) {
3237 GstSDPConnection *conn =
3238 &g_array_index (media->connections, GstSDPConnection, i);
3240 g_print (" nettype: '%s'\n", GST_STR_NULL (conn->nettype));
3241 g_print (" addrtype: '%s'\n", GST_STR_NULL (conn->addrtype));
3242 g_print (" address: '%s'\n", GST_STR_NULL (conn->address));
3243 g_print (" ttl: '%u'\n", conn->ttl);
3244 g_print (" addr_number: '%u'\n", conn->addr_number);
3247 if (media->bandwidths->len > 0) {
3250 g_print (" bandwidths:\n");
3251 for (i = 0; i < media->bandwidths->len; i++) {
3252 GstSDPBandwidth *bw =
3253 &g_array_index (media->bandwidths, GstSDPBandwidth, i);
3255 g_print (" type: '%s'\n", GST_STR_NULL (bw->bwtype));
3256 g_print (" bandwidth: '%u'\n", bw->bandwidth);
3259 g_print (" key:\n");
3260 g_print (" type: '%s'\n", GST_STR_NULL (media->key.type));
3261 g_print (" data: '%s'\n", GST_STR_NULL (media->key.data));
3262 if (media->attributes->len > 0) {
3265 g_print (" attributes:\n");
3266 for (i = 0; i < media->attributes->len; i++) {
3267 GstSDPAttribute *attr =
3268 &g_array_index (media->attributes, GstSDPAttribute, i);
3270 g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
3276 * gst_sdp_message_dump:
3277 * @msg: a #GstSDPMessage
3279 * Dump the parsed contents of @msg to stdout.
3281 * Returns: a #GstSDPResult.
3284 gst_sdp_message_dump (const GstSDPMessage * msg)
3286 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
3288 g_print ("sdp packet %p:\n", msg);
3289 g_print (" version: '%s'\n", GST_STR_NULL (msg->version));
3290 g_print (" origin:\n");
3291 g_print (" username: '%s'\n", GST_STR_NULL (msg->origin.username));
3292 g_print (" sess_id: '%s'\n", GST_STR_NULL (msg->origin.sess_id));
3293 g_print (" sess_version: '%s'\n", GST_STR_NULL (msg->origin.sess_version));
3294 g_print (" nettype: '%s'\n", GST_STR_NULL (msg->origin.nettype));
3295 g_print (" addrtype: '%s'\n", GST_STR_NULL (msg->origin.addrtype));
3296 g_print (" addr: '%s'\n", GST_STR_NULL (msg->origin.addr));
3297 g_print (" session_name: '%s'\n", GST_STR_NULL (msg->session_name));
3298 g_print (" information: '%s'\n", GST_STR_NULL (msg->information));
3299 g_print (" uri: '%s'\n", GST_STR_NULL (msg->uri));
3301 if (msg->emails->len > 0) {
3304 g_print (" emails:\n");
3305 for (i = 0; i < msg->emails->len; i++) {
3306 g_print (" email '%s'\n", g_array_index (msg->emails, gchar *, i));
3309 if (msg->phones->len > 0) {
3312 g_print (" phones:\n");
3313 for (i = 0; i < msg->phones->len; i++) {
3314 g_print (" phone '%s'\n", g_array_index (msg->phones, gchar *, i));
3317 g_print (" connection:\n");
3318 g_print (" nettype: '%s'\n", GST_STR_NULL (msg->connection.nettype));
3319 g_print (" addrtype: '%s'\n", GST_STR_NULL (msg->connection.addrtype));
3320 g_print (" address: '%s'\n", GST_STR_NULL (msg->connection.address));
3321 g_print (" ttl: '%u'\n", msg->connection.ttl);
3322 g_print (" addr_number: '%u'\n", msg->connection.addr_number);
3323 if (msg->bandwidths->len > 0) {
3326 g_print (" bandwidths:\n");
3327 for (i = 0; i < msg->bandwidths->len; i++) {
3328 GstSDPBandwidth *bw =
3329 &g_array_index (msg->bandwidths, GstSDPBandwidth, i);
3331 g_print (" type: '%s'\n", GST_STR_NULL (bw->bwtype));
3332 g_print (" bandwidth: '%u'\n", bw->bandwidth);
3335 g_print (" key:\n");
3336 g_print (" type: '%s'\n", GST_STR_NULL (msg->key.type));
3337 g_print (" data: '%s'\n", GST_STR_NULL (msg->key.data));
3338 if (msg->attributes->len > 0) {
3341 g_print (" attributes:\n");
3342 for (i = 0; i < msg->attributes->len; i++) {
3343 GstSDPAttribute *attr =
3344 &g_array_index (msg->attributes, GstSDPAttribute, i);
3346 g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
3349 if (msg->medias->len > 0) {
3352 g_print (" medias:\n");
3353 for (i = 0; i < msg->medias->len; i++) {
3354 g_print (" media %u:\n", i);
3355 print_media (&g_array_index (msg->medias, GstSDPMedia, i));
3361 static const gchar *
3362 gst_sdp_get_attribute_for_pt (const GstSDPMedia * media, const gchar * name,
3371 if ((attr = gst_sdp_media_get_attribute_val_n (media, name, i)) == NULL)
3374 if (sscanf (attr, "%d ", &val) != 1)
3383 /* this may modify the input string (and resets) */
3384 #define PARSE_INT(p, del, res) \
3387 p = strstr (p, del); \
3399 /* this may modify the string without reset */
3400 #define PARSE_STRING(p, del, res) \
3403 p = strstr (p, del); \
3415 #define SKIP_SPACES(p) \
3416 while (*p && g_ascii_isspace (*p)) \
3421 * <payload> <encoding_name>/<clock_rate>[/<encoding_params>]
3424 gst_sdp_parse_rtpmap (const gchar * rtpmap, gint * payload, gchar ** name,
3425 gint * rate, gchar ** params)
3427 gchar *p, *t, *orig_value;
3429 p = orig_value = g_strdup (rtpmap);
3431 PARSE_INT (p, " ", *payload);
3439 PARSE_STRING (p, "/", *name);
3440 if (*name == NULL) {
3441 GST_DEBUG ("no rate, name %s", p);
3442 /* no rate, assume -1 then, this is not supposed to happen but RealMedia
3443 * streams seem to omit the rate. */
3444 *name = g_strdup (p);
3449 *name = strdup (*name);
3453 p = strstr (p, "/");
3465 *params = g_strdup (p);
3468 g_free (orig_value);
3472 g_free (orig_value);
3477 * gst_sdp_media_add_rtcp_fb_attributes_from_media:
3478 * @media: a #GstSDPMedia
3482 * Parse given @media for "rtcp-fb" attributes and add it to the @caps.
3484 * Mapping of caps from SDP fields:
3486 * a=rtcp-fb:(payload) (param1) [param2]...
3488 * Returns: a #GstSDPResult.
3491 gst_sdp_media_add_rtcp_fb_attributes_from_media (const GstSDPMedia * media,
3492 gint pt, GstCaps * caps)
3494 const gchar *rtcp_fb;
3499 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
3500 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
3502 s = gst_caps_get_structure (caps, 0);
3505 gboolean all_formats = FALSE;
3507 if ((rtcp_fb = gst_sdp_media_get_attribute_val_n (media,
3508 "rtcp-fb", i)) == NULL)
3511 /* p is now of the format <payload> attr... */
3512 to_free = p = g_strdup (rtcp_fb);
3514 /* check if it applies to all formats */
3519 PARSE_INT (p, " ", payload);
3522 if (all_formats || (payload != -1 && payload == pt)) {
3527 /* replace space with '-' */
3528 key = g_strdup_printf ("rtcp-fb-%s", p);
3530 for (tmp = key; (tmp = strchr (tmp, ' ')); ++tmp) {
3534 gst_structure_set (s, key, G_TYPE_BOOLEAN, TRUE, NULL);
3535 GST_DEBUG ("adding caps: %s=TRUE", key);
3544 * gst_sdp_media_get_caps_from_media:
3545 * @media: a #GstSDPMedia
3546 * @pt: a payload type
3548 * Mapping of caps from SDP fields:
3550 * a=rtpmap:(payload) (encoding_name)/(clock_rate)[/(encoding_params)]
3552 * a=framesize:(payload) (width)-(height)
3554 * a=fmtp:(payload) (param)[=(value)];...
3556 * Note that the extmap attribute is set only by gst_sdp_media_attributes_to_caps().
3558 * Returns: a #GstCaps, or %NULL if an error happened
3563 gst_sdp_media_get_caps_from_media (const GstSDPMedia * media, gint pt)
3566 const gchar *rtpmap;
3568 gchar *framesize = NULL;
3571 gchar *params = NULL;
3577 g_return_val_if_fail (media != NULL, NULL);
3579 /* get and parse rtpmap */
3580 rtpmap = gst_sdp_get_attribute_for_pt (media, "rtpmap", pt);
3583 ret = gst_sdp_parse_rtpmap (rtpmap, &payload, &name, &rate, ¶ms);
3585 GST_ERROR ("error parsing rtpmap, ignoring");
3589 /* dynamic payloads need rtpmap or we fail */
3590 if (rtpmap == NULL && pt >= 96)
3593 /* check if we have a rate, if not, we need to look up the rate from the
3594 * default rates based on the payload types. */
3596 const GstRTPPayloadInfo *info;
3598 if (GST_RTP_PAYLOAD_IS_DYNAMIC (pt)) {
3599 /* dynamic types, use media and encoding_name */
3600 tmp = g_ascii_strdown (media->media, -1);
3601 info = gst_rtp_payload_info_for_name (tmp, name);
3604 /* static types, use payload type */
3605 info = gst_rtp_payload_info_for_pt (pt);
3609 if ((rate = info->clock_rate) == 0)
3612 /* we fail if we cannot find one */
3617 tmp = g_ascii_strdown (media->media, -1);
3618 caps = gst_caps_new_simple ("application/x-unknown",
3619 "media", G_TYPE_STRING, tmp, "payload", G_TYPE_INT, pt, NULL);
3621 s = gst_caps_get_structure (caps, 0);
3623 gst_structure_set (s, "clock-rate", G_TYPE_INT, rate, NULL);
3625 /* encoding name must be upper case */
3627 tmp = g_ascii_strup (name, -1);
3628 gst_structure_set (s, "encoding-name", G_TYPE_STRING, tmp, NULL);
3632 /* params must be lower case */
3633 if (params != NULL) {
3634 tmp = g_ascii_strdown (params, -1);
3635 gst_structure_set (s, "encoding-params", G_TYPE_STRING, tmp, NULL);
3639 /* parse optional fmtp: field */
3640 if ((fmtp = g_strdup (gst_sdp_get_attribute_for_pt (media, "fmtp", pt)))) {
3646 /* p is now of the format <payload> <param>[=<value>];... */
3647 PARSE_INT (p, " ", payload);
3648 if (payload != -1 && payload == pt) {
3652 /* <param>[=<value>] are separated with ';' */
3653 pairs = g_strsplit (p, ";", 0);
3654 for (i = 0; pairs[i]; i++) {
3656 const gchar *val, *key;
3658 const gchar *reserved_keys[] =
3659 { "media", "payload", "clock-rate", "encoding-name",
3663 /* the key may not have a '=', the value can have other '='s */
3664 valpos = strstr (pairs[i], "=");
3666 /* we have a '=' and thus a value, remove the '=' with \0 */
3668 /* value is everything between '=' and ';'. We split the pairs at ;
3669 * boundaries so we can take the remainder of the value. Some servers
3670 * put spaces around the value which we strip off here. Alternatively
3671 * we could strip those spaces in the depayloaders should these spaces
3672 * actually carry any meaning in the future. */
3673 val = g_strstrip (valpos + 1);
3675 /* simple <param>;.. is translated into <param>=1;... */
3678 /* strip the key of spaces, convert key to lowercase but not the value. */
3679 key = g_strstrip (pairs[i]);
3681 /* skip keys from the fmtp, which we already use ourselves for the
3682 * caps. Some software is adding random things like clock-rate into
3683 * the fmtp, and we would otherwise here set a string-typed clock-rate
3684 * in the caps... and thus fail to create valid RTP caps
3686 for (j = 0; j < G_N_ELEMENTS (reserved_keys); j++) {
3687 if (g_ascii_strcasecmp (reserved_keys[j], key) == 0) {
3693 if (strlen (key) > 1) {
3694 tmp = g_ascii_strdown (key, -1);
3695 gst_structure_set (s, tmp, G_TYPE_STRING, val, NULL);
3703 /* parse framesize: field */
3705 g_strdup (gst_sdp_media_get_attribute_val (media, "framesize")))) {
3708 /* p is now of the format <payload> <width>-<height> */
3711 PARSE_INT (p, " ", payload);
3712 if (payload != -1 && payload == pt) {
3713 gst_structure_set (s, "a-framesize", G_TYPE_STRING, p, NULL);
3717 /* parse rtcp-fb: field */
3718 gst_sdp_media_add_rtcp_fb_attributes_from_media (media, pt, caps);
3730 GST_ERROR ("rtpmap type not given for dynamic payload %d", pt);
3736 GST_ERROR ("rate unknown for payload type %d", pt);
3743 * gst_sdp_media_set_media_from_caps:
3745 * @media: a #GstSDPMedia
3747 * Mapping of caps to SDP fields:
3749 * a=rtpmap:(payload) (encoding_name) or (clock_rate)[or (encoding_params)]
3751 * a=framesize:(payload) (width)-(height)
3753 * a=fmtp:(payload) (param)[=(value)];...
3755 * a=rtcp-fb:(payload) (param1) [param2]...
3757 * a=extmap:(id)[/direction] (extensionname) (extensionattributes)
3759 * Returns: a #GstSDPResult.
3764 gst_sdp_media_set_media_from_caps (const GstCaps * caps, GstSDPMedia * media)
3766 const gchar *caps_str, *caps_enc, *caps_params;
3768 gint caps_pt, caps_rate;
3770 gboolean first, nack, nack_pli, ccm_fir;
3774 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
3775 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
3777 s = gst_caps_get_structure (caps, 0);
3779 GST_ERROR ("ignoring stream without media type");
3783 /* get media type and payload for the m= line */
3784 caps_str = gst_structure_get_string (s, "media");
3785 gst_sdp_media_set_media (media, caps_str);
3787 gst_structure_get_int (s, "payload", &caps_pt);
3788 tmp = g_strdup_printf ("%d", caps_pt);
3789 gst_sdp_media_add_format (media, tmp);
3792 /* get clock-rate, media type and params for the rtpmap attribute */
3793 gst_structure_get_int (s, "clock-rate", &caps_rate);
3794 caps_enc = gst_structure_get_string (s, "encoding-name");
3795 caps_params = gst_structure_get_string (s, "encoding-params");
3799 tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate,
3802 tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate);
3804 gst_sdp_media_add_attribute (media, "rtpmap", tmp);
3808 /* get rtcp-fb attributes */
3809 if (gst_structure_get_boolean (s, "rtcp-fb-nack", &nack)) {
3811 tmp = g_strdup_printf ("%d nack", caps_pt);
3812 gst_sdp_media_add_attribute (media, "rtcp-fb", tmp);
3814 GST_DEBUG ("adding rtcp-fb-nack to pt=%d", caps_pt);
3818 if (gst_structure_get_boolean (s, "rtcp-fb-nack-pli", &nack_pli)) {
3820 tmp = g_strdup_printf ("%d nack pli", caps_pt);
3821 gst_sdp_media_add_attribute (media, "rtcp-fb", tmp);
3823 GST_DEBUG ("adding rtcp-fb-nack-pli to pt=%d", caps_pt);
3827 if (gst_structure_get_boolean (s, "rtcp-fb-ccm-fir", &ccm_fir)) {
3829 tmp = g_strdup_printf ("%d ccm fir", caps_pt);
3830 gst_sdp_media_add_attribute (media, "rtcp-fb", tmp);
3832 GST_DEBUG ("adding rtcp-fb-ccm-fir to pt=%d", caps_pt);
3836 /* collect all other properties and add them to fmtp, extmap or attributes */
3837 fmtp = g_string_new ("");
3838 g_string_append_printf (fmtp, "%d ", caps_pt);
3840 n_fields = gst_structure_n_fields (s);
3841 for (j = 0; j < n_fields; j++) {
3842 const gchar *fname, *fval;
3844 fname = gst_structure_nth_field_name (s, j);
3846 /* filter out standard properties */
3847 if (!strcmp (fname, "media"))
3849 if (!strcmp (fname, "payload"))
3851 if (!strcmp (fname, "clock-rate"))
3853 if (!strcmp (fname, "encoding-name"))
3855 if (!strcmp (fname, "encoding-params"))
3857 if (!strcmp (fname, "ssrc"))
3859 if (!strcmp (fname, "timestamp-offset"))
3861 if (!strcmp (fname, "seqnum-offset"))
3863 if (g_str_has_prefix (fname, "srtp-"))
3865 if (g_str_has_prefix (fname, "srtcp-"))
3868 if (g_str_has_prefix (fname, "x-gst-rtsp-server-rtx-time"))
3870 if (g_str_has_prefix (fname, "rtcp-fb-"))
3873 if (!strcmp (fname, "a-framesize")) {
3874 /* a-framesize attribute */
3875 if ((fval = gst_structure_get_string (s, fname))) {
3876 tmp = g_strdup_printf ("%d %s", caps_pt, fval);
3877 gst_sdp_media_add_attribute (media, fname + 2, tmp);
3883 if (g_str_has_prefix (fname, "a-")) {
3885 if ((fval = gst_structure_get_string (s, fname)))
3886 gst_sdp_media_add_attribute (media, fname + 2, fval);
3889 if (g_str_has_prefix (fname, "x-")) {
3891 if ((fval = gst_structure_get_string (s, fname)))
3892 gst_sdp_media_add_attribute (media, fname, fval);
3897 if (g_str_has_prefix (fname, "extmap-")) {
3899 guint id = strtoull (fname + 7, &endptr, 10);
3902 if (*endptr != '\0' || id == 0 || id == 15 || id > 9999)
3905 if ((fval = gst_structure_get_string (s, fname))) {
3906 gchar *extmap = g_strdup_printf ("%u %s", id, fval);
3907 gst_sdp_media_add_attribute (media, "extmap", extmap);
3909 } else if ((arr = gst_structure_get_value (s, fname))
3910 && G_VALUE_HOLDS (arr, GST_TYPE_ARRAY)
3911 && gst_value_array_get_size (arr) == 3) {
3913 const gchar *direction, *extensionname, *extensionattributes;
3915 val = gst_value_array_get_value (arr, 0);
3916 direction = g_value_get_string (val);
3918 val = gst_value_array_get_value (arr, 1);
3919 extensionname = g_value_get_string (val);
3921 val = gst_value_array_get_value (arr, 2);
3922 extensionattributes = g_value_get_string (val);
3924 if (!extensionname || *extensionname == '\0')
3927 if (direction && *direction != '\0' && extensionattributes
3928 && *extensionattributes != '\0') {
3930 g_strdup_printf ("%u/%s %s %s", id, direction, extensionname,
3931 extensionattributes);
3932 gst_sdp_media_add_attribute (media, "extmap", extmap);
3934 } else if (direction && *direction != '\0') {
3936 g_strdup_printf ("%u/%s %s", id, direction, extensionname);
3937 gst_sdp_media_add_attribute (media, "extmap", extmap);
3939 } else if (extensionattributes && *extensionattributes != '\0') {
3940 gchar *extmap = g_strdup_printf ("%u %s %s", id, extensionname,
3941 extensionattributes);
3942 gst_sdp_media_add_attribute (media, "extmap", extmap);
3945 gchar *extmap = g_strdup_printf ("%u %s", id, extensionname);
3946 gst_sdp_media_add_attribute (media, "extmap", extmap);
3953 if ((fval = gst_structure_get_string (s, fname))) {
3954 g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval);
3960 tmp = g_string_free (fmtp, FALSE);
3961 gst_sdp_media_add_attribute (media, "fmtp", tmp);
3964 g_string_free (fmtp, TRUE);
3972 GST_DEBUG ("ignoring stream");
3973 return GST_SDP_EINVAL;
3978 * gst_sdp_make_keymgmt:
3979 * @uri: a #gchar URI
3980 * @base64: a #gchar base64-encoded key data
3982 * Makes key management data
3984 * Returns: (transfer full): a #gchar key-mgmt data,
3989 gst_sdp_make_keymgmt (const gchar * uri, const gchar * base64)
3991 g_return_val_if_fail (uri != NULL, NULL);
3992 g_return_val_if_fail (base64 != NULL, NULL);
3994 return g_strdup_printf ("prot=mikey;uri=\"%s\";data=\"%s\"", uri, base64);
3998 gst_sdp_parse_keymgmt (const gchar * keymgmt, GstMIKEYMessage ** mikey)
4005 p = orig_value = g_strdup (keymgmt);
4009 g_free (orig_value);
4013 PARSE_STRING (p, " ", kmpid);
4014 if (kmpid == NULL || !g_str_equal (kmpid, "mikey")) {
4015 g_free (orig_value);
4018 data = g_base64_decode (p, &size);
4019 g_free (orig_value); /* Don't need this any more */
4024 *mikey = gst_mikey_message_new_from_data (data, size, NULL, NULL);
4027 return (*mikey != NULL);
4031 sdp_add_attributes_to_keymgmt (GArray * attributes, GstMIKEYMessage ** mikey)
4033 GstSDPResult res = GST_SDP_OK;
4035 if (attributes->len > 0) {
4037 for (i = 0; i < attributes->len; i++) {
4038 GstSDPAttribute *attr = &g_array_index (attributes, GstSDPAttribute, i);
4040 if (g_str_equal (attr->key, "key-mgmt")) {
4041 res = gst_sdp_parse_keymgmt (attr->value, mikey);
4051 * gst_sdp_message_parse_keymgmt:
4052 * @msg: a #GstSDPMessage
4053 * @mikey: (out) (transfer full): pointer to new #GstMIKEYMessage
4055 * Creates a new #GstMIKEYMessage after parsing the key-mgmt attribute
4056 * from a #GstSDPMessage.
4058 * Returns: a #GstSDPResult.
4063 gst_sdp_message_parse_keymgmt (const GstSDPMessage * msg,
4064 GstMIKEYMessage ** mikey)
4066 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
4068 return sdp_add_attributes_to_keymgmt (msg->attributes, mikey);
4072 * gst_sdp_media_parse_keymgmt:
4073 * @media: a #GstSDPMedia
4074 * @mikey: (out) (transfer full): pointer to new #GstMIKEYMessage
4076 * Creates a new #GstMIKEYMessage after parsing the key-mgmt attribute
4077 * from a #GstSDPMedia.
4079 * Returns: a #GstSDPResult.
4084 gst_sdp_media_parse_keymgmt (const GstSDPMedia * media,
4085 GstMIKEYMessage ** mikey)
4087 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
4089 return sdp_add_attributes_to_keymgmt (media->attributes, mikey);
4093 sdp_add_attributes_to_caps (GArray * attributes, GstCaps * caps)
4095 if (attributes->len > 0) {
4099 s = gst_caps_get_structure (caps, 0);
4101 for (i = 0; i < attributes->len; i++) {
4102 GstSDPAttribute *attr = &g_array_index (attributes, GstSDPAttribute, i);
4103 gchar *tofree, *key;
4107 /* skip some of the attribute we already handle */
4108 if (!strcmp (key, "fmtp"))
4110 if (!strcmp (key, "rtpmap"))
4112 if (!strcmp (key, "control"))
4114 if (!strcmp (key, "range"))
4116 if (!strcmp (key, "framesize"))
4118 if (!strcmp (key, "key-mgmt"))
4120 if (!strcmp (key, "extmap"))
4123 /* string must be valid UTF8 */
4124 if (!g_utf8_validate (attr->value, -1, NULL))
4127 if (!g_str_has_prefix (key, "x-"))
4128 tofree = key = g_strdup_printf ("a-%s", key);
4132 GST_DEBUG ("adding caps: %s=%s", key, attr->value);
4133 gst_structure_set (s, key, G_TYPE_STRING, attr->value, NULL);
4142 gst_sdp_media_add_extmap_attributes (GArray * attributes, GstCaps * caps)
4144 const gchar *extmap;
4145 gchar *p, *tmp, *to_free;
4149 g_return_val_if_fail (attributes != NULL, GST_SDP_EINVAL);
4150 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
4152 s = gst_caps_get_structure (caps, 0);
4154 for (i = 0; i < attributes->len; i++) {
4155 GstSDPAttribute *attr;
4156 const gchar *direction, *extensionname, *extensionattributes;
4158 attr = &g_array_index (attributes, GstSDPAttribute, i);
4159 if (strcmp (attr->key, "extmap") != 0)
4162 extmap = attr->value;
4164 /* p is now of the format id[/direction] extensionname [extensionattributes] */
4165 to_free = p = g_strdup (extmap);
4167 id = strtoul (p, &tmp, 10);
4168 if (id == 0 || id == 15 || id > 9999 || (*tmp != ' ' && *tmp != '/')) {
4169 GST_ERROR ("Invalid extmap '%s'", to_free);
4171 } else if (*tmp == '/') {
4175 PARSE_STRING (p, " ", direction);
4177 /* Invalid format */
4178 if (direction == NULL || *direction == '\0') {
4179 GST_ERROR ("Invalid extmap '%s'", to_free);
4190 tmp = strstr (p, " ");
4193 extensionattributes = "";
4199 extensionattributes = p;
4202 if (extensionname == NULL || *extensionname == '\0') {
4203 GST_ERROR ("Invalid extmap '%s'", to_free);
4207 if (*direction != '\0' || *extensionattributes != '\0') {
4208 GValue arr = G_VALUE_INIT;
4209 GValue val = G_VALUE_INIT;
4212 key = g_strdup_printf ("extmap-%u", id);
4214 g_value_init (&arr, GST_TYPE_ARRAY);
4215 g_value_init (&val, G_TYPE_STRING);
4217 g_value_set_string (&val, direction);
4218 gst_value_array_append_value (&arr, &val);
4220 g_value_set_string (&val, extensionname);
4221 gst_value_array_append_value (&arr, &val);
4223 g_value_set_string (&val, extensionattributes);
4224 gst_value_array_append_value (&arr, &val);
4226 gst_structure_set_value (s, key, &arr);
4227 g_value_unset (&val);
4228 g_value_unset (&arr);
4229 GST_DEBUG ("adding caps: %s=<%s,%s,%s>", key, direction, extensionname,
4230 extensionattributes);
4235 key = g_strdup_printf ("extmap-%u", id);
4236 gst_structure_set (s, key, G_TYPE_STRING, extensionname, NULL);
4237 GST_DEBUG ("adding caps: %s=%s", key, extensionname);
4248 * gst_sdp_message_attributes_to_caps:
4249 * @msg: a #GstSDPMessage
4252 * Mapping of attributes of #GstSDPMessage to #GstCaps
4254 * Returns: a #GstSDPResult.
4259 gst_sdp_message_attributes_to_caps (const GstSDPMessage * msg, GstCaps * caps)
4262 GstMIKEYMessage *mikey = NULL;
4264 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
4265 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
4267 gst_sdp_message_parse_keymgmt (msg, &mikey);
4269 if (gst_mikey_message_to_caps (mikey, caps)) {
4270 res = GST_SDP_EINVAL;
4275 res = sdp_add_attributes_to_caps (msg->attributes, caps);
4277 if (res == GST_SDP_OK) {
4278 /* parse global extmap field */
4279 res = gst_sdp_media_add_extmap_attributes (msg->attributes, caps);
4284 gst_mikey_message_unref (mikey);
4289 * gst_sdp_media_attributes_to_caps:
4290 * @media: a #GstSDPMedia
4293 * Mapping of attributes of #GstSDPMedia to #GstCaps
4295 * Returns: a #GstSDPResult.
4300 gst_sdp_media_attributes_to_caps (const GstSDPMedia * media, GstCaps * caps)
4303 GstMIKEYMessage *mikey = NULL;
4305 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
4306 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
4308 gst_sdp_media_parse_keymgmt (media, &mikey);
4310 if (!gst_mikey_message_to_caps (mikey, caps)) {
4311 res = GST_SDP_EINVAL;
4316 res = sdp_add_attributes_to_caps (media->attributes, caps);
4318 if (res == GST_SDP_OK) {
4319 /* parse media extmap field */
4320 res = gst_sdp_media_add_extmap_attributes (media->attributes, caps);
4325 gst_mikey_message_unref (mikey);