; at the end of the joint list.
; remote_first - Include only the first codec in
; the remote list.
+;incoming_offer_codec_prefs=; This is a string that describes how the codecs
+ ; specified on an incoming SDP offer (pending) are
+ ; reconciled with the codecs specified on an endpoint
+ ; (configured) before being sent to the Asterisk core.
+ ; The string actually specifies 4 name:value pair
+ ; parameters separated by commas. Whitespace is
+ ; ignored and they may be specified in any order.
+ ; prefer: <pending | configured>,
+ ; operation: <intersect | only_preferred
+ ; | only_nonpreferred>,
+ ; keep: <first | all>,
+ ; transcode: <allow | prevent>
+;outgoing_offer_codec_prefs=; This is a string that describes how the codecs
+ ; specified in the topology that comes from the
+ ; Asterisk core (pending) are reconciled with the
+ ; codecs specified on an endpoint (configured)
+ ; when sending an SDP offer.
+ ; The string actually specifies 4 name:value pair
+ ; parameters separated by commas. Whitespace is
+ ; ignored and they may be specified in any order.
+ ; prefer: <pending | configured>,
+ ; operation: <intersect | union
+ ; | only_preferred | only_nonpreferred>,
+ ; keep: <first | all>,
+ ; transcode: <allow | prevent>
+;incoming_answer_codec_prefs=; This is a string that describes how the codecs
+ ; specified in an incoming SDP answer (pending)
+ ; are reconciled with the codecs specified on an
+ ; endpoint (configured) when receiving an SDP
+ ; answer.
+ ; The string actually specifies 4 name:value pair
+ ; parameters separated by commas. Whitespace is
+ ; ignored and they may be specified in any order.
+ ; prefer: <pending | configured>,
+ ; operation: <intersect | union
+ ; | only_preferred | only_nonpreferred>,
+ ; keep: <first | all>
+;outgoing_answer_codec_prefs=; This is a string that describes how the codecs
+ ; that come from the core (pending) are reconciled
+ ; with the codecs specified on an endpoint
+ ; (configured) when sending an SDP answer.
+ ; The string actually specifies 4 name:value pair
+ ; parameters separated by commas. Whitespace is
+ ; ignored and they may be specified in any order.
+ ; prefer: <pending | configured>,
+ ; operation: <intersect | union
+ ; | only_preferred | only_nonpreferred>,
+ ; keep: <first | all>
;preferred_codec_only=no ; Respond to a SIP invite with the single most
; preferred codec rather than advertising all joint
; codec capabilities. This limits the other side's
--- /dev/null
+"""Add pjsip endpoint ACN options
+
+Revision ID: b80485ff4dd0
+Revises: fbb7766f17bc
+Create Date: 2020-07-06 08:29:53.974820
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = 'b80485ff4dd0'
+down_revision = '79290b511e4b'
+
+from alembic import op
+import sqlalchemy as sa
+
+max_value_length = 128
+
+def upgrade():
+ op.add_column('ps_endpoints', sa.Column('incoming_offer_codec_prefs', sa.String(max_value_length)))
+ op.add_column('ps_endpoints', sa.Column('outgoing_offer_codec_prefs', sa.String(max_value_length)))
+ op.add_column('ps_endpoints', sa.Column('incoming_answer_codec_prefs', sa.String(max_value_length)))
+ op.add_column('ps_endpoints', sa.Column('outgoing_answer_codec_prefs', sa.String(max_value_length)))
+
+
+def downgrade():
+ op.drop_column('ps_endpoints', 'incoming_offer_codecs_prefs')
+ op.drop_column('ps_endpoints', 'outgoing_offer_codecs_prefs')
+ op.drop_column('ps_endpoints', 'incoming_answer_codecs_prefs')
+ op.drop_column('ps_endpoints', 'outgoing_answer_codecs_prefs')
/* Needed for ast_sip_for_each_channel_snapshot struct */
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_endpoints.h"
+#include "asterisk/stream.h"
#define PJSIP_MINVERSION(m,n,p) (((m << 24) | (n << 16) | (p << 8)) >= PJ_VERSION_NUM)
struct ast_flags incoming_call_offer_pref;
/*! Codec preference for an outgoing offer */
struct ast_flags outgoing_call_offer_pref;
+ /*! Codec negotiation prefs for incoming offers */
+ struct ast_stream_codec_negotiation_prefs incoming_offer_codec_prefs;
+ /*! Codec negotiation prefs for outgoing offers */
+ struct ast_stream_codec_negotiation_prefs outgoing_offer_codec_prefs;
+ /*! Codec negotiation prefs for incoming answers */
+ struct ast_stream_codec_negotiation_prefs incoming_answer_codec_prefs;
+ /*! Codec negotiation prefs for outgoing answers */
+ struct ast_stream_codec_negotiation_prefs outgoing_answer_codec_prefs;
};
/*!
<configOption name="allow">
<synopsis>Media Codec(s) to allow</synopsis>
</configOption>
+ <configOption name="incoming_offer_codec_prefs">
+ <synopsis>Codec negotiation prefs for incoming offers.</synopsis>
+ <description>
+ <para>
+ This is a string that describes how the codecs
+ specified on an incoming SDP offer (pending) are reconciled with the codecs specified
+ on an endpoint (configured) before being sent to the Asterisk core.
+ The string actually specifies 4 <literal>name:value</literal> pair parameters
+ separated by commas. Whitespace is ignored and they may be specified in any order.
+
+ </para>
+ <para>
+ Parameters:
+ </para>
+ <enumlist>
+ <enum name="prefer: < pending | configured >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="pending"><para>The codec list from the caller. (default)</para></enum>
+ <enum name="configured"><para>The codec list from the endpoint.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="operation : < intersect | only_preferred | only_nonpreferred >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="intersect"><para>Only common codecs with the preferred codecs first. (default)</para></enum>
+ <enum name="only_preferred"><para>Use only the preferred codecs.</para></enum>
+ <enum name="only_nonpreferred"><para>Use only the non-preferred codecs.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="keep : < all | first >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="all"><para>After the operation, keep all codecs. (default)</para></enum>
+ <enum name="first"><para>After the operation, keep only the first codec.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="transcode : < allow | prevent >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="allow"><para>Allow transcoding. (default)</para></enum>
+ <enum name="prevent"><para>Prevent transcoding.</para></enum>
+ </enumlist>
+ </enum>
+ </enumlist>
+ <para>
+ </para>
+ <example>
+ incoming_offer_codec_prefs = prefer: pending, operation: intersect, keep: all, transcode: allow
+ </example>
+ <para>
+ Prefer the codecs coming from the caller. Use only the ones that are common.
+ keeping the order of the preferred list. Keep all codecs in the result. Allow transcoding.
+ </para>
+ </description>
+ </configOption>
+ <configOption name="outgoing_offer_codec_prefs">
+ <synopsis>Codec negotiation prefs for outgoing offers.</synopsis>
+ <description>
+ <para>
+ This is a string that describes how the codecs specified in the topology that
+ comes from the Asterisk core (pending) are reconciled with the codecs specified on an
+ endpoint (configured) when sending an SDP offer.
+ The string actually specifies 4 <literal>name:value</literal> pair parameters
+ separated by commas. Whitespace is ignored and they may be specified in any order.
+
+ </para>
+ <para>
+ Parameters:
+ </para>
+ <enumlist>
+ <enum name="prefer: < pending | configured >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="pending"><para>The codec list from the core. (default)</para></enum>
+ <enum name="configured"><para>The codec list from the endpoint.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="operation : < union | intersect | only_preferred | only_nonpreferred >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="union"><para>Merge the lists with the preferred codecs first. (default)</para></enum>
+ <enum name="intersect"><para>Only common codecs with the preferred codecs first. (default)</para></enum>
+ <enum name="only_preferred"><para>Use only the preferred codecs.</para></enum>
+ <enum name="only_nonpreferred"><para>Use only the non-preferred codecs.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="keep : < all | first >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="all"><para>After the operation, keep all codecs. (default)</para></enum>
+ <enum name="first"><para>After the operation, keep only the first codec.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="transcode : < allow | prevent >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="allow"><para>Allow transcoding. (default)</para></enum>
+ <enum name="prevent"><para>Prevent transcoding.</para></enum>
+ </enumlist>
+ </enum>
+ </enumlist>
+ <para>
+ </para>
+ <example>
+ outgoing_offer_codec_prefs = prefer: configured, operation: union, keep: first, transcode: prevent
+ </example>
+ <para>
+ Prefer the codecs coming from the endpoint. Merge them with the codecs from the core
+ keeping the order of the preferred list. Keep only the first one. No transcoding allowed.
+ </para>
+ </description>
+ </configOption>
+ <configOption name="incoming_answer_codec_prefs">
+ <synopsis>Codec negotiation prefs for incoming answers.</synopsis>
+ <description>
+ <para>
+ This is a string that describes how the codecs specified in an incoming SDP answer
+ (pending) are reconciled with the codecs specified on an endpoint (configured)
+ when receiving an SDP answer.
+ The string actually specifies 4 <literal>name:value</literal> pair parameters
+ separated by commas. Whitespace is ignored and they may be specified in any order.
+ </para>
+ <para>
+ Parameters:
+ </para>
+ <enumlist>
+ <enum name="prefer: < pending | configured >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="pending"><para>The codec list in the received SDP answer. (default)</para></enum>
+ <enum name="configured"><para>The codec list from the endpoint.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="operation : < union | intersect | only_preferred | only_nonpreferred >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="union"><para>Merge the lists with the preferred codecs first.</para></enum>
+ <enum name="intersect"><para>Only common codecs with the preferred codecs first. (default)</para></enum>
+ <enum name="only_preferred"><para>Use only the preferred codecs.</para></enum>
+ <enum name="only_nonpreferred"><para>Use only the non-preferred codecs.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="keep : < all | first >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="all"><para>After the operation, keep all codecs. (default)</para></enum>
+ <enum name="first"><para>After the operation, keep only the first codec.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="transcode : < allow | prevent >">
+ <para>
+ The transcode parameter is ignored when processing answers.
+ </para>
+ </enum>
+ </enumlist>
+ <para>
+ </para>
+ <example>
+ incoming_answer_codec_prefs = keep: first
+ </example>
+ <para>
+ Use the defaults but keep oinly the first codec.
+ </para>
+ </description>
+ </configOption>
+ <configOption name="outgoing_answer_codec_prefs">
+ <synopsis>Codec negotiation prefs for outgoing answers.</synopsis>
+ <description>
+ <para>
+ This is a string that describes how the codecs that come from the core (pending)
+ are reconciled with the codecs specified on an endpoint (configured)
+ when sending an SDP answer.
+ The string actually specifies 4 <literal>name:value</literal> pair parameters
+ separated by commas. Whitespace is ignored and they may be specified in any order.
+ </para>
+ <para>
+ Parameters:
+ </para>
+ <enumlist>
+ <enum name="prefer: < pending | configured >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="pending"><para>The codec list that came from the core. (default)</para></enum>
+ <enum name="configured"><para>The codec list from the endpoint.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="operation : < union | intersect | only_preferred | only_nonpreferred >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="union"><para>Merge the lists with the preferred codecs first.</para></enum>
+ <enum name="intersect"><para>Only common codecs with the preferred codecs first. (default)</para></enum>
+ <enum name="only_preferred"><para>Use only the preferred codecs.</para></enum>
+ <enum name="only_nonpreferred"><para>Use only the non-preferred codecs.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="keep : < all | first >">
+ <para>
+ </para>
+ <enumlist>
+ <enum name="all"><para>After the operation, keep all codecs. (default)</para></enum>
+ <enum name="first"><para>After the operation, keep only the first codec.</para></enum>
+ </enumlist>
+ </enum>
+ <enum name="transcode : < allow | prevent >">
+ <para>
+ The transcode parameter is ignored when processing answers.
+ </para>
+ </enum>
+ </enumlist>
+ <para>
+ </para>
+ <example>
+ incoming_answer_codec_prefs = keep: first
+ </example>
+ <para>
+ Use the defaults but keep oinly the first codec.
+ </para>
+ </description>
+ </configOption>
<configOption name="allow_overlap" default="yes">
<synopsis>Enable RFC3578 overlap dialing support.</synopsis>
</configOption>
return 0;
}
+static int codec_prefs_handler(const struct aco_option *opt,
+ struct ast_variable *var, void *obj)
+{
+ struct ast_sip_endpoint *endpoint = obj;
+ struct ast_stream_codec_negotiation_prefs prefs;
+ struct ast_str *error_message = ast_str_create(128);
+ enum ast_stream_codec_negotiation_prefs_prefer_values default_prefer;
+ enum ast_stream_codec_negotiation_prefs_operation_values default_operation;
+ int res = 0;
+
+ res = ast_stream_codec_prefs_parse(var->value, &prefs, &error_message);
+ if (res < 0) {
+ ast_log(LOG_ERROR, "Endpoint '%s': %s for option '%s'\n",
+ ast_sorcery_object_get_id(endpoint), ast_str_buffer(error_message), var->name);
+ ast_free(error_message);
+ return -1;
+ }
+ ast_free(error_message);
+
+ if (strcmp(var->name, "incoming_offer_codec_prefs") == 0) {
+ if (prefs.operation == CODEC_NEGOTIATION_OPERATION_UNION) {
+ ast_log(LOG_ERROR, "Endpoint '%s': Codec preference '%s' has invalid value '%s' for option: '%s'",
+ ast_sorcery_object_get_id(endpoint),
+ ast_stream_codec_param_to_str(CODEC_NEGOTIATION_PARAM_OPERATION),
+ ast_stream_codec_operation_to_str(CODEC_NEGOTIATION_OPERATION_UNION),
+ var->name);
+ return -1;
+ }
+ endpoint->media.incoming_offer_codec_prefs = prefs;
+ default_prefer = CODEC_NEGOTIATION_PREFER_PENDING;
+ default_operation = CODEC_NEGOTIATION_OPERATION_INTERSECT;
+ } else if (strcmp(var->name, "outgoing_offer_codec_prefs") == 0) {
+ endpoint->media.outgoing_offer_codec_prefs = prefs;
+ default_prefer = CODEC_NEGOTIATION_PREFER_PENDING;
+ default_operation = CODEC_NEGOTIATION_OPERATION_UNION;
+ } else if (strcmp(var->name, "incoming_answer_codec_prefs") == 0) {
+ endpoint->media.incoming_answer_codec_prefs = prefs;
+ default_prefer = CODEC_NEGOTIATION_PREFER_PENDING;
+ default_operation = CODEC_NEGOTIATION_OPERATION_INTERSECT;
+ } else if (strcmp(var->name, "outgoing_answer_codec_prefs") == 0) {
+ endpoint->media.outgoing_answer_codec_prefs = prefs;
+ default_prefer = CODEC_NEGOTIATION_PREFER_PENDING;
+ default_operation = CODEC_NEGOTIATION_OPERATION_INTERSECT;
+ }
+
+ if (prefs.prefer == CODEC_NEGOTIATION_PREFER_UNSPECIFIED) {
+ prefs.prefer = default_prefer;
+ }
+
+ if (prefs.operation == CODEC_NEGOTIATION_OPERATION_UNSPECIFIED) {
+ prefs.operation = default_operation;
+ }
+
+ if (prefs.keep == CODEC_NEGOTIATION_KEEP_UNSPECIFIED) {
+ prefs.keep = CODEC_NEGOTIATION_KEEP_ALL;
+ }
+
+ if (prefs.transcode == CODEC_NEGOTIATION_TRANSCODE_UNSPECIFIED) {
+ prefs.transcode = CODEC_NEGOTIATION_TRANSCODE_ALLOW;
+ }
+
+ return 0;
+}
+
+static int codec_prefs_to_str(const struct ast_stream_codec_negotiation_prefs *prefs,
+ const void *obj, const intptr_t *args, char **buf)
+{
+ struct ast_str *codecs = ast_str_create(AST_STREAM_MAX_CODEC_PREFS_LENGTH);
+
+ if (!codecs) {
+ return -1;
+ }
+
+ *buf = ast_strdup(ast_stream_codec_prefs_to_str(prefs, &codecs));
+ ast_free(codecs);
+
+ return 0;
+}
+
+static int incoming_offer_codec_prefs_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+ const struct ast_sip_endpoint *endpoint = obj;
+ return codec_prefs_to_str(&endpoint->media.incoming_offer_codec_prefs, obj, args, buf);
+}
+
+static int outgoing_offer_codec_prefs_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+ const struct ast_sip_endpoint *endpoint = obj;
+ return codec_prefs_to_str(&endpoint->media.outgoing_offer_codec_prefs, obj, args, buf);
+}
+
+static int incoming_answer_codec_prefs_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+ const struct ast_sip_endpoint *endpoint = obj;
+ return codec_prefs_to_str(&endpoint->media.incoming_answer_codec_prefs, obj, args, buf);
+}
+
+static int outgoing_answer_codec_prefs_to_str(const void *obj, const intptr_t *args, char **buf)
+{
+ const struct ast_sip_endpoint *endpoint = obj;
+ return codec_prefs_to_str(&endpoint->media.outgoing_answer_codec_prefs, obj, args, buf);
+}
+
static void *sip_nat_hook_alloc(const char *name)
{
return ast_sorcery_generic_alloc(sizeof(struct ast_sip_nat_hook), NULL);
call_offer_pref_handler, incoming_call_offer_pref_to_str, NULL, 0, 0);
ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outgoing_call_offer_pref", "remote",
call_offer_pref_handler, outgoing_call_offer_pref_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "incoming_offer_codec_prefs",
+ "prefer: pending, operation: intersect, keep: all, transcode: allow",
+ codec_prefs_handler, incoming_offer_codec_prefs_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outgoing_offer_codec_prefs",
+ "prefer: pending, operation: union, keep: all, transcode: allow",
+ codec_prefs_handler, outgoing_offer_codec_prefs_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "incoming_answer_codec_prefs",
+ "prefer: pending, operation: intersect, keep: all",
+ codec_prefs_handler, incoming_answer_codec_prefs_to_str, NULL, 0, 0);
+ ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outgoing_answer_codec_prefs",
+ "prefer: pending, operation: intersect, keep: all",
+ codec_prefs_handler, outgoing_answer_codec_prefs_to_str, NULL, 0, 0);
if (ast_sip_initialize_sorcery_transport()) {
ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");