提交 9a136f90 authored 作者: Anthony Minessale's avatar Anthony Minessale

add mod_stress (needs work)

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@9345 d0543943-73ff-0310-b7d9-9358b9ac24b2
上级 20c1fb1d
差异被折叠。
/*****************************************************************************
* *
* DIGITAL SIGNAL PROCESSING TOOLS *
* Version 1.03, 2001/06/15 *
* (c) 1999 - Laurent de Soras *
* *
* FFTReal.h *
* Fourier transformation of real number arrays. *
* Portable ISO C++ *
* *
* Tab = 3 *
*****************************************************************************/
#if defined (FFTReal_CURRENT_HEADER)
#error Recursive inclusion of FFTReal header file.
#endif
#define FFTReal_CURRENT_HEADER
#if ! defined (FFTReal_HEADER_INCLUDED)
#define FFTReal_HEADER_INCLUDED
#if defined (_MSC_VER)
#pragma pack (push, 8)
#endif // _MSC_VER
class FFTReal
{
/*\\\ PUBLIC \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
public:
/* Change this typedef to use a different floating point type in your FFTs
(i.e. float, double or long double). */
typedef float flt_t;
explicit FFTReal (const long length);
~FFTReal ();
void do_fft (flt_t f [], const flt_t x []) const;
void do_ifft (const flt_t f [], flt_t x []) const;
void rescale (flt_t x []) const;
/*\\\ PRIVATE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
private:
/* Bit-reversed look-up table nested class */
class BitReversedLUT
{
public:
explicit BitReversedLUT (const int nbr_bits);
~BitReversedLUT ();
const long * get_ptr () const
{
return (_ptr);
}
private:
long * _ptr;
};
/* Trigonometric look-up table nested class */
class TrigoLUT
{
public:
explicit TrigoLUT (const int nbr_bits);
~TrigoLUT ();
const flt_t * get_ptr (const int level) const
{
return (_ptr + (1L << (level - 1)) - 4);
};
private:
flt_t * _ptr;
};
const BitReversedLUT _bit_rev_lut;
const TrigoLUT _trigo_lut;
const flt_t _sqrt2_2;
const long _length;
const int _nbr_bits;
flt_t * _buffer_ptr;
/*\\\ FORBIDDEN MEMBER FUNCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
private:
FFTReal (const FFTReal &other);
const FFTReal& operator = (const FFTReal &other);
int operator == (const FFTReal &other);
int operator != (const FFTReal &other);
};
#if defined (_MSC_VER)
#pragma pack (pop)
#endif // _MSC_VER
#endif // FFTReal_HEADER_INCLUDED
#undef FFTReal_CURRENT_HEADER
/*****************************************************************************
LEGAL
Source code may be freely used for any purpose, including commercial
applications. Programs must display in their "About" dialog-box (or
documentation) a text telling they use these routines by Laurent de Soras.
Modified source code can be distributed, but modifications must be clearly
indicated.
CONTACT
Laurent de Soras
92 avenue Albert 1er
92500 Rueil-Malmaison
France
ldesoras@club-internet.fr
*****************************************************************************/
/*\\\ EOF \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
BASE=../../../..
LOCAL_OBJS=FFTReal.o
include $(BASE)/build/modmake.rules
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
* mod_stress.cpp -- Detect Voice Stress
*
*/
#include <stdexcept>
#include <stdio.h>
#include "FFTReal.h"
using namespace std;
#include <switch.h>
SWITCH_MODULE_LOAD_FUNCTION(mod_stress_load);
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_stress_shutdown);
SWITCH_MODULE_DEFINITION(mod_stress, mod_stress_load, mod_stress_shutdown, NULL);
struct stress_helper {
switch_core_session_t *session;
int read;
uint32_t frame_size;
FFTReal *fft;
float *data;
float *result;
float *pow_spectrum;
float bind;
int start;
int end;
float avg_tremor_pwr;
float avg_total_pwr;
float total_pwr;
float tremor_ratio;
float stress;
uint32_t rate;
switch_buffer_t *audio_buffer;
int16_t *audio;
};
static switch_bool_t stress_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type)
{
struct stress_helper *sth = (struct stress_helper *) user_data;
switch (type) {
case SWITCH_ABC_TYPE_INIT:
{
switch_codec_t *read_codec = switch_core_session_get_read_codec(sth->session);
sth->rate = read_codec->implementation->actual_samples_per_second;
if (sth->rate == 8000) {
sth->frame_size = 8192;
} else if (sth->rate == 16000) {
sth->frame_size = 16384;
} else if (sth->rate == 32000) {
sth->frame_size = 32768;
} else {
return SWITCH_FALSE;
}
sth->data = (float *) switch_core_session_alloc(sth->session, sizeof(*sth->data) * sth->frame_size);
sth->result = (float *) switch_core_session_alloc(sth->session, sizeof(*sth->result) * sth->frame_size);
sth->pow_spectrum = (float *) switch_core_session_alloc(sth->session, sizeof(*sth->pow_spectrum) * sth->frame_size);
sth->audio = (int16_t *) switch_core_session_alloc(sth->session, sizeof(*sth->audio) * sth->frame_size);
sth->fft = new FFTReal (sth->frame_size);
switch_buffer_create_dynamic(&sth->audio_buffer, sth->frame_size, sth->frame_size * 3, 0);
sth->bind = (float) sth->rate / sth->frame_size;
sth->start = (int) (8.0 / sth->bind);
sth->end = (int) (14.0 / sth->bind);
}
break;
case SWITCH_ABC_TYPE_CLOSE:
{
switch_buffer_destroy(&sth->audio_buffer);
delete sth->fft;
}
break;
case SWITCH_ABC_TYPE_READ:
case SWITCH_ABC_TYPE_WRITE:
break;
case SWITCH_ABC_TYPE_READ_REPLACE:
case SWITCH_ABC_TYPE_WRITE_REPLACE:
{
switch_frame_t *frame;
if (sth->read) {
frame = switch_core_media_bug_get_read_replace_frame(bug);
} else {
frame = switch_core_media_bug_get_write_replace_frame(bug);
}
if (!switch_test_flag(frame, SFF_CNG)) {
switch_buffer_write(sth->audio_buffer, frame->data, frame->datalen);
}
sth->stress = 0.0;
if (switch_buffer_inuse(sth->audio_buffer) >= sth->frame_size * sizeof(int16_t)) {
switch_size_t bytes;
uint32_t samples, i;
const float threshold = 1.5;
bytes = switch_buffer_read(sth->audio_buffer, sth->audio, sth->frame_size * sizeof(int16_t));
samples = bytes / sizeof(int16_t);
switch_short_to_float(sth->audio, sth->data, samples);
sth->fft->do_fft(sth->result, sth->data);
for (i = 0; i < samples; ++i) {
sth->pow_spectrum[i] = pow(fabs(sth->result[i]), 2) / (float) samples;
}
sth->avg_tremor_pwr = 0.0;
sth->avg_total_pwr = 0.0;
sth->total_pwr = 0.0;
for (i = sth->start; i <= sth->end; ++i) {
sth->avg_tremor_pwr += sth->pow_spectrum[i];
}
sth->avg_tremor_pwr /= ((sth->end - sth->start) + 1);
for (i = 0; i < samples; ++i) {
sth->total_pwr += sth->pow_spectrum[i];
}
sth->avg_total_pwr = sth->total_pwr / samples;
if (sth->total_pwr < threshold) {
sth->tremor_ratio = 0.0;
} else {
sth->tremor_ratio = sth->avg_tremor_pwr / sth->avg_total_pwr;
}
if (sth->total_pwr >= 1.0) {
float d = pow(sth->tremor_ratio, 4);
if (d > 0.0) {
sth->stress = (10.0 / d) / 10000;
if (sth->stress >= 20000.0) {
sth->stress = 20000.0;
}
}
}
}
if (sth->stress) {
switch_event_t *event, *dup;
if (switch_event_create(&event, SWITCH_EVENT_DETECTED_SPEECH) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Speech-Type", "stress-level");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Stress-Level", "%02f", sth->stress);
if (switch_event_dup(&dup, event) == SWITCH_STATUS_SUCCESS) {
switch_event_fire(&dup);
}
if (switch_core_session_queue_event(sth->session, &event) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event queue failed!\n");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
switch_event_fire(&event);
}
}
}
}
default:
break;
}
return SWITCH_TRUE;
}
SWITCH_STANDARD_APP(stress_start_function)
{
switch_media_bug_t *bug;
switch_status_t status;
switch_channel_t *channel = switch_core_session_get_channel(session);
struct stress_helper *sth;
char *argv[6];
int argc;
char *lbuf = NULL;
int x = 0;
if ((bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_stress_"))) {
if (!switch_strlen_zero(data) && !strcasecmp(data, "stop")) {
switch_channel_set_private(channel, "_stress_", NULL);
switch_core_media_bug_remove(session, &bug);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n");
}
return;
}
sth = (struct stress_helper *) switch_core_session_alloc(session, sizeof(*sth));
assert(sth != NULL);
if (data && (lbuf = switch_core_session_strdup(session, data))
&& (argc = switch_separate_string(lbuf, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
if (!strncasecmp(argv[x], "read", 4)) {
sth->read = 1;
}
}
sth->session = session;
if ((status = switch_core_media_bug_add(session, stress_callback, sth, 0,
sth->read ? SMBF_READ_REPLACE : SMBF_WRITE_REPLACE, &bug)) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failure!\n");
return;
}
switch_channel_set_private(channel, "_stress_", bug);
}
SWITCH_MODULE_LOAD_FUNCTION(mod_stress_load)
{
switch_application_interface_t *app_interface;
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
SWITCH_ADD_APP(app_interface, "stress", "Analyze the stream for voice stress", "Analyze the stream for voice stress",
stress_start_function, "[read|write|stop]", SAF_NONE);
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_stress_shutdown)
{
return SWITCH_STATUS_UNLOAD;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:nil
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
*/
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论