* sap.c : SAP interface module
*****************************************************************************
* Copyright (C) 2001 VideoLAN
- * $Id: sap.c,v 1.36 2003/11/20 23:13:28 sigmunau Exp $
+ * $Id$
*
* Authors: Arnaud Schauly <gitan@via.ecp.fr>
* Clément Stenac <zorglub@via.ecp.fr>
#include <vlc/vlc.h>
#include <vlc/intf.h>
+#include <vlc/input.h>
#include <errno.h> /* ENOMEM */
#include <ctype.h>
/*****************************************************************************
* Module descriptor
*****************************************************************************/
-#define SAP_ADDR_TEXT N_("SAP multicast address")
-#define SAP_ADDR_LONGTEXT N_("SAP multicast address")
-#define SAP_IPV4_TEXT N_("IPv4-SAP listening")
-#define SAP_IPV4_LONGTEXT N_("Set this if you want SAP to listen for IPv4 announces")
-#define SAP_IPV6_TEXT N_("IPv6-SAP listening")
-#define SAP_IPV6_LONGTEXT N_("Set this if you want SAP to listen for IPv6 announces")
-#define SAP_SCOPE_TEXT N_("IPv6 SAP scope")
-#define SAP_SCOPE_LONGTEXT N_("Sets the scope for IPv6 announces (default is 8)")
+#define SAP_ADDR_TEXT N_( "SAP multicast address" )
+#define SAP_ADDR_LONGTEXT N_( "SAP multicast address" )
+#define SAP_IPV4_TEXT N_( "IPv4-SAP listening" )
+#define SAP_IPV4_LONGTEXT N_( \
+ "Set this if you want the SAP module to listen to IPv4 announces" )
+#define SAP_IPV6_TEXT N_( "IPv6-SAP listening" )
+#define SAP_IPV6_LONGTEXT N_( \
+ "Set this if you want the SAP module to listen to IPv6 announces" )
+#define SAP_SCOPE_TEXT N_( "IPv6 SAP scope" )
+#define SAP_SCOPE_LONGTEXT N_( \
+ "Sets the scope for IPv6 announces (default is 8)" )
+#define SAP_TIMEOUT_TEXT N_( "SAP timeout (seconds)" )
+#define SAP_TIMEOUT_LONGTEXT N_( \
+ "Sets the time before SAP items get deleted if no new announce " \
+ "is received." )
+#define SAP_PARSE_TEXT N_( "Try to parse the SAP" )
+#define SAP_PARSE_LONGTEXT N_( \
+ "When SAP can it will try to parse the SAP. Normal behavior is " \
+ "to have livedotcom parse the announce." )
static int Open ( vlc_object_t * );
static void Close( vlc_object_t * );
+static int OpenSDP ( vlc_object_t * );
+static void CloseSDP( vlc_object_t * );
vlc_module_begin();
- add_category_hint( N_("SAP"), NULL, VLC_TRUE );
- add_string( "sap-addr", NULL, NULL,
- SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, VLC_TRUE );
-
- add_bool( "sap-ipv4", 1 , NULL,
- SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, VLC_TRUE);
-
- add_bool( "sap-ipv6", 0 , NULL,
- SAP_IPV6_TEXT, SAP_IPV6_LONGTEXT, VLC_TRUE);
+ set_description( _("SAP interface") );
- add_string( "sap-ipv6-scope", "8" , NULL,
- SAP_SCOPE_TEXT, SAP_SCOPE_LONGTEXT, VLC_TRUE);
+ add_string( "sap-addr", NULL, NULL,
+ SAP_ADDR_TEXT, SAP_ADDR_LONGTEXT, VLC_TRUE );
+ add_bool( "sap-ipv4", 1 , NULL,
+ SAP_IPV4_TEXT,SAP_IPV4_LONGTEXT, VLC_TRUE );
+ add_bool( "sap-ipv6", 0 , NULL,
+ SAP_IPV6_TEXT, SAP_IPV6_LONGTEXT, VLC_TRUE );
+ add_string( "sap-ipv6-scope", "8" , NULL,
+ SAP_SCOPE_TEXT, SAP_SCOPE_LONGTEXT, VLC_TRUE);
+ add_integer( "sap-timeout", 1800, NULL,
+ SAP_TIMEOUT_TEXT, SAP_TIMEOUT_LONGTEXT, VLC_TRUE );
+ add_bool( "sap-parse", 1 , NULL,
+ SAP_PARSE_TEXT,SAP_PARSE_LONGTEXT, VLC_TRUE );
- set_description( _("SAP interface") );
set_capability( "interface", 0 );
set_callbacks( Open, Close );
+
+ add_submodule();
+ /* TODO FIXME
+ * This submodule is temporary and has a very high duplicate code rate
+ * This needs to be removed when SDP UDP parsing is fixed in liveMedia
+ */
+ set_description( _("SDP file parser (UDP only)") );
+ add_shortcut( "sdp" );
+ set_capability( "demux2", 51 );
+ set_callbacks( OpenSDP, CloseSDP );
+
vlc_module_end();
/*****************************************************************************
static void Run ( intf_thread_t *p_intf );
static ssize_t NetRead( intf_thread_t *, int fd[2], uint8_t *, int );
+static int Demux( demux_t *p_demux );
+static int Control( demux_t *, int, va_list );
+
typedef struct media_descr_t media_descr_t;
typedef struct sess_descr_t sess_descr_t;
typedef struct attr_descr_t attr_descr_t;
static void sess_toitem( intf_thread_t *, sess_descr_t * );
-static sess_descr_t * parse_sdp( intf_thread_t *, char * ) ;
+static sess_descr_t * parse_sdp( vlc_object_t *, char * ) ;
static void free_sd( sess_descr_t * );
/* Detect multicast addresses */
static int ismult( char * );
-/* The struct that contains sdp informations */
+/* The struct that contains sdp information */
struct sess_descr_t
{
int i_version;
attr_descr_t **pp_attributes;
};
-/* All this informations are not useful yet. */
+/* All this information is not useful yet. */
struct media_descr_t
{
char *psz_medianame;
char *psz_value;
};
+struct sap_announce_t
+{
+ mtime_t i_last;
+ int i_id;
+ char *psz_name;
+ char *psz_uri;
+};
+
struct intf_sys_t
{
/* IPV4 and IPV6 */
/* playlist group */
int i_group;
+
+ /* Table of announces */
+ int i_announces;
+ struct sap_announce_t **pp_announces;
+
+ int i_timeout;
};
#ifdef HAVE_ZLIB_H
-int do_decompress(unsigned char *src, unsigned char **_dst, int slen) {
- int result, dstsize, n;
- unsigned char *dst;
- z_stream d_stream;
-
- d_stream.zalloc = (alloc_func)0;
- d_stream.zfree = (free_func)0;
- d_stream.opaque = (voidpf)0;
- result = inflateInit(&d_stream);
- if (result != Z_OK) {
- printf("inflateInit() failed. Result: %d\n", result);
- return(-1);
- }
-
- d_stream.next_in = (Bytef *)src;
- d_stream.avail_in = slen;
- n = 0;
- dst = NULL;
- do {
- n++;
- dst = (unsigned char *)realloc(dst, n * 1000);
- d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
- d_stream.avail_out = 1000;
- result = inflate(&d_stream, Z_NO_FLUSH);
- if ((result != Z_OK) && (result != Z_STREAM_END)) {
- printf("Zlib decompression failed. Result: %d\n", result);
- return(-1);
+int do_decompress( unsigned char *src, unsigned char **_dst, int slen ) {
+ int result, dstsize, n;
+ unsigned char *dst;
+ z_stream d_stream;
+
+ d_stream.zalloc = (alloc_func)0;
+ d_stream.zfree = (free_func)0;
+ d_stream.opaque = (voidpf)0;
+ result = inflateInit(&d_stream);
+ if( result != Z_OK )
+ {
+ printf( "inflateInit() failed. Result: %d\n", result );
+ return( -1 );
}
- } while ((d_stream.avail_out == 0) && (d_stream.avail_in != 0) &&
- (result != Z_STREAM_END));
- dstsize = d_stream.total_out;
- inflateEnd(&d_stream);
+ d_stream.next_in = (Bytef *)src;
+ d_stream.avail_in = slen;
+ n = 0;
+ dst = NULL;
+ do
+ {
+ n++;
+ dst = (unsigned char *)realloc(dst, n * 1000);
+ d_stream.next_out = (Bytef *)&dst[(n - 1) * 1000];
+ d_stream.avail_out = 1000;
+ result = inflate(&d_stream, Z_NO_FLUSH);
+ if( ( result != Z_OK ) && ( result != Z_STREAM_END ) )
+ {
+ printf( "Zlib decompression failed. Result: %d\n", result );
+ return( -1 );
+ }
+ }
+ while( ( d_stream.avail_out == 0 ) && ( d_stream.avail_in != 0 ) &&
+ ( result != Z_STREAM_END ) );
+
+ dstsize = d_stream.total_out;
+ inflateEnd( &d_stream );
- *_dst = (unsigned char *)realloc(dst, dstsize);
+ *_dst = (unsigned char *)realloc( dst, dstsize );
- return dstsize;
+ return dstsize;
}
#endif
*****************************************************************************/
static int Open( vlc_object_t *p_this )
{
- intf_thread_t *p_intf = (intf_thread_t*)p_this;
+ intf_thread_t *p_intf = ( intf_thread_t* )p_this;
intf_sys_t *p_sys = malloc( sizeof( intf_sys_t ) );
playlist_t *p_playlist;
+ p_sys->i_timeout = config_GetInt( p_intf,"sap-timeout" );
p_sys->fd[0] = -1;
p_sys->fd[1] = -1;
if( config_GetInt( p_intf, "sap-ipv4" ) )
sock.psz_server_addr = "";
sock.i_server_port = 0;
sock.i_ttl = 0;
- p_intf->p_private = (void*) &sock;
+ p_intf->p_private = ( void* ) &sock;
- p_network = module_Need( p_intf, "network", "ipv4" );
+ p_network = module_Need( p_intf, "network", "ipv4", VLC_TRUE );
if( p_network )
{
p_sys->fd[0] = sock.i_handle;
{
psz_scope = strdup( "8" );
}
- snprintf( psz_address, 100, "[%s%c%s]",IPV6_ADDR_1, psz_scope[0], IPV6_ADDR_2 );
+ snprintf( psz_address, 100, "[%s%c%s]",IPV6_ADDR_1,
+ psz_scope[0], IPV6_ADDR_2 );
free( psz_scope );
sock.i_type = NETWORK_UDP;
sock.i_ttl = 0;
p_intf->p_private = (void*) &sock;
- p_network = module_Need( p_intf, "network", "ipv6" );
+ p_network = module_Need( p_intf, "network", "ipv6", VLC_TRUE );
if( p_network )
{
p_sys->fd[1] = sock.i_handle;
vlc_object_release( p_playlist );
}
+ p_sys->i_announces = 0;
+ p_sys->pp_announces = NULL;
+
p_intf->pf_run = Run;
p_intf->p_sys = p_sys;
*****************************************************************************/
static void Close( vlc_object_t *p_this )
{
- intf_thread_t *p_intf = (intf_thread_t*)p_this;
+ intf_thread_t *p_intf = ( intf_thread_t* )p_this;
intf_sys_t *p_sys = p_intf->p_sys;
+ int i;
if( p_sys->fd[0] > 0 )
{
close( p_sys->fd[1] );
}
+ for( i = 0 ; i< p_sys->i_announces ; i++ )
+ {
+ if( p_sys->pp_announces[i]->psz_name )
+ free( p_sys->pp_announces[i]->psz_name );
+ if( p_sys->pp_announces[i]->psz_uri )
+ free( p_sys->pp_announces[i]->psz_uri );
+ free( p_sys->pp_announces[i] );
+ }
+ free( p_sys->pp_announces );
+
free( p_sys );
}
intf_sys_t *p_sys = p_intf->p_sys;
uint8_t buffer[MAX_SAP_BUFFER + 1];
uint8_t *p_end;
+
+ /* Dirty hack to slow down the startup of the sap interface */
+ msleep( 500000 );
/* read SAP packets */
while( !p_intf->b_die )
{
+ playlist_t *p_playlist= NULL;
+ int i;
int i_read = NetRead( p_intf, p_sys->fd, buffer, MAX_SAP_BUFFER );
uint8_t *p_sdp;
int i_version;
int b_message_type;
int b_encrypted;
int b_compressed;
- int i_mesg_id_hash;
unsigned char *p_decompressed_buffer;
int i_decompressed_size;
-
+
+ /* Check for items that need deletion */
+ for( i = 0 ; i< p_intf->p_sys->i_announces ; i++ )
+ {
+ struct sap_announce_t *p_announce;
+ mtime_t i_timeout = ( mtime_t ) 1000000*p_sys->i_timeout;
+ if( mdate() - p_intf->p_sys->pp_announces[i]->i_last > i_timeout )
+ {
+ msg_Dbg( p_intf,"Time out for %s, deleting (%i/%i)",
+ p_intf->p_sys->pp_announces[i]->psz_name,
+ i , p_intf->p_sys->i_announces );
+
+ /* Remove the playlist item */
+ p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+ FIND_ANYWHERE );
+ if( p_playlist )
+ {
+ int i_pos = playlist_GetPositionById( p_playlist,
+ p_intf->p_sys->pp_announces[i]->i_id );
+ playlist_Delete( p_playlist, i_pos );
+ }
+
+ vlc_object_release( p_playlist );
+
+ /* Free the p_announce */
+ p_announce = p_intf->p_sys->pp_announces[i];
+ if( p_announce->psz_name )
+ free( p_announce->psz_name );
+ if( p_announce->psz_uri )
+ free( p_announce->psz_uri );
+
+ /* Remove the sap_announce from the array */
+ REMOVE_ELEM( p_intf->p_sys->pp_announces,
+ p_intf->p_sys->i_announces,
+ i );
+
+ free( p_announce );
+
+ }
+ }
+
/* Minimum length is > 6 */
if( i_read <= 6 )
{
i_version = buffer[0] >> 5;
if( i_version != 1 )
{
- msg_Warn( p_intf, "strange sap version %d found", i_version );
+ msg_Dbg( p_intf, "strange sap version %d found", i_version );
}
i_address_type = buffer[0] & 0x10;
b_reserved = buffer[0] & 0x08;
if( b_reserved != 0 )
{
- msg_Warn( p_intf, "reserved bit incorrectly set" );
+ msg_Dbg( p_intf, "reserved bit incorrectly set" );
}
b_message_type = buffer[0] & 0x04;
if( b_message_type != 0 )
{
- msg_Warn( p_intf, "got session deletion packet" );
+ msg_Dbg( p_intf, "got session deletion packet" );
}
b_encrypted = buffer[0] & 0x02;
if( b_encrypted )
{
- msg_Warn( p_intf, "encrypted packet" );
+ msg_Dbg( p_intf, "encrypted packet" );
}
b_compressed = buffer[0] & 0x01;
p_sdp = &buffer[4];
if( b_compressed )
{
#ifdef HAVE_ZLIB_H
- i_decompressed_size = do_decompress( p_sdp, &p_decompressed_buffer, i_read - ( p_sdp - buffer ) );
- if( i_decompressed_size > 0 )
+ i_decompressed_size = do_decompress( p_sdp, &p_decompressed_buffer,
+ i_read - ( p_sdp - buffer ) );
+ if( i_decompressed_size > 0 && i_decompressed_size < MAX_SAP_BUFFER )
{
memcpy( p_sdp, p_decompressed_buffer, i_decompressed_size );
p_sdp[i_decompressed_size] = '\0';
if( p_sdp < p_end )
{
- sess_descr_t *p_sd = parse_sdp( p_intf, p_sdp );
+ sess_descr_t *p_sd = parse_sdp( (vlc_object_t *)p_intf, p_sdp );
if( p_sd )
{
sess_toitem ( p_intf, p_sd );
{
msg_Warn( p_intf, "ditching sap packet" );
}
+
+ memset( buffer, 0, MAX_SAP_BUFFER );
}
}
static void cfield_parse( char *psz_cfield, char **ppsz_uri )
{
-
char *psz_pos;
if( psz_cfield )
{
}
return;
-
}
/**********************************************************************
static void sess_toitem( intf_thread_t * p_intf, sess_descr_t * p_sd )
{
- playlist_item_t * p_item;
- char *psz_uri, *psz_proto;
+ struct sap_announce_t *p_announce;
+ char *psz_uri, *psz_proto, *psz_item_uri;
char *psz_port;
char *psz_uri_default;
- int i_count , i;
+ int i_count, i, i_id = 0;
vlc_bool_t b_http = VLC_FALSE;
char *psz_http_path = NULL;
playlist_t *p_playlist = NULL;
+ playlist_item_t *p_item;
psz_uri_default = NULL;
- if( p_sd->i_media > 1 )
+ if( p_sd->i_media > 1 || !config_GetInt( p_intf, "sap-parse" ) )
{
- p_item = malloc( sizeof( playlist_item_t ) );
- if( p_item == NULL )
+ asprintf( &psz_uri, "sdp://%s", p_sd->psz_sdp );
+ /* Check if we have already added the item */
+ for( i = 0 ; i< p_intf->p_sys->i_announces ; i++ )
{
- msg_Warn( p_intf, "out of memory" );
- return;
+ if( !strcmp( p_intf->p_sys->pp_announces[i]->psz_uri,
+ psz_uri ) )
+ {
+ p_intf->p_sys->pp_announces[i]->i_last = mdate();
+ free( psz_uri );
+ return;
+ }
}
- p_item->psz_name = strdup( p_sd->psz_sessionname );
- p_item->psz_uri = NULL;
- p_item->i_duration = -1;
- p_item->ppsz_options= NULL;
- p_item->i_options = 0;
-
- p_item->i_type = 0;
- p_item->i_status = 0;
- p_item->b_autodeletion = VLC_FALSE;
- p_item->b_enabled = VLC_TRUE;
- p_item->i_group = p_intf->p_sys->i_group;
- p_item->psz_author = strdup( "" );
- psz_uri = malloc( strlen( p_sd->psz_sdp ) + 7 );
- if( psz_uri == NULL )
+ /* Add it to the playlist */
+ p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+ FIND_ANYWHERE );
+ i_id = playlist_Add( p_playlist, psz_uri, p_sd->psz_sessionname ,
+ PLAYLIST_CHECK_INSERT, PLAYLIST_END );
+ if( i_id != -1 )
{
- msg_Warn( p_intf, "out of memory" );
- free( p_item->psz_name );
- free( p_item->psz_author );
- free( p_item );
- return;
+ playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_id );
+ playlist_ItemSetGroup( p_item, p_intf->p_sys->i_group );
+ }
+
+ /* Remember it */
+ p_announce = ( struct sap_announce_t * )malloc(
+ sizeof( struct sap_announce_t ) );
+ if( p_sd->psz_sessionname )
+ {
+ p_announce->psz_name = strdup( p_sd->psz_sessionname );
+ }
+ else
+ {
+ p_announce->psz_name = strdup( "" );
+ }
+ if( psz_uri )
+ {
+ p_announce->psz_uri = strdup( psz_uri );
}
- p_item->psz_uri = psz_uri;
- memcpy( psz_uri, "sdp://", 6 );
- psz_uri += 6;
- memcpy( psz_uri, p_sd->psz_sdp, strlen( p_sd->psz_sdp ) + 1 );
- /* Enqueueing p_item in the playlist */
- p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
- playlist_AddItem ( p_playlist, p_item, PLAYLIST_CHECK_INSERT, PLAYLIST_END );
+ else
+ {
+ p_announce->psz_uri = strdup( "" );
+ }
+ p_announce->i_id = i_id;
+ p_announce->i_last = mdate();
+
+ INSERT_ELEM( p_intf->p_sys->pp_announces,
+ p_intf->p_sys->i_announces,
+ p_intf->p_sys->i_announces,
+ p_announce );
+
vlc_object_release( p_playlist );
+ free( psz_uri );
return;
- }
-
+ }
+
cfield_parse( p_sd->psz_connection, &psz_uri_default );
for( i_count = 0 ; i_count < p_sd->i_media ; i_count++ )
{
- p_item = malloc( sizeof( playlist_item_t ) );
- p_item->psz_name = strdup( p_sd->psz_sessionname );
- p_item->psz_uri = NULL;
- p_item->i_duration = -1;
- p_item->ppsz_options= NULL;
- p_item->i_options = 0;
-
- p_item->i_type = 0;
- p_item->i_status = 0;
- p_item->b_autodeletion = VLC_FALSE;
- p_item->b_enabled = VLC_TRUE;
- p_item->i_group = p_intf->p_sys->i_group;
- p_item->psz_author = strdup( "" );
-
- psz_uri = NULL;
+ int i_group = p_intf->p_sys->i_group;
+ int i_packetsize = config_GetInt( p_intf, "mtu" );
- /* Build what we have to put in p_item->psz_uri, with the m and
- * c fields */
+ /* Build what we have to put in psz_item_uri, with the m and
+ * c fields */
if( !p_sd->pp_media[i_count] )
{
for( i = 0 ; i< p_sd->i_attributes ; i++ )
{
- if(!strcasecmp( p_sd->pp_attributes[i]->psz_field , "type") &&
- strstr( p_sd->pp_attributes[i]->psz_value, "http") )
+ if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "type" ) &&
+ strstr( p_sd->pp_attributes[i]->psz_value, "http" ) )
{
b_http = VLC_TRUE;
}
- if(!strcasecmp( p_sd->pp_attributes[i]->psz_field , "http-path"))
+ if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "http-path" ) )
{
psz_http_path = strdup( p_sd->pp_attributes[i]->psz_value );
}
- if(!strcasecmp( p_sd->pp_attributes[i]->psz_field , "plgroup"))
+ if( ( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "plgroup" ) ) ||
+ ( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "x-plgroup" ) ) )
{
- int i_id;
+ int i_group_id;
p_playlist =
(playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
return;
}
- i_id = playlist_GroupToId( p_playlist,
- p_sd->pp_attributes[i]->psz_value);
- if( i_id != 0 )
+ i_group_id = playlist_GroupToId( p_playlist,
+ p_sd->pp_attributes[i]->psz_value );
+ if( i_group_id != 0 )
{
- p_item->i_group = i_id;
+ i_group = i_group_id;
}
else
{
playlist_group_t *p_group =
playlist_CreateGroup( p_playlist,
- p_sd->pp_attributes[i]->psz_value);
- p_item->i_group = p_group->i_id;
+ p_sd->pp_attributes[i]->psz_value );
+ i_group = p_group->i_id;
}
vlc_object_release( p_playlist );
}
+ if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "packetsize" ) )
+ {
+ i_packetsize = strtol( p_sd->pp_attributes[i]->psz_value, NULL, 10 );
+ }
}
-
- /* Filling p_item->psz_uri */
+ /* Filling psz_uri */
if( b_http == VLC_FALSE )
{
- p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
- strlen( psz_port ) + 7 );
if( ismult( psz_uri ) )
{
- sprintf( p_item->psz_uri, "%s://@%s:%s",
+ asprintf( &psz_item_uri, "%s://@%s:%s",
psz_proto, psz_uri, psz_port );
}
else
{
- sprintf( p_item->psz_uri, "%s://%s:%s",
+ asprintf( &psz_item_uri, "%s://%s:%s",
psz_proto, psz_uri, psz_port );
}
}
{
psz_http_path = strdup( "/" );
}
-
- p_item->psz_uri = malloc( strlen( psz_proto ) + strlen( psz_uri ) +
- strlen( psz_port ) + strlen(psz_http_path) + 5 );
- sprintf( p_item->psz_uri, "%s://%s:%s%s", psz_proto,
- psz_uri, psz_port,psz_http_path );
+ if( *psz_http_path == '/' )
+ {
+ asprintf( &psz_item_uri, "%s://%s:%s%s", psz_proto,
+ psz_uri, psz_port,psz_http_path );
+ }
+ else
+ {
+ asprintf( &psz_item_uri, "%s://%s:%s/%s", psz_proto, psz_uri,
+ psz_port, psz_http_path );
+ }
if( psz_http_path )
{
}
}
- /* Enqueueing p_item in the playlist */
- p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
- playlist_AddItem ( p_playlist, p_item, PLAYLIST_CHECK_INSERT, PLAYLIST_END );
+ /* Check if we already know this item */
+ for( i = 0 ; i< p_intf->p_sys->i_announces ; i++ )
+ {
+ if( !strcmp( p_intf->p_sys->pp_announces[i]->psz_uri,
+ psz_item_uri ) )
+ {
+ p_intf->p_sys->pp_announces[i]->i_last = mdate();
+
+ /* Check if the name changed */
+ if( strcmp( p_intf->p_sys->pp_announces[i]->psz_name,
+ p_sd->psz_sessionname ) )
+ {
+ playlist_item_t *p_item;
+ p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+ FIND_ANYWHERE );
+
+ msg_Dbg(p_intf, "Name changed (%s -> %s) for %s",
+ p_intf->p_sys->pp_announces[i]->psz_name,
+ p_sd->psz_sessionname,
+ psz_item_uri );
+
+ p_item = playlist_ItemGetById( p_playlist,
+ p_intf->p_sys->pp_announces[i]->i_id );
+
+ /* Change the name in the item */
+ if( p_item )
+ {
+ vlc_mutex_lock( &p_item->input.lock );
+ if( p_item->input.psz_name )
+ free( p_item->input.psz_name );
+ p_item->input.psz_name = strdup( p_sd->psz_sessionname );
+ vlc_mutex_unlock( &p_item->input.lock );
+ }
+
+ /* Update the stored name */
+ if( p_intf->p_sys->pp_announces[i]->psz_name )
+ free( p_intf->p_sys->pp_announces[i]->psz_name );
+ p_intf->p_sys->pp_announces[i]->psz_name =
+ strdup( p_sd->psz_sessionname );
+
+ vlc_object_release( p_playlist );
+ }
+ free( psz_item_uri );
+ return;
+ }
+ }
+
+ /* Add the item in the playlist */
+ p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
+ FIND_ANYWHERE );
+
+ p_item = playlist_ItemNew( p_intf, psz_item_uri, p_sd->psz_sessionname );
+
+ if( p_item )
+ {
+ playlist_ItemSetGroup( p_item, i_group );
+ if( i_packetsize > config_GetInt( p_intf, "mtu" ) )
+ {
+ char *psz_packetsize_option;
+ asprintf( &psz_packetsize_option, "mtu=%i", i_packetsize );
+ playlist_ItemAddOption( p_item, psz_packetsize_option );
+ free( psz_packetsize_option );
+ }
+ playlist_AddItem( p_playlist , p_item , PLAYLIST_CHECK_INSERT, PLAYLIST_END );
+ }
+
+ /* Then remember it */
+ p_announce = (struct sap_announce_t *)malloc(
+ sizeof( struct sap_announce_t ) );
+ if( p_sd->psz_sessionname )
+ {
+ p_announce->psz_name = strdup( p_sd->psz_sessionname );
+ }
+ else
+ {
+ p_announce->psz_name = strdup( "" );
+ }
+ if( psz_item_uri )
+ {
+ p_announce->psz_uri = strdup( psz_item_uri );
+ }
+ else
+ {
+ p_announce->psz_uri = strdup( "" );
+ }
+ p_announce->i_id = i_id;
+
+ p_announce->i_last = mdate();
+
vlc_object_release( p_playlist );
+
+ INSERT_ELEM( p_intf->p_sys->pp_announces,
+ p_intf->p_sys->i_announces,
+ p_intf->p_sys->i_announces,
+ p_announce );
+ free( psz_item_uri );
}
}
* Make a sess_descr_t with a psz
***********************************************************************/
-static sess_descr_t * parse_sdp( intf_thread_t * p_intf, char *p_packet )
+static sess_descr_t * parse_sdp( vlc_object_t * p_parent, char *p_packet )
{
sess_descr_t * sd;
if( p_packet[0] != 'v' || p_packet[1] != '=' )
{
- msg_Warn(p_intf, "bad SDP packet");
+ msg_Warn( p_parent, "bad SDP packet" );
return NULL;
}
sd->psz_sessionname = NULL;
sd->psz_connection = NULL;
sd->psz_sdp = strdup( p_packet );
-
+
sd->i_media = 0;
sd->pp_media = NULL;
sd->i_attributes = 0;
{
psz_end = p_packet + strlen( p_packet );
}
- if( psz_end > p_packet && *(psz_end - 1 ) == '\r' )
+ if( psz_end > p_packet && *( psz_end - 1 ) == '\r' )
{
psz_end--;
}
if( p_packet[1] != '=' )
{
- msg_Warn( p_intf, "packet invalid" );
+ msg_Warn( p_parent, "invalid packet" ) ;
free_sd( sd );
return NULL;
}
FREE( p_sd->psz_sessionname );
FREE( p_sd->psz_connection );
+ FREE( p_sd->psz_sdp );
for( i = 0; i < p_sd->i_media ; i++ )
{
FREE( p_sd->pp_media[i]->psz_medianame );
FREE( p_sd->pp_media[i]->psz_mediaconnection );
+ FREE( p_sd->pp_media[i] );
}
for( i = 0; i < p_sd->i_attributes ; i++ )
{
FREE( p_sd->pp_attributes[i]->psz_field );
FREE( p_sd->pp_attributes[i]->psz_value );
+ FREE( p_sd->pp_attributes[i] );
}
FREE( p_sd->pp_attributes );
FREE( p_sd->pp_media );
/***********************************************************************
* ismult: returns true if we have a multicast address
***********************************************************************/
-
static int ismult( char *psz_uri )
{
char *psz_end;
return( i_value < 224 ? VLC_FALSE : VLC_TRUE );
}
-
-
/*****************************************************************************
- * Read: read on a file descriptor, checking b_die periodically
+ * NetRead: read on a file descriptor, checking b_die periodically
*****************************************************************************
- * Taken from udp.c
+ * Taken from net.c
+ * Code duplication because of select(). We need a net_Select() but that's
+ * quite difficult.
*****************************************************************************/
static ssize_t NetRead( intf_thread_t *p_intf,
int fd[2], uint8_t *p_buffer, int i_len )
int i_handle_max = __MAX( fd[0], fd[1] );
/* Initialize file descriptor set */
+
FD_ZERO( &fds );
if( fd[0] > 0 ) FD_SET( fd[0], &fds );
if( fd[1] > 0 ) FD_SET( fd[1], &fds );
return 0;
#endif
}
+
+/*
+ * This submodule is temporary and has a very high duplicate code rate
+ * This needs to be removed when SDP UDP parsing is fixed in liveMedia
+ */
+static int OpenSDP( vlc_object_t * p_this )
+{
+ demux_t *p_demux = (demux_t *)p_this;
+ uint8_t *p_peek;
+
+ if( p_demux->s )
+ {
+ /* See if it looks like a SDP
+ v, o, s fields are mandatory and in this order */
+ if( stream_Peek( p_demux->s, &p_peek, 7 ) < 7 )
+ {
+ msg_Err( p_demux, "cannot peek" );
+ return VLC_EGENERIC;
+ }
+ if( strncmp( (char*)p_peek, "v=0\r\n", 5 ) && strncmp( (char*)p_peek, "v=0\n", 4 ) &&
+ ( p_peek[0] < 'a' || p_peek[0] > 'z' || p_peek[1] != '=' ) )
+ {
+ msg_Warn( p_demux, "SDP (UDP) module discarded" );
+ return VLC_EGENERIC;
+ }
+ }
+
+ p_demux->pf_control = Control;
+ p_demux->pf_demux = Demux;
+
+ return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * Demux: reads and demuxes data packets
+ * This submodule is temporary and has a very high duplicate code rate
+ * This needs to be removed when SDP UDP parsing is fixed in liveMedia
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int Demux( demux_t *p_demux )
+{
+ sess_descr_t *p_sd = NULL;
+ playlist_t *p_playlist = NULL;
+ int i_sdp = 0;
+ int i_sdp_max = 1000;
+ int i_position = -1;
+ char *p_sdp = (uint8_t*)malloc( i_sdp_max );
+
+ p_playlist = vlc_object_find( p_demux, VLC_OBJECT_PLAYLIST,
+ FIND_ANYWHERE );
+
+ if( !p_playlist )
+ {
+ msg_Err( p_demux, "can't find playlist" );
+ return -1;
+ }
+
+ p_playlist->pp_items[p_playlist->i_index]->b_autodeletion = VLC_TRUE;
+ i_position = p_playlist->i_index + 1;
+
+ /* Gather the complete sdp file */
+ for( ;; )
+ {
+ int i_read = stream_Read( p_demux->s, &p_sdp[i_sdp], i_sdp_max - i_sdp - 1 );
+
+ if( i_read < 0 )
+ {
+ msg_Err( p_demux, "failed to read SDP" );
+ return VLC_EGENERIC;
+ }
+
+ i_sdp += i_read;
+
+ if( i_read < i_sdp_max - i_sdp - 1 )
+ {
+ p_sdp[i_sdp] = '\0';
+ break;
+ }
+
+ i_sdp_max += 1000;
+ p_sdp = (uint8_t*)realloc( p_sdp, i_sdp_max );
+ }
+
+ msg_Dbg( p_demux, "sdp=%s\n", p_sdp );
+
+ p_sd = parse_sdp( (vlc_object_t *)p_demux, p_sdp );
+ if( p_sd )
+ {
+ char *psz_uri, *psz_proto, *psz_item_uri;
+ char *psz_port;
+ char *psz_uri_default;
+ int i_count, i, i_id = 0;
+ vlc_bool_t b_http = VLC_FALSE;
+ char *psz_http_path = NULL;
+ playlist_item_t *p_item;
+ psz_uri_default = NULL;
+
+ if( p_sd->i_media > 1 || !config_GetInt( p_demux, "sap-parse" ) )
+ {
+ /* Let another module try this */
+ asprintf( &psz_uri, "sdp://%s", p_sd->psz_sdp );
+ i_id = playlist_Add( p_playlist, psz_uri, p_sd->psz_sessionname ,
+ PLAYLIST_CHECK_INSERT, i_position );
+ free( psz_uri );
+ return 0;
+ }
+
+ /* We try to parse it ourselves */
+ cfield_parse( p_sd->psz_connection, &psz_uri_default );
+
+ for( i_count = 0 ; i_count < p_sd->i_media ; i_count++ )
+ {
+ int i_group = 0;
+ int i_packetsize = config_GetInt( p_demux, "mtu" );
+
+ /* Build what we have to put in psz_item_uri, with the m and
+ * c fields */
+
+ if( !p_sd->pp_media[i_count] )
+ {
+ return -1;
+ }
+
+ mfield_parse( p_sd->pp_media[i_count]->psz_medianame,
+ &psz_proto, &psz_port );
+
+ if( !psz_proto || !psz_port )
+ {
+ return -1;
+ }
+
+ if( p_sd->pp_media[i_count]->psz_mediaconnection )
+ {
+ cfield_parse( p_sd->pp_media[i_count]->psz_mediaconnection,
+ & psz_uri );
+ }
+ else
+ {
+ psz_uri = psz_uri_default;
+ }
+
+ if( psz_uri == NULL )
+ {
+ return -1;
+ }
+
+ for( i = 0 ; i< p_sd->i_attributes ; i++ )
+ {
+ if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "type" ) &&
+ strstr( p_sd->pp_attributes[i]->psz_value, "http" ) )
+ {
+ b_http = VLC_TRUE;
+ }
+ if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "http-path" ) )
+ {
+ psz_http_path = strdup( p_sd->pp_attributes[i]->psz_value );
+ }
+ if( ( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "plgroup" ) ) ||
+ ( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "x-plgroup" ) ) )
+ {
+ int i_group_id;
+
+ i_group_id = playlist_GroupToId( p_playlist,
+ p_sd->pp_attributes[i]->psz_value );
+ if( i_group_id != 0 )
+ {
+ i_group = i_group_id;
+ }
+ else
+ {
+ playlist_group_t *p_group =
+ playlist_CreateGroup( p_playlist,
+ p_sd->pp_attributes[i]->psz_value );
+ i_group = p_group->i_id;
+ }
+ }
+ if( !strcasecmp( p_sd->pp_attributes[i]->psz_field , "packetsize" ) )
+ {
+ i_packetsize = strtol( p_sd->pp_attributes[i]->psz_value, NULL, 10 );
+ }
+ }
+
+ /* Filling psz_uri */
+ if( b_http == VLC_FALSE )
+ {
+ if( ismult( psz_uri ) )
+ {
+ asprintf( &psz_item_uri, "%s://@%s:%s",
+ psz_proto, psz_uri, psz_port );
+ }
+ else
+ {
+ asprintf( &psz_item_uri, "%s://%s:%s",
+ psz_proto, psz_uri, psz_port );
+ }
+ }
+ else
+ {
+ if( psz_http_path == NULL )
+ {
+ psz_http_path = strdup( "/" );
+ }
+ if( *psz_http_path == '/' )
+ {
+ asprintf( &psz_item_uri, "%s://%s:%s%s", psz_proto,
+ psz_uri, psz_port,psz_http_path );
+ }
+ else
+ {
+ asprintf( &psz_item_uri, "%s://%s:%s/%s", psz_proto, psz_uri,
+ psz_port, psz_http_path );
+ }
+
+ if( psz_http_path )
+ {
+ free( psz_http_path );
+ }
+ }
+
+ /* Add the item in the playlist */
+ p_item = playlist_ItemNew( p_demux, psz_item_uri, p_sd->psz_sessionname );
+
+ if( p_item )
+ {
+ playlist_ItemSetGroup( p_item, i_group );
+ if( i_packetsize > config_GetInt( p_demux, "mtu" ) )
+ {
+ char *psz_packetsize_option;
+ asprintf( &psz_packetsize_option, "mtu=%i", i_packetsize );
+ playlist_ItemAddOption( p_item, psz_packetsize_option );
+ free( psz_packetsize_option );
+ }
+ playlist_AddItem( p_playlist , p_item , PLAYLIST_CHECK_INSERT, i_position );
+ }
+
+ free( psz_item_uri );
+ }
+
+ free_sd ( p_sd );
+ }
+ vlc_object_release( p_playlist );
+ return 0;
+}
+
+static int Control( demux_t *p_demux, int i_query, va_list args )
+{
+ return VLC_EGENERIC;
+}
+
+static void CloseSDP( vlc_object_t *p_this )
+{
+}