]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Improve the build system to *properly* remove unnecessary symbols from the runtime...
authorKevin P. Fleming <kpfleming@digium.com>
Wed, 18 Mar 2009 01:28:42 +0000 (01:28 +0000)
committerKevin P. Fleming <kpfleming@digium.com>
Wed, 18 Mar 2009 01:28:42 +0000 (01:28 +0000)
With these changes, for a module to export symbols into the global namespace, it must have *both* the AST_MODFLAG_GLOBAL_SYMBOLS flag and a linker script that allows the linker to leave the symbols exposed in the module's .so file (see res_odbc.exports for an example).

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@182802 65c4cc65-6c06-0410-ace0-fbb531ad65f3

33 files changed:
Makefile.rules
apps/app_chanspy.c
apps/app_meetme.c
apps/app_mixmonitor.c
build_tools/cflags-devmode.xml
build_tools/strip_nonapi [deleted file]
default.exports [new file with mode: 0644]
include/asterisk/astobj2.h
include/asterisk/frame.h
include/asterisk/linkedlists.h
main/Makefile
main/asterisk.exports [new file with mode: 0644]
main/astobj2.c
main/autoservice.c
main/channel.c
main/file.c
main/frame.c
main/slinfactory.c
makeopts.in
res/res_adsi.exports [new file with mode: 0644]
res/res_agi.exports [new file with mode: 0644]
res/res_config_odbc.c
res/res_config_pgsql.c
res/res_crypto.c
res/res_features.exports [new file with mode: 0644]
res/res_indications.c
res/res_jabber.exports [new file with mode: 0644]
res/res_monitor.exports [new file with mode: 0644]
res/res_musiconhold.c
res/res_odbc.exports [new file with mode: 0644]
res/res_smdi.exports [new file with mode: 0644]
res/res_snmp.c
res/res_speech.exports [new file with mode: 0644]

index e4b174577fba5402679f51e048f02cc0acc72542..e6427172db8d197ff4d593fd1fa24aff459dbc38 100644 (file)
@@ -51,8 +51,13 @@ endif
 # per-target settings will be applied
 CC_CFLAGS=$(PTHREAD_CFLAGS) $(ASTCFLAGS)
 CXX_CFLAGS=$(PTHREAD_CFLAGS) $(filter-out -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations $(AST_DECLARATION_AFTER_STATEMENT),$(ASTCFLAGS))
-CC_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK)
-CXX_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK)
+
+ifeq ($(GNU_LD),1)
+SO_SUPPRESS_SYMBOLS=-Wl,--version-script,$(if $(wildcard $(subst .so,.exports,$@)),$(subst .so,.exports,$@),$(ASTTOPDIR)/default.exports)
+endif
+
+CC_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $(SO_SUPPRESS_SYMBOLS)
+CXX_LDFLAGS_SO=$(PTHREAD_CFLAGS) $(ASTLDFLAGS) $(SOLINK) $(SO_SUPPRESS_SYMBOLS)
 CC_LIBS=$(PTHREAD_LIBS) $(LIBS)
 CXX_LIBS=$(PTHREAD_LIBS) $(LIBS)
 
index 18e4972a5e1a5d72e31679a7b8784348a225178c..3f19b04af4cb3898987822b0ac774e7b9ce9c605 100644 (file)
@@ -171,7 +171,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;
+       struct ast_frame *f, *cur;
 
        ast_audiohook_lock(&csth->spy_audiohook);
        if (csth->spy_audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
@@ -186,14 +186,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));
+                       }
                }
        }
 
index 67c851a2c9c0479f9e3024fbf5839bc5c9ac5fbb..a314a79f01c9651231b4350b85220f5f9d536ebe 100644 (file)
@@ -2338,9 +2338,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);
index 4d5f5be26cfcd5ea757a7da486d799ac19f1287e..f1a1624a8673ea551d71120b730d4f22776a0839 100644 (file)
@@ -229,9 +229,14 @@ static void *mixmonitor_thread(void *obj)
                                }
                        }
 
-                       /* Write out the 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);
                }
index 8be92e71f0c89628380f5fe38c19459ea46e66a3..9ce9a68d51f62dc16f42a93de5d37170a4a5a17f 100644 (file)
@@ -12,6 +12,4 @@
                </member>
                <member name="MTX_PROFILE" displayname="Enable Code Profiling Using TSC Counters">
                </member>
-               <member name="TRACE_FRAMES" displayname="Trace Frame Allocations">
-               </member>
        </category>
diff --git a/build_tools/strip_nonapi b/build_tools/strip_nonapi
deleted file mode 100755 (executable)
index ade30c9..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/bin/sh -e
-
-# This script is designed to remove all non-API global symbols from an object
-# file. The only global symbols that should be retained are those that belong
-# to the official namespace. Unfortunately doing this is platform-specific, as
-# the object file manipulation tools are not consistent across platforms.
-#
-# On platforms where this script does not know what to do, the object file
-# will retain non-API global symbols, and this may have unpleasant side effects.
-#
-# Prefixes that belong to the official namespace are:
-#      ast_
-#      _ast_
-#      __ast_
-#      astman_
-#      pbx_
-
-case "${PROC}" in
-       powerpc64)
-               TEXTSYM=" D "
-               ;;
-       *)
-               TEXTSYM=" T "
-               ;;
-esac
-
-FILTER="${GREP} -v -e ^ast_ -e ^_ast_ -e ^__ast_ -e ^astman_ -e ^pbx_"
-
-case "${OSARCH}" in
-    linux-gnu)
-       nm ${1} | ${GREP} -e "$TEXTSYM" | cut -d" " -f3 | ${FILTER} > striplist
-       sed -e "s/^/-N /" striplist | xargs -n 40 ${STRIP} ${1}
-       rm -f striplist
-       ;;
-    *)
-       ;;
-esac
diff --git a/default.exports b/default.exports
new file mode 100644 (file)
index 0000000..5e76754
--- /dev/null
@@ -0,0 +1,4 @@
+{
+       local:
+               *;
+};
index dd154ec8593d3425a482d355881d53c58281f7ce..ec841b888d48b86f197a62ad5e89d0b17e361a75 100644 (file)
@@ -188,15 +188,15 @@ int ao2_ref(void *o, int delta);
 #ifndef DEBUG_THREADS
 int ao2_lock(void *a);
 #else
-#define ao2_lock(a) _ao2_lock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
-int _ao2_lock(void *a, const char *file, const char *func, int line, const char *var);
+#define ao2_lock(a) __ao2_lock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
+int __ao2_lock(void *a, const char *file, const char *func, int line, const char *var);
 #endif
 
 #ifndef DEBUG_THREADS
 int ao2_trylock(void *a);
 #else
-#define ao2_trylock(a) _ao2_trylock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
-int _ao2_trylock(void *a, const char *file, const char *func, int line, const char *var);
+#define ao2_trylock(a) __ao2_trylock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
+int __ao2_trylock(void *a, const char *file, const char *func, int line, const char *var);
 #endif
 
 /*!
@@ -208,8 +208,8 @@ int _ao2_trylock(void *a, const char *file, const char *func, int line, const ch
 #ifndef DEBUG_THREADS
 int ao2_unlock(void *a);
 #else
-#define ao2_unlock(a) _ao2_unlock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
-int _ao2_unlock(void *a, const char *file, const char *func, int line, const char *var);
+#define ao2_unlock(a) __ao2_unlock(a, __FILE__, __PRETTY_FUNCTION__, __LINE__, #a)
+int __ao2_unlock(void *a, const char *file, const char *func, int line, const char *var);
 #endif
 
 /*!
index bb502690804fe2d06dc79eba739d20400015aa62..f874643c0d35e3fa988e66f6ec5337c3f2b45067 100644 (file)
@@ -399,9 +399,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);
@@ -415,6 +415,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);
 
index bd7f6a9b1a69f9960d9c67a7794bf189bbe468a9..7981c556c074c958d448829167d7eaf94bfc7aa9 100644 (file)
@@ -685,7 +685,7 @@ struct {                                                            \
   \param head This is a pointer to the list head structure
   \param list This is a pointer to the list to be appended.
   \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.
 
   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).
@@ -704,6 +704,30 @@ struct {                                                           \
 
 #define AST_RWLIST_APPEND_LIST AST_LIST_APPEND_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 the lists together.
+
+  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
index c8a878378d58724fa100c22da19a2b188f60478d..0b83191e06fe24bac0603865f91a45288a52e4ef 100644 (file)
@@ -94,6 +94,10 @@ ifeq ($(OSARCH),SunOS)
   ASTLINK=
 endif
 
+ifeq ($(GNU_LD),1)
+ASTLINK+=-Wl,--version-script,asterisk.exports
+endif
+
 editline/libedit.a:
        cd editline && test -f config.h || CFLAGS="$(PTHREAD_CFLAGS) $(subst $(ASTTOPDIR),../../,$(ASTCFLAGS:-Werror=))" LDFLAGS="$(ASTLDFLAGS)" ./configure --build=$(BUILD_PLATFORM) --host=$(HOST_PLATFORM) --with-ncurses=$(NCURSES_DIR) --with-curses=$(CURSES_DIR) --with-termcap=$(TERMCAP_DIR) --with-tinfo=$(TINFO_DIR)
        $(MAKE) -C editline libedit.a
@@ -133,20 +137,19 @@ else
   H323LDLIBS=
 endif
 
-asterisk: $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS)
+asterisk: $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) asterisk.exports
        @$(ASTTOPDIR)/build_tools/make_build_h > $(ASTTOPDIR)/include/asterisk/build.h.tmp
        @if cmp -s $(ASTTOPDIR)/include/asterisk/build.h.tmp $(ASTTOPDIR)/include/asterisk/build.h ; then echo ; else \
                mv $(ASTTOPDIR)/include/asterisk/build.h.tmp $(ASTTOPDIR)/include/asterisk/build.h ; \
        fi
        @rm -f $(ASTTOPDIR)/include/asterisk/build.h.tmp
        @$(CC) -c -o buildinfo.o $(ASTCFLAGS) buildinfo.c
-       $(ECHO_PREFIX) echo "   [LD] $^ -> $@"
+       $(ECHO_PREFIX) echo "   [LD] $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) -> $@"
 ifneq ($(findstring chan_h323,$(MENUSELECT_CHANNELS)),)
-       $(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS)
+       $(CMD_PREFIX) $(CC) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS)
 else
-       $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $^ buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS)
+       $(CMD_PREFIX) $(CXX) $(STATIC_BUILD) -o $@ $(ASTLINK) $(AST_EMBED_LDFLAGS) $(ASTLDFLAGS) $(H323LDFLAGS) $(OBJS) editline/libedit.a db1-ast/libdb1.a $(AST_EMBED_LDSCRIPTS) buildinfo.o $(AST_LIBS) $(AST_EMBED_LIBS) $(H323LDLIBS)
 endif
-       $(CMD_PREFIX) $(ASTTOPDIR)/build_tools/strip_nonapi $@ || rm $@
 
 clean::
        rm -f asterisk
diff --git a/main/asterisk.exports b/main/asterisk.exports
new file mode 100644 (file)
index 0000000..f18c0ff
--- /dev/null
@@ -0,0 +1,28 @@
+{
+       global:
+               ast_*;
+               _ast_*;
+               __ast_*;
+               pbx_*;
+               astman_*;
+               ao2_*;
+               __ao2_*;
+               option_debug;
+               option_verbose;
+               dahdi_chan_name;
+               dahdi_chan_name_len;
+               dahdi_chan_mode;
+               cid_di;
+               cid_dr;
+               clidsb;
+               MD5*;
+               sched_*;
+               io_*;
+               jb_*;
+               channelreloadreason2txt;
+               devstate2str;
+               manager_event;
+               dialed_interface_info;
+       local:
+               *;
+};
index 56ab75a21108d70906dacd44e875038049b248b2..8157c78cf297242f01539057fa903dfd83319090 100644 (file)
@@ -128,7 +128,7 @@ static inline struct astobj2 *INTERNAL_OBJ(void *user_data)
 #ifndef DEBUG_THREADS
 int ao2_lock(void *user_data)
 #else
-int _ao2_lock(void *user_data, const char *file, const char *func, int line, const char *var)
+int __ao2_lock(void *user_data, const char *file, const char *func, int line, const char *var)
 #endif
 {
        struct astobj2 *p = INTERNAL_OBJ(user_data);
@@ -150,7 +150,7 @@ int _ao2_lock(void *user_data, const char *file, const char *func, int line, con
 #ifndef DEBUG_THREADS
 int ao2_trylock(void *user_data)
 #else
-int _ao2_trylock(void *user_data, const char *file, const char *func, int line, const char *var)
+int __ao2_trylock(void *user_data, const char *file, const char *func, int line, const char *var)
 #endif
 {
        struct astobj2 *p = INTERNAL_OBJ(user_data);
@@ -177,7 +177,7 @@ int _ao2_trylock(void *user_data, const char *file, const char *func, int line,
 #ifndef DEBUG_THREADS
 int ao2_unlock(void *user_data)
 #else
-int _ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
+int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
 #endif
 {
        struct astobj2 *p = INTERNAL_OBJ(user_data);
index 1150c4c7fffa0af78218190879377a6998381bb6..8bcf81742b7eaed0961d0b258bc0814ebbd8c6f8 100644 (file)
@@ -168,15 +168,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);
                }
        }
index 4759421637f3785f342822f1bcb0151a69fae733..16fe23b24b66eb4562dabbbb741fa4f74a70af5d 100644 (file)
@@ -895,60 +895,90 @@ alertpipe_failed:
 }
 
 /*! \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;
+       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;
+
+       /* 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;
+               }
 
-       /* Build us a copy and free the original one */
-       if (!(f = ast_frdup(fin))) {
-               return -1;
+               AST_LIST_INSERT_TAIL(&frames, f, frame_list);
+               new_frames++;
+               if (f->frametype == AST_FRAME_VOICE) {
+                       new_voice_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);
+               while ((f = AST_LIST_REMOVE_HEAD(&frames, frame_list))) {
+                       ast_frfree(f);
+               }
                ast_channel_unlock(chan);
                return 0;
        }
 
        /* 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 {
-                       if (option_debug)
-                               ast_log(LOG_DEBUG, "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) {
-               ioctl(chan->timingfd, DAHDI_TIMERPING, &blah);
+               while (new_frames--) {
+                       ioctl(chan->timingfd, DAHDI_TIMERPING, &blah);
+               }
 #endif                         
        } else if (ast_test_flag(chan, AST_FLAG_BLOCKING)) {
                pthread_kill(chan->blocker, SIGURG);
@@ -961,12 +991,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 */
@@ -2150,7 +2180,7 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                        AST_LIST_REMOVE_CURRENT(&chan->readq, frame_list);
                        break;
                }
-               AST_LIST_TRAVERSE_SAFE_END
+               AST_LIST_TRAVERSE_SAFE_END;
                
                if (!f) {
                        /* There were no acceptable frames on the readq. */
@@ -2195,13 +2225,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;
                }
 
@@ -2410,8 +2441,26 @@ 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;
+                               }
+
+                               /* 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       */
@@ -2742,7 +2791,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 {
        int res = -1;
        int count = 0;
-       struct ast_frame *f = NULL, *f2 = NULL;
+       struct ast_frame *f = NULL;
 
        /*Deadlock avoidance*/
        while(ast_channel_trylock(chan)) {
@@ -2813,10 +2862,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);
+                       }
                }
                ast_clear_flag(chan, AST_FLAG_BLOCKING);
                ast_channel_unlock(chan);
@@ -2845,13 +2896,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 (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;
@@ -2864,37 +2908,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:
@@ -2911,13 +3000,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:
index faca5a9be9f078fcf5722fe3e9774adbbf225d61..43a7030f7b7ab9c43c0b35c5187557b60325d96f 100644 (file)
@@ -203,14 +203,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;
index 58e0762ebb4914c93f4582c458f1eb41850d5b4f..253bc053648d3036f60f6979298b5b607148a60d 100644 (file)
@@ -47,11 +47,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);
 
@@ -291,7 +286,7 @@ struct ast_frame *ast_smoother_read(struct ast_smoother *s)
                memmove(s->data, s->data + len, s->len);
                if (!ast_tvzero(s->delivery)) {
                        /* If we have delivery time, increment it, otherwise, leave it at 0 */
-                       s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
+                       s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, ast_format_rate(s->format)));
                }
        }
        /* Return frame */
@@ -328,12 +323,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;
 }
@@ -351,7 +340,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);
@@ -370,8 +359,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;
@@ -385,19 +374,25 @@ void ast_frame_free(struct ast_frame *fr, int cache)
        }
        if (fr->mallocd & AST_MALLOCD_SRC) {
                if (fr->src)
-                       free((char *)fr->src);
+                       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                 
                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).
@@ -408,19 +403,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)) {
@@ -428,26 +433,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)
-                                       free(out);
-                               return NULL;
+       if (!(fr->mallocd & AST_MALLOCD_SRC) && fr->src) {
+               if (!(out->src = ast_strdup(fr->src))) {
+                       if (out != fr) {
+                               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) {
                                free((void *) out->src);
-                       if (out != fr)
+                       }
+                       if (out != fr) {
                                free(out);
+                       }
                        return NULL;
                }
                newdata += AST_FRIENDLY_OFFSET;
@@ -455,6 +468,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;
+               fr->data = NULL;
+               fr->mallocd &= ~AST_MALLOCD_DATA;
        }
 
        out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
