Commit fab59c05 authored by Clément Stenac's avatar Clément Stenac

* ALL: Better announce system

  - The SAP handler now runs in a separate thread.
  - RTP sessions can be announced with sap (sdp=sap://,name=...)
	TODO: Make this more configurable
  - Better SDP generation (the timestamp problem is not resolved)
	About this, there is a problem : as, for a RTP session, the URI
        is the complete SDP, if the session is recreated, as the URI has 
        changed, a new item is added to the playlist
  - Experimental flow control algorithm :
       It does not follow the "Recommended" implementation, as it needs
       to count the sessions (to achieve this, we should make this work
       together with the SAP listener)
       It is disabled by default (use --sap-flow-control to enable).
       When it is disabled, sap announcement interval is set by --sap-interval

* src/misc/net.c : created net_ReadNonBlock
* sap.c : Fixed memory problem


parent 60c63d39
......@@ -348,6 +348,8 @@ SOURCES_libvlc_common = \
src/audio_output/output.c \
src/audio_output/intf.c \
src/stream_output/stream_output.c \
src/stream_output/announce.c \
src/stream_output/sap.c \
src/misc/charset.c \
src/misc/httpd.c \
src/misc/mtime.c \
......
$Id: NEWS,v 1.86 2004/03/02 23:49:38 hartman Exp $
$Id$
Changes between 0.7.1 and 0.7.2:
--------------------------------
Core support:
* Bookmarks feature
* Support for video output embedded in interfaces
Codecs:
Playlist:
Input:
Stream output:
* Improved session announcement system
Interfaces:
* Skins
- Ability to embed video output
* wxWindows
- new design and set of icons
- new streaming wizard
- Ability to embed video output
Changes between 0.7.1 and 0.7.1a:
---------------------------------
......
......@@ -2,7 +2,7 @@
* network.h: interface to communicate with network plug-ins
*****************************************************************************
* Copyright (C) 2002 VideoLAN
* $Id: network.h,v 1.10 2004/01/21 10:22:31 fenrir Exp $
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Laurent Aimar <fenrir@via.ecp.fr>
......@@ -173,6 +173,9 @@ VLC_EXPORT( void, net_Close, ( int fd ) );
#define net_Read(a,b,c,d,e) __net_Read(VLC_OBJECT(a),b,c,d,e)
VLC_EXPORT( int, __net_Read, ( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data, vlc_bool_t b_retry ) );
#define net_ReadNonBlock(a,b,c,d,e) __net_ReadNonBlock(VLC_OBJECT(a),b,c,d,e)
VLC_EXPORT( int, __net_ReadNonBlock, ( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data, mtime_t i_wait ) );
#define net_Write(a,b,c,d) __net_Write(VLC_OBJECT(a),b,c,d)
VLC_EXPORT( int, __net_Write, ( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data ) );
......
......@@ -181,6 +181,108 @@ struct sout_instance_t
sout_instance_sys_t *p_sys;
};
/* Announce handler structures */
/* Session and method descriptors */
struct sap_session_t;
struct session_descriptor_t
{
char *psz_name;
char *psz_uri;
int i_port;
int i_ttl;
int i_payload; /* SAP Payload type */
sap_session_t *p_sap; /* If we have a sap session, remember it */
char *psz_sdp;
};
#define METHOD_TYPE_SAP 1
#define METHOD_TYPE_SLP 2
struct announce_method_t
{
int i_type;
/* For SAP */
int i_ip_version;
char *psz_ipv6_scope;
char *psz_address; /* If we use a custom address */
};
/* SAP Specific structures */
/* 100ms */
#define SAP_IDLE ((mtime_t)(0.100*CLOCK_FREQ))
#define SAP_MAX_BUFFER 65534
#define MIN_INTERVAL 2
#define MAX_INTERVAL 300
/* A SAP announce address. For each of these, we run the
* control flow algorithm */
struct sap_address_t
{
char *psz_address;
int i_port;
int i_rfd; /* Read socket */
int i_wfd; /* Write socket */
/* Used for flow control */
mtime_t t1;
vlc_bool_t b_enabled;
vlc_bool_t b_ready;
int i_interval;
int i_buff;
int i_limit;
};
/* A SAP session descriptor, enqueued in the SAP handler queue */
struct sap_session_t
{
char *psz_sdp;
char *psz_data;
int i_length;
sap_address_t *p_address;
/* Last and next send */
mtime_t i_last;
mtime_t i_next;
};
/* The SAP handler, running in a separate thread */
struct sap_handler_t
{
VLC_COMMON_MEMBERS /* needed to create a thread */
sap_session_t **pp_sessions;
sap_address_t **pp_addresses;
vlc_bool_t b_control;
int i_sessions;
int i_addresses;
int i_current_session;
int (*pf_add) ( sap_handler_t*, session_descriptor_t *,announce_method_t*);
int (*pf_del) ( sap_handler_t*, session_descriptor_t *);
};
/* The main announce handler object */
struct announce_handler_t
{
VLC_COMMON_MEMBERS
sap_handler_t *p_sap;
};
/* End */
static inline sout_cfg_t *sout_cfg_find( sout_cfg_t *p_cfg, char *psz_name )
{
while( p_cfg && strcmp( p_cfg->psz_name, psz_name ) )
......@@ -205,6 +307,9 @@ static inline char *sout_cfg_find_value( sout_cfg_t *p_cfg, char *psz_name )
return NULL;
}
/*****************************************************************************
* Prototypes
*****************************************************************************/
......@@ -232,3 +337,25 @@ VLC_EXPORT( char *, sout_cfg_parser, ( char **, sout_cfg_t **, char
VLC_EXPORT( sout_stream_t *, sout_stream_new, ( sout_instance_t *, char *psz_chain ) );
VLC_EXPORT( void, sout_stream_delete, ( sout_stream_t *p_stream ) );
/* Announce system */
VLC_EXPORT( int, sout_AnnounceRegister, (sout_instance_t *,session_descriptor_t*, announce_method_t* ) );
VLC_EXPORT(session_descriptor_t*,sout_AnnounceRegisterSDP, (sout_instance_t *,char *, announce_method_t* ) );
VLC_EXPORT( int, sout_AnnounceUnRegister, (sout_instance_t *,session_descriptor_t* ) );
VLC_EXPORT(session_descriptor_t*,sout_AnnounceSessionCreate, () );
VLC_EXPORT(void, sout_AnnounceSessionDestroy, (session_descriptor_t *) );
VLC_EXPORT(announce_method_t*, sout_AnnounceMethodCreate, (int) );
#define announce_HandlerCreate(a) __announce_HandlerCreate(VLC_OBJECT(a))
announce_handler_t* __announce_HandlerCreate( vlc_object_t *);
/* Private functions for the announce handler */
int announce_HandlerDestroy( announce_handler_t * );
int announce_Register( announce_handler_t *p_announce,
session_descriptor_t *p_session,
announce_method_t *p_method );
int announce_UnRegister( announce_handler_t *p_announce,
session_descriptor_t *p_session );
sap_handler_t *announce_SAPHandlerCreate( announce_handler_t *p_announce );
void announce_SAPHandlerDestroy( sap_handler_t *p_sap );
......@@ -2,7 +2,7 @@
* vlc.h: global header for vlc
*****************************************************************************
* Copyright (C) 1998, 1999, 2000 VideoLAN
* $Id: vlc.h,v 1.30 2004/01/25 18:17:08 zorglub Exp $
* $Id$
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -19,6 +19,14 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/**
* \defgroup libvlc Libvlc
* This is libvlc.
*
* @{
*/
#ifndef _VLC_VLC_H
#define _VLC_VLC_H 1
......@@ -33,6 +41,9 @@ typedef int vlc_bool_t;
typedef struct vlc_list_t vlc_list_t;
typedef struct vlc_object_t vlc_object_t;
/**
* VLC value structure
*/
typedef union
{
int i_int;
......@@ -56,6 +67,9 @@ typedef union
} vlc_value_t;
/**
* VLC list structure
*/
struct vlc_list_t
{
int i_count;
......@@ -102,7 +116,9 @@ struct vlc_list_t
#define PLAYLIST_END -666
/** Playlist commands */
/**
* Playlist commands
*/
typedef enum {
PLAYLIST_PLAY, /**< Starts playing. No arg. */
PLAYLIST_PAUSE, /**< Toggles playlist pause. No arg. */
......@@ -122,16 +138,94 @@ typedef enum {
/*****************************************************************************
* Exported libvlc API
*****************************************************************************/
/**
* Retrieve libvlc version
*
* \return a string containing the libvlc version
*/
char const * VLC_Version ( void );
char const * VLC_Error ( int );
/**
* Return an error string
*
* \param i_err an error code
* \return an error string
*/
char const * VLC_Error ( int i_err );
/**
* Initialize libvlc
*
* This function allocates a vlc_t structure and returns a negative value
* in case of failure. Also, the thread system is initialized
*
* \return vlc object id or an error code
*/
int VLC_Create ( void );
/**
* Initialize a vlc_t structure
*
* This function initializes a previously allocated vlc_t structure:
* - CPU detection
* - gettext initialization
* - message queue, module bank and playlist initialization
* - configuration and commandline parsing
*
* \param i_object a vlc object id
* \param i_argc the number of arguments
* \param ppsz_argv an array of arguments
* \return VLC_SUCCESS on success
*/
int VLC_Init ( int, int, char *[] );
/**
* Ask vlc to die
*
* This function sets p_vlc->b_die to VLC_TRUE, but does not do any other
* task. It is your duty to call VLC_End and VLC_Destroy afterwards.
*
* \param i_object a vlc object id
* \return VLC_SUCCESS on success
*/
int VLC_Die ( int );
/**
* Stop playing and destroy everything.
*
* This function requests the running threads to finish, waits for their
* termination, and destroys their structure.
* \param i_object a vlc object id
* \return VLC_SUCCESS on success
*/
int VLC_Destroy ( int );
/**
* Set a VLC variable
*
* This function sets a variable of VLC
*
* \param i_object a vlc object id
* \param psz_var a vlc variable name
* \param value a vlc_value_t structure
* \return VLC_SUCCESS on success
*/
int VLC_Set ( int, char const *, vlc_value_t );
/**
* Get a VLC variable
*
* This function gets the value of a variable of VLC
* It stores it in the p_value argument
*
* \param i_object a vlc object id
* \param psz_var a vlc variable name
* \param p_value a pointer to a vlc_value_t structure
* \return VLC_SUCCESS on success
*/
int VLC_Get ( int, char const *, vlc_value_t * );
int VLC_AddIntf ( int, char const *, vlc_bool_t );
int VLC_AddTarget ( int, char const *, const char **, int, int, int );
......
......@@ -272,8 +272,13 @@ typedef struct sout_access_out_t sout_access_out_t;
typedef struct sout_mux_t sout_mux_t;
typedef struct sout_stream_t sout_stream_t;
typedef struct sout_cfg_t sout_cfg_t;
/*typedef struct sap_session_t sap_session_t;
typedef struct slp_session_t slp_session_t;*/
typedef struct sap_session_t sap_session_t;
typedef struct sap_address_t sap_address_t;
typedef struct session_descriptor_t session_descriptor_t;
typedef struct announce_method_t announce_method_t;
typedef struct announce_handler_t announce_handler_t;
typedef struct sap_handler_t sap_handler_t;
//typedef struct slp_session_t slp_session_t;
/* Decoders */
typedef struct decoder_t decoder_t;
......
......@@ -48,6 +48,7 @@
#define VLC_OBJECT_ENCODER (-14)
#define VLC_OBJECT_DIALOGS (-15)
#define VLC_OBJECT_VLM (-16)
#define VLC_OBJECT_ANNOUNCE (-17)
#define VLC_OBJECT_GENERIC (-666)
......
/*****************************************************************************
* sap.c : SAP interface module
*****************************************************************************
......@@ -527,6 +526,7 @@ static void Run( intf_thread_t *p_intf )
msg_Warn( p_intf, "ditching sap packet" );
}
memset( buffer, 0, MAX_SAP_BUFFER );
}
}
......@@ -972,7 +972,7 @@ static sess_descr_t * parse_sdp( intf_thread_t * p_intf, char *p_packet )
if( p_packet[1] != '=' )
{
msg_Warn( p_intf, "packet invalid" );
msg_Warn( p_intf, "invalid packet") ;
free_sd( sd );
return NULL;
}
......
......@@ -138,12 +138,12 @@ char * SDPGenerateUDP(char * psz_name_arg,char * psz_url_arg)
/*****************************************************************************
* sout_SAPNew: Creates a SAP Session
*****************************************************************************/
sap_session_t * sout_SAPNew ( sout_instance_t *p_sout,
sap_session_t2 * sout_SAPNew ( sout_instance_t *p_sout,
char * psz_sdp_arg,
int ip_version,
char * psz_v6_scope )
{
sap_session_t *p_sap; /* The SAP structure */
sap_session_t2 *p_sap; /* The SAP structure */
char *sap_ipv6_addr = NULL; /* IPv6 built address */
vlc_value_t val;
......@@ -151,7 +151,7 @@ sap_session_t * sout_SAPNew ( sout_instance_t *p_sout,
var_Create( p_sout, "ipv4", VLC_VAR_BOOL );
/* Allocate the SAP structure */
p_sap = (sap_session_t *) malloc( sizeof ( sap_session_t ) ) ;
p_sap = (sap_session_t2 *) malloc( sizeof ( sap_session_t2 ) ) ;
if ( !p_sap )
{
msg_Err( p_sout, "out of memory" );
......@@ -214,7 +214,7 @@ sap_session_t * sout_SAPNew ( sout_instance_t *p_sout,
/*****************************************************************************
* sout_SAPDelete: Deletes a SAP Session
*****************************************************************************/
void sout_SAPDelete( sout_instance_t *p_sout, sap_session_t * p_sap )
void sout_SAPDelete( sout_instance_t *p_sout, sap_session_t2 * p_sap )
{
int i_ret;
......@@ -243,7 +243,7 @@ void sout_SAPDelete( sout_instance_t *p_sout, sap_session_t * p_sap )
/*****************************************************************************
* sout_SAPSend: Sends a SAP packet
*****************************************************************************/
void sout_SAPSend( sout_instance_t *p_sout, sap_session_t * p_sap )
void sout_SAPSend( sout_instance_t *p_sout, sap_session_t2 * p_sap )
{
char *psz_msg; /* SDP content */
char *psz_head; /* SAP header */
......
......@@ -51,7 +51,7 @@
/*****************************************************************************
* sap_session_t: SAP Session descriptor
*****************************************************************************/
struct sap_session_t
struct sap_session_t2
{
char * psz_sdp;
module_t p_network;
......@@ -60,7 +60,7 @@ struct sap_session_t
int i_ip_version;
};
typedef struct sap_session_t sap_session_t;
typedef struct sap_session_t2 sap_session_t2;
/*****************************************************************************
* slp_session_t: SLP Session descriptor
*****************************************************************************/
......@@ -75,12 +75,13 @@ typedef struct slp_session_t slp_session_t;
/*****************************************************************************
* Prototypes
*****************************************************************************/
sap_session_t2 * sout_SAPNew (sout_instance_t *, char * psz_sdp_arg,
int ip_version,
char * psz_v6_scope );
char * SDPGenerateUDP(char * ,char *);
sap_session_t * sout_SAPNew (sout_instance_t *,
char* , int, char *);
void sout_SAPDelete (sout_instance_t *,sap_session_t*);
void sout_SAPSend (sout_instance_t *,sap_session_t *);
void sout_SAPDelete (sout_instance_t *,sap_session_t2*);
void sout_SAPSend (sout_instance_t *,sap_session_t2 *);
int sout_SLPReg (sout_instance_t *,char *,char *);
int sout_SLPDereg (sout_instance_t *,char *,char *);
......
......@@ -76,9 +76,14 @@ struct sout_stream_sys_t
int64_t i_sdp_id;
int i_sdp_version;
char *psz_sdp;
vlc_mutex_t lock_sdp;
char *psz_session_name;
/* sap */
vlc_bool_t b_export_sap;
session_descriptor_t *p_session;
httpd_host_t *p_httpd_host;
httpd_file_t *p_httpd_file;
......@@ -155,6 +160,7 @@ struct sout_stream_id_t
static int AccessOutGrabberWrite( sout_access_out_t *, block_t * );
static int SapSetup( sout_stream_t *p_stream );
static int HttpSetup( sout_stream_t *p_stream, vlc_url_t * );
static int RtspSetup( sout_stream_t *p_stream, vlc_url_t * );
......@@ -181,6 +187,7 @@ static int Open( vlc_object_t *p_this )
p_sys = malloc( sizeof( sout_stream_sys_t ) );
p_sys->psz_destination = sout_cfg_find_value( p_stream->p_cfg, "dst" );
p_sys->psz_session_name = sout_cfg_find_value( p_stream->p_cfg, "name" );
if( ( val = sout_cfg_find_value( p_stream->p_cfg, "port" ) ) )
{
p_sys->i_port = atoi( val );
......@@ -190,6 +197,18 @@ static int Open( vlc_object_t *p_this )
p_sys->i_port = 1234;
}
if( !p_sys->psz_session_name )
{
if( p_sys->psz_destination )
{
p_sys->psz_session_name = strdup( p_sys->psz_destination );
}
else
{
p_sys->psz_session_name = strdup( "NONE" );
}
}
if( !p_sys->psz_destination || *p_sys->psz_destination == '\0' )
{
val = sout_cfg_find_value( p_stream->p_cfg, "sdp" );
......@@ -227,6 +246,10 @@ static int Open( vlc_object_t *p_this )
p_sys->i_sdp_id = mdate();
p_sys->i_sdp_version = 1;
p_sys->psz_sdp = NULL;
p_sys->b_export_sap = VLC_FALSE;
p_sys->p_session = NULL;
p_sys->p_httpd_host = NULL;
p_sys->p_httpd_file = NULL;
p_sys->p_rtsp_host = NULL;
......@@ -320,15 +343,15 @@ static int Open( vlc_object_t *p_this )
sprintf( p_sys->psz_sdp,
"v=0\n"
"o=- "I64Fd" %d IN IP4 127.0.0.1\n"
"s=NONE\n"
"s=%s\n"
"c=IN IP4 %s/%d\n"
"m=video %d RTP/AVP %d\n"
"a=rtpmap:%d %s\n",
p_sys->i_sdp_id, p_sys->i_sdp_version,
p_sys->psz_session_name,
p_sys->psz_destination, p_sys->i_ttl,
p_sys->i_port, p_sys->i_payload_type,
p_sys->i_payload_type, psz_rtpmap );
fprintf( stderr, "sdp=%s", p_sys->psz_sdp );
/* create the rtp context */
......@@ -367,6 +390,11 @@ static int Open( vlc_object_t *p_this )
msg_Err( p_stream, "cannot export sdp as rtsp" );
}
}
else if( url.psz_protocol && !strcasecmp( url.psz_protocol, "sap" ) )
{
p_sys->b_export_sap = VLC_TRUE;
SapSetup( p_stream );
}
else
{
msg_Warn( p_stream, "unknow protocol for SDP (%s)",
......@@ -426,7 +454,13 @@ static void Close( vlc_object_t * p_this )
{
httpd_HostDelete( p_sys->p_rtsp_host );
}
#if 0
if( p_sys->psz_session_name )
{
free( p_sys->psz_session_name );
p_sys->psz_session_name = NULL;
}
#endif
if( p_sys->psz_sdp )
{
free( p_sys->psz_sdp );
......@@ -446,9 +480,10 @@ static char *SDPGenerate( sout_stream_t *p_stream, char *psz_destination, vlc_bo
i_size = strlen( "v=0\n" ) +
strlen( "o=- * * IN IP4 127.0.0.1\n" ) +
strlen( "s=NONE\n" ) +
strlen( "s=\n" ) +
strlen( "c=IN IP4 */*\n" ) +
strlen( psz_destination ? psz_destination : "0.0.0.0") +
strlen( p_sys->psz_session_name ) +
20 + 10 + 10 + 1;
for( i = 0; i < p_sys->i_es; i++ )
{
......@@ -473,7 +508,7 @@ static char *SDPGenerate( sout_stream_t *p_stream, char *psz_destination, vlc_bo
p += sprintf( p, "v=0\n" );
p += sprintf( p, "o=- "I64Fd" %d IN IP4 127.0.0.1\n",
p_sys->i_sdp_id, p_sys->i_sdp_version );
p += sprintf( p, "s=NONE\n" );
p += sprintf( p, "s=%s\n", p_sys->psz_session_name );
p += sprintf( p, "c=IN IP4 %s/%d\n", psz_destination ? psz_destination : "0.0.0.0",
p_sys->i_ttl );
......@@ -746,6 +781,12 @@ static sout_stream_id_t *Add( sout_stream_t *p_stream, es_format_t *p_fmt )
p_sys->i_sdp_version++;
fprintf( stderr, "sdp=%s", p_sys->psz_sdp );
/* Update the SAP announce */
if( p_sys->b_export_sap )
{
SapSetup( p_stream );
}
}
return id;
......@@ -784,6 +825,12 @@ static int Del( sout_stream_t *p_stream, sout_stream_id_t *id )
vlc_mutex_destroy( &id->lock_rtsp );
if( id->rtsp_access ) free( id->rtsp_access );
/* Update the SAP announce */
if( p_sys->b_export_sap )
{
SapSetup( p_stream );
}
free( id );
return VLC_SUCCESS;
}
......@@ -899,6 +946,37 @@ static int AccessOutGrabberWrite( sout_access_out_t *p_access,
return VLC_SUCCESS;
}
/****************************************************************************
* SAP:
****************************************************************************/
static int SapSetup( sout_stream_t *p_stream )
{
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_instance_t *p_sout = p_stream->p_sout;
announce_method_t *p_method = (announce_method_t *)
malloc(sizeof(announce_method_t));
/* Remove the previous session */
if( p_sys->p_session != NULL)
{
sout_AnnounceUnRegister( p_sout, p_sys->p_session);
sout_AnnounceSessionDestroy( p_sys->p_session );
p_sys->p_session = NULL;
}
p_method->i_type = METHOD_TYPE_SAP;
p_method->psz_address = NULL; /* FIXME */
p_method->i_ip_version = 4; /* FIXME ! */
if( p_sys->i_es > 0 && p_sys->psz_sdp && *p_sys->psz_sdp )
{
p_sys->p_session = sout_AnnounceRegisterSDP( p_sout, p_sys->psz_sdp,
p_method );
}
free( p_method );
return VLC_SUCCESS;
}
/****************************************************************************
* HTTP:
****************************************************************************/
......
......@@ -30,9 +30,12 @@
#include <vlc/vlc.h>
#include <vlc/sout.h>
#include "announce.h"
#include "network.h"
#define DEFAULT_IPV6_SCOPE "8"
#define DEFAULT_IPV6_SCOPE '8'
#define DEFAULT_PORT 1234
/*****************************************************************************
* Exported prototypes
......@@ -59,7 +62,7 @@ struct sout_stream_sys_t
{
sout_mux_t *p_mux;
slp_session_t *p_slp;
sap_session_t *p_sap;
session_descriptor_t *p_session;
};
/*****************************************************************************
......@@ -70,15 +73,14 @@ static int Open( vlc_object_t *p_this )
sout_stream_t *p_stream = (sout_stream_t*)p_this;
sout_instance_t *p_sout = p_stream->p_sout;
slp_session_t *p_slp = NULL;
sap_session_t *p_sap = NULL;
session_descriptor_t *p_session = NULL;
char *psz_mux = sout_cfg_find_value( p_stream->p_cfg, "mux" );
char *psz_access = sout_cfg_find_value( p_stream->p_cfg, "access" );
char *psz_url = sout_cfg_find_value( p_stream->p_cfg, "url" );
char *psz_ipv = sout_cfg_find_value( p_stream->p_cfg, "sap_ipv" );
char *psz_v6_scope = sout_cfg_find_value( p_stream->p_cfg, "sap_v6scope" );
char *psz_sdp = NULL;
vlc_url_t *p_url;
sout_cfg_t *p_sap_cfg = sout_cfg_find( p_stream->p_cfg, "sap" );
#ifdef HAVE_SLP_H
sout_cfg_t *p_slp_cfg = sout_cfg_find( p_stream->p_cfg, "slp" );
......@@ -89,6 +91,9 @@ static int Open( vlc_object_t *p_this )
char *psz_mux_byext = NULL;
p_stream->p_sys = malloc( sizeof( sout_stream_sys_t) );
p_stream->p_sys->p_session = NULL;
msg_Dbg( p_this, "creating `%s/%s://%s'",
psz_access, psz_mux, psz_url );
......@@ -240,29 +245,92 @@ static int Open( vlc_object_t *p_this )
msg_Dbg( p_stream, "mux opened" );
/* *** Create the SAP Session structure *** */
if( psz_access &&
p_sap_cfg &&
( strstr( psz_access, "udp" ) || strstr( psz_access , "rtp" ) ) )
if( psz_access && p_sap_cfg && ( strstr( psz_access, "udp" ) ||
strstr( psz_access , "rtp" ) ) )
{
msg_Info( p_this, "SAP Enabled");
session_descriptor_t *p_session= sout_AnnounceSessionCreate();
announce_method_t *p_method = sout_AnnounceMethodCreate(
METHOD_TYPE_SAP);
if( psz_ipv == NULL )
/* Parse user input */
if( p_sap_cfg->psz_value )
{
char *psz_sap = p_sap_cfg->psz_value;
/* subconfig */
if( ! strncmp(psz_sap, "sap{", 4 ) )
{
sout_cfg_t *p_cfg;
char *psz_curr,*psz_null;
sout_cfg_parser( &psz_null, &p_cfg, psz_sap );
psz_curr = sout_cfg_find_value( p_cfg,"name");
if( psz_curr != NULL)
{
p_session->psz_name = strdup( psz_curr );
}
else
{
p_session->psz_name = strdup( psz_url );
}
psz_curr = sout_cfg_find_value( p_cfg,"ip_version");
if( psz_curr != NULL)
{
p_method->i_ip_version = atoi( psz_curr ) != 0 ?
atoi(psz_curr) :
4;
}
}
else
{
p_session->psz_name = strdup( p_sap_cfg->psz_value );
}
}
else
{
psz_ipv = "4";
p_session->psz_name = strdup( psz_url );
}
if( psz_v6_scope == NULL )
/* Now, parse the URL to extract host and port */
p_url = (vlc_url_t *)malloc( sizeof(vlc_url_t ) );
if ( ! p_url )
{
psz_v6_scope = DEFAULT_IPV6_SCOPE;
return NULL;
}
msg_Dbg( p_sout , "Creating SAP with IPv%i", atoi(psz_ipv) );
psz_sdp = SDPGenerateUDP(p_sap_cfg->psz_value ? p_sap_cfg->psz_value :
psz_url, psz_url);
vlc_UrlParse( p_url, psz_url , 0);
p_sap = sout_SAPNew( p_sout , psz_sdp,atoi(psz_ipv), psz_v6_scope );
if (!p_url->psz_host)
{
return NULL;
}
if( !p_sap )
msg_Err( p_sout,"Unable to initialize SAP. SAP disabled");
if(p_url->i_port == 0)
{
p_url->i_port = DEFAULT_PORT;
}
p_session->psz_uri = p_url->psz_host;
p_session->i_port = p_url->i_port;
p_session->psz_sdp = NULL;
p_session->i_ttl = config_GetInt( p_sout,"ttl" );
p_session->i_payload = 33;
msg_Info( p_this, "SAP Enabled");
sout_AnnounceRegister( p_sout, p_session, p_method );
/* FIXME: Free p_method */
p_stream->p_sys->p_session = p_session;
if( p_url )
{
vlc_UrlClean( p_url );
free( p_url );
p_url = NULL;
}
}
/* *** Register with slp *** */
......@@ -281,8 +349,8 @@ static int Open( vlc_object_t *p_this )
p_slp = (slp_session_t*)malloc(sizeof(slp_session_t));
if(!p_slp)
{
msg_Warn(p_sout,"Out of memory");
if( p_sap ) free( p_sap );
msg_Warn(p_sout,"out of memory");
// if( p_sap ) free( p_sap );
return -1;
}
p_slp->psz_url= strdup(psz_url);
......@@ -296,10 +364,8 @@ static int Open( vlc_object_t *p_this )
p_stream->pf_del = Del;
p_stream->pf_send = Send;
p_stream->p_sys = malloc( sizeof( sout_stream_sys_t) );
p_stream->p_sys->p_mux = p_mux;
p_stream->p_sys->p_slp = p_slp;
p_stream->p_sys->p_sap = p_sap;
return VLC_SUCCESS;
}
......@@ -313,8 +379,10 @@ static void Close( vlc_object_t * p_this )
sout_stream_sys_t *p_sys = p_stream->p_sys;
sout_access_out_t *p_access = p_sys->p_mux->p_access;
if( p_sys->p_sap )
sout_SAPDelete( (sout_instance_t *)p_this , p_sys->p_sap );
if( p_sys->p_session != NULL )
{
sout_AnnounceUnRegister( p_stream->p_sout, p_sys->p_session );
}
#ifdef HAVE_SLP_H
if( p_sys->p_slp )
......@@ -374,8 +442,5 @@ static int Send( sout_stream_t *p_stream, sout_stream_id_t *id,
sout_MuxSendBuffer( p_sys->p_mux, id->p_input, p_buffer );
if( p_sys->p_sap )
sout_SAPSend( p_sout , p_sys->p_sap );
return VLC_SUCCESS;
}
......@@ -2,7 +2,7 @@
* libvlc.c: main libvlc source
*****************************************************************************
* Copyright (C) 1998-2004 VideoLAN
* $Id: libvlc.c,v 1.118 2004/03/03 20:39:52 gbazin Exp $
* $Id$
*
* Authors: Vincent Seguin <seguin@via.ecp.fr>
* Samuel Hocevar <sam@zoy.org>
......@@ -76,6 +76,8 @@
#include "vlc_video.h"
#include "video_output.h"
#include "stream_output.h"
#include "libvlc.h"
/*****************************************************************************
......@@ -1023,10 +1025,11 @@ int VLC_Play( int i_object )
*****************************************************************************/
int VLC_Stop( int i_object )
{
intf_thread_t * p_intf;
playlist_t * p_playlist;
vout_thread_t * p_vout;
aout_instance_t * p_aout;
intf_thread_t * p_intf;
playlist_t * p_playlist;
vout_thread_t * p_vout;
aout_instance_t * p_aout;
announce_handler_t * p_announce;
vlc_t *p_vlc = vlc_current_object( i_object );
/* Check that the handle is valid */
......@@ -1083,6 +1086,18 @@ int VLC_Stop( int i_object )
aout_Delete( p_aout );
}
/*
* Free announce handler(s?)
*/
msg_Dbg( p_vlc, "removing announce handler" );
while( (p_announce = vlc_object_find( p_vlc, VLC_OBJECT_ANNOUNCE,
FIND_CHILD ) ) )
{
vlc_object_detach( p_announce );
vlc_object_release( p_announce );
announce_HandlerDestroy( p_announce );
}
if( i_object ) vlc_object_release( p_vlc );
return VLC_SUCCESS;
}
......
......@@ -483,6 +483,19 @@ static char *ppsz_align_descriptions[] =
#define ACCESS_OUTPUT_LONGTEXT N_( \
"This is a legacy entry to let you configure access output modules")
#define ANN_CAT_LONGTEXT N_( \
"These options allow you to set options for the session announcement" \
"subsystem." )
#define ANN_SAPCTRL_TEXT N_("Control SAP flow")
#define ANN_SAPCTRL_LONGTEXT N_("If this option is enabled, the flow on " \
"the SAP multicast address will be controlled. This is needed if you " \
"want to make announcements on the MBone" )
#define ANN_SAPINTV_TEXT N_("SAP announcement interval")
#define ANN_SAPINTV_LONGTEXT N_("When the SAP flow control is disabled, " \
"this lets you set the fixed interval between SAP announcements" )
#define CPU_CAT_LONGTEXT N_( \
"These options allow you to enable special CPU optimizations.\n" \
"You should always leave all these enabled." )
......@@ -895,6 +908,12 @@ vlc_module_begin();
ACCESS_OUTPUT_TEXT, ACCESS_OUTPUT_LONGTEXT, VLC_TRUE );
add_integer( "ttl", 1, NULL, TTL_TEXT, TTL_LONGTEXT, VLC_TRUE );
/* Announce options */
add_category_hint( N_("Announce system"), ANN_CAT_LONGTEXT, VLC_TRUE );
add_bool( "sap-flow-control", VLC_FALSE, NULL, ANN_SAPCTRL_TEXT,
ANN_SAPCTRL_LONGTEXT, VLC_TRUE );
add_integer( "sap-interval", 5, NULL, ANN_SAPINTV_TEXT,
ANN_SAPINTV_LONGTEXT, VLC_TRUE );
/* CPU options */
add_category_hint( N_("CPU"), CPU_CAT_LONGTEXT, VLC_TRUE );
......
......@@ -265,6 +265,70 @@ int __net_Read( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data,
return i_total;
}
/*****************************************************************************
* __net_ReadNonBlock:
*****************************************************************************
* Read from a network socket, non blocking mode (with timeout)
*****************************************************************************/
int __net_ReadNonBlock( vlc_object_t *p_this, int fd, uint8_t *p_data,
int i_data, mtime_t i_wait)
{
struct timeval timeout;
fd_set fds_r, fds_e;
int i_recv;
int i_ret;
/* Initialize file descriptor set */
FD_ZERO( &fds_r );
FD_SET( fd, &fds_r );
FD_ZERO( &fds_e );
FD_SET( fd, &fds_e );
timeout.tv_sec = 0;
timeout.tv_usec = i_wait;
i_ret = select(fd + 1, &fds_r, NULL, &fds_e, &timeout);
if( i_ret < 0 && errno == EINTR )
{
return 0;
}
else if( i_ret < 0 )
{
msg_Err( p_this, "network select error (%s)", strerror(errno) );
return -1;
}
else if( i_ret == 0)
{
return 0;
}
else
{
if( ( i_recv = recv( fd, p_data, i_data, 0 ) ) < 0 )
{
#ifdef WIN32
/* For udp only */
/* On win32 recv() will fail if the datagram doesn't fit inside
* the passed buffer, even though the buffer will be filled with
* the first part of the datagram. */
if( WSAGetLastError() == WSAEMSGSIZE )
{
msg_Err( p_this, "recv() failed. "
"Increase the mtu size (--mtu option)" );
}
else
msg_Err( p_this, "recv failed (%i)", WSAGetLastError() );
#else
msg_Err( p_this, "recv failed (%s)", strerror(errno) );
#endif
return -1;
}
return i_recv;
}
/* We will never be here */
return -1;
}
/* Write exact amount requested */
int __net_Write( vlc_object_t *p_this, int fd, uint8_t *p_data, int i_data )
{
......
......@@ -160,6 +160,10 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type )
i_size = sizeof( vlm_t );
psz_type = "vlm dameon";
break;
case VLC_OBJECT_ANNOUNCE:
i_size = sizeof( announce_handler_t );
psz_type = "announce handler";
break;
default:
i_size = i_type > 0
? i_type > (int)sizeof(vlc_object_t)
......
/*****************************************************************************
* announce.c : announce handler
*****************************************************************************
* Copyright (C) 2002-2004 VideoLAN
* $Id: stream_output.c 7307 2004-04-07 23:13:03Z zorglub $
*
* Authors: Clment Stenac <zorglub@videolan.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include <stdlib.h> /* free() */
#include <stdio.h> /* sprintf() */
#include <string.h> /* strerror() */
#include <vlc/vlc.h>
#include <vlc/sout.h>
/*****************************************************************************
* Local prototypes
*****************************************************************************/
#define FREE( p ) if( p ) { free( p ); (p) = NULL; }
/****************************************************************************
* Sout-side functions
****************************************************************************/
/**
* Register a new session with the announce handler
*
* \param p_sout a sout instance structure
* \param p_session a session descriptor
* \param p_method an announce method descriptor
* \return VLC_SUCCESS or an error
*/
int sout_AnnounceRegister( sout_instance_t *p_sout,
session_descriptor_t *p_session,
announce_method_t *p_method )
{
int i_ret;
announce_handler_t *p_announce = (announce_handler_t*)
vlc_object_find( p_sout,
VLC_OBJECT_ANNOUNCE,
FIND_ANYWHERE );
if( !p_announce )
{
msg_Dbg( p_sout, "No announce handler found, creating one" );
p_announce = announce_HandlerCreate( p_sout );
if( !p_announce )
{
msg_Err( p_sout, "Creation failed" );
return VLC_ENOMEM;
}
vlc_object_yield( p_announce );
msg_Dbg( p_sout,"Creation done" );
}
i_ret = announce_Register( p_announce, p_session, p_method );
vlc_object_release( p_announce );
return i_ret;
}
/**
* Register a new session with the announce handler, using a pregenerated SDP
*
* \param p_sout a sout instance structure
* \param psz_sdp the SDP to register
* \param p_method an announce method descriptor
* \return the new session descriptor structure
*/
session_descriptor_t *sout_AnnounceRegisterSDP( sout_instance_t *p_sout,
char *psz_sdp, announce_method_t *p_method )
{
session_descriptor_t *p_session;
announce_handler_t *p_announce = (announce_handler_t*)
vlc_object_find( p_sout,
VLC_OBJECT_ANNOUNCE,
FIND_ANYWHERE );
if( !p_announce )
{
msg_Dbg( p_sout, "no announce handler found, creating one" );
p_announce = announce_HandlerCreate( p_sout );
if( !p_announce )
{
msg_Err( p_sout, "Creation failed" );
return NULL;
}
vlc_object_yield( p_announce );
}
if( p_method->i_type != METHOD_TYPE_SAP )
{
msg_Warn( p_sout,"forcing SAP announcement");
}
p_session = sout_AnnounceSessionCreate();
p_session->psz_sdp = strdup( psz_sdp );
announce_Register( p_announce, p_session, p_method );
vlc_object_release( p_announce );
return p_session;
}
/**
* UnRegister an existing session
*
* \param p_sout a sout instance structure
* \param p_session the session descriptor
* \return VLC_SUCCESS or an error
*/
int sout_AnnounceUnRegister( sout_instance_t *p_sout,
session_descriptor_t *p_session )
{
int i_ret;
announce_handler_t *p_announce = (announce_handler_t*)
vlc_object_find( p_sout,
VLC_OBJECT_ANNOUNCE,
FIND_ANYWHERE );
if( !p_announce )
{
msg_Dbg( p_sout, "Unable to remove announce: no announce handler" );
return VLC_ENOOBJ;
}
i_ret = announce_UnRegister( p_announce, p_session );
vlc_object_release( p_announce );
return i_ret;
}
/**
* Create and initialize a session descriptor
*
* \return a new session descriptor
*/
session_descriptor_t * sout_AnnounceSessionCreate()
{
session_descriptor_t *p_session;
p_session = (session_descriptor_t *)malloc( sizeof(session_descriptor_t));
if( p_session)
{
p_session->p_sap = NULL;
p_session->psz_sdp = NULL;
p_session->psz_name = NULL;
p_session->psz_uri = NULL;
p_session->i_port = 0;
}
return p_session;
}
/**
* Destroy a session descriptor and free all
*
* \param p_session the session to destroy
* \return Nothing
*/
void sout_AnnounceSessionDestroy( session_descriptor_t *p_session )
{
if( p_session )
{
FREE( p_session->psz_name );
FREE( p_session->psz_uri );
FREE( p_session->psz_sdp );
FREE( p_session );
}
}
/**
* Create and initialize an announcement method structure
*
* \param i_type METHOD_TYPE_SAP or METHOD_TYPE_SLP
* \return a new announce_method structure
*/
announce_method_t * sout_AnnounceMethodCreate( int i_type )
{
announce_method_t *p_method;
p_method = (announce_method_t *)malloc( sizeof(announce_method_t) );
if( p_method )
{
p_method->i_type = i_type;
if( i_type == METHOD_TYPE_SAP )
{
/* Default values */
p_method->psz_address = NULL;
p_method->i_ip_version = 4 ;
p_method->psz_ipv6_scope = strdup("8");
}
}
return p_method;
}
/************************************************************************
* Announce handler functions (private)
************************************************************************/
/**
* Create the announce handler object
*
* \param p_this a vlc_object structure
* \return the new announce handler or NULL on error
*/
announce_handler_t *__announce_HandlerCreate( vlc_object_t *p_this )
{
announce_handler_t *p_announce;
p_announce = vlc_object_create( p_this, VLC_OBJECT_ANNOUNCE );
if( !p_announce )
{
msg_Err( p_this, "out of memory" );
return NULL;
}
p_announce->p_sap = NULL;
vlc_object_attach( p_announce, p_this->p_vlc);
return p_announce;
}
/**
* Destroy a announce handler object
*
* \param p_announce the announce handler to destroy
* \return VLC_SUCCESS or an error
*/
int announce_HandlerDestroy( announce_handler_t *p_announce )
{
if( p_announce->p_sap )
{
p_announce->p_sap->b_die = VLC_TRUE;
/* Wait for the SAP thread to exit */
vlc_thread_join( p_announce->p_sap );
announce_SAPHandlerDestroy( p_announce->p_sap );
}
/* Free the structure */
vlc_object_destroy( p_announce );
return VLC_SUCCESS;
}
/* Register an announce */
int announce_Register( announce_handler_t *p_announce,
session_descriptor_t *p_session,
announce_method_t *p_method )
{
msg_Dbg( p_announce, "registering announce");
if( p_method->i_type == METHOD_TYPE_SAP )
{
/* Do we already have a SAP announce handler ? */
if( !p_announce->p_sap )
{
msg_Dbg( p_announce, "creating SAP announce handler");
sap_handler_t *p_sap = announce_SAPHandlerCreate( p_announce );
if( !p_sap )
{
msg_Err( p_announce, "SAP handler creation failed" );
return VLC_ENOOBJ;
}
p_announce->p_sap = p_sap;
}
/* this will set p_session->p_sap for later deletion */
msg_Dbg( p_announce, "adding SAP session");
p_announce->p_sap->pf_add( p_announce->p_sap, p_session, p_method );
}
else if( p_method->i_type == METHOD_TYPE_SLP )
{
msg_Dbg( p_announce, "SLP unsupported at the moment" );
return VLC_EGENERIC;
}
else
{
msg_Dbg( p_announce, "Announce type unsupported" );
return VLC_EGENERIC;
}
return VLC_SUCCESS;;
}
/* Unregister an announce */
int announce_UnRegister( announce_handler_t *p_announce,
session_descriptor_t *p_session )
{
msg_Dbg( p_announce, "unregistering announce" );
if( p_session->p_sap != NULL ) /* SAP Announce */
{
if( !p_announce->p_sap )
{
msg_Err( p_announce, "can't remove announce, no SAP handler");
return VLC_ENOOBJ;
}
p_announce->p_sap->pf_del( p_announce->p_sap, p_session );
}
return VLC_SUCCESS;
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment