31c84438a207791ca85562db471439d24df44d73
[asterisk/asterisk.git] / codecs / codec_zap.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Zaptel native transcoding support
5  *
6  * Copyright (C) 1999 - 2006, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  * Kevin P. Fleming <kpfleming@digium.com>
10  *
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.
16  *
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.
20  */
21
22 /*! \file
23  *
24  * \brief Translate between various formats natively through Zaptel transcoding
25  *
26  * \ingroup codecs
27  */
28
29 /*** MODULEINFO
30         <depend>zaptel_transcode</depend>
31         <depend>zaptel</depend>
32  ***/
33
34 #include "asterisk.h"
35
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 #include <fcntl.h>
39 #include <netinet/in.h>
40 #include <sys/ioctl.h>
41 #include <errno.h>
42 #include <sys/mman.h>
43 #include <zaptel/zaptel.h>
44
45 #include "asterisk/lock.h"
46 #include "asterisk/translate.h"
47 #include "asterisk/config.h"
48 #include "asterisk/options.h"
49 #include "asterisk/module.h"
50 #include "asterisk/cli.h"
51 #include "asterisk/logger.h"
52 #include "asterisk/channel.h"
53 #include "asterisk/utils.h"
54 #include "asterisk/linkedlists.h"
55
56 #define BUFFER_SAMPLES  8000
57
58 static unsigned int global_useplc = 0;
59
60 static struct channel_usage {
61         int total;
62         int encoders;
63         int decoders;
64 } channels;
65
66 static char *handle_cli_transcoder_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
67
68 static struct ast_cli_entry cli[] = {
69         AST_CLI_DEFINE(handle_cli_transcoder_show, "Display Zaptel transcoder utilization.")
70 };
71
72 struct format_map {
73         unsigned int map[32][32];
74 };
75
76 static struct format_map global_format_map = { { { 0 } } };
77
78 struct translator {
79         struct ast_translator t;
80         AST_LIST_ENTRY(translator) entry;
81 };
82
83 static AST_LIST_HEAD_STATIC(translators, translator);
84
85 struct pvt {
86         int fd;
87         int fake;
88 #ifdef DEBUG_TRANSCODE
89         int totalms;
90         int lasttotalms;
91 #endif
92         struct zt_transcode_header *hdr;
93         struct ast_frame f;
94 };
95
96 static char *handle_cli_transcoder_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
97 {
98         struct channel_usage copy;
99
100         switch (cmd) {
101         case CLI_INIT:
102                 e->command = "transcoder show";
103                 e->usage =
104                         "Usage: transcoder show\n"
105                         "       Displays channel utilization of Zaptel transcoder(s).\n";
106                 return NULL;
107         case CLI_GENERATE:
108                 return NULL;
109         }
110
111         if (a->argc != 2)
112                 return CLI_SHOWUSAGE;
113
114         copy = channels;
115
116         if (copy.total == 0)
117                 ast_cli(a->fd, "No Zaptel transcoders found.\n");
118         else
119                 ast_cli(a->fd, "%d/%d encoders/decoders of %d channels are in use.\n", copy.encoders, copy.decoders, copy.total);
120
121         return CLI_SUCCESS;
122 }
123
124 static int zap_framein(struct ast_trans_pvt *pvt, struct ast_frame *f)
125 {
126         struct pvt *ztp = pvt->pvt;
127         struct zt_transcode_header *hdr = ztp->hdr;
128
129         if (!f->subclass) {
130                 /* Fake a return frame for calculation purposes */
131                 ztp->fake = 2;
132                 pvt->samples = f->samples;
133                 return 0;
134         }
135
136         if (!hdr->srclen)
137                 /* Copy at front of buffer */
138                 hdr->srcoffset = 0;
139
140         if (hdr->srclen + f->datalen > sizeof(hdr->srcdata)) {
141                 ast_log(LOG_WARNING, "Out of space for codec translation!\n");
142                 return -1;
143         }
144
145         if (hdr->srclen + f->datalen + hdr->srcoffset > sizeof(hdr->srcdata)) {
146                 /* Very unlikely */
147                 memmove(hdr->srcdata, hdr->srcdata + hdr->srcoffset, hdr->srclen);
148                 hdr->srcoffset = 0;
149         }
150
151         memcpy(hdr->srcdata + hdr->srcoffset + hdr->srclen, f->data, f->datalen);
152         hdr->srclen += f->datalen;
153         pvt->samples += f->samples;
154
155         return -1;
156 }
157
158 static struct ast_frame *zap_frameout(struct ast_trans_pvt *pvt)
159 {
160         struct pvt *ztp = pvt->pvt;
161         struct zt_transcode_header *hdr = ztp->hdr;
162         unsigned int x;
163
164         if (ztp->fake == 2) {
165                 ztp->fake = 1;
166                 ztp->f.frametype = AST_FRAME_VOICE;
167                 ztp->f.subclass = 0;
168                 ztp->f.samples = 160;
169                 ztp->f.data = NULL;
170                 ztp->f.offset = 0;
171                 ztp->f.datalen = 0;
172                 ztp->f.mallocd = 0;
173                 pvt->samples = 0;
174         } else if (ztp->fake == 1) {
175                 return NULL;
176         } else {
177                 if (hdr->dstlen) {
178 #ifdef DEBUG_TRANSCODE
179                         ztp->totalms += hdr->dstsamples;
180                         if ((ztp->totalms - ztp->lasttotalms) > 8000) {
181                                 printf("Whee %p, %d (%d to %d)\n", ztp, hdr->dstlen, ztp->lasttotalms, ztp->totalms);
182                                 ztp->lasttotalms = ztp->totalms;
183                         }
184 #endif
185                         ztp->f.frametype = AST_FRAME_VOICE;
186                         ztp->f.subclass = hdr->dstfmt;
187                         ztp->f.samples = hdr->dstsamples;
188                         ztp->f.data = hdr->dstdata + hdr->dstoffset;
189                         ztp->f.offset = hdr->dstoffset;
190                         ztp->f.datalen = hdr->dstlen;
191                         ztp->f.mallocd = 0;
192                         pvt->samples -= ztp->f.samples;
193                         hdr->dstlen = 0;
194                         
195                 } else {
196                         if (hdr->srclen) {
197                                 hdr->dstoffset = AST_FRIENDLY_OFFSET;
198                                 x = ZT_TCOP_TRANSCODE;
199                                 if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x))
200                                         ast_log(LOG_WARNING, "Failed to transcode: %s\n", strerror(errno));
201                         }
202                         return NULL;
203                 }
204         }
205
206         return &ztp->f;
207 }
208
209 static void zap_destroy(struct ast_trans_pvt *pvt)
210 {
211         struct pvt *ztp = pvt->pvt;
212         unsigned int x;
213
214         x = ZT_TCOP_RELEASE;
215         if (ioctl(ztp->fd, ZT_TRANSCODE_OP, &x))
216                 ast_log(LOG_WARNING, "Failed to release transcoder channel: %s\n", strerror(errno));
217
218         switch (ztp->hdr->dstfmt) {
219         case AST_FORMAT_G729A:
220         case AST_FORMAT_G723_1:
221                 ast_atomic_fetchadd_int(&channels.encoders, -1);
222                 break;
223         default:
224                 ast_atomic_fetchadd_int(&channels.decoders, -1);
225                 break;
226         }
227
228         munmap(ztp->hdr, sizeof(*ztp->hdr));
229         close(ztp->fd);
230 }
231
232 static int zap_translate(struct ast_trans_pvt *pvt, int dest, int source)
233 {
234         /* Request translation through zap if possible */
235         int fd;
236         unsigned int x = ZT_TCOP_ALLOCATE;
237         struct pvt *ztp = pvt->pvt;
238         struct zt_transcode_header *hdr;
239         int flags;
240         
241         if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0)
242                 return -1;
243         flags = fcntl(fd, F_GETFL);
244         if (flags > - 1) {
245                 if (fcntl(fd, F_SETFL, flags | O_NONBLOCK))
246                         ast_log(LOG_WARNING, "Could not set non-block mode!\n");
247         }
248         
249
250         if ((hdr = mmap(NULL, sizeof(*hdr), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
251                 ast_log(LOG_ERROR, "Memory Map failed for transcoding (%s)\n", strerror(errno));
252                 close(fd);
253
254                 return -1;
255         }
256
257         if (hdr->magic != ZT_TRANSCODE_MAGIC) {
258                 ast_log(LOG_ERROR, "Transcoder header (%08x) wasn't magic.  Abandoning\n", hdr->magic);
259                 munmap(hdr, sizeof(*hdr));
260                 close(fd);
261
262                 return -1;
263         }
264         
265         hdr->srcfmt = (1 << source);
266         hdr->dstfmt = (1 << dest);
267         if (ioctl(fd, ZT_TRANSCODE_OP, &x)) {
268                 ast_log(LOG_ERROR, "Unable to attach transcoder: %s\n", strerror(errno));
269                 munmap(hdr, sizeof(*hdr));
270                 close(fd);
271
272                 return -1;
273         }
274
275         ztp = pvt->pvt;
276         ztp->fd = fd;
277         ztp->hdr = hdr;
278
279         switch (hdr->dstfmt) {
280         case AST_FORMAT_G729A:
281         case AST_FORMAT_G723_1:
282                 ast_atomic_fetchadd_int(&channels.encoders, +1);
283                 break;
284         default:
285                 ast_atomic_fetchadd_int(&channels.decoders, +1);
286                 break;
287         }
288
289         return 0;
290 }
291
292 static int zap_new(struct ast_trans_pvt *pvt)
293 {
294         return zap_translate(pvt, pvt->t->dstfmt, pvt->t->srcfmt);
295 }
296
297 static struct ast_frame *fakesrc_sample(void)
298 {
299         /* Don't bother really trying to test hardware ones. */
300         static struct ast_frame f = {
301                 .frametype = AST_FRAME_VOICE,
302                 .samples = 160,
303                 .src = __PRETTY_FUNCTION__
304         };
305
306         return &f;
307 }
308
309 static int register_translator(int dst, int src)
310 {
311         struct translator *zt;
312         int res;
313
314         if (!(zt = ast_calloc(1, sizeof(*zt))))
315                 return -1;
316
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))) {
330                 ast_free(zt);
331                 return -1;
332         }
333
334         AST_LIST_LOCK(&translators);
335         AST_LIST_INSERT_HEAD(&translators, zt, entry);
336         AST_LIST_UNLOCK(&translators);
337
338         global_format_map.map[dst][src] = 1;
339
340         return res;
341 }
342
343 static void drop_translator(int dst, int src)
344 {
345         struct translator *cur;
346
347         AST_LIST_LOCK(&translators);
348         AST_LIST_TRAVERSE_SAFE_BEGIN(&translators, cur, entry) {
349                 if (cur->t.srcfmt != src)
350                         continue;
351
352                 if (cur->t.dstfmt != dst)
353                         continue;
354
355                 AST_LIST_REMOVE_CURRENT(entry);
356                 ast_unregister_translator(&cur->t);
357                 ast_free(cur);
358                 global_format_map.map[dst][src] = 0;
359                 break;
360         }
361         AST_LIST_TRAVERSE_SAFE_END;
362         AST_LIST_UNLOCK(&translators);
363 }
364
365 static void unregister_translators(void)
366 {
367         struct translator *cur;
368
369         AST_LIST_LOCK(&translators);
370         while ((cur = AST_LIST_REMOVE_HEAD(&translators, entry))) {
371                 ast_unregister_translator(&cur->t);
372                 ast_free(cur);
373         }
374         AST_LIST_UNLOCK(&translators);
375 }
376
377 static int parse_config(int reload)
378 {
379         struct ast_variable *var;
380         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
381         struct ast_config *cfg = ast_config_load("codecs.conf", config_flags);
382
383         if (!cfg)
384                 return -1;
385         if (cfg == CONFIG_STATUS_FILEUNCHANGED)
386                 return 0;
387
388         for (var = ast_variable_browse(cfg, "plc"); var; var = var->next) {
389                if (!strcasecmp(var->name, "genericplc")) {
390                        global_useplc = ast_true(var->value);
391                            ast_verb(3, "codec_zap: %susing generic PLC\n",
392                                            global_useplc ? "" : "not ");
393                }
394         }
395         ast_config_destroy(cfg);
396         return 0;
397 }
398
399 static void build_translators(struct format_map *map, unsigned int dstfmts, unsigned int srcfmts)
400 {
401         unsigned int src, dst;
402
403         for (src = 0; src < 32; src++) {
404                 for (dst = 0; dst < 32; dst++) {
405                         if (!(srcfmts & (1 << src)))
406                                 continue;
407
408                         if (!(dstfmts & (1 << dst)))
409                                 continue;
410
411                         if (global_format_map.map[dst][src])
412                                 continue;
413
414                         if (!register_translator(dst, src))
415                                 map->map[dst][src] = 1;
416                 }
417         }
418 }
419
420 static int find_transcoders(void)
421 {
422         struct zt_transcode_info info = { 0, };
423         struct format_map map = { { { 0 } } };
424         int fd, res;
425         unsigned int x, y;
426
427         info.op = ZT_TCOP_GETINFO;
428         if ((fd = open("/dev/zap/transcode", O_RDWR)) < 0) {
429                 ast_debug(1, "No Zaptel transcoder support!\n");
430                 return 0;
431         }
432         for (info.tcnum = 0; !(res = ioctl(fd, ZT_TRANSCODE_OP, &info)); info.tcnum++) {
433                 ast_verb(2, "Found transcoder '%s'.\n", info.name);
434                 build_translators(&map, info.dstfmts, info.srcfmts);
435                 ast_atomic_fetchadd_int(&channels.total, info.numchannels / 2);
436         }
437         close(fd);
438
439         if (!info.tcnum)
440                 ast_verb(2, "No hardware transcoders found.\n");
441
442         for (x = 0; x < 32; x++) {
443                 for (y = 0; y < 32; y++) {
444                         if (!map.map[x][y] && global_format_map.map[x][y])
445                                 drop_translator(x, y);
446                 }
447         }
448
449         return 0;
450 }
451
452 static int reload(void)
453 {
454         struct translator *cur;
455
456         if (parse_config(1))
457                 return AST_MODULE_LOAD_DECLINE;
458
459         AST_LIST_LOCK(&translators);
460         AST_LIST_TRAVERSE(&translators, cur, entry)
461                 cur->t.useplc = global_useplc;
462         AST_LIST_UNLOCK(&translators);
463
464         return AST_MODULE_LOAD_SUCCESS;
465 }
466
467 static int unload_module(void)
468 {
469         ast_cli_unregister_multiple(cli, sizeof(cli) / sizeof(cli[0]));
470         unregister_translators();
471
472         return 0;
473 }
474
475 static int load_module(void)
476 {
477         if (parse_config(0))
478                 return AST_MODULE_LOAD_DECLINE;
479         find_transcoders();
480         ast_cli_register_multiple(cli, sizeof(cli) / sizeof(cli[0]));
481         return AST_MODULE_LOAD_SUCCESS;
482 }
483
484 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Generic Zaptel Transcoder Codec Translator",
485                 .load = load_module,
486                 .unload = unload_module,
487                 .reload = reload,
488                 );