]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
res_pjsip: Add new endpoint option "suppress_moh_on_sendonly"
authorGeorge Joseph <gjoseph@sangoma.com>
Tue, 5 Nov 2024 18:30:55 +0000 (11:30 -0700)
committerAsterisk Development Team <asteriskteam@digium.com>
Mon, 2 Jun 2025 13:37:24 +0000 (13:37 +0000)
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.

(cherry picked from commit 1eb7d5258b71ffdf59e384e4c433267e697dba7d)

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

index 12d8f7a395a9f185fd618ce0301ced888d0043ab..a66c619378feae70cd1c5cf7d81621cd69ba457a 100644 (file)
                 ; 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 (file)
index 0000000..fb6a3ef
--- /dev/null
@@ -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')
index 2ae806e0e355844b5af0ecae00a107f2e2793fd2..876bb1cfb63598e3889dcfca5ce3b767c6522981 100644 (file)
@@ -986,6 +986,8 @@ struct ast_sip_endpoint {
        AST_STRING_FIELD_EXTENDED(geoloc_outgoing_call_profile);
        /*! Tenant ID for the endpoint */
        AST_STRING_FIELD_EXTENDED(tenantid);
+       /*! Ignore remote hold requests */
+       int suppress_moh_on_sendonly;
 };
 
 /*! URI parameter for symmetric transport */
index 92d5631a80c72d07f89905fb93e9c9498c424a43..9fa6ae6137f616b448e5b8f6fa06eda76e2fcb92 100644 (file)
                                                </para>
                                        </description>
                                </configOption>
+                               <configOption name="suppress_moh_on_sendonly" default="no">
+                                       <synopsis>Suppress playing MOH to party A if party B sends
+                                       "sendonly" or "inactive" in an SDP</synopsis>
+                                       <description><para>
+                                       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.
+                                       </para>
+                                       <note><para>
+                                       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.
+                                       </para>
+                                       </note>
+                                       </description>
+                               </configOption>
                        </configObject>
                        <configObject name="auth">
                                <synopsis>Authentication type</synopsis>
index 93bf9898b7f0178c5bd1334af33853794ad6cf3f..d514aa427e83272c4e75c553f370beceda1bbd22 100644 (file)
@@ -2228,6 +2228,8 @@ int ast_res_pjsip_initialize_configuration(void)
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_incoming_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_incoming_call_profile));
        ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_outgoing_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_outgoing_call_profile));
        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");
index d89a37d198df36039bea1c46dc811128e60a9cab..dc13c5a6b9f7bd393c4d6fa44e635284ff94eb3e 100644 (file)
@@ -2179,14 +2179,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)