📄 dupcarddevice.cxx
字号:
/* ==================================================================== * The Vovida Software License, Version 1.0 * * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The names "VOCAL", "Vovida Open Communication Application Library", * and "Vovida Open Communication Application Library (VOCAL)" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact vocal@vovida.org. * * 4. Products derived from this software may not be called "VOCAL", nor * may "VOCAL" appear in their name, without prior written * permission of Vovida Networks, Inc. * * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. * * ==================================================================== * * This software consists of voluntary contributions made by Vovida * Networks, Inc. and many individuals on behalf of Vovida Networks, * Inc. For more information on Vovida Networks, Inc., please see * <http://www.vovida.org/>. * */#include "global.h"/* stdlib */#include <iostream>#include <fstream>#include <cstdio>#include <unistd.h>#include <sys/ioctl.h>#include <csignal>#ifdef WIN32#include <io.h>#endif/* sockets */#include <sys/types.h>#include <sys/socket.h>#include <fcntl.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#ifndef WIN32#include <sys/soundcard.h>#endif#include "VTime.hxx"#include "Rtp.hxx"#include "codec/g711.h"#include "VCondition.h"#include "DupCardDevice.hxx"#include "UaDeviceEvent.hxx"#include "UaConfiguration.hxx"#ifdef HAS_SPHINX#include "SpeechHandler.hxx"#endifusing namespace Vocal;#ifdef HAS_SPHINX SpeechHandler speechHandler;#define DATADIR "/usr/local/share/sphinx2/model/"#define MODEL_NAME "turtle"#endif#define RESID_RTP_RATE 160 // 320 byte packet size#define NETWORK_RTP_RATE 160 // 160 byte packet size#define FLASH_TIMEOUT 1000000extern "C"{ unsigned char linear2ulaw( int pcm_val ); int ulaw2linear( unsigned char u_val );}//***************************************************************************// DupCardDevice::DupCardDevice// description: Constructor. opens the PhoneCARD device. initialize the// hookstate. resets the device to get it ready.//***************************************************************************void DupCardDevice::testSoundFile(){ cpLog(LOG_ERR,"Start test"); int cc = 0; int len; int inFile_fd; unsigned char audio_buffer[480]; inFile_fd = open( "ULAW", O_RDONLY, 0 ); mySoundCard.reopen(); while( ( len = read( inFile_fd, audio_buffer, 160 ) ) != -1 ) { cc += len; if( cc > 20000 ) break; write( myFD, (char*)audio_buffer, 160 ); }#ifndef WIN32 if( ioctl( myFD, SNDCTL_DSP_SYNC, 0 ) == -1 ) { perror("SNDCTL_DSP_SYNC"); }#endif cpLog(LOG_ERR,"Stop test");}DupCardDevice::DupCardDevice( const char* deviceName, Sptr < Fifo < Sptr<SipProxyEvent> > > inputQ, Sptr < Fifo < Sptr<SipProxyEvent> > > outputQ ) : ResGwDevice( deviceName, inputQ, outputQ ), audioStack( 0 ), ringbackFd( -1 ), mySoundCard(deviceName){#ifdef HAS_SPHINX speechHandler.initialize(Data(DATADIR), Data(MODEL_NAME));#endif // initialize queues sessionQ = outputQ; myQ = inputQ; // initialize states hookStateOffhook = false; playDialTone = false; sendRingback = false; // open audio hardware device if( mySoundCard.open() == -1 ) { cpLog( LOG_ERR, "Failed to open %s", deviceName ); exit( -1 ); } // set audio API type if(mySoundCard.getFormat() == NewSoundCardSigned16LE) { apiCodec = rtpPayloadL16_mono; } else if (mySoundCard.getFormat() == NewSoundCardUlaw) { apiCodec = rtpPayloadPCMU; } else { cpLog(LOG_ERR, "could not get valid sound card encoding"); exit ( -1 ); } // store the device name// myDeviceName = deviceName;#ifndef WIN32 // enable single keypresses without pressing <enter> in terminal stdinFD = fileno( stdin ); tcgetattr( stdinFD, &initialTerm ); struct termios newTerm = initialTerm; newTerm.c_lflag &= ~ICANON; newTerm.c_cc[VMIN] = 0; newTerm.c_cc[VTIME] = 0; if( tcsetattr( stdinFD, TCSANOW, &newTerm ) != 0 ) { cpLog( LOG_ERR, "Unable to set new terminal mode" ); exit( -1 ); }#endif} // end DupCardDevice::DupCardDevice()//***************************************************************************// DupCardDevice::~DupCardDevice// description: Destructor//***************************************************************************DupCardDevice::~DupCardDevice(){ mySoundCard.close();#ifndef WIN32 tcsetattr( stdinFD, TCSANOW, &initialTerm );#endif} // end DupCardDevice::~DupCardDevice()//***************************************************************************// DupCardDevice::openAudioHardware// description: open audio hardware device//***************************************************************************//***************************************************************************// DupCardDevice::closeAudioHardware// description://***************************************************************************//***************************************************************************// DupCardDevice::mySoundCard.reopen// description://***************************************************************************//***************************************************************************// DupCardDevice::writeToSoundCard// description://***************************************************************************//***************************************************************************// DupCardDevice::hardwareMain// description: main processing loop of the hardware//***************************************************************************void*DupCardDevice::hardwareMain( void* parms ){#ifndef WIN32 // process forever on behalf of DupCardDevice hardware fd_set readfds; struct timeval tv; int retval; int maxFd = 128; // should be 0 then increment as needed when addToFdSet // reset file descriptor FD_ZERO( &readfds ); addToFdSet( &readfds ); // block on select for asyncronous events, but poll to process // audio and signal requests from endpoints in message queue tv.tv_sec = 0; tv.tv_usec = 300; if( ( retval = select( maxFd, &readfds, 0, 0, &tv ) ) < 0 ) { cpLog( LOG_ERR, "select() returned error %d", retval ); } else { if( process( &readfds ) < 0 ) { cpLog( LOG_ERR, "Hardware encountered an error" ); assert( 0 ); } }#else HANDLE handles [1]; handles[0] = GetStdHandle(STD_INPUT_HANDLE); DWORD dwd = WaitForMultipleObjects(1, handles, false, 300); fd_set* ptr = NULL; if (dwd == WAIT_OBJECT_0) { ptr = (fd_set*)&dwd; } if (process(ptr) < 0) { cerr << "Hardware encountered an error\n"; assert(0); }#endif // check for signal requests from the session if( myQ->size() > 0 ) { processSessionMsg( myQ->getNext() ); } return 0;} // end DupCardDevice::hardwareMain()//***************************************************************************// DupCardDevice::process//// description: process any events detected on the hardware as well as// simulated device events triggered by keyboard input.// report these events back to the session via the fifo queue.//***************************************************************************intDupCardDevice::process( fd_set* fd ){ if (!fd) { return 0; } deviceMutex.lock(); // check for events coming from the keyboard // initialize the event we will send Sptr<UaDeviceEvent> event = new UaDeviceEvent( sessionQ ); assert( event != 0 ); event->type = DeviceEventUndefined;#ifndef WIN32 char keystroke = '\0'; if( read( stdinFD, &keystroke, 1 ) < 1 ) { // didn't get any keystrokes deviceMutex.unlock(); return 0; }#else char keystroke = '\n'; // ignore INPUT_RECORD ir; unsigned long cNumRead; if (fd) { HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); ReadConsoleInput( hStdin, &ir, 1, &cNumRead); if (!ir.Event.KeyEvent.bKeyDown || ir.Event.KeyEvent.uChar.AsciiChar == 23 /* 0x17 */ || ir.Event.KeyEvent.uChar.AsciiChar == '\n' || ir.Event.KeyEvent.uChar.AsciiChar == 0x0a || ir.Event.KeyEvent.uChar.AsciiChar == 0) { deviceMutex.unlock(); return 0; } keystroke = ir.Event.KeyEvent.uChar.AsciiChar; }#endif if(myEntryState == EntryStateEnterUrl) { // the user is entering a URL, so do something else switch( keystroke ) { case '\x08': case '\x7F': // Backspace (\b) or Delete (DEL) { if( myTextEntry.length() > 0 ) { // xxx this is lame cout << "\b \b\b \b\b \b"; cout.flush(); myTextEntry.setchar(myTextEntry.length() - 1, ' '); myTextEntry.removeSpaces(); } else { cout << "\b \b\b \b"; cout.flush(); } break; } case '\x0A': // Line Feed (\n) -> done { cpLog( LOG_DEBUG, "URL is %s", myTextEntry.logData() ); event->type = DeviceEventCallUrl; event->text = myTextEntry; myTextEntry = ""; myEntryState = EntryStateTelephoneUI; break; } default: { if( keystroke >= '\x20' && keystroke <= '\x7E' ) { // Append a character between ' ' and '~' myTextEntry.setchar(myTextEntry.length(), keystroke); } else { // Treat everything else as abort // e.g. '\1B': // Esc -> abort myTextEntry = ""; myEntryState = EntryStateTelephoneUI; cout << endl; cpLog( LOG_DEBUG, "Abort URL input" ); // Emulate a 'z' in TelephoneUI hookStateOffhook = false; event->type = DeviceEventHookDown; } break; } } } else { // process keystroke if( keystroke != '\n' ) { cpLog( LOG_DEBUG, "Keystroke read: '%c'(%x)", ( keystroke >= ' ' && keystroke <= '~' ) ? keystroke : '.', keystroke ); } switch( keystroke ) { case 'q': // shutdown event->type = DeviceEventShutdown; cpLog( LOG_NOTICE , "User requested shutdown" ); break; case 'a': // offhook hookStateOffhook = true; playDialTone = true; event->type = DeviceEventHookUp; break; case 'z': // onhook if ( hookStateOffhook ) { hookStateOffhook = false; event->type = DeviceEventHookDown; } break; case 'f': // flash event->type = DeviceEventFlash; break; case '*': event->type = DeviceEventDtmfStar; break; case '#': event->type = DeviceEventDtmfHash; break; case '0': event->type = DeviceEventDtmf0; break; case '1': event->type = DeviceEventDtmf1; break; case '2': event->type = DeviceEventDtmf2; break; case '3': event->type = DeviceEventDtmf3; break; case '4': event->type = DeviceEventDtmf4; break; case '5': event->type = DeviceEventDtmf5; break; case '6': event->type = DeviceEventDtmf6; break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -