Merge team/russell/frame_caching
[asterisk/asterisk.git] / main / frame.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Frame and codec manipulation routines
22  *
23  * \author Mark Spencer <markster@digium.com> 
24  */
25
26 #include "asterisk.h"
27
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
29
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <stdio.h>
35
36 #include "asterisk/lock.h"
37 #include "asterisk/frame.h"
38 #include "asterisk/logger.h"
39 #include "asterisk/options.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/cli.h"
42 #include "asterisk/term.h"
43 #include "asterisk/utils.h"
44 #include "asterisk/threadstorage.h"
45 #include "asterisk/linkedlists.h"
46
47 #ifdef TRACE_FRAMES
48 static int headers = 0;
49 static AST_LIST_HEAD_STATIC(headerlist, ast_frame);
50 #endif
51
52 static void frame_cache_cleanup(void *data);
53
54 /*! \brief A per-thread cache of frame headers */
55 AST_THREADSTORAGE_CUSTOM(frame_cache, frame_cache_init, frame_cache_cleanup);
56
57 /*! 
58  * \brief Maximum ast_frame cache size
59  *
60  * In most cases where the frame header cache will be useful, the size
61  * of the cache will stay very small.  However, it is not always the case that
62  * the same thread that allocates the frame will be the one freeing them, so
63  * sometimes a thread will never have any frames in its cache, or the cache
64  * will never be pulled from.  For the latter case, we limit the maximum size. 
65  */ 
66 #define FRAME_CACHE_MAX_SIZE    10
67
68 /*! \brief This is just so ast_frames, a list head struct for holding a list of
69  *  ast_frame structures, is defined. */
70 AST_LIST_HEAD_NOLOCK(ast_frames, ast_frame);
71
72 struct ast_frame_cache {
73         struct ast_frames list;
74         size_t size;
75 };
76
77 #define SMOOTHER_SIZE 8000
78
79 enum frame_type {
80         TYPE_HIGH,     /* 0x0 */
81         TYPE_LOW,      /* 0x1 */
82         TYPE_SILENCE,  /* 0x2 */
83         TYPE_DONTSEND  /* 0x3 */
84 };
85
86 #define TYPE_MASK 0x3
87
88 struct ast_smoother {
89         int size;
90         int format;
91         int readdata;
92         int optimizablestream;
93         int flags;
94         float samplesperbyte;
95         struct ast_frame f;
96         struct timeval delivery;
97         char data[SMOOTHER_SIZE];
98         char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET];
99         struct ast_frame *opt;
100         int len;
101 };
102
103 /*! \brief Definition of supported media formats (codecs) */
104 static struct ast_format_list {
105         int visible;    /*!< Can we see this entry */
106         int bits;       /*!< bitmask value */
107         char *name;     /*!< short name */
108         char *desc;     /*!< Description */
109 } AST_FORMAT_LIST[] = {                                 /*!< Bit number: comment  - Bit numbers are hard coded in show_codec() */
110         { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1"},   /*!<  1 */
111         { 1, AST_FORMAT_GSM, "gsm" , "GSM"},            /*!<  2: codec_gsm.c */
112         { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law" },  /*!<  3: codec_ulaw.c */
113         { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law" },  /*!<  4: codec_alaw.c */
114         { 1, AST_FORMAT_G726, "g726", "G.726 RFC3551" },/*!<  5: codec_g726.c */
115         { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM"},      /*!<  6: codec_adpcm.c */
116         { 1, AST_FORMAT_SLINEAR, "slin",  "16 bit Signed Linear PCM"},  /*!< 7 */
117         { 1, AST_FORMAT_LPC10, "lpc10", "LPC10" },      /*!<  8: codec_lpc10.c */
118         { 1, AST_FORMAT_G729A, "g729", "G.729A" },      /*!<  9: Binary commercial distribution */
119         { 1, AST_FORMAT_SPEEX, "speex", "SpeeX" },      /*!< 10: codec_speex.c */
120         { 1, AST_FORMAT_ILBC, "ilbc", "iLBC"},          /*!< 11: codec_ilbc.c */
121         { 1, AST_FORMAT_G726_AAL2, "g726aal2", "G.726 AAL2" },  /*!<  12: codec_g726.c */
122         { 0, 0, "nothing", "undefined" },
123         { 0, 0, "nothing", "undefined" },
124         { 0, 0, "nothing", "undefined" },
125         { 0, 0, "nothing", "undefined" },
126         { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" },        
127         { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"},    /*!< 17: See format_jpeg.c */
128         { 1, AST_FORMAT_PNG, "png", "PNG image"},       /*!< 18: Image format */
129         { 1, AST_FORMAT_H261, "h261", "H.261 Video" },  /*!< 19: Video Passthrough */
130         { 1, AST_FORMAT_H263, "h263", "H.263 Video" },  /*!< 20: Passthrough support, see format_h263.c */
131         { 1, AST_FORMAT_H263_PLUS, "h263p", "H.263+ Video" },   /*!< 21: See format_h263.c */
132         { 1, AST_FORMAT_H264, "h264", "H.264 Video" },  /*!< 22: Passthrough support, see format_h263.c */
133         { 0, 0, "nothing", "undefined" },
134         { 0, 0, "nothing", "undefined" },
135         { 0, 0, "nothing", "undefined" },
136         { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" },
137 };
138
139 struct ast_frame ast_null_frame = { AST_FRAME_NULL, };
140
141 void ast_smoother_reset(struct ast_smoother *s, int size)
142 {
143         memset(s, 0, sizeof(*s));
144         s->size = size;
145 }
146
147 struct ast_smoother *ast_smoother_new(int size)
148 {
149         struct ast_smoother *s;
150         if (size < 1)
151                 return NULL;
152         if ((s = ast_malloc(sizeof(*s))))
153                 ast_smoother_reset(s, size);
154         return s;
155 }
156
157 int ast_smoother_get_flags(struct ast_smoother *s)
158 {
159         return s->flags;
160 }
161
162 void ast_smoother_set_flags(struct ast_smoother *s, int flags)
163 {
164         s->flags = flags;
165 }
166
167 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap)
168 {
169         if (f->frametype != AST_FRAME_VOICE) {
170                 ast_log(LOG_WARNING, "Huh?  Can't smooth a non-voice frame!\n");
171                 return -1;
172         }
173         if (!s->format) {
174                 s->format = f->subclass;
175                 s->samplesperbyte = (float)f->samples / (float)f->datalen;
176         } else if (s->format != f->subclass) {
177                 ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass);
178                 return -1;
179         }
180         if (s->len + f->datalen > SMOOTHER_SIZE) {
181                 ast_log(LOG_WARNING, "Out of smoother space\n");
182                 return -1;
183         }
184         if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729)))
185                                  && !s->opt && (f->offset >= AST_MIN_OFFSET)) {
186                 if (!s->len) {
187                         /* Optimize by sending the frame we just got
188                            on the next read, thus eliminating the douple
189                            copy */
190                         s->opt = f;
191                         return 0;
192                 } else {
193                         s->optimizablestream++;
194                         if (s->optimizablestream > 10) {
195                                 /* For the past 10 rounds, we have input and output
196                                    frames of the correct size for this smoother, yet
197                                    we were unable to optimize because there was still
198                                    some cruft left over.  Lets just drop the cruft so
199                                    we can move to a fully optimized path */
200                                 s->len = 0;
201                                 s->opt = f;
202                                 return 0;
203                         }
204                 }
205         } else 
206                 s->optimizablestream = 0;
207         if (s->flags & AST_SMOOTHER_FLAG_G729) {
208                 if (s->len % 10) {
209                         ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n");
210                         return 0;
211                 }
212         }
213         if (swap)
214                 ast_swapcopy_samples(s->data+s->len, f->data, f->samples);
215         else
216                 memcpy(s->data + s->len, f->data, f->datalen);
217         /* If either side is empty, reset the delivery time */
218         if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery))      /* XXX really ? */
219                 s->delivery = f->delivery;
220         s->len += f->datalen;
221         return 0;
222 }
223
224 struct ast_frame *ast_smoother_read(struct ast_smoother *s)
225 {
226         struct ast_frame *opt;
227         int len;
228
229         /* IF we have an optimization frame, send it */
230         if (s->opt) {
231                 if (s->opt->offset < AST_FRIENDLY_OFFSET)
232                         ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).",
233                                                         s->opt->offset);
234                 opt = s->opt;
235                 s->opt = NULL;
236                 return opt;
237         }
238
239         /* Make sure we have enough data */
240         if (s->len < s->size) {
241                 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */
242                 if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10)))
243                         return NULL;
244         }
245         len = s->size;
246         if (len > s->len)
247                 len = s->len;
248         /* Make frame */
249         s->f.frametype = AST_FRAME_VOICE;
250         s->f.subclass = s->format;
251         s->f.data = s->framedata + AST_FRIENDLY_OFFSET;
252         s->f.offset = AST_FRIENDLY_OFFSET;
253         s->f.datalen = len;
254         /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */
255         s->f.samples = len * s->samplesperbyte; /* XXX rounding */
256         s->f.delivery = s->delivery;
257         /* Fill Data */
258         memcpy(s->f.data, s->data, len);
259         s->len -= len;
260         /* Move remaining data to the front if applicable */
261         if (s->len) {
262                 /* In principle this should all be fine because if we are sending
263                    G.729 VAD, the next timestamp will take over anyawy */
264                 memmove(s->data, s->data + len, s->len);
265                 if (!ast_tvzero(s->delivery)) {
266                         /* If we have delivery time, increment it, otherwise, leave it at 0 */
267                         s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000));
268                 }
269         }
270         /* Return frame */
271         return &s->f;
272 }
273
274 void ast_smoother_free(struct ast_smoother *s)
275 {
276         free(s);
277 }
278
279 static struct ast_frame *ast_frame_header_new(void)
280 {
281         struct ast_frame *f;
282         struct ast_frame_cache *frames;
283
284         if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) {
285                 if ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list))) {
286                         size_t mallocd_len = f->mallocd_hdr_len;
287                         memset(f, 0, sizeof(*f));
288                         f->mallocd_hdr_len = mallocd_len;
289                         f->mallocd = AST_MALLOCD_HDR;
290                         frames->size--;
291                         return f;
292                 }
293         }
294
295         if (!(f = ast_calloc(1, sizeof(*f))))
296                 return NULL;
297
298         f->mallocd_hdr_len = sizeof(*f);
299 #ifdef TRACE_FRAMES
300         AST_LIST_LOCK(&headerlist);
301         headers++;
302         AST_LIST_INSERT_HEAD(&headerlist, f, frame_list);
303         AST_LIST_UNLOCK(&headerlist);
304 #endif  
305         
306         return f;
307 }
308
309 static void frame_cache_cleanup(void *data)
310 {
311         struct ast_frame_cache *frames = data;
312         struct ast_frame *f;
313
314         while ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list)))
315                 free(f);
316         
317         free(frames);
318 }
319
320 void ast_frfree(struct ast_frame *fr)
321 {
322         if (!fr->mallocd)
323                 return;
324
325         if (fr->mallocd == AST_MALLOCD_HDR) {
326                 /* Cool, only the header is malloc'd, let's just cache those for now 
327                  * to keep things simple... */
328                 struct ast_frame_cache *frames;
329
330                 if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) 
331                     && frames->size < FRAME_CACHE_MAX_SIZE) {
332                         AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list);
333                         frames->size++;
334                         return;
335                 }
336         }
337         
338         if (fr->mallocd & AST_MALLOCD_DATA) {
339                 if (fr->data) 
340                         free(fr->data - fr->offset);
341         }
342         if (fr->mallocd & AST_MALLOCD_SRC) {
343                 if (fr->src)
344                         free((char *)fr->src);
345         }
346         if (fr->mallocd & AST_MALLOCD_HDR) {
347 #ifdef TRACE_FRAMES
348                 AST_LIST_LOCK(&headerlist);
349                 headers--;
350                 AST_LIST_REMOVE(&headerlist, fr, frame_list);
351                 AST_LIST_UNLOCK(&headerlist);
352 #endif                  
353                 free(fr);
354         }
355 }
356
357 /*!
358  * \brief 'isolates' a frame by duplicating non-malloc'ed components
359  * (header, src, data).
360  * On return all components are malloc'ed
361  */
362 struct ast_frame *ast_frisolate(struct ast_frame *fr)
363 {
364         struct ast_frame *out;
365         void *newdata;
366         
367         if (!(fr->mallocd & AST_MALLOCD_HDR)) {
368                 /* Allocate a new header if needed */
369                 if (!(out = ast_frame_header_new()))
370                         return NULL;
371                 out->frametype = fr->frametype;
372                 out->subclass = fr->subclass;
373                 out->datalen = fr->datalen;
374                 out->samples = fr->samples;
375                 out->offset = fr->offset;
376                 out->data = fr->data;
377                 /* Copy the timing data */
378                 out->has_timing_info = fr->has_timing_info;
379                 if (fr->has_timing_info) {
380                         out->ts = fr->ts;
381                         out->len = fr->len;
382                         out->seqno = fr->seqno;
383                 }
384         } else
385                 out = fr;
386         
387         if (!(fr->mallocd & AST_MALLOCD_SRC)) {
388                 if (fr->src) {
389                         if (!(out->src = ast_strdup(fr->src))) {
390                                 if (out != fr)
391                                         free(out);
392                                 return NULL;
393                         }
394                 }
395         } else
396                 out->src = fr->src;
397         
398         if (!(fr->mallocd & AST_MALLOCD_DATA))  {
399                 if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) {
400                         if (out->src != fr->src)
401                                 free((void *) out->src);
402                         if (out != fr)
403                                 free(out);
404                         return NULL;
405                 }
406                 newdata += AST_FRIENDLY_OFFSET;
407                 out->offset = AST_FRIENDLY_OFFSET;
408                 out->datalen = fr->datalen;
409                 memcpy(newdata, fr->data, fr->datalen);
410                 out->data = newdata;
411         }
412
413         out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA;
414         
415         return out;
416 }
417
418 struct ast_frame *ast_frdup(const struct ast_frame *f)
419 {
420         struct ast_frame_cache *frames;
421         struct ast_frame *out;
422         int len, srclen = 0;
423         void *buf = NULL;
424
425         /* Start with standard stuff */
426         len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
427         /* If we have a source, add space for it */
428         /*
429          * XXX Watch out here - if we receive a src which is not terminated
430          * properly, we can be easily attacked. Should limit the size we deal with.
431          */
432         if (f->src)
433                 srclen = strlen(f->src);
434         if (srclen > 0)
435                 len += srclen + 1;
436         
437         if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) {
438                 AST_LIST_TRAVERSE_SAFE_BEGIN(&frames->list, out, frame_list) {
439                         if (out->mallocd_hdr_len >= len) {
440                                 size_t mallocd_len = out->mallocd_hdr_len;
441                                 AST_LIST_REMOVE_CURRENT(&frames->list, frame_list);
442                                 memset(out, 0, sizeof(*out));
443                                 out->mallocd_hdr_len = mallocd_len;
444                                 buf = out;
445                                 frames->size--;
446                                 break;
447                         }
448                 }
449                 AST_LIST_TRAVERSE_SAFE_END
450         }
451         if (!buf) {
452                 if (!(buf = ast_calloc(1, len)))
453                         return NULL;
454                 out = buf;
455                 out->mallocd_hdr_len = len;
456         }
457
458         out->frametype = f->frametype;
459         out->subclass = f->subclass;
460         out->datalen = f->datalen;
461         out->samples = f->samples;
462         out->delivery = f->delivery;
463         /* Set us as having malloc'd header only, so it will eventually
464            get freed. */
465         out->mallocd = AST_MALLOCD_HDR;
466         out->offset = AST_FRIENDLY_OFFSET;
467         if (out->datalen) {
468                 out->data = buf + sizeof(*out) + AST_FRIENDLY_OFFSET;
469                 memcpy(out->data, f->data, out->datalen);       
470         }
471         if (srclen > 0) {
472                 out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen;
473                 /* Must have space since we allocated for it */
474                 strcpy((char *)out->src, f->src);
475         }
476         out->has_timing_info = f->has_timing_info;
477         if (f->has_timing_info) {
478                 out->ts = f->ts;
479                 out->len = f->len;
480                 out->seqno = f->seqno;
481         }
482         return out;
483 }
484
485 #if 0
486 /*
487  * XXX
488  * This function is badly broken - it does not handle correctly
489  * partial reads on either header or body.
490  * However is it never used anywhere so we leave it commented out
491  */
492 struct ast_frame *ast_fr_fdread(int fd)
493 {
494         char buf[65536];
495         int res;        
496         struct ast_frame *f = (struct ast_frame *)buf;
497         int ttl = sizeof(*f);
498         /* Read a frame directly from there.  They're always in the
499            right format. */
500         
501         while(ttl) {
502                 res = read(fd, buf, ttl);
503                 if (res < 0) {
504                         ast_log(LOG_WARNING, "Bad read on %d: %s\n", fd, strerror(errno));
505                         return NULL;
506                 }
507                 ttl -= res;
508         }
509         
510         /* read the frame header */
511
512         /* Re-write data position */
513         f->data = buf + sizeof(*f);
514         f->offset = 0;
515         /* Forget about being mallocd */
516         f->mallocd = 0;
517         /* Re-write the source */
518         f->src = (char *)__FUNCTION__;
519         if (f->datalen > sizeof(buf) - sizeof(*f)) {
520                 /* Really bad read */
521                 ast_log(LOG_WARNING, "Strange read (%d bytes)\n", f->datalen);
522                 return NULL;
523         }
524         if (f->datalen) {
525                 if ((res = read(fd, f->data, f->datalen)) != f->datalen) {
526                         /* Bad read */
527                         ast_log(LOG_WARNING, "How very strange, expected %d, got %d\n", f->datalen, res);
528                         return NULL;
529                 }
530         }
531         if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
532                 return NULL;
533         }
534         return ast_frisolate(f);
535 }
536
537 /* Some convenient routines for sending frames to/from stream or datagram
538    sockets, pipes, etc (maybe even files) */
539
540 /*
541  * XXX this function is also partly broken because it does not handle
542  * partial writes. We comment it out too, and also the unique
543  * client it has, ast_fr_fdhangup()
544  */
545 int ast_fr_fdwrite(int fd, struct ast_frame *frame)
546 {
547         /* Write the frame exactly */
548         if (write(fd, frame, sizeof(*frame)) != sizeof(*frame)) {
549                 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
550                 return -1;
551         }
552         if (write(fd, frame->data, frame->datalen) != frame->datalen) {
553                 ast_log(LOG_WARNING, "Write error: %s\n", strerror(errno));
554                 return -1;
555         }
556         return 0;
557 }
558
559 int ast_fr_fdhangup(int fd)
560 {
561         struct ast_frame hangup = {
562                 AST_FRAME_CONTROL,
563                 AST_CONTROL_HANGUP
564         };
565         return ast_fr_fdwrite(fd, &hangup);
566 }
567
568 #endif /* unused functions */
569
570 void ast_swapcopy_samples(void *dst, const void *src, int samples)
571 {
572         int i;
573         unsigned short *dst_s = dst;
574         const unsigned short *src_s = src;
575
576         for (i = 0; i < samples; i++)
577                 dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8);
578 }
579
580
581 struct ast_format_list *ast_get_format_list_index(int index) 
582 {
583         return &AST_FORMAT_LIST[index];
584 }
585
586 struct ast_format_list *ast_get_format_list(size_t *size) 
587 {
588         *size = (sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]));
589         return AST_FORMAT_LIST;
590 }
591
592 char* ast_getformatname(int format)
593 {
594         int x;
595         char *ret = "unknown";
596         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
597                 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) {
598                         ret = AST_FORMAT_LIST[x].name;
599                         break;
600                 }
601         }
602         return ret;
603 }
604
605 char *ast_getformatname_multiple(char *buf, size_t size, int format)
606 {
607         int x;
608         unsigned len;
609         char *start, *end = buf;
610
611         if (!size)
612                 return buf;
613         snprintf(end, size, "0x%x (", format);
614         len = strlen(end);
615         end += len;
616         size -= len;
617         start = end;
618         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
619                 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) {
620                         snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name);
621                         len = strlen(end);
622                         end += len;
623                         size -= len;
624                 }
625         }
626         if (start == end)
627                 snprintf(start, size, "nothing)");
628         else if (size > 1)
629                 *(end -1) = ')';
630         return buf;
631 }
632
633 static struct ast_codec_alias_table {
634         char *alias;
635         char *realname;
636 } ast_codec_alias_table[] = {
637         { "slinear", "slin"},
638         { "g723.1", "g723"},
639 };
640
641 static const char *ast_expand_codec_alias(const char *in)
642 {
643         int x;
644
645         for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(ast_codec_alias_table[0]); x++) {
646                 if(!strcmp(in,ast_codec_alias_table[x].alias))
647                         return ast_codec_alias_table[x].realname;
648         }
649         return in;
650 }
651
652 int ast_getformatbyname(const char *name)
653 {
654         int x, all, format = 0;
655
656         all = strcasecmp(name, "all") ? 0 : 1;
657         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
658                 if(AST_FORMAT_LIST[x].visible && (all || 
659                           !strcasecmp(AST_FORMAT_LIST[x].name,name) ||
660                           !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) {
661                         format |= AST_FORMAT_LIST[x].bits;
662                         if(!all)
663                                 break;
664                 }
665         }
666
667         return format;
668 }
669
670 char *ast_codec2str(int codec)
671 {
672         int x;
673         char *ret = "unknown";
674         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
675                 if(AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) {
676                         ret = AST_FORMAT_LIST[x].desc;
677                         break;
678                 }
679         }
680         return ret;
681 }
682
683 static int show_codecs(int fd, int argc, char *argv[])
684 {
685         int i, found=0;
686         char hex[25];
687         
688         if ((argc < 2) || (argc > 3))
689                 return RESULT_SHOWUSAGE;
690
691         if (!ast_opt_dont_warn)
692                 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n"
693                                 "\tIt does not indicate anything about your configuration.\n");
694
695         ast_cli(fd, "%11s %9s %10s   TYPE   %8s   %s\n","INT","BINARY","HEX","NAME","DESC");
696         ast_cli(fd, "--------------------------------------------------------------------------------\n");
697         if ((argc == 2) || (!strcasecmp(argv[1],"audio"))) {
698                 found = 1;
699                 for (i=0;i<12;i++) {
700                         snprintf(hex,25,"(0x%x)",1<<i);
701                         ast_cli(fd, "%11u (1 << %2d) %10s  audio   %8s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
702                 }
703         }
704
705         if ((argc == 2) || (!strcasecmp(argv[1],"image"))) {
706                 found = 1;
707                 for (i=16;i<18;i++) {
708                         snprintf(hex,25,"(0x%x)",1<<i);
709                         ast_cli(fd, "%11u (1 << %2d) %10s  image   %8s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
710                 }
711         }
712
713         if ((argc == 2) || (!strcasecmp(argv[1],"video"))) {
714                 found = 1;
715                 for (i=18;i<22;i++) {
716                         snprintf(hex,25,"(0x%x)",1<<i);
717                         ast_cli(fd, "%11u (1 << %2d) %10s  video   %8s   (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i));
718                 }
719         }
720
721         if (! found)
722                 return RESULT_SHOWUSAGE;
723         else
724                 return RESULT_SUCCESS;
725 }
726
727 static char frame_show_codecs_usage[] =
728 "Usage: show [audio|video|image] codecs\n"
729 "       Displays codec mapping\n";
730
731 static int show_codec_n(int fd, int argc, char *argv[])
732 {
733         int codec, i, found=0;
734
735         if (argc != 3)
736                 return RESULT_SHOWUSAGE;
737
738         if (sscanf(argv[2],"%d",&codec) != 1)
739                 return RESULT_SHOWUSAGE;
740
741         for (i = 0; i < 32; i++)
742                 if (codec & (1 << i)) {
743                         found = 1;
744                         ast_cli(fd, "%11u (1 << %2d)  %s\n",1 << i,i,ast_codec2str(1<<i));
745                 }
746
747         if (!found)
748                 ast_cli(fd, "Codec %d not found\n", codec);
749
750         return RESULT_SUCCESS;
751 }
752
753 static char frame_show_codec_n_usage[] =
754 "Usage: show codec <number>\n"
755 "       Displays codec mapping\n";
756
757 /*! Dump a frame for debugging purposes */
758 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
759 {
760         const char noname[] = "unknown";
761         char ftype[40] = "Unknown Frametype";
762         char cft[80];
763         char subclass[40] = "Unknown Subclass";
764         char csub[80];
765         char moreinfo[40] = "";
766         char cn[60];
767         char cp[40];
768         char cmn[40];
769
770         if (!name)
771                 name = noname;
772
773
774         if (!f) {
775                 ast_verbose("%s [ %s (NULL) ] [%s]\n", 
776                         term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
777                         term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)), 
778                         term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
779                 return;
780         }
781         /* XXX We should probably print one each of voice and video when the format changes XXX */
782         if (f->frametype == AST_FRAME_VOICE)
783                 return;
784         if (f->frametype == AST_FRAME_VIDEO)
785                 return;
786         switch(f->frametype) {
787         case AST_FRAME_DTMF:
788                 strcpy(ftype, "DTMF");
789                 subclass[0] = f->subclass;
790                 subclass[1] = '\0';
791                 break;
792         case AST_FRAME_CONTROL:
793                 strcpy(ftype, "Control");
794                 switch(f->subclass) {
795                 case AST_CONTROL_HANGUP:
796                         strcpy(subclass, "Hangup");
797                         break;
798                 case AST_CONTROL_RING:
799                         strcpy(subclass, "Ring");
800                         break;
801                 case AST_CONTROL_RINGING:
802                         strcpy(subclass, "Ringing");
803                         break;
804                 case AST_CONTROL_ANSWER:
805                         strcpy(subclass, "Answer");
806                         break;
807                 case AST_CONTROL_BUSY:
808                         strcpy(subclass, "Busy");
809                         break;
810                 case AST_CONTROL_TAKEOFFHOOK:
811                         strcpy(subclass, "Take Off Hook");
812                         break;
813                 case AST_CONTROL_OFFHOOK:
814                         strcpy(subclass, "Line Off Hook");
815                         break;
816                 case AST_CONTROL_CONGESTION:
817                         strcpy(subclass, "Congestion");
818                         break;
819                 case AST_CONTROL_FLASH:
820                         strcpy(subclass, "Flash");
821                         break;
822                 case AST_CONTROL_WINK:
823                         strcpy(subclass, "Wink");
824                         break;
825                 case AST_CONTROL_OPTION:
826                         strcpy(subclass, "Option");
827                         break;
828                 case AST_CONTROL_RADIO_KEY:
829                         strcpy(subclass, "Key Radio");
830                         break;
831                 case AST_CONTROL_RADIO_UNKEY:
832                         strcpy(subclass, "Unkey Radio");
833                         break;
834                 case -1:
835                         strcpy(subclass, "Stop generators");
836                         break;
837                 default:
838                         snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
839                 }
840                 break;
841         case AST_FRAME_NULL:
842                 strcpy(ftype, "Null Frame");
843                 strcpy(subclass, "N/A");
844                 break;
845         case AST_FRAME_IAX:
846                 /* Should never happen */
847                 strcpy(ftype, "IAX Specific");
848                 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
849                 break;
850         case AST_FRAME_TEXT:
851                 strcpy(ftype, "Text");
852                 strcpy(subclass, "N/A");
853                 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
854                 break;
855         case AST_FRAME_IMAGE:
856                 strcpy(ftype, "Image");
857                 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
858                 break;
859         case AST_FRAME_HTML:
860                 strcpy(ftype, "HTML");
861                 switch(f->subclass) {
862                 case AST_HTML_URL:
863                         strcpy(subclass, "URL");
864                         ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
865                         break;
866                 case AST_HTML_DATA:
867                         strcpy(subclass, "Data");
868                         break;
869                 case AST_HTML_BEGIN:
870                         strcpy(subclass, "Begin");
871                         break;
872                 case AST_HTML_END:
873                         strcpy(subclass, "End");
874                         break;
875                 case AST_HTML_LDCOMPLETE:
876                         strcpy(subclass, "Load Complete");
877                         break;
878                 case AST_HTML_NOSUPPORT:
879                         strcpy(subclass, "No Support");
880                         break;
881                 case AST_HTML_LINKURL:
882                         strcpy(subclass, "Link URL");
883                         ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
884                         break;
885                 case AST_HTML_UNLINK:
886                         strcpy(subclass, "Unlink");
887                         break;
888                 case AST_HTML_LINKREJECT:
889                         strcpy(subclass, "Link Reject");
890                         break;
891                 default:
892                         snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
893                         break;
894                 }
895                 break;
896         case AST_FRAME_MODEM:
897                 strcpy(ftype, "Modem");
898                 switch (f->subclass) {
899                 case AST_MODEM_T38:
900                         strcpy(subclass, "T.38");
901                         break;
902                 case AST_MODEM_V150:
903                         strcpy(subclass, "V.150");
904                         break;
905                 default:
906                         snprintf(subclass, sizeof(subclass), "Unknown MODEM frame '%d'\n", f->subclass);
907                         break;
908                 }
909                 break;
910         default:
911                 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
912         }
913         if (!ast_strlen_zero(moreinfo))
914                 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",  
915                             term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
916                             term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
917                             f->frametype, 
918                             term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
919                             f->subclass, 
920                             term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
921                             term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
922         else
923                 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",  
924                             term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
925                             term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
926                             f->frametype, 
927                             term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
928                             f->subclass, 
929                             term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
930 }
931
932
933 #ifdef TRACE_FRAMES
934 static int show_frame_stats(int fd, int argc, char *argv[])
935 {
936         struct ast_frame *f;
937         int x=1;
938         if (argc != 3)
939                 return RESULT_SHOWUSAGE;
940         AST_LIST_LOCK(&headerlist);
941         ast_cli(fd, "     Framer Statistics     \n");
942         ast_cli(fd, "---------------------------\n");
943         ast_cli(fd, "Total allocated headers: %d\n", headers);
944         ast_cli(fd, "Queue Dump:\n");
945         AST_LIST_TRAVERSE(&headerlist, f, frame_list)
946                 ast_cli(fd, "%d.  Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
947         AST_LIST_UNLOCK(&headerlist);
948         return RESULT_SUCCESS;
949 }
950
951 static char frame_stats_usage[] =
952 "Usage: show frame stats\n"
953 "       Displays debugging statistics from framer\n";
954 #endif
955
956 /* Builtin Asterisk CLI-commands for debugging */
957 static struct ast_cli_entry my_clis[] = {
958 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage },
959 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage },
960 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage },
961 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage },
962 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage },
963 #ifdef TRACE_FRAMES
964 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage },
965 #endif
966 };
967
968
969 int init_framer(void)
970 {
971         ast_cli_register_multiple(my_clis, sizeof(my_clis)/sizeof(my_clis[0]) );
972         return 0;       
973 }
974
975 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right) 
976 {
977         int x, differential = (int) 'A', mem;
978         char *from, *to;
979
980         if(right) {
981                 from = pref->order;
982                 to = buf;
983                 mem = size;
984         } else {
985                 to = pref->order;
986                 from = buf;
987                 mem = 32;
988         }
989
990         memset(to, 0, mem);
991         for (x = 0; x < 32 ; x++) {
992                 if(!from[x])
993                         break;
994                 to[x] = right ? (from[x] + differential) : (from[x] - differential);
995         }
996 }
997
998 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) 
999 {
1000         int x, codec; 
1001         size_t total_len, slen;
1002         char *formatname;
1003         
1004         memset(buf,0,size);
1005         total_len = size;
1006         buf[0] = '(';
1007         total_len--;
1008         for(x = 0; x < 32 ; x++) {
1009                 if(total_len <= 0)
1010                         break;
1011                 if(!(codec = ast_codec_pref_index(pref,x)))
1012                         break;
1013                 if((formatname = ast_getformatname(codec))) {
1014                         slen = strlen(formatname);
1015                         if(slen > total_len)
1016                                 break;
1017                         strncat(buf,formatname,total_len);
1018                         total_len -= slen;
1019                 }
1020                 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
1021                         strncat(buf,"|",total_len);
1022                         total_len--;
1023                 }
1024         }
1025         if(total_len) {
1026                 strncat(buf,")",total_len);
1027                 total_len--;
1028         }
1029
1030         return size - total_len;
1031 }
1032
1033 int ast_codec_pref_index(struct ast_codec_pref *pref, int index) 
1034 {
1035         int slot = 0;
1036
1037         
1038         if((index >= 0) && (index < sizeof(pref->order))) {
1039                 slot = pref->order[index];
1040         }
1041
1042         return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
1043 }
1044
1045 /*! \brief Remove codec from pref list */
1046 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
1047 {
1048         struct ast_codec_pref oldorder;
1049         int x, y = 0;
1050         int slot;
1051
1052         if(!pref->order[0])
1053                 return;
1054
1055         memcpy(&oldorder, pref, sizeof(oldorder));
1056         memset(pref, 0, sizeof(*pref));
1057
1058         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1059                 slot = oldorder.order[x];
1060                 if(! slot)
1061                         break;
1062                 if(AST_FORMAT_LIST[slot-1].bits != format)
1063                         pref->order[y++] = slot;
1064         }
1065         
1066 }
1067
1068 /*! \brief Append codec to list */
1069 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
1070 {
1071         int x, newindex = -1;
1072
1073         ast_codec_pref_remove(pref, format);
1074
1075         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1076                 if(AST_FORMAT_LIST[x].bits == format) {
1077                         newindex = x + 1;
1078                         break;
1079                 }
1080         }
1081
1082         if(newindex) {
1083                 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1084                         if(!pref->order[x]) {
1085                                 pref->order[x] = newindex;
1086                                 break;
1087                         }
1088                 }
1089         }
1090
1091         return x;
1092 }
1093
1094
1095 /*! \brief Pick a codec */
1096 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
1097 {
1098         int x, ret = 0, slot;
1099
1100         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1101                 slot = pref->order[x];
1102
1103                 if (!slot)
1104                         break;
1105                 if (formats & AST_FORMAT_LIST[slot-1].bits) {
1106                         ret = AST_FORMAT_LIST[slot-1].bits;
1107                         break;
1108                 }
1109         }
1110         if(ret & AST_FORMAT_AUDIO_MASK)
1111                 return ret;
1112
1113         if (option_debug > 3)
1114                 ast_log(LOG_DEBUG, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
1115
1116         return find_best ? ast_best_codec(formats) : 0;
1117 }
1118
1119 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing) 
1120 {
1121         char *parse;
1122         char *this;
1123         int format;
1124
1125         parse = ast_strdupa(list);
1126         while ((this = strsep(&parse, ","))) {
1127                 if (!(format = ast_getformatbyname(this))) {
1128                         ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
1129                         continue;
1130                 }
1131
1132                 if (mask) {
1133                         if (allowing)
1134                                 *mask |= format;
1135                         else
1136                                 *mask &= ~format;
1137                 }
1138
1139                 /* Set up a preference list for audio. Do not include video in preferences 
1140                    since we can not transcode video and have to use whatever is offered
1141                  */
1142                 if (pref && (format & AST_FORMAT_AUDIO_MASK)) {
1143                         if (strcasecmp(this, "all")) {
1144                                 if (allowing)
1145                                         ast_codec_pref_append(pref, format);
1146                                 else
1147                                         ast_codec_pref_remove(pref, format);
1148                         } else if (!allowing) {
1149                                 memset(pref, 0, sizeof(*pref));
1150                         }
1151                 }
1152         }
1153 }
1154
1155 static int g723_len(unsigned char buf)
1156 {
1157         enum frame_type type = buf & TYPE_MASK;
1158
1159         switch(type) {
1160         case TYPE_DONTSEND:
1161                 return 0;
1162                 break;
1163         case TYPE_SILENCE:
1164                 return 4;
1165                 break;
1166         case TYPE_HIGH:
1167                 return 24;
1168                 break;
1169         case TYPE_LOW:
1170                 return 20;
1171                 break;
1172         default:
1173                 ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type);
1174         }
1175         return -1;
1176 }
1177
1178 static int g723_samples(unsigned char *buf, int maxlen)
1179 {
1180         int pos = 0;
1181         int samples = 0;
1182         int res;
1183         while(pos < maxlen) {
1184                 res = g723_len(buf[pos]);
1185                 if (res <= 0)
1186                         break;
1187                 samples += 240;
1188                 pos += res;
1189         }
1190         return samples;
1191 }
1192
1193 static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
1194 {
1195         int byte = bit / 8;       /* byte containing first bit */
1196         int rem = 8 - (bit % 8);  /* remaining bits in first byte */
1197         unsigned char ret = 0;
1198         
1199         if (n <= 0 || n > 8)
1200                 return 0;
1201
1202         if (rem < n) {
1203                 ret = (data[byte] << (n - rem));
1204                 ret |= (data[byte + 1] >> (8 - n + rem));
1205         } else {
1206                 ret = (data[byte] >> (rem - n));
1207         }
1208
1209         return (ret & (0xff >> (8 - n)));
1210 }
1211
1212 static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
1213 {
1214         static int SpeexWBSubModeSz[] = {
1215                 0, 36, 112, 192,
1216                 352, 0, 0, 0 };
1217         int off = bit;
1218         unsigned char c;
1219
1220         /* skip up to two wideband frames */
1221         if (((len * 8 - off) >= 5) && 
1222                 get_n_bits_at(data, 1, off)) {
1223                 c = get_n_bits_at(data, 3, off + 1);
1224                 off += SpeexWBSubModeSz[c];
1225
1226                 if (((len * 8 - off) >= 5) && 
1227                         get_n_bits_at(data, 1, off)) {
1228                         c = get_n_bits_at(data, 3, off + 1);
1229                         off += SpeexWBSubModeSz[c];
1230
1231                         if (((len * 8 - off) >= 5) && 
1232                                 get_n_bits_at(data, 1, off)) {
1233                                 ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1234                                 return -1;
1235                         }
1236                 }
1237
1238         }
1239         return off - bit;
1240 }
1241
1242 static int speex_samples(unsigned char *data, int len)
1243 {
1244         static int SpeexSubModeSz[] = {
1245                5, 43, 119, 160,
1246                 220, 300, 364, 492, 
1247                 79, 0, 0, 0,
1248                 0, 0, 0, 0 };
1249         static int SpeexInBandSz[] = { 
1250                 1, 1, 4, 4,
1251                 4, 4, 4, 4,
1252                 8, 8, 16, 16,
1253                 32, 32, 64, 64 };
1254         int bit = 0;
1255         int cnt = 0;
1256         int off;
1257         unsigned char c;
1258
1259         while ((len * 8 - bit) >= 5) {
1260                 /* skip wideband frames */
1261                 off = speex_get_wb_sz_at(data, len, bit);
1262                 if (off < 0)  {
1263                         ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
1264                         break;
1265                 }
1266                 bit += off;
1267
1268                 if ((len * 8 - bit) < 5) {
1269                         ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
1270                         break;
1271                 }
1272
1273                 /* get control bits */
1274                 c = get_n_bits_at(data, 5, bit);
1275                 bit += 5;
1276
1277                 if (c == 15) { 
1278                         /* terminator */
1279                         break; 
1280                 } else if (c == 14) {
1281                         /* in-band signal; next 4 bits contain signal id */
1282                         c = get_n_bits_at(data, 4, bit);
1283                         bit += 4;
1284                         bit += SpeexInBandSz[c];
1285                 } else if (c == 13) {
1286                         /* user in-band; next 5 bits contain msg len */
1287                         c = get_n_bits_at(data, 5, bit);
1288                         bit += 5;
1289                         bit += c * 8;
1290                 } else if (c > 8) {
1291                         /* unknown */
1292                         break;
1293                 } else {
1294                         /* skip number bits for submode (less the 5 control bits) */
1295                         bit += SpeexSubModeSz[c] - 5;
1296                         cnt += 160; /* new frame */
1297                 }
1298         }
1299         return cnt;
1300 }
1301
1302 int ast_codec_get_samples(struct ast_frame *f)
1303 {
1304         int samples=0;
1305         switch(f->subclass) {
1306         case AST_FORMAT_SPEEX:
1307                 samples = speex_samples(f->data, f->datalen);
1308                 break;
1309         case AST_FORMAT_G723_1:
1310                 samples = g723_samples(f->data, f->datalen);
1311                 break;
1312         case AST_FORMAT_ILBC:
1313                 samples = 240 * (f->datalen / 50);
1314                 break;
1315         case AST_FORMAT_GSM:
1316                 samples = 160 * (f->datalen / 33);
1317                 break;
1318         case AST_FORMAT_G729A:
1319                 samples = f->datalen * 8;
1320                 break;
1321         case AST_FORMAT_SLINEAR:
1322                 samples = f->datalen / 2;
1323                 break;
1324         case AST_FORMAT_LPC10:
1325                 /* assumes that the RTP packet contains one LPC10 frame */
1326                 samples = 22 * 8;
1327                 samples += (((char *)(f->data))[7] & 0x1) * 8;
1328                 break;
1329         case AST_FORMAT_ULAW:
1330         case AST_FORMAT_ALAW:
1331                 samples = f->datalen;
1332                 break;
1333         case AST_FORMAT_ADPCM:
1334         case AST_FORMAT_G726:
1335         case AST_FORMAT_G726_AAL2:
1336                 samples = f->datalen * 2;
1337                 break;
1338         default:
1339                 ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
1340         }
1341         return samples;
1342 }
1343
1344 int ast_codec_get_len(int format, int samples)
1345 {
1346         int len = 0;
1347
1348         /* XXX Still need speex, g723, and lpc10 XXX */ 
1349         switch(format) {
1350         case AST_FORMAT_ILBC:
1351                 len = (samples / 240) * 50;
1352                 break;
1353         case AST_FORMAT_GSM:
1354                 len = (samples / 160) * 33;
1355                 break;
1356         case AST_FORMAT_G729A:
1357                 len = samples / 8;
1358                 break;
1359         case AST_FORMAT_SLINEAR:
1360                 len = samples * 2;
1361                 break;
1362         case AST_FORMAT_ULAW:
1363         case AST_FORMAT_ALAW:
1364                 len = samples;
1365                 break;
1366         case AST_FORMAT_ADPCM:
1367         case AST_FORMAT_G726:
1368         case AST_FORMAT_G726_AAL2:
1369                 len = samples / 2;
1370                 break;
1371         default:
1372                 ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
1373         }
1374
1375         return len;
1376 }
1377
1378 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
1379 {
1380         int count;
1381         short *fdata = f->data;
1382         short adjust_value = abs(adjustment);
1383
1384         if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR))
1385                 return -1;
1386
1387         if (!adjustment)
1388                 return 0;
1389
1390         for (count = 0; count < f->samples; count++) {
1391                 if (adjustment > 0) {
1392                         ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
1393                 } else if (adjustment < 0) {
1394                         ast_slinear_saturated_divide(&fdata[count], &adjust_value);
1395                 }
1396         }
1397
1398         return 0;
1399 }
1400
1401 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
1402 {
1403         int count;
1404         short *data1, *data2;
1405
1406         if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass != AST_FORMAT_SLINEAR))
1407                 return -1;
1408
1409         if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR))
1410                 return -1;
1411
1412         if (f1->samples != f2->samples)
1413                 return -1;
1414
1415         for (count = 0, data1 = f1->data, data2 = f2->data;
1416              count < f1->samples;
1417              count++, data1++, data2++)
1418                 ast_slinear_saturated_add(data1, data2);
1419
1420         return 0;
1421 }