📄 chan_vpb.cc
字号:
return AST_BRIDGE_FAILED_NOWARN; #endif if ( UseNativeBridge != 1){ return AST_BRIDGE_FAILED_NOWARN; }/* ast_mutex_lock(&p0->lock); ast_mutex_lock(&p1->lock);*/ /* Bridge channels, check if we can. I believe we always can, so find a slot.*/ ast_mutex_lock(&bridge_lock); for (i = 0; i < max_bridges; i++) if (!bridges[i].inuse) break; if (i < max_bridges) { bridges[i].inuse = 1; bridges[i].endbridge = 0; bridges[i].flags = flags; bridges[i].rc = rc; bridges[i].fo = fo; bridges[i].c0 = c0; bridges[i].c1 = c1; } ast_mutex_unlock(&bridge_lock); if (i == max_bridges) { ast_log(LOG_WARNING, "%s: vpb_bridge: Failed to bridge %s and %s!\n", p0->dev, c0->name, c1->name); ast_mutex_unlock(&p0->lock); ast_mutex_unlock(&p1->lock); return AST_BRIDGE_FAILED_NOWARN; } else { /* Set bridge pointers. You don't want to take these locks while holding bridge lock.*/ ast_mutex_lock(&p0->lock); p0->bridge = &bridges[i]; ast_mutex_unlock(&p0->lock); ast_mutex_lock(&p1->lock); p1->bridge = &bridges[i]; ast_mutex_unlock(&p1->lock); ast_verb(2, "%s: vpb_bridge: Bridging call entered with [%s, %s]\n", p0->dev, c0->name, c1->name); } ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name); #ifdef HALF_DUPLEX_BRIDGE ast_debug(2, "%s: vpb_bridge: Starting half-duplex bridge [%s, %s]\n", p0->dev, c0->name, c1->name); int dir = 0; memset(p0->buf, 0, sizeof(p0->buf)); memset(p1->buf, 0, sizeof(p1->buf)); vpb_record_buf_start(p0->handle, VPB_ALAW); vpb_record_buf_start(p1->handle, VPB_ALAW); vpb_play_buf_start(p0->handle, VPB_ALAW); vpb_play_buf_start(p1->handle, VPB_ALAW); while (!bridges[i].endbridge) { struct vpb_pvt *from, *to; if (++dir % 2) { from = p0; to = p1; } else { from = p1; to = p0; } vpb_record_buf_sync(from->handle, from->buf, VPB_SAMPLES); vpb_play_buf_sync(to->handle, from->buf, VPB_SAMPLES); } vpb_record_buf_finish(p0->handle); vpb_record_buf_finish(p1->handle); vpb_play_buf_finish(p0->handle); vpb_play_buf_finish(p1->handle); ast_debug(2, "%s: vpb_bridge: Finished half-duplex bridge [%s, %s]\n", p0->dev, c0->name, c1->name); res = VPB_OK; #else res = vpb_bridge(p0->handle, p1->handle, VPB_BRIDGE_ON); if (res == VPB_OK) { /* pthread_cond_wait(&bridges[i].cond, &bridges[i].lock);*/ /* Wait for condition signal. */ while (!bridges[i].endbridge) { /* Are we really ment to be doing nothing ?!?! */ who = ast_waitfor_n(cs, 2, &timeoutms); if (!who) { if (!timeoutms) { res = AST_BRIDGE_RETRY; break; } ast_debug(1, "%s: vpb_bridge: Empty frame read...\n", p0->dev); /* check for hangup / whentohangup */ if (ast_check_hangup(c0) || ast_check_hangup(c1)) break; continue; } f = ast_read(who); if (!f || ((f->frametype == AST_FRAME_DTMF) && (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) || ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) { *fo = f; *rc = who; ast_debug(1, "%s: vpb_bridge: Got a [%s]\n", p0->dev, f ? "digit" : "hangup");#if 0 if ((c0->tech_pvt == pvt0) && (!ast_check_hangup(c0))) { if (pr0->set_rtp_peer(c0, NULL, NULL, 0)) ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name); } if ((c1->tech_pvt == pvt1) && (!ast_check_hangup(c1))) { if (pr1->set_rtp_peer(c1, NULL, NULL, 0)) ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name); } /* That's all we needed */ return 0;#endif /* Check if we need to break */ if (break_for_dtmf) { break; } else if ((f->frametype == AST_FRAME_DTMF) && ((f->subclass == '#') || (f->subclass == '*'))) { break; } } else { if ((f->frametype == AST_FRAME_DTMF) || (f->frametype == AST_FRAME_VOICE) || (f->frametype == AST_FRAME_VIDEO)) { /* Forward voice or DTMF frames if they happen upon us */ /* Actually I dont think we want to forward on any frames! if (who == c0) { ast_write(c1, f); } else if (who == c1) { ast_write(c0, f); } */ } ast_frfree(f); } /* Swap priority not that it's a big deal at this point */ cs[2] = cs[0]; cs[0] = cs[1]; cs[1] = cs[2]; }; vpb_bridge(p0->handle, p1->handle, VPB_BRIDGE_OFF); } #endif ast_mutex_lock(&bridge_lock); bridges[i].inuse = 0; ast_mutex_unlock(&bridge_lock); p0->bridge = NULL; p1->bridge = NULL; ast_verb(2, "Bridging call done with [%s, %s] => %d\n", c0->name, c1->name, res);/* ast_mutex_unlock(&p0->lock); ast_mutex_unlock(&p1->lock);*/ return (res == VPB_OK) ? AST_BRIDGE_COMPLETE : AST_BRIDGE_FAILED;}/* Caller ID can be located in different positions between the rings depending on your Telco * Australian (Telstra) callerid starts 700ms after 1st ring and finishes 1.5s after first ring * Use ANALYSE_CID to record rings and determine location of callerid *//* #define ANALYSE_CID */#define RING_SKIP 300#define CID_MSECS 2000static void get_callerid(struct vpb_pvt *p){ short buf[CID_MSECS*8]; /* 8kHz sampling rate */ struct timeval cid_record_time; int rc; struct ast_channel *owner = p->owner;/* char callerid[AST_MAX_EXTENSION] = ""; */#ifdef ANALYSE_CID void * ws; char * file="cidsams.wav";#endif if (ast_mutex_trylock(&p->record_lock) == 0) { cid_record_time = ast_tvnow(); ast_verb(4, "CID record - start\n"); /* Skip any trailing ringtone */ if (UsePolarityCID != 1){ vpb_sleep(RING_SKIP); } ast_verb(4, "CID record - skipped %dms trailing ring\n", ast_tvdiff_ms(ast_tvnow(), cid_record_time)); cid_record_time = ast_tvnow(); /* Record bit between the rings which contains the callerid */ vpb_record_buf_start(p->handle, VPB_LINEAR); rc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf)); vpb_record_buf_finish(p->handle);#ifdef ANALYSE_CID vpb_wave_open_write(&ws, file, VPB_LINEAR); vpb_wave_write(ws, (char *)buf, sizeof(buf)); vpb_wave_close_write(ws);#endif ast_verb(4, "CID record - recorded %dms between rings\n", ast_tvdiff_ms(ast_tvnow(), cid_record_time)); ast_mutex_unlock(&p->record_lock); if (rc != VPB_OK) { ast_log(LOG_ERROR, "Failed to record caller id sample on %s\n", p->dev); return; } VPB_CID *cli_struct = new VPB_CID; cli_struct->ra_cldn[0] = 0; cli_struct->ra_cn[0] = 0; /* This decodes FSK 1200baud type callerid */ if ((rc = vpb_cid_decode2(cli_struct, buf, CID_MSECS * 8)) == VPB_OK ) { /* if (owner->cid.cid_num) ast_free(owner->cid.cid_num); owner->cid.cid_num=NULL; if (owner->cid.cid_name) ast_free(owner->cid.cid_name); owner->cid.cid_name=NULL; */ if (cli_struct->ra_cldn[0] == '\0') { /* owner->cid.cid_num = ast_strdup(cli_struct->cldn); owner->cid.cid_name = ast_strdup(cli_struct->cn); */ if (owner) { ast_set_callerid(owner, cli_struct->cldn, cli_struct->cn, cli_struct->cldn); } else { strcpy(p->cid_num, cli_struct->cldn); strcpy(p->cid_name, cli_struct->cn); } ast_verb(4, "CID record - got [%s] [%s]\n", owner->cid.cid_num, owner->cid.cid_name); snprintf(p->callerid, sizeof(p->callerid), "%s %s", cli_struct->cldn, cli_struct->cn); } else { ast_log(LOG_ERROR, "CID record - No caller id avalable on %s \n", p->dev); } } else { ast_log(LOG_ERROR, "CID record - Failed to decode caller id on %s - %d\n", p->dev, rc); ast_copy_string(p->callerid, "unknown", sizeof(p->callerid)); } delete cli_struct; } else ast_log(LOG_ERROR, "CID record - Failed to set record mode for caller id on %s\n", p->dev);}static void get_callerid_ast(struct vpb_pvt *p){ struct callerid_state *cs; char buf[1024]; char *name = NULL, *number = NULL; int flags; int rc = 0, vrc; int sam_count = 0; struct ast_channel *owner = p->owner; int which_cid;/* float old_gain;*/#ifdef ANALYSE_CID void * ws; char * file = "cidsams.wav";#endif if (p->callerid_type == 1) { ast_verb(4, "Collected caller ID already\n"); return; } else if (p->callerid_type == 2 ) { which_cid = CID_SIG_V23; ast_verb(4, "Collecting Caller ID v23...\n"); } else if (p->callerid_type == 3) { which_cid = CID_SIG_BELL; ast_verb(4, "Collecting Caller ID bell...\n"); } else { ast_verb(4, "Caller ID disabled\n"); return; }/* vpb_sleep(RING_SKIP); *//* vpb_record_get_gain(p->handle, &old_gain); */ cs = callerid_new(which_cid); if (cs) {#ifdef ANALYSE_CID vpb_wave_open_write(&ws, file, VPB_MULAW); vpb_record_set_gain(p->handle, 3.0); vpb_record_set_hw_gain(p->handle, 12.0); #endif vpb_record_buf_start(p->handle, VPB_MULAW); while ((rc == 0) && (sam_count < 8000 * 3)) { vrc = vpb_record_buf_sync(p->handle, (char*)buf, sizeof(buf)); if (vrc != VPB_OK) ast_log(LOG_ERROR, "%s: Caller ID couldn't read audio buffer!\n", p->dev); rc = callerid_feed(cs, (unsigned char *)buf, sizeof(buf), AST_FORMAT_ULAW);#ifdef ANALYSE_CID vpb_wave_write(ws, (char *)buf, sizeof(buf)); #endif sam_count += sizeof(buf); ast_verb(4, "Collecting Caller ID samples [%d][%d]...\n", sam_count, rc); } vpb_record_buf_finish(p->handle);#ifdef ANALYSE_CID vpb_wave_close_write(ws);#endif if (rc == 1) { callerid_get(cs, &name, &number, &flags); ast_debug(1, "%s: Caller ID name [%s] number [%s] flags [%d]\n", p->dev, name, number, flags); } else { ast_log(LOG_ERROR, "%s: Failed to decode Caller ID \n", p->dev); }/* vpb_record_set_gain(p->handle, old_gain); *//* vpb_record_set_hw_gain(p->handle,6.0); */ } else { ast_log(LOG_ERROR, "%s: Failed to create Caller ID struct\n", p->dev); } if (owner->cid.cid_num) { ast_free(owner->cid.cid_num); owner->cid.cid_num = NULL; } if (owner->cid.cid_name) { ast_free(owner->cid.cid_name); owner->cid.cid_name = NULL; } if (number) ast_shrink_phone_number(number); ast_set_callerid(owner, number, name, owner->cid.cid_ani ? NULL : number); if (!ast_strlen_zero(name)){ snprintf(p->callerid, sizeof(p->callerid), "%s %s", number, name); } else { ast_copy_string(p->callerid, number, sizeof(p->callerid)); } if (cs) callerid_free(cs);}/* Terminate any tones we are presently playing */static void stoptone(int handle){ int ret; VPB_EVENT je; while (vpb_playtone_state(handle) != VPB_OK) { vpb_tone_terminate(handle); ret = vpb_get_event_ch_async(handle, &je); if ((ret == VPB_OK) && (je.type != VPB_DIALEND)) { ast_verb(4, "Stop tone collected a wrong event!![%d]\n", je.type);/* vpb_put_event(&je); */ } vpb_sleep(10); }}/* Safe vpb_playtone_async */static int playtone( int handle, VPB_TONE *tone){ int ret = VPB_OK; stoptone(handle); ast_verb(4, "[%02d]: Playing tone\n", handle); ret = vpb_playtone_async(handle, tone); return ret;}static inline int monitor_handle_owned(struct vpb_pvt *p, VPB_EVENT *e){ struct ast_frame f = {AST_FRAME_CONTROL}; /* default is control, Clear rest. */ int endbridge = 0; int res = 0; ast_verb(4, "%s: handle_owned: got event: [%d=>%d]\n", p->dev, e->type, e->data); f.src = "vpb"; switch (e->type) { case VPB_RING: if (p->mode == MODE_FXO) { f.subclass = AST_CONTROL_RING; vpb_timer_stop(p->ring_timer); vpb_timer_start(p->ring_timer); } else f.frametype = AST_FRAME_NULL; /* ignore ring on station port. */ break; case VPB_RING_OFF: f.frametype = AST_FRAME_NULL; break; case VPB_TIMEREXP: if (e->data == p->busy_timer_id) { playtone(p->handle, &Busytone); p->state = VPB_STATE_PLAYBUSY; vpb_timer_stop(p->busy_timer); vpb_timer_start(p->busy_timer); f.frametype = AST_FRAME_NULL; } else if (e->data == p->ringback_timer_id) { playtone(p->handle, &Ringbacktone); vpb_timer_stop(p->ringback_timer); vpb_timer_start(p->ringback_timer); f.frametype = AST_FRAME_NULL; } else if (e->data == p->ring_timer_id) { /* We didnt get another ring in time! */ if (p->owner->_state != AST_STATE_UP) { /* Assume caller has hung up */ vpb_timer_stop(p->ring_timer); f.subclass = AST_CONTROL_HANGUP; } else { vpb_timer_stop(p->ring_timer); f.frametype = AST_FRAME_NULL; } } else { f.frametype = AST_FRAME_NULL; /* Ignore. */ } break; case VPB_DTMF_DOWN: case VPB_DTMF: if (use_ast_dtmfdet) { f.frametype = AST_FRAME_NULL; } else if (p->owner->_state == AST_STATE_UP) { f.frametype = AST_FRAME_DTMF; f.subclass = e->data; } else f.frametype = AST_FRAME_NULL; break; case VPB_TONEDETECT: if (e->data == VPB_BUSY || e->data == VPB_BUSY_308 || e->data == VPB_BUSY_AUST ) { ast_debug(4, "%s: handle_owned: got event: BUSY\n", p->dev); if (p->owner->_state == AST_STATE_UP) { f.subclass = AST_CONTROL_HANGUP; } else { f.subclass = AST_CONTROL_BUSY;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -