553e70cde2dc16de3feba5d90fcc1c8493c453f5
[asterisk/asterisk.git] / main / translate.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Translate via the use of pseudo channels
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <sys/time.h>
31 #include <sys/resource.h>
32 #include <math.h>
33
34 #include "asterisk/lock.h"
35 #include "asterisk/channel.h"
36 #include "asterisk/translate.h"
37 #include "asterisk/module.h"
38 #include "asterisk/frame.h"
39 #include "asterisk/sched.h"
40 #include "asterisk/cli.h"
41 #include "asterisk/term.h"
42
43 /*! \todo
44  * TODO: sample frames for each supported input format.
45  * We build this on the fly, by taking an SLIN frame and using
46  * the existing converter to play with it.
47  */
48
49 /*! max sample recalc */
50 #define MAX_RECALC 1000
51
52 /*! \brief the list of translators */
53 static AST_RWLIST_HEAD_STATIC(translators, ast_translator);
54
55 struct translator_path {
56         struct ast_translator *step;       /*!< Next step translator */
57         uint32_t table_cost;               /*!< Complete table cost to destination */
58         uint8_t multistep;                 /*!< Multiple conversions required for this translation */
59 };
60
61 /*!
62  * \brief a matrix that, for any pair of supported formats,
63  * indicates the total cost of translation and the first step.
64  * The full path can be reconstricted iterating on the matrix
65  * until step->dstfmt == desired_format.
66  *
67  * Array indexes are 'src' and 'dest', in that order.
68  *
69  * Note: the lock in the 'translators' list is also used to protect
70  * this structure.
71  */
72 static struct translator_path **__matrix;
73
74 /*!
75  * \brief table for converting index to format id values.
76  *
77  * \note this table is protected by the table_lock.
78  */
79 static int *__indextable;
80
81 /*! protects the __indextable for resizing */
82 static ast_rwlock_t tablelock;
83
84 /* index size starts at this*/
85 #define INIT_INDEX 32
86 /* index size grows by this as necessary */
87 #define GROW_INDEX 16
88
89 /*! the current largest index used by the __matrix and __indextable arrays*/
90 static int cur_max_index;
91 /*! the largest index that can be used in either the __indextable or __matrix before resize must occur */
92 static int index_size;
93
94 static void matrix_rebuild(int samples);
95
96 /*!
97  * \internal
98  * \brief converts format id to index value.
99  */
100 static int format2index(enum ast_format_id id)
101 {
102         int x;
103
104         ast_rwlock_rdlock(&tablelock);
105         for (x = 0; x < cur_max_index; x++) {
106                 if (__indextable[x] == id) {
107                         /* format already exists in index2format table */
108                         ast_rwlock_unlock(&tablelock);
109                         return x;
110                 }
111         }
112         ast_rwlock_unlock(&tablelock);
113         return -1; /* not found */
114 }
115
116 /*!
117  * \internal
118  * \brief add a new format to the matrix and index table structures.
119  *
120  * \note it is perfectly safe to call this on formats already indexed.
121  *
122  * \retval 0, success
123  * \retval -1, matrix and index table need to be resized
124  */
125 static int add_format2index(enum ast_format_id id)
126 {
127         if (format2index(id) != -1) {
128                 /* format is already already indexed */
129                 return 0;
130         }
131
132         ast_rwlock_wrlock(&tablelock);
133         if (cur_max_index == (index_size)) {
134                 ast_rwlock_unlock(&tablelock);
135                 return -1; /* hit max length */
136         }
137         __indextable[cur_max_index] = id;
138         cur_max_index++;
139         ast_rwlock_unlock(&tablelock);
140
141         return 0;
142 }
143
144 /*! 
145  * \internal
146  * \brief converts index value back to format id
147  */
148 static enum ast_format_id index2format(int index)
149 {
150         enum ast_format_id format_id;
151
152         if (index >= cur_max_index) {
153                 return 0;
154         }
155         ast_rwlock_rdlock(&tablelock);
156         format_id = __indextable[index];
157         ast_rwlock_unlock(&tablelock);
158
159         return format_id;
160 }
161
162 /*!
163  * \internal
164  * \brief resize both the matrix and index table so they can represent
165  * more translators
166  *
167  * \note _NO_ locks can be held prior to calling this function
168  *
169  * \retval 0, success
170  * \retval -1, failure.  Old matrix and index table can still be used though
171  */
172 static int matrix_resize(int init)
173 {
174         struct translator_path **tmp_matrix = NULL;
175         int *tmp_table = NULL;
176         int old_index;
177         int x;
178
179         AST_RWLIST_WRLOCK(&translators);
180         ast_rwlock_wrlock(&tablelock);
181
182         old_index = index_size;
183         if (init) {
184                 index_size += INIT_INDEX;
185         } else {
186                 index_size += GROW_INDEX;
187         }
188
189         /* make new 2d array of translator_path structures */
190         if (!(tmp_matrix = ast_calloc(1, sizeof(struct translator_path *) * (index_size)))) {
191                 goto resize_cleanup;
192         }
193
194         for (x = 0; x < index_size; x++) {
195                 if (!(tmp_matrix[x] = ast_calloc(1, sizeof(struct translator_path) * (index_size)))) {
196                         goto resize_cleanup;
197                 }
198         }
199
200         /* make new index table */
201         if (!(tmp_table = ast_calloc(1, sizeof(int) * index_size))) {
202                 goto resize_cleanup;
203         }
204
205         /* if everything went well this far, free the old and use the new */
206         if (!init) {
207                 for (x = 0; x < old_index; x++) {
208                         ast_free(__matrix[x]);
209                 }
210                 ast_free(__matrix);
211
212                 memcpy(tmp_table, __indextable, sizeof(int) * old_index);
213                 ast_free(__indextable);
214         }
215
216         /* now copy them over */
217         __matrix = tmp_matrix;
218         __indextable = tmp_table;
219
220         matrix_rebuild(0);
221         ast_rwlock_unlock(&tablelock);
222         AST_RWLIST_UNLOCK(&translators);
223
224         return 0;
225
226 resize_cleanup:
227         ast_rwlock_unlock(&tablelock);
228         AST_RWLIST_UNLOCK(&translators);
229         if (tmp_matrix) {
230                 for (x = 0; x < index_size; x++) {
231                         ast_free(tmp_matrix[x]);
232                 }
233                 ast_free(tmp_matrix);
234         }
235         ast_free(tmp_table);
236
237         return -1;
238 }
239
240 /*!
241  * \internal
242  * \brief reinitialize the __matrix during matrix rebuild
243  *
244  * \note must be protected by the translators list lock
245  */
246 static void matrix_clear(void)
247 {
248         int x;
249         for (x = 0; x < index_size; x++) {
250                 memset(__matrix[x], '\0', sizeof(struct translator_path) * (index_size));
251         }
252 }
253
254 /*!
255  * \internal
256  * \brief get a matrix entry
257  *
258  * \note This function must be protected by the translators list lock
259  */
260 static struct translator_path *matrix_get(unsigned int x, unsigned int y)
261 {
262         if (!(x >= 0 && y >= 0)) {
263                 return NULL;
264         }
265         return __matrix[x] + y;
266 }
267
268 /*
269  * wrappers around the translator routines.
270  */
271
272 /*!
273  * \brief Allocate the descriptor, required outbuf space,
274  * and possibly desc.
275  */
276 static void *newpvt(struct ast_translator *t)
277 {
278         struct ast_trans_pvt *pvt;
279         int len;
280         char *ofs;
281
282         /*
283          * compute the required size adding private descriptor,
284          * buffer, AST_FRIENDLY_OFFSET.
285          */
286         len = sizeof(*pvt) + t->desc_size;
287         if (t->buf_size)
288                 len += AST_FRIENDLY_OFFSET + t->buf_size;
289         pvt = ast_calloc(1, len);
290         if (!pvt)
291                 return NULL;
292         pvt->t = t;
293         ofs = (char *)(pvt + 1);        /* pointer to data space */
294         if (t->desc_size) {             /* first comes the descriptor */
295                 pvt->pvt = ofs;
296                 ofs += t->desc_size;
297         }
298         if (t->buf_size)                /* finally buffer and header */
299                 pvt->outbuf.c = ofs + AST_FRIENDLY_OFFSET;
300         /* call local init routine, if present */
301         if (t->newpvt && t->newpvt(pvt)) {
302                 ast_free(pvt);
303                 return NULL;
304         }
305         ast_module_ref(t->module);
306         return pvt;
307 }
308
309 static void destroy(struct ast_trans_pvt *pvt)
310 {
311         struct ast_translator *t = pvt->t;
312
313         if (t->destroy)
314                 t->destroy(pvt);
315         ast_free(pvt);
316         ast_module_unref(t->module);
317 }
318
319 /*! \brief framein wrapper, deals with bound checks.  */
320 static int framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
321 {
322         int ret;
323         int samples = pvt->samples;     /* initial value */
324
325         /* Copy the last in jb timing info to the pvt */
326         ast_copy_flags(&pvt->f, f, AST_FRFLAG_HAS_TIMING_INFO);
327         pvt->f.ts = f->ts;
328         pvt->f.len = f->len;
329         pvt->f.seqno = f->seqno;
330
331         if (f->samples == 0) {
332                 ast_log(LOG_WARNING, "no samples for %s\n", pvt->t->name);
333         }
334         if (pvt->t->buffer_samples) {   /* do not pass empty frames to callback */
335                 if (f->datalen == 0) { /* perform native PLC if available */
336                         /* If the codec has native PLC, then do that */
337                         if (!pvt->t->native_plc)
338                                 return 0;
339                 }
340                 if (pvt->samples + f->samples > pvt->t->buffer_samples) {
341                         ast_log(LOG_WARNING, "Out of buffer space\n");
342                         return -1;
343                 }
344         }
345         /* we require a framein routine, wouldn't know how to do
346          * it otherwise.
347          */
348         ret = pvt->t->framein(pvt, f);
349         /* diagnostic ... */
350         if (pvt->samples == samples)
351                 ast_log(LOG_WARNING, "%s did not update samples %d\n",
352                         pvt->t->name, pvt->samples);
353         return ret;
354 }
355
356 /*! \brief generic frameout routine.
357  * If samples and datalen are 0, take whatever is in pvt
358  * and reset them, otherwise take the values in the caller and
359  * leave alone the pvt values.
360  */
361 struct ast_frame *ast_trans_frameout(struct ast_trans_pvt *pvt,
362         int datalen, int samples)
363 {
364         struct ast_frame *f = &pvt->f;
365
366         if (samples) {
367                 f->samples = samples;
368         } else {
369                 if (pvt->samples == 0)
370                         return NULL;
371                 f->samples = pvt->samples;
372                 pvt->samples = 0;
373         }
374         if (datalen) {
375                 f->datalen = datalen;
376         } else {
377                 f->datalen = pvt->datalen;
378                 pvt->datalen = 0;
379         }
380
381         f->frametype = AST_FRAME_VOICE;
382         ast_format_copy(&f->subclass.format, &pvt->t->dst_format);
383         f->mallocd = 0;
384         f->offset = AST_FRIENDLY_OFFSET;
385         f->src = pvt->t->name;
386         f->data.ptr = pvt->outbuf.c;
387
388         return ast_frisolate(f);
389 }
390
391 static struct ast_frame *default_frameout(struct ast_trans_pvt *pvt)
392 {
393         return ast_trans_frameout(pvt, 0, 0);
394 }
395
396 /* end of callback wrappers and helpers */
397
398 void ast_translator_free_path(struct ast_trans_pvt *p)
399 {
400         struct ast_trans_pvt *pn = p;
401         while ( (p = pn) ) {
402                 pn = p->next;
403                 destroy(p);
404         }
405 }
406
407 /*! \brief Build a chain of translators based upon the given source and dest formats */
408 struct ast_trans_pvt *ast_translator_build_path(struct ast_format *dst, struct ast_format *src)
409 {
410         struct ast_trans_pvt *head = NULL, *tail = NULL;
411         int src_index, dst_index;
412         struct ast_format tmp_fmt1;
413         struct ast_format tmp_fmt2;
414
415         src_index = format2index(src->id);
416         dst_index = format2index(dst->id);
417
418         if (src_index == -1 || dst_index == -1) {
419                 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src_index == -1 ? "starting" : "ending");
420                 return NULL;
421         }
422
423         AST_RWLIST_RDLOCK(&translators);
424
425         while (src_index != dst_index) {
426                 struct ast_trans_pvt *cur;
427                 struct ast_translator *t = matrix_get(src_index, dst_index)->step;
428                 if (!t) {
429                         int src_id = index2format(src_index);
430                         int dst_id = index2format(dst_index);
431                         ast_log(LOG_WARNING, "No translator path from %s to %s\n",
432                                 ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
433                                 ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
434                         AST_RWLIST_UNLOCK(&translators);
435                         return NULL;
436                 }
437                 if (!(cur = newpvt(t))) {
438                         int src_id = index2format(src_index);
439                         int dst_id = index2format(dst_index);
440                         ast_log(LOG_WARNING, "Failed to build translator step from %s to %s\n",
441                                 ast_getformatname(ast_format_set(&tmp_fmt1, src_id, 0)),
442                                 ast_getformatname(ast_format_set(&tmp_fmt2, dst_id, 0)));
443                         if (head) {
444                                 ast_translator_free_path(head);
445                         }
446                         AST_RWLIST_UNLOCK(&translators);
447                         return NULL;
448                 }
449                 if (!head) {
450                         head = cur;
451                 } else {
452                         tail->next = cur;
453                 }
454                 tail = cur;
455                 cur->nextin = cur->nextout = ast_tv(0, 0);
456                 /* Keep going if this isn't the final destination */
457                 src_index = cur->t->dst_fmt_index;
458         }
459
460         AST_RWLIST_UNLOCK(&translators);
461         return head;
462 }
463
464 /*! \brief do the actual translation */
465 struct ast_frame *ast_translate(struct ast_trans_pvt *path, struct ast_frame *f, int consume)
466 {
467         struct ast_trans_pvt *p = path;
468         struct ast_frame *out;
469         struct timeval delivery;
470         int has_timing_info;
471         long ts;
472         long len;
473         int seqno;
474
475         has_timing_info = ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO);
476         ts = f->ts;
477         len = f->len;
478         seqno = f->seqno;
479
480         if (!ast_tvzero(f->delivery)) {
481                 if (!ast_tvzero(path->nextin)) {
482                         /* Make sure this is in line with what we were expecting */
483                         if (!ast_tveq(path->nextin, f->delivery)) {
484                                 /* The time has changed between what we expected and this
485                                    most recent time on the new packet.  If we have a
486                                    valid prediction adjust our output time appropriately */
487                                 if (!ast_tvzero(path->nextout)) {
488                                         path->nextout = ast_tvadd(path->nextout,
489                                                                   ast_tvsub(f->delivery, path->nextin));
490                                 }
491                                 path->nextin = f->delivery;
492                         }
493                 } else {
494                         /* This is our first pass.  Make sure the timing looks good */
495                         path->nextin = f->delivery;
496                         path->nextout = f->delivery;
497                 }
498                 /* Predict next incoming sample */
499                 path->nextin = ast_tvadd(path->nextin, ast_samp2tv(f->samples, ast_format_rate(&f->subclass.format)));
500         }
501         delivery = f->delivery;
502         for (out = f; out && p ; p = p->next) {
503                 framein(p, out);
504                 if (out != f) {
505                         ast_frfree(out);
506                 }
507                 out = p->t->frameout(p);
508         }
509         if (consume) {
510                 ast_frfree(f);
511         }
512         if (out == NULL) {
513                 return NULL;
514         }
515         /* we have a frame, play with times */
516         if (!ast_tvzero(delivery)) {
517                 /* Regenerate prediction after a discontinuity */
518                 if (ast_tvzero(path->nextout)) {
519                         path->nextout = ast_tvnow();
520                 }
521
522                 /* Use next predicted outgoing timestamp */
523                 out->delivery = path->nextout;
524
525                 /* Predict next outgoing timestamp from samples in this
526                    frame. */
527                 path->nextout = ast_tvadd(path->nextout, ast_samp2tv(out->samples, ast_format_rate(&out->subclass.format)));
528         } else {
529                 out->delivery = ast_tv(0, 0);
530                 ast_set2_flag(out, has_timing_info, AST_FRFLAG_HAS_TIMING_INFO);
531                 if (has_timing_info) {
532                         out->ts = ts;
533                         out->len = len;
534                         out->seqno = seqno;
535                 }
536         }
537         /* Invalidate prediction if we're entering a silence period */
538         if (out->frametype == AST_FRAME_CNG) {
539                 path->nextout = ast_tv(0, 0);
540         }
541         return out;
542 }
543
544 /*!
545  * \internal
546  * \brief Compute the computational cost of a single translation step.
547  *
548  * \note This function is only used to decide which translation path to
549  * use between two translators with identical src and dst formats.  Computational
550  * cost acts only as a tie breaker. This is done so hardware translators
551  * can naturally have precedence over software translators.
552  */
553 static void generate_computational_cost(struct ast_translator *t, int seconds)
554 {
555         int num_samples = 0;
556         struct ast_trans_pvt *pvt;
557         struct rusage start;
558         struct rusage end;
559         int cost;
560         int out_rate = ast_format_rate(&t->dst_format);
561
562         if (!seconds) {
563                 seconds = 1;
564         }
565
566         /* If they don't make samples, give them a terrible score */
567         if (!t->sample) {
568                 ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
569                 t->comp_cost = 999999;
570                 return;
571         }
572
573         pvt = newpvt(t);
574         if (!pvt) {
575                 ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
576                 t->comp_cost = 999999;
577                 return;
578         }
579
580         getrusage(RUSAGE_SELF, &start);
581
582         /* Call the encoder until we've processed the required number of samples */
583         while (num_samples < seconds * out_rate) {
584                 struct ast_frame *f = t->sample();
585                 if (!f) {
586                         ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
587                         destroy(pvt);
588                         t->comp_cost = 999999;
589                         return;
590                 }
591                 framein(pvt, f);
592                 ast_frfree(f);
593                 while ((f = t->frameout(pvt))) {
594                         num_samples += f->samples;
595                         ast_frfree(f);
596                 }
597         }
598
599         getrusage(RUSAGE_SELF, &end);
600
601         cost = ((end.ru_utime.tv_sec - start.ru_utime.tv_sec) * 1000000) + end.ru_utime.tv_usec - start.ru_utime.tv_usec;
602         cost += ((end.ru_stime.tv_sec - start.ru_stime.tv_sec) * 1000000) + end.ru_stime.tv_usec - start.ru_stime.tv_usec;
603
604         destroy(pvt);
605
606         t->comp_cost = cost / seconds;
607
608         if (!t->comp_cost) {
609                 t->comp_cost = 1;
610         }
611 }
612
613 /*!
614  * \internal
615  *
616  * \brief If no table cost value was pre set by the translator.  An attempt is made to
617  * automatically generate that cost value from the cost table based on our src and
618  * dst formats.
619  *
620  * \note This function allows older translators built before the translation cost
621  * changed away from using onely computational time to continue to be registered
622  * correctly.  It is expected that translators built after the introduction of this
623  * function will manually assign their own table cost value.
624  *
625  * \note This function is safe to use on any audio formats that used to be defined in the
626  * first 64 bits of the old bit field codec representation.
627  *
628  * \retval Table Cost value greater than 0.
629  * \retval 0 on error.
630  */
631 static int generate_table_cost(struct ast_format *src, struct ast_format *dst)
632 {
633         int src_rate = ast_format_rate(src);
634         int src_ll = 0;
635         int dst_rate = ast_format_rate(dst);
636         int dst_ll = 0;
637
638         if ((AST_FORMAT_GET_TYPE(src->id) != AST_FORMAT_TYPE_AUDIO) || (AST_FORMAT_GET_TYPE(dst->id) != AST_FORMAT_TYPE_AUDIO)) {
639                 /* This method of generating table cost is limited to audio.
640                  * Translators for media other than audio must manually set their
641                  * table cost. */
642                 return 0;
643         }
644         if ((src->id == AST_FORMAT_SLINEAR) || (src->id == AST_FORMAT_SLINEAR16)) {
645                 src_ll = 1;
646         }
647         if ((dst->id == AST_FORMAT_SLINEAR) || (dst->id == AST_FORMAT_SLINEAR16)) {
648                 dst_ll = 1;
649         }
650
651         if (src_ll) {
652                 if (dst_ll && (src_rate == dst_rate)) {
653                         return AST_TRANS_COST_LL_LL_ORIGSAMP;
654                 } else if (!dst_ll && (src_rate == dst_rate)) {
655                         return AST_TRANS_COST_LL_LY_ORIGSAMP;
656                 } else if (dst_ll && (src_rate < dst_rate)) {
657                         return AST_TRANS_COST_LL_LL_UPSAMP;
658                 } else if (!dst_ll && (src_rate < dst_rate)) {
659                         return AST_TRANS_COST_LL_LY_UPSAMP;
660                 } else if (dst_ll && (src_rate > dst_rate)) {
661                         return AST_TRANS_COST_LL_LL_DOWNSAMP;
662                 } else if (!dst_ll && (src_rate > dst_rate)) {
663                         return AST_TRANS_COST_LL_LY_DOWNSAMP;
664                 } else {
665                         return AST_TRANS_COST_LL_UNKNOWN;
666                 }
667         } else {
668                 if (dst_ll && (src_rate == dst_rate)) {
669                         return AST_TRANS_COST_LY_LL_ORIGSAMP;
670                 } else if (!dst_ll && (src_rate == dst_rate)) {
671                         return AST_TRANS_COST_LY_LY_ORIGSAMP;
672                 } else if (dst_ll && (src_rate < dst_rate)) {
673                         return AST_TRANS_COST_LY_LL_UPSAMP;
674                 } else if (!dst_ll && (src_rate < dst_rate)) {
675                         return AST_TRANS_COST_LY_LY_UPSAMP;
676                 } else if (dst_ll && (src_rate > dst_rate)) {
677                         return AST_TRANS_COST_LY_LL_DOWNSAMP;
678                 } else if (!dst_ll && (src_rate > dst_rate)) {
679                         return AST_TRANS_COST_LY_LY_DOWNSAMP;
680                 } else {
681                         return AST_TRANS_COST_LY_UNKNOWN;
682                 }
683         }
684 }
685
686 /*!
687  * \brief rebuild a translation matrix.
688  * \note This function expects the list of translators to be locked
689 */
690 static void matrix_rebuild(int samples)
691 {
692         struct ast_translator *t;
693         int newtablecost;
694         int x;      /* source format index */
695         int y;      /* intermediate format index */
696         int z;      /* destination format index */
697
698         ast_debug(1, "Resetting translation matrix\n");
699
700         matrix_clear();
701
702         /* first, compute all direct costs */
703         AST_RWLIST_TRAVERSE(&translators, t, list) {
704                 if (!t->active) {
705                         continue;
706                 }
707
708                 x = t->src_fmt_index;
709                 z = t->dst_fmt_index;
710
711                 if (samples) {
712                         generate_computational_cost(t, samples);
713                 }
714
715                 /* This new translator is the best choice if any of the below are true.
716                  * 1. no translation path is set between x and z yet.
717                  * 2. the new table cost is less.
718                  * 3. the new computational cost is less.  Computational cost is only used
719                  *    to break a tie between two identical translation paths.
720                  */
721                 if (!matrix_get(x, z)->step ||
722                         (t->table_cost < matrix_get(x, z)->step->table_cost) ||
723                         (t->comp_cost < matrix_get(x, z)->step->comp_cost)) {
724
725                         matrix_get(x, z)->step = t;
726                         matrix_get(x, z)->table_cost = t->table_cost;
727                 }
728         }
729
730         /*
731          * For each triple x, y, z of distinct formats, check if there is
732          * a path from x to z through y which is cheaper than what is
733          * currently known, and in case, update the matrix.
734          * Repeat until the matrix is stable.
735          */
736         for (;;) {
737                 int changed = 0;
738                 for (x = 0; x < cur_max_index; x++) {      /* source format */
739                         for (y = 0; y < cur_max_index; y++) {  /* intermediate format */
740                                 if (x == y) {                      /* skip ourselves */
741                                         continue;
742                                 }
743                                 for (z = 0; z < cur_max_index; z++) {  /* dst format */
744                                         if ((z == x || z == y) ||        /* skip null conversions */
745                                                 !matrix_get(x, y)->step ||   /* no path from x to y */
746                                                 !matrix_get(y, z)->step) {   /* no path from y to z */
747                                                 continue;
748                                         }
749
750                                         /* calculate table cost from x->y->z */
751                                         newtablecost = matrix_get(x, y)->table_cost + matrix_get(y, z)->table_cost;
752
753                                         /* if no step already exists between x and z OR the new cost of using the intermediate
754                                          * step is cheaper, use this step. */
755                                         if (!matrix_get(x, z)->step || (newtablecost < matrix_get(x, z)->table_cost)) {
756                                                 struct ast_format tmpx;
757                                                 struct ast_format tmpy;
758                                                 struct ast_format tmpz;
759                                                 matrix_get(x, z)->step = matrix_get(x, y)->step;
760                                                 matrix_get(x, z)->table_cost = newtablecost;
761                                                 matrix_get(x, z)->multistep = 1;
762                                                 changed++;
763                                                 ast_debug(3, "Discovered %d cost path from %s to %s, via %s\n",
764                                                         matrix_get(x, z)->table_cost,
765                                                         ast_getformatname(ast_format_set(&tmpx, index2format(x), 0)),
766                                                         ast_getformatname(ast_format_set(&tmpy, index2format(z), 0)),
767                                                         ast_getformatname(ast_format_set(&tmpz, index2format(y), 0)));
768                                         }
769                                 }
770                         }
771                 }
772                 if (!changed) {
773                         break;
774                 }
775         }
776 }
777
778 const char *ast_translate_path_to_str(struct ast_trans_pvt *p, struct ast_str **str)
779 {
780         struct ast_trans_pvt *pn = p;
781
782         if (!p || !p->t) {
783                 return "";
784         }
785
786         ast_str_set(str, 0, "%s", ast_getformatname(&p->t->src_format));
787
788         while ( (p = pn) ) {
789                 pn = p->next;
790                 ast_str_append(str, 0, "->%s", ast_getformatname(&p->t->dst_format));
791         }
792
793         return ast_str_buffer(*str);
794 }
795
796 static char *complete_trans_path_choice(const char *line, const char *word, int pos, int state)
797 {
798         int which = 0;
799         int wordlen = strlen(word);
800         int i;
801         char *ret = NULL;
802         size_t len = 0;
803         const struct ast_format_list *format_list = ast_get_format_list(&len);
804
805         for (i = 0; i < len; i++) {
806                 if (AST_FORMAT_GET_TYPE(format_list[i].id) != AST_FORMAT_TYPE_AUDIO) {
807                         continue;
808                 }
809                 if (!strncasecmp(word, format_list[i].name, wordlen) && ++which > state) {
810                         ret = ast_strdup(format_list[i].name);
811                         break;
812                 }
813         }
814         return ret;
815 }
816
817 static void handle_cli_recalc(struct ast_cli_args *a)
818 {
819         int time = a->argv[4] ? atoi(a->argv[4]) : 1;
820
821         if (time <= 0) {
822                 ast_cli(a->fd, "         Recalc must be greater than 0.  Defaulting to 1.\n");
823                 time = 1;
824         }
825
826         if (time > MAX_RECALC) {
827                 ast_cli(a->fd, "         Maximum limit of recalc exceeded by %d, truncating value to %d\n", time - MAX_RECALC, MAX_RECALC);
828                 time = MAX_RECALC;
829         }
830         ast_cli(a->fd, "         Recalculating Codec Translation (number of sample seconds: %d)\n\n", time);
831         AST_RWLIST_WRLOCK(&translators);
832         matrix_rebuild(time);
833         AST_RWLIST_UNLOCK(&translators);
834 }
835
836 static char *handle_show_translation_table(struct ast_cli_args *a)
837 {
838         int x, y;
839         int curlen = 0, longest = 0;
840         struct ast_format tmp_fmt;
841         AST_RWLIST_RDLOCK(&translators);
842         ast_cli(a->fd, "         Translation times between formats (in microseconds) for one second of data\n");
843         ast_cli(a->fd, "          Source Format (Rows) Destination Format (Columns)\n\n");
844
845         /* Get the length of the longest (usable?) codec name, so we know how wide the left side should be */
846         for (x = 0; x < cur_max_index; x++) {
847                 /* translation only applies to audio right now. */
848                 if (AST_FORMAT_GET_TYPE(index2format(x)) != AST_FORMAT_TYPE_AUDIO)
849                         continue;
850                 curlen = strlen(ast_getformatname(ast_format_set(&tmp_fmt, index2format(x), 0)));
851                 if (curlen > longest) {
852                         longest = curlen;
853                 }
854         }
855
856         for (x = -1; x < cur_max_index; x++) {
857                 struct ast_str *out = ast_str_alloca(256);
858                 /* translation only applies to audio right now. */
859                 if (x >= 0 && (AST_FORMAT_GET_TYPE(index2format(x)) != AST_FORMAT_TYPE_AUDIO)) {
860                         continue;
861                 }
862                 /*Go ahead and move to next iteration if dealing with an unknown codec*/
863                 if (x >= 0 && !strcmp(ast_getformatname(ast_format_set(&tmp_fmt, index2format(x), 0)), "unknown")) {
864                         continue;
865                 }
866                 ast_str_set(&out, -1, " ");
867                 for (y = -1; y < cur_max_index; y++) {
868                         /* translation only applies to audio right now. */
869                         if (y >= 0 && (AST_FORMAT_GET_TYPE(index2format(y)) != AST_FORMAT_TYPE_AUDIO)) {
870                                 continue;
871                         }
872                         /*Go ahead and move to next iteration if dealing with an unknown codec*/
873                         if (y >= 0 && !strcmp(ast_getformatname(ast_format_set(&tmp_fmt, index2format(y), 0)), "unknown")) {
874                                 continue;
875                         }
876                         if (y >= 0) {
877                                 curlen = strlen(ast_getformatname(ast_format_set(&tmp_fmt, index2format(y), 0)));
878                         }
879                         if (curlen < 5) {
880                                 curlen = 5;
881                         }
882
883                         if (x >= 0 && y >= 0 && matrix_get(x, y)->step) {
884                                 /* Actual codec output */
885                                 ast_str_append(&out, -1, "%*d", curlen + 1, (matrix_get(x, y)->table_cost/100));
886                         } else if (x == -1 && y >= 0) {
887                                 /* Top row - use a dynamic size */
888                                 ast_str_append(&out, -1, "%*s", curlen + 1, ast_getformatname(ast_format_set(&tmp_fmt, index2format(y), 0)));
889                         } else if (y == -1 && x >= 0) {
890                                 /* Left column - use a static size. */
891                                 ast_str_append(&out, -1, "%*s", longest, ast_getformatname(ast_format_set(&tmp_fmt, index2format(x), 0)));
892                         } else if (x >= 0 && y >= 0) {
893                                 /* Codec not supported */
894                                 ast_str_append(&out, -1, "%*s", curlen + 1, "-");
895                         } else {
896                                 /* Upper left hand corner */
897                                 ast_str_append(&out, -1, "%*s", longest, "");
898                         }
899                 }
900                 ast_str_append(&out, -1, "\n");
901                 ast_cli(a->fd, "%s", ast_str_buffer(out));
902         }
903         AST_RWLIST_UNLOCK(&translators);
904         return CLI_SUCCESS;
905 }
906
907 static char *handle_show_translation_path(struct ast_cli_args *a)
908 {
909         struct ast_format input_src_format;
910         size_t len = 0;
911         int i;
912         const struct ast_format_list *format_list = ast_get_format_list(&len);
913         struct ast_str *str = ast_str_alloca(256);
914         struct ast_translator *step;
915
916         ast_format_clear(&input_src_format);
917
918         for (i = 0; i < len; i++) {
919                 if (AST_FORMAT_GET_TYPE(format_list[i].id) != AST_FORMAT_TYPE_AUDIO) {
920                         continue;
921                 }
922                 if (!strncasecmp(format_list[i].name, a->argv[4], strlen(format_list[i].name))) {
923                         ast_format_set(&input_src_format, format_list[i].id, 0);
924                 }
925         }
926
927         if (!input_src_format.id) {
928                 ast_cli(a->fd, "Source codec \"%s\" is not found.\n", a->argv[4]);
929                 return CLI_FAILURE;
930         }
931
932         AST_RWLIST_RDLOCK(&translators);
933         ast_cli(a->fd, "--- Translation paths SRC Codec \"%s\" sample rate %d ---\n", a->argv[4], ast_format_rate(&input_src_format));
934         for (i = 0; i < len; i++) {
935                 int src;
936                 int dst;
937                 if ((AST_FORMAT_GET_TYPE(format_list[i].id) != AST_FORMAT_TYPE_AUDIO) || (format_list[i].id == input_src_format.id)) {
938                         continue;
939                 }
940                 dst = format2index(format_list[i].id);
941                 src = format2index(input_src_format.id);
942                 ast_str_reset(str);
943                 if ((len >= cur_max_index) && (src != -1) && (dst != -1) && matrix_get(src, dst)->step) {
944                         ast_str_append(&str, 0, "%s", ast_getformatname(&matrix_get(src, dst)->step->src_format));
945                         while (src != dst) {
946                                 step = matrix_get(src, dst)->step;
947                                 if (!step) {
948                                         ast_str_reset(str);
949                                         break;
950                                 }
951                                 ast_str_append(&str, 0, "->%s", ast_getformatname(&step->dst_format));
952                                 src = step->dst_fmt_index;
953                         }
954                 }
955
956                 if (ast_strlen_zero(ast_str_buffer(str))) {
957                         ast_str_set(&str, 0, "No Translation Path");
958                 }
959                 ast_cli(a->fd, "\t%-10.10s To %-10.10s: %-60.60s\n", a->argv[4], format_list[i].name, ast_str_buffer(str));
960         }
961         AST_RWLIST_UNLOCK(&translators);
962
963         return CLI_SUCCESS;
964 }
965
966 static char *handle_cli_core_show_translation(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
967 {
968         static const char * const option[] = { "recalc", "paths", NULL };
969
970         switch (cmd) {
971         case CLI_INIT:
972                 e->command = "core show translation";
973                 e->usage =
974                         "Usage: 'core show translation' can be used in two ways.\n"
975                         "       1. 'core show translation [recalc [<recalc seconds>]]\n"
976                         "          Displays known codec translators and the cost associated\n"
977                         "          with each conversion.  If the argument 'recalc' is supplied along\n"
978                         "          with optional number of seconds to test a new test will be performed\n"
979                         "          as the chart is being displayed.\n"
980                         "       2. 'core show translation paths [codec]'\n"
981                         "           This will display all the translation paths associated with a codec\n";
982                 return NULL;
983         case CLI_GENERATE:
984                 if (a->pos == 3) {
985                         return ast_cli_complete(a->word, option, a->n);
986                 }
987                 if (a->pos == 4 && !strcasecmp(a->argv[3], option[1])) {
988                         return complete_trans_path_choice(a->line, a->word, a->pos, a->n);
989                 }
990                 return NULL;
991         }
992
993         if (a->argc > 5)
994                 return CLI_SHOWUSAGE;
995
996         if (a->argv[3] && !strcasecmp(a->argv[3], option[1]) && a->argc == 5) { /* show paths */
997                 return handle_show_translation_path(a);
998         } else if (a->argv[3] && !strcasecmp(a->argv[3], option[0])) { /* recalc and then fall through to show table */
999                 handle_cli_recalc(a);
1000         } else if (a->argc > 3) { /* wrong input */
1001                 return CLI_SHOWUSAGE;
1002         }
1003
1004         return handle_show_translation_table(a);
1005 }
1006
1007 static struct ast_cli_entry cli_translate[] = {
1008         AST_CLI_DEFINE(handle_cli_core_show_translation, "Display translation matrix")
1009 };
1010
1011 /*! \brief register codec translator */
1012 int __ast_register_translator(struct ast_translator *t, struct ast_module *mod)
1013 {
1014         struct ast_translator *u;
1015         char tmp[80];
1016
1017         if (add_format2index(t->src_format.id) || add_format2index(t->dst_format.id)) {
1018                 if (matrix_resize(0)) {
1019                         ast_log(LOG_WARNING, "Translator matrix can not represent any more translators.  Out of resources.\n");
1020                         return -1;
1021                 }
1022                 add_format2index(t->src_format.id);
1023                 add_format2index(t->dst_format.id);
1024         }
1025
1026         if (!mod) {
1027                 ast_log(LOG_WARNING, "Missing module pointer, you need to supply one\n");
1028                 return -1;
1029         }
1030
1031         if (!t->buf_size) {
1032                 ast_log(LOG_WARNING, "empty buf size, you need to supply one\n");
1033                 return -1;
1034         }
1035         if (!t->table_cost && !(t->table_cost = generate_table_cost(&t->src_format, &t->dst_format))) {
1036                 ast_log(LOG_WARNING, "Table cost could not be generated for %s, "
1037                         "Please set table_cost variable on translator.\n", t->name);
1038                 return -1;
1039         }
1040
1041         t->module = mod;
1042         t->src_fmt_index = format2index(t->src_format.id);
1043         t->dst_fmt_index = format2index(t->dst_format.id);
1044         t->active = 1;
1045
1046         if (t->src_fmt_index == -1 || t->dst_fmt_index == -1) {
1047                 ast_log(LOG_WARNING, "Invalid translator path: (%s codec is not valid)\n", t->src_fmt_index == -1 ? "starting" : "ending");
1048                 return -1;
1049         }
1050         if (t->src_fmt_index >= cur_max_index) {
1051                 ast_log(LOG_WARNING, "Source format %s is larger than cur_max_index\n", ast_getformatname(&t->src_format));
1052                 return -1;
1053         }
1054
1055         if (t->dst_fmt_index >= cur_max_index) {
1056                 ast_log(LOG_WARNING, "Destination format %s is larger than cur_max_index\n", ast_getformatname(&t->dst_format));
1057                 return -1;
1058         }
1059
1060         if (t->buf_size) {
1061                 /*
1062                  * Align buf_size properly, rounding up to the machine-specific
1063                  * alignment for pointers.
1064                  */
1065                 struct _test_align { void *a, *b; } p;
1066                 int align = (char *)&p.b - (char *)&p.a;
1067
1068                 t->buf_size = ((t->buf_size + align - 1) / align) * align;
1069         }
1070
1071         if (t->frameout == NULL) {
1072                 t->frameout = default_frameout;
1073         }
1074
1075         generate_computational_cost(t, 1);
1076
1077         ast_verb(2, "Registered translator '%s' from format %s to %s, table cost, %d, computational cost %d\n",
1078                             term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
1079                             ast_getformatname(&t->src_format), ast_getformatname(&t->dst_format), t->table_cost, t->comp_cost);
1080
1081         AST_RWLIST_WRLOCK(&translators);
1082
1083         /* find any existing translators that provide this same srcfmt/dstfmt,
1084            and put this one in order based on computational cost */
1085         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
1086                 if ((u->src_fmt_index == t->src_fmt_index) &&
1087                     (u->dst_fmt_index == t->dst_fmt_index) &&
1088                     (u->comp_cost > t->comp_cost)) {
1089                         AST_RWLIST_INSERT_BEFORE_CURRENT(t, list);
1090                         t = NULL;
1091                         break;
1092                 }
1093         }
1094         AST_RWLIST_TRAVERSE_SAFE_END;
1095
1096         /* if no existing translator was found for this format combination,
1097            add it to the beginning of the list */
1098         if (t) {
1099                 AST_RWLIST_INSERT_HEAD(&translators, t, list);
1100         }
1101
1102         matrix_rebuild(0);
1103
1104         AST_RWLIST_UNLOCK(&translators);
1105
1106         return 0;
1107 }
1108
1109 /*! \brief unregister codec translator */
1110 int ast_unregister_translator(struct ast_translator *t)
1111 {
1112         char tmp[80];
1113         struct ast_translator *u;
1114         int found = 0;
1115
1116         AST_RWLIST_WRLOCK(&translators);
1117         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&translators, u, list) {
1118                 if (u == t) {
1119                         AST_RWLIST_REMOVE_CURRENT(list);
1120                         ast_verb(2, "Unregistered translator '%s' from format %s to %s\n",
1121                                 term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)),
1122                                 ast_getformatname(&t->src_format),
1123                                 ast_getformatname(&t->dst_format));
1124                         found = 1;
1125                         break;
1126                 }
1127         }
1128         AST_RWLIST_TRAVERSE_SAFE_END;
1129
1130         if (found) {
1131                 matrix_rebuild(0);
1132         }
1133
1134         AST_RWLIST_UNLOCK(&translators);
1135
1136         return (u ? 0 : -1);
1137 }
1138
1139 void ast_translator_activate(struct ast_translator *t)
1140 {
1141         AST_RWLIST_WRLOCK(&translators);
1142         t->active = 1;
1143         matrix_rebuild(0);
1144         AST_RWLIST_UNLOCK(&translators);
1145 }
1146
1147 void ast_translator_deactivate(struct ast_translator *t)
1148 {
1149         AST_RWLIST_WRLOCK(&translators);
1150         t->active = 0;
1151         matrix_rebuild(0);
1152         AST_RWLIST_UNLOCK(&translators);
1153 }
1154
1155 /*! \brief Calculate our best translator source format, given costs, and a desired destination */
1156 int ast_translator_best_choice(struct ast_format_cap *dst_cap,
1157         struct ast_format_cap *src_cap,
1158         struct ast_format *dst_fmt_out,
1159         struct ast_format *src_fmt_out)
1160 {
1161         unsigned int besttablecost = INT_MAX;
1162         unsigned int beststeps = INT_MAX;
1163         struct ast_format best;
1164         struct ast_format bestdst;
1165         struct ast_format_cap *joint_cap = ast_format_cap_joint(dst_cap, src_cap);
1166         ast_format_clear(&best);
1167         ast_format_clear(&bestdst);
1168
1169         if (joint_cap) { /* yes, pick one and return */
1170                 struct ast_format tmp_fmt;
1171                 ast_format_cap_iter_start(joint_cap);
1172                 while (!ast_format_cap_iter_next(joint_cap, &tmp_fmt)) {
1173                         /* We are guaranteed to find one common format. */
1174                         if (!best.id) {
1175                                 ast_format_copy(&best, &tmp_fmt);
1176                                 continue;
1177                         }
1178                         /* If there are multiple common formats, pick the one with the highest sample rate */
1179                         if (ast_format_rate(&best) < ast_format_rate(&tmp_fmt)) {
1180                                 ast_format_copy(&best, &tmp_fmt);
1181                                 continue;
1182                         }
1183
1184                 }
1185                 ast_format_cap_iter_end(joint_cap);
1186
1187                 /* We are done, this is a common format to both. */
1188                 ast_format_copy(dst_fmt_out, &best);
1189                 ast_format_copy(src_fmt_out, &best);
1190                 ast_format_cap_destroy(joint_cap);
1191                 return 0;
1192         } else {      /* No, we will need to translate */
1193                 struct ast_format cur_dst;
1194                 struct ast_format cur_src;
1195                 AST_RWLIST_RDLOCK(&translators);
1196
1197                 ast_format_cap_iter_start(dst_cap);
1198                 while (!ast_format_cap_iter_next(dst_cap, &cur_dst)) {
1199                         ast_format_cap_iter_start(src_cap);
1200                         while (!ast_format_cap_iter_next(src_cap, &cur_src)) {
1201                                 int x = format2index(cur_src.id);
1202                                 int y = format2index(cur_dst.id);
1203                                 if (x < 0 || y < 0) {
1204                                         continue;
1205                                 }
1206                                 if (!matrix_get(x, y) || !(matrix_get(x, y)->step)) {
1207                                         continue;
1208                                 }
1209                                 if (((matrix_get(x, y)->table_cost < besttablecost) || (matrix_get(x, y)->multistep < beststeps))) {
1210                                         /* better than what we have so far */
1211                                         ast_format_copy(&best, &cur_src);
1212                                         ast_format_copy(&bestdst, &cur_dst);
1213                                         besttablecost = matrix_get(x, y)->table_cost;
1214                                         beststeps = matrix_get(x, y)->multistep;
1215                                 }
1216                         }
1217                         ast_format_cap_iter_end(src_cap);
1218                 }
1219
1220                 ast_format_cap_iter_end(dst_cap);
1221                 AST_RWLIST_UNLOCK(&translators);
1222                 if (best.id) {
1223                         ast_format_copy(dst_fmt_out, &bestdst);
1224                         ast_format_copy(src_fmt_out, &best);
1225                         return 0;
1226                 }
1227                 return -1;
1228         }
1229 }
1230
1231 unsigned int ast_translate_path_steps(struct ast_format *dst_format, struct ast_format *src_format)
1232 {
1233         unsigned int res = -1;
1234         int src, dest;
1235         /* convert bitwise format numbers into array indices */
1236         src = format2index(src_format->id);
1237         dest = format2index(dst_format->id);
1238
1239         if (src == -1 || dest == -1) {
1240                 ast_log(LOG_WARNING, "No translator path: (%s codec is not valid)\n", src == -1 ? "starting" : "ending");
1241                 return -1;
1242         }
1243         AST_RWLIST_RDLOCK(&translators);
1244
1245         if (matrix_get(src, dest)->step) {
1246                 res = matrix_get(src, dest)->multistep + 1;
1247         }
1248
1249         AST_RWLIST_UNLOCK(&translators);
1250
1251         return res;
1252 }
1253
1254 void ast_translate_available_formats(struct ast_format_cap *dest, struct ast_format_cap *src, struct ast_format_cap *result)
1255 {
1256         struct ast_format tmp_fmt;
1257         struct ast_format cur_src;
1258         int src_audio = 0;
1259         int src_video = 0;
1260         int index;
1261
1262         ast_format_cap_copy(result, dest);
1263
1264         /* if we don't have a source format, we just have to try all
1265            possible destination formats */
1266         if (!src) {
1267                 return;
1268         }
1269
1270         ast_format_cap_iter_start(src);
1271         while (!ast_format_cap_iter_next(src, &cur_src)) {
1272                 /* If we have a source audio format, get its format index */
1273                 if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_AUDIO) {
1274                         src_audio = format2index(cur_src.id);
1275                 }
1276
1277                 /* If we have a source video format, get its format index */
1278                 if (AST_FORMAT_GET_TYPE(cur_src.id) == AST_FORMAT_TYPE_VIDEO) {
1279                         src_video = format2index(cur_src.id);
1280                 }
1281
1282                 AST_RWLIST_RDLOCK(&translators);
1283
1284                 /* For a given source audio format, traverse the list of
1285                    known audio formats to determine whether there exists
1286                    a translation path from the source format to the
1287                    destination format. */
1288                 for (index = 0; (src_audio >= 0) && index < cur_max_index; index++) {
1289                         ast_format_set(&tmp_fmt, index2format(index), 0);
1290
1291                         if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_AUDIO) {
1292                                 continue;
1293                         }
1294
1295                         /* if this is not a desired format, nothing to do */
1296                         if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
1297                                 continue;
1298                         }
1299
1300                         /* if the source is supplying this format, then
1301                            we can leave it in the result */
1302                         if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
1303                                 continue;
1304                         }
1305
1306                         /* if we don't have a translation path from the src
1307                            to this format, remove it from the result */
1308                         if (!matrix_get(src_audio, index)->step) {
1309                                 ast_format_cap_remove_byid(result, tmp_fmt.id);
1310                                 continue;
1311                         }
1312
1313                         /* now check the opposite direction */
1314                         if (!matrix_get(index, src_audio)->step) {
1315                                 ast_format_cap_remove_byid(result, tmp_fmt.id);
1316                         }
1317                 }
1318
1319                 /* For a given source video format, traverse the list of
1320                    known video formats to determine whether there exists
1321                    a translation path from the source format to the
1322                    destination format. */
1323                 for (index = 0; (src_video >= 0) && index < cur_max_index; index++) {
1324                         ast_format_set(&tmp_fmt, index2format(index), 0);
1325                         if (AST_FORMAT_GET_TYPE(tmp_fmt.id) != AST_FORMAT_TYPE_VIDEO) {
1326                                 continue;
1327                         }
1328
1329                         /* if this is not a desired format, nothing to do */
1330                         if (!ast_format_cap_iscompatible(dest, &tmp_fmt)) {
1331                                 continue;
1332                         }
1333
1334                         /* if the source is supplying this format, then
1335                            we can leave it in the result */
1336                         if (ast_format_cap_iscompatible(src, &tmp_fmt)) {
1337                                 continue;
1338                         }
1339
1340                         /* if we don't have a translation path from the src
1341                            to this format, remove it from the result */
1342                         if (!matrix_get(src_video, index)->step) {
1343                                 ast_format_cap_remove_byid(result, tmp_fmt.id);
1344                                 continue;
1345                         }
1346
1347                         /* now check the opposite direction */
1348                         if (!matrix_get(index, src_video)->step) {
1349                                 ast_format_cap_remove_byid(result, tmp_fmt.id);
1350                         }
1351                 }
1352                 AST_RWLIST_UNLOCK(&translators);
1353         }
1354         ast_format_cap_iter_end(src);
1355 }
1356
1357 int ast_translate_init(void)
1358 {
1359         int res = 0;
1360         ast_rwlock_init(&tablelock);
1361         res = matrix_resize(1);
1362         res |= ast_cli_register_multiple(cli_translate, ARRAY_LEN(cli_translate));
1363         return res;
1364 }