Version 0.3.0 from FTP
authorMark Spencer <markster@digium.com>
Wed, 5 Feb 2003 21:18:09 +0000 (21:18 +0000)
committerMark Spencer <markster@digium.com>
Wed, 5 Feb 2003 21:18:09 +0000 (21:18 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@604 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channel.c
formats/format_mp3.c

index 87d527d..b7c4ff3 100755 (executable)
--- a/channel.c
+++ b/channel.c
@@ -18,9 +18,9 @@
 #include <sys/time.h>
 #include <signal.h>
 #include <errno.h>
-#include <asterisk/lock.h>
 #include <unistd.h>
 #include <math.h>                      /* For PI */
+#include <asterisk/pbx.h>
 #include <asterisk/frame.h>
 #include <asterisk/sched.h>
 #include <asterisk/options.h>
@@ -32,6 +32,7 @@
 #include <asterisk/manager.h>
 #include <asterisk/chanvars.h>
 #include <asterisk/linkedlists.h>
+#include <asterisk/indications.h>
 
 
 static int shutting_down = 0;
@@ -132,7 +133,10 @@ void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
 time_t myt;
 
        time(&myt);
-       chan->whentohangup = myt + offset;
+        if (offset)
+         chan->whentohangup = myt + offset;
+        else
+          chan->whentohangup = 0;
        return;
 }
 
@@ -290,6 +294,8 @@ struct ast_channel *ast_channel_alloc(int needqueue)
                                        tmp->streamid = -1;
                                        tmp->appl = NULL;
                                        tmp->data = NULL;
+                                       tmp->fin = 0;
+                                       tmp->fout = 0;
                                        headp=&tmp->varshead;
                                        ast_pthread_mutex_init(&tmp->lock);
                                        AST_LIST_HEAD_INIT(headp);
@@ -326,6 +332,7 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
        struct ast_frame *prev, *cur;
        int blah = 1;
        int qlen = 0;
+       /* Build us a copy and free the original one */
        f = ast_frdup(fin);
        if (!f) {
                ast_log(LOG_WARNING, "Unable to duplicate frame\n");
@@ -340,6 +347,18 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
                cur = cur->next;
                qlen++;
        }
+       if (qlen  > 128) {
+               if (fin->frametype != AST_FRAME_VOICE) {
+                       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);
+                       ast_frfree(fin);
+                       if (lock)
+                               ast_pthread_mutex_unlock(&chan->lock);
+                       return 0;
+               }
+       }
        if (prev)
                prev->next = f;
        else
@@ -349,9 +368,6 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
                        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);
-       }
        if (lock)
                ast_pthread_mutex_unlock(&chan->lock);
        return 0;
@@ -405,6 +421,27 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev)
        
 }
 
+int ast_safe_sleep_conditional(        struct ast_channel *chan, int ms,
+                                                               int (*cond)(void*), void *data )
+{
+       struct ast_frame *f;
+
+       while(ms > 0) {
+               if( cond && ((*cond)(data) == 0 ) )
+                       return 0;
+               ms = ast_waitfor(chan, ms);
+               if (ms <0)
+                       return -1;
+               if (ms > 0) {
+                       f = ast_read(chan);
+                       if (!f)
+                               return -1;
+                       ast_frfree(f);
+               }
+       }
+       return 0;
+}
+
 int ast_safe_sleep(struct ast_channel *chan, int ms)
 {
        struct ast_frame *f;
@@ -462,6 +499,8 @@ void ast_channel_free(struct ast_channel *chan)
                free(chan->callerid);   
        if (chan->ani)
                free(chan->ani);
+       if (chan->rdnis)
+               free(chan->rdnis);
        pthread_mutex_destroy(&chan->lock);
        /* Close pipes if appropriate */
        if ((fd = chan->pvt->alertpipe[0]) > -1)
@@ -488,6 +527,7 @@ void ast_channel_free(struct ast_channel *chan)
                                                         
 
        free(chan->pvt);
+       chan->pvt = NULL;
        free(chan);
        PTHREAD_MUTEX_UNLOCK(&chlock);
 }
@@ -516,6 +556,8 @@ int ast_softhangup(struct ast_channel *chan, int cause)
        return res;
 }
 
+static int ast_do_masquerade(struct ast_channel *original);
+
 static void free_translation(struct ast_channel *clone)
 {
        if (clone->pvt->writetrans)
@@ -535,7 +577,12 @@ int ast_hangup(struct ast_channel *chan)
           if someone is going to masquerade as us */
        ast_pthread_mutex_lock(&chan->lock);
        if (chan->masq) {
-               ast_log(LOG_WARNING, "We're getting hung up, but someone is trying to masq into us?!?\n");
+               if (ast_do_masquerade(chan)) 
+                       ast_log(LOG_WARNING, "Failed to perform masquerade\n");
+       }
+
+       if (chan->masq) {
+               ast_log(LOG_WARNING, "%s getting hung up, but someone is trying to masq into us?!?\n", chan->name);
                ast_pthread_mutex_unlock(&chan->lock);
                return 0;
        }
@@ -629,6 +676,8 @@ int ast_answer(struct ast_channel *chan)
                return res;
                break;
        case AST_STATE_UP:
+               if (chan->cdr)
+                       ast_cdr_answer(chan->cdr);
                break;
        }
        return 0;
@@ -704,8 +753,6 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
        return winner;
 }
 
-static int ast_do_masquerade(struct ast_channel *original);
-
 struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, 
        int *exception, int *outfd, int *ms)
 {
@@ -901,8 +948,10 @@ struct ast_frame *ast_read(struct ast_channel *chan)
                if (chan->exception) {
                        if (chan->pvt->exception) 
                                f = chan->pvt->exception(chan);
-                       else
-                               ast_log(LOG_WARNING, "Exception flag set, but no exception handler\n");
+                       else {
+                               ast_log(LOG_WARNING, "Exception flag set on '%s', but no exception handler\n", chan->name);
+                               f = &null_frame;
+                       }
                        /* Clear the exception flag */
                        chan->exception = 0;
                } else
@@ -912,8 +961,14 @@ struct ast_frame *ast_read(struct ast_channel *chan)
                        ast_log(LOG_WARNING, "No read routine on channel %s\n", chan->name);
        }
 
+
        if (f && (f->frametype == AST_FRAME_VOICE)) {
-               if (chan->pvt->readtrans) {
+               if (!(f->subclass & chan->nativeformats)) {
+                       /* This frame can't be from the current native formats -- drop it on the
+                          floor */
+                       ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s since our native format has changed\n", chan->name);
+                       f = &null_frame;
+               } else if (chan->pvt->readtrans) {
                        f = ast_translate(chan->pvt->readtrans, f, 1);
                        if (!f)
                                f = &null_frame;
@@ -948,14 +1003,14 @@ struct ast_frame *ast_read(struct ast_channel *chan)
                int res;
                tmp = chan->generatordata;
                chan->generatordata = NULL;
-               res = chan->generator->generate(chan, tmp, f->datalen);
+               res = chan->generator->generate(chan, tmp, f->datalen, f->samples);
                chan->generatordata = tmp;
                if (res) {
                        ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
                        ast_deactivate_generator(chan);
                }
        }
-
+       chan->fin++;
        return f;
 }
 
@@ -965,13 +1020,39 @@ int ast_indicate(struct ast_channel *chan, int condition)
        /* Stop if we're a zombie or need a soft hangup */
        if (chan->zombie || ast_check_hangup(chan)) 
                return -1;
-       if (chan->pvt->indicate) {
+       if (chan->pvt->indicate)
                res = chan->pvt->indicate(chan, condition);
-               if (res)
-                       ast_log(LOG_WARNING, "Driver for channel '%s' failed to indicate condition %d\n", chan->name, condition);
-       } else
-               ast_log(LOG_WARNING, "Driver for channel '%s' does not support indication\n", chan->name);
-       return res;
+       if (!chan->pvt->indicate || res) {
+               /*
+                * Device does not support (that) indication, lets fake
+                * it by doing our own tone generation. (PM2002)
+                */
+               if (condition >= 0) {
+                       const struct tone_zone_sound *ts = NULL;
+                       switch (condition) {
+                        case AST_CONTROL_RINGING:
+                               ts = ast_get_indication_tone(chan->zone, "ring");
+                               break;
+                        case AST_CONTROL_BUSY:
+                               ts = ast_get_indication_tone(chan->zone, "busy");
+                               break;
+                        case AST_CONTROL_CONGESTION:
+                               ts = ast_get_indication_tone(chan->zone, "congestion");
+                               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);
+                               ast_playtones_start(chan,0,ts->data);
+                       }
+                       else  {
+                               /* not handled */
+                               ast_log(LOG_WARNING, "Unable to handle indication %d for '%s'\n", condition, chan->name);
+                               return -1;
+                       }
+               }
+               else ast_playtones_stop(chan);
+       }
+       return 0;
 }
 
 int ast_recvchar(struct ast_channel *chan, int timeout)
@@ -1016,6 +1097,51 @@ int ast_sendtext(struct ast_channel *chan, char *text)
        return res;
 }
 
+static int do_senddigit(struct ast_channel *chan, char digit)
+{
+       int res = -1;
+
+       if (chan->pvt->send_digit)
+               res = chan->pvt->send_digit(chan, digit);
+       if (!chan->pvt->send_digit || res) {
+               /*
+                * Device does not support DTMF tones, lets fake
+                * it by doing our own generation. (PM2002)
+                */
+               static const char* dtmf_tones[] = {
+                       "!941+1336/50,!0/50",   /* 0 */
+                       "!697+1209/50,!0/50",   /* 1 */
+                       "!697+1336/50,!0/50",   /* 2 */
+                       "!697+1477/50,!0/50",   /* 3 */
+                       "!770+1209/50,!0/50",   /* 4 */
+                       "!770+1336/50,!0/50",   /* 5 */
+                       "!770+1477/50,!0/50",   /* 6 */
+                       "!852+1209/50,!0/50",   /* 7 */
+                       "!852+1336/50,!0/50",   /* 8 */
+                       "!852+1477/50,!0/50",   /* 9 */
+                       "!697+1633/50,!0/50",   /* A */
+                       "!770+1633/50,!0/50",   /* B */
+                       "!852+1633/50,!0/50",   /* C */
+                       "!941+1633/50,!0/50",   /* D */
+                       "!941+1209/50,!0/50",   /* * */
+                       "!941+1477/50,!0/50" }; /* # */
+               if (digit >= '0' && digit <='9')
+                       ast_playtones_start(chan,0,dtmf_tones[digit-'0']);
+               else if (digit >= 'A' && digit <= 'D')
+                       ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10]);
+               else if (digit == '*')
+                       ast_playtones_start(chan,0,dtmf_tones[14]);
+               else if (digit == '#')
+                       ast_playtones_start(chan,0,dtmf_tones[15]);
+               else {
+                       /* not handled */
+                       ast_log(LOG_WARNING, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
+                       return -1;
+               }
+       }
+       return 0;
+}
+
 int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 {
        int res = -1;
@@ -1045,8 +1171,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                ast_log(LOG_WARNING, "Don't know how to handle control frames yet\n");
                break;
        case AST_FRAME_DTMF:
-               if (chan->pvt->send_digit)
-                       res = chan->pvt->send_digit(chan, fr->subclass);
+               res = do_senddigit(chan,fr->subclass);
                break;
        case AST_FRAME_TEXT:
                if (chan->pvt->send_text)
@@ -1068,6 +1193,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
        /* Consider a write failure to force a soft hangup */
        if (res < 0)
                chan->_softhangup |= AST_SOFTHANGUP_DEV;
+       else
+               chan->fout++;
        return res;
 }
 
