diff options
-rw-r--r-- | include/asterisk/sdp.h | 10 | ||||
-rw-r--r-- | include/asterisk/sdp_options.h | 20 | ||||
-rw-r--r-- | include/asterisk/sdp_state.h | 86 | ||||
-rw-r--r-- | main/sdp.c | 93 | ||||
-rw-r--r-- | main/sdp_options.c | 1 | ||||
-rw-r--r-- | main/sdp_state.c | 302 |
6 files changed, 392 insertions, 120 deletions
diff --git a/include/asterisk/sdp.h b/include/asterisk/sdp.h index 4d6d2fbb5..3649b4037 100644 --- a/include/asterisk/sdp.h +++ b/include/asterisk/sdp.h @@ -395,20 +395,20 @@ struct ast_sdp_a_line *ast_sdp_get_a(const struct ast_sdp *sdp, int index); int ast_sdp_add_m(struct ast_sdp *sdp, struct ast_sdp_m_line *m_line); /*! - * \brief Add a Media Description to an SDP + * \brief Add an RTP Media Description to an SDP * * \param sdp SDP + * \param sdp_state SDP state information * \param options SDP Options - * \param rtp ast_rtp_instance - * \param stream stream + * \param stream_index stream * * \retval 0 Success * \retval non-0 Failure * * \since 15 */ -int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options *options, - struct ast_rtp_instance *rtp, const struct ast_stream *stream); +int ast_sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, + const struct ast_sdp_options *options, int stream_index); /*! * \brief Get the count of Media Descriptions on an SDP diff --git a/include/asterisk/sdp_options.h b/include/asterisk/sdp_options.h index 3995faf4a..0186eea57 100644 --- a/include/asterisk/sdp_options.h +++ b/include/asterisk/sdp_options.h @@ -270,26 +270,6 @@ unsigned int ast_sdp_options_get_g726_non_standard(struct ast_sdp_options *optio /*! * \since 15.0.0 - * \brief Set SDP Options locally_held - * - * \param options SDP Options - * \param locally_held - */ -void ast_sdp_options_set_locally_held(struct ast_sdp_options *options, - unsigned int locally_held); - -/*! - * \since 15.0.0 - * \brief Get SDP Options locally_held - * - * \param options SDP Options - * - * \returns locally_held - */ -unsigned int ast_sdp_options_get_locally_held(struct ast_sdp_options *options); - -/*! - * \since 15.0.0 * \brief Set SDP Options tos_audio * * \param options SDP Options diff --git a/include/asterisk/sdp_state.h b/include/asterisk/sdp_state.h index e2f13eb61..a186d7eef 100644 --- a/include/asterisk/sdp_state.h +++ b/include/asterisk/sdp_state.h @@ -23,6 +23,7 @@ #include "asterisk/sdp_options.h" struct ast_sdp_state; +struct ast_sockaddr; /*! * \brief Allocate a new SDP state @@ -51,6 +52,26 @@ struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(const struct ast_sdp_sta int stream_index); /*! + * \brief Get the global connection address on the SDP state. + */ +const struct ast_sockaddr *ast_sdp_state_get_connection_address(const struct ast_sdp_state *sdp_state); + +/*! + * \brief Get the connection address for a particular stream. + * + * \param sdp_state + * \param stream_index The particular stream to get the connection address of + * \param address[out] A place to store the address in + * + * \retval 0 Success + * + * \note + * Stream numbers correspond to the streams in the topology of the associated channel + */ +int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_state, + int stream_index, struct ast_sockaddr *address); + +/*! * \brief Get the joint negotiated streams based on local and remote capabilities. * * If this is called prior to receiving a remote SDP, then this will just mirror @@ -149,4 +170,69 @@ int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, void */ int ast_sdp_state_reset(struct ast_sdp_state *sdp_state); +/*! + * \brief Update the local stream topology on the SDP state. + * + * \param sdp_state + * \param streams The new stream topology. + * + * \retval 0 Success + * + * \since 15 + */ +int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *streams); + +/*! + * \brief Set the local address (IP address) to use for connection addresses + * + * \param sdp_state + * \param address The local address + * + * \note + * Passing NULL as an address will unset the explicit local connection address. + * + * \since 15 + */ +void ast_sdp_state_set_local_address(struct ast_sdp_state *sdp_state, struct ast_sockaddr *address); + +/*! + * \brief Set the connection address (IP address and port) to use for a specific stream + * + * \param sdp_state + * \param stream_index The stream to set the connection address for + * \param address The connection address + * + * \retval 0 Success + * + * \note + * Passing NULL as an address will unset the explicit local connection address. + * + * \since 15 + */ +int ast_sdp_state_set_connection_address(struct ast_sdp_state *sdp_state, int stream_index, + struct ast_sockaddr *address); + +/*! + * \since 15.0.0 + * \brief Set a stream to be held or unheld + * + * \param sdp_state + * \param stream_index The stream to set the held value for + * \param locally_held + */ +void ast_sdp_state_set_locally_held(struct ast_sdp_state *sdp_state, + int stream_index, unsigned int locally_held); + +/*! + * \since 15.0.0 + * \brief Get whether a stream is held or not + * + * \param sdp_state + * \param stream_index The stream to get the held state for + * + * \returns locally_held + */ +unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_state, + int stream_index); + #endif /* _ASTERISK_SDP_STATE_H */ diff --git a/main/sdp.c b/main/sdp.c index 246763edf..1ef6400b9 100644 --- a/main/sdp.c +++ b/main/sdp.c @@ -500,69 +500,10 @@ int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_opt return 0; } -/* TODO - * This isn't set anywhere yet. - */ -/*! \brief Scheduler for RTCP purposes */ -static struct ast_sched_context *sched; - -/*! \brief Internal function which creates an RTP instance */ -static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options, - enum ast_media_type media_type) -{ - struct ast_rtp_instance *rtp; - struct ast_rtp_engine_ice *ice; - struct ast_sockaddr temp_media_address; - static struct ast_sockaddr address_rtp; - struct ast_sockaddr *media_address = &address_rtp; - - if (options->bind_rtp_to_media_address && !ast_strlen_zero(options->media_address)) { - ast_sockaddr_parse(&temp_media_address, options->media_address, 0); - media_address = &temp_media_address; - } else { - if (ast_check_ipv6()) { - ast_sockaddr_parse(&address_rtp, "::", 0); - } else { - ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0); - } - } - - if (!(rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL))) { - ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", - options->rtp_engine); - return NULL; - } - - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, 1); - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_NAT, options->rtp_symmetric); - - if (options->ice == AST_SDP_ICE_DISABLED && (ice = ast_rtp_instance_get_ice(rtp))) { - ice->stop(rtp); - } - - if (options->telephone_event) { - ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_RFC2833); - ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_DTMF, 1); - } - - if (media_type == AST_MEDIA_TYPE_AUDIO && - (options->tos_audio || options->cos_audio)) { - ast_rtp_instance_set_qos(rtp, options->tos_audio, - options->cos_audio, "SIP RTP Audio"); - } else if (media_type == AST_MEDIA_TYPE_VIDEO && - (options->tos_video || options->cos_video)) { - ast_rtp_instance_set_qos(rtp, options->tos_video, - options->cos_video, "SIP RTP Video"); - } - - ast_rtp_instance_set_last_rx(rtp, time(NULL)); - - return rtp; -} - -int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options *options, - struct ast_rtp_instance *rtp, const struct ast_stream *stream) +int ast_sdp_add_m_from_rtp_stream(struct ast_sdp *sdp, const struct ast_sdp_state *sdp_state, + const struct ast_sdp_options *options, int stream_index) { + struct ast_stream *stream = ast_stream_topology_get_stream(ast_sdp_state_get_local_topology(sdp_state), stream_index); struct ast_sdp_m_line *m_line; struct ast_format_cap *caps; int i; @@ -572,13 +513,15 @@ int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options enum ast_media_type media_type; char tmp[64]; struct ast_sockaddr address_rtp; + struct ast_rtp_instance *rtp = ast_sdp_state_get_rtp_instance(sdp_state, stream_index); struct ast_sdp_a_line *a_line; - - ast_assert(sdp && options && rtp && stream); + ast_assert(sdp && options && stream); media_type = ast_stream_get_type(stream); - ast_rtp_instance_get_local_address(rtp, &address_rtp); + if (ast_sdp_state_get_stream_connection_address(sdp_state, 0, &address_rtp)) { + return -1; + } m_line = ast_sdp_m_alloc( ast_codec_media_type2str(ast_stream_get_type(stream)), @@ -673,7 +616,7 @@ int ast_sdp_add_m_from_stream(struct ast_sdp *sdp, const struct ast_sdp_options } } - a_line = ast_sdp_a_alloc(options->locally_held ? "sendonly" : "sendrecv", ""); + a_line = ast_sdp_a_alloc(ast_sdp_state_get_locally_held(sdp_state, stream_index) ? "sendonly" : "sendrecv", ""); if (!a_line || ast_sdp_m_add_a(m_line, a_line)) { ast_sdp_a_free(a_line); ast_sdp_m_free(m_line); @@ -699,7 +642,6 @@ struct ast_sdp *ast_sdp_create_from_state(const struct ast_sdp_state *sdp_state) struct ast_sdp_c_line *c_line = NULL; struct ast_sdp_s_line *s_line = NULL; struct ast_sdp_t_line *t_line = NULL; - struct ast_rtp_instance *rtp = NULL; char *address_type; struct timeval tv = ast_tvnow(); uint32_t t; @@ -732,25 +674,18 @@ struct ast_sdp *ast_sdp_create_from_state(const struct ast_sdp_state *sdp_state) } for (stream_num = 0; stream_num < stream_count; stream_num++) { - struct ast_stream *stream = ast_stream_topology_get_stream(topology, stream_num); - - rtp = create_rtp(options, ast_stream_get_type(stream)); - if (!rtp) { - goto error; - } - - ast_stream_set_data(stream, AST_STREAM_DATA_RTP_INSTANCE, - rtp, (ast_stream_data_free_fn)&ast_rtp_instance_destroy); + enum ast_media_type type = ast_stream_get_type(ast_stream_topology_get_stream(topology, stream_num)); - if (ast_sdp_add_m_from_stream(sdp, options, rtp, stream)) { - goto error; + if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { + if (ast_sdp_add_m_from_rtp_stream(sdp, sdp_state, options, stream_num)) { + goto error; + } } } return sdp; error: - ao2_cleanup(rtp); if (sdp) { ast_sdp_free(sdp); } else { diff --git a/main/sdp_options.c b/main/sdp_options.c index ca076ac7b..608481722 100644 --- a/main/sdp_options.c +++ b/main/sdp_options.c @@ -64,7 +64,6 @@ DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_symmetric); DEFINE_GETTERS_SETTERS_FOR(unsigned int, telephone_event); DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_ipv6); DEFINE_GETTERS_SETTERS_FOR(unsigned int, g726_non_standard); -DEFINE_GETTERS_SETTERS_FOR(unsigned int, locally_held); DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_audio); DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_video); diff --git a/main/sdp_state.c b/main/sdp_state.c index 1b09ce16f..5858a65ab 100644 --- a/main/sdp_state.c +++ b/main/sdp_state.c @@ -22,10 +22,14 @@ #include "asterisk/sdp_translator.h" #include "asterisk/vector.h" #include "asterisk/utils.h" +#include "asterisk/netsock2.h" +#include "asterisk/rtp_engine.h" #include "../include/asterisk/sdp.h" #include "asterisk/stream.h" +#include "sdp_private.h" + enum ast_sdp_state_machine { /*! \brief The initial state. * @@ -61,13 +65,33 @@ enum ast_sdp_state_machine { typedef int (*state_fn)(struct ast_sdp_state *state); +struct sdp_state_stream { + union { + /*! The underlying RTP instance */ + struct ast_rtp_instance *instance; + }; + /*! An explicit connection address for this stream */ + struct ast_sockaddr connection_address; + /*! Whether this stream is held or not */ + unsigned int locally_held; +}; + +struct sdp_state_capabilities { + /*! Stream topology */ + struct ast_stream_topology *topology; + /*! Additional information about the streams */ + AST_VECTOR(, struct sdp_state_stream) streams; + /*! An explicit global connection address */ + struct ast_sockaddr connection_address; +}; + struct ast_sdp_state { /*! Local capabilities, learned through configuration */ - struct ast_stream_topology *local_capabilities; + struct sdp_state_capabilities local_capabilities; /*! Remote capabilities, learned through remote SDP */ struct ast_stream_topology *remote_capabilities; /*! Joint capabilities. The combined local and remote capabilities. */ - struct ast_stream_topology *joint_capabilities; + struct sdp_state_capabilities joint_capabilities; /*! Local SDP. Generated via the options and local capabilities. */ struct ast_sdp *local_sdp; /*! Remote SDP. Received directly from a peer. */ @@ -100,25 +124,42 @@ struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams, return NULL; } - sdp_state->local_capabilities = ast_stream_topology_clone(streams); - if (!sdp_state->local_capabilities) { + if (ast_sdp_state_update_local_topology(sdp_state, streams)) { ast_sdp_state_free(sdp_state); return NULL; } + sdp_state->state = SDP_STATE_INITIAL; return sdp_state; } +static void sdp_state_capabilities_free(struct sdp_state_capabilities *sdp_capabilities) +{ + int stream_index; + + for (stream_index = 0; stream_index < AST_VECTOR_SIZE(&sdp_capabilities->streams); stream_index++) { + struct sdp_state_stream *stream_state = AST_VECTOR_GET_ADDR(&sdp_capabilities->streams, stream_index); + enum ast_media_type type = ast_stream_get_type(ast_stream_topology_get_stream(sdp_capabilities->topology, stream_index)); + + if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { + ast_rtp_instance_destroy(stream_state->instance); + } + } + + ast_stream_topology_free(sdp_capabilities->topology); + AST_VECTOR_FREE(&sdp_capabilities->streams); +} + void ast_sdp_state_free(struct ast_sdp_state *sdp_state) { if (!sdp_state) { return; } - ast_stream_topology_free(sdp_state->local_capabilities); + sdp_state_capabilities_free(&sdp_state->local_capabilities); ast_stream_topology_free(sdp_state->remote_capabilities); - ast_stream_topology_free(sdp_state->joint_capabilities); + sdp_state_capabilities_free(&sdp_state->joint_capabilities); ast_sdp_free(sdp_state->local_sdp); ast_sdp_free(sdp_state->remote_sdp); ast_sdp_free(sdp_state->joint_sdp); @@ -126,19 +167,75 @@ void ast_sdp_state_free(struct ast_sdp_state *sdp_state) ast_sdp_translator_free(sdp_state->translator); } +static struct sdp_state_stream *sdp_state_get_stream(const struct ast_sdp_state *sdp_state, int stream_index) +{ + if (stream_index >= AST_VECTOR_SIZE(&sdp_state->local_capabilities.streams)) { + return NULL; + } + + return AST_VECTOR_GET_ADDR(&sdp_state->local_capabilities.streams, stream_index); +} + struct ast_rtp_instance *ast_sdp_state_get_rtp_instance( const struct ast_sdp_state *sdp_state, int stream_index) { - struct ast_stream *stream; + struct sdp_state_stream *stream_state; ast_assert(sdp_state != NULL); - stream = ast_stream_topology_get_stream(sdp_state->local_capabilities, stream_index); - if (!stream) { + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { return NULL; } - return (struct ast_rtp_instance *)ast_stream_get_data(stream, AST_STREAM_DATA_RTP_INSTANCE); + return stream_state->instance; +} + +const struct ast_sockaddr *ast_sdp_state_get_connection_address(const struct ast_sdp_state *sdp_state) +{ + ast_assert(sdp_state != NULL); + + return &sdp_state->local_capabilities.connection_address; +} + +int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_state, + int stream_index, struct ast_sockaddr *address) +{ + struct sdp_state_stream *stream_state; + enum ast_media_type type; + + ast_assert(sdp_state != NULL); + ast_assert(address != NULL); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return -1; + } + + /* If an explicit connection address has been provided for the stream return it */ + if (!ast_sockaddr_isnull(&stream_state->connection_address)) { + ast_sockaddr_copy(address, &stream_state->connection_address); + return 0; + } + + type = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->local_capabilities.topology, + stream_index)); + + if (type == AST_MEDIA_TYPE_AUDIO || type == AST_MEDIA_TYPE_VIDEO) { + ast_rtp_instance_get_local_address(stream_state->instance, address); + } else { + return -1; + } + + /* If an explicit global connection address is set use it here for the IP part */ + if (!ast_sockaddr_isnull(&sdp_state->local_capabilities.connection_address)) { + int port = ast_sockaddr_port(address); + + ast_sockaddr_copy(address, &sdp_state->local_capabilities.connection_address); + ast_sockaddr_set_port(address, port); + } + + return 0; } const struct ast_stream_topology *ast_sdp_state_get_joint_topology( @@ -146,9 +243,9 @@ const struct ast_stream_topology *ast_sdp_state_get_joint_topology( { ast_assert(sdp_state != NULL); if (sdp_state->state == SDP_STATE_NEGOTIATED) { - return sdp_state->joint_capabilities; + return sdp_state->joint_capabilities.topology; } else { - return sdp_state->local_capabilities; + return sdp_state->local_capabilities.topology; } } @@ -157,7 +254,7 @@ const struct ast_stream_topology *ast_sdp_state_get_local_topology( { ast_assert(sdp_state != NULL); - return sdp_state->local_capabilities; + return sdp_state->local_capabilities.topology; } const struct ast_sdp_options *ast_sdp_state_get_options( @@ -193,11 +290,109 @@ static int merge_sdps(struct ast_sdp_state *sdp_state) } #endif +/* TODO + * This isn't set anywhere yet. + */ +/*! \brief Scheduler for RTCP purposes */ +static struct ast_sched_context *sched; + +/*! \brief Internal function which creates an RTP instance */ +static struct ast_rtp_instance *create_rtp(const struct ast_sdp_options *options, + enum ast_media_type media_type) +{ + struct ast_rtp_instance *rtp; + struct ast_rtp_engine_ice *ice; + struct ast_sockaddr temp_media_address; + static struct ast_sockaddr address_rtp; + struct ast_sockaddr *media_address = &address_rtp; + + if (options->bind_rtp_to_media_address && !ast_strlen_zero(options->media_address)) { + ast_sockaddr_parse(&temp_media_address, options->media_address, 0); + media_address = &temp_media_address; + } else { + if (ast_check_ipv6()) { + ast_sockaddr_parse(&address_rtp, "::", 0); + } else { + ast_sockaddr_parse(&address_rtp, "0.0.0.0", 0); + } + } + + if (!(rtp = ast_rtp_instance_new(options->rtp_engine, sched, media_address, NULL))) { + ast_log(LOG_ERROR, "Unable to create RTP instance using RTP engine '%s'\n", + options->rtp_engine); + return NULL; + } + + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_RTCP, 1); + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_NAT, options->rtp_symmetric); + + if (options->ice == AST_SDP_ICE_DISABLED && (ice = ast_rtp_instance_get_ice(rtp))) { + ice->stop(rtp); + } + + if (options->telephone_event) { + ast_rtp_instance_dtmf_mode_set(rtp, AST_RTP_DTMF_MODE_RFC2833); + ast_rtp_instance_set_prop(rtp, AST_RTP_PROPERTY_DTMF, 1); + } + + if (media_type == AST_MEDIA_TYPE_AUDIO && + (options->tos_audio || options->cos_audio)) { + ast_rtp_instance_set_qos(rtp, options->tos_audio, + options->cos_audio, "SIP RTP Audio"); + } else if (media_type == AST_MEDIA_TYPE_VIDEO && + (options->tos_video || options->cos_video)) { + ast_rtp_instance_set_qos(rtp, options->tos_video, + options->cos_video, "SIP RTP Video"); + } + + ast_rtp_instance_set_last_rx(rtp, time(NULL)); + + return rtp; +} + +static int sdp_state_setup_local_streams(struct ast_sdp_state *sdp_state) +{ + int stream_index; + + for (stream_index = 0; stream_index < AST_VECTOR_SIZE(&sdp_state->local_capabilities.streams); stream_index++) { + struct sdp_state_stream *stream_state_local = AST_VECTOR_GET_ADDR(&sdp_state->local_capabilities.streams, stream_index); + struct sdp_state_stream *stream_state_joint = NULL; + enum ast_media_type type_local = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->local_capabilities.topology, stream_index)); + enum ast_media_type type_joint = AST_MEDIA_TYPE_UNKNOWN; + + if (stream_index < AST_VECTOR_SIZE(&sdp_state->joint_capabilities.streams)) { + stream_state_joint = AST_VECTOR_GET_ADDR(&sdp_state->joint_capabilities.streams, stream_index); + type_joint = ast_stream_get_type(ast_stream_topology_get_stream(sdp_state->joint_capabilities.topology, stream_index)); + } + + /* If we can reuse an existing media stream then do so */ + if (type_local == type_joint) { + if (type_local == AST_MEDIA_TYPE_AUDIO || type_local == AST_MEDIA_TYPE_VIDEO) { + stream_state_local->instance = ao2_bump(stream_state_joint->instance); + continue; + } + } + + if (type_local == AST_MEDIA_TYPE_AUDIO || type_local == AST_MEDIA_TYPE_VIDEO) { + /* We need to create a new RTP instance */ + stream_state_local->instance = create_rtp(sdp_state->options, type_local); + if (!stream_state_local->instance) { + return -1; + } + } + } + + return 0; +} + const struct ast_sdp *ast_sdp_state_get_local_sdp(struct ast_sdp_state *sdp_state) { ast_assert(sdp_state != NULL); if (!sdp_state->local_sdp) { + if (sdp_state_setup_local_streams(sdp_state)) { + return NULL; + } sdp_state->local_sdp = ast_sdp_create_from_state(sdp_state); } @@ -254,10 +449,87 @@ int ast_sdp_state_reset(struct ast_sdp_state *sdp_state) 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; + ast_stream_topology_free(sdp_state->joint_capabilities.topology); + sdp_state->joint_capabilities.topology = NULL; sdp_state->state = SDP_STATE_INITIAL; return 0; } + +int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *streams) +{ + ast_assert(sdp_state != NULL); + ast_assert(streams != NULL); + + sdp_state_capabilities_free(&sdp_state->local_capabilities); + sdp_state->local_capabilities.topology = ast_stream_topology_clone(streams); + if (!sdp_state->local_capabilities.topology) { + return -1; + } + + if (AST_VECTOR_INIT(&sdp_state->local_capabilities.streams, ast_stream_topology_get_count(streams))) { + return -1; + } + + return 0; +} + +void ast_sdp_state_set_local_address(struct ast_sdp_state *sdp_state, struct ast_sockaddr *address) +{ + ast_assert(sdp_state != NULL); + + if (!address) { + ast_sockaddr_setnull(&sdp_state->local_capabilities.connection_address); + } else { + ast_sockaddr_copy(&sdp_state->local_capabilities.connection_address, address); + } +} + +int ast_sdp_state_set_connection_address(struct ast_sdp_state *sdp_state, int stream_index, + struct ast_sockaddr *address) +{ + struct sdp_state_stream *stream_state; + ast_assert(sdp_state != NULL); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return -1; + } + + if (!address) { + ast_sockaddr_setnull(&stream_state->connection_address); + } else { + ast_sockaddr_copy(&stream_state->connection_address, address); + } + + return 0; +} + +void ast_sdp_state_set_locally_held(struct ast_sdp_state *sdp_state, + int stream_index, unsigned int locally_held) +{ + struct sdp_state_stream *stream_state; + ast_assert(sdp_state != NULL); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return; + } + + stream_state->locally_held = locally_held; +} + +unsigned int ast_sdp_state_get_locally_held(const struct ast_sdp_state *sdp_state, + int stream_index) +{ + struct sdp_state_stream *stream_state; + ast_assert(sdp_state != NULL); + + stream_state = sdp_state_get_stream(sdp_state, stream_index); + if (!stream_state) { + return 0; + } + + return stream_state->locally_held; +} |