Logo Search packages:      
Sourcecode: iaxclient version File versions  Download package

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, 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, 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, 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, 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, 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;

  return c;
}


Generated by  Doxygen 1.6.0   Back to index