/*****************************************************************************
* announce.c : announce handler
*****************************************************************************
* Copyright (C) 2002-2007 the VideoLAN team
* $Id$
*
* Authors: Clément 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "vlc_common.h"
#include "vlc_sout.h"
#include "stream_output.h"
#include <assert.h>
/* Private functions for the announce handler */
static announce_handler_t* announce_HandlerCreate( vlc_object_t *);
static int announce_Register( announce_handler_t *p_announce,
session_descriptor_t *p_session,
announce_method_t *p_method );
static int announce_UnRegister( announce_handler_t *p_announce,
session_descriptor_t *p_session );
struct announce_method_t
{
} sap_method;
/****************************************************************************
* Sout-side functions
****************************************************************************/
/**
* 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 psz_dst session address (needed for SAP address auto detection)
* \param p_method an announce method descriptor
* \return the new session descriptor structure
*/
session_descriptor_t *
sout_AnnounceRegisterSDP( sout_instance_t *p_sout, const char *psz_sdp,
const char *psz_dst, 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( VLC_OBJECT( p_sout ) );
if( !p_announce )
{
msg_Err( p_sout, "Creation failed" );
return NULL;
}
vlc_object_yield( p_announce );
}
p_session = malloc( sizeof( *p_session ) );
memset( p_session, 0, sizeof( *p_session ) );
p_session->psz_sdp = strdup( psz_sdp );
/* GRUIK. We should not convert back-and-forth from string to numbers */
struct addrinfo *res;
if (vlc_getaddrinfo (VLC_OBJECT (p_sout), psz_dst, 0, NULL, &res) == 0)
{
if (res->ai_addrlen <= sizeof (p_session->addr))
memcpy (&p_session->addr, res->ai_addr,
p_session->addrlen = res->ai_addrlen);
vlc_freeaddrinfo (res);
}
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 );
if( i_ret == 0 )
free( p_session );
vlc_object_release( p_announce );
return i_ret;
}
/**
* \return the SAP announce method
*/
announce_method_t * sout_SAPMethod (void)
{
return &sap_method;
}
void sout_MethodRelease (announce_method_t *m)
{
assert (m == &sap_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
*/
static 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 )
return NULL;
p_announce->p_sap = NULL;
vlc_object_attach( p_announce, p_this->p_libvlc);
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 )
{
/* Exit the SAP */
vlc_object_release( p_announce->p_sap );
}
/* Free the structure */
vlc_object_release( p_announce );
return VLC_SUCCESS;
}
/* Register an announce */
static int announce_Register( announce_handler_t *p_announce,
session_descriptor_t *p_session,
announce_method_t *p_method )
{
if (p_method == NULL)
return VLC_EGENERIC;
msg_Dbg( p_announce, "registering announce");
if( p_method == &sap_method )
{
/* Do we already have a SAP announce handler ? */
if( !p_announce->p_sap )
{
sap_handler_t *p_sap = announce_SAPHandlerCreate( p_announce );
msg_Dbg( p_announce, "creating SAP announce handler");
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 );
}
else
{
msg_Err( p_announce, "announce type unsupported" );
return VLC_EGENERIC;
}
return VLC_SUCCESS;
}
/* Unregister an announce */
static int announce_UnRegister( announce_handler_t *p_announce,
session_descriptor_t *p_session )
{
msg_Dbg( p_announce, "unregistering announce" );
if( p_announce->p_sap )
p_announce->p_sap->pf_del( p_announce->p_sap, p_session );
return VLC_SUCCESS;
}