@ -25,6 +25,41 @@
# include "asterisk/utils.h"
# include "asterisk/stream.h"
enum ast_sdp_state_machine {
/*! \brief The initial state.
*
* The state machine starts here . It also goes back to this
* state whenever ast_sdp_state_reset ( ) is called .
*/
SDP_STATE_INITIAL ,
/*! \brief We are the SDP offerer.
*
* The state machine enters this state if in the initial state
* and ast_sdp_state_get_local ( ) is called . When this state is
* entered , a local SDP is created and then returned .
*/
SDP_STATE_OFFERER ,
/*! \brief We are the SDP answerer.
*
* The state machine enters this state if in the initial state
* and ast_sdp_state_set_remote ( ) is called .
*/
SDP_STATE_ANSWERER ,
/*! \brief The SDP has been negotiated.
*
* This state can be entered from either the offerer or answerer
* state . When this state is entered , a joint SDP is created .
*/
SDP_STATE_NEGOTIATED ,
/*! \brief Not an actual state.
*
* This is just here to mark the end of the enumeration .
*/
SDP_STATE_END ,
} ;
typedef int ( * state_fn ) ( struct ast_sdp_state * state ) ;
struct ast_sdp_state {
/*! Local capabilities, learned through configuration */
struct ast_stream_topology * local_capabilities ;
@ -44,6 +79,8 @@ struct ast_sdp_state {
struct ast_sdp_translator * translator ;
/*! RTP instance for each media stream */
AST_VECTOR ( , struct ast_rtp_instance * ) rtp ;
/*! The current state machine state that we are in */
enum ast_sdp_state_machine state ;
} ;
struct ast_sdp_state * ast_sdp_state_alloc ( struct ast_stream_topology * streams , struct ast_sdp_options * options )
@ -68,6 +105,7 @@ struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, s
ast_sdp_state_free ( sdp_state ) ;
return NULL ;
}
sdp_state - > state = SDP_STATE_INITIAL ;
return sdp_state ;
}
@ -90,6 +128,8 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state)
struct ast_rtp_instance * ast_sdp_state_get_rtp_instance ( struct ast_sdp_state * sdp_state , int stream_index )
{
ast_assert ( sdp_state ! = NULL ) ;
if ( stream_index > = AST_VECTOR_SIZE ( & sdp_state - > rtp ) ) {
return NULL ;
}
@ -99,9 +139,124 @@ struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(struct ast_sdp_state *sd
struct ast_stream_topology * ast_sdp_state_get_joint_topology ( struct ast_sdp_state * sdp_state )
{
if ( sdp_state - > joint_capabilities ) {
ast_assert ( sdp_state ! = NULL ) ;
if ( sdp_state - > state = = SDP_STATE_NEGOTIATED ) {
return sdp_state - > joint_capabilities ;
} else {
return sdp_state - > local_capabilities ;
}
}
static int merge_sdps ( struct ast_sdp_state * sdp_state )
{
ast_assert ( sdp_state - > local_sdp ! = NULL ) ;
ast_assert ( sdp_state - > remote_sdp ! = NULL ) ;
/* XXX STUB */
/* The goal of this function is to take
* sdp_state - > local_sdp and sdp_state - > remote_sdp
* and negotiate those into a joint SDP . This joint
* SDP should be stored in sdp_state - > joint_sdp . After
* the joint SDP is created , the joint SDP should be
* used to create the joint topology . Finally , if necessary ,
* the RTP session may need to be adjusted in some ways . For
* instance , if we previously opened three ports for three
* streams , but we negotiate down to two streams , then we
* can shut down the port for the third stream . Similarly ,
* if we end up negotiating something like BUNDLE , then we may
* need to tell the RTP layer to close ports and to multiplex
* streams .
*/
return 0 ;
}
const void * ast_sdp_state_get_local ( struct ast_sdp_state * sdp_state )
{
struct ast_sdp * sdp ;
ast_assert ( sdp_state ! = NULL ) ;
/*TODO Create RTP instances based on local topology and SDP options (if not already created) */
/*TODO Create local SDP based on local topology, SDP options, and RTP ports (if not already created) */
switch ( sdp_state - > state ) {
case SDP_STATE_INITIAL :
sdp_state - > state = SDP_STATE_OFFERER ;
/* Fall through */
case SDP_STATE_OFFERER :
default :
sdp = sdp_state - > local_sdp ;
break ;
case SDP_STATE_ANSWERER :
sdp_state - > state = SDP_STATE_NEGOTIATED ;
merge_sdps ( sdp_state ) ;
/* Fall through */
case SDP_STATE_NEGOTIATED :
sdp = sdp_state - > joint_sdp ;
break ;
}
return ast_sdp_translator_from_sdp ( sdp_state - > translator , sdp ) ;
}
int ast_sdp_state_set_remote ( struct ast_sdp_state * sdp_state , void * remote )
{
struct ast_sdp * sdp ;
ast_assert ( sdp_state ! = NULL ) ;
sdp = ast_sdp_translator_to_sdp ( sdp_state - > translator , remote ) ;
if ( ! sdp ) {
return - 1 ;
}
sdp_state - > remote_sdp = remote ;
/* TODO Convert the remote SDP into a topology and store that in
* sdp_state - > remote_capabilities
*/
switch ( sdp_state - > state ) {
case SDP_STATE_ANSWERER :
default :
break ;
case SDP_STATE_INITIAL :
sdp_state - > state = SDP_STATE_ANSWERER ;
break ;
case SDP_STATE_OFFERER :
sdp_state - > state = SDP_STATE_NEGOTIATED ;
/* Fall through */
case SDP_STATE_NEGOTIATED :
/* If state is already negotiated, and we receive a new
* remote SDP , we need to re - create the joint SDP and joint
* capabilities
*/
merge_sdps ( sdp_state ) ;
break ;
}
return 0 ;
}
int ast_sdp_state_reset ( struct ast_sdp_state * sdp_state )
{
ast_assert ( sdp_state ! = NULL ) ;
ast_sdp_free ( sdp_state - > local_sdp ) ;
sdp_state - > local_sdp = NULL ;
ast_sdp_free ( sdp_state - > remote_sdp ) ;
sdp_state - > remote_sdp = NULL ;
ast_sdp_free ( sdp_state - > joint_sdp ) ;
sdp_state - > joint_sdp = NULL ;
ast_stream_topology_free ( sdp_state - > remote_capabilities ) ;
sdp_state - > remote_capabilities = NULL ;
ast_stream_topology_free ( sdp_state - > joint_capabilities ) ;
sdp_state - > joint_capabilities = NULL ;
sdp_state - > state = SDP_STATE_INITIAL ;
return 0 ;
}