Version 0.1.12 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, 
308                                                                 struct timeval *last)
309 {
310         struct ast_trans_pvt *p;
311         struct ast_frame *out;
312         struct timeval tv;
313         int ms;
314         p = path;
315         /* Feed the first frame into the first translator */
316         p->step->framein(p->state, f);
317         while(p) {
318                 /* Read all the frames from the current translator */
319                 while((out = p->step->frameout(p->state)))  {
320                         if (p->next) {
321                                 /* Feed to next layer */
322                                 p->next->step->framein(p->next->state, out);
323                         } else {
324                                 /* Delay if needed */
325                                 if (last->tv_sec || last->tv_usec) {
326                                         gettimeofday(&tv, NULL);
327                                         ms = 1000 * (tv.tv_sec - last->tv_sec) +
328                                                 (tv.tv_usec - last->tv_usec) / 1000;
329 #ifdef EXPERIMENTAL_TRANSLATION
330                                         if (ms + FUDGE < out->timelen) 
331                                                 schedule_delivery(pvt->sched, pvt, 
332                                                                                         c, fd, out, out->timelen - ms);
333                                         else {
334                                                 if (c)
335                                                         ast_write(c, out);
336                                                 else
337                                                         ast_fr_fdwrite(fd, out);
338                                         }
339                                         last->tv_sec = tv.tv_sec;
340                                         last->tv_usec = tv.tv_usec;
341                                         /* Schedule this packet to be delivered at the
342                                            right time */
343                                 } else
344                                         gettimeofday(last, NULL);
345 #else
346 #if 0
347                                         /* XXX Not correct in the full duplex case XXX */
348                                         if (ms + FUDGE < out->timelen) 
349                                                 usleep((out->timelen - ms - FUDGE) * 1000);
350 #endif
351                                         last->tv_sec = tv.tv_sec;
352                                         last->tv_usec = tv.tv_usec;
353                                 } else
354                                         gettimeofday(last, NULL);
355 #endif
356                                 if (c)
357                                         ast_write(c, out);
358                                 else
359                                         ast_fr_fdwrite(fd, out);
360                         }
361                         ast_frfree(out);
362                 }
363                 p = p->next;
364         }
365 }
366
367 static void *translator_thread(void *data)
368 {
369         struct ast_channel *real = data;
370         struct ast_frame *f;
371         int ms = -1;
372         struct translator_pvt *pvt = NULL;
373         int fd = -1;
374         int fds[2];
375         int res;
376         /* Read from the real, translate, write as necessary to the fake */
377         for(;;) {
378                 /* Break here if need be */
379                 pthread_testcancel();
380                 if (!real->trans) {
381                         ast_log(LOG_WARNING, "No translator anymore\n");
382                         break;
383                 }
384                 pvt = real->trans->pvt->pvt;
385                 fd = pvt->comm[1];
386                 fds[0] = fd;
387                 fds[1] = real->fd;
388                 CHECK_BLOCKING(real);
389                 res = ast_waitfor_n_fd(fds, 2, &ms);
390                 real->blocking = 0;
391                 /* Or we can die here, that's fine too */
392                 pthread_testcancel();
393                 if (res >= 0) {
394                         if (res == real->fd) {
395                                 f = ast_read(real);
396                                 if (!f) {
397                                         if (option_debug)
398                                                 ast_log(LOG_DEBUG, "Empty frame\n");
399                                         break;
400                                 }
401                                 if (f->frametype ==  AST_FRAME_VOICE) {
402                                         if (pvt->system)
403                                                 translator_apply(pvt, pvt->system, f, fd, NULL, &pvt->lastpass);
404                                 } else {
405                                         /* If it's not voice, just pass it along */
406                                         ast_fr_fdwrite(fd, f);
407                                 }
408                                 ast_frfree(f);
409                         } else {
410                                 f = ast_fr_fdread(res);
411                                 if (!f) {
412                                         if (option_debug)
413                                                 ast_log(LOG_DEBUG, "Empty (hangup) frame\n");
414                                         break;
415                                 }
416                                 
417                                 if (f->frametype == AST_FRAME_VOICE) {
418                                         if (pvt->rsystem)
419                                                 translator_apply(pvt, pvt->rsystem, f, -1, real, &pvt->lastpass);
420                                 } else {
421                                         ast_write(real, f);
422                                 }
423                                 ast_frfree(f);
424                         }
425                 } else {
426                         ast_log(LOG_DEBUG, "Waitfor returned non-zero\n");
427                         break;
428                 }
429         }
430         if (pvt)
431                 pvt->comm[1] = -1;
432         if (fd > -1) {
433                 /* Write a bogus frame */
434                 write(fd, data, 1);
435                 close(fd);
436         }
437         return NULL;
438 }
439
440 struct ast_channel *ast_translator_create(struct ast_channel *real, int format, int direction)
441 {
442         struct ast_channel *tmp;
443         struct translator_pvt *pvt;
444         if (real->trans) {
445                 ast_log(LOG_WARNING, "Translator already exists on '%s'\n", real->name);
446                 return NULL;
447         }
448         if (!(pvt = malloc(sizeof(struct translator_pvt)))) {
449                 ast_log(LOG_WARNING, "Unable to allocate private translator on '%s'\n", real->name);
450                 return NULL;
451         }
452         pvt->comm[0] = -1;
453         pvt->comm[1] = -1;
454         pvt->lastpass.tv_usec = 0;
455         pvt->lastpass.tv_sec = 0;
456
457 #ifdef EXPERIMENTAL_TRANSLATION 
458         pvt->head = NULL;
459         pvt->tail = NULL;
460         pvt->sched = sched_context_create();
461         if (!pvt->sched) {
462                 ast_log(LOG_WARNING, "Out of memory\n");
463                 ast_translator_free(pvt);
464                 return NULL;
465         }
466 #endif
467         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pvt->comm)) {
468                 ast_log(LOG_WARNING, "Unable to create UNIX domain socket on '%s'\n", real->name);
469                 ast_translator_free(pvt);
470                 return NULL;
471         }
472         /* In to the system */
473         if (direction & AST_DIRECTION_IN)
474                 pvt->system = ast_translator_build_path(real->format, format);
475         else
476                 pvt->system = NULL;
477         /* Out from the system */
478         if (direction & AST_DIRECTION_OUT)
479                 pvt->rsystem = ast_translator_build_path(format, real->format);
480         else
481                 pvt->rsystem = NULL;
482         if (!pvt->system && !pvt->rsystem) {
483                 ast_log(LOG_WARNING, "Unable to build a translation path for %s (%d to %d)\n", real->name, real->format, format);
484                 ast_translator_free(pvt);
485                 return NULL;
486         }
487         if (!pvt->system && (direction & AST_DIRECTION_IN)) {
488                 ast_log(LOG_WARNING, "Translation path for '%s' is one-way (reverse)\n", real->name);
489                 ast_translator_free(pvt);
490                 return NULL;
491         }
492         if (!pvt->rsystem && (direction & AST_DIRECTION_OUT)) {
493                 ast_log(LOG_WARNING, "Translation path for '%s' is one-way (forward)\n", real->name);
494                 ast_translator_free(pvt);
495                 return NULL;
496         }
497         if ((tmp = ast_channel_alloc())) {
498                 snprintf(tmp->name, sizeof(tmp->name), "%s/Translate:%d", real->name, format);
499                 tmp->type = type;
500                 tmp->fd = pvt->comm[0];
501                 tmp->format = format;
502                 tmp->state = real->state;
503                 tmp->rings = 0;
504                 tmp->pvt->pvt = pvt;
505                 tmp->master = real;
506                 tmp->pvt->send_digit = translator_send_digit;
507                 tmp->pvt->call = translator_call;
508                 tmp->pvt->hangup = translator_hangup;
509                 tmp->pvt->answer = translator_answer;
510                 tmp->pvt->read = translator_read;
511                 tmp->pvt->write = translator_write;
512                 tmp->pvt->pvt = pvt;
513                 real->trans = tmp;
514                 if (option_verbose > 2)
515                         ast_verbose(VERBOSE_PREFIX_3 "Created translator %s\n", tmp->name);
516                 if (pthread_create(&pvt->threadid, NULL, translator_thread, real) < 0) {
517                         ast_translator_destroy(tmp);
518                         tmp = NULL;
519                         ast_log(LOG_WARNING, "Failed to start thread\n");
520                 }
521         } else {
522                 ast_translator_free(pvt);
523                 ast_log(LOG_WARNING, "Unable to allocate channel\n");
524         }
525         return tmp;
526
527
528 static void rebuild_matrix()
529 {
530         struct ast_translator *t;
531         int changed;
532         int x,y,z;
533         if (option_debug)
534                 ast_log(LOG_DEBUG, "Reseting translation matrix\n");
535         /* Use the list of translators to build a translation matrix */
536         bzero(tr_matrix, sizeof(tr_matrix));
537         t = list;
538         while(t) {
539                 if (!tr_matrix[t->srcfmt][t->dstfmt].step ||
540                      tr_matrix[t->srcfmt][t->dstfmt].cost > t->cost) {
541                         tr_matrix[t->srcfmt][t->dstfmt].step = t;
542                         tr_matrix[t->srcfmt][t->dstfmt].cost = t->cost;
543                 }
544                 t = t->next;
545         }
546         do {
547                 changed = 0;
548                 /* Don't you just love O(N^3) operations? */
549                 for (x=0; x< MAX_FORMAT; x++)                           /* For each source format */
550                         for (y=0; y < MAX_FORMAT; y++)                  /* And each destination format */
551                                 if (x != y)                                                     /* Except ourselves, of course */
552                                         for (z=0; z < MAX_FORMAT; z++)  /* And each format it might convert to */
553                                                 if ((x!=z) && (y!=z))           /* Don't ever convert back to us */
554                                                         if (tr_matrix[x][y].step && /* We can convert from x to y */
555                                                                 tr_matrix[y][z].step && /* And from y to z and... */
556                                                                 (!tr_matrix[x][z].step ||       /* Either there isn't an x->z conversion */
557                                                                 (tr_matrix[x][y].cost + 
558                                                                  tr_matrix[y][z].cost < /* Or we're cheaper than the existing */
559                                                                  tr_matrix[x][z].cost)  /* solution */
560                                                              )) {
561                                                                                         /* We can get from x to z via y with a cost that
562                                                                                            is the sum of the transition from x to y and
563                                                                                            from y to z */
564                                                                  
565                                                                         tr_matrix[x][z].step = tr_matrix[x][y].step;
566                                                                         tr_matrix[x][z].cost = tr_matrix[x][y].cost + 
567                                                                                                                    tr_matrix[y][z].cost;
568                                                                         if (option_debug)
569                                                                                 ast_log(LOG_DEBUG, "Discovered %d cost path from %d to %d, via %d\n", tr_matrix[x][z].cost, x, z, y);
570                                                                         changed++;
571                                                                  }
572                 
573         } while (changed);
574 }
575
576 static void calc_cost(struct ast_translator *t)
577 {
578         int sofar=0;
579         struct ast_translator_pvt *pvt;
580         struct ast_frame *f, *out;
581         struct timeval start, finish;
582         int cost;
583         /* If they don't make samples, give them a terrible score */
584         if (!t->sample) {
585                 ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
586                 t->cost = 99999;
587                 return;
588         }
589         pvt = t->new();
590         if (!pvt) {
591                 ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
592                 t->cost = 99999;
593                 return;
594         }
595         gettimeofday(&start, NULL);
596         /* Call the encoder until we've processed one second of time */
597         while(sofar < 1000) {
598                 f = t->sample();
599                 if (!f) {
600                         ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
601                         t->destroy(pvt);
602                         t->cost = 99999;
603                         return;
604                 }
605                 t->framein(pvt, f);
606                 ast_frfree(f);
607                 while((out = t->frameout(pvt))) {
608                         sofar += out->timelen;
609                         ast_frfree(out);
610                 }
611         }
612         gettimeofday(&finish, NULL);
613         t->destroy(pvt);
614         cost = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000;
615         t->cost = cost;
616 }
617
618 static int show_translation(int fd, int argc, char *argv[])
619 {
620 #define SHOW_TRANS 14
621         int x,y;
622         char line[80];
623         if (argc != 2) 
624                 return RESULT_SHOWUSAGE;
625         ast_cli(fd, "                        Translation times between formats (in milliseconds)\n");
626         ast_cli(fd, "                                 Destination Format\n");
627         pthread_mutex_lock(&list_lock);
628         for (x=0;x<SHOW_TRANS; x++) {
629                 if (x == 1) 
630                         strcpy(line, "  Src  ");
631                 else if (x == 2)
632                         strcpy(line, "  Fmt  ");
633                 else
634                         strcpy(line, "       ");
635                 for (y=0;y<SHOW_TRANS;y++) {
636                         if (tr_matrix[x][y].step)
637                                 snprintf(line + strlen(line), sizeof(line) - strlen(line), " %4d", tr_matrix[x][y].cost);
638                         else
639                                 snprintf(line + strlen(line), sizeof(line) - strlen(line), "  n/a");
640                 }
641                 snprintf(line + strlen(line), sizeof(line) - strlen(line), "\n");
642                 ast_cli(fd, line);                      
643         }
644         pthread_mutex_unlock(&list_lock);
645         return RESULT_SUCCESS;
646 }
647
648 static int added_cli = 0;
649
650 static char show_trans_usage[] =
651 "Usage: show translation\n"
652 "       Displays known codec translators and the cost associated\n"
653 "with each conversion.\n";
654
655 static struct ast_cli_entry show_trans =
656 { { "show", "translation", NULL }, show_translation, "Display translation matrix", show_trans_usage };
657
658 int ast_register_translator(struct ast_translator *t)
659 {
660         t->srcfmt = powerof(t->srcfmt);
661         t->dstfmt = powerof(t->dstfmt);
662         if ((t->srcfmt >= MAX_FORMAT) || (t->dstfmt >= MAX_FORMAT)) {
663                 ast_log(LOG_WARNING, "Format %d is larger than MAX_FORMAT\n", t->srcfmt);
664                 return -1;
665         }
666         calc_cost(t);
667         if (option_verbose > 1)
668                 ast_verbose(VERBOSE_PREFIX_2 "Registered translator '%s' from format %d to %d, cost %d\n", t->name, t->srcfmt, t->dstfmt, t->cost);
669         pthread_mutex_lock(&list_lock);
670         if (!added_cli) {
671                 ast_cli_register(&show_trans);
672                 added_cli++;
673         }
674         t->next = list;
675         list = t;
676         rebuild_matrix();
677         pthread_mutex_unlock(&list_lock);
678         return 0;
679 }
680
681 int ast_unregister_translator(struct ast_translator *t)
682 {
683         struct ast_translator *u, *ul = NULL;
684         pthread_mutex_lock(&list_lock);
685         u = list;
686         while(u) {
687                 if (u == t) {
688                         if (ul)
689                                 ul->next = u->next;
690                         else
691                                 list = u->next;
692                         break;
693                 }
694                 ul = u;
695                 u = u->next;
696         }
697         rebuild_matrix();
698         pthread_mutex_unlock(&list_lock);
699         return (u ? 0 : -1);
700 }
701
702 void ast_translator_destroy(struct ast_channel *trans)
703 {
704         struct translator_pvt *pvt;
705         if (!trans->master) {
706                 ast_log(LOG_WARNING, "Translator is not part of a real channel?\n");
707                 return;
708         }
709         if (trans->master->trans != trans) {
710                 ast_log(LOG_WARNING, "Translator is not the right one!?!?\n");
711                 return;
712         }
713         trans->master->trans = NULL;
714         pvt = trans->pvt->pvt;
715         /* Cancel the running translator thread */
716         pthread_cancel(pvt->threadid);
717         pthread_join(pvt->threadid, NULL);
718         ast_translator_free(pvt);
719         trans->pvt->pvt = NULL;
720         if (option_verbose > 2)
721                 ast_verbose(VERBOSE_PREFIX_3 "Destroyed translator %s\n", trans->name);
722         ast_channel_free(trans);
723 }
724
725 int ast_translator_best_choice(int dst, int srcs)
726 {
727         /* Calculate our best source format, given costs, and a desired destination */
728         int x,y;
729         int best=-1;
730         int cur = 1;
731         int besttime=999999999;
732         pthread_mutex_lock(&list_lock);
733         for (y=0;y<MAX_FORMAT;y++) {
734                 if (cur & dst)
735                         for (x=0;x<MAX_FORMAT;x++) {
736                                 if (tr_matrix[x][y].step &&     /* There's a step */
737                                  (tr_matrix[x][y].cost < besttime) && /* We're better than what exists now */
738                                         (srcs & (1 << x)))                      /* x is a valid source format */
739                                         {
740                                                 best = 1 << x;
741                                                 besttime = tr_matrix[x][dst].cost;
742                                         }
743                         }
744                 cur = cur << 1;
745         }
746         pthread_mutex_unlock(&list_lock);
747         return best;
748 }