file: Ensure nativeformats remains valid for lifetime of use.
authorJoshua Colp <jcolp@digium.com>
Thu, 5 May 2016 10:07:50 +0000 (07:07 -0300)
committerJoshua Colp <jcolp@digium.com>
Thu, 5 May 2016 16:02:48 +0000 (11:02 -0500)
It is possible for the nativeformats of a channel to change
throughout its lifetime. As a result a user of it needs to either
ensure the channel is locked when accessing the formats or keep
a reference to the nativeformats themselves.

This change fixes the file playback support so it keeps a
reference to the nativeformats when accessing things.

ASTERISK-25998 #close

Change-Id: Ie45b65475e1481ddf05b874ee48f63e39fff8915

main/file.c

index 654937a..4503625 100644 (file)
@@ -799,7 +799,7 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil
        /* As above, but for video. But here we don't have translators
         * so we must enforce a format.
         */
-       struct ast_format_cap *tmp_cap;
+       struct ast_format_cap *nativeformats, *tmp_cap;
        char *buf;
        int buflen;
        int i, fd;
@@ -810,16 +810,23 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil
        buflen = strlen(preflang) + strlen(filename) + 4;
        buf = ast_alloca(buflen);
 
+       ast_channel_lock(chan);
+       nativeformats = ao2_bump(ast_channel_nativeformats(chan));
+       ast_channel_unlock(chan);
+
        /* is the channel capable of video without translation ?*/
-       if (!ast_format_cap_has_type(ast_channel_nativeformats(chan), AST_MEDIA_TYPE_VIDEO)) {
+       if (!ast_format_cap_has_type(nativeformats, AST_MEDIA_TYPE_VIDEO)) {
+               ao2_cleanup(nativeformats);
                return NULL;
        }
        if (!(tmp_cap = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
+               ao2_cleanup(nativeformats);
                return NULL;
        }
        /* Video is supported, so see what video formats exist for this file */
        if (!fileexists_core(filename, NULL, preflang, buf, buflen, tmp_cap)) {
                ao2_ref(tmp_cap, -1);
+               ao2_cleanup(nativeformats);
                return NULL;
        }
 
@@ -828,7 +835,7 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil
                struct ast_format *format = ast_format_cap_get_format(tmp_cap, i);
 
                if ((ast_format_get_type(format) != AST_MEDIA_TYPE_VIDEO) ||
-                       !ast_format_cap_iscompatible(ast_channel_nativeformats(chan), tmp_cap)) {
+                       !ast_format_cap_iscompatible(nativeformats, tmp_cap)) {
                        ao2_ref(format, -1);
                        continue;
                }
@@ -837,12 +844,14 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil
                if (fd >= 0) {
                        ao2_ref(format, -1);
                        ao2_ref(tmp_cap, -1);
+                       ao2_cleanup(nativeformats);
                        return ast_channel_vstream(chan);
                }
                ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
                ao2_ref(format, -1);
        }
        ao2_ref(tmp_cap, -1);
+       ao2_cleanup(nativeformats);
 
        return NULL;
 }
@@ -1097,8 +1106,10 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
        fs = ast_openstream(chan, filename, preflang);
        if (!fs) {
                struct ast_str *codec_buf = ast_str_alloca(AST_FORMAT_CAP_NAMES_LEN);
+               ast_channel_lock(chan);
                ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n",
                        filename, ast_format_cap_get_names(ast_channel_nativeformats(chan), &codec_buf), strerror(errno));
+               ast_channel_unlock(chan);
                return -1;
        }
 
@@ -1133,7 +1144,12 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
        res = ast_playstream(fs);
        if (!res && vfs)
                res = ast_playstream(vfs);
-       ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default");
+
+       if (VERBOSITY_ATLEAST(3)) {
+               ast_channel_lock(chan);
+               ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", ast_channel_name(chan), filename, ast_format_get_name(ast_channel_writeformat(chan)), preflang ? preflang : "default");
+               ast_channel_unlock(chan);
+       }
 
        return res;
 }