Sat Apr 26 2014 22:02:52

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 __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Noise reduction and Automatic Gain Control (AGC)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
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 1.2 library - http://www.speex.org
Note:
Requires the 1.2 version of the Speex library (which might not be what you find in Linux packages)

Definition in file func_speex.c.


Define Documentation

#define DEFAULT_AGC_LEVEL   8000.0

Definition at line 51 of file func_speex.c.

Referenced by speex_write().


Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 384 of file func_speex.c.

static void __unreg_module ( void  ) [static]

Definition at line 384 of file func_speex.c.

static void destroy_callback ( void *  data) [static]

Definition at line 113 of file func_speex.c.

References ast_audiohook_destroy(), ast_free, speex_info::audiohook, speex_info::rx, 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 143 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_format_rate(), AST_FRAME_VOICE, ast_free, AST_MALLOCD_SRC, ast_strdup, ast_datastore::data, ast_frame::data, speex_direction_info::denoise, ast_frame_subclass::format, ast_frame::frametype, speex_info::lastrate, ast_frame::mallocd, ast_frame::ptr, speex_info::rx, speex_direction_info::samples, ast_frame::samples, ast_frame::src, speex_direction_info::state, ast_audiohook::status, ast_frame::subclass, 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) || (ast_format_rate(&frame->subclass.format) != si->lastrate)) {
      si->lastrate = ast_format_rate(&frame->subclass.format);
      if (sdi->state) {
         speex_preprocess_state_destroy(sdi->state);
      }

      if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), si->lastrate))) {
         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 312 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, 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 198 of file func_speex.c.

References ast_audiohook_attach(), ast_audiohook_detach(), ast_audiohook_init(), AST_AUDIOHOOK_MANIPULATE_ALL_RATES, 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, speex_info::lastrate, LOG_ERROR, LOG_WARNING, ast_audiohook::manipulate_callback, speex_info::rx, speex_direction_info::samples, 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;

   if (!chan) {
      ast_log(LOG_WARNING, "No channel was provided to %s function.\n", cmd);
      return -1;
   }

   if (strcasecmp(data, "rx") && strcasecmp(data, "tx")) {
      ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
      return -1;
   }

   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", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
      si->audiohook.manipulate_callback = speex_callback;
      si->lastrate = 8000;
      is_new = 1;
   } else {
      ast_channel_unlock(chan);
      si = datastore->data;
   }

   if (!strcasecmp(data, "rx")) {
      sdi = &si->rx;
   } else {
      sdi = &si->tx;
   }

   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 __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Noise reduction and Automatic Gain Control (AGC)" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 384 of file func_speex.c.

Definition at line 349 of file func_speex.c.

Definition at line 384 of file func_speex.c.

Definition at line 356 of file func_speex.c.

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

Definition at line 138 of file func_speex.c.