diff options
Diffstat (limited to 'main/frame.c')
-rw-r--r-- | main/frame.c | 583 |
1 files changed, 29 insertions, 554 deletions
diff --git a/main/frame.c b/main/frame.c index 76ea3f66c..64af88237 100644 --- a/main/frame.c +++ b/main/frame.c @@ -34,6 +34,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") #include "asterisk/_private.h" #include "asterisk/lock.h" #include "asterisk/frame.h" +#include "asterisk/format_cache.h" #include "asterisk/channel.h" #include "asterisk/cli.h" #include "asterisk/term.h" @@ -71,199 +72,8 @@ struct ast_frame_cache { }; #endif -#define SMOOTHER_SIZE 8000 - -enum frame_type { - TYPE_HIGH, /* 0x0 */ - TYPE_LOW, /* 0x1 */ - TYPE_SILENCE, /* 0x2 */ - TYPE_DONTSEND /* 0x3 */ -}; - -#define TYPE_MASK 0x3 - -struct ast_smoother { - int size; - struct ast_format format; - int flags; - float samplesperbyte; - unsigned int opt_needs_swap:1; - struct ast_frame f; - struct timeval delivery; - char data[SMOOTHER_SIZE]; - char framedata[SMOOTHER_SIZE + AST_FRIENDLY_OFFSET]; - struct ast_frame *opt; - int len; -}; - struct ast_frame ast_null_frame = { AST_FRAME_NULL, }; -static int smoother_frame_feed(struct ast_smoother *s, struct ast_frame *f, int swap) -{ - if (s->flags & AST_SMOOTHER_FLAG_G729) { - if (s->len % 10) { - ast_log(LOG_NOTICE, "Dropping extra frame of G.729 since we already have a VAD frame at the end\n"); - return 0; - } - } - if (swap) { - ast_swapcopy_samples(s->data + s->len, f->data.ptr, f->samples); - } else { - memcpy(s->data + s->len, f->data.ptr, f->datalen); - } - /* If either side is empty, reset the delivery time */ - if (!s->len || ast_tvzero(f->delivery) || ast_tvzero(s->delivery)) { /* XXX really ? */ - s->delivery = f->delivery; - } - s->len += f->datalen; - - return 0; -} - -void ast_smoother_reset(struct ast_smoother *s, int bytes) -{ - memset(s, 0, sizeof(*s)); - s->size = bytes; -} - -void ast_smoother_reconfigure(struct ast_smoother *s, int bytes) -{ - /* if there is no change, then nothing to do */ - if (s->size == bytes) { - return; - } - /* set the new desired output size */ - s->size = bytes; - /* if there is no 'optimized' frame in the smoother, - * then there is nothing left to do - */ - if (!s->opt) { - return; - } - /* there is an 'optimized' frame here at the old size, - * but it must now be put into the buffer so the data - * can be extracted at the new size - */ - smoother_frame_feed(s, s->opt, s->opt_needs_swap); - s->opt = NULL; -} - -struct ast_smoother *ast_smoother_new(int size) -{ - struct ast_smoother *s; - if (size < 1) - return NULL; - if ((s = ast_malloc(sizeof(*s)))) - ast_smoother_reset(s, size); - return s; -} - -int ast_smoother_get_flags(struct ast_smoother *s) -{ - return s->flags; -} - -void ast_smoother_set_flags(struct ast_smoother *s, int flags) -{ - s->flags = flags; -} - -int ast_smoother_test_flag(struct ast_smoother *s, int flag) -{ - return (s->flags & flag); -} - -int __ast_smoother_feed(struct ast_smoother *s, struct ast_frame *f, int swap) -{ - if (f->frametype != AST_FRAME_VOICE) { - ast_log(LOG_WARNING, "Huh? Can't smooth a non-voice frame!\n"); - return -1; - } - if (!s->format.id) { - ast_format_copy(&s->format, &f->subclass.format); - s->samplesperbyte = (float)f->samples / (float)f->datalen; - } else if (ast_format_cmp(&s->format, &f->subclass.format) == AST_FORMAT_CMP_NOT_EQUAL) { - ast_log(LOG_WARNING, "Smoother was working on %s format frames, now trying to feed %s?\n", - ast_getformatname(&s->format), ast_getformatname(&f->subclass.format)); - return -1; - } - if (s->len + f->datalen > SMOOTHER_SIZE) { - ast_log(LOG_WARNING, "Out of smoother space\n"); - return -1; - } - if (((f->datalen == s->size) || - ((f->datalen < 10) && (s->flags & AST_SMOOTHER_FLAG_G729))) && - !s->opt && - !s->len && - (f->offset >= AST_MIN_OFFSET)) { - /* Optimize by sending the frame we just got - on the next read, thus eliminating the douple - copy */ - if (swap) - ast_swapcopy_samples(f->data.ptr, f->data.ptr, f->samples); - s->opt = f; - s->opt_needs_swap = swap ? 1 : 0; - return 0; - } - - return smoother_frame_feed(s, f, swap); -} - -struct ast_frame *ast_smoother_read(struct ast_smoother *s) -{ - struct ast_frame *opt; - int len; - - /* IF we have an optimization frame, send it */ - if (s->opt) { - if (s->opt->offset < AST_FRIENDLY_OFFSET) - ast_log(LOG_WARNING, "Returning a frame of inappropriate offset (%d).\n", - s->opt->offset); - opt = s->opt; - s->opt = NULL; - return opt; - } - - /* Make sure we have enough data */ - if (s->len < s->size) { - /* Or, if this is a G.729 frame with VAD on it, send it immediately anyway */ - if (!((s->flags & AST_SMOOTHER_FLAG_G729) && (s->len % 10))) - return NULL; - } - len = s->size; - if (len > s->len) - len = s->len; - /* Make frame */ - s->f.frametype = AST_FRAME_VOICE; - ast_format_copy(&s->f.subclass.format, &s->format); - s->f.data.ptr = s->framedata + AST_FRIENDLY_OFFSET; - s->f.offset = AST_FRIENDLY_OFFSET; - s->f.datalen = len; - /* Samples will be improper given VAD, but with VAD the concept really doesn't even exist */ - s->f.samples = len * s->samplesperbyte; /* XXX rounding */ - s->f.delivery = s->delivery; - /* Fill Data */ - memcpy(s->f.data.ptr, s->data, len); - s->len -= len; - /* Move remaining data to the front if applicable */ - if (s->len) { - /* In principle this should all be fine because if we are sending - G.729 VAD, the next timestamp will take over anyawy */ - memmove(s->data, s->data + len, s->len); - if (!ast_tvzero(s->delivery)) { - /* If we have delivery time, increment it, otherwise, leave it at 0 */ - s->delivery = ast_tvadd(s->delivery, ast_samp2tv(s->f.samples, ast_format_rate(&s->format))); - } - } - /* Return frame */ - return &s->f; -} - -void ast_smoother_free(struct ast_smoother *s) -{ - ast_free(s); -} - static struct ast_frame *ast_frame_header_new(void) { struct ast_frame *f; @@ -316,9 +126,13 @@ static void __frame_free(struct ast_frame *fr, int cache) /* Cool, only the header is malloc'd, let's just cache those for now * to keep things simple... */ struct ast_frame_cache *frames; - if ((frames = ast_threadstorage_get(&frame_cache, sizeof(*frames))) && (frames->size < FRAME_CACHE_MAX_SIZE)) { + if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || + (fr->frametype == AST_FRAME_IMAGE)) { + ao2_cleanup(fr->subclass.format); + } + AST_LIST_INSERT_HEAD(&frames->list, fr, frame_list); frames->size++; return; @@ -335,7 +149,14 @@ static void __frame_free(struct ast_frame *fr, int cache) ast_free((void *) fr->src); } if (fr->mallocd & AST_MALLOCD_HDR) { + if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || + (fr->frametype == AST_FRAME_IMAGE)) { + ao2_cleanup(fr->subclass.format); + } + ast_free(fr); + } else { + fr->mallocd = 0; } } @@ -387,7 +208,12 @@ struct ast_frame *ast_frisolate(struct ast_frame *fr) return NULL; } out->frametype = fr->frametype; - ast_format_copy(&out->subclass.format, &fr->subclass.format); + if ((fr->frametype == AST_FRAME_VOICE) || (fr->frametype == AST_FRAME_VIDEO) || + (fr->frametype == AST_FRAME_IMAGE)) { + out->subclass.format = ao2_bump(fr->subclass.format); + } else { + memcpy(&out->subclass, &fr->subclass, sizeof(out->subclass)); + } out->datalen = fr->datalen; out->samples = fr->samples; out->offset = fr->offset; @@ -494,7 +320,12 @@ struct ast_frame *ast_frdup(const struct ast_frame *f) } out->frametype = f->frametype; - ast_format_copy(&out->subclass.format, &f->subclass.format); + if ((f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO) || + (f->frametype == AST_FRAME_IMAGE)) { + out->subclass.format = ao2_bump(f->subclass.format); + } else { + memcpy(&out->subclass, &f->subclass, sizeof(out->subclass)); + } out->datalen = f->datalen; out->samples = f->samples; out->delivery = f->delivery; @@ -650,7 +481,7 @@ void ast_frame_subclass2str(struct ast_frame *f, char *subclass, size_t slen, ch } break; case AST_FRAME_IMAGE: - snprintf(subclass, slen, "Image format %s\n", ast_getformatname(&f->subclass.format)); + snprintf(subclass, slen, "Image format %s\n", ast_format_get_name(f->subclass.format)); break; case AST_FRAME_HTML: switch (f->subclass.integer) { @@ -816,369 +647,13 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix) term_color(cn, name, COLOR_YELLOW, COLOR_BLACK, sizeof(cn))); } -int ast_parse_allow_disallow(struct ast_codec_pref *pref, struct ast_format_cap *cap, const char *list, int allowing) -{ - int errors = 0, framems = 0, all = 0, iter_allowing; - char *parse = NULL, *this = NULL, *psize = NULL; - struct ast_format format; - - parse = ast_strdupa(list); - while ((this = strsep(&parse, ","))) { - iter_allowing = allowing; - framems = 0; - if (*this == '!') { - this++; - iter_allowing = !allowing; - } - if ((psize = strrchr(this, ':'))) { - *psize++ = '\0'; - ast_debug(1, "Packetization for codec: %s is %s\n", this, psize); - framems = atoi(psize); - if (framems < 0) { - framems = 0; - errors++; - ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this); - } - } - all = strcasecmp(this, "all") ? 0 : 1; - - if (!all && !ast_getformatbyname(this, &format)) { - ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", iter_allowing ? "allow" : "disallow", this); - errors++; - continue; - } - - if (cap) { - if (iter_allowing) { - if (all) { - ast_format_cap_add_all(cap); - } else { - ast_format_cap_add(cap, &format); - } - } else { - if (all) { - ast_format_cap_remove_all(cap); - } else { - ast_format_cap_remove(cap, &format); - } - } - } - - if (pref) { - if (!all) { - if (iter_allowing) { - ast_codec_pref_append(pref, &format); - ast_codec_pref_setsize(pref, &format, framems); - } else { - ast_codec_pref_remove(pref, &format); - } - } else if (!iter_allowing) { - memset(pref, 0, sizeof(*pref)); - } else { - ast_codec_pref_append_all(pref); - } - } - } - return errors; -} - -static int g723_len(unsigned char buf) -{ - enum frame_type type = buf & TYPE_MASK; - - switch(type) { - case TYPE_DONTSEND: - return 0; - break; - case TYPE_SILENCE: - return 4; - break; - case TYPE_HIGH: - return 24; - break; - case TYPE_LOW: - return 20; - break; - default: - ast_log(LOG_WARNING, "Badly encoded frame (%u)\n", type); - } - return -1; -} - -static int g723_samples(unsigned char *buf, int maxlen) -{ - int pos = 0; - int samples = 0; - int res; - while(pos < maxlen) { - res = g723_len(buf[pos]); - if (res <= 0) - break; - samples += 240; - pos += res; - } - return samples; -} - -static unsigned char get_n_bits_at(unsigned char *data, int n, int bit) -{ - int byte = bit / 8; /* byte containing first bit */ - int rem = 8 - (bit % 8); /* remaining bits in first byte */ - unsigned char ret = 0; - - if (n <= 0 || n > 8) - return 0; - - if (rem < n) { - ret = (data[byte] << (n - rem)); - ret |= (data[byte + 1] >> (8 - n + rem)); - } else { - ret = (data[byte] >> (rem - n)); - } - - return (ret & (0xff >> (8 - n))); -} - -static int speex_get_wb_sz_at(unsigned char *data, int len, int bit) -{ - static const int SpeexWBSubModeSz[] = { - 4, 36, 112, 192, - 352, 0, 0, 0 }; - int off = bit; - unsigned char c; - - /* skip up to two wideband frames */ - if (((len * 8 - off) >= 5) && - get_n_bits_at(data, 1, off)) { - c = get_n_bits_at(data, 3, off + 1); - off += SpeexWBSubModeSz[c]; - - if (((len * 8 - off) >= 5) && - get_n_bits_at(data, 1, off)) { - c = get_n_bits_at(data, 3, off + 1); - off += SpeexWBSubModeSz[c]; - - if (((len * 8 - off) >= 5) && - get_n_bits_at(data, 1, off)) { - ast_log(LOG_WARNING, "Encountered corrupt speex frame; too many wideband frames in a row.\n"); - return -1; - } - } - - } - return off - bit; -} - -static int speex_samples(unsigned char *data, int len) -{ - static const int SpeexSubModeSz[] = { - 5, 43, 119, 160, - 220, 300, 364, 492, - 79, 0, 0, 0, - 0, 0, 0, 0 }; - static const int SpeexInBandSz[] = { - 1, 1, 4, 4, - 4, 4, 4, 4, - 8, 8, 16, 16, - 32, 32, 64, 64 }; - int bit = 0; - int cnt = 0; - int off; - unsigned char c; - - while ((len * 8 - bit) >= 5) { - /* skip wideband frames */ - off = speex_get_wb_sz_at(data, len, bit); - if (off < 0) { - ast_log(LOG_WARNING, "Had error while reading wideband frames for speex samples\n"); - break; - } - bit += off; - - if ((len * 8 - bit) < 5) - break; - - /* get control bits */ - c = get_n_bits_at(data, 5, bit); - bit += 5; - - if (c == 15) { - /* terminator */ - break; - } else if (c == 14) { - /* in-band signal; next 4 bits contain signal id */ - c = get_n_bits_at(data, 4, bit); - bit += 4; - bit += SpeexInBandSz[c]; - } else if (c == 13) { - /* user in-band; next 4 bits contain msg len */ - c = get_n_bits_at(data, 4, bit); - bit += 4; - /* after which it's 5-bit signal id + c bytes of data */ - bit += 5 + c * 8; - } else if (c > 8) { - /* unknown */ - ast_log(LOG_WARNING, "Unknown speex control frame %d\n", c); - break; - } else { - /* skip number bits for submode (less the 5 control bits) */ - bit += SpeexSubModeSz[c] - 5; - cnt += 160; /* new frame */ - } - } - return cnt; -} - -int ast_codec_get_samples(struct ast_frame *f) -{ - int samples = 0; - - switch (f->subclass.format.id) { - case AST_FORMAT_SPEEX: - samples = speex_samples(f->data.ptr, f->datalen); - break; - case AST_FORMAT_SPEEX16: - samples = 2 * speex_samples(f->data.ptr, f->datalen); - break; - case AST_FORMAT_SPEEX32: - samples = 4 * speex_samples(f->data.ptr, f->datalen); - break; - case AST_FORMAT_G723_1: - samples = g723_samples(f->data.ptr, f->datalen); - break; - case AST_FORMAT_ILBC: - samples = 240 * (f->datalen / 50); - break; - case AST_FORMAT_GSM: - samples = 160 * (f->datalen / 33); - break; - case AST_FORMAT_G729A: - samples = f->datalen * 8; - break; - case AST_FORMAT_SLINEAR: - case AST_FORMAT_SLINEAR16: - samples = f->datalen / 2; - break; - case AST_FORMAT_LPC10: - /* assumes that the RTP packet contains one LPC10 frame */ - samples = 22 * 8; - samples += (((char *)(f->data.ptr))[7] & 0x1) * 8; - break; - case AST_FORMAT_ULAW: - case AST_FORMAT_ALAW: - case AST_FORMAT_TESTLAW: - samples = f->datalen; - break; - case AST_FORMAT_G722: - case AST_FORMAT_ADPCM: - case AST_FORMAT_G726: - case AST_FORMAT_G726_AAL2: - samples = f->datalen * 2; - break; - case AST_FORMAT_SIREN7: - /* 16,000 samples per second at 32kbps is 4,000 bytes per second */ - samples = f->datalen * (16000 / 4000); - break; - case AST_FORMAT_SIREN14: - /* 32,000 samples per second at 48kbps is 6,000 bytes per second */ - samples = (int) f->datalen * ((float) 32000 / 6000); - break; - case AST_FORMAT_G719: - /* 48,000 samples per second at 64kbps is 8,000 bytes per second */ - samples = (int) f->datalen * ((float) 48000 / 8000); - break; - case AST_FORMAT_SILK: - if (!(ast_format_isset(&f->subclass.format, - SILK_ATTR_KEY_SAMP_RATE, - SILK_ATTR_VAL_SAMP_24KHZ, - AST_FORMAT_ATTR_END))) { - return 480; - } else if (!(ast_format_isset(&f->subclass.format, - SILK_ATTR_KEY_SAMP_RATE, - SILK_ATTR_VAL_SAMP_16KHZ, - AST_FORMAT_ATTR_END))) { - return 320; - } else if (!(ast_format_isset(&f->subclass.format, - SILK_ATTR_KEY_SAMP_RATE, - SILK_ATTR_VAL_SAMP_12KHZ, - AST_FORMAT_ATTR_END))) { - return 240; - } else { - return 160; - } - case AST_FORMAT_CELT: - /* TODO This assumes 20ms delivery right now, which is incorrect */ - samples = ast_format_rate(&f->subclass.format) / 50; - break; - case AST_FORMAT_OPUS: - /* TODO This assumes 20ms delivery right now, which is incorrect */ - samples = 960; - break; - default: - ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(&f->subclass.format)); - } - return samples; -} - -int ast_codec_get_len(struct ast_format *format, int samples) -{ - int len = 0; - - /* XXX Still need speex, and lpc10 XXX */ - switch(format->id) { - case AST_FORMAT_G723_1: - len = (samples / 240) * 20; - break; - case AST_FORMAT_ILBC: - len = (samples / 240) * 50; - break; - case AST_FORMAT_GSM: - len = (samples / 160) * 33; - break; - case AST_FORMAT_G729A: - len = samples / 8; - break; - case AST_FORMAT_SLINEAR: - case AST_FORMAT_SLINEAR16: - len = samples * 2; - break; - case AST_FORMAT_ULAW: - case AST_FORMAT_ALAW: - case AST_FORMAT_TESTLAW: - len = samples; - break; - case AST_FORMAT_G722: - case AST_FORMAT_ADPCM: - case AST_FORMAT_G726: - case AST_FORMAT_G726_AAL2: - len = samples / 2; - break; - case AST_FORMAT_SIREN7: - /* 16,000 samples per second at 32kbps is 4,000 bytes per second */ - len = samples / (16000 / 4000); - break; - case AST_FORMAT_SIREN14: - /* 32,000 samples per second at 48kbps is 6,000 bytes per second */ - len = (int) samples / ((float) 32000 / 6000); - break; - case AST_FORMAT_G719: - /* 48,000 samples per second at 64kbps is 8,000 bytes per second */ - len = (int) samples / ((float) 48000 / 8000); - break; - default: - ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format)); - } - - return len; -} - int ast_frame_adjust_volume(struct ast_frame *f, int adjustment) { int count; short *fdata = f->data.ptr; short adjust_value = abs(adjustment); - if ((f->frametype != AST_FRAME_VOICE) || !(ast_format_is_slinear(&f->subclass.format))) { + if ((f->frametype != AST_FRAME_VOICE) || !(ast_format_cache_is_slinear(f->subclass.format))) { return -1; } @@ -1202,10 +677,10 @@ int ast_frame_slinear_sum(struct ast_frame *f1, struct ast_frame *f2) int count; short *data1, *data2; - if ((f1->frametype != AST_FRAME_VOICE) || (f1->subclass.format.id != AST_FORMAT_SLINEAR)) + if ((f1->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f1->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL)) return -1; - if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass.format.id != AST_FORMAT_SLINEAR)) + if ((f2->frametype != AST_FRAME_VOICE) || (ast_format_cmp(f2->subclass.format, ast_format_slin) != AST_FORMAT_CMP_NOT_EQUAL)) return -1; if (f1->samples != f2->samples) |