📄 phonecarddevice.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/>. * */static const char* const PhoneCardDevice_cxx_Version = "$Id: PhoneCardDevice.cxx,v 1.19 2002/03/19 21:40:16 jason Exp $";#include "global.h"#include <cassert>/* stdlib */#include <iostream>#include <fstream>#include <cstdio>#include <unistd.h>#include <sys/ioctl.h>#include <csignal>#include <termios.h>/* sockets */#include <sys/types.h>#include <sys/socket.h>#include <fcntl.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <linux/ixjuser.h>#include <linux/telephony.h>#include "VTime.hxx"#include "Rtp.hxx"#include "VCondition.h"/* error handling */#include <cerrno>#include "PhoneCardDevice.hxx"#include "UaDeviceEvent.hxx"#define ULAW_PAYLOAD 1012#define ULAW_SAMPLE_RATE 240#define RESID_RTP_RATE 240#define NETWORK_RTP_RATE 160#define FLASH_TIMEOUT 1000000using namespace Vocal;//***************************************************************************// PhoneCardDevice::PhoneCardDevice// description: Constructor. opens the PhoneCARD device. initialize the// hookstate. resets the device to get it ready.//***************************************************************************PhoneCardDevice::PhoneCardDevice( const char* deviceName, Sptr < Fifo < Sptr < SipProxyEvent > > > inputQ, Sptr < Fifo < Sptr < SipProxyEvent > > > outputQ ) : ResGwDevice( deviceName, inputQ, outputQ ), // audioActive( false ), // hasPlayed( false ), audioStack( 0 ), inRtpPkt( 0 ), ringbackFd( -1 ), sendRingback( false ){ // initialize queues sessionQ = outputQ; myQ = inputQ; hookStateOffhook = false; // assume onhook for phonecard playDialTone = false; // open hardware device char pname[80]; sprintf( pname, "%s", deviceName ); myFD = open( pname, O_RDWR ); if ( myFD < 0 ) { cpLog( LOG_ERR, "Cannot open %s", deviceName ); exit( -1 ); } // close and reopen to make sure device is not in a funny state ioctl( myFD, IXJCTL_REC_STOP ); ioctl( myFD, IXJCTL_PLAY_STOP ); ioctl( myFD, IXJCTL_AEC_STOP ); close( myFD ); myFD = open( deviceName, O_RDWR ); if ( myFD < 0 ) { cpLog( LOG_ERR, "Cannot re-open ", deviceName ); exit( 1 ); } // initialize hookstate to onhook even if IXJCTL_HOOKSTATE returns // offhook. onhook signifies that the cord is plugged in! if ( ioctl( myFD, IXJCTL_HOOKSTATE ) ) // this means that the cord is { // plugged in. cpLog( LOG_DEBUG, "Cord is plugged into the PhoneCARD:" " [hardware-offhook]" ); } else { cpLog( LOG_ERR, "Cord is not plugged into the PhoneCARD, or" " PhoneCARD error." ); exit( -1 ); } // set ring to 3 ring instead of the default of 5 //ioctl(myFD, IXJCTL_MAXRINGS, 3); // store the device name. myDeviceName = deviceName; // we need to set the terminal correctly. this will enable us to do // single keypresses without needing to press <enter>. // store stdin file descriptor stdinFD = fileno( stdin ); // retrieve current term settings tcgetattr( stdinFD, &initialTerm ); // change the term settings to non-canonical 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 ); }} // end PhoneCardDevice::PhoneCardDevice()//***************************************************************************// PhoneCardDevice::~PhoneCardDevice// description: Destructor//***************************************************************************PhoneCardDevice::~PhoneCardDevice(){ close( myFD ); tcsetattr( stdinFD, TCSANOW, &initialTerm );} // end PhoneCardDevice::~PhoneCardDevice()//***************************************************************************// PhoneCardDevice::hardwareMain// description: main processing loop of the hardware//***************************************************************************void*PhoneCardDevice::hardwareMain( void* parms ){ // process forever on behalf of PhoneCardDevice 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 ); //if (maxFd <= gateway.myAgent->getFd()) //maxFd = gateway.myAgent->getFd() + 1; // 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 ); } } // check for signal requests from the session if ( myQ->size() > 0 ) { processSessionMsg( myQ->getNext() ); }; return 0;} // end PhoneCardDevice::hardwareMain()//***************************************************************************// PhoneCardDevice::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.//***************************************************************************intPhoneCardDevice::process( fd_set* fd ){ vusleep( 0 ); // needed to stabilize hookstate readings deviceMutex.lock(); // check to make sure the user has the cord plugged into the // phonecard. this is done through IXJCTL_HOOKSTATE for this // card only. if the cord is plugged in, we assume a 'live' // state in which we can go onhook / offhook using the keyboard. if ( ioctl( myFD, IXJCTL_HOOKSTATE ) ) { // user has the cord plugged in and the phonecard is in // the proper state. // now, 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; // default to undefined // now, we need to set the flags for the stdin file descriptor. // this will allow us to do a non-blocking read on stdin. // int stdinFD = fileno( stdin ); // int flags; char keystroke = '\0'; int retval = 0; // if( ( flags = fcntl( stdinFD, F_GETFL, 0 ) ) == -1 ) // printf("fcntl err: unable to get flags\n"); // if( fcntl( stdinFD, F_SETFL, flags | O_NONBLOCK ) == -1) // printf("fcntl err: unable to set O_NONBLOCK\n"); // vusleep( 50000 ); // sleep 50ms retval = read( stdinFD, &keystroke, 1 ); if ( retval < 1 ) { // didn't get any keystrokes deviceMutex.unlock(); return ( 0 ); } // we should have a keystroke at this point. if ( keystroke != '\n' ) // if it's a newline, ignore it { cpLog( LOG_DEBUG, "Keystroke read: %c", keystroke ); } switch ( keystroke ) { case 'q': { // shutdown event->type = DeviceEventShutdown; cpLog( LOG_NOTICE , "User requested shutdown" ); killTone(); } break; case 'a': { hookStateOffhook = true; playDialTone = true; event->type = DeviceEventHookUp; } break; case 'z': { // onhook if ( hookStateOffhook ) // this avoids multiple { // onhook events hookStateOffhook = false; event->type = DeviceEventHookDown; killTone(); } } break; case 'f': { event->type = DeviceEventFlash; } break; case '*': { event->type = DeviceEventDtmfStar; killTone(); } break; case '#': { event->type = DeviceEventDtmfHash; killTone(); } break; case '0': { event->type = DeviceEventDtmf0; killTone(); } break; case '1': { event->type = DeviceEventDtmf1; killTone(); } break; case '2': { event->type = DeviceEventDtmf2; killTone(); } break; case '3': { event->type = DeviceEventDtmf3; killTone(); } break; case '4': { event->type = DeviceEventDtmf4; killTone(); } break; case '5': { event->type = DeviceEventDtmf5; killTone(); } break; case '6': { event->type = DeviceEventDtmf6; killTone(); } break; case '7': { event->type = DeviceEventDtmf7; killTone(); } break; case '8': { event->type = DeviceEventDtmf8; killTone(); } break; case '9': { event->type = DeviceEventDtmf9; killTone(); } break; case '\n': { // ignore } break; default: { // no events cpLog( LOG_ERR, "Unknown keyboard input = %d", keystroke ); } break; } // end switch // now send the event if ( event->type != DeviceEventUndefined ) { assert( sessionQ != 0 ); event->callId = callId; sessionQ->add( event ); } } deviceMutex.unlock(); return 0;} // end PhoneCardDevice::process()//***************************************************************************// PhoneCardDevice::processRTP// description: main processing loop for RTP//***************************************************************************
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -