diff --git a/src/mod/applications/mod_avmd/fast_acosf.c b/src/mod/applications/mod_avmd/fast_acosf.c index 6c990d2520..6db0fadad4 100644 --- a/src/mod/applications/mod_avmd/fast_acosf.c +++ b/src/mod/applications/mod_avmd/fast_acosf.c @@ -1,3 +1,4 @@ +#include #include #include #ifndef _MSC_VER @@ -12,6 +13,7 @@ #include #include #include +#include #ifndef _MSC_VER #include #endif @@ -56,57 +58,94 @@ static float strip_float(float f) } #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) diff --git a/src/mod/applications/mod_avmd/fast_acosf.h b/src/mod/applications/mod_avmd/fast_acosf.h index d608050da0..a5f2f0649e 100644 --- a/src/mod/applications/mod_avmd/fast_acosf.h +++ b/src/mod/applications/mod_avmd/fast_acosf.h @@ -1,10 +1,46 @@ #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 diff --git a/src/mod/applications/mod_avmd/mod_avmd.c b/src/mod/applications/mod_avmd/mod_avmd.c index 14848dcb6b..9d6999d236 100644 --- a/src/mod/applications/mod_avmd/mod_avmd.c +++ b/src/mod/applications/mod_avmd/mod_avmd.c @@ -93,7 +93,7 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_avmd_shutdown); 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 */ @@ -206,10 +206,16 @@ static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, sw /*! \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; @@ -218,7 +224,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load) 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; } @@ -227,14 +234,66 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load) 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 @@ -246,7 +305,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load) avmd_start_function, "[start] [stop]", SAF_NONE - ); + ); SWITCH_ADD_API(api_interface, "avmd", "Voicemail beep detection", avmd_api_main, AVMD_SYNTAX); @@ -328,11 +387,34 @@ SWITCH_STANDARD_APP(avmd_start_function) */ 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( @@ -537,13 +619,16 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame) /* 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 */ @@ -551,7 +636,8 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame) 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; @@ -559,7 +645,8 @@ static void avmd_process(avmd_session_t *session, switch_frame_t *frame) 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);