Version 0.2.0 from FTP
authorMark Spencer <markster@digium.com>
Tue, 10 Sep 2002 20:48:20 +0000 (20:48 +0000)
committerMark Spencer <markster@digium.com>
Tue, 10 Sep 2002 20:48:20 +0000 (20:48 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@522 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channel.c

index f975db5..87d527d 100755 (executable)
--- a/channel.c
+++ b/channel.c
 #include <asterisk/logger.h>
 #include <asterisk/file.h>
 #include <asterisk/translate.h>
+#include <asterisk/manager.h>
+#include <asterisk/chanvars.h>
+#include <asterisk/linkedlists.h>
+
 
 static int shutting_down = 0;
 
@@ -72,13 +76,15 @@ int ast_check_hangup(struct ast_channel *chan)
 time_t myt;
 
          /* if soft hangup flag, return true */
-       if (chan->softhangup) return 1;
+       if (chan->_softhangup) return 1;
+         /* if no private structure, return true */
+       if (!chan->pvt->pvt) return 1;
          /* if no hangup scheduled, just return here */
        if (!chan->whentohangup) return 0;
        time(&myt); /* get current time */
          /* return, if not yet */
        if (chan->whentohangup > myt) return 0;
-       chan->softhangup = 1;
+       chan->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
        return 1;
 }
 
@@ -90,7 +96,7 @@ void ast_begin_shutdown(int hangup)
                PTHREAD_MUTEX_LOCK(&chlock);
                c = channels;
                while(c) {
-                       c->softhangup = 1;
+                       ast_softhangup(c, AST_SOFTHANGUP_SHUTDOWN);
                        c = c->next;
                }
                PTHREAD_MUTEX_UNLOCK(&chlock);
@@ -214,9 +220,13 @@ int ast_best_codec(int fmts)
                /* Okay, we're down to vocoders now, so pick GSM because it's small and easier to
                   translate and sounds pretty good */
                AST_FORMAT_GSM,
+               /* Speex is free, but computationally more expensive than GSM */
+               AST_FORMAT_SPEEX,
                /* Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
                   to use it */
                AST_FORMAT_LPC10,
+               /* G.729a is faster than 723 and slightly less expensive */
+               AST_FORMAT_G729A,
                /* Down to G.723.1 which is proprietary but at least designed for voice */
                AST_FORMAT_G723_1,
                /* Last and least, MP3 which was of course never designed for real-time voice */
@@ -237,6 +247,9 @@ struct ast_channel *ast_channel_alloc(int needqueue)
        struct ast_channel_pvt *pvt;
        int x;
        int flags;
+       struct varshead *headp;        
+               
+       
        /* If shutting down, don't allocate any new channels */
        if (shutting_down)
                return NULL;
@@ -271,12 +284,17 @@ struct ast_channel *ast_channel_alloc(int needqueue)
                                        tmp->fds[AST_MAX_FDS-1] = pvt->alertpipe[0];
                                        strncpy(tmp->name, "**Unknown**", sizeof(tmp->name)-1);
                                        tmp->pvt = pvt;
-                                       tmp->state = AST_STATE_DOWN;
+                                       /* Initial state */
+                                       tmp->_state = AST_STATE_DOWN;
                                        tmp->stack = -1;
                                        tmp->streamid = -1;
                                        tmp->appl = NULL;
                                        tmp->data = NULL;
+                                       headp=&tmp->varshead;
                                        ast_pthread_mutex_init(&tmp->lock);
+                                       AST_LIST_HEAD_INIT(headp);
+                                       tmp->vars=ast_var_assign("tempvar","tempval");
+                                       AST_LIST_INSERT_HEAD(headp,tmp->vars,entries);
                                        strncpy(tmp->context, "default", sizeof(tmp->context)-1);
                                        strncpy(tmp->language, defaultlanguage, sizeof(tmp->language)-1);
                                        strncpy(tmp->exten, "s", sizeof(tmp->exten)-1);
