Tue Aug 20 16:35:04 2013

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"

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

 AST_MODULE_INFO_STANDARD (ASTERISK_GPL_KEY,"Noise reduction and Automatic Gain Control (AGC)")
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_custom_function agc_function
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

AST_MODULE_INFO_STANDARD ( ASTERISK_GPL_KEY  ,
"Noise reduction and Automatic Gain Control (AGC)"   
)
static void destroy_callback ( void *  data  )  [static]

Definition at line 112 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.

00113 {
00114    struct speex_info *si = data;
00115 
00116    ast_audiohook_destroy(&si->audiohook);
00117 
00118    if (si->rx && si->rx->state) {
00119       speex_preprocess_state_destroy(si->rx->state);
00120    }
00121 
00122    if (si->tx && si->tx->state) {
00123       speex_preprocess_state_destroy(si->tx->state);
00124    }
00125 
00126    if (si->rx) {
00127       ast_free(si->rx);
00128    }
00129 
00130    if (si->tx) {
00131       ast_free(si->tx);
00132    }
00133 
00134    ast_free(data);
00135 };

static int load_module ( void   )  [static]
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 142 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, ast_frame::src, speex_direction_info::state, ast_audiohook::status, and speex_info::tx.

Referenced by speex_write().

00143 {
00144    struct ast_datastore *datastore = NULL;
00145    struct speex_direction_info *sdi = NULL;
00146    struct speex_info *si = NULL;
00147    char source[80];
00148 
00149    /* If the audiohook is stopping it means the channel is shutting down.... but we let the datastore destroy take care of it */
00150    if (audiohook->status == AST_AUDIOHOOK_STATUS_DONE || frame->frametype != AST_FRAME_VOICE) {
00151       return -1;
00152    }
00153 
00154    /* We are called with chan already locked */
00155    if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
00156       return -1;
00157    }
00158 
00159    si = datastore->data;
00160 
00161    sdi = (direction == AST_AUDIOHOOK_DIRECTION_READ) ? si->rx : si->tx;
00162 
00163    if (!sdi) {
00164       return -1;
00165    }
00166 
00167    if (sdi->samples != frame->samples) {
00168       if (sdi->state) {
00169          speex_preprocess_state_destroy(sdi->state);
00170       }
00171 
00172       if (!(sdi->state = speex_preprocess_state_init((sdi->samples = frame->samples), 8000))) {
00173          return -1;
00174       }
00175 
00176       speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC, &sdi->agc);
00177 
00178       if (sdi->agc) {
00179          speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &sdi->agclevel);
00180       }
00181 
00182       speex_preprocess_ctl(sdi->state, SPEEX_PREPROCESS_SET_DENOISE, &sdi->denoise);
00183    }
00184 
00185    speex_preprocess(sdi->state, frame->data.ptr, NULL);
00186    snprintf(source, sizeof(source), "%s/speex", frame->src);
00187    if (frame->mallocd & AST_MALLOCD_SRC) {
00188       ast_free((char *) frame->src);
00189    }
00190    frame->src = ast_strdup(source);
00191    frame->mallocd |= AST_MALLOCD_SRC;
00192 
00193    return 0;
00194 }

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, and speex_info::tx.

00306 {
00307    struct ast_datastore *datastore = NULL;
00308    struct speex_info *si = NULL;
00309    struct speex_direction_info *sdi = NULL;
00310 
00311    if (!chan) {
00312       ast_log(LOG_ERROR, "%s cannot be used without a channel!\n", cmd);
00313       return -1;
00314    }
00315 
00316    ast_channel_lock(chan);
00317    if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
00318       ast_channel_unlock(chan);
00319       return -1;
00320    }
00321    ast_channel_unlock(chan);
00322 
00323    si = datastore->data;
00324 
00325    if (!strcasecmp(data, "tx"))
00326       sdi = si->tx;
00327    else if (!strcasecmp(data, "rx"))
00328       sdi = si->rx;
00329    else {
00330       ast_log(LOG_ERROR, "%s(%s) must either \"tx\" or \"rx\"\n", cmd, data);
00331       return -1;
00332    }
00333 
00334    if (!strcasecmp(cmd, "agc"))
00335       snprintf(buf, len, "%.01f", sdi ? sdi->agclevel : 0.0);
00336    else
00337       snprintf(buf, len, "%d", sdi ? sdi->denoise : 0);
00338 
00339    return 0;
00340 }

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

