SavedCondition(switch_memory_pool_t *pool=NULL): _pool(pool), _can_delete_pool(false) { if(!_pool) { switch_core_new_memory_pool(&_pool); _can_delete_pool = true; } switch_thread_cond_create(&_condition, _pool); switch_mutex_init(&_mutex, SWITCH_MUTEX_DEFAULT, _pool); }
static switch_status_t timer_init(switch_timer_t *timer) { timer_private_t *private_info; int sanity = 0; while (globals.STARTED == 0) { do_sleep(100000); if (++sanity == 300) { abort(); } } if (globals.RUNNING != 1 || !globals.mutex || timer->interval < 1) { return SWITCH_STATUS_FALSE; } if ((private_info = switch_core_alloc(timer->memory_pool, sizeof(*private_info)))) { switch_mutex_lock(globals.mutex); if (!TIMER_MATRIX[timer->interval].mutex) { switch_mutex_init(&TIMER_MATRIX[timer->interval].mutex, SWITCH_MUTEX_NESTED, module_pool); switch_thread_cond_create(&TIMER_MATRIX[timer->interval].cond, module_pool); } TIMER_MATRIX[timer->interval].count++; switch_mutex_unlock(globals.mutex); timer->private_info = private_info; private_info->start = private_info->reference = TIMER_MATRIX[timer->interval].tick; private_info->start -= 2; /* switch_core_timer_init sets samplecount to samples, this makes first next() step once */ private_info->roll = TIMER_MATRIX[timer->interval].roll; private_info->ready = 1; if (timer->interval > 0 && timer->interval < MS_PER_TICK) { MS_PER_TICK = timer->interval; STEP_MS = 1; STEP_MIC = 1000; TICK_PER_SEC = 10000; switch_time_sync(); } switch_mutex_lock(globals.mutex); globals.timer_count++; if (globals.timer_count == (runtime.tipping_point + 1)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Crossed tipping point of %u, shifting into high-gear.\n", runtime.tipping_point); } switch_mutex_unlock(globals.mutex); return SWITCH_STATUS_SUCCESS; } return SWITCH_STATUS_MEMERR; }
static switch_status_t bind_fetch_agent(switch_xml_section_t section, switch_xml_binding_t **binding) { switch_memory_pool_t *pool = NULL; ei_xml_agent_t *agent; /* create memory pool for this xml search binging (lives for duration of mod_kazoo runtime) */ if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Out of memory: They're not people; they're hippies!\n"); return SWITCH_STATUS_MEMERR; } /* allocate some memory to store the fetch bindings for this section */ if (!(agent = switch_core_alloc(pool, sizeof (*agent)))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Out of memory: Oh, Jesus tap-dancing Christ!\n"); return SWITCH_STATUS_MEMERR; } /* try to bind to the switch */ if (switch_xml_bind_search_function_ret(fetch_handler, section, agent, binding) != SWITCH_STATUS_SUCCESS) { switch_core_destroy_memory_pool(&pool); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not bind to FreeSWITCH %s XML requests\n" ,xml_section_to_string(section)); return SWITCH_STATUS_GENERR; } agent->pool = pool; agent->section = section; switch_thread_rwlock_create(&agent->lock, pool); agent->clients = NULL; switch_mutex_init(&agent->current_client_mutex, SWITCH_MUTEX_DEFAULT, pool); agent->current_client = NULL; switch_mutex_init(&agent->replies_mutex, SWITCH_MUTEX_DEFAULT, pool); switch_thread_cond_create(&agent->new_reply, pool); agent->replies = NULL; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Bound to %s XML requests\n" ,xml_section_to_string(section)); return SWITCH_STATUS_SUCCESS; }
static switch_status_t timerfd_start_interval(interval_timer_t *it, int interval) { struct itimerspec val; struct epoll_event e; int fd; it->users++; if (it->users > 1) return SWITCH_STATUS_SUCCESS; it->tick = 0; switch_mutex_init(&it->mutex, SWITCH_MUTEX_NESTED, module_pool); switch_thread_cond_create(&it->cond, module_pool); fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); if (fd < 0) return SWITCH_STATUS_GENERR; val.it_interval.tv_sec = interval / 1000; val.it_interval.tv_nsec = (interval % 1000) * 1000000; val.it_value.tv_sec = 0; val.it_value.tv_nsec = 100000; if (timerfd_settime(fd, 0, &val, NULL) < 0) { close(fd); return SWITCH_STATUS_GENERR; } e.events = EPOLLIN | EPOLLERR; e.data.ptr = it; if (epoll_ctl(interval_poll_fd, EPOLL_CTL_ADD, fd, &e) < 0) { close(fd); return SWITCH_STATUS_GENERR; } it->fd = fd; return SWITCH_STATUS_SUCCESS; }
/** * Start a new interval timer * @param it the timer * @param interval the timer interval * @return SWITCH_STATUS_SUCCESS if successful */ static switch_status_t interval_timer_start(interval_timer_t *it, int interval) { if (globals.shutdown) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "module is shutting down, ignoring request\n"); return SWITCH_STATUS_GENERR; } if (it->users <= 0) { struct sigevent sigev; struct itimerspec val; int active_id = -1; int i; /* find an available id for this timer */ for (i = 0; i < MAX_ACTIVE_TIMERS && active_id == -1; i++) { switch_mutex_lock(globals.active_timers_mutex); if(globals.active_interval_timers[i] == NULL) { active_id = i; } switch_mutex_unlock(globals.active_timers_mutex); } if (active_id == -1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "no more timers can be created!\n"); return SWITCH_STATUS_GENERR; } it->active_id = active_id; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "starting %d ms timer #%d (%d)\n", it->interval, it->num + 1, it->active_id); /* reset timer data */ it->tick = 0; it->users = 0; /* reuse mutex/condvar */ if (it->mutex == NULL) { switch_mutex_init(&it->mutex, SWITCH_MUTEX_NESTED, globals.pool); switch_thread_cond_create(&it->cond, globals.pool); } /* create the POSIX timer. Will send SIG on each tick. */ memset(&sigev, 0, sizeof(sigev)); sigev.sigev_notify = SIGEV_SIGNAL; sigev.sigev_signo = SIG; sigev.sigev_value.sival_int = active_id; if (timer_create(CLOCK_MONOTONIC, &sigev, &it->timer) == -1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to create timer: %s\n", strerror(errno)); return SWITCH_STATUS_GENERR; } switch_mutex_lock(globals.active_timers_mutex); globals.active_interval_timers[it->active_id] = it; globals.active_timers_count++; switch_mutex_unlock(globals.active_timers_mutex); /* start the timer to tick at interval */ memset(&val, 0, sizeof(val)); val.it_interval.tv_sec = interval / 1000; val.it_interval.tv_nsec = (interval % 1000) * 1000000; val.it_value.tv_sec = 0; val.it_value.tv_nsec = 100000; if (timer_settime(it->timer, 0, &val, NULL) == -1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to start timer: %s\n", strerror(errno)); switch_mutex_lock(globals.active_timers_mutex); globals.active_interval_timers[it->active_id] = NULL; globals.active_timers_count--; switch_mutex_unlock(globals.active_timers_mutex); return SWITCH_STATUS_GENERR; } } it->users++; return SWITCH_STATUS_SUCCESS; }
static switch_status_t vlc_file_open(switch_file_handle_t *handle, const char *path) { vlc_file_context_t *context; libvlc_event_manager_t *mp_event_manager, *m_event_manager; context = switch_core_alloc(handle->memory_pool, sizeof(*context)); context->pool = handle->memory_pool; context->path = switch_core_strdup(context->pool, path); switch_buffer_create_dynamic(&(context->audio_buffer), VLC_BUFFER_SIZE, VLC_BUFFER_SIZE * 8, 0); switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->pool); switch_thread_cond_create(&(context->started), context->pool); if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for reading\n", path); /* Determine if this is a url or a path */ /* TODO: Change this so that it tries local files first, and then if it fails try location. */ if(! strncmp(context->path, "http", 4)){ context->m = libvlc_media_new_location(read_inst, context->path); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is http %s\n", context->path); } else if (! strncmp(context->path, "mms", 3)){ context->m = libvlc_media_new_path(read_inst, context->path); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is mms %s\n", context->path); } else if (! strncmp(context->path, "/", 1)){ context->m = libvlc_media_new_path(read_inst, context->path); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is file %s\n", context->path); } else { context->m = libvlc_media_new_location(read_inst, context->path); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "VLC Path is unknown type %s\n", context->path); } if ( context->m == NULL ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC error opening %s for reading\n", path); return SWITCH_STATUS_GENERR; } context->playing = 0; context->err = 0; context->mp = libvlc_media_player_new_from_media(context->m); if (!handle->samplerate) { handle->samplerate = 16000; } context->samplerate = handle->samplerate; context->channels = handle->channels; libvlc_audio_set_format(context->mp, "S16N", context->samplerate, handle->channels); m_event_manager = libvlc_media_event_manager(context->m); libvlc_event_attach(m_event_manager, libvlc_MediaStateChanged, vlc_media_state_callback, (void *) context); mp_event_manager = libvlc_media_player_event_manager(context->mp); libvlc_event_attach(mp_event_manager, libvlc_MediaPlayerEncounteredError, vlc_mediaplayer_error_callback, (void *) context); libvlc_audio_set_callbacks(context->mp, vlc_auto_play_callback, NULL,NULL,NULL,NULL, (void *) context); libvlc_media_player_play(context->mp); } else if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { const char * opts[10] = { vlc_args, switch_mprintf("--sout=%s", path) }; int opts_count = 10; if ( !handle->samplerate) handle->samplerate = 16000; context->samplerate = handle->samplerate; opts[2] = switch_mprintf("--imem-get=%ld", vlc_imem_get_callback); opts[3] = switch_mprintf("--imem-release=%ld", vlc_imem_release_callback); opts[4] = switch_mprintf("--imem-cat=%d", 4); opts[5] = "--demux=rawaud"; opts[6] = "--rawaud-fourcc=s16l"; opts[7] = switch_mprintf("--rawaud-samplerate=%d", context->samplerate); opts[8] = switch_mprintf("--imem-data=%ld", context); //opts[9] = "--rawaud-channels=1"; /* Prepare to write to an output stream. */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "VLC open %s for writing\n", path); /* load the vlc engine. */ context->inst_out = libvlc_new(opts_count, opts); /* Tell VLC the audio will come from memory, and to use the callbacks to fetch it. */ context->m = libvlc_media_new_location(context->inst_out, "imem/rawaud://"); context->mp = libvlc_media_player_new_from_media(context->m); context->samples = 0; context->pts = 0; context->playing = 1; libvlc_media_player_play(context->mp); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VLC tried to open %s for unknown reason\n", path); return SWITCH_STATUS_GENERR; } handle->private_info = context; return SWITCH_STATUS_SUCCESS; }
int modem_close(modem_t *modem) { int r = 0; switch_status_t was_running = switch_test_flag(modem, MODEM_FLAG_RUNNING); switch_clear_flag(modem, MODEM_FLAG_RUNNING); #ifndef WIN32 if (modem->master > -1) { shutdown(modem->master, 2); close(modem->master); modem->master = -1; #else if (modem->master) { SetEvent(modem->threadAbort); CloseHandle(modem->threadAbort); CloseHandle(modem->master); modem->master = 0; #endif r++; } if (modem->slave > -1) { shutdown(modem->slave, 2); close(modem->slave); modem->slave = -1; r++; } if (modem->t31_state) { t31_free(modem->t31_state); modem->t31_state = NULL; } unlink(modem->devlink); if (was_running) { switch_mutex_lock(globals.mutex); globals.REF_COUNT--; switch_mutex_unlock(globals.mutex); } return r; } switch_status_t modem_init(modem_t *modem, modem_control_handler_t control_handler) { switch_status_t status = SWITCH_STATUS_SUCCESS; #ifdef WIN32 COMMTIMEOUTS timeouts={0}; #endif memset(modem, 0, sizeof(*modem)); modem->master = -1; modem->slave = -1; /* windows will have to try something like: http://com0com.cvs.sourceforge.net/viewvc/com0com/com0com/ReadMe.txt?revision=RELEASED */ #if USE_OPENPTY if (openpty(&modem->master, &modem->slave, NULL, NULL, NULL)) { if (modem->master < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize pty\n"); status = SWITCH_STATUS_FALSE; goto end; } modem->stty = ttyname(modem->slave); #else #if WIN32 modem->slot = 4+globals.NEXT_ID++; /* need work here we start at COM4 for now*/ snprintf(modem->devlink, sizeof(modem->devlink), "COM%d", modem->slot); modem->master = CreateFile(modem->devlink, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0); if(modem->master==INVALID_HANDLE_VALUE) { status = SWITCH_STATUS_FALSE; if(GetLastError()==ERROR_FILE_NOT_FOUND) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port does not exist\n"); goto end; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: Serial port open error\n"); goto end; } #elif !defined(HAVE_POSIX_OPENPT) modem->master = open("/dev/ptmx", O_RDWR); #else modem->master = posix_openpt(O_RDWR | O_NOCTTY); #endif #ifndef WIN32 if (modem->master < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to initialize UNIX98 master pty\n"); } if (grantpt(modem->master) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to grant access to slave pty\n"); } if (unlockpt(modem->master) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to unlock slave pty\n"); } modem->stty = ptsname(modem->master); if (modem->stty == NULL) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to obtain slave pty filename\n"); } modem->slave = open(modem->stty, O_RDWR); if (modem->slave < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to open slave pty %s\n", modem->stty); } #endif #ifdef SOLARIS ioctl(modem->slave, I_PUSH, "ptem"); /* push ptem */ ioctl(modem->slave, I_PUSH, "ldterm"); /* push ldterm*/ #endif #endif #ifndef WIN32 modem->slot = globals.NEXT_ID++; snprintf(modem->devlink, sizeof(modem->devlink), "/dev/FS%d", modem->slot); unlink(modem->devlink); if (symlink(modem->stty, modem->devlink)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Fatal error: failed to create %s symbolic link\n", modem->devlink); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } if (fcntl(modem->master, F_SETFL, fcntl(modem->master, F_GETFL, 0) | O_NONBLOCK)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", ttyname(modem->master)); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } #else timeouts.ReadIntervalTimeout=50; timeouts.ReadTotalTimeoutConstant=50; timeouts.ReadTotalTimeoutMultiplier=10; timeouts.WriteTotalTimeoutConstant=50; timeouts.WriteTotalTimeoutMultiplier=10; SetCommMask(modem->master, EV_RXCHAR); if(!SetCommTimeouts(modem->master, &timeouts)){ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot set up non-blocking read on %s\n", modem->devlink); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } modem->threadAbort = CreateEvent(NULL, TRUE, FALSE, NULL); #endif if (!(modem->t31_state = t31_init(NULL, t31_at_tx_handler, modem, t31_call_control_handler, modem, NULL, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot initialize the T.31 modem\n"); modem_close(modem); status = SWITCH_STATUS_FALSE; goto end; } if (spandsp_globals.modem_verbose) { span_log_set_message_handler(&modem->t31_state->logging, spanfax_log_message, NULL); span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v17_rx.logging, spanfax_log_message, NULL); span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v29_rx.logging, spanfax_log_message, NULL); span_log_set_message_handler(&modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging, spanfax_log_message, NULL); modem->t31_state->logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; modem->t31_state->audio.modems.fast_modems.v17_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; modem->t31_state->audio.modems.fast_modems.v29_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; modem->t31_state->audio.modems.fast_modems.v27ter_rx.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW; } modem->control_handler = control_handler; modem->flags = 0; switch_set_flag(modem, MODEM_FLAG_RUNNING); switch_mutex_init(&modem->mutex, SWITCH_MUTEX_NESTED, globals.pool); switch_mutex_init(&modem->cond_mutex, SWITCH_MUTEX_NESTED, globals.pool); switch_thread_cond_create(&modem->cond, globals.pool); modem_set_state(modem, MODEM_STATE_INIT); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Modem [%s]->[%s] Ready\n", modem->devlink, modem->stty); switch_mutex_lock(globals.mutex); globals.REF_COUNT++; switch_mutex_unlock(globals.mutex); end: return status; } static switch_endpoint_interface_t *modem_endpoint_interface = NULL; struct private_object { switch_mutex_t *mutex; switch_core_session_t *session; switch_channel_t *channel; switch_codec_t read_codec; switch_codec_t write_codec; switch_frame_t read_frame; unsigned char databuf[SWITCH_RECOMMENDED_BUFFER_SIZE]; switch_timer_t timer; modem_t *modem; switch_caller_profile_t *caller_profile; int dead; }; typedef struct private_object private_t; static switch_status_t channel_on_init(switch_core_session_t *session); static switch_status_t channel_on_hangup(switch_core_session_t *session); static switch_status_t channel_on_destroy(switch_core_session_t *session); static switch_status_t channel_on_routing(switch_core_session_t *session); static switch_status_t channel_on_exchange_media(switch_core_session_t *session); static switch_status_t channel_on_soft_execute(switch_core_session_t *session); static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *session, switch_event_t *var_event, switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, switch_call_cause_t *cancel_cause); static switch_status_t channel_read_frame(switch_core_session_t *session, switch_frame_t **frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_write_frame(switch_core_session_t *session, switch_frame_t *frame, switch_io_flag_t flags, int stream_id); static switch_status_t channel_kill_channel(switch_core_session_t *session, int sig); /* State methods they get called when the state changes to the specific state returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it. */ static switch_status_t channel_on_init(switch_core_session_t *session) { switch_channel_t *channel; private_t *tech_pvt = NULL; int to_ticks = 60, ring_ticks = 10, rt = ring_ticks; int rest = 500000; tech_pvt = switch_core_session_get_private(session); switch_assert(tech_pvt != NULL); channel = switch_core_session_get_channel(session); switch_assert(channel != NULL); if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { #ifndef WIN32 int tioflags; #endif char call_time[16]; char call_date[16]; switch_size_t retsize; switch_time_exp_t tm; switch_time_exp_lt(&tm, switch_micro_time_now()); switch_strftime(call_date, &retsize, sizeof(call_date), "%m%d", &tm); switch_strftime(call_time, &retsize, sizeof(call_time), "%H%M", &tm); #ifndef WIN32 ioctl(tech_pvt->modem->slave, TIOCMGET, &tioflags); tioflags |= TIOCM_RI; ioctl(tech_pvt->modem->slave, TIOCMSET, &tioflags); #endif at_reset_call_info(&tech_pvt->modem->t31_state->at_state); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "DATE", call_date); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "TIME", call_time); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NAME", tech_pvt->caller_profile->caller_id_name); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NMBR", tech_pvt->caller_profile->caller_id_number); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "ANID", tech_pvt->caller_profile->ani); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "USER", tech_pvt->caller_profile->username); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "CDID", tech_pvt->caller_profile->context); at_set_call_info(&tech_pvt->modem->t31_state->at_state, "NDID", tech_pvt->caller_profile->destination_number); modem_set_state(tech_pvt->modem, MODEM_STATE_RINGING); t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING); while(to_ticks > 0 && switch_channel_up(channel) && modem_get_state(tech_pvt->modem) == MODEM_STATE_RINGING) { if (--rt <= 0) { t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ALERTING); rt = ring_ticks; } switch_yield(rest); to_ticks--; } if (to_ticks < 1 || modem_get_state(tech_pvt->modem) != MODEM_STATE_ANSWERED) { t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_NO_ANSWER); switch_channel_hangup(channel, SWITCH_CAUSE_NO_ANSWER); } else { t31_call_event(tech_pvt->modem->t31_state, AT_CALL_EVENT_ANSWERED); modem_set_state(tech_pvt->modem, MODEM_STATE_CONNECTED); switch_channel_mark_answered(channel); } } switch_channel_set_state(channel, CS_ROUTING); return SWITCH_STATUS_SUCCESS; }