@@ -328,8 +346,8 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
                chan->pvt->readq = f;
        if (chan->pvt->alertpipe[1] > -1) {
                if (write(chan->pvt->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah))
-                       ast_log(LOG_WARNING, "Unable to write to alert pipe, frametype/subclass %d/%d (qlen = %d): %s!\n",
-                               f->frametype, f->subclass, qlen, strerror(errno));
+                       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 (qlen  > 128) {
                ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
@@ -408,7 +426,12 @@ void ast_channel_free(struct ast_channel *chan)
 {
        struct ast_channel *last=NULL, *cur;
        int fd;
+       struct ast_var_t *vardata;
        struct ast_frame *f, *fp;
+       struct varshead *headp;
+       
+       headp=&chan->varshead;
+       
        PTHREAD_MUTEX_LOCK(&chlock);
        cur = channels;
        while(cur) {
@@ -446,29 +469,53 @@ void ast_channel_free(struct ast_channel *chan)
        if ((fd = chan->pvt->alertpipe[1]) > -1)
                close(fd);
        f = chan->pvt->readq;
+       chan->pvt->readq = NULL;
        while(f) {
                fp = f;
                f = f->next;
                ast_frfree(fp);
        }
+       
+       /* loop over the variables list, freeing all data and deleting list items */
+       /* no need to lock the list, as the channel is already locked */
+       
+       while (!AST_LIST_EMPTY(headp)) {           /* List Deletion. */
+                   vardata = AST_LIST_FIRST(headp);
+                   AST_LIST_REMOVE_HEAD(headp, entries);
+//                 printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata));
+                   ast_var_delete(vardata);
+       }
+                                                        
+
        free(chan->pvt);
        free(chan);
        PTHREAD_MUTEX_UNLOCK(&chlock);
 }
 
-int ast_softhangup(struct ast_channel *chan)
+int ast_softhangup_nolock(struct ast_channel *chan, int cause)
 {
        int res = 0;
+       struct ast_frame f = { AST_FRAME_NULL };
        if (option_debug)
                ast_log(LOG_DEBUG, "Soft-Hanging up channel '%s'\n", chan->name);
        /* Inform channel driver that we need to be hung up, if it cares */
-       chan->softhangup = 1;           
+       chan->_softhangup |= cause;
+       ast_queue_frame(chan, &f, 0);
        /* Interrupt any select call or such */
        if (chan->blocking)
                pthread_kill(chan->blocker, SIGURG);
        return res;
 }
 
+int ast_softhangup(struct ast_channel *chan, int cause)
+{
+       int res;
+       ast_pthread_mutex_lock(&chan->lock);
+       res = ast_softhangup_nolock(chan, cause);
+       ast_pthread_mutex_unlock(&chan->lock);
+       return res;
+}
+
 static void free_translation(struct ast_channel *clone)
 {
        if (clone->pvt->writetrans)
@@ -532,6 +579,9 @@ int ast_hangup(struct ast_channel *chan)
                        ast_log(LOG_DEBUG, "Hanging up zombie '%s'\n", chan->name);
                        
        ast_pthread_mutex_unlock(&chan->lock);
+       manager_event(EVENT_FLAG_CALL, "Hangup", 
+                       "Channel: %s\r\n",
+                       chan->name);
        ast_channel_free(chan);
        return res;
 }
@@ -568,12 +618,12 @@ int ast_answer(struct ast_channel *chan)
        /* Stop if we're a zombie or need a soft hangup */
        if (chan->zombie || ast_check_hangup(chan)) 
                return -1;
-       switch(chan->state) {
+       switch(chan->_state) {
        case AST_STATE_RINGING:
        case AST_STATE_RING:
                if (chan->pvt->answer)
                        res = chan->pvt->answer(chan);
-               chan->state = AST_STATE_UP;
+               ast_setstate(chan, AST_STATE_UP);
                if (chan->cdr)
                        ast_cdr_answer(chan->cdr);
                return res;
@@ -589,6 +639,7 @@ void ast_deactivate_generator(struct ast_channel *chan)
        if (chan->generatordata) {
                chan->generator->release(chan, chan->generatordata);
                chan->generatordata = NULL;
+               chan->generator = NULL;
                chan->writeinterrupt = 0;
        }
 }
@@ -816,6 +867,8 @@ struct ast_frame *ast_read(struct ast_channel *chan)
 
        /* Stop if we're a zombie or need a soft hangup */
        if (chan->zombie || ast_check_hangup(chan)) {
+               if (chan->generator)
+                       ast_deactivate_generator(chan);
                pthread_mutex_unlock(&chan->lock);
                return NULL;
        }
@@ -869,7 +922,9 @@ struct ast_frame *ast_read(struct ast_channel *chan)
 
        /* Make sure we always return NULL in the future */
        if (!f) {
-               chan->softhangup = 1;
+               chan->_softhangup |= AST_SOFTHANGUP_DEV;
+               if (chan->generator)
+                       ast_deactivate_generator(chan);
                /* End the CDR if appropriate */
                if (chan->cdr)
                        ast_cdr_end(chan->cdr);
@@ -881,7 +936,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
                f = &null_frame;
        } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
                /* Answer the CDR */
-               chan->state = AST_STATE_UP;
+               ast_setstate(chan, AST_STATE_UP);
                ast_cdr_answer(chan->cdr);
        }
        pthread_mutex_unlock(&chan->lock);
@@ -1012,7 +1067,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
        chan->blocking = 0;
        /* Consider a write failure to force a soft hangup */
        if (res < 0)
-               chan->softhangup = 1;
+               chan->_softhangup |= AST_SOFTHANGUP_DEV;
        return res;
 }
 
@@ -1074,6 +1129,65 @@ int ast_set_read_format(struct ast_channel *chan, int fmts)
        return 0;
 }
 
+struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int timeout, int *outstate)
+{
+       int state = 0;
+       struct ast_channel *chan;
+       struct ast_frame *f;
+       int res;
+       
+       chan = ast_request(type, format, data);
+       if (chan) {
+               if (!ast_call(chan, data, 0)) {
+                       while(timeout && (chan->_state != AST_STATE_UP)) {
+                               res = ast_waitfor(chan, timeout);
+                               if (res < 0) {
+                                       /* Something not cool, or timed out */
+                                       ast_hangup(chan);
+                                       chan = NULL;
+                                       break;
+                               }
+                               /* If done, break out */
+                               if (!res)
+                                       break;
+                               if (timeout > -1)
+                                       timeout = res;
+                               f = ast_read(chan);
+                               if (!f) {
+                                       state = AST_CONTROL_HANGUP;
+                                       ast_hangup(chan);
+                                       chan = NULL;
+                                       break;
+                               }
+                               if (f->frametype == AST_FRAME_CONTROL) {
+                                       if (f->subclass == AST_CONTROL_RINGING)
+                                               state = AST_CONTROL_RINGING;
+                                       else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
+                                               state = f->subclass;
+                                               break;
+                                       } else if (f->subclass == AST_CONTROL_ANSWER) {
+                                               state = f->subclass;
+                                               break;
+                                       } else {
+                                               ast_log(LOG_NOTICE, "Don't know what to do with control frame %d\n", f->subclass);
+                                       }
+                               }
+                               ast_frfree(f);
+                       }
+               } else {
+                       ast_hangup(chan);
+                       chan = NULL;
+                       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
+               }
+       } else
+               ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
+       if (chan && (chan->_state == AST_STATE_UP))
+               state = AST_CONTROL_ANSWER;
+       if (outstate)
+               *outstate = state;
+       return chan;
+}
+
 struct ast_channel *ast_request(char *type, int format, void *data)
 {
        struct chanlist *chan;
@@ -1099,6 +1213,13 @@ struct ast_channel *ast_request(char *type, int format, void *data)
                        PTHREAD_MUTEX_UNLOCK(&chlock);
                        if (chan->requester)
                                c = chan->requester(type, capabilities, data);
+                       if (c) {
+                               manager_event(EVENT_FLAG_CALL, "Newchannel",
+                               "Channel: %s\r\n"
+                               "State: %s\r\n"
+                               "Callerid: %s\r\n",
+                               c->name, ast_state2str(c->_state), c->callerid ? c->callerid : "<unknown>");
+                       }
                        return c;
                }
                chan = chan->next;
