Merge "SDP: Rework SDP offer/answer model and update capabilities merges."

This commit is contained in:
Joshua Colp
2017-07-26 08:20:35 -05:00
committed by Gerrit Code Review
11 changed files with 3400 additions and 612 deletions

View File

@@ -253,16 +253,6 @@ void ast_sdp_s_free(struct ast_sdp_s_line *s_line);
*/
void ast_sdp_t_free(struct ast_sdp_t_line *t_line);
/*!
* \brief Free an SDP
* Frees the sdp and all resources it contains
*
* \param sdp The sdp to free
*
* \since 15
*/
void ast_sdp_free(struct ast_sdp *sdp);
/*!
* \brief Allocate an SDP Attribute
*
@@ -544,7 +534,7 @@ int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_opt
int rtp_code, int asterisk_format, const struct ast_format *format, int code);
/*!
* \brief Create an SDP
* \brief Create an SDP ao2 object
*
* \param o_line Origin
* \param c_line Connection

View File

@@ -20,6 +20,7 @@
#define _ASTERISK_SDP_OPTIONS_H
#include "asterisk/udptl.h"
#include "asterisk/format_cap.h"
struct ast_sdp_options;
@@ -79,6 +80,149 @@ enum ast_sdp_options_encryption {
AST_SDP_ENCRYPTION_DTLS,
};
/*!
* \brief Callback when processing an offer SDP for our answer SDP.
* \since 15.0.0
*
* \details
* This callback is called after merging our last negotiated topology
* with the remote's offer topology and before we have sent our answer
* SDP. At this point you can alter new_topology streams. You can
* decline, remove formats, or rename streams. Changing anything else
* on the streams is likely to not end well.
*
* * To decline a stream simply set the stream state to
* AST_STREAM_STATE_REMOVED. You could implement a maximum number
* of active streams of a given type policy.
*
* * To remove formats use the format API to remove any formats from a
* stream. The streams have the current joint negotiated formats.
* Most likely you would want to remove all but the first format.
*
* * To rename a stream you need to clone the stream and give it a
* new name and then set it in new_topology using
* ast_stream_topology_set_stream().
*
* \note Removing all formats is an error. You should decline the
* stream instead.
*
* \param context User supplied context data pointer for the SDP
* state.
* \param old_topology Active negotiated topology. NULL if this is
* the first SDP negotiation. The old topology is available so you
* can tell if any streams are new or changing type.
* \param new_topology New negotiated topology that we intend to
* generate the answer SDP.
*
* \return Nothing
*/
typedef void (*ast_sdp_answerer_modify_cb)(void *context,
const struct ast_stream_topology *old_topology,
struct ast_stream_topology *new_topology);
/*!
* \internal
* \brief Callback when generating a topology for our SDP offer.
* \since 15.0.0
*
* \details
* This callback is called after merging any topology updates from the
* system by ast_sdp_state_update_local_topology() and before we have
* sent our offer SDP. At this point you can alter new_topology
* streams. You can decline, add/remove/update formats, or rename
* streams. Changing anything else on the streams is likely to not
* end well.
*
* * To decline a stream simply set the stream state to
* AST_STREAM_STATE_REMOVED. You could implement a maximum number
* of active streams of a given type policy.
*
* * To update formats use the format API to change formats of the
* streams. The streams have the current proposed formats. You
* could do whatever you want for formats but you should stay within
* the configured formats for the stream type's endpoint. However,
* you should use ast_sdp_state_update_local_topology() instead of
* this backdoor method.
*
* * To rename a stream you need to clone the stream and give it a
* new name and then set it in new_topology using
* ast_stream_topology_set_stream().
*
* \note Removing all formats is an error. You should decline the
* stream instead.
*
* \note Declined new streams that are in slots higher than present in
* old_topology are removed so the SDP can be smaller. The remote has
* never seen those slots so we shouldn't bother keeping them.
*
* \param context User supplied context data pointer for the SDP
* state.
* \param old_topology Active negotiated topology. NULL if this is
* the first SDP negotiation. The old topology is available so you
* can tell if any streams are new or changing type.
* \param new_topology Merged topology that we intend to generate the
* offer SDP.
*
* \return Nothing
*/
typedef void (*ast_sdp_offerer_modify_cb)(void *context,
const struct ast_stream_topology *old_topology,
struct ast_stream_topology *new_topology);
/*!
* \brief Callback when generating an offer SDP to configure extra stream data.
* \since 15.0.0
*
* \details
* This callback is called after any ast_sdp_offerer_modify_cb
* callback and before we have sent our offer SDP. The callback can
* call several SDP API calls to configure the proposed capabilities
* of streams before we create the SDP offer. For example, the
* callback could configure a stream specific connection address, T.38
* parameters, RTP instance, or UDPTL instance parameters.
*
* \param context User supplied context data pointer for the SDP
* state.
* \param topology Topology ready to configure extra stream options.
*
* \return Nothing
*/
typedef void (*ast_sdp_offerer_config_cb)(void *context, const struct ast_stream_topology *topology);
/*!
* \brief Callback before applying a topology.
* \since 15.0.0
*
* \details
* This callback is called before the topology is applied so the
* using module can do what is necessary before the topology becomes
* active.
*
* \param context User supplied context data pointer for the SDP
* state.
* \param topology Topology ready to be applied.
*
* \return Nothing
*/
typedef void (*ast_sdp_preapply_cb)(void *context, const struct ast_stream_topology *topology);
/*!
* \brief Callback after applying a topology.
* \since 15.0.0
*
* \details
* This callback is called after the topology is applied so the
* using module can do what is necessary after the topology becomes
* active.
*
* \param context User supplied context data pointer for the SDP
* state.
* \param topology Topology already applied.
*
* \return Nothing
*/
typedef void (*ast_sdp_postapply_cb)(void *context, const struct ast_stream_topology *topology);
/*!
* \since 15.0.0
* \brief Allocate a new SDP options structure.
@@ -204,6 +348,24 @@ void ast_sdp_options_set_rtp_engine(struct ast_sdp_options *options,
*/
const char *ast_sdp_options_get_rtp_engine(const struct ast_sdp_options *options);
void ast_sdp_options_set_state_context(struct ast_sdp_options *options, void *state_context);
void *ast_sdp_options_get_state_context(const struct ast_sdp_options *options);
void ast_sdp_options_set_answerer_modify_cb(struct ast_sdp_options *options, ast_sdp_answerer_modify_cb answerer_modify_cb);
ast_sdp_answerer_modify_cb ast_sdp_options_get_answerer_modify_cb(const struct ast_sdp_options *options);
void ast_sdp_options_set_offerer_modify_cb(struct ast_sdp_options *options, ast_sdp_offerer_modify_cb offerer_modify_cb);
ast_sdp_offerer_modify_cb ast_sdp_options_get_offerer_modify_cb(const struct ast_sdp_options *options);
void ast_sdp_options_set_offerer_config_cb(struct ast_sdp_options *options, ast_sdp_offerer_config_cb offerer_config_cb);
ast_sdp_offerer_config_cb ast_sdp_options_get_offerer_config_cb(const struct ast_sdp_options *options);
void ast_sdp_options_set_preapply_cb(struct ast_sdp_options *options, ast_sdp_preapply_cb preapply_cb);
ast_sdp_preapply_cb ast_sdp_options_get_preapply_cb(const struct ast_sdp_options *options);
void ast_sdp_options_set_postapply_cb(struct ast_sdp_options *options, ast_sdp_postapply_cb postapply_cb);
ast_sdp_postapply_cb ast_sdp_options_get_postapply_cb(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options rtp_symmetric
@@ -503,6 +665,26 @@ void ast_sdp_options_set_udptl_far_max_datagram(struct ast_sdp_options *options,
*/
unsigned int ast_sdp_options_get_udptl_far_max_datagram(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options max_streams
*
* \param options SDP Options
* \param max_streams
*/
void ast_sdp_options_set_max_streams(struct ast_sdp_options *options,
unsigned int max_streams);
/*!
* \since 15.0.0
* \brief Get SDP Options max_streams
*
* \param options SDP Options
*
* \returns max_streams
*/
unsigned int ast_sdp_options_get_max_streams(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Enable setting SSRC level attributes on SDPs
@@ -547,4 +729,46 @@ void ast_sdp_options_set_sched_type(struct ast_sdp_options *options,
struct ast_sched_context *ast_sdp_options_get_sched_type(const struct ast_sdp_options *options,
enum ast_media_type type);
/*!
* \brief Set all allowed stream types to create new streams.
* \since 15.0.0
*
* \param options SDP Options
* \param cap Format capabilities to set all allowed stream types at once.
* Could be NULL to disable creating any new streams.
*
* \return Nothing
*/
void ast_sdp_options_set_format_caps(struct ast_sdp_options *options,
struct ast_format_cap *cap);
/*!
* \brief Set the SDP options format cap used to create new streams of the type.
* \since 15.0.0
*
* \param options SDP Options
* \param type Media type the format cap represents.
* \param cap Format capabilities to use for the specified media type.
* Could be NULL to disable creating new streams of type.
*
* \return Nothing
*/
void ast_sdp_options_set_format_cap_type(struct ast_sdp_options *options,
enum ast_media_type type, struct ast_format_cap *cap);
/*!
* \brief Get the SDP options format cap used to create new streams of the type.
* \since 15.0.0
*
* \param options SDP Options
* \param type Media type the format cap represents.
*
* \retval NULL if stream not allowed to be created.
* \retval cap to use in negotiating the new stream.
*
* \note The returned cap does not have its own ao2 ref.
*/
struct ast_format_cap *ast_sdp_options_get_format_cap_type(const struct ast_sdp_options *options,
enum ast_media_type type);
#endif /* _ASTERISK_SDP_OPTIONS_H */

View File

@@ -30,12 +30,22 @@ struct ast_control_t38_parameters;
/*!
* \brief Allocate a new SDP state
*
* \details
* SDP state keeps tabs on everything SDP-related for a media session.
* Most SDP operations will require the state to be provided.
* Ownership of the SDP options is taken on by the SDP state.
* A good strategy is to call this during session creation.
*
* \param topology Initial stream topology to offer.
* NULL if we are going to be the answerer. We can always
* update the local topology later if it turns out we need
* to be the offerer.
* \param options SDP options for the duration of the session.
*
* \retval SDP state struct
* \retval NULL on failure
*/
struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *streams,
struct ast_sdp_state *ast_sdp_state_alloc(struct ast_stream_topology *topology,
struct ast_sdp_options *options);
/*!
@@ -86,6 +96,8 @@ int ast_sdp_state_get_stream_connection_address(const struct ast_sdp_state *sdp_
*
* If this is called prior to receiving a remote SDP, then this will just mirror
* the local configured endpoint capabilities.
*
* \note Cannot return NULL. It is a BUG if it does.
*/
const struct ast_stream_topology *ast_sdp_state_get_joint_topology(
const struct ast_sdp_state *sdp_state);
@@ -93,6 +105,7 @@ const struct ast_stream_topology *ast_sdp_state_get_joint_topology(
/*!
* \brief Get the local topology
*
* \note Cannot return NULL. It is a BUG if it does.
*/
const struct ast_stream_topology *ast_sdp_state_get_local_topology(
const struct ast_sdp_state *sdp_state);
@@ -114,9 +127,10 @@ const struct ast_sdp_options *ast_sdp_state_get_options(
* \retval NULL Failure
*
* \note
* This function will allocate a new SDP with RTP instances if it has not already
* been allocated.
*
* This function will return the last local SDP created if one were
* previously requested for the current negotiation. Otherwise it
* creates our SDP offer/answer depending on what role we are playing
* in the current negotiation.
*/
const struct ast_sdp *ast_sdp_state_get_local_sdp(struct ast_sdp_state *sdp_state);
@@ -152,6 +166,7 @@ const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state);
*
* \retval 0 Success
* \retval non-0 Failure
* Use ast_sdp_state_is_offer_rejected() to see if the SDP offer was rejected.
*
* \since 15
*/
@@ -165,39 +180,72 @@ int ast_sdp_state_set_remote_sdp(struct ast_sdp_state *sdp_state, const struct a
*
* \retval 0 Success
* \retval non-0 Failure
* Use ast_sdp_state_is_offer_rejected() to see if the SDP offer was rejected.
*
* \since 15
*/
int ast_sdp_state_set_remote_sdp_from_impl(struct ast_sdp_state *sdp_state, const void *remote);
/*!
* \brief Reset the SDP state and stream capabilities as if the SDP state had just been allocated.
* \brief Was the set remote offer rejected.
* \since 15.0.0
*
* \param sdp_state
*
* \retval 0 if not rejected.
* \retval non-zero if rejected.
*/
int ast_sdp_state_is_offer_rejected(struct ast_sdp_state *sdp_state);
/*!
* \brief Are we the SDP offerer.
* \since 15.0.0
*
* \param sdp_state
*
* \retval 0 if we are not the offerer.
* \retval non-zero we are the offerer.
*/
int ast_sdp_state_is_offerer(struct ast_sdp_state *sdp_state);
/*!
* \brief Are we the SDP answerer.
* \since 15.0.0
*
* \param sdp_state
*
* \retval 0 if we are not the answerer.
* \retval non-zero we are the answerer.
*/
int ast_sdp_state_is_answerer(struct ast_sdp_state *sdp_state);
/*!
* \brief Restart the SDP offer/answer negotiations.
*
* \param sdp_state
* \param remote The implementation's representation of an SDP.
*
* \retval 0 Success
*
* \note
* This is most useful for when a channel driver is sending a session refresh message
* and needs to re-advertise its initial capabilities instead of the previously-negotiated
* joint capabilities.
*
* \since 15
* \retval non-0 Failure
*/
int ast_sdp_state_reset(struct ast_sdp_state *sdp_state);
int ast_sdp_state_restart_negotiations(struct ast_sdp_state *sdp_state);
/*!
* \brief Update the local stream topology on the SDP state.
*
* \details
* Basically we are saving off any topology updates until we create the
* next SDP offer. Repeated updates merge with the previous updated
* topology.
*
* \param sdp_state
* \param streams The new stream topology.
* \param topology The new stream topology.
*
* \retval 0 Success
* \retval non-0 Failure
*
* \since 15
*/
int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *streams);
int ast_sdp_state_update_local_topology(struct ast_sdp_state *sdp_state, struct ast_stream_topology *topology);
/*!
* \brief Set the local address (IP address) to use for connection addresses
@@ -231,7 +279,26 @@ int ast_sdp_state_set_connection_address(struct ast_sdp_state *sdp_state, int st
/*!
* \since 15.0.0
* \brief Set a stream to be held or unheld
* \brief Set the global locally held state.
*
* \param sdp_state
* \param locally_held
*/
void ast_sdp_state_set_global_locally_held(struct ast_sdp_state *sdp_state, unsigned int locally_held);
/*!
* \since 15.0.0
* \brief Get the global locally held state.
*
* \param sdp_state
*
* \returns locally_held
*/
unsigned int ast_sdp_state_get_global_locally_held(const struct ast_sdp_state *sdp_state);
/*!
* \since 15.0.0
* \brief Set a stream to be held or unheld locally
*
* \param sdp_state
* \param stream_index The stream to set the held value for
@@ -240,6 +307,30 @@ int ast_sdp_state_set_connection_address(struct ast_sdp_state *sdp_state, int st
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 locally 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);
/*!
* \since 15.0.0
* \brief Get whether a stream is remotely held or not
*
* \param sdp_state
* \param stream_index The stream to get the held state for
*
* \returns remotely_held
*/
unsigned int ast_sdp_state_get_remotely_held(const struct ast_sdp_state *sdp_state,
int stream_index);
/*!
* \since 15.0.0
* \brief Set the UDPTL session parameters
@@ -251,16 +342,4 @@ void ast_sdp_state_set_locally_held(struct ast_sdp_state *sdp_state,
void ast_sdp_state_set_t38_parameters(struct ast_sdp_state *sdp_state,
int stream_index, struct ast_control_t38_parameters *params);
/*!
* \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 */

View File

@@ -227,6 +227,17 @@ void ast_stream_set_state(struct ast_stream *stream, enum ast_stream_state state
*/
const char *ast_stream_state2str(enum ast_stream_state state);
/*!
* \brief Convert a string to a stream state
*
* \param str The string to convert
*
* \return The stream state
*
* \since 15.0.0
*/
enum ast_stream_state ast_stream_str2state(const char *str);
/*!
* \brief Get the opaque stream data
*

View File

@@ -109,11 +109,9 @@ void ast_sdp_t_free(struct ast_sdp_t_line *t_line)
ast_free(t_line);
}
void ast_sdp_free(struct ast_sdp *sdp)
static void ast_sdp_dtor(void *vdoomed)
{
if (!sdp) {
return;
}
struct ast_sdp *sdp = vdoomed;
ast_sdp_o_free(sdp->o_line);
ast_sdp_s_free(sdp->s_line);
@@ -121,7 +119,6 @@ void ast_sdp_free(struct ast_sdp *sdp)
ast_sdp_t_free(sdp->t_line);
ast_sdp_a_lines_free(sdp->a_lines);
ast_sdp_m_lines_free(sdp->m_lines);
ast_free(sdp);
}
#define COPY_STR_AND_ADVANCE(p, dest, source) \
@@ -314,28 +311,28 @@ struct ast_sdp *ast_sdp_alloc(struct ast_sdp_o_line *o_line,
{
struct ast_sdp *new_sdp;
new_sdp = ast_calloc(1, sizeof *new_sdp);
new_sdp = ao2_alloc_options(sizeof(*new_sdp), ast_sdp_dtor, AO2_ALLOC_OPT_LOCK_NOLOCK);
if (!new_sdp) {
return NULL;
}
new_sdp->a_lines = ast_calloc(1, sizeof(*new_sdp->a_lines));
if (!new_sdp->a_lines) {
ast_sdp_free(new_sdp);
ao2_ref(new_sdp, -1);
return NULL;
}
if (AST_VECTOR_INIT(new_sdp->a_lines, 20)) {
ast_sdp_free(new_sdp);
ao2_ref(new_sdp, -1);
return NULL;
}
new_sdp->m_lines = ast_calloc(1, sizeof(*new_sdp->m_lines));
if (!new_sdp->m_lines) {
ast_sdp_free(new_sdp);
ao2_ref(new_sdp, -1);
return NULL;
}
if (AST_VECTOR_INIT(new_sdp->m_lines, 20)) {
ast_sdp_free(new_sdp);
ao2_ref(new_sdp, -1);
return NULL;
}
@@ -741,6 +738,62 @@ static void process_fmtp_lines(const struct ast_sdp_m_line *m_line, int payload,
}
}
/*!
* \internal
* \brief Determine the RTP stream direction in the given a lines.
* \since 15.0.0
*
* \param a_lines Attribute lines to search.
*
* \retval Stream direction on success.
* \retval AST_STREAM_STATE_REMOVED on failure.
*
* \return Nothing
*/
static enum ast_stream_state get_a_line_direction(const struct ast_sdp_a_lines *a_lines)
{
if (a_lines) {
enum ast_stream_state direction;
int idx;
const struct ast_sdp_a_line *a_line;
for (idx = 0; idx < AST_VECTOR_SIZE(a_lines); ++idx) {
a_line = AST_VECTOR_GET(a_lines, idx);
direction = ast_stream_str2state(a_line->name);
if (direction != AST_STREAM_STATE_REMOVED) {
return direction;
}
}
}
return AST_STREAM_STATE_REMOVED;
}
/*!
* \internal
* \brief Determine the RTP stream direction.
* \since 15.0.0
*
* \param a_lines The SDP media global attributes
* \param m_line The SDP media section to convert
*
* \return Stream direction
*/
static enum ast_stream_state get_stream_direction(const struct ast_sdp_a_lines *a_lines, const struct ast_sdp_m_line *m_line)
{
enum ast_stream_state direction;
direction = get_a_line_direction(m_line->a_lines);
if (direction != AST_STREAM_STATE_REMOVED) {
return direction;
}
direction = get_a_line_direction(a_lines);
if (direction != AST_STREAM_STATE_REMOVED) {
return direction;
}
return AST_STREAM_STATE_SENDRECV;
}
/*
* Needed so we don't have an external function referenced as data.
* The dynamic linker doesn't handle that very well.
@@ -758,13 +811,14 @@ static void rtp_codecs_free(struct ast_rtp_codecs *codecs)
* Given an m-line from an SDP, convert it into an ast_stream structure.
* This takes formats, as well as clock-rate and fmtp attributes into account.
*
* \param a_lines The SDP media global attributes
* \param m_line The SDP media section to convert
* \param g726_non_standard Non-zero if G.726 is non-standard
*
* \retval NULL An error occurred
* \retval non-NULL The converted stream
*/
static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line, int g726_non_standard)
static struct ast_stream *get_stream_from_m(const struct ast_sdp_a_lines *a_lines, const struct ast_sdp_m_line *m_line, int g726_non_standard)
{
int i;
int non_ast_fmts;
@@ -793,6 +847,14 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line,
ao2_ref(caps, -1);
return NULL;
}
ast_stream_set_data(stream, AST_STREAM_DATA_RTP_CODECS, codecs,
(ast_stream_data_free_fn) rtp_codecs_free);
if (!m_line->port) {
/* Stream is declined. There may not be any attributes. */
ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);
break;
}
options = g726_non_standard ? AST_RTP_OPT_G726_NONSTANDARD : 0;
for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) {
@@ -819,10 +881,16 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line,
}
ast_rtp_codecs_payload_formats(codecs, caps, &non_ast_fmts);
ast_stream_set_data(stream, AST_STREAM_DATA_RTP_CODECS, codecs,
(ast_stream_data_free_fn) rtp_codecs_free);
ast_stream_set_state(stream, get_stream_direction(a_lines, m_line));
break;
case AST_MEDIA_TYPE_IMAGE:
if (!m_line->port) {
/* Stream is declined. There may not be any attributes. */
ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);
break;
}
for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) {
struct ast_sdp_payload *payload;
@@ -830,12 +898,15 @@ static struct ast_stream *get_stream_from_m(const struct ast_sdp_m_line *m_line,
payload = ast_sdp_m_get_payload(m_line, i);
if (!strcasecmp(payload->fmt, "t38")) {
ast_format_cap_append(caps, ast_format_t38, 0);
ast_stream_set_state(stream, AST_STREAM_STATE_SENDRECV);
}
}
break;
case AST_MEDIA_TYPE_UNKNOWN:
case AST_MEDIA_TYPE_TEXT:
case AST_MEDIA_TYPE_END:
/* Consider these unsupported streams as declined */
ast_stream_set_state(stream, AST_STREAM_STATE_REMOVED);
break;
}
@@ -858,7 +929,7 @@ struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp,
for (i = 0; i < ast_sdp_get_m_count(sdp); ++i) {
struct ast_stream *stream;
stream = get_stream_from_m(ast_sdp_get_m(sdp, i), g726_non_standard);
stream = get_stream_from_m(sdp->a_lines, ast_sdp_get_m(sdp, i), g726_non_standard);
if (!stream) {
/*
* The topology cannot match the SDP because

View File

@@ -27,6 +27,7 @@
#define DEFAULT_ICE AST_SDP_ICE_DISABLED
#define DEFAULT_IMPL AST_SDP_IMPL_STRING
#define DEFAULT_ENCRYPTION AST_SDP_ENCRYPTION_DISABLED
#define DEFAULT_MAX_STREAMS 16 /* Set to match our PJPROJECT PJMEDIA_MAX_SDP_MEDIA. */
#define DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(field, assert_on_null) \
void ast_sdp_options_set_##field(struct ast_sdp_options *options, const char *value) \
@@ -60,6 +61,12 @@ DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(sdpowner, 0);
DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(sdpsession, 0);
DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(rtp_engine, 0);
DEFINE_GETTERS_SETTERS_FOR(void *, state_context);
DEFINE_GETTERS_SETTERS_FOR(ast_sdp_answerer_modify_cb, answerer_modify_cb);
DEFINE_GETTERS_SETTERS_FOR(ast_sdp_offerer_modify_cb, offerer_modify_cb);
DEFINE_GETTERS_SETTERS_FOR(ast_sdp_offerer_config_cb, offerer_config_cb);
DEFINE_GETTERS_SETTERS_FOR(ast_sdp_preapply_cb, preapply_cb);
DEFINE_GETTERS_SETTERS_FOR(ast_sdp_postapply_cb, postapply_cb);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_symmetric);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, udptl_symmetric);
DEFINE_GETTERS_SETTERS_FOR(enum ast_t38_ec_modes, udptl_error_correction);
@@ -71,6 +78,7 @@ DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_audio);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_audio);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, tos_video);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, cos_video);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, max_streams);
DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_dtmf, dtmf);
DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_ice, ice);
DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_impl, impl);
@@ -110,12 +118,87 @@ void ast_sdp_options_set_sched_type(struct ast_sdp_options *options, enum ast_me
}
}
struct ast_format_cap *ast_sdp_options_get_format_cap_type(const struct ast_sdp_options *options,
enum ast_media_type type)
{
struct ast_format_cap *cap = NULL;
switch (type) {
case AST_MEDIA_TYPE_AUDIO:
case AST_MEDIA_TYPE_VIDEO:
case AST_MEDIA_TYPE_IMAGE:
case AST_MEDIA_TYPE_TEXT:
cap = options->caps[type];
break;
case AST_MEDIA_TYPE_UNKNOWN:
case AST_MEDIA_TYPE_END:
break;
}
return cap;
}
void ast_sdp_options_set_format_cap_type(struct ast_sdp_options *options,
enum ast_media_type type, struct ast_format_cap *cap)
{
switch (type) {
case AST_MEDIA_TYPE_AUDIO:
case AST_MEDIA_TYPE_VIDEO:
case AST_MEDIA_TYPE_IMAGE:
case AST_MEDIA_TYPE_TEXT:
ao2_cleanup(options->caps[type]);
options->caps[type] = NULL;
if (cap && !ast_format_cap_empty(cap)) {
ao2_ref(cap, +1);
options->caps[type] = cap;
}
break;
case AST_MEDIA_TYPE_UNKNOWN:
case AST_MEDIA_TYPE_END:
break;
}
}
void ast_sdp_options_set_format_caps(struct ast_sdp_options *options,
struct ast_format_cap *cap)
{
enum ast_media_type type;
for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; ++type) {
ao2_cleanup(options->caps[type]);
options->caps[type] = NULL;
}
if (!cap || ast_format_cap_empty(cap)) {
return;
}
for (type = AST_MEDIA_TYPE_UNKNOWN + 1; type < AST_MEDIA_TYPE_END; ++type) {
struct ast_format_cap *type_cap;
type_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
if (!type_cap) {
continue;
}
ast_format_cap_set_framing(type_cap, ast_format_cap_get_framing(cap));
if (ast_format_cap_append_from_cap(type_cap, cap, type)
|| ast_format_cap_empty(type_cap)) {
ao2_ref(type_cap, -1);
continue;
}
/* This takes the allocation reference */
options->caps[type] = type_cap;
}
}
static void set_defaults(struct ast_sdp_options *options)
{
options->dtmf = DEFAULT_DTMF;
options->ice = DEFAULT_ICE;
options->impl = DEFAULT_IMPL;
options->encryption = DEFAULT_ENCRYPTION;
options->max_streams = DEFAULT_MAX_STREAMS;
}
struct ast_sdp_options *ast_sdp_options_alloc(void)
@@ -138,6 +221,15 @@ struct ast_sdp_options *ast_sdp_options_alloc(void)
void ast_sdp_options_free(struct ast_sdp_options *options)
{
enum ast_media_type type;
if (!options) {
return;
}
for (type = AST_MEDIA_TYPE_UNKNOWN; type < AST_MEDIA_TYPE_END; ++type) {
ao2_cleanup(options->caps[type]);
}
ast_string_field_free_memory(options);
ast_free(options);
}

