This mod via bug 7531
[asterisk/asterisk.git] / main / channel.c
index 24fe88a..ace4a41 100644 (file)
@@ -29,6 +29,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <string.h>
 #include <sys/time.h>
 #include <signal.h>
 #include <string.h>
 #include <sys/time.h>
 #include <signal.h>
@@ -84,6 +85,7 @@ struct ast_channel_whisper_buffer {
        ast_mutex_t lock;
        struct ast_slinfactory sf;
        unsigned int original_format;
        ast_mutex_t lock;
        struct ast_slinfactory sf;
        unsigned int original_format;
+       struct ast_trans_pvt *path;
 };
 
 /* uncomment if you have problems with 'monitoring' synchronized files */
 };
 
 /* uncomment if you have problems with 'monitoring' synchronized files */
@@ -99,7 +101,7 @@ static int uniqueint = 0;
 
 unsigned long global_fin = 0, global_fout = 0;
 
 
 unsigned long global_fin = 0, global_fout = 0;
 
-AST_THREADSTORAGE(state2str_threadbuf, state2str_threadbuf_init);
+AST_THREADSTORAGE(state2str_threadbuf);
 #define STATE2STR_BUFSIZE   32
 
 /* XXX 100ms ... this won't work with wideband support */
 #define STATE2STR_BUFSIZE   32
 
 /* XXX 100ms ... this won't work with wideband support */
@@ -288,18 +290,22 @@ static char *complete_channeltypes(const char *line, const char *word, int pos,
 }
 
 static char show_channeltypes_usage[] =
 }
 
 static char show_channeltypes_usage[] =
-"Usage: show channeltypes\n"
-"       Shows available channel types registered in your Asterisk server.\n";
+"Usage: core show channeltypes\n"
+"       Lists available channel types registered in your Asterisk server.\n";
 
 static char show_channeltype_usage[] =
 
 static char show_channeltype_usage[] =
-"Usage: show channeltype <name>\n"
+"Usage: core show channeltype <name>\n"
 "      Show details about the specified channel type, <name>.\n";
 
 "      Show details about the specified channel type, <name>.\n";
 
-static struct ast_cli_entry cli_show_channeltypes =
-       { { "show", "channeltypes", NULL }, show_channeltypes, "Show available channel types", show_channeltypes_usage };
+static struct ast_cli_entry cli_channel[] = {
+       { { "core", "show", "channeltypes", NULL },
+       show_channeltypes, "List available channel types",
+       show_channeltypes_usage },
 
 
-static struct ast_cli_entry cli_show_channeltype =
-       { { "show", "channeltype", NULL }, show_channeltype, "Give more details on that channel type", show_channeltype_usage, complete_channeltypes };
+       { { "core", "show", "channeltype", NULL },
+       show_channeltype, "Give more details on that channel type",
+       show_channeltype_usage, complete_channeltypes },
+};
 
 /*! \brief Checks to see if a channel is needing hang up */
 int ast_check_hangup(struct ast_channel *chan)
 
 /*! \brief Checks to see if a channel is needing hang up */
 int ast_check_hangup(struct ast_channel *chan)
@@ -325,6 +331,21 @@ static int ast_check_hangup_locked(struct ast_channel *chan)
        return res;
 }
 
        return res;
 }
 
