/* * Farstream - Farstream RTP specific types * * Copyright 2011 Collabora Ltd. * @author: Olivier Crete * Copyright 2011 Nokia Corp. * * fs-rtp.c - Farstream RTP specific types * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "fs-rtp.h" #include typedef GList FsRtpHeaderExtensionGList; G_DEFINE_BOXED_TYPE (FsRtpHeaderExtension, fs_rtp_header_extension, fs_rtp_header_extension_copy, fs_rtp_header_extension_destroy) G_DEFINE_BOXED_TYPE (FsRtpHeaderExtensionGList, fs_rtp_header_extension_list, fs_rtp_header_extension_list_copy, fs_rtp_header_extension_list_destroy) /** * fs_rtp_header_extension_new: * @id: The identifier of the RTP header extension * @direction: the direction in which this extension can be used * @uri: The URI that defines this extension * * Creates a new #FsRtpHeaderExtension * * Returns: a new #FsRtpHeaderExtension */ FsRtpHeaderExtension * fs_rtp_header_extension_new (guint id, FsStreamDirection direction, const gchar *uri) { FsRtpHeaderExtension *extension; extension = g_slice_new (FsRtpHeaderExtension); extension->id = id; extension->direction = direction; extension->uri = g_strdup (uri); return extension; } /** * fs_rtp_header_extension_copy: (skip) * @extension: The RTP header extension definition to copy * * Copies a #FsRtpHeaderExtension * * Returns: a new #FsRtpHeaderExtension */ FsRtpHeaderExtension * fs_rtp_header_extension_copy (FsRtpHeaderExtension *extension) { if (extension) return fs_rtp_header_extension_new (extension->id, extension->direction, extension->uri); else return NULL; } /** * fs_rtp_header_extension_are_equal: * @extension1: The first #FsRtpHeaderExtension * @extension2: The second #FsRtpHeaderExtension * * Compares two #FsRtpHeaderExtension structures * * Returns: %TRUE if they are identical, %FALSE otherwise */ gboolean fs_rtp_header_extension_are_equal (FsRtpHeaderExtension *extension1, FsRtpHeaderExtension *extension2) { if (extension1 == extension2) return TRUE; if (!extension1 || !extension2) return FALSE; if (extension1->id == extension2->id && extension1->direction == extension2->direction && (extension1->uri == extension2->uri || (extension1->uri && extension2->uri && !strcmp (extension1->uri, extension2->uri)))) return TRUE; else return FALSE; } /** * fs_rtp_header_extension_destroy: (skip) * @extension: A RTP header extension to free * * Frees the passed #FsRtpHeaderExtension */ void fs_rtp_header_extension_destroy (FsRtpHeaderExtension *extension) { if (extension) { g_free (extension->uri); g_slice_free (FsRtpHeaderExtension, extension); } } /** * fs_rtp_header_extension_list_copy: * @extensions: (element-type FsRtpHeaderExtension) (transfer none): * a #GList of #FsRtpHeaderExtension * * Does a deep copy of a #GList of #FsRtpHeaderExtension * * Returns: (element-type FsRtpHeaderExtension) (transfer full): a new * #GList of #FsRtpHeaderExtension */ GList * fs_rtp_header_extension_list_copy (GList *extensions) { GQueue copy = G_QUEUE_INIT; const GList *lp; for (lp = extensions; lp; lp = g_list_next (lp)) { FsRtpHeaderExtension *ext = lp->data; g_queue_push_tail (©, fs_rtp_header_extension_copy (ext)); } return copy.head; } /** * fs_rtp_header_extension_list_destroy: (skip) * @extensions: a #GList of #FsRtpHeaderExtension * * Frees the passed #GList of #FsRtpHeaderExtension */ void fs_rtp_header_extension_list_destroy (GList *extensions) { g_list_foreach (extensions, (GFunc) fs_rtp_header_extension_destroy, NULL); g_list_free (extensions); } #define RTP_HDREXT_PREFIX "rtp-hdrext:" #define RTP_HDREXT_AUDIO_PREFIX "audio:" #define RTP_HDREXT_VIDEO_PREFIX "video:" #define RTP_HDREXT_APPLICATION_PREFIX "application:" /** * fs_rtp_header_extension_list_from_keyfile: * @filename: Name of the #GKeyFile to read the RTP Header Extensions from * @media_type: The media type for which to get header extensions * @error: location of a #GError, or NULL if no error occured * * Reads the content of a #GKeyFile of the following format into a * #GList of #FsRtpHeaderExtension structures. * * The groups have a format "rtp-hdrext:audio:XXX" or * "rtp-hdrext:video:XXX" where XXX is a unique string (per media type). * * The valid keys are: * * id: a int between in the 1-255 and 4096-4351 ranges * uri: a URI describing the RTP Header Extension * direction (optional): To only send or receive a RTP Header * Extension, possible values are "send", "receive", "none" or "both". * Defaults to "both" * * * Example: * |[ * [rtp-hdrext:audio:a] * id=1 * uri=urn:ietf:params:rtp-hdrext:toffset * * [rtp-hdrext:audio:abc] * id=3 * uri=urn:ietf:params:rtp-hdrext:ntp-64 * direction=receive * ]| * * Returns: (element-type FsRtpHeaderExtension) (transfer full): a * #GList of #FsRtpHeaderExtension that must be freed with * fs_rtp_header_extension_list_destroy() */ GList * fs_rtp_header_extension_list_from_keyfile (const gchar *filename, FsMediaType media_type, GError **error) { GKeyFile *keyfile = NULL; GList *extensions = NULL; gchar **groups = NULL; gsize groups_count = 0; int i; g_return_val_if_fail (filename, NULL); g_return_val_if_fail (media_type <= FS_MEDIA_TYPE_LAST, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); keyfile = g_key_file_new (); if (!g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, error)) goto out; groups = g_key_file_get_groups (keyfile, &groups_count); if (!groups) goto out; for (i=0; i < groups_count && groups[i]; i++) { FsStreamDirection direction = FS_DIRECTION_BOTH; gint id; gchar *uri; GError *gerror = NULL; gchar *str; if (g_ascii_strncasecmp (RTP_HDREXT_PREFIX, groups[i], strlen (RTP_HDREXT_PREFIX))) continue; if (!g_ascii_strncasecmp (RTP_HDREXT_AUDIO_PREFIX, groups[i] + strlen (RTP_HDREXT_PREFIX), strlen (RTP_HDREXT_AUDIO_PREFIX))) { if (media_type != FS_MEDIA_TYPE_AUDIO) continue; } else if (!g_ascii_strncasecmp (RTP_HDREXT_VIDEO_PREFIX, groups[i] + strlen (RTP_HDREXT_PREFIX), strlen (RTP_HDREXT_VIDEO_PREFIX))) { if (media_type != FS_MEDIA_TYPE_VIDEO) continue; } else if (!g_ascii_strncasecmp (RTP_HDREXT_APPLICATION_PREFIX, groups[i] + strlen (RTP_HDREXT_PREFIX), strlen (RTP_HDREXT_APPLICATION_PREFIX))) { if (media_type != FS_MEDIA_TYPE_APPLICATION) continue; } else { continue; } id = g_key_file_get_integer (keyfile, groups[i], "id", &gerror); if (gerror) { g_clear_error (&gerror); continue; } str = g_key_file_get_string (keyfile, groups[i], "direction", &gerror); if (gerror) { GQuark domain = gerror->domain; gint code = gerror->code; g_clear_error (&gerror); if (domain != G_KEY_FILE_ERROR || code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) continue; } else { if (!g_ascii_strcasecmp (str, "none")) direction = FS_DIRECTION_NONE; else if (!g_ascii_strcasecmp (str, "send")) direction = FS_DIRECTION_SEND; else if (!g_ascii_strcasecmp (str, "recv") || !g_ascii_strcasecmp (str, "receive")) direction = FS_DIRECTION_RECV; g_free (str); } uri = g_key_file_get_string (keyfile, groups[i], "uri", &gerror); if (gerror) { g_clear_error (&gerror); continue; } extensions = g_list_append (extensions, fs_rtp_header_extension_new (id, direction, uri)); g_free (uri); } out: g_strfreev (groups); g_key_file_free (keyfile); return extensions; }