gst/rtsp/: Added README

Original commit message from CVS:
* gst/rtsp/README:
* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
(gst_rtspsrc_class_init), (gst_rtspsrc_create_stream),
(gst_rtspsrc_add_element), (gst_rtspsrc_set_state),
(gst_rtspsrc_stream_setup_rtp),
(gst_rtspsrc_stream_configure_transport), (find_stream),
(gst_rtspsrc_loop), (gst_rtspsrc_open), (gst_rtspsrc_play):
* gst/rtsp/rtsp.h:
* gst/rtsp/rtspconnection.c: (rtsp_connection_create),
(rtsp_connection_send), (read_line), (parse_request_line),
(parse_line), (read_body), (rtsp_connection_receive),
(rtsp_connection_free):
* gst/rtsp/rtspconnection.h:
* gst/rtsp/rtspdefs.c: (rtsp_find_method):
* gst/rtsp/rtspdefs.h:
* gst/rtsp/rtspmessage.c: (rtsp_message_set_body),
(rtsp_message_take_body):
* gst/rtsp/rtspmessage.h:
* gst/rtsp/rtspstream.h:
* gst/rtsp/sdpmessage.c: (sdp_parse_line):
Added README
Some cleanups.
This commit is contained in:
Wim Taymans 2005-05-11 12:01:10 +00:00
parent 91ce2b294e
commit 63177e0731
12 changed files with 368 additions and 124 deletions

View file

@ -1,3 +1,28 @@
2005-05-11 Wim Taymans <wim@fluendo.com>
* gst/rtsp/README:
* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
(gst_rtspsrc_class_init), (gst_rtspsrc_create_stream),
(gst_rtspsrc_add_element), (gst_rtspsrc_set_state),
(gst_rtspsrc_stream_setup_rtp),
(gst_rtspsrc_stream_configure_transport), (find_stream),
(gst_rtspsrc_loop), (gst_rtspsrc_open), (gst_rtspsrc_play):
* gst/rtsp/rtsp.h:
* gst/rtsp/rtspconnection.c: (rtsp_connection_create),
(rtsp_connection_send), (read_line), (parse_request_line),
(parse_line), (read_body), (rtsp_connection_receive),
(rtsp_connection_free):
* gst/rtsp/rtspconnection.h:
* gst/rtsp/rtspdefs.c: (rtsp_find_method):
* gst/rtsp/rtspdefs.h:
* gst/rtsp/rtspmessage.c: (rtsp_message_set_body),
(rtsp_message_take_body):
* gst/rtsp/rtspmessage.h:
* gst/rtsp/rtspstream.h:
* gst/rtsp/sdpmessage.c: (sdp_parse_line):
Added README
Some cleanups.
2005-05-11 Wim Taymans <wim@fluendo.com>
* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),

156
gst/rtsp/README Normal file
View file

@ -0,0 +1,156 @@
RTSP source
-----------
The RTSP source establishes a connection to an RTSP server and sets up
the UDP sources and RTP session handlers.
An RTSP session is created as follows:
- Parse RTSP URL:
ex:
rtsp://thread:5454/south-rtsp.mp3
- Open a connection to the server with the url. All further conversation with
the server should be done with this connection. Each request/reply has
a CSeq number added to the header.
- Send a DESCRIBE request for the url. We currently support a response in
SDP.
ex:
>> DESCRIBE rtsp://thread:5454/south-rtsp.mp3 RTSP/1.0
>> Accept: application/sdp
>> CSeq: 0
>>
<< RTSP/1.0 200 OK
<< Content-Length: 84
<< Content-Type: application/sdp
<< CSeq: 0
<< Date: Wed May 11 13:09:37 2005 GMT
<<
<< v=0
<< o=- 0 0 IN IP4 192.168.1.1
<< s=No Title
<< m=audio 0 RTP/AVP 14
<< a=control:streamid=0
- Parse the SDP message, for each stream (m=) we create an GstRTPStream. We need
to allocate two local UDP ports for receiving the RTP and RTCP data because we
need to send the port numbers to the server in the next request.
In RTSPSrc we create two elements that can handle the udp://0.0.0.0:0 uri. This
will create an udp source element. We get the port number by getting the "port"
property of the element after setting the element to PAUSED.
+-----------------+
| +------------+ |
| | udpsrc0 | |
| | port=5000 | |
| +------------+ |
| +------------+ |
| | udpsrc1 | |
| | port=5001 | |
| +------------+ |
+-----------------+
- Send a SETUP message to the server with the RTP ports. We get the setup URI from
the a= attribute in the SDP message. This can be an absolute URL or a relative
url.
ex:
>> SETUP rtsp://thread:5454/south-rtsp.mp3/streamid=0 RTSP/1.0
>> CSeq: 1
>> Transport: RTP/AVP/UDP;unicast;client_port=5000-5001,RTP/AVP/UDP;multicast,RTP/AVP/TCP
>>
<< RTSP/1.0 200 OK
<< Transport: RTP/AVP/UDP;unicast;client_port=5000-5001;server_port=6000-6001
<< CSeq: 1
<< Date: Wed May 11 13:21:43 2005 GMT
<< Session: 5d5cb94413288ccd
<<
The client needs to send the local ports to the server along with the supported
transport types. The server selects the final transport which it returns in the
Transport header field. The server also includes its ports where RTP and RTCP
messages can be sent to.
In the above example UDP was choosen as a transport. At this point the RTSPSrc element
will furter configure its elements to process this stream.
The RTSPSrc will create and connect an RTP session manager element and will
connect it to the src pads of the udp element. The data pad from the RTP session
manager is ghostpadded to RTPSrc.
The RTCP pad of the rtpdec is routed to a new udpsink that sends data to the RTCP
port of the server as returned in the Transport: header field.
+---------------------------------------------+
| +------------+ |
| | udpsrc0 | +--------+ |
| | port=5000 ----- rtpdec --------------------
| +------------+ | | |
| +------------+ | | +------------+ |
| | udpsrc1 ----- RTCP ---- udpsink | |
| | port=5001 | +--------+ | port=6001 | |
| +------------+ +------------+ |
+---------------------------------------------+
The output type of rtpdec is configured as the media type specified in the SDP
message.
- All the elements are set to PAUSED/PLAYING and the PLAY RTSP message is
sent.
>> PLAY rtsp://thread:5454/south-rtsp.mp3 RTSP/1.0
>> CSeq: 2
>>
<< RTSP/1.0 200 OK
<< CSeq: 2
<< Date: Wed May 11 13:21:43 2005 GMT
<< Session: 5d5cb94413288ccd
<<
- The udp source elements receive data from that point and the RTP/RTCP messages
are processed by the elements.
- In the case of interleaved mode, the SETUP method yields:
>> SETUP rtsp://thread:5454/south-rtsp.mp3/streamid=0 RTSP/1.0
>> CSeq: 1
>> Transport: RTP/AVP/UDP;unicast;client_port=5000-5001,RTP/AVP/UDP;multicast,RTP/AVP/TCP
>>
<< RTSP/1.0 200 OK
<< Transport: RTP/AVP/TCP;interleaved=0-1
<< CSeq: 1
<< Date: Wed May 11 13:21:43 2005 GMT
<< Session: 5d5cb94413288ccd
<<
This means that RTP/RTCP messages will be send on channel 0/1 respectively and that
the data will be received on the same connection as the RTSP connection.
At this point, we remove the UDP source elements as we don't need them anymore. We
setup the rtpdec session manager element though as follows:
+---------------------------------------------+
| +------------+ |
| | _loop() | +--------+ |
| | ----- rtpdec --------------------
| | | | | |
| | | | | +------------+ |
| | ----- RTCP ---- udpsink | |
| | | +--------+ | port=6001 | |
| +------------+ +------------+ |
+---------------------------------------------+
We start an interal task to start reading from the RTSP connection waiting
for data. The received data is then pushed to the rtpdec element.
When reading from the RTSP connection we receive data packets in the
following layout (see also RFC2326)
$<1 byte channel><2 bytes length, big endian><length bytes of data>

