make t38 terminal mode more reliable

This commit is contained in:
Anthony Minessale 2010-09-16 17:01:53 -05:00
parent 19dc1ab0f2
commit 83da7bd318

View File

@ -74,6 +74,8 @@ static struct {
char header[50]; char header[50];
char *prepend_string; char *prepend_string;
char *spool; char *spool;
switch_thread_cond_t *cond;
switch_mutex_t *cond_mutex;
} globals; } globals;
struct pvt_s { struct pvt_s {
@ -121,24 +123,16 @@ static struct {
static int add_pvt(pvt_t *pvt) static int add_pvt(pvt_t *pvt)
{ {
int r = 0; 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) { if (t38_state_list.thread_running) {
switch_mutex_lock(t38_state_list.mutex); switch_mutex_lock(t38_state_list.mutex);
pvt->next = t38_state_list.head; pvt->next = t38_state_list.head;
t38_state_list.head = pvt; t38_state_list.head = pvt;
switch_mutex_unlock(t38_state_list.mutex); 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; return r;
@ -151,9 +145,9 @@ static int del_pvt(pvt_t *del_pvt)
pvt_t *p, *l = NULL; pvt_t *p, *l = NULL;
int r = 0; int r = 0;
if (!t38_state_list.thread_running) goto end;
switch_mutex_lock(t38_state_list.mutex); switch_mutex_lock(t38_state_list.mutex);
for (p = t38_state_list.head; p; p = p->next) { for (p = t38_state_list.head; p; p = p->next) {
if (p == del_pvt) { if (p == del_pvt) {
if (l) { if (l) {
@ -163,42 +157,48 @@ static int del_pvt(pvt_t *del_pvt)
} }
p->next = NULL; p->next = NULL;
r = 1; r = 1;
goto end; break;
} }
l = p; l = p;
} }
end:
switch_mutex_unlock(t38_state_list.mutex); 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) static void *SWITCH_THREAD_FUNC timer_thread_run(switch_thread_t *thread, void *obj)
{ {
switch_timer_t timer = { 0 }; switch_timer_t timer = { 0 };
pvt_t *pvt; pvt_t *pvt;
int samples = 240; int samples = 160;
int ms = 30; 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) { 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) { while(t38_state_list.thread_running) {
switch_mutex_lock(globals.cond_mutex);
switch_mutex_lock(t38_state_list.mutex); switch_mutex_lock(t38_state_list.mutex);
if (!t38_state_list.head) { if (!t38_state_list.head) {
switch_mutex_unlock(t38_state_list.mutex); 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) { 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: 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; 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; return NULL;
} }
@ -468,49 +473,61 @@ static switch_status_t spanfax_init(pvt_t *pvt, transport_mode_t trans_mode)
} }
break; break;
case T38_MODE: 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)); switch_core_session_message_t msg = { 0 };
}
if (pvt->t38_state == NULL) { if (pvt->t38_state == NULL) {
return SWITCH_STATUS_FALSE; pvt->t38_state = (t38_terminal_state_t *) switch_core_session_alloc(pvt->session, sizeof(t38_terminal_state_t));
} }
if (pvt->udptl_state == NULL) { if (pvt->t38_state == NULL) {
pvt->udptl_state = (udptl_state_t *) switch_core_session_alloc(pvt->session, sizeof(udptl_state_t)); 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);
/* 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);
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->udptl_state == NULL) {
t38_terminal_free(pvt->t38_state);
pvt->t38_state = NULL;
return SWITCH_STATUS_FALSE;
}
/* add to timer thread processing */
add_pvt(pvt);
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;
}
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);
}
break; break;
case T38_GATEWAY_MODE: case T38_GATEWAY_MODE:
if (pvt->t38_gateway_state == NULL) { 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); //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); udptl_rx_packet(pvt->udptl_state, read_frame->packet, read_frame->packetlen);
} }
} }
continue; 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) void mod_spandsp_fax_load(switch_memory_pool_t *pool)
{ {
uint32_t sanity = 200;
memset(&globals, 0, sizeof(globals)); memset(&globals, 0, sizeof(globals));
memset(&t38_state_list, 0, sizeof(t38_state_list)); memset(&t38_state_list, 0, sizeof(t38_state_list));
@ -1290,6 +1307,9 @@ void mod_spandsp_fax_load(switch_memory_pool_t *pool)
switch_mutex_init(&globals.mutex, SWITCH_MUTEX_NESTED, globals.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(&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.enable_t38 = 1;
globals.total_sessions = 0; globals.total_sessions = 0;
globals.verbose = 1; globals.verbose = 1;
@ -1301,10 +1321,22 @@ void mod_spandsp_fax_load(switch_memory_pool_t *pool)
strncpy(globals.header, "SpanDSP Fax Header", sizeof(globals.header) - 1); strncpy(globals.header, "SpanDSP Fax Header", sizeof(globals.header) - 1);
load_configuration(0); load_configuration(0);
launch_timer_thread();
while(--sanity && !t38_state_list.thread_running) {
switch_yield(20000);
}
} }
void mod_spandsp_fax_shutdown(void) 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)); memset(&globals, 0, sizeof(globals));
} }