Thu Apr 28 2011 17:16:06

Asterisk developer's documentation


func_speex.c File Reference

Noise reduction and automatic gain control (AGC) More...

#include "asterisk.h"
#include <speex/speex_preprocess.h>
#include "asterisk/module.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
#include "asterisk/audiohook.h"
Include dependency graph for func_speex.c:

Go to the source code of this file.

Data Structures

struct  speex_direction_info
struct  speex_info

Defines

#define DEFAULT_AGC_LEVEL   8000.0

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void destroy_callback (void *data)
static int load_module (void)
static int speex_callback (struct ast_audiohook *audiohook, struct ast_channel *chan, struct ast_frame *frame, enum ast_audiohook_direction direction)
static int speex_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int speex_write (struct ast_channel *chan, const char *cmd, char *data, const char *value)
static int unload_module (void)

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Noise reduction and Automatic Gain Control (AGC)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static struct ast_custom_function agc_function
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_custom_function denoise_function
static struct ast_datastore_info speex_datastore

Detailed Description

Noise reduction and automatic gain control (AGC)

Author:
Brian Degenhardt <bmd@digium.com>
Brett Bryant <bbryant@digium.com>
ExtRef:
The Speex library - http://www.speex.org

Definition in file func_speex.c.


Define Documentation

#define DEFAULT_AGC_LEVEL   8000.0

Definition at line 49 of file func_speex.c.

Referenced by speex_write().


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 375 of file func_speex.c.

static void __unreg_module ( void  ) [static]

Definition at line 375 of file func_speex.c.

static void destroy_callback ( void *  data) [static]

Definition at line 110 of file func_speex.c.

References ast_audiohook_destroy(), ast_free, speex_info::audiohook, speex_info::rx, si, speex_direction_info::state, and speex_info::tx.

{
   struct speex_info *si = data;

   ast_audiohook_destroy(&si->audiohook);

   if (si->rx && si->rx->state) {
      speex_preprocess_state_destroy(si->rx->state);
   }

   if (si->tx && si->tx->state) {
      speex_preprocess_state_destroy(si->tx->state);
   }

   if (si->rx) {
      ast_free(si->rx);
   }

   if (si->tx) {
      ast_free(si->tx);
   }

   ast_free(data);
};
static int speex_callback ( struct ast_audiohook audiohook,
struct ast_channel chan,
struct ast_frame frame,
enum ast_audiohook_direction  direction 
) [static]

Definition at line 140 of file func_speex.c.

References speex_direction_info::agc, speex_direction_info::agclevel, AST_AUDIOHOOK_DIRECTION_READ, AST_AUDIOHOOK_STATUS_DONE, ast_channel_datastore_find(), AST_FRAME_VOICE, ast_free, AST_MALLOCD_SRC, ast_strdup, ast_frame::data, ast_datastore::data, speex_direction_info::denoise, ast_frame::frametype, ast_frame::mallocd, ast_frame::ptr, speex_info::rx, ast_frame::samples, speex_direction_info::samples, si, ast_frame::src, speex_direction_info::state, ast_audiohook::status, and speex_info::tx.

Referenced by speex_write().

{
   struct ast_datastore *datastore = NULL;
   struct speex_direction_info *sdi = NULL;
   struct speex_info *si = NULL;
   char source[80];

   /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
   if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || frame->frametype != AST_FRAME_VOICE) {
      return -1;
   }

   /* We are called with chan already locked */
   if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
      return -1;
   }

   si = datastore->data;

   sdi = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? si->rx : si->tx;

   if (!sdi) {
      return -1;
   }

   if (sdi->samples != frame->samples) {
      if (sdi->state) {
         speex_preprocess_state_destroy(sdi->state);
      }

      if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), 8000))) {
         return -1;
      }

      speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC, &sdi->agc);

      if (sdi->agc) {
         speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &sdi->agclevel);
      }

      speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_DENOISE, &sdi->denoise);
   }

   speex_preprocess(sdi->state, frame->data.ptr, NULL);
   snprintf(source, sizeof(source), "%s/speex", frame->src);
   if (frame->mallocd & AST_MALLOCD_SRC) {
      ast_free((char *) frame->src);
   }
   frame->src = ast_strdup(source);
   frame->mallocd |= AST_MALLOCD_SRC;

   return 0;
}
static int speex_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 305 of file func_speex.c.

References speex_direction_info::agclevel, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_log(), ast_datastore::data, speex_direction_info::denoise, LOG_ERROR, speex_info::rx, si, and speex_info::tx.