@@ -1129,7 +1256,7 @@ 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)
+struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int timeout, int *outstate, char *callerid)
 {
        int state = 0;
        struct ast_channel *chan;
@@ -1138,6 +1265,8 @@ struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int
        
        chan = ast_request(type, format, data);
        if (chan) {
+               if (callerid)
+                       ast_set_callerid(chan, callerid, 1);
                if (!ast_call(chan, data, 0)) {
                        while(timeout && (chan->_state != AST_STATE_UP)) {
                                res = ast_waitfor(chan, timeout);
@@ -1370,11 +1499,20 @@ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clo
        return 0;
 }
 
+void ast_change_name(struct ast_channel *chan, char *newname)
+{
+       char tmp[256];
+       strncpy(tmp, chan->name, 256);
+       strncpy(chan->name, newname, sizeof(chan->name) - 1);
+       manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", tmp, chan->name);
+}
+
 static int ast_do_masquerade(struct ast_channel *original)
 {
        int x;
        int res=0;
        char *tmp;
+       void *tmpv;
        struct ast_channel_pvt *p;
        struct ast_channel *clone = original->masq;
        int rformat = original->readformat;
@@ -1384,9 +1522,9 @@ static int ast_do_masquerade(struct ast_channel *original)
        char masqn[100];
        char zombn[100];
        
-#if 0
+#if 1
        ast_log(LOG_DEBUG, "Actually 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);
 #endif
        /* 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
@@ -1456,6 +1594,10 @@ static int ast_do_masquerade(struct ast_channel *original)
        /* Copy the FD's */
        for (x=0;x<AST_MAX_FDS;x++)
                original->fds[x] = clone->fds[x];
+       /* Move the variables */
+       tmpv = original->varshead.first;
+       original->varshead.first = clone->varshead.first;
+       clone->varshead.first = tmpv;
        /* Presense of ADSI capable CPE follows clone */
        original->adsicpe = clone->adsicpe;
        /* Bridge remains the same */
@@ -1482,6 +1624,11 @@ static int ast_do_masquerade(struct ast_channel *original)
        
        /* Our native formats are different now */
        original->nativeformats = clone->nativeformats;
+
+       /* And of course, so does our current state.  Note we need not
+          call ast_setstate since the event manager doesn't really consider
+          these separate */
+       original->_state = clone->_state;
        
        /* Context, extension, priority, app data, jump table,  remain the same */
        /* pvt switches.  pbx stays the same, as does next */
@@ -1492,6 +1639,7 @@ static int ast_do_masquerade(struct ast_channel *original)
        if (clone->zombie) {
                pthread_mutex_unlock(&clone->lock);
                ast_channel_free(clone);
+               manager_event(EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n", zombn);
        } else {
                clone->zombie=1;
                pthread_mutex_unlock(&clone->lock);
@@ -1519,19 +1667,26 @@ static int ast_do_masquerade(struct ast_channel *original)
        /* Signal any blocker */
        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);
        return 0;
 }
 
-void ast_set_callerid(struct ast_channel *chan, char *callerid)
+void ast_set_callerid(struct ast_channel *chan, char *callerid, int anitoo)
 {
        if (chan->callerid)
                free(chan->callerid);
-       if (callerid)
+       if (anitoo && chan->ani)
+               free(chan->ani);
+       if (callerid) {
                chan->callerid = strdup(callerid);
-       else
+               if (anitoo)
+                       chan->ani = strdup(callerid);
+       } else {
                chan->callerid = NULL;
+               if (anitoo)
+                       chan->ani = NULL;
+       }
+       if (chan->cdr)
+               ast_cdr_setcid(chan->cdr, chan);
        manager_event(EVENT_FLAG_CALL, "Newcallerid", 
                                "Channel: %s\r\n"
                                "Callerid: %s\r\n",
@@ -1571,6 +1726,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
        struct ast_channel *who = NULL;
        int res;
        int nativefailed=0;
+
        /* Stop if we're a zombie or need a soft hangup */
        if (c0->zombie || ast_check_hangup(c0) || c1->zombie || ast_check_hangup(c1)) 
                return -1;
@@ -1639,7 +1795,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                }
                who = ast_waitfor_n(cs, 2, &to);
                if (!who) {
-                       ast_log(LOG_WARNING, "Nobody there??\n"); 
+                       ast_log(LOG_DEBUG, "Nobody there, continuing...\n"); 
                        continue;
                }
                f = ast_read(who);
@@ -1649,6 +1805,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                        res = 0;
                        break;
                }
+
                if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
                        *fo = f;
                        *rc = who;
@@ -1748,7 +1905,6 @@ struct tonepair_state {
        float vol;
        int duration;
        int pos;
-       int origrfmt;
        int origwfmt;
        struct ast_frame f;
        unsigned char offset[AST_FRIENDLY_OFFSET];
@@ -1760,7 +1916,6 @@ static void tonepair_release(struct ast_channel *chan, void *params)
        struct tonepair_state *ts = params;
        if (chan) {
                ast_set_write_format(chan, ts->origwfmt);
-               ast_set_read_format(chan, ts->origrfmt);
        }
        free(ts);
 }
@@ -1773,17 +1928,11 @@ static void * tonepair_alloc(struct ast_channel *chan, void *params)
        if (!ts)
                return NULL;
        memset(ts, 0, sizeof(struct tonepair_state));
-       ts->origrfmt = chan->readformat;
        ts->origwfmt = chan->writeformat;
        if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
                ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
                tonepair_release(NULL, ts);
                ts = NULL;
-       } else if (ast_set_read_format(chan, AST_FORMAT_SLINEAR)) {
-               ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (read)\n", chan->name);
-               ast_set_write_format(chan, ts->origwfmt);
-               tonepair_release(NULL, ts);
-               ts = NULL;
        } else {
                ts->freq1 = td->freq1;
                ts->freq2 = td->freq2;
@@ -1795,10 +1944,16 @@ static void * tonepair_alloc(struct ast_channel *chan, void *params)
        return ts;
 }
 
-static int tonepair_generator(struct ast_channel *chan, void *data, int len)
+static int tonepair_generator(struct ast_channel *chan, void *data, int len, int samples)
 {
        struct tonepair_state *ts = data;
        int x;
+
+       /* we need to prepare a frame with 16 * timelen samples as we're 
+        * generating SLIN audio
+        */
+       len = samples * 2;
+
        if (len > sizeof(ts->data) / 2 - 1) {
                ast_log(LOG_WARNING, "Can't generate that much data!\n");
                return -1;
@@ -1813,7 +1968,7 @@ static int tonepair_generator(struct ast_channel *chan, void *data, int len)
        ts->f.frametype = AST_FRAME_VOICE;
        ts->f.subclass = AST_FORMAT_SLINEAR;
        ts->f.datalen = len;
-       ts->f.timelen = len/8;
+       ts->f.samples = samples;
        ts->f.offset = AST_FRIENDLY_OFFSET;
        ts->f.data = ts->data;
        ast_write(chan, &ts->f);
index 5c730f0..e702e55 100755 (executable)
@@ -192,7 +192,7 @@ static int ast_read_callback(void *data)
                        s->adj -= (ms - delay);
                s->adj -= 2;
        }
-       s->fr.timelen = delay;
+       s->fr.samples = delay * 8;
 #if 0
        ast_log(LOG_DEBUG, "delay is %d, adjusting by %d, as last was %d\n", delay, s->adj, ms);
 #endif
@@ -218,6 +218,11 @@ static int mp3_apply(struct ast_channel *c, struct ast_filestream *s)
 {
        /* Select our owner for this stream, and get the ball rolling. */
        s->owner = c;
+       return 0;
+}
+
+static int mp3_play(struct ast_filestream *s)
+{
        ast_read_callback(s);
        return 0;
 }
@@ -240,6 +245,21 @@ static int mp3_write(struct ast_filestream *fs, struct ast_frame *f)
        return 0;
 }
 
+static int mp3_seek(struct ast_filestream *fs, long sample_offset, int whence)
+{
+       return -1;
+}
+
+static int mp3_trunc(struct ast_filestream *fs)
+{
+       return -1;
+}
+
+static long mp3_tell(struct ast_filestream *fs)
+{
+       return -1;
+}
+
 static char *mp3_getcomment(struct ast_filestream *s)
 {
        return NULL;
@@ -251,7 +271,11 @@ int load_module()
                                                                mp3_open,
                                                                mp3_rewrite,
                                                                mp3_apply,
+                                                               mp3_play,
                                                                mp3_write,
+                                                               mp3_seek,
+                                                               mp3_trunc,
+                                                               mp3_tell,
                                                                mp3_read,
                                                                mp3_close,
                                                                mp3_getcomment);