diff --git a/include/asterisk/file.h b/include/asterisk/file.h index e1dd99e268..43b32fd12a 100644 --- a/include/asterisk/file.h +++ b/include/asterisk/file.h @@ -315,21 +315,6 @@ off_t ast_tellstream(struct ast_filestream *fs); */ 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 diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h index 7196f91e52..9dff03602e 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -134,10 +134,6 @@ enum { * 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 diff --git a/main/file.c b/main/file.c index 8fedf754af..12e3fcb30f 100644 --- a/main/file.c +++ b/main/file.c @@ -692,17 +692,36 @@ struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *fil 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; + } + + 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 f; + + return fr; +} + +struct ast_frame *ast_readframe(struct ast_filestream *s) +{ + int whennext = 0; + + return read_frame(s, &whennext); } enum fsread_res { @@ -719,15 +738,13 @@ static enum fsread_res ast_readaudio_callback(struct ast_filestream *s) 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"); @@ -735,10 +752,12 @@ static enum fsread_res ast_readaudio_callback(struct ast_filestream *s) } goto return_failure; } + if (fr) { ast_frfree(fr); } } + if (whennext != s->lasttimeout) { if (s->owner->timingfd > -1) { float samp_rate = (float) ast_format_rate(s->fmt->format); @@ -782,11 +801,8 @@ static enum fsread_res ast_readvideo_callback(struct ast_filestream *s) 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"); @@ -795,6 +811,7 @@ static enum fsread_res ast_readvideo_callback(struct ast_filestream *s) s->owner->vstreamid = -1; return FSREAD_FAILURE; } + if (fr) { ast_frfree(fr); } @@ -886,20 +903,6 @@ 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; } @@ -1331,17 +1334,6 @@ int ast_waitstream_exten(struct ast_channel *c, const char *context) -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. diff --git a/main/frame.c b/main/frame.c index 999699f2e5..206c7f8b7f 100644 --- a/main/frame.c +++ b/main/frame.c @@ -334,8 +334,6 @@ static void __frame_free(struct ast_frame *fr, int cache) 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) @@ -424,7 +422,6 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr) } 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; }