diff options
Diffstat (limited to 'main/sdp_state.c')
-rw-r--r-- | main/sdp_state.c | 157 |
1 files changed, 156 insertions, 1 deletions
diff --git a/main/sdp_state.c b/main/sdp_state.c index 04de6e385..b478e7148 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -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; +} |