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</depend>
35 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
40 #include <netinet/in.h>
43 #include <sys/ioctl.h>
46 #include <zaptel/zaptel.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/logger.h"
54 #include "asterisk/channel.h"
55 #include "asterisk/utils.h"
56 #include "asterisk/linkedlists.h"
58 #define BUFFER_SAMPLES 8000
60 static unsigned int global_useplc
= 0;
63 unsigned int map
[32][32];
66 static struct format_map global_format_map
= { { { 0 } } };
69 struct ast_translator t
;
70 AST_LIST_ENTRY(translator
) entry
;
73 static AST_LIST_HEAD_STATIC(translators
, translator
);
78 struct zt_transcode_header
*hdr
;
82 static int zap_framein(struct ast_trans_pvt
*pvt
, struct ast_frame
*f
)
84 struct pvt
*ztp
= pvt
->pvt
;
85 struct zt_transcode_header
*hdr
= ztp
->hdr
;
88 /* Fake a return frame for calculation purposes */
90 pvt
->samples
= f
->samples
;
95 /* Copy at front of buffer */
98 if (hdr
->srclen
+ f
->datalen
> sizeof(hdr
->srcdata
)) {
99 ast_log(LOG_WARNING
, "Out of space for codec translation!\n");
103 if (hdr
->srclen
+ f
->datalen
+ hdr
->srcoffset
> sizeof(hdr
->srcdata
)) {
105 memmove(hdr
->srcdata
, hdr
->srcdata
+ hdr
->srcoffset
, hdr
->srclen
);
109 memcpy(hdr
->srcdata
+ hdr
->srcoffset
, f
->data
, f
->datalen
);
110 hdr
->srclen
+= f
->datalen
;
111 pvt
->samples
+= f
->samples
;
116 static struct ast_frame
*zap_frameout(struct ast_trans_pvt
*pvt
)
118 struct pvt
*ztp
= pvt
->pvt
;
119 struct zt_transcode_header
*hdr
= ztp
->hdr
;
122 if (ztp
->fake
== 2) {
124 ztp
->f
.frametype
= AST_FRAME_VOICE
;
126 ztp
->f
.samples
= 160;
132 } else if (ztp
->fake
== 1) {
134 } else if (!hdr
->srclen
) {
139 x
= ZT_TCOP_TRANSCODE
;
140 if (ioctl(ztp
->fd
, ZT_TRANSCODE_OP
, &x
))
141 ast_log(LOG_WARNING
, "Failed to transcode: %s\n", strerror(errno
));
144 ztp
->f
.frametype
= AST_FRAME_VOICE
;
145 ztp
->f
.subclass
= hdr
->dstfmt
;
146 ztp
->f
.samples
= hdr
->dstsamples
;
147 ztp
->f
.data
= hdr
->dstdata
+ hdr
->dstoffset
;
148 ztp
->f
.offset
= hdr
->dstoffset
;
149 ztp
->f
.datalen
= hdr
->dstlen
;
151 pvt
->samples
-= ztp
->f
.samples
;
157 static void zap_destroy(struct ast_trans_pvt
*pvt
)
159 struct pvt
*ztp
= pvt
->pvt
;
161 munmap(ztp
->hdr
, sizeof(*ztp
->hdr
));
165 static int zap_translate(struct ast_trans_pvt
*pvt
, int dest
, int source
)
167 /* Request translation through zap if possible */
169 unsigned int x
= ZT_TCOP_RESET
;
170 struct pvt
*ztp
= pvt
->pvt
;
171 struct zt_transcode_header
*hdr
;
173 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0)
176 if ((hdr
= mmap(NULL
, sizeof(*hdr
), PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0)) == MAP_FAILED
) {
177 ast_log(LOG_ERROR
, "Memory Map failed for transcoding (%s)\n", strerror(errno
));
183 if (hdr
->magic
!= ZT_TRANSCODE_MAGIC
) {
184 ast_log(LOG_ERROR
, "Transcoder header (%08x) wasn't magic. Abandoning\n", hdr
->magic
);
185 munmap(hdr
, sizeof(*hdr
));
191 hdr
->srcfmt
= (1 << source
);
192 hdr
->dstfmt
= (1 << dest
);
193 if (ioctl(fd
, ZT_TRANSCODE_OP
, &x
)) {
194 ast_log(LOG_ERROR
, "Unable to attach transcoder: %s\n", strerror(errno
));
195 munmap(hdr
, sizeof(*hdr
));
208 static int zap_new(struct ast_trans_pvt
*pvt
)
210 return zap_translate(pvt
, pvt
->t
->dstfmt
, pvt
->t
->srcfmt
);
213 static struct ast_frame
*fakesrc_sample(void)
215 /* Don't bother really trying to test hardware ones. */
216 static struct ast_frame f
= {
217 .frametype
= AST_FRAME_VOICE
,
219 .src
= __PRETTY_FUNCTION__
225 static int register_translator(int dst
, int src
, void *mod
)
227 struct translator
*zt
;
230 if (!(zt
= ast_calloc(1, sizeof(*zt
))))
233 snprintf((char *) (zt
->t
.name
), sizeof(zt
->t
.name
), "zap%sto%s",
234 ast_getformatname((1 << src
)), ast_getformatname((1 << dst
)));
235 zt
->t
.srcfmt
= (1 << src
);
236 zt
->t
.dstfmt
= (1 << dst
);
237 zt
->t
.newpvt
= zap_new
;
238 zt
->t
.framein
= zap_framein
;
239 zt
->t
.frameout
= zap_frameout
;
240 zt
->t
.destroy
= zap_destroy
;
241 zt
->t
.sample
= fakesrc_sample
;
242 zt
->t
.useplc
= global_useplc
;
243 zt
->t
.buf_size
= BUFFER_SAMPLES
* 2;
244 zt
->t
.desc_size
= sizeof(struct pvt
);
245 if ((res
= ast_register_translator(&zt
->t
, mod
))) {
250 AST_LIST_LOCK(&translators
);
251 AST_LIST_INSERT_HEAD(&translators
, zt
, entry
);
252 AST_LIST_UNLOCK(&translators
);
254 global_format_map
.map
[dst
][src
] = 1;
259 static void drop_translator(int dst
, int src
)
261 struct translator
*cur
;
263 AST_LIST_LOCK(&translators
);
264 AST_LIST_TRAVERSE_SAFE_BEGIN(&translators
, cur
, entry
) {
265 if (cur
->t
.srcfmt
!= src
)
268 if (cur
->t
.dstfmt
!= dst
)
271 AST_LIST_REMOVE_CURRENT(&translators
, entry
);
272 ast_unregister_translator(&cur
->t
);
274 global_format_map
.map
[dst
][src
] = 0;
277 AST_LIST_TRAVERSE_SAFE_END
;
278 AST_LIST_UNLOCK(&translators
);
281 static void unregister_translators(void)
283 struct translator
*cur
;
285 AST_LIST_LOCK(&translators
);
286 while ((cur
= AST_LIST_REMOVE_HEAD(&translators
, entry
))) {
287 ast_unregister_translator(&cur
->t
);
290 AST_LIST_UNLOCK(&translators
);
293 static void parse_config(void)
295 struct ast_variable
*var
;
296 struct ast_config
*cfg
= ast_config_load("codecs.conf");
301 for (var
= ast_variable_browse(cfg
, "plc"); var
; var
= var
->next
) {
302 if (!strcasecmp(var
->name
, "genericplc")) {
303 global_useplc
= ast_true(var
->value
);
304 if (option_verbose
> 2)
305 ast_verbose(VERBOSE_PREFIX_3
"codec_zap: %susing generic PLC\n",
306 global_useplc
? "" : "not ");
310 ast_config_destroy(cfg
);
313 static void build_translators(void *mod
, struct format_map
*map
, unsigned int dstfmts
, unsigned int srcfmts
)
315 unsigned int src
, dst
;
317 for (src
= 0; src
< 32; src
++) {
318 for (dst
= 0; dst
< 32; dst
++) {
319 if (!(srcfmts
& (1 << src
)))
322 if (!(dstfmts
& (1 << dst
)))
325 if (global_format_map
.map
[dst
][src
])
328 if (!register_translator(dst
, src
, mod
))
329 map
->map
[dst
][src
] = 1;
334 static int find_transcoders(void *mod
)
336 struct zt_transcode_info info
= { 0, };
337 struct format_map map
= { { { 0 } } };
341 info
.op
= ZT_TCOP_GETINFO
;
342 if ((fd
= open("/dev/zap/transcode", O_RDWR
)) < 0) {
343 ast_log(LOG_NOTICE
, "No Zaptel transcoder support!\n");
346 for (info
.tcnum
= 0; !(res
= ioctl(fd
, ZT_TRANSCODE_OP
, &info
)); info
.tcnum
++) {
347 if (option_verbose
> 1)
348 ast_verbose(VERBOSE_PREFIX_2
"Found transcoder '%s'.\n", info
.name
);
349 build_translators(mod
, &map
, info
.dstfmts
, info
.srcfmts
);
353 if (!info
.tcnum
&& (option_verbose
> 1))
354 ast_verbose(VERBOSE_PREFIX_2
"No hardware transcoders found.\n");
356 for (x
= 0; x
< 32; x
++) {
357 for (y
= 0; y
< 32; y
++) {
358 if (!map
.map
[x
][y
] && global_format_map
.map
[x
][y
])
359 drop_translator(x
, y
);
366 static int reload(void *mod
)
368 struct translator
*cur
;
371 find_transcoders(mod
);
373 AST_LIST_LOCK(&translators
);
374 AST_LIST_TRAVERSE(&translators
, cur
, entry
)
375 cur
->t
.useplc
= global_useplc
;
376 AST_LIST_UNLOCK(&translators
);
381 static int unload_module(void *mod
)
383 unregister_translators();
388 static int load_module(void *mod
)
391 find_transcoders(mod
);
396 static const char *description(void)
398 return "Generic Zaptel Transcoder Codec Translator";
401 static const char *key(void)
403 return ASTERISK_GPL_KEY
;
406 STD_MOD(MOD_1
, reload
, NULL
, NULL
);