View File

@@ -24,7 +24,7 @@
struct ast_sdp_options {
AST_DECLARE_STRING_FIELDS(
/*! Media address to use in SDP */
/*! Media address to advertise in SDP session c= line */
AST_STRING_FIELD(media_address);
/*! Optional address of the interface media should use. */
AST_STRING_FIELD(interface_address);
@@ -37,12 +37,25 @@ struct ast_sdp_options {
);
/*! Scheduler context for the media stream types (Mainly for RTP) */
struct ast_sched_context *sched[AST_MEDIA_TYPE_END];
/*! Capabilities to create new streams of the indexed media type. */
struct ast_format_cap *caps[AST_MEDIA_TYPE_END];
/*! User supplied context data pointer for the SDP state. */
void *state_context;
/*! Modify negotiated topology before create answer SDP callback. */
ast_sdp_answerer_modify_cb answerer_modify_cb;
/*! Modify proposed topology before create offer SDP callback. */
ast_sdp_offerer_modify_cb offerer_modify_cb;
/*! Configure proposed topology extra stream options before create offer SDP callback. */
ast_sdp_offerer_config_cb offerer_config_cb;
/*! Negotiated topology is about to be applied callback. */
ast_sdp_preapply_cb preapply_cb;
/*! Negotiated topology was just applied callback. */
ast_sdp_postapply_cb postapply_cb;
struct {
unsigned int rtp_symmetric:1;
unsigned int udptl_symmetric:1;
unsigned int rtp_ipv6:1;
unsigned int g726_non_standard:1;
unsigned int locally_held:1;
unsigned int rtcp_mux:1;
unsigned int ssrc:1;
};
@@ -52,6 +65,8 @@ struct ast_sdp_options {
unsigned int tos_video;
unsigned int cos_video;
unsigned int udptl_far_max_datagram;
/*! Maximum number of streams to allow. */
unsigned int max_streams;
};
enum ast_sdp_options_dtmf dtmf;
enum ast_sdp_options_ice ice;

File diff suppressed because it is too large Load Diff

View File

@@ -214,6 +214,23 @@ const char *ast_stream_state2str(enum ast_stream_state state)
}
}
enum ast_stream_state ast_stream_str2state(const char *str)
{
if (!strcmp("sendrecv", str)) {
return AST_STREAM_STATE_SENDRECV;
}
if (!strcmp("sendonly", str)) {
return AST_STREAM_STATE_SENDONLY;
}
if (!strcmp("recvonly", str)) {
return AST_STREAM_STATE_RECVONLY;
}
if (!strcmp("inactive", str)) {
return AST_STREAM_STATE_INACTIVE;
}
return AST_STREAM_STATE_REMOVED;
}
void *ast_stream_get_data(struct ast_stream *stream, enum ast_stream_data_slot slot)
{
ast_assert(stream != NULL);

View File

@@ -484,7 +484,7 @@ AST_TEST_DEFINE(pjmedia_to_sdp_test)
}
cleanup:
ast_sdp_free(sdp);
ao2_cleanup(sdp);
ast_sdp_translator_free(translator);
pj_pool_release(pool);
return res;
@@ -560,7 +560,7 @@ AST_TEST_DEFINE(sdp_to_pjmedia_test)
}
cleanup:
ast_sdp_free(sdp);
ao2_cleanup(sdp);
ast_sdp_translator_free(translator);
pj_pool_release(pool);
return res;

File diff suppressed because it is too large Load Diff