+/*! \brief printf the string into a correctly sized mallocd buffer, and return the buffer */
+char *ast_safe_string_alloc(const char *fmt, ...)
+{
+       char *b2,buf[1];
+       int len;
+
+       va_list args;
+       va_start(args, fmt);
+       len = vsnprintf(buf, 1, fmt, args);
+       b2 = ast_malloc(len+1);
+       vsnprintf(b2, len+1,  fmt, args);
+       va_end(args);
+       return b2;
+}
+
 /*! \brief Initiate system shutdown */
 void ast_begin_shutdown(int hangup)
 {
 /*! \brief Initiate system shutdown */
 void ast_begin_shutdown(int hangup)
 {
@@ -603,12 +624,13 @@ static const struct ast_channel_tech null_tech = {
 };
 
 /*! \brief Create a new channel structure */
 };
 
 /*! \brief Create a new channel structure */
-struct ast_channel *ast_channel_alloc(int needqueue)
+struct ast_channel *ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *name_fmt, ...)
 {
        struct ast_channel *tmp;
        int x;
        int flags;
        struct varshead *headp;
 {
        struct ast_channel *tmp;
        int x;
        int flags;
        struct varshead *headp;
+       va_list ap1, ap2;
 
        /* If shutting down, don't allocate any new channels */
        if (shutting_down) {
 
        /* If shutting down, don't allocate any new channels */
        if (shutting_down) {
@@ -649,7 +671,7 @@ struct ast_channel *ast_channel_alloc(int needqueue)
        if (needqueue) {
                if (pipe(tmp->alertpipe)) {
                        ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
        if (needqueue) {
                if (pipe(tmp->alertpipe)) {
                        ast_log(LOG_WARNING, "Channel allocation failed: Can't create alert pipe!\n");
-                       ast_string_field_free_all(tmp);
+                       ast_string_field_free_pools(tmp);
                        free(tmp);
                        return NULL;
                } else {
                        free(tmp);
                        return NULL;
                } else {
@@ -666,10 +688,10 @@ struct ast_channel *ast_channel_alloc(int needqueue)
        /* And timing pipe */
        tmp->fds[AST_TIMING_FD] = tmp->timingfd;
        ast_string_field_set(tmp, name, "**Unknown**");
        /* And timing pipe */
        tmp->fds[AST_TIMING_FD] = tmp->timingfd;
        ast_string_field_set(tmp, name, "**Unknown**");
-       
+
        /* Initial state */
        /* Initial state */
-       tmp->_state = AST_STATE_DOWN;
-       
+       tmp->_state = state;
+
        tmp->streamid = -1;
        
        tmp->fin = global_fin;
        tmp->streamid = -1;
        
        tmp->fin = global_fin;
@@ -683,6 +705,37 @@ struct ast_channel *ast_channel_alloc(int needqueue)
                        (long) time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
        }
 
                        (long) time(NULL), ast_atomic_fetchadd_int(&uniqueint, 1));
        }
 
+       if (!ast_strlen_zero(name_fmt)) {
+               /* Almost every channel is calling this function, and setting the name via the ast_string_field_build() call.
+                * And they all use slightly different formats for their name string.
+                * This means, to set the name here, we have to accept variable args, and call the string_field_build from here.
+                * This means, that the stringfields must have a routine that takes the va_lists directly, and 
+                * uses them to build the string, instead of forming the va_lists internally from the vararg ... list.
+                * This new function was written so this can be accomplished.
+                */
+               va_start(ap1, name_fmt);
+               va_start(ap2, name_fmt);
+               ast_string_field_build_va(tmp, name, name_fmt, ap1, ap2);
+               va_end(ap1);
+               va_end(ap2);
+
+               /* and now, since the channel structure is built, and has its name, let's call the
+                * manager event generator with this Newchannel event. This is the proper and correct
+                * place to make this call, but you sure do have to pass a lot of data into this func
+                * to do it here!
+                */
+               manager_event(EVENT_FLAG_CALL, "Newchannel",
+                             "Channel: %s\r\n"
+                             "State: %s\r\n"
+                             "CallerIDNum: %s\r\n"
+                             "CallerIDName: %s\r\n"
+                             "Uniqueid: %s\r\n",
+                             tmp->name, ast_state2str(state),
+                             S_OR(cid_num, "<unknown>"),
+                             S_OR(cid_name, "<unknown>"),
+                             tmp->uniqueid);
+       }
+       
        headp = &tmp->varshead;
        AST_LIST_HEAD_INIT_NOLOCK(headp);
        
        headp = &tmp->varshead;
        AST_LIST_HEAD_INIT_NOLOCK(headp);
        
@@ -740,7 +793,8 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin)
                        ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
                        CRASH;
                } else {
                        ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
                        CRASH;
                } else {
-                       ast_log(LOG_DEBUG, "Dropping voice to exceptionally long queue on %s\n", chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Dropping voice to exceptionally long queue on %s\n", chan->name);
                        ast_frfree(f);
                        ast_channel_unlock(chan);
                        return 0;
                        ast_frfree(f);
                        ast_channel_unlock(chan);
                        return 0;
@@ -876,8 +930,10 @@ static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
                /* exit if chan not found or mutex acquired successfully */
                /* this is slightly unsafe, as we _should_ hold the lock to access c->name */
                done = c == NULL || ast_channel_trylock(c) == 0;
                /* exit if chan not found or mutex acquired successfully */
                /* this is slightly unsafe, as we _should_ hold the lock to access c->name */
                done = c == NULL || ast_channel_trylock(c) == 0;
-               if (!done)
-                       ast_log(LOG_DEBUG, "Avoiding %s for channel '%p'\n", msg, c);
+               if (!done) {
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Avoiding %s for channel '%p'\n", msg, c);
+               }
                AST_LIST_UNLOCK(&channels);
                if (done)
                        return c;
                AST_LIST_UNLOCK(&channels);
                if (done)
                        return c;
@@ -887,8 +943,9 @@ static struct ast_channel *channel_find_locked(const struct ast_channel *prev,
         * c is surely not null, but we don't have the lock so cannot
         * access c->name
         */
         * c is surely not null, but we don't have the lock so cannot
         * access c->name
         */
-       ast_log(LOG_DEBUG, "Failure, could not lock '%p' after %d retries!\n",
-               c, retries);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Failure, could not lock '%p' after %d retries!\n",
+                       c, retries);
 
        return NULL;
 }
 
        return NULL;
 }
@@ -1046,7 +1103,7 @@ void ast_channel_free(struct ast_channel *chan)
        /* Destroy the jitterbuffer */
        ast_jb_destroy(chan);
 
        /* Destroy the jitterbuffer */
        ast_jb_destroy(chan);
 
-       ast_string_field_free_all(chan);
+       ast_string_field_free_pools(chan);
        free(chan);
        AST_LIST_UNLOCK(&channels);
 
        free(chan);
        AST_LIST_UNLOCK(&channels);
 
@@ -1197,8 +1254,9 @@ int ast_channel_spy_add(struct ast_channel *chan, struct ast_channel_spy *spy)
                ast_clear_flag(spy, CHANSPY_TRIGGER_WRITE);
        }
 
                ast_clear_flag(spy, CHANSPY_TRIGGER_WRITE);
        }
 
-       ast_log(LOG_DEBUG, "Spy %s added to channel %s\n",
-               spy->type, chan->name);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Spy %s added to channel %s\n",
+                       spy->type, chan->name);
 
        return 0;
 }
 
        return 0;
 }
