![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
frame.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2005, Digium, Inc. 00005 * 00006 * Mark Spencer <markster@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 /*! \file 00020 * 00021 * \brief Frame and codec manipulation routines 00022 * 00023 * \author Mark Spencer <markster@digium.com> 00024 */ 00025 00026 #include "asterisk.h" 00027 00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 51499 $") 00029 00030 #include <stdlib.h> 00031 #include <unistd.h> 00032 #include <string.h> 00033 #include <errno.h> 00034 #include <stdio.h> 00035 00036 #include "asterisk/lock.h" 00037 #include "asterisk/frame.h" 00038 #include "asterisk/logger.h" 00039 #include "asterisk/options.h" 00040 #include "asterisk/channel.h" 00041 #include "asterisk/cli.h" 00042 #include "asterisk/term.h" 00043 #include "asterisk/utils.h" 00044 #include "asterisk/threadstorage.h" 00045 #include "asterisk/linkedlists.h" 00046 00047 #ifdef TRACE_FRAMES 00048 static int headers; 00049 static AST_LIST_HEAD_STATIC(headerlist, ast_frame); 00050 #endif 00051 00052 #if !defined(LOW_MEMORY) 00053 static void frame_cache_cleanup(void *data); 00054 00055 /*! \brief A per-thread cache of frame headers */ 00056 AST_THREADSTORAGE_CUSTOM(frame_cache, NULL, frame_cache_cleanup); 00057 00058 /*! 00059 * \brief Maximum ast_frame cache size 00060 * 00061 * In most cases where the frame header cache will be useful, the size 00062 * of the cache will stay very small. However, it is not always the case that 00063 * the same thread that allocates the frame will be the one freeing them, so 00064 * sometimes a thread will never have any frames in its cache, or the cache 00065 * will never be pulled from. For the latter case, we limit the maximum size. 00066 */ 00067 #define FRAME_CACHE_MAX_SIZE 10 00068 00069 /*! \brief This is just so ast_frames, a list head struct for holding a list of 00070 * ast_frame structures, is defined. */ 00071 AST_LIST_HEAD_NOLOCK(ast_frames, ast_frame); 00072 00073 struct ast_frame_cache { 00074 struct ast_frames list; 00075 size_t size; 00076 }; 00077 #endif 00078 00079 #define SMOOTHER_SIZE 8000 00080 00081 enum frame_type { 00082 TYPE_HIGH, /* 0x0 */ 00083 TYPE_LOW, /* 0x1 */ 00084 TYPE_SILENCE, /* 0x2 */ 00085 TYPE_DONTSEND /* 0x3 */ 00086 }; 00087 00088 #define TYPE_MASK 0x3 00089 00090 struct ast_smoother { 00091 int size; 00092 int format; 00093 int readdata; 00094 int optimizablestream; 00095 int flags; 00096 float samplesperbyte; 00097 struct ast_frame f; 00098 struct timeval delivery; 00099 char data[SMOOTHER_SIZE]; 00100 char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET]; 00101 struct ast_frame *opt; 00102 int len; 00103 }; 00104 00105 /*! \brief Definition of supported media formats (codecs) */ 00106 static struct ast_format_list AST_FORMAT_LIST[] = { /*!< Bit number: comment - Bit numbers are hard coded in show_codec() */ 00107 { 1, AST_FORMAT_G723_1 , "g723" , "G.723.1", 20, 30, 300, 30, 30 }, /*!< 1 */ 00108 { 1, AST_FORMAT_GSM, "gsm" , "GSM", 33, 20, 300, 20, 20 }, /*!< 2: codec_gsm.c */ 00109 { 1, AST_FORMAT_ULAW, "ulaw", "G.711 u-law", 80, 10, 150, 10, 20 }, /*!< 3: codec_ulaw.c */ 00110 { 1, AST_FORMAT_ALAW, "alaw", "G.711 A-law", 80, 10, 150, 10, 20 }, /*!< 4: codec_alaw.c */ 00111 { 1, AST_FORMAT_G726, "g726", "G.726 RFC3551", 40, 10, 300, 10, 20 }, /*!< 5: codec_g726.c */ 00112 { 1, AST_FORMAT_ADPCM, "adpcm" , "ADPCM", 40, 10, 300, 10, 20 }, /*!< 6: codec_adpcm.c */ 00113 { 1, AST_FORMAT_SLINEAR, "slin", "16 bit Signed Linear PCM", 160, 10, 70, 10, 20, AST_SMOOTHER_FLAG_BE }, /*!< 7 */ 00114 { 1, AST_FORMAT_LPC10, "lpc10", "LPC10", 7, 20, 20, 20, 20 }, /*!< 8: codec_lpc10.c */ 00115 { 1, AST_FORMAT_G729A, "g729", "G.729A", 10, 10, 230, 10, 20, AST_SMOOTHER_FLAG_G729 }, /*!< 9: Binary commercial distribution */ 00116 { 1, AST_FORMAT_SPEEX, "speex", "SpeeX", 10, 10, 60, 10, 20 }, /*!< 10: codec_speex.c */ 00117 { 1, AST_FORMAT_ILBC, "ilbc", "iLBC", 50, 30, 30, 30, 30 }, /*!< 11: codec_ilbc.c */ /* inc=30ms - workaround */ 00118 { 1, AST_FORMAT_G726_AAL2, "g726aal2", "G.726 AAL2", 40, 10, 300, 10, 20 }, /*!< 12: codec_g726.c */ 00119 { 1, AST_FORMAT_G722, "g722", "G722"}, /*!< 13 */ 00120 { 0, 0, "nothing", "undefined" }, 00121 { 0, 0, "nothing", "undefined" }, 00122 { 0, 0, "nothing", "undefined" }, 00123 { 0, 0, "nothing", "undefined" }, 00124 { 0, AST_FORMAT_MAX_AUDIO, "maxaudio", "Maximum audio format" }, 00125 { 1, AST_FORMAT_JPEG, "jpeg", "JPEG image"}, /*!< 17: See format_jpeg.c */ 00126 { 1, AST_FORMAT_PNG, "png", "PNG image"}, /*!< 18: Image format */ 00127 { 1, AST_FORMAT_H261, "h261", "H.261 Video" }, /*!< 19: H.261 Video Passthrough */ 00128 { 1, AST_FORMAT_H263, "h263", "H.263 Video" }, /*!< 20: H.263 Passthrough support, see format_h263.c */ 00129 { 1, AST_FORMAT_H263_PLUS, "h263p", "H.263+ Video" }, /*!< 21: H.263plus passthrough support See format_h263.c */ 00130 { 1, AST_FORMAT_H264, "h264", "H.264 Video" }, /*!< 22: Passthrough support, see format_h263.c */ 00131 { 1, AST_FORMAT_MP4_VIDEO, "mpeg4", "MPEG4 Video" }, /*!< Passthrough support for MPEG4 */ 00132 { 0, 0, "nothing", "undefined" }, 00133 { 0, 0, "nothing", "undefined" }, 00134 { 0, 0, "nothing", "undefined" }, 00135 { 0, AST_FORMAT_MAX_VIDEO, "maxvideo", "Maximum video format" }, 00136 { 1, AST_FORMAT_T140, "t140", "Passthrough T.140 Realtime Text" }, 00137 { 0, 0, "nothing", "undefined" }, 00138 { 0, 0, "nothing", "undefined" }, 00139 { 0, AST_FORMAT_MAX_TEXT, "maxtext", "Maximum text format" }, 00140 }; 00141 00142 struct ast_frame ast_null_frame = { AST_FRAME_NULL, }; 00143 00144 void ast_smoother_reset(struct ast_smoother *s, int size) 00145 { 00146 memset(s, 0, sizeof(*s)); 00147 s->size = size; 00148 } 00149 00150 struct ast_smoother *ast_smoother_new(int size) 00151 { 00152 struct ast_smoother *s; 00153 if (size < 1) 00154 return NULL; 00155 if ((s = ast_malloc(sizeof(*s)))) 00156 ast_smoother_reset(s, size); 00157 return s; 00158 } 00159 00160 int ast_smoother_get_flags(struct ast_smoother *s) 00161 { 00162 return s->flags; 00163 } 00164 00165 void ast_smoother_set_flags(struct ast_smoother *s, int flags) 00166 { 00167 s->flags = flags; 00168 } 00169 00170 int ast_smoother_test_flag(struct ast_smoother *s, int flag) 00171 { 00172 return (s->flags & flag); 00173 } 00174 00175 int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap) 00176 { 00177 if (f->frametype != AST_FRAME_VOICE) { 00178 ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n"); 00179 return -1; 00180 } 00181 if (!s->format) { 00182 s->format = f->subclass; 00183 s->samplesperbyte = (float)f->samples / (float)f->datalen; 00184 } else if (s->format != f->subclass) { 00185 ast_log(LOG_WARNING, "Smoother was working on %d format frames, now trying to feed %d?\n", s->format, f->subclass); 00186 return -1; 00187 } 00188 if (s->len + f->datalen > SMOOTHER_SIZE) { 00189 ast_log(LOG_WARNING, "Out of smoother space\n"); 00190 return -1; 00191 } 00192 if (((f->datalen == s->size) || ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) 00193 && !s->opt && (f->offset >= AST_MIN_OFFSET)) { 00194 if (!s->len) { 00195 /* Optimize by sending the frame we just got 00196 on the next read, thus eliminating the douple 00197 copy */ 00198 if (swap) 00199 ast_swapcopy_samples(f->data, f->data, f->samples); 00200 s->opt = f; 00201 return 0; 00202 } else { 00203 s->optimizablestream++; 00204 if (s->optimizablestream > 10) { 00205 /* For the past 10 rounds, we have input and output 00206 frames of the correct size for this smoother, yet 00207 we were unable to optimize because there was still 00208 some cruft left over. Lets just drop the cruft so 00209 we can move to a fully optimized path */ 00210 if (swap) 00211 ast_swapcopy_samples(f->data, f->data, f->samples); 00212 s->len = 0; 00213 s->opt = f; 00214 return 0; 00215 } 00216 } 00217 } else 00218 s->optimizablestream = 0; 00219 if (s->flags & AST_SMOOTHER_FLAG_G729) { 00220 if (s->len % 10) { 00221 ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n"); 00222 return 0; 00223 } 00224 } 00225 if (swap) 00226 ast_swapcopy_samples(s->data+s->len, f->data, f->samples); 00227 else 00228 memcpy(s->data + s->len, f->data, f->datalen); 00229 /* If either side is empty, reset the delivery time */ 00230 if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) /* XXX really ? */ 00231 s->delivery = f->delivery; 00232 s->len += f->datalen; 00233 return 0; 00234 } 00235 00236 struct ast_frame *ast_smoother_read(struct ast_smoother *s) 00237 { 00238 struct ast_frame *opt; 00239 int len; 00240 00241 /* IF we have an optimization frame, send it */ 00242 if (s->opt) { 00243 if (s->opt->offset < AST_FRIENDLY_OFFSET) 00244 ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n", 00245 s->opt->offset); 00246 opt = s->opt; 00247 s->opt = NULL; 00248 return opt; 00249 } 00250 00251 /* Make sure we have enough data */ 00252 if (s->len < s->size) { 00253 /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */ 00254 if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->size % 10))) 00255 return NULL; 00256 } 00257 len = s->size; 00258 if (len > s->len) 00259 len = s->len; 00260 /* Make frame */ 00261 s->f.frametype = AST_FRAME_VOICE; 00262 s->f.subclass = s->format; 00263 s->f.data = s->framedata + AST_FRIENDLY_OFFSET; 00264 s->f.offset = AST_FRIENDLY_OFFSET; 00265 s->f.datalen = len; 00266 /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */ 00267 s->f.samples = len * s->samplesperbyte; /* XXX rounding */ 00268 s->f.delivery = s->delivery; 00269 /* Fill Data */ 00270 memcpy(s->f.data, s->data, len); 00271 s->len -= len; 00272 /* Move remaining data to the front if applicable */ 00273 if (s->len) { 00274 /* In principle this should all be fine because if we are sending 00275 G.729 VAD, the next timestamp will take over anyawy */ 00276 memmove(s->data, s->data + len, s->len); 00277 if (!ast_tvzero(s->delivery)) { 00278 /* If we have delivery time, increment it, otherwise, leave it at 0 */ 00279 s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, 8000)); 00280 } 00281 } 00282 /* Return frame */ 00283 return &s->f; 00284 } 00285 00286 void ast_smoother_free(struct ast_smoother *s) 00287 { 00288 free(s); 00289 } 00290 00291 static struct ast_frame *ast_frame_header_new(void) 00292 { 00293 struct ast_frame *f; 00294 00295 #if !defined(LOW_MEMORY) 00296 struct ast_frame_cache *frames; 00297 00298 if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) { 00299 if ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list))) { 00300 size_t mallocd_len = f->mallocd_hdr_len; 00301 memset(f, 0, sizeof(*f)); 00302 f->mallocd_hdr_len = mallocd_len; 00303 f->mallocd = AST_MALLOCD_HDR; 00304 frames->size--; 00305 return f; 00306 } 00307 } 00308 if (!(f = ast_calloc_cache(1, sizeof(*f)))) 00309 return NULL; 00310 #else 00311 if (!(f = ast_calloc(1, sizeof(*f)))) 00312 return NULL; 00313 #endif 00314 00315 f->mallocd_hdr_len = sizeof(*f); 00316 #ifdef TRACE_FRAMES 00317 AST_LIST_LOCK(&headerlist); 00318 headers++; 00319 AST_LIST_INSERT_HEAD(&headerlist, f, frame_list); 00320 AST_LIST_UNLOCK(&headerlist); 00321 #endif 00322 00323 return f; 00324 } 00325 00326 #if !defined(LOW_MEMORY) 00327 static void frame_cache_cleanup(void *data) 00328 { 00329 struct ast_frame_cache *frames = data; 00330 struct ast_frame *f; 00331 00332 while ((f = AST_LIST_REMOVE_HEAD(&frames->list, frame_list))) 00333 free(f); 00334 00335 free(frames); 00336 } 00337 #endif 00338 00339 void ast_frame_free(struct ast_frame *fr, int cache) 00340 { 00341 if (!fr->mallocd) 00342 return; 00343 00344 #if !defined(LOW_MEMORY) 00345 if (cache && fr->mallocd == AST_MALLOCD_HDR) { 00346 /* Cool, only the header is malloc'd, let's just cache those for now 00347 * to keep things simple... */ 00348 struct ast_frame_cache *frames; 00349 00350 if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) 00351 && frames->size < FRAME_CACHE_MAX_SIZE) { 00352 AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list); 00353 frames->size++; 00354 return; 00355 } 00356 } 00357 #endif 00358 00359 if (fr->mallocd & AST_MALLOCD_DATA) { 00360 if (fr->data) 00361 free(fr->data - fr->offset); 00362 } 00363 if (fr->mallocd & AST_MALLOCD_SRC) { 00364 if (fr->src) 00365 free((char *)fr->src); 00366 } 00367 if (fr->mallocd & AST_MALLOCD_HDR) { 00368 #ifdef TRACE_FRAMES 00369 AST_LIST_LOCK(&headerlist); 00370 headers--; 00371 AST_LIST_REMOVE(&headerlist, fr, frame_list); 00372 AST_LIST_UNLOCK(&headerlist); 00373 #endif 00374 free(fr); 00375 } 00376 } 00377 00378 /*! 00379 * \brief 'isolates' a frame by duplicating non-malloc'ed components 00380 * (header, src, data). 00381 * On return all components are malloc'ed 00382 */ 00383 struct ast_frame *ast_frisolate(struct ast_frame *fr) 00384 { 00385 struct ast_frame *out; 00386 void *newdata; 00387 00388 if (!(fr->mallocd & AST_MALLOCD_HDR)) { 00389 /* Allocate a new header if needed */ 00390 if (!(out = ast_frame_header_new())) 00391 return NULL; 00392 out->frametype = fr->frametype; 00393 out->subclass = fr->subclass; 00394 out->datalen = fr->datalen; 00395 out->samples = fr->samples; 00396 out->offset = fr->offset; 00397 out->data = fr->data; 00398 /* Copy the timing data */ 00399 out->has_timing_info = fr->has_timing_info; 00400 if (fr->has_timing_info) { 00401 out->ts = fr->ts; 00402 out->len = fr->len; 00403 out->seqno = fr->seqno; 00404 } 00405 } else 00406 out = fr; 00407 00408 if (!(fr->mallocd & AST_MALLOCD_SRC)) { 00409 if (fr->src) { 00410 if (!(out->src = ast_strdup(fr->src))) { 00411 if (out != fr) 00412 free(out); 00413 return NULL; 00414 } 00415 } 00416 } else 00417 out->src = fr->src; 00418 00419 if (!(fr->mallocd & AST_MALLOCD_DATA)) { 00420 if (!(newdata = ast_malloc(fr->datalen + AST_FRIENDLY_OFFSET))) { 00421 if (out->src != fr->src) 00422 free((void *) out->src); 00423 if (out != fr) 00424 free(out); 00425 return NULL; 00426 } 00427 newdata += AST_FRIENDLY_OFFSET; 00428 out->offset = AST_FRIENDLY_OFFSET; 00429 out->datalen = fr->datalen; 00430 memcpy(newdata, fr->data, fr->datalen); 00431 out->data = newdata; 00432 } 00433 00434 out->mallocd = AST_MALLOCD_HDR | AST_MALLOCD_SRC | AST_MALLOCD_DATA; 00435 00436 return out; 00437 } 00438 00439 struct ast_frame *ast_frdup(const struct ast_frame *f) 00440 { 00441 struct ast_frame *out = NULL; 00442 int len, srclen = 0; 00443 void *buf = NULL; 00444 00445 #if !defined(LOW_MEMORY) 00446 struct ast_frame_cache *frames; 00447 #endif 00448 00449 /* Start with standard stuff */ 00450 len = sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen; 00451 /* If we have a source, add space for it */ 00452 /* 00453 * XXX Watch out here - if we receive a src which is not terminated 00454 * properly, we can be easily attacked. Should limit the size we deal with. 00455 */ 00456 if (f->src) 00457 srclen = strlen(f->src); 00458 if (srclen > 0) 00459 len += srclen + 1; 00460 00461 #if !defined(LOW_MEMORY) 00462 if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames)))) { 00463 AST_LIST_TRAVERSE_SAFE_BEGIN(&frames->list, out, frame_list) { 00464 if (out->mallocd_hdr_len >= len) { 00465 size_t mallocd_len = out->mallocd_hdr_len; 00466 AST_LIST_REMOVE_CURRENT(&frames->list, frame_list); 00467 memset(out, 0, sizeof(*out)); 00468 out->mallocd_hdr_len = mallocd_len; 00469 buf = out; 00470 frames->size--; 00471 break; 00472 } 00473 } 00474 AST_LIST_TRAVERSE_SAFE_END 00475 } 00476 #endif 00477 00478 if (!buf) { 00479 if (!(buf = ast_calloc_cache(1, len))) 00480 return NULL; 00481 out = buf; 00482 out->mallocd_hdr_len = len; 00483 } 00484 00485 out->frametype = f->frametype; 00486 out->subclass = f->subclass; 00487 out->datalen = f->datalen; 00488 out->samples = f->samples; 00489 out->delivery = f->delivery; 00490 /* Set us as having malloc'd header only, so it will eventually 00491 get freed. */ 00492 out->mallocd = AST_MALLOCD_HDR; 00493 out->offset = AST_FRIENDLY_OFFSET; 00494 if (out->datalen) { 00495 out->data = buf + sizeof(*out) + AST_FRIENDLY_OFFSET; 00496 memcpy(out->data, f->data, out->datalen); 00497 } 00498 if (srclen > 0) { 00499 out->src = buf + sizeof(*out) + AST_FRIENDLY_OFFSET + f->datalen; 00500 /* Must have space since we allocated for it */ 00501 strcpy((char *)out->src, f->src); 00502 } 00503 out->has_timing_info = f->has_timing_info; 00504 out->ts = f->ts; 00505 out->len = f->len; 00506 out->seqno = f->seqno; 00507 return out; 00508 } 00509 00510 void ast_swapcopy_samples(void *dst, const void *src, int samples) 00511 { 00512 int i; 00513 unsigned short *dst_s = dst; 00514 const unsigned short *src_s = src; 00515 00516 for (i = 0; i < samples; i++) 00517 dst_s[i] = (src_s[i]<<8) | (src_s[i]>>8); 00518 } 00519 00520 00521 struct ast_format_list *ast_get_format_list_index(int index) 00522 { 00523 return &AST_FORMAT_LIST[index]; 00524 } 00525 00526 struct ast_format_list *ast_get_format_list(size_t *size) 00527 { 00528 *size = (sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0])); 00529 return AST_FORMAT_LIST; 00530 } 00531 00532 char* ast_getformatname(int format) 00533 { 00534 int x; 00535 char *ret = "unknown"; 00536 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 00537 if (AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == format) { 00538 ret = AST_FORMAT_LIST[x].name; 00539 break; 00540 } 00541 } 00542 return ret; 00543 } 00544 00545 char *ast_getformatname_multiple(char *buf, size_t size, int format) 00546 { 00547 int x; 00548 unsigned len; 00549 char *start, *end = buf; 00550 00551 if (!size) 00552 return buf; 00553 snprintf(end, size, "0x%x (", format); 00554 len = strlen(end); 00555 end += len; 00556 size -= len; 00557 start = end; 00558 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 00559 if (AST_FORMAT_LIST[x].visible && (AST_FORMAT_LIST[x].bits & format)) { 00560 snprintf(end, size,"%s|",AST_FORMAT_LIST[x].name); 00561 len = strlen(end); 00562 end += len; 00563 size -= len; 00564 } 00565 } 00566 if (start == end) 00567 snprintf(start, size, "nothing)"); 00568 else if (size > 1) 00569 *(end -1) = ')'; 00570 return buf; 00571 } 00572 00573 static struct ast_codec_alias_table { 00574 char *alias; 00575 char *realname; 00576 } ast_codec_alias_table[] = { 00577 { "slinear", "slin"}, 00578 { "g723.1", "g723"}, 00579 }; 00580 00581 static const char *ast_expand_codec_alias(const char *in) 00582 { 00583 int x; 00584 00585 for (x = 0; x < sizeof(ast_codec_alias_table) / sizeof(ast_codec_alias_table[0]); x++) { 00586 if (!strcmp(in,ast_codec_alias_table[x].alias)) 00587 return ast_codec_alias_table[x].realname; 00588 } 00589 return in; 00590 } 00591 00592 int ast_getformatbyname(const char *name) 00593 { 00594 int x, all, format = 0; 00595 00596 all = strcasecmp(name, "all") ? 0 : 1; 00597 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 00598 if (AST_FORMAT_LIST[x].visible && (all || 00599 !strcasecmp(AST_FORMAT_LIST[x].name,name) || 00600 !strcasecmp(AST_FORMAT_LIST[x].name,ast_expand_codec_alias(name)))) { 00601 format |= AST_FORMAT_LIST[x].bits; 00602 if (!all) 00603 break; 00604 } 00605 } 00606 00607 return format; 00608 } 00609 00610 char *ast_codec2str(int codec) 00611 { 00612 int x; 00613 char *ret = "unknown"; 00614 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 00615 if (AST_FORMAT_LIST[x].visible && AST_FORMAT_LIST[x].bits == codec) { 00616 ret = AST_FORMAT_LIST[x].desc; 00617 break; 00618 } 00619 } 00620 return ret; 00621 } 00622 00623 static int show_codecs(int fd, int argc, char *argv[]) 00624 { 00625 int i, found=0; 00626 char hex[25]; 00627 00628 if ((argc < 3) || (argc > 4)) 00629 return RESULT_SHOWUSAGE; 00630 00631 if (!ast_opt_dont_warn) 00632 ast_cli(fd, "Disclaimer: this command is for informational purposes only.\n" 00633 "\tIt does not indicate anything about your configuration.\n"); 00634 00635 ast_cli(fd, "%11s %9s %10s TYPE %8s %s\n","INT","BINARY","HEX","NAME","DESC"); 00636 ast_cli(fd, "--------------------------------------------------------------------------------\n"); 00637 if ((argc == 3) || (!strcasecmp(argv[3],"audio"))) { 00638 found = 1; 00639 for (i=0;i<13;i++) { 00640 snprintf(hex,25,"(0x%x)",1<<i); 00641 ast_cli(fd, "%11u (1 << %2d) %10s audio %8s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i)); 00642 } 00643 } 00644 00645 if ((argc == 3) || (!strcasecmp(argv[3],"image"))) { 00646 found = 1; 00647 for (i=16;i<18;i++) { 00648 snprintf(hex,25,"(0x%x)",1<<i); 00649 ast_cli(fd, "%11u (1 << %2d) %10s image %8s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i)); 00650 } 00651 } 00652 00653 if ((argc == 3) || (!strcasecmp(argv[3],"video"))) { 00654 found = 1; 00655 for (i=18;i<22;i++) { 00656 snprintf(hex,25,"(0x%x)",1<<i); 00657 ast_cli(fd, "%11u (1 << %2d) %10s video %8s (%s)\n",1 << i,i,hex,ast_getformatname(1<<i),ast_codec2str(1<<i)); 00658 } 00659 } 00660 00661 if (! found) 00662 return RESULT_SHOWUSAGE; 00663 else 00664 return RESULT_SUCCESS; 00665 } 00666 00667 static const char frame_show_codecs_usage[] = 00668 "Usage: core show codecs [audio|video|image]\n" 00669 " Displays codec mapping\n"; 00670 00671 static int show_codec_n(int fd, int argc, char *argv[]) 00672 { 00673 int codec, i, found=0; 00674 00675 if (argc != 4) 00676 return RESULT_SHOWUSAGE; 00677 00678 if (sscanf(argv[3],"%d",&codec) != 1) 00679 return RESULT_SHOWUSAGE; 00680 00681 for (i = 0; i < 32; i++) 00682 if (codec & (1 << i)) { 00683 found = 1; 00684 ast_cli(fd, "%11u (1 << %2d) %s\n",1 << i,i,ast_codec2str(1<<i)); 00685 } 00686 00687 if (!found) 00688 ast_cli(fd, "Codec %d not found\n", codec); 00689 00690 return RESULT_SUCCESS; 00691 } 00692 00693 static char frame_show_codec_n_usage[] = 00694 "Usage: core show codec <number>\n" 00695 " Displays codec mapping\n"; 00696 00697 /*! Dump a frame for debugging purposes */ 00698 void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix) 00699 { 00700 const char noname[] = "unknown"; 00701 char ftype[40] = "Unknown Frametype"; 00702 char cft[80]; 00703 char subclass[40] = "Unknown Subclass"; 00704 char csub[80]; 00705 char moreinfo[40] = ""; 00706 char cn[60]; 00707 char cp[40]; 00708 char cmn[40]; 00709 00710 if (!name) 00711 name = noname; 00712 00713 00714 if (!f) { 00715 ast_verbose("%s [ %s (NULL) ] [%s]\n", 00716 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)), 00717 term_color(cft, "HANGUP", COLOR_BRRED, COLOR_BLACK, sizeof(cft)), 00718 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn))); 00719 return; 00720 } 00721 /* XXX We should probably print one each of voice and video when the format changes XXX */ 00722 if (f->frametype == AST_FRAME_VOICE) 00723 return; 00724 if (f->frametype == AST_FRAME_VIDEO) 00725 return; 00726 switch(f->frametype) { 00727 case AST_FRAME_DTMF_BEGIN: 00728 strcpy(ftype, "DTMF Begin"); 00729 subclass[0] = f->subclass; 00730 subclass[1] = '\0'; 00731 break; 00732 case AST_FRAME_DTMF_END: 00733 strcpy(ftype, "DTMF End"); 00734 subclass[0] = f->subclass; 00735 subclass[1] = '\0'; 00736 break; 00737 case AST_FRAME_CONTROL: 00738 strcpy(ftype, "Control"); 00739 switch(f->subclass) { 00740 case AST_CONTROL_HANGUP: 00741 strcpy(subclass, "Hangup"); 00742 break; 00743 case AST_CONTROL_RING: 00744 strcpy(subclass, "Ring"); 00745 break; 00746 case AST_CONTROL_RINGING: 00747 strcpy(subclass, "Ringing"); 00748 break; 00749 case AST_CONTROL_ANSWER: 00750 strcpy(subclass, "Answer"); 00751 break; 00752 case AST_CONTROL_BUSY: 00753 strcpy(subclass, "Busy"); 00754 break; 00755 case AST_CONTROL_TAKEOFFHOOK: 00756 strcpy(subclass, "Take Off Hook"); 00757 break; 00758 case AST_CONTROL_OFFHOOK: 00759 strcpy(subclass, "Line Off Hook"); 00760 break; 00761 case AST_CONTROL_CONGESTION: 00762 strcpy(subclass, "Congestion"); 00763 break; 00764 case AST_CONTROL_FLASH: 00765 strcpy(subclass, "Flash"); 00766 break; 00767 case AST_CONTROL_WINK: 00768 strcpy(subclass, "Wink"); 00769 break; 00770 case AST_CONTROL_OPTION: 00771 strcpy(subclass, "Option"); 00772 break; 00773 case AST_CONTROL_RADIO_KEY: 00774 strcpy(subclass, "Key Radio"); 00775 break; 00776 case AST_CONTROL_RADIO_UNKEY: 00777 strcpy(subclass, "Unkey Radio"); 00778 break; 00779 case -1: 00780 strcpy(subclass, "Stop generators"); 00781 break; 00782 default: 00783 snprintf(subclass, sizeof(subclass), "Unknown control '%d'", f->subclass); 00784 } 00785 break; 00786 case AST_FRAME_NULL: 00787 strcpy(ftype, "Null Frame"); 00788 strcpy(subclass, "N/A"); 00789 break; 00790 case AST_FRAME_IAX: 00791 /* Should never happen */ 00792 strcpy(ftype, "IAX Specific"); 00793 snprintf(subclass, sizeof(subclass), "IAX Frametype %d", f->subclass); 00794 break; 00795 case AST_FRAME_TEXT: 00796 strcpy(ftype, "Text"); 00797 strcpy(subclass, "N/A"); 00798 ast_copy_string(moreinfo, f->data, sizeof(moreinfo)); 00799 break; 00800 case AST_FRAME_IMAGE: 00801 strcpy(ftype, "Image"); 00802 snprintf(subclass, sizeof(subclass), "Image format %s\n", ast_getformatname(f->subclass)); 00803 break; 00804 case AST_FRAME_HTML: 00805 strcpy(ftype, "HTML"); 00806 switch(f->subclass) { 00807 case AST_HTML_URL: 00808 strcpy(subclass, "URL"); 00809 ast_copy_string(moreinfo, f->data, sizeof(moreinfo)); 00810 break; 00811 case AST_HTML_DATA: 00812 strcpy(subclass, "Data"); 00813 break; 00814 case AST_HTML_BEGIN: 00815 strcpy(subclass, "Begin"); 00816 break; 00817 case AST_HTML_END: 00818 strcpy(subclass, "End"); 00819 break; 00820 case AST_HTML_LDCOMPLETE: 00821 strcpy(subclass, "Load Complete"); 00822 break; 00823 case AST_HTML_NOSUPPORT: 00824 strcpy(subclass, "No Support"); 00825 break; 00826 case AST_HTML_LINKURL: 00827 strcpy(subclass, "Link URL"); 00828 ast_copy_string(moreinfo, f->data, sizeof(moreinfo)); 00829 break; 00830 case AST_HTML_UNLINK: 00831 strcpy(subclass, "Unlink"); 00832 break; 00833 case AST_HTML_LINKREJECT: 00834 strcpy(subclass, "Link Reject"); 00835 break; 00836 default: 00837 snprintf(subclass, sizeof(subclass), "Unknown HTML frame '%d'\n", f->subclass); 00838 break; 00839 } 00840 break; 00841 case AST_FRAME_MODEM: 00842 strcpy(ftype, "Modem"); 00843 switch (f->subclass) { 00844 case AST_MODEM_T38: 00845 strcpy(subclass, "T.38"); 00846 break; 00847 case AST_MODEM_V150: 00848 strcpy(subclass, "V.150"); 00849 break; 00850 default: 00851 snprintf(subclass, sizeof(subclass), "Unknown MODEM frame '%d'\n", f->subclass); 00852 break; 00853 } 00854 break; 00855 default: 00856 snprintf(ftype, sizeof(ftype), "Unknown Frametype '%d'", f->frametype); 00857 } 00858 if (!ast_strlen_zero(moreinfo)) 00859 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) '%s' ] [%s]\n", 00860 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)), 00861 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)), 00862 f->frametype, 00863 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)), 00864 f->subclass, 00865 term_color(cmn, moreinfo, COLOR_BRGREEN, COLOR_BLACK, sizeof(cmn)), 00866 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn))); 00867 else 00868 ast_verbose("%s [ TYPE: %s (%d) SUBCLASS: %s (%d) ] [%s]\n", 00869 term_color(cp, prefix, COLOR_BRMAGENTA, COLOR_BLACK, sizeof(cp)), 00870 term_color(cft, ftype, COLOR_BRRED, COLOR_BLACK, sizeof(cft)), 00871 f->frametype, 00872 term_color(csub, subclass, COLOR_BRCYAN, COLOR_BLACK, sizeof(csub)), 00873 f->subclass, 00874 term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn))); 00875 } 00876 00877 00878 #ifdef TRACE_FRAMES 00879 static int show_frame_stats(int fd, int argc, char *argv[]) 00880 { 00881 struct ast_frame *f; 00882 int x=1; 00883 if (argc != 4) 00884 return RESULT_SHOWUSAGE; 00885 AST_LIST_LOCK(&headerlist); 00886 ast_cli(fd, " Framer Statistics \n"); 00887 ast_cli(fd, "---------------------------\n"); 00888 ast_cli(fd, "Total allocated headers: %d\n", headers); 00889 ast_cli(fd, "Queue Dump:\n"); 00890 AST_LIST_TRAVERSE(&headerlist, f, frame_list) 00891 ast_cli(fd, "%d. Type %d, subclass %d from %s\n", x++, f->frametype, f->subclass, f->src ? f->src : "<Unknown>"); 00892 AST_LIST_UNLOCK(&headerlist); 00893 return RESULT_SUCCESS; 00894 } 00895 00896 static const char frame_stats_usage[] = 00897 "Usage: core show frame stats\n" 00898 " Displays debugging statistics from framer\n"; 00899 #endif 00900 00901 /* Builtin Asterisk CLI-commands for debugging */ 00902 static struct ast_cli_entry my_clis[] = { 00903 { { "core", "show", "codecs", NULL }, 00904 show_codecs, "Displays a list of codecs", 00905 frame_show_codecs_usage }, 00906 00907 { { "core", "show", "audio", "codecs", NULL }, 00908 show_codecs, "Displays a list of audio codecs", 00909 frame_show_codecs_usage }, 00910 00911 { { "core", "show", "video", "codecs", NULL }, 00912 show_codecs, "Displays a list of video codecs", 00913 frame_show_codecs_usage }, 00914 00915 { { "core", "show", "image", "codecs", NULL }, 00916 show_codecs, "Displays a list of image codecs", 00917 frame_show_codecs_usage }, 00918 00919 { { "core", "show", "codec", NULL }, 00920 show_codec_n, "Shows a specific codec", 00921 frame_show_codec_n_usage }, 00922 00923 #ifdef TRACE_FRAMES 00924 { { "core", "show", "frame", "stats", NULL }, 00925 show_frame_stats, "Shows frame statistics", 00926 frame_stats_usage }, 00927 #endif 00928 }; 00929 00930 int init_framer(void) 00931 { 00932 ast_cli_register_multiple(my_clis, sizeof(my_clis) / sizeof(struct ast_cli_entry)); 00933 return 0; 00934 } 00935 00936 void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_t size, int right) 00937 { 00938 int x, differential = (int) 'A', mem; 00939 char *from, *to; 00940 00941 if (right) { 00942 from = pref->order; 00943 to = buf; 00944 mem = size; 00945 } else { 00946 to = pref->order; 00947 from = buf; 00948 mem = 32; 00949 } 00950 00951 memset(to, 0, mem); 00952 for (x = 0; x < 32 ; x++) { 00953 if (!from[x]) 00954 break; 00955 to[x] = right ? (from[x] + differential) : (from[x] - differential); 00956 } 00957 } 00958 00959 int ast_codec_pref_string(struct ast_codec_pref *pref, char *buf, size_t size) 00960 { 00961 int x, codec; 00962 size_t total_len, slen; 00963 char *formatname; 00964 00965 memset(buf,0,size); 00966 total_len = size; 00967 buf[0] = '('; 00968 total_len--; 00969 for(x = 0; x < 32 ; x++) { 00970 if (total_len <= 0) 00971 break; 00972 if (!(codec = ast_codec_pref_index(pref,x))) 00973 break; 00974 if ((formatname = ast_getformatname(codec))) { 00975 slen = strlen(formatname); 00976 if (slen > total_len) 00977 break; 00978 strncat(buf,formatname,total_len); 00979 total_len -= slen; 00980 } 00981 if (total_len && x < 31 && ast_codec_pref_index(pref , x + 1)) { 00982 strncat(buf,"|",total_len); 00983 total_len--; 00984 } 00985 } 00986 if (total_len) { 00987 strncat(buf,")",total_len); 00988 total_len--; 00989 } 00990 00991 return size - total_len; 00992 } 00993 00994 int ast_codec_pref_index(struct ast_codec_pref *pref, int index) 00995 { 00996 int slot = 0; 00997 00998 00999 if ((index >= 0) && (index < sizeof(pref->order))) { 01000 slot = pref->order[index]; 01001 } 01002 01003 return slot ? AST_FORMAT_LIST[slot-1].bits : 0; 01004 } 01005 01006 /*! \brief Remove codec from pref list */ 01007 void ast_codec_pref_remove(struct ast_codec_pref *pref, int format) 01008 { 01009 struct ast_codec_pref oldorder; 01010 int x, y = 0; 01011 int slot; 01012 int size; 01013 01014 if (!pref->order[0]) 01015 return; 01016 01017 memcpy(&oldorder, pref, sizeof(oldorder)); 01018 memset(pref, 0, sizeof(*pref)); 01019 01020 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 01021 slot = oldorder.order[x]; 01022 size = oldorder.framing[x]; 01023 if (! slot) 01024 break; 01025 if (AST_FORMAT_LIST[slot-1].bits != format) { 01026 pref->order[y] = slot; 01027 pref->framing[y++] = size; 01028 } 01029 } 01030 01031 } 01032 01033 /*! \brief Append codec to list */ 01034 int ast_codec_pref_append(struct ast_codec_pref *pref, int format) 01035 { 01036 int x, newindex = -1; 01037 01038 ast_codec_pref_remove(pref, format); 01039 01040 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 01041 if (AST_FORMAT_LIST[x].bits == format) { 01042 newindex = x + 1; 01043 break; 01044 } 01045 } 01046 01047 if (newindex) { 01048 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 01049 if (!pref->order[x]) { 01050 pref->order[x] = newindex; 01051 break; 01052 } 01053 } 01054 } 01055 01056 return x; 01057 } 01058 01059 01060 /*! \brief Set packet size for codec */ 01061 int ast_codec_pref_setsize(struct ast_codec_pref *pref, int format, int framems) 01062 { 01063 int x, index = -1; 01064 01065 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 01066 if (AST_FORMAT_LIST[x].bits == format) { 01067 index = x; 01068 break; 01069 } 01070 } 01071 01072 if (index < 0) 01073 return -1; 01074 01075 /* size validation */ 01076 if (!framems) 01077 framems = AST_FORMAT_LIST[index].def_ms; 01078 01079 if (AST_FORMAT_LIST[index].inc_ms && framems % AST_FORMAT_LIST[index].inc_ms) /* avoid division by zero */ 01080 framems -= framems % AST_FORMAT_LIST[index].inc_ms; 01081 01082 if (framems < AST_FORMAT_LIST[index].min_ms) 01083 framems = AST_FORMAT_LIST[index].min_ms; 01084 01085 if (framems > AST_FORMAT_LIST[index].max_ms) 01086 framems = AST_FORMAT_LIST[index].max_ms; 01087 01088 01089 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 01090 if (pref->order[x] == (index + 1)) { 01091 pref->framing[x] = framems; 01092 break; 01093 } 01094 } 01095 01096 return x; 01097 } 01098 01099 /*! \brief Get packet size for codec */ 01100 struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, int format) 01101 { 01102 int x, index = -1, framems = 0; 01103 struct ast_format_list fmt = { 0, }; 01104 01105 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 01106 if (AST_FORMAT_LIST[x].bits == format) { 01107 fmt = AST_FORMAT_LIST[x]; 01108 index = x; 01109 break; 01110 } 01111 } 01112 01113 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 01114 if (pref->order[x] == (index + 1)) { 01115 framems = pref->framing[x]; 01116 break; 01117 } 01118 } 01119 01120 /* size validation */ 01121 if (!framems) 01122 framems = AST_FORMAT_LIST[index].def_ms; 01123 01124 if (AST_FORMAT_LIST[index].inc_ms && framems % AST_FORMAT_LIST[index].inc_ms) /* avoid division by zero */ 01125 framems -= framems % AST_FORMAT_LIST[index].inc_ms; 01126 01127 if (framems < AST_FORMAT_LIST[index].min_ms) 01128 framems = AST_FORMAT_LIST[index].min_ms; 01129 01130 if (framems > AST_FORMAT_LIST[index].max_ms) 01131 framems = AST_FORMAT_LIST[index].max_ms; 01132 01133 fmt.cur_ms = framems; 01134 01135 return fmt; 01136 } 01137 01138 /*! \brief Pick a codec */ 01139 int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best) 01140 { 01141 int x, ret = 0, slot; 01142 01143 for (x = 0; x < sizeof(AST_FORMAT_LIST) / sizeof(AST_FORMAT_LIST[0]); x++) { 01144 slot = pref->order[x]; 01145 01146 if (!slot) 01147 break; 01148 if (formats & AST_FORMAT_LIST[slot-1].bits) { 01149 ret = AST_FORMAT_LIST[slot-1].bits; 01150 break; 01151 } 01152 } 01153 if (ret & AST_FORMAT_AUDIO_MASK) 01154 return ret; 01155 01156 if (option_debug > 3) 01157 ast_log(LOG_DEBUG, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec"); 01158 01159 return find_best ? ast_best_codec(formats) : 0; 01160 } 01161 01162 int ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing) 01163 { 01164 int errors = 0; 01165 char *parse = NULL, *this = NULL, *psize = NULL; 01166 int format = 0, framems = 0; 01167 01168 parse = ast_strdupa(list); 01169 while ((this = strsep(&parse, ","))) { 01170 framems = 0; 01171 if ((psize = strrchr(this, ':'))) { 01172 *psize++ = '\0'; 01173 if (option_debug) 01174 ast_log(LOG_DEBUG,"Packetization for codec: %s is %s\n", this, psize); 01175 framems = atoi(psize); 01176 if (framems < 0) { 01177 framems = 0; 01178 errors++; 01179 ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this); 01180 } 01181 } 01182 if (!(format = ast_getformatbyname(this))) { 01183 ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this); 01184 errors++; 01185 continue; 01186 } 01187 01188 if (mask) { 01189 if (allowing) 01190 *mask |= format; 01191 else 01192 *mask &= ~format; 01193 } 01194 01195 /* Set up a preference list for audio. Do not include video in preferences 01196 since we can not transcode video and have to use whatever is offered 01197 */ 01198 if (pref && (format & AST_FORMAT_AUDIO_MASK)) { 01199 if (strcasecmp(this, "all")) { 01200 if (allowing) { 01201 ast_codec_pref_append(pref, format); 01202 ast_codec_pref_setsize(pref, format, framems); 01203 } 01204 else 01205 ast_codec_pref_remove(pref, format); 01206 } else if (!allowing) { 01207 memset(pref, 0, sizeof(*pref)); 01208 } 01209 } 01210 } 01211 return errors; 01212 } 01213 01214 static int g723_len(unsigned char buf) 01215 { 01216 enum frame_type type = buf & TYPE_MASK; 01217 01218 switch(type) { 01219 case TYPE_DONTSEND: 01220 return 0; 01221 break; 01222 case TYPE_SILENCE: 01223 return 4; 01224 break; 01225 case TYPE_HIGH: 01226 return 24; 01227 break; 01228 case TYPE_LOW: 01229 return 20; 01230 break; 01231 default: 01232 ast_log(LOG_WARNING, "Badly encoded frame (%d)\n", type); 01233 } 01234 return -1; 01235 } 01236 01237 static int g723_samples(unsigned char *buf, int maxlen) 01238 { 01239 int pos = 0; 01240 int samples = 0; 01241 int res; 01242 while(pos < maxlen) { 01243 res = g723_len(buf[pos]); 01244 if (res <= 0) 01245 break; 01246 samples += 240; 01247 pos += res; 01248 } 01249 return samples; 01250 } 01251 01252 static unsigned char get_n_bits_at(unsigned char *data, int n, int bit) 01253 { 01254 int byte = bit / 8; /* byte containing first bit */ 01255 int rem = 8 - (bit % 8); /* remaining bits in first byte */ 01256 unsigned char ret = 0; 01257 01258 if (n <= 0 || n > 8) 01259 return 0; 01260 01261 if (rem < n) { 01262 ret = (data[byte] << (n - rem)); 01263 ret |= (data[byte + 1] >> (8 - n + rem)); 01264 } else { 01265 ret = (data[byte] >> (rem - n)); 01266 } 01267 01268 return (ret & (0xff >> (8 - n))); 01269 } 01270 01271 static int speex_get_wb_sz_at(unsigned char *data, int len, int bit) 01272 { 01273 static int SpeexWBSubModeSz[] = { 01274 0, 36, 112, 192, 01275 352, 0, 0, 0 }; 01276 int off = bit; 01277 unsigned char c; 01278 01279 /* skip up to two wideband frames */ 01280 if (((len * 8 - off) >= 5) && 01281 get_n_bits_at(data, 1, off)) { 01282 c = get_n_bits_at(data, 3, off + 1); 01283 off += SpeexWBSubModeSz[c]; 01284 01285 if (((len * 8 - off) >= 5) && 01286 get_n_bits_at(data, 1, off)) { 01287 c = get_n_bits_at(data, 3, off + 1); 01288 off += SpeexWBSubModeSz[c]; 01289 01290 if (((len * 8 - off) >= 5) && 01291 get_n_bits_at(data, 1, off)) { 01292 ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n"); 01293 return -1; 01294 } 01295 } 01296 01297 } 01298 return off - bit; 01299 } 01300 01301 static int speex_samples(unsigned char *data, int len) 01302 { 01303 static int SpeexSubModeSz[] = { 01304 5, 43, 119, 160, 01305 220, 300, 364, 492, 01306 79, 0, 0, 0, 01307 0, 0, 0, 0 }; 01308 static int SpeexInBandSz[] = { 01309 1, 1, 4, 4, 01310 4, 4, 4, 4, 01311 8, 8, 16, 16, 01312 32, 32, 64, 64 }; 01313 int bit = 0; 01314 int cnt = 0; 01315 int off; 01316 unsigned char c; 01317 01318 while ((len * 8 - bit) >= 5) { 01319 /* skip wideband frames */ 01320 off = speex_get_wb_sz_at(data, len, bit); 01321 if (off < 0) { 01322 ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n"); 01323 break; 01324 } 01325 bit += off; 01326 01327 if ((len * 8 - bit) < 5) { 01328 ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n"); 01329 break; 01330 } 01331 01332 /* get control bits */ 01333 c = get_n_bits_at(data, 5, bit); 01334 bit += 5; 01335 01336 if (c == 15) { 01337 /* terminator */ 01338 break; 01339 } else if (c == 14) { 01340 /* in-band signal; next 4 bits contain signal id */ 01341 c = get_n_bits_at(data, 4, bit); 01342 bit += 4; 01343 bit += SpeexInBandSz[c]; 01344 } else if (c == 13) { 01345 /* user in-band; next 5 bits contain msg len */ 01346 c = get_n_bits_at(data, 5, bit); 01347 bit += 5; 01348 bit += c * 8; 01349 } else if (c > 8) { 01350 /* unknown */ 01351 break; 01352 } else { 01353 /* skip number bits for submode (less the 5 control bits) */ 01354 bit += SpeexSubModeSz[c] - 5; 01355 cnt += 160; /* new frame */ 01356 } 01357 } 01358 return cnt; 01359 } 01360 01361 int ast_codec_get_samples(struct ast_frame *f) 01362 { 01363 int samples=0; 01364 switch(f->subclass) { 01365 case AST_FORMAT_SPEEX: 01366 samples = speex_samples(f->data, f->datalen); 01367 break; 01368 case AST_FORMAT_G723_1: 01369 samples = g723_samples(f->data, f->datalen); 01370 break; 01371 case AST_FORMAT_ILBC: 01372 samples = 240 * (f->datalen / 50); 01373 break; 01374 case AST_FORMAT_GSM: 01375 samples = 160 * (f->datalen / 33); 01376 break; 01377 case AST_FORMAT_G729A: 01378 samples = f->datalen * 8; 01379 break; 01380 case AST_FORMAT_SLINEAR: 01381 samples = f->datalen / 2; 01382 break; 01383 case AST_FORMAT_LPC10: 01384 /* assumes that the RTP packet contains one LPC10 frame */ 01385 samples = 22 * 8; 01386 samples += (((char *)(f->data))[7] & 0x1) * 8; 01387 break; 01388 case AST_FORMAT_ULAW: 01389 case AST_FORMAT_ALAW: 01390 case AST_FORMAT_G722: 01391 samples = f->datalen; 01392 break; 01393 case AST_FORMAT_ADPCM: 01394 case AST_FORMAT_G726: 01395 case AST_FORMAT_G726_AAL2: 01396 samples = f->datalen * 2; 01397 break; 01398 default: 01399 ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass)); 01400 } 01401 return samples; 01402 } 01403 01404 int ast_codec_get_len(int format, int samples) 01405 { 01406 int len = 0; 01407 01408 /* XXX Still need speex, g723, and lpc10 XXX */ 01409 switch(format) { 01410 case AST_FORMAT_G723_1: 01411 len = (samples / 240) * 20; 01412 break; 01413 case AST_FORMAT_ILBC: 01414 len = (samples / 240) * 50; 01415 break; 01416 case AST_FORMAT_GSM: 01417 len = (samples / 160) * 33; 01418 break; 01419 case AST_FORMAT_G729A: 01420 len = samples / 8; 01421 break; 01422 case AST_FORMAT_SLINEAR: 01423 len = samples * 2; 01424 break; 01425 case AST_FORMAT_ULAW: 01426 case AST_FORMAT_ALAW: 01427 len = samples; 01428 break; 01429 case AST_FORMAT_ADPCM: 01430 case AST_FORMAT_G726: 01431 case AST_FORMAT_G726_AAL2: 01432 len = samples / 2; 01433 break; 01434 default: 01435 ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format)); 01436 } 01437 01438 return len; 01439 } 01440 01441 int ast_frame_adjust_volume(struct ast_frame *f, int adjustment) 01442 { 01443 int count; 01444 short *fdata = f->data; 01445 short adjust_value = abs(adjustment); 01446 01447 if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR)) 01448 return -1; 01449 01450 if (!adjustment) 01451 return 0; 01452 01453 for (count = 0; count < f->samples; count++) { 01454 if (adjustment > 0) { 01455 ast_slinear_saturated_multiply(&fdata[count], &adjust_value); 01456 } else if (adjustment < 0) { 01457 ast_slinear_saturated_divide(&fdata[count], &adjust_value); 01458 } 01459 } 01460 01461 return 0; 01462 } 01463 01464 int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2) 01465 { 01466 int count; 01467 short *data1, *data2; 01468 01469 if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass != AST_FORMAT_SLINEAR)) 01470 return -1; 01471 01472 if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR)) 01473 return -1; 01474 01475 if (f1->samples != f2->samples) 01476 return -1; 01477 01478 for (count = 0, data1 = f1->data, data2 = f2->data; 01479 count < f1->samples; 01480 count++, data1++, data2++) 01481 ast_slinear_saturated_add(data1, data2); 01482 01483 return 0; 01484 }