root/src/ftmod/ftmod_analog_em/ftmod_analog_em.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. FIO_CHANNEL_OUTGOING_CALL_FUNCTION
  2. ftdm_analog_em_start
  3. FIO_CHANNEL_GET_SIG_STATUS_FUNCTION
  4. FIO_SPAN_GET_SIG_STATUS_FUNCTION
  5. FIO_SIG_CONFIGURE_FUNCTION
  6. teletone_handler
  7. ftdm_analog_em_channel_run
  8. process_event
  9. ftdm_analog_em_run
  10. FIO_SIG_LOAD_FUNCTION

   1 /*
   2  * Copyright (c) 2008, Anthony Minessale II
   3  * All rights reserved.
   4  * 
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 
   9  * * Redistributions of source code must retain the above copyright
  10  * notice, this list of conditions and the following disclaimer.
  11  * 
  12  * * Redistributions in binary form must reproduce the above copyright
  13  * notice, this list of conditions and the following disclaimer in the
  14  * documentation and/or other materials provided with the distribution.
  15  * 
  16  * * Neither the name of the original author; nor the names of any contributors
  17  * may be used to endorse or promote products derived from this software
  18  * without specific prior written permission.
  19  * 
  20  * 
  21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  24  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
  25  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32  *
  33  * Contributor(s):
  34  *
  35  * John Wehle (john@feith.com)
  36  *
  37  */
  38 
  39 #include "private/ftdm_core.h"
  40 #include "ftdm_analog_em.h"
  41 
  42 #ifndef localtime_r
  43 struct tm * localtime_r(const time_t *clock, struct tm *result);
  44 #endif
  45 
  46 static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj);
  47 
  48 /**
  49  * \brief Starts an EM channel thread (outgoing call)
  50  * \param ftdmchan Channel to initiate call on
  51  * \return Success or failure
  52  *
  53  * Initialises state, starts tone progress detection and runs the channel in a new a thread.
  54  */
  55 static FIO_CHANNEL_OUTGOING_CALL_FUNCTION(analog_em_outgoing_call)
  56 {
  57         if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {              
  58                 ftdm_channel_clear_needed_tones(ftdmchan);
  59                 ftdm_channel_clear_detected_tones(ftdmchan);
  60 
  61                 ftdm_set_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND);
  62 
  63                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
  64                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_PROGRESS_DETECT, NULL);
  65                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DIALING);
  66                 ftdm_thread_create_detached(ftdm_analog_em_channel_run, ftdmchan);
  67                 return FTDM_SUCCESS;
  68         }
  69 
  70         return FTDM_FAIL;
  71 }
  72 
  73 /**
  74  * \brief Starts an EM span thread (monitor)
  75  * \param span Span to monitor
  76  * \return Success or failure
  77  */
  78 static ftdm_status_t ftdm_analog_em_start(ftdm_span_t *span)
  79 {
  80         ftdm_analog_em_data_t *analog_data = span->signal_data;
  81         ftdm_set_flag(analog_data, FTDM_ANALOG_EM_RUNNING);
  82         return ftdm_thread_create_detached(ftdm_analog_em_run, span);
  83 }
  84 
  85 /**
  86  * \brief Returns the signalling status on a channel
  87  * \param ftdmchan Channel to get status on
  88  * \param status        Pointer to set signalling status
  89  * \return Success or failure
  90  */
  91 
  92 static FIO_CHANNEL_GET_SIG_STATUS_FUNCTION(analog_em_get_channel_sig_status)
  93 {
  94         *status = FTDM_SIG_STATE_UP;
  95         return FTDM_SUCCESS;
  96 }
  97 
  98 /**
  99  * \brief Returns the signalling status on a span
 100  * \param span Span to get status on
 101  * \param status        Pointer to set signalling status
 102  * \return Success or failure
 103  */
 104 
 105 static FIO_SPAN_GET_SIG_STATUS_FUNCTION(analog_em_get_span_sig_status)
 106 {
 107         *status = FTDM_SIG_STATE_UP;
 108         return FTDM_SUCCESS;
 109 }
 110 
 111 /**
 112  * \brief Initialises an EM span from configuration variables
 113  * \param span Span to configure
 114  * \param sig_cb Callback function for event signals
 115  * \param ap List of configuration variables
 116  * \return Success or failure
 117  */
 118 static FIO_SIG_CONFIGURE_FUNCTION(ftdm_analog_em_configure_span)
 119 //ftdm_status_t ftdm_analog_em_configure_span(ftdm_span_t *span, char *tonemap, uint32_t digit_timeout, uint32_t max_dialstr, fio_signal_cb_t sig_cb)
 120 {
 121         ftdm_analog_em_data_t *analog_data;
 122         const char *tonemap = "us";
 123         uint32_t digit_timeout = 10;
 124         uint32_t max_dialstr = 11;
 125         const char *var, *val;
 126         int *intval;
 127 
 128         assert(sig_cb != NULL);
 129 
 130         if (span->signal_type) {
 131                 snprintf(span->last_error, sizeof(span->last_error), "Span is already configured for signalling.");
 132                 return FTDM_FAIL;
 133         }
 134         
 135         analog_data = ftdm_malloc(sizeof(*analog_data));
 136         assert(analog_data != NULL);
 137         memset(analog_data, 0, sizeof(*analog_data));
 138 
 139         while((var = va_arg(ap, char *))) {
 140                 if (!strcasecmp(var, "tonemap")) {
 141                         if (!(val = va_arg(ap, char *))) {
 142                                 break;
 143                         }
 144                         tonemap = val;
 145                 } else if (!strcasecmp(var, "digit_timeout")) {
 146                         if (!(intval = va_arg(ap, int *))) {
 147                                 break;
 148                         }
 149                         digit_timeout = *intval;
 150                 } else if (!strcasecmp(var, "max_dialstr")) {
 151                         if (!(intval = va_arg(ap, int *))) {
 152                                 break;
 153                         }
 154                         max_dialstr = *intval;
 155                 } else {
 156                         snprintf(span->last_error, sizeof(span->last_error), "Unknown parameter [%s]", var);
 157                         return FTDM_FAIL;
 158                 }
 159         }
 160 
 161 
 162         if (digit_timeout < 2000 || digit_timeout > 10000) {
 163                 digit_timeout = 2000;
 164         }
 165 
 166         if (max_dialstr < 2 || max_dialstr > MAX_DIALSTRING) {
 167                 ftdm_log(FTDM_LOG_ERROR, "Invalid max_dialstr, setting to %d\n", MAX_DIALSTRING);
 168                 max_dialstr = MAX_DIALSTRING;
 169         }
 170 
 171         span->start = ftdm_analog_em_start;
 172         analog_data->digit_timeout = digit_timeout;
 173         analog_data->max_dialstr = max_dialstr;
 174         span->signal_cb = sig_cb;
 175         span->signal_type = FTDM_SIGTYPE_ANALOG;
 176         span->signal_data = analog_data;
 177         span->outgoing_call = analog_em_outgoing_call;
 178         span->get_channel_sig_status = analog_em_get_channel_sig_status;
 179         span->get_span_sig_status = analog_em_get_span_sig_status;
 180         ftdm_span_load_tones(span, tonemap);
 181 
 182         return FTDM_SUCCESS;
 183 
 184 }
 185 
 186 /**
 187  * \brief Retrieves tone generation output to be sent
 188  * \param ts Teletone generator
 189  * \param map Tone map
 190  * \return -1 on error, 0 on success
 191  */
 192 static int teletone_handler(teletone_generation_session_t *ts, teletone_tone_map_t *map)
 193 {
 194         ftdm_buffer_t *dt_buffer = ts->user_data;
 195         int wrote;
 196 
 197         if (!dt_buffer) {
 198                 return -1;
 199         }
 200         wrote = teletone_mux_tones(ts, map);
 201         ftdm_buffer_write(dt_buffer, ts->buffer, wrote * 2);
 202         return 0;
 203 }
 204 
 205 /**
 206  * \brief Main thread function for EM channel (outgoing call)
 207  * \param me Current thread
 208  * \param obj Channel to run in this thread
 209  */
 210 static void *ftdm_analog_em_channel_run(ftdm_thread_t *me, void *obj)
 211 {
 212         ftdm_channel_t *ftdmchan = (ftdm_channel_t *) obj;
 213         ftdm_buffer_t *dt_buffer = NULL;
 214         teletone_generation_session_t ts;
 215         uint8_t frame[1024];
 216         ftdm_size_t len, rlen;
 217         ftdm_tone_type_t tt = FTDM_TONE_DTMF;
 218         char dtmf[128] = "";
 219         ftdm_size_t dtmf_offset = 0;
 220         ftdm_analog_em_data_t *analog_data = ftdmchan->span->signal_data;
 221         ftdm_channel_t *closed_chan;
 222         uint32_t state_counter = 0, elapsed = 0, collecting = 0, interval = 0, last_digit = 0, indicate = 0, dial_timeout = 30000;
 223         ftdm_sigmsg_t sig;
 224         ftdm_status_t status;
 225         
 226         ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread starting.\n");
 227 
 228         ts.buffer = NULL;
 229 
 230         if (ftdm_channel_open_chan(ftdmchan) != FTDM_SUCCESS) {
 231                 ftdm_log(FTDM_LOG_ERROR, "OPEN ERROR [%s]\n", ftdmchan->last_error);
 232                 goto done;
 233         }
 234 
 235         if (ftdm_buffer_create(&dt_buffer, 1024, 3192, 0) != FTDM_SUCCESS) {
 236                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "memory error!");
 237                 ftdm_log(FTDM_LOG_ERROR, "MEM ERROR\n");
 238                 goto done;
 239         }
 240 
 241         if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_ENABLE_DTMF_DETECT, &tt) != FTDM_SUCCESS) {
 242                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "error initilizing tone detector!");
 243                 ftdm_log(FTDM_LOG_ERROR, "TONE ERROR\n");
 244                 goto done;
 245         }
 246 
 247         ftdm_set_flag_locked(ftdmchan, FTDM_CHANNEL_INTHREAD);
 248         teletone_init_session(&ts, 0, teletone_handler, dt_buffer);
 249         ts.rate = 8000;
 250 #if 0
 251         ts.debug = 1;
 252         ts.debug_stream = stdout;
 253 #endif
 254         ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_INTERVAL, &interval);
 255         ftdm_buffer_set_loops(dt_buffer, -1);
 256         
 257         memset(&sig, 0, sizeof(sig));
 258         sig.chan_id = ftdmchan->chan_id;
 259         sig.span_id = ftdmchan->span_id;
 260         sig.channel = ftdmchan;
 261         
 262         assert(interval != 0);
 263 
 264         while (ftdm_running() && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_INTHREAD)) {
 265                 ftdm_wait_flag_t flags = FTDM_READ;
 266                 ftdm_size_t dlen = 0;
 267                 
 268                 len = sizeof(frame);
 269                 
 270                 elapsed += interval;
 271                 state_counter += interval;
 272                 
 273                 if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_STATE_CHANGE)) {
 274                         switch(ftdmchan->state) {
 275                         case FTDM_CHANNEL_STATE_DIALING:
 276                                 {
 277                                         if (! ftdmchan->needed_tones[FTDM_TONEMAP_RING]
 278                                                 && ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
 279                                                 if (ftdm_strlen_zero(ftdmchan->caller_data.dnis.digits)) {
 280                                                         ftdm_log(FTDM_LOG_ERROR, "No Digits to send!\n");
 281                                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
 282                                                 } else {
 283                                                         if (ftdm_channel_command(ftdmchan, FTDM_COMMAND_SEND_DTMF, ftdmchan->caller_data.dnis.digits) != FTDM_SUCCESS) {
 284                                                                 ftdm_log(FTDM_LOG_ERROR, "Send Digits Failed [%s]\n", ftdmchan->last_error);
 285                                                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
 286                                                         } else {
 287                                                                 state_counter = 0;
 288                                                                 ftdmchan->needed_tones[FTDM_TONEMAP_RING] = 1;
 289                                                                 ftdmchan->needed_tones[FTDM_TONEMAP_BUSY] = 1;
 290                                                                 ftdmchan->needed_tones[FTDM_TONEMAP_FAIL1] = 1;
 291                                                                 ftdmchan->needed_tones[FTDM_TONEMAP_FAIL2] = 1;
 292                                                                 ftdmchan->needed_tones[FTDM_TONEMAP_FAIL3] = 1;
 293                                                                 dial_timeout = ((ftdmchan->dtmf_on + ftdmchan->dtmf_off) * strlen(ftdmchan->caller_data.dnis.digits)) + 2000;
 294                                                         }
 295                                                 }
 296                                                 break;
 297                                         }
 298                                         if (state_counter > dial_timeout) {
 299                                                 if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_WINK)) {
 300                                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
 301                                                 } else {
 302                                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
 303                                                 }
 304                                         } 
 305                                 }
 306                                 break;
 307                         case FTDM_CHANNEL_STATE_DIALTONE:
 308                                 {
 309                                         if (state_counter > 10000) {
 310                                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
 311                                         }
 312                                 }
 313                                 break;
 314                         case FTDM_CHANNEL_STATE_BUSY:
 315                                 {
 316                                         if (state_counter > 20000) {
 317                                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_ATTN);
 318                                         }
 319                                 }
 320                                 break;
 321                         case FTDM_CHANNEL_STATE_ATTN:
 322                                 {
 323                                         if (state_counter > 20000) {
 324                                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 325                                         }
 326                                 }
 327                                 break;
 328                         case FTDM_CHANNEL_STATE_HANGUP:
 329                                 {
 330                                         if (state_counter > 500) {
 331                                                 if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && 
 332                                                         (ftdmchan->last_state == FTDM_CHANNEL_STATE_RING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE 
 333                                                          || ftdmchan->last_state >= FTDM_CHANNEL_STATE_IDLE)) {
 334                                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
 335                                                 } else {
 336                                                         ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CLEARING;
 337                                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 338                                                 }
 339                                         }
 340                                 }
 341                                 break;
 342                         case FTDM_CHANNEL_STATE_UP:
 343                         case FTDM_CHANNEL_STATE_IDLE:
 344                                 {
 345                                         ftdm_sleep(interval);
 346                                         continue;
 347                                 }
 348                                 break;
 349                         case FTDM_CHANNEL_STATE_DOWN:
 350                                 {
 351                                         goto done;
 352                                 }
 353                                 break;
 354                         default:
 355                                 break;
 356                         }
 357                 } else {
 358                         ftdm_clear_flag_locked(ftdmchan, FTDM_CHANNEL_STATE_CHANGE);
 359                         ftdm_clear_flag_locked(ftdmchan->span, FTDM_SPAN_STATE_CHANGE);
 360                         ftdm_channel_complete_state(ftdmchan);
 361                         indicate = 0;
 362                         state_counter = 0;
 363 
 364                         ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", 
 365                                         ftdmchan->span_id, ftdmchan->chan_id,
 366                                         ftdm_channel_state2str(ftdmchan->state));
 367                         switch(ftdmchan->state) {
 368                         case FTDM_CHANNEL_STATE_UP:
 369                                 {
 370                                         ftdm_channel_use(ftdmchan);
 371                                         ftdm_channel_clear_needed_tones(ftdmchan);
 372                                         ftdm_channel_flush_dtmf(ftdmchan);
 373 
 374                                         if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
 375                                                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
 376                                         }
 377 
 378                                         sig.event_id = FTDM_SIGEVENT_UP;
 379 
 380                                         ftdm_span_send_signal(ftdmchan->span, &sig);
 381                                         continue;
 382                                 }
 383                                 break;
 384                         case FTDM_CHANNEL_STATE_DIALING:
 385                                 {
 386                                         ftdm_channel_use(ftdmchan);
 387                                 }
 388                                 break;
 389                         case FTDM_CHANNEL_STATE_IDLE:
 390                                 {
 391                                         ftdm_channel_use(ftdmchan);
 392 
 393                                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 394                                                 ftdm_set_string(ftdmchan->caller_data.dnis.digits, ftdmchan->chan_number);
 395                                         } else {
 396                                                 ftdm_set_string(ftdmchan->caller_data.dnis.digits, dtmf);
 397                                         }
 398 
 399                                         sig.event_id = FTDM_SIGEVENT_START;
 400 
 401                                         ftdm_span_send_signal(ftdmchan->span, &sig);
 402                                         continue;
 403                                 }
 404                                 break;
 405                         case FTDM_CHANNEL_STATE_DOWN:
 406                                 {
 407                                         sig.event_id = FTDM_SIGEVENT_STOP;
 408                                         ftdm_span_send_signal(ftdmchan->span, &sig);
 409                                         goto done;
 410                                 }
 411                                 break;
 412                         case FTDM_CHANNEL_STATE_DIALTONE:
 413                                 {
 414                                         memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
 415                                         *dtmf = '\0';
 416                                         dtmf_offset = 0;
 417                                         ftdm_buffer_zero(dt_buffer);
 418                                         teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_DIAL]);
 419                                         indicate = 1;
 420 
 421                                         ftdm_channel_command(ftdmchan, FTDM_COMMAND_WINK, NULL);
 422                                 }
 423                                 break;
 424                         case FTDM_CHANNEL_STATE_RING:
 425                                 {
 426                                         ftdm_buffer_zero(dt_buffer);
 427                                         teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
 428                                         indicate = 1;
 429                                 }
 430                                 break;
 431                         case FTDM_CHANNEL_STATE_BUSY:
 432                                 {
 433                                         ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 434                                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 435                                                 ftdm_buffer_zero(dt_buffer);
 436                                                 teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_BUSY]);
 437                                                 indicate = 1;
 438                                         } else {
 439                                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 440                                         }
 441                                 }
 442                                 break;
 443                         case FTDM_CHANNEL_STATE_ATTN:
 444                                 {
 445                                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 446                                                 ftdm_buffer_zero(dt_buffer);
 447                                                 teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_ATTN]);
 448                                                 indicate = 1;
 449                                         } else {
 450                                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 451                                         }
 452                                 }
 453                                 break;
 454                         default:
 455                                 break;
 456                         }
 457                 }
 458 
 459 
 460                 if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE || ftdmchan->state == FTDM_CHANNEL_STATE_COLLECT) {
 461                         if ((dlen = ftdm_channel_dequeue_dtmf(ftdmchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
 462 
 463                                 if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE) {
 464                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
 465                                         collecting = 1;
 466                                 }
 467                                 dtmf_offset = strlen(dtmf);
 468                                 last_digit = elapsed;
 469                                 sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
 470                                 sig.raw_data = dtmf;
 471                                 if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
 472                                         collecting = 0;
 473                                 }
 474                         }
 475                 }
 476 
 477 
 478                 if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) {
 479                         ftdm_log(FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
 480                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_IDLE);
 481                         last_digit = 0;
 482                         collecting = 0;
 483                 }
 484 
 485                 if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) {
 486                         continue;
 487                 }
 488 
 489                 if (!(flags & FTDM_READ)) {
 490                         continue;
 491                 }
 492 
 493                 if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) {
 494                         ftdm_log(FTDM_LOG_ERROR, "READ ERROR [%s]\n", ftdmchan->last_error);
 495                         goto done;
 496                 }
 497 
 498                 if (ftdmchan->detected_tones[0]) {
 499                         int i;
 500                         
 501                         for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
 502                                 if (ftdmchan->detected_tones[i]) {
 503                                         ftdm_log(FTDM_LOG_DEBUG, "Detected tone %s on %d:%d\n", ftdm_tonemap2str(i), ftdmchan->span_id, ftdmchan->chan_id);
 504                                 }
 505                         }
 506                         
 507                         if (ftdmchan->detected_tones[FTDM_TONEMAP_BUSY] || 
 508                                 ftdmchan->detected_tones[FTDM_TONEMAP_FAIL1] ||
 509                                 ftdmchan->detected_tones[FTDM_TONEMAP_FAIL2] ||
 510                                 ftdmchan->detected_tones[FTDM_TONEMAP_FAIL3] ||
 511                                 ftdmchan->detected_tones[FTDM_TONEMAP_ATTN]
 512                                 ) {
 513                                 ftdm_log(FTDM_LOG_ERROR, "Failure indication detected!\n");
 514                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
 515                         } else if (ftdmchan->detected_tones[FTDM_TONEMAP_RING]) {
 516                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
 517                         }
 518                         
 519                         ftdm_channel_clear_detected_tones(ftdmchan);
 520                 }
 521 
 522                 if ((ftdmchan->dtmf_buffer && ftdm_buffer_inuse(ftdmchan->dtmf_buffer))) {
 523                         rlen = len;
 524                         memset(frame, 0, len);
 525                         ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
 526                         continue;
 527                 }
 528                 
 529                 if (!indicate) {
 530                         continue;
 531                 }
 532 
 533                 if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
 534                         len *= 2;
 535                 }
 536 
 537                 rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
 538 
 539                 if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
 540                         fio_codec_t codec_func = NULL;
 541 
 542                         if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
 543                                 codec_func = fio_slin2ulaw;
 544                         } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
 545                                 codec_func = fio_slin2alaw;
 546                         }
 547 
 548                         if (codec_func) {
 549                                 status = codec_func(frame, sizeof(frame), &rlen);
 550                         } else {
 551                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
 552                                 goto done;
 553                         }
 554                 }
 555 
 556                 ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
 557         }
 558 
 559  done:
 560 
 561         ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
 562         
 563         closed_chan = ftdmchan;
 564         ftdm_channel_close(&ftdmchan);
 565 
 566         ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
 567 
 568         if (ts.buffer) {
 569                 teletone_destroy_session(&ts);
 570         }
 571 
 572         if (dt_buffer) {
 573                 ftdm_buffer_destroy(&dt_buffer);
 574         }
 575 
 576         ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
 577 
 578         ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread ended.\n");
 579 
 580         return NULL;
 581 }
 582 
 583 /**
 584  * \brief Processes EM events coming from ftdmtel/dahdi
 585  * \param span Span on which the event was fired
 586  * \param event Event to be treated
 587  * \return Success or failure
 588  */
 589 static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
 590 {
 591         ftdm_sigmsg_t sig;
 592         int locked = 0;
 593         
 594         memset(&sig, 0, sizeof(sig));
 595         sig.chan_id = event->channel->chan_id;
 596         sig.span_id = event->channel->span_id;
 597         sig.channel = event->channel;
 598 
 599 
 600         ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", 
 601                         ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
 602 
 603         ftdm_mutex_lock(event->channel->mutex);
 604         locked++;
 605 
 606         switch(event->enum_id) {
 607         case FTDM_OOB_ONHOOK:
 608                 {
 609                         if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
 610                                 ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
 611                         }
 612 
 613                 }
 614                 break;
 615         case FTDM_OOB_OFFHOOK:
 616                 {
 617                         if (ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
 618                                 ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
 619                         } else {
 620                                 ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
 621                                 ftdm_mutex_unlock(event->channel->mutex);
 622                                 locked = 0;
 623                                 ftdm_thread_create_detached(ftdm_analog_em_channel_run, event->channel);
 624                         }
 625                 break;
 626                 }
 627         case FTDM_OOB_WINK:
 628                 {
 629                         if (event->channel->state != FTDM_CHANNEL_STATE_DIALING) {
 630                                 ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
 631                         } else {
 632                                 ftdm_set_flag_locked(event->channel, FTDM_CHANNEL_WINK);
 633                         }
 634 
 635                 }
 636                 break;
 637         }
 638         if (locked) {
 639                 ftdm_mutex_unlock(event->channel->mutex);
 640         }
 641         return FTDM_SUCCESS;
 642 }
 643 
 644 /**
 645  * \brief Main thread function for EM span (monitor)
 646  * \param me Current thread
 647  * \param obj Span to run in this thread
 648  */
 649 static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj)
 650 {
 651         ftdm_span_t *span = (ftdm_span_t *) obj;
 652         ftdm_analog_em_data_t *analog_data = span->signal_data;
 653 
 654         ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM thread starting.\n");
 655 
 656         while(ftdm_running() && ftdm_test_flag(analog_data, FTDM_ANALOG_EM_RUNNING)) {
 657                 int waitms = 10;
 658                 ftdm_status_t status;
 659 
 660                 status = ftdm_span_poll_event(span, waitms);
 661                 
 662                 switch(status) {
 663                 case FTDM_SUCCESS:
 664                         {
 665                                 ftdm_event_t *event;
 666                                 while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
 667                                         if (event->enum_id == FTDM_OOB_NOOP) {
 668                                                 continue;
 669                                         }
 670                                         if (process_event(span, event) != FTDM_SUCCESS) {
 671                                                 goto end;
 672                                         }
 673                                 }
 674                         }
 675                         break;
 676                 case FTDM_FAIL:
 677                         {
 678                                 ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
 679                         }
 680                         break;
 681                 default:
 682                         break;
 683                 }
 684 
 685         }
 686 
 687  end:
 688 
 689         ftdm_clear_flag(analog_data, FTDM_ANALOG_EM_RUNNING);
 690         
 691         ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM thread ending.\n");
 692 
 693         return NULL;
 694 }
 695 
 696 /**
 697  * \brief FreeTDM analog EM module initialisation
 698  * \return Success
 699  */
 700 static FIO_SIG_LOAD_FUNCTION(ftdm_analog_em_init)
 701 {
 702         return FTDM_SUCCESS;
 703 }
 704 
 705 /**
 706  * \brief FreeTDM analog EM module definition
 707  */
 708 EX_DECLARE_DATA ftdm_module_t ftdm_module = {
 709         "analog_em",
 710         NULL,
 711         NULL,
 712         ftdm_analog_em_init,
 713         ftdm_analog_em_configure_span,
 714         NULL
 715 };
 716 
 717 
 718 /* For Emacs:
 719  * Local Variables:
 720  * mode:c
 721  * indent-tabs-mode:t
 722  * tab-width:4
 723  * c-basic-offset:4
 724  * End:
 725  * For VIM:
 726  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
 727  */

/* [<][>][^][v][top][bottom][index][help] */