View file

@ -637,7 +637,7 @@ gst_rtspsrc_open (GstRTSPSrc * src)
new =
g_strconcat (transports, transports[0] ? "," : "",
",RTP/AVP/UDP;multicast", NULL);
"RTP/AVP/UDP;multicast", NULL);
g_free (transports);
transports = new;
}
@ -645,7 +645,7 @@ gst_rtspsrc_open (GstRTSPSrc * src)
gchar *new;
new =
g_strconcat (transports, transports[0] ? "," : "", ",RTP/AVP/TCP",
g_strconcat (transports, transports[0] ? "," : "", "RTP/AVP/TCP",
NULL);
g_free (transports);
transports = new;

View file

@ -23,7 +23,6 @@
#include <rtspconnection.h>
#include <rtspdefs.h>
#include <rtspmessage.h>
#include <rtspstream.h>
#include <rtsptransport.h>
#include <rtspurl.h>

View file

@ -20,6 +20,7 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
@ -94,7 +95,7 @@ rtsp_connection_create (gint fd, RTSPConnection ** conn)
{
RTSPConnection *newconn;
/* FIXME check fd */
/* FIXME check fd, must be connected SOCK_STREAM */
newconn = g_new (RTSPConnection, 1);
@ -120,30 +121,70 @@ RTSPResult
rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
{
GString *str;
gint towrite;
gchar *data;
if (conn == NULL || message == NULL)
return RTSP_EINVAL;
str = g_string_new ("");
/* create request string, add CSeq */
g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
"CSeq: %d\r\n",
rtsp_method_as_text (message->type_data.request.method),
message->type_data.request.uri, conn->cseq);
/* append session id if we have one */
if (conn->session_id[0] != '\0') {
rtsp_message_add_header (message, RTSP_HDR_SESSION, conn->session_id);
}
/* append headers */
g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str);
/* append Content-Length and body if needed */
if (message->body != NULL && message->body_size > 0) {
gchar *len;
g_string_append (str, "\r\n");
len = g_strdup_printf ("%d", message->body_size);
append_header (RTSP_HDR_CONTENT_LENGTH, len, str);
g_free (len);
/* header ends here */
g_string_append (str, "\r\n");
str = g_string_append_len (str, message->body, message->body_size);
} else {
/* just end headers */
g_string_append (str, "\r\n");
}
write (conn->fd, str->str, str->len);
/* write request */
towrite = str->len;
data = str->str;
while (towrite > 0) {
gint written;
written = write (conn->fd, data, towrite);
if (written < 0) {
if (errno != EAGAIN && errno != EINTR)
goto write_error;
} else {
towrite -= written;
data += written;
}
}
g_string_free (str, TRUE);
conn->cseq++;
return RTSP_OK;
write_error:
{
g_string_free (str, TRUE);
return RTSP_ESYS;
}
}
static RTSPResult
@ -151,29 +192,30 @@ read_line (gint fd, gchar * buffer, guint size)
{
gint idx;
gchar c;
gint ret;
gint r;
idx = 0;
while (TRUE) {
ret = read (fd, &c, 1);
if (ret < 1)
goto error;
r = read (fd, &c, 1);
if (r < 1) {
if (errno != EAGAIN && errno != EINTR)
goto read_error;
} else {
if (c == '\n') /* end on \n */
break;
if (c == '\r') /* ignore \r */
continue;
if (c == '\n') /* end on \n */
break;
if (c == '\r') /* ignore \r */
continue;
if (idx < size - 1)
buffer[idx++] = c;
if (idx < size - 1)
buffer[idx++] = c;
}
}
buffer[idx] = '\0';
return RTSP_OK;
error:
read_error:
{
perror ("read");
return RTSP_ESYS;
}
}
@ -242,6 +284,43 @@ wrong_version:
}
}
static RTSPResult
parse_request_line (gchar * buffer, RTSPMessage * msg)
{
gchar versionstr[20];
gchar methodstr[20];
gchar urlstr[4096];
gchar *bptr;
RTSPMethod method;
bptr = buffer;
read_string (methodstr, sizeof (methodstr), &bptr);
method = rtsp_find_method (methodstr);
if (method == -1)
goto wrong_method;
read_string (urlstr, sizeof (urlstr), &bptr);
read_string (versionstr, sizeof (versionstr), &bptr);
if (strcmp (versionstr, "RTSP/1.0") != 0)
goto wrong_version;
rtsp_message_init_request (method, urlstr, msg);
return RTSP_OK;
wrong_method:
{
return RTSP_EINVAL;
}
wrong_version:
{
return RTSP_EINVAL;
}
}
/* parsing lines means reading a Key: Value pair */
static RTSPResult
parse_line (gchar * buffer, RTSPMessage * msg)
{
@ -251,6 +330,7 @@ parse_line (gchar * buffer, RTSPMessage * msg)
bptr = buffer;
/* read key */
read_key (key, sizeof (key), &bptr);
if (*bptr != ':')
return RTSP_EINVAL;
@ -259,7 +339,7 @@ parse_line (gchar * buffer, RTSPMessage * msg)
field = rtsp_find_header_field (key);
if (field == -1) {
g_warning ("unknown header field '%s'\n", key);
g_warning ("ignoring unknown header field '%s'\n", key);
} else {
while (g_ascii_isspace (*bptr))
bptr++;
@ -276,8 +356,9 @@ read_body (gint fd, glong content_length, RTSPMessage * msg)
gint to_read, r;
if (content_length <= 0) {
rtsp_message_set_body (msg, NULL, 0);
return RTSP_OK;
body = NULL;
content_length = 0;
goto done;
}
body = g_malloc (content_length);
@ -285,14 +366,25 @@ read_body (gint fd, glong content_length, RTSPMessage * msg)
to_read = content_length;
while (to_read > 0) {
r = read (fd, bodyptr, to_read);
to_read -= r;
bodyptr += r;
if (r < 0) {
if (errno != EAGAIN && errno != EINTR)
goto read_error;
} else {
to_read -= r;
bodyptr += r;
}
}
done:
rtsp_message_set_body (msg, body, content_length);
return RTSP_OK;
read_error:
{
g_free (body);
return RTSP_ESYS;
}
}
RTSPResult
@ -312,30 +404,36 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg)
need_body = TRUE;
res = RTSP_OK;
/* parse first line and headers */
while (TRUE) {
while (res == RTSP_OK) {
gchar c;
gint ret;
/* read first character, this identifies data messages */
ret = read (conn->fd, &c, 1);
if (ret < 0)
goto read_error;
if (ret < 1)
break;
/* check for data packet */
/* check for data packet, first character is $ */
if (c == '$') {
guint16 size;
/* read channel */
/* data packets are $<1 byte channel><2 bytes length,BE><data bytes> */
/* read channel, which is the next char */
ret = read (conn->fd, &c, 1);
if (ret < 0)
goto read_error;
if (ret < 1)
goto error;
/* now we create a data message */
rtsp_message_init_data ((gint) c, msg);
/* next two bytes are the length of the data */
ret = read (conn->fd, &size, 2);
if (ret < 0)
goto read_error;
@ -344,12 +442,14 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg)
size = GUINT16_FROM_BE (size);
read_body (conn->fd, size, msg);
/* and read the body */
res = read_body (conn->fd, size, msg);
need_body = FALSE;
break;
} else {
gint offset = 0;
/* we have a regular response */
if (c != '\r') {
buffer[0] = c;
offset = 1;
@ -358,46 +458,54 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg)
if (c == '\n')
break;
read_line (conn->fd, buffer + offset, sizeof (buffer) - offset);
/* read lines */
res = read_line (conn->fd, buffer + offset, sizeof (buffer) - offset);
if (res != RTSP_OK)
goto read_error;
if (buffer[0] == '\0')
break;
if (line == 0) {
/* first line, check for response status */
if (g_str_has_prefix (buffer, "RTSP")) {
parse_response_status (buffer, msg);
res = parse_response_status (buffer, msg);
} else {
g_warning ("parsing request not implemented\n");
goto error;
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) {
/* parse body */
res = rtsp_message_get_header (msg, RTSP_HDR_CONTENT_LENGTH, &hdrval);
if (res == RTSP_OK) {
/* see if there is a Content-Length header */
if (rtsp_message_get_header (msg, RTSP_HDR_CONTENT_LENGTH,
&hdrval) == RTSP_OK) {
/* there is, read the body */
content_length = atol (hdrval);
read_body (conn->fd, content_length, msg);
res = read_body (conn->fd, content_length, msg);
}
/* save session id */
/* save session id in the connection for further use */
{
gchar *session_id;
if (rtsp_message_get_header (msg, RTSP_HDR_SESSION,
&session_id) == RTSP_OK) {
strncpy (conn->session_id, session_id, sizeof (conn->session_id) - 1);
conn->session_id[sizeof (conn->session_id) - 1] = '\0';
gint maxlen = sizeof (conn->session_id) - 1;
/* make sure to not overflow */
strncpy (conn->session_id, session_id, maxlen);
conn->session_id[maxlen] = '\0';
}
}
}
return RTSP_OK;
return res;
error:
{
@ -405,7 +513,6 @@ error:
}
read_error:
{
perror ("read");
return RTSP_ESYS;
}
}
@ -430,3 +537,12 @@ sys_error:
return RTSP_ESYS;
}
}
RTSPResult
rtsp_connection_free (RTSPConnection * conn)
{
if (conn == NULL)
return RTSP_EINVAL;
g_free (conn);
}

View file

@ -24,33 +24,30 @@
#include <rtspdefs.h>
#include <rtspurl.h>
#include <rtspstream.h>
#include <rtspmessage.h>
G_BEGIN_DECLS
typedef struct _RTSPConnection
{
gint fd;
gint fd; /* our socket */
gint cseq;
gchar session_id[512];
RTSPState state;
int num_streams;
RTSPStream **streams;
gint cseq; /* sequence number */
gchar session_id[512]; /* session id */
RTSPState state; /* state of the connection */
} RTSPConnection;
/* opening/closing a connection */
RTSPResult rtsp_connection_open (RTSPUrl *url, RTSPConnection **conn);
RTSPResult rtsp_connection_create (gint fd, RTSPConnection **conn);
RTSPResult rtsp_connection_close (RTSPConnection *conn);
RTSPResult rtsp_connection_free (RTSPConnection *conn);
/* sending/receiving messages */
RTSPResult rtsp_connection_send (RTSPConnection *conn, RTSPMessage *message);
RTSPResult rtsp_connection_receive (RTSPConnection *conn, RTSPMessage *message);
RTSPResult rtsp_connection_close (RTSPConnection *conn);
G_END_DECLS
#endif /* __RTSP_CONNECTION_H__ */

View file

@ -169,3 +169,16 @@ rtsp_find_header_field (gchar * header)
}
return -1;
}
RTSPMethod
rtsp_find_method (gchar * method)
{
gint idx;
for (idx = 0; rtsp_methods[idx]; idx++) {
if (g_ascii_strcasecmp (rtsp_headers[idx], method) == 0) {
return idx;
}
}
return -1;
}

