Skip to content
Snippets Groups Projects
frame.c 39.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 		strncat(buf, ")", total_len - 1); /* safe */
    
    int ast_codec_pref_index(struct ast_codec_pref *pref, int idx)
    
    	if ((idx >= 0) && (idx < sizeof(pref->order))) {
    		slot = pref->order[idx];
    
    	return slot ? AST_FORMAT_LIST[slot - 1].bits : 0;
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief Remove codec from pref list */
    
    void ast_codec_pref_remove(struct ast_codec_pref *pref, int format)
    {
    	struct ast_codec_pref oldorder;
    
    	memcpy(&oldorder, pref, sizeof(oldorder));
    	memset(pref, 0, sizeof(*pref));
    
    	for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
    
    		size = oldorder.framing[x];
    
    		if (AST_FORMAT_LIST[slot-1].bits != format) {
    
    			pref->order[y] = slot;
    			pref->framing[y++] = size;
    		}
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief Append codec to list */
    
    int ast_codec_pref_append(struct ast_codec_pref *pref, int format)
    {
    
    	int x, newindex = 0;
    
    	for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
    
    		if (AST_FORMAT_LIST[x].bits == format) {
    
    		for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
    
    /*! \brief Prepend codec to list */
    void ast_codec_pref_prepend(struct ast_codec_pref *pref, int format, int only_if_existing)
    {
    	int x, newindex = 0;
    
    	/* First step is to get the codecs "index number" */
    	for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
    		if (AST_FORMAT_LIST[x].bits == format) {
    			newindex = x + 1;
    			break;
    		}
    	}
    	/* Done if its unknown */
    	if (!newindex)
    		return;
    
    	/* Now find any existing occurrence, or the end */
    	for (x = 0; x < 32; x++) {
    		if (!pref->order[x] || pref->order[x] == newindex)
    			break;
    	}
    
    	if (only_if_existing && !pref->order[x])
    		return;
    
    	/* Move down to make space to insert - either all the way to the end,
    	   or as far as the existing location (which will be overwritten) */
    	for (; x > 0; x--) {
    		pref->order[x] = pref->order[x - 1];
    		pref->framing[x] = pref->framing[x - 1];
    	}
    
    	/* And insert the new entry */
    	pref->order[0] = newindex;
    	pref->framing[0] = 0; /* ? */
    }
    
    /*! \brief Set packet size for codec */
    int ast_codec_pref_setsize(struct ast_codec_pref *pref, int format, int framems)
    {
    
    	for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
    
    		if (AST_FORMAT_LIST[x].bits == format) {
    
    		framems = AST_FORMAT_LIST[idx].def_ms;
    
    	if (AST_FORMAT_LIST[idx].inc_ms && framems % AST_FORMAT_LIST[idx].inc_ms) /* avoid division by zero */
    		framems -= framems % AST_FORMAT_LIST[idx].inc_ms;
    
    	if (framems < AST_FORMAT_LIST[idx].min_ms)
    		framems = AST_FORMAT_LIST[idx].min_ms;
    
    	if (framems > AST_FORMAT_LIST[idx].max_ms)
    		framems = AST_FORMAT_LIST[idx].max_ms;
    
    	for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
    
    		if (pref->order[x] == (idx + 1)) {
    
    			pref->framing[x] = framems;
    			break;
    		}
    	}
    
    	return x;
    }
    
    /*! \brief Get packet size for codec */
    struct ast_format_list ast_codec_pref_getsize(struct ast_codec_pref *pref, int format)
    {
    
    	struct ast_format_list fmt = { 0, };
    
    	for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
    
    		if (AST_FORMAT_LIST[x].bits == format) {
    
    	for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
    
    		if (pref->order[x] == (idx + 1)) {
    
    			framems = pref->framing[x];
    			break;
    		}
    	}
    
    	/* size validation */
    
    		framems = AST_FORMAT_LIST[idx].def_ms;
    
    	if (AST_FORMAT_LIST[idx].inc_ms && framems % AST_FORMAT_LIST[idx].inc_ms) /* avoid division by zero */
    		framems -= framems % AST_FORMAT_LIST[idx].inc_ms;
    
    	if (framems < AST_FORMAT_LIST[idx].min_ms)
    		framems = AST_FORMAT_LIST[idx].min_ms;
    
    	if (framems > AST_FORMAT_LIST[idx].max_ms)
    		framems = AST_FORMAT_LIST[idx].max_ms;
    
    Olle Johansson's avatar
    Olle Johansson committed
    /*! \brief Pick a codec */
    
    int ast_codec_choose(struct ast_codec_pref *pref, int formats, int find_best)
    {
    
    	for (x = 0; x < ARRAY_LEN(AST_FORMAT_LIST); x++) {
    
    Olle Johansson's avatar
    Olle Johansson committed
    		if (!slot)
    
    Olle Johansson's avatar
    Olle Johansson committed
    		if (formats & AST_FORMAT_LIST[slot-1].bits) {
    
    	ast_debug(4, "Could not find preferred codec - %s\n", find_best ? "Going for the best codec" : "Returning zero codec");
    
       	return find_best ? ast_best_codec(formats) : 0;
    }
    
    
    int ast_parse_allow_disallow(struct ast_codec_pref *pref, int *mask, const char *list, int allowing) 
    
    Joshua Colp's avatar
    Joshua Colp committed
    	char *parse = NULL, *this = NULL, *psize = NULL;
    	int format = 0, framems = 0;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    
    	parse = ast_strdupa(list);
    	while ((this = strsep(&parse, ","))) {
    
    		framems = 0;
    		if ((psize = strrchr(this, ':'))) {
    
    Joshua Colp's avatar
    Joshua Colp committed
    			*psize++ = '\0';
    
    			ast_debug(1, "Packetization for codec: %s is %s\n", this, psize);
    
    Joshua Colp's avatar
    Joshua Colp committed
    			framems = atoi(psize);
    
    				errors++;
    				ast_log(LOG_WARNING, "Bad packetization value for codec %s\n", this);
    			}
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		if (!(format = ast_getformatbyname(this))) {
    			ast_log(LOG_WARNING, "Cannot %s unknown format '%s'\n", allowing ? "allow" : "disallow", this);
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			continue;
    		}
    
    		if (mask) {
    			if (allowing)
    				*mask |= format;
    			else
    				*mask &= ~format;
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    
    
    		/* Set up a preference list for audio. Do not include video in preferences 
    		   since we can not transcode video and have to use whatever is offered
    		 */
    		if (pref && (format & AST_FORMAT_AUDIO_MASK)) {
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    			if (strcasecmp(this, "all")) {
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    					ast_codec_pref_append(pref, format);
    
    					ast_codec_pref_setsize(pref, format, framems);
    				}
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    					ast_codec_pref_remove(pref, format);
    			} else if (!allowing) {
    				memset(pref, 0, sizeof(*pref));
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    		}
    
    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 (%d)\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 int SpeexWBSubModeSz[] = {
    		0, 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 int SpeexSubModeSz[] = {
    
    Tilghman Lesher's avatar
    Tilghman Lesher committed
    		5, 43, 119, 160,
    
    		220, 300, 364, 492, 
    		79, 0, 0, 0,
    		0, 0, 0, 0 };
    	static int SpeexInBandSz[] = { 
    		1, 1, 4, 4,
    		4, 4, 4, 4,
    		8, 8, 16, 16,
    		32, 32, 64, 64 };
    	int bit = 0;
    	int cnt = 0;
    
    	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) {
    			ast_log(LOG_WARNING, "Not enough bits remaining after wide band for speex samples.\n");
    			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 5 bits contain msg len */
    			c = get_n_bits_at(data, 5, bit);
    			bit += 5;
    			bit += c * 8;
    		} else if (c > 8) {
    			/* unknown */
    			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) {
    	case AST_FORMAT_SPEEX:
    
    		samples = 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 += (((char *)(f->data.ptr))[7] & 0x1) * 8;
    
    		break;
    	case AST_FORMAT_ULAW:
    	case AST_FORMAT_ALAW:
    		samples = f->datalen;
    		break;
    
    	case AST_FORMAT_ADPCM:
    	case AST_FORMAT_G726:
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	case AST_FORMAT_G726_AAL2:
    
    		samples = f->datalen * 2;
    		break;
    	default:
    		ast_log(LOG_WARNING, "Unable to calculate samples for format %s\n", ast_getformatname(f->subclass));
    	}
    	return samples;
    }
    
    int ast_codec_get_len(int format, int samples)
    {
    	int len = 0;
    
    	/* XXX Still need speex, g723, and lpc10 XXX */	
    	switch(format) {
    
    	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:
    		len = samples;
    		break;
    
    	case AST_FORMAT_ADPCM:
    	case AST_FORMAT_G726:
    
    Kevin P. Fleming's avatar
    Kevin P. Fleming committed
    	case AST_FORMAT_G726_AAL2:
    
    		len = samples / 2;
    		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;
    
    
    	if ((f->frametype != AST_FRAME_VOICE) || (f->subclass != AST_FORMAT_SLINEAR))
    		return -1;
    
    
    	for (count = 0; count < f->samples; count++) {
    		if (adjustment > 0) {
    
    			ast_slinear_saturated_multiply(&fdata[count], &adjust_value);
    
    			ast_slinear_saturated_divide(&fdata[count], &adjust_value);
    
    
    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 != AST_FORMAT_SLINEAR))
    		return -1;
    
    	if ((f2->frametype != AST_FRAME_VOICE) || (f2->subclass != AST_FORMAT_SLINEAR))
    		return -1;
    
    	if (f1->samples != f2->samples)
    		return -1;
    
    
    	for (count = 0, data1 = f1->data.ptr, data2 = f2->data.ptr;
    
    	     count < f1->samples;
    	     count++, data1++, data2++)