Version 0.1.3 from FTP
[asterisk/asterisk.git] / translate.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Translate via the use of pseudo channels
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 <asterisk/channel.h>
15 #include <asterisk/channel_pvt.h>
16 #include <asterisk/logger.h>
17 #include <asterisk/translate.h>
18 #include <asterisk/options.h>
19 #include <asterisk/frame.h>
20 #include <asterisk/sched.h>
21 #include <asterisk/cli.h>
22 #include <sys/socket.h>
23 #include <sys/time.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <pthread.h>
27 #include <string.h>
28 #include <stdio.h>
29
30 /* Uncomment the EXPERIMENTAL_TRANSLATION to enable a more complicated, but probably more
31    correct way of handling full duplex translation */
32
33 /*
34 #define EXPERIMENTAL_TRANSLATION
35 */
36
37 /* This could all be done more efficiently *IF* we chained packets together
38    by default, but it would also complicate virtually every application. */
39    
40 static char *type = "Trans";
41
42 static pthread_mutex_t list_lock = PTHREAD_MUTEX_INITIALIZER;
43 static struct ast_translator *list = NULL;
44
45 struct ast_translator_dir {
46         struct ast_translator *step;    /* Next step translator */
47         int cost;                                               /* Complete cost to destination */
48 };
49
50 struct ast_frame_delivery {
51         struct ast_frame *f;
52         struct ast_channel *chan;
53         int fd;
54         struct translator_pvt *owner;
55         struct ast_frame_delivery *prev;
56         struct ast_frame_delivery *next;
57 };
58
59 static struct ast_translator_dir tr_matrix[MAX_FORMAT][MAX_FORMAT];
60
61 struct ast_trans_pvt {
62         struct ast_translator *step;
63         struct ast_translator_pvt *state;
64         struct ast_trans_pvt *next;
65 };
66
67
68 static int powerof(int d)
69 {
70         int x;
71         for (x = 0; x < 32; x++)
72                 if ((1 << x) & d)
73                         return x;
74         ast_log(LOG_WARNING, "Powerof %d: No power??\n", d);
75         return -1;
76 }
77
78 struct translator_pvt {
79         /* Sockets for communication */
80         int comm[2];
81         struct ast_trans_pvt *system;
82         struct ast_trans_pvt *rsystem;
83         struct timeval lastpass;
84 #ifdef EXPERIMENTAL_TRANSLATION
85         struct ast_frame_delivery *head;
86         struct ast_frame_delivery *tail;
87         struct sched_context *sched;
88 #endif
89         pthread_t       threadid;
90 };
91
92
93 #ifdef EXPERIMENTAL_TRANSLATION
94 static int deliver(void *data)
95 {
96         struct ast_frame_delivery *del = data;
97         ast_log(LOG_DEBUG, "Delivering a packet\n");
98         if (del->f) {
99                 if (del->chan)
100                         ast_write(del->chan, del->f);
101                 else
102                         ast_fr_fdwrite(del->fd, del->f);
103                 ast_frfree(del->f);
104         }
105         /* Take us out of the list */
106         if (del->prev) 
107                 del->prev->next = del->next;
108         else
109                 del->owner->head = del->next;
110         if (del->next)
111                 del->next->prev = del->prev;
112         else
113                 del->owner->tail = del->prev;
114         /* Free used memory */
115         free(del);
116         /* Never run again */
117         return 0;
118 }
119
120 /* Schedule the delivery of a packet in the near future, using the given context */
121 static int schedule_delivery(struct sched_context *sched, struct translator_pvt *p, struct ast_channel *c, 
122                                                         int fd, struct ast_frame *f, int ms)
123 {
124         struct ast_frame_delivery *del;
125         ast_log(LOG_DEBUG, "Scheduling a packet delivery\n");
126         del = malloc(sizeof(struct ast_frame_delivery));
127         if (del) {
128                 del->f = ast_frdup(f);
129                 del->chan = c;
130                 del->fd = fd;
131                 del->owner = p;
132                 if (p->tail) {
133                         del->prev = p->tail;
134                         p->tail = del;
135                         del->next = NULL;
136                 } else {
137                         p->head = p->tail = del;
138                         del->next = NULL;
139                         del->prev = NULL;
140                 }
141                 ast_sched_add(sched, ms, deliver, del);
142                 return 0;       
143         } else
144                 return -1;
145 }
146 #endif
147 static int translator_hangup(struct ast_channel *chan)
148 {
149         ast_log(LOG_WARNING, "Explicit hangup on '%s' not recommended!  Call translator_destroy() instead.\n", chan->name);
150         chan->master->trans = NULL;
151         ast_hangup(chan->master);
152         chan->master = NULL;
153         return 0;
154 }
155
156 static int translator_send_digit(struct ast_channel *chan, char digit)
157 {
158         /* Pass digits right along */
159         if (chan->master->pvt->send_digit)
160                 return chan->master->pvt->send_digit(chan->master, digit);
161         return -1;
162 }
163
164 static int translator_call(struct ast_channel *chan, char *addr, int timeout)
165 {
166         if (chan->master->pvt->call)
167                 return chan->master->pvt->call(chan->master, addr, timeout);
168         return -1;
169 }
170
171 static int translator_answer(struct ast_channel *chan)
172 {
173         if (chan->master->pvt->answer)
174                 return chan->master->pvt->answer(chan->master);
175         return -1;
176 }
177
178 void ast_translator_free_path(struct ast_trans_pvt *p)
179 {
180         struct ast_trans_pvt *pl;
181         while(p) {
182                 pl = p;
183                 p = p->next;
184                 if (pl->state && pl->step->destroy)
185                         pl->step->destroy(pl->state);
186                 free(pl);
187         }
188 }
189
190 static void ast_translator_free(struct translator_pvt *pvt)
191 {
192 #ifdef EXPERIMENTAL_TRANSLATION
193         struct ast_frame_delivery *d, *dl;
194         if (pvt->sched)
195                 sched_context_destroy(pvt->sched);
196         d = pvt->head;
197         while(d) {
198                 dl = d;
199                 d = d->next;
200                 ast_frfree(dl->f);
201                 free(dl);
202         }
203 #endif
204         ast_translator_free_path(pvt->system);
205         ast_translator_free_path(pvt->rsystem);
206         if (pvt->comm[0] > -1)
207                 close(pvt->comm[0]);
208         if (pvt->comm[1] > -1)
209                 close(pvt->comm[1]);
210         free(pvt);
211 }
212
213 struct ast_trans_pvt *ast_translator_build_path(int source, int dest)
214 {
215         struct ast_trans_pvt *tmpr = NULL, *tmp = NULL;
216         /* One of the hardest parts:  Build a set of translators based upon
217            the given source and destination formats */
218         source = powerof(source);
219         dest = powerof(dest);
220         while(source != dest) {
221                 if (tr_matrix[source][dest].step) {
222                         if (tmp) {
223                                 tmp->next = malloc(sizeof(struct ast_trans_pvt));
224                                 tmp = tmp->next;
225                         } else
226                                 tmp = malloc(sizeof(struct ast_trans_pvt));
227
228                                 
229                         if (tmp) {
230                                 tmp->next = NULL;
231                                 tmp->step = tr_matrix[source][dest].step;
232                                 tmp->state = tmp->step->new();
233                                 if (!tmp->state) {
234                                         free(tmp);
235                                         tmp = NULL;
236                                 }
237                                 /* Set the root, if it doesn't exist yet... */
238                                 if (!tmpr)
239                                         tmpr = tmp;
240                                 /* Keep going if this isn't the final destination */
241                                 source = tmp->step->dstfmt;
242                         } else {
243                                 /* XXX This could leak XXX */
244                                 ast_log(LOG_WARNING, "Out of memory\n");
245                                 return NULL;
246                         }
247                 } else {
248                         /* We shouldn't have allocated any memory */
249                         ast_log(LOG_WARNING, "No translator path from %d to %d\n", source, dest);
250                         return NULL;
251                 }
252         }
253         return tmpr;
254 }
255
256 static struct ast_frame *translator_read(struct ast_channel *chan)
257 {
258         return ast_fr_fdread(chan->fd);
259 }
260
261 static int translator_write(struct ast_channel *chan, struct ast_frame *frame)
262 {
263         return ast_fr_fdwrite(chan->fd, frame);
264 }
265
266 struct ast_frame_chain *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f)
267 {
268         struct ast_trans_pvt *p;
269         struct ast_frame *out;
270         struct ast_frame_chain *outc = NULL, *prev = NULL, *cur;
271         p = path;
272         /* Feed the first frame into the first translator */
273         p->step->framein(p->state, f);
274         while(p) {
275                 /* Read all the frames from the current translator */
276                 while((out = p->step->frameout(p->state)))  {
277                         if (p->next) {
278                                 /* Feed to next layer */
279                                 p->next->step->framein(p->next->state, out);
280                         } else {
281                                 /* Last layer -- actually do something */
282                                 cur = malloc(sizeof(struct ast_frame_chain));
283                                 if (!cur) {
284                                         /* XXX Leak majorly on a problem XXX */
285                                         ast_log(LOG_WARNING, "Out of memory\n");
286                                         return NULL;
287                                 }
288                                 if (prev) 
289                                         prev->next = cur;
290                                 else
291                                         outc = cur;
292                                 cur->fr = ast_frisolate(out);
293                                 cur->next = NULL;
294                                 if (prev)
295                                         prev = prev->next;
296                                 else
297                                         prev = outc;
298                         }
299                 }
300                 p = p->next;
301         }
302         return outc;
303 }
304
305 #define FUDGE 0
306
307 static void translator_apply(struct translator_pvt *pvt, struct ast_trans_pvt *path, struct ast_frame *f, int fd, struct ast_channel *c, struct timeval *last)
308 {
309         struct ast_trans_pvt *p;
310         struct ast_frame *out;
311         struct timeval tv;
312         int ms;
313         p = path;
314         /* Feed the first frame into the first translator */
315         p->step->framein(p->state, f);
316         while(p) {
317                 /* Read all the frames from the current translator */
318                 while((out = p->step->frameout(p->state)))  {
319                         if (p->next) {
320                                 /* Feed to next layer */
321                                 p->next->step->framein(p->next->state, out);
322                         } else {
323                                 /* Delay if needed */
324                                 if (last->tv_sec || last->tv_usec) {
325                                         gettimeofday(&tv, NULL);
326                                         ms = 1000 * (tv.tv_sec - last->tv_sec) +
327                                                 (tv.tv_usec - last->tv_usec) / 1000;
328 #ifdef EXPERIMENTAL_TRANSLATION
329                                         if (ms + FUDGE < out->timelen) 
330                                                 schedule_delivery(pvt->sched, pvt, 
331                                                                                         c, fd, out, ms);
332                                         else {
333                                                 if (c)
334                                                         ast_write(c, out);
335                                                 else
336                                                         ast_fr_fdwrite(fd, out);
337                                         }
338                                         last->tv_sec = tv.tv_sec;
339                                         last->tv_usec = tv.tv_usec;
340                                         /* Schedule this packet to be delivered at the
341                                            right time */
342                                 } else
343 #else
344                                         /* XXX Not correct in the full duplex case XXX */
345                                         if (ms + FUDGE < out->timelen) 
346                                                 usleep((out->timelen - ms - FUDGE) * 1000);
347                                         last->tv_sec = tv.tv_sec;
348                                         last->tv_usec = tv.tv_usec;
349                                 }
350 #endif
351                                 if (c)
352                                         ast_write(c, out);
353                                 else
354                                         ast_fr_fdwrite(fd, out);
355                         }
356                         ast_frfree(out);
357                 }
358                 p = p->next;
359         }
360 }
361
362 static void *translator_thread(void *data)
363 {
364         struct ast_channel *real = data;
365         struct ast_frame *f;
366         int ms = -1;
367         struct translator_pvt *pvt = NULL;
368         int fd = -1;
369         int fds[2];
370         int res;
371         /* Read from the real, translate, write as necessary to the fake */
372         for(;;) {
373                 /* Break here if need be */
374                 pthread_testcancel();
375                 if (!real->trans) {
376                         ast_log(LOG_WARNING, "No translator anymore\n");
377                         break;
378                 }
379                 pvt = real->trans->pvt->pvt;
380                 fd = pvt->comm[1];
381                 fds[0] = fd;
382                 fds[1] = real->fd;
383                 CHECK_BLOCKING(real);
384                 res = ast_waitfor_n_fd(fds, 2, &ms);
385                 real->blocking = 0;
386                 /* Or we can die here, that's fine too */
387                 pthread_testcancel();
388                 if (res >= 0) {
389                         if (res == real->fd) {
390                                 f = ast_read(real);
391                                 if (!f) {
392                                         if (option_debug)
393                                                 ast_log(LOG_DEBUG, "Empty frame\n");
394                                         break;
395                                 }
396                                 if (f->frametype ==  AST_FRAME_VOICE) {
397                                         if (pvt->system)
398                                                 translator_apply(pvt, pvt->system, f, fd, NULL, &pvt->lastpass);
399                                 } else {
400                                         /* If it's not voice, just pass it along */
401                                         ast_fr_fdwrite(fd, f);
402                                 }
403                                 ast_frfree(f);
404                         } else {
405                                 f = ast_fr_fdread(res);
406                                 if (!f) {
407                                         if (option_debug)
408                                                 ast_log(LOG_DEBUG, "Empty (hangup) frame\n");
409                                         break;
410                                 }
411                                 
412                                 if (f->frametype == AST_FRAME_VOICE) {
413                                         if (pvt->rsystem)
414                                                 translator_apply(pvt, pvt->rsystem, f, -1, real, &pvt->lastpass);
415                                 } else {
416                                         ast_write(real, f);
417                                 }
418                                 ast_frfree(f);
419                         }
420                 } else {
421                         ast_log(LOG_DEBUG, "Waitfor returned non-zero\n");
422                         break;
423                 }
424         }
425         if (pvt)
426                 pvt->comm[1] = -1;
427         if (fd > -1) {
428                 /* Write a bogus frame */
429                 write(fd, data, 1);
430                 close(fd);
431         }
432         return NULL;
433 }
434
435 struct ast_channel *ast_translator_create(struct ast_channel *real, int format, int direction)
436 {
437         struct ast_channel *tmp;
438         struct translator_pvt *pvt;
439         if (real->trans) {
440                 ast_log(LOG_WARNING, "Translator already exists on '%s'\n", real->name);
441                 return NULL;
442         }
443         if (!(pvt = malloc(sizeof(struct translator_pvt)))) {
444                 ast_log(LOG_WARNING, "Unable to allocate private translator on '%s'\n", real->name);
445                 return NULL;
446         }
447         pvt->comm[0] = -1;
448         pvt->comm[1] = -1;
449         pvt->lastpass.tv_usec = 0;
450         pvt->lastpass.tv_sec = 0;
451
452 #ifdef EXPERIMENTAL_TRANSLATION 
453         pvt->head = NULL;
454         pvt->tail = NULL;
455         pvt->sched = sched_context_create();
456         if (!pvt->sched) {
457                 ast_log(LOG_WARNING, "Out of memory\n");
458                 ast_translator_free(pvt);
459                 return NULL;
460         }
461 #endif
462         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pvt->comm)) {
463                 ast_log(LOG_WARNING, "Unable to create UNIX domain socket on '%s'\n", real->name);
464                 ast_translator_free(pvt);
465                 return NULL;
466         }
467         /* In to the system */
468         if (direction & AST_DIRECTION_IN)
469                 pvt->system = ast_translator_build_path(real->format, format);
470         else
471                 pvt->system = NULL;
472         /* Out from the system */
473         if (direction & AST_DIRECTION_OUT)
474                 pvt->rsystem = ast_translator_build_path(format, real->format);
475         else
476                 pvt->rsystem = NULL;
477         if (!pvt->system && !pvt->rsystem) {
478                 ast_log(LOG_WARNING, "Unable to build a translation path for %s (%d to %d)\n", real->name, real->format, format);
479                 ast_translator_free(pvt);
480                 return NULL;
481         }
482         if (!pvt->system && (direction & AST_DIRECTION_IN)) {
483                 ast_log(LOG_WARNING, "Translation path for '%s' is one-way (reverse)\n", real->name);
484                 ast_translator_free(pvt);
485                 return NULL;
486         }
487         if (!pvt->rsystem && (direction & AST_DIRECTION_OUT)) {
488                 ast_log(LOG_WARNING, "Translation path for '%s' is one-way (forward)\n", real->name);
489                 ast_translator_free(pvt);
490                 return NULL;
491         }
492         if ((tmp = ast_channel_alloc())) {
493                 snprintf(tmp->name, sizeof(tmp->name), "%s/Translate:%d", real->name, format);
494                 tmp->type = type;
495                 tmp->fd = pvt->comm[0];
496                 tmp->format = format;
497                 tmp->state = real->state;
498                 tmp->rings = 0;
499                 tmp->pvt->pvt = pvt;
500                 tmp->master = real;
501                 tmp->pvt->send_digit = translator_send_digit;
502                 tmp->pvt->call = translator_call;
503                 tmp->pvt->hangup = translator_hangup;
504                 tmp->pvt->answer = translator_answer;
505                 tmp->pvt->read = translator_read;
506                 tmp->pvt->write = translator_write;
507                 tmp->pvt->pvt = pvt;
508                 real->trans = tmp;
509                 if (option_verbose > 2)
510                         ast_verbose(VERBOSE_PREFIX_3 "Created translator %s\n", tmp->name);
511                 if (pthread_create(&pvt->threadid, NULL, translator_thread, real) < 0) {
512                         ast_translator_destroy(tmp);
513                         tmp = NULL;
514                         ast_log(LOG_WARNING, "Failed to start thread\n");
515                 }
516         } else {
517                 ast_translator_free(pvt);
518                 ast_log(LOG_WARNING, "Unable to allocate channel\n");
519         }
520         return tmp;
521
522
523 static void rebuild_matrix()
524 {
525         struct ast_translator *t;
526         int changed;
527         int x,y,z;
528         if (option_debug)
529                 ast_log(LOG_DEBUG, "Reseting translation matrix\n");
530         /* Use the list of translators to build a translation matrix */
531         bzero(tr_matrix, sizeof(tr_matrix));
532         t = list;
533         while(t) {
534                 if (!tr_matrix[t->srcfmt][t->dstfmt].step ||
535                      tr_matrix[t->srcfmt][t->dstfmt].cost > t->cost) {
536                         tr_matrix[t->srcfmt][t->dstfmt].step = t;
537                         tr_matrix[t->srcfmt][t->dstfmt].cost = t->cost;
538                 }
539                 t = t->next;
540         }
541         do {
542                 changed = 0;
543                 /* Don't you just love O(N^3) operations? */
544                 for (x=0; x< MAX_FORMAT; x++)                           /* For each source format */
545                         for (y=0; y < MAX_FORMAT; y++)                  /* And each destination format */
546                                 if (x != y)                                                     /* Except ourselves, of course */
547                                         for (z=0; z < MAX_FORMAT; z++)  /* And each format it might convert to */
548                                                 if ((x!=z) && (y!=z))           /* Don't ever convert back to us */
549                                                         if (tr_matrix[x][y].step && /* We can convert from x to y */
550                                                                 tr_matrix[y][z].step && /* And from y to z and... */
551                                                                 (!tr_matrix[x][z].step ||       /* Either there isn't an x->z conversion */
552                                                                 (tr_matrix[x][y].cost + 
553                                                                  tr_matrix[y][z].cost < /* Or we're cheaper than the existing */
554                                                                  tr_matrix[x][z].cost)  /* solution */
555                                                              )) {
556                                                                                         /* We can get from x to z via y with a cost that
557                                                                                            is the sum of the transition from x to y and
558                                                                                            from y to z */
559                                                                  
560                                                                         tr_matrix[x][z].step = tr_matrix[x][y].step;
561                                                                         tr_matrix[x][z].cost = tr_matrix[x][y].cost + 
562                                                                                                                    tr_matrix[y][z].cost;
563                                                                         if (option_debug)
564                                                                                 ast_log(LOG_DEBUG, "Discovered %d cost path from %d to %d, via %d\n", tr_matrix[x][z].cost, x, z, y);
565                                                                         changed++;
566                                                                  }
567                 
568         } while (changed);
569 }
570
571 static void calc_cost(struct ast_translator *t)
572 {
573         int sofar=0;
574         struct ast_translator_pvt *pvt;
575         struct ast_frame *f, *out;
576         struct timeval start, finish;
577         int cost;
578         /* If they don't make samples, give them a terrible score */
579         if (!t->sample) {
580                 ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
581                 t->cost = 99999;
582                 return;
583         }
584         pvt = t->new();
585         if (!pvt) {
586                 ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
587                 t->cost = 99999;
588                 return;
589         }
590         gettimeofday(&start, NULL);
591         /* Call the encoder until we've processed one second of time */
592         while(sofar < 1000) {
593                 f = t->sample();
594                 if (!f) {
595                         ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
596                         t->destroy(pvt);
597                         t->cost = 99999;
598                         return;
599                 }
600                 t->framein(pvt, f);
601                 ast_frfree(f);
602                 while((out = t->frameout(pvt))) {
603                         sofar += out->timelen;
604                         ast_frfree(out);
605                 }
606         }
607         gettimeofday(&finish, NULL);
608         t->destroy(pvt);
609         cost = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000;
610         t->cost = cost;
611 }
612
613 static int show_translation(int fd, int argc, char *argv[])
614 {
615 #define SHOW_TRANS 14
616         int x,y;
617         char line[80];
618         if (argc != 2) 
619                 return RESULT_SHOWUSAGE;
620         ast_cli(fd, "                        Translation times between formats (in milliseconds)\n");
621         ast_cli(fd, "                                 Destination Format\n");
622         pthread_mutex_lock(&list_lock);
623         for (x=0;x<SHOW_TRANS; x++) {
624                 if (x == 1) 
625                         strcpy(line, "  Src  ");
626                 else if (x == 2)
627                         strcpy(line, "  Fmt  ");
628                 else
629                         strcpy(line, "       ");
630                 for (y=0;y<SHOW_TRANS;y++) {
631                         if (tr_matrix[x][y].step)
632                                 snprintf(line + strlen(line), sizeof(line) - strlen(line), " %4d", tr_matrix[x][y].cost);
633                         else
634                                 snprintf(line + strlen(line), sizeof(line) - strlen(line), "  n/a");
635                 }
636                 snprintf(line + strlen(line), sizeof(line) - strlen(line), "\n");
637                 ast_cli(fd, line);                      
638         }
639         pthread_mutex_unlock(&list_lock);
640         return RESULT_SUCCESS;
641 }
642
643 static int added_cli = 0;
644
645 static char show_trans_usage[] =
646 "Usage: show translation\n"
647 "       Displays known codec translators and the cost associated\n"
648 "with each conversion.\n";
649
650 static struct ast_cli_entry show_trans =
651 { { "show", "translation", NULL }, show_translation, "Display translation matrix", show_trans_usage };
652
653 int ast_register_translator(struct ast_translator *t)
654 {
655         t->srcfmt = powerof(t->srcfmt);
656         t->dstfmt = powerof(t->dstfmt);
657         if ((t->srcfmt >= MAX_FORMAT) || (t->dstfmt >= MAX_FORMAT)) {
658                 ast_log(LOG_WARNING, "Format %d is larger than MAX_FORMAT\n", t->srcfmt);
659                 return -1;
660         }
661         calc_cost(t);
662         if (option_verbose > 1)
663                 ast_verbose(VERBOSE_PREFIX_2 "Registered translator '%s' from format %d to %d, cost %d\n", t->name, t->srcfmt, t->dstfmt, t->cost);
664         pthread_mutex_lock(&list_lock);
665         if (!added_cli) {
666                 ast_cli_register(&show_trans);
667                 added_cli++;
668         }
669         t->next = list;
670         list = t;
671         rebuild_matrix();
672         pthread_mutex_unlock(&list_lock);
673         return 0;
674 }
675
676 int ast_unregister_translator(struct ast_translator *t)
677 {
678         struct ast_translator *u, *ul = NULL;
679         pthread_mutex_lock(&list_lock);
680         u = list;
681         while(u) {
682                 if (u == t) {
683                         if (ul)
684                                 ul->next = u->next;
685                         else
686                                 list = u->next;
687                         break;
688                 }
689                 ul = u;
690                 u = u->next;
691         }
692         rebuild_matrix();
693         pthread_mutex_unlock(&list_lock);
694         return (u ? 0 : -1);
695 }
696
697 void ast_translator_destroy(struct ast_channel *trans)
698 {
699         struct translator_pvt *pvt;
700         if (!trans->master) {
701                 ast_log(LOG_WARNING, "Translator is not part of a real channel?\n");
702                 return;
703         }
704         if (trans->master->trans != trans) {
705                 ast_log(LOG_WARNING, "Translator is not the right one!?!?\n");
706                 return;
707         }
708         trans->master->trans = NULL;
709         pvt = trans->pvt->pvt;
710         /* Cancel the running translator thread */
711         pthread_cancel(pvt->threadid);
712         pthread_join(pvt->threadid, NULL);
713         ast_translator_free(pvt);
714         trans->pvt->pvt = NULL;
715         if (option_verbose > 2)
716                 ast_verbose(VERBOSE_PREFIX_3 "Destroyed translator %s\n", trans->name);
717         ast_channel_free(trans);
718 }
719
720 int ast_translator_best_choice(int dst, int srcs)
721 {
722         /* Calculate our best source format, given costs, and a desired destination */
723         int x,y;
724         int best=-1;
725         int cur = 1;
726         int besttime=999999999;
727         pthread_mutex_lock(&list_lock);
728         for (y=0;y<MAX_FORMAT;y++) {
729                 if (cur & dst)
730                         for (x=0;x<MAX_FORMAT;x++) {
731                                 if (tr_matrix[x][y].step &&     /* There's a step */
732                                  (tr_matrix[x][y].cost < besttime) && /* We're better than what exists now */
733                                         (srcs & (1 << x)))                      /* x is a valid source format */
734                                         {
735                                                 best = 1 << x;
736                                                 besttime = tr_matrix[x][dst].cost;
737                                         }
738                         }
739                 cur = cur << 1;
740         }
741         pthread_mutex_unlock(&list_lock);
742         return best;
743 }