📄 chan_vpb.cc
字号:
} continue; } /* flush the event from the channel event Q */ vpb_get_event_ch_async(e.handle, &je); vpb_translate_event(&je, str); ast_verb(5, "%s: Flushing event [%d]=>%s\n", p->dev, je.type, str); /* Check for ownership and locks */ if ((p->owner) && (!p->golock)) { /* Need to get owner lock */ /* Safely grab both p->lock and p->owner->lock so that there cannot be a race with something from the other side */ /* ast_mutex_lock(&p->lock); while (ast_mutex_trylock(&p->owner->lock)) { ast_mutex_unlock(&p->lock); usleep(1); ast_mutex_lock(&p->lock); if (!p->owner) break; } if (p->owner) p->golock = 1; */ } /* Two scenarios: Are you owned or not. */ if (p->owner) { monitor_handle_owned(p, &e); } else { monitor_handle_notowned(p, &e); } /* if ((!p->owner)&&(p->golock)) { ast_mutex_unlock(&p->owner->lock); ast_mutex_unlock(&p->lock); } */ } return NULL;}static int restart_monitor(void){ int error = 0; /* If we're supposed to be stopped -- stay stopped */ if (mthreadactive == -2) return 0; ast_verb(4, "Restarting monitor\n"); ast_mutex_lock(&monlock); if (monitor_thread == pthread_self()) { ast_log(LOG_WARNING, "Cannot kill myself\n"); error = -1; ast_verb(4, "Monitor trying to kill monitor\n"); } else { if (mthreadactive != -1) { /* Why do other drivers kill the thread? No need says I, simply awake thread with event. */ VPB_EVENT e; e.handle = 0; e.type = VPB_EVT_NONE; e.data = 0; ast_verb(4, "Trying to reawake monitor\n"); vpb_put_event(&e); } else { /* Start a new monitor */ int pid = ast_pthread_create(&monitor_thread, NULL, do_monitor, NULL); ast_verb(4, "Created new monitor thread %d\n", pid); if (pid < 0) { ast_log(LOG_ERROR, "Unable to start monitor thread.\n"); error = -1; } else { mthreadactive = 0; /* Started the thread!*/ } } } ast_mutex_unlock(&monlock); ast_verb(4, "Monitor restarted\n"); return error;}/* Per board config that must be called after vpb_open() */static void mkbrd(vpb_model_t model, int echo_cancel){ if (!bridges) { if (model == vpb_model_v4pci) { max_bridges = MAX_BRIDGES_V4PCI; } bridges = (vpb_bridge_t *)ast_calloc(1, max_bridges * sizeof(vpb_bridge_t)); if (!bridges) { ast_log(LOG_ERROR, "Failed to initialize bridges\n"); } else { int i; for (i = 0; i < max_bridges; i++) { ast_mutex_init(&bridges[i].lock); ast_cond_init(&bridges[i].cond, NULL); } } } if (!echo_cancel) { if (model == vpb_model_v4pci) { vpb_echo_canc_disable(); ast_log(LOG_NOTICE, "Voicetronix echo cancellation OFF\n"); } else { /* need to do it port by port for OpenSwitch */ } } else { if (model == vpb_model_v4pci) { vpb_echo_canc_enable(); ast_log(LOG_NOTICE, "Voicetronix echo cancellation ON\n"); if (ec_supp_threshold > -1) { vpb_echo_canc_set_sup_thresh(0, &ec_supp_threshold); ast_log(LOG_NOTICE, "Voicetronix EC Sup Thres set\n"); } } else { /* need to do it port by port for OpenSwitch */ } }}static struct vpb_pvt *mkif(int board, int channel, int mode, int gains, float txgain, float rxgain, float txswgain, float rxswgain, int bal1, int bal2, int bal3, char * callerid, int echo_cancel, int group, ast_group_t callgroup, ast_group_t pickupgroup ){ struct vpb_pvt *tmp; char buf[64]; tmp = (vpb_pvt *)ast_calloc(1, sizeof(*tmp)); if (!tmp) return NULL; tmp->handle = vpb_open(board, channel); if (tmp->handle < 0) { ast_log(LOG_WARNING, "Unable to create channel vpb/%d-%d: %s\n", board, channel, strerror(errno)); ast_free(tmp); return NULL; } snprintf(tmp->dev, sizeof(tmp->dev), "vpb/%d-%d", board, channel); tmp->mode = mode; tmp->group = group; tmp->callgroup = callgroup; tmp->pickupgroup = pickupgroup; /* Initilize dtmf caller ID position variable */ tmp->dtmf_caller_pos = 0; ast_copy_string(tmp->language, language, sizeof(tmp->language)); ast_copy_string(tmp->context, context, sizeof(tmp->context)); tmp->callerid_type = 0; if (callerid) { if (strcasecmp(callerid, "on") == 0) { tmp->callerid_type = 1; ast_copy_string(tmp->callerid, "unknown", sizeof(tmp->callerid)); } else if (strcasecmp(callerid, "v23") == 0) { tmp->callerid_type = 2; ast_copy_string(tmp->callerid, "unknown", sizeof(tmp->callerid)); } else if (strcasecmp(callerid, "bell") == 0) { tmp->callerid_type = 3; ast_copy_string(tmp->callerid, "unknown", sizeof(tmp->callerid)); } else { ast_copy_string(tmp->callerid, callerid, sizeof(tmp->callerid)); } } else { ast_copy_string(tmp->callerid, "unknown", sizeof(tmp->callerid)); } /* check if codec balances have been set in the config file */ if (bal3 >= 0) { if ((bal1>=0) && !(bal1 & 32)) bal1 |= 32; vpb_set_codec_reg(tmp->handle, 0x42, bal3); } if (bal1 >= 0) { vpb_set_codec_reg(tmp->handle, 0x32, bal1); } if (bal2 >= 0) { vpb_set_codec_reg(tmp->handle, 0x3a, bal2); } if (gains & VPB_GOT_TXHWG) { if (txgain > MAX_VPB_GAIN) { tmp->txgain = MAX_VPB_GAIN; } else if (txgain < MIN_VPB_GAIN) { tmp->txgain = MIN_VPB_GAIN; } else { tmp->txgain = txgain; } ast_log(LOG_NOTICE, "VPB setting Tx Hw gain to [%f]\n", tmp->txgain); vpb_play_set_hw_gain(tmp->handle, tmp->txgain); } if (gains & VPB_GOT_RXHWG) { if (rxgain > MAX_VPB_GAIN) { tmp->rxgain = MAX_VPB_GAIN; } else if (rxgain < MIN_VPB_GAIN) { tmp->rxgain = MIN_VPB_GAIN; } else { tmp->rxgain = rxgain; } ast_log(LOG_NOTICE, "VPB setting Rx Hw gain to [%f]\n", tmp->rxgain); vpb_record_set_hw_gain(tmp->handle, tmp->rxgain); } if (gains & VPB_GOT_TXSWG) { tmp->txswgain = txswgain; ast_log(LOG_NOTICE, "VPB setting Tx Sw gain to [%f]\n", tmp->txswgain); vpb_play_set_gain(tmp->handle, tmp->txswgain); } if (gains & VPB_GOT_RXSWG) { tmp->rxswgain = rxswgain; ast_log(LOG_NOTICE, "VPB setting Rx Sw gain to [%f]\n", tmp->rxswgain); vpb_record_set_gain(tmp->handle, tmp->rxswgain); } tmp->vpb_model = vpb_model_unknown; if (vpb_get_model(tmp->handle, buf) == VPB_OK) { if (strcmp(buf, "V12PCI") == 0) { tmp->vpb_model = vpb_model_v12pci; } else if (strcmp(buf, "VPB4") == 0) { tmp->vpb_model = vpb_model_v4pci; } } ast_mutex_init(&tmp->owner_lock); ast_mutex_init(&tmp->lock); ast_mutex_init(&tmp->record_lock); ast_mutex_init(&tmp->play_lock); ast_mutex_init(&tmp->play_dtmf_lock); /* set default read state */ tmp->read_state = 0; tmp->golock = 0; tmp->busy_timer_id = vpb_timer_get_unique_timer_id(); vpb_timer_open(&tmp->busy_timer, tmp->handle, tmp->busy_timer_id, TIMER_PERIOD_BUSY); tmp->ringback_timer_id = vpb_timer_get_unique_timer_id(); vpb_timer_open(&tmp->ringback_timer, tmp->handle, tmp->ringback_timer_id, TIMER_PERIOD_RINGBACK); tmp->ring_timer_id = vpb_timer_get_unique_timer_id(); vpb_timer_open(&tmp->ring_timer, tmp->handle, tmp->ring_timer_id, timer_period_ring); tmp->dtmfidd_timer_id = vpb_timer_get_unique_timer_id(); vpb_timer_open(&tmp->dtmfidd_timer, tmp->handle, tmp->dtmfidd_timer_id, dtmf_idd); if (mode == MODE_FXO){ if (use_ast_dtmfdet) vpb_set_event_mask(tmp->handle, VPB_EVENTS_NODTMF); else vpb_set_event_mask(tmp->handle, VPB_EVENTS_ALL); } else {/* if (use_ast_dtmfdet) vpb_set_event_mask(tmp->handle, VPB_EVENTS_NODTMF); else*/ vpb_set_event_mask(tmp->handle, VPB_EVENTS_STAT); } if ((tmp->vpb_model == vpb_model_v12pci) && (echo_cancel)) { vpb_hostecho_on(tmp->handle); } if (use_ast_dtmfdet) { tmp->vad = ast_dsp_new(); ast_dsp_set_features(tmp->vad, DSP_FEATURE_DTMF_DETECT); ast_dsp_digitmode(tmp->vad, DSP_DIGITMODE_DTMF); if (relaxdtmf) ast_dsp_digitmode(tmp->vad, DSP_DIGITMODE_DTMF|DSP_DIGITMODE_RELAXDTMF); } else { tmp->vad = NULL; } /* define grunt tone */ vpb_settonedet(tmp->handle,&toned_ungrunt); ast_log(LOG_NOTICE,"Voicetronix %s channel %s initialized (rxsg=%f/txsg=%f/rxhg=%f/txhg=%f)(0x%x/0x%x/0x%x)\n", (tmp->vpb_model == vpb_model_v4pci) ? "V4PCI" : (tmp->vpb_model == vpb_model_v12pci) ? "V12PCI" : "[Unknown model]", tmp->dev, tmp->rxswgain, tmp->txswgain, tmp->rxgain, tmp->txgain, bal1, bal2, bal3); return tmp;}static int vpb_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen){ struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; int res = 0; int tmp = 0; if (use_ast_ind == 1) { ast_verb(4, "%s: vpb_indicate called when using Ast Indications !?!\n", p->dev); return 0; } ast_verb(4, "%s: vpb_indicate [%d] state[%d]\n", p->dev, condition,ast->_state);/* if (ast->_state != AST_STATE_UP) { ast_verb(4, "%s: vpb_indicate Not in AST_STATE_UP\n", p->dev, condition,ast->_state); return res; }*//* ast_verb(4, "%s: LOCKING in indicate \n", p->dev); ast_verb(4, "%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count, p->lock.__m_owner);*/ ast_mutex_lock(&p->lock); switch (condition) { case AST_CONTROL_BUSY: case AST_CONTROL_CONGESTION: if (ast->_state == AST_STATE_UP) { playtone(p->handle, &Busytone); p->state = VPB_STATE_PLAYBUSY; vpb_timer_stop(p->busy_timer); vpb_timer_start(p->busy_timer); } break; case AST_CONTROL_RINGING: if (ast->_state == AST_STATE_UP) { playtone(p->handle, &Ringbacktone); p->state = VPB_STATE_PLAYRING; ast_verb(4, "%s: vpb indicate: setting ringback timer [%d]\n", p->dev,p->ringback_timer_id); vpb_timer_stop(p->ringback_timer); vpb_timer_start(p->ringback_timer); } break; case AST_CONTROL_ANSWER: case -1: /* -1 means stop playing? */ vpb_timer_stop(p->ringback_timer); vpb_timer_stop(p->busy_timer); stoptone(p->handle); break; case AST_CONTROL_HANGUP: if (ast->_state == AST_STATE_UP) { playtone(p->handle, &Busytone); p->state = VPB_STATE_PLAYBUSY; vpb_timer_stop(p->busy_timer); vpb_timer_start(p->busy_timer); } break; case AST_CONTROL_HOLD: ast_moh_start(ast, (const char *) data, NULL); break; case AST_CONTROL_UNHOLD: ast_moh_stop(ast); break; default: res = 0; break; } tmp = ast_mutex_unlock(&p->lock);/* ast_verb(4, "%s: unLOCKING in indicate [%d]\n", p->dev,tmp);*/ return res;}static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan){ struct vpb_pvt *p = (struct vpb_pvt *)newchan->tech_pvt; int res = 0;/* ast_verb(4, "%s: LOCKING in fixup \n", p->dev); ast_verb(4, "%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);*/ ast_mutex_lock(&p->lock); ast_debug(1, "New owner for channel %s is %s\n", p->dev, newchan->name); if (p->owner == oldchan) { p->owner = newchan; } if (newchan->_state == AST_STATE_RINGING){ if (use_ast_ind == 1) { ast_verb(4, "%s: vpb_fixup Calling ast_indicate\n", p->dev); ast_indicate(newchan, AST_CONTROL_RINGING); } else { ast_verb(4, "%s: vpb_fixup Calling vpb_indicate\n", p->dev); vpb_indicate(newchan, AST_CONTROL_RINGING, NULL, 0); } } res = ast_mutex_unlock(&p->lock);/* ast_verb(4, "%s: unLOCKING in fixup [%d]\n", p->dev,res);*/ return 0;}static int vpb_digit_begin(struct ast_channel *ast, char digit){ /* XXX Modify this callback to let Asterisk control the length of DTMF */ return 0;}static int vpb_digit_end(struct ast_channel *ast, char digit, unsigned int duration){ struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; char s[2]; int res = 0; if (use_ast_dtmf) { ast_verb(4, "%s: vpb_digit: asked to play digit[%c] but we are using asterisk dtmf play back?!\n", p->dev, digit); return 0; }/* ast_verb(4, "%s: LOCKING in digit \n", p->dev); ast_verb(4, "%s: LOCKING count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);*/ ast_mutex_lock(&p->lock); s[0] = digit; s[1] = '\0'; ast_verb(4, "%s: vpb_digit: asked to play digit[%s]\n", p->dev, s); ast_mutex_lock(&p->play_dtmf_lock); strncat(p->play_dtmf, s, sizeof(*p->play_dtmf) - strlen(p->play_dtmf) - 1); ast_mutex_unlock(&p->play_dtmf_lock); res = ast_mutex_unlock(&p->lock);/* ast_verb(4, "%s: unLOCKING in digit [%d]\n", p->dev,res);*/ return 0;}/* Places a call out of a VPB channel */static int vpb_call(struct ast_channel *ast, char *dest, int timeout){ struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; int res = 0, i; char *s = strrchr(dest, '/'); char dialstring[254] = ""; int tmp = 0;/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -