diff --git a/include/asterisk/file.h b/include/asterisk/file.h index e1dd99e268dd9d4e1f9778fbb13769abe0bc39e0..43b32fd12a7faf61712976bd5534435f3a2f7fe5 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 db90e1845999b967c3f4c2d2dcf8370ff5b418b2..7246aad8334b377dc92dd3e1b90e078fcd848f45 100644 --- a/include/asterisk/frame.h +++ b/include/asterisk/frame.h @@ -136,10 +136,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 5855f45227eb3e0b62680beb3d39517306ee72f0..10764c67f7d9662cd3ca1ce33a1b24173eaabf6c 100644 --- a/main/file.c +++ b/main/file.c @@ -688,17 +688,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 { @@ -715,15 +734,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"); @@ -731,10 +748,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); @@ -778,11 +797,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"); @@ -791,6 +807,7 @@ static enum fsread_res ast_readvideo_callback(struct ast_filestream *s) s->owner->vstreamid = -1; return FSREAD_FAILURE; } + if (fr) { ast_frfree(fr); } @@ -882,20 +899,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; } @@ -1327,17 +1330,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 7b8a3cc9fbef444a8880a50be5f0c7327ce97aea..1b8dead2a3f668a1a910a5b8d997f58101c746f4 100644 --- a/main/frame.c +++ b/main/frame.c @@ -336,8 +336,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) @@ -426,7 +424,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; }