res_pjsip: Add option to force G.726 to be treated as AAL2 packed.
authorKevin Harwell <kharwell@digium.com>
Fri, 12 Jun 2015 21:58:27 +0000 (16:58 -0500)
committerKevin Harwell <kharwell@digium.com>
Mon, 15 Jun 2015 17:40:03 +0000 (12:40 -0500)
Some phones send g.726 audio packed for AAL2, which differs from what is
recommended by RFC 3351. If Asterisk receives audio formatted as such when
negotiating g.726 then it sounds a bit distorted. Added an option to
res_pjsip_endpoint that allows g.726 negotiated audio to be treated as g.726
AAL2 packed.

ASTERISK-25158 #close
Reported by: Steve Pitts

Change-Id: Ie7e21f75493d7fe53e75e12c971e72f5afa33615

CHANGES
configs/samples/pjsip.conf.sample
contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py [new file with mode: 0644]
include/asterisk/res_pjsip.h
res/res_pjsip.c
res/res_pjsip/pjsip_configuration.c
res/res_pjsip_sdp_rtp.c

diff --git a/CHANGES b/CHANGES
index 281d059..d2fa84c 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -186,6 +186,12 @@ AMI
  * A new ContactStatus event has been added that reflects res_pjsip contact
    lifecycle changes:  Created, Removed, Reachable, Unreachable, Unknown.
 
+res_pjsip
+------------------
+* A new 'g726_non_standard' endpoint option has been added that, when set to
+  'yes' and g.726 audio is negotiated, forces the codec to be treated as if it
+  is AAL2 packed on the channel.
+
 ------------------------------------------------------------------------------
 --- Functionality changes from Asterisk 13.3.0 to Asterisk 13.4.0 ------------
 ------------------------------------------------------------------------------
index 276e214..24ff327 100644 (file)
                         ; "no")
 ;media_encryption_optimistic=no ; Use encryption if possible but don't fail the call
                                                                ; if not possible.
+;g726_non_standard=no   ; When set to "yes" and an endpoint negotiates g.726
+                        ; audio then g.726 for AAL2 packing order is used contrary
+                        ; to what is recommended in RFC3551. Note, 'g726aal2' also
+                        ; needs to be specified in the codec allow list
+                        ; (default: "no")
 ;inband_progress=no     ; Determines whether chan_pjsip will indicate ringing
                         ; using inband progress (default: "no")
 ;call_group=    ; The numeric pickup groups for a channel (default: "")
diff --git a/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py b/contrib/ast-db-manage/config/versions/28b8e71e541f_add_g726_non_standard.py
new file mode 100644 (file)
index 0000000..ad36bd9
--- /dev/null
@@ -0,0 +1,30 @@
+"""add g726_non_standard
+
+Revision ID: 28b8e71e541f
+Revises: a541e0b5e89
+Create Date: 2015-06-12 16:07:08.609628
+
+"""
+
+# revision identifiers, used by Alembic.
+revision = '28b8e71e541f'
+down_revision = 'a541e0b5e89'
+
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects.postgresql import ENUM
+
+YESNO_NAME = 'yesno_values'
+YESNO_VALUES = ['yes', 'no']
+
+def upgrade():
+    ############################# Enums ##############################
+
+    # yesno_values have already been created, so use postgres enum object
+    # type to get around "already created" issue - works okay with mysql
+    yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False)
+    op.add_column('ps_endpoints', sa.Column('g726_non_standard', yesno_values))
+
+
+def downgrade():
+    op.drop_column('ps_endpoints', 'g726_non_standard')
index 08d6954..5267603 100644 (file)
@@ -557,6 +557,8 @@ struct ast_sip_endpoint_media_configuration {
        unsigned int tos_video;
        /*! Priority for video streams */
        unsigned int cos_video;
+       /*! Is g.726 packed in a non standard way */
+       unsigned int g726_non_standard;
 };
 
 /*!
index f90b475..8d5adf6 100644 (file)
                                                set to <literal>sdes</literal> or <literal>dtls</literal>.
                                        </para></description>
                                </configOption>
+                               <configOption name="g726_non_standard" default="no">
+                                       <synopsis>Force g.726 to use AAL2 packing order when negotiating g.726 audio</synopsis>
+                                       <description><para>
+                                                When set to "yes" and an endpoint negotiates g.726 audio then use g.726 for AAL2
+                                                packing order instead of what is recommended by RFC3551. Since this essentially
+                                                replaces the underlying 'g726' codec with 'g726aal2' then 'g726aal2' needs to be
+                                                specified in the endpoint's allowed codec list.
+                                       </para></description>
+                               </configOption>
                                <configOption name="inband_progress" default="no">
                                        <synopsis>Determines whether chan_pjsip will indicate ringing using inband
                                            progress.</synopsis>
index 4ce7735..d4fa152 100644 (file)
@@ -1923,6 +1923,7 @@ int ast_res_pjsip_initialize_configuration(void)
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_fingerprint", "", dtls_handler, dtlsfingerprint_to_str, NULL, 0, 0);
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "srtp_tag_32", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.srtp_tag_32));
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_encryption_optimistic", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.encryption_optimistic));
+       ast_sorcery_object_field_register(sip_sorcery, "endpoint", "g726_non_standard", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.g726_non_standard));
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, NULL, 0, 0);
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, set_var_to_vl, 0, 0);
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "message_context", "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct ast_sip_endpoint, message_context));
index 3f48683..22c4529 100644 (file)
@@ -155,6 +155,8 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp
        char name[256];
        char media[20];
        char fmt_param[256];
+       enum ast_rtp_options options = session->endpoint->media.g726_non_standard ?
+               AST_RTP_OPT_G726_NONSTANDARD : 0;
 
        ast_rtp_codecs_payloads_initialize(codecs);
 
@@ -176,9 +178,10 @@ static void get_codecs(struct ast_sip_session *session, const struct pjmedia_sdp
                 if (strcmp(name,"telephone-event") == 0) {
                         tel_event++;
                 }
+
                ast_copy_pj_str(media, (pj_str_t*)&stream->desc.media, sizeof(media));
                ast_rtp_codecs_payloads_set_rtpmap_type_rate(codecs, NULL, pj_strtoul(&stream->desc.fmt[i]),
-                                                            media, name, 0, rtpmap->clock_rate);
+                                                            media, name, options, rtpmap->clock_rate);
                /* Look for an optional associated fmtp attribute */
                if (!(attr = pjmedia_sdp_media_find_attr2(stream, "fmtp", &rtpmap->pt))) {
                        continue;
@@ -304,18 +307,20 @@ static int set_caps(struct ast_sip_session *session, struct ast_sip_session_medi
        return 0;
 }
 
-static pjmedia_sdp_attr* generate_rtpmap_attr(pjmedia_sdp_media *media, pj_pool_t *pool, int rtp_code,
-                                             int asterisk_format, struct ast_format *format, int code)
+static pjmedia_sdp_attr* generate_rtpmap_attr(struct ast_sip_session *session, pjmedia_sdp_media *media, pj_pool_t *pool,
+                                             int rtp_code, int asterisk_format, struct ast_format *format, int code)
 {
        pjmedia_sdp_rtpmap rtpmap;
        pjmedia_sdp_attr *attr = NULL;
        char tmp[64];
+       enum ast_rtp_options options = session->endpoint->media.g726_non_standard ?
+               AST_RTP_OPT_G726_NONSTANDARD : 0;
 
        snprintf(tmp, sizeof(tmp), "%d", rtp_code);
        pj_strdup2(pool, &media->desc.fmt[media->desc.fmt_count++], tmp);
        rtpmap.pt = media->desc.fmt[media->desc.fmt_count - 1];
        rtpmap.clock_rate = ast_rtp_lookup_sample_rate2(asterisk_format, format, code);
-       pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, 0));
+       pj_strdup2(pool, &rtpmap.enc_name, ast_rtp_lookup_mime_subtype2(asterisk_format, format, code, options));
        rtpmap.param.slen = 0;
        rtpmap.param.ptr = NULL;
 
@@ -1051,7 +1056,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
                        continue;
                }
 
-               if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 1, format, 0))) {
+               if (!(attr = generate_rtpmap_attr(session, media, pool, rtp_code, 1, format, 0))) {
                        ao2_ref(format, -1);
                        continue;
                }
@@ -1076,7 +1081,7 @@ static int create_outgoing_sdp_stream(struct ast_sip_session *session, struct as
                                continue;
                        }
 
-                       if (!(attr = generate_rtpmap_attr(media, pool, rtp_code, 0, NULL, index))) {
+                       if (!(attr = generate_rtpmap_attr(session, media, pool, rtp_code, 0, NULL, index))) {
                                continue;
                        }