+2007-07-24 Wim Taymans <wim.taymans@gmail.com>
+
+ * configure.ac:
+ * gst-libs/gst/Makefile.am:
+ * gst-libs/gst/rtsp/Makefile.am:
+ * gst-libs/gst/rtsp/gstrtspbase64.c: (gst_rtsp_base64_encode):
+ * gst-libs/gst/rtsp/gstrtspbase64.h:
+ * gst-libs/gst/rtsp/gstrtspconnection.c: (inet_aton),
+ (gst_rtsp_connection_create), (gst_rtsp_connection_connect),
+ (add_auth_header), (add_date_header), (gst_rtsp_connection_write),
+ (gst_rtsp_connection_send), (read_line), (read_string), (read_key),
+ (parse_response_status), (parse_request_line), (parse_line),
+ (gst_rtsp_connection_read), (read_body),
+ (gst_rtsp_connection_receive), (gst_rtsp_connection_close),
+ (gst_rtsp_connection_free), (gst_rtsp_connection_next_timeout),
+ (gst_rtsp_connection_reset_timeout), (gst_rtsp_connection_flush),
+ (gst_rtsp_connection_set_auth):
+ * gst-libs/gst/rtsp/gstrtspconnection.h:
+ * gst-libs/gst/rtsp/gstrtspdefs.c: (rtsp_init_status),
+ (gst_rtsp_strresult), (gst_rtsp_method_as_text),
+ (gst_rtsp_version_as_text), (gst_rtsp_header_as_text),
+ (gst_rtsp_status_as_text), (gst_rtsp_find_header_field),
+ (gst_rtsp_find_method):
+ * gst-libs/gst/rtsp/gstrtspdefs.h:
+ * gst-libs/gst/rtsp/gstrtspmessage.c: (key_value_foreach),
+ (gst_rtsp_message_new), (gst_rtsp_message_init),
+ (gst_rtsp_message_new_request), (gst_rtsp_message_init_request),
+ (gst_rtsp_message_new_response), (gst_rtsp_message_init_response),
+ (gst_rtsp_message_init_data), (gst_rtsp_message_unset),
+ (gst_rtsp_message_free), (gst_rtsp_message_add_header),
+ (gst_rtsp_message_remove_header), (gst_rtsp_message_get_header),
+ (gst_rtsp_message_append_headers), (gst_rtsp_message_set_body),
+ (gst_rtsp_message_take_body), (gst_rtsp_message_get_body),
+ (gst_rtsp_message_steal_body), (dump_mem), (dump_key_value),
+ (gst_rtsp_message_dump):
+ * gst-libs/gst/rtsp/gstrtspmessage.h:
+ * gst-libs/gst/rtsp/gstrtsprange.c: (parse_npt_time),
+ (parse_npt_range), (parse_clock_range), (parse_smpte_range),
+ (gst_rtsp_range_parse), (gst_rtsp_range_free):
+ * gst-libs/gst/rtsp/gstrtsprange.h:
+ * gst-libs/gst/rtsp/gstrtsptransport.c: (gst_rtsp_transport_new),
+ (gst_rtsp_transport_init), (gst_rtsp_transport_get_mime),
+ (gst_rtsp_transport_get_manager), (parse_mode), (parse_range),
+ (range_as_text), (rtsp_transport_mode_as_text),
+ (rtsp_transport_profile_as_text), (rtsp_transport_ltrans_as_text),
+ (gst_rtsp_transport_parse), (gst_rtsp_transport_as_text),
+ (gst_rtsp_transport_free):
+ * gst-libs/gst/rtsp/gstrtsptransport.h:
+ * gst-libs/gst/rtsp/gstrtspurl.c: (gst_rtsp_url_parse),
+ (gst_rtsp_url_free), (gst_rtsp_url_set_port),
+ (gst_rtsp_url_get_port), (gst_rtsp_url_get_request_uri):
+ * gst-libs/gst/rtsp/gstrtspurl.h:
+ * gst-libs/gst/sdp/Makefile.am:
+ * gst-libs/gst/sdp/gstsdp.h:
+ * gst-libs/gst/sdp/gstsdpmessage.c: (gst_sdp_origin_init),
+ (gst_sdp_connection_init), (gst_sdp_bandwidth_init),
+ (gst_sdp_time_init), (gst_sdp_zone_init), (gst_sdp_key_init),
+ (gst_sdp_attribute_init), (gst_sdp_message_new),
+ (gst_sdp_message_init), (gst_sdp_message_uninit),
+ (gst_sdp_message_free), (gst_sdp_media_new), (gst_sdp_media_init),
+ (gst_sdp_media_uninit), (gst_sdp_media_free),
+ (gst_sdp_message_set_origin), (gst_sdp_message_get_origin),
+ (gst_sdp_message_set_connection), (gst_sdp_message_get_connection),
+ (gst_sdp_message_add_bandwidth), (gst_sdp_message_add_time),
+ (gst_sdp_message_add_zone), (gst_sdp_message_set_key),
+ (gst_sdp_message_get_key), (gst_sdp_message_get_attribute_val_n),
+ (gst_sdp_message_get_attribute_val),
+ (gst_sdp_message_add_attribute), (gst_sdp_message_add_media),
+ (gst_sdp_media_add_attribute), (gst_sdp_media_add_bandwidth),
+ (gst_sdp_media_add_format), (gst_sdp_media_get_attribute),
+ (gst_sdp_media_get_attribute_val_n),
+ (gst_sdp_media_get_attribute_val), (gst_sdp_media_get_format),
+ (read_string), (read_string_del), (gst_sdp_parse_line),
+ (gst_sdp_message_parse_buffer), (print_media),
+ (gst_sdp_message_dump):
+ * gst-libs/gst/sdp/gstsdpmessage.h:
+ * pkgconfig/gstreamer-plugins-base-uninstalled.pc.in:
+ Move SDP and RTSP from helper objects in -good to a reusable library.
+ Use a proper gst_ namespace.
+
2007-07-23 Sebastian Dröge <slomo@circular-chaos.org>
* ext/vorbis/vorbisdec.c: (vorbis_dec_push_forward),
gst-libs/gst/netbuffer/Makefile
gst-libs/gst/riff/Makefile
gst-libs/gst/rtp/Makefile
+gst-libs/gst/rtsp/Makefile
+gst-libs/gst/sdp/Makefile
gst-libs/gst/tag/Makefile
gst-libs/gst/pbutils/Makefile
gst-libs/gst/video/Makefile
pbutils \
riff \
rtp \
+ rtsp \
+ sdp \
video
noinst_HEADERS = gettext.h gst-i18n-plugin.h
--- /dev/null
+libgstrtspincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtsp
+
+libgstrtspinclude_HEADERS = gstrtspbase64.h \
+ gstrtspconnection.h \
+ gstrtspdefs.h \
+ gstrtspmessage.h \
+ gstrtsprange.h \
+ gstrtsptransport.h \
+ gstrtspurl.h
+
+#gstrtspextreal.h
+#gstrtspextwms.h
+
+lib_LTLIBRARIES = libgstrtsp-@GST_MAJORMINOR@.la
+
+libgstrtsp_@GST_MAJORMINOR@_la_SOURCES = gstrtspbase64.c \
+ gstrtspconnection.c \
+ gstrtspdefs.c \
+ gstrtspmessage.c \
+ gstrtsprange.c \
+ gstrtsptransport.c \
+ gstrtspurl.c
+
+#gstrtspextwms.c
+#rtspextreal.c
+
+libgstrtsp_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstrtsp_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS)
+libgstrtsp_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2007> Mike Smith <msmith@xiph.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtspbase64.h"
+
+static char base64table[64] = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+ 'P',
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e',
+ 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
+ 'v',
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+/* This isn't efficient, but it doesn't need to be */
+gchar *
+gst_rtsp_base64_encode (gchar * data, gint len)
+{
+ gchar *out = g_malloc (len * 4 / 3 + 4);
+ gchar *result = out;
+ int chunk;
+
+ while (len > 0) {
+ chunk = (len > 3) ? 3 : len;
+ *out++ = base64table[(*data & 0xFC) >> 2];
+ *out++ = base64table[((*data & 0x03) << 4) | ((*(data + 1) & 0xF0) >> 4)];
+ switch (chunk) {
+ case 3:
+ *out++ =
+ base64table[((*(data + 1) & 0x0F) << 2) | ((*(data +
+ 2) & 0xC0) >> 6)];
+ *out++ = base64table[(*(data + 2)) & 0x3F];
+ break;
+ case 2:
+ *out++ = base64table[((*(data + 1) & 0x0F) << 2)];
+ *out++ = '=';
+ break;
+ case 1:
+ *out++ = '=';
+ *out++ = '=';
+ break;
+ }
+ data += chunk;
+ len -= chunk;
+ }
+ *out = 0;
+
+ return result;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2007> Mike Smith <msmith@xiph.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __BASE64_H__
+#define __BASE64_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gchar *gst_rtsp_base64_encode(gchar *data, gint len);
+
+G_END_DECLS
+
+#endif
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+
+
+/* we include this here to get the G_OS_* defines */
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+#include <winsock2.h>
+#define EINPROGRESS WSAEINPROGRESS
+#else
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_FIONREAD_IN_SYS_FILIO
+#include <sys/filio.h>
+#endif
+
+#include "gstrtspconnection.h"
+#include "gstrtspbase64.h"
+
+/* the select call is also performed on the control sockets, that way
+ * we can send special commands to unlock or restart the select call */
+#define CONTROL_RESTART 'R' /* restart the select call */
+#define CONTROL_STOP 'S' /* stop the select call */
+#define CONTROL_SOCKETS(conn) conn->control_sock
+#define WRITE_SOCKET(conn) conn->control_sock[1]
+#define READ_SOCKET(conn) conn->control_sock[0]
+
+#define SEND_COMMAND(conn, command) \
+G_STMT_START { \
+ unsigned char c; c = command; \
+ write (WRITE_SOCKET(conn), &c, 1); \
+} G_STMT_END
+
+#define READ_COMMAND(conn, command, res) \
+G_STMT_START { \
+ res = read(READ_SOCKET(conn), &command, 1); \
+} G_STMT_END
+
+#ifdef G_OS_WIN32
+#define IOCTL_SOCKET ioctlsocket
+#define CLOSE_SOCKET(sock) closesocket(sock);
+#else
+#define IOCTL_SOCKET ioctl
+#define CLOSE_SOCKET(sock) close(sock);
+#endif
+
+#ifdef G_OS_WIN32
+static int
+inet_aton (const char *c, struct in_addr *paddr)
+{
+ /* note that inet_addr is deprecated on unix because
+ * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255
+ * address. */
+ paddr->s_addr = inet_addr (c);
+
+ if (paddr->s_addr == INADDR_NONE)
+ return 0;
+
+ return 1;
+}
+#endif
+
+GstRTSPResult
+gst_rtsp_connection_create (GstRTSPUrl * url, GstRTSPConnection ** conn)
+{
+ gint ret;
+ GstRTSPConnection *newconn;
+
+#ifdef G_OS_WIN32
+ unsigned long flags;
+#endif /* G_OS_WIN32 */
+
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+ newconn = g_new0 (GstRTSPConnection, 1);
+
+#ifdef G_OS_WIN32
+ /* This should work on UNIX too. PF_UNIX sockets replaced with pipe */
+ /* pipe( CONTROL_SOCKETS(newconn) ) */
+ if ((ret = pipe (CONTROL_SOCKETS (newconn))) < 0)
+ goto no_socket_pair;
+
+ ioctlsocket (READ_SOCKET (newconn), FIONBIO, &flags);
+ ioctlsocket (WRITE_SOCKET (newconn), FIONBIO, &flags);
+#else
+ if ((ret =
+ socketpair (PF_UNIX, SOCK_STREAM, 0, CONTROL_SOCKETS (newconn))) < 0)
+ goto no_socket_pair;
+
+ fcntl (READ_SOCKET (newconn), F_SETFL, O_NONBLOCK);
+ fcntl (WRITE_SOCKET (newconn), F_SETFL, O_NONBLOCK);
+#endif
+
+ newconn->url = url;
+ newconn->fd = -1;
+ newconn->timer = g_timer_new ();
+
+ newconn->auth_method = GST_RTSP_AUTH_NONE;
+ newconn->username = NULL;
+ newconn->passwd = NULL;
+
+ *conn = newconn;
+
+ return GST_RTSP_OK;
+
+ /* ERRORS */
+no_socket_pair:
+ {
+ g_free (newconn);
+ return GST_RTSP_ESYS;
+ }
+}
+
+GstRTSPResult
+gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
+{
+ gint fd;
+ struct sockaddr_in sa_in;
+ struct hostent *hostinfo;
+ char **addrs;
+ const gchar *ip;
+ gchar ipbuf[INET_ADDRSTRLEN];
+ struct in_addr addr;
+ gint ret;
+ guint16 port;
+ GstRTSPUrl *url;
+ fd_set writefds;
+ fd_set readfds;
+ struct timeval tv, *tvp;
+ gint max_fd, retval;
+
+#ifdef G_OS_WIN32
+ unsigned long flags;
+#endif /* G_OS_WIN32 */
+
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (conn->fd < 0, GST_RTSP_EINVAL);
+
+ url = conn->url;
+
+ /* first check if it already is an IP address */
+ if (inet_aton (url->host, &addr)) {
+ ip = url->host;
+ } else {
+ hostinfo = gethostbyname (url->host);
+ if (!hostinfo)
+ goto not_resolved; /* h_errno set */
+
+ if (hostinfo->h_addrtype != AF_INET)
+ goto not_ip; /* host not an IP host */
+
+ addrs = hostinfo->h_addr_list;
+ ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
+ sizeof (ipbuf));
+ }
+
+ /* get the port from the url */
+ gst_rtsp_url_get_port (url, &port);
+
+ memset (&sa_in, 0, sizeof (sa_in));
+ sa_in.sin_family = AF_INET; /* network socket */
+ sa_in.sin_port = htons (port); /* on port */
+ sa_in.sin_addr.s_addr = inet_addr (ip); /* on host ip */
+
+ fd = socket (AF_INET, SOCK_STREAM, 0);
+ if (fd == -1)
+ goto sys_error;
+
+ /* set to non-blocking mode so that we can cancel the connect */
+#ifndef G_OS_WIN32
+ fcntl (fd, F_SETFL, O_NONBLOCK);
+#else
+ ioctlsocket (fd, FIONBIO, &flags);
+#endif /* G_OS_WIN32 */
+
+ /* we are going to connect ASYNC now */
+ ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
+ if (ret == 0)
+ goto done;
+ if (errno != EINPROGRESS)
+ goto sys_error;
+
+ /* wait for connect to complete up to the specified timeout or until we got
+ * interrupted. */
+ FD_ZERO (&writefds);
+ FD_SET (fd, &writefds);
+ FD_ZERO (&readfds);
+ FD_SET (READ_SOCKET (conn), &readfds);
+
+ if (timeout->tv_sec != 0 || timeout->tv_usec != 0) {
+ tv.tv_sec = timeout->tv_sec;
+ tv.tv_usec = timeout->tv_usec;
+ tvp = &tv;
+ } else {
+ tvp = NULL;
+ }
+
+ max_fd = MAX (fd, READ_SOCKET (conn));
+
+ do {
+ retval = select (max_fd + 1, &readfds, &writefds, NULL, tvp);
+ } while ((retval == -1 && errno == EINTR));
+
+ if (retval == 0)
+ goto timeout;
+ else if (retval == -1)
+ goto sys_error;
+
+done:
+ conn->fd = fd;
+ conn->ip = g_strdup (ip);
+
+ return GST_RTSP_OK;
+
+sys_error:
+ {
+ if (fd != -1)
+ CLOSE_SOCKET (fd);
+ return GST_RTSP_ESYS;
+ }
+not_resolved:
+ {
+ return GST_RTSP_ENET;
+ }
+not_ip:
+ {
+ return GST_RTSP_ENOTIP;
+ }
+timeout:
+ {
+ return GST_RTSP_ETIMEOUT;
+ }
+}
+
+static void
+add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
+{
+ switch (conn->auth_method) {
+ case GST_RTSP_AUTH_BASIC:{
+ gchar *user_pass =
+ g_strdup_printf ("%s:%s", conn->username, conn->passwd);
+ gchar *user_pass64 =
+ gst_rtsp_base64_encode (user_pass, strlen (user_pass));
+ gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64);
+
+ gst_rtsp_message_add_header (message, GST_RTSP_HDR_AUTHORIZATION,
+ auth_string);
+
+ g_free (user_pass);
+ g_free (user_pass64);
+ g_free (auth_string);
+ break;
+ }
+ default:
+ /* Nothing to do */
+ break;
+ }
+}
+
+static void
+add_date_header (GstRTSPMessage * message)
+{
+ GTimeVal tv;
+ gchar date_string[100];
+
+ g_get_current_time (&tv);
+ strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
+ gmtime (&tv.tv_sec));
+
+ gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
+}
+
+GstRTSPResult
+gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
+ guint size, GTimeVal * timeout)
+{
+ guint towrite;
+ fd_set writefds;
+ fd_set readfds;
+ int max_fd;
+ gint retval;
+ struct timeval tv, *tvp;
+
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
+
+ FD_ZERO (&writefds);
+ FD_SET (conn->fd, &writefds);
+ FD_ZERO (&readfds);
+ FD_SET (READ_SOCKET (conn), &readfds);
+
+ max_fd = MAX (conn->fd, READ_SOCKET (conn));
+
+ if (timeout) {
+ tv.tv_sec = timeout->tv_sec;
+ tv.tv_usec = timeout->tv_usec;
+ tvp = &tv;
+ } else {
+ tvp = NULL;
+ }
+
+ towrite = size;
+
+ while (towrite > 0) {
+ gint written;
+
+ do {
+ retval = select (max_fd + 1, &readfds, &writefds, NULL, tvp);
+ } while ((retval == -1 && errno == EINTR));
+
+ if (retval == 0)
+ goto timeout;
+
+ if (retval == -1)
+ goto select_error;
+
+ if (FD_ISSET (READ_SOCKET (conn), &readfds)) {
+ /* read all stop commands */
+ while (TRUE) {
+ gchar command;
+ int res;
+
+ READ_COMMAND (conn, command, res);
+ if (res <= 0) {
+ /* no more commands */
+ break;
+ }
+ }
+ goto stopped;
+ }
+
+ /* now we can write */
+ written = write (conn->fd, data, towrite);
+ if (written < 0) {
+ if (errno != EAGAIN && errno != EINTR)
+ goto write_error;
+ } else {
+ towrite -= written;
+ data += written;
+ }
+ }
+ return GST_RTSP_OK;
+
+ /* ERRORS */
+timeout:
+ {
+ return GST_RTSP_ETIMEOUT;
+ }
+select_error:
+ {
+ return GST_RTSP_ESYS;
+ }
+stopped:
+ {
+ return GST_RTSP_EINTR;
+ }
+write_error:
+ {
+ return GST_RTSP_ESYS;
+ }
+}
+
+GstRTSPResult
+gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
+ GTimeVal * timeout)
+{
+ GString *str = NULL;
+ GstRTSPResult res;
+
+#ifdef G_OS_WIN32
+ WSADATA w;
+ int error;
+#endif
+
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
+
+#ifdef G_OS_WIN32
+ error = WSAStartup (0x0202, &w);
+
+ if (error)
+ goto startup_error;
+
+ if (w.wVersion != 0x0202)
+ goto version_error;
+#endif
+
+ str = g_string_new ("");
+
+ switch (message->type) {
+ case GST_RTSP_MESSAGE_REQUEST:
+ /* create request string, add CSeq */
+ g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
+ "CSeq: %d\r\n",
+ gst_rtsp_method_as_text (message->type_data.request.method),
+ message->type_data.request.uri, conn->cseq++);
+ /* add session id if we have one */
+ if (conn->session_id[0] != '\0') {
+ gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
+ conn->session_id);
+ }
+ /* add any authentication headers */
+ add_auth_header (conn, message);
+ break;
+ case GST_RTSP_MESSAGE_RESPONSE:
+ /* create response string */
+ g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
+ message->type_data.response.code, message->type_data.response.reason);
+ break;
+ case GST_RTSP_MESSAGE_DATA:
+ {
+ guint8 data_header[4];
+
+ /* prepare data header */
+ data_header[0] = '$';
+ data_header[1] = message->type_data.data.channel;
+ data_header[2] = (message->body_size >> 8) & 0xff;
+ data_header[3] = message->body_size & 0xff;
+
+ /* create string with header and data */
+ str = g_string_append_len (str, (gchar *) data_header, 4);
+ str =
+ g_string_append_len (str, (gchar *) message->body,
+ message->body_size);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* append headers and body */
+ if (message->type != GST_RTSP_MESSAGE_DATA) {
+ /* add date header */
+ add_date_header (message);
+
+ /* append headers */
+ gst_rtsp_message_append_headers (message, str);
+
+ /* append Content-Length and body if needed */
+ if (message->body != NULL && message->body_size > 0) {
+ gchar *len;
+
+ len = g_strdup_printf ("%d", message->body_size);
+ g_string_append_printf (str, "%s: %s\r\n",
+ gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
+ g_free (len);
+ /* header ends here */
+ g_string_append (str, "\r\n");
+ str =
+ g_string_append_len (str, (gchar *) message->body,
+ message->body_size);
+ } else {
+ /* just end headers */
+ g_string_append (str, "\r\n");
+ }
+ }
+
+ /* write request */
+ res =
+ gst_rtsp_connection_write (conn, (guint8 *) str->str, str->len, timeout);
+
+ g_string_free (str, TRUE);
+
+ return res;
+
+#ifdef G_OS_WIN32
+startup_error:
+ {
+ g_warning ("Error %d on WSAStartup", error);
+ return GST_RTSP_EWSASTART;
+ }
+version_error:
+ {
+ g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
+ w.wVersion);
+ WSACleanup ();
+ return GST_RTSP_EWSAVERSION;
+ }
+#endif
+}
+
+static GstRTSPResult
+read_line (gint fd, gchar * buffer, guint size)
+{
+ guint idx;
+ gchar c;
+ gint r;
+
+ idx = 0;
+ while (TRUE) {
+ r = read (fd, &c, 1);
+ if (r == 0) {
+ goto eof;
+ } else if (r < 0) {
+ if (errno != EAGAIN && errno != EINTR)
+ goto read_error;
+ } else {
+ if (c == '\n') /* end on \n */
+ break;
+ if (c == '\r') /* ignore \r */
+ continue;
+
+ if (idx < size - 1)
+ buffer[idx++] = c;
+ }
+ }
+ buffer[idx] = '\0';
+
+ return GST_RTSP_OK;
+
+eof:
+ {
+ return GST_RTSP_EEOF;
+ }
+read_error:
+ {
+ return GST_RTSP_ESYS;
+ }
+}
+
+static void
+read_string (gchar * dest, gint size, gchar ** src)
+{
+ gint idx;
+
+ idx = 0;
+ /* skip spaces */
+ while (g_ascii_isspace (**src))
+ (*src)++;
+
+ while (!g_ascii_isspace (**src) && **src != '\0') {
+ if (idx < size - 1)
+ dest[idx++] = **src;
+ (*src)++;
+ }
+ if (size > 0)
+ dest[idx] = '\0';
+}
+
+static void
+read_key (gchar * dest, gint size, gchar ** src)
+{
+ gint idx;
+
+ idx = 0;
+ while (**src != ':' && **src != '\0') {
+ if (idx < size - 1)
+ dest[idx++] = **src;
+ (*src)++;
+ }
+ if (size > 0)
+ dest[idx] = '\0';
+}
+
+static GstRTSPResult
+parse_response_status (gchar * buffer, GstRTSPMessage * msg)
+{
+ GstRTSPResult res;
+ gchar versionstr[20];
+ gchar codestr[4];
+ gint code;
+ gchar *bptr;
+
+ bptr = buffer;
+
+ read_string (versionstr, sizeof (versionstr), &bptr);
+ read_string (codestr, sizeof (codestr), &bptr);
+ code = atoi (codestr);
+
+ while (g_ascii_isspace (*bptr))
+ bptr++;
+
+ if (strcmp (versionstr, "RTSP/1.0") == 0)
+ GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
+ parse_error);
+ else if (strncmp (versionstr, "RTSP/", 5) == 0) {
+ GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
+ parse_error);
+ msg->type_data.response.version = GST_RTSP_VERSION_INVALID;
+ } else
+ goto parse_error;
+
+ return GST_RTSP_OK;
+
+parse_error:
+ {
+ return GST_RTSP_EPARSE;
+ }
+}
+
+static GstRTSPResult
+parse_request_line (gchar * buffer, GstRTSPMessage * msg)
+{
+ GstRTSPResult res = GST_RTSP_OK;
+ gchar versionstr[20];
+ gchar methodstr[20];
+ gchar urlstr[4096];
+ gchar *bptr;
+ GstRTSPMethod method;
+
+ bptr = buffer;
+
+ read_string (methodstr, sizeof (methodstr), &bptr);
+ method = gst_rtsp_find_method (methodstr);
+
+ read_string (urlstr, sizeof (urlstr), &bptr);
+ if (*urlstr == '\0')
+ res = GST_RTSP_EPARSE;
+
+ read_string (versionstr, sizeof (versionstr), &bptr);
+
+ if (*bptr != '\0')
+ res = GST_RTSP_EPARSE;
+
+ if (strcmp (versionstr, "RTSP/1.0") == 0) {
+ if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
+ res = GST_RTSP_EPARSE;
+ } else if (strncmp (versionstr, "RTSP/", 5) == 0) {
+ if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
+ res = GST_RTSP_EPARSE;
+ msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
+ } else {
+ gst_rtsp_message_init_request (msg, method, urlstr);
+ msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
+ res = GST_RTSP_EPARSE;
+ }
+
+ return res;
+}
+
+/* parsing lines means reading a Key: Value pair */
+static GstRTSPResult
+parse_line (gchar * buffer, GstRTSPMessage * msg)
+{
+ gchar key[32];
+ gchar *bptr;
+ GstRTSPHeaderField field;
+
+ bptr = buffer;
+
+ /* read key */
+ read_key (key, sizeof (key), &bptr);
+ if (*bptr != ':')
+ goto no_column;
+
+ bptr++;
+
+ field = gst_rtsp_find_header_field (key);
+ if (field != GST_RTSP_HDR_INVALID) {
+ while (g_ascii_isspace (*bptr))
+ bptr++;
+ gst_rtsp_message_add_header (msg, field, bptr);
+ }
+
+ return GST_RTSP_OK;
+
+no_column:
+ {
+ return GST_RTSP_EPARSE;
+ }
+}
+
+GstRTSPResult
+gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
+ GTimeVal * timeout)
+{
+ fd_set readfds;
+ guint toread;
+ gint retval;
+ struct timeval tv_timeout, *ptv_timeout = NULL;
+
+#ifndef G_OS_WIN32
+ gint avail;
+#else
+ gulong avail;
+#endif
+
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
+
+ if (size == 0)
+ return GST_RTSP_OK;
+
+ toread = size;
+
+ /* if the call fails, just go in the select.. it should not fail. Else if
+ * there is enough data to read, skip the select call al together.*/
+ if (IOCTL_SOCKET (conn->fd, FIONREAD, &avail) < 0)
+ avail = 0;
+ else if (avail >= toread)
+ goto do_read;
+
+ /* configure timeout if any */
+ if (timeout != NULL) {
+ tv_timeout.tv_sec = timeout->tv_sec;
+ tv_timeout.tv_usec = timeout->tv_usec;
+ ptv_timeout = &tv_timeout;
+ }
+
+ FD_ZERO (&readfds);
+ FD_SET (conn->fd, &readfds);
+ FD_SET (READ_SOCKET (conn), &readfds);
+
+ while (toread > 0) {
+ gint bytes;
+
+ do {
+ retval = select (FD_SETSIZE, &readfds, NULL, NULL, ptv_timeout);
+ } while ((retval == -1 && errno == EINTR));
+
+ if (retval == -1)
+ goto select_error;
+
+ /* check for timeout */
+ if (retval == 0)
+ goto select_timeout;
+
+ if (FD_ISSET (READ_SOCKET (conn), &readfds)) {
+ /* read all stop commands */
+ while (TRUE) {
+ gchar command;
+ int res;
+
+ READ_COMMAND (conn, command, res);
+ if (res <= 0) {
+ /* no more commands */
+ break;
+ }
+ }
+ goto stopped;
+ }
+
+ do_read:
+ /* if we get here there is activity on the real fd since the select
+ * completed and the control socket was not readable. */
+ bytes = read (conn->fd, data, toread);
+
+ if (bytes == 0) {
+ goto eof;
+ } else if (bytes < 0) {
+ if (errno != EAGAIN && errno != EINTR)
+ goto read_error;
+ } else {
+ toread -= bytes;
+ data += bytes;
+ }
+ }
+ return GST_RTSP_OK;
+
+ /* ERRORS */
+select_error:
+ {
+ return GST_RTSP_ESYS;
+ }
+select_timeout:
+ {
+ return GST_RTSP_ETIMEOUT;
+ }
+stopped:
+ {
+ return GST_RTSP_EINTR;
+ }
+eof:
+ {
+ return GST_RTSP_EEOF;
+ }
+read_error:
+ {
+ return GST_RTSP_ESYS;
+ }
+}
+
+static GstRTSPResult
+read_body (GstRTSPConnection * conn, glong content_length, GstRTSPMessage * msg,
+ GTimeVal * timeout)
+{
+ guint8 *body;
+ GstRTSPResult res;
+
+ if (content_length <= 0) {
+ body = NULL;
+ content_length = 0;
+ goto done;
+ }
+
+ body = g_malloc (content_length + 1);
+ body[content_length] = '\0';
+
+ GST_RTSP_CHECK (gst_rtsp_connection_read (conn, body, content_length,
+ timeout), read_error);
+
+ content_length += 1;
+
+done:
+ gst_rtsp_message_take_body (msg, (guint8 *) body, content_length);
+
+ return GST_RTSP_OK;
+
+ /* ERRORS */
+read_error:
+ {
+ g_free (body);
+ return res;
+ }
+}
+
+GstRTSPResult
+gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * msg,
+ GTimeVal * timeout)
+{
+ gchar buffer[4096];
+ gint line;
+ glong content_length;
+ GstRTSPResult res;
+ gboolean need_body;
+
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ line = 0;
+
+ need_body = TRUE;
+
+ res = GST_RTSP_OK;
+ /* parse first line and headers */
+ while (res == GST_RTSP_OK) {
+ guint8 c;
+
+ /* read first character, this identifies data messages */
+ GST_RTSP_CHECK (gst_rtsp_connection_read (conn, &c, 1, timeout),
+ read_error);
+
+ /* check for data packet, first character is $ */
+ if (c == '$') {
+ guint16 size;
+
+ /* data packets are $<1 byte channel><2 bytes length,BE><data bytes> */
+
+ /* read channel, which is the next char */
+ GST_RTSP_CHECK (gst_rtsp_connection_read (conn, &c, 1, timeout),
+ read_error);
+
+ /* now we create a data message */
+ gst_rtsp_message_init_data (msg, c);
+
+ /* next two bytes are the length of the data */
+ GST_RTSP_CHECK (gst_rtsp_connection_read (conn, (guint8 *) & size, 2,
+ timeout), read_error);
+
+ size = GUINT16_FROM_BE (size);
+
+ /* and read the body */
+ res = read_body (conn, size, msg, timeout);
+ need_body = FALSE;
+ break;
+ } else {
+ gint offset = 0;
+
+ /* we have a regular response */
+ if (c != '\r') {
+ buffer[0] = c;
+ offset = 1;
+ }
+ /* should not happen */
+ if (c == '\n')
+ break;
+
+ /* read lines */
+ GST_RTSP_CHECK (read_line (conn->fd, buffer + offset,
+ sizeof (buffer) - offset), read_error);
+
+ if (buffer[0] == '\0')
+ break;
+
+ if (line == 0) {
+ /* first line, check for response status */
+ if (g_str_has_prefix (buffer, "RTSP")) {
+ res = parse_response_status (buffer, msg);
+ } else {
+ res = parse_request_line (buffer, msg);
+ }
+ } else {
+ /* else just parse the line */
+ parse_line (buffer, msg);
+ }
+ }
+ line++;
+ }
+
+ /* read the rest of the body if needed */
+ if (need_body) {
+ gchar *session_id;
+ gchar *hdrval;
+
+ /* see if there is a Content-Length header */
+ if (gst_rtsp_message_get_header (msg, GST_RTSP_HDR_CONTENT_LENGTH,
+ &hdrval, 0) == GST_RTSP_OK) {
+ /* there is, read the body */
+ content_length = atol (hdrval);
+ GST_RTSP_CHECK (read_body (conn, content_length, msg, timeout),
+ read_error);
+ }
+
+ /* save session id in the connection for further use */
+ if (gst_rtsp_message_get_header (msg, GST_RTSP_HDR_SESSION,
+ &session_id, 0) == GST_RTSP_OK) {
+ gint maxlen, i;
+
+ /* default session timeout */
+ conn->timeout = 60;
+
+ maxlen = sizeof (conn->session_id) - 1;
+ /* the sessionid can have attributes marked with ;
+ * Make sure we strip them */
+ for (i = 0; session_id[i] != '\0'; i++) {
+ if (session_id[i] == ';') {
+ maxlen = i;
+ /* parse timeout */
+ do {
+ i++;
+ } while (g_ascii_isspace (session_id[i]));
+ if (g_str_has_prefix (&session_id[i], "timeout=")) {
+ gint to;
+
+ /* if we parsed something valid, configure */
+ if ((to = atoi (&session_id[i + 9])) > 0)
+ conn->timeout = to;
+ }
+ break;
+ }
+ }
+
+ /* make sure to not overflow */
+ strncpy (conn->session_id, session_id, maxlen);
+ conn->session_id[maxlen] = '\0';
+ }
+ }
+ return res;
+
+read_error:
+ {
+ return res;
+ }
+}
+
+GstRTSPResult
+gst_rtsp_connection_close (GstRTSPConnection * conn)
+{
+ gint res;
+
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+ g_free (conn->ip);
+ conn->ip = NULL;
+
+ if (conn->fd != -1) {
+ res = CLOSE_SOCKET (conn->fd);
+#ifdef G_OS_WIN32
+ WSACleanup ();
+#endif
+ conn->fd = -1;
+ if (res != 0)
+ goto sys_error;
+ }
+
+ return GST_RTSP_OK;
+
+sys_error:
+ {
+ return GST_RTSP_ESYS;
+ }
+}
+
+GstRTSPResult
+gst_rtsp_connection_free (GstRTSPConnection * conn)
+{
+ GstRTSPResult res;
+
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+#ifdef G_OS_WIN32
+ WSACleanup ();
+#endif
+ res = gst_rtsp_connection_close (conn);
+ g_timer_destroy (conn->timer);
+ g_free (conn->username);
+ g_free (conn->passwd);
+ g_free (conn);
+
+ return res;
+}
+
+GstRTSPResult
+gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
+{
+ gdouble elapsed;
+ glong sec;
+ gulong usec;
+
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
+
+ elapsed = g_timer_elapsed (conn->timer, &usec);
+ if (elapsed >= conn->timeout) {
+ sec = 0;
+ usec = 0;
+ } else {
+ sec = conn->timeout - elapsed;
+ }
+
+ timeout->tv_sec = sec;
+ timeout->tv_usec = usec;
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
+{
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+ g_timer_start (conn->timer);
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
+{
+ g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+ if (flush) {
+ SEND_COMMAND (conn, CONTROL_STOP);
+ } else {
+ while (TRUE) {
+ gchar command;
+ int res;
+
+ READ_COMMAND (conn, command, res);
+ if (res <= 0) {
+ /* no more commands */
+ break;
+ }
+ }
+ }
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
+ GstRTSPAuthMethod method, gchar * user, gchar * pass)
+{
+ /* Digest isn't implemented yet */
+ if (method == GST_RTSP_AUTH_DIGEST)
+ return GST_RTSP_ENOTIMPL;
+
+ /* Make sure the username and passwd are being set for authentication */
+ if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
+ return GST_RTSP_EINVAL;
+
+ /* ":" chars are not allowed in usernames for basic auth */
+ if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
+ return GST_RTSP_EINVAL;
+
+ g_free (conn->username);
+ g_free (conn->passwd);
+
+ conn->auth_method = method;
+ conn->username = g_strdup (user);
+ conn->passwd = g_strdup (pass);
+
+ return GST_RTSP_OK;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTSP_CONNECTION_H__
+#define __GST_RTSP_CONNECTION_H__
+
+#include <glib.h>
+
+#include <gst/rtsp/gstrtspdefs.h>
+#include <gst/rtsp/gstrtspurl.h>
+#include <gst/rtsp/gstrtspmessage.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTSPConnection
+{
+ /* URL for the connection */
+ GstRTSPUrl *url;
+
+ /* connection state */
+ gint fd;
+ gint control_sock[2];
+ gchar *ip;
+
+ /* Session state */
+ gint cseq; /* sequence number */
+ gchar session_id[512]; /* session id */
+ gint timeout; /* session timeout in seconds */
+ GTimer *timer; /* timeout timer */
+
+ /* Authentication */
+ GstRTSPAuthMethod auth_method;
+ gchar *username;
+ gchar *passwd;
+} GstRTSPConnection;
+
+/* opening/closing a connection */
+GstRTSPResult gst_rtsp_connection_create (GstRTSPUrl *url, GstRTSPConnection **conn);
+GstRTSPResult gst_rtsp_connection_connect (GstRTSPConnection *conn, GTimeVal *timeout);
+GstRTSPResult gst_rtsp_connection_close (GstRTSPConnection *conn);
+GstRTSPResult gst_rtsp_connection_free (GstRTSPConnection *conn);
+
+/* sending/receiving raw bytes */
+GstRTSPResult gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data,
+ guint size, GTimeVal * timeout);
+GstRTSPResult gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
+ guint size, GTimeVal * timeout);
+
+/* sending/receiving messages */
+GstRTSPResult gst_rtsp_connection_send (GstRTSPConnection *conn, GstRTSPMessage *message, GTimeVal *timeout);
+GstRTSPResult gst_rtsp_connection_receive (GstRTSPConnection *conn, GstRTSPMessage *message, GTimeVal *timeout);
+
+/* reset the timeout */
+GstRTSPResult gst_rtsp_connection_next_timeout (GstRTSPConnection *conn, GTimeVal *timeout);
+GstRTSPResult gst_rtsp_connection_reset_timeout (GstRTSPConnection *conn);
+
+/* flushing state */
+GstRTSPResult gst_rtsp_connection_flush (GstRTSPConnection *conn, gboolean flush);
+
+/* Configure Authentication data */
+GstRTSPResult gst_rtsp_connection_set_auth (GstRTSPConnection *conn, GstRTSPAuthMethod method,
+ gchar *user, gchar *pass);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_CONNECTION_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <errno.h>
+
+extern int h_errno;
+
+#include "gstrtspdefs.h"
+
+#ifndef G_OS_WIN32
+#include <netdb.h>
+#endif
+
+static const gchar *rtsp_results[] = {
+ "OK",
+ /* errors */
+ "Generic error",
+ "Invalid parameter specified",
+ "Operation interrupted",
+ "Out of memory",
+ "Cannot resolve host",
+ "Function not implemented",
+ "System error: %s",
+ "Parse error",
+ "Error on WSAStartup",
+ "Windows sockets are not version 0x202",
+ "Received end-of-file",
+ "Network error: %s",
+ "Host is not a valid IP address",
+ "Timeout while waiting for server response",
+ "Unknown error (%d)",
+ NULL
+};
+
+static const gchar *rtsp_methods[] = {
+ "DESCRIBE",
+ "ANNOUNCE",
+ "GET_PARAMETER",
+ "OPTIONS",
+ "PAUSE",
+ "PLAY",
+ "RECORD",
+ "REDIRECT",
+ "SETUP",
+ "SET_PARAMETER",
+ "TEARDOWN",
+ NULL
+};
+
+static const gchar *rtsp_headers[] = {
+ "Accept", /* Accept R opt. entity */
+ "Accept-Encoding", /* Accept-Encoding R opt. entity */
+ "Accept-Language", /* Accept-Language R opt. all */
+ "Allow", /* Allow r opt. all */
+ "Authorization", /* Authorization R opt. all */
+ "Bandwidth", /* Bandwidth R opt. all */
+ "Blocksize", /* Blocksize R opt. all but OPTIONS, TEARDOWN */
+ "Cache-Control", /* Cache-Control g opt. SETUP */
+ "Conference", /* Conference R opt. SETUP */
+ "Connection", /* Connection g req. all */
+ "Content-Base", /* Content-Base e opt. entity */
+ "Content-Encoding", /* Content-Encoding e req. SET_PARAMETER, DESCRIBE, ANNOUNCE */
+ "Content-Language", /* Content-Language e req. DESCRIBE, ANNOUNCE */
+ "Content-Length", /* Content-Length e req. SET_PARAMETER, ANNOUNCE, entity */
+ "Content-Location", /* Content-Location e opt. entity */
+ "Content-Type", /* Content-Type e req. SET_PARAMETER, ANNOUNCE, entity */
+ "CSeq", /* CSeq g req. all */
+ "Date", /* Date g opt. all */
+ "Expires", /* Expires e opt. DESCRIBE, ANNOUNCE */
+ "From", /* From R opt. all */
+ "If-Modified-Since", /* If-Modified-Since R opt. DESCRIBE, SETUP */
+ "Last-Modified", /* Last-Modified e opt. entity */
+ "Proxy-Authenticate", /* Proxy-Authenticate */
+ "Proxy-Require", /* Proxy-Require R req. all */
+ "Public", /* Public r opt. all */
+ "Range", /* Range Rr opt. PLAY, PAUSE, RECORD */
+ "Referer", /* Referer R opt. all */
+ "Require", /* Require R req. all */
+ "Retry-After", /* Retry-After r opt. all */
+ "RTP-Info", /* RTP-Info r req. PLAY */
+ "Scale", /* Scale Rr opt. PLAY, RECORD */
+ "Session", /* Session Rr req. all but SETUP, OPTIONS */
+ "Server", /* Server r opt. all */
+ "Speed", /* Speed Rr opt. PLAY */
+ "Transport", /* Transport Rr req. SETUP */
+ "Unsupported", /* Unsupported r req. all */
+ "User-Agent", /* User-Agent R opt. all */
+ "Via", /* Via g opt. all */
+ "WWW-Authenticate", /* WWW-Authenticate r opt. all */
+
+ /* Real extensions */
+ "ClientChallenge", /* ClientChallenge */
+ "RealChallenge1", /* RealChallenge1 */
+ "RealChallenge2", /* RealChallenge2 */
+ "RealChallenge3", /* RealChallenge3 */
+ "Subscribe", /* Subscribe */
+ "Alert", /* Alert */
+ "ClientID", /* ClientID */
+ "CompanyID", /* CompanyID */
+ "GUID", /* GUID */
+ "RegionData", /* RegionData */
+ "SupportsMaximumASMBandwidth", /* SupportsMaximumASMBandwidth */
+ "Language", /* Language */
+ "PlayerStarttime", /* PlayerStarttime */
+
+ NULL
+};
+
+#define DEF_STATUS(c, t) \
+ g_hash_table_insert (statuses, GUINT_TO_POINTER(c), t)
+
+static GHashTable *
+rtsp_init_status (void)
+{
+ GHashTable *statuses = g_hash_table_new (NULL, NULL);
+
+ DEF_STATUS (GST_RTSP_STS_CONTINUE, "Continue");
+ DEF_STATUS (GST_RTSP_STS_OK, "OK");
+ DEF_STATUS (GST_RTSP_STS_CREATED, "Created");
+ DEF_STATUS (GST_RTSP_STS_LOW_ON_STORAGE, "Low on Storage Space");
+ DEF_STATUS (GST_RTSP_STS_MULTIPLE_CHOICES, "Multiple Choices");
+ DEF_STATUS (GST_RTSP_STS_MOVED_PERMANENTLY, "Moved Permanently");
+ DEF_STATUS (GST_RTSP_STS_MOVE_TEMPORARILY, "Moved Temporarily");
+ DEF_STATUS (GST_RTSP_STS_SEE_OTHER, "See Other");
+ DEF_STATUS (GST_RTSP_STS_NOT_MODIFIED, "Not Modified");
+ DEF_STATUS (GST_RTSP_STS_USE_PROXY, "Use Proxy");
+ DEF_STATUS (GST_RTSP_STS_BAD_REQUEST, "Bad Request");
+ DEF_STATUS (GST_RTSP_STS_UNAUTHORIZED, "Unauthorized");
+ DEF_STATUS (GST_RTSP_STS_PAYMENT_REQUIRED, "Payment Required");
+ DEF_STATUS (GST_RTSP_STS_FORBIDDEN, "Forbidden");
+ DEF_STATUS (GST_RTSP_STS_NOT_FOUND, "Not Found");
+ DEF_STATUS (GST_RTSP_STS_METHOD_NOT_ALLOWED, "Method Not Allowed");
+ DEF_STATUS (GST_RTSP_STS_NOT_ACCEPTABLE, "Not Acceptable");
+ DEF_STATUS (GST_RTSP_STS_PROXY_AUTH_REQUIRED,
+ "Proxy Authentication Required");
+ DEF_STATUS (GST_RTSP_STS_REQUEST_TIMEOUT, "Request Time-out");
+ DEF_STATUS (GST_RTSP_STS_GONE, "Gone");
+ DEF_STATUS (GST_RTSP_STS_LENGTH_REQUIRED, "Length Required");
+ DEF_STATUS (GST_RTSP_STS_PRECONDITION_FAILED, "Precondition Failed");
+ DEF_STATUS (GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE,
+ "Request Entity Too Large");
+ DEF_STATUS (GST_RTSP_STS_REQUEST_URI_TOO_LARGE, "Request-URI Too Large");
+ DEF_STATUS (GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
+ DEF_STATUS (GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD,
+ "Parameter Not Understood");
+ DEF_STATUS (GST_RTSP_STS_CONFERENCE_NOT_FOUND, "Conference Not Found");
+ DEF_STATUS (GST_RTSP_STS_NOT_ENOUGH_BANDWIDTH, "Not Enough Bandwidth");
+ DEF_STATUS (GST_RTSP_STS_SESSION_NOT_FOUND, "Session Not Found");
+ DEF_STATUS (GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
+ "Method Not Valid in This State");
+ DEF_STATUS (GST_RTSP_STS_HEADER_FIELD_NOT_VALID_FOR_RESOURCE,
+ "Header Field Not Valid for Resource");
+ DEF_STATUS (GST_RTSP_STS_INVALID_RANGE, "Invalid Range");
+ DEF_STATUS (GST_RTSP_STS_PARAMETER_IS_READONLY, "Parameter Is Read-Only");
+ DEF_STATUS (GST_RTSP_STS_AGGREGATE_OPERATION_NOT_ALLOWED,
+ "Aggregate operation not allowed");
+ DEF_STATUS (GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED,
+ "Only aggregate operation allowed");
+ DEF_STATUS (GST_RTSP_STS_UNSUPPORTED_TRANSPORT, "Unsupported transport");
+ DEF_STATUS (GST_RTSP_STS_DESTINATION_UNREACHABLE, "Destination unreachable");
+ DEF_STATUS (GST_RTSP_STS_INTERNAL_SERVER_ERROR, "Internal Server Error");
+ DEF_STATUS (GST_RTSP_STS_NOT_IMPLEMENTED, "Not Implemented");
+ DEF_STATUS (GST_RTSP_STS_BAD_GATEWAY, "Bad Gateway");
+ DEF_STATUS (GST_RTSP_STS_SERVICE_UNAVAILABLE, "Service Unavailable");
+ DEF_STATUS (GST_RTSP_STS_GATEWAY_TIMEOUT, "Gateway Time-out");
+ DEF_STATUS (GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
+ "RTSP Version not supported");
+ DEF_STATUS (GST_RTSP_STS_OPTION_NOT_SUPPORTED, "Option not supported");
+
+ return statuses;
+}
+
+gchar *
+gst_rtsp_strresult (GstRTSPResult result)
+{
+ gint idx;
+ gchar *res;
+
+ idx = ABS (result);
+ idx = CLAMP (idx, 0, -GST_RTSP_ELAST);
+
+ switch (idx) {
+ case -GST_RTSP_ESYS:
+ res = g_strdup_printf (rtsp_results[idx], g_strerror (errno));
+ break;
+ case -GST_RTSP_ENET:
+#ifndef G_OS_WIN32
+ res = g_strdup_printf (rtsp_results[idx], hstrerror (h_errno));
+#else
+ res =
+ g_strdup
+ ("not supported on win32, implement me in a different way ??");
+#endif
+ break;
+ case -GST_RTSP_ELAST:
+ res = g_strdup_printf (rtsp_results[idx], result);
+ break;
+ default:
+ res = g_strdup (rtsp_results[idx]);
+ break;
+ }
+ return res;
+}
+
+const gchar *
+gst_rtsp_method_as_text (GstRTSPMethod method)
+{
+ gint i;
+
+ if (method == GST_RTSP_INVALID)
+ return NULL;
+
+ i = 0;
+ while ((method & 1) == 0) {
+ i++;
+ method >>= 1;
+ }
+ return rtsp_methods[i];
+}
+
+const gchar *
+gst_rtsp_version_as_text (GstRTSPVersion version)
+{
+ switch (version) {
+ case GST_RTSP_VERSION_1_0:
+ return "1.0";
+
+ default:
+ return "0.0";
+ }
+}
+
+const gchar *
+gst_rtsp_header_as_text (GstRTSPHeaderField field)
+{
+ if (field == GST_RTSP_HDR_INVALID)
+ return NULL;
+ else
+ return rtsp_headers[field - 1];
+}
+
+const gchar *
+gst_rtsp_status_as_text (GstRTSPStatusCode code)
+{
+ static GHashTable *statuses;
+
+ if (G_UNLIKELY (statuses == NULL))
+ statuses = rtsp_init_status ();
+
+ return g_hash_table_lookup (statuses, GUINT_TO_POINTER (code));
+}
+
+GstRTSPHeaderField
+gst_rtsp_find_header_field (const gchar * header)
+{
+ gint idx;
+
+ for (idx = 0; rtsp_headers[idx]; idx++) {
+ if (g_ascii_strcasecmp (rtsp_headers[idx], header) == 0) {
+ return idx + 1;
+ }
+ }
+ return GST_RTSP_HDR_INVALID;
+}
+
+GstRTSPMethod
+gst_rtsp_find_method (const gchar * method)
+{
+ gint idx;
+
+ for (idx = 0; rtsp_methods[idx]; idx++) {
+ if (g_ascii_strcasecmp (rtsp_methods[idx], method) == 0) {
+ return (1 << idx);
+ }
+ }
+ return GST_RTSP_INVALID;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTSP_DEFS_H__
+#define __GST_RTSP_DEFS_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define GST_RTSP_CHECK(stmt, label) \
+G_STMT_START { \
+ if (G_UNLIKELY ((res = (stmt)) != GST_RTSP_OK)) \
+ goto label; \
+} G_STMT_END
+
+typedef enum {
+ GST_RTSP_OK = 0,
+ /* errors */
+ GST_RTSP_ERROR = -1,
+ GST_RTSP_EINVAL = -2,
+ GST_RTSP_EINTR = -3,
+ GST_RTSP_ENOMEM = -4,
+ GST_RTSP_ERESOLV = -5,
+ GST_RTSP_ENOTIMPL = -6,
+ GST_RTSP_ESYS = -7,
+ GST_RTSP_EPARSE = -8,
+ GST_RTSP_EWSASTART = -9,
+ GST_RTSP_EWSAVERSION = -10,
+ GST_RTSP_EEOF = -11,
+ GST_RTSP_ENET = -12,
+ GST_RTSP_ENOTIP = -13,
+ GST_RTSP_ETIMEOUT = -14,
+
+ GST_RTSP_ELAST = -15,
+} GstRTSPResult;
+
+typedef enum {
+ GST_RTSP_FAM_NONE,
+ GST_RTSP_FAM_INET,
+ GST_RTSP_FAM_INET6,
+} GstRTSPFamily;
+
+typedef enum {
+ GST_RTSP_STATE_INVALID,
+ GST_RTSP_STATE_INIT,
+ GST_RTSP_STATE_READY,
+ GST_RTSP_STATE_SEEKING,
+ GST_RTSP_STATE_PLAYING,
+ GST_RTSP_STATE_RECORDING,
+} GstRTSPState;
+
+typedef enum {
+ GST_RTSP_VERSION_INVALID = 0x00,
+ GST_RTSP_VERSION_1_0 = 0x10,
+} GstRTSPVersion;
+
+typedef enum {
+ GST_RTSP_INVALID = 0,
+ GST_RTSP_DESCRIBE = (1 << 0),
+ GST_RTSP_ANNOUNCE = (1 << 1),
+ GST_RTSP_GET_PARAMETER = (1 << 2),
+ GST_RTSP_OPTIONS = (1 << 3),
+ GST_RTSP_PAUSE = (1 << 4),
+ GST_RTSP_PLAY = (1 << 5),
+ GST_RTSP_RECORD = (1 << 6),
+ GST_RTSP_REDIRECT = (1 << 7),
+ GST_RTSP_SETUP = (1 << 8),
+ GST_RTSP_SET_PARAMETER = (1 << 9),
+ GST_RTSP_TEARDOWN = (1 << 10),
+} GstRTSPMethod;
+
+/* Authentication methods, ordered by strength */
+typedef enum {
+ GST_RTSP_AUTH_NONE = 0x00,
+ GST_RTSP_AUTH_BASIC = 0x01,
+ GST_RTSP_AUTH_DIGEST = 0x02
+} GstRTSPAuthMethod;
+
+/* Strongest available authentication method */
+#define GST_RTSP_AUTH_MAX GST_RTSP_AUTH_DIGEST
+
+typedef enum {
+ GST_RTSP_HDR_INVALID,
+
+ /*
+ * R = Request
+ * r = response
+ * g = general
+ * e = entity
+ */
+ GST_RTSP_HDR_ACCEPT, /* Accept R opt. entity */
+ GST_RTSP_HDR_ACCEPT_ENCODING, /* Accept-Encoding R opt. entity */
+ GST_RTSP_HDR_ACCEPT_LANGUAGE, /* Accept-Language R opt. all */
+ GST_RTSP_HDR_ALLOW, /* Allow r opt. all */
+ GST_RTSP_HDR_AUTHORIZATION, /* Authorization R opt. all */
+ GST_RTSP_HDR_BANDWIDTH, /* Bandwidth R opt. all */
+ GST_RTSP_HDR_BLOCKSIZE, /* Blocksize R opt. all but OPTIONS, TEARDOWN */
+ GST_RTSP_HDR_CACHE_CONTROL, /* Cache-Control g opt. SETUP */
+ GST_RTSP_HDR_CONFERENCE, /* Conference R opt. SETUP */
+ GST_RTSP_HDR_CONNECTION, /* Connection g req. all */
+ GST_RTSP_HDR_CONTENT_BASE, /* Content-Base e opt. entity */
+ GST_RTSP_HDR_CONTENT_ENCODING, /* Content-Encoding e req. SET_PARAMETER, DESCRIBE, ANNOUNCE */
+ GST_RTSP_HDR_CONTENT_LANGUAGE, /* Content-Language e req. DESCRIBE, ANNOUNCE */
+ GST_RTSP_HDR_CONTENT_LENGTH, /* Content-Length e req. SET_PARAMETER, ANNOUNCE, entity */
+ GST_RTSP_HDR_CONTENT_LOCATION, /* Content-Location e opt. entity */
+ GST_RTSP_HDR_CONTENT_TYPE, /* Content-Type e req. SET_PARAMETER, ANNOUNCE, entity */
+ GST_RTSP_HDR_CSEQ, /* CSeq g req. all */
+ GST_RTSP_HDR_DATE, /* Date g opt. all */
+ GST_RTSP_HDR_EXPIRES, /* Expires e opt. DESCRIBE, ANNOUNCE */
+ GST_RTSP_HDR_FROM, /* From R opt. all */
+ GST_RTSP_HDR_IF_MODIFIED_SINCE, /* If-Modified-Since R opt. DESCRIBE, SETUP */
+ GST_RTSP_HDR_LAST_MODIFIED, /* Last-Modified e opt. entity */
+ GST_RTSP_HDR_PROXY_AUTHENTICATE, /* Proxy-Authenticate */
+ GST_RTSP_HDR_PROXY_REQUIRE, /* Proxy-Require R req. all */
+ GST_RTSP_HDR_PUBLIC, /* Public r opt. all */
+ GST_RTSP_HDR_RANGE, /* Range Rr opt. PLAY, PAUSE, RECORD */
+ GST_RTSP_HDR_REFERER, /* Referer R opt. all */
+ GST_RTSP_HDR_REQUIRE, /* Require R req. all */
+ GST_RTSP_HDR_RETRY_AFTER, /* Retry-After r opt. all */
+ GST_RTSP_HDR_RTP_INFO, /* RTP-Info r req. PLAY */
+ GST_RTSP_HDR_SCALE, /* Scale Rr opt. PLAY, RECORD */
+ GST_RTSP_HDR_SESSION, /* Session Rr req. all but SETUP, OPTIONS */
+ GST_RTSP_HDR_SERVER, /* Server r opt. all */
+ GST_RTSP_HDR_SPEED, /* Speed Rr opt. PLAY */
+ GST_RTSP_HDR_TRANSPORT, /* Transport Rr req. SETUP */
+ GST_RTSP_HDR_UNSUPPORTED, /* Unsupported r req. all */
+ GST_RTSP_HDR_USER_AGENT, /* User-Agent R opt. all */
+ GST_RTSP_HDR_VIA, /* Via g opt. all */
+ GST_RTSP_HDR_WWW_AUTHENTICATE, /* WWW-Authenticate r opt. all */
+
+ /* Real extensions */
+ GST_RTSP_HDR_CLIENT_CHALLENGE, /* ClientChallenge */
+ GST_RTSP_HDR_REAL_CHALLENGE1, /* RealChallenge1 */
+ GST_RTSP_HDR_REAL_CHALLENGE2, /* RealChallenge2 */
+ GST_RTSP_HDR_REAL_CHALLENGE3, /* RealChallenge3 */
+ GST_RTSP_HDR_SUBSCRIBE, /* Subscribe */
+ GST_RTSP_HDR_ALERT, /* Alert */
+ GST_RTSP_HDR_CLIENT_ID, /* ClientID */
+ GST_RTSP_HDR_COMPANY_ID, /* CompanyID */
+ GST_RTSP_HDR_GUID, /* GUID */
+ GST_RTSP_HDR_REGION_DATA, /* RegionData */
+ GST_RTSP_HDR_MAX_ASM_WIDTH, /* SupportsMaximumASMBandwidth */
+ GST_RTSP_HDR_LANGUAGE, /* Language */
+ GST_RTSP_HDR_PLAYER_START_TIME, /* PlayerStarttime */
+
+
+} GstRTSPHeaderField;
+
+typedef enum {
+ GST_RTSP_STS_INVALID = 0,
+ GST_RTSP_STS_CONTINUE = 100,
+ GST_RTSP_STS_OK = 200,
+ GST_RTSP_STS_CREATED = 201,
+ GST_RTSP_STS_LOW_ON_STORAGE = 250,
+ GST_RTSP_STS_MULTIPLE_CHOICES = 300,
+ GST_RTSP_STS_MOVED_PERMANENTLY = 301,
+ GST_RTSP_STS_MOVE_TEMPORARILY = 302,
+ GST_RTSP_STS_SEE_OTHER = 303,
+ GST_RTSP_STS_NOT_MODIFIED = 304,
+ GST_RTSP_STS_USE_PROXY = 305,
+ GST_RTSP_STS_BAD_REQUEST = 400,
+ GST_RTSP_STS_UNAUTHORIZED = 401,
+ GST_RTSP_STS_PAYMENT_REQUIRED = 402,
+ GST_RTSP_STS_FORBIDDEN = 403,
+ GST_RTSP_STS_NOT_FOUND = 404,
+ GST_RTSP_STS_METHOD_NOT_ALLOWED = 405,
+ GST_RTSP_STS_NOT_ACCEPTABLE = 406,
+ GST_RTSP_STS_PROXY_AUTH_REQUIRED = 407,
+ GST_RTSP_STS_REQUEST_TIMEOUT = 408,
+ GST_RTSP_STS_GONE = 410,
+ GST_RTSP_STS_LENGTH_REQUIRED = 411,
+ GST_RTSP_STS_PRECONDITION_FAILED = 412,
+ GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE = 413,
+ GST_RTSP_STS_REQUEST_URI_TOO_LARGE = 414,
+ GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE = 415,
+ GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD = 451,
+ GST_RTSP_STS_CONFERENCE_NOT_FOUND = 452,
+ GST_RTSP_STS_NOT_ENOUGH_BANDWIDTH = 453,
+ GST_RTSP_STS_SESSION_NOT_FOUND = 454,
+ GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE = 455,
+ GST_RTSP_STS_HEADER_FIELD_NOT_VALID_FOR_RESOURCE = 456,
+ GST_RTSP_STS_INVALID_RANGE = 457,
+ GST_RTSP_STS_PARAMETER_IS_READONLY = 458,
+ GST_RTSP_STS_AGGREGATE_OPERATION_NOT_ALLOWED = 459,
+ GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED = 460,
+ GST_RTSP_STS_UNSUPPORTED_TRANSPORT = 461,
+ GST_RTSP_STS_DESTINATION_UNREACHABLE = 462,
+ GST_RTSP_STS_INTERNAL_SERVER_ERROR = 500,
+ GST_RTSP_STS_NOT_IMPLEMENTED = 501,
+ GST_RTSP_STS_BAD_GATEWAY = 502,
+ GST_RTSP_STS_SERVICE_UNAVAILABLE = 503,
+ GST_RTSP_STS_GATEWAY_TIMEOUT = 504,
+ GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED = 505,
+ GST_RTSP_STS_OPTION_NOT_SUPPORTED = 551,
+} GstRTSPStatusCode;
+
+gchar* gst_rtsp_strresult (GstRTSPResult result);
+
+const gchar* gst_rtsp_method_as_text (GstRTSPMethod method);
+const gchar* gst_rtsp_version_as_text (GstRTSPVersion version);
+const gchar* gst_rtsp_header_as_text (GstRTSPHeaderField field);
+const gchar* gst_rtsp_status_as_text (GstRTSPStatusCode code);
+
+GstRTSPHeaderField gst_rtsp_find_header_field (const gchar *header);
+GstRTSPMethod gst_rtsp_find_method (const gchar *method);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_DEFS_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ * <2006> Lutz Mueller <lutz at topfrose dot de>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "gstrtspmessage.h"
+
+typedef struct _RTSPKeyValue
+{
+ GstRTSPHeaderField field;
+ gchar *value;
+} RTSPKeyValue;
+
+static void
+key_value_foreach (GArray * array, GFunc func, gpointer user_data)
+{
+ guint i;
+
+ g_return_if_fail (array != NULL);
+
+ for (i = 0; i < array->len; i++) {
+ (*func) (&g_array_index (array, RTSPKeyValue, i), user_data);
+ }
+}
+
+GstRTSPResult
+gst_rtsp_message_new (GstRTSPMessage ** msg)
+{
+ GstRTSPMessage *newmsg;
+
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ newmsg = g_new0 (GstRTSPMessage, 1);
+
+ *msg = newmsg;
+
+ return gst_rtsp_message_init (newmsg);
+}
+
+GstRTSPResult
+gst_rtsp_message_init (GstRTSPMessage * msg)
+{
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ gst_rtsp_message_unset (msg);
+
+ msg->type = GST_RTSP_MESSAGE_INVALID;
+ msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_new_request (GstRTSPMessage ** msg, GstRTSPMethod method,
+ const gchar * uri)
+{
+ GstRTSPMessage *newmsg;
+
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (uri != NULL, GST_RTSP_EINVAL);
+
+ newmsg = g_new0 (GstRTSPMessage, 1);
+
+ *msg = newmsg;
+
+ return gst_rtsp_message_init_request (newmsg, method, uri);
+}
+
+GstRTSPResult
+gst_rtsp_message_init_request (GstRTSPMessage * msg, GstRTSPMethod method,
+ const gchar * uri)
+{
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (uri != NULL, GST_RTSP_EINVAL);
+
+ gst_rtsp_message_unset (msg);
+
+ msg->type = GST_RTSP_MESSAGE_REQUEST;
+ msg->type_data.request.method = method;
+ msg->type_data.request.uri = g_strdup (uri);
+ msg->type_data.request.version = GST_RTSP_VERSION_1_0;
+ msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_new_response (GstRTSPMessage ** msg, GstRTSPStatusCode code,
+ const gchar * reason, const GstRTSPMessage * request)
+{
+ GstRTSPMessage *newmsg;
+
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ newmsg = g_new0 (GstRTSPMessage, 1);
+
+ *msg = newmsg;
+
+ return gst_rtsp_message_init_response (newmsg, code, reason, request);
+}
+
+GstRTSPResult
+gst_rtsp_message_init_response (GstRTSPMessage * msg, GstRTSPStatusCode code,
+ const gchar * reason, const GstRTSPMessage * request)
+{
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ gst_rtsp_message_unset (msg);
+
+ if (reason == NULL)
+ reason = gst_rtsp_status_as_text (code);
+
+ msg->type = GST_RTSP_MESSAGE_RESPONSE;
+ msg->type_data.response.code = code;
+ msg->type_data.response.reason = g_strdup (reason);
+ msg->type_data.response.version = GST_RTSP_VERSION_1_0;
+ msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
+
+ if (request) {
+ gchar *header;
+
+ /* copy CSEQ */
+ if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_CSEQ, &header,
+ 0) == GST_RTSP_OK) {
+ gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CSEQ, header);
+ }
+
+ /* copy session id */
+ if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &header,
+ 0) == GST_RTSP_OK) {
+ char *pos;
+
+ header = g_strdup (header);
+ if ((pos = strchr (header, ';'))) {
+ *pos = '\0';
+ }
+ g_strchomp (header);
+ gst_rtsp_message_add_header (msg, GST_RTSP_HDR_SESSION, header);
+ g_free (header);
+ }
+
+ /* FIXME copy more headers? */
+ }
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_init_data (GstRTSPMessage * msg, guint8 channel)
+{
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ gst_rtsp_message_unset (msg);
+
+ msg->type = GST_RTSP_MESSAGE_DATA;
+ msg->type_data.data.channel = channel;
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_unset (GstRTSPMessage * msg)
+{
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ switch (msg->type) {
+ case GST_RTSP_MESSAGE_INVALID:
+ break;
+ case GST_RTSP_MESSAGE_REQUEST:
+ g_free (msg->type_data.request.uri);
+ break;
+ case GST_RTSP_MESSAGE_RESPONSE:
+ g_free (msg->type_data.response.reason);
+ break;
+ case GST_RTSP_MESSAGE_DATA:
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ if (msg->hdr_fields != NULL)
+ g_array_free (msg->hdr_fields, TRUE);
+
+ g_free (msg->body);
+
+ memset (msg, 0, sizeof *msg);
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_free (GstRTSPMessage * msg)
+{
+ GstRTSPResult res;
+
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ res = gst_rtsp_message_unset (msg);
+ if (res == GST_RTSP_OK)
+ g_free (msg);
+
+ return res;
+}
+
+GstRTSPResult
+gst_rtsp_message_add_header (GstRTSPMessage * msg, GstRTSPHeaderField field,
+ const gchar * value)
+{
+ RTSPKeyValue key_value;
+
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (value != NULL, GST_RTSP_EINVAL);
+
+ key_value.field = field;
+ key_value.value = g_strdup (value);
+
+ g_array_append_val (msg->hdr_fields, key_value);
+
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_remove_header (GstRTSPMessage * msg, GstRTSPHeaderField field,
+ gint indx)
+{
+ GstRTSPResult res = GST_RTSP_ENOTIMPL;
+ guint i = 0;
+ gint cnt = 0;
+
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ while (i < msg->hdr_fields->len) {
+ RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i);
+
+ if (key_value.field == field && (indx == -1 || cnt++ == indx)) {
+ g_array_remove_index (msg->hdr_fields, i);
+ res = GST_RTSP_OK;
+ if (indx != -1)
+ break;
+ } else {
+ i++;
+ }
+ }
+
+ return res;
+}
+
+GstRTSPResult
+gst_rtsp_message_get_header (const GstRTSPMessage * msg,
+ GstRTSPHeaderField field, gchar ** value, gint indx)
+{
+ guint i;
+ gint cnt = 0;
+
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ for (i = 0; i < msg->hdr_fields->len; i++) {
+ RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i);
+
+ if (key_value.field == field && cnt++ == indx) {
+ if (value)
+ *value = key_value.value;
+ return GST_RTSP_OK;
+ }
+ }
+
+ return GST_RTSP_ENOTIMPL;
+}
+
+GstRTSPResult
+gst_rtsp_message_append_headers (const GstRTSPMessage * msg, GString * str)
+{
+ guint i;
+
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (str != NULL, GST_RTSP_EINVAL);
+
+ for (i = 0; i < msg->hdr_fields->len; i++) {
+ RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i);
+ const gchar *keystr = gst_rtsp_header_as_text (key_value.field);
+
+ g_string_append_printf (str, "%s: %s\r\n", keystr, key_value.value);
+ }
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_set_body (GstRTSPMessage * msg, const guint8 * data,
+ guint size)
+{
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ return gst_rtsp_message_take_body (msg, g_memdup (data, size), size);
+}
+
+GstRTSPResult
+gst_rtsp_message_take_body (GstRTSPMessage * msg, guint8 * data, guint size)
+{
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
+
+ if (msg->body)
+ g_free (msg->body);
+
+ msg->body = data;
+ msg->body_size = size;
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_get_body (const GstRTSPMessage * msg, guint8 ** data,
+ guint * size)
+{
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (size != NULL, GST_RTSP_EINVAL);
+
+ *data = msg->body;
+ *size = msg->body_size;
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_steal_body (GstRTSPMessage * msg, guint8 ** data, guint * size)
+{
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (size != NULL, GST_RTSP_EINVAL);
+
+ *data = msg->body;
+ *size = msg->body_size;
+
+ msg->body = NULL;
+ msg->body_size = 0;
+
+ return GST_RTSP_OK;
+}
+
+static void
+dump_mem (guint8 * mem, guint size)
+{
+ guint i, j;
+ GString *string = g_string_sized_new (50);
+ GString *chars = g_string_sized_new (18);
+
+ i = j = 0;
+ while (i < size) {
+ if (g_ascii_isprint (mem[i]))
+ g_string_append_printf (chars, "%c", mem[i]);
+ else
+ g_string_append_printf (chars, ".");
+
+ g_string_append_printf (string, "%02x ", mem[i]);
+
+ j++;
+ i++;
+
+ if (j == 16 || i == size) {
+ g_print ("%08x (%p): %-48.48s %-16.16s\n", i - j, mem + i - j,
+ string->str, chars->str);
+ g_string_set_size (string, 0);
+ g_string_set_size (chars, 0);
+ j = 0;
+ }
+ }
+ g_string_free (string, TRUE);
+ g_string_free (chars, TRUE);
+}
+
+static void
+dump_key_value (gpointer data, gpointer user_data)
+{
+ RTSPKeyValue *key_value = (RTSPKeyValue *) data;
+
+ g_print (" key: '%s', value: '%s'\n",
+ gst_rtsp_header_as_text (key_value->field), key_value->value);
+}
+
+GstRTSPResult
+gst_rtsp_message_dump (GstRTSPMessage * msg)
+{
+ guint8 *data;
+ guint size;
+
+ g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+ switch (msg->type) {
+ case GST_RTSP_MESSAGE_REQUEST:
+ g_print ("RTSP request message %p\n", msg);
+ g_print (" request line:\n");
+ g_print (" method: '%s'\n",
+ gst_rtsp_method_as_text (msg->type_data.request.method));
+ g_print (" uri: '%s'\n", msg->type_data.request.uri);
+ g_print (" version: '%s'\n",
+ gst_rtsp_version_as_text (msg->type_data.request.version));
+ g_print (" headers:\n");
+ key_value_foreach (msg->hdr_fields, dump_key_value, NULL);
+ g_print (" body:\n");
+ gst_rtsp_message_get_body (msg, &data, &size);
+ dump_mem (data, size);
+ break;
+ case GST_RTSP_MESSAGE_RESPONSE:
+ g_print ("RTSP response message %p\n", msg);
+ g_print (" status line:\n");
+ g_print (" code: '%d'\n", msg->type_data.response.code);
+ g_print (" reason: '%s'\n", msg->type_data.response.reason);
+ g_print (" version: '%s'\n",
+ gst_rtsp_version_as_text (msg->type_data.response.version));
+ g_print (" headers:\n");
+ key_value_foreach (msg->hdr_fields, dump_key_value, NULL);
+ gst_rtsp_message_get_body (msg, &data, &size);
+ g_print (" body: length %d\n", size);
+ dump_mem (data, size);
+ break;
+ case GST_RTSP_MESSAGE_DATA:
+ g_print ("RTSP data message %p\n", msg);
+ g_print (" channel: '%d'\n", msg->type_data.data.channel);
+ g_print (" size: '%d'\n", msg->body_size);
+ gst_rtsp_message_get_body (msg, &data, &size);
+ dump_mem (data, size);
+ break;
+ default:
+ g_print ("unsupported message type %d\n", msg->type);
+ return GST_RTSP_EINVAL;
+ }
+ return GST_RTSP_OK;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTSP_MESSAGE_H__
+#define __GST_RTSP_MESSAGE_H__
+
+#include <glib.h>
+
+#include <gst/rtsp/gstrtspdefs.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ GST_RTSP_MESSAGE_INVALID,
+ GST_RTSP_MESSAGE_REQUEST,
+ GST_RTSP_MESSAGE_RESPONSE,
+ GST_RTSP_MESSAGE_DATA,
+} GstRTSPMsgType;
+
+typedef struct _GstRTSPMessage
+{
+ GstRTSPMsgType type;
+
+ union {
+ struct {
+ GstRTSPMethod method;
+ gchar *uri;
+ GstRTSPVersion version;
+ } request;
+ struct {
+ GstRTSPStatusCode code;
+ gchar *reason;
+ GstRTSPVersion version;
+ } response;
+ struct {
+ guint8 channel;
+ } data;
+ } type_data;
+
+ GArray *hdr_fields;
+
+ guint8 *body;
+ guint body_size;
+
+} GstRTSPMessage;
+
+GstRTSPResult gst_rtsp_message_new (GstRTSPMessage **msg);
+GstRTSPResult gst_rtsp_message_init (GstRTSPMessage *msg);
+
+GstRTSPResult gst_rtsp_message_new_request (GstRTSPMessage **msg,
+ GstRTSPMethod method,
+ const gchar *uri);
+GstRTSPResult gst_rtsp_message_init_request (GstRTSPMessage *msg,
+ GstRTSPMethod method,
+ const gchar *uri);
+
+GstRTSPResult gst_rtsp_message_new_response (GstRTSPMessage **msg,
+ GstRTSPStatusCode code,
+ const gchar *reason,
+ const GstRTSPMessage *request);
+GstRTSPResult gst_rtsp_message_init_response (GstRTSPMessage *msg,
+ GstRTSPStatusCode code,
+ const gchar *reason,
+ const GstRTSPMessage *request);
+
+GstRTSPResult gst_rtsp_message_init_data (GstRTSPMessage *msg,
+ guint8 channel);
+
+GstRTSPResult gst_rtsp_message_unset (GstRTSPMessage *msg);
+GstRTSPResult gst_rtsp_message_free (GstRTSPMessage *msg);
+
+
+GstRTSPResult gst_rtsp_message_add_header (GstRTSPMessage *msg,
+ GstRTSPHeaderField field,
+ const gchar *value);
+GstRTSPResult gst_rtsp_message_remove_header (GstRTSPMessage *msg,
+ GstRTSPHeaderField field,
+ gint indx);
+GstRTSPResult gst_rtsp_message_get_header (const GstRTSPMessage *msg,
+ GstRTSPHeaderField field,
+ gchar **value,
+ gint indx);
+
+GstRTSPResult gst_rtsp_message_append_headers (const GstRTSPMessage *msg,
+ GString *str);
+
+GstRTSPResult gst_rtsp_message_set_body (GstRTSPMessage *msg,
+ const guint8 *data,
+ guint size);
+GstRTSPResult gst_rtsp_message_take_body (GstRTSPMessage *msg,
+ guint8 *data,
+ guint size);
+GstRTSPResult gst_rtsp_message_get_body (const GstRTSPMessage *msg,
+ guint8 **data,
+ guint *size);
+GstRTSPResult gst_rtsp_message_steal_body (GstRTSPMessage *msg,
+ guint8 **data,
+ guint *size);
+
+GstRTSPResult gst_rtsp_message_dump (GstRTSPMessage *msg);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_MESSAGE_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "gstrtsprange.h"
+
+/* npt-time = "now" | npt-sec | npt-hhmmss
+ * npt-sec = 1*DIGIT [ "." *DIGIT ]
+ * npt-hhmmss = npt-hh ":" npt-mm ":" npt-ss [ "." *DIGIT ]
+ * npt-hh = 1*DIGIT ; any positive number
+ * npt-mm = 1*2DIGIT ; 0-59
+ * npt-ss = 1*2DIGIT ; 0-59
+ */
+static GstRTSPResult
+parse_npt_time (const gchar * str, GstRTSPTime * time)
+{
+ if (strcmp (str, "now") == 0) {
+ time->type = GST_RTSP_TIME_NOW;
+ } else if (str[0] == '\0') {
+ time->type = GST_RTSP_TIME_END;
+ } else if (strstr (str, ":")) {
+ gfloat seconds;
+ gint hours, mins;
+
+ sscanf (str, "%2d:%2d:%f", &hours, &mins, &seconds);
+
+ time->type = GST_RTSP_TIME_SECONDS;
+ time->seconds = ((hours * 60) + mins) * 60 + seconds;
+ } else {
+ gfloat seconds;
+
+ sscanf (str, "%f", &seconds);
+
+ time->type = GST_RTSP_TIME_SECONDS;
+ time->seconds = seconds;
+ }
+ return GST_RTSP_OK;
+}
+
+/* npt-range = ( npt-time "-" [ npt-time ] ) | ( "-" npt-time )
+ */
+static GstRTSPResult
+parse_npt_range (const gchar * str, GstRTSPTimeRange * range)
+{
+ GstRTSPResult res;
+ gchar *p;
+
+ range->unit = GST_RTSP_RANGE_NPT;
+
+ /* find '-' separator */
+ p = strstr (str, "-");
+ if (p == NULL)
+ return GST_RTSP_EINVAL;
+
+ if ((res = parse_npt_time (str, &range->min)) != GST_RTSP_OK)
+ goto done;
+
+ res = parse_npt_time (p + 1, &range->max);
+
+done:
+ return res;
+}
+
+static GstRTSPResult
+parse_clock_range (const gchar * str, GstRTSPTimeRange * range)
+{
+ return GST_RTSP_ENOTIMPL;
+}
+
+static GstRTSPResult
+parse_smpte_range (const gchar * str, GstRTSPTimeRange * range)
+{
+ return GST_RTSP_ENOTIMPL;
+}
+
+/**
+ * rtsp_range_parse:
+ * @rangestr: a range string to parse
+ * @range: location to hold the #GstRTSPTimeRange result
+ *
+ * Parse @rangestr to a #GstRTSPTimeRange.
+ *
+ * Returns: #GST_RTSP_OK on success.
+ */
+GstRTSPResult
+gst_rtsp_range_parse (const gchar * rangestr, GstRTSPTimeRange ** range)
+{
+ GstRTSPResult ret;
+ GstRTSPTimeRange *res;
+ gchar *p;
+
+ g_return_val_if_fail (rangestr != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (range != NULL, GST_RTSP_EINVAL);
+
+ res = g_new0 (GstRTSPTimeRange, 1);
+
+ p = (gchar *) rangestr;
+ /* first figure out the units of the range */
+ if (g_str_has_prefix (p, "npt=")) {
+ ret = parse_npt_range (p + 4, res);
+ } else if (g_str_has_prefix (p, "clock=")) {
+ ret = parse_clock_range (p + 6, res);
+ } else if (g_str_has_prefix (p, "smpte=")) {
+ res->unit = GST_RTSP_RANGE_SMPTE;
+ ret = parse_smpte_range (p + 6, res);
+ } else if (g_str_has_prefix (p, "smpte-30-drop=")) {
+ res->unit = GST_RTSP_RANGE_SMPTE_30_DROP;
+ ret = parse_smpte_range (p + 14, res);
+ } else if (g_str_has_prefix (p, "smpte-25=")) {
+ res->unit = GST_RTSP_RANGE_SMPTE_25;
+ ret = parse_smpte_range (p + 9, res);
+ } else
+ goto invalid;
+
+ if (ret == GST_RTSP_OK)
+ *range = res;
+
+ return ret;
+
+ /* ERRORS */
+invalid:
+ {
+ gst_rtsp_range_free (res);
+ return GST_RTSP_EINVAL;
+ }
+}
+
+void
+gst_rtsp_range_free (GstRTSPTimeRange * range)
+{
+ if (range == NULL)
+ return;
+
+ g_free (range);
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTSP_RANGE_H__
+#define __GST_RTSP_RANGE_H__
+
+#include <glib.h>
+
+#include <gst/rtsp/gstrtspdefs.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstRTSPRangeUnit:
+ * @GST_RTSP_RANGE_SMPTE:
+ * @GST_RTSP_RANGE_SMPTE_30_DROP:
+ * @GST_RTSP_RANGE_SMPTE_25:
+ * @GST_RTSP_RANGE_NPT:
+ * @GST_RTSP_RANGE_CLOCK:
+ *
+ * Different possible time range units.
+ */
+typedef enum
+{
+ GST_RTSP_RANGE_SMPTE,
+ GST_RTSP_RANGE_SMPTE_30_DROP,
+ GST_RTSP_RANGE_SMPTE_25,
+ GST_RTSP_RANGE_NPT,
+ GST_RTSP_RANGE_CLOCK
+} GstRTSPRangeUnit;
+
+typedef struct _GstRTSPTimeRange GstRTSPTimeRange;
+typedef struct _GstRTSPTime GstRTSPTime;
+
+typedef enum {
+ GST_RTSP_TIME_SECONDS,
+ GST_RTSP_TIME_NOW,
+ GST_RTSP_TIME_END
+} GstRTSPTimeType;
+
+struct _GstRTSPTime {
+ GstRTSPTimeType type;
+ gdouble seconds;
+};
+
+struct _GstRTSPTimeRange {
+ GstRTSPRangeUnit unit;
+
+ GstRTSPTime min;
+ GstRTSPTime max;
+};
+
+GstRTSPResult gst_rtsp_range_parse (const gchar *rangestr, GstRTSPTimeRange **range);
+void gst_rtsp_range_free (GstRTSPTimeRange *range);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_RANGE_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006,2007> Wim Taymans <wim@fluendo.com>
+ * <2007> Peter Kjellerstedt <pkj at axis com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "gstrtsptransport.h"
+
+#define MAX_MANAGERS 2
+
+typedef enum
+{
+ RTSP_TRANSPORT_DELIVERY = 1 << 0, /* multicast | unicast */
+ RTSP_TRANSPORT_DESTINATION = 1 << 1,
+ RTSP_TRANSPORT_SOURCE = 1 << 2,
+ RTSP_TRANSPORT_INTERLEAVED = 1 << 3,
+ RTSP_TRANSPORT_APPEND = 1 << 4,
+ RTSP_TRANSPORT_TTL = 1 << 5,
+ RTSP_TRANSPORT_LAYERS = 1 << 6,
+ RTSP_TRANSPORT_PORT = 1 << 7,
+ RTSP_TRANSPORT_CLIENT_PORT = 1 << 8,
+ RTSP_TRANSPORT_SERVER_PORT = 1 << 9,
+ RTSP_TRANSPORT_SSRC = 1 << 10,
+ RTSP_TRANSPORT_MODE = 1 << 11,
+} RTSPTransportParameter;
+
+typedef struct
+{
+ const gchar *name;
+ const GstRTSPTransMode mode;
+ const gchar *gst_mime;
+ const gchar *manager[MAX_MANAGERS];
+} GstRTSPTransMap;
+
+static const GstRTSPTransMap transports[] = {
+ {"rtp", GST_RTSP_TRANS_RTP, "application/x-rtp", {"gstrtpbin", "rtpdec"}},
+ {"x-real-rdt", GST_RTSP_TRANS_RDT, "application/x-rdt", {NULL, NULL}},
+ {"x-pn-tng", GST_RTSP_TRANS_RDT, "application/x-rdt", {NULL, NULL}},
+ {NULL, GST_RTSP_TRANS_UNKNOWN, NULL, {NULL, NULL}}
+};
+
+typedef struct
+{
+ const gchar *name;
+ const GstRTSPProfile profile;
+} RTSPProfileMap;
+
+static const RTSPProfileMap profiles[] = {
+ {"avp", GST_RTSP_PROFILE_AVP},
+ {"savp", GST_RTSP_PROFILE_SAVP},
+ {NULL, GST_RTSP_PROFILE_UNKNOWN}
+};
+
+typedef struct
+{
+ const gchar *name;
+ const GstRTSPLowerTrans ltrans;
+} RTSPLTransMap;
+
+static const RTSPLTransMap ltrans[] = {
+ {"udp", GST_RTSP_LOWER_TRANS_UDP},
+ {"mcast", GST_RTSP_LOWER_TRANS_UDP_MCAST},
+ {"tcp", GST_RTSP_LOWER_TRANS_TCP},
+ {NULL, GST_RTSP_LOWER_TRANS_UNKNOWN}
+};
+
+#define RTSP_TRANSPORT_PARAMETER_IS_UNIQUE(param) \
+G_STMT_START { \
+ if ((transport_params & (param)) != 0) \
+ goto invalid_transport; \
+ transport_params |= (param); \
+} G_STMT_END
+
+GstRTSPResult
+gst_rtsp_transport_new (GstRTSPTransport ** transport)
+{
+ GstRTSPTransport *trans;
+
+ g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
+
+ trans = g_new0 (GstRTSPTransport, 1);
+
+ *transport = trans;
+
+ return gst_rtsp_transport_init (trans);
+}
+
+GstRTSPResult
+gst_rtsp_transport_init (GstRTSPTransport * transport)
+{
+ g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
+
+ g_free (transport->destination);
+ g_free (transport->source);
+
+ memset (transport, 0, sizeof (GstRTSPTransport));
+
+ transport->trans = GST_RTSP_TRANS_RTP;
+ transport->profile = GST_RTSP_PROFILE_AVP;
+ transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
+ transport->mode_play = TRUE;
+ transport->mode_record = FALSE;
+ transport->interleaved.min = -1;
+ transport->interleaved.max = -1;
+ transport->port.min = -1;
+ transport->port.max = -1;
+ transport->client_port.min = -1;
+ transport->client_port.max = -1;
+ transport->server_port.min = -1;
+ transport->server_port.max = -1;
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_transport_get_mime (GstRTSPTransMode trans, const gchar ** mime)
+{
+ gint i;
+
+ g_return_val_if_fail (mime != NULL, GST_RTSP_EINVAL);
+
+ for (i = 0; transports[i].name; i++)
+ if (transports[i].mode == trans)
+ break;
+ *mime = transports[i].gst_mime;
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_transport_get_manager (GstRTSPTransMode trans, const gchar ** manager,
+ guint option)
+{
+ gint i;
+
+ g_return_val_if_fail (manager != NULL, GST_RTSP_EINVAL);
+
+ for (i = 0; transports[i].name; i++)
+ if (transports[i].mode == trans)
+ break;
+
+ if (option < MAX_MANAGERS)
+ *manager = transports[i].manager[option];
+ else
+ *manager = NULL;
+
+ return GST_RTSP_OK;
+}
+
+static void
+parse_mode (GstRTSPTransport * transport, const gchar * str)
+{
+ transport->mode_play = (strstr (str, "play") != NULL);
+ transport->mode_record = (strstr (str, "record") != NULL);
+}
+
+static void
+parse_range (const gchar * str, GstRTSPRange * range)
+{
+ gchar *minus;
+ gchar *tmp;
+
+ /* even though strtol() allows white space, plus and minus in front of
+ * the number, we do not allow it
+ */
+ if (g_ascii_isspace (*str) || *str == '+' || *str == '-')
+ goto invalid_range;
+
+ minus = strstr (str, "-");
+ if (minus) {
+ if (g_ascii_isspace (minus[1]) || minus[1] == '+' || minus[1] == '-')
+ goto invalid_range;
+
+ range->min = strtol (str, &tmp, 10);
+ if (str == tmp || tmp != minus)
+ goto invalid_range;
+
+ range->max = strtol (minus + 1, &tmp, 10);
+ if (*tmp && *tmp != ';')
+ goto invalid_range;
+ } else {
+ range->min = strtol (str, &tmp, 10);
+ if (str == tmp || (*tmp && *tmp != ';'))
+ goto invalid_range;
+
+ range->max = -1;
+ }
+
+ return;
+
+invalid_range:
+ {
+ range->min = -1;
+ range->max = -1;
+ return;
+ }
+}
+
+static gchar *
+range_as_text (const GstRTSPRange * range)
+{
+ if (range->min < 0)
+ return NULL;
+ else if (range->max < 0)
+ return g_strdup_printf ("%d", range->min);
+ else
+ return g_strdup_printf ("%d-%d", range->min, range->max);
+}
+
+static const gchar *
+rtsp_transport_mode_as_text (const GstRTSPTransport * transport)
+{
+ gint i;
+
+ for (i = 0; transports[i].name; i++)
+ if (transports[i].mode == transport->trans)
+ return transports[i].name;
+
+ return NULL;
+}
+
+static const gchar *
+rtsp_transport_profile_as_text (const GstRTSPTransport * transport)
+{
+ gint i;
+
+ for (i = 0; profiles[i].name; i++)
+ if (profiles[i].profile == transport->profile)
+ return profiles[i].name;
+
+ return NULL;
+}
+
+static const gchar *
+rtsp_transport_ltrans_as_text (const GstRTSPTransport * transport)
+{
+ gint i;
+
+ /* need to special case GST_RTSP_LOWER_TRANS_UDP_MCAST */
+ if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)
+ return "udp";
+
+ for (i = 0; ltrans[i].name; i++)
+ if (ltrans[i].ltrans == transport->lower_transport)
+ return ltrans[i].name;
+
+ return NULL;
+}
+
+GstRTSPResult
+gst_rtsp_transport_parse (const gchar * str, GstRTSPTransport * transport)
+{
+ gchar **split, *down, **transp = NULL;
+ guint transport_params = 0;
+ gint i;
+
+ g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (str != NULL, GST_RTSP_EINVAL);
+
+ gst_rtsp_transport_init (transport);
+
+ /* case insensitive */
+ down = g_ascii_strdown (str, -1);
+
+ split = g_strsplit (down, ";", 0);
+ g_free (down);
+
+ /* First field contains the transport/profile/lower_transport */
+ if (split[0] == NULL)
+ goto invalid_transport;
+
+ transp = g_strsplit (split[0], "/", 0);
+
+ if (transp[0] == NULL || transp[1] == NULL)
+ goto invalid_transport;
+
+ for (i = 0; transports[i].name; i++)
+ if (strcmp (transp[0], transports[i].name) == 0)
+ break;
+ transport->trans = transports[i].mode;
+
+ for (i = 0; profiles[i].name; i++)
+ if (strcmp (transp[1], profiles[i].name) == 0)
+ break;
+ transport->profile = profiles[i].profile;
+
+ if (transp[2] != NULL) {
+ for (i = 0; ltrans[i].name; i++)
+ if (strcmp (transp[2], ltrans[i].name) == 0)
+ break;
+ transport->lower_transport = ltrans[i].ltrans;
+ } else {
+ /* specifying the lower transport is optional */
+ if (transport->trans == GST_RTSP_TRANS_RTP &&
+ transport->profile == GST_RTSP_PROFILE_AVP)
+ transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
+ else
+ transport->lower_transport = GST_RTSP_LOWER_TRANS_UNKNOWN;
+ }
+
+ g_strfreev (transp);
+ transp = NULL;
+
+ if (transport->trans == GST_RTSP_TRANS_UNKNOWN ||
+ transport->profile == GST_RTSP_PROFILE_UNKNOWN ||
+ transport->lower_transport == GST_RTSP_LOWER_TRANS_UNKNOWN)
+ goto unsupported_transport;
+
+ i = 1;
+ while (split[i]) {
+ if (strcmp (split[i], "multicast") == 0) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_DELIVERY);
+ if (transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP)
+ goto invalid_transport;
+ transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
+ } else if (strcmp (split[i], "unicast") == 0) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_DELIVERY);
+ if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)
+ transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP;
+ } else if (g_str_has_prefix (split[i], "destination=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_DESTINATION);
+ transport->destination = g_strdup (split[i] + 12);
+ } else if (g_str_has_prefix (split[i], "source=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_SOURCE);
+ transport->source = g_strdup (split[i] + 7);
+ } else if (g_str_has_prefix (split[i], "layers=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_LAYERS);
+ transport->layers = strtoul (split[i] + 7, NULL, 10);
+ } else if (g_str_has_prefix (split[i], "mode=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_MODE);
+ parse_mode (transport, split[i] + 5);
+ if (!transport->mode_play && !transport->mode_record)
+ goto invalid_transport;
+ } else if (strcmp (split[i], "append") == 0) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_APPEND);
+ transport->append = TRUE;
+ } else if (g_str_has_prefix (split[i], "interleaved=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_INTERLEAVED);
+ parse_range (split[i] + 12, &transport->interleaved);
+ if (transport->interleaved.min < 0 ||
+ transport->interleaved.min >= 256 ||
+ transport->interleaved.max >= 256)
+ goto invalid_transport;
+ } else if (g_str_has_prefix (split[i], "ttl=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_TTL);
+ transport->ttl = strtoul (split[i] + 4, NULL, 10);
+ if (transport->ttl >= 256)
+ goto invalid_transport;
+ } else if (g_str_has_prefix (split[i], "port=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_PORT);
+ parse_range (split[i] + 5, &transport->port);
+ if (transport->port.min < 0 ||
+ transport->port.min >= 65536 || transport->port.max >= 65536)
+ goto invalid_transport;
+ } else if (g_str_has_prefix (split[i], "client_port=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_CLIENT_PORT);
+ parse_range (split[i] + 12, &transport->client_port);
+ if (transport->client_port.min < 0 ||
+ transport->client_port.min >= 65536 ||
+ transport->client_port.max >= 65536)
+ goto invalid_transport;
+ } else if (g_str_has_prefix (split[i], "server_port=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_SERVER_PORT);
+ parse_range (split[i] + 12, &transport->server_port);
+ if (transport->server_port.min < 0 ||
+ transport->server_port.min >= 65536 ||
+ transport->server_port.max >= 65536)
+ goto invalid_transport;
+ } else if (g_str_has_prefix (split[i], "ssrc=")) {
+ RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_SSRC);
+ transport->ssrc = strtoul (split[i] + 5, NULL, 16);
+ } else {
+ /* unknown field... */
+ g_warning ("unknown transport field \"%s\"", split[i]);
+ }
+ i++;
+ }
+ g_strfreev (split);
+
+ return GST_RTSP_OK;
+
+unsupported_transport:
+ {
+ g_strfreev (split);
+ return GST_RTSP_ERROR;
+ }
+invalid_transport:
+ {
+ g_strfreev (transp);
+ g_strfreev (split);
+ return GST_RTSP_EINVAL;
+ }
+}
+
+gchar *
+gst_rtsp_transport_as_text (GstRTSPTransport * transport)
+{
+ GPtrArray *strs;
+ gchar *res;
+ const gchar *tmp;
+
+ g_return_val_if_fail (transport != NULL, NULL);
+
+ strs = g_ptr_array_new ();
+
+ /* add the transport specifier */
+ if ((tmp = rtsp_transport_mode_as_text (transport)) == NULL)
+ goto invalid_transport;
+ g_ptr_array_add (strs, g_ascii_strup (tmp, -1));
+
+ g_ptr_array_add (strs, g_strdup ("/"));
+
+ if ((tmp = rtsp_transport_profile_as_text (transport)) == NULL)
+ goto invalid_transport;
+ g_ptr_array_add (strs, g_ascii_strup (tmp, -1));
+
+ if (transport->trans != GST_RTSP_TRANS_RTP ||
+ transport->profile != GST_RTSP_PROFILE_AVP ||
+ transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
+ g_ptr_array_add (strs, g_strdup ("/"));
+
+ if ((tmp = rtsp_transport_ltrans_as_text (transport)) == NULL)
+ goto invalid_transport;
+ g_ptr_array_add (strs, g_ascii_strup (tmp, -1));
+ }
+
+ /*
+ * the order of the following parameters is the same as the one specified in
+ * RFC 2326 to please some weird RTSP clients that require it
+ */
+
+ /* add the unicast/multicast parameter */
+ if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)
+ g_ptr_array_add (strs, g_strdup (";multicast"));
+ else
+ g_ptr_array_add (strs, g_strdup (";unicast"));
+
+ /* add the destination parameter */
+ if (transport->destination != NULL) {
+ g_ptr_array_add (strs, g_strdup (";destination="));
+ g_ptr_array_add (strs, g_strdup (transport->destination));
+ }
+
+ /* add the source parameter */
+ if (transport->source != NULL) {
+ g_ptr_array_add (strs, g_strdup (";source="));
+ g_ptr_array_add (strs, g_strdup (transport->source));
+ }
+
+ /* add the interleaved parameter */
+ if (transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP &&
+ transport->interleaved.min >= 0) {
+ if (transport->interleaved.min < 256 && transport->interleaved.max < 256) {
+ g_ptr_array_add (strs, g_strdup (";interleaved="));
+ g_ptr_array_add (strs, range_as_text (&transport->interleaved));
+ } else
+ goto invalid_transport;
+ }
+
+ /* add the append parameter */
+ if (transport->mode_record && transport->append)
+ g_ptr_array_add (strs, g_strdup (";append"));
+
+ /* add the ttl parameter */
+ if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST &&
+ transport->ttl != 0) {
+ if (transport->ttl < 256) {
+ g_ptr_array_add (strs, g_strdup (";ttl="));
+ g_ptr_array_add (strs, g_strdup_printf ("%u", transport->ttl));
+ } else
+ goto invalid_transport;
+ }
+
+ /* add the layers parameter */
+ if (transport->layers != 0) {
+ g_ptr_array_add (strs, g_strdup (";layers="));
+ g_ptr_array_add (strs, g_strdup_printf ("%u", transport->layers));
+ }
+
+ /* add the port parameter */
+ if (transport->trans == GST_RTSP_TRANS_RTP && transport->port.min >= 0) {
+ if (transport->port.min < 65536 && transport->port.max < 65536) {
+ g_ptr_array_add (strs, g_strdup (";port="));
+ g_ptr_array_add (strs, range_as_text (&transport->port));
+ } else
+ goto invalid_transport;
+ }
+
+ /* add the client_port parameter */
+ if (transport->trans == GST_RTSP_TRANS_RTP && transport->client_port.min >= 0) {
+ if (transport->client_port.min < 65536 &&
+ transport->client_port.max < 65536) {
+ g_ptr_array_add (strs, g_strdup (";client_port="));
+ g_ptr_array_add (strs, range_as_text (&transport->client_port));
+ } else
+ goto invalid_transport;
+ }
+
+ /* add the server_port parameter */
+ if (transport->trans == GST_RTSP_TRANS_RTP && transport->server_port.min >= 0) {
+ if (transport->server_port.min < 65536 &&
+ transport->server_port.max < 65536) {
+ g_ptr_array_add (strs, g_strdup (";server_port="));
+ g_ptr_array_add (strs, range_as_text (&transport->server_port));
+ } else
+ goto invalid_transport;
+ }
+
+ /* add the ssrc parameter */
+ if (transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP_MCAST &&
+ transport->ssrc != 0) {
+ g_ptr_array_add (strs, g_strdup (";ssrc="));
+ g_ptr_array_add (strs, g_strdup_printf ("%08X", transport->ssrc));
+ }
+
+ /* add the mode parameter */
+ if (transport->mode_play && transport->mode_record)
+ g_ptr_array_add (strs, g_strdup (";mode=\"PLAY,RECORD\""));
+ else if (transport->mode_record)
+ g_ptr_array_add (strs, g_strdup (";mode=\"RECORD\""));
+ else if (transport->mode_play)
+ g_ptr_array_add (strs, g_strdup (";mode=\"PLAY\""));
+
+ /* add a terminating NULL */
+ g_ptr_array_add (strs, NULL);
+
+ res = g_strjoinv (NULL, (gchar **) strs->pdata);
+ g_strfreev ((gchar **) g_ptr_array_free (strs, FALSE));
+
+ return res;
+
+invalid_transport:
+ {
+ g_ptr_array_add (strs, NULL);
+ g_strfreev ((gchar **) g_ptr_array_free (strs, FALSE));
+ return NULL;
+ }
+}
+
+GstRTSPResult
+gst_rtsp_transport_free (GstRTSPTransport * transport)
+{
+ g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
+
+ gst_rtsp_transport_init (transport);
+ g_free (transport);
+
+ return GST_RTSP_OK;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTSP_TRANSPORT_H__
+#define __GST_RTSP_TRANSPORT_H__
+
+#include <gst/rtsp/gstrtspdefs.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstRTSPTransMode:
+ * @GST_RTSP_TRANS_UNKNOWN: invalid tansport mode
+ * @GST_RTSP_TRANS_RTP: transfer RTP data
+ * @GST_RTSP_TRANS_RDT: transfer RDT (RealMedia) data
+ *
+ * The transfer mode to use.
+ */
+typedef enum {
+ GST_RTSP_TRANS_UNKNOWN = 0,
+ GST_RTSP_TRANS_RTP = (1 << 0),
+ GST_RTSP_TRANS_RDT = (1 << 1)
+} GstRTSPTransMode;
+
+/**
+ * GstRTSPProfile:
+ * @GST_RTSP_PROFILE_UNKNOWN: invalid profile
+ * @GST_RTSP_PROFILE_AVP: the Audio/Visual profile
+ * @GST_RTSP_PROFILE_SAVP: the secure Audio/Visual profile
+ *
+ * The transfer profile to use.
+ */
+typedef enum {
+ GST_RTSP_PROFILE_UNKNOWN = 0,
+ GST_RTSP_PROFILE_AVP = (1 << 0),
+ GST_RTSP_PROFILE_SAVP = (1 << 1)
+} GstRTSPProfile;
+
+/**
+ * GstRTSPLowerTrans:
+ * @GST_RTSP_LOWER_TRANS_UNKNOWN: invalid transport flag
+ * @GST_RTSP_LOWER_TRANS_UDP: stream data over UDP
+ * @GST_RTSP_LOWER_TRANS_UDP_MCAST: stream data over UDP multicast
+ * @GST_RTSP_LOWER_TRANS_TCP: stream data over TCP
+ *
+ * The different transport methods.
+ */
+typedef enum {
+ GST_RTSP_LOWER_TRANS_UNKNOWN = 0,
+ GST_RTSP_LOWER_TRANS_UDP = (1 << 0),
+ GST_RTSP_LOWER_TRANS_UDP_MCAST = (1 << 1),
+ GST_RTSP_LOWER_TRANS_TCP = (1 << 2)
+} GstRTSPLowerTrans;
+
+/**
+ * RTSPRange:
+ * @min: minimum value of the range
+ * @max: maximum value of the range
+ *
+ * A type to specify a range.
+ */
+typedef struct
+{
+ gint min;
+ gint max;
+} GstRTSPRange;
+
+/**
+ * GstRTSPTransport:
+ *
+ * A structure holding the RTSP transport values.
+ */
+typedef struct _GstRTSPTransport {
+ /*< private >*/
+ GstRTSPTransMode trans;
+ GstRTSPProfile profile;
+ GstRTSPLowerTrans lower_transport;
+
+ gchar *destination;
+ gchar *source;
+ guint layers;
+ gboolean mode_play;
+ gboolean mode_record;
+ gboolean append;
+ GstRTSPRange interleaved;
+
+ /* multicast specific */
+ guint ttl;
+
+ /* UDP specific */
+ GstRTSPRange port;
+ GstRTSPRange client_port;
+ GstRTSPRange server_port;
+ /* RTP specific */
+ guint ssrc;
+
+} GstRTSPTransport;
+
+GstRTSPResult gst_rtsp_transport_new (GstRTSPTransport **transport);
+GstRTSPResult gst_rtsp_transport_init (GstRTSPTransport *transport);
+
+GstRTSPResult gst_rtsp_transport_parse (const gchar *str, GstRTSPTransport *transport);
+gchar* gst_rtsp_transport_as_text (GstRTSPTransport *transport);
+
+GstRTSPResult gst_rtsp_transport_get_mime (GstRTSPTransMode trans, const gchar **mime);
+GstRTSPResult gst_rtsp_transport_get_manager (GstRTSPTransMode trans, const gchar **manager, guint option);
+
+GstRTSPResult gst_rtsp_transport_free (GstRTSPTransport *transport);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_TRANSPORT_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstrtspurl.h"
+
+#define RTSP_PROTO "rtsp://"
+#define RTSP_PROTO_LEN 7
+#define RTSPU_PROTO "rtspu://"
+#define RTSPU_PROTO_LEN 8
+#define RTSPT_PROTO "rtspt://"
+#define RTSPT_PROTO_LEN 8
+
+/* format is rtsp[u]://[user:passwd@]host[:port]/abspath[?query] */
+
+GstRTSPResult
+gst_rtsp_url_parse (const gchar * urlstr, GstRTSPUrl ** url)
+{
+ GstRTSPUrl *res;
+ gchar *p, *delim, *at, *col;
+
+ g_return_val_if_fail (urlstr != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL);
+
+ res = g_new0 (GstRTSPUrl, 1);
+
+ p = (gchar *) urlstr;
+ if (g_str_has_prefix (p, RTSP_PROTO)) {
+ res->transports =
+ GST_RTSP_LOWER_TRANS_TCP | GST_RTSP_LOWER_TRANS_UDP |
+ GST_RTSP_LOWER_TRANS_UDP_MCAST;
+ p += RTSP_PROTO_LEN;
+ } else if (g_str_has_prefix (p, RTSPU_PROTO)) {
+ res->transports = GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST;
+ p += RTSPU_PROTO_LEN;
+ } else if (g_str_has_prefix (p, RTSPT_PROTO)) {
+ res->transports = GST_RTSP_LOWER_TRANS_TCP;
+ p += RTSPT_PROTO_LEN;
+ } else
+ goto invalid;
+
+ delim = strpbrk (p, "/?");
+ at = strchr (p, '@');
+
+ if (at && delim && at > delim)
+ at = NULL;
+
+ if (at) {
+ col = strchr (p, ':');
+
+ /* must have a ':' and it must be before the '@' */
+ if (col == NULL || col > at)
+ goto invalid;
+
+ res->user = g_strndup (p, col - p);
+ col++;
+ res->passwd = g_strndup (col, at - col);
+
+ /* move to host */
+ p = at + 1;
+ }
+
+ col = strchr (p, ':');
+ /* we have a ':' and a delimiter but the ':' is after the delimiter, it's
+ * not really part of the hostname */
+ if (col && delim && col >= delim)
+ col = NULL;
+
+ if (col) {
+ res->host = g_strndup (p, col - p);
+ p = col + 1;
+ res->port = strtoul (p, (char **) &p, 10);
+ if (delim)
+ p = delim;
+ } else {
+ /* no port specified, set to 0. _get_port() will return the default port. */
+ res->port = 0;
+ if (!delim) {
+ res->host = g_strdup (p);
+ p = NULL;
+ } else {
+ res->host = g_strndup (p, delim - p);
+ p = delim;
+ }
+ }
+
+ if (p && *p == '/') {
+ delim = strchr (p, '?');
+ if (!delim) {
+ res->abspath = g_strdup (p);
+ p = NULL;
+ } else {
+ res->abspath = g_strndup (p, delim - p);
+ p = delim;
+ }
+ } else {
+ res->abspath = g_strdup ("/");
+ }
+
+ if (p && *p == '?')
+ res->query = g_strdup (p + 1);
+
+ *url = res;
+
+ return GST_RTSP_OK;
+
+ /* ERRORS */
+invalid:
+ {
+ gst_rtsp_url_free (res);
+ return GST_RTSP_EINVAL;
+ }
+}
+
+void
+gst_rtsp_url_free (GstRTSPUrl * url)
+{
+ if (url == NULL)
+ return;
+
+ g_free (url->user);
+ g_free (url->passwd);
+ g_free (url->host);
+ g_free (url->abspath);
+ g_free (url->query);
+ g_free (url);
+}
+
+GstRTSPResult
+gst_rtsp_url_set_port (GstRTSPUrl * url, guint16 port)
+{
+ g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL);
+
+ url->port = port;
+
+ return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_url_get_port (GstRTSPUrl * url, guint16 * port)
+{
+ g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL);
+ g_return_val_if_fail (port != NULL, GST_RTSP_EINVAL);
+
+ /* if a port was specified, use that else use the default port. */
+ if (url->port != 0)
+ *port = url->port;
+ else
+ *port = GST_RTSP_DEFAULT_PORT;
+
+ return GST_RTSP_OK;
+}
+
+gchar *
+gst_rtsp_url_get_request_uri (GstRTSPUrl * url)
+{
+ gchar *uri;
+
+ g_return_val_if_fail (url != NULL, NULL);
+
+ if (url->port != 0) {
+ uri = g_strdup_printf ("rtsp://%s:%u%s%s%s", url->host, url->port,
+ url->abspath, url->query ? "?" : "", url->query ? url->query : "");
+ } else {
+ uri = g_strdup_printf ("rtsp://%s%s%s%s", url->host, url->abspath,
+ url->query ? "?" : "", url->query ? url->query : "");
+ }
+
+ return uri;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RTSP_URL_H__
+#define __GST_RTSP_URL_H__
+
+#include <glib.h>
+
+#include <gst/rtsp/gstrtspdefs.h>
+#include <gst/rtsp/gstrtsptransport.h>
+
+G_BEGIN_DECLS
+
+#define GST_RTSP_DEFAULT_PORT 554
+
+typedef struct _GstRTSPUrl GstRTSPUrl;
+
+struct _GstRTSPUrl {
+ GstRTSPLowerTrans transports;
+ GstRTSPFamily family;
+ gchar *user;
+ gchar *passwd;
+ gchar *host;
+ guint16 port;
+ gchar *abspath;
+ gchar *query;
+};
+
+GstRTSPResult gst_rtsp_url_parse (const gchar *urlstr, GstRTSPUrl **url);
+void gst_rtsp_url_free (GstRTSPUrl *url);
+gchar* gst_rtsp_url_get_request_uri (GstRTSPUrl *url);
+
+GstRTSPResult gst_rtsp_url_set_port (GstRTSPUrl *url, guint16 port);
+GstRTSPResult gst_rtsp_url_get_port (GstRTSPUrl *url, guint16 *port);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_URL_H__ */
--- /dev/null
+libgstsdpincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/sdp
+
+libgstsdpinclude_HEADERS = gstsdp.h \
+ gstsdpmessage.h
+
+lib_LTLIBRARIES = libgstsdp-@GST_MAJORMINOR@.la
+
+libgstsdp_@GST_MAJORMINOR@_la_SOURCES = gstsdpmessage.c
+
+libgstsdp_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstsdp_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS)
+libgstsdp_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_SDP_H__
+#define __GST_SDP_H__
+
+typedef enum {
+ GST_SDP_OK = 0,
+ GST_SDP_EINVAL = -1
+} GstSDPResult;
+
+#endif /* __GST_SDP_H__ */
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstsdpmessage.h"
+
+/* FIXME, is currently allocated on the stack */
+#define MAX_LINE_LEN 1024 * 16
+
+#define FREE_STRING(field) g_free ((field)); (field) = NULL;
+#define FREE_ARRAY(field) \
+G_STMT_START { \
+ if (field) \
+ g_array_free (field, TRUE); \
+ field = NULL; \
+} G_STMT_END
+#define REPLACE_STRING(field,val) FREE_STRING(field);field=g_strdup (val);
+
+#define INIT_ARRAY(field,type,init_func) \
+G_STMT_START { \
+ if (field) { \
+ guint i; \
+ for(i=0; i<field->len; i++) \
+ init_func (&g_array_index(field, type, i)); \
+ g_array_set_size (field,0); \
+ } \
+ else \
+ field = g_array_new (FALSE, TRUE, sizeof(type)); \
+} G_STMT_END
+
+#define DEFINE_STRING_SETTER(field) \
+GstSDPResult gst_sdp_message_set_##field (GstSDPMessage *msg, gchar *val) { \
+ g_free (msg->field); \
+ msg->field = g_strdup (val); \
+ return GST_SDP_OK; \
+}
+#define DEFINE_STRING_GETTER(field) \
+char* gst_sdp_message_get_##field (GstSDPMessage *msg) { \
+ return msg->field; \
+}
+
+#define DEFINE_ARRAY_LEN(field) \
+gint gst_sdp_message_##field##_len (GstSDPMessage *msg) { \
+ return ((msg)->field->len); \
+}
+#define DEFINE_ARRAY_GETTER(method,field,type) \
+type gst_sdp_message_get_##method (GstSDPMessage *msg, guint idx) { \
+ return g_array_index ((msg)->field, type, idx); \
+}
+#define DEFINE_ARRAY_P_GETTER(method,field,type) \
+type * gst_sdp_message_get_##method (GstSDPMessage *msg, guint idx) { \
+ return &g_array_index ((msg)->field, type, idx); \
+}
+#define DEFINE_ARRAY_ADDER(method,field,type,dup_method) \
+GstSDPResult gst_sdp_message_add_##method (GstSDPMessage *msg, type val) { \
+ type v = dup_method(val); \
+ g_array_append_val((msg)->field, v); \
+ return GST_SDP_OK; \
+}
+
+static void
+gst_sdp_origin_init (GstSDPOrigin * origin)
+{
+ FREE_STRING (origin->username);
+ FREE_STRING (origin->sess_id);
+ FREE_STRING (origin->sess_version);
+ FREE_STRING (origin->nettype);
+ FREE_STRING (origin->addrtype);
+ FREE_STRING (origin->addr);
+}
+
+static void
+gst_sdp_connection_init (GstSDPConnection * connection)
+{
+ FREE_STRING (connection->nettype);
+ FREE_STRING (connection->addrtype);
+ FREE_STRING (connection->address);
+ connection->ttl = 0;
+ connection->addr_number = 0;
+}
+
+static void
+gst_sdp_bandwidth_init (GstSDPBandwidth * bandwidth)
+{
+ FREE_STRING (bandwidth->bwtype);
+ bandwidth->bandwidth = 0;
+}
+
+static void
+gst_sdp_time_init (GstSDPTime * time)
+{
+ FREE_STRING (time->start);
+ FREE_STRING (time->stop);
+ time->n_repeat = 0;
+}
+
+static void
+gst_sdp_zone_init (GstSDPZone * zone)
+{
+ FREE_STRING (zone->time);
+ FREE_STRING (zone->typed_time);
+}
+
+static void
+gst_sdp_key_init (GstSDPKey * key)
+{
+ FREE_STRING (key->type);
+ FREE_STRING (key->data);
+}
+
+static void
+gst_sdp_attribute_init (GstSDPAttribute * attr)
+{
+ FREE_STRING (attr->key);
+ FREE_STRING (attr->value);
+}
+
+/**
+ * gst_sdp_message_new:
+ * @msg: pointer to new #GstSDPMessage
+ *
+ * Allocate a new GstSDPMessage and store the result in @msg.
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_new (GstSDPMessage ** msg)
+{
+ GstSDPMessage *newmsg;
+
+ g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+ newmsg = g_new0 (GstSDPMessage, 1);
+
+ *msg = newmsg;
+
+ return gst_sdp_message_init (newmsg);
+}
+
+/**
+ * gst_sdp_message_init:
+ * @msg: an #GstSDPMessage
+ *
+ * Initialize @msg so that its contents are as if it was freshly allocated
+ * with gst_sdp_message_new(). This function is mostly used to initialize a message
+ * allocated on the stack. gst_sdp_message_uninit() undoes this operation.
+ *
+ * When this function is invoked on newly allocated data (with malloc or on the
+ * stack), its contents should be set to 0 before calling this function.
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_init (GstSDPMessage * msg)
+{
+ g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+ FREE_STRING (msg->version);
+ gst_sdp_origin_init (&msg->origin);
+ FREE_STRING (msg->session_name);
+ FREE_STRING (msg->information);
+ FREE_STRING (msg->uri);
+ INIT_ARRAY (msg->emails, gchar *, g_free);
+ INIT_ARRAY (msg->phones, gchar *, g_free);
+ gst_sdp_connection_init (&msg->connection);
+ INIT_ARRAY (msg->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_init);
+ INIT_ARRAY (msg->times, GstSDPTime, gst_sdp_time_init);
+ INIT_ARRAY (msg->zones, GstSDPZone, gst_sdp_zone_init);
+ gst_sdp_key_init (&msg->key);
+ INIT_ARRAY (msg->attributes, GstSDPAttribute, gst_sdp_attribute_init);
+ INIT_ARRAY (msg->medias, GstSDPMedia, gst_sdp_media_uninit);
+
+ return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_message_uninit:
+ * @msg: an #GstSDPMessage
+ *
+ * Free all resources allocated in @msg. @msg should not be used anymore after
+ * this function. This function should be used when @msg was allocated on the
+ * stack and initialized with gst_sdp_message_init().
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_uninit (GstSDPMessage * msg)
+{
+ g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+ gst_sdp_message_init (msg);
+
+ FREE_ARRAY (msg->emails);
+ FREE_ARRAY (msg->phones);
+ FREE_ARRAY (msg->bandwidths);
+ FREE_ARRAY (msg->times);
+ FREE_ARRAY (msg->zones);
+ FREE_ARRAY (msg->attributes);
+ FREE_ARRAY (msg->medias);
+
+ return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_message_free:
+ * @msg: an #GstSDPMessage
+ *
+ * Free all resources allocated by @msg. @msg should not be used anymore after
+ * this function. This function should be used when @msg was dynamically
+ * allocated with gst_sdp_message_new().
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_free (GstSDPMessage * msg)
+{
+ g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+ gst_sdp_message_uninit (msg);
+ g_free (msg);
+
+ return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_media_new:
+ * @media: pointer to new #GstSDPMedia
+ *
+ * Allocate a new GstSDPMedia and store the result in @media.
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_media_new (GstSDPMedia ** media)
+{
+ GstSDPMedia *newmedia;
+
+ g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
+
+ newmedia = g_new0 (GstSDPMedia, 1);
+
+ *media = newmedia;
+
+ return gst_sdp_media_init (newmedia);
+}
+
+/**
+ * gst_sdp_media_init:
+ * @media: a #GstSDPMedia
+ *
+ * Initialize @media so that its contents are as if it was freshly allocated
+ * with gst_sdp_media_new(). This function is mostly used to initialize a media
+ * allocated on the stack. gst_sdp_media_uninit() undoes this operation.
+ *
+ * When this function is invoked on newly allocated data (with malloc or on the
+ * stack), its contents should be set to 0 before calling this function.
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_media_init (GstSDPMedia * media)
+{
+ g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
+
+ FREE_STRING (media->media);
+ media->port = 0;
+ media->num_ports = 0;
+ FREE_STRING (media->proto);
+ INIT_ARRAY (media->fmts, gchar *, g_free);
+ FREE_STRING (media->information);
+ INIT_ARRAY (media->connections, GstSDPConnection, gst_sdp_connection_init);
+ INIT_ARRAY (media->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_init);
+ gst_sdp_key_init (&media->key);
+ INIT_ARRAY (media->attributes, GstSDPAttribute, gst_sdp_attribute_init);
+
+ return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_media_uninit:
+ * @media: an #GstSDPMedia
+ *
+ * Free all resources allocated in @media. @media should not be used anymore after
+ * this function. This function should be used when @media was allocated on the
+ * stack and initialized with gst_sdp_media_init().
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_media_uninit (GstSDPMedia * media)
+{
+ g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
+
+ gst_sdp_media_init (media);
+ FREE_ARRAY (media->fmts);
+ FREE_ARRAY (media->connections);
+ FREE_ARRAY (media->bandwidths);
+ FREE_ARRAY (media->attributes);
+
+ return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_media_free:
+ * @media: an #GstSDPMedia
+ *
+ * Free all resources allocated by @media. @media should not be used anymore after
+ * this function. This function should be used when @media was dynamically
+ * allocated with gst_sdp_media_new().
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_media_free (GstSDPMedia * media)
+{
+ g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
+
+ gst_sdp_media_uninit (media);
+ g_free (media);
+
+ return GST_SDP_OK;
+}
+
+DEFINE_STRING_SETTER (version);
+DEFINE_STRING_GETTER (version);
+
+GstSDPResult
+gst_sdp_message_set_origin (GstSDPMessage * msg, gchar * username,
+ gchar * sess_id, gchar * sess_version, gchar * nettype, gchar * addrtype,
+ gchar * addr)
+{
+ REPLACE_STRING (msg->origin.username, username);
+ REPLACE_STRING (msg->origin.sess_id, sess_id);
+ REPLACE_STRING (msg->origin.sess_version, sess_version);
+ REPLACE_STRING (msg->origin.nettype, nettype);
+ REPLACE_STRING (msg->origin.addrtype, addrtype);
+ REPLACE_STRING (msg->origin.addr, addr);
+ return GST_SDP_OK;
+}
+
+GstSDPOrigin *
+gst_sdp_message_get_origin (GstSDPMessage * msg)
+{
+ return &msg->origin;
+}
+
+DEFINE_STRING_SETTER (session_name);
+DEFINE_STRING_GETTER (session_name);
+DEFINE_STRING_SETTER (information);
+DEFINE_STRING_GETTER (information);
+DEFINE_STRING_SETTER (uri);
+DEFINE_STRING_GETTER (uri);
+
+DEFINE_ARRAY_LEN (emails);
+DEFINE_ARRAY_GETTER (email, emails, gchar *);
+DEFINE_ARRAY_ADDER (email, emails, gchar *, g_strdup);
+
+DEFINE_ARRAY_LEN (phones);
+DEFINE_ARRAY_GETTER (phone, phones, gchar *);
+DEFINE_ARRAY_ADDER (phone, phones, gchar *, g_strdup);
+
+GstSDPResult
+gst_sdp_message_set_connection (GstSDPMessage * msg, gchar * nettype,
+ gchar * addrtype, gchar * address, gint ttl, gint addr_number)
+{
+ REPLACE_STRING (msg->connection.nettype, nettype);
+ REPLACE_STRING (msg->connection.addrtype, addrtype);
+ REPLACE_STRING (msg->connection.address, address);
+ msg->connection.ttl = ttl;
+ msg->connection.addr_number = addr_number;
+ return GST_SDP_OK;
+}
+
+GstSDPConnection *
+gst_sdp_message_get_connection (GstSDPMessage * msg)
+{
+ return &msg->connection;
+}
+
+DEFINE_ARRAY_LEN (bandwidths);
+DEFINE_ARRAY_P_GETTER (bandwidth, bandwidths, GstSDPBandwidth);
+
+GstSDPResult
+gst_sdp_message_add_bandwidth (GstSDPMessage * msg, gchar * bwtype,
+ gint bandwidth)
+{
+ GstSDPBandwidth bw;
+
+ bw.bwtype = g_strdup (bwtype);
+ bw.bandwidth = bandwidth;
+
+ g_array_append_val (msg->bandwidths, bw);
+
+ return GST_SDP_OK;
+}
+
+DEFINE_ARRAY_LEN (times);
+DEFINE_ARRAY_P_GETTER (time, times, GstSDPTime);
+
+GstSDPResult
+gst_sdp_message_add_time (GstSDPMessage * msg, gchar * time)
+{
+ return GST_SDP_OK;
+}
+
+DEFINE_ARRAY_LEN (zones);
+DEFINE_ARRAY_P_GETTER (zone, zones, GstSDPZone);
+GstSDPResult
+gst_sdp_message_add_zone (GstSDPMessage * msg, gchar * time, gchar * typed_time)
+{
+ GstSDPZone zone;
+
+ zone.time = g_strdup (time);
+ zone.typed_time = g_strdup (typed_time);
+
+ g_array_append_val (msg->zones, zone);
+
+ return GST_SDP_OK;
+}
+
+GstSDPResult
+gst_sdp_message_set_key (GstSDPMessage * msg, gchar * type, gchar * data)
+{
+ REPLACE_STRING (msg->key.type, type);
+ REPLACE_STRING (msg->key.data, data);
+ return GST_SDP_OK;
+}
+
+GstSDPKey *
+gst_sdp_message_get_key (GstSDPMessage * msg)
+{
+ return &msg->key;
+}
+
+
+DEFINE_ARRAY_LEN (attributes);
+DEFINE_ARRAY_P_GETTER (attribute, attributes, GstSDPAttribute);
+gchar *
+gst_sdp_message_get_attribute_val_n (GstSDPMessage * msg, gchar * key,
+ guint nth)
+{
+ guint i;
+
+ for (i = 0; i < msg->attributes->len; i++) {
+ GstSDPAttribute *attr;
+
+ attr = &g_array_index (msg->attributes, GstSDPAttribute, i);
+ if (!strcmp (attr->key, key)) {
+ if (nth == 0)
+ return attr->value;
+ else
+ nth--;
+ }
+ }
+ return NULL;
+}
+
+gchar *
+gst_sdp_message_get_attribute_val (GstSDPMessage * msg, gchar * key)
+{
+ return gst_sdp_message_get_attribute_val_n (msg, key, 0);
+}
+
+GstSDPResult
+gst_sdp_message_add_attribute (GstSDPMessage * msg, gchar * key, gchar * value)
+{
+ GstSDPAttribute attr;
+
+ attr.key = g_strdup (key);
+ attr.value = g_strdup (value);
+
+ g_array_append_val (msg->attributes, attr);
+
+ return GST_SDP_OK;
+}
+
+DEFINE_ARRAY_LEN (medias);
+DEFINE_ARRAY_P_GETTER (media, medias, GstSDPMedia);
+
+/**
+ * gst_sdp_message_add_media:
+ * @msg: an #GstSDPMessage
+ * @media: an #GstSDPMedia to add
+ *
+ * Adds @media to the array of medias in @msg. This function takes ownership of
+ * the contents of @media so that @media will have to be reinitialized with
+ * gst_media_init() before it can be used again.
+ *
+ * Returns: an #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_add_media (GstSDPMessage * msg, GstSDPMedia * media)
+{
+ gint len;
+ GstSDPMedia *nmedia;
+
+ len = msg->medias->len;
+ g_array_set_size (msg->medias, len + 1);
+ nmedia = &g_array_index (msg->medias, GstSDPMedia, len);
+
+ memcpy (nmedia, media, sizeof (GstSDPMedia));
+ memset (media, 0, sizeof (GstSDPMedia));
+
+ return GST_SDP_OK;
+}
+
+/* media access */
+
+GstSDPResult
+gst_sdp_media_add_attribute (GstSDPMedia * media, gchar * key, gchar * value)
+{
+ GstSDPAttribute attr;
+
+ attr.key = g_strdup (key);
+ attr.value = g_strdup (value);
+
+ g_array_append_val (media->attributes, attr);
+
+ return GST_SDP_OK;
+}
+
+GstSDPResult
+gst_sdp_media_add_bandwidth (GstSDPMedia * media, gchar * bwtype,
+ gint bandwidth)
+{
+ GstSDPBandwidth bw;
+
+ bw.bwtype = g_strdup (bwtype);
+ bw.bandwidth = bandwidth;
+
+ g_array_append_val (media->bandwidths, bw);
+
+ return GST_SDP_OK;
+}
+
+GstSDPResult
+gst_sdp_media_add_format (GstSDPMedia * media, gchar * format)
+{
+ gchar *fmt;
+
+ fmt = g_strdup (format);
+
+ g_array_append_val (media->fmts, fmt);
+
+ return GST_SDP_OK;
+}
+
+GstSDPAttribute *
+gst_sdp_media_get_attribute (GstSDPMedia * media, guint idx)
+{
+ return &g_array_index (media->attributes, GstSDPAttribute, idx);
+}
+
+gchar *
+gst_sdp_media_get_attribute_val_n (GstSDPMedia * media, gchar * key, guint nth)
+{
+ guint i;
+
+ for (i = 0; i < media->attributes->len; i++) {
+ GstSDPAttribute *attr;
+
+ attr = &g_array_index (media->attributes, GstSDPAttribute, i);
+ if (!strcmp (attr->key, key)) {
+ if (nth == 0)
+ return attr->value;
+ else
+ nth--;
+ }
+ }
+ return NULL;
+}
+
+gchar *
+gst_sdp_media_get_attribute_val (GstSDPMedia * media, gchar * key)
+{
+ return gst_sdp_media_get_attribute_val_n (media, key, 0);
+}
+
+gchar *
+gst_sdp_media_get_format (GstSDPMedia * media, guint idx)
+{
+ if (idx >= media->fmts->len)
+ return NULL;
+ return g_array_index (media->fmts, gchar *, idx);
+}
+
+static void
+read_string (gchar * dest, guint size, gchar ** src)
+{
+ guint idx;
+
+ idx = 0;
+ /* skip spaces */
+ while (g_ascii_isspace (**src))
+ (*src)++;
+
+ while (!g_ascii_isspace (**src) && **src != '\0') {
+ if (idx < size - 1)
+ dest[idx++] = **src;
+ (*src)++;
+ }
+ if (size > 0)
+ dest[idx] = '\0';
+}
+
+static void
+read_string_del (gchar * dest, guint size, gchar del, gchar ** src)
+{
+ guint idx;
+
+ idx = 0;
+ /* skip spaces */
+ while (g_ascii_isspace (**src))
+ (*src)++;
+
+ while (**src != del && **src != '\0') {
+ if (idx < size - 1)
+ dest[idx++] = **src;
+ (*src)++;
+ }
+ if (size > 0)
+ dest[idx] = '\0';
+}
+
+enum
+{
+ SDP_SESSION,
+ SDP_MEDIA,
+};
+
+typedef struct
+{
+ gint state;
+ GstSDPMessage *msg;
+ GstSDPMedia *media;
+} SDPContext;
+
+static gboolean
+gst_sdp_parse_line (SDPContext * c, gchar type, gchar * buffer)
+{
+ gchar str[8192];
+ gchar *p = buffer;
+
+#define READ_STRING(field) read_string (str, sizeof(str), &p);REPLACE_STRING (field, str);
+#define READ_INT(field) read_string (str, sizeof(str), &p);field = atoi(str);
+
+ switch (type) {
+ case 'v':
+ if (buffer[0] != '0')
+ g_warning ("wrong SDP version");
+ gst_sdp_message_set_version (c->msg, buffer);
+ break;
+ case 'o':
+ READ_STRING (c->msg->origin.username);
+ READ_STRING (c->msg->origin.sess_id);
+ READ_STRING (c->msg->origin.sess_version);
+ READ_STRING (c->msg->origin.nettype);
+ READ_STRING (c->msg->origin.addrtype);
+ READ_STRING (c->msg->origin.addr);
+ break;
+ case 's':
+ REPLACE_STRING (c->msg->session_name, buffer);
+ break;
+ case 'i':
+ if (c->state == SDP_SESSION) {
+ REPLACE_STRING (c->msg->information, buffer);
+ } else {
+ REPLACE_STRING (c->media->information, buffer);
+ }
+ break;
+ case 'u':
+ REPLACE_STRING (c->msg->uri, buffer);
+ break;
+ case 'e':
+ gst_sdp_message_add_email (c->msg, buffer);
+ break;
+ case 'p':
+ gst_sdp_message_add_phone (c->msg, buffer);
+ break;
+ case 'c':
+ READ_STRING (c->msg->connection.nettype);
+ READ_STRING (c->msg->connection.addrtype);
+ READ_STRING (c->msg->connection.address);
+ READ_INT (c->msg->connection.ttl);
+ READ_INT (c->msg->connection.addr_number);
+ break;
+ case 'b':
+ {
+ gchar str2[MAX_LINE_LEN];
+
+ read_string_del (str, sizeof (str), ':', &p);
+ read_string (str2, sizeof (str2), &p);
+ if (c->state == SDP_SESSION)
+ gst_sdp_message_add_bandwidth (c->msg, str, atoi (str2));
+ else
+ gst_sdp_media_add_bandwidth (c->media, str, atoi (str2));
+ break;
+ }
+ case 't':
+ break;
+ case 'k':
+
+ break;
+ case 'a':
+ read_string_del (str, sizeof (str), ':', &p);
+ if (*p != '\0')
+ p++;
+ if (c->state == SDP_SESSION)
+ gst_sdp_message_add_attribute (c->msg, str, p);
+ else
+ gst_sdp_media_add_attribute (c->media, str, p);
+ break;
+ case 'm':
+ {
+ gchar *slash;
+ GstSDPMedia nmedia;
+
+ c->state = SDP_MEDIA;
+ memset (&nmedia, 0, sizeof (nmedia));
+ gst_sdp_media_init (&nmedia);
+
+ READ_STRING (nmedia.media);
+ read_string (str, sizeof (str), &p);
+ slash = g_strrstr (str, "/");
+ if (slash) {
+ *slash = '\0';
+ nmedia.port = atoi (str);
+ nmedia.num_ports = atoi (slash + 1);
+ } else {
+ nmedia.port = atoi (str);
+ nmedia.num_ports = -1;
+ }
+ READ_STRING (nmedia.proto);
+ do {
+ read_string (str, sizeof (str), &p);
+ gst_sdp_media_add_format (&nmedia, str);
+ } while (*p != '\0');
+
+ gst_sdp_message_add_media (c->msg, &nmedia);
+ c->media =
+ &g_array_index (c->msg->medias, GstSDPMedia, c->msg->medias->len - 1);
+ break;
+ }
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+GstSDPResult
+gst_sdp_message_parse_buffer (guint8 * data, guint size, GstSDPMessage * msg)
+{
+ gchar *p;
+ SDPContext c;
+ gchar type;
+ gchar buffer[MAX_LINE_LEN];
+ guint idx = 0;
+
+ g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+ g_return_val_if_fail (data != NULL, GST_SDP_EINVAL);
+ g_return_val_if_fail (size != 0, GST_SDP_EINVAL);
+
+ c.state = SDP_SESSION;
+ c.msg = msg;
+ c.media = NULL;
+
+ p = (gchar *) data;
+ while (TRUE) {
+ while (g_ascii_isspace (*p))
+ p++;
+
+ type = *p++;
+ if (type == '\0')
+ break;
+
+ if (*p != '=')
+ goto line_done;
+ p++;
+
+ idx = 0;
+ while (*p != '\n' && *p != '\r' && *p != '\0') {
+ if (idx < sizeof (buffer) - 1)
+ buffer[idx++] = *p;
+ p++;
+ }
+ buffer[idx] = '\0';
+ gst_sdp_parse_line (&c, type, buffer);
+
+ line_done:
+ while (*p != '\n' && *p != '\0')
+ p++;
+ if (*p == '\n')
+ p++;
+ }
+
+ return GST_SDP_OK;
+}
+
+static void
+print_media (GstSDPMedia * media)
+{
+ g_print (" media: '%s'\n", media->media);
+ g_print (" port: '%d'\n", media->port);
+ g_print (" num_ports: '%d'\n", media->num_ports);
+ g_print (" proto: '%s'\n", media->proto);
+ if (media->fmts->len > 0) {
+ guint i;
+
+ g_print (" formats:\n");
+ for (i = 0; i < media->fmts->len; i++) {
+ g_print (" format '%s'\n", g_array_index (media->fmts, gchar *, i));
+ }
+ }
+ g_print (" information: '%s'\n", media->information);
+ g_print (" key:\n");
+ g_print (" type: '%s'\n", media->key.type);
+ g_print (" data: '%s'\n", media->key.data);
+ if (media->attributes->len > 0) {
+ guint i;
+
+ g_print (" attributes:\n");
+ for (i = 0; i < media->attributes->len; i++) {
+ GstSDPAttribute *attr =
+ &g_array_index (media->attributes, GstSDPAttribute, i);
+
+ g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
+ }
+ }
+}
+
+GstSDPResult
+gst_sdp_message_dump (GstSDPMessage * msg)
+{
+ g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+ g_print ("sdp packet %p:\n", msg);
+ g_print (" version: '%s'\n", msg->version);
+ g_print (" origin:\n");
+ g_print (" username: '%s'\n", msg->origin.username);
+ g_print (" sess_id: '%s'\n", msg->origin.sess_id);
+ g_print (" sess_version: '%s'\n", msg->origin.sess_version);
+ g_print (" nettype: '%s'\n", msg->origin.nettype);
+ g_print (" addrtype: '%s'\n", msg->origin.addrtype);
+ g_print (" addr: '%s'\n", msg->origin.addr);
+ g_print (" session_name: '%s'\n", msg->session_name);
+ g_print (" information: '%s'\n", msg->information);
+ g_print (" uri: '%s'\n", msg->uri);
+
+ if (msg->emails->len > 0) {
+ guint i;
+
+ g_print (" emails:\n");
+ for (i = 0; i < msg->emails->len; i++) {
+ g_print (" email '%s'\n", g_array_index (msg->emails, gchar *, i));
+ }
+ }
+ if (msg->phones->len > 0) {
+ guint i;
+
+ g_print (" phones:\n");
+ for (i = 0; i < msg->phones->len; i++) {
+ g_print (" phone '%s'\n", g_array_index (msg->phones, gchar *, i));
+ }
+ }
+ g_print (" connection:\n");
+ g_print (" nettype: '%s'\n", msg->connection.nettype);
+ g_print (" addrtype: '%s'\n", msg->connection.addrtype);
+ g_print (" address: '%s'\n", msg->connection.address);
+ g_print (" ttl: '%d'\n", msg->connection.ttl);
+ g_print (" addr_number: '%d'\n", msg->connection.addr_number);
+ g_print (" key:\n");
+ g_print (" type: '%s'\n", msg->key.type);
+ g_print (" data: '%s'\n", msg->key.data);
+ if (msg->attributes->len > 0) {
+ guint i;
+
+ g_print (" attributes:\n");
+ for (i = 0; i < msg->attributes->len; i++) {
+ GstSDPAttribute *attr =
+ &g_array_index (msg->attributes, GstSDPAttribute, i);
+
+ g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
+ }
+ }
+ if (msg->medias->len > 0) {
+ guint i;
+
+ g_print (" medias:\n");
+ for (i = 0; i < msg->medias->len; i++) {
+ g_print (" media %d:\n", i);
+ print_media (&g_array_index (msg->medias, GstSDPMedia, i));
+ }
+ }
+ return GST_SDP_OK;
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_SDP_MESSAGE_H__
+#define __GST_SDP_MESSAGE_H__
+
+#include <glib.h>
+
+#include <gst/sdp/gstsdp.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+ gchar *username;
+ gchar *sess_id;
+ gchar *sess_version;
+ gchar *nettype;
+ gchar *addrtype;
+ gchar *addr;
+} GstSDPOrigin;
+
+typedef struct {
+ gchar *nettype;
+ gchar *addrtype;
+ gchar *address;
+ gint ttl;
+ gint addr_number;
+} GstSDPConnection;
+
+#define GST_SDP_BWTYPE_CT "CT" /* conference total */
+#define GST_SDP_BWTYPE_AS "AS" /* application specific */
+#define GST_SDP_BWTYPE_EXT_PREFIX "X-" /* extension prefix */
+
+typedef struct {
+ gchar *bwtype;
+ gint bandwidth;
+} GstSDPBandwidth;
+
+typedef struct {
+ gchar *start;
+ gchar *stop;
+ gint n_repeat;
+ gchar **repeat;
+} GstSDPTime;
+
+typedef struct {
+ gchar *time;
+ gchar *typed_time;
+} GstSDPZone;
+
+typedef struct {
+ gchar *type;
+ gchar *data;
+} GstSDPKey;
+
+typedef struct {
+ gchar *key;
+ gchar *value;
+} GstSDPAttribute;
+
+typedef struct {
+ gchar *media;
+ gint port;
+ gint num_ports;
+ gchar *proto;
+ GArray *fmts;
+ gchar *information;
+ GArray *connections;
+ GArray *bandwidths;
+ GstSDPKey key;
+ GArray *attributes;
+} GstSDPMedia;
+
+typedef struct {
+ gchar *version;
+ GstSDPOrigin origin;
+ gchar *session_name;
+ gchar *information;
+ gchar *uri;
+ GArray *emails;
+ GArray *phones;
+ GstSDPConnection connection;
+ GArray *bandwidths;
+ GArray *times;
+ GArray *zones;
+ GstSDPKey key;
+ GArray *attributes;
+ GArray *medias;
+} GstSDPMessage;
+
+/* Session descriptions */
+GstSDPResult gst_sdp_message_new (GstSDPMessage **msg);
+GstSDPResult gst_sdp_message_init (GstSDPMessage *msg);
+GstSDPResult gst_sdp_message_uninit (GstSDPMessage *msg);
+GstSDPResult gst_sdp_message_free (GstSDPMessage *msg);
+
+GstSDPResult gst_sdp_message_parse_buffer (guint8 *data, guint size, GstSDPMessage *msg);
+
+GstSDPResult gst_sdp_message_set_version (GstSDPMessage *msg, gchar *version);
+gchar* gst_sdp_message_get_version (GstSDPMessage *msg);
+GstSDPResult gst_sdp_message_set_origin (GstSDPMessage *msg, gchar *username, gchar *sess_id,
+ gchar *sess_version, gchar *nettype,
+ gchar *addrtype, gchar *addr);
+GstSDPOrigin* gst_sdp_message_get_origin (GstSDPMessage *msg);
+GstSDPResult gst_sdp_message_set_session_name (GstSDPMessage *msg, gchar *session_name);
+gchar* gst_sdp_message_get_session_name (GstSDPMessage *msg);
+GstSDPResult gst_sdp_message_set_information (GstSDPMessage *msg, gchar *information);
+gchar* gst_sdp_message_get_information (GstSDPMessage *msg);
+GstSDPResult gst_sdp_message_set_uri (GstSDPMessage *msg, gchar *uri);
+gchar* gst_sdp_message_get_uri (GstSDPMessage *msg);
+gint gst_sdp_message_emails_len (GstSDPMessage *msg);
+gchar* gst_sdp_message_get_email (GstSDPMessage *msg, guint idx);
+GstSDPResult gst_sdp_message_add_email (GstSDPMessage *msg, gchar *email);
+gint gst_sdp_message_phones_len (GstSDPMessage *msg);
+gchar* gst_sdp_message_get_phone (GstSDPMessage *msg, guint idx);
+GstSDPResult gst_sdp_message_add_phone (GstSDPMessage *msg, gchar *phone);
+GstSDPResult gst_sdp_message_set_connection (GstSDPMessage *msg, gchar *nettype, gchar *addrtype,
+ gchar *address, gint ttl, gint addr_number);
+GstSDPConnection* gst_sdp_message_get_connection (GstSDPMessage *msg);
+gint gst_sdp_message_bandwidths_len (GstSDPMessage *msg);
+GstSDPBandwidth* gst_sdp_message_get_bandwidth (GstSDPMessage *msg, guint idx);
+GstSDPResult gst_sdp_message_add_bandwidth (GstSDPMessage *msg, gchar *bwtype, gint bandwidth);
+gint gst_sdp_message_times_len (GstSDPMessage *msg);
+GstSDPTime* gst_sdp_message_get_time (GstSDPMessage *msg, guint idx);
+GstSDPResult gst_sdp_message_add_time (GstSDPMessage *msg, gchar *time);
+gint gst_sdp_message_zones_len (GstSDPMessage *msg);
+GstSDPZone* gst_sdp_message_get_zone (GstSDPMessage *msg, guint idx);
+GstSDPResult gst_sdp_message_add_zone (GstSDPMessage *msg, gchar *time, gchar *typed_time);
+GstSDPResult gst_sdp_message_set_key (GstSDPMessage *msg, gchar *type, gchar *data);
+GstSDPKey* gst_sdp_message_get_key (GstSDPMessage *msg);
+gint gst_sdp_message_attributes_len (GstSDPMessage *msg);
+GstSDPAttribute* gst_sdp_message_get_attribute (GstSDPMessage *msg, guint idx);
+gchar* gst_sdp_message_get_attribute_val (GstSDPMessage *msg, gchar *key);
+gchar* gst_sdp_message_get_attribute_val_n (GstSDPMessage *msg, gchar *key, guint nth);
+GstSDPResult gst_sdp_message_add_attribute (GstSDPMessage *msg, gchar *key, gchar *value);
+gint gst_sdp_message_medias_len (GstSDPMessage *msg);
+GstSDPMedia* gst_sdp_message_get_media (GstSDPMessage *msg, guint idx);
+GstSDPResult gst_sdp_message_add_media (GstSDPMessage *msg, GstSDPMedia *media);
+
+
+GstSDPResult gst_sdp_message_dump (GstSDPMessage *msg);
+
+/* Media descriptions */
+GstSDPResult gst_sdp_media_new (GstSDPMedia **media);
+GstSDPResult gst_sdp_media_init (GstSDPMedia *media);
+GstSDPResult gst_sdp_media_uninit (GstSDPMedia *media);
+GstSDPResult gst_sdp_media_free (GstSDPMedia *media);
+
+GstSDPResult gst_sdp_media_add_bandwidth (GstSDPMedia * media, gchar * bwtype, gint bandwidth);
+
+GstSDPResult gst_sdp_media_add_attribute (GstSDPMedia *media, gchar * key, gchar * value);
+GstSDPAttribute * gst_sdp_media_get_attribute (GstSDPMedia *media, guint idx);
+gchar* gst_sdp_media_get_attribute_val (GstSDPMedia *media, gchar *key);
+gchar* gst_sdp_media_get_attribute_val_n (GstSDPMedia *media, gchar *key, guint nth);
+
+GstSDPResult gst_sdp_media_add_format (GstSDPMedia * media, gchar * format);
+gchar* gst_sdp_media_get_format (GstSDPMedia *media, guint idx);
+
+G_END_DECLS
+
+#endif /* __GST_SDP_MESSAGE_H__ */
Version: @VERSION@
Requires: gstreamer-@GST_MAJORMINOR@
-Libs: -L${libdir}/audio -L${libdir}/cdda -L${libdir}/floatcast -L${libdir}/interfaces -L${libdir}/netbuffer -L${libdir}/riff -L${libdir}/rtp -L${libdir}/tag -L${libdir}/pbutils -L${libdir}/video
+Libs: -L${libdir}/audio -L${libdir}/cdda -L${libdir}/floatcast -L${libdir}/interfaces -L${libdir}/netbuffer -L${libdir}/riff -L${libdir}/rtp -L${libdir}/rtsp -L${libdir}/sdp -L${libdir}/tag -L${libdir}/pbutils -L${libdir}/video
Cflags: -I${includedir}
libraries=audio cdda floatcast interfaces netbuffer riff tag pbutils video