codec_speex.c

00001 /*
00002  * iaxclient: a cross-platform IAX softphone library
00003  *
00004  * Copyrights:
00005  * Copyright (C) 2003-2004, Horizon Wimba, Inc.
00006  * Copyright (C) 2007, Wimba, Inc.
00007  *
00008  * Contributors:
00009  * Steve Kann <stevek@stevek.com>
00010  *
00011  * This program is free software, distributed under the terms of
00012  * the GNU Lesser (Library) General Public License.
00013  */
00014 
00015 #include "codec_speex.h"
00016 #include "iaxclient_lib.h"
00017 #include "speex/speex.h"
00018 
00019 struct State
00020 {
00021         void *state;
00022         int frame_size;
00023         SpeexBits bits;
00024 };
00025 
00026 
00027 static void destroy ( struct iaxc_audio_codec *c)
00028 {
00029         struct State * encstate = (struct State *) c->encstate;
00030         struct State * decstate = (struct State *) c->decstate;
00031 
00032         speex_bits_destroy(&encstate->bits);
00033         speex_bits_destroy(&decstate->bits);
00034         speex_encoder_destroy(encstate->state);
00035         speex_decoder_destroy(decstate->state);
00036 
00037         free(c->encstate);
00038         free(c->decstate);
00039 
00040         free(c);
00041 }
00042 
00043 
00044 static int decode( struct iaxc_audio_codec *c,
00045                 int *inlen, unsigned char *in, int *outlen, short *out )
00046 {
00047         struct State * decstate = (struct State *) c->decstate;
00048 
00049         if ( *inlen == 0 )
00050         {
00051                 speex_decode_int(decstate->state, NULL, out);
00052                 *outlen -= decstate->frame_size;
00053                 return 0;
00054         }
00055 
00056         speex_bits_read_from(&decstate->bits, (char *) in, *inlen);
00057         *inlen = 0;
00058 
00059         while ( speex_bits_remaining(&decstate->bits) &&
00060                         *outlen >= decstate->frame_size )
00061         {
00062                 int ret = speex_decode_int(decstate->state, &decstate->bits, out);
00063 
00064                 // from speex/speex.h, speex_decode returns:
00065                 // @return return status (0 for no error, -1 for end of stream, -2 other)
00066                 if (ret == 0)
00067                 {
00068                         /* one frame of output */
00069                         *outlen -= decstate->frame_size;
00070                         out += decstate->frame_size;
00071                 } else if (ret == -1)
00072                 {
00073                         /* at end of stream, or just a terminator */
00074                         int bits_left = speex_bits_remaining(&decstate->bits) % 8;
00075                         if(bits_left >= 5)
00076                                 speex_bits_advance(&decstate->bits, bits_left);
00077                         else
00078                                 break;
00079                 } else
00080                 {
00081                         /* maybe there's not a whole frame somehow? */
00082                         fprintf(stderr, "decode_int returned non-zero => %d\n",ret);
00083                         break;
00084                 }
00085         }
00086         return 0;
00087 }
00088 
00089 static int encode( struct iaxc_audio_codec *c,
00090                 int *inlen, short *in, int *outlen, unsigned char *out )
00091 {
00092         int bytes;
00093         struct State * encstate = (struct State *) c->encstate;
00094 
00095         /* need to encode minimum of encstate->frame_size samples */
00096 
00097         /*  only add terminator at end of bits */
00098         speex_bits_reset(&encstate->bits);
00099 
00100         /* need to encode minimum of encstate->frame_size samples */
00101         while(*inlen >= encstate->frame_size)
00102         {
00103                 //fprintf(stderr, "encode: inlen=%d outlen=%d\n", *inlen, *outlen);
00104                 speex_encode_int(encstate->state, in, &encstate->bits);
00105                 *inlen -= encstate->frame_size;
00106                 in += encstate->frame_size;
00107         }
00108 
00109         /* add terminator */
00110         speex_bits_pack(&encstate->bits, 15, 5);
00111 
00112         bytes = speex_bits_write(&encstate->bits, (char *) out, *outlen);
00113 
00114         /* can an error happen here?  no bytes? */
00115         *outlen -= bytes;
00116 
00117         return 0;
00118 }
00119 
00120 struct iaxc_audio_codec *codec_audio_speex_new(struct iaxc_speex_settings *set)
00121 {
00122         struct State * encstate;
00123         struct State * decstate;
00124         struct iaxc_audio_codec *c = (struct iaxc_audio_codec *)calloc(sizeof(struct iaxc_audio_codec),1);
00125         const SpeexMode *sm;
00126 
00127         if(!c)
00128                 return c;
00129 
00130         strcpy(c->name,"speex");
00131         c->format = IAXC_FORMAT_SPEEX;
00132         c->encode = encode;
00133         c->decode = decode;
00134         c->destroy = destroy;
00135 
00136         c->encstate = calloc(sizeof(struct State),1);
00137         c->decstate = calloc(sizeof(struct State),1);
00138 
00139         /* leaks a bit on no-memory */
00140         if(!(c->encstate && c->decstate))
00141                 return NULL;
00142 
00143         encstate = (struct State *) c->encstate;
00144         decstate = (struct State *) c->decstate;
00145 
00146         sm = speex_lib_get_mode(SPEEX_MODEID_NB);
00147 
00148         encstate->state = speex_encoder_init(sm);
00149         decstate->state = speex_decoder_init(sm);
00150         speex_bits_init(&encstate->bits);
00151         speex_bits_init(&decstate->bits);
00152         speex_bits_reset(&encstate->bits);
00153         speex_bits_reset(&decstate->bits);
00154 
00155         speex_decoder_ctl(decstate->state, SPEEX_SET_ENH, &set->decode_enhance);
00156 
00157         speex_encoder_ctl(encstate->state, SPEEX_SET_COMPLEXITY, &set->complexity);
00158 
00159         if(set->quality >= 0) {
00160                 if(set->vbr) {
00161                         speex_encoder_ctl(encstate->state, SPEEX_SET_VBR_QUALITY, &set->quality);
00162                 } else {
00163                         int quality = (int)set->quality;
00164                         speex_encoder_ctl(encstate->state, SPEEX_SET_QUALITY, &quality);
00165                 }
00166         }
00167         if(set->bitrate >= 0)
00168                 speex_encoder_ctl(encstate->state, SPEEX_SET_BITRATE, &set->bitrate);
00169         if(set->vbr)
00170                 speex_encoder_ctl(encstate->state, SPEEX_SET_VBR, &set->vbr);
00171         if(set->abr)
00172                 speex_encoder_ctl(encstate->state, SPEEX_SET_ABR, &set->abr);
00173 
00174         /* set up frame sizes (normally, this is 20ms worth) */
00175         speex_encoder_ctl(encstate->state,SPEEX_GET_FRAME_SIZE,&encstate->frame_size);
00176         speex_decoder_ctl(decstate->state,SPEEX_GET_FRAME_SIZE,&decstate->frame_size);
00177 
00178         c->minimum_frame_size = 160;
00179 
00180         if(encstate->frame_size > c->minimum_frame_size)
00181                 c->minimum_frame_size = encstate->frame_size;
00182         if(decstate->frame_size > c->minimum_frame_size)
00183                 c->minimum_frame_size = decstate->frame_size;
00184 
00185         if(!(encstate->state && decstate->state))
00186                 return NULL;
00187 
00188         return c;
00189 }
00190 

Generated on Mon Sep 24 15:43:29 2007 for IAXClient by  doxygen 1.5.3