2 * Asterisk -- An open source telephony toolkit.
4 * Zaptel native transcoding support
6 * Copyright (C) 1999 - 2006, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
9 * Kevin P. Fleming <kpfleming@digium.com>
11 * See http://www.asterisk.org for more information about
12 * the Asterisk project. Please do not directly contact
13 * any of the maintainers of this project for assistance;
14 * the project provides a web site, mailing lists and IRC
15 * channels for your use.
17 * This program is free software, distributed under the terms of
18 * the GNU General Public License Version 2. See the LICENSE file
19 * at the top of the source tree.
24 * \brief Translate between various formats natively through Zaptel transcoding
30 <depend>zaptel_transcode</depend>
31 <depend>zaptel</depend>
36 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
41 #include <netinet/in.h>
44 #include <sys/ioctl.h>
47 #include <zaptel/zaptel.h>
49 #include "asterisk/lock.h"
50 #include "asterisk/translate.h"
51 #include "asterisk/config.h"
52 #include "asterisk/options.h"
53 #include "asterisk/module.h"
54 #include "asterisk/cli.h"
55 #include "asterisk/logger.h"
56 #include "asterisk/channel.h"
57 #include "asterisk/utils.h"
58 #include "asterisk/linkedlists.h"
60 #define BUFFER_SAMPLES 8000
62 static unsigned int global_useplc
= 0;
64 static struct channel_usage
{
70 static char show_transcoder_usage
[] =
71 "Usage: show transcoder\n"
72 " Displays channel utilization of Zaptel transcoder(s).\n";
74 static char transcoder_show_usage
[] =
75 "Usage: transcoder show\n"
76 " Displays channel utilization of Zaptel transcoder(s).\n";
78 static int transcoder_show(int fd
, int argc
, char **argv
);
80 static struct ast_cli_entry cli_deprecated
[] = {
81 { { "show", "transcoder", NULL
},
83 "Display Zaptel transcoder utilization.",
84 show_transcoder_usage
}
87 static struct ast_cli_entry cli
[] = {
88 { { "transcoder", "show", NULL
},
90 "Display Zaptel transcoder utilization.",
91 transcoder_show_usage
, NULL
,
96 unsigned int map
[32][32];
99 static struct format_map global_format_map
= { { { 0 } } };
102 struct ast_translator t
;
103 AST_LIST_ENTRY(translator
) entry
;
106 static AST_LIST_HEAD_STATIC(translators
, translator
);
111 unsigned int g729b_warning
:1;
112 #ifdef DEBUG_TRANSCODE
116 struct zt_transcode_header
*hdr
;
119 static int transcoder_show(int fd
, int argc
, char **argv
)
121 struct channel_usage copy
;
126 ast_cli(fd
, "No Zaptel transcoders found.\n");
128 ast_cli(fd
, "%d/%d encoders/decoders of %d channels are in use.\n", copy
.encoders
, copy
.decoders
, copy
.total
);
130 return RESULT_SUCCESS
;
133 static int zap_framein(struct ast_trans_pvt
*pvt
, struct ast_frame
*f
)
135 struct pvt
*ztp
= pvt
->pvt
;
136 struct zt_transcode_header
*hdr
= ztp
->hdr
;
139 /* Fake a return frame for calculation purposes */
141 pvt
->samples
= f
->samples
;
146 /* Copy at front of buffer */
149 /* if we get handed a G.729 frame that is not a multiple of
150 10 bytes (10 milliseconds), then it has a CNG frame and
151 we need to avoid sending that to the transcoder
153 if ((f
->subclass
== AST_FORMAT_G729A
) && ((f
->datalen
% 10) != 0)) {
154 if (!ztp
->g729b_warning
) {
155 ast_log(LOG_WARNING
, "G.729B CNG frame received but is not supported; dropping.\n");
156 ztp
->g729b_warning
= 1;
158 f
->datalen
-= f
->datalen
% 10;
159 f
->samples
= f
->datalen
* 8;
162 if (hdr
->srclen
+ f
->datalen
> sizeof(hdr
->srcdata
)) {
163 ast_log(LOG_WARNING
, "Out of space for codec translation!\n");
167 if (hdr
->srclen
+ f
->datalen
+ hdr
->srcoffset
> sizeof(hdr
->srcdata
)) {
169 memmove(hdr
->srcdata
, hdr
->srcdata
+ hdr
->srcoffset
, hdr
->srclen
);
173 memcpy(hdr
->srcdata
+ hdr
->srcoffset
+ hdr
->srclen
, f
->data
, f
->datalen
);
174 hdr
->srclen
+= f
->datalen
;
175 pvt
->samples
+= f
->samples
;
180 static struct ast_frame
*zap_frameout(struct ast_trans_pvt
*pvt
)
182 struct pvt
*ztp
= pvt
->pvt
;
183 struct zt_transcode_header
*hdr
= ztp
->hdr
;
186 if (ztp
->fake
== 2) {
188 pvt
->f
.frametype
= AST_FRAME_VOICE
;
190 pvt
->f
.samples
= 160;
195 ast_set_flag(&pvt
->f
, AST_FRFLAG_FROM_TRANSLATOR
);
197 } else if (ztp
->fake
== 1) {
201 #ifdef DEBUG_TRANSCODE
202 ztp
->totalms
+= hdr
->dstsamples
;
203 if ((ztp
->totalms
- ztp
->lasttotalms
) > 8000) {
204 printf("Whee %p, %d (%d to %d)\n", ztp
, hdr
->dstlen
, ztp
->lasttotalms
, ztp
->totalms
);
205 ztp
->lasttotalms
= ztp
->totalms
;
208 pvt
->f
.frametype
= AST_FRAME_VOICE
;
209 pvt
->f
.subclass
= hdr
->dstfmt
;
210 pvt
->f
.samples
= hdr
->dstsamples
;
211 pvt
->f
.data
= hdr
->dstdata
+ hdr
->dstoffset
;
212 pvt
->f
.offset
= hdr
->dstoffset
;
213 pvt
->f
.datalen
= hdr
->dstlen
;
215 ast_set_flag(&pvt
->f
, AST_FRFLAG_FROM_TRANSLATOR
);
216 pvt
->samples
-= pvt
->f
.samples
;
221 hdr
->dstoffset
= AST_FRIENDLY_OFFSET
;
222 x
= ZT_TCOP_TRANSCODE
;
223 if (ioctl(ztp
->fd
, ZT_TRANSCODE_OP
, &x
))
224 ast_log(LOG_WARNING
, "Failed to transcode: %s\n", strerror(errno
));
233 static void zap_destroy(struct ast_trans_pvt
*pvt
)
235 struct pvt
*ztp
= pvt
->pvt
;
239 if (ioctl(ztp
->fd
, ZT_TRANSCODE_OP
, &x
))
240 ast_log(LOG_WARNING
, "Failed to release transcoder channel: %s\n", strerror(errno
));
242 switch (ztp
->hdr
->dstfmt
) {
243 case AST_FORMAT_G729A
:
244 case AST_FORMAT_G723_1
:
245 ast_atomic_fetchadd_int(&channels
.encoders
, -1);
248 ast_atomic_fetchadd_int(&channels
.decoders
, -1);
252 munmap(ztp
->hdr
, sizeof(*ztp
->hdr
));
256 static int zap_translate(struct ast_trans_pvt
*pvt
, int dest
, int source
)
258 /* Request translation through zap if possible */
260 unsigned int x
= ZT_TCOP_ALLOCATE
;
261 struct pvt
*ztp
= pvt
->pvt
;
262 struct zt_transcode_header
*hdr
;
265 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0)
267 flags
= fcntl(fd
, F_GETFL
);
269 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
))
270 ast_log(LOG_WARNING
, "Could not set non-block mode!\n");
274 if ((hdr
= mmap(NULL
, sizeof(*hdr
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
275 ast_log(LOG_ERROR
, "Memory Map failed for transcoding (%s)\n", strerror(errno
));
281 if (hdr
->magic
!= ZT_TRANSCODE_MAGIC
) {
282 ast_log(LOG_ERROR
, "Transcoder header (%08x) wasn't magic. Abandoning\n", hdr
->magic
);
283 munmap(hdr
, sizeof(*hdr
));
289 hdr
->srcfmt
= (1 << source
);
290 hdr
->dstfmt
= (1 << dest
);
291 if (ioctl(fd
, ZT_TRANSCODE_OP
, &x
)) {
292 ast_log(LOG_ERROR
, "Unable to attach transcoder: %s\n", strerror(errno
));
293 munmap(hdr
, sizeof(*hdr
));
303 switch (hdr
->dstfmt
) {
304 case AST_FORMAT_G729A
:
305 case AST_FORMAT_G723_1
:
306 ast_atomic_fetchadd_int(&channels
.encoders
, +1);
309 ast_atomic_fetchadd_int(&channels
.decoders
, +1);
316 static int zap_new(struct ast_trans_pvt
*pvt
)
318 return zap_translate(pvt
, pvt
->t
->dstfmt
, pvt
->t
->srcfmt
);
321 static struct ast_frame
*fakesrc_sample(void)
323 /* Don't bother really trying to test hardware ones. */
324 static struct ast_frame f
= {
325 .frametype
= AST_FRAME_VOICE
,
327 .src
= __PRETTY_FUNCTION__
333 static int register_translator(int dst
, int src
)
335 struct translator
*zt
;
338 if (!(zt
= ast_calloc(1, sizeof(*zt
))))
341 snprintf((char *) (zt
->t
.name
), sizeof(zt
->t
.name
), "zap%sto%s",
342 ast_getformatname((1 << src
)), ast_getformatname((1 << dst
)));
343 zt
->t
.srcfmt
= (1 << src
);
344 zt
->t
.dstfmt
= (1 << dst
);
345 zt
->t
.newpvt
= zap_new
;
346 zt
->t
.framein
= zap_framein
;
347 zt
->t
.frameout
= zap_frameout
;
348 zt
->t
.destroy
= zap_destroy
;
349 zt
->t
.sample
= fakesrc_sample
;
350 zt
->t
.useplc
= global_useplc
;
351 zt
->t
.buf_size
= BUFFER_SAMPLES
* 2;
352 zt
->t
.desc_size
= sizeof(struct pvt
);
353 if ((res
= ast_register_translator(&zt
->t
))) {
358 AST_LIST_LOCK(&translators
);
359 AST_LIST_INSERT_HEAD(&translators
, zt
, entry
);
360 AST_LIST_UNLOCK(&translators
);
362 global_format_map
.map
[dst
][src
] = 1;
367 static void drop_translator(int dst
, int src
)
369 struct translator
*cur
;
371 AST_LIST_LOCK(&translators
);
372 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators
, cur
, entry
) {
373 if (cur
->t
.srcfmt
!= src
)
376 if (cur
->t
.dstfmt
!= dst
)
379 AST_LIST_REMOVE_CURRENT(&translators
, entry
);
380 ast_unregister_translator(&cur
->t
);
382 global_format_map
.map
[dst
][src
] = 0;
385 AST_LIST_TRAVERSE_SAFE_END
;
386 AST_LIST_UNLOCK(&translators
);
389 static void unregister_translators(void)
391 struct translator
*cur
;
393 AST_LIST_LOCK(&translators
);
394 while ((cur
= AST_LIST_REMOVE_HEAD(&translators
, entry
))) {
395 ast_unregister_translator(&cur
->t
);
398 AST_LIST_UNLOCK(&translators
);
401 static void parse_config(void)
403 struct ast_variable
*var
;
404 struct ast_config
*cfg
= ast_config_load("codecs.conf");
409 for (var
= ast_variable_browse(cfg
, "plc"); var
; var
= var
->next
) {
410 if (!strcasecmp(var
->name
, "genericplc")) {
411 global_useplc
= ast_true(var
->value
);
412 if (option_verbose
> 2)
413 ast_verbose(VERBOSE_PREFIX_3
"codec_zap: %susing generic PLC\n",
414 global_useplc
? "" : "not ");
418 ast_config_destroy(cfg
);
421 static void build_translators(struct format_map
*map
, unsigned int dstfmts
, unsigned int srcfmts
)
423 unsigned int src
, dst
;
425 for (src
= 0; src
< 32; src
++) {
426 for (dst
= 0; dst
< 32; dst
++) {
427 if (!(srcfmts
& (1 << src
)))
430 if (!(dstfmts
& (1 << dst
)))
433 if (global_format_map
.map
[dst
][src
])
436 if (!register_translator(dst
, src
))
437 map
->map
[dst
][src
] = 1;
442 static int find_transcoders(void)
444 struct zt_transcode_info info
= { 0, };
445 struct format_map map
= { { { 0 } } };
449 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0) {
450 ast_verbose(VERBOSE_PREFIX_2
"No hardware transcoders found.\n");
454 info
.op
= ZT_TCOP_GETINFO
;
455 for (info
.tcnum
= 0; !(res
= ioctl(fd
, ZT_TRANSCODE_OP
, &info
)); info
.tcnum
++) {
456 if (option_verbose
> 1)
457 ast_verbose(VERBOSE_PREFIX_2
"Found transcoder '%s'.\n", info
.name
);
458 build_translators(&map
, info
.dstfmts
, info
.srcfmts
);
459 ast_atomic_fetchadd_int(&channels
.total
, info
.numchannels
/ 2);
464 if (!info
.tcnum
&& (option_verbose
> 1))
465 ast_verbose(VERBOSE_PREFIX_2
"No hardware transcoders found.\n");
467 for (x
= 0; x
< 32; x
++) {
468 for (y
= 0; y
< 32; y
++) {
469 if (!map
.map
[x
][y
] && global_format_map
.map
[x
][y
])
470 drop_translator(x
, y
);
477 static int reload(void)
479 struct translator
*cur
;
483 AST_LIST_LOCK(&translators
);
484 AST_LIST_TRAVERSE(&translators
, cur
, entry
)
485 cur
->t
.useplc
= global_useplc
;
486 AST_LIST_UNLOCK(&translators
);
491 static int unload_module(void)
493 ast_cli_unregister_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
494 unregister_translators();
499 static int load_module(void)
503 ast_cli_register_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
508 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Generic Zaptel Transcoder Codec Translator",
510 .unload
= unload_module
,