@@ -497,7 +514,7 @@ struct ast_frame *ast_frdup(const struct ast_frame *f)
                                break;
                        }
                }
-               AST_LIST_TRAVERSE_SAFE_END
+               AST_LIST_TRAVERSE_SAFE_END;
        }
 #endif
 
@@ -970,29 +987,6 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
 }
 
 
-#ifdef TRACE_FRAMES
-static int show_frame_stats(int fd, int argc, char *argv[])
-{
-       struct ast_frame *f;
-       int x=1;
-       if (argc != 4)
-               return RESULT_SHOWUSAGE;
-       AST_LIST_LOCK(&headerlist);
-       ast_cli(fd, "     Framer Statistics     \n");
-       ast_cli(fd, "---------------------------\n");
-       ast_cli(fd, "Total allocated headers: %d\n", headers);
-       ast_cli(fd, "Queue Dump:\n");
-       AST_LIST_TRAVERSE(&headerlist, f, frame_list)
-               ast_cli(fd, "%d.  Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
-       AST_LIST_UNLOCK(&headerlist);
-       return RESULT_SUCCESS;
-}
-
-static char frame_stats_usage[] =
-"Usage: core show frame stats\n"
-"       Displays debugging statistics from framer\n";
-#endif
-
 /* Builtin Asterisk CLI-commands for debugging */
 static struct ast_cli_entry cli_show_codecs = {
        { "show", "codecs", NULL },
@@ -1019,13 +1013,6 @@ static struct ast_cli_entry cli_show_codec = {
        show_codec_n_deprecated, NULL,
        NULL };
 
-#ifdef TRACE_FRAMES
-static struct ast_cli_entry cli_show_frame_stats = {
-       { "show", "frame", "stats", NULL },
-       show_frame_stats, NULL,
-       NULL };
-#endif
-
 static struct ast_cli_entry my_clis[] = {
        { { "core", "show", "codecs", NULL },
        show_codecs, "Displays a list of codecs",
@@ -1046,12 +1033,6 @@ static struct ast_cli_entry my_clis[] = {
        { { "core", "show", "codec", NULL },
        show_codec_n, "Shows a specific codec",
        frame_show_codec_n_usage, NULL, &cli_show_codec },
-
-#ifdef TRACE_FRAMES
-       { { "core", "show", "frame", "stats", NULL },
-       show_frame_stats, "Shows frame statistics",
-       frame_stats_usage, NULL, &cli_show_frame_stats },
-#endif
 };
 
 int init_framer(void)
index 212edef92e42a933f055c35ec0c4ec99b777a6a7..b848fb0740282bba3a84b91d6443d32129e4e8a8 100644 (file)
@@ -57,7 +57,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
@@ -84,27 +84,33 @@ int ast_slinfactory_feed(struct ast_slinfactory *sf, struct ast_frame *f)
                        }
                }
 
-               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 (!(duped_frame = ast_frdup(f)))
                        return 0;
        }
 
-       x = 0;
-       AST_LIST_TRAVERSE(&sf->queue, frame_ptr, frame_list)
+       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;
 }
