From: George Joseph Date: Tue, 5 Nov 2024 18:30:55 +0000 (-0700) Subject: res_pjsip: Add new endpoint option "suppress_moh_on_sendonly" X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d443a960e20bb7bd3b1205972c367e6ab39a2763;p=thirdparty%2Fasterisk.git res_pjsip: Add new endpoint option "suppress_moh_on_sendonly" Normally, when one party in a call sends Asterisk an SDP with a "sendonly" or "inactive" attribute it means "hold" and causes Asterisk to start playing MOH back to the other party. This can be problematic if it happens at certain times, such as in a 183 Progress message, because the MOH will replace any early media you may be playing to the calling party. If you set this option to "yes" on an endpoint and the endpoint receives an SDP with "sendonly" or "inactive", Asterisk will NOT play MOH back to the other party. Resolves: #979 UserNote: The new "suppress_moh_on_sendonly" endpoint option can be used to prevent playing MOH back to a caller if the remote end sends "sendonly" or "inactive" (hold) to Asterisk in an SDP. --- diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample index 335f660b87..5f8fd14042 100644 --- a/configs/samples/pjsip.conf.sample +++ b/configs/samples/pjsip.conf.sample @@ -988,7 +988,21 @@ ; using the same CHANNEL function if needed. Setting tenant ID here ; will cause it to show up on channel creation and the initial ; channel snapshot. - +; +; suppress_moh_on_sendonly = no + ; Normally, when one party in a call sends Asterisk an SDP with + ; a "sendonly" or "inactive" attribute it means "hold" and + ; causes Asterisk to start playing MOH back to the other party. + ; This can be problematic if it happens at certain times, such + ; as in a 183 Progress message, because the MOH will replace + ; any early media you may be playing to the calling party. If + ; you set this option to "yes" on an endpoint and the endpoint + ; receives an SDP with "sendonly" or "inactive", Asterisk will + ; NOT play MOH back to the other party. + ; NOTE: This doesn't just apply to 183 responses. MOH will + ; be suppressed when the attribute appears in any SDP received + ; including INVITEs, re-INVITES, and other responses. + ; (default: no) ;==========================AUTH SECTION OPTIONS========================= ;[auth] diff --git a/contrib/ast-db-manage/config/versions/4f91fc18c979_add_suppress_moh_on_sendonly.py b/contrib/ast-db-manage/config/versions/4f91fc18c979_add_suppress_moh_on_sendonly.py new file mode 100644 index 0000000000..fb6a3efc71 --- /dev/null +++ b/contrib/ast-db-manage/config/versions/4f91fc18c979_add_suppress_moh_on_sendonly.py @@ -0,0 +1,30 @@ +"""Add suppress_moh_on_sendonly + +Revision ID: 4f91fc18c979 +Revises: 801b9fced8b7 +Create Date: 2024-11-05 11:37:33.604448 + +""" + +# revision identifiers, used by Alembic. +revision = '4f91fc18c979' +down_revision = '801b9fced8b7' + +from alembic import op +import sqlalchemy as sa +from sqlalchemy.dialects.postgresql import ENUM + +YESNO_NAME = 'yesno_values' +YESNO_VALUES = ['yes', 'no'] + + +def upgrade(): + yesno_values = ENUM(*YESNO_VALUES, name=YESNO_NAME, create_type=False) + + op.add_column('ps_endpoints', sa.Column('suppress_moh_on_sendonly', yesno_values)) + + +def downgrade(): + if op.get_context().bind.dialect.name == 'mssql': + op.drop_constraint('ck_ps_endpoints_suppress_moh_on_sendonly_yesno_values', 'ps_endpoints') + op.drop_column('ps_endpoints', 'suppress_moh_on_sendonly') diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index f83cbe82cf..3ee643b56f 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -1062,6 +1062,8 @@ struct ast_sip_endpoint { unsigned int send_aoc; /*! Tenant ID for the endpoint */ AST_STRING_FIELD_EXTENDED(tenantid); + /*! Ignore remote hold requests */ + int suppress_moh_on_sendonly; }; /*! URI parameter for symmetric transport */ diff --git a/res/res_pjsip/pjsip_config.xml b/res/res_pjsip/pjsip_config.xml index 328ec08c22..9ad4915d3a 100644 --- a/res/res_pjsip/pjsip_config.xml +++ b/res/res_pjsip/pjsip_config.xml @@ -1527,6 +1527,27 @@ Send Advice-of-Charge messages + + Suppress playing MOH to party A if party B sends + "sendonly" or "inactive" in an SDP + + Normally, when one party in a call sends Asterisk an SDP with a "sendonly" + or "inactive" attribute it means "hold" and causes Asterisk to start + playing MOH back to the other party. This can be problematic if it happens at + certain times, such as in a 183 Progress message, because the MOH will + replace any early media you may be playing to the calling party. If you set + this option to "yes" on an endpoint and the endpoint receives an SDP + with "sendonly" or "inactive", Asterisk will NOT play MOH back to the other + party. + + + This doesn't just apply to 183 responses. MOH will be suppressed when + the attribute appears in any SDP received including INVITEs, re-INVITES, + and other responses. + + + + Authentication type diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index 8b24f29ae5..9b4a524e3b 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -2299,6 +2299,8 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "security_negotiation", "no", security_negotiation_handler, security_negotiation_to_str, NULL, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_aoc", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, send_aoc)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tenantid", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, tenantid)); + ast_sorcery_object_field_register(sip_sorcery, "endpoint", "suppress_moh_on_sendonly", + "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, suppress_moh_on_sendonly)); if (ast_sip_initialize_sorcery_transport()) { ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n"); diff --git a/res/res_pjsip_sdp_rtp.c b/res/res_pjsip_sdp_rtp.c index 8d1c5c3635..42bdd60a50 100644 --- a/res/res_pjsip_sdp_rtp.c +++ b/res/res_pjsip_sdp_rtp.c @@ -2199,14 +2199,18 @@ static int apply_negotiated_sdp_stream(struct ast_sip_session *session, if (session_media->remotely_held_changed) { if (session_media->remotely_held) { /* The remote side has put us on hold */ - ast_queue_hold(session->channel, session->endpoint->mohsuggest); - ast_rtp_instance_stop(session_media->rtp); - ast_queue_frame(session->channel, &ast_null_frame); + if (!session->endpoint->suppress_moh_on_sendonly) { + ast_queue_hold(session->channel, session->endpoint->mohsuggest); + ast_rtp_instance_stop(session_media->rtp); + ast_queue_frame(session->channel, &ast_null_frame); + } session_media->remotely_held_changed = 0; } else { /* The remote side has taken us off hold */ - ast_queue_unhold(session->channel); - ast_queue_frame(session->channel, &ast_null_frame); + if (!session->endpoint->suppress_moh_on_sendonly) { + ast_queue_unhold(session->channel); + ast_queue_frame(session->channel, &ast_null_frame); + } session_media->remotely_held_changed = 0; } } else if ((pjmedia_sdp_neg_was_answer_remote(session->inv_session->neg) == PJ_FALSE)