Added extra credits. Adjusted indentation.

git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@10643 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Eric des Courtis 2008-12-07 19:57:03 +00:00
parent d3852f3aee
commit b31df55196
1 changed files with 289 additions and 336 deletions

View File

@ -21,6 +21,16 @@
* *
* Eric des Courtis <eric.des.courtis@benbria.com> * Eric des Courtis <eric.des.courtis@benbria.com>
* *
* Special thanks to the following companies for their help:
* - JohnnyVoIP
* - Magor Communications Corporation
*
* Special thanks to the following people for their help:
* - The FreeSWITCH Team
* - Matt Battig
* - Dean Swan
* - Lucas Cornelisse
* - Kevin Green
* *
* mod_vmd.c -- Voicemail Detection Module * mod_vmd.c -- Voicemail Detection Module
* *
@ -108,24 +118,24 @@ SWITCH_MODULE_DEFINITION(mod_vmd, mod_vmd_load, NULL, NULL);
SWITCH_STANDARD_APP(vmd_start_function); SWITCH_STANDARD_APP(vmd_start_function);
/* Type that holds state information about the beep */ /* Type that holds state information about the beep */
typedef enum vmd_state{ typedef enum vmd_state {
BEEP_DETECTED, BEEP_NOT_DETECTED BEEP_DETECTED, BEEP_NOT_DETECTED
} vmd_state_t; } vmd_state_t;
/* Type that holds data for 5 points of discreet energy separation */ /* Type that holds data for 5 points of discreet energy separation */
typedef struct vmd_point{ typedef struct vmd_point {
double freq; double freq;
double ampl; double ampl;
} vmd_point_t; } vmd_point_t;
/* Type that holds codec information */ /* Type that holds codec information */
typedef struct vmd_codec_info{ typedef struct vmd_codec_info {
int rate; int rate;
int channels; int channels;
} vmd_codec_info_t; } vmd_codec_info_t;
/* Type that holds session information pertinent to the vmd module */ /* Type that holds session information pertinent to the vmd module */
typedef struct vmd_session_info{ typedef struct vmd_session_info {
/* State of the session */ /* State of the session */
vmd_state_t state; vmd_state_t state;
/* Snapshot of DESA samples */ /* Snapshot of DESA samples */
@ -143,12 +153,12 @@ typedef struct vmd_session_info{
switch_size_t timestamp; switch_size_t timestamp;
} vmd_session_info_t; } vmd_session_info_t;
static switch_bool_t process_data(vmd_session_info_t *vmd_info, switch_frame_t *frame); static switch_bool_t process_data(vmd_session_info_t * vmd_info, switch_frame_t * frame);
static switch_bool_t vmd_callback(switch_media_bug_t *bug, void *user_data, switch_abc_type_t type); static switch_bool_t vmd_callback(switch_media_bug_t * bug, void *user_data, switch_abc_type_t type);
static double freq_estimator(double *x); static double freq_estimator(double *x);
static double ampl_estimator(double *x); static double ampl_estimator(double *x);
static void convert_pts(int16_t *i_pts, double *d_pts, int16_t max); static void convert_pts(int16_t * i_pts, double *d_pts, int16_t max);
static void find_beep(vmd_session_info_t *vmd_info, switch_frame_t *frame); static void find_beep(vmd_session_info_t * vmd_info, switch_frame_t * frame);
static double median(double *m, int n); static double median(double *m, int n);
/* /*
@ -156,62 +166,59 @@ static double median(double *m, int n);
#define PRINT2(a, b) do{ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, a, b); }while(0) #define PRINT2(a, b) do{ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, a, b); }while(0)
*/ */
static switch_bool_t vmd_callback(switch_media_bug_t *bug, static switch_bool_t vmd_callback(switch_media_bug_t * bug, void *user_data, switch_abc_type_t type)
void *user_data,
switch_abc_type_t type)
{ {
vmd_session_info_t *vmd_info; vmd_session_info_t *vmd_info;
switch_codec_t *read_codec; switch_codec_t *read_codec;
switch_frame_t *frame; switch_frame_t *frame;
vmd_info = (vmd_session_info_t *)user_data; vmd_info = (vmd_session_info_t *) user_data;
if(vmd_info == NULL) { if (vmd_info == NULL) {
return SWITCH_FALSE; return SWITCH_FALSE;
} }
switch(type){ switch (type) {
case SWITCH_ABC_TYPE_INIT: case SWITCH_ABC_TYPE_INIT:
read_codec = switch_core_session_get_read_codec(vmd_info->session); read_codec = switch_core_session_get_read_codec(vmd_info->session);
vmd_info->vmd_codec.rate = read_codec->implementation->samples_per_second; vmd_info->vmd_codec.rate = read_codec->implementation->samples_per_second;
vmd_info->vmd_codec.channels = read_codec->implementation->number_of_channels; vmd_info->vmd_codec.channels = read_codec->implementation->number_of_channels;
break; break;
case SWITCH_ABC_TYPE_READ_PING: case SWITCH_ABC_TYPE_READ_PING:
case SWITCH_ABC_TYPE_CLOSE: case SWITCH_ABC_TYPE_CLOSE:
case SWITCH_ABC_TYPE_READ: case SWITCH_ABC_TYPE_READ:
case SWITCH_ABC_TYPE_WRITE: case SWITCH_ABC_TYPE_WRITE:
break; break;
case SWITCH_ABC_TYPE_READ_REPLACE: case SWITCH_ABC_TYPE_READ_REPLACE:
frame = switch_core_media_bug_get_read_replace_frame(bug); frame = switch_core_media_bug_get_read_replace_frame(bug);
return process_data(vmd_info, frame); return process_data(vmd_info, frame);
case SWITCH_ABC_TYPE_WRITE_REPLACE: case SWITCH_ABC_TYPE_WRITE_REPLACE:
break; break;
} }
return SWITCH_TRUE; return SWITCH_TRUE;
} }
static switch_bool_t process_data(vmd_session_info_t *vmd_info, static switch_bool_t process_data(vmd_session_info_t * vmd_info, switch_frame_t * frame)
switch_frame_t *frame)
{ {
uint32_t i; uint32_t i;
unsigned int j; unsigned int j;
double pts[P]; double pts[P];
int16_t *data; int16_t *data;
int16_t max; int16_t max;
switch_ssize_t len; switch_ssize_t len;
len = frame->samples * sizeof(int16_t); len = frame->samples * sizeof(int16_t);
data = (int16_t *)frame->data; data = (int16_t *) frame->data;
for(max = (int16_t)abs(data[0]), i = 1; i < frame->samples; i++) { for (max = (int16_t) abs(data[0]), i = 1; i < frame->samples; i++) {
if ((int16_t)abs(data[i]) > max) { if ((int16_t) abs(data[i]) > max) {
max = (int16_t)abs(data[i]); max = (int16_t) abs(data[i]);
} }
} }
/* /*
if(vmd_info->data_len != len){ if(vmd_info->data_len != len){
@ -234,189 +241,184 @@ static switch_bool_t process_data(vmd_session_info_t *vmd_info,
} }
*/ */
for(i = 0, j = vmd_info->pos; i < frame->samples; j++, j %= POINTS, i += 5) { for (i = 0, j = vmd_info->pos; i < frame->samples; j++, j %= POINTS, i += 5) {
/* convert_pts(vmd_info->data + i, pts); */ /* convert_pts(vmd_info->data + i, pts); */
convert_pts(data + i, pts, max); convert_pts(data + i, pts, max);
vmd_info->points[j].freq = TO_HZ(freq_estimator(pts)); vmd_info->points[j].freq = TO_HZ(freq_estimator(pts));
vmd_info->points[j].ampl = ampl_estimator(pts); vmd_info->points[j].ampl = ampl_estimator(pts);
vmd_info->pos = j % POINTS; vmd_info->pos = j % POINTS;
find_beep(vmd_info, frame); find_beep(vmd_info, frame);
} }
return SWITCH_TRUE; return SWITCH_TRUE;
} }
static void find_beep(vmd_session_info_t *vmd_info, switch_frame_t *frame) static void find_beep(vmd_session_info_t * vmd_info, switch_frame_t * frame)
{ {
int i; int i;
int c; int c;
double m[POINTS]; double m[POINTS];
double med; double med;
unsigned int j = (vmd_info->pos + 1) % POINTS; unsigned int j = (vmd_info->pos + 1) % POINTS;
unsigned int k = j; unsigned int k = j;
switch_event_t *event; switch_event_t *event;
switch_status_t status; switch_status_t status;
switch_event_t *event_copy; switch_event_t *event_copy;
switch_channel_t *channel = switch_core_session_get_channel(vmd_info->session); switch_channel_t *channel = switch_core_session_get_channel(vmd_info->session);
switch(vmd_info->state){ switch (vmd_info->state) {
case BEEP_DETECTED: case BEEP_DETECTED:
for(c = 0, i = 0; i < POINTS; j++, j %= POINTS, i++){ for (c = 0, i = 0; i < POINTS; j++, j %= POINTS, i++) {
vmd_info->timestamp++; vmd_info->timestamp++;
if (vmd_info->points[j].freq < TOLERANCE_T(vmd_info->beep_freq) && if (vmd_info->points[j].freq < TOLERANCE_T(vmd_info->beep_freq) &&
vmd_info->points[j].freq > TOLERANCE_B(vmd_info->beep_freq)) { vmd_info->points[j].freq > TOLERANCE_B(vmd_info->beep_freq)) {
c++; c++;
vmd_info->beep_freq = (vmd_info->beep_freq * 0.95) + (vmd_info->points[j].freq * 0.05); vmd_info->beep_freq = (vmd_info->beep_freq * 0.95) + (vmd_info->points[j].freq * 0.05);
} }
} }
if (c < (POINTS - MAX_CHIRP)) { if (c < (POINTS - MAX_CHIRP)) {
vmd_info->state = BEEP_NOT_DETECTED; vmd_info->state = BEEP_NOT_DETECTED;
if (vmd_info->timestamp < MIN_TIME) { if (vmd_info->timestamp < MIN_TIME) {
break; break;
} }
status = switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, VMD_EVENT_BEEP); status = switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, VMD_EVENT_BEEP);
if (status != SWITCH_STATUS_SUCCESS) { if (status != SWITCH_STATUS_SUCCESS) {
return; return;
} }
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Beep-Status", "stop"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Beep-Status", "stop");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Beep-Time", "%d", (int)vmd_info->timestamp / POINTS); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Beep-Time", "%d", (int) vmd_info->timestamp / POINTS);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Unique-ID", "%s", switch_core_session_get_uuid(vmd_info->session));
"%s", switch_core_session_get_uuid(vmd_info->session)); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Frequency", "%6.4lf", vmd_info->beep_freq);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Frequency", "%6.4lf", vmd_info->beep_freq); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "vmd");
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "vmd");
if ((switch_event_dup(&event_copy, event)) != SWITCH_STATUS_SUCCESS) { if ((switch_event_dup(&event_copy, event)) != SWITCH_STATUS_SUCCESS) {
return; return;
} }
switch_core_session_queue_event(vmd_info->session, &event); switch_core_session_queue_event(vmd_info->session, &event);
switch_event_fire(&event_copy); switch_event_fire(&event_copy);
switch_log_printf( switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "<<< VMD - Beep Detected >>>\n");
SWITCH_CHANNEL_LOG, switch_channel_set_variable(channel, "vmd_detect", "TRUE");
SWITCH_LOG_INFO,
"<<< VMD - Beep Detected >>>\n"
);
switch_channel_set_variable(channel, "vmd_detect", "TRUE");
vmd_info->timestamp = 0; vmd_info->timestamp = 0;
} }
break; break;
case BEEP_NOT_DETECTED: case BEEP_NOT_DETECTED:
for(i = 0; i < POINTS; k++, k %= POINTS, i++){ for (i = 0; i < POINTS; k++, k %= POINTS, i++) {
m[i] = vmd_info->points[k].freq; m[i] = vmd_info->points[k].freq;
if (ISNAN(m[i])) { if (ISNAN(m[i])) {
m[i] = 0.0; m[i] = 0.0;
} }
} }
med = median(m, POINTS); med = median(m, POINTS);
if (ISNAN(med)){ if (ISNAN(med)) {
for(i = 0; i < POINTS; i++){ for (i = 0; i < POINTS; i++) {
if (!ISNAN(m[i])){ if (!ISNAN(m[i])) {
med = m[i]; med = m[i];
break; break;
} }
} }
} }
for(c = 0, i = 0; i < POINTS; j++, j %= POINTS, i++){ for (c = 0, i = 0; i < POINTS; j++, j %= POINTS, i++) {
if (vmd_info->points[j].freq < TOLERANCE_T(med) && if (vmd_info->points[j].freq < TOLERANCE_T(med) && vmd_info->points[j].freq > TOLERANCE_B(med)) {
vmd_info->points[j].freq > TOLERANCE_B(med)){ if (vmd_info->points[j].ampl > MIN_AMPL &&
if (vmd_info->points[j].ampl > MIN_AMPL && vmd_info->points[j].freq > MIN_FREQ && vmd_info->points[j].freq < MAX_FREQ) {
vmd_info->points[j].freq > MIN_FREQ && c++;
vmd_info->points[j].freq < MAX_FREQ){ }
c++; }
} }
}
}
if(c >= VALID){ if (c >= VALID) {
vmd_info->state = BEEP_DETECTED; vmd_info->state = BEEP_DETECTED;
vmd_info->beep_freq = med; vmd_info->beep_freq = med;
vmd_info->timestamp = 0; vmd_info->timestamp = 0;
} }
break; break;
} }
} }
/* Find the median of an array of doubles */ /* Find the median of an array of doubles */
static double median(double *m, int n) static double median(double *m, int n)
{ {
int i; int i;
int less; int less;
int greater; int greater;
int equal; int equal;
double min; double min;
double max; double max;
double guess; double guess;
double maxltguess; double maxltguess;
double mingtguess; double mingtguess;
min = max = m[0] ; min = max = m[0];
for (i = 1; i < n; i++) { for (i = 1; i < n; i++) {
if(m[i] < min) min = m[i]; if (m[i] < min)
if(m[i] > max) max = m[i]; min = m[i];
} if (m[i] > max)
max = m[i];
}
for(;;) { for (;;) {
guess = ( min + max ) / 2; guess = (min + max) / 2;
less = 0; less = 0;
greater = 0; greater = 0;
equal = 0; equal = 0;
maxltguess = min; maxltguess = min;
mingtguess = max; mingtguess = max;
for(i = 0; i < n; i++) { for (i = 0; i < n; i++) {
if (m[i] < guess) { if (m[i] < guess) {
less++; less++;
if(m[i] > maxltguess) { if (m[i] > maxltguess) {
maxltguess = m[i]; maxltguess = m[i];
} }
} else if (m[i] > guess) { } else if (m[i] > guess) {
greater++; greater++;
if(m[i] < mingtguess) { if (m[i] < mingtguess) {
mingtguess = m[i]; mingtguess = m[i];
} }
} else { } else {
equal++; equal++;
} }
} }
if (less <= ( n + 1 ) / 2 && greater <= ( n + 1 ) / 2) { if (less <= (n + 1) / 2 && greater <= (n + 1) / 2) {
break; break;
} else if (less > greater) { } else if (less > greater) {
max = maxltguess; max = maxltguess;
} else { } else {
min = mingtguess; min = mingtguess;
} }
} }
if (less >= ( n + 1 ) / 2) { if (less >= (n + 1) / 2) {
return maxltguess; return maxltguess;
} else if (less + equal >= ( n + 1 ) / 2) { } else if (less + equal >= (n + 1) / 2) {
return guess; return guess;
} }
return mingtguess; return mingtguess;
} }
/* Convert many points for Signed L16 to relative floating point */ /* Convert many points for Signed L16 to relative floating point */
static void convert_pts(int16_t *i_pts, double *d_pts, int16_t max) static void convert_pts(int16_t * i_pts, double *d_pts, int16_t max)
{ {
int i; int i;
for(i = 0; i < P; i++) { for (i = 0; i < P; i++) {
/* Signed L16 to relative floating point conversion */ /* Signed L16 to relative floating point conversion */
d_pts[i] = ((((double)(i_pts[i]) + (double)max) / (double)(2 * max)) - 0.5) * 2.0; d_pts[i] = ((((double) (i_pts[i]) + (double) max) / (double) (2 * max)) - 0.5) * 2.0;
} }
} }
/* Amplitude estimator for DESA-2 */ /* Amplitude estimator for DESA-2 */
@ -427,22 +429,18 @@ double ampl_estimator(double *x)
freq_sq = freq_estimator(x); freq_sq = freq_estimator(x);
freq_sq *= freq_sq; freq_sq *= freq_sq;
return sqrt( PSI(x) / sin(freq_sq) ); return sqrt(PSI(x) / sin(freq_sq));
} }
/* The DESA-2 algorithm */ /* The DESA-2 algorithm */
double freq_estimator(double *x) double freq_estimator(double *x)
{ {
return 0.5 * acos( return 0.5 * acos((((x[2] * x[2]) - (x[0] * x[4]))
(((x[2] * x[2]) - (x[0] * x[4])) - ((x[1] * x[1]) - (x[0] * x[2]))
- - ((x[3] * x[3]) - (x[2] * x[4])))
( (x[1] * x[1]) - (x[0] * x[2])) / (2.0 * ((x[2] * x[2]) - (x[1] * x[3])))
-
( (x[3] * x[3]) - (x[2] * x[4]))) );
/
(2.0 * ((x[2] * x[2]) - (x[1] * x[3])))
);
} }
@ -451,20 +449,13 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vmd_load)
switch_application_interface_t *app_interface; switch_application_interface_t *app_interface;
switch_api_interface_t *api_interface; switch_api_interface_t *api_interface;
/* connect my internal structure to the blank pointer passed to me */ /* connect my internal structure to the blank pointer passed to me */
*module_interface = *module_interface = switch_loadable_module_create_module_interface(pool, modname);
switch_loadable_module_create_module_interface(pool, modname);
switch_log_printf(
SWITCH_CHANNEL_LOG,
SWITCH_LOG_NOTICE,
"Voicemail detection enabled\n"
);
SWITCH_ADD_APP(app_interface, "vmd", "Detect beeps", "Detect voicemail beeps", switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Voicemail detection enabled\n");
vmd_start_function, "[start] [stop]", SAF_NONE);
SWITCH_ADD_APP(app_interface, "vmd", "Detect beeps", "Detect voicemail beeps", vmd_start_function, "[start] [stop]", SAF_NONE);
SWITCH_ADD_API(api_interface, "vmd", "Detected voicemail beeps",
vmd_api_main, VMD_SYNTAX); SWITCH_ADD_API(api_interface, "vmd", "Detected voicemail beeps", vmd_api_main, VMD_SYNTAX);
/* indicate that the module should continue to be loaded */ /* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
@ -473,84 +464,64 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_vmd_load)
/* Same as api function see it for comments */ /* Same as api function see it for comments */
SWITCH_STANDARD_APP(vmd_start_function) SWITCH_STANDARD_APP(vmd_start_function)
{ {
switch_media_bug_t *bug; switch_media_bug_t *bug;
switch_status_t status; switch_status_t status;
switch_channel_t *channel; switch_channel_t *channel;
vmd_session_info_t *vmd_info; vmd_session_info_t *vmd_info;
int i; int i;
if (session == NULL) return; if (session == NULL)
return;
channel = switch_core_session_get_channel(session); channel = switch_core_session_get_channel(session);
/* Is this channel already set? */ /* Is this channel already set? */
bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_vmd_"); bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_vmd_");
/* If yes */ /* If yes */
if (bug != NULL){ if (bug != NULL) {
/* If we have a stop remove audio bug */ /* If we have a stop remove audio bug */
if(strcasecmp(data, "stop") == 0){ if (strcasecmp(data, "stop") == 0) {
switch_channel_set_private(channel, "_vmd_", NULL); switch_channel_set_private(channel, "_vmd_", NULL);
switch_core_media_bug_remove(session, &bug); switch_core_media_bug_remove(session, &bug);
return; return;
} }
/* We have already started */ /* We have already started */
switch_log_printf( switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n");
SWITCH_CHANNEL_LOG,
SWITCH_LOG_WARNING,
"Cannot run 2 at once on the same channel!\n"
);
return; return;
} }
vmd_info = (vmd_session_info_t *)switch_core_session_alloc( vmd_info = (vmd_session_info_t *) switch_core_session_alloc(session, sizeof(vmd_session_info_t)
session, );
sizeof(vmd_session_info_t)
);
vmd_info->state = BEEP_NOT_DETECTED; vmd_info->state = BEEP_NOT_DETECTED;
vmd_info->session = session; vmd_info->session = session;
vmd_info->pos = 0; vmd_info->pos = 0;
/* /*
vmd_info->data = NULL; vmd_info->data = NULL;
vmd_info->data_len = 0; vmd_info->data_len = 0;
*/ */
for(i = 0; i < POINTS; i++){ for (i = 0; i < POINTS; i++) {
vmd_info->points[i].freq = 0.0; vmd_info->points[i].freq = 0.0;
vmd_info->points[i].ampl = 0.0; vmd_info->points[i].ampl = 0.0;
} }
status = switch_core_media_bug_add( status = switch_core_media_bug_add(session, vmd_callback, vmd_info, 0, SMBF_READ_REPLACE, &bug);
session,
vmd_callback,
vmd_info,
0,
SMBF_READ_REPLACE,
&bug
);
if(status != SWITCH_STATUS_SUCCESS){ if (status != SWITCH_STATUS_SUCCESS) {
switch_log_printf( switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failure hooking to stream\n");
SWITCH_CHANNEL_LOG, return;
SWITCH_LOG_ERROR, }
"Failure hooking to stream\n"
);
return;
}
switch_channel_set_private(channel, "_vmd_", bug); switch_channel_set_private(channel, "_vmd_", bug);
} }
/* Called when the system shuts down */ /* Called when the system shuts down */
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_vmd_shutdown) SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_vmd_shutdown)
{ {
switch_log_printf( switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Voicemail detection disabled\n");
SWITCH_CHANNEL_LOG,
SWITCH_LOG_NOTICE,
"Voicemail detection disabled\n"
);
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
@ -568,11 +539,11 @@ SWITCH_STANDARD_API(vmd_api_main)
char *uuid; char *uuid;
char *command; char *command;
int i; int i;
/* No command? Display usage */ /* No command? Display usage */
if(cmd == NULL){ if (cmd == NULL) {
stream->write_function(stream, "-USAGE: %s\n", VMD_SYNTAX); stream->write_function(stream, "-USAGE: %s\n", VMD_SYNTAX);
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
/* Duplicated contents of original string */ /* Duplicated contents of original string */
@ -582,23 +553,23 @@ SWITCH_STANDARD_API(vmd_api_main)
/* If we don't have the expected number of parameters /* If we don't have the expected number of parameters
* display usage */ * display usage */
if (argc != VMD_PARAMS){ if (argc != VMD_PARAMS) {
stream->write_function(stream, "-USAGE: %s\n", VMD_SYNTAX); stream->write_function(stream, "-USAGE: %s\n", VMD_SYNTAX);
switch_safe_free(ccmd); switch_safe_free(ccmd);
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
uuid = argv[0]; uuid = argv[0];
command = argv[1]; command = argv[1];
/* using uuid locate a reference to the FreeSWITCH session */ /* using uuid locate a reference to the FreeSWITCH session */
vmd_session = switch_core_session_locate(uuid); vmd_session = switch_core_session_locate(uuid);
/* If the session was not found exit */ /* If the session was not found exit */
if (vmd_session == NULL) { if (vmd_session == NULL) {
switch_safe_free(ccmd); switch_safe_free(ccmd);
stream->write_function(stream, "-USAGE: %s\n", VMD_SYNTAX); stream->write_function(stream, "-USAGE: %s\n", VMD_SYNTAX);
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
} }
/* Get current channel of the session to tag the session /* Get current channel of the session to tag the session
@ -608,9 +579,9 @@ SWITCH_STANDARD_API(vmd_api_main)
/* Is this channel already set? */ /* Is this channel already set? */
bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_vmd_"); bug = (switch_media_bug_t *) switch_channel_get_private(channel, "_vmd_");
/* If yes */ /* If yes */
if (bug != NULL){ if (bug != NULL) {
/* If we have a stop remove audio bug */ /* If we have a stop remove audio bug */
if(strcasecmp(command, "stop") == 0) { if (strcasecmp(command, "stop") == 0) {
switch_channel_set_private(channel, "_vmd_", NULL); switch_channel_set_private(channel, "_vmd_", NULL);
switch_core_media_bug_remove(vmd_session, &bug); switch_core_media_bug_remove(vmd_session, &bug);
switch_safe_free(ccmd); switch_safe_free(ccmd);
@ -618,30 +589,24 @@ SWITCH_STANDARD_API(vmd_api_main)
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
/* We have already started */ /* We have already started */
switch_log_printf( switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot run 2 at once on the same channel!\n");
SWITCH_CHANNEL_LOG,
SWITCH_LOG_WARNING, switch_safe_free(ccmd);
"Cannot run 2 at once on the same channel!\n" return SWITCH_STATUS_FALSE;
);
switch_safe_free(ccmd);
return SWITCH_STATUS_FALSE;
} }
/* If we don't see the expected start exit */ /* If we don't see the expected start exit */
if(strcasecmp(command, "start") != 0) { if (strcasecmp(command, "start") != 0) {
switch_safe_free(ccmd); switch_safe_free(ccmd);
stream->write_function(stream, "-USAGE: %s\n", VMD_SYNTAX); stream->write_function(stream, "-USAGE: %s\n", VMD_SYNTAX);
return SWITCH_STATUS_FALSE; return SWITCH_STATUS_FALSE;
} }
/* Allocate memory attached to this FreeSWITCH session for /* Allocate memory attached to this FreeSWITCH session for
* use in the callback routine and to store state information */ * use in the callback routine and to store state information */
vmd_info = (vmd_session_info_t *)switch_core_session_alloc( vmd_info = (vmd_session_info_t *) switch_core_session_alloc(vmd_session, sizeof(vmd_session_info_t)
vmd_session, );
sizeof(vmd_session_info_t)
);
/* Set initial values and states */ /* Set initial values and states */
vmd_info->state = BEEP_NOT_DETECTED; vmd_info->state = BEEP_NOT_DETECTED;
@ -652,40 +617,29 @@ SWITCH_STANDARD_API(vmd_api_main)
vmd_info->data_len = 0; vmd_info->data_len = 0;
*/ */
for(i = 0; i < POINTS; i++) { for (i = 0; i < POINTS; i++) {
vmd_info->points[i].freq = 0.0; vmd_info->points[i].freq = 0.0;
vmd_info->points[i].ampl = 0.0; vmd_info->points[i].ampl = 0.0;
} }
/* Add a media bug that allows me to intercept the /* Add a media bug that allows me to intercept the
* reading leg of the audio stream */ * reading leg of the audio stream */
status = switch_core_media_bug_add( status = switch_core_media_bug_add(vmd_session, vmd_callback, vmd_info, 0, SMBF_READ_REPLACE, &bug);
vmd_session,
vmd_callback,
vmd_info,
0,
SMBF_READ_REPLACE,
&bug
);
/* If adding a media bug fails exit */ /* If adding a media bug fails exit */
if (status != SWITCH_STATUS_SUCCESS) { if (status != SWITCH_STATUS_SUCCESS) {
switch_log_printf( switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failure hooking to stream\n");
SWITCH_CHANNEL_LOG,
SWITCH_LOG_ERROR, switch_safe_free(ccmd);
"Failure hooking to stream\n" return SWITCH_STATUS_FALSE;
);
switch_safe_free(ccmd);
return SWITCH_STATUS_FALSE;
} }
/* Set the vmd tag to detect an existing vmd media bug */ /* Set the vmd tag to detect an existing vmd media bug */
switch_channel_set_private(channel, "_vmd_", bug); switch_channel_set_private(channel, "_vmd_", bug);
/* Everything went according to plan! Notify the user */ /* Everything went according to plan! Notify the user */
stream->write_function(stream, "+OK\n"); stream->write_function(stream, "+OK\n");
switch_safe_free(ccmd); switch_safe_free(ccmd);
return SWITCH_STATUS_SUCCESS; return SWITCH_STATUS_SUCCESS;
} }
@ -701,4 +655,3 @@ SWITCH_STANDARD_API(vmd_api_main)
* For VIM: * For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab: * vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
*/ */