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>dahdi_transcode</depend>
31 <depend>dahdi</depend>
36 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
41 #include <netinet/in.h>
44 #include <sys/ioctl.h>
48 #include "asterisk/lock.h"
49 #include "asterisk/translate.h"
50 #include "asterisk/config.h"
51 #include "asterisk/options.h"
52 #include "asterisk/module.h"
53 #include "asterisk/cli.h"
54 #include "asterisk/logger.h"
55 #include "asterisk/channel.h"
56 #include "asterisk/utils.h"
57 #include "asterisk/linkedlists.h"
59 #include "asterisk/dahdi_compat.h"
61 #define BUFFER_SAMPLES 8000
63 static unsigned int global_useplc
= 0;
65 static struct channel_usage
{
71 static char show_transcoder_usage
[] =
72 "Usage: show transcoder\n"
73 " Displays channel utilization of Zaptel transcoder(s).\n";
75 static char transcoder_show_usage
[] =
76 "Usage: transcoder show\n"
77 " Displays channel utilization of Zaptel transcoder(s).\n";
79 static int transcoder_show(int fd
, int argc
, char **argv
);
81 static struct ast_cli_entry cli_deprecated
[] = {
82 { { "show", "transcoder", NULL
},
84 "Display Zaptel transcoder utilization.",
85 show_transcoder_usage
}
88 static struct ast_cli_entry cli
[] = {
89 { { "transcoder", "show", NULL
},
91 "Display Zaptel transcoder utilization.",
92 transcoder_show_usage
, NULL
,
97 unsigned int map
[32][32];
100 static struct format_map global_format_map
= { { { 0 } } };
103 struct ast_translator t
;
104 AST_LIST_ENTRY(translator
) entry
;
107 static AST_LIST_HEAD_STATIC(translators
, translator
);
112 unsigned int g729b_warning
:1;
113 #ifdef DEBUG_TRANSCODE
117 DAHDI_TRANSCODE_HEADER
*hdr
;
120 static int transcoder_show(int fd
, int argc
, char **argv
)
122 struct channel_usage copy
;
127 ast_cli(fd
, "No Zaptel transcoders found.\n");
129 ast_cli(fd
, "%d/%d encoders/decoders of %d channels are in use.\n", copy
.encoders
, copy
.decoders
, copy
.total
);
131 return RESULT_SUCCESS
;
134 static int zap_framein(struct ast_trans_pvt
*pvt
, struct ast_frame
*f
)
136 struct pvt
*ztp
= pvt
->pvt
;
137 DAHDI_TRANSCODE_HEADER
*hdr
= ztp
->hdr
;
140 /* Fake a return frame for calculation purposes */
142 pvt
->samples
= f
->samples
;
147 /* Copy at front of buffer */
150 /* if we get handed a G.729 frame that is not a multiple of
151 10 bytes (10 milliseconds), then it has a CNG frame and
152 we need to avoid sending that to the transcoder
154 if ((f
->subclass
== AST_FORMAT_G729A
) && ((f
->datalen
% 10) != 0)) {
155 if (!ztp
->g729b_warning
) {
156 ast_log(LOG_WARNING
, "G.729B CNG frame received but is not supported; dropping.\n");
157 ztp
->g729b_warning
= 1;
159 f
->datalen
-= f
->datalen
% 10;
160 f
->samples
= f
->datalen
* 8;
163 if (hdr
->srclen
+ f
->datalen
> sizeof(hdr
->srcdata
)) {
164 ast_log(LOG_WARNING
, "Out of space for codec translation!\n");
168 if (hdr
->srclen
+ f
->datalen
+ hdr
->srcoffset
> sizeof(hdr
->srcdata
)) {
170 memmove(hdr
->srcdata
, hdr
->srcdata
+ hdr
->srcoffset
, hdr
->srclen
);
174 memcpy(hdr
->srcdata
+ hdr
->srcoffset
+ hdr
->srclen
, f
->data
, f
->datalen
);
175 hdr
->srclen
+= f
->datalen
;
176 pvt
->samples
+= f
->samples
;
181 static struct ast_frame
*zap_frameout(struct ast_trans_pvt
*pvt
)
183 struct pvt
*ztp
= pvt
->pvt
;
184 DAHDI_TRANSCODE_HEADER
*hdr
= ztp
->hdr
;
187 if (ztp
->fake
== 2) {
189 pvt
->f
.frametype
= AST_FRAME_VOICE
;
191 pvt
->f
.samples
= 160;
196 ast_set_flag(&pvt
->f
, AST_FRFLAG_FROM_TRANSLATOR
);
198 } else if (ztp
->fake
== 1) {
202 #ifdef DEBUG_TRANSCODE
203 ztp
->totalms
+= hdr
->dstsamples
;
204 if ((ztp
->totalms
- ztp
->lasttotalms
) > 8000) {
205 printf("Whee %p, %d (%d to %d)\n", ztp
, hdr
->dstlen
, ztp
->lasttotalms
, ztp
->totalms
);
206 ztp
->lasttotalms
= ztp
->totalms
;
209 pvt
->f
.frametype
= AST_FRAME_VOICE
;
210 pvt
->f
.subclass
= hdr
->dstfmt
;
211 pvt
->f
.samples
= hdr
->dstsamples
;
212 pvt
->f
.data
= hdr
->dstdata
+ hdr
->dstoffset
;
213 pvt
->f
.offset
= hdr
->dstoffset
;
214 pvt
->f
.datalen
= hdr
->dstlen
;
216 ast_set_flag(&pvt
->f
, AST_FRFLAG_FROM_TRANSLATOR
);
217 pvt
->samples
-= pvt
->f
.samples
;
222 hdr
->dstoffset
= AST_FRIENDLY_OFFSET
;
223 x
= DAHDI_TCOP_TRANSCODE
;
224 if (ioctl(ztp
->fd
, DAHDI_TRANSCODE_OP
, &x
))
225 ast_log(LOG_WARNING
, "Failed to transcode: %s\n", strerror(errno
));
234 static void zap_destroy(struct ast_trans_pvt
*pvt
)
236 struct pvt
*ztp
= pvt
->pvt
;
239 x
= DAHDI_TCOP_RELEASE
;
240 if (ioctl(ztp
->fd
, DAHDI_TRANSCODE_OP
, &x
))
241 ast_log(LOG_WARNING
, "Failed to release transcoder channel: %s\n", strerror(errno
));
243 switch (ztp
->hdr
->dstfmt
) {
244 case AST_FORMAT_G729A
:
245 case AST_FORMAT_G723_1
:
246 ast_atomic_fetchadd_int(&channels
.encoders
, -1);
249 ast_atomic_fetchadd_int(&channels
.decoders
, -1);
253 munmap(ztp
->hdr
, sizeof(*ztp
->hdr
));
257 static int zap_translate(struct ast_trans_pvt
*pvt
, int dest
, int source
)
259 /* Request translation through zap if possible */
261 unsigned int x
= DAHDI_TCOP_ALLOCATE
;
262 struct pvt
*ztp
= pvt
->pvt
;
263 DAHDI_TRANSCODE_HEADER
*hdr
;
266 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0)
268 flags
= fcntl(fd
, F_GETFL
);
270 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
))
271 ast_log(LOG_WARNING
, "Could not set non-block mode!\n");
275 if ((hdr
= mmap(NULL
, sizeof(*hdr
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
276 ast_log(LOG_ERROR
, "Memory Map failed for transcoding (%s)\n", strerror(errno
));
282 if (hdr
->magic
!= DAHDI_TRANSCODE_MAGIC
) {
283 ast_log(LOG_ERROR
, "Transcoder header (%08x) wasn't magic. Abandoning\n", hdr
->magic
);
284 munmap(hdr
, sizeof(*hdr
));
290 hdr
->srcfmt
= (1 << source
);
291 hdr
->dstfmt
= (1 << dest
);
292 if (ioctl(fd
, DAHDI_TRANSCODE_OP
, &x
)) {
293 ast_log(LOG_ERROR
, "Unable to attach transcoder: %s\n", strerror(errno
));
294 munmap(hdr
, sizeof(*hdr
));
304 switch (hdr
->dstfmt
) {
305 case AST_FORMAT_G729A
:
306 case AST_FORMAT_G723_1
:
307 ast_atomic_fetchadd_int(&channels
.encoders
, +1);
310 ast_atomic_fetchadd_int(&channels
.decoders
, +1);
317 static int zap_new(struct ast_trans_pvt
*pvt
)
319 return zap_translate(pvt
, pvt
->t
->dstfmt
, pvt
->t
->srcfmt
);
322 static struct ast_frame
*fakesrc_sample(void)
324 /* Don't bother really trying to test hardware ones. */
325 static struct ast_frame f
= {
326 .frametype
= AST_FRAME_VOICE
,
328 .src
= __PRETTY_FUNCTION__
334 static int register_translator(int dst
, int src
)
336 struct translator
*zt
;
339 if (!(zt
= ast_calloc(1, sizeof(*zt
))))
342 snprintf((char *) (zt
->t
.name
), sizeof(zt
->t
.name
), "zap%sto%s",
343 ast_getformatname((1 << src
)), ast_getformatname((1 << dst
)));
344 zt
->t
.srcfmt
= (1 << src
);
345 zt
->t
.dstfmt
= (1 << dst
);
346 zt
->t
.newpvt
= zap_new
;
347 zt
->t
.framein
= zap_framein
;
348 zt
->t
.frameout
= zap_frameout
;
349 zt
->t
.destroy
= zap_destroy
;
350 zt
->t
.sample
= fakesrc_sample
;
351 zt
->t
.useplc
= global_useplc
;
352 zt
->t
.buf_size
= BUFFER_SAMPLES
* 2;
353 zt
->t
.desc_size
= sizeof(struct pvt
);
354 if ((res
= ast_register_translator(&zt
->t
))) {
359 AST_LIST_LOCK(&translators
);
360 AST_LIST_INSERT_HEAD(&translators
, zt
, entry
);
361 AST_LIST_UNLOCK(&translators
);
363 global_format_map
.map
[dst
][src
] = 1;
368 static void drop_translator(int dst
, int src
)
370 struct translator
*cur
;
372 AST_LIST_LOCK(&translators
);
373 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators
, cur
, entry
) {
374 if (cur
->t
.srcfmt
!= src
)
377 if (cur
->t
.dstfmt
!= dst
)
380 AST_LIST_REMOVE_CURRENT(&translators
, entry
);
381 ast_unregister_translator(&cur
->t
);
383 global_format_map
.map
[dst
][src
] = 0;
386 AST_LIST_TRAVERSE_SAFE_END
;
387 AST_LIST_UNLOCK(&translators
);
390 static void unregister_translators(void)
392 struct translator
*cur
;
394 AST_LIST_LOCK(&translators
);
395 while ((cur
= AST_LIST_REMOVE_HEAD(&translators
, entry
))) {
396 ast_unregister_translator(&cur
->t
);
399 AST_LIST_UNLOCK(&translators
);
402 static void parse_config(void)
404 struct ast_variable
*var
;
405 struct ast_config
*cfg
= ast_config_load("codecs.conf");
410 for (var
= ast_variable_browse(cfg
, "plc"); var
; var
= var
->next
) {
411 if (!strcasecmp(var
->name
, "genericplc")) {
412 global_useplc
= ast_true(var
->value
);
413 if (option_verbose
> 2)
414 ast_verbose(VERBOSE_PREFIX_3
"codec_zap: %susing generic PLC\n",
415 global_useplc
? "" : "not ");
419 ast_config_destroy(cfg
);
422 static void build_translators(struct format_map
*map
, unsigned int dstfmts
, unsigned int srcfmts
)
424 unsigned int src
, dst
;
426 for (src
= 0; src
< 32; src
++) {
427 for (dst
= 0; dst
< 32; dst
++) {
428 if (!(srcfmts
& (1 << src
)))
431 if (!(dstfmts
& (1 << dst
)))
434 if (global_format_map
.map
[dst
][src
])
437 if (!register_translator(dst
, src
))
438 map
->map
[dst
][src
] = 1;
443 static int find_transcoders(void)
445 DAHDI_TRANSCODE_INFO info
= { 0, };
446 struct format_map map
= { { { 0 } } };
450 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0) {
451 ast_verbose(VERBOSE_PREFIX_2
"No hardware transcoders found.\n");
455 info
.op
= DAHDI_TCOP_GETINFO
;
456 for (info
.tcnum
= 0; !(res
= ioctl(fd
, DAHDI_TRANSCODE_OP
, &info
)); info
.tcnum
++) {
457 if (option_verbose
> 1)
458 ast_verbose(VERBOSE_PREFIX_2
"Found transcoder '%s'.\n", info
.name
);
459 build_translators(&map
, info
.dstfmts
, info
.srcfmts
);
460 ast_atomic_fetchadd_int(&channels
.total
, info
.numchannels
/ 2);
465 if (!info
.tcnum
&& (option_verbose
> 1))
466 ast_verbose(VERBOSE_PREFIX_2
"No hardware transcoders found.\n");
468 for (x
= 0; x
< 32; x
++) {
469 for (y
= 0; y
< 32; y
++) {
470 if (!map
.map
[x
][y
] && global_format_map
.map
[x
][y
])
471 drop_translator(x
, y
);
478 static int reload(void)
480 struct translator
*cur
;
484 AST_LIST_LOCK(&translators
);
485 AST_LIST_TRAVERSE(&translators
, cur
, entry
)
486 cur
->t
.useplc
= global_useplc
;
487 AST_LIST_UNLOCK(&translators
);
492 static int unload_module(void)
494 ast_cli_unregister_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
495 unregister_translators();
500 static int load_module(void)
504 ast_cli_register_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
509 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Generic Zaptel Transcoder Codec Translator",
511 .unload
= unload_module
,