📄 soundcarddevice.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 "SoundCardDevice.hxx"#include "UaDeviceEvent.hxx"#include "UaConfiguration.hxx"using namespace Vocal;#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 );}//***************************************************************************// SoundCardDevice::SoundCardDevice// description: Constructor. opens the PhoneCARD device. initialize the// hookstate. resets the device to get it ready.//***************************************************************************void SoundCardDevice::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 ); reopenAudioHardware(); 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");}SoundCardDevice::SoundCardDevice( const char* deviceName, Sptr < Fifo < Sptr<SipProxyEvent> > > inputQ, Sptr < Fifo < Sptr<SipProxyEvent> > > outputQ ) : ResGwDevice( deviceName, inputQ, outputQ ), audioStack( 0 ), inRtpPkt( 0 ), ringbackFd( -1 ){ // initialize queues sessionQ = outputQ; myQ = inputQ; // initialize states hookStateOffhook = false; playDialTone = false; sendRingback = false; // open audio hardware device if( ( myFD = openAudioHardware( deviceName ) ) == -1 ) { cpLog( LOG_ERR, "Failed to open %s", deviceName ); 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 SoundCardDevice::SoundCardDevice()//***************************************************************************// SoundCardDevice::~SoundCardDevice// description: Destructor//***************************************************************************SoundCardDevice::~SoundCardDevice(){ closeAudioHardware();#ifndef WIN32 tcsetattr( stdinFD, TCSANOW, &initialTerm );#endif} // end SoundCardDevice::~SoundCardDevice()//***************************************************************************// SoundCardDevice::openAudioHardware// description: open audio hardware device//***************************************************************************int SoundCardDevice::openAudioHardware( const char* pname ){ deviceMutex.lock(); cpLog(LOG_DEBUG, "Opening audio hardware" ); int audioFD; // open audio device assert(pname);#ifndef WIN32 if( ( audioFD = open( pname, O_RDWR, 0 ) ) == -1 ) { perror("Open failed:"); deviceMutex.unlock(); return -1; }#else if (waveInGetNumDevs() <= 0) { cpLog(LOG_DEBUG, "could not get any devices"); deviceMutex.unlock(); return -1; } if (!m_aSoundCardWinOut.Open(SoundOut)) { perror("Open openAudioHardware failed (not found input sound card device) : "); deviceMutex.unlock(); return -1; } if (!m_aSoundCardWinIn.Open(SoundIn)) {#ifndef _DEBUG //AND:Need for run 2 exemplars program on one computer (debug version) m_aSoundCardWinOut.Close(); perror("Open openAudioHardware failed (not found output sound card device) : "); deviceMutex.unlock(); return -1;#endif } audioFD = 1;#endif#ifndef WIN32 // query audio formats int ioctlParam = -1; if( ioctl( audioFD, SNDCTL_DSP_GETFMTS, &ioctlParam ) == -1 ) { perror("SNDCTL_DSP_GETFMTS"); deviceMutex.unlock(); return -1; } // choose codec if( ioctlParam & AFMT_MU_LAW ) { //cpLog(LOG_DEBUG,"Setting sound card to ulaw"); ioctlParam = AFMT_MU_LAW; apiCodec = rtpPayloadPCMU; } else if( ioctlParam & AFMT_S16_LE ) { //cpLog(LOG_DEBUG,"Setting sound card to linear16"); ioctlParam = AFMT_S16_LE; apiCodec = rtpPayloadL16_mono; } else { cpLog(LOG_ERR,"Sound card doesn't support any known encodings"); printf("Sound card supports the following (Mask:%d:)\n", ioctlParam); if( ioctlParam & AFMT_MU_LAW ) printf(" AFMT_MU_LAW\n"); if( ioctlParam & AFMT_A_LAW ) printf(" AFMT_A_LAW\n"); if( ioctlParam & AFMT_IMA_ADPCM ) printf(" AFMT_IMA_ADPCM\n"); if( ioctlParam & AFMT_U8 ) printf(" AFMT_U8\n"); if( ioctlParam & AFMT_S16_LE ) printf(" AFMT_S16_LE\n"); if( ioctlParam & AFMT_S16_BE ) printf(" AFMT_S16_BE\n"); if( ioctlParam & AFMT_S8 ) printf(" AFMT_S8\n"); if( ioctlParam & AFMT_U16_LE ) printf(" AFMT_U16_LE\n"); if( ioctlParam & AFMT_U16_BE ) printf(" AFMT_U16_BE\n"); if( ioctlParam & AFMT_MPEG ) printf(" AFMT_MPEG\n"); deviceMutex.unlock(); return -1; } // setting audio device parameters //ioctlParam = AFMT_MU_LAW; //test setting to ulaw int ioctlParamSave = ioctlParam; if( ioctl( audioFD, SNDCTL_DSP_SETFMT, &ioctlParam ) == -1 ) { perror("SNDCTL_DSP_SETFMT"); deviceMutex.unlock(); return -1; } if( ioctlParam != ioctlParamSave ) { perror("Failed to set DSP Format, sound card returned format"); deviceMutex.unlock(); return -1; } ioctlParam = 1; // set the number of channels to 1. if this is an error, it // should probably not be a major failure. if( ioctl( audioFD, SNDCTL_DSP_CHANNELS, &ioctlParam ) == -1 ) { perror("SNDCTL_DSP_CHANNELS"); deviceMutex.unlock(); return -1; } if( ioctlParam != 1) { cout << "warning: unable to set audio output to mono," << " may cause problems later\n"; } ioctlParam = 8000; if( ioctl( audioFD, SNDCTL_DSP_SPEED, &ioctlParam ) == -1 ) { perror("SNDCTL_DSP_SPEED"); deviceMutex.unlock(); return -1; } if( ioctlParam != 8000 ) { perror("Failed to set sample rate"); deviceMutex.unlock(); return -1; }#else apiCodec = rtpPayloadL16_mono;#endif deviceMutex.unlock(); return audioFD;}//***************************************************************************// SoundCardDevice::closeAudioHardware// description://***************************************************************************int SoundCardDevice::closeAudioHardware(){ deviceMutex.lock(); cpLog(LOG_DEBUG, "Closing audio hardware" );#ifndef WIN32 if( ioctl( myFD, SNDCTL_DSP_RESET, 0 ) == -1 ) { perror("SNDCTL_DSP_RESET"); }#else m_aSoundCardWinOut.Close(); m_aSoundCardWinIn.Close();#endif deviceMutex.unlock();#ifndef WIN32 close( myFD );#endif return 1;}//***************************************************************************// SoundCardDevice::reopenAudioHardware// description://***************************************************************************int SoundCardDevice::reopenAudioHardware( ){ // close audio device if( closeAudioHardware() == -1 ) { cpLog(LOG_ERR, "Fail to close %s during reopen", myDeviceName); return -1; } // open audio device if( ( myFD = openAudioHardware( myDeviceName ) ) == -1 ) { cpLog(LOG_ERR, "Fail to open %s during reopen", myDeviceName); return -1; } return 1;}//***************************************************************************// SoundCardDevice::writeToSoundCard// description://***************************************************************************void SoundCardDevice::writeToSoundCard ( const unsigned char* data, const int samples ){ char* dspData = 0; int cc = 0; int p = 0; // check codec encodings switch( apiCodec ) { case rtpPayloadPCMU: // no conversion needed cc = samples; dspData = (char*)data; break; case rtpPayloadL16_mono: // convert sound sample from ULAW to Linear16 cc = samples; for(p = 0; p < cc; p++ ) longdataBuffer[p] = ulaw2linear( data[p] ); cc *= 2; dspData = (char*)longdataBuffer; break; default: cpLog(LOG_ERR,"Failed to provide correct codec encoding"); return; }#ifndef WIN32 write( myFD, dspData, cc );#else m_aSoundCardWinOut.Write(dspData, cc);#endif return;}int SoundCardDevice::readFromSoundCard( unsigned char* data, const int samples ){ int cc = -1; int p = 0; //check codec encodings switch( apiCodec ) {#ifndef WIN32 case rtpPayloadPCMU: // no conversion needed cc = 0; cc = read( myFD, data, samples ); break;#endif case rtpPayloadL16_mono: // convert sound sample from Liner16 to ULAW#ifndef WIN32 cc = read( myFD, (char*)longdataBuffer, samples * 2 );#else cc = m_aSoundCardWinIn.Read( (char*)longdataBuffer, samples * 2 );#endif for(; p < cc; p++ ) { data[p] = linear2ulaw( longdataBuffer[p] ); } cc /= 2; break; default: cpLog(LOG_DEBUG,"Failed to provide correct encoding"); break; }#ifndef WIN32 if( samples != cc ) { cpLog(LOG_DEBUG,"Incomplete read from Sound Card (%d)", cc); }#else // AND:prevent - many garbage on screen (when run 2 programs and // input from sound card already use one from him) :-/ if( m_aSoundCardWinIn.IsOpen() && samples != cc ) { cpLog(LOG_ERR,"Incomplete read from Sound Card (%d)", cc); }#endif return cc;}//***************************************************************************// SoundCardDevice::hardwareMain// description: main processing loop of the hardware//***************************************************************************void*SoundCardDevice::hardwareMain( void* parms ){#ifndef WIN32 // process forever on behalf of SoundCardDevice 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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -