#include "StdAfx.h" #include "SpanChannel.h" #include "DspChannel.h" #include "DevDsp.h" #include "PrdVirtualDevice.h" #include "MC.h" #include "../IVR/IvrSysInc.h" #include "TtsInterface.h" CDspChannel::CDspChannel(DEV_RES_CH_TYPE ChannelNo, DEV_RES_NO_TYPE NodeNo, DEV_RES_NO_TYPE BoardNo) : CChannelResource(DEV_RES_TYPE_DSP, NodeNo, BoardNo, DEVICE_RES_NO_ANY, ChannelNo), m_pMixer(NULL), m_Job(DEV_VOC_JOB_NONE), m_IsRecording(false) { } CDspChannel::~CDspChannel(void) { } /***************************************************************** **【函数名称】 __constructPlayStruct **【函数功能】 构造放音SDK所需结构体 **【参数】 **【返回值】 ****************************************************************/ bool CDspChannel::__constructPlayStruct( PlayVoiceContent* pContent ) { PlayVoiceMode Mode = pContent->nModel; switch(Mode) { case PVM_PLAY_WAIT_DIGIT: m_Job = DEV_VOC_JOB_PLAY_DTMF; case PVM_PLAY_ONLY: { // 如果使用了TTS,进行TTS转换 switch(pContent->nTts) { default: case PLAY_CONTENT_AUDIO: // 不使用TTS sprintf_s(m_AudioFilePlay, MAX_PATH, _T("%s\0"), pContent->szFileName); break; case PLAY_CONTENT_TTS_STR: // TTS文本 { ITtsInterface::getInstance().setTTSParam(pContent->nTtsDigitMode, pContent->nTtsSpeed, pContent->nTtsVolume); if(!ITtsInterface::getInstance().string2Audio(pContent->szFileName, m_AudioFilePlay, MAX_PATH)) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_WARNING, _T("{DspCh}: 通道[%d-%d-%d]TTS文本转换失败"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo); return false; } } break; case PLAY_CONTENT_TTS_FILE: // TTS文件 { ITtsInterface::getInstance().setTTSParam(pContent->nTtsDigitMode, pContent->nTtsSpeed, pContent->nTtsVolume); if(!ITtsInterface::getInstance().file2Audio(pContent->szFileName, m_AudioFilePlay, MAX_PATH)) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_WARNING, _T("{DspCh}: 通道[%d-%d-%d]TTS文件转换失败, File = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, pContent->szFileName); return false; } } break; } memset(&m_IottPlay[0], 0, sizeof(DX_IOTT)); m_IottPlay[0].io_fhandle = CMC::GetInstance().allocPrd(m_Id.NodeNo).handle(); m_IottPlay[0].io_bufp = m_AudioFilePlay; m_IottPlay[0].io_offset = 0; m_IottPlay[0].io_length = -1; m_IottPlay[0].io_type = IO_PRD_DEV | IO_EOT; memset(&m_XpbPlay, 0, sizeof(m_XpbPlay)); m_XpbPlay.wFileFormat = FILE_FORMAT_WAVE; // WAV file. m_XpbPlay.wDataFormat = DATA_FORMAT_PCM; // PCM m_XpbPlay.wBitsPerSample = 16; // The number of bits per sample. m_XpbPlay.nSamplesPerSec = DRT_8KHZ; // Sampling rates } case PVM_WAIT_DIGIT: { int Idx = 0; bool Used = false; if(pContent->nDtmfCount > 0) { ISX_dx_clrtpt(&m_TptPlay[Idx], 1); m_TptPlay[Idx].tp_type = IO_EOT; m_TptPlay[Idx].tp_termno = DX_MAXDTMF; m_TptPlay[Idx].tp_length = pContent->nDtmfCount; m_TptPlay[Idx].tp_flags = TF_MAXDTMF; Idx++; Used = true; } if(pContent->cDtmfEnd > 0) { if(Used) { m_TptPlay[Idx - 1].tp_type &= ~IO_EOT; m_TptPlay[Idx - 1].tp_type = IO_CONT; } ISX_dx_clrtpt(&m_TptPlay[Idx], 1); m_TptPlay[Idx].tp_type = IO_EOT; m_TptPlay[Idx].tp_termno = DX_DIGMASK; switch(pContent->cDtmfEnd) { case '*': m_TptPlay[Idx].tp_length = DM_S; break; case '#': m_TptPlay[Idx].tp_length = DM_P; break; case '0': m_TptPlay[Idx].tp_length = DM_0; break; case '1': m_TptPlay[Idx].tp_length = DM_1; break; case '2': m_TptPlay[Idx].tp_length = DM_2; break; case '3': m_TptPlay[Idx].tp_length = DM_3; break; case '4': m_TptPlay[Idx].tp_length = DM_4; break; case '5': m_TptPlay[Idx].tp_length = DM_5; break; case '6': m_TptPlay[Idx].tp_length = DM_6; break; case '7': m_TptPlay[Idx].tp_length = DM_7; break; case '8': m_TptPlay[Idx].tp_length = DM_8; break; case '9': m_TptPlay[Idx].tp_length = DM_9; break; default: ASSERT(FALSE); break; } m_TptPlay[Idx].tp_flags = TF_DIGMASK; Idx++; Used = true; } // 只放音的模式下也允许被按键打断,所以要在此设置跳出条件 if(Mode == PVM_PLAY_ONLY) { m_Job = DEV_VOC_JOB_PLAY_FILE; break; } if(pContent->nDtmfPeriod > 0) { if(Used) { m_TptPlay[Idx - 1].tp_type &= ~IO_EOT; m_TptPlay[Idx - 1].tp_type = IO_CONT; } ISX_dx_clrtpt(&m_TptPlay[Idx], 1); m_TptPlay[Idx].tp_type = IO_EOT; m_TptPlay[Idx].tp_termno = DX_IDDTIME; m_TptPlay[Idx].tp_length = pContent->nDtmfPeriod; m_TptPlay[Idx].tp_flags = TF_1000MS | TF_IDDTIME | TF_FIRST; } if(Mode == PVM_WAIT_DIGIT) m_Job = DEV_VOC_JOB_GET_DTMF; } break; } return true; } /***************************************************************** **【函数名称】 __construcRecStruct **【函数功能】 构造录音SDK所需结构体 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::__construcRecStruct( RecordContent* pContent ) { memset(&m_IottRec, 0, sizeof(DX_IOTT)); m_IottRec.io_fhandle = CMC::GetInstance().allocPrd(m_Id.NodeNo).handle(); sprintf_s(m_AudioFileRec, MAX_PATH, _T("%s\0"), pContent->szFileName); m_IottRec.io_bufp = m_AudioFileRec; m_IottRec.io_offset = 0; m_IottRec.io_length = -1; m_IottRec.io_type = IO_PRD_DEV | IO_EOT; int Idx = 0; bool Used = false; if(pContent->cEnd > 0) { ISX_dx_clrtpt(&m_TptPlay[Idx], 1); m_TptRec[Idx].tp_type = IO_EOT; m_TptRec[Idx].tp_termno = DX_DIGMASK; switch(pContent->cEnd) { case '*': m_TptRec[Idx].tp_length = DM_S; break; case '#': m_TptRec[Idx].tp_length = DM_P; break; case '0': m_TptRec[Idx].tp_length = DM_0; break; case '1': m_TptRec[Idx].tp_length = DM_1; break; case '2': m_TptRec[Idx].tp_length = DM_2; break; case '3': m_TptRec[Idx].tp_length = DM_3; break; case '4': m_TptRec[Idx].tp_length = DM_4; break; case '5': m_TptRec[Idx].tp_length = DM_5; break; case '6': m_TptRec[Idx].tp_length = DM_6; break; case '7': m_TptRec[Idx].tp_length = DM_7; break; case '8': m_TptRec[Idx].tp_length = DM_8; break; case '9': m_TptRec[Idx].tp_length = DM_9; break; default: ASSERT(FALSE); break; } m_TptRec[Idx].tp_flags = TF_DIGMASK; Idx++; Used = true; } if(pContent->nPeriod > 0) { if(Used) { m_TptRec[Idx - 1].tp_type &= ~IO_EOT; m_TptRec[Idx - 1].tp_type = IO_CONT; } ISX_dx_clrtpt(&m_TptPlay[Idx], 1); m_TptRec[Idx].tp_type = IO_EOT; m_TptRec[Idx].tp_termno = DX_MAXTIME; m_TptRec[Idx].tp_length = pContent->nPeriod; m_TptRec[Idx].tp_flags = TF_1000MS | TF_MAXTIME; Used = true; } if(!Used) { ISX_dx_clrtpt(&m_TptRec[Idx], 1); m_TptRec[0].tp_type = IO_EOT; m_TptRec[0].tp_termno = DX_MAXTIME; m_TptRec[0].tp_length = 65535; m_TptRec[0].tp_flags = TF_MAXTIME; } memset(&m_XpbRec, 0, sizeof(m_XpbPlay)); m_XpbRec.wFileFormat = FILE_FORMAT_WAVE; // WAV file. m_XpbRec.wDataFormat = DATA_FORMAT_ALAW; // ALAW m_XpbRec.wBitsPerSample = 16; // The number of bits per sample. m_XpbRec.nSamplesPerSec = DRT_8KHZ; // Sampling rates } /***************************************************************** **【函数名称】 __constructDtmfStruct **【函数功能】 构造收按键SDK所需结构体 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::__constructDtmfStruct( void ) { int DtmfCount = 0; int DtmfPeriod = 0; int LastIdx = 0; for(int i = 0; i < 3; ++i) { DV_TPT* pDvtpt = &m_TptPlay[i]; if(pDvtpt->tp_type == IO_CONT) ++LastIdx; if(pDvtpt->tp_termno == DX_MAXDTMF) DtmfCount = pDvtpt->tp_length; if(pDvtpt->tp_termno == DX_IDDTIME) DtmfPeriod = pDvtpt->tp_length; } if(DtmfCount > 0 && DtmfPeriod > 0) { m_TptPlay[LastIdx - 1].tp_type &= ~IO_EOT; m_TptPlay[LastIdx - 1].tp_type = IO_CONT; ISX_dx_clrtpt(&m_TptPlay[LastIdx], 1); m_TptPlay[LastIdx].tp_type = IO_EOT; m_TptPlay[LastIdx].tp_termno = DX_MAXTIME; m_TptPlay[LastIdx].tp_length = DtmfCount * DtmfPeriod; m_TptPlay[LastIdx].tp_flags = TF_1000MS | TF_MAXTIME; } } /***************************************************************** **【函数名称】 __replay **【函数功能】 继续播放上一声音 **【参数】 **【返回值】 ****************************************************************/ bool CDspChannel::__replay( void ) { /* Clear the digits on this channel, avoid the digit to terminate the playback */ ISX_dx_clrdigbuf(m_Handle); if(ISX_dx_playiottdata(m_Handle, m_IottPlay, m_TptPlay, &m_XpbPlay, EV_ASYNC) != 0) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_ERROR, _T("{DspCh}: 通道[%d-%d-%d]放音失败, file = %s, reason = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_AudioFilePlay, ISX_ATDV_ERRMSGP(m_Handle)); return false; } return true; } /***************************************************************** **【函数名称】 __redoGetDigit **【函数功能】 重新收号 **【参数】 **【返回值】 ****************************************************************/ bool CDspChannel::__redoGetDigit( void ) { __constructDtmfStruct(); memset(&m_DigitBuf, 0, sizeof(DV_DIGIT)); if(ISX_dx_getdig(m_Handle, m_TptPlay, &m_DigitBuf, EV_ASYNC) != 0) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_ERROR, _T("{DspCh}: 通道[%d-%d-%d]收号失败, reason = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, ISX_ATDV_ERRMSGP(m_Handle)); return false; } return true; } /***************************************************************** **【函数名称】 onPlayStart **【函数功能】 放音开始 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::__onPlayStart( void ) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{DspCh}: 通道[%d-%d-%d]开始放音, AudioFile = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_AudioFilePlay); CMC::GetInstance().onDevResState(m_Id); } /***************************************************************** **【函数名称】 onPlayEnd **【函数功能】 放音结束 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::__onPlayEnd( void ) { ULONG OperIndex = ISX_sr_getevtoperindex(); if(m_Job == DEV_VOC_JOB_PLAY_DTMF) { // 获取结束原因 long TermMask = ISX_ATDX_TERMMSK(m_Handle); if((TermMask & TM_USRSTOP) || (TermMask & TM_ERROR)) { m_Job = DEV_VOC_JOB_NONE; if(m_pMixer != NULL) m_pMixer->onPlayEnd(NULL); } else __redoGetDigit(); } else if(m_Job == DEV_VOC_JOB_PLAY_FILE) { m_Job = DEV_VOC_JOB_NONE; if(m_pMixer != NULL) m_pMixer->onPlayEnd(NULL); } else if(m_Job == DEV_VOC_JOB_PLAY_TONE) { m_Job = DEV_VOC_JOB_NONE; if(m_pMixer != NULL) m_pMixer->onToneEnd(OperIndex); } LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{DspCh}: 通道[%d-%d-%d]放音结束, AudioFile = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_AudioFilePlay); CMC::GetInstance().onDevResState(m_Id); } /***************************************************************** **【函数名称】 __onRecordStart **【函数功能】 录音开始 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::__onRecordStart( void ) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{DspCh}: 通道[%d-%d-%d]开始录音, AudioFile = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_AudioFileRec); CMC::GetInstance().onDevResState(m_Id); } /***************************************************************** **【函数名称】 __onRecordEnd **【函数功能】 录音结束 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::__onRecordEnd( void ) { ULONG OperIndex = ISX_sr_getevtoperindex(); m_IsRecording = false; // 录音时忽略停止录音的原因,直接通知录音结束 if(m_pMixer != NULL) m_pMixer->onRecEnd(OperIndex); LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{DspCh}: 通道[%d-%d-%d]录音结束, AudioFile = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_AudioFileRec); CMC::GetInstance().onDevResState(m_Id); } /***************************************************************** **【函数名称】 __onGotDigit **【函数功能】 收按键结束 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::__onGotDigit( void ) { m_Job = DEV_VOC_JOB_NONE; if(m_pMixer != NULL) m_pMixer->onPlayEnd(m_DigitBuf.dg_value); LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{DspCh}: 通道[%d-%d-%d]收号结束, DTMF = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_DigitBuf.dg_value); CMC::GetInstance().onDevResState(m_Id); } /***************************************************************** **【函数名称】 __onError **【函数功能】 出错处理 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::__onError( void ) { ULONG OperIndex = ISX_sr_getevtoperindex(); int OperType = ISX_sr_getevtopertype(); LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{DspCh}: 通道[%d-%d-%d]操作[%s]出错, Reason = %s, OperIndex = %u"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, ISX_sr_getopername(), ISX_ATDV_ERRMSGP(m_Handle), OperIndex); ASSERT(m_pMixer != NULL); if(OperType == OPER_PLAY) { DEV_VOICE_JOB_TYPE Job = m_Job; m_Job = DEV_VOC_JOB_NONE; if(Job == DEV_VOC_JOB_PLAY_TONE) { if(m_pMixer != NULL) m_pMixer->onToneEnd(OperIndex); } else { if(m_pMixer != NULL) m_pMixer->onPlayEnd(CONST_ERR_PLAY_AUDIO); } } else if(OperType == OPER_RECORD) { m_IsRecording = false; if(m_pMixer != NULL) m_pMixer->onRecEnd(OperIndex); } } /***************************************************************** **【函数名称】 open **【函数功能】 打开系统资源 **【参数】 **【返回值】 成功true,失败false ****************************************************************/ bool CDspChannel::open( void ) { ASSERT(m_Handle == DEV_HANDLE_INVALID); // 打开DTI channel m_Handle = ISX_dx_open(DT_DSP_CH, m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, this); if(m_Handle == -1) { m_Handle = DEV_HANDLE_INVALID; LOGGER(LOG_CLASS_DEV, LOG_LEVEL_ERROR, _T("{DSPCh}: 通道[%d-%d-%d]打开失败"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo); return false; } //LOGGER(LOG_CLASS_DEV, LOG_LEVEL_NORMAL, _T("{DSPCh}: 通道[%d-%d-%d]打开成功"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo); return true; } /***************************************************************** **【函数名称】 close **【函数功能】 关闭系统资源 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::close( void ) { if(m_Handle != DEV_HANDLE_INVALID) { ISX_dx_close(m_Handle, 0); m_Handle = DEV_HANDLE_INVALID; //LOGGER(LOG_CLASS_DEV, LOG_LEVEL_WARNING, _T("{DSPCh}: 通道[%d-%d-%d]关闭"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo); } } /***************************************************************** **【函数名称】 reset **【函数功能】 重置通道 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::reset( void ) { ASSERT(m_Handle != DEV_HANDLE_INVALID); /* Stop all the activity on this channel. */ ISX_dx_stopch(m_Handle, EV_STOPALL|EV_ASYNC); m_Job = DEV_VOC_JOB_NONE; m_IsRecording = false; } /***************************************************************** **【函数名称】 playSound **【函数功能】 放音 **【参数】 **【返回值】 ****************************************************************/ bool CDspChannel::playSound( PlayVoiceContent* pContent ) { ASSERT(pContent != NULL); if(pContent->nModel == PVM_STOP_PLAY) { m_Job = DEV_VOC_JOB_NONE; return ISX_dx_stopch(m_Handle, EV_STOPPLAY|EV_ASYNC) == 0; } else { if(!__constructPlayStruct(pContent)) return false; /* Clear the digits on this channel, avoid the digit to terminate the playback */ ISX_dx_clrdigbuf(m_Handle); if(pContent->nModel == PVM_WAIT_DIGIT) { memset(&m_DigitBuf, 0, sizeof(DV_DIGIT)); if(ISX_dx_getdig(m_Handle, m_TptPlay, &m_DigitBuf, EV_ASYNC) != 0) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_ERROR, _T("{DspCh}: 通道[%d-%d-%d]收号失败, reason = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, ISX_ATDV_ERRMSGP(m_Handle)); return false; } } else { if(ISX_dx_playiottdata(m_Handle, m_IottPlay, m_TptPlay, &m_XpbPlay, EV_ASYNC) != 0) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_ERROR, _T("{DspCh}: 通道[%d-%d-%d]放音失败, file = %s, reason = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_AudioFilePlay, ISX_ATDV_ERRMSGP(m_Handle)); return false; } } return true; } } /***************************************************************** **【函数名称】 playTone **【函数功能】 放Tone音 **【参数】 **【返回值】 ****************************************************************/ bool CDspChannel::playTone( int ToneTp ) { if(ToneTp == CHANNEL_TONE_NULL) { m_Job = DEV_VOC_JOB_NONE; return ISX_dx_stopch(m_Handle, EV_STOPPLAY|EV_ASYNC) == 0; } switch(ToneTp) { case CHANNEL_TONE_RINGBACK: sprintf_s(m_AudioFilePlay, MAX_PATH, _T("%s\0"), TONE_NAME_RINGBACK); break; case CHANNEL_TONE_DIAL: sprintf_s(m_AudioFilePlay, MAX_PATH, _T("%s\0"), TONE_NAME_DIAL); break; case CHANNEL_TONE_BUSY: sprintf_s(m_AudioFilePlay, MAX_PATH, _T("%s\0"), TONE_NAME_BUSY); break; case CHANNEL_TONE_HOLD: sprintf_s(m_AudioFilePlay, MAX_PATH, _T("%s\0"), TONE_NAME_HOLD); break; default: return false; } m_Job = DEV_VOC_JOB_PLAY_TONE; memset(m_IottPlay, 0, sizeof(DX_IOTT) * 2); m_IottPlay[0].io_fhandle = CMC::GetInstance().allocPrd(m_Id.NodeNo).handle(); m_IottPlay[0].io_bufp = m_AudioFilePlay; m_IottPlay[0].io_offset = 0; m_IottPlay[0].io_length = -1; m_IottPlay[0].io_type = IO_PRD_DEV | IO_CONT; m_IottPlay[1].io_fhandle = CMC::GetInstance().allocPrd(m_Id.NodeNo).handle(); m_IottPlay[1].io_bufp = m_AudioFilePlay; m_IottPlay[1].io_offset = 0; m_IottPlay[1].io_length = -1; m_IottPlay[1].io_type = IO_PRD_DEV | IO_EOT; memset(&m_TptPlay[0], 0, sizeof(DV_TPT)); m_TptPlay[0].tp_type = IO_EOT; m_TptPlay[0].tp_termno = DX_MAXTIME; m_TptPlay[0].tp_length = 65535; m_TptPlay[0].tp_flags = TF_MAXTIME; memset(&m_XpbPlay, 0, sizeof(m_XpbPlay)); m_XpbPlay.wFileFormat = FILE_FORMAT_VOX; // WAV file. m_XpbPlay.wDataFormat = DATA_FORMAT_G711_ALAW; // ALAW编码格式 m_XpbPlay.wBitsPerSample = 8; // The number of bits per sample. m_XpbPlay.nSamplesPerSec = DRT_8KHZ; // Sampling rates ISX_dx_clrdigbuf(m_Handle); if(ISXE_dx_PlayMultiFiles(m_Handle, m_IottPlay, m_TptPlay, &m_XpbPlay, EV_ASYNC, ToneTp) != 0) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_ERROR, _T("{DspCh}: 通道[%d-%d-%d]放Tone音失败, file = %s, reason = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_AudioFilePlay, ISX_ATDV_ERRMSGP(m_Handle)); return false; } return true; } /***************************************************************** **【函数名称】 startRecord **【函数功能】 开始录音 **【参数】 **【返回值】 ****************************************************************/ bool CDspChannel::startRecord( RecordContent* pContent ) { ASSERT(pContent != NULL); __construcRecStruct(pContent); ISX_dx_clrdigbuf(m_Handle); if(ISX_dx_reciottdata(m_Handle, &m_IottRec, m_TptRec, &m_XpbRec, EV_ASYNC, pContent->nTaskId) != 0) { LOGGER(LOG_CLASS_DEV, LOG_LEVEL_ERROR, _T("{DspCh}: 通道[%d-%d-%d]录音失败, file = %s, reason = %s"), m_Id.NodeNo, m_Id.BoardNo, m_Id.ChanNo, m_AudioFileRec, ISX_ATDV_ERRMSGP(m_Handle)); return false; } m_IsRecording = true; return true; } /***************************************************************** **【函数名称】 stopRecord **【函数功能】 停止录音 **【参数】 **【返回值】 ****************************************************************/ bool CDspChannel::stopRecord( void ) { m_IsRecording = false; return ISX_dx_stopch(m_Handle, EV_STOPREC|EV_ASYNC) == 0; } /***************************************************************** **【函数名称】 setVoiceMode **【函数功能】 设置会议语音模式 **【参数】 **【返回值】 ****************************************************************/ bool CDspChannel::setVoiceMode( int Mode ) { return ISX_dx_setparm(m_Handle, DXCH_VOICE_MODE, &Mode) == 0; } /***************************************************************** **【函数名称】 onDevEvent **【函数功能】 系统事件处理 **【参数】 **【返回值】 ****************************************************************/ void CDspChannel::onDevEvent( METAEVENT* pMetaEvent ) { ASSERT(pMetaEvent != NULL); switch(pMetaEvent->evttype) { case TDX_PLAY: // 放音结束 __onPlayEnd(); break; case TDX_RECORD: // 录音结束 __onRecordEnd(); break; case TDX_GETDIG: // 取按键结束 __onGotDigit(); break; case TDX_PLAYBEGIN: // 开始放音 __onPlayStart(); break; case TDX_RECBEGIN: // 开始录音 __onRecordStart(); break; case TDX_ERROR: // 出错处理 __onError(); break; } } /***************************************************************** **【函数名称】 state **【函数功能】 返回状态字符串 **【参数】 **【返回值】 ****************************************************************/ LPCTSTR CDspChannel::getStateStr( void ) const { switch(m_Job) { case DEV_VOC_JOB_NONE: return (m_IsRecording ? _T("录音中") : _T("空闲")); case DEV_VOC_JOB_PLAY_TONE: return _T("播放信号音"); case DEV_VOC_JOB_PLAY_FILE: return _T("放音中"); case DEV_VOC_JOB_PLAY_DTMF: return _T("放音收号"); case DEV_VOC_JOB_GET_DTMF: return _T("收号"); default: return _T("未知"); } }