📄 codec_speex.c
字号:
/*
* iaxclient: a portable telephony toolkit
*
* Copyright (C) 2003-2004, Horizon Wimba, Inc.
*
* Steve Kann <stevek@stevek.com>
*
* This program is free software, distributed under the terms of
* the GNU Lesser (Library) General Public License
*/
#include "codec_speex.h"
#include "iaxclient_lib.h"
#include "speex/speex.h"
/* see codec_speex.h for termination mode definition; Zero is the "asterisk-compatible" method --
* generally, any other choice will not be compatible with established practice */
struct state {
void *state;
int frame_size;
int termination_mode;
SpeexBits bits;
};
static void destroy ( struct iaxc_audio_codec *c) {
struct state * encstate = (struct state *) c->encstate;
struct state * decstate = (struct state *) c->decstate;
speex_bits_destroy(&encstate->bits);
speex_bits_destroy(&decstate->bits);
speex_encoder_destroy(encstate->state);
speex_decoder_destroy(decstate->state);
free(c->encstate);
free(c->decstate);
free(c);
}
static int decode ( struct iaxc_audio_codec *c,
int *inlen, unsigned char *in, int *outlen, short *out ) {
struct state * decstate = (struct state *) c->decstate;
int ret =0;
int bits_left = 0;
int bits_read = 0;
int start_bits = 0;
if(*inlen == 0) {
//return 0;
//fprintf(stderr, "Speex Interpolate\n");
speex_decode_int(decstate->state, NULL, out);
*outlen -= decstate->frame_size;
return 0;
}
/* XXX if the input contains more than we can read, we lose here */
speex_bits_read_from(&decstate->bits, (char *) in, *inlen);
*inlen = 0;
start_bits = speex_bits_remaining(&decstate->bits);
while(speex_bits_remaining(&decstate->bits) && (*outlen >= decstate->frame_size))
{
ret = speex_decode_int(decstate->state, &decstate->bits, out);
// * from speex/speex.h, speex_decode returns:
// * @return return status (0 for no error, -1 for end of stream, -2 other)
if (ret == 0) {
//fprintf(stderr, "decode: inlen=%d outlen=%d\n", *inlen, *outlen);
/* one frame of output */
*outlen -= decstate->frame_size;
out += decstate->frame_size;
if(decstate->termination_mode == IAXC_SPEEX_TERMINATION_NONE) {
bits_left = speex_bits_remaining(&decstate->bits) % 8;
if(bits_left)
speex_bits_advance(&decstate->bits, bits_left);
}
} else if (ret == -1) {
/* at end of stream, or just a terminator */
bits_left = speex_bits_remaining(&decstate->bits) % 8;
if(bits_left >= 5)
speex_bits_advance(&decstate->bits, bits_left);
else
break;
} else {
/* maybe there's not a whole frame somehow? */
fprintf(stderr, "decode_int returned non-zero => %d\n",ret);
break;
}
}
return 0;
}
static int encode ( struct iaxc_audio_codec *c,
int *inlen, short *in, int *outlen, unsigned char *out ) {
int bytes;
//int bitrate;
struct state * encstate = (struct state *) c->encstate;
/* need to encode minimum of encstate->frame_size samples */
if(encstate->termination_mode) {
/* abnormal termination modes: separate frames, with or without termination in-between */
while(*inlen >= encstate->frame_size)
{
/* reset and encode*/
speex_bits_reset(&encstate->bits);
speex_encode_int(encstate->state, in, &encstate->bits);
/* add terminator */
if(encstate->termination_mode != IAXC_SPEEX_TERMINATION_NONE)
speex_bits_pack(&encstate->bits, 15, 5);
/* write to output */
/* can an error happen here? no bytes? */
bytes = speex_bits_write(&encstate->bits, (char *) out, *outlen);
//fprintf(stderr, "encode wrote %d bytes, outlen was %d\n", bytes, *outlen);
/* advance pointers to input and output */
*inlen -= encstate->frame_size;
in += encstate->frame_size;
*outlen -= bytes;
out += bytes;
}
} else {
/* only add terminator at end of bits */
speex_bits_reset(&encstate->bits);
/* need to encode minimum of encstate->frame_size samples */
while(*inlen >= encstate->frame_size) {
//fprintf(stderr, "encode: inlen=%d outlen=%d\n", *inlen, *outlen);
speex_encode_int(encstate->state, in, &encstate->bits);
*inlen -= encstate->frame_size;
in += encstate->frame_size;
}
/* add terminator */
speex_bits_pack(&encstate->bits, 15, 5);
bytes = speex_bits_write(&encstate->bits, (char *) out, *outlen);
/* can an error happen here? no bytes? */
*outlen -= bytes;
}
return 0;
}
struct iaxc_audio_codec *iaxc_audio_codec_speex_new(struct iaxc_speex_settings *set) {
struct state * encstate;
struct state * decstate;
struct iaxc_audio_codec *c = calloc(sizeof(struct iaxc_audio_codec),1);
const SpeexMode *sm;
if(!c) return c;
strcpy(c->name,"speex");
c->format = IAXC_FORMAT_SPEEX;
c->encode = encode;
c->decode = decode;
c->destroy = destroy;
c->encstate = calloc(sizeof(struct state),1);
c->decstate = calloc(sizeof(struct state),1);
/* leaks a bit on no-memory */
if(!(c->encstate && c->decstate))
return NULL;
encstate = (struct state *) c->encstate;
decstate = (struct state *) c->decstate;
sm = set->mode;
if(!sm) sm = &speex_nb_mode;
encstate->state = speex_encoder_init(sm);
decstate->state = speex_decoder_init(sm);
speex_bits_init(&encstate->bits);
speex_bits_init(&decstate->bits);
speex_bits_reset(&encstate->bits);
speex_bits_reset(&decstate->bits);
speex_decoder_ctl(decstate->state, SPEEX_SET_ENH, &set->decode_enhance);
speex_encoder_ctl(encstate->state, SPEEX_SET_COMPLEXITY, &set->complexity);
if(set->quality >= 0) {
if(set->vbr) {
speex_encoder_ctl(encstate->state, SPEEX_SET_VBR_QUALITY, &set->quality);
} else {
int quality = set->quality;
speex_encoder_ctl(encstate->state, SPEEX_SET_QUALITY, &quality);
}
}
if(set->bitrate >= 0)
speex_encoder_ctl(encstate->state, SPEEX_SET_BITRATE, &set->bitrate);
if(set->vbr)
speex_encoder_ctl(encstate->state, SPEEX_SET_VBR, &set->vbr);
if(set->abr)
speex_encoder_ctl(encstate->state, SPEEX_SET_ABR, &set->abr);
/* set up frame sizes (normally, this is 20ms worth) */
speex_encoder_ctl(encstate->state,SPEEX_GET_FRAME_SIZE,&encstate->frame_size);
speex_encoder_ctl(decstate->state,SPEEX_GET_FRAME_SIZE,&decstate->frame_size);
/* XXX: for some reason, with narrowband, we get 0 for decstate sometimes? */
if(!decstate->frame_size) decstate->frame_size = 160;
if(!encstate->frame_size) encstate->frame_size = 160;
c->minimum_frame_size = 160;
if(encstate->frame_size > c->minimum_frame_size) c->minimum_frame_size = encstate->frame_size;
if(decstate->frame_size > c->minimum_frame_size) c->minimum_frame_size = decstate->frame_size;
encstate->termination_mode = set->termination_mode;
decstate->termination_mode = set->termination_mode;
if(!(encstate->state && decstate->state))
return NULL;
OutputDebugString(L"Creating Speex Codec");
return c;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -