RTSP: add support for Quicktime tunneled RTSP

Add support for tunneling RTSP over HTTP.
Fix documentation some more.
See also #573173.

API: RTSP:gst_rtsp_connection_is_tunneled()
API: RTSP:gst_rtsp_connection_set_tunneled()
This commit is contained in:
Wim Taymans 2009-03-02 16:03:49 +01:00
parent 40db590e71
commit fbc4f2d4fe
4 changed files with 486 additions and 138 deletions

View File

@ -1210,14 +1210,30 @@ gst_rtsp_connection_accept
gst_rtsp_connection_connect gst_rtsp_connection_connect
gst_rtsp_connection_close gst_rtsp_connection_close
gst_rtsp_connection_free gst_rtsp_connection_free
gst_rtsp_connection_read gst_rtsp_connection_read
gst_rtsp_connection_write gst_rtsp_connection_write
gst_rtsp_connection_poll
gst_rtsp_connection_send gst_rtsp_connection_send
gst_rtsp_connection_receive gst_rtsp_connection_receive
gst_rtsp_connection_next_timeout gst_rtsp_connection_next_timeout
gst_rtsp_connection_reset_timeout gst_rtsp_connection_reset_timeout
gst_rtsp_connection_flush gst_rtsp_connection_flush
gst_rtsp_connection_set_auth gst_rtsp_connection_set_auth
gst_rtsp_connection_set_auth_param
gst_rtsp_connection_clear_auth_params
gst_rtsp_connection_set_qos_dscp
gst_rtsp_connection_get_ip
gst_rtsp_connection_get_url
gst_rtsp_connection_set_tunneled
gst_rtsp_connection_is_tunneled
GstRTSPWatch GstRTSPWatch
GstRTSPWatchFuncs GstRTSPWatchFuncs

View File

@ -95,6 +95,12 @@
#include "gstrtspbase64.h" #include "gstrtspbase64.h"
#include "md5.h" #include "md5.h"
static GstRTSPResult read_line (gint fd, guint8 * buffer, guint * idx,
guint size);
static GstRTSPResult parse_key_value (guint8 * buffer, gchar * key,
guint keysize, gchar ** value);
static void parse_string (gchar * dest, gint size, gchar ** src);
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
#define READ_SOCKET(fd, buf, len) recv (fd, (char *)buf, len, 0) #define READ_SOCKET(fd, buf, len) recv (fd, (char *)buf, len, 0)
#define WRITE_SOCKET(fd, buf, len) send (fd, (const char *)buf, len, 0) #define WRITE_SOCKET(fd, buf, len) send (fd, (const char *)buf, len, 0)
@ -115,20 +121,20 @@
#define ERRNO_IS_EINPROGRESS (errno == EINPROGRESS) #define ERRNO_IS_EINPROGRESS (errno == EINPROGRESS)
#endif #endif
#define ADD_POLLFD(fdset, pfd, fd) \ #define ADD_POLLFD(fdset, pfd, fd) \
G_STMT_START { \ G_STMT_START { \
pfd.fd = fd; \ (pfd)->fd = fd; \
gst_poll_add_fd (fdset, &pfd); \ gst_poll_add_fd (fdset, pfd); \
} G_STMT_END } G_STMT_END
#define REMOVE_POLLFD(fdset, pfd) \ #define REMOVE_POLLFD(fdset, pfd) \
G_STMT_START { \ G_STMT_START { \
if (pfd.fd != -1) { \ if ((pfd)->fd != -1) { \
GST_DEBUG ("remove fd %d", pfd.fd); \ GST_DEBUG ("remove fd %d", (pfd)->fd); \
gst_poll_remove_fd (fdset, &pfd); \ gst_poll_remove_fd (fdset, pfd); \
CLOSE_SOCKET (pfd.fd); \ CLOSE_SOCKET ((pfd)->fd); \
pfd.fd = -1; \ (pfd)->fd = -1; \
} \ } \
} G_STMT_END } G_STMT_END
struct _GstRTSPConnection struct _GstRTSPConnection
@ -144,6 +150,8 @@ struct _GstRTSPConnection
GstPollFD *readfd; GstPollFD *readfd;
GstPollFD *writefd; GstPollFD *writefd;
gboolean tunneled;
GstPoll *fdset; GstPoll *fdset;
gchar *ip; gchar *ip;
@ -247,6 +255,7 @@ gst_rtsp_connection_create (GstRTSPUrl * url, GstRTSPConnection ** conn)
newconn->fd1.fd = -1; newconn->fd1.fd = -1;
newconn->timer = g_timer_new (); newconn->timer = g_timer_new ();
newconn->timeout = 60; newconn->timeout = 60;
newconn->tunneled = FALSE;
newconn->auth_method = GST_RTSP_AUTH_NONE; newconn->auth_method = GST_RTSP_AUTH_NONE;
newconn->username = NULL; newconn->username = NULL;
@ -331,7 +340,7 @@ gst_rtsp_connection_accept (gint sock, GstRTSPConnection ** conn)
/* now create the connection object */ /* now create the connection object */
gst_rtsp_connection_create (url, &newconn); gst_rtsp_connection_create (url, &newconn);
ADD_POLLFD (newconn->fdset, newconn->fd0, fd); ADD_POLLFD (newconn->fdset, &newconn->fd0, fd);
newconn->readfd = &newconn->fd0; newconn->readfd = &newconn->fd0;
newconn->writefd = &newconn->fd0; newconn->writefd = &newconn->fd0;
@ -347,6 +356,331 @@ accept_failed:
} }
} }
static const gchar *
do_resolve (const gchar * host)
{
struct hostent *hostinfo;
struct in_addr addr;
const gchar *ip;
#ifdef G_OS_WIN32
struct in_addr *addrp;
#else
char **addrs;
gchar ipbuf[INET_ADDRSTRLEN];
#endif /* G_OS_WIN32 */
ip = NULL;
/* first check if it already is an IP address */
if (inet_aton (host, &addr)) {
ip = host;
} else {
hostinfo = gethostbyname (host);
if (!hostinfo)
goto not_resolved; /* h_errno set */
if (hostinfo->h_addrtype != AF_INET)
goto not_ip; /* host not an IP host */
#ifdef G_OS_WIN32
addrp = (struct in_addr *) hostinfo->h_addr_list[0];
/* this is not threadsafe */
ip = inet_ntoa (*addrp);
#else
addrs = hostinfo->h_addr_list;
ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
sizeof (ipbuf));
#endif /* G_OS_WIN32 */
}
return ip;
/* ERRORS */
not_resolved:
{
GST_ERROR ("could not resolve %s", host);
return NULL;
}
not_ip:
{
GST_ERROR ("not an IP address");
return NULL;
}
}
static GstRTSPResult
do_connect (const gchar * ip, guint16 port, GstPollFD * fdout,
GstPoll * fdset, GTimeVal * timeout)
{
gint fd;
struct sockaddr_in sa_in;
gint ret;
#ifdef G_OS_WIN32
unsigned long flags = 1;
#endif /* G_OS_WIN32 */
GstClockTime to;
gint retval;
g_message ("connect %s:%u", ip, 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 no_socket;
/* 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 */
/* add the socket to our fdset */
ADD_POLLFD (fdset, fdout, fd);
/* we are going to connect ASYNC now */
ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
if (ret == 0)
goto done;
if (!ERRNO_IS_EINPROGRESS)
goto sys_error;
/* wait for connect to complete up to the specified timeout or until we got
* interrupted. */
gst_poll_fd_ctl_write (fdset, fdout, TRUE);
to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
do {
retval = gst_poll_wait (fdset, to);
} while (retval == -1 && (errno == EINTR || errno == EAGAIN));
if (retval == 0)
goto timeout;
else if (retval == -1)
goto sys_error;
/* we can still have an error connecting on windows */
if (gst_poll_fd_has_error (fdset, fdout)) {
socklen_t len = sizeof (errno);
#ifndef G_OS_WIN32
getsockopt (fd, SOL_SOCKET, SO_ERROR, &errno, &len);
#else
getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno, &len);
#endif
goto sys_error;
}
gst_poll_fd_ignored (fdset, fdout);
done:
return GST_RTSP_OK;
/* ERRORS */
no_socket:
{
GST_ERROR ("no socket %d (%s)", errno, g_strerror (errno));
return GST_RTSP_ESYS;
}
sys_error:
{
GST_ERROR ("system error %d (%s)", errno, g_strerror (errno));
REMOVE_POLLFD (fdset, fdout);
return GST_RTSP_ESYS;
}
timeout:
{
GST_ERROR ("timeout");
REMOVE_POLLFD (fdset, fdout);
return GST_RTSP_ETIMEOUT;
}
}
static GstRTSPResult
setup_tunneling (GstRTSPConnection * conn, GTimeVal * timeout)
{
gchar sessionid[24];
gint i;
GstRTSPResult res;
gchar *str;
guint idx, line;
gint retval;
GstClockTime to;
const gchar *ip;
guint16 port;
gchar codestr[4];
gint code;
/* create a random sessionid */
for (i = 0; i < 24; i++)
sessionid[i] = g_random_int_range ('a', 'z');
sessionid[23] = '\0';
/* */
str = g_strdup_printf ("GET %s HTTP/1.0\r\n"
"x-sessioncookie: %s\r\n"
"Accept: application/x-rtsp-tunnelled\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n" "\r\n", conn->url->host, sessionid);
/* we start by writing to this fd */
conn->writefd = &conn->fd0;
res = gst_rtsp_connection_write (conn, (guint8 *) str, strlen (str), timeout);
g_free (str);
if (res != GST_RTSP_OK)
goto write_failed;
gst_poll_fd_ctl_write (conn->fdset, &conn->fd0, FALSE);
gst_poll_fd_ctl_read (conn->fdset, &conn->fd0, TRUE);
to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
line = 0;
while (TRUE) {
guint8 buffer[4096];
idx = 0;
while (TRUE) {
res = read_line (conn->fd0.fd, buffer, &idx, sizeof (buffer));
if (res == GST_RTSP_EEOF)
goto eof;
if (res == GST_RTSP_OK)
break;
if (res != GST_RTSP_EINTR)
goto read_error;
do {
retval = gst_poll_wait (conn->fdset, to);
} while (retval == -1 && (errno == EINTR || errno == EAGAIN));
/* check for timeout */
if (retval == 0)
goto timeout;
if (retval == -1) {
if (errno == EBUSY)
goto stopped;
else
goto select_error;
}
}
/* check for last line */
if (buffer[0] == '\r')
buffer[0] = '\0';
if (buffer[0] == '\0')
break;
if (line == 0) {
/* first line, parse response */
gchar versionstr[20];
gchar *bptr;
bptr = (gchar *) buffer;
parse_string (versionstr, sizeof (versionstr), &bptr);
parse_string (codestr, sizeof (codestr), &bptr);
code = atoi (codestr);
if (code != 200)
goto wrong_result;
} else {
gchar key[32];
gchar *value;
/* other lines, parse key/value */
res = parse_key_value (buffer, key, sizeof (key), &value);
if (res == GST_RTSP_OK) {
/* we got a new ip address */
if (g_ascii_strcasecmp (key, "x-server-ip-address") == 0) {
g_free (conn->ip);
conn->ip = g_strdup (value);
}
}
}
line++;
}
if (!(ip = do_resolve (conn->ip)))
goto not_resolved;
/* get the port from the url */
gst_rtsp_url_get_port (conn->url, &port);
/* connect to the host/port */
res = do_connect (ip, port, &conn->fd1, conn->fdset, timeout);
if (res != GST_RTSP_OK)
goto connect_failed;
/* this is now our writing socket */
conn->writefd = &conn->fd1;
/* */
str = g_strdup_printf ("POST %s HTTP/1.0\r\n"
"x-sessioncookie: %s\r\n"
"Content-Type: application/x-rtsp-tunnelled\r\n"
"Pragma: no-cache\r\n"
"Cache-Control: no-cache\r\n"
"Content-Length: 32767\r\n"
"Expires: Sun, 9 Jan 1972 00:00:00 GMT\r\n"
"\r\n", conn->url->host, sessionid);
/* we start by writing to this fd */
conn->writefd = &conn->fd1;
res = gst_rtsp_connection_write (conn, (guint8 *) str, strlen (str), timeout);
g_free (str);
if (res != GST_RTSP_OK)
goto write_failed;
return res;
/* ERRORS */
write_failed:
{
GST_ERROR ("write failed", res);
return res;
}
eof:
{
return GST_RTSP_EEOF;
}
read_error:
{
return res;
}
timeout:
{
return GST_RTSP_ETIMEOUT;
}
select_error:
{
return GST_RTSP_ESYS;
}
stopped:
{
return GST_RTSP_EINTR;
}
wrong_result:
{
GST_ERROR ("got failure response %d %s", code, codestr);
return GST_RTSP_ERROR;
}
not_resolved:
{
GST_ERROR ("could not resolve %s", conn->ip);
return GST_RTSP_ENET;
}
connect_failed:
{
GST_ERROR ("failed to connect");
return res;
}
}
/** /**
* gst_rtsp_connection_connect: * gst_rtsp_connection_connect:
* @conn: a #GstRTSPConnection * @conn: a #GstRTSPConnection
@ -364,23 +698,12 @@ accept_failed:
GstRTSPResult GstRTSPResult
gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout) gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
{ {
gint fd; GstRTSPResult res;
struct sockaddr_in sa_in;
struct hostent *hostinfo;
const gchar *ip; const gchar *ip;
struct in_addr addr;
gint ret;
guint16 port; guint16 port;
GstRTSPUrl *url; GstRTSPUrl *url;
GstClockTime to;
gint retval;
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
unsigned long flags = 1; unsigned long flags = 1;
struct in_addr *addrp;
#else
char **addrs;
gchar ipbuf[INET_ADDRSTRLEN];
#endif /* G_OS_WIN32 */ #endif /* G_OS_WIN32 */
g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
@ -389,116 +712,47 @@ gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
url = conn->url; url = conn->url;
/* first check if it already is an IP address */ if (!(ip = do_resolve (url->host)))
if (inet_aton (url->host, &addr)) { goto not_resolved;
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 */
#ifdef G_OS_WIN32
addrp = (struct in_addr *) hostinfo->h_addr_list[0];
/* this is not threadsafe */
ip = inet_ntoa (*addrp);
#else
addrs = hostinfo->h_addr_list;
ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
sizeof (ipbuf));
#endif /* G_OS_WIN32 */
}
/* get the port from the url */ /* get the port from the url */
gst_rtsp_url_get_port (url, &port); gst_rtsp_url_get_port (url, &port);
memset (&sa_in, 0, sizeof (sa_in)); /* connect to the host/port */
sa_in.sin_family = AF_INET; /* network socket */ res = do_connect (ip, port, &conn->fd0, conn->fdset, timeout);
sa_in.sin_port = htons (port); /* on port */ if (res != GST_RTSP_OK)
sa_in.sin_addr.s_addr = inet_addr (ip); /* on host ip */ goto connect_failed;
fd = socket (AF_INET, SOCK_STREAM, 0); g_free (conn->ip);
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 */
/* add the socket to our fdset */
ADD_POLLFD (conn->fdset, conn->fd0, fd);
conn->readfd = &conn->fd0;
conn->writefd = &conn->fd0;
/* we are going to connect ASYNC now */
ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
if (ret == 0)
goto done;
if (!ERRNO_IS_EINPROGRESS)
goto sys_error;
/* wait for connect to complete up to the specified timeout or until we got
* interrupted. */
gst_poll_fd_ctl_write (conn->fdset, conn->writefd, TRUE);
to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
do {
retval = gst_poll_wait (conn->fdset, to);
} while (retval == -1 && (errno == EINTR || errno == EAGAIN));
if (retval == 0)
goto timeout;
else if (retval == -1)
goto sys_error;
/* we can still have an error connecting on windows */
if (gst_poll_fd_has_error (conn->fdset, conn->writefd)) {
socklen_t len = sizeof (errno);
#ifndef G_OS_WIN32
getsockopt (fd, SOL_SOCKET, SO_ERROR, &errno, &len);
#else
getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno, &len);
#endif
goto sys_error;
}
gst_poll_fd_ignored (conn->fdset, conn->writefd);
gst_poll_fd_ignored (conn->fdset, conn->readfd);
done:
conn->ip = g_strdup (ip); conn->ip = g_strdup (ip);
/* this is our read URL */
conn->readfd = &conn->fd0;
if (conn->tunneled) {
res = setup_tunneling (conn, timeout);
if (res != GST_RTSP_OK)
goto tunneling_failed;
} else {
conn->writefd = &conn->fd0;
}
return GST_RTSP_OK; return GST_RTSP_OK;
sys_error:
{
GST_ERROR ("system error %d (%s)", errno, g_strerror (errno));
REMOVE_POLLFD (conn->fdset, conn->fd0);
REMOVE_POLLFD (conn->fdset, conn->fd1);
return GST_RTSP_ESYS;
}
not_resolved: not_resolved:
{ {
GST_ERROR ("could not resolve %s", url->host); GST_ERROR ("could not resolve %s", url->host);
return GST_RTSP_ENET; return GST_RTSP_ENET;
} }
not_ip: connect_failed:
{ {
GST_ERROR ("not an IP address"); GST_ERROR ("failed to connect");
return GST_RTSP_ENOTIP; return res;
} }
timeout: tunneling_failed:
{ {
GST_ERROR ("timeout"); GST_ERROR ("failed to setup tunneling");
REMOVE_POLLFD (conn->fdset, conn->fd0); return res;
REMOVE_POLLFD (conn->fdset, conn->fd1);
return GST_RTSP_ETIMEOUT;
} }
} }
@ -922,20 +1176,31 @@ GstRTSPResult
gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message, gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
GTimeVal * timeout) GTimeVal * timeout)
{ {
GString *str = NULL; GString *string = NULL;
GstRTSPResult res; GstRTSPResult res;
gchar *str;
gsize len;
g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL); g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL); g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
if (!(str = message_to_string (conn, message))) if (!(string = message_to_string (conn, message)))
goto no_message; goto no_message;
/* write request */ if (conn->tunneled) {
res = str = g_base64_encode ((const guchar *) string->str, string->len);
gst_rtsp_connection_write (conn, (guint8 *) str->str, str->len, timeout); g_string_free (string, TRUE);
len = strlen (str);
} else {
str = string->str;
len = string->len;
g_string_free (string, FALSE);
}
g_string_free (str, TRUE); /* write request */
res = gst_rtsp_connection_write (conn, (guint8 *) str, len, timeout);
g_free (str);
return res; return res;
@ -1056,38 +1321,59 @@ parse_request_line (guint8 * buffer, GstRTSPMessage * msg)
return res; return res;
} }
/* parsing lines means reading a Key: Value pair */
static GstRTSPResult static GstRTSPResult
parse_line (guint8 * buffer, GstRTSPMessage * msg) parse_key_value (guint8 * buffer, gchar * key, guint keysize, gchar ** value)
{ {
gchar key[32];
gchar *bptr; gchar *bptr;
GstRTSPHeaderField field;
bptr = (gchar *) buffer; bptr = (gchar *) buffer;
/* read key */ /* read key */
parse_key (key, sizeof (key), &bptr); parse_key (key, keysize, &bptr);
if (*bptr != ':') if (*bptr != ':')
goto no_column; goto no_column;
bptr++; bptr++;
while (g_ascii_isspace (*bptr))
bptr++;
field = gst_rtsp_find_header_field (key); *value = bptr;
if (field != GST_RTSP_HDR_INVALID) {
while (g_ascii_isspace (*bptr))
bptr++;
gst_rtsp_message_add_header (msg, field, bptr);
}
return GST_RTSP_OK; return GST_RTSP_OK;
/* ERRORS */
no_column: no_column:
{ {
return GST_RTSP_EPARSE; return GST_RTSP_EPARSE;
} }
} }
/* parsing lines means reading a Key: Value pair */
static GstRTSPResult
parse_line (guint8 * buffer, GstRTSPMessage * msg)
{
GstRTSPResult res;
gchar key[32];
gchar *value;
GstRTSPHeaderField field;
res = parse_key_value (buffer, key, sizeof (key), &value);
if (res != GST_RTSP_OK)
goto parse_error;
field = gst_rtsp_find_header_field (key);
if (field != GST_RTSP_HDR_INVALID)
gst_rtsp_message_add_header (msg, field, value);
return GST_RTSP_OK;
/* ERRORS */
parse_error:
{
return res;
}
}
/* returns: /* returns:
* GST_RTSP_OK when a complete message was read. * GST_RTSP_OK when a complete message was read.
* GST_RTSP_EEOF: when the socket is closed * GST_RTSP_EEOF: when the socket is closed
@ -1456,8 +1742,8 @@ gst_rtsp_connection_close (GstRTSPConnection * conn)
g_free (conn->ip); g_free (conn->ip);
conn->ip = NULL; conn->ip = NULL;
REMOVE_POLLFD (conn->fdset, conn->fd0); REMOVE_POLLFD (conn->fdset, &conn->fd0);
REMOVE_POLLFD (conn->fdset, conn->fd1); REMOVE_POLLFD (conn->fdset, &conn->fd1);
conn->writefd = NULL; conn->writefd = NULL;
conn->readfd = NULL; conn->readfd = NULL;
@ -1902,6 +2188,45 @@ gst_rtsp_connection_get_ip (const GstRTSPConnection * conn)
return conn->ip; return conn->ip;
} }
/**
* gst_rtsp_connection_set_tunneled:
* @conn: a #GstRTSPConnection
* @tunneled: the new state
*
* Set the HTTP tunneling state of the connection. This must be configured before
* the @conn is connected.
*
* Since: 0.10.23
*/
void
gst_rtsp_connection_set_tunneled (GstRTSPConnection * conn, gboolean tunneled)
{
g_return_if_fail (conn != NULL);
g_return_if_fail (conn->readfd == NULL);
g_return_if_fail (conn->writefd == NULL);
conn->tunneled = tunneled;
}
/**
* gst_rtsp_connection_is_tunneled:
* @conn: a #GstRTSPConnection
*
* Get the tunneling state of the connection.
*
* Returns: if @conn is using HTTP tunneling.
*
* Since: 0.10.23
*/
gboolean
gst_rtsp_connection_is_tunneled (GstRTSPConnection * conn)
{
g_return_val_if_fail (conn != NULL, FALSE);
return conn->tunneled;
}
#define READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR) #define READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
#define WRITE_COND (G_IO_OUT | G_IO_ERR) #define WRITE_COND (G_IO_OUT | G_IO_ERR)
@ -2080,6 +2405,7 @@ static GSourceFuncs gst_rtsp_source_funcs = {
* @conn: a #GstRTSPConnection * @conn: a #GstRTSPConnection
* @funcs: watch functions * @funcs: watch functions
* @user_data: user data to pass to @funcs * @user_data: user data to pass to @funcs
* @notify: notify when @user_data is not referenced anymore
* *
* Create a watch object for @conn. The functions provided in @funcs will be * Create a watch object for @conn. The functions provided in @funcs will be
* called with @user_data when activity happened on the watch. * called with @user_data when activity happened on the watch.
@ -2151,7 +2477,7 @@ gst_rtsp_watch_attach (GstRTSPWatch * watch, GMainContext * context)
} }
/** /**
* gst_rtsp_watch_free: * gst_rtsp_watch_unref:
* @watch: a #GstRTSPWatch * @watch: a #GstRTSPWatch
* *
* Decreases the reference count of @watch by one. If the resulting reference * Decreases the reference count of @watch by one. If the resulting reference

View File

@ -65,6 +65,7 @@ GstRTSPResult gst_rtsp_connection_connect (GstRTSPConnection *conn, G
GstRTSPResult gst_rtsp_connection_close (GstRTSPConnection *conn); GstRTSPResult gst_rtsp_connection_close (GstRTSPConnection *conn);
GstRTSPResult gst_rtsp_connection_free (GstRTSPConnection *conn); GstRTSPResult gst_rtsp_connection_free (GstRTSPConnection *conn);
/* sending/receiving raw bytes */ /* sending/receiving raw bytes */
GstRTSPResult gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, GstRTSPResult gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data,
guint size, GTimeVal * timeout); guint size, GTimeVal * timeout);
@ -105,6 +106,9 @@ GstRTSPResult gst_rtsp_connection_set_qos_dscp (GstRTSPConnection *conn,
GstRTSPUrl * gst_rtsp_connection_get_url (const GstRTSPConnection *conn); GstRTSPUrl * gst_rtsp_connection_get_url (const GstRTSPConnection *conn);
const gchar * gst_rtsp_connection_get_ip (const GstRTSPConnection *conn); const gchar * gst_rtsp_connection_get_ip (const GstRTSPConnection *conn);
void gst_rtsp_connection_set_tunneled (GstRTSPConnection *conn, gboolean tunneled);
gboolean gst_rtsp_connection_is_tunneled (GstRTSPConnection *conn);
/* async IO */ /* async IO */
/** /**

View File

@ -11,6 +11,7 @@ EXPORTS
gst_rtsp_connection_free gst_rtsp_connection_free
gst_rtsp_connection_get_ip gst_rtsp_connection_get_ip
gst_rtsp_connection_get_url gst_rtsp_connection_get_url
gst_rtsp_connection_is_tunneled
gst_rtsp_connection_next_timeout gst_rtsp_connection_next_timeout
gst_rtsp_connection_poll gst_rtsp_connection_poll
gst_rtsp_connection_read gst_rtsp_connection_read
@ -20,6 +21,7 @@ EXPORTS
gst_rtsp_connection_set_auth gst_rtsp_connection_set_auth
gst_rtsp_connection_set_auth_param gst_rtsp_connection_set_auth_param
gst_rtsp_connection_set_qos_dscp gst_rtsp_connection_set_qos_dscp
gst_rtsp_connection_set_tunneled
gst_rtsp_connection_write gst_rtsp_connection_write
gst_rtsp_event_get_type gst_rtsp_event_get_type
gst_rtsp_extension_after_send gst_rtsp_extension_after_send