@@ -1233,7 +1291,8 @@ static void spy_detach(struct ast_channel_spy *spy, struct ast_channel *chan)
        }
 
        /* Print it out while we still have a lock so the structure can't go away (if signalled above) */
        }
 
        /* Print it out while we still have a lock so the structure can't go away (if signalled above) */
-       ast_log(LOG_DEBUG, "Spy %s removed from channel %s\n", spy->type, chan->name);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Spy %s removed from channel %s\n", spy->type, chan->name);
 
        ast_mutex_unlock(&spy->lock);
 
 
        ast_mutex_unlock(&spy->lock);
 
@@ -1378,8 +1437,9 @@ static void queue_frame_to_spies(struct ast_channel *chan, struct ast_frame *f,
                                        trans->path = NULL;
                                }
                                if (!trans->path) {
                                        trans->path = NULL;
                                }
                                if (!trans->path) {
-                                       ast_log(LOG_DEBUG, "Building translator from %s to SLINEAR for spies on channel %s\n",
-                                               ast_getformatname(f->subclass), chan->name);
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG, "Building translator from %s to SLINEAR for spies on channel %s\n",
+                                                       ast_getformatname(f->subclass), chan->name);
                                        if ((trans->path = ast_translator_build_path(AST_FORMAT_SLINEAR, f->subclass)) == NULL) {
                                                ast_log(LOG_WARNING, "Cannot build a path from %s to %s\n",
                                                        ast_getformatname(f->subclass), ast_getformatname(AST_FORMAT_SLINEAR));
                                        if ((trans->path = ast_translator_build_path(AST_FORMAT_SLINEAR, f->subclass)) == NULL) {
                                                ast_log(LOG_WARNING, "Cannot build a path from %s to %s\n",
                                                        ast_getformatname(f->subclass), ast_getformatname(AST_FORMAT_SLINEAR));
@@ -1623,7 +1683,8 @@ static int generator_force(void *data)
        res = generate(chan, tmp, 0, 160);
        chan->generatordata = tmp;
        if (res) {
        res = generate(chan, tmp, 0, 160);
        chan->generatordata = tmp;
        if (res) {
-               ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
                ast_deactivate_generator(chan);
        }
        return 0;
                ast_deactivate_generator(chan);
        }
        return 0;
@@ -1842,7 +1903,8 @@ int ast_settimeout(struct ast_channel *c, int samples, int (*func)(void *data),
                        samples = 0;
                        data = 0;
                }
                        samples = 0;
                        data = 0;
                }
-               ast_log(LOG_DEBUG, "Scheduling timer at %d sample intervals\n", samples);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Scheduling timer at %d sample intervals\n", samples);
                res = ioctl(c->timingfd, ZT_TIMERCONFIG, &samples);
                c->timingfunc = func;
                c->timingdata = data;
                res = ioctl(c->timingfd, ZT_TIMERCONFIG, &samples);
                c->timingfunc = func;
                c->timingdata = data;
@@ -2047,11 +2109,13 @@ static struct ast_frame *__ast_read(struct ast_channel *chan, int dropaudio)
                case AST_FRAME_CONTROL:
                        if (f->subclass == AST_CONTROL_ANSWER) {
                                if (!ast_test_flag(chan, AST_FLAG_OUTGOING)) {
                case AST_FRAME_CONTROL:
                        if (f->subclass == AST_CONTROL_ANSWER) {
                                if (!ast_test_flag(chan, AST_FLAG_OUTGOING)) {
-                                       ast_log(LOG_DEBUG, "Ignoring answer on an inbound call!\n");
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG, "Ignoring answer on an inbound call!\n");
                                        ast_frfree(f);
                                        f = &ast_null_frame;
                                } else if (prestate == AST_STATE_UP) {
                                        ast_frfree(f);
                                        f = &ast_null_frame;
                                } else if (prestate == AST_STATE_UP) {
-                                       ast_log(LOG_DEBUG, "Dropping duplicate answer!\n");
+                                       if (option_debug)
+                                               ast_log(LOG_DEBUG, "Dropping duplicate answer!\n");
                                        ast_frfree(f);
                                        f = &ast_null_frame;
                                } else {
                                        ast_frfree(f);
                                        f = &ast_null_frame;
                                } else {
@@ -2261,7 +2325,8 @@ int ast_indicate_data(struct ast_channel *chan, int condition, const void *data,
                                break;
                        }
                        if (ts && ts->data[0]) {
                                break;
                        }
                        if (ts && ts->data[0]) {
-                               ast_log(LOG_DEBUG, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
                                ast_playtones_start(chan,0,ts->data, 1);
                                res = 0;
                        } else if (condition == AST_CONTROL_PROGRESS) {
                                ast_playtones_start(chan,0,ts->data, 1);
                                res = 0;
                        } else if (condition == AST_CONTROL_PROGRESS) {
@@ -2374,7 +2439,8 @@ int ast_senddigit_begin(struct ast_channel *chan, char digit)
                        ast_playtones_start(chan, 0, dtmf_tones[15], 0);
                else {
                        /* not handled */
                        ast_playtones_start(chan, 0, dtmf_tones[15], 0);
                else {
                        /* not handled */
-                       ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, chan->name);
                }
        }
 
                }
        }
 
@@ -2410,7 +2476,8 @@ int ast_prod(struct ast_channel *chan)
 
        /* Send an empty audio frame to get things moving */
        if (chan->_state != AST_STATE_UP) {
 
        /* Send an empty audio frame to get things moving */
        if (chan->_state != AST_STATE_UP) {
-               ast_log(LOG_DEBUG, "Prodding channel '%s'\n", chan->name);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Prodding channel '%s'\n", chan->name);
                a.subclass = chan->rawwriteformat;
                a.data = nothing + AST_FRIENDLY_OFFSET;
                a.src = "ast_prod";
                a.subclass = chan->rawwriteformat;
                a.data = nothing + AST_FRIENDLY_OFFSET;
                a.src = "ast_prod";
@@ -2502,66 +2569,93 @@ 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->tech->write == NULL)
                        break;  /*! \todo XXX should return 0 maybe ? */
 
-               /* Bypass translator if we're writing format in the raw write format.  This
-                  allows mixing of native / non-native formats */
-               if (fr->subclass == chan->rawwriteformat)
-                       f = fr;
-               else
-                       f = (chan->writetrans) ? ast_translate(chan->writetrans, fr, 0) : fr;
+               /* If someone is whispering on this channel then we must ensure that we are always getting signed linear frames */
+               if (ast_test_flag(chan, AST_FLAG_WHISPER)) {
+                       if (fr->subclass == AST_FORMAT_SLINEAR)
+                               f = fr;
+                       else {
+                               ast_mutex_lock(&chan->whisper->lock);
+                               if (chan->writeformat != AST_FORMAT_SLINEAR) {
+                                       /* Rebuild the translation path and set our write format back to signed linear */
+                                       chan->whisper->original_format = chan->writeformat;
+                                       ast_set_write_format(chan, AST_FORMAT_SLINEAR);
+                                       if (chan->whisper->path)
+                                               ast_translator_free_path(chan->whisper->path);
+                                       chan->whisper->path = ast_translator_build_path(AST_FORMAT_SLINEAR, chan->whisper->original_format);
+                               }
+                               /* Translate frame using the above translation path */
+                               f = (chan->whisper->path) ? ast_translate(chan->whisper->path, fr, 0) : fr;
+                               ast_mutex_unlock(&chan->whisper->lock);
+                       }
+               } else {
+                       /* 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;
+                       else
+                               f = (chan->writetrans) ? ast_translate(chan->writetrans, fr, 0) : fr;
+               }
+
+               /* If we have no frame of audio, then we have to bail out */
                if (f == NULL) {
                        res = 0;
                if (f == NULL) {
                        res = 0;
-               } else {
-                       if (chan->spies)
-                               queue_frame_to_spies(chan, f, SPY_WRITE);
+                       break;
+               }
+
+               /* If spies are on the channel then queue the frame out to them */
+               if (chan->spies)
+                       queue_frame_to_spies(chan, f, SPY_WRITE);
 
 
-                       if (chan->monitor && chan->monitor->write_stream) {
-                               /* XXX must explain this code */
+               /* If Monitor is running on this channel, then we have to write frames out there too */
+               if (chan->monitor && chan->monitor->write_stream) {
+                       /* XXX must explain this code */
 #ifndef MONITOR_CONSTANT_DELAY
 #ifndef MONITOR_CONSTANT_DELAY
-                               int jump = chan->insmpl - chan->outsmpl - 4 * f->samples;
-                               if (jump >= 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 + 4 * f->samples;
-                               } else
-                                       chan->outsmpl += f->samples;
+                       int jump = chan->insmpl - chan->outsmpl - 4 * f->samples;
+                       if (jump >= 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 + 4 * f->samples;
+                       } else
+                               chan->outsmpl += f->samples;
 #else
 #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 - 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;
 #endif
 #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, f) < 0)
+                                       ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
                        }
                        }
+               }
 
 
-                       if (ast_test_flag(chan, AST_FLAG_WHISPER)) {
-                               /* frame is assumed to be in SLINEAR, since that is
-                                  required for whisper mode */
-                               ast_frame_adjust_volume(f, -2);
-                               if (ast_slinfactory_available(&chan->whisper->sf) >= f->samples) {
-                                       short buf[f->samples];
-                                       struct ast_frame whisper = {
-                                               .frametype = AST_FRAME_VOICE,
-                                               .subclass = AST_FORMAT_SLINEAR,
-                                               .data = buf,
-                                               .datalen = sizeof(buf),
-                                               .samples = f->samples,
-                                       };
-
-                                       ast_mutex_lock(&chan->whisper->lock);
-                                       if (ast_slinfactory_read(&chan->whisper->sf, buf, f->samples))
-                                               ast_frame_slinear_sum(f, &whisper);
-                                       ast_mutex_unlock(&chan->whisper->lock);
-                               }
+               /* Finally the good part! Write this out to the channel */
+               if (ast_test_flag(chan, AST_FLAG_WHISPER)) {
+                       /* frame is assumed to be in SLINEAR, since that is
+                          required for whisper mode */
+                       ast_frame_adjust_volume(f, -2);
+                       if (ast_slinfactory_available(&chan->whisper->sf) >= f->samples) {
+                               short buf[f->samples];
+                               struct ast_frame whisper = {
+                                       .frametype = AST_FRAME_VOICE,
+                                       .subclass = AST_FORMAT_SLINEAR,
+                                       .data = buf,
+                                       .datalen = sizeof(buf),
+                                       .samples = f->samples,
+                               };
+                               
+                               ast_mutex_lock(&chan->whisper->lock);
+                               if (ast_slinfactory_read(&chan->whisper->sf, buf, f->samples))
+                                       ast_frame_slinear_sum(f, &whisper);
+                               ast_mutex_unlock(&chan->whisper->lock);
                        }
                        }
-
-                       res = chan->tech->write(chan, f);
+                       /* and now put it through the regular translator */
+                       f = (chan->writetrans) ? ast_translate(chan->writetrans, f, 0) : f;
                }
                }
+               
+               res = chan->tech->write(chan, f);
                break;
        case AST_FRAME_NULL:
        case AST_FRAME_IAX:
                break;
        case AST_FRAME_NULL:
        case AST_FRAME_IAX:
@@ -2569,7 +2663,10 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                res = 0;
                break;
        default:
                res = 0;
                break;
        default:
-               res = chan->tech->write(chan, f);
+               /* At this point, fr is the incoming frame and f is NULL.  Channels do
+                * not expect to get NULL as a frame pointer and will segfault.  Hence,
+                * we output the original frame passed in. */
+               res = chan->tech->write(chan, fr);
                break;
        }
 
                break;
        }
 
@@ -2809,19 +2906,8 @@ struct ast_channel *ast_request(const char *type, int format, void *data, int *c
                
                if (!(c = chan->tech->requester(type, capabilities | videoformat, data, cause)))
                        return NULL;
                
                if (!(c = chan->tech->requester(type, capabilities | videoformat, data, cause)))
                        return NULL;
-
-               if (c->_state == AST_STATE_DOWN) {
-                       manager_event(EVENT_FLAG_CALL, "Newchannel",
-                                     "Channel: %s\r\n"
-                                     "State: %s\r\n"
-                                     "CallerID: %s\r\n"
-                                     "CallerIDName: %s\r\n"
-                                     "Uniqueid: %s\r\n",
-                                     c->name, ast_state2str(c->_state),
-                                     S_OR(c->cid.cid_num, "<unknown>"),
-                                     S_OR(c->cid.cid_name, "<unknown>"),
-                                     c->uniqueid);
-               }
+               
+               /* no need to generate a Newchannel event here; it is done in the channel_alloc call */
                return c;
        }
 
                return c;
        }
 
@@ -3034,8 +3120,9 @@ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clo
                return -1;
        }
 
                return -1;
        }
 
