📄 chan_vpb.cc
字号:
ast_verb(4, "%s: LOCKING in call \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_verb(4, "%s: starting call to [%s]\n", p->dev, dest); if (s) s = s + 1; else s = dest; ast_copy_string(dialstring, s, sizeof(dialstring)); for (i = 0; dialstring[i] != '\0'; i++) { if ((dialstring[i] == 'w') || (dialstring[i] == 'W')) dialstring[i] = ','; else if ((dialstring[i] == 'f') || (dialstring[i] == 'F')) dialstring[i] = '&'; } if (ast->_state != AST_STATE_DOWN && ast->_state != AST_STATE_RESERVED) { ast_log(LOG_WARNING, "vpb_call on %s neither down nor reserved!\n", ast->name); tmp = ast_mutex_unlock(&p->lock);/* ast_verb(4, "%s: unLOCKING in call [%d]\n", p->dev,tmp);*/ return -1; } if (p->mode != MODE_FXO) /* Station port, ring it. */ vpb_ring_station_async(p->handle, 2); else { VPB_CALL call; int j; /* Dial must timeout or it can leave channels unuseable */ if (timeout == 0) { timeout = TIMER_PERIOD_NOANSWER; } else { timeout = timeout * 1000; /* convert from secs to ms. */ } /* These timeouts are only used with call progress dialing */ call.dialtones = 1; /* Number of dialtones to get outside line */ call.dialtone_timeout = VPB_DIALTONE_WAIT; /* Wait this long for dialtone (ms) */ call.ringback_timeout = VPB_RINGWAIT; /* Wait this long for ringing after dialing (ms) */ call.inter_ringback_timeout = VPB_CONNECTED_WAIT; /* If ringing stops for this long consider it connected (ms) */ call.answer_timeout = timeout; /* Time to wait for answer after ringing starts (ms) */ memcpy(&call.tone_map, DialToneMap, sizeof(DialToneMap)); vpb_set_call(p->handle, &call); ast_verb(2, "%s: Calling %s on %s \n",p->dev, dialstring, ast->name); ast_verb(2, "%s: Dial parms for %s %d/%dms/%dms/%dms/%dms\n", p->dev, ast->name, call.dialtones, call.dialtone_timeout, call.ringback_timeout, call.inter_ringback_timeout, call.answer_timeout); for (j = 0; !call.tone_map[j].terminate; j++) { ast_verb(2, "%s: Dial parms for %s tone %d->%d\n", p->dev, ast->name, call.tone_map[j].tone_id, call.tone_map[j].call_id); } ast_verb(4, "%s: Disabling Loop Drop detection\n", p->dev); vpb_disable_event(p->handle, VPB_MDROP); vpb_sethook_sync(p->handle, VPB_OFFHOOK); p->state = VPB_STATE_OFFHOOK; #ifndef DIAL_WITH_CALL_PROGRESS vpb_sleep(300); ast_verb(4, "%s: Enabling Loop Drop detection\n", p->dev); vpb_enable_event(p->handle, VPB_MDROP); res = vpb_dial_async(p->handle, dialstring); #else ast_verb(4, "%s: Enabling Loop Drop detection\n", p->dev); vpb_enable_event(p->handle, VPB_MDROP); res = vpb_call_async(p->handle, dialstring); #endif if (res != VPB_OK) { ast_debug(1, "Call on %s to %s failed: %d\n", ast->name, s, res); res = -1; } else res = 0; } ast_verb(3, "%s: VPB Calling %s [t=%d] on %s returned %d\n", p->dev , s, timeout, ast->name, res); if (res == 0) { ast_setstate(ast, AST_STATE_RINGING); ast_queue_control(ast, AST_CONTROL_RINGING); } if (!p->readthread) { ast_pthread_create(&p->readthread, NULL, do_chanreads, (void *)p); } tmp = ast_mutex_unlock(&p->lock);/* ast_verb(4, "%s: unLOCKING in call [%d]\n", p->dev,tmp);*/ return res;}static int vpb_hangup(struct ast_channel *ast){ struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; VPB_EVENT je; char str[VPB_MAX_STR]; int res = 0;/* ast_verb(4, "%s: LOCKING in hangup \n", p->dev); ast_verb(4, "%s: LOCKING in hangup count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner); ast_verb(4, "%s: LOCKING pthread_self(%d)\n", p->dev,pthread_self()); ast_mutex_lock(&p->lock);*/ ast_verb(2, "%s: Hangup requested\n", ast->name); if (!ast->tech || !ast->tech_pvt) { ast_log(LOG_WARNING, "%s: channel not connected?\n", ast->name); res = ast_mutex_unlock(&p->lock);/* ast_verb(4, "%s: unLOCKING in hangup [%d]\n", p->dev,res);*/ /* Free up ast dsp if we have one */ if (use_ast_dtmfdet && p->vad) { ast_dsp_free(p->vad); p->vad = NULL; } return 0; } /* Stop record */ p->stopreads = 1; if (p->readthread) { pthread_join(p->readthread, NULL); ast_verb(4, "%s: stopped record thread \n", ast->name); } /* Stop play */ if (p->lastoutput != -1) { ast_verb(2, "%s: Ending play mode \n", ast->name); vpb_play_terminate(p->handle); ast_mutex_lock(&p->play_lock); vpb_play_buf_finish(p->handle); ast_mutex_unlock(&p->play_lock); } ast_verb(4, "%s: Setting state down\n", ast->name); ast_setstate(ast, AST_STATE_DOWN);/* ast_verb(4, "%s: LOCKING in hangup \n", p->dev); ast_verb(4, "%s: LOCKING in hangup count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner); ast_verb(4, "%s: LOCKING pthread_self(%d)\n", p->dev,pthread_self());*/ ast_mutex_lock(&p->lock); if (p->mode != MODE_FXO) { /* station port. */ vpb_ring_station_async(p->handle, 0); if (p->state != VPB_STATE_ONHOOK) { /* This is causing a "dial end" "play tone" loop playtone(p->handle, &Busytone); p->state = VPB_STATE_PLAYBUSY; ast_verb(5, "%s: Station offhook[%d], playing busy tone\n", ast->name,p->state); */ } else { stoptone(p->handle); } #ifdef VPB_PRI vpb_setloop_async(p->handle, VPB_OFFHOOK); vpb_sleep(100); vpb_setloop_async(p->handle, VPB_ONHOOK); #endif } else { stoptone(p->handle); /* Terminates any dialing */ vpb_sethook_sync(p->handle, VPB_ONHOOK); p->state=VPB_STATE_ONHOOK; } while (VPB_OK == vpb_get_event_ch_async(p->handle, &je)) { vpb_translate_event(&je, str); ast_verb(4, "%s: Flushing event [%d]=>%s\n", ast->name, je.type, str); } p->readthread = 0; p->lastoutput = -1; p->lastinput = -1; p->last_ignore_dtmf = 1; p->ext[0] = 0; p->dialtone = 0; p->owner = NULL; ast->tech_pvt = NULL; /* Free up ast dsp if we have one */ if (use_ast_dtmfdet && p->vad) { ast_dsp_free(p->vad); p->vad = NULL; } ast_verb(2, "%s: Hangup complete\n", ast->name); restart_monitor();/* ast_verb(4, "%s: LOCKING in hangup count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);*/ res = ast_mutex_unlock(&p->lock);/* ast_verb(4, "%s: unLOCKING in hangup [%d]\n", p->dev,res); ast_verb(4, "%s: LOCKING in hangup count[%d] owner[%d] \n", p->dev, p->lock.__m_count,p->lock.__m_owner);*/ return 0;}static int vpb_answer(struct ast_channel *ast){ struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; int res = 0;/* VPB_EVENT je; int ret; ast_verb(4, "%s: LOCKING in answer \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_verb(4, "%s: Answering channel\n", p->dev); if (p->mode == MODE_FXO) { ast_verb(4, "%s: Disabling Loop Drop detection\n", p->dev); vpb_disable_event(p->handle, VPB_MDROP); } if (ast->_state != AST_STATE_UP) { if (p->mode == MODE_FXO) { vpb_sethook_sync(p->handle, VPB_OFFHOOK); p->state = VPB_STATE_OFFHOOK;/* vpb_sleep(500); ret = vpb_get_event_ch_async(p->handle, &je); if ((ret == VPB_OK) && ((je.type != VPB_DROP)&&(je.type != VPB_RING))){ ast_verb(4, "%s: Answer collected a wrong event!!\n", p->dev); vpb_put_event(&je); }*/ } ast_setstate(ast, AST_STATE_UP); ast_verb(2, "%s: Answered call on %s [%s]\n", p->dev, ast->name, (p->mode == MODE_FXO) ? "FXO" : "FXS"); ast->rings = 0; if (!p->readthread) { /* res = ast_mutex_unlock(&p->lock); */ /* ast_verbose("%s: unLOCKING in answer [%d]\n", p->dev,res); */ ast_pthread_create(&p->readthread, NULL, do_chanreads, (void *)p); } else { ast_verb(4, "%s: Record thread already running!!\n", p->dev); } } else { ast_verb(4, "%s: Answered state is up\n", p->dev); /* res = ast_mutex_unlock(&p->lock); */ /* ast_verbose("%s: unLOCKING in answer [%d]\n", p->dev,res); */ } vpb_sleep(500); if (p->mode == MODE_FXO) { ast_verb(4, "%s: Re-enabling Loop Drop detection\n", p->dev); vpb_enable_event(p->handle, VPB_MDROP); } res = ast_mutex_unlock(&p->lock);/* ast_verb(4, "%s: unLOCKING in answer [%d]\n", p->dev,res);*/ return 0;}static struct ast_frame *vpb_read(struct ast_channel *ast){ struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; static struct ast_frame f = { AST_FRAME_NULL }; f.src = "vpb"; ast_log(LOG_NOTICE, "%s: vpb_read: should never be called!\n", p->dev); ast_verbose("%s: vpb_read: should never be called!\n", p->dev); return &f;}static inline AudioCompress ast2vpbformat(int ast_format){ switch (ast_format) { case AST_FORMAT_ALAW: return VPB_ALAW; case AST_FORMAT_SLINEAR: return VPB_LINEAR; case AST_FORMAT_ULAW: return VPB_MULAW; case AST_FORMAT_ADPCM: return VPB_OKIADPCM; default: return VPB_RAW; }}static inline const char * ast2vpbformatname(int ast_format){ switch(ast_format) { case AST_FORMAT_ALAW: return "AST_FORMAT_ALAW:VPB_ALAW"; case AST_FORMAT_SLINEAR: return "AST_FORMAT_SLINEAR:VPB_LINEAR"; case AST_FORMAT_ULAW: return "AST_FORMAT_ULAW:VPB_MULAW"; case AST_FORMAT_ADPCM: return "AST_FORMAT_ADPCM:VPB_OKIADPCM"; default: return "UNKN:UNKN"; }}static inline int astformatbits(int ast_format){ switch (ast_format) { case AST_FORMAT_SLINEAR: return 16; case AST_FORMAT_ADPCM: return 4; case AST_FORMAT_ALAW: case AST_FORMAT_ULAW: default: return 8; }}int a_gain_vector(float g, short *v, int n) { int i; float tmp; for (i = 0; i < n; i++) { tmp = g * v[i]; if (tmp > 32767.0) tmp = 32767.0; if (tmp < -32768.0) tmp = -32768.0; v[i] = (short)tmp; } return i;}/* Writes a frame of voice data to a VPB channel */static int vpb_write(struct ast_channel *ast, struct ast_frame *frame){ struct vpb_pvt *p = (struct vpb_pvt *)ast->tech_pvt; int res = 0; AudioCompress fmt = VPB_RAW; struct timeval play_buf_time_start; int tdiff;/* ast_mutex_lock(&p->lock); */ ast_verb(6, "%s: vpb_write: Writing to channel\n", p->dev); if (frame->frametype != AST_FRAME_VOICE) { ast_verb(4, "%s: vpb_write: Don't know how to handle from type %d\n", ast->name, frame->frametype);/* ast_mutex_unlock(&p->lock); */ return 0; } else if (ast->_state != AST_STATE_UP) { ast_verb(4, "%s: vpb_write: Attempt to Write frame type[%d]subclass[%d] on not up chan(state[%d])\n",ast->name, frame->frametype, frame->subclass,ast->_state); p->lastoutput = -1;/* ast_mutex_unlock(&p->lock); */ return 0; }/* ast_debug(1, "%s: vpb_write: Checked frame type..\n", p->dev); */ fmt = ast2vpbformat(frame->subclass); if (fmt < 0) { ast_log(LOG_WARNING, "%s: vpb_write: Cannot handle frames of %d format!\n", ast->name, frame->subclass); return -1; } tdiff = ast_tvdiff_ms(ast_tvnow(), p->lastplay); ast_debug(1, "%s: vpb_write: time since last play(%d) \n", p->dev, tdiff); if (tdiff < (VPB_SAMPLES / 8 - 1)) { ast_debug(1, "%s: vpb_write: Asked to play too often (%d) (%d)\n", p->dev, tdiff, frame->datalen); /* return 0; */ } p->lastplay = ast_tvnow();/* ast_debug(1, "%s: vpb_write: Checked frame format..\n", p->dev); */ ast_mutex_lock(&p->play_lock);/* ast_debug(1, "%s: vpb_write: Got play lock..\n", p->dev); */ /* Check if we have set up the play_buf */ if (p->lastoutput == -1) { vpb_play_buf_start(p->handle, fmt); ast_verb(2, "%s: vpb_write: Starting play mode (codec=%d)[%s]\n", p->dev, fmt, ast2vpbformatname(frame->subclass)); p->lastoutput = fmt; ast_mutex_unlock(&p->play_lock); return 0; } else if (p->lastoutput != fmt) { vpb_play_buf_finish(p->handle); vpb_play_buf_start(p->handle, fmt); ast_verb(2, "%s: vpb_write: Changed play format (%d=>%d)\n", p->dev, p->lastoutput, fmt); ast_mutex_unlock(&p->play_lock); return 0; } p->lastoutput = fmt; /* Apply extra gain ! */ if( p->txswgain > MAX_VPB_GAIN ) a_gain_vector(p->txswgain - MAX_VPB_GAIN , (short*)frame->data, frame->datalen / sizeof(short));/* ast_debug(1, "%s: vpb_write: Applied gain..\n", p->dev); *//* ast_debug(1, "%s: vpb_write: play_buf_time %d\n", p->dev, p->play_buf_time); */ if ((p->read_state == 1) && (p->play_buf_time < 5)){ play_buf_time_start = ast_tvnow();/* res = vpb_play_buf_sync(p->handle, (char *)frame->data, tdiff * 8 * 2); */ res = vpb_play_buf_sync(p->handle, (char *)frame->data, frame->datalen); if(res == VPB_OK) { short * data = (short*)frame->data; ast_verb(6, "%s: vpb_write: Wrote chan (codec=%d) %d %d\n", p->dev, fmt, data[0], data[1]); } p->play_buf_time = ast_tvdiff_ms(ast_tvnow(), play_buf_time_start); } else { p->chuck_count++; ast_debug(1, "%s: vpb_write: Tossed data away, tooooo much data!![%d]\n", p->dev, p->chuck_count); p->play_buf_time = 0; } ast_mutex_unlock(&p->play_lock);/* ast_mutex_unlock(&p->lock); */ ast_verb(6, "%s: vpb_write: Done Writing to channel\n", p->dev); return 0;}/* Read monitor thread function. */static void *do_chanreads(void *pvt){ struct vpb_pvt *p = (struct vpb_pvt *)pvt; struct ast_frame *fr = &p->fr; char *readbuf = ((char *)p->buf) + AST_FRIENDLY_OFFSET; int bridgerec = 0; int afmt, readlen, res, trycnt=0; AudioCompress fmt; int ignore_dtmf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -