aboutsummaryrefslogtreecommitdiffstats
path: root/main
diff options
context:
space:
mode:
authorkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2009-06-16 18:54:30 +0000
committerkpfleming <kpfleming@f38db490-d61c-443f-a65b-d21fe96a405b>2009-06-16 18:54:30 +0000
commitea5a74f18bf3fc8f013718409de934279f1f2560 (patch)
tree1dd57b8b026f8601093e89d231d739594d6b7288 /main
parentd2292f0eca49f9ec9297bab8aa9c551557213662 (diff)
Merged revisions 200991 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4 ........ r200991 | kpfleming | 2009-06-16 12:05:38 -0500 (Tue, 16 Jun 2009) | 11 lines Improve support for media paths that can generate multiple frames at once. There are various media paths in Asterisk (codec translators and UDPTL, primarily) that can generate more than one frame to be generated when the application calling them expects only a single frame. This patch addresses a number of those cases, at least the primary ones to solve the known problems. In addition it removes the broken TRACE_FRAMES support, fixes a number of bugs in various frame-related API functions, and cleans up various code paths affected by these changes. https://reviewboard.asterisk.org/r/175/ ........ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@201056 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'main')
-rw-r--r--main/autoservice.c17
-rw-r--r--main/channel.c239
-rw-r--r--main/file.c18
-rw-r--r--main/frame.c121
-rw-r--r--main/slinfactory.c27
5 files changed, 253 insertions, 169 deletions
diff --git a/main/autoservice.c b/main/autoservice.c
index 26cb08582..7ed271016 100644
--- a/main/autoservice.c
+++ b/main/autoservice.c
@@ -163,15 +163,22 @@ static void *autoservice_run(void *ign)
continue;
}
- if ((dup_f = ast_frdup(defer_frame))) {
- AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+ if (defer_frame != f) {
+ if ((dup_f = ast_frdup(defer_frame))) {
+ AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+ }
+ } else {
+ if ((dup_f = ast_frisolate(defer_frame))) {
+ if (dup_f != defer_frame) {
+ ast_frfree(defer_frame);
+ }
+ AST_LIST_INSERT_HEAD(&ents[i]->deferred_frames, dup_f, frame_list);
+ }
}
break;
}
- }
-
- if (f) {
+ } else if (f) {
ast_frfree(f);
}
}
diff --git a/main/channel.c b/main/channel.c
index e4ab3d780..5f4676f6b 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1006,56 +1006,82 @@ struct ast_channel *__ast_channel_alloc(int needqueue, int state, const char *ci
return result;
}
-/*! \brief Queue an outgoing media frame */
-static int __ast_queue_frame(struct ast_channel *chan, const struct ast_frame *fin, int head)
+static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int head, struct ast_frame *after)
{
struct ast_frame *f;
struct ast_frame *cur;
int blah = 1;
- int qlen = 0;
-
- /* Build us a copy and free the original one */
- if (!(f = ast_frdup(fin))) {
- return -1;
- }
+ unsigned int new_frames = 0;
+ unsigned int new_voice_frames = 0;
+ unsigned int queued_frames = 0;
+ unsigned int queued_voice_frames = 0;
+ AST_LIST_HEAD_NOLOCK(, ast_frame) frames;
ast_channel_lock(chan);
/* See if the last frame on the queue is a hangup, if so don't queue anything */
- if ((cur = AST_LIST_LAST(&chan->readq)) && (cur->frametype == AST_FRAME_CONTROL) && (cur->subclass == AST_CONTROL_HANGUP)) {
- ast_frfree(f);
+ if ((cur = AST_LIST_LAST(&chan->readq)) &&
+ (cur->frametype == AST_FRAME_CONTROL) &&
+ (cur->subclass == AST_CONTROL_HANGUP)) {
ast_channel_unlock(chan);
return 0;
}
+ /* Build copies of all the frames and count them */
+ AST_LIST_HEAD_INIT_NOLOCK(&frames);
+ for (cur = fin; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ if (!(f = ast_frdup(cur))) {
+ ast_frfree(AST_LIST_FIRST(&frames));
+ return -1;
+ }
+
+ AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+ new_frames++;
+ if (f->frametype == AST_FRAME_VOICE) {
+ new_voice_frames++;
+ }
+ }
+
/* Count how many frames exist on the queue */
AST_LIST_TRAVERSE(&chan->readq, cur, frame_list) {
- qlen++;
+ queued_frames++;
+ if (cur->frametype == AST_FRAME_VOICE) {
+ queued_voice_frames++;
+ }
}
- /* Allow up to 96 voice frames outstanding, and up to 128 total frames */
- if (((fin->frametype == AST_FRAME_VOICE) && (qlen > 96)) || (qlen > 128)) {
- if (fin->frametype != AST_FRAME_VOICE) {
- ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
- ast_assert(fin->frametype == AST_FRAME_VOICE);
- } else {
- ast_debug(1, "Dropping voice to exceptionally long queue on %s\n", chan->name);
+ if ((queued_frames + new_frames) > 128) {
+ ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
+ while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
ast_frfree(f);
- ast_channel_unlock(chan);
- return 0;
}
+ ast_channel_unlock(chan);
+ return 0;
}
- if (head) {
- AST_LIST_INSERT_HEAD(&chan->readq, f, frame_list);
+ if ((queued_voice_frames + new_voice_frames) > 96) {
+ ast_log(LOG_WARNING, "Exceptionally long voice queue length queuing to %s\n", chan->name);
+ while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
+ ast_frfree(f);
+ }
+ ast_channel_unlock(chan);
+ return 0;
+ }
+
+ if (after) {
+ AST_LIST_INSERT_LIST_AFTER(&chan->readq, &frames, after, frame_list);
} else {
- AST_LIST_INSERT_TAIL(&chan->readq, f, frame_list);
+ if (head) {
+ AST_LIST_APPEND_LIST(&frames, &chan->readq, frame_list);
+ AST_LIST_HEAD_INIT_NOLOCK(&chan->readq);
+ }
+ AST_LIST_APPEND_LIST(&chan->readq, &frames, frame_list);
}
if (chan->alertpipe[1] > -1) {
- if (write(chan->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah)) {
- ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d (qlen = %d): %s!\n",
- chan->name, f->frametype, f->subclass, qlen, strerror(errno));
+ if (write(chan->alertpipe[1], &blah, new_frames * sizeof(blah)) != (new_frames * sizeof(blah))) {
+ ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %d): %s!\n",
+ chan->name, queued_frames, strerror(errno));
}
} else if (chan->timingfd > -1) {
ast_timer_enable_continuous(chan->timer);
@@ -1068,14 +1094,14 @@ static int __ast_queue_frame(struct ast_channel *chan, const struct ast_frame *f
return 0;
}
-int ast_queue_frame(struct ast_channel *chan, const struct ast_frame *fin)
+int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
{
- return __ast_queue_frame(chan, fin, 0);
+ return __ast_queue_frame(chan, fin, 0, NULL);
}
-int ast_queue_frame_head(struct ast_channel *chan, const struct ast_frame *fin)
+int ast_queue_frame_head(struct ast_channel *chan, struct ast_frame *fin)
{
- return __ast_queue_frame(chan, fin, 1);
+ return __ast_queue_frame(chan, fin, 1, NULL);
}
/*! \brief Queue a hangup frame for channel */
@@ -3029,13 +3055,14 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
chan->fdno = -1;
if (f) {
+ struct ast_frame *readq_tail = AST_LIST_LAST(&chan->readq);
+
/* if the channel driver returned more than one frame, stuff the excess
- into the readq for the next ast_read call (note that we can safely assume
- that the readq is empty, because otherwise we would not have called into
- the channel driver and f would be only a single frame)
+ into the readq for the next ast_read call
*/
if (AST_LIST_NEXT(f, frame_list)) {
- AST_LIST_HEAD_SET_NOLOCK(&chan->readq, AST_LIST_NEXT(f, frame_list));
+ ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list));
+ ast_frfree(AST_LIST_NEXT(f, frame_list));
AST_LIST_NEXT(f, frame_list) = NULL;
}
@@ -3255,12 +3282,30 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
}
}
- if (chan->readtrans && (f = ast_translate(chan->readtrans, f, 1)) == NULL)
+ if (chan->readtrans && (f = ast_translate(chan->readtrans, f, 1)) == NULL) {
f = &ast_null_frame;
- else
- /* Run generator sitting on the line if timing device not available
- * and synchronous generation of outgoing frames is necessary */
- ast_read_generator_actions(chan, f);
+ }
+
+ /* it is possible for the translation process on chan->readtrans to have
+ produced multiple frames from the single input frame we passed it; if
+ this happens, queue the additional frames *before* the frames we may
+ have queued earlier. if the readq was empty, put them at the head of
+ the queue, and if it was not, put them just after the frame that was
+ at the end of the queue.
+ */
+ if (AST_LIST_NEXT(f, frame_list)) {
+ if (!readq_tail) {
+ ast_queue_frame_head(chan, AST_LIST_NEXT(f, frame_list));
+ } else {
+ __ast_queue_frame(chan, AST_LIST_NEXT(f, frame_list), 0, readq_tail);
+ }
+ ast_frfree(AST_LIST_NEXT(f, frame_list));
+ AST_LIST_NEXT(f, frame_list) = NULL;
+ }
+
+ /* Run generator sitting on the line if timing device not available
+ * and synchronous generation of outgoing frames is necessary */
+ ast_read_generator_actions(chan, f);
}
default:
/* Just pass it on! */
@@ -3636,7 +3681,7 @@ int ast_write_video(struct ast_channel *chan, struct ast_frame *fr)
int ast_write(struct ast_channel *chan, struct ast_frame *fr)
{
int res = -1;
- struct ast_frame *f = NULL, *f2 = NULL;
+ struct ast_frame *f = NULL;
int count = 0;
/*Deadlock avoidance*/
@@ -3708,10 +3753,12 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
break;
case AST_FRAME_DTMF_END:
if (chan->audiohooks) {
- struct ast_frame *old_frame = fr;
- fr = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
- if (old_frame != fr)
- f = fr;
+ struct ast_frame *new_frame = fr;
+
+ new_frame = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
+ if (new_frame != fr) {
+ ast_frfree(new_frame);
+ }
}
send_dtmf_event(chan, "Sent", fr->subclass, "No", "Yes");
ast_clear_flag(chan, AST_FLAG_BLOCKING);
@@ -3746,14 +3793,6 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
if (chan->tech->write == NULL)
break; /*! \todo XXX should return 0 maybe ? */
- /* If audiohooks are present, write the frame out */
- if (chan->audiohooks) {
- struct ast_frame *old_frame = fr;
- fr = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, fr);
- if (old_frame != fr)
- f2 = fr;
- }
-
/* If the frame is in the raw write format, then it's easy... just use the frame - otherwise we will have to translate */
if (fr->subclass == chan->rawwriteformat)
f = fr;
@@ -3765,37 +3804,82 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
break;
}
+ if (chan->audiohooks) {
+ struct ast_frame *new_frame, *cur;
+
+ for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ new_frame = ast_audiohook_write_list(chan, chan->audiohooks, AST_AUDIOHOOK_DIRECTION_WRITE, cur);
+ if (new_frame != cur) {
+ ast_frfree(new_frame);
+ }
+ }
+ }
+
/* If Monitor is running on this channel, then we have to write frames out there too */
+ /* the translator on chan->writetrans may have returned multiple frames
+ from the single frame we passed in; if so, feed each one of them to the
+ monitor */
if (chan->monitor && chan->monitor->write_stream) {
+ struct ast_frame *cur;
+
+ for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
/* XXX must explain this code */
#ifndef MONITOR_CONSTANT_DELAY
- int jump = chan->insmpl - chan->outsmpl - 4 * f->samples;
- if (jump >= 0) {
- jump = chan->insmpl - chan->outsmpl;
- if (ast_seekstream(chan->monitor->write_stream, jump, SEEK_FORCECUR) == -1)
- ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
- chan->outsmpl += jump + f->samples;
- } else
- chan->outsmpl += f->samples;
+ int jump = chan->insmpl - chan->outsmpl - 4 * cur->samples;
+ if (jump >= 0) {
+ jump = chan->insmpl - chan->outsmpl;
+ if (ast_seekstream(chan->monitor->write_stream, jump, SEEK_FORCECUR) == -1)
+ ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
+ chan->outsmpl += jump + cur->samples;
+ } else {
+ chan->outsmpl += cur->samples;
+ }
#else
- int jump = chan->insmpl - chan->outsmpl;
- if (jump - MONITOR_DELAY >= 0) {
- if (ast_seekstream(chan->monitor->write_stream, jump - f->samples, SEEK_FORCECUR) == -1)
- ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
- chan->outsmpl += jump;
- } else
- chan->outsmpl += f->samples;
+ int jump = chan->insmpl - chan->outsmpl;
+ if (jump - MONITOR_DELAY >= 0) {
+ if (ast_seekstream(chan->monitor->write_stream, jump - cur->samples, SEEK_FORCECUR) == -1)
+ ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
+ chan->outsmpl += jump;
+ } else {
+ chan->outsmpl += cur->samples;
+ }
#endif
- if (chan->monitor->state == AST_MONITOR_RUNNING) {
- if (ast_writestream(chan->monitor->write_stream, f) < 0)
- ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
+ if (chan->monitor->state == AST_MONITOR_RUNNING) {
+ if (ast_writestream(chan->monitor->write_stream, cur) < 0)
+ ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
+ }
}
}
- if (f)
- res = chan->tech->write(chan,f);
- else
- res = 0;
+ /* the translator on chan->writetrans may have returned multiple frames
+ from the single frame we passed in; if so, feed each one of them to the
+ channel, freeing each one after it has been written */
+ if ((f != fr) && AST_LIST_NEXT(f, frame_list)) {
+ struct ast_frame *cur, *next;
+ unsigned int skip = 0;
+
+ for (cur = f, next = AST_LIST_NEXT(cur, frame_list);
+ cur;
+ cur = next, next = cur ? AST_LIST_NEXT(cur, frame_list) : NULL) {
+ if (!skip) {
+ if ((res = chan->tech->write(chan, cur)) < 0) {
+ chan->_softhangup |= AST_SOFTHANGUP_DEV;
+ skip = 1;
+ } else if (next) {
+ /* don't do this for the last frame in the list,
+ as the code outside the loop will do it once
+ */
+ chan->fout = FRAMECOUNT_INC(chan->fout);
+ }
+ }
+ ast_frfree(cur);
+ }
+
+ /* reset f so the code below doesn't attempt to free it */
+ f = NULL;
+ } else {
+ res = chan->tech->write(chan, f);
+ }
break;
case AST_FRAME_NULL:
case AST_FRAME_IAX:
@@ -3812,13 +3896,12 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
if (f && f != fr)
ast_frfree(f);
- if (f2)
- ast_frfree(f2);
ast_clear_flag(chan, AST_FLAG_BLOCKING);
+
/* Consider a write failure to force a soft hangup */
- if (res < 0)
+ if (res < 0) {
chan->_softhangup |= AST_SOFTHANGUP_DEV;
- else {
+ } else {
chan->fout = FRAMECOUNT_INC(chan->fout);
}
done:
diff --git a/main/file.c b/main/file.c
index cfeb2d1a9..ca7070351 100644
--- a/main/file.c
+++ b/main/file.c
@@ -187,14 +187,20 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
struct ast_frame *trf;
fs->lastwriteformat = f->subclass;
/* Get the translated frame but don't consume the original in case they're using it on another stream */
- trf = ast_translate(fs->trans, f, 0);
- if (trf) {
- res = fs->fmt->write(fs, trf);
+ if ((trf = ast_translate(fs->trans, f, 0))) {
+ struct ast_frame *cur;
+
+ /* the translator may have returned multiple frames, so process them */
+ for (cur = trf; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ if ((res = fs->fmt->write(fs, trf))) {
+ ast_log(LOG_WARNING, "Translated frame write failed\n");
+ break;
+ }
+ }
ast_frfree(trf);
- if (res)
- ast_log(LOG_WARNING, "Translated frame write failed\n");
- } else
+ } else {
res = 0;
+ }
}
}
return res;
diff --git a/main/frame.c b/main/frame.c
index bc1c60b8a..e305580ac 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -40,11 +40,6 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/dsp.h"
#include "asterisk/file.h"
-#ifdef TRACE_FRAMES
-static int headers;
-static AST_LIST_HEAD_STATIC(headerlist, ast_frame);
-#endif
-
#if !defined(LOW_MEMORY)
static void frame_cache_cleanup(void *data);
@@ -318,12 +313,6 @@ static struct ast_frame *ast_frame_header_new(void)
#endif
f->mallocd_hdr_len = sizeof(*f);
-#ifdef TRACE_FRAMES
- AST_LIST_LOCK(&headerlist);
- headers++;
- AST_LIST_INSERT_HEAD(&headerlist, f, frame_list);
- AST_LIST_UNLOCK(&headerlist);
-#endif
return f;
}
@@ -341,7 +330,7 @@ static void frame_cache_cleanup(void *data)
}
#endif
-void ast_frame_free(struct ast_frame *fr, int cache)
+static void __frame_free(struct ast_frame *fr, int cache)
{
if (ast_test_flag(fr, AST_FRFLAG_FROM_TRANSLATOR)) {
ast_translate_frame_freed(fr);
@@ -360,8 +349,8 @@ void ast_frame_free(struct ast_frame *fr, int cache)
* to keep things simple... */
struct ast_frame_cache *frames;
- if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))
- && frames->size < FRAME_CACHE_MAX_SIZE) {
+ if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) &&
+ (frames->size < FRAME_CACHE_MAX_SIZE)) {
AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);
frames->size++;
return;
@@ -375,19 +364,25 @@ void ast_frame_free(struct ast_frame *fr, int cache)
}
if (fr->mallocd & AST_MALLOCD_SRC) {
if (fr->src)
- ast_free((char *)fr->src);
+ ast_free((void *) fr->src);
}
if (fr->mallocd & AST_MALLOCD_HDR) {
-#ifdef TRACE_FRAMES
- AST_LIST_LOCK(&headerlist);
- headers--;
- AST_LIST_REMOVE(&headerlist, fr, frame_list);
- AST_LIST_UNLOCK(&headerlist);
-#endif
ast_free(fr);
}
}
+
+void ast_frame_free(struct ast_frame *frame, int cache)
+{
+ struct ast_frame *next;
+
+ for (next = AST_LIST_NEXT(frame, frame_list);
+ frame;
+ frame = next, next = frame ? AST_LIST_NEXT(frame, frame_list) : NULL) {
+ __frame_free(frame, cache);
+ }
+}
+
/*!
* \brief 'isolates' a frame by duplicating non-malloc'ed components
* (header, src, data).
@@ -398,19 +393,29 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
struct ast_frame *out;
void *newdata;
- ast_clear_flag(fr, AST_FRFLAG_FROM_TRANSLATOR);
- ast_clear_flag(fr, AST_FRFLAG_FROM_DSP);
+ /* if none of the existing frame is malloc'd, let ast_frdup() do it
+ since it is more efficient
+ */
+ if (fr->mallocd == 0) {
+ return ast_frdup(fr);
+ }
+
+ /* if everything is already malloc'd, we are done */
+ if ((fr->mallocd & (AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA)) ==
+ (AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA)) {
+ return fr;
+ }
if (!(fr->mallocd & AST_MALLOCD_HDR)) {
/* Allocate a new header if needed */
- if (!(out = ast_frame_header_new()))
+ if (!(out = ast_frame_header_new())) {
return NULL;
+ }
out->frametype = fr->frametype;
out->subclass = fr->subclass;
out->datalen = fr->datalen;
out->samples = fr->samples;
out->offset = fr->offset;
- out->data = fr->data;
/* Copy the timing data */
ast_copy_flags(out, fr, AST_FRFLAG_HAS_TIMING_INFO);
if (ast_test_flag(fr, AST_FRFLAG_HAS_TIMING_INFO)) {
@@ -418,26 +423,34 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
out->len = fr->len;
out->seqno = fr->seqno;
}
- } else
+ } 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;
+ }
- if (!(fr->mallocd & AST_MALLOCD_SRC)) {
- if (fr->src) {
- if (!(out->src = ast_strdup(fr->src))) {
- if (out != fr)
- ast_free(out);
- return NULL;
+ if (!(fr->mallocd & AST_MALLOCD_SRC) && fr->src) {
+ if (!(out->src = ast_strdup(fr->src))) {
+ if (out != fr) {
+ ast_free(out);
}
+ return NULL;
}
- } else
+ } else {
out->src = fr->src;
+ fr->src = NULL;
+ fr->mallocd &= ~AST_MALLOCD_SRC;
+ }
if (!(fr->mallocd & AST_MALLOCD_DATA)) {
if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) {
- if (out->src != fr->src)
+ if (out->src != fr->src) {
ast_free((void *) out->src);
- if (out != fr)
+ }
+ if (out != fr) {
ast_free(out);
+ }
return NULL;
}
newdata += AST_FRIENDLY_OFFSET;
@@ -445,6 +458,10 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
out->datalen = fr->datalen;
memcpy(newdata, fr->data.ptr, fr->datalen);
out->data.ptr = newdata;
+ } else {
+ out->data = fr->data;
+ memset(&fr->data, 0, sizeof(fr->data));
+ fr->mallocd &= ~AST_MALLOCD_DATA;
}
out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
@@ -939,44 +956,10 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
}
-#ifdef TRACE_FRAMES
-static char *show_frame_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
- struct ast_frame *f;
- int x=1;
-
- switch (cmd) {
- case CLI_INIT:
- e->command = "core show frame stats";
- e->usage =
- "Usage: core show frame stats\n"
- " Displays debugging statistics from framer\n";
- return NULL;
- case CLI_GENERATE:
- return NULL;
- }
-
- if (a->argc != 4)
- return CLI_SHOWUSAGE;
- AST_LIST_LOCK(&headerlist);
- ast_cli(a->fd, " Framer Statistics \n");
- ast_cli(a->fd, "---------------------------\n");
- ast_cli(a->fd, "Total allocated headers: %d\n", headers);
- ast_cli(a->fd, "Queue Dump:\n");
- AST_LIST_TRAVERSE(&headerlist, f, frame_list)
- ast_cli(a->fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
- AST_LIST_UNLOCK(&headerlist);
- return CLI_SUCCESS;
-}
-#endif
-
/* Builtin Asterisk CLI-commands for debugging */
static struct ast_cli_entry my_clis[] = {
AST_CLI_DEFINE(show_codecs, "Displays a list of codecs"),
AST_CLI_DEFINE(show_codec_n, "Shows a specific codec"),
-#ifdef TRACE_FRAMES
- AST_CLI_DEFINE(show_frame_stats, "Shows frame statistics"),
-#endif
};
int init_framer(void)
diff --git a/main/slinfactory.c b/main/slinfactory.c
index c58d32e00..8f004da8d 100644
--- a/main/slinfactory.c
+++ b/main/slinfactory.c
@@ -73,7 +73,7 @@ void ast_slinfactory_destroy(struct ast_slinfactory *sf)
int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
{
struct ast_frame *begin_frame = f, *duped_frame = NULL, *frame_ptr;
- unsigned int x;
+ unsigned int x = 0;
/* In some cases, we can be passed a frame which has no data in it, but
* which has a positive number of samples defined. Once such situation is
@@ -100,15 +100,17 @@ int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
sf->format = f->subclass;
}
- if (!(begin_frame = ast_translate(sf->trans, f, 0)))
+ if (!(begin_frame = ast_translate(sf->trans, f, 0))) {
return 0;
+ }
- duped_frame = ast_frdup(begin_frame);
-
- ast_frfree(begin_frame);
-
- if (!duped_frame)
+ if (!(duped_frame = ast_frisolate(begin_frame))) {
return 0;
+ }
+
+ if (duped_frame != begin_frame) {
+ ast_frfree(begin_frame);
+ }
} else {
if (sf->trans) {
ast_translator_free_path(sf->trans);
@@ -118,14 +120,17 @@ int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
return 0;
}
- x = 0;
AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list) {
x++;
}
- AST_LIST_INSERT_TAIL(&sf->queue, duped_frame, frame_list);
-
- sf->size += duped_frame->samples;
+ /* if the frame was translated, the translator may have returned multiple
+ frames, so process each of them
+ */
+ for (begin_frame = duped_frame; begin_frame; begin_frame = AST_LIST_NEXT(begin_frame, frame_list)) {
+ AST_LIST_INSERT_TAIL(&sf->queue, begin_frame, frame_list);
+ sf->size += begin_frame->samples;
+ }
return x;
}