#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include "asterisk.h"
#include "asterisk/lock.h"
#include "asterisk/vmodem.h"
#include "asterisk/module.h"
#include "asterisk/frame.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/dsp.h"
#include "asterisk/callerid.h"
#include "asterisk/ulaw.h"
#include "asterisk/pbx.h"
#include "asterisk/utils.h"
Go to the source code of this file.
Defines | |
#define | MAX_WRITE_SIZE 2048 |
#define | STATE_COMMAND 0 |
#define | STATE_VOICE 1 |
Functions | |
AST_MUTEX_DEFINE_STATIC (usecnt_lock) | |
char * | description () |
Provides a description of the module. | |
static int | i4l_answer (struct ast_modem_pvt *p) |
static int | i4l_break (struct ast_modem_pvt *p) |
static void | i4l_decusecnt (void) |
static int | i4l_dial (struct ast_modem_pvt *p, char *stuff) |
static int | i4l_dialdigit (struct ast_modem_pvt *p, char digit) |
static struct ast_frame * | i4l_handle_escape (struct ast_modem_pvt *p, char esc) |
static int | i4l_hangup (struct ast_modem_pvt *p) |
static char * | i4l_identify (struct ast_modem_pvt *p) |
static void | i4l_incusecnt (void) |
static int | i4l_init (struct ast_modem_pvt *p) |
static struct ast_frame * | i4l_read (struct ast_modem_pvt *p) |
static int | i4l_setdev (struct ast_modem_pvt *p, int dev) |
static int | i4l_startrec (struct ast_modem_pvt *p) |
static int | i4l_write (struct ast_modem_pvt *p, struct ast_frame *f) |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
int | load_module (void) |
Initialize the module. | |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
int | usecount (void) |
Provides a usecount. | |
Variables | |
static char * | breakcmd = "\0x10\0x14\0x10\0x3" |
static char * | desc = "ISDN4Linux Emulated Modem Driver" |
static struct ast_modem_driver | i4l_driver |
static char * | i4l_idents [] |
static int | usecnt |
Definition in file chan_modem_i4l.c.
#define MAX_WRITE_SIZE 2048 |
Referenced by i4l_write().
#define STATE_COMMAND 0 |
Definition at line 50 of file chan_modem_i4l.c.
#define STATE_VOICE 1 |
Definition at line 51 of file chan_modem_i4l.c.
AST_MUTEX_DEFINE_STATIC | ( | usecnt_lock | ) |
char* description | ( | void | ) |
Provides a description of the module.
Definition at line 735 of file chan_modem_i4l.c.
00736 { 00737 return desc; 00738 }
static int i4l_answer | ( | struct ast_modem_pvt * | p | ) | [static] |
Definition at line 571 of file chan_modem_i4l.c.
References ast_dsp_digitmode(), ast_dsp_new(), ast_dsp_set_features(), ast_log(), ast_modem_expect(), ast_modem_send(), ast_modem_pvt::dev, ast_modem_pvt::dsp, DSP_DIGITMODE_DTMF, DSP_FEATURE_DTMF_DETECT, DSP_FEATURE_FAX_DETECT, ast_modem_pvt::dtmfmode, LOG_DEBUG, LOG_WARNING, ast_modem_pvt::ministate, MODEM_DTMF_AST, ast_modem_pvt::response, and STATE_VOICE.
00572 { 00573 if (ast_modem_send(p, "ATA\r", 4) || 00574 ast_modem_expect(p, "VCON", 10)) { 00575 ast_log(LOG_WARNING, "Unable to answer: %s", p->response); 00576 return -1; 00577 } 00578 #if 1 00579 if (ast_modem_send(p, "AT+VDD=0,8", 0) || 00580 ast_modem_expect(p, "OK", 5)) { 00581 ast_log(LOG_WARNING, "Unable to set to phone line interface\n"); 00582 return -1; 00583 } 00584 #endif 00585 if (ast_modem_send(p, "AT+VTX+VRX", 0) || 00586 ast_modem_expect(p, "CONNECT", 10)) { 00587 ast_log(LOG_WARNING, "Unable to answer: %s", p->response); 00588 return -1; 00589 } 00590 p->ministate = STATE_VOICE; 00591 00592 /* let ast dsp detect dtmf */ 00593 if (p->dtmfmode & MODEM_DTMF_AST) { 00594 if (p->dsp) { 00595 ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev); 00596 } else { 00597 p->dsp = ast_dsp_new(); 00598 if (p->dsp) { 00599 ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev); 00600 ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT|DSP_FEATURE_FAX_DETECT); 00601 ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0); 00602 } 00603 } 00604 } 00605 00606 return 0; 00607 }
static int i4l_break | ( | struct ast_modem_pvt * | p | ) | [static] |
Definition at line 136 of file chan_modem_i4l.c.
References ast_log(), ast_modem_expect(), ast_modem_read_response(), ast_modem_send(), and LOG_WARNING.
Referenced by i4l_init().
00137 { 00138 if (ast_modem_send(p, breakcmd, 2)) { 00139 ast_log(LOG_WARNING, "Failed to break\n"); 00140 return -1; 00141 } 00142 if (ast_modem_send(p, "\r\n", 2)) { 00143 ast_log(LOG_WARNING, "Failed to send enter?\n"); 00144 return -1; 00145 } 00146 #if 0 00147 /* Read any outstanding junk */ 00148 while(!ast_modem_read_response(p, 1)); 00149 #endif 00150 if (ast_modem_send(p, "AT", 0)) { 00151 /* Modem might be stuck in some weird mode, try to get it out */ 00152 ast_modem_send(p, "+++", 3); 00153 if (ast_modem_expect(p, "OK", 10)) { 00154 ast_log(LOG_WARNING, "Modem is not responding\n"); 00155 return -1; 00156 } 00157 if (ast_modem_send(p, "AT", 0)) { 00158 ast_log(LOG_WARNING, "Modem is not responding\n"); 00159 return -1; 00160 } 00161 } 00162 if (ast_modem_expect(p, "OK", 5)) { 00163 ast_log(LOG_WARNING, "Modem did not respond properly\n"); 00164 return -1; 00165 } 00166 return 0; 00167 }
static void i4l_decusecnt | ( | void | ) | [static] |
Definition at line 563 of file chan_modem_i4l.c.
References ast_mutex_lock(), ast_mutex_unlock(), ast_update_use_count(), and usecnt_lock.
00564 { 00565 ast_mutex_lock(&usecnt_lock); 00566 usecnt++; 00567 ast_mutex_unlock(&usecnt_lock); 00568 ast_update_use_count(); 00569 }
static int i4l_dial | ( | struct ast_modem_pvt * | p, | |
char * | stuff | |||
) | [static] |
Definition at line 628 of file chan_modem_i4l.c.
References ast_log(), ast_modem_send(), ast_strlen_zero(), ast_channel::cid, ast_callerid::cid_num, ast_callerid::cid_pres, ast_modem_pvt::dialtype, LOG_WARNING, ast_modem_pvt::outgoingmsn, and ast_modem_pvt::owner.
00629 { 00630 char cmd[80]; 00631 char tmpmsn[255]; 00632 struct ast_channel *c = p->owner; 00633 00634 /* Find callerid number first, to set the correct A number */ 00635 if (c && c->cid.cid_num && !(c->cid.cid_pres & 0x20)) { 00636 snprintf(tmpmsn, sizeof(tmpmsn), ",%s,", c->cid.cid_num); 00637 if(!ast_strlen_zero(p->outgoingmsn) && strstr(p->outgoingmsn,tmpmsn) != NULL) { 00638 /* Tell ISDN4Linux to use this as A number */ 00639 snprintf(cmd, sizeof(cmd), "AT&E%s\n", c->cid.cid_num); 00640 if (ast_modem_send(p, cmd, strlen(cmd))) { 00641 ast_log(LOG_WARNING, "Unable to set A number to %s\n", c->cid.cid_num); 00642 } 00643 00644 } else { 00645 ast_log(LOG_WARNING, "Outgoing MSN %s not allowed (see outgoingmsn=%s in modem.conf)\n",c->cid.cid_num,p->outgoingmsn); 00646 } 00647 } 00648 00649 snprintf(cmd, sizeof(cmd), "ATD%c %s\n", p->dialtype,stuff); 00650 if (ast_modem_send(p, cmd, strlen(cmd))) { 00651 ast_log(LOG_WARNING, "Unable to dial\n"); 00652 return -1; 00653 } 00654 return 0; 00655 }
static int i4l_dialdigit | ( | struct ast_modem_pvt * | p, | |
char | digit | |||
) | [static] |
Definition at line 609 of file chan_modem_i4l.c.
References ast_log(), CHAR_DLE, ast_modem_pvt::dev, ast_modem_pvt::dtmfmodegen, ast_modem_pvt::fd, LOG_DEBUG, ast_modem_pvt::ministate, MODEM_DTMF_AST, MODEM_DTMF_I4L, and STATE_VOICE.
00610 { 00611 char c[2]; 00612 if (p->ministate == STATE_VOICE) { 00613 if (p->dtmfmodegen & MODEM_DTMF_I4L) { 00614 c[0] = CHAR_DLE; 00615 c[1] = digit; 00616 write(p->fd, c, 2); 00617 ast_log(LOG_DEBUG, "Send ISDN out-of-band DTMF %c\n",digit); 00618 } 00619 if(p->dtmfmodegen & MODEM_DTMF_AST) { 00620 ast_log(LOG_DEBUG, "Generating inband DTMF\n"); 00621 return -1; 00622 } 00623 } else 00624 ast_log(LOG_DEBUG, "Asked to send digit but call not up on %s\n", p->dev); 00625 return 0; 00626 }
static struct ast_frame* i4l_handle_escape | ( | struct ast_modem_pvt * | p, | |
char | esc | |||
) | [static] |
Definition at line 247 of file chan_modem_i4l.c.
References AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_RING, AST_CONTROL_RINGING, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_NULL, ast_log(), ast_modem_send(), ast_setstate(), AST_STATE_UP, CHAR_ETX, ast_frame::data, ast_frame::datalen, ast_frame::delivery, ast_modem_pvt::fr, ast_frame::frametype, i4l_startrec(), LOG_DEBUG, LOG_WARNING, ast_frame::mallocd, ast_frame::offset, option_debug, ast_modem_pvt::owner, ast_frame::samples, and ast_frame::subclass.
Referenced by i4l_read().
00248 { 00249 /* Handle escaped characters -- but sometimes we call it directly as 00250 a quick way to cause known responses */ 00251 p->fr.frametype = AST_FRAME_NULL; 00252 p->fr.subclass = 0; 00253 p->fr.data = NULL; 00254 p->fr.datalen = 0; 00255 p->fr.samples = 0; 00256 p->fr.offset = 0; 00257 p->fr.mallocd = 0; 00258 p->fr.delivery.tv_sec = 0; 00259 p->fr.delivery.tv_usec = 0; 00260 if (esc && option_debug) 00261 ast_log(LOG_DEBUG, "Escaped character '%c'\n", esc); 00262 00263 switch(esc) { 00264 case 'R': /* Pseudo ring */ 00265 p->fr.frametype = AST_FRAME_CONTROL; 00266 p->fr.subclass = AST_CONTROL_RING; 00267 return &p->fr; 00268 case 'I': /* Pseudo ringing */ 00269 p->fr.frametype = AST_FRAME_CONTROL; 00270 p->fr.subclass = AST_CONTROL_RINGING; 00271 return &p->fr; 00272 case 'X': /* Pseudo connect */ 00273 p->fr.frametype = AST_FRAME_CONTROL; 00274 p->fr.subclass = AST_CONTROL_ANSWER; 00275 if (p->owner) 00276 ast_setstate(p->owner, AST_STATE_UP); 00277 if (i4l_startrec(p)) 00278 return NULL; 00279 return &p->fr; 00280 case 'b': /* Busy signal */ 00281 p->fr.frametype = AST_FRAME_CONTROL; 00282 p->fr.subclass = AST_CONTROL_BUSY; 00283 return &p->fr; 00284 case 'o': /* Overrun */ 00285 ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n"); 00286 if (ast_modem_send(p, "\0x10E", 2)) 00287 ast_log(LOG_WARNING, "Unable to flush buffers\n"); 00288 return &p->fr; 00289 case CHAR_ETX: /* End Transmission */ 00290 return NULL; 00291 case 'u': /* Underrun */ 00292 ast_log(LOG_WARNING, "Data underrun\n"); 00293 /* Fall Through */ 00294 case 'd': /* Dialtone */ 00295 case 'c': /* Calling Tone */ 00296 case 'e': /* European version */ 00297 case 'a': /* Answer Tone */ 00298 case 'f': /* Bell Answer Tone */ 00299 case 'T': /* Timing mark */ 00300 case 't': /* Handset off hook */ 00301 case 'h': /* Handset hungup */ 00302 /* Ignore */ 00303 if (option_debug) 00304 ast_log(LOG_DEBUG, "Ignoring Escaped character '%c' (%d)\n", esc, esc); 00305 return &p->fr; 00306 case '0': 00307 case '1': 00308 case '2': 00309 case '3': 00310 case '4': 00311 case '5': 00312 case '6': 00313 case '7': 00314 case '8': 00315 case '9': 00316 case '*': 00317 case '#': 00318 ast_log(LOG_DEBUG, "Detected outband DTMF digit: '%c' (%d)\n", esc, esc); 00319 p->fr.frametype=AST_FRAME_DTMF; 00320 p->fr.subclass=esc; 00321 return &p->fr; 00322 case 0: /* Pseudo signal */ 00323 return &p->fr; 00324 default: 00325 ast_log(LOG_DEBUG, "Unknown Escaped character '%c' (%d)\n", esc, esc); 00326 } 00327 return &p->fr; 00328 }
static int i4l_hangup | ( | struct ast_modem_pvt * | p | ) | [static] |
Definition at line 657 of file chan_modem_i4l.c.
References ast_dsp_free(), ast_log(), ast_modem_expect(), ast_modem_send(), ast_modem_pvt::dsp, ast_modem_pvt::fd, and LOG_WARNING.
00658 { 00659 char dummy[50]; 00660 int dtr = TIOCM_DTR; 00661 00662 /* free the memory used by the DSP */ 00663 if (p->dsp) { 00664 ast_dsp_free(p->dsp); 00665 p->dsp = NULL; 00666 } 00667 00668 /* down DTR to hangup modem */ 00669 ioctl(p->fd, TIOCMBIC, &dtr); 00670 /* Read anything outstanding */ 00671 while(read(p->fd, dummy, sizeof(dummy)) > 0); 00672 00673 /* rise DTR to re-enable line */ 00674 ioctl(p->fd, TIOCMBIS, &dtr); 00675 00676 /* Read anything outstanding */ 00677 while(read(p->fd, dummy, sizeof(dummy)) > 0); 00678 00679 /* basically we're done, just to be sure */ 00680 write(p->fd, "\n\n", 2); 00681 read(p->fd, dummy, sizeof(dummy)); 00682 if (ast_modem_send(p, "ATH", 0)) { 00683 ast_log(LOG_WARNING, "Unable to hang up\n"); 00684 return -1; 00685 } 00686 if (ast_modem_expect(p, "OK", 5)) { 00687 ast_log(LOG_WARNING, "Final 'OK' not received\n"); 00688 return -1; 00689 } 00690 00691 return 0; 00692 }
static char* i4l_identify | ( | struct ast_modem_pvt * | p | ) | [static] |
Definition at line 550 of file chan_modem_i4l.c.
References strdup.
00551 { 00552 return strdup("Linux ISDN"); 00553 }
static void i4l_incusecnt | ( | void | ) | [static] |
Definition at line 555 of file chan_modem_i4l.c.
References ast_mutex_lock(), ast_mutex_unlock(), ast_update_use_count(), and usecnt_lock.
00556 { 00557 ast_mutex_lock(&usecnt_lock); 00558 usecnt++; 00559 ast_mutex_unlock(&usecnt_lock); 00560 ast_update_use_count(); 00561 }
static int i4l_init | ( | struct ast_modem_pvt * | p | ) | [static] |
Definition at line 169 of file chan_modem_i4l.c.
References ast_log(), ast_modem_expect(), ast_modem_send(), ast_strlen_zero(), ast_modem_pvt::escape, i4l_break(), ast_modem_pvt::incomingmsn, LOG_DEBUG, LOG_WARNING, ast_modem_pvt::ministate, ast_modem_pvt::msn, option_debug, and STATE_COMMAND.
00170 { 00171 char cmd[256]; 00172 if (option_debug) 00173 ast_log(LOG_DEBUG, "i4l_init()\n"); 00174 if (i4l_break(p)) 00175 return -1; 00176 /* Force into command mode */ 00177 p->ministate = STATE_COMMAND; 00178 if (ast_modem_send(p, "AT+FCLASS=8", 0) || 00179 ast_modem_expect(p, "OK", 5)) { 00180 ast_log(LOG_WARNING, "Unable to set to voice mode\n"); 00181 return -1; 00182 } 00183 if (!ast_strlen_zero(p->msn)) { 00184 snprintf(cmd, sizeof(cmd), "AT&E%s", p->msn); 00185 if (ast_modem_send(p, cmd, 0) || 00186 ast_modem_expect(p, "OK", 5)) { 00187 ast_log(LOG_WARNING, "Unable to set MSN to %s\n", p->msn); 00188 return -1; 00189 } 00190 } 00191 if (!ast_strlen_zero(p->incomingmsn)) { 00192 char *q; 00193 snprintf(cmd, sizeof(cmd), "AT&L%s", p->incomingmsn); 00194 /* translate , into ; since that is the seperator I4L uses, but can't be directly */ 00195 /* put in the config file because it will interpret the rest of the line as comment. */ 00196 q = cmd+4; 00197 while (*q) { 00198 if (*q == ',') *q = ';'; 00199 ++q; 00200 } 00201 if (ast_modem_send(p, cmd, 0) || 00202 ast_modem_expect(p, "OK", 5)) { 00203 ast_log(LOG_WARNING, "Unable to set Listen to %s\n", p->msn); 00204 return -1; 00205 } 00206 } 00207 if (ast_modem_send(p, "AT&D2", 0) || 00208 ast_modem_expect(p, "OK", 5)) { 00209 ast_log(LOG_WARNING, "Unable to set to DTR disconnect mode\n"); 00210 return -1; 00211 } 00212 if (ast_modem_send(p, "ATS18=1", 0) || 00213 ast_modem_expect(p, "OK", 5)) { 00214 ast_log(LOG_WARNING, "Unable to set to audio only mode\n"); 00215 return -1; 00216 } 00217 if (ast_modem_send(p, "ATS13.6=1", 0) || 00218 ast_modem_expect(p, "OK", 5)) { 00219 ast_log(LOG_WARNING, "Unable to set to RUNG indication\n"); 00220 return -1; 00221 } 00222 if (ast_modem_send(p, "ATS14=4", 0) || 00223 ast_modem_expect(p, "OK", 5)) { 00224 ast_log(LOG_WARNING, "Unable to set to transparent mode\n"); 00225 return -1; 00226 } 00227 if (ast_modem_send(p, "ATS23=9", 0) || 00228 ast_modem_expect(p, "OK", 5)) { 00229 ast_log(LOG_WARNING, "Unable to set to transparent/ringing mode\n"); 00230 return -1; 00231 } 00232 00233 if (ast_modem_send(p, "AT+VSM=6", 0) || 00234 ast_modem_expect(p, "OK", 5)) { 00235 ast_log(LOG_WARNING, "Unable to set to muLAW mode\n"); 00236 return -1; 00237 } 00238 if (ast_modem_send(p, "AT+VLS=2", 0) || 00239 ast_modem_expect(p, "OK", 5)) { 00240 ast_log(LOG_WARNING, "Unable to set to phone line interface\n"); 00241 return -1; 00242 } 00243 p->escape = 0; 00244 return 0; 00245 }
static struct ast_frame* i4l_read | ( | struct ast_modem_pvt * | p | ) | [static] |
Definition at line 330 of file chan_modem_i4l.c.
References ast_log(), ast_modem_trim(), AST_MULAW, ast_verbose(), CHAR_DLE, ast_modem_pvt::cid_num, ast_modem_pvt::dev, ast_modem_pvt::dnid, ast_modem_pvt::escape, ast_modem_pvt::f, ast_modem_pvt::fd, i4l_handle_escape(), LOG_DEBUG, LOG_WARNING, ast_modem_pvt::ministate, ast_modem_pvt::obuf, ast_modem_pvt::obuflen, option_debug, option_verbose, result, STATE_COMMAND, and VERBOSE_PREFIX_3.
00331 { 00332 unsigned char result[256]; 00333 short *b; 00334 struct ast_frame *f=NULL; 00335 int res; 00336 int x; 00337 if (p->ministate == STATE_COMMAND) { 00338 /* Read the first two bytes, first, in case it's a control message */ 00339 res = read(p->fd, result, 2); 00340 if (res < 2) { 00341 /* short read, means there was a hangup? */ 00342 /* (or is this also possible without hangup?) */ 00343 /* Anyway, reading from unitialized buffers is a bad idea anytime. */ 00344 if (errno == EAGAIN) 00345 return i4l_handle_escape(p, 0); 00346 return NULL; 00347 } 00348 if (result[0] == CHAR_DLE) { 00349 return i4l_handle_escape(p, result[1]); 00350 00351 } else { 00352 if ((result[0] == '\n') || (result[0] == '\r')) 00353 return i4l_handle_escape(p, 0); 00354 /* Read the rest of the line */ 00355 fgets(result + 2, sizeof(result) - 2, p->f); 00356 ast_modem_trim(result); 00357 if (!strcasecmp(result, "VCON")) { 00358 /* If we're in immediate mode, reply now */ 00359 /* if (p->mode == MODEM_MODE_IMMEDIATE) */ 00360 return i4l_handle_escape(p, 'X'); 00361 } else 00362 if (!strcasecmp(result, "BUSY")) { 00363 /* Same as a busy signal */ 00364 return i4l_handle_escape(p, 'b'); 00365 } else 00366 if (!strncasecmp(result, "CALLER NUMBER: ", 15 )) { 00367 strncpy(p->cid_num, result + 15, sizeof(p->cid_num)-1); 00368 return i4l_handle_escape(p, 0); 00369 } else 00370 if (!strcasecmp(result, "RINGING")) { 00371 if (option_verbose > 2) 00372 ast_verbose(VERBOSE_PREFIX_3 "%s is ringing...\n", p->dev); 00373 return i4l_handle_escape(p, 'I'); 00374 } else 00375 if (!strncasecmp(result, "RUNG", 4)) { 00376 /* PM2002: the line was hung up before we picked it up, bye bye */ 00377 if (option_verbose > 2) 00378 ast_verbose(VERBOSE_PREFIX_3 "%s was hung up on before we answered\n", p->dev); 00379 return NULL; 00380 } else 00381 if (!strncasecmp(result, "RING", 4)) { 00382 if (result[4]=='/') 00383 strncpy(p->dnid, result + 5, sizeof(p->dnid)-1); 00384 return i4l_handle_escape(p, 'R'); 00385 } else 00386 if (!strcasecmp(result, "NO CARRIER")) { 00387 if (option_verbose > 2) 00388 ast_verbose(VERBOSE_PREFIX_3 "%s hung up on\n", p->dev); 00389 return NULL; 00390 } else 00391 if (!strcasecmp(result, "NO DIALTONE")) { 00392 /* There's no dialtone, so the line isn't working */ 00393 ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev); 00394 return NULL; 00395 } 00396 if (option_debug) 00397 ast_log(LOG_DEBUG, "Modem said '%s'\n", result); 00398 return i4l_handle_escape(p, 0); 00399 } 00400 } else { 00401 /* We have to be more efficient in voice mode */ 00402 b = (short *)(p->obuf + p->obuflen); 00403 while (p->obuflen/2 < 240) { 00404 /* Read ahead the full amount */ 00405 res = read(p->fd, result, 240 - p->obuflen/2); 00406 if (res < 1) { 00407 /* If there's nothing there, just continue on */ 00408 if (errno == EAGAIN) 00409 return i4l_handle_escape(p, 0); 00410 ast_log(LOG_WARNING, "Read failed: %s\n", strerror(errno)); 00411 return NULL; 00412 } 00413 00414 for (x=0;x<res;x++) { 00415 /* Process all the bytes that we've read */ 00416 switch(result[x]) { 00417 case CHAR_DLE: 00418 #if 0 00419 ast_log(LOG_DEBUG, "Ooh, an escape at %d...\n", x); 00420 #endif 00421 if (!p->escape) { 00422 /* Note that next value is 00423 an escape, and continue. */ 00424 p->escape++; 00425 break; 00426 } else { 00427 /* Send as is -- fallthrough */ 00428 p->escape = 0; 00429 } 00430 default: 00431 if (p->escape) { 00432 ast_log(LOG_DEBUG, "Value of escape is %c (%d)...\n", result[x] < 32 ? '^' : result[x], result[x]); 00433 p->escape = 0; 00434 if (f) 00435 ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n"); 00436 f = i4l_handle_escape(p, result[x]); 00437 /* If i4l_handle_escape says NULL, say it now, doesn't matter 00438 what else is there, the connection is dead. */ 00439 if (!f) 00440 return NULL; 00441 } else { 00442 *(b++) = AST_MULAW((int)result[x]); 00443 p->obuflen += 2; 00444 } 00445 } 00446 } 00447 if (f) 00448 break; 00449 } 00450 if (f) { 00451 if( ! (!(p->dtmfmode & MODEM_DTMF_I4L) && f->frametype == AST_FRAME_DTMF)) 00452 return f; 00453 } 00454 00455 /* If we get here, we have a complete voice frame */ 00456 p->fr.frametype = AST_FRAME_VOICE; 00457 p->fr.subclass = AST_FORMAT_SLINEAR; 00458 p->fr.samples = 240; 00459 p->fr.data = p->obuf; 00460 p->fr.datalen = p->obuflen; 00461 p->fr.mallocd = 0; 00462 p->fr.delivery.tv_sec = 0; 00463 p->fr.delivery.tv_usec = 0; 00464 p->fr.offset = AST_FRIENDLY_OFFSET; 00465 p->fr.src = __FUNCTION__; 00466 p->obuflen = 0; 00467 00468 /* process with dsp */ 00469 if (p->dsp) { 00470 f = ast_dsp_process(p->owner, p->dsp, &p->fr); 00471 if (f && (f->frametype == AST_FRAME_DTMF)) { 00472 ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c on %s\n", f->subclass, p->dev); 00473 if (f->subclass == 'f') { 00474 /* Fax tone -- Handle and return NULL */ 00475 struct ast_channel *ast = p->owner; 00476 if (!p->faxhandled) { 00477 p->faxhandled++; 00478 if (strcmp(ast->exten, "fax")) { 00479 const char *target_context = ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext; 00480 00481 if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) { 00482 if (option_verbose > 2) 00483 ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name); 00484 /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */ 00485 pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten); 00486 if (ast_async_goto(ast, target_context, "fax", 1)) 00487 ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context); 00488 } else 00489 ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n"); 00490 } else 00491 ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n"); 00492 } else 00493 ast_log(LOG_DEBUG, "Fax already handled\n"); 00494 p->fr.frametype = AST_FRAME_NULL; 00495 p->fr.subclass = 0; 00496 f = &p->fr; 00497 } 00498 return f; 00499 } 00500 } 00501 00502 return &p->fr; 00503 } 00504 return NULL; 00505 }
static int i4l_setdev | ( | struct ast_modem_pvt * | p, | |
int | dev | |||
) | [static] |
Definition at line 66 of file chan_modem_i4l.c.
References ast_log(), ast_modem_expect(), ast_modem_read_response(), ast_modem_send(), ast_modem_trim(), LOG_WARNING, MODEM_DEV_TELCO, MODEM_DEV_TELCO_SPK, and ast_modem_pvt::response.
00067 { 00068 char cmd[80]; 00069 if ((dev != MODEM_DEV_TELCO) && (dev != MODEM_DEV_TELCO_SPK)) { 00070 ast_log(LOG_WARNING, "ISDN4Linux only supports telco device, not %d.\n", dev); 00071 return -1; 00072 } else /* Convert DEV to our understanding of it */ 00073 dev = 2; 00074 if (ast_modem_send(p, "AT+VLS?", 0)) { 00075 ast_log(LOG_WARNING, "Unable to select current mode %d\n", dev); 00076 return -1; 00077 } 00078 if (ast_modem_read_response(p, 5)) { 00079 ast_log(LOG_WARNING, "Unable to select device %d\n", dev); 00080 return -1; 00081 } 00082 ast_modem_trim(p->response); 00083 strncpy(cmd, p->response, sizeof(cmd)-1); 00084 if (ast_modem_expect(p, "OK", 5)) { 00085 ast_log(LOG_WARNING, "Modem did not respond properly\n"); 00086 return -1; 00087 } 00088 if (dev == atoi(cmd)) { 00089 /* We're already in the right mode, don't bother changing for fear of 00090 hanging up */ 00091 return 0; 00092 } 00093 snprintf(cmd, sizeof(cmd), "AT+VLS=%d", dev); 00094 if (ast_modem_send(p, cmd, 0)) { 00095 ast_log(LOG_WARNING, "Unable to select device %d\n", dev); 00096 return -1; 00097 } 00098 if (ast_modem_read_response(p, 5)) { 00099 ast_log(LOG_WARNING, "Unable to select device %d\n", dev); 00100 return -1; 00101 } 00102 ast_modem_trim(p->response); 00103 if (strcasecmp(p->response, "VCON") && strcasecmp(p->response, "OK")) { 00104 ast_log(LOG_WARNING, "Unexpected reply: %s\n", p->response); 00105 return -1; 00106 } 00107 return 0; 00108 }
static int i4l_startrec | ( | struct ast_modem_pvt * | p | ) | [static] |
Definition at line 110 of file chan_modem_i4l.c.
References ast_dsp_digitmode(), ast_dsp_new(), ast_dsp_set_features(), ast_log(), ast_modem_expect(), ast_modem_send(), ast_modem_pvt::dev, ast_modem_pvt::dsp, DSP_DIGITMODE_DTMF, DSP_FEATURE_DTMF_DETECT, DSP_FEATURE_FAX_DETECT, ast_modem_pvt::dtmfmode, LOG_DEBUG, LOG_WARNING, ast_modem_pvt::ministate, MODEM_DTMF_AST, and STATE_VOICE.
Referenced by i4l_handle_escape().
00111 { 00112 if (ast_modem_send(p, "AT+VRX+VTX", 0) || 00113 ast_modem_expect(p, "CONNECT", 5)) { 00114 ast_log(LOG_WARNING, "Unable to start recording\n"); 00115 return -1; 00116 } 00117 p->ministate = STATE_VOICE; 00118 00119 /* let ast dsp detect dtmf */ 00120 if (p->dtmfmode & MODEM_DTMF_AST) { 00121 if (p->dsp) { 00122 ast_log(LOG_DEBUG, "Already have a dsp on %s?\n", p->dev); 00123 } else { 00124 p->dsp = ast_dsp_new(); 00125 if (p->dsp) { 00126 ast_log(LOG_DEBUG, "Detecting DTMF inband with sw DSP on %s\n",p->dev); 00127 ast_dsp_set_features(p->dsp, DSP_FEATURE_DTMF_DETECT|DSP_FEATURE_FAX_DETECT); 00128 ast_dsp_digitmode(p->dsp, DSP_DIGITMODE_DTMF | 0); 00129 } 00130 } 00131 } 00132 00133 return 0; 00134 }
static int i4l_write | ( | struct ast_modem_pvt * | p, | |
struct ast_frame * | f | |||
) | [static] |
Definition at line 507 of file chan_modem_i4l.c.
References AST_FORMAT_SLINEAR, AST_FRAME_VOICE, AST_LIN2MU, ast_log(), CHAR_DLE, ast_frame::data, ast_frame::datalen, ast_modem_pvt::f, ast_modem_pvt::fd, ast_frame::frametype, LOG_WARNING, MAX_WRITE_SIZE, result, and ast_frame::subclass.
00508 { 00509 #define MAX_WRITE_SIZE 2048 00510 unsigned char result[MAX_WRITE_SIZE << 1]; 00511 unsigned char b; 00512 int bpos=0, x; 00513 int res; 00514 if (f->datalen > MAX_WRITE_SIZE) { 00515 ast_log(LOG_WARNING, "Discarding too big frame of size %d\n", f->datalen); 00516 return -1; 00517 } 00518 if (f->frametype != AST_FRAME_VOICE) { 00519 ast_log(LOG_WARNING, "Don't know how to handle %d type frames\n", f->frametype); 00520 return -1; 00521 } 00522 if (f->subclass != AST_FORMAT_SLINEAR) { 00523 ast_log(LOG_WARNING, "Don't know how to handle anything but signed linear frames\n"); 00524 return -1; 00525 } 00526 for (x=0;x<f->datalen/2;x++) { 00527 b = AST_LIN2MU(((short *)f->data)[x]); 00528 result[bpos++] = b; 00529 if (b == CHAR_DLE) 00530 result[bpos++]=b; 00531 } 00532 #if 0 00533 res = fwrite(result, bpos, 1, p->f); 00534 res *= bpos; 00535 #else 00536 res = write(p->fd, result, bpos); 00537 #endif 00538 if (res < 1) { 00539 if (errno != EAGAIN) { 00540 ast_log(LOG_WARNING, "Failed to write buffer\n"); 00541 return -1; 00542 } 00543 } 00544 #if 0 00545 printf("Result of write is %d\n", res); 00546 #endif 00547 return 0; 00548 }
char* key | ( | void | ) |
Returns the ASTERISK_GPL_KEY.
This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:
char *key(void) { return ASTERISK_GPL_KEY; }
Definition at line 740 of file chan_modem_i4l.c.
References ASTERISK_GPL_KEY.
00741 { 00742 return ASTERISK_GPL_KEY; 00743 }
int load_module | ( | void | ) |
Initialize the module.
Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
Definition at line 725 of file chan_modem_i4l.c.
References ast_register_modem_driver(), and i4l_driver.
00726 { 00727 return ast_register_modem_driver(&i4l_driver); 00728 }
int unload_module | ( | void | ) |
Cleanup all module structures, sockets, etc.
This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).
Definition at line 730 of file chan_modem_i4l.c.
References ast_unregister_modem_driver(), and i4l_driver.
00731 { 00732 return ast_unregister_modem_driver(&i4l_driver); 00733 }
int usecount | ( | void | ) |
Provides a usecount.
This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.
Definition at line 720 of file chan_modem_i4l.c.
00721 { 00722 return usecnt; 00723 }
char* breakcmd = "\0x10\0x14\0x10\0x3" [static] |
Definition at line 53 of file chan_modem_i4l.c.
char* desc = "ISDN4Linux Emulated Modem Driver" [static] |
Definition at line 55 of file chan_modem_i4l.c.
struct ast_modem_driver i4l_driver [static] |
char* i4l_idents[] [static] |
int usecnt [static] |
Definition at line 57 of file chan_modem_i4l.c.