25
25
#include <sys/time.h>
26
26
#include <unistd.h>
27
27
#include <stdlib.h>
29
28
#include <string.h>
31
#define MAX_RECALC 200 /* max sample recalc */
32
33
/* This could all be done more efficiently *IF* we chained packets together
33
34
by default, but it would also complicate virtually every application. */
35
static ast_mutex_t list_lock = AST_MUTEX_INITIALIZER;
36
AST_MUTEX_DEFINE_STATIC(list_lock);
36
37
static struct ast_translator *list = NULL;
38
39
struct ast_translator_dir {
101
104
tmp->next = NULL;
105
tmp->nextin.tv_sec = 0;
106
tmp->nextin.tv_usec = 0;
107
tmp->nextout.tv_sec = 0;
108
tmp->nextout.tv_usec = 0;
102
109
tmp->step = tr_matrix[source][dest].step;
103
tmp->state = tmp->step->new();
110
tmp->state = tmp->step->newpvt();
104
111
if (!tmp->state) {
105
112
ast_log(LOG_WARNING, "Failed to build translator step from %d to %d\n", source, dest);
132
139
struct ast_trans_pvt *p;
133
140
struct ast_frame *out;
141
struct timeval delivery;
135
143
/* Feed the first frame into the first translator */
136
144
p->step->framein(p->state, f);
145
if (f->delivery.tv_sec || f->delivery.tv_usec) {
146
if (path->nextin.tv_sec || path->nextin.tv_usec) {
147
/* Make sure this is in line with what we were expecting */
148
if ((path->nextin.tv_sec != f->delivery.tv_sec) ||
149
(path->nextin.tv_usec != f->delivery.tv_usec)) {
150
/* The time has changed between what we expected and this
151
most recent time on the new packet. Adjust our output
152
time appropriately */
155
sdiff = f->delivery.tv_sec - path->nextin.tv_sec;
156
udiff = f->delivery.tv_usec - path->nextin.tv_usec;
157
path->nextin.tv_sec = f->delivery.tv_sec;
158
path->nextin.tv_usec = f->delivery.tv_usec;
159
path->nextout.tv_sec += sdiff;
160
path->nextout.tv_usec += udiff;
161
if (path->nextout.tv_usec < 0) {
162
path->nextout.tv_usec += 1000000;
163
path->nextout.tv_sec--;
164
} else if (path->nextout.tv_usec >= 1000000) {
165
path->nextout.tv_usec -= 1000000;
166
path->nextout.tv_sec++;
170
/* This is our first pass. Make sure the timing looks good */
171
path->nextin.tv_sec = f->delivery.tv_sec;
172
path->nextin.tv_usec = f->delivery.tv_usec;
173
path->nextout.tv_sec = f->delivery.tv_sec;
174
path->nextout.tv_usec = f->delivery.tv_usec;
176
/* Predict next incoming sample */
177
path->nextin.tv_sec += (f->samples / 8000);
178
path->nextin.tv_usec += ((f->samples % 8000) * 125);
179
if (path->nextin.tv_usec >= 1000000) {
180
path->nextin.tv_usec -= 1000000;
181
path->nextin.tv_sec++;
184
delivery.tv_sec = f->delivery.tv_sec;
185
delivery.tv_usec = f->delivery.tv_usec;
145
194
return this frame */
147
196
p->next->step->framein(p->next->state, out);
198
if (delivery.tv_sec || delivery.tv_usec) {
199
/* Use next predicted outgoing timestamp */
200
out->delivery.tv_sec = path->nextout.tv_sec;
201
out->delivery.tv_usec = path->nextout.tv_usec;
203
/* Predict next outgoing timestamp from samples in this
205
path->nextout.tv_sec += (out->samples / 8000);
206
path->nextout.tv_usec += ((out->samples % 8000) * 125);
207
if (path->nextout.tv_usec >= 1000000) {
208
path->nextout.tv_sec++;
209
path->nextout.tv_usec -= 1000000;
212
out->delivery.tv_sec = 0;
213
out->delivery.tv_usec = 0;
152
219
ast_log(LOG_WARNING, "I should never get here...\n");
156
static void rebuild_matrix(void)
224
static void calc_cost(struct ast_translator *t,int samples)
227
struct ast_translator_pvt *pvt;
228
struct ast_frame *f, *out;
229
struct timeval start, finish;
234
/* If they don't make samples, give them a terrible score */
236
ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
242
ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
246
gettimeofday(&start, NULL);
247
/* Call the encoder until we've processed one second of time */
248
while(sofar < samples * 8000) {
251
ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
258
while((out = t->frameout(pvt))) {
259
sofar += out->samples;
263
gettimeofday(&finish, NULL);
265
cost = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000;
266
t->cost = cost / samples;
271
static void rebuild_matrix(int samples)
158
273
struct ast_translator *t;
201
319
} while (changed);
204
static void calc_cost(struct ast_translator *t)
207
struct ast_translator_pvt *pvt;
208
struct ast_frame *f, *out;
209
struct timeval start, finish;
211
/* If they don't make samples, give them a terrible score */
213
ast_log(LOG_WARNING, "Translator '%s' does not produce sample frames.\n", t->name);
219
ast_log(LOG_WARNING, "Translator '%s' appears to be broken and will probably fail.\n", t->name);
223
gettimeofday(&start, NULL);
224
/* Call the encoder until we've processed one second of time */
225
while(sofar < 8000) {
228
ast_log(LOG_WARNING, "Translator '%s' failed to produce a sample frame.\n", t->name);
235
while((out = t->frameout(pvt))) {
236
sofar += out->samples;
240
gettimeofday(&finish, NULL);
242
cost = (finish.tv_sec - start.tv_sec) * 1000 + (finish.tv_usec - start.tv_usec) / 1000;
248
326
static int show_translation(int fd, int argc, char *argv[])
250
328
#define SHOW_TRANS 11
254
332
return RESULT_SHOWUSAGE;
334
if (argv[2] && !strcasecmp(argv[2],"recalc")) {
335
z = argv[3] ? atoi(argv[3]) : 1;
338
ast_cli(fd," C'mon let's be serious here... defaulting to 1.\n");
342
if (z > MAX_RECALC) {
343
ast_cli(fd," Maximum limit of recalc exceeded by %d, truncating value to %d\n",z-MAX_RECALC,MAX_RECALC);
346
ast_cli(fd," Recalculating Codec Translation (number of sample seconds: %d)\n\n",z);
255
350
ast_cli(fd, " Translation times between formats (in milliseconds)\n");
256
351
ast_cli(fd, " Source Format (Rows) Destination Format(Columns)\n\n");
257
352
ast_mutex_lock(&list_lock);
258
353
for (x=-1;x<SHOW_TRANS; x++) {
354
/* next 2 lines run faster than using strcpy() */
260
357
for (y=-1;y<SHOW_TRANS;y++) {
261
358
if (x >= 0 && y >= 0 && tr_matrix[x][y].step)
262
359
snprintf(line + strlen(line), sizeof(line) - strlen(line), " %5d", tr_matrix[x][y].cost >= 99999 ? tr_matrix[x][y].cost-99999 : tr_matrix[x][y].cost);
264
361
if (((x == -1 && y >= 0) || (y == -1 && x >= 0))) {
265
362
snprintf(line + strlen(line), sizeof(line) - strlen(line),
266
363
" %5s", ast_getformatname(1<<(x+y+1)) );
267
} else if (x != -1 && y != -1 ) {
364
} else if (x != -1 && y != -1) {
268
365
snprintf(line + strlen(line), sizeof(line) - strlen(line), " -");
270
367
snprintf(line + strlen(line), sizeof(line) - strlen(line), " ");
280
377
static int added_cli = 0;
282
379
static char show_trans_usage[] =
283
"Usage: show translation\n"
380
"Usage: show translation [recalc] [<recalc seconds>]\n"
284
381
" Displays known codec translators and the cost associated\n"
285
"with each conversion.\n";
382
"with each conversion. if the arguement 'recalc' is supplied along\n"
383
"with optional number of seconds to test a new test will be performed\n"
384
"as the chart is being displayed.\n";
287
386
static struct ast_cli_entry show_trans =
288
387
{ { "show", "translation", NULL }, show_translation, "Display translation matrix", show_trans_usage };
296
395
ast_log(LOG_WARNING, "Format %s is larger than MAX_FORMAT\n", ast_getformatname(t->srcfmt));
300
399
if (option_verbose > 1)
301
400
ast_verbose(VERBOSE_PREFIX_2 "Registered translator '%s' from format %s to %s, cost %d\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt), t->cost);
302
401
ast_mutex_lock(&list_lock);
322
422
ul->next = u->next;
425
if (option_verbose > 1)
426
ast_verbose(VERBOSE_PREFIX_2 "Unregistered translator '%s' from format %s to %s\n", term_color(tmp, t->name, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), ast_getformatname(1 << t->srcfmt), ast_getformatname(1 << t->dstfmt));
331
433
ast_mutex_unlock(&list_lock);
332
434
return (u ? 0 : -1);