📄 chan_phone.c
字号:
/* Reset the extension */ i->ext[0] = '\0'; /* Play the dialtone */ i->dialtone++; ioctl(i->fd, PHONE_PLAY_STOP); ioctl(i->fd, PHONE_PLAY_CODEC, ULAW); ioctl(i->fd, PHONE_PLAY_START); i->lastformat = -1; } else if (i->mode == MODE_SIGMA) { ast_module_ref(ast_module_info->self); /* Reset the extension */ i->ext[0] = '\0'; /* Play the dialtone */ i->dialtone++; ioctl(i->fd, PHONE_DIALTONE); } } else { if (i->dialtone) ast_module_unref(ast_module_info->self); memset(i->ext, 0, sizeof(i->ext)); if (i->cpt) { ioctl(i->fd, PHONE_CPT_STOP); i->cpt = 0; } ioctl(i->fd, PHONE_PLAY_STOP); ioctl(i->fd, PHONE_REC_STOP); i->dialtone = 0; i->lastformat = -1; } } if (phonee.bits.pstn_ring) { ast_verbose("Unit is ringing\n"); phone_new(i, AST_STATE_RING, i->context); } if (phonee.bits.caller_id) ast_verbose("We have caller ID\n"); }static void *do_monitor(void *data){ fd_set rfds, efds; int n, res; struct phone_pvt *i; int tonepos = 0; /* The tone we're playing this round */ struct timeval tv = {0,0}; int dotone; /* This thread monitors all the frame relay interfaces which are not yet in use (and thus do not have a separate thread) indefinitely */ while (monitor) { /* Don't let anybody kill us right away. Nobody should lock the interface list and wait for the monitor list, but the other way around is okay. */ /* Lock the interface list */ if (ast_mutex_lock(&iflock)) { ast_log(LOG_ERROR, "Unable to grab interface lock\n"); return NULL; } /* Build the stuff we're going to select on, that is the socket of every phone_pvt that does not have an associated owner channel */ n = -1; FD_ZERO(&rfds); FD_ZERO(&efds); i = iflist; dotone = 0; while (i) { if (FD_ISSET(i->fd, &rfds)) ast_log(LOG_WARNING, "Descriptor %d appears twice (%s)?\n", i->fd, i->dev); if (!i->owner) { /* This needs to be watched, as it lacks an owner */ FD_SET(i->fd, &rfds); FD_SET(i->fd, &efds); if (i->fd > n) n = i->fd; if (i->dialtone && i->mode != MODE_SIGMA) { /* Remember we're going to have to come back and play more dialtones */ if (ast_tvzero(tv)) { /* If we're due for a dialtone, play one */ if (write(i->fd, DialTone + tonepos, 240) != 240) ast_log(LOG_WARNING, "Dial tone write error\n"); } dotone++; } } i = i->next; } /* Okay, now that we know what to do, release the interface lock */ ast_mutex_unlock(&iflock); /* Wait indefinitely for something to happen */ if (dotone && i && i->mode != MODE_SIGMA) { /* If we're ready to recycle the time, set it to 30 ms */ tonepos += 240; if (tonepos >= sizeof(DialTone)) tonepos = 0; if (ast_tvzero(tv)) { tv = ast_tv(30000, 0); } res = ast_select(n + 1, &rfds, NULL, &efds, &tv); } else { res = ast_select(n + 1, &rfds, NULL, &efds, NULL); tv = ast_tv(0,0); tonepos = 0; } /* Okay, select has finished. Let's see what happened. */ if (res < 0) { ast_log(LOG_DEBUG, "select return %d: %s\n", res, strerror(errno)); continue; } /* If there are no fd's changed, just continue, it's probably time to play some more dialtones */ if (!res) continue; /* Alright, lock the interface list again, and let's look and see what has happened */ if (ast_mutex_lock(&iflock)) { ast_log(LOG_WARNING, "Unable to lock the interface list\n"); continue; } i = iflist; for(; i; i=i->next) { if (FD_ISSET(i->fd, &rfds)) { if (i->owner) { continue; } phone_mini_packet(i); } if (FD_ISSET(i->fd, &efds)) { if (i->owner) { continue; } phone_check_exception(i); } } ast_mutex_unlock(&iflock); } return NULL; }static int restart_monitor(){ /* If we're supposed to be stopped -- stay stopped */ if (monitor_thread == AST_PTHREADT_STOP) return 0; if (ast_mutex_lock(&monlock)) { ast_log(LOG_WARNING, "Unable to lock monitor\n"); return -1; } if (monitor_thread == pthread_self()) { ast_mutex_unlock(&monlock); ast_log(LOG_WARNING, "Cannot kill myself\n"); return -1; } if (monitor_thread != AST_PTHREADT_NULL) { if (ast_mutex_lock(&iflock)) { ast_mutex_unlock(&monlock); ast_log(LOG_WARNING, "Unable to lock the interface list\n"); return -1; } monitor = 0; while (pthread_kill(monitor_thread, SIGURG) == 0) sched_yield(); pthread_join(monitor_thread, NULL); ast_mutex_unlock(&iflock); } monitor = 1; /* Start a new monitor */ if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) { ast_mutex_unlock(&monlock); ast_log(LOG_ERROR, "Unable to start monitor thread.\n"); return -1; } ast_mutex_unlock(&monlock); return 0;}static struct phone_pvt *mkif(char *iface, int mode, int txgain, int rxgain){ /* Make a phone_pvt structure for this interface */ struct phone_pvt *tmp; int flags; tmp = malloc(sizeof(struct phone_pvt)); if (tmp) { tmp->fd = open(iface, O_RDWR); if (tmp->fd < 0) { ast_log(LOG_WARNING, "Unable to open '%s'\n", iface); free(tmp); return NULL; } if (mode == MODE_FXO) { if (ioctl(tmp->fd, IXJCTL_PORT, PORT_PSTN)) ast_log(LOG_DEBUG, "Unable to set port to PSTN\n"); } else { if (ioctl(tmp->fd, IXJCTL_PORT, PORT_POTS)) if (mode != MODE_FXS) ast_log(LOG_DEBUG, "Unable to set port to POTS\n"); } ioctl(tmp->fd, PHONE_PLAY_STOP); ioctl(tmp->fd, PHONE_REC_STOP); ioctl(tmp->fd, PHONE_RING_STOP); ioctl(tmp->fd, PHONE_CPT_STOP); if (ioctl(tmp->fd, PHONE_PSTN_SET_STATE, PSTN_ON_HOOK)) ast_log(LOG_DEBUG, "ioctl(PHONE_PSTN_SET_STATE) failed on %s (%s)\n",iface, strerror(errno)); if (echocancel != AEC_OFF) ioctl(tmp->fd, IXJCTL_AEC_START, echocancel); if (silencesupression) tmp->silencesupression = 1;#ifdef PHONE_VAD ioctl(tmp->fd, PHONE_VAD, tmp->silencesupression);#endif tmp->mode = mode; flags = fcntl(tmp->fd, F_GETFL); fcntl(tmp->fd, F_SETFL, flags | O_NONBLOCK); tmp->owner = NULL; tmp->lastformat = -1; tmp->lastinput = -1; tmp->ministate = 0; memset(tmp->ext, 0, sizeof(tmp->ext)); ast_copy_string(tmp->language, language, sizeof(tmp->language)); ast_copy_string(tmp->dev, iface, sizeof(tmp->dev)); ast_copy_string(tmp->context, context, sizeof(tmp->context)); tmp->next = NULL; tmp->obuflen = 0; tmp->dialtone = 0; tmp->cpt = 0; ast_copy_string(tmp->cid_num, cid_num, sizeof(tmp->cid_num)); ast_copy_string(tmp->cid_name, cid_name, sizeof(tmp->cid_name)); tmp->txgain = txgain; ioctl(tmp->fd, PHONE_PLAY_VOLUME, tmp->txgain); tmp->rxgain = rxgain; ioctl(tmp->fd, PHONE_REC_VOLUME, tmp->rxgain); } return tmp;}static struct ast_channel *phone_request(const char *type, int format, void *data, int *cause){ int oldformat; struct phone_pvt *p; struct ast_channel *tmp = NULL; char *name = data; /* Search for an unowned channel */ if (ast_mutex_lock(&iflock)) { ast_log(LOG_ERROR, "Unable to lock interface list???\n"); return NULL; } p = iflist; while(p) { if (p->mode == MODE_FXS || format & (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW)) { size_t length = strlen(p->dev + 5); if (strncmp(name, p->dev + 5, length) == 0 && !isalnum(name[length])) { if (!p->owner) { tmp = phone_new(p, AST_STATE_DOWN, p->context); break; } else *cause = AST_CAUSE_BUSY; } } p = p->next; } ast_mutex_unlock(&iflock); restart_monitor(); if (tmp == NULL) { oldformat = format; format &= (AST_FORMAT_G723_1 | AST_FORMAT_SLINEAR | AST_FORMAT_ULAW); if (!format) { ast_log(LOG_NOTICE, "Asked to get a channel of unsupported format '%d'\n", oldformat); return NULL; } } return tmp;}/* parse gain value from config file */static int parse_gain_value(char *gain_type, char *value){ float gain; /* try to scan number */ if (sscanf(value, "%f", &gain) != 1) { ast_log(LOG_ERROR, "Invalid %s value '%s' in '%s' config\n", value, gain_type, config); return DEFAULT_GAIN; } /* multiplicate gain by 1.0 gain value */ gain = gain * (float)DEFAULT_GAIN; /* percentage? */ if (value[strlen(value) - 1] == '%') return (int)(gain / (float)100); return (int)gain;}static int __unload_module(void){ struct phone_pvt *p, *pl; /* First, take us out of the channel loop */ if (cur_tech) ast_channel_unregister(cur_tech); if (!ast_mutex_lock(&iflock)) { /* Hangup all interfaces if they have an owner */ p = iflist; while(p) { if (p->owner) ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD); p = p->next; } iflist = NULL; ast_mutex_unlock(&iflock); } else { ast_log(LOG_WARNING, "Unable to lock the monitor\n"); return -1; } if (!ast_mutex_lock(&monlock)) { if (monitor_thread > AST_PTHREADT_NULL) { monitor = 0; while (pthread_kill(monitor_thread, SIGURG) == 0) sched_yield(); pthread_join(monitor_thread, NULL); } monitor_thread = AST_PTHREADT_STOP; ast_mutex_unlock(&monlock); } else { ast_log(LOG_WARNING, "Unable to lock the monitor\n"); return -1; } if (!ast_mutex_lock(&iflock)) { /* Destroy all the interfaces and free their memory */ p = iflist; while(p) { /* Close the socket, assuming it's real */ if (p->fd > -1) close(p->fd); pl = p; p = p->next; /* Free associated memory */ free(pl); } iflist = NULL; ast_mutex_unlock(&iflock); } else { ast_log(LOG_WARNING, "Unable to lock the monitor\n"); return -1; } return 0;}static int unload_module(void){ return __unload_module();}static int load_module(void){ struct ast_config *cfg; struct ast_variable *v; struct phone_pvt *tmp; int mode = MODE_IMMEDIATE; int txgain = DEFAULT_GAIN, rxgain = DEFAULT_GAIN; /* default gain 1.0 */ cfg = ast_config_load(config); /* We *must* have a config file otherwise stop immediately */ if (!cfg) { ast_log(LOG_ERROR, "Unable to load config %s\n", config); return AST_MODULE_LOAD_DECLINE; } if (ast_mutex_lock(&iflock)) { /* It's a little silly to lock it, but we mind as well just to be sure */ ast_log(LOG_ERROR, "Unable to lock interface list???\n"); return AST_MODULE_LOAD_FAILURE; } v = ast_variable_browse(cfg, "interfaces"); while(v) { /* Create the interface list */ if (!strcasecmp(v->name, "device")) { tmp = mkif(v->value, mode, txgain, rxgain); if (tmp) { tmp->next = iflist; iflist = tmp; } else { ast_log(LOG_ERROR, "Unable to register channel '%s'\n", v->value); ast_config_destroy(cfg); ast_mutex_unlock(&iflock); __unload_module(); return AST_MODULE_LOAD_FAILURE; } } else if (!strcasecmp(v->name, "silencesupression")) { silencesupression = ast_true(v->value); } else if (!strcasecmp(v->name, "language")) { ast_copy_string(language, v->value, sizeof(language)); } else if (!strcasecmp(v->name, "callerid")) { ast_callerid_split(v->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num)); } else if (!strcasecmp(v->name, "mode")) { if (!strncasecmp(v->value, "di", 2)) mode = MODE_DIALTONE; else if (!strncasecmp(v->value, "sig", 3)) mode = MODE_SIGMA; else if (!strncasecmp(v->value, "im", 2)) mode = MODE_IMMEDIATE; else if (!strncasecmp(v->value, "fxs", 3)) { mode = MODE_FXS; prefformat = 0x01ff0000; /* All non-voice */ } else if (!strncasecmp(v->value, "fx", 2)) mode = MODE_FXO; else ast_log(LOG_WARNING, "Unknown mode: %s\n", v->value); } else if (!strcasecmp(v->name, "context")) { ast_copy_string(context, v->value, sizeof(context)); } else if (!strcasecmp(v->name, "format")) { if (!strcasecmp(v->value, "g723.1")) { prefformat = AST_FORMAT_G723_1; } else if (!strcasecmp(v->value, "slinear")) { if (mode == MODE_FXS) prefformat |= AST_FORMAT_SLINEAR; else prefformat = AST_FORMAT_SLINEAR; } else if (!strcasecmp(v->value, "ulaw")) { prefformat = AST_FORMAT_ULAW; } else ast_log(LOG_WARNING, "Unknown format '%s'\n", v->value); } else if (!strcasecmp(v->name, "echocancel")) { if (!strcasecmp(v->value, "off")) { echocancel = AEC_OFF; } else if (!strcasecmp(v->value, "low")) { echocancel = AEC_LOW; } else if (!strcasecmp(v->value, "medium")) { echocancel = AEC_MED; } else if (!strcasecmp(v->value, "high")) { echocancel = AEC_HIGH; } else ast_log(LOG_WARNING, "Unknown echo cancellation '%s'\n", v->value); } else if (!strcasecmp(v->name, "txgain")) { txgain = parse_gain_value(v->name, v->value); } else if (!strcasecmp(v->name, "rxgain")) { rxgain = parse_gain_value(v->name, v->value); } v = v->next; } ast_mutex_unlock(&iflock); if (mode == MODE_FXS) { phone_tech_fxs.capabilities = prefformat; cur_tech = &phone_tech_fxs; } else cur_tech = (struct ast_channel_tech *) &phone_tech; /* Make sure we can register our Adtranphone channel type */ if (ast_channel_register(cur_tech)) { ast_log(LOG_ERROR, "Unable to register channel class 'Phone'\n"); ast_config_destroy(cfg); __unload_module(); return AST_MODULE_LOAD_FAILURE; } ast_config_destroy(cfg); /* And start the monitor for the first time */ restart_monitor(); return AST_MODULE_LOAD_SUCCESS;}AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Linux Telephony API Support");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -