Add the ability to specify that a frame should not be considered for 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_frame_free(struct ast_frame *fr, int cache)
321 {
322         if (!fr->mallocd)
323                 return;
324
325         if (cache && 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_BEGIN:
788                 strcpy(ftype, "DTMF Begin");
789                 subclass[0] = f->subclass;
790                 subclass[1] = '\0';
791                 break;
792         case AST_FRAME_DTMF_END:
793                 strcpy(ftype, "DTMF End");
794                 subclass[0] = f->subclass;
795                 subclass[1] = '\0';
796                 break;
797         case AST_FRAME_CONTROL:
798                 strcpy(ftype, "Control");
799                 switch(f->subclass) {
800                 case AST_CONTROL_HANGUP:
801                         strcpy(subclass, "Hangup");
802                         break;
803                 case AST_CONTROL_RING:
804                         strcpy(subclass, "Ring");
805                         break;
806                 case AST_CONTROL_RINGING:
807                         strcpy(subclass, "Ringing");
808                         break;
809                 case AST_CONTROL_ANSWER:
810                         strcpy(subclass, "Answer");
811                         break;
812                 case AST_CONTROL_BUSY:
813                         strcpy(subclass, "Busy");
814                         break;
815                 case AST_CONTROL_TAKEOFFHOOK:
816                         strcpy(subclass, "Take Off Hook");
817                         break;
818                 case AST_CONTROL_OFFHOOK:
819                         strcpy(subclass, "Line Off Hook");
820                         break;
821                 case AST_CONTROL_CONGESTION:
822                         strcpy(subclass, "Congestion");
823                         break;
824                 case AST_CONTROL_FLASH:
825                         strcpy(subclass, "Flash");
826                         break;
827                 case AST_CONTROL_WINK:
828                         strcpy(subclass, "Wink");
829                         break;
830                 case AST_CONTROL_OPTION:
831                         strcpy(subclass, "Option");
832                         break;
833                 case AST_CONTROL_RADIO_KEY:
834                         strcpy(subclass, "Key Radio");
835                         break;
836                 case AST_CONTROL_RADIO_UNKEY:
837                         strcpy(subclass, "Unkey Radio");
838                         break;
839                 case -1:
840                         strcpy(subclass, "Stop generators");
841                         break;
842                 default:
843                         snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass);
844                 }
845                 break;
846         case AST_FRAME_NULL:
847                 strcpy(ftype, "Null Frame");
848                 strcpy(subclass, "N/A");
849                 break;
850         case AST_FRAME_IAX:
851                 /* Should never happen */
852                 strcpy(ftype, "IAX Specific");
853                 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass);
854                 break;
855         case AST_FRAME_TEXT:
856                 strcpy(ftype, "Text");
857                 strcpy(subclass, "N/A");
858                 ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
859                 break;
860         case AST_FRAME_IMAGE:
861                 strcpy(ftype, "Image");
862                 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass));
863                 break;
864         case AST_FRAME_HTML:
865                 strcpy(ftype, "HTML");
866                 switch(f->subclass) {
867                 case AST_HTML_URL:
868                         strcpy(subclass, "URL");
869                         ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
870                         break;
871                 case AST_HTML_DATA:
872                         strcpy(subclass, "Data");
873                         break;
874                 case AST_HTML_BEGIN:
875                         strcpy(subclass, "Begin");
876                         break;
877                 case AST_HTML_END:
878                         strcpy(subclass, "End");
879                         break;
880                 case AST_HTML_LDCOMPLETE:
881                         strcpy(subclass, "Load Complete");
882                         break;
883                 case AST_HTML_NOSUPPORT:
884                         strcpy(subclass, "No Support");
885                         break;
886                 case AST_HTML_LINKURL:
887                         strcpy(subclass, "Link URL");
888                         ast_copy_string(moreinfo, f->data, sizeof(moreinfo));
889                         break;
890                 case AST_HTML_UNLINK:
891                         strcpy(subclass, "Unlink");
892                         break;
893                 case AST_HTML_LINKREJECT:
894                         strcpy(subclass, "Link Reject");
895                         break;
896                 default:
897                         snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass);
898                         break;
899                 }
900                 break;
901         case AST_FRAME_MODEM:
902                 strcpy(ftype, "Modem");
903                 switch (f->subclass) {
904                 case AST_MODEM_T38:
905                         strcpy(subclass, "T.38");
906                         break;
907                 case AST_MODEM_V150:
908                         strcpy(subclass, "V.150");
909                         break;
910                 default:
911                         snprintf(subclass, sizeof(subclass), "Unknown MODEM frame '%d'\n", f->subclass);
912                         break;
913                 }
914                 break;
915         default:
916                 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype);
917         }
918         if (!ast_strlen_zero(moreinfo))
919                 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n",  
920                             term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
921                             term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
922                             f->frametype, 
923                             term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
924                             f->subclass, 
925                             term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)),
926                             term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
927         else
928                 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n",  
929                             term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)),
930                             term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)),
931                             f->frametype, 
932                             term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)),
933                             f->subclass, 
934                             term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn)));
935 }
936
937
938 #ifdef TRACE_FRAMES
939 static int show_frame_stats(int fd, int argc, char *argv[])
940 {
941         struct ast_frame *f;
942         int x=1;
943         if (argc != 3)
944                 return RESULT_SHOWUSAGE;
945         AST_LIST_LOCK(&headerlist);
946         ast_cli(fd, "     Framer Statistics     \n");
947         ast_cli(fd, "---------------------------\n");
948         ast_cli(fd, "Total allocated headers: %d\n", headers);
949         ast_cli(fd, "Queue Dump:\n");
950         AST_LIST_TRAVERSE(&headerlist, f, frame_list)
951                 ast_cli(fd, "%d.  Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>");
952         AST_LIST_UNLOCK(&headerlist);
953         return RESULT_SUCCESS;
954 }
955
956 static char frame_stats_usage[] =
957 "Usage: show frame stats\n"
958 "       Displays debugging statistics from framer\n";
959 #endif
960
961 /* Builtin Asterisk CLI-commands for debugging */
962 static struct ast_cli_entry my_clis[] = {
963 { { "show", "codecs", NULL }, show_codecs, "Shows codecs", frame_show_codecs_usage },
964 { { "show", "audio", "codecs", NULL }, show_codecs, "Shows audio codecs", frame_show_codecs_usage },
965 { { "show", "video", "codecs", NULL }, show_codecs, "Shows video codecs", frame_show_codecs_usage },
966 { { "show", "image", "codecs", NULL }, show_codecs, "Shows image codecs", frame_show_codecs_usage },
967 { { "show", "codec", NULL }, show_codec_n, "Shows a specific codec", frame_show_codec_n_usage },
968 #ifdef TRACE_FRAMES
969 { { "show", "frame", "stats", NULL }, show_frame_stats, "Shows frame statistics", frame_stats_usage },
970 #endif
971 };
972
973
974 int init_framer(void)
975 {
976         ast_cli_register_multiple(my_clis, sizeof(my_clis)/sizeof(my_clis[0]) );
977         return 0;       
978 }
979
980 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right) 
981 {
982         int x, differential = (int) 'A', mem;
983         char *from, *to;
984
985         if(right) {
986                 from = pref->order;
987                 to = buf;
988                 mem = size;
989         } else {
990                 to = pref->order;
991                 from = buf;
992                 mem = 32;
993         }
994
995         memset(to, 0, mem);
996         for (x = 0; x < 32 ; x++) {
997                 if(!from[x])
998                         break;
999                 to[x] = right ? (from[x] + differential) : (from[x] - differential);
1000         }
1001 }
1002
1003 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) 
1004 {
1005         int x, codec; 
1006         size_t total_len, slen;
1007         char *formatname;
1008         
1009         memset(buf,0,size);
1010         total_len = size;
1011         buf[0] = '(';
1012         total_len--;
1013         for(x = 0; x < 32 ; x++) {
1014                 if(total_len <= 0)
1015                         break;
1016                 if(!(codec = ast_codec_pref_index(pref,x)))
1017                         break;
1018                 if((formatname = ast_getformatname(codec))) {
1019                         slen = strlen(formatname);
1020                         if(slen > total_len)
1021                                 break;
1022                         strncat(buf,formatname,total_len);
1023                         total_len -= slen;
1024                 }
1025                 if(total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) {
1026                         strncat(buf,"|",total_len);
1027                         total_len--;
1028                 }
1029         }
1030         if(total_len) {
1031                 strncat(buf,")",total_len);
1032                 total_len--;
1033         }
1034
1035         return size - total_len;
1036 }
1037
1038 int ast_codec_pref_index(struct ast_codec_pref *pref, int index) 
1039 {
1040         int slot = 0;
1041
1042         
1043         if((index >= 0) && (index < sizeof(pref->order))) {
1044                 slot = pref->order[index];
1045         }
1046
1047         return slot ? AST_FORMAT_LIST[slot-1].bits : 0;
1048 }
1049
1050 /*! \brief Remove codec from pref list */
1051 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
1052 {
1053         struct ast_codec_pref oldorder;
1054         int x, y = 0;
1055         int slot;
1056
1057         if(!pref->order[0])
1058                 return;
1059
1060         memcpy(&oldorder, pref, sizeof(oldorder));
1061         memset(pref, 0, sizeof(*pref));
1062
1063         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1064                 slot = oldorder.order[x];
1065                 if(! slot)
1066                         break;
1067                 if(AST_FORMAT_LIST[slot-1].bits != format)
1068                         pref->order[y++] = slot;
1069         }
1070         
1071 }
1072
1073 /*! \brief Append codec to list */
1074 int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
1075 {
1076         int x, newindex = -1;
1077
1078         ast_codec_pref_remove(pref, format);
1079
1080         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1081                 if(AST_FORMAT_LIST[x].bits == format) {
1082                         newindex = x + 1;
1083                         break;
1084                 }
1085         }
1086
1087         if(newindex) {
1088                 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1089                         if(!pref->order[x]) {
1090                                 pref->order[x] = newindex;
1091                                 break;
1092                         }
1093                 }
1094         }
1095
1096         return x;
1097 }
1098
1099
1100 /*! \brief Pick a codec */
1101 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
1102 {
1103         int x, ret = 0, slot;
1104
1105         for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) {
1106                 slot = pref->order[x];
1107
1108                 if (!slot)
1109                         break;
1110                 if (formats & AST_FORMAT_LIST[slot-1].bits) {
1111                         ret = AST_FORMAT_LIST[slot-1].bits;
1112                         break;
1113                 }
1114         }
1115         if(ret & AST_FORMAT_AUDIO_MASK)
1116                 return ret;
1117
1118         if (option_debug > 3)
1119                 ast_log(LOG_DEBUG, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
1120
1121         return find_best ? ast_best_codec(formats) : 0;
1122 }
1123
1124 void ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing) 
1125 {
1126         char *parse;
1127         char *this;
1128         int format;
1129
1130         parse = ast_strdupa(list);
1131         while ((this = strsep(&parse, ","))) {
1132                 if (!(format = ast_getformatbyname(this))) {
1133                         ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
1134                         continue;
1135                 }
1136
1137                 if (mask) {
1138                         if (allowing)
1139                                 *mask |= format;
1140                         else
1141                                 *mask &= ~format;
1142                 }
1143
1144                 /* Set up a preference list for audio. Do not include video in preferences 
1145                    since we can not transcode video and have to use whatever is offered
1146                  */
1147                 if (pref && (format & AST_FORMAT_AUDIO_MASK)) {
1148                         if (strcasecmp(this, "all")) {
1149                                 if (allowing)
1150                                         ast_codec_pref_append(pref, format);
1151                                 else
1152                                         ast_codec_pref_remove(pref, format);
1153                         } else if (!allowing) {
1154                                 memset(pref, 0, sizeof(*pref));
1155                         }
1156                 }
1157         }
1158 }
1159
1160 static int g723_len(unsigned char buf)
1161 {
1162         enum frame_type type = buf & TYPE_MASK;
1163
1164         switch(type) {
1165         case TYPE_DONTSEND:
1166                 return 0;
1167                 break;
1168         case TYPE_SILENCE:
1169                 return 4;
1170                 break;
1171         case TYPE_HIGH:
1172                 return 24;
1173                 break;
1174         case TYPE_LOW:
1175                 return 20;
1176                 break;
1177         default:
1178                 ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type);
1179         }
1180         return -1;
1181 }
1182
1183 static int g723_samples(unsigned char *buf, int maxlen)
1184 {
1185         int pos = 0;
1186         int samples = 0;
1187         int res;
1188         while(pos < maxlen) {
1189                 res = g723_len(buf[pos]);
1190                 if (res <= 0)
1191                         break;
1192                 samples += 240;
1193                 pos += res;
1194         }
1195         return samples;
1196 }
1197
1198 static unsigned char get_n_bits_at(unsigned char *data, int n, int bit)
1199 {
1200         int byte = bit / 8;       /* byte containing first bit */
1201         int rem = 8 - (bit % 8);  /* remaining bits in first byte */
1202         unsigned char ret = 0;
1203         
1204         if (n <= 0 || n > 8)
1205                 return 0;
1206
1207         if (rem < n) {
1208                 ret = (data[byte] << (n - rem));
1209                 ret |= (data[byte + 1] >> (8 - n + rem));
1210         } else {
1211                 ret = (data[byte] >> (rem - n));
1212         }
1213
1214         return (ret & (0xff >> (8 - n)));
1215 }
1216
1217 static int speex_get_wb_sz_at(unsigned char *data, int len, int bit)
1218 {
1219         static int SpeexWBSubModeSz[] = {
1220                 0, 36, 112, 192,
1221                 352, 0, 0, 0 };
1222         int off = bit;
1223         unsigned char c;
1224
1225         /* skip up to two wideband frames */
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                         c = get_n_bits_at(data, 3, off + 1);
1234                         off += SpeexWBSubModeSz[c];
1235
1236                         if (((len * 8 - off) >= 5) && 
1237                                 get_n_bits_at(data, 1, off)) {
1238                                 ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n");
1239                                 return -1;
1240                         }
1241                 }
1242
1243         }
1244         return off - bit;
1245 }
1246
1247 static int speex_samples(unsigned char *data, int len)
1248 {
1249         static int SpeexSubModeSz[] = {
1250                5, 43, 119, 160,
1251                 220, 300, 364, 492, 
1252                 79, 0, 0, 0,
1253                 0, 0, 0, 0 };
1254         static int SpeexInBandSz[] = { 
1255                 1, 1, 4, 4,
1256                 4, 4, 4, 4,
1257                 8, 8, 16, 16,
1258                 32, 32, 64, 64 };
1259         int bit = 0;
1260         int cnt = 0;
1261         int off;
1262         unsigned char c;
1263
1264         while ((len * 8 - bit) >= 5) {
1265                 /* skip wideband frames */
1266                 off = speex_get_wb_sz_at(data, len, bit);
1267                 if (off < 0)  {
1268                         ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n");
1269                         break;
1270                 }
1271                 bit += off;
1272
1273                 if ((len * 8 - bit) < 5) {
1274                         ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
1275                         break;
1276                 }
1277
1278                 /* get control bits */
1279                 c = get_n_bits_at(data, 5, bit);
1280                 bit += 5;
1281
1282                 if (c == 15) { 
1283                         /* terminator */
1284                         break; 
1285                 } else if (c == 14) {
1286                         /* in-band signal; next 4 bits contain signal id */
1287                         c = get_n_bits_at(data, 4, bit);
1288                         bit += 4;
1289                         bit += SpeexInBandSz[c];
1290                 } else if (c == 13) {
1291                         /* user in-band; next 5 bits contain msg len */
1292                         c = get_n_bits_at(data, 5, bit);
1293                         bit += 5;
1294                         bit += c * 8;
1295                 } else if (c > 8) {
1296                         /* unknown */
1297                         break;
1298                 } else {
1299                         /* skip number bits for submode (less the 5 control bits) */
1300                         bit += SpeexSubModeSz[c] - 5;
1301                         cnt += 160; /* new frame */
1302                 }
1303         }
1304         return cnt;
1305 }
1306
1307 int ast_codec_get_samples(struct ast_frame *f)
1308 {
1309         int samples=0;
1310         switch(f->subclass) {
1311         case AST_FORMAT_SPEEX:
1312                 samples = speex_samples(f->data, f->datalen);
1313                 break;
1314         case AST_FORMAT_G723_1:
1315                 samples = g723_samples(f->data, f->datalen);
1316                 break;
1317         case AST_FORMAT_ILBC:
1318                 samples = 240 * (f->datalen / 50);
1319                 break;
1320         case AST_FORMAT_GSM:
1321                 samples = 160 * (f->datalen / 33);
1322                 break;
1323         case AST_FORMAT_G729A:
1324                 samples = f->datalen * 8;
1325                 break;
1326         case AST_FORMAT_SLINEAR:
1327                 samples = f->datalen / 2;
1328                 break;
1329         case AST_FORMAT_LPC10:
1330                 /* assumes that the RTP packet contains one LPC10 frame */
1331                 samples = 22 * 8;
1332                 samples += (((char *)(f->data))[7] & 0x1) * 8;
1333                 break;
1334         case AST_FORMAT_ULAW:
1335         case AST_FORMAT_ALAW:
1336                 samples = f->datalen;
1337                 break;
1338         case AST_FORMAT_ADPCM:
1339         case AST_FORMAT_G726:
1340         case AST_FORMAT_G726_AAL2:
1341                 samples = f->datalen * 2;
1342                 break;
1343         default:
1344                 ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
1345         }
1346         return samples;
1347 }
1348
1349 int ast_codec_get_len(int format, int samples)
1350 {
1351         int len = 0;
1352
1353         /* XXX Still need speex, g723, and lpc10 XXX */ 
1354         switch(format) {
1355         case AST_FORMAT_ILBC:
1356                 len = (samples / 240) * 50;
1357                 break;
1358         case AST_FORMAT_GSM:
1359                 len = (samples / 160) * 33;
1360                 break;
1361         case AST_FORMAT_G729A:
1362                 len = samples / 8;
1363                 break;
1364         case AST_FORMAT_SLINEAR:
1365                 len = samples * 2;
1366                 break;
1367         case AST_FORMAT_ULAW:
1368         case AST_FORMAT_ALAW:
1369                 len = samples;
1370                 break;
1371         case AST_FORMAT_ADPCM:
1372         case AST_FORMAT_G726:
1373         case AST_FORMAT_G726_AAL2:
1374                 len = samples / 2;
1375                 break;
1376         default:
1377                 ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format));
1378         }
1379
1380         return len;
1381 }
1382
1383 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment)
1384 {
1385         int count;
1386         short *fdata = f->data;
1387         short adjust_value = abs(adjustment);
1388
1389         if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR))
1390                 return -1;
1391
1392         if (!adjustment)
1393                 return 0;
1394
1395         for (count = 0; count < f->samples; count++) {
1396                 if (adjustment > 0) {
1397                         ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
1398                 } else if (adjustment < 0) {
1399                         ast_slinear_saturated_divide(&fdata[count], &adjust_value);
1400                 }
1401         }
1402
1403         return 0;
1404 }
1405
1406 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2)
1407 {
1408         int count;
1409         short *data1, *data2;
1410
1411         if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass != AST_FORMAT_SLINEAR))
1412                 return -1;
1413
1414         if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR))
1415                 return -1;
1416
1417         if (f1->samples != f2->samples)
1418                 return -1;
1419
1420         for (count = 0, data1 = f1->data, data2 = f2->data;
1421              count < f1->samples;
1422              count++, data1++, data2++)
1423                 ast_slinear_saturated_add(data1, data2);
1424
1425         return 0;
1426 }