2 * Asterisk -- An open source telephony toolkit.
4 * DAHDI native transcoding support
6 * Copyright (C) 1999 - 2008, 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 DAHDI 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"
58 #include "asterisk/dahdi_compat.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 DAHDI transcoder(s).\n";
74 static char transcoder_show_usage
[] =
75 "Usage: transcoder show\n"
76 " Displays channel utilization of DAHDI 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 DAHDI transcoder utilization.",
84 show_transcoder_usage
}
87 static struct ast_cli_entry cli
[] = {
88 { { "transcoder", "show", NULL
},
90 "Display DAHDI 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
);
112 struct dahdi_transcoder_formats fmts
;
115 static int transcoder_show(int fd
, int argc
, char **argv
)
117 struct channel_usage copy
;
122 ast_cli(fd
, "No DAHDI transcoders found.\n");
124 ast_cli(fd
, "%d/%d encoders/decoders of %d channels are in use.\n", copy
.encoders
, copy
.decoders
, copy
.total
);
126 return RESULT_SUCCESS
;
129 static int zap_framein(struct ast_trans_pvt
*pvt
, struct ast_frame
*f
)
132 struct pvt
*ztp
= pvt
->pvt
;
135 /* Give the frame to the hardware transcoder... */
136 res
= write(ztp
->fd
, f
->data
, f
->datalen
);
138 ast_log(LOG_ERROR
, "Failed to write to transcoder: %s\n", strerror(errno
));
140 if (f
->datalen
!= res
) {
141 ast_log(LOG_ERROR
, "Requested write of %d bytes, but only wrote %d bytes.\n", f
->datalen
, res
);
144 pvt
->samples
+= f
->samples
;
146 /* Fake a return frame for calculation purposes */
148 pvt
->samples
= f
->samples
;
154 static struct ast_frame
*zap_frameout(struct ast_trans_pvt
*pvt
)
156 struct pvt
*ztp
= pvt
->pvt
;
158 if (0 == ztp
->fake
) {
160 /* Let's check to see if there is a new frame for us.... */
161 res
= read(ztp
->fd
, pvt
->outbuf
+ pvt
->datalen
, pvt
->t
->buf_size
- pvt
->datalen
);
163 if (EWOULDBLOCK
== errno
) {
164 /* Nothing waiting... */
167 ast_log(LOG_ERROR
, "Failed to read from transcoder: %s\n", strerror(errno
));
171 pvt
->f
.samples
= ztp
->samples
;
172 pvt
->f
.datalen
= res
;
174 pvt
->f
.frametype
= AST_FRAME_VOICE
;
175 pvt
->f
.subclass
= 1 << (pvt
->t
->dstfmt
);
177 pvt
->f
.offset
= AST_FRIENDLY_OFFSET
;
178 pvt
->f
.src
= pvt
->t
->name
;
179 pvt
->f
.data
= pvt
->outbuf
;
180 ast_set_flag(&pvt
->f
, AST_FRFLAG_FROM_TRANSLATOR
);
185 } else if (2 == ztp
->fake
) {
188 pvt
->f
.frametype
= AST_FRAME_VOICE
;
190 pvt
->f
.samples
= 160;
195 ast_set_flag(&pvt
->f
, AST_FRFLAG_FROM_TRANSLATOR
);
200 } else if (1 == ztp
->fake
) {
205 /* Shouldn't get here... */
209 static void zap_destroy(struct ast_trans_pvt
*pvt
)
211 struct pvt
*ztp
= pvt
->pvt
;
213 switch (ztp
->fmts
.dstfmt
) {
214 case AST_FORMAT_G729A
:
215 case AST_FORMAT_G723_1
:
216 ast_atomic_fetchadd_int(&channels
.encoders
, -1);
219 ast_atomic_fetchadd_int(&channels
.decoders
, -1);
226 static int zap_translate(struct ast_trans_pvt
*pvt
, int dest
, int source
)
228 /* Request translation through zap if possible */
230 struct pvt
*ztp
= pvt
->pvt
;
234 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0) {
235 ast_log(LOG_ERROR
, "Failed to open /dev/zap/transcode: %s\n", strerror(errno
));
239 if ((fd
= open("/dev/dahdi/transcode", O_RDWR
)) < 0) {
240 ast_log(LOG_ERROR
, "Failed to open /dev/dahdi/transcode: %s\n", strerror(errno
));
245 ztp
->fmts
.srcfmt
= (1 << source
);
246 ztp
->fmts
.dstfmt
= (1 << dest
);
248 ast_log(LOG_VERBOSE
, "Opening transcoder channel from %d to %d.\n", source
, dest
);
250 if (ioctl(fd
, DAHDI_TC_ALLOCATE
, &ztp
->fmts
)) {
251 ast_log(LOG_ERROR
, "Unable to attach to transcoder: %s\n", strerror(errno
));
257 flags
= fcntl(fd
, F_GETFL
);
259 if (fcntl(fd
, F_SETFL
, flags
| O_NONBLOCK
))
260 ast_log(LOG_WARNING
, "Could not set non-block mode!\n");
265 switch (ztp
->fmts
.dstfmt
) {
266 case AST_FORMAT_G729A
:
269 case AST_FORMAT_G723_1
:
277 switch (ztp
->fmts
.dstfmt
) {
278 case AST_FORMAT_G729A
:
279 ast_atomic_fetchadd_int(&channels
.encoders
, +1);
281 case AST_FORMAT_G723_1
:
282 ast_atomic_fetchadd_int(&channels
.encoders
, +1);
285 ast_atomic_fetchadd_int(&channels
.decoders
, +1);
292 static int zap_new(struct ast_trans_pvt
*pvt
)
294 return zap_translate(pvt
, pvt
->t
->dstfmt
, pvt
->t
->srcfmt
);
297 static struct ast_frame
*fakesrc_sample(void)
299 /* Don't bother really trying to test hardware ones. */
300 static struct ast_frame f
= {
301 .frametype
= AST_FRAME_VOICE
,
303 .src
= __PRETTY_FUNCTION__
309 static int register_translator(int dst
, int src
)
311 struct translator
*zt
;
314 if (!(zt
= ast_calloc(1, sizeof(*zt
))))
317 snprintf((char *) (zt
->t
.name
), sizeof(zt
->t
.name
), "zap%sto%s",
318 ast_getformatname((1 << src
)), ast_getformatname((1 << dst
)));
319 zt
->t
.srcfmt
= (1 << src
);
320 zt
->t
.dstfmt
= (1 << dst
);
321 zt
->t
.newpvt
= zap_new
;
322 zt
->t
.framein
= zap_framein
;
323 zt
->t
.frameout
= zap_frameout
;
324 zt
->t
.destroy
= zap_destroy
;
325 zt
->t
.sample
= fakesrc_sample
;
326 zt
->t
.useplc
= global_useplc
;
327 zt
->t
.buf_size
= BUFFER_SAMPLES
* 2;
328 zt
->t
.desc_size
= sizeof(struct pvt
);
329 if ((res
= ast_register_translator(&zt
->t
))) {
334 AST_LIST_LOCK(&translators
);
335 AST_LIST_INSERT_HEAD(&translators
, zt
, entry
);
336 AST_LIST_UNLOCK(&translators
);
338 global_format_map
.map
[dst
][src
] = 1;
343 static void drop_translator(int dst
, int src
)
345 struct translator
*cur
;
347 AST_LIST_LOCK(&translators
);
348 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators
, cur
, entry
) {
349 if (cur
->t
.srcfmt
!= src
)
352 if (cur
->t
.dstfmt
!= dst
)
355 AST_LIST_REMOVE_CURRENT(&translators
, entry
);
356 ast_unregister_translator(&cur
->t
);
358 global_format_map
.map
[dst
][src
] = 0;
361 AST_LIST_TRAVERSE_SAFE_END
;
362 AST_LIST_UNLOCK(&translators
);
365 static void unregister_translators(void)
367 struct translator
*cur
;
369 AST_LIST_LOCK(&translators
);
370 while ((cur
= AST_LIST_REMOVE_HEAD(&translators
, entry
))) {
371 ast_unregister_translator(&cur
->t
);
374 AST_LIST_UNLOCK(&translators
);
377 static void parse_config(void)
379 struct ast_variable
*var
;
380 struct ast_config
*cfg
= ast_config_load("codecs.conf");
385 for (var
= ast_variable_browse(cfg
, "plc"); var
; var
= var
->next
) {
386 if (!strcasecmp(var
->name
, "genericplc")) {
387 global_useplc
= ast_true(var
->value
);
388 if (option_verbose
> 2)
389 ast_verbose(VERBOSE_PREFIX_3
"codec_zap: %susing generic PLC\n",
390 global_useplc
? "" : "not ");
394 ast_config_destroy(cfg
);
397 static void build_translators(struct format_map
*map
, unsigned int dstfmts
, unsigned int srcfmts
)
399 unsigned int src
, dst
;
401 for (src
= 0; src
< 32; src
++) {
402 for (dst
= 0; dst
< 32; dst
++) {
403 if (!(srcfmts
& (1 << src
)))
406 if (!(dstfmts
& (1 << dst
)))
409 if (global_format_map
.map
[dst
][src
])
412 if (!register_translator(dst
, src
))
413 map
->map
[dst
][src
] = 1;
418 static int find_transcoders(void)
420 struct dahdi_transcoder_info info
= { 0, };
421 struct format_map map
= { { { 0 } } };
426 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0) {
427 ast_log(LOG_ERROR
, "Failed to open /dev/zap/transcode: %s\n", strerror(errno
));
431 if ((fd
= open("/dev/dahdi/transcode", O_RDWR
)) < 0) {
432 ast_log(LOG_ERROR
, "Failed to open /dev/dahdi/transcode: %s\n", strerror(errno
));
437 for (info
.tcnum
= 0; !(res
= ioctl(fd
, DAHDI_TC_GETINFO
, &info
)); info
.tcnum
++) {
438 if (option_verbose
> 1)
439 ast_verbose(VERBOSE_PREFIX_2
"Found transcoder '%s'.\n", info
.name
);
440 build_translators(&map
, info
.dstfmts
, info
.srcfmts
);
441 ast_atomic_fetchadd_int(&channels
.total
, info
.numchannels
/ 2);
446 if (!info
.tcnum
&& (option_verbose
> 1))
447 ast_verbose(VERBOSE_PREFIX_2
"No hardware transcoders found.\n");
449 for (x
= 0; x
< 32; x
++) {
450 for (y
= 0; y
< 32; y
++) {
451 if (!map
.map
[x
][y
] && global_format_map
.map
[x
][y
])
452 drop_translator(x
, y
);
459 static int reload(void)
461 struct translator
*cur
;
465 AST_LIST_LOCK(&translators
);
466 AST_LIST_TRAVERSE(&translators
, cur
, entry
)
467 cur
->t
.useplc
= global_useplc
;
468 AST_LIST_UNLOCK(&translators
);
473 static int unload_module(void)
475 ast_cli_unregister_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
476 unregister_translators();
481 static int load_module(void)
485 ast_cli_register_multiple(cli
, sizeof(cli
) / sizeof(cli
[0]));
490 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "Generic DAHDI Transcoder Codec Translator",
492 .unload
= unload_module
,