Merge Mahmut's recording patches
[asterisk/asterisk.git] / channel.c
index b7c4ff3..f1ea7f7 100755 (executable)
--- a/channel.c
+++ b/channel.c
@@ -33,6 +33,7 @@
 #include <asterisk/chanvars.h>
 #include <asterisk/linkedlists.h>
 #include <asterisk/indications.h>
+#include <asterisk/monitor.h>
 
 
 static int shutting_down = 0;
@@ -347,7 +348,8 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
                cur = cur->next;
                qlen++;
        }
-       if (qlen  > 128) {
+       /* Allow up to 96 voice frames outstanding, and up to 128 total frames */
+       if (((fin->frametype == AST_FRAME_VOICE) && (qlen > 96)) || (qlen  > 128)) {
                if (fin->frametype != AST_FRAME_VOICE) {
                        ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
                        CRASH;
@@ -376,6 +378,7 @@ int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
 int ast_queue_hangup(struct ast_channel *chan, int lock)
 {
        struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
+       chan->_softhangup |= AST_SOFTHANGUP_DEV;
        return ast_queue_frame(chan, &f, lock);
 }
 
@@ -486,6 +489,10 @@ void ast_channel_free(struct ast_channel *chan)
                ast_log(LOG_WARNING, "Unable to find channel in list\n");
        if (chan->pvt->pvt)
                ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
+       /* Stop monitoring */
+       if (chan->monitor) {
+               chan->monitor->stop( chan, 0 );
+       }
        /* Free translatosr */
        if (chan->pvt->readtrans)
                ast_translator_free_path(chan->pvt->readtrans);
@@ -868,6 +875,7 @@ int ast_waitfor(struct ast_channel *c, int ms)
 
 char ast_waitfordigit(struct ast_channel *c, int ms)
 {
+       /* XXX Should I be merged with waitfordigit_full XXX */
        struct ast_frame *f;
        char result = 0;
        /* Stop if we're a zombie or need a soft hangup */
@@ -892,6 +900,36 @@ char ast_waitfordigit(struct ast_channel *c, int ms)
        return result;
 }
 
+char ast_waitfordigit_full(struct ast_channel *c, int ms, int audio, int ctrl)
+{
+       struct ast_frame *f;
+       char result = 0;
+       struct ast_channel *rchan;
+       int outfd;
+       /* Stop if we're a zombie or need a soft hangup */
+       if (c->zombie || ast_check_hangup(c)) 
+               return -1;
+       /* Wait for a digit, no more than ms milliseconds total. */
+       while(ms && !result) {
+               rchan = ast_waitfor_nandfds(&c, 1, &audio, (audio > -1) ? 1 : 0, NULL, &outfd, &ms);
+               if ((!rchan) && (outfd < 0) && (ms)) /* Error */
+                       result = -1; 
+               else if (outfd > -1) {
+                       result = 1;
+               } else if (rchan) {
+                       /* Read something */
+                       f = ast_read(c);
+                       if (f) {
+                               if (f->frametype == AST_FRAME_DTMF) 
+                                       result = f->subclass;
+                               ast_frfree(f);
+                       } else
+                               result = -1;
+               }
+       }
+       return result;
+}
+
 struct ast_frame *ast_read(struct ast_channel *chan)
 {
        struct ast_frame *f = NULL;
@@ -966,7 +1004,8 @@ struct ast_frame *ast_read(struct ast_channel *chan)
                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);
+                       ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %d since our native format has changed to %d\n", chan->name, f->subclass, chan->nativeformats);
+                       ast_frfree(f);
                        f = &null_frame;
                } else if (chan->pvt->readtrans) {
                        f = ast_translate(chan->pvt->readtrans, f, 1);
@@ -993,6 +1032,10 @@ struct ast_frame *ast_read(struct ast_channel *chan)
                /* Answer the CDR */
                ast_setstate(chan, AST_STATE_UP);
                ast_cdr_answer(chan->cdr);
+       } else if( ( f->frametype == AST_FRAME_VOICE ) && chan->monitor && chan->monitor->read_stream ) {
+               if( ast_writestream( chan->monitor->read_stream, f ) < 0 ) {
+                       ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n");
+               }
        }
        pthread_mutex_unlock(&chan->lock);
 
@@ -1010,7 +1053,12 @@ struct ast_frame *ast_read(struct ast_channel *chan)
                        ast_deactivate_generator(chan);
                }
        }
-       chan->fin++;
+       if (chan->fin & 0x80000000)
+               ast_frame_dump(chan->name, f, "<<");
+       if ((chan->fin & 0x7fffffff) == 0x7fffffff)
+               chan->fin &= 0x80000000;
+       else
+               chan->fin++;
        return f;
 }
 
@@ -1042,7 +1090,7 @@ int ast_indicate(struct ast_channel *chan, int condition)
                        }
                        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);
+                               ast_playtones_start(chan,0,ts->data, 1);
                        }
                        else  {
                                /* not handled */
@@ -1126,13 +1174,13 @@ static int do_senddigit(struct ast_channel *chan, char digit)
                        "!941+1209/50,!0/50",   /* * */
                        "!941+1477/50,!0/50" }; /* # */
                if (digit >= '0' && digit <='9')
-                       ast_playtones_start(chan,0,dtmf_tones[digit-'0']);
+                       ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
                else if (digit >= 'A' && digit <= 'D')
-                       ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10]);
+                       ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10], 0);
                else if (digit == '*')
-                       ast_playtones_start(chan,0,dtmf_tones[14]);
+                       ast_playtones_start(chan,0,dtmf_tones[14], 0);
                else if (digit == '#')
-                       ast_playtones_start(chan,0,dtmf_tones[15]);
+                       ast_playtones_start(chan,0,dtmf_tones[15], 0);
                else {
                        /* not handled */
                        ast_log(LOG_WARNING, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
@@ -1145,7 +1193,7 @@ static int do_senddigit(struct ast_channel *chan, char digit)
 int ast_write(struct ast_channel *chan, struct ast_frame *fr)
 {
        int res = -1;
-       struct ast_frame *f;
+       struct ast_frame *f = NULL;
        /* Stop if we're a zombie or need a soft hangup */
        if (chan->zombie || ast_check_hangup(chan)) 
                return -1;
@@ -1164,6 +1212,8 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
                else
                        return 0;
        }
+       if (chan->fout & 0x80000000)
+               ast_frame_dump(chan->name, fr, ">>");
        CHECK_BLOCKING(chan);
        switch(fr->frametype) {
        case AST_FRAME_CONTROL:
@@ -1180,21 +1230,37 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
        default:
                if (chan->pvt->write) {
                        if (chan->pvt->writetrans) {
-                               f = ast_translate(chan->pvt->writetrans, fr, 1);
+                               f = ast_translate(chan->pvt->writetrans, fr, 0);
                        } else
                                f = fr;
                        if (f)  
+                       {
                                res = chan->pvt->write(chan, f);
+                               if( chan->monitor &&
+                                               chan->monitor->write_stream &&
+                                               f && ( f->frametype == AST_FRAME_VOICE ) ) {
+                                       if( ast_writestream( chan->monitor->write_stream, f ) < 0 ) {
+                                               ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
+                                       }
+                               }
+                       }
                        else
                                res = 0;
                }
        }
+       if (f && (f != fr))
+               ast_frfree(f);
        chan->blocking = 0;
        /* Consider a write failure to force a soft hangup */
        if (res < 0)
                chan->_softhangup |= AST_SOFTHANGUP_DEV;
-       else
+       else {
+               if ((chan->fout & 0x7fffffff) == 0x7fffffff)
+                       chan->fout &= 0x80000000;
+               else
+                       chan->fout++;
                chan->fout++;
+       }
        return res;
 }
 
@@ -1379,6 +1445,7 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
        int pos=0;
        int to = ftimeout;
        char d;
+       /* XXX Merge with full version? XXX */
        /* Stop if we're a zombie or need a soft hangup */
        if (c->zombie || ast_check_hangup(c)) 
                return -1;
@@ -1412,6 +1479,48 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
        return 0;
 }
 
+int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders, int audiofd, int ctrlfd)
+{
+       int pos=0;
+       int to = ftimeout;
+       char d;
+       /* Stop if we're a zombie or need a soft hangup */
+       if (c->zombie || ast_check_hangup(c)) 
+               return -1;
+       if (!len)
+               return -1;
+       do {
+               if (c->streamid > -1) {
+                       d = ast_waitstream_full(c, AST_DIGIT_ANY, audiofd, ctrlfd);
+                       ast_stopstream(c);
+                       usleep(1000);
+                       if (!d)
+                               d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
+               } else {
+                       d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
+               }
+               if (d < 0)
+                       return -1;
+               if (d == 0) {
+                       s[pos]='\0';
+                       return 1;
+               }
+               if (d == 1) {
+                       s[pos]='\0';
+                       return 2;
+               }
+               if (!strchr(enders, d))
+                       s[pos++] = d;
+               if (strchr(enders, d) || (pos >= len)) {
+                       s[pos]='\0';
+                       return 0;
+               }
+               to = timeout;
+       } while(1);
+       /* Never reached */
+       return 0;
+}
+
 int ast_channel_supports_html(struct ast_channel *chan)
 {
        if (chan->pvt->send_html)
@@ -1482,6 +1591,7 @@ int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *pe
 
 int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
 {
+       struct ast_frame null = { AST_FRAME_NULL, };
        ast_log(LOG_DEBUG, "Planning to masquerade %s into the structure of %s\n",
                clone->name, original->name);
        if (original->masq) {
@@ -1496,6 +1606,9 @@ int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clo
        }
        original->masq = clone;
        clone->masqr = original;
+       /* XXX can't really hold the lock here, but at the same time, it' s
+          not really safe not to XXX */
+       ast_queue_frame(original, &null, 0);
        return 0;
 }
 
@@ -1761,7 +1874,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
                        break;
                }
                if (c0->pvt->bridge && 
-                       (c0->pvt->bridge == c1->pvt->bridge) && !nativefailed) {
+                       (c0->pvt->bridge == c1->pvt->bridge) && !nativefailed && !c0->monitor && !c1->monitor) {
                                /* Looks like they share a bridge code */
                        if (option_verbose > 2) 
                                ast_verbose(VERBOSE_PREFIX_3 "Attempting native bridge of %s and %s\n", c0->name, c1->name);
@@ -1848,12 +1961,10 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
 tackygoto:
                                /* Don't copy packets if there is a generator on either one, since they're
                                   not supposed to be listening anyway */
-                               if (!c0->generator && !c1->generator) {
-                                       if (who == c0) 
-                                               ast_write(c1, f);
-                                       else 
-                                               ast_write(c0, f);
-                               }
+                               if (who == c0) 
+                                       ast_write(c1, f);
+                               else 
+                                       ast_write(c0, f);
                        }
                        ast_frfree(f);
                } else
@@ -2023,3 +2134,5 @@ int ast_tonepair(struct ast_channel *chan, int freq1, int freq2, int duration, i
        }
        return 0;
 }
+
+