core: Remove unused/incomplete SDP modules.

Change-Id: Icc28fbdc46f58e54a21554e6fe8b078f841b1f86
This commit is contained in:
Richard Mudgett 2017-12-22 13:11:53 -06:00 committed by Joshua Colp
parent 1dedc73951
commit 661fec4b59
11 changed files with 0 additions and 9413 deletions

View File

@ -1,703 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2017, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
/* NOTE: It is unlikely that you need to include this file. You probably will only need
* this if you are an SDP translator, or if you are an inner part of the SDP API
*/
#ifndef _SDP_PRIV_H
#define _SDP_PRIV_H
#include "asterisk/vector.h"
#include "asterisk/format.h"
#include "asterisk/sdp_state.h"
#include "asterisk/stream.h"
/*!
* \brief Structure representing an SDP Attribute
*/
struct ast_sdp_a_line {
/*! Attribute name */
char *name;
/*! Attribute value. For attributes that have no value, this will be an empty string */
char *value;
};
/*!
* \brief A collection of SDP Attributes
*/
AST_VECTOR(ast_sdp_a_lines, struct ast_sdp_a_line *);
/*!
* \brief Structure representing an SDP Connection
*/
struct ast_sdp_c_line {
/* IP family string (e.g. IP4 or IP6) */
char *address_type;
/* Connection address. Can be an IP address or FQDN */
char *address;
};
/*!
* \brief Structre representing SDP Media Payloads
*/
struct ast_sdp_payload {
/* Media format description */
char *fmt;
};
/*!
* \brief A collection of SDP Media Payloads
*/
AST_VECTOR(ast_sdp_payloads, struct ast_sdp_payload *);
/*!
* \brief Structure representing an SDP Media Stream
*
* This contains both the m line, as well as its
* constituent a lines.
*/
struct ast_sdp_m_line {
/*! Media type (e.g. "audio" or "video") */
char *type;
/*! RTP profile string (e.g. "RTP/AVP") */
char *proto;
/*! Port number in m line */
uint16_t port;
/*! Number of ports specified in m line */
uint16_t port_count;
/*! RTP payloads */
struct ast_sdp_payloads *payloads;
/*! Connection information for this media stream */
struct ast_sdp_c_line *c_line;
/*! The attributes for this media stream */
struct ast_sdp_a_lines *a_lines;
};
/*!
* \brief A collection of SDP Media Streams
*/
AST_VECTOR(ast_sdp_m_lines, struct ast_sdp_m_line *);
/*!
* \brief Structure representing an SDP Origin
*/
struct ast_sdp_o_line {
/*! Origin user name */
char *username;
/*! Origin id */
uint64_t session_id;
/*! Origin version */
uint64_t session_version;
/*! Origin IP address type (e.g. "IP4" or "IP6") */
char *address_type;
/*! Origin address. Can be an IP address or FQDN */
char *address;
};
/*!
* \brief Structure representing an SDP Session Name
*/
struct ast_sdp_s_line {
/* Session Name */
char *session_name;
};
/*!
* \brief Structure representing SDP Timing
*/
struct ast_sdp_t_line {
/*! Session start time */
uint64_t start_time;
/*! Session end time */
uint64_t stop_time;
};
/*!
* \brief An SDP
*/
struct ast_sdp {
/*! SDP Origin line */
struct ast_sdp_o_line *o_line;
/*! SDP Session name */
struct ast_sdp_s_line *s_line;
/*! SDP top-level connection information */
struct ast_sdp_c_line *c_line;
/*! SDP timing information */
struct ast_sdp_t_line *t_line;
/*! SDP top-level attributes */
struct ast_sdp_a_lines *a_lines;
/*! SDP media streams */
struct ast_sdp_m_lines *m_lines;
};
/*!
* \brief A structure representing an SDP rtpmap attribute
*/
struct ast_sdp_rtpmap {
/*! The RTP payload number for the rtpmap */
int payload;
/*! The Name of the codec */
char *encoding_name;
/*! The clock rate of the codec */
int clock_rate;
/*! Optional encoding parameters */
char *encoding_parameters;
/*! Area where strings are stored */
char buf[0];
};
/*!
* \brief Free an SDP Attribute
*
* \param a_line The attribute to free
*
* \since 15
*/
void ast_sdp_a_free(struct ast_sdp_a_line *a_line);
/*!
* \brief Free an SDP Attribute collection
*
* \param a_lines The attribute collection to free
*
* \since 15
*/
void ast_sdp_a_lines_free(struct ast_sdp_a_lines *a_lines);
/*!
* \brief Free SDP Connection Data
*
* \param c_line The connection data to free
*
* \since 15
*/
void ast_sdp_c_free(struct ast_sdp_c_line *c_line);
/*!
* \brief Free an SDP Media Description Payload
*
* \param payload The payload to free
*
* \since 15
*/
void ast_sdp_payload_free(struct ast_sdp_payload *payload);
/*!
* \brief Free an SDP Media Description Payload collection
*
* \param payloads collection to free
*
* \since 15
*/
void ast_sdp_payloads_free(struct ast_sdp_payloads *payloads);
/*!
* \brief Free an SDP Media Description
* Frees the media description and all resources it contains
*
* \param m_line The media description to free
*
* \since 15
*/
void ast_sdp_m_free(struct ast_sdp_m_line *m_line);
/*!
* \brief Free an SDP Media Description collection
*
* \param m_lines The collection description to free
*
* \since 15
*/
void ast_sdp_m_lines_free(struct ast_sdp_m_lines *m_lines);
/*!
* \brief Free an SDP Origin
*
* \param o_line The origin description to free
*
* \since 15
*/
void ast_sdp_o_free(struct ast_sdp_o_line *o_line);
/*!
* \brief Free an SDP Session
*
* \param s_line The session to free
*
* \since 15
*/
void ast_sdp_s_free(struct ast_sdp_s_line *s_line);
/*!
* \brief Free SDP Timing
*
* \param t_line The timing description to free
*
* \since 15
*/
void ast_sdp_t_free(struct ast_sdp_t_line *t_line);
/*!
* \brief Allocate an SDP Attribute
*
* \param name Attribute Name
* \param value Attribute Name
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_a_line *ast_sdp_a_alloc(const char *name, const char *value);
/*!
* \brief Allocate an SDP Connection
*
* \param family Family ("IN", etc)
* \param addr Address
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_c_line *ast_sdp_c_alloc(const char *family, const char *addr);
/*!
* \brief Allocate an SDP Media Description Payload
*
* \param fmt The media format description
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_payload *ast_sdp_payload_alloc(const char *fmt);
/*!
* \brief Allocate an SDP Media Description
*
* \param type ("audio", "video", etc)
* \param port Starting port
* \param port_count Port pairs to allocate
* \param proto ("RTP/AVP", "RTP/SAVP", "udp")
* \param c_line Connection to add. May be NULL
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_m_line *ast_sdp_m_alloc(const char *type, uint16_t port,
uint16_t port_count, const char *proto, struct ast_sdp_c_line *c_line);
/*!
* \brief Allocate an SDP Session
*
* \param session_name The session name
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_s_line *ast_sdp_s_alloc(const char *session_name);
/*!
* \brief Allocate SDP Timing
*
* \param start_time (Seconds since 1900)
* \param end_time (Seconds since 1900)
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_t_line *ast_sdp_t_alloc(uint64_t start_time, uint64_t stop_time);
/*!
* \brief Allocate an SDP Origin
*
* \param username User name
* \param sesison_id Session ID
* \param sesison_version Session Version
* \param address_type Address type ("IN4", "IN6", etc)
* \param address Unicast address
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_o_line *ast_sdp_o_alloc(const char *username, uint64_t session_id,
uint64_t session_version, const char *address_type, const char *address);
/*!
* \brief Add an SDP Attribute to an SDP
*
* \param sdp SDP
* \param a_line Attribute
*
* \retval 0 Success
* \retval non-0 Failure
*
* \since 15
*/
int ast_sdp_add_a(struct ast_sdp *sdp, struct ast_sdp_a_line *a_line);
/*!
* \brief Get the count of Attributes on an SDP
*
* \param sdp SDP
*
* \returns Number of Attributes
*
* \since 15
*/
int ast_sdp_get_a_count(const struct ast_sdp *sdp);
/*!
* \brief Get an Attribute from an SDP
*
* \param sdp SDP
* \param index Attribute index
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_a_line *ast_sdp_get_a(const struct ast_sdp *sdp, int index);
/*!
* \brief Add a Media Description to an SDP
*
* \param sdp SDP
* \param m_line Media Description
*
* \retval 0 Success
* \retval non-0 Failure
*
* \since 15
*/
int ast_sdp_add_m(struct ast_sdp *sdp, struct ast_sdp_m_line *m_line);
/*!
* \brief Add an RTP Media Description to an SDP
*
* \param sdp SDP
* \param sdp_state SDP state information
* \param options SDP Options
* \param stream_index stream
*
* \retval 0 Success
* \retval non-0 Failure
*
* \since 15
*/
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
*
* \param sdp SDP
*
* \returns The number of Media Descriptions
*
* \since 15
*/
int ast_sdp_get_m_count(const struct ast_sdp *sdp);
/*!
* \brief Get a Media Descriptions from an SDP
*
* \param sdp SDP
* \param index Media Description index
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_m_line *ast_sdp_get_m(const struct ast_sdp *sdp, int index);
/*!
* \brief Add an SDP Attribute to a Media Description
*
* \param m_line Media Description
* \param a_line Attribute
*
* \retval 0 Success
* \retval non-0 Failure
*
* \since 15
*/
int ast_sdp_m_add_a(struct ast_sdp_m_line *m_line, struct ast_sdp_a_line *a_line);
/*!
* \brief Get the count of Attributes on a Media Description
*
* \param m_line Media Description
*
* \returns Number of Attributes
*
* \since 15
*/
int ast_sdp_m_get_a_count(const struct ast_sdp_m_line *m_line);
/*!
* \brief Get an Attribute from a Media Description
*
* \param m_line Media Description
* \param index Attribute index
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_a_line *ast_sdp_m_get_a(const struct ast_sdp_m_line *m_line, int index);
/*!
* \brief Add a Payload to a Media Description
*
* \param m_line Media Description
* \param payload Payload
*
* \retval 0 Success
* \retval non-0 Failure
*
* \since 15
*/
int ast_sdp_m_add_payload(struct ast_sdp_m_line *m_line,
struct ast_sdp_payload *payload);
/*!
* \brief Get the count of Payloads on a Media Description
*
* \param m_line Media Description
*
* \returns Number of Attributes
*
* \since 15
*/
int ast_sdp_m_get_payload_count(const struct ast_sdp_m_line *m_line);
/*!
* \brief Get a Payload from a Media Description
*
* \param m_line Media Description
* \param index Payload index
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp_payload *ast_sdp_m_get_payload(const struct ast_sdp_m_line *m_line, int index);
/*!
* \brief Add a Format to a Media Description
*
* \param m_line Media Description
* \param options SDP Options
* \param rtp_code rtp_code from ast_rtp_codecs_payload_code
* \param asterisk_format True if the value in format is to be used.
* \param format Format
* \param code from AST_RTP list
*
* \retval 0 Success
* \retval non-0 Failure
*
* \since 15
*/
int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_options *options,
int rtp_code, int asterisk_format, const struct ast_format *format, int code);
/*!
* \brief Create an SDP ao2 object
*
* \param o_line Origin
* \param c_line Connection
* \param s_line Session
* \param t_line Timing
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \since 15
*/
struct ast_sdp *ast_sdp_alloc(struct ast_sdp_o_line *o_line,
struct ast_sdp_c_line *c_line, struct ast_sdp_s_line *s_line,
struct ast_sdp_t_line *t_line);
/*!
* \brief Find the first attribute match index in the top-level SDP
*
* \note This will not search within streams for the given attribute.
*
* \param sdp The SDP in which to search
* \param attr_name The name of the attribute to search for
* \param payload Optional payload number to search for. If irrelevant, set to -1
*
* \retval index of attribute line on success.
* \retval -1 on failure or not found.
*
* \since 15.0.0
*/
int ast_sdp_find_a_first(const struct ast_sdp *sdp, const char *attr_name, int payload);
/*!
* \brief Find the next attribute match index in the top-level SDP
*
* \note This will not search within streams for the given attribute.
*
* \param sdp The SDP in which to search
* \param last The last matching index found
* \param attr_name The name of the attribute to search for
* \param payload Optional payload number to search for. If irrelevant, set to -1
*
* \retval index of attribute line on success.
* \retval -1 on failure or not found.
*
* \since 15.0.0
*/
int ast_sdp_find_a_next(const struct ast_sdp *sdp, int last, const char *attr_name, int payload);
/*!
* \brief Find an attribute in the top-level SDP
*
* \note This will not search within streams for the given attribute.
*
* \param sdp The SDP in which to search
* \param attr_name The name of the attribute to search for
* \param payload Optional payload number to search for. If irrelevant, set to -1
*
* \retval NULL Could not find the given attribute
* \retval Non-NULL The attribute to find
*
* \since 15.0.0
*/
struct ast_sdp_a_line *ast_sdp_find_attribute(const struct ast_sdp *sdp,
const char *attr_name, int payload);
/*!
* \brief Find the first attribute match index in an SDP stream (m-line)
*
* \param m_line The SDP m-line in which to search
* \param attr_name The name of the attribute to search for
* \param payload Optional payload number to search for. If irrelevant, set to -1
*
* \retval index of attribute line on success.
* \retval -1 on failure or not found.
*
* \since 15.0.0
*/
int ast_sdp_m_find_a_first(const struct ast_sdp_m_line *m_line, const char *attr_name,
int payload);
/*!
* \brief Find the next attribute match index in an SDP stream (m-line)
*
* \param m_line The SDP m-line in which to search
* \param last The last matching index found
* \param attr_name The name of the attribute to search for
* \param payload Optional payload number to search for. If irrelevant, set to -1
*
* \retval index of attribute line on success.
* \retval -1 on failure or not found.
*
* \since 15.0.0
*/
int ast_sdp_m_find_a_next(const struct ast_sdp_m_line *m_line, int last,
const char *attr_name, int payload);
/*!
* \brief Find an attribute in an SDP stream (m-line)
*
* \param m_line The SDP m-line in which to search
* \param attr_name The name of the attribute to search for
* \param payload Optional payload number to search for. If irrelevant, set to -1
*
* \retval NULL Could not find the given attribute
* \retval Non-NULL The attribute to find
*
* \since 15.0.0
*/
struct ast_sdp_a_line *ast_sdp_m_find_attribute(const struct ast_sdp_m_line *m_line,
const char *attr_name, int payload);
/*!
* \brief Convert an SDP a_line into an rtpmap
*
* The returned value is heap-allocated and must be freed with
* ast_sdp_rtpmap_free()
*
* \param a_line The SDP a_line to convert
*
* \retval NULL Fail
* \retval non-NULL Success
*
* \since 15.0.0
*/
struct ast_sdp_rtpmap *ast_sdp_a_get_rtpmap(const struct ast_sdp_a_line *a_line);
/*!
* \brief Allocate a new SDP rtpmap
*
* \param payload The RTP payload number
* \param encoding_name The human-readable name for the codec
* \param clock_rate The rate of the codec, in cycles per second
* \param encoding_parameters Optional codec-specific parameters (such as number of channels)
*
* \retval NULL Fail
* \retval non-NULL Success
*
* \since 15.0.0
*/
struct ast_sdp_rtpmap *ast_sdp_rtpmap_alloc(int payload, const char *encoding_name,
int clock_rate, const char *encoding_parameters);
/*!
* \brief Free an SDP rtpmap
*
* \since 15.0.0
*/
void ast_sdp_rtpmap_free(struct ast_sdp_rtpmap *rtpmap);
/*!
* \brief Turn an SDP into a stream topology
*
* This traverses the m-lines of the SDP and creates a stream topology, with
* each m-line corresponding to a stream in the created topology.
*
* \param sdp The SDP to convert
* \param g726_non_standard Non-zero if G.726 is non-standard
*
* \retval NULL An error occurred when converting
* \retval non-NULL The generated stream topology
*
* \since 15.0.0
*/
struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp, int g726_non_standard);
#endif /* _SDP_PRIV_H */

