Index: include/asterisk/frame.h =================================================================== --- include/asterisk/frame.h (revision 219411) +++ include/asterisk/frame.h (working copy) @@ -135,10 +135,6 @@ * The dsp cannot be free'd if the frame inside of it still has * this flag set. */ AST_FRFLAG_FROM_DSP = (1 << 2), - /*! This frame came from a filestream and is still the original frame. - * The filestream cannot be free'd if the frame inside of it still has - * this flag set. */ - AST_FRFLAG_FROM_FILESTREAM = (1 << 3), }; /*! \brief Data structure associated with a single frame of data Index: include/asterisk/file.h =================================================================== --- include/asterisk/file.h (revision 219411) +++ include/asterisk/file.h (working copy) @@ -402,21 +402,6 @@ */ struct ast_frame *ast_readframe(struct ast_filestream *s); -/*!\brief destroy a filestream using an ast_frame as input - * - * This is a hack that is used also by the ast_trans_pvt and - * ast_dsp structures. When a structure contains an ast_frame - * pointer as one of its fields. It may be that the frame is - * still used after the outer structure is freed. This leads to - * invalid memory accesses. This function allows for us to hold - * off on destroying the ast_filestream until we are done using - * the ast_frame pointer that is part of it - * - * \param fr The ast_frame that is part of an ast_filestream we wish - * to free. - */ -void ast_filestream_frame_freed(struct ast_frame *fr); - /*! Initialize file stuff */ /*! * Initializes all the various file stuff. Basically just registers the cli stuff Index: main/frame.c =================================================================== --- main/frame.c (revision 219411) +++ main/frame.c (working copy) @@ -346,8 +346,6 @@ ast_translate_frame_freed(fr); } else if (ast_test_flag(fr, AST_FRFLAG_FROM_DSP)) { ast_dsp_frame_freed(fr); - } else if (ast_test_flag(fr, AST_FRFLAG_FROM_FILESTREAM)) { - ast_filestream_frame_freed(fr); } if (!fr->mallocd) @@ -436,7 +434,6 @@ } else { ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR); ast_clear_flag(fr, AST_FRFLAG_FROM_DSP); - ast_clear_flag(fr, AST_FRFLAG_FROM_FILESTREAM); out = fr; } Index: main/file.c =================================================================== --- main/file.c (revision 219411) +++ main/file.c (working copy) @@ -706,19 +706,38 @@ return NULL; } -struct ast_frame *ast_readframe(struct ast_filestream *s) +static struct ast_frame *read_frame(struct ast_filestream *s, int *whennext) { - struct ast_frame *f = NULL; - int whennext = 0; - if (s && s->fmt) - f = s->fmt->read(s, &whennext); - if (f) { - ast_set_flag(f, AST_FRFLAG_FROM_FILESTREAM); - ao2_ref(s, +1); + struct ast_frame *fr, *new_fr; + + if (!s || !s->fmt) { + return NULL; } - return f; + + if (!(fr = s->fmt->read(s, whennext))) { + return NULL; + } + + if (!(new_fr = ast_frisolate(fr))) { + ast_frfree(fr); + return NULL; + } + + if (new_fr != fr) { + ast_frfree(fr); + fr = new_fr; + } + + return fr; } +struct ast_frame *ast_readframe(struct ast_filestream *s) +{ + int whennext = 0; + + return read_frame(s, &whennext); +} + enum fsread_res { FSREAD_FAILURE, FSREAD_SUCCESS_SCHED, @@ -733,15 +752,13 @@ while (!whennext) { struct ast_frame *fr; - - if (s->orig_chan_name && strcasecmp(s->owner->name, s->orig_chan_name)) + + if (s->orig_chan_name && strcasecmp(s->owner->name, s->orig_chan_name)) { goto return_failure; - - fr = s->fmt->read(s, &whennext); - if (fr) { - ast_set_flag(fr, AST_FRFLAG_FROM_FILESTREAM); - ao2_ref(s, +1); } + + fr = read_frame(s, &whennext); + if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) { if (fr) { ast_log(LOG_WARNING, "Failed to write frame\n"); @@ -749,10 +766,12 @@ } goto return_failure; } + if (fr) { ast_frfree(fr); } } + if (whennext != s->lasttimeout) { #ifdef HAVE_DAHDI if (s->owner->timingfd > -1) { @@ -803,11 +822,8 @@ int whennext = 0; while (!whennext) { - struct ast_frame *fr = s->fmt->read(s, &whennext); - if (fr) { - ast_set_flag(fr, AST_FRFLAG_FROM_FILESTREAM); - ao2_ref(s, +1); - } + struct ast_frame *fr = read_frame(s, &whennext); + if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) { if (fr) { ast_log(LOG_WARNING, "Failed to write frame\n"); @@ -816,6 +832,7 @@ s->owner->vstreamid = -1; return FSREAD_FAILURE; } + if (fr) { ast_frfree(fr); } @@ -890,26 +907,10 @@ int ast_closestream(struct ast_filestream *f) { - - if (ast_test_flag(&f->fr, AST_FRFLAG_FROM_FILESTREAM)) { - /* If this flag is still set, it essentially means that the reference - * count of f is non-zero. We can't destroy this filestream until - * whatever is using the filestream's frame has finished. - * - * Since this was called, however, we need to remove the reference from - * when this filestream was first allocated. That way, when the embedded - * frame is freed, the refcount will reach 0 and we can finish destroying - * this filestream properly. - */ - ao2_ref(f, -1); - return 0; - } - ao2_ref(f, -1); return 0; } - /* * Look the various language-specific places where a file could exist. */ @@ -1322,17 +1323,6 @@ -1, -1, context); } -void ast_filestream_frame_freed(struct ast_frame *fr) -{ - struct ast_filestream *fs; - - ast_clear_flag(fr, AST_FRFLAG_FROM_FILESTREAM); - - fs = (struct ast_filestream *) (((char *) fr) - offsetof(struct ast_filestream, fr)); - - ao2_ref(fs, -1); -} - /* * if the file name is non-empty, try to play it. * Return 0 if success, -1 if error, digit if interrupted by a digit.