Commit 5574f54d authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

SAP announce: rewrite, use one thread per SAP group (fixes #1839)

parent 4129590e
...@@ -263,8 +263,6 @@ typedef struct sout_stream_t sout_stream_t; ...@@ -263,8 +263,6 @@ typedef struct sout_stream_t sout_stream_t;
typedef struct sout_stream_sys_t sout_stream_sys_t; typedef struct sout_stream_sys_t sout_stream_sys_t;
typedef struct config_chain_t config_chain_t; typedef struct config_chain_t config_chain_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 session_descriptor_t session_descriptor_t;
typedef struct announce_method_t announce_method_t; typedef struct announce_method_t announce_method_t;
typedef struct announce_handler_t announce_handler_t; typedef struct announce_handler_t announce_handler_t;
......
...@@ -1832,8 +1832,7 @@ vlc_module_begin(); ...@@ -1832,8 +1832,7 @@ vlc_module_begin();
PACKETIZER_TEXT, PACKETIZER_LONGTEXT, true ); PACKETIZER_TEXT, PACKETIZER_LONGTEXT, true );
set_subcategory( SUBCAT_SOUT_SAP ); set_subcategory( SUBCAT_SOUT_SAP );
add_bool( "sap-flow-control", false, NULL, ANN_SAPCTRL_TEXT, add_obsolete_bool( "sap-flow-control" );
ANN_SAPCTRL_LONGTEXT, true );
add_integer( "sap-interval", 5, NULL, ANN_SAPINTV_TEXT, add_integer( "sap-interval", 5, NULL, ANN_SAPINTV_TEXT,
ANN_SAPINTV_LONGTEXT, true ); ANN_SAPINTV_LONGTEXT, true );
......
...@@ -176,10 +176,7 @@ static announce_handler_t *announce_HandlerCreate( vlc_object_t *p_this ) ...@@ -176,10 +176,7 @@ static announce_handler_t *announce_HandlerCreate( vlc_object_t *p_this )
int announce_HandlerDestroy( announce_handler_t *p_announce ) int announce_HandlerDestroy( announce_handler_t *p_announce )
{ {
if( p_announce->p_sap ) if( p_announce->p_sap )
{ SAP_Destroy( p_announce->p_sap );
/* Exit the SAP */
vlc_object_release( p_announce->p_sap );
}
/* Free the structure */ /* Free the structure */
vlc_object_release( p_announce ); vlc_object_release( p_announce );
...@@ -201,7 +198,7 @@ static int announce_Register( announce_handler_t *p_announce, ...@@ -201,7 +198,7 @@ static int announce_Register( announce_handler_t *p_announce,
/* Do we already have a SAP announce handler ? */ /* Do we already have a SAP announce handler ? */
if( !p_announce->p_sap ) if( !p_announce->p_sap )
{ {
sap_handler_t *p_sap = announce_SAPHandlerCreate( p_announce ); sap_handler_t *p_sap = SAP_Create (VLC_OBJECT(p_announce));
msg_Dbg( p_announce, "creating SAP announce handler"); msg_Dbg( p_announce, "creating SAP announce handler");
if( !p_sap ) if( !p_sap )
{ {
...@@ -212,7 +209,7 @@ static int announce_Register( announce_handler_t *p_announce, ...@@ -212,7 +209,7 @@ static int announce_Register( announce_handler_t *p_announce,
} }
/* this will set p_session->p_sap for later deletion */ /* this will set p_session->p_sap for later deletion */
msg_Dbg( p_announce, "adding SAP session"); msg_Dbg( p_announce, "adding SAP session");
p_announce->p_sap->pf_add( p_announce->p_sap, p_session ); SAP_Add( p_announce->p_sap, p_session );
} }
else else
{ {
...@@ -228,7 +225,6 @@ static int announce_UnRegister( announce_handler_t *p_announce, ...@@ -228,7 +225,6 @@ static int announce_UnRegister( announce_handler_t *p_announce,
session_descriptor_t *p_session ) session_descriptor_t *p_session )
{ {
msg_Dbg( p_announce, "unregistering announce" ); msg_Dbg( p_announce, "unregistering announce" );
if( p_announce->p_sap ) SAP_Del( p_announce->p_sap, p_session );
p_announce->p_sap->pf_del( p_announce->p_sap, p_session );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -40,144 +40,131 @@ ...@@ -40,144 +40,131 @@
#include <vlc_sout.h> #include <vlc_sout.h>
#include <vlc_network.h> #include <vlc_network.h>
#include <vlc_charset.h>
#include "stream_output.h" #include "stream_output.h"
#include "libvlc.h" #include "libvlc.h"
/* SAP is always on that port */ /* SAP is always on that port */
#define SAP_PORT 9875 #define IPPORT_SAP 9875
#define DEFAULT_PORT "1234" /* A SAP session descriptor, enqueued in the SAP handler queue */
typedef struct sap_session_t
#undef EXTRA_DEBUG {
struct sap_session_t *next;
/* SAP Specific structures */ const session_descriptor_t *p_sd;
size_t length;
/* 100ms */ uint8_t data[0];
#define SAP_IDLE ((mtime_t)(0.100*CLOCK_FREQ)) } sap_session_t;
#define SAP_MAX_BUFFER 65534
#define MIN_INTERVAL 2
#define MAX_INTERVAL 300
/* A SAP announce address. For each of these, we run the /* A SAP announce address. For each of these, we run the
* control flow algorithm */ * control flow algorithm */
struct sap_address_t typedef struct sap_address_t
{ {
char *psz_address; struct sap_address_t *next;
vlc_thread_t thread;
vlc_mutex_t lock;
vlc_cond_t wait;
char group[NI_MAXNUMERICHOST];
struct sockaddr_storage orig; struct sockaddr_storage orig;
socklen_t origlen; socklen_t origlen;
int i_rfd; /* Read socket */ int fd;
int i_wfd; /* Write socket */ unsigned interval;
/* Used for flow control */
mtime_t t1;
bool b_enabled;
bool b_ready;
int i_interval;
int i_buff;
int i_limit;
};
/* A SAP session descriptor, enqueued in the SAP handler queue */ unsigned session_count;
struct sap_session_t { sap_session_t *first;
uint8_t *psz_data; } sap_address_t;
size_t i_length;
sap_address_t *p_address; /* The SAP handler, running in a separate thread */
session_descriptor_t *p_sd; struct sap_handler_t
{
/* Last and next send */ VLC_COMMON_MEMBERS
mtime_t i_next;
vlc_mutex_t lock;
sap_address_t *first;
}; };
#define SAP_MAX_BUFFER 65534
#define MIN_INTERVAL 2
#define MAX_INTERVAL 300
/***************************************************************************** /*****************************************************************************
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
static void * RunThread( vlc_object_t *p_this); static void *RunThread (void *);
static int ComputeRate( sap_address_t *p_address );
static void announce_SendSAPAnnounce( sap_handler_t *p_sap,
sap_session_t *p_session );
static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
session_descriptor_t *p_session );
static int announce_SAPAnnounceDel( sap_handler_t *p_sap,
session_descriptor_t *p_session );
static void announce_SAPHandlerDestructor( vlc_object_t *p_this );
/** /**
* Create the SAP handler * Create the SAP handler
* *
* \param p_announce the parent announce_handler * \param p_announce a VLC object
* \return the newly created SAP handler or NULL on error * \return the newly created SAP handler or NULL on error
*/ */
sap_handler_t *announce_SAPHandlerCreate( announce_handler_t *p_announce ) sap_handler_t *SAP_Create (vlc_object_t *p_announce)
{ {
sap_handler_t *p_sap; sap_handler_t *p_sap;
p_sap = vlc_custom_create( VLC_OBJECT(p_announce), sizeof( sap_handler_t ), p_sap = vlc_custom_create (p_announce, sizeof (*p_sap),
VLC_OBJECT_ANNOUNCE, "sap announcer" ); VLC_OBJECT_GENERIC, "sap sender");
if( !p_sap ) if (p_sap == NULL)
return NULL; return NULL;
p_sap->pf_add = announce_SAPAnnounceAdd; vlc_mutex_init (&p_sap->lock);
p_sap->pf_del = announce_SAPAnnounceDel; p_sap->first = NULL;
return p_sap;
}
p_sap->i_sessions = 0; void SAP_Destroy (sap_handler_t *p_sap)
p_sap->i_addresses = 0; {
p_sap->i_current_session = 0; assert (p_sap->first == NULL);
vlc_mutex_destroy (&p_sap->lock);
vlc_object_release (p_sap);
}
p_sap->b_control = config_GetInt( p_sap, "sap-flow-control"); static sap_address_t *AddressCreate (vlc_object_t *obj, const char *group)
{
int fd = net_ConnectUDP (obj, group, IPPORT_SAP, 255);
if (fd == -1)
return NULL;
if( vlc_thread_create( p_sap, "sap handler", RunThread, sap_address_t *addr = malloc (sizeof (*addr));
VLC_THREAD_PRIORITY_LOW, false ) ) if (addr == NULL)
{ {
msg_Dbg( p_announce, "unable to spawn SAP handler thread"); net_Close (fd);
vlc_object_release( p_sap );
return NULL; return NULL;
} }
vlc_object_set_destructor( p_sap, announce_SAPHandlerDestructor ); strlcpy (addr->group, group, sizeof (addr->group));
addr->fd = fd;
msg_Dbg( p_announce, "thread created, %i sessions", p_sap->i_sessions); addr->origlen = sizeof (addr->orig);
getsockname (fd, (struct sockaddr *)&addr->orig, &addr->origlen);
return p_sap;
}
static void announce_SAPHandlerDestructor( vlc_object_t * p_this ) addr->interval = var_CreateGetInteger (obj, "sap-interval");
{ vlc_mutex_init (&addr->lock);
sap_handler_t *p_sap = (sap_handler_t *)p_this; vlc_cond_init (&addr->wait);
int i; addr->session_count = 0;
addr->first = NULL;
/* Free the remaining sessions */ if (vlc_clone (&addr->thread, RunThread, addr, VLC_THREAD_PRIORITY_LOW))
for( i = 0 ; i< p_sap->i_sessions ; i++)
{ {
sap_session_t *p_session = p_sap->pp_sessions[i]; msg_Err (obj, "unable to spawn SAP announce thread");
FREENULL( p_session->psz_data ); net_Close (fd);
REMOVE_ELEM( p_sap->pp_sessions, p_sap->i_sessions , i ); free (addr);
FREENULL( p_session ); return NULL;
} }
return addr;
}
/* Free the remaining addresses */ static void AddressDestroy (sap_address_t *addr)
for( i = 0 ; i< p_sap->i_addresses ; i++) {
{ assert (addr->first == NULL);
sap_address_t *p_address = p_sap->pp_addresses[i];
FREENULL( p_address->psz_address ); vlc_cancel (addr->thread);
if( p_address->i_rfd > -1 ) vlc_join (addr->thread, NULL);
{ vlc_cond_destroy (&addr->wait);
net_Close( p_address->i_rfd ); vlc_mutex_destroy (&addr->lock);
} net_Close (addr->fd);
if( p_address->i_wfd > -1 && p_sap->b_control ) free (addr);
{
net_Close( p_address->i_wfd );
}
REMOVE_ELEM( p_sap->pp_addresses, p_sap->i_addresses, i );
FREENULL( p_address );
}
} }
/** /**
...@@ -185,63 +172,42 @@ static void announce_SAPHandlerDestructor( vlc_object_t * p_this ) ...@@ -185,63 +172,42 @@ static void announce_SAPHandlerDestructor( vlc_object_t * p_this )
* \param p_this the SAP Handler object * \param p_this the SAP Handler object
* \return nothing * \return nothing
*/ */
static void * RunThread( vlc_object_t *p_this) static void *RunThread (void *self)
{ {
sap_handler_t *p_sap = (sap_handler_t*)p_this; sap_address_t *addr = self;
sap_session_t *p_session;
/* TODO: Use poll() instead of msleep()). */ vlc_mutex_lock (&addr->lock);
mutex_cleanup_push (&addr->lock);
for (;;) for (;;)
{ {
int i; sap_session_t *p_session;
mtime_t deadline;
msleep( SAP_IDLE ); while (addr->first == NULL)
vlc_cond_wait (&addr->wait, &addr->lock);
/* If needed, get the rate info */ assert (addr->session_count > 0);
if( p_sap->b_control == true )
{
for( i = 0 ; i< p_sap->i_addresses ; i++)
{
if( p_sap->pp_addresses[i]->b_enabled == true )
{
ComputeRate( p_sap->pp_addresses[i] );
}
}
}
/* Find the session to announce */ deadline = mdate ();
vlc_object_lock( p_sap ); for (p_session = addr->first; p_session; p_session = p_session->next)
if( p_sap->i_sessions > p_sap->i_current_session + 1)
{
p_sap->i_current_session++;
}
else if( p_sap->i_sessions > 0)
{ {
p_sap->i_current_session = 0; send (addr->fd, p_session->data, p_session->length, 0);
} deadline += addr->interval * CLOCK_FREQ / addr->session_count;
else
{
vlc_object_unlock( p_sap );
continue;
}
p_session = p_sap->pp_sessions[p_sap->i_current_session];
/* And announce it */ if (vlc_cond_timedwait (&addr->wait, &addr->lock, deadline) == 0)
if( p_session->p_address->b_enabled == true && break; /* list may have changed! */
p_session->p_address->b_ready == true )
{
int canc = vlc_savecancel ();
announce_SendSAPAnnounce( p_sap, p_session );
vlc_restorecancel (canc);
} }
vlc_object_unlock( p_sap );
} }
return NULL;
vlc_cleanup_pop ();
assert (0);
} }
/* Add a SAP announce */ /**
static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, * Add a SAP announce
session_descriptor_t *p_session ) */
int SAP_Add (sap_handler_t *p_sap, session_descriptor_t *p_session)
{ {
int i; int i;
char psz_addr[NI_MAXNUMERICHOST]; char psz_addr[NI_MAXNUMERICHOST];
...@@ -251,11 +217,9 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, ...@@ -251,11 +217,9 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
struct sockaddr_storage addr; struct sockaddr_storage addr;
socklen_t addrlen; socklen_t addrlen;
vlc_object_lock( p_sap );
addrlen = p_session->addrlen; addrlen = p_session->addrlen;
if ((addrlen == 0) || (addrlen > sizeof (addr))) if ((addrlen == 0) || (addrlen > sizeof (addr)))
{ {
vlc_object_unlock( p_sap );
msg_Err( p_sap, "No/invalid address specified for SAP announce" ); msg_Err( p_sap, "No/invalid address specified for SAP announce" );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
...@@ -322,7 +286,6 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, ...@@ -322,7 +286,6 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
{ {
msg_Err( p_sap, "Out-of-scope multicast address " msg_Err( p_sap, "Out-of-scope multicast address "
"not supported by SAP" ); "not supported by SAP" );
vlc_object_unlock( p_sap );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
...@@ -331,7 +294,6 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, ...@@ -331,7 +294,6 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
} }
default: default:
vlc_object_unlock( p_sap );
msg_Err( p_sap, "Address family %d not supported by SAP", msg_Err( p_sap, "Address family %d not supported by SAP",
addr.ss_family ); addr.ss_family );
return VLC_EGENERIC; return VLC_EGENERIC;
...@@ -342,84 +304,39 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, ...@@ -342,84 +304,39 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
if( i ) if( i )
{ {
vlc_object_unlock( p_sap );
msg_Err( p_sap, "%s", vlc_gai_strerror( i ) ); msg_Err( p_sap, "%s", vlc_gai_strerror( i ) );
return VLC_EGENERIC; return VLC_EGENERIC;
} }
/* Find/create SAP address thread */
msg_Dbg( p_sap, "using SAP address: %s", psz_addr); msg_Dbg( p_sap, "using SAP address: %s", psz_addr);
/* XXX: Check for dupes */ vlc_mutex_lock (&p_sap->lock);
p_sap_session = (sap_session_t*)malloc(sizeof(sap_session_t)); sap_address_t *sap_addr;
p_sap_session->p_sd = p_session; for (sap_addr = p_sap->first; sap_addr; sap_addr = sap_addr->next)
p_sap_session->p_address = NULL; if (!strcmp (psz_addr, sap_addr->group))
/* Add the address to the buffer */
for( i = 0; i < p_sap->i_addresses; i++)
{
if( !strcmp( psz_addr, p_sap->pp_addresses[i]->psz_address ) )
{
p_sap_session->p_address = p_sap->pp_addresses[i];
break; break;
}
}
if( p_sap_session->p_address == NULL ) if (sap_addr == NULL)
{ {
sap_address_t *p_address = (sap_address_t *) sap_addr = AddressCreate (VLC_OBJECT(p_sap), psz_addr);
malloc( sizeof(sap_address_t) ); if (sap_addr == NULL)
if( !p_address )
{ {
vlc_object_unlock( p_sap ); vlc_mutex_unlock (&p_sap->lock);
return VLC_ENOMEM; return VLC_EGENERIC;
}
p_address->psz_address = strdup( psz_addr );
p_address->i_wfd = net_ConnectUDP( VLC_OBJECT(p_sap), psz_addr, SAP_PORT, 255 );
if( p_address->i_wfd != -1 )
{
shutdown( p_address->i_wfd, SHUT_RD );
p_address->origlen = sizeof (p_address->orig);
getsockname (p_address->i_wfd, (struct sockaddr *)&p_address->orig,
&p_address->origlen);
}
if( p_sap->b_control == true )
{
p_address->i_rfd = net_ListenUDP1( (vlc_object_t*)p_sap, psz_addr, SAP_PORT );
if( p_address->i_rfd != -1 )
shutdown( p_address->i_rfd, SHUT_WR );
p_address->i_buff = 0;
p_address->b_enabled = true;
p_address->b_ready = false;
p_address->i_limit = 10000; /* 10000 bps */
p_address->t1 = 0;
}
else
{
p_address->b_enabled = true;
p_address->b_ready = true;
p_address->i_interval = config_GetInt( p_sap,"sap-interval");
p_address->i_rfd = -1;
}
if( p_address->i_wfd == -1 || (p_address->i_rfd == -1
&& p_sap->b_control ) )
{
msg_Warn( p_sap, "disabling address" );
p_address->b_enabled = false;
} }
sap_addr->next = p_sap->first;
INSERT_ELEM( p_sap->pp_addresses, p_sap->first = sap_addr;
p_sap->i_addresses,
p_sap->i_addresses,
p_address );
p_sap_session->p_address = p_address;
} }
/* Switch locks.
* NEVER take the global SAP lock when holding a SAP thread lock! */
vlc_mutex_lock (&sap_addr->lock);
vlc_mutex_unlock (&p_sap->lock);
memcpy (&p_session->orig, &p_sap_session->p_address->orig, memcpy (&p_session->orig, &sap_addr->orig, sap_addr->origlen);
p_session->origlen = p_sap_session->p_address->origlen); p_session->origlen = sap_addr->origlen;
size_t headsize = 20; size_t headsize = 20, length;
switch (p_session->orig.ss_family) switch (p_session->orig.ss_family)
{ {
#ifdef AF_INET6 #ifdef AF_INET6
...@@ -431,27 +348,24 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, ...@@ -431,27 +348,24 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
headsize += 4; headsize += 4;
break; break;
default: default:
msg_Err( p_sap, "Address family %d not supported by SAP", assert (0);
addr.ss_family );
vlc_object_unlock( p_sap );
return VLC_EGENERIC;
} }
/* If needed, build the SDP */ /* XXX: Check for dupes */
assert( p_session->psz_sdp != NULL ); length = headsize + strlen (p_session->psz_sdp);
p_sap_session = malloc (sizeof (*p_sap_session) + length + 1);
p_sap_session->i_next = 0; if (p_sap_session == NULL)
p_sap_session->i_length = headsize + strlen (p_session->psz_sdp);
p_sap_session->psz_data = malloc (p_sap_session->i_length + 1);
if (p_sap_session->psz_data == NULL)
{ {
free (p_session->psz_sdp); vlc_mutex_unlock (&sap_addr->lock);
vlc_object_unlock( p_sap ); return VLC_EGENERIC; /* NOTE: we should destroy the thread if left unused */
return VLC_ENOMEM;
} }
p_sap_session->next = sap_addr->first;
sap_addr->first = p_sap_session;
p_sap_session->p_sd = p_session;
p_sap_session->length = length;
/* Build the SAP Headers */ /* Build the SAP Headers */
uint8_t *psz_head = p_sap_session->psz_data; uint8_t *psz_head = p_sap_session->data;
/* SAPv1, not encrypted, not compressed */ /* SAPv1, not encrypted, not compressed */
psz_head[0] = 0x20; psz_head[0] = 0x20;
...@@ -492,127 +406,59 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap, ...@@ -492,127 +406,59 @@ static int announce_SAPAnnounceAdd( sap_handler_t *p_sap,
/* Build the final message */ /* Build the final message */
strcpy( (char *)psz_head + headsize, p_session->psz_sdp); strcpy( (char *)psz_head + headsize, p_session->psz_sdp);
/* Enqueue the announce */ sap_addr->session_count++;
INSERT_ELEM( p_sap->pp_sessions, vlc_cond_signal (&sap_addr->wait);
p_sap->i_sessions, vlc_mutex_unlock (&sap_addr->lock);
p_sap->i_sessions,
p_sap_session );
msg_Dbg( p_sap,"%i addresses, %i sessions",
p_sap->i_addresses,p_sap->i_sessions);
vlc_object_unlock( p_sap );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/* Remove a SAP Announce */ /**
static int announce_SAPAnnounceDel( sap_handler_t *p_sap, * Remove a SAP Announce
session_descriptor_t *p_session ) */
void SAP_Del (sap_handler_t *p_sap, const session_descriptor_t *p_session)
{ {
int i; vlc_mutex_lock (&p_sap->lock);
vlc_object_lock( p_sap );
msg_Dbg( p_sap, "removing session %p from SAP", p_session); /* TODO: give a handle back in SAP_Add, and use that... */
sap_address_t *addr, **paddr;
sap_session_t *session, **psession;
/* Dequeue the announce */ paddr = &p_sap->first;
for( i = 0; i< p_sap->i_sessions; i++) for (addr = p_sap->first; addr; addr = addr->next)
{ {
if( p_session == p_sap->pp_sessions[i]->p_sd ) psession = &addr->first;
vlc_mutex_lock (&addr->lock);
for (session = addr->first; session; session = session->next)
{ {
free( p_session->psz_sdp ); if (session->p_sd == p_session)
sap_session_t *p_mysession = p_sap->pp_sessions[i]; goto found;
REMOVE_ELEM( p_sap->pp_sessions, psession = &session->next;
p_sap->i_sessions,
i );
free( p_mysession->psz_data );
free( p_mysession );
break;
} }
vlc_mutex_unlock (&addr->lock);
paddr = &addr->next;
} }
assert (0);
/* XXX: Dequeue the address too if it is not used anymore found:
* TODO: - address refcount *psession = session->next;
- send a SAP deletion packet */
msg_Dbg( p_sap,"%i announcements remaining", p_sap->i_sessions ); if (addr->first == NULL)
/* Last session for this address -> unlink the address */
*paddr = addr->next;
vlc_mutex_unlock (&p_sap->lock);
vlc_object_unlock( p_sap ); if (addr->first == NULL)
return VLC_SUCCESS;
}
static void announce_SendSAPAnnounce( sap_handler_t *p_sap,
sap_session_t *p_session )
{
mtime_t now = mdate();
if( p_session->i_next >= now )
return;
ssize_t i_ret = send( p_session->p_address->i_wfd, p_session->psz_data,
p_session->i_length, 0 );
if( i_ret != (ssize_t)p_session->i_length )
{
msg_Warn( p_sap, "SAP send failed on address %s (%zd/%zu)",
p_session->p_address->psz_address,
i_ret, p_session->i_length );
}
p_session->i_next = now + p_session->p_address->i_interval*CLOCK_FREQ;
}
static int ComputeRate( sap_address_t *p_address )
{
uint8_t buffer[SAP_MAX_BUFFER];
ssize_t i_tot = 0;
mtime_t i_temp;
int i_rate;
if( p_address->t1 == 0 )
{
p_address->t1 = mdate();
return VLC_SUCCESS;
}
for (;;)
{
/* Might be too slow if we have huge data */
ssize_t i_read = recv( p_address->i_rfd, buffer, SAP_MAX_BUFFER, 0 );
if (i_read == -1)
break;
i_tot += i_read;
}
i_temp = mdate();
/* We calculate the rate every 5 seconds */
if( i_temp - p_address->t1 < 5000000 )
{ {
p_address->i_buff += i_tot; /* Last session for this address -> unlink the address */
return VLC_SUCCESS; vlc_mutex_unlock (&addr->lock);
AddressDestroy (addr);
} }
else
/* Bits/second */
i_rate = (int)(8*1000000*((mtime_t)p_address->i_buff + (mtime_t)i_tot ) /
(i_temp - p_address->t1 ));
p_address->i_limit = 10000;
p_address->i_interval = ((1000*i_rate / p_address->i_limit) *
(MAX_INTERVAL - MIN_INTERVAL))/1000 + MIN_INTERVAL;
if( p_address->i_interval > MAX_INTERVAL || p_address->i_interval < 0 )
{ {
p_address->i_interval = MAX_INTERVAL; addr->session_count--;
vlc_cond_signal (&addr->wait);
vlc_mutex_unlock (&addr->lock);
} }
#ifdef EXTRA_DEBUG
msg_Dbg( p_sap,"%s:%i: rate=%i, interval = %i s",
p_address->psz_address,SAP_PORT, i_rate, p_address->i_interval );
#endif
p_address->b_ready = true;
p_address->t1 = i_temp; free (session);
p_address->i_buff = 0;
return VLC_SUCCESS;
} }
...@@ -47,36 +47,15 @@ struct sout_packetizer_input_t ...@@ -47,36 +47,15 @@ struct sout_packetizer_input_t
}; };
#define sout_NewInstance(a,b) __sout_NewInstance(VLC_OBJECT(a),b) #define sout_NewInstance(a,b) __sout_NewInstance(VLC_OBJECT(a),b)
VLC_EXPORT( sout_instance_t *, __sout_NewInstance, ( vlc_object_t *, const char * ) ); sout_instance_t * __sout_NewInstance( vlc_object_t *, const char * );
VLC_EXPORT( void, sout_DeleteInstance, ( sout_instance_t * ) ); void sout_DeleteInstance( sout_instance_t * );
VLC_EXPORT( sout_packetizer_input_t *, sout_InputNew,( sout_instance_t *, es_format_t * ) ); sout_packetizer_input_t *sout_InputNew( sout_instance_t *, es_format_t * );
VLC_EXPORT( int, sout_InputDelete, ( sout_packetizer_input_t * ) ); int sout_InputDelete( sout_packetizer_input_t * );
VLC_EXPORT( int, sout_InputSendBuffer, ( sout_packetizer_input_t *, block_t* ) ); int sout_InputSendBuffer( sout_packetizer_input_t *, block_t* );
/* Announce system */ /* Announce system */
/* 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;
bool b_control;
int i_sessions;
int i_addresses;
int i_current_session;
int (*pf_add) ( sap_handler_t*, session_descriptor_t *);
int (*pf_del) ( sap_handler_t*, session_descriptor_t *);
/* private data, not in p_sys as there is one kind of sap_handler_t */
};
struct session_descriptor_t struct session_descriptor_t
{ {
struct sockaddr_storage orig; struct sockaddr_storage orig;
...@@ -98,7 +77,9 @@ struct announce_handler_t ...@@ -98,7 +77,9 @@ struct announce_handler_t
int announce_HandlerDestroy( announce_handler_t * ); int announce_HandlerDestroy( announce_handler_t * );
/* Release it with vlc_object_release() */ sap_handler_t *SAP_Create (vlc_object_t *);
sap_handler_t *announce_SAPHandlerCreate( announce_handler_t *p_announce ); void SAP_Destroy (sap_handler_t *);
int SAP_Add (sap_handler_t *, session_descriptor_t *);
void SAP_Del (sap_handler_t *, const session_descriptor_t *);
#endif #endif
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