-       ast_log(LOG_DEBUG, "Planning to masquerade channel %s into the structure of %s\n",
-               clone->name, original->name);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Planning to masquerade channel %s into the structure of %s\n",
+                       clone->name, original->name);
        if (original->masq) {
                ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
                        original->masq->name, original->name);
        if (original->masq) {
                ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
                        original->masq->name, original->name);
@@ -3047,7 +3134,8 @@ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clo
                clone->masqr = original;
                ast_queue_frame(original, &ast_null_frame);
                ast_queue_frame(clone, &ast_null_frame);
                clone->masqr = original;
                ast_queue_frame(original, &ast_null_frame);
                ast_queue_frame(clone, &ast_null_frame);
-               ast_log(LOG_DEBUG, "Done planning to masquerade channel %s into the structure of %s\n", clone->name, original->name);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Done planning to masquerade channel %s into the structure of %s\n", clone->name, original->name);
                res = 0;
        }
 
                res = 0;
        }
 
@@ -3167,6 +3255,9 @@ int ast_do_masquerade(struct ast_channel *original)
                ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
                        clone->name, clone->_state, original->name, original->_state);
 
                ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
                        clone->name, clone->_state, original->name, original->_state);
 
+       manager_event(EVENT_FLAG_CALL, "Masquerade", "Clone: %s\r\nCloneState: %s\r\nOriginal: %s\r\nOriginalState: %s\r\n",
+                     clone->name, ast_state2str(clone->_state), original->name, ast_state2str(original->_state));
+
        /* XXX This is a seriously wacked out operation.  We're essentially putting the guts of
           the clone channel into the original channel.  Start by killing off the original
           channel's backend.   I'm not sure we're going to keep this function, because
        /* XXX This is a seriously wacked out operation.  We're essentially putting the guts of
           the clone channel into the original channel.  Start by killing off the original
           channel's backend.   I'm not sure we're going to keep this function, because
@@ -3406,7 +3497,8 @@ int ast_do_masquerade(struct ast_channel *original)
                        );
                ast_channel_free(clone);
        } else {
                        );
                ast_channel_free(clone);
        } else {
-               ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
                ast_set_flag(clone, AST_FLAG_ZOMBIE);
                ast_queue_frame(clone, &ast_null_frame);
                ast_channel_unlock(clone);
                ast_set_flag(clone, AST_FLAG_ZOMBIE);
                ast_queue_frame(clone, &ast_null_frame);
                ast_channel_unlock(clone);
@@ -3441,7 +3533,7 @@ void ast_set_callerid(struct ast_channel *chan, const char *callerid, const char
                ast_cdr_setcid(chan->cdr, chan);
        manager_event(EVENT_FLAG_CALL, "Newcallerid",
                                "Channel: %s\r\n"
                ast_cdr_setcid(chan->cdr, chan);
        manager_event(EVENT_FLAG_CALL, "Newcallerid",
                                "Channel: %s\r\n"
-                               "CallerID: %s\r\n"
+                               "CallerIDNum: %s\r\n"
                                "CallerIDName: %s\r\n"
                                "Uniqueid: %s\r\n"
                                "CID-CallingPres: %d (%s)\r\n",
                                "CallerIDName: %s\r\n"
                                "Uniqueid: %s\r\n"
                                "CID-CallingPres: %d (%s)\r\n",
@@ -3463,11 +3555,12 @@ int ast_setstate(struct ast_channel *chan, enum ast_channel_state state)
 
        chan->_state = state;
        ast_device_state_changed_literal(chan->name);
 
        chan->_state = state;
        ast_device_state_changed_literal(chan->name);
+       /* setstate used to conditionally report Newchannel; this is no more */
        manager_event(EVENT_FLAG_CALL,
        manager_event(EVENT_FLAG_CALL,
-                     (oldstate == AST_STATE_DOWN) ? "Newchannel" : "Newstate",
+                     "Newstate",
                      "Channel: %s\r\n"
                      "State: %s\r\n"
                      "Channel: %s\r\n"
                      "State: %s\r\n"
-                     "CallerID: %s\r\n"
+                     "CallerIDNum: %s\r\n"
                      "CallerIDName: %s\r\n"
                      "Uniqueid: %s\r\n",
                      chan->name, ast_state2str(chan->_state),
                      "CallerIDName: %s\r\n"
                      "Uniqueid: %s\r\n",
                      chan->name, ast_state2str(chan->_state),
@@ -3565,7 +3658,7 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                if (bridge_end.tv_sec) {
                        to = ast_tvdiff_ms(bridge_end, ast_tvnow());
                        if (to <= 0) {
                if (bridge_end.tv_sec) {
                        to = ast_tvdiff_ms(bridge_end, ast_tvnow());
                        if (to <= 0) {
-                               res = AST_BRIDGE_RETRY;
+                               res = AST_BRIDGE_COMPLETE;
                                break;
                        }
                } else
                                break;
                        }
                } else
@@ -3593,7 +3686,8 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                if (!f) {
                        *fo = NULL;
                        *rc = who;
                if (!f) {
                        *fo = NULL;
                        *rc = who;
-                       ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name);
                        break;
                }
 
                        break;
                }
 
@@ -3615,7 +3709,8 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                                *fo = f;
                                *rc = who;
                                bridge_exit = 1;
                                *fo = f;
                                *rc = who;
                                bridge_exit = 1;
-                               ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
                                break;
                        }
                        if (bridge_exit)
                                break;
                        }
                        if (bridge_exit)
