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 #ifdef DEBUG_TRANSCODE
115 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 (hdr
->srclen
+ f
->datalen
> sizeof(hdr
->srcdata
)) {
150 ast_log(LOG_WARNING
, "Out of space for codec translation!\n");
154 if (hdr
->srclen
+ f
->datalen
+ hdr
->srcoffset
> sizeof(hdr
->srcdata
)) {
156 memmove(hdr
->srcdata
, hdr
->srcdata
+ hdr
->srcoffset
, hdr
->srclen
);
160 memcpy(hdr
->srcdata
+ hdr
->srcoffset
+ hdr
->srclen
, f
->data
, f
->datalen
);
161 hdr
->srclen
+= f
->datalen
;
162 pvt
->samples
+= f
->samples
;
167 static struct ast_frame
*zap_frameout(struct ast_trans_pvt
*pvt
)
169 struct pvt
*ztp
= pvt
->pvt
;
170 struct zt_transcode_header
*hdr
= ztp
->hdr
;
173 if (ztp
->fake
== 2) {
175 ztp
->f
.frametype
= AST_FRAME_VOICE
;
177 ztp
->f
.samples
= 160;
183 } else if (ztp
->fake
== 1) {
187 #ifdef DEBUG_TRANSCODE
188 ztp
->totalms
+= hdr
->dstsamples
;
189 if ((ztp
->totalms
- ztp
->lasttotalms
) > 8000) {
190 printf("Whee %p, %d (%d to %d)\n", ztp
, hdr
->dstlen
, ztp
->lasttotalms
, ztp
->totalms
);
191 ztp
->lasttotalms
= ztp
->totalms
;
194 ztp
->f
.frametype
= AST_FRAME_VOICE
;
195 ztp
->f
.subclass
= hdr
->dstfmt
;
196 ztp
->f
.samples
= hdr
->dstsamples
;
197 ztp
->f
.data
= hdr
->dstdata
+ hdr
->dstoffset
;
198 ztp
->f
.offset
= hdr
->dstoffset
;
199 ztp
->f
.datalen
= hdr
->dstlen
;
201 pvt
->samples
-= ztp
->f
.samples
;
206 hdr
->dstoffset
= AST_FRIENDLY_OFFSET
;
207 x
= ZT_TCOP_TRANSCODE
;
208 if (ioctl(ztp
->fd
, ZT_TRANSCODE_OP
, &x
))
209 ast_log(LOG_WARNING
, "Failed to transcode: %s\n", strerror(errno
));
218 static void zap_destroy(struct ast_trans_pvt
*pvt
)
220 struct pvt
*ztp
= pvt
->pvt
;
222 ast_atomic_fetchadd_int(&channels
.total
, -1);
223 switch (ztp
->hdr
->dstfmt
) {
224 case AST_FORMAT_G729A
:
225 case AST_FORMAT_G723_1
:
226 ast_atomic_fetchadd_int(&channels
.encoders
, -1);
229 ast_atomic_fetchadd_int(&channels
.decoders
, -1);
233 munmap(ztp
->hdr
, sizeof(*ztp
->hdr
));
237 static int zap_translate(struct ast_trans_pvt
*pvt
, int dest
, int source
)
239 /* Request translation through zap if possible */
241 unsigned int x
= ZT_TCOP_ALLOCATE
;
242 struct pvt
*ztp
= pvt
->pvt
;
243 struct zt_transcode_header
*hdr
;
246 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0)
248 flags
= fcntl(fd
, F_GETFL
);
250 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
))
251 ast_log(LOG_WARNING
, "Could not set non-block mode!\n");
255 if ((hdr
= mmap(NULL
, sizeof(*hdr
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
256 ast_log(LOG_ERROR
, "Memory Map failed for transcoding (%s)\n", strerror(errno
));
262 if (hdr
->magic
!= ZT_TRANSCODE_MAGIC
) {
263 ast_log(LOG_ERROR
, "Transcoder header (%08x) wasn't magic. Abandoning\n", hdr
->magic
);
264 munmap(hdr
, sizeof(*hdr
));
270 hdr
->srcfmt
= (1 << source
);
271 hdr
->dstfmt
= (1 << dest
);
272 if (ioctl(fd
, ZT_TRANSCODE_OP
, &x
)) {
273 ast_log(LOG_ERROR
, "Unable to attach transcoder: %s\n", strerror(errno
));
274 munmap(hdr
, sizeof(*hdr
));
284 ast_atomic_fetchadd_int(&channels
.total
, +1);
285 switch (hdr
->dstfmt
) {
286 case AST_FORMAT_G729A
:
287 case AST_FORMAT_G723_1
:
288 ast_atomic_fetchadd_int(&channels
.encoders
, +1);
291 ast_atomic_fetchadd_int(&channels
.decoders
, +1);
298 static int zap_new(struct ast_trans_pvt
*pvt
)
300 return zap_translate(pvt
, pvt
->t
->dstfmt
, pvt
->t
->srcfmt
);
303 static struct ast_frame
*fakesrc_sample(void)
305 /* Don't bother really trying to test hardware ones. */
306 static struct ast_frame f
= {
307 .frametype
= AST_FRAME_VOICE
,
309 .src
= __PRETTY_FUNCTION__
315 static int register_translator(int dst
, int src
)
317 struct translator
*zt
;
320 if (!(zt
= ast_calloc(1, sizeof(*zt
))))
323 snprintf((char *) (zt
->t
.name
), sizeof(zt
->t
.name
), "zap%sto%s",
324 ast_getformatname((1 << src
)), ast_getformatname((1 << dst
)));
325 zt
->t
.srcfmt
= (1 << src
);
326 zt
->t
.dstfmt
= (1 << dst
);
327 zt
->t
.newpvt
= zap_new
;
328 zt
->t
.framein
= zap_framein
;
329 zt
->t
.frameout
= zap_frameout
;
330 zt
->t
.destroy
= zap_destroy
;
331 zt
->t
.sample
= fakesrc_sample
;
332 zt
->t
.useplc
= global_useplc
;
333 zt
->t
.buf_size
= BUFFER_SAMPLES
* 2;
334 zt
->t
.desc_size
= sizeof(struct pvt
);
335 if ((res
= ast_register_translator(&zt
->t
))) {
340 AST_LIST_LOCK(&translators
);
341 AST_LIST_INSERT_HEAD(&translators
, zt
, entry
);
342 AST_LIST_UNLOCK(&translators
);
344 global_format_map
.map
[dst
][src
] = 1;
349 static void drop_translator(int dst
, int src
)
351 struct translator
*cur
;
353 AST_LIST_LOCK(&translators
);
354 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators
, cur
, entry
) {
355 if (cur
->t
.srcfmt
!= src
)
358 if (cur
->t
.dstfmt
!= dst
)
361 AST_LIST_REMOVE_CURRENT(&translators
, entry
);
362 ast_unregister_translator(&cur
->t
);
364 global_format_map
.map
[dst
][src
] = 0;
367 AST_LIST_TRAVERSE_SAFE_END
;
368 AST_LIST_UNLOCK(&translators
);
371 static void unregister_translators(void)
373 struct translator
*cur
;
375 AST_LIST_LOCK(&translators
);
376 while ((cur
= AST_LIST_REMOVE_HEAD(&translators
, entry
))) {
377 ast_unregister_translator(&cur
->t
);
380 AST_LIST_UNLOCK(&translators
);
383 static void parse_config(void)
385 struct ast_variable
*var
;
386 struct ast_config
*cfg
= ast_config_load("codecs.conf");
391 for (var
= ast_variable_browse(cfg
, "plc"); var
; var
= var
->next
) {
392 if (!strcasecmp(var
->name
, "genericplc")) {
393 global_useplc
= ast_true(var
->value
);
394 if (option_verbose
> 2)
395 ast_verbose(VERBOSE_PREFIX_3
"codec_zap: %susing generic PLC\n",
396 global_useplc
? "" : "not ");
400 ast_config_destroy(cfg
);
403 static void build_translators(struct format_map
*map
, unsigned int dstfmts
, unsigned int srcfmts
)
405 unsigned int src
, dst
;
407 for (src
= 0; src
< 32; src
++) {
408 for (dst
= 0; dst
< 32; dst
++) {
409 if (!(srcfmts
& (1 << src
)))
412 if (!(dstfmts
& (1 << dst
)))
415 if (global_format_map
.map
[dst
][src
])
418 if (!register_translator(dst
, src
))
419 map
->map
[dst
][src
] = 1;
424 static int find_transcoders(void)
426 struct zt_transcode_info info
= { 0, };
427 struct format_map map
= { { { 0 } } };
431 info
.op
= ZT_TCOP_GETINFO
;
432 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0) {
433 ast_log(LOG_DEBUG
, "No Zaptel transcoder support!\n");
436 for (info
.tcnum
= 0; !(res
= ioctl(fd
, ZT_TRANSCODE_OP
, &info
)); info
.tcnum
++) {
437 if (option_verbose
> 1)
438 ast_verbose(VERBOSE_PREFIX_2
"Found transcoder '%s'.\n", info
.name
);
439 build_translators(&map
, info
.dstfmts
, info
.srcfmts
);
443 if (!info
.tcnum
&& (option_verbose
> 1))
444 ast_verbose(VERBOSE_PREFIX_2
"No hardware transcoders found.\n");
446 for (x
= 0; x
< 32; x
++) {
447 for (y
= 0; y
< 32; y
++) {
448 if (!map
.map
[x
][y
] && global_format_map
.map
[x
][y
])
449 drop_translator(x
, y
);
456 static int reload(void)
458 struct translator
*cur
;
462 AST_LIST_LOCK(&translators
);
463 AST_LIST_TRAVERSE(&translators
, cur
, entry
)
464 cur
->t
.useplc
= global_useplc
;
465 AST_LIST_UNLOCK(&translators
);
470 static int unload_module(void)
472 ast_cli_unregister_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
473 unregister_translators();
478 static int load_module(void)
482 ast_cli_register_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
487 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Generic Zaptel Transcoder Codec Translator",
489 .unload
= unload_module
,