@@ -1258,6 +1379,10 @@ static int ast_do_masquerade(struct ast_channel *original)
        struct ast_channel *clone = original->masq;
        int rformat = original->readformat;
        int wformat = original->writeformat;
+       char newn[100];
+       char orig[100];
+       char masqn[100];
+       char zombn[100];
        
 #if 0
        ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
@@ -1279,19 +1404,30 @@ static int ast_do_masquerade(struct ast_channel *original)
        /* Unlink the masquerade */
        original->masq = NULL;
        clone->masqr = NULL;
+       
+       /* Save the original name */
+       strncpy(orig, original->name, sizeof(orig) - 1);
+       /* Save the new name */
+       strncpy(newn, clone->name, sizeof(newn) - 1);
+       /* Create the masq name */
+       snprintf(masqn, sizeof(masqn), "%s<MASQ>", newn);
                
        /* Copy the name from the clone channel */
-       strncpy(original->name, clone->name, sizeof(original->name)-1);
+       strncpy(original->name, newn, sizeof(original->name)-1);
 
        /* Mangle the name of the clone channel */
-       strncat(clone->name, "<MASQ>", sizeof(clone->name));
+       strncpy(clone->name, masqn, sizeof(clone->name) - 1);
+       
+       /* Notify any managers of the change, first the masq then the other */
+       manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", newn, masqn);
+       manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", orig, newn);
 
        /* Swap the guts */     
        p = original->pvt;
        original->pvt = clone->pvt;
        clone->pvt = p;
        
-       clone->softhangup = 1;
+       clone->_softhangup = AST_SOFTHANGUP_DEV;
 
 
        if (clone->pvt->fixup){
@@ -1309,8 +1445,10 @@ static int ast_do_masquerade(struct ast_channel *original)
                return -1;
        }
        
+       snprintf(zombn, sizeof(zombn), "%s<ZOMBIE>", orig);
        /* Mangle the name of the clone channel */
-       snprintf(clone->name, sizeof(clone->name), "%s<ZOMBIE>", original->name);
+       strncpy(clone->name, zombn, sizeof(clone->name) - 1);
+       manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", masqn, zombn);
 
        /* Keep the same language.  */
        /* Update the type. */
@@ -1382,7 +1520,44 @@ static int ast_do_masquerade(struct ast_channel *original)
        if (original->blocking)
                pthread_kill(original->blocker, SIGURG);
        ast_log(LOG_DEBUG, "Done Masquerading %s(%d) into the structure of %s(%d)\n",
-               clone->name, clone->state, original->name, original->state);
+               clone->name, clone->_state, original->name, original->_state);
+       return 0;
+}
+
+void ast_set_callerid(struct ast_channel *chan, char *callerid)
+{
+       if (chan->callerid)
+               free(chan->callerid);
+       if (callerid)
+               chan->callerid = strdup(callerid);
+       else
+               chan->callerid = NULL;
+       manager_event(EVENT_FLAG_CALL, "Newcallerid", 
+                               "Channel: %s\r\n"
+                               "Callerid: %s\r\n",
+                               chan->name, chan->callerid ? 
+                               chan->callerid : "<Unknown>");
+}
+
+int ast_setstate(struct ast_channel *chan, int state)
+{
+       if (chan->_state != state) {
+               int oldstate = chan->_state;
+               chan->_state = state;
+               if (oldstate == AST_STATE_DOWN) {
+                       manager_event(EVENT_FLAG_CALL, "Newchannel",
+                       "Channel: %s\r\n"
+                       "State: %s\r\n"
+                       "Callerid: %s\r\n",
+                       chan->name, ast_state2str(chan->_state), chan->callerid ? chan->callerid : "<unknown>");
+               } else {
+                       manager_event(EVENT_FLAG_CALL, "Newstate", 
+                               "Channel: %s\r\n"
+                               "State: %s\r\n"
+                               "Callerid: %s\r\n",
+                               chan->name, ast_state2str(chan->_state), chan->callerid ? chan->callerid : "<unknown>");
+               }
+       }
        return 0;
 }
 
@@ -1415,6 +1590,12 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
        c1->bridge = c0;
        cs[0] = c0;
        cs[1] = c1;
+       
+       manager_event(EVENT_FLAG_CALL, "Link", 
+                       "Channel1: %s\r\n"
+                       "Channel2: %s\r\n",
+                       c0->name, c1->name);
+
        for (/* ever */;;) {
                /* Stop if we're a zombie or need a soft hangup */
                if (c0->zombie || ast_check_hangup(c0) || c1->zombie || ast_check_hangup(c1)) {
@@ -1431,6 +1612,10 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                        if (!(res = c0->pvt->bridge(c0, c1, flags, fo, rc))) {
                                c0->bridge = NULL;
                                c1->bridge = NULL;
+                               manager_event(EVENT_FLAG_CALL, "Unlink", 
+                                       "Channel1: %s\r\n"
+                                       "Channel2: %s\r\n",
+                                       c0->name, c1->name);
                                return 0;
                        }
                        /* If they return non-zero then continue on normally.  Let "-2" mean don't worry about
@@ -1445,6 +1630,10 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                        !(c0->generator || c1->generator))  {
                        if (ast_channel_make_compatible(c0, c1)) {
                                ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name);
+                               manager_event(EVENT_FLAG_CALL, "Unlink", 
+                                       "Channel1: %s\r\n"
+                                       "Channel2: %s\r\n",
+                                       c0->name, c1->name);
                                return -1;
                        }
                }
@@ -1519,6 +1708,10 @@ tackygoto:
        }
        c0->bridge = NULL;
        c1->bridge = NULL;
+       manager_event(EVENT_FLAG_CALL, "Unlink", 
+                                       "Channel1: %s\r\n"
+                                       "Channel2: %s\r\n",
+                                       c0->name, c1->name);
        return res;
 }