📄 soundcarddevice.cxx
字号:
{ 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 SoundCardDevice::hardwareMain()//***************************************************************************// SoundCardDevice::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.//***************************************************************************intSoundCardDevice::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; case '7': event->type = DeviceEventDtmf7; break; case '8': event->type = DeviceEventDtmf8; break; case '9': event->type = DeviceEventDtmf9; break; case 'u': if( hookStateOffhook ) { cout << "\nEnter URL: "; cout.flush(); myEntryState = EntryStateEnterUrl; } else { cpLog( LOG_ERR, "Enter 'a' first" ); } break; case '\n': // ignore break; default: // no events cpLog( LOG_ERR, "Unknown keyboard input" ); break; } } // send the event if( event->type != DeviceEventUndefined ) { assert( sessionQ != 0 ); event->callId = callId;#ifndef WIN32 sessionQ->add( event );#else Sptr <SipProxyEvent> proxyEvent; proxyEvent.dynamicCast( event ); sessionQ->add( proxyEvent );#endif } deviceMutex.unlock(); return 0;} // end SoundCardDevice::process()//***************************************************************************// SoundCardDevice::processRTP// description: main processing loop for RTP//***************************************************************************voidSoundCardDevice::processRTP (){ if( audioStack == 0 ) { vusleep( 1000 ); return; } deviceMutex.lock(); //AND:BUGFIX:? if (audioStack == 0) { deviceMutex.unlock(); vusleep( 1000 ); return; } bool bNothingDo = true; RtpSessionState sessionState = audioStack->getSessionState(); if ( sessionState == rtp_session_undefined ) { deviceMutex.unlock(); vusleep( 1000 ); return; } // receive audio if( sessionState == rtp_session_recvonly || sessionState == rtp_session_sendrecv ) { inRtpPkt = audioStack->receive(); if( inRtpPkt ) { if( inRtpPkt->getPayloadType() != rtpPayloadPCMU || inRtpPkt->getPayloadUsage() != NETWORK_RTP_RATE ) { cpLog(LOG_ERR,"Received from RTP stack incorrect payload type"); } writeToSoundCard( (unsigned char*) inRtpPkt->getPayloadLoc(), inRtpPkt->getPayloadUsage() ); bNothingDo = false; // need to delete since RTP stack doesn't do it any more delete inRtpPkt; inRtpPkt = NULL; } } // transmit audio if( sessionState == rtp_session_sendonly || sessionState == rtp_session_sendrecv ) { int cc; if( audioStack->getRtcpTran() ) { if( sendRingback ) { cc = getRingbackTone( dataBuffer, RESID_RTP_RATE );#ifdef WIN32 Sleep(15);#endif } else { cc = readFromSoundCard( dataBuffer, RESID_RTP_RATE ); } if ((cc > 0) && audioStack) { audioStack->transmitRaw( (char*)dataBuffer, cc ); bNothingDo = false; } else { cpLog(LOG_DEBUG, "failed to read data from sound card"); } } }#ifdef WIN32 if (bNothingDo) { //AND: Prevent processor from 100% load Sleep(2); }#endif // process RTCP //if( audioStack && sessionState != rtp_session_inactive ) //{ // audioStack->processRTCP(); //} deviceMutex.unlock(); return;}intSoundCardDevice::addToFdSet( fd_set* fd ){ if( ( audioActive || audioHalfActive ) && audioStack ) { RtpSessionState sessionState = audioStack->getSessionState(); if( sessionState == rtp_session_recvonly || sessionState == rtp_session_sendrecv ) { FD_SET( ( audioStack->getRtpRecv() )->getSocketFD(), fd );// FD_SET( ( audioStack->getRtcpRecv() )->getSocketFD(), fd ); } } FD_SET( myFD, fd ); return 0;} // end SoundCardDevice::addToFdSet()//***************************************************************************// SoundCardDevice::getRtpPort()//// description: creates a new rtp session and reserves a rtp port//***************************************************************************intSoundCardDevice::getRtpPort(){ deviceMutex.lock(); //this is an arbitrarily defined number const int MAX_RTP_PORT = UaConfiguration::instance()->getMaxRtpPort(); const int MIN_RTP_PORT = UaConfiguration::instance()->getMinRtpPort(); int port = 0; int minPort = MIN_RTP_PORT; // create a rtp session if there is no existing session alread // this Rtp session will be idle if( audioStack == 0 ) { audioStack = new RtpSession(0); } while( 1 ) { // reserve a rtp port port = audioStack->reserveRtpPort(minPort, MAX_RTP_PORT); minPort = (port > minPort) ? port : minPort; // attempt to reserve a rtcp port on port number higher than // the rtp port if ( port != 0 && audioStack->reserveRtcpPort(port + 1, 0) != 0 ) { break; } // if not successful allocating rtcp port, increment the minimum rtp // port and try again. If minPort reaches MAX_RTP_PORT, return 0 // to indicate port allocation failed. minPort += 2; if ( minPort > MAX_RTP_PORT ) { port = 0; break; } } deviceMutex.unlock(); return port;}//***************************************************************************// SoundCardDevice::releaseRtpPort()//// description: destroy the rtp session and release the rtp port//***************************************************************************voidSoundCardDevice::releaseRtpPort(){ deviceMutex.lock(); // destroy the rtp session if one exists if ( audioStack != 0 ) { //AND:BUGFIX: swap 2x2 bottom 4 lines // (or releaseRtcpPort() try use _rtp_ stack when his already // destroy releaseRtpPort) may be Unix to be able use class // after his ~destroy, but WIN32 close thread :) int port = audioStack->releaseRtcpPort(); cpLog( LOG_DEBUG, "rtcp port %d released", port ); port = audioStack->releaseRtpPort(); cpLog( LOG_DEBUG, "rtp port %d released", port ); delete audioStack; audioStack = 0; } deviceMutex.unlock();}//***************************************************************************// SoundCardDevice::audioStart//// description: creates a new rtp session and also allocates memory for// incoming and outgoing rtp packet. ioctl calls to initialize// the quicknet card.//***************************************************************************intSoundCardDevice::audioStart( const HardwareAudioRequest& request ){ deviceMutex.lock(); cerr << "%%% Establishing soundcard audio" << endl; cerr << "%%% Listening on port: " << request.localPort << endl; cerr << "%%% Sending to host : " << request.remoteHost << endl; cerr << "%%% Sending to port : " << request.remotePort << endl; cerr << "%%% RTP packet size : " << request.rtpPacketSize << " ms" << endl; // create new audioStack for this audio session // 0 is rtpPayloadPCUM // last paramter, -1, disables jitter buffer if( audioStack == 0 ) { int remoteRtcpPort = (request.remotePort > 0) ? request.remotePort + 1 : 0; int localRtcpPort = (request.localPort > 0) ? request.localPort + 1 : 0; cerr << "%%% Remote rtcp port : " << remoteRtcpPort << "\n"; cerr << "%%% Local rtcp port : " << localRtcpPort << "\n\n"; const char* remoteHost = 0; if ( request.remotePort != 0 ) remoteHost = request.remoteHost; audioStack = new RtpSession( remoteHost, request.remotePort, request.localPort, remoteRtcpPort, localRtcpPort, rtpPayloadPCMU, rtpPayloadPCMU, 0 ); } else { cerr << "%%% Turn half duplex into full duplex" << endl; //need to determine what mode RtpSession is in RtpSessionState sessionState = audioStack->getSessionState(); switch ( sessionState ) { case rtp_session_sendonly: //turn on the receive cerr << "%%% Turn on receive" << endl; cerr << "%%% local port " << request.localPort << endl; if ( request.localPort != 0 ) { audioStack->setSessionState( rtp_session_sendrecv ); audioStack->setReceiver( request.localPort, request.localPort + 1, 0, rtpPayloadPCMU, rtpPayloadPCMU, 0); } break; case rtp_session_recvonly: //turn on the send cerr << "%%% Turn on send" << endl; cerr << "%%% remote host " << request.remoteHost << endl; cerr << "%%% remote port " << request.remotePort << endl; if ( request.remotePort != 0 ) { audioStack->setSessionState(rtp_session_sendrecv); audioStack->setTransmiter(request.remoteHost, request.remotePort, request.remotePort + 1, rtpPayloadPCMU, rtpPayloadPCMU);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -