Version 0.1.8 from FTP
[asterisk/asterisk.git] / channel.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Management
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <pthread.h>
17 #include <string.h>
18 #include <sys/time.h>
19 #include <signal.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <asterisk/sched.h>
23 #include <asterisk/options.h>
24 #include <asterisk/channel.h>
25 #include <asterisk/channel_pvt.h>
26 #include <asterisk/logger.h>
27 #include <asterisk/file.h>
28 #include <asterisk/translate.h>
29
30
31
32 #ifdef DEBUG_MUTEX
33 /* Convenient mutex debugging functions */
34 #define PTHREAD_MUTEX_LOCK(a) __PTHREAD_MUTEX_LOCK(__FUNCTION__, a)
35 #define PTHREAD_MUTEX_UNLOCK(a) __PTHREAD_MUTEX_UNLOCK(__FUNCTION__, a)
36
37 static int __PTHREAD_MUTEX_LOCK(char *f, pthread_mutex_t *a) {
38         ast_log(LOG_DEBUG, "Locking %p (%s)\n", a, f); 
39         return pthread_mutex_lock(a);
40 }
41
42 static int __PTHREAD_MUTEX_UNLOCK(char *f, pthread_mutex_t *a) {
43         ast_log(LOG_DEBUG, "Unlocking %p (%s)\n", a, f); 
44         return pthread_mutex_unlock(a);
45 }
46 #else
47 #define PTHREAD_MUTEX_LOCK(a) pthread_mutex_lock(a)
48 #define PTHREAD_MUTEX_UNLOCK(a) pthread_mutex_unlock(a)
49 #endif
50
51 struct chanlist {
52         char type[80];
53         char description[80];
54         int capabilities;
55         struct ast_channel * (*requester)(char *type, int format, void *data);
56         struct chanlist *next;
57 } *backends = NULL;
58 struct ast_channel *channels = NULL;
59
60 /* Protect the channel list (highly unlikely that two things would change
61    it at the same time, but still! */
62    
63 static pthread_mutex_t chlock = PTHREAD_MUTEX_INITIALIZER;
64
65 int ast_channel_register(char *type, char *description, int capabilities,
66                 struct ast_channel *(*requester)(char *type, int format, void *data))
67 {
68         struct chanlist *chan, *last=NULL;
69         if (PTHREAD_MUTEX_LOCK(&chlock)) {
70                 ast_log(LOG_WARNING, "Unable to lock channel list\n");
71                 return -1;
72         }
73         chan = backends;
74         while(chan) {
75                 if (!strcasecmp(type, chan->type)) {
76                         ast_log(LOG_WARNING, "Already have a handler for type '%s'\n", type);
77                         PTHREAD_MUTEX_UNLOCK(&chlock);
78                         return -1;
79                 }
80                 last = chan;
81                 chan = chan->next;
82         }
83         chan = malloc(sizeof(struct chanlist));
84         if (!chan) {
85                 ast_log(LOG_WARNING, "Out of memory\n");
86                 PTHREAD_MUTEX_UNLOCK(&chlock);
87                 return -1;
88         }
89         strncpy(chan->type, type, sizeof(chan->type));
90         strncpy(chan->description, description, sizeof(chan->description));
91         chan->capabilities = capabilities;
92         chan->requester = requester;
93         chan->next = NULL;
94         if (last)
95                 last->next = chan;
96         else
97                 backends = chan;
98         if (option_debug)
99                 ast_log(LOG_DEBUG, "Registered handler for '%s' (%s)\n", chan->type, chan->description);
100         else if (option_verbose > 1)
101                 ast_verbose( VERBOSE_PREFIX_2 "Registered channel type '%s' (%s)\n", chan->type, chan->description);
102         PTHREAD_MUTEX_UNLOCK(&chlock);
103         return 0;
104 }
105
106 struct ast_channel *ast_channel_alloc(void)
107 {
108         struct ast_channel *tmp;
109         struct ast_channel_pvt *pvt;
110         PTHREAD_MUTEX_LOCK(&chlock);
111         tmp = malloc(sizeof(struct ast_channel));
112         memset(tmp, 0, sizeof(struct ast_channel));
113         if (tmp) {
114                 pvt = malloc(sizeof(struct ast_channel_pvt));
115                 if (pvt) {
116                         memset(pvt, 0, sizeof(struct ast_channel_pvt));
117                         tmp->sched = sched_context_create();
118                         if (tmp->sched) {
119                                 tmp->fd = -1;
120                                 strncpy(tmp->name, "**Unknown**", sizeof(tmp->name));
121                                 tmp->pvt = pvt;
122                                 tmp->state = AST_STATE_DOWN;
123                                 tmp->stack = -1;
124                                 tmp->streamid = -1;
125                                 tmp->appl = NULL;
126                                 tmp->data = NULL;
127                                 pthread_mutex_init(&tmp->lock, NULL);
128                                 strncpy(tmp->context, "default", sizeof(tmp->context));
129                                 strncpy(tmp->language, defaultlanguage, sizeof(tmp->language));
130                                 strncpy(tmp->exten, "s", sizeof(tmp->exten));
131                                 tmp->priority=1;
132                                 tmp->next = channels;
133                                 channels= tmp;
134                         } else {
135                                 ast_log(LOG_WARNING, "Unable to create schedule context\n");
136                                 free(tmp);
137                                 tmp = NULL;
138                         }
139                 } else {
140                         ast_log(LOG_WARNING, "Out of memory\n");
141                         free(tmp);
142                         tmp = NULL;
143                 }
144         } else 
145                 ast_log(LOG_WARNING, "Out of memory\n");
146         PTHREAD_MUTEX_UNLOCK(&chlock);
147         return tmp;
148 }
149
150 struct ast_channel *ast_channel_walk(struct ast_channel *prev)
151 {
152         struct ast_channel *l, *ret=NULL;
153         PTHREAD_MUTEX_LOCK(&chlock);
154         l = channels;
155         if (!prev) {
156                 PTHREAD_MUTEX_UNLOCK(&chlock);
157                 return l;
158         }
159         while(l) {
160                 if (l == prev)
161                         ret = l->next;
162                 l = l->next;
163         }
164         PTHREAD_MUTEX_UNLOCK(&chlock);
165         return ret;
166         
167 }
168
169 void ast_channel_free(struct ast_channel *chan)
170 {
171         struct ast_channel *last=NULL, *cur;
172         PTHREAD_MUTEX_LOCK(&chlock);
173         cur = channels;
174         while(cur) {
175                 if (cur == chan) {
176                         if (last)
177                                 last->next = cur->next;
178                         else
179                                 channels = cur->next;
180                         break;
181                 }
182                 last = cur;
183                 cur = cur->next;
184         }
185         if (!cur)
186                 ast_log(LOG_WARNING, "Unable to find channel in list\n");
187         if (chan->pvt->pvt)
188                 ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
189         /* Free translatosr */
190         if (chan->pvt->readtrans)
191                 ast_translator_free_path(chan->pvt->readtrans);
192         if (chan->pvt->writetrans)
193                 ast_translator_free_path(chan->pvt->writetrans);
194         if (chan->pbx) 
195                 ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
196         if (chan->dnid)
197                 free(chan->dnid);
198         if (chan->callerid)
199                 free(chan->callerid);   
200         pthread_mutex_destroy(&chan->lock);
201         free(chan->pvt);
202         free(chan);
203         PTHREAD_MUTEX_UNLOCK(&chlock);
204 }
205
206 int ast_softhangup(struct ast_channel *chan)
207 {
208         int res = 0;
209         if (chan->stream)
210                 ast_stopstream(chan);
211         if (option_debug)
212                 ast_log(LOG_DEBUG, "Soft-Hanging up channel '%s'\n", chan->name);
213         if (chan->pvt->hangup)
214                 res = chan->pvt->hangup(chan);
215         if (chan->pvt->pvt)
216                 ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
217         if (chan->pbx) 
218                 ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);        
219         /* Interrupt any select call or such */
220         if (chan->blocking)
221                 pthread_kill(chan->blocker, SIGURG);
222         return res;
223 }
224
225 int ast_hangup(struct ast_channel *chan)
226 {
227         int res = 0;
228         if (chan->stream)
229                 ast_stopstream(chan);
230         if (chan->sched)
231                 sched_context_destroy(chan->sched);
232         if (chan->blocking) {
233                 ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd "
234                                         "is blocked by thread %ld in procedure %s!  Expect a failure\n",
235                                         pthread_self(), chan->name, chan->blocker, chan->blockproc);
236                 CRASH;
237         }
238         if (option_debug)
239                 ast_log(LOG_DEBUG, "Hanging up channel '%s'\n", chan->name);
240         if (chan->pvt->hangup)
241                 res = chan->pvt->hangup(chan);
242         ast_channel_free(chan);
243         return res;
244 }
245
246 void ast_channel_unregister(char *type)
247 {
248         struct chanlist *chan, *last=NULL;
249         if (option_debug)
250                 ast_log(LOG_DEBUG, "Unregistering channel type '%s'\n", type);
251         if (PTHREAD_MUTEX_LOCK(&chlock)) {
252                 ast_log(LOG_WARNING, "Unable to lock channel list\n");
253                 return;
254         }
255         chan = backends;
256         while(chan) {
257                 if (!strcasecmp(chan->type, type)) {
258                         if (last)
259                                 last->next = chan->next;
260                         else
261                                 backends = backends->next;
262                         free(chan);
263                         PTHREAD_MUTEX_UNLOCK(&chlock);
264                         return;
265                 }
266                 last = chan;
267                 chan = chan->next;
268         }
269         PTHREAD_MUTEX_UNLOCK(&chlock);
270 }
271
272 int ast_answer(struct ast_channel *chan)
273 {
274         /* Answer the line, if possible */
275         if (chan->state == AST_STATE_RING) {
276                 if (chan->pvt->answer)
277                         return chan->pvt->answer(chan);
278         }
279         return 0;
280 }
281
282 int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
283 {
284         /* Wait for x amount of time on a file descriptor to have input.  */
285         struct timeval tv;
286         fd_set rfds, efds;
287         int res;
288         int x, max=-1;
289         int winner = -1;
290         
291         tv.tv_sec = *ms / 1000;
292         tv.tv_usec = (*ms % 1000) * 1000;
293         FD_ZERO(&rfds);
294         FD_ZERO(&efds);
295         for (x=0;x<n;x++) {
296                 FD_SET(fds[x], &rfds);
297                 FD_SET(fds[x], &efds);
298                 if (fds[x] > max)
299                         max = fds[x];
300         }
301         if (*ms >= 0) 
302                 res = select(max + 1, &rfds, NULL, &efds, &tv);
303         else
304                 res = select(max + 1, &rfds, NULL, &efds, NULL);
305         for (x=0;x<n;x++) {
306                 if ((FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && (winner < 0)) {
307                         if (exception)
308                                 *exception = FD_ISSET(fds[x], &efds);
309                         winner = fds[x];
310                 }
311         }
312         *ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
313         if (res < 0)
314                 *ms = -10;
315         return winner;
316 }
317
318 struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
319 {
320         /* Wait for x amount of time on a file descriptor to have input.  */
321         struct timeval tv;
322         fd_set rfds, efds;
323         int res;
324         int x, max=-1;
325         struct ast_channel *winner = NULL;
326         
327         tv.tv_sec = *ms / 1000;
328         tv.tv_usec = (*ms % 1000) * 1000;
329         FD_ZERO(&rfds);
330         FD_ZERO(&efds);
331         for (x=0;x<n;x++) {
332                 FD_SET(c[x]->fd, &rfds);
333                 FD_SET(c[x]->fd, &efds);
334                 CHECK_BLOCKING(c[x]);
335                 if (c[x]->fd > max)
336                         max = c[x]->fd;
337         }
338         if (*ms >= 0) 
339                 res = select(max + 1, &rfds, NULL, &efds, &tv);
340         else
341                 res = select(max + 1, &rfds, NULL, &efds, NULL);
342         for (x=0;x<n;x++) {
343                 c[x]->blocking = 0;
344                 if ((FD_ISSET(c[x]->fd, &rfds) || FD_ISSET(c[x]->fd, &efds)) && !winner) {
345                         /* Set exception flag if appropriate */
346                         if (FD_ISSET(c[x]->fd, &efds))
347                                 c[x]->exception = 1;
348                         winner = c[x];
349                 }
350         }
351         *ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
352         if (res < 0)
353                 *ms = -10;
354         return winner;
355 }
356
357 int ast_waitfor(struct ast_channel *c, int ms)
358 {
359         if (ast_waitfor_n(&c, 1, &ms)) {
360                 if (ms < 0)
361                         return -ms;
362                 return ms;
363         }
364         /* Error if ms < 0 */
365         if (ms < 0) 
366                 return -1;
367         return 0;
368 }
369
370 char ast_waitfordigit(struct ast_channel *c, int ms)
371 {
372         struct ast_frame *f;
373         char result = 0;
374         /* Wait for a digit, no more than ms milliseconds total. */
375         while(ms && !result) {
376                 ms = ast_waitfor(c, ms);
377                 if (ms < 0) /* Error */
378                         result = -1; 
379                 else if (ms > 0) {
380                         /* Read something */
381                         f = ast_read(c);
382                         if (f) {
383                                 if (f->frametype == AST_FRAME_DTMF) 
384                                         result = f->subclass;
385                                 ast_frfree(f);
386                         } else
387                                 result = -1;
388                 }
389         }
390         return result;
391 }
392
393 struct ast_frame *ast_read(struct ast_channel *chan)
394 {
395         struct ast_frame *f = NULL;
396         static struct ast_frame null_frame = 
397         {
398                 AST_FRAME_NULL,
399         };
400         chan->blocker = pthread_self();
401         if (chan->exception) {
402                 if (chan->pvt->exception) 
403                         f = chan->pvt->exception(chan);
404                 else
405                         ast_log(LOG_WARNING, "Exception flag set, but no exception handler\n");
406                 /* Clear the exception flag */
407                 chan->exception = 0;
408         } else
409         if (chan->pvt->read)
410                 f = chan->pvt->read(chan);
411         else
412                 ast_log(LOG_WARNING, "No read routine on channel %s\n", chan);
413         if (f && (f->frametype == AST_FRAME_VOICE)) {
414                 if (chan->pvt->readtrans) {
415                         f = ast_translate(chan->pvt->readtrans, f, 1);
416                         if (!f)
417                                 f = &null_frame;
418                 }
419         }
420         return f;
421 }
422
423 int ast_sendtext(struct ast_channel *chan, char *text)
424 {
425         int res = 0;
426         CHECK_BLOCKING(chan);
427         if (chan->pvt->send_text)
428                 res = chan->pvt->send_text(chan, text);
429         chan->blocking = 0;
430         return res;
431 }
432
433 int ast_write(struct ast_channel *chan, struct ast_frame *fr)
434 {
435         int res = -1;
436         struct ast_frame *f;
437         CHECK_BLOCKING(chan);
438         switch(fr->frametype) {
439         case AST_FRAME_CONTROL:
440                 /* XXX Interpret control frames XXX */
441                 ast_log(LOG_WARNING, "Don't know how to handle control frames yet\n");
442                 break;
443         case AST_FRAME_DTMF:
444                 
445                 if (chan->pvt->send_digit)
446                         res = chan->pvt->send_digit(chan, fr->subclass);
447                 break;
448         default:
449                 if (chan->pvt->write) {
450                         if (chan->pvt->writetrans) {
451                                 f = ast_translate(chan->pvt->writetrans, fr, 1);
452                         } else
453                                 f = fr;
454                         if (f)  
455                                 res = chan->pvt->write(chan, f);
456                 }
457         }
458         chan->blocking = 0;
459         return res;
460 }
461
462 int ast_set_write_format(struct ast_channel *chan, int fmts)
463 {
464         int fmt;
465         int native;
466         int res;
467         
468         native = chan->nativeformats;
469         fmt = fmts;
470         
471         res = ast_translator_best_choice(&native, &fmt);
472         if (res < 0) {
473                 ast_log(LOG_NOTICE, "Unable to find a path from %d to %d\n", fmts, chan->nativeformats);
474                 return -1;
475         }
476         
477         /* Now we have a good choice for both.  We'll write using our native format. */
478         chan->pvt->rawwriteformat = native;
479         /* User perspective is fmt */
480         chan->writeformat = fmt;
481         /* Free any write translation we have right now */
482         if (chan->pvt->writetrans)
483                 ast_translator_free_path(chan->pvt->writetrans);
484         /* Build a translation path from the user write format to the raw writing format */
485         chan->pvt->writetrans = ast_translator_build_path(chan->pvt->rawwriteformat, chan->writeformat);
486         ast_log(LOG_DEBUG, "Set channel %s to format %d\n", chan->name, chan->writeformat);
487         return 0;
488 }
489
490 int ast_set_read_format(struct ast_channel *chan, int fmts)
491 {
492         int fmt;
493         int native;
494         int res;
495         
496         native = chan->nativeformats;
497         fmt = fmts;
498         /* Find a translation path from the native read format to one of the user's read formats */
499         res = ast_translator_best_choice(&fmt, &native);
500         if (res < 0) {
501                 ast_log(LOG_NOTICE, "Unable to find a path from %d to %d\n", chan->nativeformats, fmts);
502                 return -1;
503         }
504         
505         /* Now we have a good choice for both.  We'll write using our native format. */
506         chan->pvt->rawreadformat = native;
507         /* User perspective is fmt */
508         chan->readformat = fmt;
509         /* Free any read translation we have right now */
510         if (chan->pvt->readtrans)
511                 ast_translator_free_path(chan->pvt->readtrans);
512         /* Build a translation path from the raw read format to the user reading format */
513         chan->pvt->readtrans = ast_translator_build_path(chan->readformat, chan->pvt->rawreadformat);
514         return 0;
515 }
516
517 struct ast_channel *ast_request(char *type, int format, void *data)
518 {
519         struct chanlist *chan;
520         struct ast_channel *c = NULL;
521         int capabilities;
522         int fmt;
523         int res;
524         if (PTHREAD_MUTEX_LOCK(&chlock)) {
525                 ast_log(LOG_WARNING, "Unable to lock channel list\n");
526                 return NULL;
527         }
528         chan = backends;
529         while(chan) {
530                 if (!strcasecmp(type, chan->type)) {
531                         capabilities = chan->capabilities;
532                         fmt = format;
533                         res = ast_translator_best_choice(&fmt, &capabilities);
534                         if (res < 0) {
535                                 ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %d) to %d\n", type, chan->capabilities, format);
536                                 PTHREAD_MUTEX_UNLOCK(&chlock);
537                                 return NULL;
538                         }
539                         PTHREAD_MUTEX_UNLOCK(&chlock);
540                         if (chan->requester)
541                                 c = chan->requester(type, capabilities, data);
542                         return c;
543                 }
544                 chan = chan->next;
545         }
546         if (!chan)
547                 ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
548         PTHREAD_MUTEX_UNLOCK(&chlock);
549         return c;
550 }
551
552 int ast_call(struct ast_channel *chan, char *addr, int timeout) 
553 {
554         /* Place an outgoing call, but don't wait any longer than timeout ms before returning. 
555            If the remote end does not answer within the timeout, then do NOT hang up, but 
556            return anyway.  */
557         int res = -1;
558         if (chan->pvt->call)
559                 res = chan->pvt->call(chan, addr, timeout);
560         return res;
561 }
562
563 int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders)
564 {
565         int pos=0;
566         int to = ftimeout;
567         char d;
568         if (!len)
569                 return -1;
570         do {
571                 if (c->streamid > -1) {
572                         d = ast_waitstream(c, AST_DIGIT_ANY);
573                         ast_stopstream(c);
574                         usleep(1000);
575                         if (!d)
576                                 d = ast_waitfordigit(c, to);
577                 } else {
578                         d = ast_waitfordigit(c, to);
579                 }
580                 if (d < 0)
581                         return -1;
582                 if (!strchr(enders, d))
583                         s[pos++] = d;
584                 if ((d == 0) || strchr(enders, d) || (pos >= len - 1)) {
585                         s[pos]='\0';
586                         return 0;
587                 }
588                 to = timeout;
589         } while(1);
590         /* Never reached */
591         return 0;
592 }
593
594 int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
595 {
596         int peerf;
597         int chanf;
598         int res;
599         peerf = peer->nativeformats;
600         chanf = chan->nativeformats;
601         res = ast_translator_best_choice(&peerf, &chanf);
602         if (res < 0) {
603                 ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan, chan->nativeformats, peer, peer->nativeformats);
604                 return -1;
605         }
606         /* Set read format on channel */
607         res = ast_set_read_format(chan, peerf);
608         if (res < 0) {
609                 ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", chan, chanf);
610                 return -1;
611         }
612         /* Set write format on peer channel */
613         res = ast_set_write_format(peer, peerf);
614         if (res < 0) {
615                 ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", peer, peerf);
616                 return -1;
617         }
618         /* Now we go the other way */
619         peerf = peer->nativeformats;
620         chanf = chan->nativeformats;
621         res = ast_translator_best_choice(&chanf, &peerf);
622         if (res < 0) {
623                 ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer, peer->nativeformats, chan, chan->nativeformats);
624                 return -1;
625         }
626         /* Set writeformat on channel */
627         res = ast_set_write_format(chan, chanf);
628         if (res < 0) {
629                 ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", chan, chanf);
630                 return -1;
631         }
632         /* Set read format on peer channel */
633         res = ast_set_read_format(peer, chanf);
634         if (res < 0) {
635                 ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", peer, peerf);
636                 return -1;
637         }
638         return 0;
639 }
640
641
642
643 int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
644 {
645         /* Copy voice back and forth between the two channels.  Give the peer
646            the ability to transfer calls with '#<extension' syntax. */
647         struct ast_channel *cs[3];
648         int to = -1;
649         struct ast_frame *f;
650         struct ast_channel *who;
651         if (c0->pvt->bridge && 
652                 (c0->pvt->bridge == c1->pvt->bridge)) {
653                         /* Looks like they share a bridge code */
654                 if (!c0->pvt->bridge(c0, c1, flags, fo, rc))
655                         return 0;
656                 ast_log(LOG_WARNING, "Private bridge between %s and %s failed\n", c0->name, c1->name);
657                 /* If they return non-zero then continue on normally */
658         }
659         
660         
661         
662         cs[0] = c0;
663         cs[1] = c1;
664         for (/* ever */;;) {
665                 who = ast_waitfor_n(cs, 2, &to);
666                 if (!who) {
667                         ast_log(LOG_WARNING, "Nobody there??\n");
668                         continue;
669                 }
670                 f = ast_read(who);
671                 if (!f) {
672                         *fo = NULL;
673                         *rc = who;
674                         return 0;
675                 }
676                 if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
677                         *fo = f;
678                         *rc = who;
679                         return 0;
680                 }
681                 if ((f->frametype == AST_FRAME_VOICE) ||
682                         (f->frametype == AST_FRAME_TEXT) ||
683                         (f->frametype == AST_FRAME_VIDEO) || 
684                         (f->frametype == AST_FRAME_IMAGE) ||
685                         (f->frametype == AST_FRAME_DTMF)) {
686                         if ((f->frametype == AST_FRAME_DTMF) && (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
687                                 if ((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
688                                         *rc = c0;
689                                         *fo = f;
690                                         /* Take out of conference mode */
691                                         return 0;
692                                 } else
693                                 if ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)) {
694                                         *rc = c1;
695                                         *fo = f;
696                                         return 0;
697                                 }
698                         } else {
699 #if 0
700                                 ast_log(LOG_DEBUG, "Read from %s\n", who->name);
701                                 if (who == last) 
702                                         ast_log(LOG_DEBUG, "Servicing channel %s twice in a row?\n", last->name);
703                                 last = who;
704 #endif
705                                 if (who == c0) 
706                                         ast_write(c1, f);
707                                 else 
708                                         ast_write(c0, f);
709                         }
710                         ast_frfree(f);
711                 } else
712                         ast_frfree(f);
713                 /* Swap who gets priority */
714                 cs[2] = cs[0];
715                 cs[0] = cs[1];
716                 cs[1] = cs[2];
717         }
718         return 0;
719 }