]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
chan_pjsip: Check audio frame when remote SSRC changes.
authorPaulo Vicentini <paulo.vicentini@gmail.com>
Wed, 26 Feb 2020 00:30:04 +0000 (01:30 +0100)
committerPaulo Vicentini <paulo.vicentini@gmail.com>
Mon, 9 Mar 2020 10:52:13 +0000 (04:52 -0600)
If the SSRC of a received RTP packet differed from the previous SSRC
an SSRC change control frame would be queued ahead of the media
frame. In the case of audio this would result in the format of the
audio frame not being checked, and if it differed or was not allowed
then it could cause the call to drop due to failure to set up a
translation path.

The chan_pjsip module will now no longer assume the first frame
will be the audio frame and instead goes through the complete list
to find it.

ASTERISK-28759

Change-Id: I6d854cc523f343e299a615636fc65bdbd5f809ec

channels/chan_pjsip.c

index 0e43373c9a1e97564cc62e2bc0e7992a87dafcb0..0ec17915f74afe28d3fa13b1752828e2ef7863dd 100644 (file)
@@ -829,6 +829,7 @@ static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast)
        struct ast_sip_session_media_read_callback_state *callback_state;
        struct ast_frame *f;
        int fdno = ast_channel_fdno(ast) - AST_EXTENDED_FDS;
+       struct ast_frame *cur;
 
        if (fdno >= AST_VECTOR_SIZE(&session->active_media_state->read_callbacks)) {
                return &ast_null_frame;
@@ -841,8 +842,13 @@ static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast)
                return f;
        }
 
-       if (f->frametype != AST_FRAME_VOICE ||
-               callback_state->session != session->active_media_state->default_session[callback_state->session->type]) {
+       for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+               if (cur->frametype == AST_FRAME_VOICE) {
+                       break;
+               }
+       }
+
+       if (!cur || callback_state->session != session->active_media_state->default_session[callback_state->session->type]) {
                return f;
        }
 
@@ -854,36 +860,36 @@ static struct ast_frame *chan_pjsip_read_stream(struct ast_channel *ast)
         * raw read format BEFORE the native format check
         */
        if (!session->endpoint->asymmetric_rtp_codec &&
-               ast_format_cmp(ast_channel_rawwriteformat(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL &&
-               is_compatible_format(session, f)) {
+               ast_format_cmp(ast_channel_rawwriteformat(ast), cur->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL &&
+               is_compatible_format(session, cur)) {
                struct ast_format_cap *caps;
 
                /* For maximum compatibility we ensure that the formats match that of the received media */
                ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when we're sending '%s', switching to match\n",
-                       ast_format_get_name(f->subclass.format), ast_channel_name(ast),
+                       ast_format_get_name(cur->subclass.format), ast_channel_name(ast),
                        ast_format_get_name(ast_channel_rawwriteformat(ast)));
 
                caps = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT);
                if (caps) {
                        ast_format_cap_append_from_cap(caps, ast_channel_nativeformats(ast), AST_MEDIA_TYPE_UNKNOWN);
                        ast_format_cap_remove_by_type(caps, AST_MEDIA_TYPE_AUDIO);
-                       ast_format_cap_append(caps, f->subclass.format, 0);
+                       ast_format_cap_append(caps, cur->subclass.format, 0);
                        ast_channel_nativeformats_set(ast, caps);
                        ao2_ref(caps, -1);
                }
 
-               ast_set_write_format_path(ast, ast_channel_writeformat(ast), f->subclass.format);
-               ast_set_read_format_path(ast, ast_channel_readformat(ast), f->subclass.format);
+               ast_set_write_format_path(ast, ast_channel_writeformat(ast), cur->subclass.format);
+               ast_set_read_format_path(ast, ast_channel_readformat(ast), cur->subclass.format);
 
                if (ast_channel_is_bridged(ast)) {
                        ast_channel_set_unbridged_nolock(ast, 1);
                }
        }
 
-       if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) {
+       if (ast_format_cap_iscompatible_format(ast_channel_nativeformats(ast), cur->subclass.format)
+                       == AST_FORMAT_CMP_NOT_EQUAL) {
                ast_debug(1, "Oooh, got a frame with format of %s on channel '%s' when it has not been negotiated\n",
-                       ast_format_get_name(f->subclass.format), ast_channel_name(ast));
-
+                               ast_format_get_name(cur->subclass.format), ast_channel_name(ast));
                ast_frfree(f);
                return &ast_null_frame;
        }