aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/app_chanspy.c18
-rw-r--r--apps/app_meetme.c16
-rw-r--r--apps/app_mixmonitor.c13
-rw-r--r--autoconf/ast_gcc_attribute.m411
-rwxr-xr-xconfigure79
-rw-r--r--configure.ac2
-rw-r--r--include/asterisk/channel.h23
-rw-r--r--include/asterisk/frame.h9
-rw-r--r--include/asterisk/linkedlists.h32
-rw-r--r--main/autoservice.c17
-rw-r--r--main/channel.c235
-rw-r--r--main/file.c18
-rw-r--r--main/frame.c121
-rw-r--r--main/slinfactory.c27
14 files changed, 351 insertions, 270 deletions
diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c
index c5a26772d..4c1bf0e4b 100644
--- a/apps/app_chanspy.c
+++ b/apps/app_chanspy.c
@@ -192,7 +192,7 @@ static void spy_release(struct ast_channel *chan, void *data)
static int spy_generate(struct ast_channel *chan, void *data, int len, int samples)
{
struct chanspy_translation_helper *csth = data;
- struct ast_frame *f = NULL;
+ struct ast_frame *f, *cur;
ast_audiohook_lock(&csth->spy_audiohook);
if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
@@ -208,14 +208,16 @@ static int spy_generate(struct ast_channel *chan, void *data, int len, int sampl
if (!f)
return 0;
- if (ast_write(chan, f)) {
- ast_frfree(f);
- return -1;
- }
+ for (cur = f; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ if (ast_write(chan, cur)) {
+ ast_frfree(f);
+ return -1;
+ }
- if (csth->fd) {
- if (write(csth->fd, f->data, f->datalen) < 0) {
- ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
+ if (csth->fd) {
+ if (write(csth->fd, cur->data, cur->datalen) < 0) {
+ ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
+ }
}
}
diff --git a/apps/app_meetme.c b/apps/app_meetme.c
index c4b5a1df2..bbbd87f90 100644
--- a/apps/app_meetme.c
+++ b/apps/app_meetme.c
@@ -2700,9 +2700,19 @@ static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int c
}
}
if (conf->transframe[index]) {
- if (conf->transframe[index]->frametype != AST_FRAME_NULL) {
- if (can_write(chan, confflags) && ast_write(chan, conf->transframe[index]))
- ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
+ if ((conf->transframe[index]->frametype != AST_FRAME_NULL) &&
+ can_write(chan, confflags)) {
+ struct ast_frame *cur;
+
+ /* the translator may have returned a list of frames, so
+ write each one onto the channel
+ */
+ for (cur = conf->transframe[index]; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ if (ast_write(chan, cur)) {
+ ast_log(LOG_WARNING, "Unable to write frame to channel %s\n", chan->name);
+ break;
+ }
+ }
}
} else {
ast_mutex_unlock(&conf->listenlock);
diff --git a/apps/app_mixmonitor.c b/apps/app_mixmonitor.c
index 8f9a26e8e..2f659a7b4 100644
--- a/apps/app_mixmonitor.c
+++ b/apps/app_mixmonitor.c
@@ -222,10 +222,15 @@ static void *mixmonitor_thread(void *obj)
errflag = 1;
}
}
-
- /* Write out frame */
- if (fs)
- ast_writestream(fs, fr);
+
+ /* Write out the frame(s) */
+ if (fs) {
+ struct ast_frame *cur;
+
+ for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
+ ast_writestream(fs, cur);
+ }
+ }
} else {
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
diff --git a/autoconf/ast_gcc_attribute.m4 b/autoconf/ast_gcc_attribute.m4
index f08b2545b..d3f05be5b 100644
--- a/autoconf/ast_gcc_attribute.m4
+++ b/autoconf/ast_gcc_attribute.m4
@@ -7,17 +7,10 @@ AC_MSG_CHECKING(for compiler 'attribute $1' support)
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
-if test "x$3" = "x"
-then
-attribute_scope="static"
-else
-attribute_scope="$3"
-fi
-
if test "x$2" = "x"
then
AC_COMPILE_IFELSE(
- AC_LANG_PROGRAM([$attribute_scope void __attribute__(($1)) *test(void *muffin, ...) {return (void *) 0;}],
+ AC_LANG_PROGRAM([$3 void __attribute__(($1)) *test(void *muffin, ...) {return (void *) 0;}],
[]),
AC_MSG_RESULT(yes)
AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
@@ -25,7 +18,7 @@ AC_COMPILE_IFELSE(
)
else
AC_COMPILE_IFELSE(
- AC_LANG_PROGRAM([$attribute_scope void __attribute__(($2)) *test(void *muffin, ...) {return (void *) 0;}],
+ AC_LANG_PROGRAM([$3 void __attribute__(($2)) *test(void *muffin, ...) {return (void *) 0;}],
[]),
AC_MSG_RESULT(yes)
AC_DEFINE_UNQUOTED([HAVE_ATTRIBUTE_$1], 1, [Define to 1 if your GCC C compiler supports the '$1' attribute.]),
diff --git a/configure b/configure
index 6dd8adedc..2830b2827 100755
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
#! /bin/sh
-# From configure.ac Revision: 191368 .
+# From configure.ac Revision: 200986 .
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.63 for asterisk 1.6.
#
@@ -17398,20 +17398,13 @@ CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
if test "x" = "x"
then
-attribute_scope="static"
-else
-attribute_scope=""
-fi
-
-if test "x" = "x"
-then
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__((pure)) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__((pure)) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -17462,7 +17455,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -17519,20 +17512,13 @@ CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
if test "x" = "x"
then
-attribute_scope="static"
-else
-attribute_scope=""
-fi
-
-if test "x" = "x"
-then
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__((malloc)) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__((malloc)) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -17583,7 +17569,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -17640,20 +17626,13 @@ CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
if test "x" = "x"
then
-attribute_scope="static"
-else
-attribute_scope=""
-fi
-
-if test "x" = "x"
-then
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__((const)) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__((const)) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -17704,7 +17683,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -17761,20 +17740,13 @@ CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
if test "x" = "x"
then
-attribute_scope="static"
-else
-attribute_scope=""
-fi
-
-if test "x" = "x"
-then
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__((unused)) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__((unused)) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -17825,7 +17797,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -17882,20 +17854,13 @@ CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
if test "x" = "x"
then
-attribute_scope="static"
-else
-attribute_scope=""
-fi
-
-if test "x" = "x"
-then
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__((always_inline)) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__((always_inline)) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -17946,7 +17911,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -18003,20 +17968,13 @@ CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
if test "x" = "x"
then
-attribute_scope="static"
-else
-attribute_scope=""
-fi
-
-if test "x" = "x"
-then
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__((deprecated)) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__((deprecated)) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -18067,7 +18025,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -18122,13 +18080,6 @@ $as_echo_n "checking for compiler 'attribute weak' support... " >&6; }
saved_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Wall -Wno-unused -Werror"
-if test "x""" = "x"
-then
-attribute_scope="static"
-else
-attribute_scope=""""
-fi
-
if test "x" = "x"
then
cat >conftest.$ac_ext <<_ACEOF
@@ -18137,7 +18088,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__((weak)) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__((weak)) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
@@ -18188,7 +18139,7 @@ _ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
-$attribute_scope void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
+ void __attribute__(()) *test(void *muffin, ...) {return (void *) 0;}
int
main ()
{
diff --git a/configure.ac b/configure.ac
index f1801231b..ce3f23ea8 100644
--- a/configure.ac
+++ b/configure.ac
@@ -484,7 +484,7 @@ AST_GCC_ATTRIBUTE(const)
AST_GCC_ATTRIBUTE(unused)
AST_GCC_ATTRIBUTE(always_inline)
AST_GCC_ATTRIBUTE(deprecated)
-AST_GCC_ATTRIBUTE(weak, , "")
+AST_GCC_ATTRIBUTE(weak)
AC_MSG_CHECKING(for -ffunction-sections support)
saved_CFLAGS="${CFLAGS}"
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 54710379e..c9a70faca 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -741,20 +741,27 @@ struct ast_channel * attribute_malloc __attribute__((format(printf, 12, 13)))
__ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, amaflag, \
__FILE__, __LINE__, __FUNCTION__, __VA_ARGS__)
-/*!
- * \brief Queue an outgoing frame
+/*!
+ * \brief Queue one or more frames to a channel's frame queue
*
- * \note The channel does not need to be locked before calling this function.
+ * \param chan the channel to queue the frame(s) on
+ * \param f the frame(s) to queue. Note that the frame(s) will be duplicated
+ * by this function. It is the responsibility of the caller to handle
+ * freeing the memory associated with the frame(s) being passed if
+ * necessary.
+ *
+ * \retval 0 success
+ * \retval non-zero failure
*/
int ast_queue_frame(struct ast_channel *chan, struct ast_frame *f);
/*!
- * \brief Queue an outgoing frame to the head of the frame queue
+ * \brief Queue one or more frames to the head of a channel's frame queue
*
- * \param chan the channel to queue the frame on
- * \param f the frame to queue. Note that this frame will be duplicated by
- * this function. It is the responsibility of the caller to handle
- * freeing the memory associated with the frame being passed if
+ * \param chan the channel to queue the frame(s) on
+ * \param f the frame(s) to queue. Note that the frame(s) will be duplicated
+ * by this function. It is the responsibility of the caller to handle
+ * freeing the memory associated with the frame(s) being passed if
* necessary.
*
* \retval 0 success
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 430c79b17..144040525 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -424,9 +424,9 @@ struct ast_frame *ast_fralloc(char *source, int len);
#endif
/*!
- * \brief Frees a frame
+ * \brief Frees a frame or list of frames
*
- * \param fr Frame to free
+ * \param fr Frame to free, or head of list to free
* \param cache Whether to consider this frame for frame caching
*/
void ast_frame_free(struct ast_frame *fr, int cache);
@@ -440,6 +440,11 @@ void ast_frame_free(struct ast_frame *fr, int cache);
* data malloc'd. If you need to store frames, say for queueing, then
* you should call this function.
* \return Returns a frame on success, NULL on error
+ * \note This function may modify the frame passed to it, so you must
+ * not assume the frame will be intact after the isolated frame has
+ * been produced. In other words, calling this function on a frame
+ * should be the last operation you do with that frame before freeing
+ * it (or exiting the block, if the frame is on the stack.)
*/
struct ast_frame *ast_frisolate(struct ast_frame *fr);
diff --git a/include/asterisk/linkedlists.h b/include/asterisk/linkedlists.h
index 3c89e7117..d35cfad3e 100644
--- a/include/asterisk/linkedlists.h
+++ b/include/asterisk/linkedlists.h
@@ -744,13 +744,37 @@ struct { \
#define AST_RWLIST_APPEND_LIST AST_LIST_APPEND_LIST
/*!
- \brief Removes and returns the head entry from a list.
+ \brief Inserts a whole list after a specific entry in a list
\param head This is a pointer to the list head structure
+ \param list This is a pointer to the list to be inserted.
+ \param elm This is a pointer to the entry after which the new list should
+ be inserted.
\param field This is the name of the field (declared using AST_LIST_ENTRY())
- used to link entries of this list together.
+ used to link entries of the lists together.
- Removes the head entry from the list, and returns a pointer to it.
- This macro is safe to call on an empty list.
+ Note: The source list (the \a list parameter) will be empty after
+ calling this macro (the list entries are \b moved to the target list).
+ */
+#define AST_LIST_INSERT_LIST_AFTER(head, list, elm, field) do { \
+ (list)->last->field.next = (elm)->field.next; \
+ (elm)->field.next = (list)->first; \
+ if ((head)->last == elm) { \
+ (head)->last = (list)->last; \
+ } \
+ (list)->first = NULL; \
+ (list)->last = NULL; \
+} while(0)
+
+#define AST_RWLIST_INSERT_LIST_AFTER AST_LIST_INSERT_LIST_AFTER
+
+/*!
+ * \brief Removes and returns the head entry from a list.
+ * \param head This is a pointer to the list head structure
+ * \param field This is the name of the field (declared using AST_LIST_ENTRY())
+ * used to link entries of this list together.
+ *
+ * Removes the head entry from the list, and returns a pointer to it.
+ * This macro is safe to call on an empty list.
*/
#define AST_LIST_REMOVE_HEAD(head, field) ({ \
typeof((head)->first) cur = (head)->first; \
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 3bcccea02..ddeee3310 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -981,56 +981,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, 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));
}
#ifdef HAVE_DAHDI
} else if (chan->timingfd > -1) {
@@ -1047,12 +1073,12 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in
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, 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 */
@@ -2701,13 +2727,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;
}
@@ -2927,12 +2954,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! */
@@ -3268,7 +3313,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*/
@@ -3340,10 +3385,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);
@@ -3378,14 +3425,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;
@@ -3397,37 +3436,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:
@@ -3444,13 +3528,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 799410b59..67c8c77c5 100644
--- a/main/file.c
+++ b/main/file.c
@@ -186,14 +186,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 269370d2a..c394718db 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);
@@ -316,12 +311,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;
}
@@ -339,7 +328,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);
@@ -358,8 +347,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;
@@ -373,19 +362,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).
@@ -396,19 +391,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)) {
@@ -416,26 +421,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;
@@ -443,6 +456,10 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr)
out->datalen = fr->datalen;
memcpy(newdata, fr->data, fr->datalen);
out->data = 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;
@@ -933,44 +950,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 4b71db42d..529c2557c 100644
--- a/main/slinfactory.c
+++ b/main/slinfactory.c
@@ -54,7 +54,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
@@ -80,15 +80,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);
@@ -98,13 +100,16 @@ 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;
}