+#include <switch.h>
#include <stdio.h>
#include <stdlib.h>
#ifndef _MSC_VER
#include <assert.h>
#include <errno.h>
#include <math.h>
+#include <string.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
}
#endif
-extern void compute_table(void)
+extern int compute_table(void)
{
uint32_t i;
- float f;
- FILE *acos_table_file;
- size_t ret;
+ float f;
+ FILE *acos_table_file;
+ size_t res;
acos_table_file = fopen(ACOS_TABLE_FILENAME, "w");
for (i = 0; i < ACOS_TABLE_LENGTH; i++) {
f = acosf(float_from_index(i));
- ret = fwrite(&f, sizeof(f), 1, acos_table_file);
- assert(ret != 0);
+ res = fwrite(&f, sizeof(f), 1, acos_table_file);
+ if (res != 1) {
+ goto fail;
+ }
}
- ret = fclose(acos_table_file);
- assert(ret != EOF);
-}
+ res = fclose(acos_table_file);
+ if (res != 0) {
+ return -2;
+ }
+ return 0;
+fail:
+ fclose(acos_table_file);
+ return -1;
+}
-extern void init_fast_acosf(void)
+extern int init_fast_acosf(void)
{
- int ret;
+ int ret, errsv;
+ FILE *acos_fp;
+ char err[150];
if (acos_table == NULL) {
ret = access(ACOS_TABLE_FILENAME, F_OK);
- if (ret == 0) compute_table();
+ if (ret == -1) {
+ /* file doesn't exist, bad permissions,
+ * or some other error occured */
+ errsv = errno;
+ strerror_r(errsv, err, 150);
+ if (errsv != ENOENT) return -1;
+ else {
+ switch_log_printf(
+ SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_NOTICE,
+ "File [%s] doesn't exist. Creating file...\n", ACOS_TABLE_FILENAME
+ );
+ ret = compute_table();
+ if (ret != 0) return -2;
+ }
+ } else {
+ switch_log_printf(
+ SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_INFO,
+ "Using previously created file [%s]\n", ACOS_TABLE_FILENAME
+ );
+ }
+ }
- acos_fd = open(ACOS_TABLE_FILENAME, O_RDONLY);
- if (acos_fd == -1) perror("Could not open file " ACOS_TABLE_FILENAME);
- assert(acos_fd != -1);
- acos_table = (float *)mmap(
- NULL,
+ acos_fp = fopen(ACOS_TABLE_FILENAME, "r");
+ if (acos_fp == NULL) return -3;
+ /* can't fail */
+ acos_fd = fileno(acos_fp);
+ acos_table = (float *) mmap(
+ NULL, /* kernel chooses the address at which to create the mapping */
ACOS_TABLE_LENGTH * sizeof(float),
PROT_READ,
- MAP_SHARED | MAP_POPULATE,
+ MAP_SHARED | MAP_POPULATE, /* read-ahead on the file. Later accesses to the mapping
+ * will not be blocked by page faults */
acos_fd,
0
- );
- }
+ );
+ if (acos_table == MAP_FAILED) return -4;
+
+ return 0;
}
-extern void destroy_fast_acosf(void)
+extern int destroy_fast_acosf(void)
{
- int ret;
-
- ret = munmap(acos_table, ACOS_TABLE_LENGTH);
- assert(ret != -1);
- ret = close(acos_fd);
- assert(ret != -1);
+ if (munmap(acos_table, ACOS_TABLE_LENGTH) == -1) return -1;
+ if (acos_fd != -1) {
+ if (close(acos_fd) == -1) return -2;
+ }
+ /* disable use of fast arc cosine file */
acos_table = NULL;
+
+ return 0;
}
extern float fast_acosf(float x)
#ifndef __FAST_ACOSF_H__
#define __FAST_ACOSF_H__
-extern void init_fast_acosf(void);
+
+#define ACOS_TABLE_FILENAME "/tmp/acos_table.dat"
+
+/*! \brief Arc cosine table initialization.
+ *
+ * @author Eric des Courtis
+ * @par Changes: Piotr Gregor, 07 Feb 2016 (FS-8809, FS-8810)
+ * @return 0 on success, negative value otherwise:
+ * -1 can't access arc cos table with error != NOENT,
+ * -2 table creation failed (compute_table)
+ * -3 can access table but fopen failed
+ * -4 mmap failed
+ */
+extern int init_fast_acosf(void);
+
+/*! \brief Arc cosine table deinitialization.
+ *
+ * @author Eric des Courtis
+ * @par Changes: Piotr Gregor, 09 Feb 2016 (FS-8809, FS-8810)
+ * @return 0 on success, negative value otherwise:
+ * -1 munmap failed,
+ * -2 close failed
+ */
+extern int destroy_fast_acosf(void);
+
+/*! \brief Return arc cos for this argument.
+ * @details Uses previously created and mmapped file.
+ * @author Eric des Courtis
+ */
extern float fast_acosf(float x);
-extern void destroy_fast_acosf(void);
-extern void compute_table(void);
+
+/*! \brief Arc cosine table creation.
+ *
+ * @author Eric des Courtis
+ * @par Changes: Piotr Gregor, 07 Feb 2016 (FS-8809, FS-8810)
+ * @return 0 on success, negative value otherwise:
+ * -1 fwrite failed,
+ * -2 fclose failed
+ */
+extern int compute_table(void);
#endif
SWITCH_STANDARD_API(avmd_api_main);
SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load);
-SWITCH_MODULE_DEFINITION(mod_avmd, mod_avmd_load, NULL, NULL);
+SWITCH_MODULE_DEFINITION(mod_avmd, mod_avmd_load, mod_avmd_shutdown, NULL);
SWITCH_STANDARD_APP(avmd_start_function);
/*! Status of the beep detection */
/*! \brief FreeSWITCH module loading function.
*
* @author Eric des Courtis
- * @return Load success or failure.
+ * @par Changes: Piotr Gregor, 07 Feb 2016 (FS-8809, FS-8810)
+ * @return On success SWITCH_STATUS_SUCCES,
+ * on failure SWITCH_STATUS_TERM.
*/
SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load)
{
+#ifdef FASTMATH
+ char err[150];
+ int ret;
+#endif
switch_application_interface_t *app_interface;
switch_api_interface_t *api_interface;
if (switch_event_reserve_subclass(AVMD_EVENT_BEEP) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", AVMD_EVENT_BEEP);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Couldn't register subclass [%s]!\n", AVMD_EVENT_BEEP);
return SWITCH_STATUS_TERM;
}
SWITCH_CHANNEL_LOG,
SWITCH_LOG_NOTICE,
"Advanced Voicemail detection enabled\n"
- );
+ );
#ifdef FASTMATH
- init_fast_acosf();
+ ret = init_fast_acosf();
+ if (ret != 0) {
+ strerror_r(errno, err, 150);
+ switch (ret) {
+
+ case -1:
+ switch_log_printf(
+ SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Can't access file [%s], error [%s]\n",
+ ACOS_TABLE_FILENAME, err
+ );
+ break;
+
+ case -2:
+ switch_log_printf(
+ SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Error creating file [%s], error [%s]\n",
+ ACOS_TABLE_FILENAME, err
+ );
+ break;
+
+ case -3:
+ switch_log_printf(
+ SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Access rights are OK but can't open file [%s], error [%s]\n",
+ ACOS_TABLE_FILENAME, err
+ );
+ break;
+
+ case -4:
+ switch_log_printf(
+ SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Access rights are OK but can't mmap file [%s], error [%s]\n",
+ ACOS_TABLE_FILENAME, err
+ );
+ break;
+
+ default:
+ switch_log_printf(
+ SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Unknown error [%d] while initializing fast cos table [%s], "
+ "errno [%s]\n", ret, ACOS_TABLE_FILENAME, err
+ );
+ return SWITCH_STATUS_TERM;
+ }
+ return SWITCH_STATUS_TERM;
+ } else
switch_log_printf(
SWITCH_CHANNEL_LOG,
SWITCH_LOG_NOTICE,
- "Advanced Voicemail detection: fast math enabled\n"
+ "Advanced Voicemail detection: fast math enabled, arc cosine table "
+ "is [%s]\n", ACOS_TABLE_FILENAME
);
#endif
avmd_start_function,
"[start] [stop]",
SAF_NONE
- );
+ );
SWITCH_ADD_API(api_interface, "avmd", "Voicemail beep detection", avmd_api_main, AVMD_SYNTAX);
*/
SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown)
{
+#ifdef FASTMATH
+ int res;
+#endif
switch_event_free_subclass(AVMD_EVENT_BEEP);
#ifdef FASTMATH
- destroy_fast_acosf();
+ res = destroy_fast_acosf();
+ if (res != 0) {
+ switch (res) {
+ case -1:
+ switch_log_printf(
+ SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Failed unmap arc cosine table\n"
+ );
+ break;
+ case -2:
+ switch_log_printf(
+ SWITCH_CHANNEL_LOG,
+ SWITCH_LOG_ERROR,
+ "Failed closing arc cosine table\n"
+ );
+ break;
+ default:
+ break;
+ }
+ }
#endif
switch_log_printf(
/* calculate variance */
v = session->sqa_b.sma - (session->sma_b.sma * session->sma_b.sma);
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG, "<<< AVMD v=%f f=%f %fHz sma=%f sqa=%f >>>\n", v, f, TO_HZ(session->rate, f), session->sma_b.sma, session->sqa_b.sma);
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG,
+ "<<< AVMD v=[%f] f=[%f] [%f]Hz sma=[%f] sqa=[%f] >>>\n", v, f, TO_HZ(session->rate, f),
+ session->sma_b.sma, session->sqa_b.sma);
}
/*! If variance is less than threshold then we have detection */
if (v < VARIANCE_THRESHOLD) {
- switch_channel_set_variable_printf(channel, "avmd_total_time", "%d", (int)(switch_micro_time_now() - session->start_time) / 1000);
+ switch_channel_set_variable_printf(channel, "avmd_total_time",
+ "[%d]", (int)(switch_micro_time_now() - session->start_time) / 1000);
switch_channel_execute_on(channel, "execute_on_avmd_beep");
/*! Throw an event to FreeSWITCH */
if (status != SWITCH_STATUS_SUCCESS) return;
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Beep-Status", "stop");
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(session->session));
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Unique-ID",
+ switch_core_session_get_uuid(session->session));
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "avmd");
if ((switch_event_dup(&event_copy, event)) != SWITCH_STATUS_SUCCESS) return;
switch_core_session_queue_event(session->session, &event);
switch_event_fire(&event_copy);
- switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG, "<<< AVMD - Beep Detected >>>\n");
+ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session->session), SWITCH_LOG_DEBUG,
+ "<<< AVMD - Beep Detected >>>\n");
switch_channel_set_variable(channel, "avmd_detect", "TRUE");
RESET_SMA_BUFFER(&session->sma_b);
RESET_SMA_BUFFER(&session->sqa_b);