Definition at line 196 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, speex_direction_info::samples, speex_callback(), and speex_info::tx.

00197 {
00198    struct ast_datastore *datastore = NULL;
00199    struct speex_info *si = NULL;
00200    struct speex_direction_info **sdi = NULL;
00201    int is_new = 0;
00202 
00203    if (strcasecmp(data, "rx") && strcasecmp(data, "tx")) {
00204       ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
00205       return -1;
00206    }
00207 
00208    ast_channel_lock(chan);
00209    if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
00210       ast_channel_unlock(chan);
00211 
00212       if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) {
00213          return 0;
00214       }
00215 
00216       if (!(si = ast_calloc(1, sizeof(*si)))) {
00217          ast_datastore_free(datastore);
00218          return 0;
00219       }
00220 
00221       ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex");
00222       si->audiohook.manipulate_callback = speex_callback;
00223 
00224       is_new = 1;
00225    } else {
00226       ast_channel_unlock(chan);
00227       si = datastore->data;
00228    }
00229 
00230    if (!strcasecmp(data, "rx")) {
00231       sdi = &si->rx;
00232    } else {
00233       sdi = &si->tx;
00234    }
00235 
00236    if (!*sdi) {
00237       if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) {
00238          return 0;
00239       }
00240       /* Right now, the audiohooks API will _only_ provide us 8 kHz slinear
00241        * audio.  When it supports 16 kHz (or any other sample rates, we will
00242        * have to take that into account here. */
00243       (*sdi)->samples = -1;
00244    }
00245 
00246    if (!strcasecmp(cmd, "agc")) {
00247       if (!sscanf(value, "%30f", &(*sdi)->agclevel))
00248          (*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0;
00249    
00250       if ((*sdi)->agclevel > 32768.0) {
00251          ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n", 
00252                ((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel);
00253          (*sdi)->agclevel = 32768.0;
00254       }
00255    
00256       (*sdi)->agc = !!((*sdi)->agclevel);
00257 
00258       if ((*sdi)->state) {
00259          speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc);
00260          if ((*sdi)->agc) {
00261             speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel);
00262          }
00263       }
00264    } else if (!strcasecmp(cmd, "denoise")) {
00265       (*sdi)->denoise = (ast_true(value) != 0);
00266 
00267       if ((*sdi)->state) {
00268          speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise);
00269       }
00270    }
00271 
00272    if (!(*sdi)->agc && !(*sdi)->denoise) {
00273       if ((*sdi)->state)
00274          speex_preprocess_state_destroy((*sdi)->state);
00275 
00276       ast_free(*sdi);
00277       *sdi = NULL;
00278    }
00279 
00280    if (!si->rx && !si->tx) {
00281       if (is_new) {
00282          is_new = 0;
00283       } else {
00284          ast_channel_lock(chan);
00285          ast_channel_datastore_remove(chan, datastore);
00286          ast_channel_unlock(chan);
00287          ast_audiohook_remove(chan, &si->audiohook);
00288          ast_audiohook_detach(&si->audiohook);
00289       }
00290       
00291       ast_datastore_free(datastore);
00292    }
00293 
00294    if (is_new) { 
00295       datastore->data = si;
00296       ast_channel_lock(chan);
00297       ast_channel_datastore_add(chan, datastore);
00298       ast_channel_unlock(chan);
00299       ast_audiohook_attach(chan, &si->audiohook);
00300    }
00301 
00302    return 0;
00303 }

static int unload_module ( void   )  [static]

Definition at line 356 of file func_speex.c.

References ast_custom_function_unregister().


Variable Documentation

Definition at line 342 of file func_speex.c.

Definition at line 349 of file func_speex.c.

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

Definition at line 137 of file func_speex.c.


Generated on 20 Aug 2013 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1