View file

@ -167,7 +167,9 @@ const gchar* rtsp_method_as_text (RTSPMethod method);
const gchar* rtsp_header_as_text (RTSPHeaderField field);
const gchar* rtsp_status_as_text (RTSPStatusCode code);
const gchar* rtsp_status_to_string (RTSPStatusCode code);
RTSPHeaderField rtsp_find_header_field (gchar *header);
RTSPMethod rtsp_find_method (gchar *method);
G_END_DECLS

View file

@ -161,24 +161,16 @@ rtsp_message_get_header (RTSPMessage * msg, RTSPHeaderField field,
}
RTSPResult
rtsp_message_get_header_copy (RTSPMessage * msg, RTSPHeaderField field,
gchar ** value)
rtsp_message_set_body (RTSPMessage * msg, guint8 * data, guint size)
{
gchar *val;
if (msg == NULL || value == NULL)
if (msg == NULL)
return RTSP_EINVAL;
val = g_hash_table_lookup (msg->hdr_fields, GINT_TO_POINTER (field));
*value = g_strdup (val);
return RTSP_OK;
return rtsp_message_take_body (msg, g_memdup (data, size), size);
}
RTSPResult
rtsp_message_set_body (RTSPMessage * msg, guint8 * data, guint size)
rtsp_message_take_body (RTSPMessage * msg, guint8 * data, guint size)
{
if (msg == NULL)
return RTSP_EINVAL;
@ -192,13 +184,6 @@ rtsp_message_set_body (RTSPMessage * msg, guint8 * data, guint size)
return RTSP_OK;
}
RTSPResult
rtsp_message_set_body_copy (RTSPMessage * msg, guint8 * data, guint size)
{
return RTSP_ENOTIMPL;
}
RTSPResult
rtsp_message_get_body (RTSPMessage * msg, guint8 ** data, guint * size)
{
@ -211,18 +196,6 @@ rtsp_message_get_body (RTSPMessage * msg, guint8 ** data, guint * size)
return RTSP_OK;
}
RTSPResult
rtsp_message_get_body_copy (RTSPMessage * msg, guint8 ** data, guint * size)
{
if (msg == NULL || data == NULL || size == NULL)
return RTSP_EINVAL;
*data = g_memdup (msg->body, msg->body_size);
*size = msg->body_size;
return RTSP_OK;
}
static void
dump_mem (guint8 * mem, gint size)
{

View file

@ -73,13 +73,10 @@ RTSPResult rtsp_message_free (RTSPMessage *msg);
RTSPResult rtsp_message_add_header (RTSPMessage *msg, RTSPHeaderField field, gchar *value);
RTSPResult rtsp_message_remove_header (RTSPMessage *msg, RTSPHeaderField field);
RTSPResult rtsp_message_get_header (RTSPMessage *msg, RTSPHeaderField field, gchar **value);
RTSPResult rtsp_message_get_header_copy (RTSPMessage *msg, RTSPHeaderField field, gchar **value);
RTSPResult rtsp_message_set_body (RTSPMessage *msg, guint8 *data, guint size);
RTSPResult rtsp_message_set_body_copy (RTSPMessage *msg, guint8 *data, guint size);
RTSPResult rtsp_message_take_body (RTSPMessage *msg, guint8 *data, guint size);
RTSPResult rtsp_message_get_body (RTSPMessage *msg, guint8 **data, guint *size);
RTSPResult rtsp_message_get_body_copy (RTSPMessage *msg, guint8 **data, guint *size);
RTSPResult rtsp_message_dump (RTSPMessage *msg);

View file

@ -1,32 +0,0 @@
/* GStreamer
* Copyright (C) <2005> 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.
*/
#ifndef __RTSP_STREAM_H__
#define __RTSP_STREAM_H__
#include <rtspdefs.h>
G_BEGIN_DECLS
typedef struct _RTSPStream {
} RTSPStream;
G_END_DECLS
#endif /* __RTSP_STREAM_H__ */

View file

@ -462,7 +462,7 @@ sdp_parse_line (SDPContext * c, gchar type, guint8 * buffer)
switch (type) {
case 'v':
if (buffer[0] != '0')
g_print ("wrong SDP version\n");
g_warning ("wrong SDP version");
sdp_message_set_version (c->msg, buffer);
break;
case 'o':
@ -550,11 +550,9 @@ sdp_parse_line (SDPContext * c, gchar type, guint8 * buffer)
sdp_media_add_format (&nmedia, str);
} while (*p != '\0');
g_print ("%p\n", &nmedia);
sdp_message_add_media (c->msg, &nmedia);
c->media =
&g_array_index (c->msg->medias, SDPMedia, c->msg->medias->len - 1);
g_print ("%p\n", c->media);
break;
}
default: