add preprocess framework for agc ec etc, ALPHA, needs work

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@14960 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2009-09-23 22:39:00 +00:00
parent f3b33b9521
commit 113c45bf4b
4 changed files with 324 additions and 0 deletions

View File

@ -1900,6 +1900,9 @@ SWITCH_DECLARE(void) switch_cond_yield(switch_interval_time_t t);
SWITCH_DECLARE(void) switch_cond_next(void);
SWITCH_DECLARE(switch_status_t) switch_core_chat_send(const char *name, const char *proto, const char *from, const char *to,
const char *subject, const char *body, const char *type, const char *hint);
SWITCH_DECLARE(switch_status_t) switch_ivr_preprocess_session(switch_core_session_t *session, const char *cmds);
///\}
/*!

View File

@ -1529,6 +1529,29 @@ SWITCH_STANDARD_API(kill_function)
return SWITCH_STATUS_SUCCESS;
}
#define PREPROCESS_SYNTAX "<>"
SWITCH_STANDARD_API(preprocess_function)
{
switch_core_session_t *ksession = NULL;
char *mycmd = NULL;
if (switch_strlen_zero(cmd)) {
stream->write_function(stream, "-USAGE: %s\n", KILL_SYNTAX);
return SWITCH_STATUS_SUCCESS;
}
if (!(ksession = switch_core_session_locate(cmd))) {
stream->write_function(stream, "-ERR No Such Channel!\n");
} else {
switch_ivr_preprocess_session(session, (char *)cmd);
switch_core_session_rwunlock(ksession);
stream->write_function(stream, "+OK\n");
}
switch_safe_free(mycmd);
return SWITCH_STATUS_SUCCESS;
}
#define PARK_SYNTAX "<uuid>"
SWITCH_STANDARD_API(park_function)
{
@ -3580,6 +3603,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load)
SWITCH_ADD_API(commands_api_interface, "originate", "Originate a Call", originate_function, ORIGINATE_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "tone_detect", "Start Tone Detection on a channel", tone_detect_session_function, TONE_DETECT_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_kill", "Kill Channel", kill_function, KILL_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_preprocess", "Pre-process Channel", preprocess_function, PREPROCESS_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "uuid_park", "Park Channel", park_function, PARK_SYNTAX);
SWITCH_ADD_API(commands_api_interface, "reloadacl", "Reload ACL", reload_acl_function, "[reloadxml]");
switch_console_set_complete("add reloadacl reloadxml");

View File

@ -2022,6 +2022,11 @@ SWITCH_STANDARD_APP(record_function)
}
}
SWITCH_STANDARD_APP(preprocess_session_function)
{
switch_ivr_preprocess_session(session, (char *)data);
}
SWITCH_STANDARD_APP(record_session_function)
{
char *path = NULL;
@ -2806,6 +2811,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load)
SWITCH_ADD_APP(app_interface, "record_session", "Record Session", SESS_REC_DESC, record_session_function, "<path> [+<timeout>]", SAF_NONE);
SWITCH_ADD_APP(app_interface, "record", "Record File", "Record a file from the channels input", record_function,
"<path> [<time_limit_secs>] [<silence_thresh>] [<silence_hits>]", SAF_NONE);
SWITCH_ADD_APP(app_interface, "preprocess", "pre-process", "pre-process", preprocess_session_function, "", SAF_NONE);
SWITCH_ADD_APP(app_interface, "stop_displace_session", "Stop Displace File", "Stop Displacing to a file", stop_displace_session_function, "<path>",
SAF_NONE);
SWITCH_ADD_APP(app_interface, "displace_session", "Displace File", DISPLACE_DESC, displace_session_function, "<path> [<flags>] [+time_limit_ms]",

View File

@ -32,6 +32,8 @@
*/
#include <switch.h>
#include <speex/speex_preprocess.h>
#include <speex/speex_echo.h>
#ifdef SWITCH_VIDEO_IN_THREADS
struct echo_helper {
@ -1026,6 +1028,295 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t
return SWITCH_STATUS_SUCCESS;
}
typedef struct {
SpeexPreprocessState *read_st;
SpeexPreprocessState *write_st;
SpeexEchoState *read_ec;
SpeexEchoState *write_ec;
switch_byte_t read_data[2048];
switch_byte_t write_data[2048];
switch_byte_t read_out[2048];
switch_byte_t write_out[2048];
switch_mutex_t *read_mutex;
switch_mutex_t *write_mutex;
int done;
} pp_cb_t;
static switch_bool_t preprocess_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
switch_core_session_t *session = switch_core_media_bug_get_session(bug);
switch_channel_t *channel = switch_core_session_get_channel(session);
pp_cb_t *cb = (pp_cb_t *) user_data;
switch_codec_implementation_t read_impl = {0};
switch_core_session_get_read_impl(session, &read_impl);
switch_frame_t *frame = NULL;
int y;
switch (type) {
case SWITCH_ABC_TYPE_INIT:
{
switch_mutex_init(&cb->read_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
switch_mutex_init(&cb->write_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
}
break;
case SWITCH_ABC_TYPE_CLOSE:
{
if (cb->read_st) {
speex_preprocess_state_destroy(cb->read_st);
}
if (cb->write_st) {
speex_preprocess_state_destroy(cb->write_st);
}
if (cb->read_ec) {
speex_echo_state_destroy(cb->read_ec);
}
if (cb->write_ec) {
speex_echo_state_destroy(cb->write_ec);
}
switch_channel_set_private(channel, "_preprocess", NULL);
}
break;
case SWITCH_ABC_TYPE_READ_REPLACE:
{
if (cb->done) return SWITCH_FALSE;
frame = switch_core_media_bug_get_read_replace_frame(bug);
if (cb->read_st) {
if (cb->read_ec) {
speex_echo_cancellation(cb->read_ec, (int16_t *)frame->data, (int16_t *)cb->write_data, (int16_t *)cb->read_out);
memcpy(frame->data, cb->read_out, frame->datalen);
}
y = speex_preprocess_run(cb->read_st, frame->data);
}
if (cb->write_ec) {
memcpy(cb->read_data, frame->data, frame->datalen);
}
}
break;
case SWITCH_ABC_TYPE_WRITE_REPLACE:
{
if (cb->done) return SWITCH_FALSE;
frame = switch_core_media_bug_get_write_replace_frame(bug);
if (cb->write_st) {
if (cb->write_ec) {
speex_echo_cancellation(cb->write_ec, (int16_t *)frame->data, (int16_t *)cb->read_data, (int16_t *)cb->write_out);
memcpy(frame->data, cb->write_out, frame->datalen);
}
y = speex_preprocess_run(cb->write_st, frame->data);
}
if (cb->read_ec) {
memcpy(cb->write_data, frame->data, frame->datalen);
}
}
break;
default:
break;
}
return SWITCH_TRUE;
}
SWITCH_DECLARE(switch_status_t) switch_ivr_preprocess_session(switch_core_session_t *session, const char *cmds)
{
switch_channel_t *channel = switch_core_session_get_channel(session);
switch_media_bug_t *bug;
switch_status_t status;
time_t to = 0;
switch_media_bug_flag_t flags = 0;
switch_codec_implementation_t read_impl = {0};
pp_cb_t *cb;
int update = 0;
int argc;
char *mydata = NULL, *argv[5];
int i = 0;
switch_core_session_get_read_impl(session, &read_impl);
if ((cb = switch_channel_get_private(channel, "_preprocess"))) {
update = 1;
} else {
cb = switch_core_session_alloc(session, sizeof(*cb));
}
if (update) {
if (!strcasecmp(cmds, "stop")) {
cb->done = 1;
return SWITCH_STATUS_SUCCESS;
}
}
mydata = strdup(cmds);
argc = switch_separate_string(mydata, ',', argv, (sizeof(argv) / sizeof(argv[0])));
for(i = 0; i < argc; i++) {
char *var = argv[i];
char *val = NULL;
char rw;
int tr;
int err = 1;
SpeexPreprocessState *st = NULL;
SpeexEchoState *ec;
switch_mutex_t *mutex = NULL;
int r = 0;
if (var) {
if ((val = strchr(var, '='))) {
*val++ = '\0';
rw = *var++;
while(*var == '.' || *var == '_') {
var++;
}
if (rw == 'r') {
if (!cb->read_st) {
cb->read_st = speex_preprocess_state_init(read_impl.samples_per_packet, read_impl.samples_per_second);
flags |= SMBF_READ_REPLACE;
}
st = cb->read_st;
ec = cb->read_ec;
mutex = cb->read_mutex;
} else if (rw == 'w') {
if (!cb->write_st) {
cb->write_st = speex_preprocess_state_init(read_impl.samples_per_packet, read_impl.samples_per_second);
flags |= SMBF_WRITE_REPLACE;
}
st = cb->write_st;
ec = cb->write_ec;
mutex = cb->write_mutex;
}
if (mutex) switch_mutex_lock(mutex);
if (st) {
err = 0;
tr = switch_true(val);
if (!strcasecmp(var, "agc")) {
int l = read_impl.samples_per_second;
int tmp = atoi(val);
if (!tr) {
l = tmp;
}
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting AGC on %c to %d\n", rw, tr);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC, &tr);
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_AGC_LEVEL, &l);
} else if (!strcasecmp(var, "noise_supress")) {
int db = atoi(val);
if (db < 0) {
r = speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &db);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting NOISE_SUPRESS on %c to %d [%d]\n", rw, db, r);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Syntax error noise_supress should be in -db\n");
}
} else if (!strcasecmp(var, "echo_cancel")) {
int tail = 1024;
int tmp = atoi(val);
if (!tr && tmp > 0) {
tail = tmp;
} else if (!tr) {
if (ec) {
if (rw == 'r') {
speex_echo_state_destroy(cb->read_ec);
cb->read_ec = NULL;
} else {
speex_echo_state_destroy(cb->write_ec);
cb->write_ec = NULL;
}
}
ec = NULL;
}
if (!ec) {
if (rw == 'r') {
ec = cb->read_ec = speex_echo_state_init(read_impl.samples_per_packet, tail);
speex_echo_ctl(ec, SPEEX_ECHO_SET_SAMPLING_RATE, &read_impl.samples_per_second);
flags |= SMBF_WRITE_REPLACE;
} else {
ec = cb->write_ec = speex_echo_state_init(read_impl.samples_per_packet, tail);
speex_echo_ctl(ec, SPEEX_ECHO_SET_SAMPLING_RATE, &read_impl.samples_per_second);
flags |= SMBF_READ_REPLACE;
}
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_STATE, ec);
}
} else if (!strcasecmp(var, "echo_supress")) {
int db = atoi(val);
if (db < 0) {
speex_preprocess_ctl(st, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS, &db);
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Setting ECHO_SUPRESS on %c to %d [%d]\n", rw, db, r);
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Syntax error echo_supress should be in -db\n");
}
} else {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Warning unknown parameter [%s] \n", var);
}
}
}
if (mutex) switch_mutex_unlock(mutex);
if (err) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Syntax error parsing preprossor commands\n");
}
} else {
break;
}
}
switch_safe_free(mydata);
if (update) {
return SWITCH_STATUS_SUCCESS;
}
if ((status = switch_core_media_bug_add(session, preprocess_callback, cb, to, flags, &bug)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error adding media bug.\n");
if (cb->read_st) {
speex_preprocess_state_destroy(cb->read_st);
}
if (cb->write_st) {
speex_preprocess_state_destroy(cb->write_st);
}
if (cb->read_ec) {
speex_echo_state_destroy(cb->read_ec);
}
if (cb->write_ec) {
speex_echo_state_destroy(cb->write_ec);
}
return status;
}
switch_channel_set_private(channel, "_preprocess", cb);
return SWITCH_STATUS_SUCCESS;
}
typedef struct {
switch_core_session_t *session;
teletone_dtmf_detect_state_t dtmf_detect;