Wed Jan 27 20:02:40 2016

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 310 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.

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

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

static int unload_module ( void   )  [static]

Definition at line 361 of file func_speex.c.

References ast_custom_function_unregister().


Variable Documentation

Definition at line 347 of file func_speex.c.

Definition at line 354 of file func_speex.c.

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

Definition at line 137 of file func_speex.c.


Generated on 27 Jan 2016 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1