View File

@ -1,774 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2017, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#ifndef _ASTERISK_SDP_OPTIONS_H
#define _ASTERISK_SDP_OPTIONS_H
#include "asterisk/udptl.h"
#include "asterisk/format_cap.h"
struct ast_sdp_options;
/*!
* \brief SDP DTMF mode options
*/
enum ast_sdp_options_dtmf {
/*! No DTMF to be used */
AST_SDP_DTMF_NONE,
/*! Use RFC 4733 events for DTMF */
AST_SDP_DTMF_RFC_4733,
/*! Use DTMF in the audio stream */
AST_SDP_DTMF_INBAND,
/*! Use SIP 4733 if supported by the other side or INBAND if not */
AST_SDP_DTMF_AUTO,
};
/*!
* \brief ICE options
*
* This is an enum because it will support a TRICKLE-ICE option
* in the future.
*/
enum ast_sdp_options_ice {
/*! ICE is not enabled on this session */
AST_SDP_ICE_DISABLED,
/*! Standard ICE is enabled on this session */
AST_SDP_ICE_ENABLED_STANDARD,
};
/*!
* \brief Implementation of the SDP
*
* Users of the SDP API set the implementation based on what they
* natively handle. This indicates the type of SDP that the API expects
* when being given an SDP, and it indicates the type of SDP that the API
* returns when asked for one.
*/
enum ast_sdp_options_impl {
/*! SDP is represented as a string */
AST_SDP_IMPL_STRING,
/*! SDP is represented as a pjmedia_sdp_session */
AST_SDP_IMPL_PJMEDIA,
/*! End of the list */
AST_SDP_IMPL_END,
};
/*!
* \brief SDP encryption options
*/
enum ast_sdp_options_encryption {
/*! No encryption */
AST_SDP_ENCRYPTION_DISABLED,
/*! SRTP SDES encryption */
AST_SDP_ENCRYPTION_SRTP_SDES,
/*! DTLS 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.
*
* This will heap-allocate an SDP options structure and
* initialize it to a set of default values.
*
* \retval NULL Allocation failure
* \retval non-NULL Newly allocated SDP options
*/
struct ast_sdp_options *ast_sdp_options_alloc(void);
/*!
* \since 15.0.0
* \brief Free an SDP options structure.
*
* \note This only needs to be called if an error occurs between
* options allocation and a call to ast_sdp_state_alloc()
* Otherwise, the SDP state will take care of freeing the
* options for you.
*
* \param options The options to free
*/
void ast_sdp_options_free(struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options media_address
*
* \param options SDP Options
* \param media_address
*/
void ast_sdp_options_set_media_address(struct ast_sdp_options *options,
const char *media_address);
/*!
* \since 15.0.0
* \brief Get SDP Options media_address
*
* \param options SDP Options
*
* \returns media_address
*/
const char *ast_sdp_options_get_media_address(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options interface_address
*
* \param options SDP Options
* \param interface_address
*/
void ast_sdp_options_set_interface_address(struct ast_sdp_options *options,
const char *interface_address);
/*!
* \since 15.0.0
* \brief Get SDP Options interface_address
*
* \param options SDP Options
*
* \returns interface_address
*/
const char *ast_sdp_options_get_interface_address(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options sdpowner
*
* \param options SDP Options
* \param sdpowner
*/
void ast_sdp_options_set_sdpowner(struct ast_sdp_options *options,
const char *sdpowner);
/*!
* \since 15.0.0
* \brief Get SDP Options sdpowner
*
* \param options SDP Options
*
* \returns sdpowner
*/
const char *ast_sdp_options_get_sdpowner(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options sdpsession
*
* \param options SDP Options
* \param sdpsession
*/
void ast_sdp_options_set_sdpsession(struct ast_sdp_options *options,
const char *sdpsession);
/*!
* \since 15.0.0
* \brief Get SDP Options sdpsession
*
* \param options SDP Options
*
* \returns sdpsession
*/
const char *ast_sdp_options_get_sdpsession(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options rtp_engine
*
* \param options SDP Options
* \param rtp_engine
*/
void ast_sdp_options_set_rtp_engine(struct ast_sdp_options *options,
const char *rtp_engine);
/*!
* \since 15.0.0
* \brief Get SDP Options rtp_engine
*
* \param options SDP Options
*
* \returns rtp_engine
*/
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
*
* \param options SDP Options
* \param rtp_symmetric
*/
void ast_sdp_options_set_rtp_symmetric(struct ast_sdp_options *options,
unsigned int rtp_symmetric);
/*!
* \since 15.0.0
* \brief Get SDP Options rtp_symmetric
*
* \param options SDP Options
*
* \returns rtp_symmetric
*/
unsigned int ast_sdp_options_get_rtp_symmetric(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options rtp_ipv6
*
* \param options SDP Options
* \param rtp_ipv6
*/
void ast_sdp_options_set_rtp_ipv6(struct ast_sdp_options *options,
unsigned int rtp_ipv6);
/*!
* \since 15.0.0
* \brief Get SDP Options rtp_ipv6
*
* \param options SDP Options
*
* \returns rtp_ipv6
*/
unsigned int ast_sdp_options_get_rtp_ipv6(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options g726_non_standard
*
* \param options SDP Options
* \param g726_non_standard
*/
void ast_sdp_options_set_g726_non_standard(struct ast_sdp_options *options,
unsigned int g726_non_standard);
/*!
* \since 15.0.0
* \brief Get SDP Options g726_non_standard
*
* \param options SDP Options
*
* \returns g726_non_standard
*/
unsigned int ast_sdp_options_get_g726_non_standard(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options tos_audio
*
* \param options SDP Options
* \param tos_audio
*/
void ast_sdp_options_set_tos_audio(struct ast_sdp_options *options,
unsigned int tos_audio);
/*!
* \since 15.0.0
* \brief Get SDP Options tos_audio
*
* \param options SDP Options
*
* \returns tos_audio
*/
unsigned int ast_sdp_options_get_tos_audio(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options cos_audio
*
* \param options SDP Options
* \param cos_audio
*/
void ast_sdp_options_set_cos_audio(struct ast_sdp_options *options,
unsigned int cos_audio);
/*!
* \since 15.0.0
* \brief Get SDP Options cos_audio
*
* \param options SDP Options
*
* \returns cos_audio
*/
unsigned int ast_sdp_options_get_cos_audio(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options tos_video
*
* \param options SDP Options
* \param tos_video
*/
void ast_sdp_options_set_tos_video(struct ast_sdp_options *options,
unsigned int tos_video);
/*!
* \since 15.0.0
* \brief Get SDP Options tos_video
*
* \param options SDP Options
*
* \returns tos_video
*/
unsigned int ast_sdp_options_get_tos_video(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options cos_video
*
* \param options SDP Options
* \param cos_video
*/
void ast_sdp_options_set_cos_video(struct ast_sdp_options *options,
unsigned int cos_video);
/*!
* \since 15.0.0
* \brief Get SDP Options cos_video
*
* \param options SDP Options
*
* \returns cos_video
*/
unsigned int ast_sdp_options_get_cos_video(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options dtmf
*
* \param options SDP Options
* \param dtmf
*/
void ast_sdp_options_set_dtmf(struct ast_sdp_options *options,
enum ast_sdp_options_dtmf dtmf);
/*!
* \since 15.0.0
* \brief Get SDP Options dtmf
*
* \param options SDP Options
*
* \returns dtmf
*/
enum ast_sdp_options_dtmf ast_sdp_options_get_dtmf(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options ice
*
* \param options SDP Options
* \param ice
*/
void ast_sdp_options_set_ice(struct ast_sdp_options *options,
enum ast_sdp_options_ice ice);
/*!
* \since 15.0.0
* \brief Get SDP Options ice
*
* \param options SDP Options
*
* \returns ice
*/
enum ast_sdp_options_ice ast_sdp_options_get_ice(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options impl
*
* \param options SDP Options
* \param impl
*/
void ast_sdp_options_set_impl(struct ast_sdp_options *options,
enum ast_sdp_options_impl impl);
/*!
* \since 15.0.0
* \brief Get SDP Options impl
*
* \param options SDP Options
*
* \returns impl
*/
enum ast_sdp_options_impl ast_sdp_options_get_impl(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options encryption
*
* \param options SDP Options
* \param encryption
*/
void ast_sdp_options_set_encryption(struct ast_sdp_options *options,
enum ast_sdp_options_encryption encryption);
/*!
* \since 15.0.0
* \brief Get SDP Options encryption
*
* \param options SDP Options
*
* \returns encryption
*/
enum ast_sdp_options_encryption ast_sdp_options_get_encryption(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Get SDP Options RTCP MUX
*
* \param options SDP Options
*
* \returns Boolean indicating if RTCP MUX is enabled.
*/
unsigned int ast_sdp_options_get_rtcp_mux(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options RTCP MUX
*
* \param options SDP Options
* \param value Boolean that indicates if RTCP MUX should be enabled.
*/
void ast_sdp_options_set_rtcp_mux(struct ast_sdp_options *options, unsigned int value);
/*!
* \since 15.0.0
* \brief Set SDP Options udptl_symmetric
*
* \param options SDP Options
* \param udptl_symmetric
*/
void ast_sdp_options_set_udptl_symmetric(struct ast_sdp_options *options,
unsigned int udptl_symmetric);
/*!
* \since 15.0.0
* \brief Get SDP Options udptl_symmetric
*
* \param options SDP Options
*
* \returns udptl_symmetric
*/
unsigned int ast_sdp_options_get_udptl_symmetric(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options udptl_error_correction
*
* \param options SDP Options
* \param error_correction
*/
void ast_sdp_options_set_udptl_error_correction(struct ast_sdp_options *options,
enum ast_t38_ec_modes error_correction);
/*!
* \since 15.0.0
* \brief Get SDP Options udptl_error_correction
*
* \param options SDP Options
*
* \returns udptl_error_correction
*/
enum ast_t38_ec_modes ast_sdp_options_get_udptl_error_correction(const struct ast_sdp_options *options);
/*!
* \since 15.0.0
* \brief Set SDP Options udptl_far_max_datagram
*
* \param options SDP Options
* \param far_max_datagram
*/
void ast_sdp_options_set_udptl_far_max_datagram(struct ast_sdp_options *options,
unsigned int far_max_datagram);
/*!
* \since 15.0.0
* \brief Get SDP Options udptl_far_max_datagram
*
* \param options SDP Options
*
* \returns udptl_far_max_datagram
*/
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
*
* \param options SDP Options
* \param ssrc Boolean indicating if SSRC attributes should be included in generated SDPs
*/
void ast_sdp_options_set_ssrc(struct ast_sdp_options *options, unsigned int ssrc);
/*!
* \since 15.0.0
* \brief Get SDP Options ssrc
*
* \param options SDP Options
*
* \returns Whether SSRC-level attributes will be added to our SDP.
*/
unsigned int ast_sdp_options_get_ssrc(const struct ast_sdp_options *options);
/*!
* \brief Set the SDP options scheduler context used to create new streams of the type.
* \since 15.0.0
*
* \param options SDP Options
* \param type Media type the scheduler context is for.
* \param sched Scheduler context to use for the specified media type.
*
* \return Nothing
*/
void ast_sdp_options_set_sched_type(struct ast_sdp_options *options,
enum ast_media_type type, struct ast_sched_context *sched);
/*!
* \brief Get the SDP options scheduler context used to create new streams of the type.
* \since 15.0.0
*
* \param options SDP Options
* \param type Media type the format cap represents.
*
* \return The stored scheduler context to create new streams of the type.
*/
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

@ -1,345 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2017, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#ifndef _ASTERISK_SDP_STATE_H
#define _ASTERISK_SDP_STATE_H
#include "asterisk/stream.h"
#include "asterisk/sdp_options.h"
struct ast_sdp_state;
struct ast_sockaddr;
struct ast_udptl;
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 *topology,
struct ast_sdp_options *options);
/*!
* \brief Free the SDP state.
*
* A good strategy is to call this during session destruction
*/
void ast_sdp_state_free(struct ast_sdp_state *sdp_state);
/*!
* \brief Get the associated RTP instance for a particular stream on the SDP state.
*
* Stream numbers correspond to the streams in the topology of the associated channel
*/
struct ast_rtp_instance *ast_sdp_state_get_rtp_instance(const struct ast_sdp_state *sdp_state,
int stream_index);
/*!
* \brief Get the associated UDPTL instance for a particular stream on the SDP state.
*
* Stream numbers correspond to the streams in the topology of the associated channel
*/
struct ast_udptl *ast_sdp_state_get_udptl_instance(const struct ast_sdp_state *sdp_state,
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
* 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);
/*!
* \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);
/*!
* \brief Get the sdp_state options
*
*/
const struct ast_sdp_options *ast_sdp_state_get_options(
const struct ast_sdp_state *sdp_state);
/*!
* \brief Get the local SDP.
*
* \param sdp_state
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \note
* 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);
/*!
* \brief Get the local SDP Implementation.
*
* \param sdp_state
*
* \retval non-NULL Success
* \retval NULL Failure
*
* \note
* This function calls ast_sdp_state_get_local_sdp then translates it into
* the defined implementation.
*
* The return here is const. The use case for this is so that a channel can add
* the SDP to an outgoing message. The API user should not attempt to modify the SDP.
* SDP modification should only be done through the API.
*
* \since 15
*/
const void *ast_sdp_state_get_local_sdp_impl(struct ast_sdp_state *sdp_state);
/*!
* \brief Set the remote SDP
*
* \param sdp_state
* \param sdp
*
* \note It is assumed that the passed in SDP has been checked for sanity
* already. e.g., There are no syntax errors, a c= line is reachable for
* each m= line, etc...
*
* \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(struct ast_sdp_state *sdp_state, const struct ast_sdp *sdp);
/*!
* \brief Set the remote SDP from an Implementation
*
* \param sdp_state
* \param remote The implementation's representation of an SDP.
*
* \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 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
*
* \retval 0 Success
* \retval non-0 Failure
*/
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 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 *topology);
/*!
* \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 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
* \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 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
*
* \param sdp_state
* \param stream_index The stream to set the UDPTL session parameters for
* \param params
*/
void ast_sdp_state_set_t38_parameters(struct ast_sdp_state *sdp_state,
int stream_index, struct ast_control_t38_parameters *params);
#endif /* _ASTERISK_SDP_STATE_H */

View File

@ -1,103 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2017, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#ifndef _ASTERISK_SDP_TRANSLATOR_H
#define _ASTERISK_SDP_TRANSLATOR_H
#include "asterisk/sdp_options.h"
struct sdp;
/*!
* \brief SDP translator operations
*/
struct ast_sdp_translator_ops {
/*! The SDP representation on which this translator operates */
enum ast_sdp_options_impl repr;
/*! Allocate new translator private data for a translator */
void *(*translator_new)(void);
/*! Free translator private data */
void (*translator_free)(void *translator_priv);
/*! Convert the channel-native SDP into an internal Asterisk SDP */
struct ast_sdp *(*to_sdp)(const void *repr_sdp, void *translator_priv);
/*! Convert an internal Asterisk SDP into a channel-native SDP */
const void *(*from_sdp)(const struct ast_sdp *sdp, void *translator_priv);
};
/*!
* \brief An SDP translator
*
* An SDP translator is responsible for converting between Asterisk's internal
* representation of an SDP and the representation that is native to the channel
* driver. Translators are allocated per-use.
*/
struct ast_sdp_translator {
/*! The operations this translator uses */
struct ast_sdp_translator_ops *ops;
/*! Private data this translator uses */
void *translator_priv;
};
/*!
* \brief Register an SDP translator
* \param ops The SDP operations defined by this translator
* \retval 0 Success
* \retval -1 FAIL
*/
int ast_sdp_register_translator(struct ast_sdp_translator_ops *ops);
/*!
* \brief Unregister an SDP translator
*/
void ast_sdp_unregister_translator(struct ast_sdp_translator_ops *ops);
/*!
* \brief Allocate a new SDP translator
* \param Representation corresponding to the translator_ops to use
* \retval NULL FAIL
* \retval non-NULL New SDP translator
*/
struct ast_sdp_translator *ast_sdp_translator_new(enum ast_sdp_options_impl repr);
/*!
* \brief Free an SDP translator
*/
void ast_sdp_translator_free(struct ast_sdp_translator *translator);
/*!
* \brief Translate a native SDP to internal Asterisk SDP
*
* \param translator The translator to use when translating
* \param native_sdp The SDP from the channel driver
* \retval NULL FAIL
* \retval Non-NULL The translated SDP
*/
struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator, const void *native_sdp);
/*!
* \brief Translate an internal Asterisk SDP to a native SDP
*
* \param translator The translator to use when translating
* \param ast_sdp The Asterisk SDP to translate
* \retval NULL FAIL
* \retval non-NULL The translated SDP
*/
const void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator,
const struct ast_sdp *ast_sdp);
#endif /* _ASTERISK_SDP_TRANSLATOR_H */

View File

@ -1,950 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2017, Digium, Inc.
*
* George Joseph <gjoseph@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#include "asterisk.h"
#include "asterisk/utils.h"
#include "asterisk/netsock2.h"
#include "asterisk/codec.h"
#include "asterisk/format.h"
#include "asterisk/format_cap.h"
#include "asterisk/format_cache.h"
#include "asterisk/rtp_engine.h"
#include "asterisk/sdp_state.h"
#include "asterisk/sdp_options.h"
#include "asterisk/sdp_translator.h"
#include "asterisk/sdp.h"
#include "asterisk/vector.h"
#include "asterisk/utils.h"
#include "asterisk/stream.h"
#include "sdp_private.h"
void ast_sdp_a_free(struct ast_sdp_a_line *a_line)
{
ast_free(a_line);
}
void ast_sdp_a_lines_free(struct ast_sdp_a_lines *a_lines)
{
if (!a_lines) {
return;
}
AST_VECTOR_CALLBACK_VOID(a_lines, ast_sdp_a_free);
AST_VECTOR_FREE(a_lines);
ast_free(a_lines);
}
void ast_sdp_c_free(struct ast_sdp_c_line *c_line)
{
ast_free(c_line);
}
void ast_sdp_payload_free(struct ast_sdp_payload *payload)
{
ast_free(payload);
}
void ast_sdp_payloads_free(struct ast_sdp_payloads *payloads)
{
if (!payloads) {
return;
}
AST_VECTOR_CALLBACK_VOID(payloads, ast_sdp_payload_free);
AST_VECTOR_FREE(payloads);
ast_free(payloads);
}
void ast_sdp_m_free(struct ast_sdp_m_line *m_line)
{
if (!m_line) {
return;
}
ast_sdp_a_lines_free(m_line->a_lines);
ast_sdp_payloads_free(m_line->payloads);
ast_sdp_c_free(m_line->c_line);
ast_free(m_line);
}
void ast_sdp_m_lines_free(struct ast_sdp_m_lines *m_lines)
{
if (!m_lines) {
return;
}
AST_VECTOR_CALLBACK_VOID(m_lines, ast_sdp_m_free);
AST_VECTOR_FREE(m_lines);
ast_free(m_lines);
}
void ast_sdp_o_free(struct ast_sdp_o_line *o_line)
{
ast_free(o_line);
}
void ast_sdp_s_free(struct ast_sdp_s_line *s_line)
{
ast_free(s_line);
}
void ast_sdp_t_free(struct ast_sdp_t_line *t_line)
{
ast_free(t_line);
}
static void ast_sdp_dtor(void *vdoomed)
{
struct ast_sdp *sdp = vdoomed;
ast_sdp_o_free(sdp->o_line);
ast_sdp_s_free(sdp->s_line);
ast_sdp_c_free(sdp->c_line);
ast_sdp_t_free(sdp->t_line);
ast_sdp_a_lines_free(sdp->a_lines);
ast_sdp_m_lines_free(sdp->m_lines);
}
#define COPY_STR_AND_ADVANCE(p, dest, source) \
({ \
dest = p; \
strcpy(dest, source); \
p += (strlen(source) + 1); \
})
struct ast_sdp_a_line *ast_sdp_a_alloc(const char *name, const char *value)
{
struct ast_sdp_a_line *a_line;
size_t len;
char *p;
ast_assert(!ast_strlen_zero(name));
if (ast_strlen_zero(value)) {
value = "";
}
len = sizeof(*a_line) + strlen(name) + strlen(value) + 2;
a_line = ast_calloc(1, len);
if (!a_line) {
return NULL;
}
p = ((char *)a_line) + sizeof(*a_line);
COPY_STR_AND_ADVANCE(p, a_line->name, name);
COPY_STR_AND_ADVANCE(p, a_line->value, value);
return a_line;
}
struct ast_sdp_c_line *ast_sdp_c_alloc(const char *address_type, const char *address)
{
struct ast_sdp_c_line *c_line;
size_t len;
char *p;
ast_assert(!ast_strlen_zero(address_type) && !ast_strlen_zero(address));
len = sizeof(*c_line) + strlen(address_type) + strlen(address) + 2;
c_line = ast_calloc(1, len);
if (!c_line) {
return NULL;
}
p = ((char *)c_line) + sizeof(*c_line);
COPY_STR_AND_ADVANCE(p, c_line->address_type, address_type);
COPY_STR_AND_ADVANCE(p, c_line->address, address);
return c_line;
}
struct ast_sdp_payload *ast_sdp_payload_alloc(const char *fmt)
{
struct ast_sdp_payload *payload;
size_t len;
ast_assert(!ast_strlen_zero(fmt));
len = sizeof(*payload) + strlen(fmt) + 1;
payload = ast_calloc(1, len);
if (!payload) {
return NULL;
}
payload->fmt = ((char *)payload) + sizeof(*payload);
strcpy(payload->fmt, fmt); /* Safe */
return payload;
}
struct ast_sdp_m_line *ast_sdp_m_alloc(const char *type, uint16_t port,
uint16_t port_count, const char *proto, struct ast_sdp_c_line *c_line)
{
struct ast_sdp_m_line *m_line;
size_t len;
char *p;
ast_assert(!ast_strlen_zero(type) && !ast_strlen_zero(proto));
len = sizeof(*m_line) + strlen(type) + strlen(proto) + 2;
m_line = ast_calloc(1, len);
if (!m_line) {
return NULL;
}
m_line->a_lines = ast_calloc(1, sizeof(*m_line->a_lines));
if (!m_line->a_lines) {
ast_sdp_m_free(m_line);
return NULL;
}
if (AST_VECTOR_INIT(m_line->a_lines, 20)) {
ast_sdp_m_free(m_line);
return NULL;
}
m_line->payloads = ast_calloc(1, sizeof(*m_line->payloads));
if (!m_line->payloads) {
ast_sdp_m_free(m_line);
return NULL;
}
if (AST_VECTOR_INIT(m_line->payloads, 20)) {
ast_sdp_m_free(m_line);
return NULL;
}
p = ((char *)m_line) + sizeof(*m_line);
COPY_STR_AND_ADVANCE(p, m_line->type, type);
COPY_STR_AND_ADVANCE(p, m_line->proto, proto);
m_line->port = port;
m_line->port_count = port_count;
m_line->c_line = c_line;
return m_line;
}
struct ast_sdp_s_line *ast_sdp_s_alloc(const char *session_name)
{
struct ast_sdp_s_line *s_line;
size_t len;
if (ast_strlen_zero(session_name)) {
session_name = " ";
}
len = sizeof(*s_line) + strlen(session_name) + 1;
s_line = ast_calloc(1, len);
if (!s_line) {
return NULL;
}
s_line->session_name = ((char *)s_line) + sizeof(*s_line);
strcpy(s_line->session_name, session_name); /* Safe */
return s_line;
}
struct ast_sdp_t_line *ast_sdp_t_alloc(uint64_t start_time, uint64_t stop_time)
{
struct ast_sdp_t_line *t_line;
t_line = ast_calloc(1, sizeof(*t_line));
if (!t_line) {
return NULL;
}
t_line->start_time = start_time;
t_line->stop_time = stop_time;
return t_line;
}
struct ast_sdp_o_line *ast_sdp_o_alloc(const char *username, uint64_t session_id,
uint64_t session_version, const char *address_type, const char *address)
{
struct ast_sdp_o_line *o_line;
size_t len;
char *p;
ast_assert(!ast_strlen_zero(username) && !ast_strlen_zero(address_type)
&& !ast_strlen_zero(address));
len = sizeof(*o_line) + strlen(username) + strlen(address_type) + strlen(address) + 3;
o_line = ast_calloc(1, len);
if (!o_line) {
return NULL;
}
o_line->session_id = session_id;
o_line->session_version = session_version;
p = ((char *)o_line) + sizeof(*o_line);
COPY_STR_AND_ADVANCE(p, o_line->username, username);
COPY_STR_AND_ADVANCE(p, o_line->address_type, address_type);
COPY_STR_AND_ADVANCE(p, o_line->address, address);
return o_line;
}
struct ast_sdp *ast_sdp_alloc(struct ast_sdp_o_line *o_line,
struct ast_sdp_c_line *c_line, struct ast_sdp_s_line *s_line,
struct ast_sdp_t_line *t_line)
{
struct ast_sdp *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) {
ao2_ref(new_sdp, -1);
return NULL;
}
if (AST_VECTOR_INIT(new_sdp->a_lines, 20)) {
ao2_ref(new_sdp, -1);
return NULL;
}
new_sdp->m_lines = ast_calloc(1, sizeof(*new_sdp->m_lines));
if (!new_sdp->m_lines) {
ao2_ref(new_sdp, -1);
return NULL;
}
if (AST_VECTOR_INIT(new_sdp->m_lines, 20)) {
ao2_ref(new_sdp, -1);
return NULL;
}
new_sdp->o_line = o_line;
new_sdp->c_line = c_line;
new_sdp->s_line = s_line;
new_sdp->t_line = t_line;
return new_sdp;
}
int ast_sdp_add_a(struct ast_sdp *sdp, struct ast_sdp_a_line *a_line)
{
ast_assert(sdp && a_line);
return AST_VECTOR_APPEND(sdp->a_lines, a_line);
}
int ast_sdp_get_a_count(const struct ast_sdp *sdp)
{
ast_assert(sdp != NULL);
return AST_VECTOR_SIZE(sdp->a_lines);
}
struct ast_sdp_a_line *ast_sdp_get_a(const struct ast_sdp *sdp, int index)
{
ast_assert(sdp != NULL);
return AST_VECTOR_GET(sdp->a_lines, index);
}
int ast_sdp_add_m(struct ast_sdp *sdp, struct ast_sdp_m_line *m_line)
{
ast_assert(sdp && m_line);
return AST_VECTOR_APPEND(sdp->m_lines, m_line);
}
int ast_sdp_get_m_count(const struct ast_sdp *sdp)
{
ast_assert(sdp != NULL);
return AST_VECTOR_SIZE(sdp->m_lines);
}
struct ast_sdp_m_line *ast_sdp_get_m(const struct ast_sdp *sdp, int index)
{
ast_assert(sdp != NULL);
return AST_VECTOR_GET(sdp->m_lines, index);
}
int ast_sdp_m_add_a(struct ast_sdp_m_line *m_line, struct ast_sdp_a_line *a_line)
{
ast_assert(m_line && a_line);
return AST_VECTOR_APPEND(m_line->a_lines, a_line);
}
int ast_sdp_m_get_a_count(const struct ast_sdp_m_line *m_line)
{
ast_assert(m_line != NULL);
return AST_VECTOR_SIZE(m_line->a_lines);
}
struct ast_sdp_a_line *ast_sdp_m_get_a(const struct ast_sdp_m_line *m_line, int index)
{
ast_assert(m_line != NULL);
return AST_VECTOR_GET(m_line->a_lines, index);
}
int ast_sdp_m_add_payload(struct ast_sdp_m_line *m_line, struct ast_sdp_payload *payload)
{
ast_assert(m_line && payload);
return AST_VECTOR_APPEND(m_line->payloads, payload);
}
int ast_sdp_m_get_payload_count(const struct ast_sdp_m_line *m_line)
{
ast_assert(m_line != NULL);
return AST_VECTOR_SIZE(m_line->payloads);
}
struct ast_sdp_payload *ast_sdp_m_get_payload(const struct ast_sdp_m_line *m_line, int index)
{
ast_assert(m_line != NULL);
return AST_VECTOR_GET(m_line->payloads, index);
}
static int sdp_m_add_fmtp(struct ast_sdp_m_line *m_line, const struct ast_format *format,
int rtp_code)
{
struct ast_str *fmtp0 = ast_str_alloca(256);
struct ast_sdp_a_line *a_line;
char *tmp;
ast_format_generate_sdp_fmtp(format, rtp_code, &fmtp0);
if (ast_str_strlen(fmtp0) == 0) {
/* Format doesn't have fmtp attributes */
return 0;
}
tmp = ast_str_buffer(fmtp0) + ast_str_strlen(fmtp0) - 1;
/* remove any carriage return line feeds */
while (*tmp == '\r' || *tmp == '\n') --tmp;
*++tmp = '\0';
/*
* ast...generate gives us everything, just need value
*
* It can also give multiple fmtp attribute lines. (silk does)
*/
tmp = strchr(ast_str_buffer(fmtp0), ':');
if (tmp && tmp[1] != '\0') {
tmp++;
} else {
tmp = ast_str_buffer(fmtp0);
}
a_line = ast_sdp_a_alloc("fmtp", tmp);
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
return -1;
}
return 0;
}
static int sdp_m_add_rtpmap(struct ast_sdp_m_line *m_line,
const struct ast_sdp_options *options, int rtp_code, int asterisk_format,
const struct ast_format *format, int code)
{
char tmp[64];
const char *enc_name;
struct ast_sdp_payload *payload;
struct ast_sdp_a_line *a_line;
snprintf(tmp, sizeof(tmp), "%d", rtp_code);
payload = ast_sdp_payload_alloc(tmp);
if (!payload || ast_sdp_m_add_payload(m_line, payload)) {
ast_sdp_payload_free(payload);
return -1;
}
enc_name = ast_rtp_lookup_mime_subtype2(asterisk_format, format, code,
options->g726_non_standard ? AST_RTP_OPT_G726_NONSTANDARD : 0);
snprintf(tmp, sizeof(tmp), "%d %s/%d%s%s", rtp_code, enc_name,
ast_rtp_lookup_sample_rate2(asterisk_format, format, code),
strcmp(enc_name, "opus") ? "" : "/", strcmp(enc_name, "opus") ? "" : "2");
a_line = ast_sdp_a_alloc("rtpmap", tmp);
if (!a_line || ast_sdp_m_add_a(m_line, a_line)) {
ast_sdp_a_free(a_line);
return -1;
}
return 0;
}
int ast_sdp_m_add_format(struct ast_sdp_m_line *m_line, const struct ast_sdp_options *options,
int rtp_code, int asterisk_format, const struct ast_format *format, int code)
{
return sdp_m_add_rtpmap(m_line, options, rtp_code, asterisk_format, format, code)
|| sdp_m_add_fmtp(m_line, format, rtp_code) ? -1 : 0;
}
static int sdp_find_a_common(const struct ast_sdp_a_lines *a_lines, int start,
const char *attr_name, int payload)
{
struct ast_sdp_a_line *a_line;
int idx;
ast_assert(-1 <= start);
for (idx = start + 1; idx < AST_VECTOR_SIZE(a_lines); ++idx) {
int a_line_payload;
a_line = AST_VECTOR_GET(a_lines, idx);
if (strcmp(a_line->name, attr_name)) {
continue;
}
if (payload >= 0) {
int sscanf_res;
sscanf_res = sscanf(a_line->value, "%30d", &a_line_payload);
if (sscanf_res == 1 && payload == a_line_payload) {
return idx;
}
} else {
return idx;
}
}
return -1;
}
int ast_sdp_find_a_first(const struct ast_sdp *sdp, const char *attr_name, int payload)
{
return sdp_find_a_common(sdp->a_lines, -1, attr_name, payload);
}
int ast_sdp_find_a_next(const struct ast_sdp *sdp, int last, const char *attr_name, int payload)
{
return sdp_find_a_common(sdp->a_lines, last, attr_name, payload);
}
struct ast_sdp_a_line *ast_sdp_find_attribute(const struct ast_sdp *sdp,
const char *attr_name, int payload)
{
int idx;
idx = ast_sdp_find_a_first(sdp, attr_name, payload);
if (idx < 0) {
return NULL;
}
return ast_sdp_get_a(sdp, idx);
}
int ast_sdp_m_find_a_first(const struct ast_sdp_m_line *m_line, const char *attr_name,
int payload)
{
return sdp_find_a_common(m_line->a_lines, -1, attr_name, payload);
}
int ast_sdp_m_find_a_next(const struct ast_sdp_m_line *m_line, int last,
const char *attr_name, int payload)
{
return sdp_find_a_common(m_line->a_lines, last, attr_name, payload);
}
struct ast_sdp_a_line *ast_sdp_m_find_attribute(const struct ast_sdp_m_line *m_line,
const char *attr_name, int payload)
{
int idx;
idx = ast_sdp_m_find_a_first(m_line, attr_name, payload);
if (idx < 0) {
return NULL;
}
return ast_sdp_m_get_a(m_line, idx);
}
struct ast_sdp_rtpmap *ast_sdp_rtpmap_alloc(int payload, const char *encoding_name,
int clock_rate, const char *encoding_parameters)
{
struct ast_sdp_rtpmap *rtpmap;
char *buf_pos;
rtpmap = ast_calloc(1, sizeof(*rtpmap) + strlen(encoding_name) + strlen(encoding_parameters) + 2);
if (!rtpmap) {
return NULL;
}
rtpmap->payload = payload;
rtpmap->clock_rate = clock_rate;
buf_pos = rtpmap->buf;
COPY_STR_AND_ADVANCE(buf_pos, rtpmap->encoding_name, encoding_name);
COPY_STR_AND_ADVANCE(buf_pos, rtpmap->encoding_parameters, encoding_parameters);
return rtpmap;
}
void ast_sdp_rtpmap_free(struct ast_sdp_rtpmap *rtpmap)
{
ast_free(rtpmap);
}
struct ast_sdp_rtpmap *ast_sdp_a_get_rtpmap(const struct ast_sdp_a_line *a_line)
{
char *value_copy;
char *slash;
int payload;
char encoding_name[64];
int clock_rate;
char *encoding_parameters;
struct ast_sdp_rtpmap *rtpmap;
int clock_rate_len;
value_copy = ast_strip(ast_strdupa(a_line->value));
if (sscanf(value_copy, "%30d %63s", &payload, encoding_name) != 2) {
return NULL;
}
slash = strchr(encoding_name, '/');
if (!slash) {
return NULL;
}
*slash++ = '\0';
if (ast_strlen_zero(encoding_name)) {
return NULL;
}
if (sscanf(slash, "%30d%n", &clock_rate, &clock_rate_len) < 1) {
return NULL;
}
slash += clock_rate_len;
if (!ast_strlen_zero(slash)) {
if (*slash == '/') {
*slash++ = '\0';
encoding_parameters = slash;
if (ast_strlen_zero(encoding_parameters)) {
return NULL;
}
} else {
return NULL;
}
} else {
encoding_parameters = "";
}
rtpmap = ast_sdp_rtpmap_alloc(payload, encoding_name, clock_rate,
encoding_parameters);
return rtpmap;
}
/*!
* \brief Turn an SDP attribute into an sdp_rtpmap structure
*
* \param m_line The media section where this attribute was found.
* \param payload The RTP payload to find an rtpmap for
* \param[out] rtpmap The rtpmap to fill in.
* \return Zero if successful, otherwise less than zero
*/
static struct ast_sdp_rtpmap *sdp_payload_get_rtpmap(const struct ast_sdp_m_line *m_line, int payload)
{
struct ast_sdp_a_line *rtpmap_attr;
rtpmap_attr = ast_sdp_m_find_attribute(m_line, "rtpmap", payload);
if (!rtpmap_attr) {
return NULL;
}
return ast_sdp_a_get_rtpmap(rtpmap_attr);
}
static void process_fmtp_value(const char *value, int payload, struct ast_rtp_codecs *codecs)
{
char *param;
char *param_start;
char *param_end;
size_t len;
struct ast_format *replace;
struct ast_format *format;
/*
* Extract the "a=fmtp:%d %s" attribute parameter string value which
* starts after the colon.
*/
param_start = ast_skip_nonblanks(value);/* Skip payload type */
param_start = ast_skip_blanks(param_start);
param_end = ast_skip_nonblanks(param_start);
if (param_end == param_start) {
/* There is no parameter string */
return;
}
len = param_end - param_start;
param = ast_alloca(len + 1);
memcpy(param, param_start, len);
param[len] = '\0';
format = ast_rtp_codecs_get_payload_format(codecs, payload);
if (!format) {
return;
}
replace = ast_format_parse_sdp_fmtp(format, param);
if (replace) {
ast_rtp_codecs_payload_replace_format(codecs, payload, replace);
ao2_ref(replace, -1);
}
ao2_ref(format, -1);
}
/*!
* \brief Find and process all fmtp attribute lines for a given payload
*
* \param m_line The stream on which to search for the fmtp attributes
* \param payload The specific fmtp attribute to search for
* \param codecs The current RTP codecs that have been built up
*/
static void process_fmtp_lines(const struct ast_sdp_m_line *m_line, int payload,
struct ast_rtp_codecs *codecs)
{
const struct ast_sdp_a_line *a_line;
int idx;
idx = ast_sdp_m_find_a_first(m_line, "fmtp", payload);
for (; 0 <= idx; idx = ast_sdp_m_find_a_next(m_line, idx, "fmtp", payload)) {
a_line = ast_sdp_m_get_a(m_line, idx);
ast_assert(a_line != NULL);
process_fmtp_value(a_line->value, payload, codecs);
}
}
/*!
* \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.
*/
static void rtp_codecs_free(struct ast_rtp_codecs *codecs)
{
if (codecs) {
ast_rtp_codecs_payloads_destroy(codecs);
}
}
/*!
* \brief Convert an SDP stream into an Asterisk stream
*
* 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_a_lines *a_lines, const struct ast_sdp_m_line *m_line, int g726_non_standard)
{
int i;
int non_ast_fmts;
struct ast_rtp_codecs *codecs;
struct ast_format_cap *caps;
struct ast_stream *stream;
enum ast_rtp_options options;
caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
if (!caps) {
return NULL;
}
stream = ast_stream_alloc(m_line->type, ast_media_type_from_str(m_line->type));
if (!stream) {
ao2_ref(caps, -1);
return NULL;
}
switch (ast_stream_get_type(stream)) {
case AST_MEDIA_TYPE_AUDIO:
case AST_MEDIA_TYPE_VIDEO:
codecs = ast_calloc(1, sizeof(*codecs));
if (!codecs || ast_rtp_codecs_payloads_initialize(codecs)) {
rtp_codecs_free(codecs);
ast_stream_free(stream);
ao2_ref(caps, -1);
ast_free(codecs);
return NULL;
}
ast_stream_set_rtp_codecs(stream, codecs);
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) {
struct ast_sdp_payload *payload_s;
struct ast_sdp_rtpmap *rtpmap;
int payload;
payload_s = ast_sdp_m_get_payload(m_line, i);
sscanf(payload_s->fmt, "%30d", &payload);
rtpmap = sdp_payload_get_rtpmap(m_line, payload);
if (!rtpmap) {
/* No rtpmap attribute. Try static payload type format assignment */
ast_rtp_codecs_payloads_set_m_type(codecs, NULL, payload);
continue;
}
if (!ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, payload,
m_line->type, rtpmap->encoding_name, options, rtpmap->clock_rate)) {
/* Successfully mapped the payload type to format */
process_fmtp_lines(m_line, payload, codecs);
}
ast_sdp_rtpmap_free(rtpmap);
}
ast_rtp_codecs_payload_formats(codecs, caps, &non_ast_fmts);
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;
/* As we don't carry T.38 over RTP we do our own format check */
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;
}
ast_stream_set_formats(stream, caps);
ao2_ref(caps, -1);
return stream;
}
struct ast_stream_topology *ast_get_topology_from_sdp(const struct ast_sdp *sdp, int g726_non_standard)
{
struct ast_stream_topology *topology;
int i;
topology = ast_stream_topology_alloc();
if (!topology) {
return NULL;
}
for (i = 0; i < ast_sdp_get_m_count(sdp); ++i) {
struct ast_stream *stream;
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
* we failed to create a corresponding stream.
*/
ast_stream_topology_free(topology);
return NULL;
}
if (ast_stream_topology_append_stream(topology, stream) < 0) {
/* Failed to add stream to topology */
ast_stream_free(stream);
ast_stream_topology_free(topology);
return NULL;
}
}
return topology;
}

View File

@ -1,235 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2017, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#include "asterisk.h"
#include "asterisk/utils.h"
#include "asterisk/sdp_options.h"
#include "sdp_private.h"
#define DEFAULT_DTMF AST_SDP_DTMF_NONE
#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) \
{ \
ast_assert(options != NULL); \
if ((assert_on_null)) ast_assert(!ast_strlen_zero(value)); \
if (!strcmp(value, options->field)) return; \
ast_string_field_set(options, field, value); \
} \
const char *ast_sdp_options_get_##field(const struct ast_sdp_options *options) \
{ \
ast_assert(options != NULL); \
return options->field; \
} \
#define DEFINE_GETTERS_SETTERS_FOR(type, field) \
void ast_sdp_options_set_##field(struct ast_sdp_options *options, type value) \
{ \
ast_assert(options != NULL); \
options->field = value; \
} \
type ast_sdp_options_get_##field(const struct ast_sdp_options *options) \
{ \
ast_assert(options != NULL); \
return options->field; \
} \
DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(media_address, 0);
DEFINE_STRINGFIELD_GETTERS_SETTERS_FOR(interface_address, 0);
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);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, udptl_far_max_datagram);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtp_ipv6);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, g726_non_standard);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, rtcp_mux);
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);
DEFINE_GETTERS_SETTERS_FOR(enum ast_sdp_options_encryption, encryption);
DEFINE_GETTERS_SETTERS_FOR(unsigned int, ssrc);
struct ast_sched_context *ast_sdp_options_get_sched_type(const struct ast_sdp_options *options, enum ast_media_type type)
{
struct ast_sched_context *sched = NULL;
switch (type) {
case AST_MEDIA_TYPE_AUDIO:
case AST_MEDIA_TYPE_VIDEO:
case AST_MEDIA_TYPE_IMAGE:
case AST_MEDIA_TYPE_TEXT:
sched = options->sched[type];
break;
case AST_MEDIA_TYPE_UNKNOWN:
case AST_MEDIA_TYPE_END:
break;
}
return sched;
}
void ast_sdp_options_set_sched_type(struct ast_sdp_options *options, enum ast_media_type type, struct ast_sched_context *sched)
{
switch (type) {
case AST_MEDIA_TYPE_AUDIO:
case AST_MEDIA_TYPE_VIDEO:
case AST_MEDIA_TYPE_IMAGE:
case AST_MEDIA_TYPE_TEXT:
options->sched[type] = sched;
break;
case AST_MEDIA_TYPE_UNKNOWN:
case AST_MEDIA_TYPE_END:
break;
}
}
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)
{
struct ast_sdp_options *options;
options = ast_calloc(1, sizeof(*options));
if (!options) {
return NULL;
}
if (ast_string_field_init(options, 256)) {
ast_free(options);
return NULL;
}
set_defaults(options);
return options;
}
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

@ -1,78 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2017, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#ifndef _MAIN_SDP_PRIVATE_H
#define _MAIN_SDP_PRIVATE_H
#include "asterisk/stringfields.h"
#include "asterisk/sdp_options.h"
struct ast_sdp_options {
AST_DECLARE_STRING_FIELDS(
/*! 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);
/*! SDP origin username */
AST_STRING_FIELD(sdpowner);
/*! SDP session name */
AST_STRING_FIELD(sdpsession);
/*! RTP Engine Name */
AST_STRING_FIELD(rtp_engine);
);
/*! 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 rtcp_mux:1;
unsigned int ssrc:1;
};
struct {
unsigned int tos_audio;
unsigned int cos_audio;
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;
enum ast_sdp_options_impl impl;
enum ast_sdp_options_encryption encryption;
enum ast_t38_ec_modes udptl_error_correction;
};
#endif /* _MAIN_SDP_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,104 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2017, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#include "asterisk.h"
#include "asterisk/sdp_options.h"
#include "asterisk/sdp_translator.h"
#include "asterisk/logger.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
AST_RWLOCK_DEFINE_STATIC(registered_ops_lock);
static struct ast_sdp_translator_ops *registered_ops[AST_SDP_IMPL_END];
int ast_sdp_register_translator(struct ast_sdp_translator_ops *ops)
{
SCOPED_WRLOCK(lock, &registered_ops_lock);
if (ops->repr >= AST_SDP_IMPL_END) {
ast_log(LOG_ERROR, "SDP translator has unrecognized representation\n");
return -1;
}
if (registered_ops[ops->repr] != NULL) {
ast_log(LOG_ERROR, "SDP_translator with this representation already registered\n");
return -1;
}
registered_ops[ops->repr] = ops;
ast_log(LOG_NOTICE, "Placed ops %p at slot %d\n", ops, ops->repr);
return 0;
}
void ast_sdp_unregister_translator(struct ast_sdp_translator_ops *ops)
{
SCOPED_WRLOCK(lock, &registered_ops_lock);
if (ops->repr >= AST_SDP_IMPL_END) {
return;
}
registered_ops[ops->repr] = NULL;
}
struct ast_sdp_translator *ast_sdp_translator_new(enum ast_sdp_options_impl repr)
{
struct ast_sdp_translator *translator;
SCOPED_RDLOCK(lock, &registered_ops_lock);
if (registered_ops[repr] == NULL) {
ast_log(LOG_NOTICE, "No registered SDP translator with representation %d\n", repr);
return NULL;
}
translator = ast_calloc(1, sizeof(*translator));
if (!translator) {
return NULL;
}
translator->ops = registered_ops[repr];
translator->translator_priv = translator->ops->translator_new();
if (!translator->translator_priv) {
ast_free(translator);
return NULL;
}
return translator;
}
void ast_sdp_translator_free(struct ast_sdp_translator *translator)
{
if (!translator) {
return;
}
translator->ops->translator_free(translator->translator_priv);
ast_free(translator);
}
struct ast_sdp *ast_sdp_translator_to_sdp(struct ast_sdp_translator *translator,
const void *native_sdp)
{
return translator->ops->to_sdp(native_sdp, translator->translator_priv);
}
const void *ast_sdp_translator_from_sdp(struct ast_sdp_translator *translator,
const struct ast_sdp *ast_sdp)
{
return translator->ops->from_sdp(ast_sdp, translator->translator_priv);
}

View File

@ -1,605 +0,0 @@
/*
* Asterisk -- An open source telephony toolkit.
*
* Copyright (C) 2017, Digium, Inc.
*
* Mark Michelson <mmichelson@digium.com>
*
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
#include "asterisk.h"
#include <pjlib.h>
#include <pjmedia.h>
#include "asterisk/res_pjproject.h"
#include "asterisk/sdp_translator.h"
#include "asterisk/sdp_options.h"
#include "asterisk/vector.h"
#include "asterisk/netsock2.h"
#include "asterisk/utils.h"
#include "asterisk/config.h"
#include "asterisk/test.h"
#include "asterisk/module.h"
#include "asterisk/sdp.h"
/*** MODULEINFO
<depend>pjproject</depend>
<support_level>core</support_level>
***/
/*
* XXX TODO: The memory in the pool is held onto longer than necessary. It
* is kept and grows for the duration of the associated chan_pjsip session.
*
* The translation API does not need to be so generic. The users will know
* at compile time what the non-Asterisk SDP format they have or need. They
* should simply call the specific translation functions. However, to make
* this a loadable module we need to be able to keep it in memory when a
* dependent module is loaded.
*
* To address both issues I propose this API:
*
* void ast_sdp_translate_pjmedia_ref(void) - Inc this module's user ref
* void ast_sdp_translate_pjmedia_unref(void) - Dec this module's user ref.
* The res_pjsip_session.c:ast_sip_session_alloc() can call the module ref
* and the session's destructor can call the module unref.
*
* struct ast_sdp *ast_sdp_translate_pjmedia_from(const pjmedia_sdp_session *pjmedia_sdp);
*
* pjmedia_sdp_session *ast_sdp_translate_pjmedia_to(const struct ast_sdp *sdp, pj_pool_t *pool);
* Passing in a memory pool allows the memory to be obtained from an
* rdata memory pool that will be released when the message processing
* is complete. This prevents memory from accumulating for the duration
* of a call.
*
* int ast_sdp_translate_pjmedia_set_remote_sdp(struct ast_sdp_state *sdp_state, const pjmedia_sdp_session *remote);
* const pjmedia_sdp_session *ast_sdp_translate_pjmedia_get_local_sdp(struct ast_sdp_state *sdp_state, pj_pool_t *pool);
* These two functions just do the bookkeeping to translate and set or get
* the requested SDP.
*
*
* XXX TODO: This code doesn't handle allocation failures very well. i.e.,
* It assumes they will never happen.
*
* XXX TODO: This code uses ast_alloca() inside loops. Doing so if the number
* of times through the loop is unconstrained will blow the stack.
* See dupa_pj_str() usage.
*/
static pj_caching_pool sdp_caching_pool;
static void *pjmedia_new(void)
{
pj_pool_t *pool;
pool = pj_pool_create(&sdp_caching_pool.factory, "pjmedia sdp translator", 1024, 1024, NULL);
return pool;
}
static void pjmedia_free(void *translator_priv)
{
pj_pool_t *pool = translator_priv;
pj_pool_release(pool);
}
#define dupa_pj_str(pjstr) \
({ \
char *dest = ast_alloca(pjstr.slen + 1); \
memcpy(dest, pjstr.ptr, pjstr.slen); \
dest[pjstr.slen] = '\0'; \
dest; \
})
static struct ast_sdp_m_line *pjmedia_copy_m_line(struct pjmedia_sdp_media *pjmedia_m_line)
{
int i;
struct ast_sdp_c_line *c_line = pjmedia_m_line->conn ?
ast_sdp_c_alloc(dupa_pj_str(pjmedia_m_line->conn->addr_type),
dupa_pj_str(pjmedia_m_line->conn->addr)) : NULL;
struct ast_sdp_m_line *m_line = ast_sdp_m_alloc(dupa_pj_str(pjmedia_m_line->desc.media),
pjmedia_m_line->desc.port, pjmedia_m_line->desc.port_count,
dupa_pj_str(pjmedia_m_line->desc.transport), c_line);
for (i = 0; i < pjmedia_m_line->desc.fmt_count; ++i) {
ast_sdp_m_add_payload(m_line,
ast_sdp_payload_alloc(dupa_pj_str(pjmedia_m_line->desc.fmt[i])));
}
for (i = 0; i < pjmedia_m_line->attr_count; ++i) {
ast_sdp_m_add_a(m_line, ast_sdp_a_alloc(dupa_pj_str(pjmedia_m_line->attr[i]->name),
dupa_pj_str(pjmedia_m_line->attr[i]->value)));
}
return m_line;
}
static void pjmedia_copy_a_lines(struct ast_sdp *new_sdp, const pjmedia_sdp_session *pjmedia_sdp)
{
int i;
for (i = 0; i < pjmedia_sdp->attr_count; ++i) {
ast_sdp_add_a(new_sdp, ast_sdp_a_alloc(dupa_pj_str(pjmedia_sdp->attr[i]->name),
dupa_pj_str(pjmedia_sdp->attr[i]->value)));
}
}
static void pjmedia_copy_m_lines(struct ast_sdp *new_sdp,
const struct pjmedia_sdp_session *pjmedia_sdp)
{
int i;
for (i = 0; i < pjmedia_sdp->media_count; ++i) {
ast_sdp_add_m(new_sdp, pjmedia_copy_m_line(pjmedia_sdp->media[i]));
}
}
static struct ast_sdp *pjmedia_to_sdp(const void *in, void *translator_priv)
{
const struct pjmedia_sdp_session *pjmedia_sdp = in;
struct ast_sdp_o_line *o_line = ast_sdp_o_alloc(dupa_pj_str(pjmedia_sdp->origin.user),
pjmedia_sdp->origin.id, pjmedia_sdp->origin.version,
dupa_pj_str(pjmedia_sdp->origin.addr_type), dupa_pj_str(pjmedia_sdp->origin.addr));
struct ast_sdp_c_line *c_line = pjmedia_sdp->conn ?
ast_sdp_c_alloc(dupa_pj_str(pjmedia_sdp->conn->addr_type),
dupa_pj_str(pjmedia_sdp->conn->addr)) : NULL;
struct ast_sdp_s_line *s_line = ast_sdp_s_alloc(dupa_pj_str(pjmedia_sdp->name));
struct ast_sdp_t_line *t_line = ast_sdp_t_alloc(pjmedia_sdp->time.start,
pjmedia_sdp->time.stop);
struct ast_sdp *new_sdp = ast_sdp_alloc(o_line, c_line, s_line, t_line);
pjmedia_copy_a_lines(new_sdp, pjmedia_sdp);
pjmedia_copy_m_lines(new_sdp, pjmedia_sdp);
return new_sdp;
}
static void copy_o_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp,
struct ast_sdp_o_line *o_line)
{
pjmedia_sdp->origin.id = o_line->session_id;
pjmedia_sdp->origin.version = o_line->session_version;
pj_strdup2(pool, &pjmedia_sdp->origin.user, o_line->username);
pj_strdup2(pool, &pjmedia_sdp->origin.addr_type, o_line->address_type);
pj_strdup2(pool, &pjmedia_sdp->origin.addr, o_line->address);
pj_strdup2(pool, &pjmedia_sdp->origin.net_type, "IN");
}
static void copy_s_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp,
struct ast_sdp_s_line *s_line)
{
pj_strdup2(pool, &pjmedia_sdp->name, s_line->session_name);
}
static void copy_t_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp,
struct ast_sdp_t_line *t_line)
{
pjmedia_sdp->time.start = t_line->start_time;
pjmedia_sdp->time.stop = t_line->stop_time;
}
static void copy_c_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_conn **conn,
struct ast_sdp_c_line *c_line)
{
pjmedia_sdp_conn *local_conn;
local_conn = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_conn);
pj_strdup2(pool, &local_conn->addr_type, c_line->address_type);
pj_strdup2(pool, &local_conn->addr, c_line->address);
pj_strdup2(pool, &local_conn->net_type, "IN");
*conn = local_conn;
}
static void copy_a_lines_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp,
const struct ast_sdp *sdp)
{
int i;
for (i = 0; i < ast_sdp_get_a_count(sdp); ++i) {
pjmedia_sdp_attr *attr;
pj_str_t value;
struct ast_sdp_a_line *a_line;
a_line = ast_sdp_get_a(sdp, i);
pj_strdup2(pool, &value, a_line->value);
attr = pjmedia_sdp_attr_create(pool, a_line->name, &value);
pjmedia_sdp_session_add_attr(pjmedia_sdp, attr);
}
}
static void copy_a_lines_pjmedia_media(pj_pool_t *pool, pjmedia_sdp_media *media,
struct ast_sdp_m_line *m_line)
{
int i;
for (i = 0; i < ast_sdp_m_get_a_count(m_line); ++i) {
pjmedia_sdp_attr *attr;
pj_str_t value;
struct ast_sdp_a_line *a_line;
a_line = ast_sdp_m_get_a(m_line, i);
pj_strdup2(pool, &value, a_line->value);
attr = pjmedia_sdp_attr_create(pool, a_line->name, &value);
pjmedia_sdp_media_add_attr(media, attr);
}
}
static void copy_m_line_pjmedia(pj_pool_t *pool, pjmedia_sdp_media *media,
struct ast_sdp_m_line *m_line)
{
int i;
media->desc.port = m_line->port;
media->desc.port_count = m_line->port_count;
pj_strdup2(pool, &media->desc.transport, m_line->proto);
pj_strdup2(pool, &media->desc.media, m_line->type);
for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) {
pj_strdup2(pool, &media->desc.fmt[i], ast_sdp_m_get_payload(m_line, i)->fmt);
++media->desc.fmt_count;
}
if (m_line->c_line && m_line->c_line->address) {
copy_c_line_pjmedia(pool, &media->conn, m_line->c_line);
}
copy_a_lines_pjmedia_media(pool, media, m_line);
}
static void copy_m_lines_pjmedia(pj_pool_t *pool, pjmedia_sdp_session *pjmedia_sdp,
const struct ast_sdp *sdp)
{
int i;
for (i = 0; i < ast_sdp_get_m_count(sdp); ++i) {
pjmedia_sdp_media *media;
media = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
copy_m_line_pjmedia(pool, media, ast_sdp_get_m(sdp, i));
pjmedia_sdp->media[pjmedia_sdp->media_count] = media;
++pjmedia_sdp->media_count;
}
}
static const void *sdp_to_pjmedia(const struct ast_sdp *sdp, void *translator_priv)
{
pj_pool_t *pool = translator_priv;
pjmedia_sdp_session *pjmedia_sdp;
pjmedia_sdp = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_session);
copy_o_line_pjmedia(pool, pjmedia_sdp, sdp->o_line);
copy_s_line_pjmedia(pool, pjmedia_sdp, sdp->s_line);
copy_t_line_pjmedia(pool, pjmedia_sdp, sdp->t_line);
copy_c_line_pjmedia(pool, &pjmedia_sdp->conn, sdp->c_line);
copy_a_lines_pjmedia(pool, pjmedia_sdp, sdp);
copy_m_lines_pjmedia(pool, pjmedia_sdp, sdp);
return pjmedia_sdp;
}
static struct ast_sdp_translator_ops pjmedia_translator = {
.repr = AST_SDP_IMPL_PJMEDIA,
.translator_new = pjmedia_new,
.translator_free = pjmedia_free,
.to_sdp = pjmedia_to_sdp,
.from_sdp = sdp_to_pjmedia,
};
#ifdef TEST_FRAMEWORK
static int verify_s_line(struct ast_sdp_s_line *s_line, char *expected)
{
return strcmp(s_line->session_name, expected) == 0;
}
static int verify_c_line(struct ast_sdp_c_line *c_line, char *family, char *addr)
{
return strcmp(c_line->address_type, family) == 0 && strcmp(c_line->address, addr) == 0;
}
static int verify_t_line(struct ast_sdp_t_line *t_line, uint32_t start, uint32_t end)
{
return t_line->start_time == start && t_line->stop_time == end;
}
static int verify_m_line(struct ast_sdp *sdp, int index, char *type, int port,
int port_count, char *profile, ...)
{
struct ast_sdp_m_line *m_line;
int res;
va_list ap;
int i;
m_line = ast_sdp_get_m(sdp, index);
res = strcmp(m_line->type, type) == 0;
res |= m_line->port == port;
res |= m_line->port_count == port_count;
res |= strcmp(m_line->proto, profile) == 0;
va_start(ap, profile);
for (i = 0; i < ast_sdp_m_get_payload_count(m_line); ++i) {
char *payload;
payload = va_arg(ap, char *);
if (!payload) {
res = -1;
break;
}
res |= strcmp(ast_sdp_m_get_payload(m_line, i)->fmt, payload) == 0;
}
va_end(ap);
return res;
}
static int verify_a_line(struct ast_sdp *sdp, int m_index, int a_index, char *name,
char *value)
{
struct ast_sdp_m_line *m_line;
struct ast_sdp_a_line *a_line;
m_line = ast_sdp_get_m(sdp, m_index);
a_line = ast_sdp_m_get_a(m_line, a_index);
return strcmp(a_line->name, name) == 0 && strcmp(a_line->value, value) == 0;
}
AST_TEST_DEFINE(pjmedia_to_sdp_test)
{
struct ast_sdp_translator *translator;
pj_pool_t *pool;
char *sdp_str =
"v=0\r\n"
"o=alice 2890844526 2890844527 IN IP4 host.atlanta.example.com\r\n"
"s= \r\n"
"c=IN IP4 host.atlanta.example.com\r\n"
"t=123 456\r\n"
"m=audio 49170 RTP/AVP 0 8 97\r\n"
"a=rtpmap:0 PCMU/8000\r\n"
"a=rtpmap:8 PCMA/8000\r\n"
"a=rtpmap:97 iLBC/8000\r\n"
"a=sendrecv\r\n"
"m=video 51372 RTP/AVP 31 32\r\n"
"a=rtpmap:31 H261/90000\r\n"
"a=rtpmap:32 MPV/90000\r\n";
pjmedia_sdp_session *pjmedia_sdp;
struct ast_sdp *sdp = NULL;
pj_status_t status;
enum ast_test_result_state res = AST_TEST_PASS;
switch (cmd) {
case TEST_INIT:
info->name = "pjmedia_to_sdp";
info->category = "/main/sdp/";
info->summary = "PJMEDIA to SDP unit test";
info->description =
"Ensures PJMEDIA SDPs are translated correctly";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
pool = pj_pool_create(&sdp_caching_pool.factory, "pjmedia to sdp test", 1024, 1024, NULL);
translator = ast_sdp_translator_new(AST_SDP_IMPL_PJMEDIA);
if (!translator) {
ast_test_status_update(test, "Failed to create SDP translator\n");
res = AST_TEST_FAIL;
goto cleanup;
}
status = pjmedia_sdp_parse(pool, sdp_str, strlen(sdp_str), &pjmedia_sdp);
if (status != PJ_SUCCESS) {
ast_test_status_update(test, "Error parsing SDP\n");
res = AST_TEST_FAIL;
goto cleanup;
}
sdp = ast_sdp_translator_to_sdp(translator, pjmedia_sdp);
if (strcmp(sdp->o_line->username, "alice")) {
ast_test_status_update(test, "Unexpected SDP user '%s'\n", sdp->o_line->username);
res = AST_TEST_FAIL;
goto cleanup;
} else if (sdp->o_line->session_id != 2890844526UL) {
ast_test_status_update(test, "Unexpected SDP id '%" PRId64 "lu'\n", sdp->o_line->session_id);
res = AST_TEST_FAIL;
goto cleanup;
} else if (sdp->o_line->session_version != 2890844527UL) {
ast_test_status_update(test, "Unexpected SDP version '%" PRId64 "'\n", sdp->o_line->session_version);
res = AST_TEST_FAIL;
goto cleanup;
} else if (strcmp(sdp->o_line->address_type, "IP4")) {
ast_test_status_update(test, "Unexpected address family '%s'\n", sdp->o_line->address_type);
res = AST_TEST_FAIL;
goto cleanup;
} else if (strcmp(sdp->o_line->address, "host.atlanta.example.com")) {
ast_test_status_update(test, "Unexpected address '%s'\n", sdp->o_line->address);
res = AST_TEST_FAIL;
goto cleanup;
}
if (!verify_s_line(sdp->s_line, " ")) {
ast_test_status_update(test, "Bad s line\n");
res = AST_TEST_FAIL;
goto cleanup;
} else if (!verify_c_line(sdp->c_line, "IP4", "host.atlanta.example.com")) {
ast_test_status_update(test, "Bad c line\n");
res = AST_TEST_FAIL;
goto cleanup;
} else if (!verify_t_line(sdp->t_line, 123, 456)) {
ast_test_status_update(test, "Bad t line\n");
res = AST_TEST_FAIL;
goto cleanup;
}
if (!verify_m_line(sdp, 0, "audio", 49170, 1, "RTP/AVP", "0", "8", "97", NULL)) {
ast_test_status_update(test, "Bad m line 1\n");
res = AST_TEST_FAIL;
goto cleanup;
} else if (!verify_a_line(sdp, 0, 0, "rtpmap", "0 PCMU/8000")) {
ast_test_status_update(test, "Bad a line 1\n");
res = AST_TEST_FAIL;
goto cleanup;
} else if (!verify_a_line(sdp, 0, 1, "rtpmap", "8 PCMA/8000")) {
ast_test_status_update(test, "Bad a line 2\n");
res = AST_TEST_FAIL;
goto cleanup;
} else if (!verify_a_line(sdp, 0, 2, "rtpmap", "97 iLBC/8000")) {
ast_test_status_update(test, "Bad a line 3\n");
res = AST_TEST_FAIL;
goto cleanup;
} else if (!verify_a_line(sdp, 0, 3, "sendrecv", "")) {
ast_test_status_update(test, "Bad a line 3\n");
res = AST_TEST_FAIL;
goto cleanup;
} else if (!verify_m_line(sdp, 1, "video", 51372, 1, "RTP/AVP", "31", "32", NULL)) {
ast_test_status_update(test, "Bad m line 2\n");
res = AST_TEST_FAIL;
goto cleanup;
} else if (!verify_a_line(sdp, 1, 0, "rtpmap", "31 H261/90000")) {
ast_test_status_update(test, "Bad a line 4\n");
res = AST_TEST_FAIL;
goto cleanup;
} else if (!verify_a_line(sdp, 1, 1, "rtpmap", "32 MPV/90000")) {
ast_test_status_update(test, "Bad a line 5\n");
res = AST_TEST_FAIL;
goto cleanup;
}
cleanup:
ao2_cleanup(sdp);
ast_sdp_translator_free(translator);
pj_pool_release(pool);
return res;
}
AST_TEST_DEFINE(sdp_to_pjmedia_test)
{
struct ast_sdp_translator *translator;
char *sdp_str =
"v=0\r\n"
"o=alice 2890844526 2890844526 IN IP4 host.atlanta.example.com\r\n"
"s= \r\n"
"c=IN IP4 host.atlanta.example.com\r\n"
"t=123 456\r\n"
"m=audio 49170 RTP/AVP 0 8 97\r\n"
"a=rtpmap:0 PCMU/8000\r\n"
"a=rtpmap:8 PCMA/8000\r\n"
"a=rtpmap:97 iLBC/8000\r\n"
"a=sendrecv\r\n"
"m=video 51372 RTP/AVP 31 32\r\n"
"a=rtpmap:31 H261/90000\r\n"
"a=rtpmap:32 MPV/90000\r\n\r\n";
pj_pool_t *pool;
pjmedia_sdp_session *pjmedia_sdp_orig;
const pjmedia_sdp_session *pjmedia_sdp_dup;
struct ast_sdp *sdp = NULL;
pj_status_t status;
enum ast_test_result_state res = AST_TEST_PASS;
char buf[2048];
char errbuf[256];
switch (cmd) {
case TEST_INIT:
info->name = "sdp_to_pjmedia";
info->category = "/main/sdp/";
info->summary = "SDP to PJMEDIA unit test";
info->description =
"Ensures PJMEDIA SDPs are translated correctly";
return AST_TEST_NOT_RUN;
case TEST_EXECUTE:
break;
}
pool = pj_pool_create(&sdp_caching_pool.factory, "pjmedia to sdp test", 1024, 1024, NULL);
translator = ast_sdp_translator_new(AST_SDP_IMPL_PJMEDIA);
if (!translator) {
ast_test_status_update(test, "Failed to create SDP translator\n");
res = AST_TEST_FAIL;
goto cleanup;
}
status = pjmedia_sdp_parse(pool, sdp_str, strlen(sdp_str), &pjmedia_sdp_orig);
if (status != PJ_SUCCESS) {
ast_test_status_update(test, "Error parsing SDP\n");
res = AST_TEST_FAIL;
goto cleanup;
}
sdp = ast_sdp_translator_to_sdp(translator, pjmedia_sdp_orig);
pjmedia_sdp_dup = ast_sdp_translator_from_sdp(translator, sdp);
if ((status = pjmedia_sdp_session_cmp(pjmedia_sdp_orig, pjmedia_sdp_dup, 0)) != PJ_SUCCESS) {
ast_test_status_update(test, "SDPs aren't equal\n");
pjmedia_sdp_print(pjmedia_sdp_orig, buf, sizeof(buf));
ast_test_status_update(test, "Original SDP is %s\n", buf);
pjmedia_sdp_print(pjmedia_sdp_dup, buf, sizeof(buf));
ast_test_status_update(test, "New SDP is %s\n", buf);
pjmedia_strerror(status, errbuf, sizeof(errbuf));
ast_test_status_update(test, "PJMEDIA says %d: '%s'\n", status, errbuf);
res = AST_TEST_FAIL;
goto cleanup;
}
cleanup:
ao2_cleanup(sdp);
ast_sdp_translator_free(translator);
pj_pool_release(pool);
return res;
}
#endif /* TEST_FRAMEWORK */
static int load_module(void)
{
if (ast_sdp_register_translator(&pjmedia_translator)) {
return AST_MODULE_LOAD_DECLINE;
}
ast_pjproject_caching_pool_init(&sdp_caching_pool, NULL, 1024 * 1024);
AST_TEST_REGISTER(pjmedia_to_sdp_test);
AST_TEST_REGISTER(sdp_to_pjmedia_test);
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
{
ast_sdp_unregister_translator(&pjmedia_translator);
ast_pjproject_caching_pool_destroy(&sdp_caching_pool);
AST_TEST_UNREGISTER(pjmedia_to_sdp_test);
AST_TEST_UNREGISTER(sdp_to_pjmedia_test);
return 0;
}
static int reload_module(void)
{
return 0;
}
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJMEDIA SDP Translator",
.support_level = AST_MODULE_SUPPORT_CORE,
.load = load_module,
.unload = unload_module,
.reload = reload_module,
.load_pri = AST_MODPRI_CHANNEL_DEPEND,
.requires = "res_pjproject",
);

File diff suppressed because it is too large Load Diff