@@ -3637,9 +3732,10 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
                                f->frametype == AST_FRAME_DTMF_BEGIN)) {
                                *fo = f;
                                *rc = who;
                                f->frametype == AST_FRAME_DTMF_BEGIN)) {
                                *fo = f;
                                *rc = who;
-                               ast_log(LOG_DEBUG, "Got DTMF %s on channel (%s)\n", 
-                                       f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",
-                                       who->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Got DTMF %s on channel (%s)\n", 
+                                               f->frametype == AST_FRAME_DTMF_END ? "end" : "begin",
+                                               who->name);
                                break;
                        }
                        /* Write immediately frames, not passed through jb */
                                break;
                        }
                        /* Write immediately frames, not passed through jb */
@@ -3661,6 +3757,16 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
        return res;
 }
 
        return res;
 }
 
+/*! \brief Bridge two channels together (early) */
+int ast_channel_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
+{
+       /* Make sure we can early bridge, if not error out */
+       if (!c0->tech->early_bridge || (c1 && (!c1->tech->early_bridge || c0->tech->early_bridge != c1->tech->early_bridge)))
+               return -1;
+
+       return c0->tech->early_bridge(c0, c1);
+}
+
 /*! \brief Bridge two channels together */
 enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1,
                                          struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc)
 /*! \brief Bridge two channels together */
 enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1,
                                          struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc)