index 790ba6e864408e3a2f66bbf3903e560ba7613b0d..f680cd76d8bb6cee34f0f5a71c0ff08658068133 100644 (file)
@@ -43,6 +43,8 @@ GC_LDFLAGS=@GC_LDFLAGS@
 PTHREAD_CFLAGS=@PTHREAD_CFLAGS@
 PTHREAD_LIBS=@PTHREAD_LIBS@
 
+GNU_LD=@GNU_LD@
+
 prefix = @prefix@
 exec_prefix = @exec_prefix@
 
diff --git a/res/res_adsi.exports b/res/res_adsi.exports
new file mode 100644 (file)
index 0000000..a4119dc
--- /dev/null
@@ -0,0 +1,33 @@
+{
+       global:
+               ast_adsi_available;
+               ast_adsi_begin_download;
+               ast_adsi_channel_restore;
+               ast_adsi_clear_screen;
+               ast_adsi_clear_soft_keys;
+               ast_adsi_connect_session;
+               ast_adsi_data_mode;
+               ast_adsi_disconnect_session;
+               ast_adsi_display;
+               ast_adsi_download_connect;
+               ast_adsi_download_disconnect;
+               ast_adsi_end_download;
+               ast_adsi_get_cpeid;
+               ast_adsi_get_cpeinfo;
+               ast_adsi_input_control;
+               ast_adsi_input_format;
+               ast_adsi_load_session;
+               ast_adsi_load_soft_key;
+               ast_adsi_print;
+               ast_adsi_query_cpeid;
+               ast_adsi_query_cpeinfo;
+               ast_adsi_read_encoded_dtmf;
+               ast_adsi_set_keys;
+               ast_adsi_set_line;
+               ast_adsi_transmit_message;
+               ast_adsi_transmit_message_full;
+               ast_adsi_unload_session;
+               ast_adsi_voice_mode;
+       local:
+               *;
+};
diff --git a/res/res_agi.exports b/res/res_agi.exports
new file mode 100644 (file)
index 0000000..e1b1196
--- /dev/null
@@ -0,0 +1,7 @@
+{
+       global:
+               ast_agi_register;
+               ast_agi_unregister;
+       local:
+               *;
+};
index 7f11b5db356123b6bddd8404d6a1dd4cb05e00fe..5c3c1f6693d88317f07b4bafb2e2511f62b71c48 100644 (file)
@@ -558,7 +558,7 @@ static int load_module (void)
        return 0;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "ODBC Configuration",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC Configuration",
                .load = load_module,
                .unload = unload_module,
                );
index 494497033c61fe9940cccd335d52d04bf3f21280..986223480488e2512895ec51a32833816d6bcc20 100644 (file)
@@ -835,7 +835,7 @@ static int realtime_pgsql_status(int fd, int argc, char **argv)
 }
 
 /* needs usecount semantics defined */
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "PostgreSQL RealTime Configuration Driver",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "PostgreSQL RealTime Configuration Driver",
                .load = load_module,
                .unload = unload_module,
                .reload = reload
index c2c33d0158afaeed66b9406b97353347f77e83a2..8fd78c498af68e745f08c7cfe470d41d7df7385b 100644 (file)
@@ -624,7 +624,7 @@ static int unload_module(void)
 }
 
 /* needs usecount semantics defined */
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Cryptographic Digital Signatures",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Cryptographic Digital Signatures",
                .load = load_module,
                .unload = unload_module,
                .reload = reload
diff --git a/res/res_features.exports b/res/res_features.exports
new file mode 100644 (file)
index 0000000..344a652
--- /dev/null
@@ -0,0 +1,13 @@
+{
+       global:
+               ast_bridge_call;
+               ast_masq_park_call;
+               ast_park_call;
+               ast_parking_ext;
+               ast_pickup_call;
+               ast_pickup_ext;
+               ast_register_feature;
+               ast_unregister_feature;
+       local:
+               *;
+};
index 9bff10b76e8fca6aa4831f6b0110f5fa779d7a78..b1c948c95cf7e4fe6708259373ad232b25e1569a 100644 (file)
@@ -399,7 +399,7 @@ static int reload(void)
        return ind_load_module();
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Indications Resource",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Indications Resource",
                .load = load_module,
                .unload = unload_module,
                .reload = reload,
