summaryrefslogtreecommitdiff
path: root/main/sdp_state.c
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2017-02-22 15:11:29 -0600
committerJoshua Colp <jcolp@digium.com>2017-03-01 12:12:46 +0000
commit9c55a7179800fa66e1887383f2a75eac0efd24b0 (patch)
treef72f33b1a52cd08d7a69f9a9f388f4c3042c2e6a /main/sdp_state.c
parent26bf1846e2d436ffec1867351f25e5bcd43139c6 (diff)
SDP: Add initial SDP state machine.
This introduces and documents the various states in the state machine. This also introduces API functions that induce state changes, and places TODO comments telling what needs to be done in addition to what is already there. Those TODOs will be replaced with real code in upcoming changes. Change-Id: I871c0eb480b4c84d83e91ac5628e7a673e8b89ed
Diffstat (limited to 'main/sdp_state.c')
-rw-r--r--main/sdp_state.c157
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;
+}