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_RINGING || ftdmchan->last_state == FTDM_CHANNEL_STATE_DIALTONE 
 333                                                          || ftdmchan->last_state == FTDM_CHANNEL_STATE_RING)) {
 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_RING:
 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->span, FTDM_SPAN_STATE_CHANGE);
 359                         ftdm_channel_complete_state(ftdmchan);
 360                         indicate = 0;
 361                         state_counter = 0;
 362 
 363                         ftdm_log(FTDM_LOG_DEBUG, "Executing state handler on %d:%d for %s\n", 
 364                                         ftdmchan->span_id, ftdmchan->chan_id,
 365                                         ftdm_channel_state2str(ftdmchan->state));
 366                         switch(ftdmchan->state) {
 367                         case FTDM_CHANNEL_STATE_UP:
 368                                 {
 369                                         ftdm_channel_use(ftdmchan);
 370                                         ftdm_channel_clear_needed_tones(ftdmchan);
 371                                         ftdm_channel_flush_dtmf(ftdmchan);
 372 
 373                                         if (!ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK)) {
 374                                                 ftdm_channel_command(ftdmchan, FTDM_COMMAND_OFFHOOK, NULL);
 375                                         }
 376 
 377                                         sig.event_id = FTDM_SIGEVENT_UP;
 378 
 379                                         ftdm_span_send_signal(ftdmchan->span, &sig);
 380                                         continue;
 381                                 }
 382                                 break;
 383                         case FTDM_CHANNEL_STATE_DIALING:
 384                                 {
 385                                         ftdm_channel_use(ftdmchan);
 386                                 }
 387                                 break;
 388                         case FTDM_CHANNEL_STATE_RING:
 389                                 {
 390                                         ftdm_channel_use(ftdmchan);
 391 
 392                                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 393                                                 ftdm_set_string(ftdmchan->caller_data.dnis.digits, ftdmchan->chan_number);
 394                                         } else {
 395                                                 ftdm_set_string(ftdmchan->caller_data.dnis.digits, dtmf);
 396                                         }
 397 
 398                                         sig.event_id = FTDM_SIGEVENT_START;
 399 
 400                                         ftdm_span_send_signal(ftdmchan->span, &sig);
 401                                         continue;
 402                                 }
 403                                 break;
 404                         case FTDM_CHANNEL_STATE_DOWN:
 405                                 {
 406                                         sig.event_id = FTDM_SIGEVENT_STOP;
 407                                         ftdm_span_send_signal(ftdmchan->span, &sig);
 408                                         goto done;
 409                                 }
 410                                 break;
 411                         case FTDM_CHANNEL_STATE_DIALTONE:
 412                                 {
 413                                         memset(&ftdmchan->caller_data, 0, sizeof(ftdmchan->caller_data));
 414                                         *dtmf = '\0';
 415                                         dtmf_offset = 0;
 416                                         ftdm_buffer_zero(dt_buffer);
 417                                         teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_DIAL]);
 418                                         indicate = 1;
 419 
 420                                         ftdm_channel_command(ftdmchan, FTDM_COMMAND_WINK, NULL);
 421                                 }
 422                                 break;
 423                         case FTDM_CHANNEL_STATE_RINGING:
 424                                 {
 425                                         ftdm_buffer_zero(dt_buffer);
 426                                         teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_RING]);
 427                                         indicate = 1;
 428                                 }
 429                                 break;
 430                         case FTDM_CHANNEL_STATE_BUSY:
 431                                 {
 432                                         ftdmchan->caller_data.hangup_cause = FTDM_CAUSE_NORMAL_CIRCUIT_CONGESTION;
 433                                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 434                                                 ftdm_buffer_zero(dt_buffer);
 435                                                 teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_BUSY]);
 436                                                 indicate = 1;
 437                                         } else {
 438                                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 439                                         }
 440                                 }
 441                                 break;
 442                         case FTDM_CHANNEL_STATE_ATTN:
 443                                 {
 444                                         if (ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OFFHOOK) && !ftdm_test_flag(ftdmchan, FTDM_CHANNEL_OUTBOUND)) {
 445                                                 ftdm_buffer_zero(dt_buffer);
 446                                                 teletone_run(&ts, ftdmchan->span->tone_map[FTDM_TONEMAP_ATTN]);
 447                                                 indicate = 1;
 448                                         } else {
 449                                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_DOWN);
 450                                         }
 451                                 }
 452                                 break;
 453                         default:
 454                                 break;
 455                         }
 456                 }
 457 
 458 
 459                 if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE || ftdmchan->state == FTDM_CHANNEL_STATE_COLLECT) {
 460                         if ((dlen = ftdm_channel_dequeue_dtmf(ftdmchan, dtmf + dtmf_offset, sizeof(dtmf) - strlen(dtmf)))) {
 461 
 462                                 if (ftdmchan->state == FTDM_CHANNEL_STATE_DIALTONE) {
 463                                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_COLLECT);
 464                                         collecting = 1;
 465                                 }
 466                                 dtmf_offset = strlen(dtmf);
 467                                 last_digit = elapsed;
 468                                 sig.event_id = FTDM_SIGEVENT_COLLECTED_DIGIT;
 469                                 ftdm_set_string(sig.ev_data.collected.digits, dtmf);
 470                                 if (ftdm_span_send_signal(ftdmchan->span, &sig) == FTDM_BREAK) {
 471                                         collecting = 0;
 472                                 }
 473                         }
 474                 }
 475 
 476 
 477                 if (last_digit && (!collecting || ((elapsed - last_digit > analog_data->digit_timeout) || strlen(dtmf) > analog_data->max_dialstr))) {
 478                         ftdm_log(FTDM_LOG_DEBUG, "Number obtained [%s]\n", dtmf);
 479                         ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_RING);
 480                         last_digit = 0;
 481                         collecting = 0;
 482                 }
 483 
 484                 if (ftdm_channel_wait(ftdmchan, &flags, interval * 2) != FTDM_SUCCESS) {
 485                         continue;
 486                 }
 487 
 488                 if (!(flags & FTDM_READ)) {
 489                         continue;
 490                 }
 491 
 492                 if (ftdm_channel_read(ftdmchan, frame, &len) != FTDM_SUCCESS) {
 493                         ftdm_log(FTDM_LOG_ERROR, "READ ERROR [%s]\n", ftdmchan->last_error);
 494                         goto done;
 495                 }
 496 
 497                 if (ftdmchan->detected_tones[0]) {
 498                         int i;
 499                         
 500                         for (i = 1; i < FTDM_TONEMAP_INVALID; i++) {
 501                                 if (ftdmchan->detected_tones[i]) {
 502                                         ftdm_log(FTDM_LOG_DEBUG, "Detected tone %s on %d:%d\n", ftdm_tonemap2str(i), ftdmchan->span_id, ftdmchan->chan_id);
 503                                 }
 504                         }
 505                         
 506                         if (ftdmchan->detected_tones[FTDM_TONEMAP_BUSY] || 
 507                                 ftdmchan->detected_tones[FTDM_TONEMAP_FAIL1] ||
 508                                 ftdmchan->detected_tones[FTDM_TONEMAP_FAIL2] ||
 509                                 ftdmchan->detected_tones[FTDM_TONEMAP_FAIL3] ||
 510                                 ftdmchan->detected_tones[FTDM_TONEMAP_ATTN]
 511                                 ) {
 512                                 ftdm_log(FTDM_LOG_ERROR, "Failure indication detected!\n");
 513                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_BUSY);
 514                         } else if (ftdmchan->detected_tones[FTDM_TONEMAP_RING]) {
 515                                 ftdm_set_state_locked(ftdmchan, FTDM_CHANNEL_STATE_UP);
 516                         }
 517                         
 518                         ftdm_channel_clear_detected_tones(ftdmchan);
 519                 }
 520 
 521                 if ((ftdmchan->dtmf_buffer && ftdm_buffer_inuse(ftdmchan->dtmf_buffer))) {
 522                         rlen = len;
 523                         memset(frame, 0, len);
 524                         ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
 525                         continue;
 526                 }
 527                 
 528                 if (!indicate) {
 529                         continue;
 530                 }
 531 
 532                 if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
 533                         len *= 2;
 534                 }
 535 
 536                 rlen = ftdm_buffer_read_loop(dt_buffer, frame, len);
 537 
 538                 if (ftdmchan->effective_codec != FTDM_CODEC_SLIN) {
 539                         fio_codec_t codec_func = NULL;
 540 
 541                         if (ftdmchan->native_codec == FTDM_CODEC_ULAW) {
 542                                 codec_func = fio_slin2ulaw;
 543                         } else if (ftdmchan->native_codec == FTDM_CODEC_ALAW) {
 544                                 codec_func = fio_slin2alaw;
 545                         }
 546 
 547                         if (codec_func) {
 548                                 status = codec_func(frame, sizeof(frame), &rlen);
 549                         } else {
 550                                 snprintf(ftdmchan->last_error, sizeof(ftdmchan->last_error), "codec error!");
 551                                 goto done;
 552                         }
 553                 }
 554 
 555                 ftdm_channel_write(ftdmchan, frame, sizeof(frame), &rlen);
 556         }
 557 
 558  done:
 559 
 560         ftdm_channel_command(ftdmchan, FTDM_COMMAND_ONHOOK, NULL);
 561         
 562         closed_chan = ftdmchan;
 563         ftdm_channel_close(&ftdmchan);
 564 
 565         ftdm_channel_command(closed_chan, FTDM_COMMAND_SET_NATIVE_CODEC, NULL);
 566 
 567         if (ts.buffer) {
 568                 teletone_destroy_session(&ts);
 569         }
 570 
 571         if (dt_buffer) {
 572                 ftdm_buffer_destroy(&dt_buffer);
 573         }
 574 
 575         ftdm_clear_flag(closed_chan, FTDM_CHANNEL_INTHREAD);
 576 
 577         ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM CHANNEL thread ended.\n");
 578 
 579         return NULL;
 580 }
 581 
 582 /**
 583  * \brief Processes EM events coming from ftdmtel/dahdi
 584  * \param span Span on which the event was fired
 585  * \param event Event to be treated
 586  * \return Success or failure
 587  */
 588 static __inline__ ftdm_status_t process_event(ftdm_span_t *span, ftdm_event_t *event)
 589 {
 590         ftdm_sigmsg_t sig;
 591         int locked = 0;
 592         
 593         memset(&sig, 0, sizeof(sig));
 594         sig.chan_id = event->channel->chan_id;
 595         sig.span_id = event->channel->span_id;
 596         sig.channel = event->channel;
 597 
 598 
 599         ftdm_log(FTDM_LOG_DEBUG, "EVENT [%s][%d:%d] STATE [%s]\n", 
 600                         ftdm_oob_event2str(event->enum_id), event->channel->span_id, event->channel->chan_id, ftdm_channel_state2str(event->channel->state));
 601 
 602         ftdm_mutex_lock(event->channel->mutex);
 603         locked++;
 604 
 605         switch(event->enum_id) {
 606         case FTDM_OOB_ONHOOK:
 607                 {
 608                         if (event->channel->state != FTDM_CHANNEL_STATE_DOWN) {
 609                                 ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
 610                         }
 611 
 612                 }
 613                 break;
 614         case FTDM_OOB_OFFHOOK:
 615                 {
 616                         if (ftdm_test_flag(event->channel, FTDM_CHANNEL_INTHREAD)) {
 617                                 ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_UP);
 618                         } else {
 619                                 ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DIALTONE);
 620                                 ftdm_mutex_unlock(event->channel->mutex);
 621                                 locked = 0;
 622                                 ftdm_thread_create_detached(ftdm_analog_em_channel_run, event->channel);
 623                         }
 624                 break;
 625                 }
 626         case FTDM_OOB_WINK:
 627                 {
 628                         if (event->channel->state != FTDM_CHANNEL_STATE_DIALING) {
 629                                 ftdm_set_state_locked(event->channel, FTDM_CHANNEL_STATE_DOWN);
 630                         } else {
 631                                 ftdm_set_flag_locked(event->channel, FTDM_CHANNEL_WINK);
 632                         }
 633 
 634                 }
 635                 break;
 636         }
 637         if (locked) {
 638                 ftdm_mutex_unlock(event->channel->mutex);
 639         }
 640         return FTDM_SUCCESS;
 641 }
 642 
 643 /**
 644  * \brief Main thread function for EM span (monitor)
 645  * \param me Current thread
 646  * \param obj Span to run in this thread
 647  */
 648 static void *ftdm_analog_em_run(ftdm_thread_t *me, void *obj)
 649 {
 650         ftdm_span_t *span = (ftdm_span_t *) obj;
 651         ftdm_analog_em_data_t *analog_data = span->signal_data;
 652 
 653         ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM thread starting.\n");
 654 
 655         while(ftdm_running() && ftdm_test_flag(analog_data, FTDM_ANALOG_EM_RUNNING)) {
 656                 int waitms = 10;
 657                 ftdm_status_t status;
 658 
 659                 status = ftdm_span_poll_event(span, waitms, NULL);
 660                 
 661                 switch(status) {
 662                 case FTDM_SUCCESS:
 663                         {
 664                                 ftdm_event_t *event;
 665                                 while (ftdm_span_next_event(span, &event) == FTDM_SUCCESS) {
 666                                         if (event->enum_id == FTDM_OOB_NOOP) {
 667                                                 continue;
 668                                         }
 669                                         if (process_event(span, event) != FTDM_SUCCESS) {
 670                                                 goto end;
 671                                         }
 672                                 }
 673                         }
 674                         break;
 675                 case FTDM_FAIL:
 676                         {
 677                                 ftdm_log(FTDM_LOG_ERROR, "Failure Polling event! [%s]\n", span->last_error);
 678                         }
 679                         break;
 680                 default:
 681                         break;
 682                 }
 683 
 684         }
 685 
 686  end:
 687 
 688         ftdm_clear_flag(analog_data, FTDM_ANALOG_EM_RUNNING);
 689         
 690         ftdm_log(FTDM_LOG_DEBUG, "ANALOG EM thread ending.\n");
 691 
 692         return NULL;
 693 }
 694 
 695 /**
 696  * \brief FreeTDM analog EM module initialisation
 697  * \return Success
 698  */
 699 static FIO_SIG_LOAD_FUNCTION(ftdm_analog_em_init)
 700 {
 701         return FTDM_SUCCESS;
 702 }
 703 
 704 /**
 705  * \brief FreeTDM analog EM module definition
 706  */
 707 EX_DECLARE_DATA ftdm_module_t ftdm_module = {
 708         "analog_em",
 709         NULL,
 710         NULL,
 711         ftdm_analog_em_init,
 712         ftdm_analog_em_configure_span,
 713         NULL
 714 };
 715 
 716 
 717 /* For Emacs:
 718  * Local Variables:
 719  * mode:c
 720  * indent-tabs-mode:t
 721  * tab-width:4
 722  * c-basic-offset:4
 723  * End:
 724  * For VIM:
 725  * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
 726  */

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