*/
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
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 {
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");
}
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);
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");
s->owner->vstreamid = -1;
return FSREAD_FAILURE;
}
+
if (fr) {
ast_frfree(fr);
}
}
}
- 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;
}
-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.