{
   struct ast_datastore *datastore = NULL;
   struct speex_info *si = NULL;
   struct speex_direction_info *sdi = NULL;

   if (!chan) {
      ast_log(LOG_ERROR, "%s cannot be used without a channel!\n", cmd);
      return -1;
   }

   ast_channel_lock(chan);
   if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
      ast_channel_unlock(chan);
      return -1;
   }
   ast_channel_unlock(chan);

   si = datastore->data;

   if (!strcasecmp(data, "tx"))
      sdi = si->tx;
   else if (!strcasecmp(data, "rx"))
      sdi = si->rx;
   else {
      ast_log(LOG_ERROR, "%s(%s) must either \"tx\" or \"rx\"\n", cmd, data);
      return -1;
   }

   if (!strcasecmp(cmd, "agc"))
      snprintf(buf, len, "%.01f", sdi ? sdi->agclevel : 0.0);
   else
      snprintf(buf, len, "%d", sdi ? sdi->denoise : 0);

   return 0;
}
static int speex_write ( struct ast_channel chan,
const char *  cmd,
char *  data,
const char *  value 
) [static]

Definition at line 194 of file func_speex.c.

References ast_audiohook_attach(), ast_audiohook_detach(), ast_audiohook_init(), ast_audiohook_remove(), AST_AUDIOHOOK_TYPE_MANIPULATE, ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_datastore_alloc(), ast_datastore_free(), ast_free, ast_log(), ast_true(), speex_info::audiohook, ast_datastore::data, DEFAULT_AGC_LEVEL, LOG_ERROR, LOG_WARNING, ast_audiohook::manipulate_callback, speex_info::rx, si, speex_callback(), and speex_info::tx.

{
   struct ast_datastore *datastore = NULL;
   struct speex_info *si = NULL;
   struct speex_direction_info **sdi = NULL;
   int is_new = 0;

   ast_channel_lock(chan);
   if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
      ast_channel_unlock(chan);

      if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) {
         return 0;
      }

      if (!(si = ast_calloc(1, sizeof(*si)))) {
         ast_datastore_free(datastore);
         return 0;
      }

      ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex");
      si->audiohook.manipulate_callback = speex_callback;

      is_new = 1;
   } else {
      ast_channel_unlock(chan);
      si = datastore->data;
   }

   if (!strcasecmp(data, "rx")) {
      sdi = &si->rx;
   } else if (!strcasecmp(data, "tx")) {
      sdi = &si->tx;
   } else {
      ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);

      if (is_new) {
         ast_datastore_free(datastore);
         return -1;
      }
   }

   if (!*sdi) {
      if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) {
         return 0;
      }
      /* Right now, the audiohooks API will _only_ provide us 8 kHz slinear
       * audio.  When it supports 16 kHz (or any other sample rates, we will
       * have to take that into account here. */
      (*sdi)->samples = -1;
   }

   if (!strcasecmp(cmd, "agc")) {
      if (!sscanf(value, "%30f", &(*sdi)->agclevel))
         (*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0;
   
      if ((*sdi)->agclevel > 32768.0) {
         ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n", 
               ((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel);
         (*sdi)->agclevel = 32768.0;
      }
   
      (*sdi)->agc = !!((*sdi)->agclevel);

      if ((*sdi)->state) {
         speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc);
         if ((*sdi)->agc) {
            speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel);
         }
      }
   } else if (!strcasecmp(cmd, "denoise")) {
      (*sdi)->denoise = (ast_true(value) != 0);

      if ((*sdi)->state) {
         speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise);
      }
   }

   if (!(*sdi)->agc && !(*sdi)->denoise) {
      if ((*sdi)->state)
         speex_preprocess_state_destroy((*sdi)->state);

      ast_free(*sdi);
      *sdi = NULL;
   }

   if (!si->rx && !si->tx) {
      if (is_new) {
         is_new = 0;
      } else {
         ast_channel_lock(chan);
         ast_channel_datastore_remove(chan, datastore);
         ast_channel_unlock(chan);
         ast_audiohook_remove(chan, &si->audiohook);
         ast_audiohook_detach(&si->audiohook);
      }
      
      ast_datastore_free(datastore);
   }

   if (is_new) { 
      datastore->data = si;
      ast_channel_lock(chan);
      ast_channel_datastore_add(chan, datastore);
      ast_channel_unlock(chan);
      ast_audiohook_attach(chan, &si->audiohook);
   }

   return 0;
}
static int unload_module ( void  ) [static]

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Noise reduction and Automatic Gain Control (AGC)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 375 of file func_speex.c.

Initial value:
 {
   .name = "AGC",
   .write = speex_write,
   .read = speex_read
}

Definition at line 342 of file func_speex.c.

Definition at line 375 of file func_speex.c.

Initial value:
 {
   .name = "DENOISE",
   .write = speex_write,
   .read = speex_read
}

Definition at line 348 of file func_speex.c.

Initial value:
 {
   .type = "speex",
   .destroy = destroy_callback
}

Definition at line 135 of file func_speex.c.