@@ -3744,8 +3850,10 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                if (!ast_tvzero(nexteventts)) {
                        now = ast_tvnow();
                        to = ast_tvdiff_ms(nexteventts, now);
                if (!ast_tvzero(nexteventts)) {
                        now = ast_tvnow();
                        to = ast_tvdiff_ms(nexteventts, now);
-                       if (to < 0)
-                               to = 0;
+                       if (to <= 0) {
+                               res = AST_BRIDGE_COMPLETE;
+                               break;
+                       }
                }
 
                if (config->timelimit) {
                }
 
                if (config->timelimit) {
@@ -3774,7 +3882,11 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                                bridge_playfile(c1, c0, config->warning_sound, t);
                                }
                                if (config->warning_freq) {
                                                bridge_playfile(c1, c0, config->warning_sound, t);
                                }
                                if (config->warning_freq) {
-                                       nexteventts = ast_tvadd(nexteventts, ast_samp2tv(config->warning_freq, 1000));
+
+                                       if (time_left_ms > (config->warning_freq + 5000)) {
+                                               nexteventts = ast_tvadd(nexteventts, ast_samp2tv(config->warning_freq, 1000));
+                                       }
+                                                               
                                } else
                                        nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
                        }
                                } else
                                        nexteventts = ast_tvadd(config->start_time, ast_samp2tv(config->timelimit, 1000));
                        }
@@ -3787,7 +3899,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                c1->_softhangup = 0;
                        c0->_bridge = c1;
                        c1->_bridge = c0;
                                c1->_softhangup = 0;
                        c0->_bridge = c1;
                        c1->_bridge = c0;
-                       ast_log(LOG_DEBUG, "Unbridge signal received. Ending native bridge.\n");
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Unbridge signal received. Ending native bridge.\n");
                        continue;
                }
                
                        continue;
                }
                
@@ -3798,12 +3911,13 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                        if (who)
                                *rc = who;
                        res = 0;
                        if (who)
                                *rc = who;
                        res = 0;
-                       ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",
-                               c0->name, c1->name,
-                               ast_test_flag(c0, AST_FLAG_ZOMBIE) ? "Yes" : "No",
-                               ast_check_hangup(c0) ? "Yes" : "No",
-                               ast_test_flag(c1, AST_FLAG_ZOMBIE) ? "Yes" : "No",
-                               ast_check_hangup(c1) ? "Yes" : "No");
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",
+                                       c0->name, c1->name,
+                                       ast_test_flag(c0, AST_FLAG_ZOMBIE) ? "Yes" : "No",
+                                       ast_check_hangup(c0) ? "Yes" : "No",
+                                       ast_test_flag(c1, AST_FLAG_ZOMBIE) ? "Yes" : "No",
+                                       ast_check_hangup(c1) ? "Yes" : "No");
                        break;
                }
 
                        break;
                }
 
@@ -3826,7 +3940,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                                              "CallerID1: %s\r\n"
                                              "CallerID2: %s\r\n",
                                              c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
                                              "CallerID1: %s\r\n"
                                              "CallerID2: %s\r\n",
                                              c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
-                               ast_log(LOG_DEBUG, "Returning from native bridge, channels: %s, %s\n", c0->name, c1->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "Returning from native bridge, channels: %s, %s\n", c0->name, c1->name);
 
                                ast_clear_flag(c0, AST_FLAG_NBRIDGE);
                                ast_clear_flag(c1, AST_FLAG_NBRIDGE);
 
                                ast_clear_flag(c0, AST_FLAG_NBRIDGE);
                                ast_clear_flag(c1, AST_FLAG_NBRIDGE);
@@ -3892,7 +4007,8 @@ enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_cha
                      "CallerID1: %s\r\n"
                      "CallerID2: %s\r\n",
                      c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
                      "CallerID1: %s\r\n"
                      "CallerID2: %s\r\n",
                      c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num);
-       ast_log(LOG_DEBUG, "Bridge stops bridging channels %s and %s\n", c0->name, c1->name);
+       if (option_debug)
+               ast_log(LOG_DEBUG, "Bridge stops bridging channels %s and %s\n", c0->name, c1->name);
 
        return res;
 }
 
        return res;
 }
@@ -4149,8 +4265,7 @@ void ast_moh_cleanup(struct ast_channel *chan)
 
 void ast_channels_init(void)
 {
 
 void ast_channels_init(void)
 {
-       ast_cli_register(&cli_show_channeltypes);
-       ast_cli_register(&cli_show_channeltype);
+       ast_cli_register_multiple(cli_channel, sizeof(cli_channel) / sizeof(struct ast_cli_entry));
 }
 
 /*! \brief Print call group and pickup group ---*/
 }
 
 /*! \brief Print call group and pickup group ---*/
