From 83da7bd3188ddcb92b10ddc4e07792c40aa4885f Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 16 Sep 2010 17:01:53 -0500 Subject: [PATCH] make t38 terminal mode more reliable --- .../mod_spandsp/mod_spandsp_fax.c | 172 +++++++++++------- 1 file changed, 102 insertions(+), 70 deletions(-) diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c index 52ba941d43..1c825ec8dd 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c @@ -74,6 +74,8 @@ static struct { char header[50]; char *prepend_string; char *spool; + switch_thread_cond_t *cond; + switch_mutex_t *cond_mutex; } globals; struct pvt_s { @@ -121,24 +123,16 @@ static struct { static int add_pvt(pvt_t *pvt) { int r = 0; - uint32_t sanity = 50; - - switch_mutex_lock(t38_state_list.mutex); - if (!t38_state_list.thread_running) { - - launch_timer_thread(); - - while(--sanity && !t38_state_list.thread_running) { - switch_yield(10000); - } - } - switch_mutex_unlock(t38_state_list.mutex); if (t38_state_list.thread_running) { switch_mutex_lock(t38_state_list.mutex); pvt->next = t38_state_list.head; t38_state_list.head = pvt; switch_mutex_unlock(t38_state_list.mutex); + r = 1; + switch_thread_cond_broadcast(globals.cond); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error launching thread\n"); } return r; @@ -151,9 +145,9 @@ static int del_pvt(pvt_t *del_pvt) pvt_t *p, *l = NULL; int r = 0; - if (!t38_state_list.thread_running) goto end; - + switch_mutex_lock(t38_state_list.mutex); + for (p = t38_state_list.head; p; p = p->next) { if (p == del_pvt) { if (l) { @@ -163,42 +157,48 @@ static int del_pvt(pvt_t *del_pvt) } p->next = NULL; r = 1; - goto end; + break; } l = p; } - end: - switch_mutex_unlock(t38_state_list.mutex); - return r; + switch_thread_cond_broadcast(globals.cond); + return r; } static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *obj) { switch_timer_t timer = { 0 }; pvt_t *pvt; - int samples = 240; - int ms = 30; + int samples = 160; + int ms = 20; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "timer thread started.\n"); + switch_mutex_lock(t38_state_list.mutex); + t38_state_list.thread_running = 1; + switch_mutex_unlock(t38_state_list.mutex); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FAX timer thread started.\n"); if (switch_core_timer_init(&timer, "soft", ms, samples, NULL) != SWITCH_STATUS_SUCCESS) { - return NULL; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "timer init failed.\n"); + goto end; } - t38_state_list.thread_running = 1; - while(t38_state_list.thread_running) { + switch_mutex_lock(globals.cond_mutex); + switch_mutex_lock(t38_state_list.mutex); if (!t38_state_list.head) { switch_mutex_unlock(t38_state_list.mutex); - goto end; + switch_thread_cond_wait(globals.cond, globals.cond_mutex); + switch_core_timer_sync(&timer); + continue; } for (pvt = t38_state_list.head; pvt; pvt = pvt->next) { @@ -214,10 +214,15 @@ static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void * end: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "timer thread ended.\n"); - + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FAX timer thread ended.\n"); + + switch_mutex_lock(t38_state_list.mutex); t38_state_list.thread_running = 0; - switch_core_timer_destroy(&timer); + switch_mutex_unlock(t38_state_list.mutex); + + if (timer.timer_interface) { + switch_core_timer_destroy(&timer); + } return NULL; } @@ -468,49 +473,61 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode) } break; case T38_MODE: - if (pvt->t38_state == NULL) { - pvt->t38_state = (t38_terminal_state_t *) switch_core_session_alloc(pvt->session, sizeof(t38_terminal_state_t)); - } - if (pvt->t38_state == NULL) { - return SWITCH_STATUS_FALSE; - } - if (pvt->udptl_state == NULL) { - pvt->udptl_state = (udptl_state_t *) switch_core_session_alloc(pvt->session, sizeof(udptl_state_t)); - } - if (pvt->udptl_state == NULL) { - t38_terminal_free(pvt->t38_state); - pvt->t38_state = NULL; - return SWITCH_STATUS_FALSE; - } + { + switch_core_session_message_t msg = { 0 }; - /* add to timer thread processing */ - add_pvt(pvt); + if (pvt->t38_state == NULL) { + pvt->t38_state = (t38_terminal_state_t *) switch_core_session_alloc(pvt->session, sizeof(t38_terminal_state_t)); + } + if (pvt->t38_state == NULL) { + return SWITCH_STATUS_FALSE; + } + if (pvt->udptl_state == NULL) { + pvt->udptl_state = (udptl_state_t *) switch_core_session_alloc(pvt->session, sizeof(udptl_state_t)); + } + if (pvt->udptl_state == NULL) { + t38_terminal_free(pvt->t38_state); + pvt->t38_state = NULL; + return SWITCH_STATUS_FALSE; + } + + t38 = pvt->t38_state; + t30 = t38_terminal_get_t30_state(t38); + + memset(t38, 0, sizeof(t38_terminal_state_t)); + + if (t38_terminal_init(t38, pvt->caller, t38_tx_packet_handler, pvt) == NULL) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my T.38 structs\n"); + return SWITCH_STATUS_FALSE; + } + + pvt->t38_core = t38_terminal_get_t38_core_state(pvt->t38_state); + + if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3, + (udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet, (void *) pvt->t38_core) == NULL) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my UDPTL structs\n"); + return SWITCH_STATUS_FALSE; + } + + msg.from = __FILE__; + msg.message_id = SWITCH_MESSAGE_INDICATE_UDPTL_MODE; + switch_core_session_receive_message(pvt->session, &msg); - t38 = pvt->t38_state; - t30 = t38_terminal_get_t30_state(t38); + /* add to timer thread processing */ + if (!add_pvt(pvt)) { + if (channel) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } + } + + span_log_set_message_handler(&t38->logging, spanfax_log_message); + span_log_set_message_handler(&t30->logging, spanfax_log_message); - memset(t38, 0, sizeof(t38_terminal_state_t)); - - if (t38_terminal_init(t38, pvt->caller, t38_tx_packet_handler, pvt) == NULL) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my T.38 structs\n"); - return SWITCH_STATUS_FALSE; - } - - pvt->t38_core = t38_terminal_get_t38_core_state(pvt->t38_state); - - if (udptl_init(pvt->udptl_state, UDPTL_ERROR_CORRECTION_REDUNDANCY, 3, 3, - (udptl_rx_packet_handler_t *) t38_core_rx_ifp_packet, (void *) pvt->t38_core) == NULL) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Cannot initialize my UDPTL structs\n"); - return SWITCH_STATUS_FALSE; - } - - span_log_set_message_handler(&t38->logging, spanfax_log_message); - span_log_set_message_handler(&t30->logging, spanfax_log_message); - - if (pvt->verbose) { - span_log_set_level(&t38->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); - } + if (pvt->verbose) { + span_log_set_level(&t38->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + span_log_set_level(&t30->logging, SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW); + } + } break; case T38_GATEWAY_MODE: if (pvt->t38_gateway_state == NULL) { @@ -1145,8 +1162,6 @@ void mod_spandsp_fax_process_fax(switch_core_session_t *session, const char *dat //switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "READ %d udptl bytes\n", read_frame->packetlen); udptl_rx_packet(pvt->udptl_state, read_frame->packet, read_frame->packetlen); - - } } continue; @@ -1282,6 +1297,8 @@ void mod_spandsp_fax_event_handler(switch_event_t *event) void mod_spandsp_fax_load(switch_memory_pool_t *pool) { + uint32_t sanity = 200; + memset(&globals, 0, sizeof(globals)); memset(&t38_state_list, 0, sizeof(t38_state_list)); @@ -1289,6 +1306,9 @@ void mod_spandsp_fax_load(switch_memory_pool_t *pool) switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.pool); switch_mutex_init(&t38_state_list.mutex, SWITCH_MUTEX_NESTED, globals.pool); + + switch_mutex_init(&globals.cond_mutex, SWITCH_MUTEX_NESTED, globals.pool); + switch_thread_cond_create(&globals.cond, globals.pool); globals.enable_t38 = 1; globals.total_sessions = 0; @@ -1301,10 +1321,22 @@ void mod_spandsp_fax_load(switch_memory_pool_t *pool) strncpy(globals.header, "SpanDSP Fax Header", sizeof(globals.header) - 1); load_configuration(0); + + + launch_timer_thread(); + + while(--sanity && !t38_state_list.thread_running) { + switch_yield(20000); + } } void mod_spandsp_fax_shutdown(void) { + switch_status_t tstatus = SWITCH_STATUS_SUCCESS; + + t38_state_list.thread_running = 0; + switch_thread_cond_broadcast(globals.cond); + switch_thread_join(&tstatus, t38_state_list.thread); memset(&globals, 0, sizeof(globals)); }