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 <gst/pbutils/pbutils.h>
65 #include "gstsdpmessage.h"
67 #define FREE_STRING(field) g_free (field); (field) = NULL
68 #define REPLACE_STRING(field, val) FREE_STRING(field); (field) = g_strdup (val)
71 free_string (gchar ** str)
76 #define INIT_ARRAY(field, type, init_func) \
80 for(i = 0; i < (field)->len; i++) \
81 init_func (&g_array_index ((field), type, i)); \
82 g_array_set_size ((field), 0); \
85 (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
88 #define FREE_ARRAY(field) \
91 g_array_free ((field), TRUE); \
95 #define DEFINE_STRING_SETTER(field) \
96 GstSDPResult gst_sdp_message_set_##field (GstSDPMessage *msg, const gchar *val) { \
97 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
98 g_free (msg->field); \
99 msg->field = g_strdup (val); \
102 #define DEFINE_STRING_GETTER(field) \
103 const gchar* gst_sdp_message_get_##field (const GstSDPMessage *msg) { \
104 g_return_val_if_fail (msg != NULL, NULL); \
108 #define DEFINE_ARRAY_LEN(field) \
109 guint gst_sdp_message_##field##_len (const GstSDPMessage *msg) { \
110 g_return_val_if_fail (msg != NULL, 0); \
111 return msg->field->len; \
113 #define DEFINE_ARRAY_GETTER(method, field, type) \
114 const type * gst_sdp_message_get_##method (const GstSDPMessage *msg, guint idx) { \
115 g_return_val_if_fail (msg != NULL, NULL); \
116 return &g_array_index (msg->field, type, idx); \
118 #define DEFINE_PTR_ARRAY_GETTER(method, field, type) \
119 const type gst_sdp_message_get_##method (const GstSDPMessage *msg, guint idx) { \
120 g_return_val_if_fail (msg != NULL, (type) 0); \
121 return g_array_index (msg->field, type, idx); \
123 #define DEFINE_ARRAY_INSERT(method, field, intype, dup_method, type) \
124 GstSDPResult gst_sdp_message_insert_##method (GstSDPMessage *msg, gint idx, intype val) { \
127 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
128 dup_method (v, val); \
130 g_array_append_val (msg->field, vt); \
132 g_array_insert_val (msg->field, idx, vt); \
136 #define DEFINE_ARRAY_REPLACE(method, field, intype, free_method, dup_method, type) \
137 GstSDPResult gst_sdp_message_replace_##method (GstSDPMessage *msg, guint idx, intype val) { \
139 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
140 v = &g_array_index (msg->field, type, idx); \
142 dup_method (v, val); \
145 #define DEFINE_ARRAY_REMOVE(method, field, type, free_method) \
146 GstSDPResult gst_sdp_message_remove_##method (GstSDPMessage *msg, guint idx) { \
148 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
149 v = &g_array_index (msg->field, type, idx); \
151 g_array_remove_index (msg->field, idx); \
154 #define DEFINE_ARRAY_ADDER(method, type) \
155 GstSDPResult gst_sdp_message_add_##method (GstSDPMessage *msg, const type val) { \
156 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL); \
157 return gst_sdp_message_insert_##method (msg, -1, val); \
160 #define dup_string(v,val) ((*v) = g_strdup (val))
161 #define INIT_STR_ARRAY(field) \
162 INIT_ARRAY (field, gchar *, free_string)
163 #define DEFINE_STR_ARRAY_GETTER(method, field) \
164 DEFINE_PTR_ARRAY_GETTER(method, field, gchar *)
165 #define DEFINE_STR_ARRAY_INSERT(method, field) \
166 DEFINE_ARRAY_INSERT (method, field, const gchar *, dup_string, gchar *)
167 #define DEFINE_STR_ARRAY_ADDER(method, field) \
168 DEFINE_ARRAY_ADDER (method, gchar *)
169 #define DEFINE_STR_ARRAY_REPLACE(method, field) \
170 DEFINE_ARRAY_REPLACE (method, field, const gchar *, free_string, dup_string, gchar *)
171 #define DEFINE_STR_ARRAY_REMOVE(method, field) \
172 DEFINE_ARRAY_REMOVE (method, field, gchar *, free_string)
174 static GstSDPMessage *gst_sdp_message_boxed_copy (GstSDPMessage * orig);
175 static void gst_sdp_message_boxed_free (GstSDPMessage * msg);
177 G_DEFINE_BOXED_TYPE (GstSDPMessage, gst_sdp_message, gst_sdp_message_boxed_copy,
178 gst_sdp_message_boxed_free);
180 static GstSDPMessage *
181 gst_sdp_message_boxed_copy (GstSDPMessage * orig)
188 if (gst_sdp_message_copy (orig, ©) == GST_SDP_OK)
195 gst_sdp_message_boxed_free (GstSDPMessage * msg)
197 gst_sdp_message_free (msg);
201 gst_sdp_origin_init (GstSDPOrigin * origin)
203 FREE_STRING (origin->username);
204 FREE_STRING (origin->sess_id);
205 FREE_STRING (origin->sess_version);
206 FREE_STRING (origin->nettype);
207 FREE_STRING (origin->addrtype);
208 FREE_STRING (origin->addr);
212 gst_sdp_key_init (GstSDPKey * key)
214 FREE_STRING (key->type);
215 FREE_STRING (key->data);
219 * gst_sdp_message_new:
220 * @msg: (out) (transfer full): pointer to new #GstSDPMessage
222 * Allocate a new GstSDPMessage and store the result in @msg.
224 * Returns: a #GstSDPResult.
227 gst_sdp_message_new (GstSDPMessage ** msg)
229 GstSDPMessage *newmsg;
231 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
233 newmsg = g_new0 (GstSDPMessage, 1);
237 return gst_sdp_message_init (newmsg);
241 * gst_sdp_message_new_from_text:
242 * @text: A dynamically allocated string representing the SDP description
243 * @msg: (out) (transfer full): pointer to new #GstSDPMessage
245 * Parse @text and create a new SDPMessage from these.
247 * Returns: a #GstSDPResult.
251 gst_sdp_message_new_from_text (const gchar * text, GstSDPMessage ** msg)
255 if ((res = gst_sdp_message_new (msg)) != GST_SDP_OK)
259 gst_sdp_message_parse_buffer ((const guint8 *) text, strlen (text), *msg);
265 * gst_sdp_message_init:
266 * @msg: (out caller-allocates): a #GstSDPMessage
268 * Initialize @msg so that its contents are as if it was freshly allocated
269 * with gst_sdp_message_new(). This function is mostly used to initialize a message
270 * allocated on the stack. gst_sdp_message_uninit() undoes this operation.
272 * When this function is invoked on newly allocated data (with malloc or on the
273 * stack), its contents should be set to 0 before calling this function.
275 * Returns: a #GstSDPResult.
278 gst_sdp_message_init (GstSDPMessage * msg)
280 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
282 FREE_STRING (msg->version);
283 gst_sdp_origin_init (&msg->origin);
284 FREE_STRING (msg->session_name);
285 FREE_STRING (msg->information);
286 FREE_STRING (msg->uri);
287 INIT_STR_ARRAY (msg->emails);
288 INIT_STR_ARRAY (msg->phones);
289 gst_sdp_connection_clear (&msg->connection);
290 INIT_ARRAY (msg->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_clear);
291 INIT_ARRAY (msg->times, GstSDPTime, gst_sdp_time_clear);
292 INIT_ARRAY (msg->zones, GstSDPZone, gst_sdp_zone_clear);
293 gst_sdp_key_init (&msg->key);
294 INIT_ARRAY (msg->attributes, GstSDPAttribute, gst_sdp_attribute_clear);
295 INIT_ARRAY (msg->medias, GstSDPMedia, gst_sdp_media_uninit);
301 * gst_sdp_message_uninit:
302 * @msg: a #GstSDPMessage
304 * Free all resources allocated in @msg. @msg should not be used anymore after
305 * this function. This function should be used when @msg was allocated on the
306 * stack and initialized with gst_sdp_message_init().
308 * Returns: a #GstSDPResult.
311 gst_sdp_message_uninit (GstSDPMessage * msg)
313 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
315 gst_sdp_message_init (msg);
317 FREE_ARRAY (msg->emails);
318 FREE_ARRAY (msg->phones);
319 FREE_ARRAY (msg->bandwidths);
320 FREE_ARRAY (msg->times);
321 FREE_ARRAY (msg->zones);
322 FREE_ARRAY (msg->attributes);
323 FREE_ARRAY (msg->medias);
329 * gst_sdp_message_copy:
330 * @msg: a #GstSDPMessage
331 * @copy: (out) (transfer full): pointer to new #GstSDPMessage
333 * Allocate a new copy of @msg and store the result in @copy. The value in
334 * @copy should be release with gst_sdp_message_free function.
336 * Returns: a #GstSDPResult
341 gst_sdp_message_copy (const GstSDPMessage * msg, GstSDPMessage ** copy)
346 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
348 gst_sdp_message_new (copy);
352 REPLACE_STRING (cp->version, msg->version);
353 gst_sdp_message_set_origin (cp, msg->origin.username, msg->origin.sess_id,
354 msg->origin.sess_version, msg->origin.nettype, msg->origin.addrtype,
356 REPLACE_STRING (cp->session_name, msg->session_name);
357 REPLACE_STRING (cp->information, msg->information);
358 REPLACE_STRING (cp->uri, msg->uri);
360 len = gst_sdp_message_emails_len (msg);
361 for (i = 0; i < len; i++) {
362 gst_sdp_message_add_email (cp, gst_sdp_message_get_email (msg, i));
365 len = gst_sdp_message_phones_len (msg);
366 for (i = 0; i < len; i++) {
367 gst_sdp_message_add_phone (cp, gst_sdp_message_get_phone (msg, i));
370 gst_sdp_message_set_connection (cp, msg->connection.nettype,
371 msg->connection.addrtype, msg->connection.address, msg->connection.ttl,
372 msg->connection.addr_number);
374 len = gst_sdp_message_bandwidths_len (msg);
375 for (i = 0; i < len; i++) {
376 const GstSDPBandwidth *bw = gst_sdp_message_get_bandwidth (msg, i);
377 gst_sdp_message_add_bandwidth (cp, bw->bwtype, bw->bandwidth);
380 len = gst_sdp_message_times_len (msg);
381 for (i = 0; i < len; i++) {
382 const gchar **repeat = NULL;
383 const GstSDPTime *time = gst_sdp_message_get_time (msg, i);
385 if (time->repeat != NULL) {
388 repeat = g_malloc0 ((time->repeat->len + 1) * sizeof (gchar *));
389 for (j = 0; j < time->repeat->len; j++) {
390 repeat[j] = g_array_index (time->repeat, char *, j);
395 gst_sdp_message_add_time (cp, time->start, time->stop, repeat);
397 g_free ((gchar **) repeat);
400 len = gst_sdp_message_zones_len (msg);
401 for (i = 0; i < len; i++) {
402 const GstSDPZone *zone = gst_sdp_message_get_zone (msg, i);
403 gst_sdp_message_add_zone (cp, zone->time, zone->typed_time);
406 gst_sdp_message_set_key (cp, msg->key.type, msg->key.data);
408 len = gst_sdp_message_attributes_len (msg);
409 for (i = 0; i < len; i++) {
410 const GstSDPAttribute *attr = gst_sdp_message_get_attribute (msg, i);
411 gst_sdp_message_add_attribute (cp, attr->key, attr->value);
414 len = gst_sdp_message_medias_len (msg);
415 for (i = 0; i < len; i++) {
416 GstSDPMedia *media_copy;
417 const GstSDPMedia *media = gst_sdp_message_get_media (msg, i);
419 if (gst_sdp_media_copy (media, &media_copy) == GST_SDP_OK) {
420 gst_sdp_message_add_media (cp, media_copy);
421 gst_sdp_media_free (media_copy);
429 * gst_sdp_message_free:
430 * @msg: a #GstSDPMessage
432 * Free all resources allocated by @msg. @msg should not be used anymore after
433 * this function. This function should be used when @msg was dynamically
434 * allocated with gst_sdp_message_new().
436 * Returns: a #GstSDPResult.
439 gst_sdp_message_free (GstSDPMessage * msg)
441 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
443 gst_sdp_message_uninit (msg);
450 * gst_sdp_address_is_multicast:
451 * @nettype: a network type
452 * @addrtype: an address type
455 * Check if the given @addr is a multicast address.
457 * Returns: TRUE when @addr is multicast.
460 gst_sdp_address_is_multicast (const gchar * nettype, const gchar * addrtype,
463 gboolean ret = FALSE;
466 g_return_val_if_fail (addr, FALSE);
468 /* we only support IN */
469 if (nettype && strcmp (nettype, "IN") != 0)
472 /* guard against parse failures */
473 if ((iaddr = g_inet_address_new_from_string (addr)) == NULL)
476 ret = g_inet_address_get_is_multicast (iaddr);
477 g_object_unref (iaddr);
483 * gst_sdp_message_as_text:
484 * @msg: a #GstSDPMessage
486 * Convert the contents of @msg to a text string.
488 * Returns: (transfer full): A dynamically allocated string representing the SDP description.
491 gst_sdp_message_as_text (const GstSDPMessage * msg)
493 /* change all vars so they match rfc? */
497 g_return_val_if_fail (msg != NULL, NULL);
499 lines = g_string_new ("");
502 g_string_append_printf (lines, "v=%s\r\n", msg->version);
504 if (msg->origin.sess_id && msg->origin.sess_version && msg->origin.nettype &&
505 msg->origin.addrtype && msg->origin.addr)
506 g_string_append_printf (lines, "o=%s %s %s %s %s %s\r\n",
507 msg->origin.username ? msg->origin.username : "-", msg->origin.sess_id,
508 msg->origin.sess_version, msg->origin.nettype, msg->origin.addrtype,
511 if (msg->session_name)
512 g_string_append_printf (lines, "s=%s\r\n", msg->session_name);
514 if (msg->information)
515 g_string_append_printf (lines, "i=%s\r\n", msg->information);
518 g_string_append_printf (lines, "u=%s\r\n", msg->uri);
520 for (i = 0; i < gst_sdp_message_emails_len (msg); i++)
521 g_string_append_printf (lines, "e=%s\r\n",
522 gst_sdp_message_get_email (msg, i));
524 for (i = 0; i < gst_sdp_message_phones_len (msg); i++)
525 g_string_append_printf (lines, "p=%s\r\n",
526 gst_sdp_message_get_phone (msg, i));
528 if (msg->connection.nettype && msg->connection.addrtype &&
529 msg->connection.address) {
530 g_string_append_printf (lines, "c=%s %s %s", msg->connection.nettype,
531 msg->connection.addrtype, msg->connection.address);
532 if (gst_sdp_address_is_multicast (msg->connection.nettype,
533 msg->connection.addrtype, msg->connection.address)) {
534 /* only add ttl for IP4 */
535 if (strcmp (msg->connection.addrtype, "IP4") == 0)
536 g_string_append_printf (lines, "/%u", msg->connection.ttl);
537 if (msg->connection.addr_number > 1)
538 g_string_append_printf (lines, "/%u", msg->connection.addr_number);
540 g_string_append_printf (lines, "\r\n");
543 for (i = 0; i < gst_sdp_message_bandwidths_len (msg); i++) {
544 const GstSDPBandwidth *bandwidth = gst_sdp_message_get_bandwidth (msg, i);
546 g_string_append_printf (lines, "b=%s:%u\r\n", bandwidth->bwtype,
547 bandwidth->bandwidth);
550 if (gst_sdp_message_times_len (msg) == 0) {
551 g_string_append_printf (lines, "t=0 0\r\n");
553 for (i = 0; i < gst_sdp_message_times_len (msg); i++) {
554 const GstSDPTime *times = gst_sdp_message_get_time (msg, i);
556 g_string_append_printf (lines, "t=%s %s\r\n", times->start, times->stop);
558 if (times->repeat != NULL) {
561 g_string_append_printf (lines, "r=%s",
562 g_array_index (times->repeat, gchar *, 0));
563 for (j = 1; j < times->repeat->len; j++)
564 g_string_append_printf (lines, " %s",
565 g_array_index (times->repeat, gchar *, j));
566 g_string_append_printf (lines, "\r\n");
571 if (gst_sdp_message_zones_len (msg) > 0) {
572 const GstSDPZone *zone = gst_sdp_message_get_zone (msg, 0);
574 g_string_append_printf (lines, "z=%s %s", zone->time, zone->typed_time);
575 for (i = 1; i < gst_sdp_message_zones_len (msg); i++) {
576 zone = gst_sdp_message_get_zone (msg, i);
577 g_string_append_printf (lines, " %s %s", zone->time, zone->typed_time);
579 g_string_append_printf (lines, "\r\n");
583 g_string_append_printf (lines, "k=%s", msg->key.type);
585 g_string_append_printf (lines, ":%s", msg->key.data);
586 g_string_append_printf (lines, "\r\n");
589 for (i = 0; i < gst_sdp_message_attributes_len (msg); i++) {
590 const GstSDPAttribute *attr = gst_sdp_message_get_attribute (msg, i);
593 g_string_append_printf (lines, "a=%s", attr->key);
594 if (attr->value && attr->value[0] != '\0')
595 g_string_append_printf (lines, ":%s", attr->value);
596 g_string_append_printf (lines, "\r\n");
600 for (i = 0; i < gst_sdp_message_medias_len (msg); i++) {
601 const GstSDPMedia *media = gst_sdp_message_get_media (msg, i);
602 gchar *sdp_media_str;
604 sdp_media_str = gst_sdp_media_as_text (media);
605 g_string_append_printf (lines, "%s", sdp_media_str);
606 g_free (sdp_media_str);
609 return g_string_free (lines, FALSE);
615 return c >= '0' && c <= '9' ? c - '0'
616 : c >= 'A' && c <= 'F' ? c - 'A' + 10
617 : c >= 'a' && c <= 'f' ? c - 'a' + 10 : 0;
621 * gst_sdp_message_parse_uri:
622 * @uri: the start of the uri
623 * @msg: (out caller-allocates): the result #GstSDPMessage
625 * Parse the null-terminated @uri and store the result in @msg.
627 * The uri should be of the form:
629 * scheme://[address[:ttl=ttl][:noa=noa]]/[sessionname]
630 * [#type=value *[&type=value]]
632 * where value is url encoded. This looslely resembles
633 * http://tools.ietf.org/html/draft-fujikawa-sdp-url-01
635 * Returns: #GST_SDP_OK on success.
638 gst_sdp_message_parse_uri (const gchar * uri, GstSDPMessage * msg)
642 const gchar *colon, *slash, *hash, *p;
645 g_return_val_if_fail (uri != NULL, GST_SDP_EINVAL);
646 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
648 colon = strstr (uri, "://");
652 /* FIXME connection info goes here */
654 slash = strstr (colon + 3, "/");
658 /* FIXME session name goes here */
660 hash = strstr (slash + 1, "#");
664 lines = g_string_new ("");
667 for (p = hash + 1; *p; p++) {
669 g_string_append_printf (lines, "\r\n");
671 g_string_append_c (lines, ' ');
672 else if (*p == '%') {
677 g_string_append_c (lines, (hex_to_int (a) << 4) | hex_to_int (b));
684 g_string_append_c (lines, *p);
687 message = g_string_free (lines, FALSE);
689 gst_sdp_message_parse_buffer ((const guint8 *) message, strlen (message),
698 return GST_SDP_EINVAL;
702 return GST_SDP_EINVAL;
706 return GST_SDP_EINVAL;
710 static const guchar acceptable[96] = {
711 /* X0 X1 X2 X3 X4 X5 X6 X7 X8 X9 XA XB XC XD XE XF */
712 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x00, /* 2X !"#$%&'()*+,-./ */
713 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 3X 0123456789:;<=>? */
714 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 4X @ABCDEFGHIJKLMNO */
715 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, /* 5X PQRSTUVWXYZ[\]^_ */
716 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, /* 6X `abcdefghijklmno */
717 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 /* 7X pqrstuvwxyz{|}~DEL */
720 static const gchar hex[16] = "0123456789ABCDEF";
722 #define ACCEPTABLE_CHAR(a) (((guchar)(a))>=32 && ((guchar)(a))<128 && acceptable[(((guchar)a))-32])
725 * gst_sdp_message_as_uri:
726 * @scheme: the uri scheme
727 * @msg: the #GstSDPMessage
729 * Creates a uri from @msg with the given @scheme. The uri has the format:
731 * \@scheme:///[#type=value *[&type=value]]
733 * Where each value is url encoded.
735 * Returns: (transfer full): a uri for @msg.
738 gst_sdp_message_as_uri (const gchar * scheme, const GstSDPMessage * msg)
740 gchar *serialized, *p;
745 g_return_val_if_fail (scheme != NULL, NULL);
746 g_return_val_if_fail (msg != NULL, NULL);
748 serialized = gst_sdp_message_as_text (msg);
750 lines = g_string_new ("");
751 g_string_append_printf (lines, "%s:///#", scheme);
755 for (p = serialized; *p; p++) {
757 g_string_append_printf (lines, "%c=", *p);
765 else if (*p == '\n') {
767 g_string_append_c (lines, '&');
769 } else if (*p == ' ')
770 g_string_append_c (lines, '+');
771 else if (ACCEPTABLE_CHAR (*p))
772 g_string_append_c (lines, *p);
775 g_string_append_printf (lines, "%%%c%c", hex[*p >> 4], hex[*p & 0xf]);
779 res = g_string_free (lines, FALSE);
786 * gst_sdp_message_set_version:
787 * @msg: a #GstSDPMessage
788 * @version: the version
790 * Set the version in @msg.
792 * Returns: a #GstSDPResult.
794 DEFINE_STRING_SETTER (version);
796 * gst_sdp_message_get_version:
797 * @msg: a #GstSDPMessage
799 * Get the version in @msg.
801 * Returns: a #GstSDPResult.
803 DEFINE_STRING_GETTER (version);
806 * gst_sdp_message_set_origin:
807 * @msg: a #GstSDPMessage
808 * @username: the user name
809 * @sess_id: a session id
810 * @sess_version: a session version
811 * @nettype: a network type
812 * @addrtype: an address type
815 * Configure the SDP origin in @msg with the given parameters.
817 * Returns: #GST_SDP_OK.
820 gst_sdp_message_set_origin (GstSDPMessage * msg, const gchar * username,
821 const gchar * sess_id, const gchar * sess_version, const gchar * nettype,
822 const gchar * addrtype, const gchar * addr)
824 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
826 REPLACE_STRING (msg->origin.username, username);
827 REPLACE_STRING (msg->origin.sess_id, sess_id);
828 REPLACE_STRING (msg->origin.sess_version, sess_version);
829 REPLACE_STRING (msg->origin.nettype, nettype);
830 REPLACE_STRING (msg->origin.addrtype, addrtype);
831 REPLACE_STRING (msg->origin.addr, addr);
837 * gst_sdp_message_get_origin:
838 * @msg: a #GstSDPMessage
840 * Get the origin of @msg.
842 * Returns: a #GstSDPOrigin. The result remains valid as long as @msg is valid.
845 gst_sdp_message_get_origin (const GstSDPMessage * msg)
847 g_return_val_if_fail (msg != NULL, NULL);
853 * gst_sdp_message_set_session_name:
854 * @msg: a #GstSDPMessage
855 * @session_name: the session name
857 * Set the session name in @msg.
859 * Returns: a #GstSDPResult.
861 DEFINE_STRING_SETTER (session_name);
863 * gst_sdp_message_get_session_name:
864 * @msg: a #GstSDPMessage
866 * Get the session name in @msg.
868 * Returns: a #GstSDPResult.
870 DEFINE_STRING_GETTER (session_name);
872 * gst_sdp_message_set_information:
873 * @msg: a #GstSDPMessage
874 * @information: the information
876 * Set the information in @msg.
878 * Returns: a #GstSDPResult.
880 DEFINE_STRING_SETTER (information);
882 * gst_sdp_message_get_information:
883 * @msg: a #GstSDPMessage
885 * Get the information in @msg.
887 * Returns: a #GstSDPResult.
889 DEFINE_STRING_GETTER (information);
891 * gst_sdp_message_set_uri:
892 * @msg: a #GstSDPMessage
895 * Set the URI in @msg.
897 * Returns: a #GstSDPResult.
899 DEFINE_STRING_SETTER (uri);
901 * gst_sdp_message_get_uri:
902 * @msg: a #GstSDPMessage
904 * Get the URI in @msg.
906 * Returns: a #GstSDPResult.
908 DEFINE_STRING_GETTER (uri);
911 * gst_sdp_message_emails_len:
912 * @msg: a #GstSDPMessage
914 * Get the number of emails in @msg.
916 * Returns: the number of emails in @msg.
918 DEFINE_ARRAY_LEN (emails);
920 * gst_sdp_message_get_email:
921 * @msg: a #GstSDPMessage
922 * @idx: an email index
924 * Get the email with number @idx from @msg.
926 * Returns: the email at position @idx.
928 DEFINE_STR_ARRAY_GETTER (email, emails);
931 * gst_sdp_message_insert_email:
932 * @msg: a #GstSDPMessage
936 * Insert @email into the array of emails in @msg at index @idx.
937 * When -1 is given as @idx, the email is inserted at the end.
939 * Returns: a #GstSDPResult.
943 DEFINE_STR_ARRAY_INSERT (email, emails);
946 * gst_sdp_message_replace_email:
947 * @msg: a #GstSDPMessage
948 * @idx: an email index
951 * Replace the email in @msg at index @idx with @email.
953 * Returns: a #GstSDPResult.
957 DEFINE_STR_ARRAY_REPLACE (email, emails);
960 * gst_sdp_message_remove_email:
961 * @msg: a #GstSDPMessage
962 * @idx: an email index
964 * Remove the email in @msg at index @idx.
966 * Returns: a #GstSDPResult.
970 DEFINE_STR_ARRAY_REMOVE (email, emails);
973 * gst_sdp_message_add_email:
974 * @msg: a #GstSDPMessage
977 * Add @email to the list of emails in @msg.
979 * Returns: a #GstSDPResult.
981 DEFINE_STR_ARRAY_ADDER (email, emails);
984 * gst_sdp_message_phones_len:
985 * @msg: a #GstSDPMessage
987 * Get the number of phones in @msg.
989 * Returns: the number of phones in @msg.
991 DEFINE_ARRAY_LEN (phones);
993 * gst_sdp_message_get_phone:
994 * @msg: a #GstSDPMessage
995 * @idx: a phone index
997 * Get the phone with number @idx from @msg.
999 * Returns: the phone at position @idx.
1001 DEFINE_STR_ARRAY_GETTER (phone, phones);
1004 * gst_sdp_message_insert_phone:
1005 * @msg: a #GstSDPMessage
1006 * @idx: a phone index
1009 * Insert @phone into the array of phone numbers in @msg at index @idx.
1010 * When -1 is given as @idx, the phone is inserted at the end.
1012 * Returns: a #GstSDPResult.
1016 DEFINE_STR_ARRAY_INSERT (phone, phones);
1019 * gst_sdp_message_replace_phone:
1020 * @msg: a #GstSDPMessage
1021 * @idx: a phone index
1024 * Replace the phone number in @msg at index @idx with @phone.
1026 * Returns: a #GstSDPResult.
1030 DEFINE_STR_ARRAY_REPLACE (phone, phones);
1033 * gst_sdp_message_remove_phone:
1034 * @msg: a #GstSDPMessage
1035 * @idx: a phone index
1037 * Remove the phone number in @msg at index @idx.
1039 * Returns: a #GstSDPResult.
1043 DEFINE_STR_ARRAY_REMOVE (phone, phones);
1046 * gst_sdp_message_add_phone:
1047 * @msg: a #GstSDPMessage
1050 * Add @phone to the list of phones in @msg.
1052 * Returns: a #GstSDPResult.
1054 DEFINE_STR_ARRAY_ADDER (phone, phones);
1058 * gst_sdp_message_set_connection:
1059 * @msg: a #GstSDPMessage
1060 * @nettype: the type of network. "IN" is defined to have the meaning
1062 * @addrtype: the type of address.
1063 * @address: the address
1064 * @ttl: the time to live of the address
1065 * @addr_number: the number of layers
1067 * Configure the SDP connection in @msg with the given parameters.
1069 * Returns: a #GstSDPResult.
1072 gst_sdp_message_set_connection (GstSDPMessage * msg, const gchar * nettype,
1073 const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
1075 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1077 REPLACE_STRING (msg->connection.nettype, nettype);
1078 REPLACE_STRING (msg->connection.addrtype, addrtype);
1079 REPLACE_STRING (msg->connection.address, address);
1080 msg->connection.ttl = ttl;
1081 msg->connection.addr_number = addr_number;
1087 * gst_sdp_message_get_connection:
1088 * @msg: a #GstSDPMessage
1090 * Get the connection of @msg.
1092 * Returns: a #GstSDPConnection. The result remains valid as long as @msg is valid.
1094 const GstSDPConnection *
1095 gst_sdp_message_get_connection (const GstSDPMessage * msg)
1097 g_return_val_if_fail (msg != NULL, NULL);
1099 return &msg->connection;
1103 * gst_sdp_bandwidth_set:
1104 * @bw: a #GstSDPBandwidth
1105 * @bwtype: the bandwidth modifier type
1106 * @bandwidth: the bandwidth in kilobits per second
1108 * Set bandwidth information in @bw.
1110 * Returns: a #GstSDPResult.
1115 gst_sdp_bandwidth_set (GstSDPBandwidth * bw, const gchar * bwtype,
1118 g_return_val_if_fail (bw != NULL, GST_SDP_EINVAL);
1120 bw->bwtype = g_strdup (bwtype);
1121 bw->bandwidth = bandwidth;
1126 * gst_sdp_bandwidth_clear:
1127 * @bw: a #GstSDPBandwidth
1129 * Reset the bandwidth information in @bw.
1131 * Returns: a #GstSDPResult.
1136 gst_sdp_bandwidth_clear (GstSDPBandwidth * bw)
1138 g_return_val_if_fail (bw != NULL, GST_SDP_EINVAL);
1140 FREE_STRING (bw->bwtype);
1146 * gst_sdp_message_bandwidths_len:
1147 * @msg: a #GstSDPMessage
1149 * Get the number of bandwidth information in @msg.
1151 * Returns: the number of bandwidth information in @msg.
1153 DEFINE_ARRAY_LEN (bandwidths);
1155 * gst_sdp_message_get_bandwidth:
1156 * @msg: a #GstSDPMessage
1157 * @idx: the bandwidth index
1159 * Get the bandwidth at index @idx from @msg.
1161 * Returns: a #GstSDPBandwidth.
1163 DEFINE_ARRAY_GETTER (bandwidth, bandwidths, GstSDPBandwidth);
1165 #define DUP_BANDWIDTH(v, val) memcpy (v, val, sizeof (GstSDPBandwidth))
1166 #define FREE_BANDWIDTH(v) gst_sdp_bandwidth_clear(v)
1169 * gst_sdp_message_insert_bandwidth:
1170 * @msg: a #GstSDPMessage
1172 * @bw: the bandwidth
1174 * Insert bandwidth parameters into the array of bandwidths in @msg
1176 * When -1 is given as @idx, the bandwidth is inserted at the end.
1178 * Returns: a #GstSDPResult.
1182 DEFINE_ARRAY_INSERT (bandwidth, bandwidths, GstSDPBandwidth *, DUP_BANDWIDTH,
1186 * gst_sdp_message_replace_bandwidth:
1187 * @msg: a #GstSDPMessage
1188 * @idx: the bandwidth index
1189 * @bw: the bandwidth
1191 * Replace the bandwidth information in @msg at index @idx with @bw.
1193 * Returns: a #GstSDPResult.
1197 DEFINE_ARRAY_REPLACE (bandwidth, bandwidths, GstSDPBandwidth *, FREE_BANDWIDTH,
1198 DUP_BANDWIDTH, GstSDPBandwidth);
1201 * gst_sdp_message_remove_bandwidth:
1202 * @msg: a #GstSDPMessage
1203 * @idx: the bandwidth index
1205 * Remove the bandwidth information in @msg at index @idx.
1207 * Returns: a #GstSDPResult.
1211 DEFINE_ARRAY_REMOVE (bandwidth, bandwidths, GstSDPBandwidth, FREE_BANDWIDTH);
1214 * gst_sdp_message_add_bandwidth:
1215 * @msg: a #GstSDPMessage
1216 * @bwtype: the bandwidth modifier type
1217 * @bandwidth: the bandwidth in kilobits per second
1219 * Add the specified bandwidth information to @msg.
1221 * Returns: a #GstSDPResult.
1224 gst_sdp_message_add_bandwidth (GstSDPMessage * msg, const gchar * bwtype,
1229 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1231 gst_sdp_bandwidth_set (&bw, bwtype, bandwidth);
1232 return gst_sdp_message_insert_bandwidth (msg, -1, &bw);
1238 * @start: the start time
1239 * @stop: the stop time
1240 * @repeat: (array zero-terminated=1): the repeat times
1242 * Set time information @start, @stop and @repeat in @t.
1244 * Returns: a #GstSDPResult.
1249 gst_sdp_time_set (GstSDPTime * t, const gchar * start,
1250 const gchar * stop, const gchar ** repeat)
1252 g_return_val_if_fail (t != NULL, GST_SDP_EINVAL);
1254 t->start = g_strdup (start);
1255 t->stop = g_strdup (stop);
1257 t->repeat = g_array_new (FALSE, TRUE, sizeof (gchar *));
1258 for (; *repeat; repeat++) {
1259 gchar *r = g_strdup (*repeat);
1261 g_array_append_val (t->repeat, r);
1270 * gst_sdp_time_clear:
1273 * Reset the time information in @t.
1275 * Returns: a #GstSDPResult.
1280 gst_sdp_time_clear (GstSDPTime * t)
1282 g_return_val_if_fail (t != NULL, GST_SDP_EINVAL);
1284 FREE_STRING (t->start);
1285 FREE_STRING (t->stop);
1286 INIT_STR_ARRAY (t->repeat);
1287 FREE_ARRAY (t->repeat);
1293 * gst_sdp_message_times_len:
1294 * @msg: a #GstSDPMessage
1296 * Get the number of time information entries in @msg.
1298 * Returns: the number of time information entries in @msg.
1300 DEFINE_ARRAY_LEN (times);
1303 * gst_sdp_message_get_time:
1304 * @msg: a #GstSDPMessage
1305 * @idx: the time index
1307 * Get time information with index @idx from @msg.
1309 * Returns: a #GstSDPTime.
1311 DEFINE_ARRAY_GETTER (time, times, GstSDPTime);
1313 #define DUP_TIME(v, val) memcpy (v, val, sizeof (GstSDPTime))
1314 #define FREE_TIME(v) gst_sdp_time_clear(v)
1317 * gst_sdp_message_insert_time:
1318 * @msg: a #GstSDPMessage
1322 * Insert time parameters into the array of times in @msg
1324 * When -1 is given as @idx, the times are inserted at the end.
1326 * Returns: a #GstSDPResult.
1330 DEFINE_ARRAY_INSERT (time, times, GstSDPTime *, DUP_TIME, GstSDPTime);
1333 * gst_sdp_message_replace_time:
1334 * @msg: a #GstSDPMessage
1338 * Replace the time information in @msg at index @idx with @t.
1340 * Returns: a #GstSDPResult.
1344 DEFINE_ARRAY_REPLACE (time, times, GstSDPTime *, FREE_TIME,
1345 DUP_TIME, GstSDPTime);
1348 * gst_sdp_message_remove_time:
1349 * @msg: a #GstSDPMessage
1352 * Remove the time information in @msg at index @idx.
1354 * Returns: a #GstSDPResult.
1358 DEFINE_ARRAY_REMOVE (time, times, GstSDPTime, FREE_TIME);
1361 * gst_sdp_message_add_time:
1362 * @msg: a #GstSDPMessage
1363 * @start: the start time
1364 * @stop: the stop time
1365 * @repeat: (array zero-terminated=1): the repeat times
1367 * Add time information @start and @stop to @msg.
1369 * Returns: a #GstSDPResult.
1372 gst_sdp_message_add_time (GstSDPMessage * msg, const gchar * start,
1373 const gchar * stop, const gchar ** repeat)
1377 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1379 gst_sdp_time_set (×, start, stop, repeat);
1380 g_array_append_val (msg->times, times);
1387 * @zone: a #GstSDPZone
1388 * @adj_time: the NTP time that a time zone adjustment happens
1389 * @typed_time: the offset from the time when the session was first scheduled
1391 * Set zone information in @zone.
1393 * Returns: a #GstSDPResult.
1398 gst_sdp_zone_set (GstSDPZone * zone, const gchar * adj_time,
1399 const gchar * typed_time)
1401 g_return_val_if_fail (zone != NULL, GST_SDP_EINVAL);
1403 zone->time = g_strdup (adj_time);
1404 zone->typed_time = g_strdup (typed_time);
1409 * gst_sdp_zone_clear:
1410 * @zone: a #GstSDPZone
1412 * Reset the zone information in @zone.
1414 * Returns: a #GstSDPResult.
1419 gst_sdp_zone_clear (GstSDPZone * zone)
1421 g_return_val_if_fail (zone != NULL, GST_SDP_EINVAL);
1423 FREE_STRING (zone->time);
1424 FREE_STRING (zone->typed_time);
1429 * gst_sdp_message_zones_len:
1430 * @msg: a #GstSDPMessage
1432 * Get the number of time zone information entries in @msg.
1434 * Returns: the number of time zone information entries in @msg.
1436 DEFINE_ARRAY_LEN (zones);
1438 * gst_sdp_message_get_zone:
1439 * @msg: a #GstSDPMessage
1440 * @idx: the zone index
1442 * Get time zone information with index @idx from @msg.
1444 * Returns: a #GstSDPZone.
1446 DEFINE_ARRAY_GETTER (zone, zones, GstSDPZone);
1448 #define DUP_ZONE(v, val) memcpy (v, val, sizeof (GstSDPZone))
1449 #define FREE_ZONE(v) gst_sdp_zone_clear(v)
1452 * gst_sdp_message_insert_zone:
1453 * @msg: a #GstSDPMessage
1455 * @zone: a #GstSDPZone
1457 * Insert zone parameters into the array of zones in @msg
1459 * When -1 is given as @idx, the zone is inserted at the end.
1461 * Returns: a #GstSDPResult.
1465 DEFINE_ARRAY_INSERT (zone, zones, GstSDPZone *, DUP_ZONE, GstSDPZone);
1468 * gst_sdp_message_replace_zone:
1469 * @msg: a #GstSDPMessage
1471 * @zone: a #GstSDPZone
1473 * Replace the zone information in @msg at index @idx with @zone.
1475 * Returns: a #GstSDPResult.
1479 DEFINE_ARRAY_REPLACE (zone, zones, GstSDPZone *, FREE_ZONE,
1480 DUP_ZONE, GstSDPZone);
1483 * gst_sdp_message_remove_zone:
1484 * @msg: a #GstSDPMessage
1487 * Remove the zone information in @msg at index @idx.
1489 * Returns: a #GstSDPResult.
1493 DEFINE_ARRAY_REMOVE (zone, zones, GstSDPZone, FREE_ZONE);
1496 * gst_sdp_message_add_zone:
1497 * @msg: a #GstSDPMessage
1498 * @adj_time: the NTP time that a time zone adjustment happens
1499 * @typed_time: the offset from the time when the session was first scheduled
1501 * Add time zone information to @msg.
1503 * Returns: a #GstSDPResult.
1506 gst_sdp_message_add_zone (GstSDPMessage * msg, const gchar * adj_time,
1507 const gchar * typed_time)
1511 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1513 gst_sdp_zone_set (&zone, adj_time, typed_time);
1514 g_array_append_val (msg->zones, zone);
1520 * gst_sdp_message_set_key:
1521 * @msg: a #GstSDPMessage
1522 * @type: the encryption type
1523 * @data: the encryption data
1525 * Adds the encryption information to @msg.
1527 * Returns: a #GstSDPResult.
1530 gst_sdp_message_set_key (GstSDPMessage * msg, const gchar * type,
1533 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1535 REPLACE_STRING (msg->key.type, type);
1536 REPLACE_STRING (msg->key.data, data);
1542 * gst_sdp_message_get_key:
1543 * @msg: a #GstSDPMessage
1545 * Get the encryption information from @msg.
1547 * Returns: a #GstSDPKey.
1550 gst_sdp_message_get_key (const GstSDPMessage * msg)
1552 g_return_val_if_fail (msg != NULL, NULL);
1558 * gst_sdp_attribute_set:
1559 * @attr: a #GstSDPAttribute
1561 * @value: (nullable): the value
1563 * Set the attribute with @key and @value.
1565 * Returns: @GST_SDP_OK.
1570 gst_sdp_attribute_set (GstSDPAttribute * attr, const gchar * key,
1571 const gchar * value)
1573 g_return_val_if_fail (attr != NULL, GST_SDP_EINVAL);
1574 g_return_val_if_fail (key != NULL, GST_SDP_EINVAL);
1576 attr->key = g_strdup (key);
1577 attr->value = g_strdup (value);
1582 * gst_sdp_attribute_clear:
1583 * @attr: a #GstSDPAttribute
1585 * Clear the attribute.
1587 * Returns: @GST_SDP_OK.
1592 gst_sdp_attribute_clear (GstSDPAttribute * attr)
1594 g_return_val_if_fail (attr != NULL, GST_SDP_EINVAL);
1596 FREE_STRING (attr->key);
1597 FREE_STRING (attr->value);
1602 * gst_sdp_message_attributes_len:
1603 * @msg: a #GstSDPMessage
1605 * Get the number of attributes in @msg.
1607 * Returns: the number of attributes in @msg.
1609 DEFINE_ARRAY_LEN (attributes);
1612 * gst_sdp_message_get_attribute:
1613 * @msg: a #GstSDPMessage
1616 * Get the attribute at position @idx in @msg.
1618 * Returns: the #GstSDPAttribute at position @idx.
1620 DEFINE_ARRAY_GETTER (attribute, attributes, GstSDPAttribute);
1623 * gst_sdp_message_get_attribute_val_n:
1624 * @msg: a #GstSDPMessage
1628 * Get the @nth attribute with key @key in @msg.
1630 * Returns: (nullable): the attribute value of the @nth attribute with @key.
1633 gst_sdp_message_get_attribute_val_n (const GstSDPMessage * msg,
1634 const gchar * key, guint nth)
1638 g_return_val_if_fail (msg != NULL, NULL);
1639 g_return_val_if_fail (key != NULL, NULL);
1641 for (i = 0; i < msg->attributes->len; i++) {
1642 GstSDPAttribute *attr;
1644 attr = &g_array_index (msg->attributes, GstSDPAttribute, i);
1645 if (!strcmp (attr->key, key)) {
1656 * gst_sdp_message_get_attribute_val:
1657 * @msg: a #GstSDPMessage
1660 * Get the first attribute with key @key in @msg.
1662 * Returns: (nullable): the attribute value of the first attribute with @key.
1665 gst_sdp_message_get_attribute_val (const GstSDPMessage * msg, const gchar * key)
1667 return gst_sdp_message_get_attribute_val_n (msg, key, 0);
1670 #define DUP_ATTRIBUTE(v, val) memcpy (v, val, sizeof (GstSDPAttribute))
1671 #define FREE_ATTRIBUTE(v) gst_sdp_attribute_clear(v)
1674 * gst_sdp_message_insert_attribute:
1675 * @msg: a #GstSDPMessage
1677 * @attr: a #GstSDPAttribute
1679 * Insert attribute into the array of attributes in @msg
1681 * When -1 is given as @idx, the attribute is inserted at the end.
1683 * Returns: a #GstSDPResult.
1687 DEFINE_ARRAY_INSERT (attribute, attributes, GstSDPAttribute *, DUP_ATTRIBUTE,
1691 * gst_sdp_message_replace_attribute:
1692 * @msg: a #GstSDPMessage
1694 * @attr: a #GstSDPAttribute
1696 * Replace the attribute in @msg at index @idx with @attr.
1698 * Returns: a #GstSDPResult.
1702 DEFINE_ARRAY_REPLACE (attribute, attributes, GstSDPAttribute *, FREE_ATTRIBUTE,
1703 DUP_ATTRIBUTE, GstSDPAttribute);
1706 * gst_sdp_message_remove_attribute:
1707 * @msg: a #GstSDPMessage
1710 * Remove the attribute in @msg at index @idx.
1712 * Returns: a #GstSDPResult.
1716 DEFINE_ARRAY_REMOVE (attribute, attributes, GstSDPAttribute, FREE_ATTRIBUTE);
1719 * gst_sdp_message_add_attribute:
1720 * @msg: a #GstSDPMessage
1722 * @value: (nullable): the value
1724 * Add the attribute with @key and @value to @msg.
1726 * Returns: @GST_SDP_OK.
1729 gst_sdp_message_add_attribute (GstSDPMessage * msg, const gchar * key,
1730 const gchar * value)
1732 GstSDPAttribute attr;
1734 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1735 g_return_val_if_fail (key != NULL, GST_SDP_EINVAL);
1737 gst_sdp_attribute_set (&attr, key, value);
1738 g_array_append_val (msg->attributes, attr);
1744 * gst_sdp_message_medias_len:
1745 * @msg: a #GstSDPMessage
1747 * Get the number of media descriptions in @msg.
1749 * Returns: the number of media descriptions in @msg.
1751 DEFINE_ARRAY_LEN (medias);
1753 * gst_sdp_message_get_media:
1754 * @msg: a #GstSDPMessage
1757 * Get the media description at index @idx in @msg.
1759 * Returns: a #GstSDPMedia.
1761 DEFINE_ARRAY_GETTER (media, medias, GstSDPMedia);
1764 * gst_sdp_message_add_media:
1765 * @msg: a #GstSDPMessage
1766 * @media: a #GstSDPMedia to add
1768 * Adds @media to the array of medias in @msg. This function takes ownership of
1769 * the contents of @media so that @media will have to be reinitialized with
1770 * gst_sdp_media_init() before it can be used again.
1772 * Returns: a #GstSDPResult.
1775 gst_sdp_message_add_media (GstSDPMessage * msg, GstSDPMedia * media)
1778 GstSDPMedia *nmedia;
1780 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
1781 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1783 len = msg->medias->len;
1784 g_array_set_size (msg->medias, len + 1);
1785 nmedia = &g_array_index (msg->medias, GstSDPMedia, len);
1787 memcpy (nmedia, media, sizeof (GstSDPMedia));
1788 memset (media, 0, sizeof (GstSDPMedia));
1796 * gst_sdp_media_new:
1797 * @media: (out) (transfer full): pointer to new #GstSDPMedia
1799 * Allocate a new GstSDPMedia and store the result in @media.
1801 * Returns: a #GstSDPResult.
1804 gst_sdp_media_new (GstSDPMedia ** media)
1806 GstSDPMedia *newmedia;
1808 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1810 newmedia = g_new0 (GstSDPMedia, 1);
1814 return gst_sdp_media_init (newmedia);
1818 * gst_sdp_media_init:
1819 * @media: (out caller-allocates): a #GstSDPMedia
1821 * Initialize @media so that its contents are as if it was freshly allocated
1822 * with gst_sdp_media_new(). This function is mostly used to initialize a media
1823 * allocated on the stack. gst_sdp_media_uninit() undoes this operation.
1825 * When this function is invoked on newly allocated data (with malloc or on the
1826 * stack), its contents should be set to 0 before calling this function.
1828 * Returns: a #GstSDPResult.
1831 gst_sdp_media_init (GstSDPMedia * media)
1833 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1835 FREE_STRING (media->media);
1837 media->num_ports = 0;
1838 FREE_STRING (media->proto);
1839 INIT_STR_ARRAY (media->fmts);
1840 FREE_STRING (media->information);
1841 INIT_ARRAY (media->connections, GstSDPConnection, gst_sdp_connection_clear);
1842 INIT_ARRAY (media->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_clear);
1843 gst_sdp_key_init (&media->key);
1844 INIT_ARRAY (media->attributes, GstSDPAttribute, gst_sdp_attribute_clear);
1850 * gst_sdp_media_uninit:
1851 * @media: a #GstSDPMedia
1853 * Free all resources allocated in @media. @media should not be used anymore after
1854 * this function. This function should be used when @media was allocated on the
1855 * stack and initialized with gst_sdp_media_init().
1857 * Returns: a #GstSDPResult.
1860 gst_sdp_media_uninit (GstSDPMedia * media)
1862 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1864 gst_sdp_media_init (media);
1865 FREE_ARRAY (media->fmts);
1866 FREE_ARRAY (media->connections);
1867 FREE_ARRAY (media->bandwidths);
1868 FREE_ARRAY (media->attributes);
1874 * gst_sdp_media_free:
1875 * @media: a #GstSDPMedia
1877 * Free all resources allocated by @media. @media should not be used anymore after
1878 * this function. This function should be used when @media was dynamically
1879 * allocated with gst_sdp_media_new().
1881 * Returns: a #GstSDPResult.
1884 gst_sdp_media_free (GstSDPMedia * media)
1886 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1888 gst_sdp_media_uninit (media);
1895 * gst_sdp_media_copy:
1896 * @media: a #GstSDPMedia
1897 * @copy: (out) (transfer full): pointer to new #GstSDPMedia
1899 * Allocate a new copy of @media and store the result in @copy. The value in
1900 * @copy should be release with gst_sdp_media_free function.
1902 * Returns: a #GstSDPResult
1907 gst_sdp_media_copy (const GstSDPMedia * media, GstSDPMedia ** copy)
1912 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
1914 gst_sdp_media_new (copy);
1918 REPLACE_STRING (cp->media, media->media);
1919 cp->port = media->port;
1920 cp->num_ports = media->num_ports;
1921 REPLACE_STRING (cp->proto, media->proto);
1923 len = gst_sdp_media_formats_len (media);
1924 for (i = 0; i < len; i++) {
1925 gst_sdp_media_add_format (cp, gst_sdp_media_get_format (media, i));
1928 REPLACE_STRING (cp->information, media->information);
1930 len = gst_sdp_media_connections_len (media);
1931 for (i = 0; i < len; i++) {
1932 const GstSDPConnection *connection =
1933 gst_sdp_media_get_connection (media, i);
1934 gst_sdp_media_add_connection (cp, connection->nettype, connection->addrtype,
1935 connection->address, connection->ttl, connection->addr_number);
1938 len = gst_sdp_media_bandwidths_len (media);
1939 for (i = 0; i < len; i++) {
1940 const GstSDPBandwidth *bw = gst_sdp_media_get_bandwidth (media, i);
1941 gst_sdp_media_add_bandwidth (cp, bw->bwtype, bw->bandwidth);
1944 gst_sdp_media_set_key (cp, media->key.type, media->key.data);
1946 len = gst_sdp_media_attributes_len (media);
1947 for (i = 0; i < len; i++) {
1948 const GstSDPAttribute *att = gst_sdp_media_get_attribute (media, i);
1949 gst_sdp_media_add_attribute (cp, att->key, att->value);
1956 * gst_sdp_media_as_text:
1957 * @media: a #GstSDPMedia
1959 * Convert the contents of @media to a text string.
1961 * Returns: (transfer full): A dynamically allocated string representing the media.
1964 gst_sdp_media_as_text (const GstSDPMedia * media)
1969 g_return_val_if_fail (media != NULL, NULL);
1971 lines = g_string_new ("");
1974 g_string_append_printf (lines, "m=%s", media->media);
1976 g_string_append_printf (lines, " %u", media->port);
1978 if (media->num_ports > 1)
1979 g_string_append_printf (lines, "/%u", media->num_ports);
1981 g_string_append_printf (lines, " %s", media->proto);
1983 for (i = 0; i < gst_sdp_media_formats_len (media); i++)
1984 g_string_append_printf (lines, " %s", gst_sdp_media_get_format (media, i));
1985 g_string_append_printf (lines, "\r\n");
1987 if (media->information)
1988 g_string_append_printf (lines, "i=%s", media->information);
1990 for (i = 0; i < gst_sdp_media_connections_len (media); i++) {
1991 const GstSDPConnection *conn = gst_sdp_media_get_connection (media, i);
1993 if (conn->nettype && conn->addrtype && conn->address) {
1994 g_string_append_printf (lines, "c=%s %s %s", conn->nettype,
1995 conn->addrtype, conn->address);
1996 if (gst_sdp_address_is_multicast (conn->nettype, conn->addrtype,
1998 /* only add TTL for IP4 multicast */
1999 if (strcmp (conn->addrtype, "IP4") == 0)
2000 g_string_append_printf (lines, "/%u", conn->ttl);
2001 if (conn->addr_number > 1)
2002 g_string_append_printf (lines, "/%u", conn->addr_number);
2004 g_string_append_printf (lines, "\r\n");
2008 for (i = 0; i < gst_sdp_media_bandwidths_len (media); i++) {
2009 const GstSDPBandwidth *bandwidth = gst_sdp_media_get_bandwidth (media, i);
2011 g_string_append_printf (lines, "b=%s:%u\r\n", bandwidth->bwtype,
2012 bandwidth->bandwidth);
2015 if (media->key.type) {
2016 g_string_append_printf (lines, "k=%s", media->key.type);
2017 if (media->key.data)
2018 g_string_append_printf (lines, ":%s", media->key.data);
2019 g_string_append_printf (lines, "\r\n");
2022 for (i = 0; i < gst_sdp_media_attributes_len (media); i++) {
2023 const GstSDPAttribute *attr = gst_sdp_media_get_attribute (media, i);
2026 g_string_append_printf (lines, "a=%s", attr->key);
2027 if (attr->value && attr->value[0] != '\0')
2028 g_string_append_printf (lines, ":%s", attr->value);
2029 g_string_append_printf (lines, "\r\n");
2033 return g_string_free (lines, FALSE);
2037 * gst_sdp_media_get_media:
2038 * @media: a #GstSDPMedia
2040 * Get the media description of @media.
2042 * Returns: the media description.
2045 gst_sdp_media_get_media (const GstSDPMedia * media)
2047 g_return_val_if_fail (media != NULL, NULL);
2049 return media->media;
2053 * gst_sdp_media_set_media:
2054 * @media: a #GstSDPMedia
2055 * @med: the media description
2057 * Set the media description of @media to @med.
2059 * Returns: #GST_SDP_OK.
2062 gst_sdp_media_set_media (GstSDPMedia * media, const gchar * med)
2064 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2065 g_return_val_if_fail (med != NULL, GST_SDP_EINVAL);
2067 g_free (media->media);
2068 media->media = g_strdup (med);
2074 * gst_sdp_media_get_port:
2075 * @media: a #GstSDPMedia
2077 * Get the port number for @media.
2079 * Returns: the port number of @media.
2082 gst_sdp_media_get_port (const GstSDPMedia * media)
2084 g_return_val_if_fail (media != NULL, 0);
2090 * gst_sdp_media_get_num_ports:
2091 * @media: a #GstSDPMedia
2093 * Get the number of ports for @media.
2095 * Returns: the number of ports for @media.
2098 gst_sdp_media_get_num_ports (const GstSDPMedia * media)
2100 g_return_val_if_fail (media != NULL, 0);
2102 return media->num_ports;
2106 * gst_sdp_media_set_port_info:
2107 * @media: a #GstSDPMedia
2108 * @port: the port number
2109 * @num_ports: the number of ports
2111 * Set the port information in @media.
2113 * Returns: #GST_SDP_OK.
2116 gst_sdp_media_set_port_info (GstSDPMedia * media, guint port, guint num_ports)
2118 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2121 media->num_ports = num_ports;
2127 * gst_sdp_media_get_proto:
2128 * @media: a #GstSDPMedia
2130 * Get the transport protocol of @media
2132 * Returns: the transport protocol of @media.
2135 gst_sdp_media_get_proto (const GstSDPMedia * media)
2137 g_return_val_if_fail (media != NULL, NULL);
2139 return media->proto;
2143 * gst_sdp_media_set_proto:
2144 * @media: a #GstSDPMedia
2145 * @proto: the media transport protocol
2147 * Set the media transport protocol of @media to @proto.
2149 * Returns: #GST_SDP_OK.
2152 gst_sdp_media_set_proto (GstSDPMedia * media, const gchar * proto)
2154 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2156 g_free (media->proto);
2157 media->proto = g_strdup (proto);
2163 * gst_sdp_media_formats_len:
2164 * @media: a #GstSDPMedia
2166 * Get the number of formats in @media.
2168 * Returns: the number of formats in @media.
2171 gst_sdp_media_formats_len (const GstSDPMedia * media)
2173 g_return_val_if_fail (media != NULL, 0);
2175 return media->fmts->len;
2179 * gst_sdp_media_get_format:
2180 * @media: a #GstSDPMedia
2183 * Get the format information at position @idx in @media.
2185 * Returns: the format at position @idx.
2188 gst_sdp_media_get_format (const GstSDPMedia * media, guint idx)
2190 g_return_val_if_fail (media != NULL, NULL);
2192 if (idx >= media->fmts->len)
2194 return g_array_index (media->fmts, gchar *, idx);
2198 * gst_sdp_media_insert_format:
2199 * @media: a #GstSDPMedia
2201 * @format: the format
2203 * Insert the format information to @media at @idx. When @idx is -1,
2204 * the format is appended.
2206 * Returns: #GST_SDP_OK.
2211 gst_sdp_media_insert_format (GstSDPMedia * media, gint idx,
2212 const gchar * format)
2216 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2217 g_return_val_if_fail (format != NULL, GST_SDP_EINVAL);
2219 fmt = g_strdup (format);
2222 g_array_append_val (media->fmts, fmt);
2224 g_array_insert_val (media->fmts, idx, fmt);
2230 * gst_sdp_media_replace_format:
2231 * @media: a #GstSDPMedia
2233 * @format: the format
2235 * Replace the format information in @media at @idx with @format.
2237 * Returns: #GST_SDP_OK.
2242 gst_sdp_media_replace_format (GstSDPMedia * media, guint idx,
2243 const gchar * format)
2247 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2248 g_return_val_if_fail (format != NULL, GST_SDP_EINVAL);
2250 old = &g_array_index (media->fmts, gchar *, idx);
2252 *old = g_strdup (format);
2258 * gst_sdp_media_remove_format:
2259 * @media: a #GstSDPMedia
2262 * Remove the format information in @media at @idx.
2264 * Returns: #GST_SDP_OK.
2269 gst_sdp_media_remove_format (GstSDPMedia * media, guint idx)
2273 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2275 old = &g_array_index (media->fmts, gchar *, idx);
2277 g_array_remove_index (media->fmts, idx);
2283 * gst_sdp_media_add_format:
2284 * @media: a #GstSDPMedia
2285 * @format: the format
2287 * Add the format information to @media.
2289 * Returns: #GST_SDP_OK.
2292 gst_sdp_media_add_format (GstSDPMedia * media, const gchar * format)
2296 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2297 g_return_val_if_fail (format != NULL, GST_SDP_EINVAL);
2299 fmt = g_strdup (format);
2301 g_array_append_val (media->fmts, fmt);
2307 * gst_sdp_media_get_information:
2308 * @media: a #GstSDPMedia
2310 * Get the information of @media
2312 * Returns: the information of @media.
2315 gst_sdp_media_get_information (const GstSDPMedia * media)
2317 g_return_val_if_fail (media != NULL, NULL);
2319 return media->information;
2323 * gst_sdp_media_set_information:
2324 * @media: a #GstSDPMedia
2325 * @information: the media information
2327 * Set the media information of @media to @information.
2329 * Returns: #GST_SDP_OK.
2332 gst_sdp_media_set_information (GstSDPMedia * media, const gchar * information)
2334 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2336 g_free (media->information);
2337 media->information = g_strdup (information);
2343 * gst_sdp_connection_set:
2344 * @conn: a #GstSDPConnection
2345 * @nettype: the type of network. "IN" is defined to have the meaning
2347 * @addrtype: the type of address.
2348 * @address: the address
2349 * @ttl: the time to live of the address
2350 * @addr_number: the number of layers
2352 * Set the connection with the given parameters.
2354 * Returns: @GST_SDP_OK.
2359 gst_sdp_connection_set (GstSDPConnection * conn, const gchar * nettype,
2360 const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
2362 g_return_val_if_fail (conn != NULL, GST_SDP_EINVAL);
2363 g_return_val_if_fail (nettype != NULL, GST_SDP_EINVAL);
2364 g_return_val_if_fail (addrtype != NULL, GST_SDP_EINVAL);
2365 g_return_val_if_fail (address != NULL, GST_SDP_EINVAL);
2367 conn->nettype = g_strdup (nettype);
2368 conn->addrtype = g_strdup (addrtype);
2369 conn->address = g_strdup (address);
2371 conn->addr_number = addr_number;
2376 * gst_sdp_connection_clear:
2377 * @conn: a #GstSDPConnection
2379 * Clear the connection.
2381 * Returns: @GST_SDP_OK.
2386 gst_sdp_connection_clear (GstSDPConnection * conn)
2388 g_return_val_if_fail (conn != NULL, GST_SDP_EINVAL);
2390 FREE_STRING (conn->nettype);
2391 FREE_STRING (conn->addrtype);
2392 FREE_STRING (conn->address);
2394 conn->addr_number = 0;
2400 * gst_sdp_media_connections_len:
2401 * @media: a #GstSDPMedia
2403 * Get the number of connection fields in @media.
2405 * Returns: the number of connections in @media.
2408 gst_sdp_media_connections_len (const GstSDPMedia * media)
2410 g_return_val_if_fail (media != NULL, 0);
2412 return media->connections->len;
2416 * gst_sdp_media_get_connection:
2417 * @media: a #GstSDPMedia
2420 * Get the connection at position @idx in @media.
2422 * Returns: the #GstSDPConnection at position @idx.
2424 const GstSDPConnection *
2425 gst_sdp_media_get_connection (const GstSDPMedia * media, guint idx)
2427 g_return_val_if_fail (media != NULL, NULL);
2428 g_return_val_if_fail (idx < media->connections->len, NULL);
2430 return &g_array_index (media->connections, GstSDPConnection, idx);
2434 * gst_sdp_media_insert_connection:
2435 * @media: a #GstSDPMedia
2437 * @conn: a #GstSDPConnection
2439 * Insert the connection information to @media at @idx. When @idx is -1,
2440 * the connection is appended.
2442 * Returns: #GST_SDP_OK.
2447 gst_sdp_media_insert_connection (GstSDPMedia * media, gint idx,
2448 GstSDPConnection * conn)
2450 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2451 g_return_val_if_fail (conn != NULL, GST_SDP_EINVAL);
2452 g_return_val_if_fail (idx == -1
2453 || idx < media->connections->len, GST_SDP_EINVAL);
2456 g_array_append_val (media->connections, *conn);
2458 g_array_insert_val (media->connections, idx, *conn);
2464 * gst_sdp_media_replace_connection:
2465 * @media: a #GstSDPMedia
2467 * @conn: a #GstSDPConnection
2469 * Replace the connection information in @media at @idx with @conn.
2471 * Returns: #GST_SDP_OK.
2476 gst_sdp_media_replace_connection (GstSDPMedia * media, guint idx,
2477 GstSDPConnection * conn)
2479 GstSDPConnection *old;
2481 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2482 g_return_val_if_fail (conn != NULL, GST_SDP_EINVAL);
2483 g_return_val_if_fail (idx < media->connections->len, GST_SDP_EINVAL);
2485 old = &g_array_index (media->connections, GstSDPConnection, idx);
2486 gst_sdp_connection_clear (old);
2493 * gst_sdp_media_remove_connection:
2494 * @media: a #GstSDPMedia
2497 * Remove the connection information in @media at @idx.
2499 * Returns: #GST_SDP_OK.
2504 gst_sdp_media_remove_connection (GstSDPMedia * media, guint idx)
2506 GstSDPConnection *old;
2508 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2509 g_return_val_if_fail (idx < media->connections->len, GST_SDP_EINVAL);
2511 old = &g_array_index (media->connections, GstSDPConnection, idx);
2512 gst_sdp_connection_clear (old);
2513 g_array_remove_index (media->connections, idx);
2519 * gst_sdp_media_add_connection:
2520 * @media: a #GstSDPMedia
2521 * @nettype: the type of network. "IN" is defined to have the meaning
2523 * @addrtype: the type of address.
2524 * @address: the address
2525 * @ttl: the time to live of the address
2526 * @addr_number: the number of layers
2528 * Add the given connection parameters to @media.
2530 * Returns: a #GstSDPResult.
2533 gst_sdp_media_add_connection (GstSDPMedia * media, const gchar * nettype,
2534 const gchar * addrtype, const gchar * address, guint ttl, guint addr_number)
2536 GstSDPConnection conn;
2538 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2539 g_return_val_if_fail (nettype != NULL, GST_SDP_EINVAL);
2540 g_return_val_if_fail (addrtype != NULL, GST_SDP_EINVAL);
2541 g_return_val_if_fail (address != NULL, GST_SDP_EINVAL);
2543 gst_sdp_connection_set (&conn, nettype, addrtype, address, ttl, addr_number);
2544 g_array_append_val (media->connections, conn);
2550 * gst_sdp_media_bandwidths_len:
2551 * @media: a #GstSDPMedia
2553 * Get the number of bandwidth fields in @media.
2555 * Returns: the number of bandwidths in @media.
2558 gst_sdp_media_bandwidths_len (const GstSDPMedia * media)
2560 g_return_val_if_fail (media != NULL, 0);
2562 return media->bandwidths->len;
2566 * gst_sdp_media_get_bandwidth:
2567 * @media: a #GstSDPMedia
2570 * Get the bandwidth at position @idx in @media.
2572 * Returns: the #GstSDPBandwidth at position @idx.
2574 const GstSDPBandwidth *
2575 gst_sdp_media_get_bandwidth (const GstSDPMedia * media, guint idx)
2577 g_return_val_if_fail (media != NULL, NULL);
2579 return &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
2583 * gst_sdp_media_insert_bandwidth:
2584 * @media: a #GstSDPMedia
2586 * @bw: a #GstSDPBandwidth
2588 * Insert the bandwidth information to @media at @idx. When @idx is -1,
2589 * the bandwidth is appended.
2591 * Returns: #GST_SDP_OK.
2596 gst_sdp_media_insert_bandwidth (GstSDPMedia * media, gint idx,
2597 GstSDPBandwidth * bw)
2599 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2600 g_return_val_if_fail (bw != NULL, GST_SDP_EINVAL);
2601 g_return_val_if_fail (idx == -1
2602 || idx < media->bandwidths->len, GST_SDP_EINVAL);
2605 g_array_append_val (media->bandwidths, *bw);
2607 g_array_insert_val (media->bandwidths, idx, *bw);
2613 * gst_sdp_media_replace_bandwidth:
2614 * @media: a #GstSDPMedia
2616 * @bw: a #GstSDPBandwidth
2618 * Replace the bandwidth information in @media at @idx with @bw.
2620 * Returns: #GST_SDP_OK.
2625 gst_sdp_media_replace_bandwidth (GstSDPMedia * media, guint idx,
2626 GstSDPBandwidth * bw)
2628 GstSDPBandwidth *old;
2629 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2630 g_return_val_if_fail (bw != NULL, GST_SDP_EINVAL);
2631 g_return_val_if_fail (idx < media->bandwidths->len, GST_SDP_EINVAL);
2633 old = &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
2634 gst_sdp_bandwidth_clear (old);
2641 * gst_sdp_media_remove_bandwidth:
2642 * @media: a #GstSDPMedia
2645 * Remove the bandwidth information in @media at @idx.
2647 * Returns: #GST_SDP_OK.
2652 gst_sdp_media_remove_bandwidth (GstSDPMedia * media, guint idx)
2654 GstSDPBandwidth *old;
2656 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2657 g_return_val_if_fail (idx < media->bandwidths->len, GST_SDP_EINVAL);
2659 old = &g_array_index (media->bandwidths, GstSDPBandwidth, idx);
2660 gst_sdp_bandwidth_clear (old);
2661 g_array_remove_index (media->bandwidths, idx);
2667 * gst_sdp_media_add_bandwidth:
2668 * @media: a #GstSDPMedia
2669 * @bwtype: the bandwidth modifier type
2670 * @bandwidth: the bandwidth in kilobits per second
2672 * Add the bandwidth information with @bwtype and @bandwidth to @media.
2674 * Returns: #GST_SDP_OK.
2677 gst_sdp_media_add_bandwidth (GstSDPMedia * media, const gchar * bwtype,
2682 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2683 g_return_val_if_fail (bwtype != NULL, GST_SDP_EINVAL);
2685 gst_sdp_bandwidth_set (&bw, bwtype, bandwidth);
2686 g_array_append_val (media->bandwidths, bw);
2692 * gst_sdp_media_set_key:
2693 * @media: a #GstSDPMedia
2694 * @type: the encryption type
2695 * @data: the encryption data
2697 * Adds the encryption information to @media.
2699 * Returns: a #GstSDPResult.
2702 gst_sdp_media_set_key (GstSDPMedia * media, const gchar * type,
2705 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2707 g_free (media->key.type);
2708 media->key.type = g_strdup (type);
2709 g_free (media->key.data);
2710 media->key.data = g_strdup (data);
2716 * gst_sdp_media_get_key:
2717 * @media: a #GstSDPMedia
2719 * Get the encryption information from @media.
2721 * Returns: a #GstSDPKey.
2724 gst_sdp_media_get_key (const GstSDPMedia * media)
2726 g_return_val_if_fail (media != NULL, NULL);
2732 * gst_sdp_media_attributes_len:
2733 * @media: a #GstSDPMedia
2735 * Get the number of attribute fields in @media.
2737 * Returns: the number of attributes in @media.
2740 gst_sdp_media_attributes_len (const GstSDPMedia * media)
2742 g_return_val_if_fail (media != NULL, 0);
2744 return media->attributes->len;
2748 * gst_sdp_media_add_attribute:
2749 * @media: a #GstSDPMedia
2751 * @value: (nullable): a value
2753 * Add the attribute with @key and @value to @media.
2755 * Returns: #GST_SDP_OK.
2758 gst_sdp_media_add_attribute (GstSDPMedia * media, const gchar * key,
2759 const gchar * value)
2761 GstSDPAttribute attr;
2763 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2764 g_return_val_if_fail (key != NULL, GST_SDP_EINVAL);
2766 gst_sdp_attribute_set (&attr, key, value);
2767 g_array_append_val (media->attributes, attr);
2773 * gst_sdp_media_get_attribute:
2774 * @media: a #GstSDPMedia
2777 * Get the attribute at position @idx in @media.
2779 * Returns: the #GstSDPAttribute at position @idx.
2781 const GstSDPAttribute *
2782 gst_sdp_media_get_attribute (const GstSDPMedia * media, guint idx)
2784 g_return_val_if_fail (media != NULL, NULL);
2785 g_return_val_if_fail (idx < media->attributes->len, NULL);
2787 return &g_array_index (media->attributes, GstSDPAttribute, idx);
2791 * gst_sdp_media_get_attribute_val_n:
2792 * @media: a #GstSDPMedia
2796 * Get the @nth attribute value for @key in @media.
2798 * Returns: (nullable): the @nth attribute value.
2801 gst_sdp_media_get_attribute_val_n (const GstSDPMedia * media, const gchar * key,
2806 g_return_val_if_fail (media != NULL, NULL);
2807 g_return_val_if_fail (key != NULL, NULL);
2809 for (i = 0; i < media->attributes->len; i++) {
2810 GstSDPAttribute *attr;
2812 attr = &g_array_index (media->attributes, GstSDPAttribute, i);
2813 if (!strcmp (attr->key, key)) {
2824 * gst_sdp_media_get_attribute_val:
2825 * @media: a #GstSDPMedia
2828 * Get the first attribute value for @key in @media.
2830 * Returns: (nullable): the first attribute value for @key.
2833 gst_sdp_media_get_attribute_val (const GstSDPMedia * media, const gchar * key)
2835 g_return_val_if_fail (media != NULL, NULL);
2836 g_return_val_if_fail (key != NULL, NULL);
2838 return gst_sdp_media_get_attribute_val_n (media, key, 0);
2842 * gst_sdp_media_insert_attribute:
2843 * @media: a #GstSDPMedia
2845 * @attr: a #GstSDPAttribute
2847 * Insert the attribute to @media at @idx. When @idx is -1,
2848 * the attribute is appended.
2850 * Returns: #GST_SDP_OK.
2855 gst_sdp_media_insert_attribute (GstSDPMedia * media, gint idx,
2856 GstSDPAttribute * attr)
2858 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2859 g_return_val_if_fail (attr != NULL, GST_SDP_EINVAL);
2860 g_return_val_if_fail (idx == -1
2861 || idx < media->attributes->len, GST_SDP_EINVAL);
2864 g_array_append_val (media->attributes, *attr);
2866 g_array_insert_val (media->attributes, idx, *attr);
2872 * gst_sdp_media_replace_attribute:
2873 * @media: a #GstSDPMedia
2875 * @attr: a #GstSDPAttribute
2877 * Replace the attribute in @media at @idx with @attr.
2879 * Returns: #GST_SDP_OK.
2884 gst_sdp_media_replace_attribute (GstSDPMedia * media, guint idx,
2885 GstSDPAttribute * attr)
2887 GstSDPAttribute *old;
2889 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2890 g_return_val_if_fail (attr != NULL, GST_SDP_EINVAL);
2891 g_return_val_if_fail (idx < media->attributes->len, GST_SDP_EINVAL);
2893 old = &g_array_index (media->attributes, GstSDPAttribute, idx);
2894 gst_sdp_attribute_clear (old);
2901 * gst_sdp_media_remove_attribute:
2902 * @media: a #GstSDPMedia
2905 * Remove the attribute in @media at @idx.
2907 * Returns: #GST_SDP_OK.
2912 gst_sdp_media_remove_attribute (GstSDPMedia * media, guint idx)
2914 GstSDPAttribute *old;
2915 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
2916 g_return_val_if_fail (idx < media->attributes->len, GST_SDP_EINVAL);
2918 old = &g_array_index (media->attributes, GstSDPAttribute, idx);
2919 gst_sdp_attribute_clear (old);
2920 g_array_remove_index (media->attributes, idx);
2926 read_string (gchar * dest, guint size, gchar ** src)
2932 while (g_ascii_isspace (**src))
2935 while (!g_ascii_isspace (**src) && **src != '\0') {
2937 dest[idx++] = **src;
2945 read_string_del (gchar * dest, guint size, gchar del, gchar ** src)
2951 while (g_ascii_isspace (**src))
2954 while (**src != del && **src != '\0') {
2956 dest[idx++] = **src;
2977 gst_sdp_parse_line (SDPContext * c, gchar type, gchar * buffer)
2982 #define READ_STRING(field) \
2983 do { read_string (str, sizeof (str), &p); REPLACE_STRING (field, str); } while (0)
2984 #define READ_UINT(field) \
2985 do { read_string (str, sizeof (str), &p); field = strtoul (str, NULL, 10); } while (0)
2989 if (buffer[0] != '0')
2990 GST_WARNING ("wrong SDP version");
2991 gst_sdp_message_set_version (c->msg, buffer);
2994 READ_STRING (c->msg->origin.username);
2995 READ_STRING (c->msg->origin.sess_id);
2996 READ_STRING (c->msg->origin.sess_version);
2997 READ_STRING (c->msg->origin.nettype);
2998 READ_STRING (c->msg->origin.addrtype);
2999 READ_STRING (c->msg->origin.addr);
3002 REPLACE_STRING (c->msg->session_name, buffer);
3005 if (c->state == SDP_SESSION) {
3006 REPLACE_STRING (c->msg->information, buffer);
3008 REPLACE_STRING (c->media->information, buffer);
3012 REPLACE_STRING (c->msg->uri, buffer);
3015 gst_sdp_message_add_email (c->msg, buffer);
3018 gst_sdp_message_add_phone (c->msg, buffer);
3022 GstSDPConnection conn;
3025 memset (&conn, 0, sizeof (conn));
3028 while ((str2 = strchr (str2, '/')))
3030 READ_STRING (conn.nettype);
3031 READ_STRING (conn.addrtype);
3032 READ_STRING (conn.address);
3033 /* only read TTL for IP4 */
3034 if (strcmp (conn.addrtype, "IP4") == 0)
3035 READ_UINT (conn.ttl);
3036 READ_UINT (conn.addr_number);
3038 if (c->state == SDP_SESSION) {
3039 gst_sdp_message_set_connection (c->msg, conn.nettype, conn.addrtype,
3040 conn.address, conn.ttl, conn.addr_number);
3042 gst_sdp_media_add_connection (c->media, conn.nettype, conn.addrtype,
3043 conn.address, conn.ttl, conn.addr_number);
3045 gst_sdp_connection_clear (&conn);
3052 read_string_del (str, sizeof (str), ':', &p);
3055 read_string (str2, sizeof (str2), &p);
3056 if (c->state == SDP_SESSION)
3057 gst_sdp_message_add_bandwidth (c->msg, str, atoi (str2));
3059 gst_sdp_media_add_bandwidth (c->media, str, atoi (str2));
3065 read_string_del (str, sizeof (str), ':', &p);
3068 if (c->state == SDP_SESSION)
3069 gst_sdp_message_set_key (c->msg, str, p);
3071 gst_sdp_media_set_key (c->media, str, p);
3074 read_string_del (str, sizeof (str), ':', &p);
3077 if (c->state == SDP_SESSION)
3078 gst_sdp_message_add_attribute (c->msg, str, p);
3080 gst_sdp_media_add_attribute (c->media, str, p);
3087 c->state = SDP_MEDIA;
3088 memset (&nmedia, 0, sizeof (nmedia));
3089 gst_sdp_media_init (&nmedia);
3091 /* m=<media> <port>/<number of ports> <proto> <fmt> ... */
3092 READ_STRING (nmedia.media);
3093 read_string (str, sizeof (str), &p);
3094 slash = g_strrstr (str, "/");
3097 nmedia.port = atoi (str);
3098 nmedia.num_ports = atoi (slash + 1);
3100 nmedia.port = atoi (str);
3101 nmedia.num_ports = 0;
3103 READ_STRING (nmedia.proto);
3105 read_string (str, sizeof (str), &p);
3106 gst_sdp_media_add_format (&nmedia, str);
3107 } while (*p != '\0');
3109 gst_sdp_message_add_media (c->msg, &nmedia);
3111 &g_array_index (c->msg->medias, GstSDPMedia, c->msg->medias->len - 1);
3121 * gst_sdp_message_parse_buffer:
3122 * @data: (array length=size): the start of the buffer
3123 * @size: the size of the buffer
3124 * @msg: (out caller-allocates): the result #GstSDPMessage
3126 * Parse the contents of @size bytes pointed to by @data and store the result in
3129 * Returns: #GST_SDP_OK on success.
3132 gst_sdp_message_parse_buffer (const guint8 * data, guint size,
3133 GstSDPMessage * msg)
3138 gchar *buffer = NULL;
3142 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
3143 g_return_val_if_fail (data != NULL, GST_SDP_EINVAL);
3144 g_return_val_if_fail (size != 0, GST_SDP_EINVAL);
3146 c.state = SDP_SESSION;
3150 #define SIZE_CHECK_GUARD \
3152 if (p - (gchar *) data >= size) \
3158 while (p - (gchar *) data < size && g_ascii_isspace (*p))
3176 while (p - (gchar *) data < size && *p != '\n' && *p != '\r' && *p != '\0')
3180 if (bufsize <= len) {
3181 buffer = g_realloc (buffer, len + 1);
3184 memcpy (buffer, s, len);
3187 gst_sdp_parse_line (&c, type, buffer);
3192 while (p - (gchar *) data < size && *p != '\n' && *p != '\0')
3201 #undef SIZE_CHECK_GUARD
3210 print_media (GstSDPMedia * media)
3212 g_print (" media: '%s'\n", GST_STR_NULL (media->media));
3213 g_print (" port: '%u'\n", media->port);
3214 g_print (" num_ports: '%u'\n", media->num_ports);
3215 g_print (" proto: '%s'\n", GST_STR_NULL (media->proto));
3216 if (media->fmts->len > 0) {
3219 g_print (" formats:\n");
3220 for (i = 0; i < media->fmts->len; i++) {
3221 g_print (" format '%s'\n", g_array_index (media->fmts, gchar *, i));
3224 g_print (" information: '%s'\n", GST_STR_NULL (media->information));
3225 if (media->connections->len > 0) {
3228 g_print (" connections:\n");
3229 for (i = 0; i < media->connections->len; i++) {
3230 GstSDPConnection *conn =
3231 &g_array_index (media->connections, GstSDPConnection, i);
3233 g_print (" nettype: '%s'\n", GST_STR_NULL (conn->nettype));
3234 g_print (" addrtype: '%s'\n", GST_STR_NULL (conn->addrtype));
3235 g_print (" address: '%s'\n", GST_STR_NULL (conn->address));
3236 g_print (" ttl: '%u'\n", conn->ttl);
3237 g_print (" addr_number: '%u'\n", conn->addr_number);
3240 if (media->bandwidths->len > 0) {
3243 g_print (" bandwidths:\n");
3244 for (i = 0; i < media->bandwidths->len; i++) {
3245 GstSDPBandwidth *bw =
3246 &g_array_index (media->bandwidths, GstSDPBandwidth, i);
3248 g_print (" type: '%s'\n", GST_STR_NULL (bw->bwtype));
3249 g_print (" bandwidth: '%u'\n", bw->bandwidth);
3252 g_print (" key:\n");
3253 g_print (" type: '%s'\n", GST_STR_NULL (media->key.type));
3254 g_print (" data: '%s'\n", GST_STR_NULL (media->key.data));
3255 if (media->attributes->len > 0) {
3258 g_print (" attributes:\n");
3259 for (i = 0; i < media->attributes->len; i++) {
3260 GstSDPAttribute *attr =
3261 &g_array_index (media->attributes, GstSDPAttribute, i);
3263 g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
3269 * gst_sdp_message_dump:
3270 * @msg: a #GstSDPMessage
3272 * Dump the parsed contents of @msg to stdout.
3274 * Returns: a #GstSDPResult.
3277 gst_sdp_message_dump (const GstSDPMessage * msg)
3279 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
3281 g_print ("sdp packet %p:\n", msg);
3282 g_print (" version: '%s'\n", GST_STR_NULL (msg->version));
3283 g_print (" origin:\n");
3284 g_print (" username: '%s'\n", GST_STR_NULL (msg->origin.username));
3285 g_print (" sess_id: '%s'\n", GST_STR_NULL (msg->origin.sess_id));
3286 g_print (" sess_version: '%s'\n", GST_STR_NULL (msg->origin.sess_version));
3287 g_print (" nettype: '%s'\n", GST_STR_NULL (msg->origin.nettype));
3288 g_print (" addrtype: '%s'\n", GST_STR_NULL (msg->origin.addrtype));
3289 g_print (" addr: '%s'\n", GST_STR_NULL (msg->origin.addr));
3290 g_print (" session_name: '%s'\n", GST_STR_NULL (msg->session_name));
3291 g_print (" information: '%s'\n", GST_STR_NULL (msg->information));
3292 g_print (" uri: '%s'\n", GST_STR_NULL (msg->uri));
3294 if (msg->emails->len > 0) {
3297 g_print (" emails:\n");
3298 for (i = 0; i < msg->emails->len; i++) {
3299 g_print (" email '%s'\n", g_array_index (msg->emails, gchar *, i));
3302 if (msg->phones->len > 0) {
3305 g_print (" phones:\n");
3306 for (i = 0; i < msg->phones->len; i++) {
3307 g_print (" phone '%s'\n", g_array_index (msg->phones, gchar *, i));
3310 g_print (" connection:\n");
3311 g_print (" nettype: '%s'\n", GST_STR_NULL (msg->connection.nettype));
3312 g_print (" addrtype: '%s'\n", GST_STR_NULL (msg->connection.addrtype));
3313 g_print (" address: '%s'\n", GST_STR_NULL (msg->connection.address));
3314 g_print (" ttl: '%u'\n", msg->connection.ttl);
3315 g_print (" addr_number: '%u'\n", msg->connection.addr_number);
3316 if (msg->bandwidths->len > 0) {
3319 g_print (" bandwidths:\n");
3320 for (i = 0; i < msg->bandwidths->len; i++) {
3321 GstSDPBandwidth *bw =
3322 &g_array_index (msg->bandwidths, GstSDPBandwidth, i);
3324 g_print (" type: '%s'\n", GST_STR_NULL (bw->bwtype));
3325 g_print (" bandwidth: '%u'\n", bw->bandwidth);
3328 g_print (" key:\n");
3329 g_print (" type: '%s'\n", GST_STR_NULL (msg->key.type));
3330 g_print (" data: '%s'\n", GST_STR_NULL (msg->key.data));
3331 if (msg->attributes->len > 0) {
3334 g_print (" attributes:\n");
3335 for (i = 0; i < msg->attributes->len; i++) {
3336 GstSDPAttribute *attr =
3337 &g_array_index (msg->attributes, GstSDPAttribute, i);
3339 g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
3342 if (msg->medias->len > 0) {
3345 g_print (" medias:\n");
3346 for (i = 0; i < msg->medias->len; i++) {
3347 g_print (" media %u:\n", i);
3348 print_media (&g_array_index (msg->medias, GstSDPMedia, i));
3354 static const gchar *
3355 gst_sdp_get_attribute_for_pt (const GstSDPMedia * media, const gchar * name,
3364 if ((attr = gst_sdp_media_get_attribute_val_n (media, name, i)) == NULL)
3367 if (sscanf (attr, "%d ", &val) != 1)
3376 /* this may modify the input string (and resets) */
3377 #define PARSE_INT(p, del, res) \
3380 p = strstr (p, del); \
3392 /* this may modify the string without reset */
3393 #define PARSE_STRING(p, del, res) \
3396 p = strstr (p, del); \
3408 #define SKIP_SPACES(p) \
3409 while (*p && g_ascii_isspace (*p)) \
3414 * <payload> <encoding_name>/<clock_rate>[/<encoding_params>]
3417 gst_sdp_parse_rtpmap (const gchar * rtpmap, gint * payload, gchar ** name,
3418 gint * rate, gchar ** params)
3420 gchar *p, *t, *orig_value;
3422 p = orig_value = g_strdup (rtpmap);
3424 PARSE_INT (p, " ", *payload);
3432 PARSE_STRING (p, "/", *name);
3433 if (*name == NULL) {
3434 GST_DEBUG ("no rate, name %s", p);
3435 /* no rate, assume -1 then, this is not supposed to happen but RealMedia
3436 * streams seem to omit the rate. */
3437 *name = g_strdup (p);
3442 *name = strdup (*name);
3446 p = strstr (p, "/");
3458 *params = g_strdup (p);
3461 g_free (orig_value);
3465 g_free (orig_value);
3470 * gst_sdp_media_add_rtcp_fb_attributes_from_media:
3471 * @media: a #GstSDPMedia
3475 * Parse given @media for "rtcp-fb" attributes and add it to the @caps.
3477 * Mapping of caps from SDP fields:
3479 * a=rtcp-fb:(payload) (param1) [param2]...
3481 * Returns: a #GstSDPResult.
3484 gst_sdp_media_add_rtcp_fb_attributes_from_media (const GstSDPMedia * media,
3485 gint pt, GstCaps * caps)
3487 const gchar *rtcp_fb;
3492 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
3493 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
3495 s = gst_caps_get_structure (caps, 0);
3498 gboolean all_formats = FALSE;
3500 if ((rtcp_fb = gst_sdp_media_get_attribute_val_n (media,
3501 "rtcp-fb", i)) == NULL)
3504 /* p is now of the format <payload> attr... */
3505 to_free = p = g_strdup (rtcp_fb);
3507 /* check if it applies to all formats */
3512 PARSE_INT (p, " ", payload);
3515 if (all_formats || (payload != -1 && payload == pt)) {
3520 /* replace space with '-' */
3521 key = g_strdup_printf ("rtcp-fb-%s", p);
3523 for (tmp = key; (tmp = strchr (tmp, ' ')); ++tmp) {
3527 gst_structure_set (s, key, G_TYPE_BOOLEAN, TRUE, NULL);
3528 GST_DEBUG ("adding caps: %s=TRUE", key);
3537 gst_sdp_media_caps_adjust_h264 (GstCaps * caps)
3541 const gchar *profile_level_id;
3542 GstStructure *s = gst_caps_get_structure (caps, 0);
3544 if (g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "H264") ||
3545 g_strcmp0 (gst_structure_get_string (s, "level-asymmetry-allowed"), "1"))
3548 profile_level_id = gst_structure_get_string (s, "profile-level-id");
3549 if (!profile_level_id)
3552 spsint = strtol (profile_level_id, NULL, 16);
3553 sps[0] = spsint >> 16;
3554 sps[1] = spsint >> 8;
3556 GST_DEBUG ("'level-asymmetry-allowed' is set so we shouldn't care about "
3557 "'profile-level-id' and only set a 'profile' instead");
3558 gst_structure_set (s, "profile", G_TYPE_STRING,
3559 gst_codec_utils_h264_get_profile (sps, 2), NULL);
3561 gst_structure_remove_fields (s, "level-asymmetry-allowed", "profile-level-id",
3566 * gst_sdp_media_get_caps_from_media:
3567 * @media: a #GstSDPMedia
3568 * @pt: a payload type
3570 * Mapping of caps from SDP fields:
3572 * a=rtpmap:(payload) (encoding_name)/(clock_rate)[/(encoding_params)]
3574 * a=framesize:(payload) (width)-(height)
3576 * a=fmtp:(payload) (param)[=(value)];...
3578 * Note that the extmap, ssrc and rid attributes are set only by gst_sdp_media_attributes_to_caps().
3580 * Returns: (transfer full) (nullable): a #GstCaps, or %NULL if an error happened
3585 gst_sdp_media_get_caps_from_media (const GstSDPMedia * media, gint pt)
3588 const gchar *rtpmap;
3590 gchar *framesize = NULL;
3593 gchar *params = NULL;
3599 g_return_val_if_fail (media != NULL, NULL);
3601 /* get and parse rtpmap */
3602 rtpmap = gst_sdp_get_attribute_for_pt (media, "rtpmap", pt);
3605 ret = gst_sdp_parse_rtpmap (rtpmap, &payload, &name, &rate, ¶ms);
3607 GST_ERROR ("error parsing rtpmap, ignoring");
3611 /* dynamic payloads need rtpmap or we fail */
3612 if (rtpmap == NULL && pt >= 96)
3615 /* check if we have a rate, if not, we need to look up the rate from the
3616 * default rates based on the payload types. */
3618 const GstRTPPayloadInfo *info;
3620 if (GST_RTP_PAYLOAD_IS_DYNAMIC (pt)) {
3621 /* dynamic types, use media and encoding_name */
3622 tmp = g_ascii_strdown (media->media, -1);
3623 info = gst_rtp_payload_info_for_name (tmp, name);
3626 /* static types, use payload type */
3627 info = gst_rtp_payload_info_for_pt (pt);
3631 if ((rate = info->clock_rate) == 0)
3634 /* we fail if we cannot find one */
3639 tmp = g_ascii_strdown (media->media, -1);
3640 caps = gst_caps_new_simple ("application/x-unknown",
3641 "media", G_TYPE_STRING, tmp, "payload", G_TYPE_INT, pt, NULL);
3643 s = gst_caps_get_structure (caps, 0);
3645 gst_structure_set (s, "clock-rate", G_TYPE_INT, rate, NULL);
3647 /* encoding name must be upper case */
3649 tmp = g_ascii_strup (name, -1);
3650 gst_structure_set (s, "encoding-name", G_TYPE_STRING, tmp, NULL);
3654 /* params must be lower case */
3655 if (params != NULL) {
3656 tmp = g_ascii_strdown (params, -1);
3657 gst_structure_set (s, "encoding-params", G_TYPE_STRING, tmp, NULL);
3661 /* parse optional fmtp: field */
3662 if ((fmtp = g_strdup (gst_sdp_get_attribute_for_pt (media, "fmtp", pt)))) {
3668 /* p is now of the format <payload> <param>[=<value>];... */
3669 PARSE_INT (p, " ", payload);
3670 if (payload != -1 && payload == pt) {
3674 /* <param>[=<value>] are separated with ';' */
3675 pairs = g_strsplit (p, ";", 0);
3676 for (i = 0; pairs[i]; i++) {
3678 const gchar *val, *key;
3680 const gchar *reserved_keys[] =
3681 { "media", "payload", "clock-rate", "encoding-name",
3685 /* the key may not have a '=', the value can have other '='s */
3686 valpos = strstr (pairs[i], "=");
3688 /* we have a '=' and thus a value, remove the '=' with \0 */
3690 /* value is everything between '=' and ';'. We split the pairs at ;
3691 * boundaries so we can take the remainder of the value. Some servers
3692 * put spaces around the value which we strip off here. Alternatively
3693 * we could strip those spaces in the depayloaders should these spaces
3694 * actually carry any meaning in the future. */
3695 val = g_strstrip (valpos + 1);
3697 /* simple <param>;.. is translated into <param>=1;... */
3700 /* strip the key of spaces, convert key to lowercase but not the value. */
3701 key = g_strstrip (pairs[i]);
3703 /* skip keys from the fmtp, which we already use ourselves for the
3704 * caps. Some software is adding random things like clock-rate into
3705 * the fmtp, and we would otherwise here set a string-typed clock-rate
3706 * in the caps... and thus fail to create valid RTP caps
3708 for (j = 0; j < G_N_ELEMENTS (reserved_keys); j++) {
3709 if (g_ascii_strcasecmp (reserved_keys[j], key) == 0) {
3715 if (strlen (key) > 0) {
3716 tmp = g_ascii_strdown (key, -1);
3717 gst_structure_set (s, tmp, G_TYPE_STRING, val, NULL);
3725 /* parse framesize: field */
3727 g_strdup (gst_sdp_media_get_attribute_val (media, "framesize")))) {
3730 /* p is now of the format <payload> <width>-<height> */
3733 PARSE_INT (p, " ", payload);
3734 if (payload != -1 && payload == pt) {
3735 gst_structure_set (s, "a-framesize", G_TYPE_STRING, p, NULL);
3739 gst_sdp_media_caps_adjust_h264 (caps);
3741 /* parse rtcp-fb: field */
3742 gst_sdp_media_add_rtcp_fb_attributes_from_media (media, pt, caps);
3754 GST_ERROR ("rtpmap type not given for dynamic payload %d", pt);
3760 GST_ERROR ("rate unknown for payload type %d", pt);
3767 * gst_sdp_media_set_media_from_caps:
3769 * @media: (out caller-allocates): a #GstSDPMedia
3771 * Mapping of caps to SDP fields:
3773 * a=rtpmap:(payload) (encoding_name) or (clock_rate)[or (encoding_params)]
3775 * a=framesize:(payload) (width)-(height)
3777 * a=fmtp:(payload) (param)[=(value)];...
3779 * a=rtcp-fb:(payload) (param1) [param2]...
3781 * a=extmap:(id)[/direction] (extensionname) (extensionattributes)
3783 * Returns: a #GstSDPResult.
3788 gst_sdp_media_set_media_from_caps (const GstCaps * caps, GstSDPMedia * media)
3790 const gchar *caps_str, *caps_enc, *caps_params;
3792 gint caps_pt, caps_rate;
3794 gboolean first, nack, nack_pli, ccm_fir, transport_cc;
3798 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
3799 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
3801 s = gst_caps_get_structure (caps, 0);
3803 GST_ERROR ("ignoring stream without media type");
3807 /* get media type and payload for the m= line */
3808 caps_str = gst_structure_get_string (s, "media");
3810 GST_ERROR ("ignoring stream without media type");
3813 gst_sdp_media_set_media (media, caps_str);
3815 if (!gst_structure_get_int (s, "payload", &caps_pt)) {
3816 GST_ERROR ("ignoring stream without payload type");
3819 tmp = g_strdup_printf ("%d", caps_pt);
3820 gst_sdp_media_add_format (media, tmp);
3823 /* get clock-rate, media type and params for the rtpmap attribute */
3824 if (!gst_structure_get_int (s, "clock-rate", &caps_rate)) {
3825 GST_ERROR ("ignoring stream without payload type");
3828 caps_enc = gst_structure_get_string (s, "encoding-name");
3829 caps_params = gst_structure_get_string (s, "encoding-params");
3833 tmp = g_strdup_printf ("%d %s/%d/%s", caps_pt, caps_enc, caps_rate,
3836 tmp = g_strdup_printf ("%d %s/%d", caps_pt, caps_enc, caps_rate);
3838 gst_sdp_media_add_attribute (media, "rtpmap", tmp);
3842 /* get rtcp-fb attributes */
3843 if (gst_structure_get_boolean (s, "rtcp-fb-nack", &nack)) {
3845 tmp = g_strdup_printf ("%d nack", caps_pt);
3846 gst_sdp_media_add_attribute (media, "rtcp-fb", tmp);
3848 GST_DEBUG ("adding rtcp-fb-nack to pt=%d", caps_pt);
3852 if (gst_structure_get_boolean (s, "rtcp-fb-nack-pli", &nack_pli)) {
3854 tmp = g_strdup_printf ("%d nack pli", caps_pt);
3855 gst_sdp_media_add_attribute (media, "rtcp-fb", tmp);
3857 GST_DEBUG ("adding rtcp-fb-nack-pli to pt=%d", caps_pt);
3861 if (gst_structure_get_boolean (s, "rtcp-fb-ccm-fir", &ccm_fir)) {
3863 tmp = g_strdup_printf ("%d ccm fir", caps_pt);
3864 gst_sdp_media_add_attribute (media, "rtcp-fb", tmp);
3866 GST_DEBUG ("adding rtcp-fb-ccm-fir to pt=%d", caps_pt);
3870 if (gst_structure_get_boolean (s, "rtcp-fb-transport-cc", &transport_cc)) {
3872 tmp = g_strdup_printf ("%d transport-cc", caps_pt);
3873 gst_sdp_media_add_attribute (media, "rtcp-fb", tmp);
3875 GST_DEBUG ("adding rtcp-fb-transport-cc to pt=%d", caps_pt);
3879 /* collect all other properties and add them to fmtp, extmap or attributes */
3880 fmtp = g_string_new ("");
3881 g_string_append_printf (fmtp, "%d ", caps_pt);
3883 n_fields = gst_structure_n_fields (s);
3884 for (j = 0; j < n_fields; j++) {
3885 const gchar *fname, *fval;
3887 fname = gst_structure_nth_field_name (s, j);
3889 /* filter out standard properties */
3890 if (!strcmp (fname, "media"))
3892 if (!strcmp (fname, "payload"))
3894 if (!strcmp (fname, "clock-rate"))
3896 if (!strcmp (fname, "encoding-name"))
3898 if (!strcmp (fname, "encoding-params"))
3900 if (!strcmp (fname, "ssrc"))
3902 if (!strcmp (fname, "timestamp-offset"))
3904 if (!strcmp (fname, "seqnum-offset"))
3906 if (g_str_has_prefix (fname, "srtp-"))
3908 if (g_str_has_prefix (fname, "srtcp-"))
3911 if (g_str_has_prefix (fname, "x-gst-rtsp-server-rtx-time"))
3913 if (g_str_has_prefix (fname, "rtcp-fb-"))
3916 if (!strcmp (fname, "a-framesize")) {
3917 /* a-framesize attribute */
3918 if ((fval = gst_structure_get_string (s, fname))) {
3919 tmp = g_strdup_printf ("%d %s", caps_pt, fval);
3920 gst_sdp_media_add_attribute (media, fname + 2, tmp);
3926 if (g_str_has_prefix (fname, "a-")) {
3928 if ((fval = gst_structure_get_string (s, fname)))
3929 gst_sdp_media_add_attribute (media, fname + 2, fval);
3932 if (g_str_has_prefix (fname, "x-")) {
3934 if ((fval = gst_structure_get_string (s, fname)))
3935 gst_sdp_media_add_attribute (media, fname, fval);
3940 if (g_str_has_prefix (fname, "extmap-")) {
3942 guint id = strtoull (fname + 7, &endptr, 10);
3945 if (*endptr != '\0' || id == 0 || id == 15 || id > 9999)
3948 if ((fval = gst_structure_get_string (s, fname))) {
3949 gchar *extmap = g_strdup_printf ("%u %s", id, fval);
3950 gst_sdp_media_add_attribute (media, "extmap", extmap);
3952 } else if ((arr = gst_structure_get_value (s, fname))
3953 && G_VALUE_HOLDS (arr, GST_TYPE_ARRAY)
3954 && gst_value_array_get_size (arr) == 3) {
3956 const gchar *direction, *extensionname, *extensionattributes;
3958 val = gst_value_array_get_value (arr, 0);
3959 direction = g_value_get_string (val);
3961 val = gst_value_array_get_value (arr, 1);
3962 extensionname = g_value_get_string (val);
3964 val = gst_value_array_get_value (arr, 2);
3965 extensionattributes = g_value_get_string (val);
3967 if (!extensionname || *extensionname == '\0')
3970 if (direction && *direction != '\0' && extensionattributes
3971 && *extensionattributes != '\0') {
3973 g_strdup_printf ("%u/%s %s %s", id, direction, extensionname,
3974 extensionattributes);
3975 gst_sdp_media_add_attribute (media, "extmap", extmap);
3977 } else if (direction && *direction != '\0') {
3979 g_strdup_printf ("%u/%s %s", id, direction, extensionname);
3980 gst_sdp_media_add_attribute (media, "extmap", extmap);
3982 } else if (extensionattributes && *extensionattributes != '\0') {
3983 gchar *extmap = g_strdup_printf ("%u %s %s", id, extensionname,
3984 extensionattributes);
3985 gst_sdp_media_add_attribute (media, "extmap", extmap);
3988 gchar *extmap = g_strdup_printf ("%u %s", id, extensionname);
3989 gst_sdp_media_add_attribute (media, "extmap", extmap);
3997 if (g_str_has_prefix (fname, "rid-")) {
3998 const char *rid_id = &fname[strlen ("rid-")];
4001 if (!rid_id || !*rid_id)
4004 if ((fval = gst_structure_get_string (s, fname))) {
4005 char *rid_val = g_strdup_printf ("%s %s", rid_id, fval);
4006 gst_sdp_media_add_attribute (media, "rid", rid_val);
4008 } else if ((arr = gst_structure_get_value (s, fname))
4009 && GST_VALUE_HOLDS_ARRAY (arr)
4010 && gst_value_array_get_size (arr) > 1) {
4011 const gchar *direction, *param;
4015 str = g_string_new (NULL);
4017 g_string_append_printf (str, "%s ", rid_id);
4019 n = gst_value_array_get_size (arr);
4020 for (i = 0; i < n; i++) {
4021 const GValue *val = gst_value_array_get_value (arr, i);
4023 direction = g_value_get_string (val);
4024 g_string_append_printf (str, "%s", direction);
4026 param = g_value_get_string (val);
4028 g_string_append_c (str, ' ');
4030 g_string_append_c (str, ';');
4031 g_string_append_printf (str, "%s", param);
4034 gst_sdp_media_add_attribute (media, "rid", str->str);
4035 g_string_free (str, TRUE);
4037 GST_WARNING ("caps field %s is an unsupported format", fname);
4042 if ((fval = gst_structure_get_string (s, fname))) {
4044 /* "profile" is our internal representation of the notion of
4045 * "level-asymmetry-allowed" with caps, convert it back to the SDP
4047 if (!g_strcmp0 (gst_structure_get_string (s, "encoding-name"), "H264")
4048 && !g_strcmp0 (fname, "profile")) {
4049 fname = "level-asymmetry-allowed";
4053 g_string_append_printf (fmtp, "%s%s=%s", first ? "" : ";", fname, fval);
4059 tmp = g_string_free (fmtp, FALSE);
4060 gst_sdp_media_add_attribute (media, "fmtp", tmp);
4063 g_string_free (fmtp, TRUE);
4071 GST_DEBUG ("ignoring stream");
4072 return GST_SDP_EINVAL;
4077 * gst_sdp_make_keymgmt:
4078 * @uri: a #gchar URI
4079 * @base64: a #gchar base64-encoded key data
4081 * Makes key management data
4083 * Returns: (transfer full): a #gchar key-mgmt data,
4088 gst_sdp_make_keymgmt (const gchar * uri, const gchar * base64)
4090 g_return_val_if_fail (uri != NULL, NULL);
4091 g_return_val_if_fail (base64 != NULL, NULL);
4093 return g_strdup_printf ("prot=mikey;uri=\"%s\";data=\"%s\"", uri, base64);
4097 gst_sdp_parse_keymgmt (const gchar * keymgmt, GstMIKEYMessage ** mikey)
4104 p = orig_value = g_strdup (keymgmt);
4108 g_free (orig_value);
4112 PARSE_STRING (p, " ", kmpid);
4113 if (kmpid == NULL || !g_str_equal (kmpid, "mikey")) {
4114 g_free (orig_value);
4117 data = g_base64_decode (p, &size);
4118 g_free (orig_value); /* Don't need this any more */
4123 *mikey = gst_mikey_message_new_from_data (data, size, NULL, NULL);
4126 return (*mikey != NULL);
4130 sdp_add_attributes_to_keymgmt (GArray * attributes, GstMIKEYMessage ** mikey)
4132 GstSDPResult res = GST_SDP_OK;
4134 if (attributes->len > 0) {
4136 for (i = 0; i < attributes->len; i++) {
4137 GstSDPAttribute *attr = &g_array_index (attributes, GstSDPAttribute, i);
4139 if (g_str_equal (attr->key, "key-mgmt")) {
4140 res = gst_sdp_parse_keymgmt (attr->value, mikey);
4150 * gst_sdp_message_parse_keymgmt:
4151 * @msg: a #GstSDPMessage
4152 * @mikey: (out) (transfer full): pointer to new #GstMIKEYMessage
4154 * Creates a new #GstMIKEYMessage after parsing the key-mgmt attribute
4155 * from a #GstSDPMessage.
4157 * Returns: a #GstSDPResult.
4162 gst_sdp_message_parse_keymgmt (const GstSDPMessage * msg,
4163 GstMIKEYMessage ** mikey)
4165 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
4167 return sdp_add_attributes_to_keymgmt (msg->attributes, mikey);
4171 * gst_sdp_media_parse_keymgmt:
4172 * @media: a #GstSDPMedia
4173 * @mikey: (out) (transfer full): pointer to new #GstMIKEYMessage
4175 * Creates a new #GstMIKEYMessage after parsing the key-mgmt attribute
4176 * from a #GstSDPMedia.
4178 * Returns: a #GstSDPResult.
4183 gst_sdp_media_parse_keymgmt (const GstSDPMedia * media,
4184 GstMIKEYMessage ** mikey)
4186 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
4188 return sdp_add_attributes_to_keymgmt (media->attributes, mikey);
4192 sdp_add_attributes_to_caps (GArray * attributes, GstCaps * caps)
4194 if (attributes->len > 0) {
4198 s = gst_caps_get_structure (caps, 0);
4200 for (i = 0; i < attributes->len; i++) {
4201 GstSDPAttribute *attr = &g_array_index (attributes, GstSDPAttribute, i);
4202 gchar *tofree, *key;
4206 /* skip some of the attribute we already handle */
4207 if (!strcmp (key, "fmtp"))
4209 if (!strcmp (key, "rtpmap"))
4211 if (!strcmp (key, "control"))
4213 if (!strcmp (key, "range"))
4215 if (!strcmp (key, "framesize"))
4217 if (!strcmp (key, "key-mgmt"))
4219 if (!strcmp (key, "extmap"))
4221 if (!strcmp (key, "ssrc"))
4223 if (!strcmp (key, "rid"))
4226 /* string must be valid UTF8 */
4227 if (!g_utf8_validate (attr->value, -1, NULL))
4230 if (!g_str_has_prefix (key, "x-"))
4231 tofree = key = g_strdup_printf ("a-%s", key);
4235 GST_DEBUG ("adding caps: %s=%s", key, attr->value);
4236 gst_structure_set (s, key, G_TYPE_STRING, attr->value, NULL);
4245 gst_sdp_media_add_extmap_attributes (GArray * attributes, GstCaps * caps)
4247 const gchar *extmap;
4248 gchar *p, *tmp, *to_free;
4252 g_return_val_if_fail (attributes != NULL, GST_SDP_EINVAL);
4253 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
4255 s = gst_caps_get_structure (caps, 0);
4257 for (i = 0; i < attributes->len; i++) {
4258 GstSDPAttribute *attr;
4259 const gchar *direction, *extensionname, *extensionattributes;
4261 attr = &g_array_index (attributes, GstSDPAttribute, i);
4262 if (strcmp (attr->key, "extmap") != 0)
4265 extmap = attr->value;
4267 /* p is now of the format id[/direction] extensionname [extensionattributes] */
4268 to_free = p = g_strdup (extmap);
4270 id = strtoul (p, &tmp, 10);
4271 if (id == 0 || id == 15 || id > 9999 || (*tmp != ' ' && *tmp != '/')) {
4272 GST_ERROR ("Invalid extmap '%s'", to_free);
4274 } else if (*tmp == '/') {
4278 PARSE_STRING (p, " ", direction);
4280 /* Invalid format */
4281 if (direction == NULL || *direction == '\0') {
4282 GST_ERROR ("Invalid extmap '%s'", to_free);
4293 tmp = strstr (p, " ");
4296 extensionattributes = "";
4302 extensionattributes = p;
4305 if (extensionname == NULL || *extensionname == '\0') {
4306 GST_ERROR ("Invalid extmap '%s'", to_free);
4310 if (*direction != '\0' || *extensionattributes != '\0') {
4311 GValue arr = G_VALUE_INIT;
4312 GValue val = G_VALUE_INIT;
4315 key = g_strdup_printf ("extmap-%u", id);
4317 g_value_init (&arr, GST_TYPE_ARRAY);
4318 g_value_init (&val, G_TYPE_STRING);
4320 g_value_set_string (&val, direction);
4321 gst_value_array_append_value (&arr, &val);
4323 g_value_set_string (&val, extensionname);
4324 gst_value_array_append_value (&arr, &val);
4326 g_value_set_string (&val, extensionattributes);
4327 gst_value_array_append_value (&arr, &val);
4329 gst_structure_set_value (s, key, &arr);
4330 g_value_unset (&val);
4331 g_value_unset (&arr);
4332 GST_DEBUG ("adding caps: %s=<%s,%s,%s>", key, direction, extensionname,
4333 extensionattributes);
4338 key = g_strdup_printf ("extmap-%u", id);
4339 gst_structure_set (s, key, G_TYPE_STRING, extensionname, NULL);
4340 GST_DEBUG ("adding caps: %s=%s", key, extensionname);
4350 /* parses Source-specific media SDP attributes (RFC5576) into caps */
4352 gst_sdp_media_add_ssrc_attributes (GArray * attributes, GstCaps * caps)
4354 gchar *p, *tmp, *to_free;
4358 g_return_val_if_fail (attributes != NULL, GST_SDP_EINVAL);
4359 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
4361 s = gst_caps_get_structure (caps, 0);
4363 for (i = 0; i < attributes->len; i++) {
4365 GstSDPAttribute *attr;
4367 gchar *ssrc_val, *ssrc_attr;
4370 attr = &g_array_index (attributes, GstSDPAttribute, i);
4371 if (strcmp (attr->key, "ssrc") != 0)
4374 value = attr->value;
4376 /* p is now of the format ssrc attribute[:value] */
4377 to_free = p = g_strdup (value);
4379 ssrc = strtoul (p, &tmp, 10);
4381 GST_ERROR ("Invalid ssrc attribute '%s'", to_free);
4390 tmp = strstr (p, ":");
4393 ssrc_val = (gchar *) "";
4401 if (ssrc_attr == NULL || *ssrc_attr == '\0') {
4402 GST_ERROR ("Invalid ssrc attribute '%s'", to_free);
4406 key = g_strdup_printf ("ssrc-%u-%s", ssrc, ssrc_attr);
4407 gst_structure_set (s, key, G_TYPE_STRING, ssrc_val, NULL);
4408 GST_DEBUG ("adding caps: %s=%s", key, ssrc_val);
4417 /* parses RID SDP attributes (RFC8851) into caps */
4419 gst_sdp_media_add_rid_attributes (GArray * attributes, GstCaps * caps)
4426 g_return_val_if_fail (attributes != NULL, GST_SDP_EINVAL);
4427 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
4428 g_return_val_if_fail (gst_caps_is_writable (caps), GST_SDP_EINVAL);
4430 s = gst_caps_get_structure (caps, 0);
4432 for (i = 0; i < attributes->len; i++) {
4433 GstSDPAttribute *attr;
4434 const char *direction, *params, *id;
4437 attr = &g_array_index (attributes, GstSDPAttribute, i);
4438 if (strcmp (attr->key, "rid") != 0)
4443 /* p is now of the format id dir ;-separated-params */
4444 to_free = p = g_strdup (rid);
4446 PARSE_STRING (p, " ", id);
4447 if (id == NULL || *id == '\0') {
4448 GST_ERROR ("Invalid rid \'%s\'", to_free);
4452 while (*tmp && (*tmp == '-' || *tmp == '_' || g_ascii_isalnum (*tmp)))
4455 GST_ERROR ("Invalid rid-id \'%s\'", id);
4461 PARSE_STRING (p, " ", direction);
4462 if (direction == NULL || *direction == '\0') {
4471 if (direction == NULL || *direction == '\0'
4472 || (g_strcmp0 (direction, "send") != 0
4473 && g_strcmp0 (direction, "recv") != 0)) {
4474 GST_ERROR ("Invalid rid direction \'%s\'", p);
4478 if (params && *params != '\0') {
4479 GValue arr = G_VALUE_INIT;
4480 GValue val = G_VALUE_INIT;
4482 #if !defined(GST_DISABLE_DEBUG)
4483 GString *debug_params = g_string_new (NULL);
4487 key = g_strdup_printf ("rid-%s", id);
4489 g_value_init (&arr, GST_TYPE_ARRAY);
4490 g_value_init (&val, G_TYPE_STRING);
4492 g_value_set_string (&val, direction);
4493 gst_value_array_append_and_take_value (&arr, &val);
4494 val = (GValue) G_VALUE_INIT;
4498 gboolean done = FALSE;
4500 PARSE_STRING (p, ";", param);
4510 g_value_init (&val, G_TYPE_STRING);
4511 g_value_set_string (&val, param);
4512 gst_value_array_append_and_take_value (&arr, &val);
4513 val = (GValue) G_VALUE_INIT;
4514 #if !defined(GST_DISABLE_DEBUG)
4516 g_string_append_c (debug_params, ',');
4517 g_string_append (debug_params, param);
4524 gst_structure_take_value (s, key, &arr);
4525 arr = (GValue) G_VALUE_INIT;
4526 #if !defined(GST_DISABLE_DEBUG)
4528 char *debug_str = g_string_free (debug_params, FALSE);
4529 GST_DEBUG ("adding caps: %s=<%s,%s>", key, direction, debug_str);
4537 key = g_strdup_printf ("rid-%s", id);
4538 gst_structure_set (s, key, G_TYPE_STRING, direction, NULL);
4539 GST_DEBUG ("adding caps: %s=%s", key, direction);
4544 g_clear_pointer (&to_free, g_free);
4550 * gst_sdp_message_attributes_to_caps:
4551 * @msg: a #GstSDPMessage
4554 * Mapping of attributes of #GstSDPMessage to #GstCaps
4556 * Returns: a #GstSDPResult.
4561 gst_sdp_message_attributes_to_caps (const GstSDPMessage * msg, GstCaps * caps)
4564 GstMIKEYMessage *mikey = NULL;
4566 g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
4567 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
4569 gst_sdp_message_parse_keymgmt (msg, &mikey);
4571 if (gst_mikey_message_to_caps (mikey, caps)) {
4572 res = GST_SDP_EINVAL;
4577 res = sdp_add_attributes_to_caps (msg->attributes, caps);
4579 if (res == GST_SDP_OK) {
4580 /* parse global extmap field */
4581 res = gst_sdp_media_add_extmap_attributes (msg->attributes, caps);
4586 gst_mikey_message_unref (mikey);
4591 * gst_sdp_media_attributes_to_caps:
4592 * @media: a #GstSDPMedia
4595 * Mapping of attributes of #GstSDPMedia to #GstCaps
4597 * Returns: a #GstSDPResult.
4602 gst_sdp_media_attributes_to_caps (const GstSDPMedia * media, GstCaps * caps)
4605 GstMIKEYMessage *mikey = NULL;
4607 g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
4608 g_return_val_if_fail (caps != NULL && GST_IS_CAPS (caps), GST_SDP_EINVAL);
4610 gst_sdp_media_parse_keymgmt (media, &mikey);
4612 if (!gst_mikey_message_to_caps (mikey, caps)) {
4613 res = GST_SDP_EINVAL;
4618 res = sdp_add_attributes_to_caps (media->attributes, caps);
4620 if (res == GST_SDP_OK) {
4621 /* parse media extmap field */
4622 res = gst_sdp_media_add_extmap_attributes (media->attributes, caps);
4625 if (res == GST_SDP_OK) {
4626 /* parse media ssrc field */
4627 res = gst_sdp_media_add_ssrc_attributes (media->attributes, caps);
4630 if (res == GST_SDP_OK) {
4631 /* parse media rid fields */
4632 res = gst_sdp_media_add_rid_attributes (media->attributes, caps);
4637 gst_mikey_message_unref (mikey);