@@ -4418,30 +4533,26 @@ int ast_channel_unlock(struct ast_channel *chan)
                ast_log(LOG_DEBUG, "::::==== Unlocking AST channel %s\n", chan->name);
        
        if (!chan) {
                ast_log(LOG_DEBUG, "::::==== Unlocking AST channel %s\n", chan->name);
        
        if (!chan) {
-               ast_log(LOG_DEBUG, "::::==== Unlocking non-existing channel \n");
+               if (option_debug)
+                       ast_log(LOG_DEBUG, "::::==== Unlocking non-existing channel \n");
                return 0;
        }
 
        res = ast_mutex_unlock(&chan->lock);
 
        if (option_debug > 2) {
                return 0;
        }
 
        res = ast_mutex_unlock(&chan->lock);
 
        if (option_debug > 2) {
-               /* Try to find counter if possible on your platform 
-                       I've only found out how to do this on Linux
-                       DEBUG_THREADS changes the lock structure
-               */
-#ifdef __linux__
-               int count = 0;
 #ifdef DEBUG_THREADS
 #ifdef DEBUG_THREADS
-               if ((count = chan->lock.mutex.__m_count))
-#else
-               if ((count = chan->lock.__m_count))
-#endif
-                       ast_log(LOG_DEBUG, ":::=== Still have %d locks (recursive)\n", count);
+               int count = 0;
+               if ((count = chan->lock.reentrancy))
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, ":::=== Still have %d locks (recursive)\n", count);
 #endif
                if (!res)
 #endif
                if (!res)
-                       ast_log(LOG_DEBUG, "::::==== Channel %s was unlocked\n", chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "::::==== Channel %s was unlocked\n", chan->name);
                        if (res == EINVAL) {
                        if (res == EINVAL) {
-                               ast_log(LOG_DEBUG, "::::==== Channel %s had no lock by this thread. Failed unlocking\n", chan->name);
+                               if (option_debug)
+                                       ast_log(LOG_DEBUG, "::::==== Channel %s had no lock by this thread. Failed unlocking\n", chan->name);
                        }
                }
                if (res == EPERM) {
                        }
                }
                if (res == EPERM) {
@@ -4465,17 +4576,15 @@ int ast_channel_lock(struct ast_channel *chan)
        res = ast_mutex_lock(&chan->lock);
 
        if (option_debug > 3) {
        res = ast_mutex_lock(&chan->lock);
 
        if (option_debug > 3) {
-#ifdef __linux__
-               int count = 0;
 #ifdef DEBUG_THREADS
 #ifdef DEBUG_THREADS
-               if ((count = chan->lock.mutex.__m_count))
-#else
-               if ((count = chan->lock.__m_count))
-#endif
-                       ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
+               int count = 0;
+               if ((count = chan->lock.reentrancy))
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
 #endif
                if (!res)
 #endif
                if (!res)
-                       ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
                if (res == EDEADLK) {
                /* We had no lock, so okey any way */
                if (option_debug > 3)
                if (res == EDEADLK) {
                /* We had no lock, so okey any way */
                if (option_debug > 3)
@@ -4501,17 +4610,15 @@ int ast_channel_trylock(struct ast_channel *chan)
        res = ast_mutex_trylock(&chan->lock);
 
        if (option_debug > 2) {
        res = ast_mutex_trylock(&chan->lock);
 
        if (option_debug > 2) {
-#ifdef __linux__
-               int count = 0;
 #ifdef DEBUG_THREADS
 #ifdef DEBUG_THREADS
-               if ((count = chan->lock.mutex.__m_count))
-#else
-               if ((count = chan->lock.__m_count))
-#endif
-                       ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
+               int count = 0;
+               if ((count = chan->lock.reentrancy))
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
 #endif
                if (!res)
 #endif
                if (!res)
-                       ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
+                       if (option_debug)
+                               ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
                if (res == EBUSY) {
                        /* We failed to lock */
                        if (option_debug > 2)
                if (res == EBUSY) {
                        /* We failed to lock */
                        if (option_debug > 2)
@@ -4593,7 +4700,6 @@ int ast_channel_whisper_start(struct ast_channel *chan)
 
        ast_mutex_init(&chan->whisper->lock);
        ast_slinfactory_init(&chan->whisper->sf);
 
        ast_mutex_init(&chan->whisper->lock);
        ast_slinfactory_init(&chan->whisper->sf);
-       chan->whisper->original_format = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
        ast_set_flag(chan, AST_FLAG_WHISPER);
 
        return 0;
        ast_set_flag(chan, AST_FLAG_WHISPER);
 
        return 0;
@@ -4617,7 +4723,10 @@ void ast_channel_whisper_stop(struct ast_channel *chan)
                return;
 
        ast_clear_flag(chan, AST_FLAG_WHISPER);
                return;
 
        ast_clear_flag(chan, AST_FLAG_WHISPER);
-       ast_set_write_format(chan, chan->whisper->original_format);
+       if (chan->whisper->path)
+               ast_translator_free_path(chan->whisper->path);
+       if (chan->whisper->original_format && chan->writeformat == AST_FORMAT_SLINEAR)
+               ast_set_write_format(chan, chan->whisper->original_format);
        ast_slinfactory_destroy(&chan->whisper->sf);
        ast_mutex_destroy(&chan->whisper->lock);
        free(chan->whisper);
        ast_slinfactory_destroy(&chan->whisper->sf);
        ast_mutex_destroy(&chan->whisper->lock);
        free(chan->whisper);