diff --git a/res/res_jabber.exports b/res/res_jabber.exports
new file mode 100644 (file)
index 0000000..8df1fee
--- /dev/null
@@ -0,0 +1,13 @@
+{
+       global:
+               ast_aji_create_chat;
+               ast_aji_disconnect;
+               ast_aji_get_client;
+               ast_aji_get_clients;
+               ast_aji_increment_mid;
+               ast_aji_invite_chat;
+               ast_aji_join_chat;
+               ast_aji_send;
+       local:
+               *;
+};
diff --git a/res/res_monitor.exports b/res/res_monitor.exports
new file mode 100644 (file)
index 0000000..4352dc8
--- /dev/null
@@ -0,0 +1,11 @@
+{
+       global:
+               ast_monitor_change_fname;
+               ast_monitor_pause;
+               ast_monitor_setjoinfiles;
+               ast_monitor_start;
+               ast_monitor_stop;
+               ast_monitor_unpause;
+       local:
+               *;
+};
index cd8bb3e1007c6df1420cd64a0ed7a50268e393c4..95fe16ec2a0f3dc166db3d967c51a96615c65f8a 100644 (file)
@@ -1486,7 +1486,7 @@ static int unload_module(void)
        return res;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Music On Hold Resource",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Music On Hold Resource",
        .load = load_module,
        .unload = unload_module,
        .reload = reload,
diff --git a/res/res_odbc.exports b/res/res_odbc.exports
new file mode 100644 (file)
index 0000000..1e38d49
--- /dev/null
@@ -0,0 +1,11 @@
+{
+       global:
+               ast_odbc_backslash_is_escape;
+               ast_odbc_prepare_and_execute;
+               ast_odbc_release_obj;
+               ast_odbc_request_obj;
+               ast_odbc_sanity_check;
+               ast_odbc_smart_execute;
+       local:
+               *;
+};
diff --git a/res/res_smdi.exports b/res/res_smdi.exports
new file mode 100644 (file)
index 0000000..7fe3edf
--- /dev/null
@@ -0,0 +1,18 @@
+{
+       global:
+               ast_smdi_interface_find;
+               ast_smdi_interface_unref;
+               ast_smdi_md_message_destroy;
+               ast_smdi_md_message_pop;
+               ast_smdi_md_message_putback;
+               ast_smdi_md_message_wait;
+               ast_smdi_mwi_message_destroy;
+               ast_smdi_mwi_message_pop;
+               ast_smdi_mwi_message_putback;
+               ast_smdi_mwi_message_wait;
+               ast_smdi_mwi_message_wait_station;
+               ast_smdi_mwi_set;
+               ast_smdi_mwi_unset;
+       local:
+               *;
+};
index 6bbf231718935bc0c8f738e881dbb7cc7b54b2c2..5ec0419ade91465c3f64159bafec2d73ac1d5fe6 100644 (file)
@@ -109,7 +109,7 @@ static int unload_module(void)
        return ((thread != AST_PTHREADT_NULL) ? pthread_join(thread, NULL) : 0);
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "SNMP [Sub]Agent for Asterisk",
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "SNMP [Sub]Agent for Asterisk",
                .load = load_module,
                .unload = unload_module,
                );
diff --git a/res/res_speech.exports b/res/res_speech.exports
new file mode 100644 (file)
index 0000000..2266607
--- /dev/null
@@ -0,0 +1,21 @@
+{
+       global:
+               ast_speech_change;
+               ast_speech_change_results_type;
+               ast_speech_change_state;
+               ast_speech_destroy;
+               ast_speech_dtmf;
+               ast_speech_grammar_activate;
+               ast_speech_grammar_deactivate;
+               ast_speech_grammar_load;
+               ast_speech_grammar_unload;
+               ast_speech_new;
+               ast_speech_register;
+               ast_speech_results_free;
+               ast_speech_results_get;
+               ast_speech_start;
+               ast_speech_unregister;
+               ast_speech_write;
+       local:
+               *;
+};