int main( int argc, char **argv ) { osg::notify(osg::WARN) << "\n\n" << osgAudio::getLibraryName() << " demo" << std::endl; osg::notify(osg::WARN) << "Version: " << osgAudio::getVersion() << "\n\n" << std::endl; osg::notify(osg::WARN) << "Demonstrates occluders" << std::endl; try { // use an ArgumentParser object to manage the program arguments. osg::ArgumentParser arguments(&argc,argv); // set up the usage document, in case we need to print out how to use this program. arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" demonstrates the use of the osgAudio toolkit for spatial sound."); arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ..."); arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); // initialize the viewer. osgViewer::Viewer viewer(arguments); osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator; keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() ); viewer.setCameraManipulator( keyswitchManipulator.get() ); // add the window size toggle handler viewer.addEventHandler(new osgViewer::WindowSizeHandler); // add the stats handler viewer.addEventHandler(new osgViewer::StatsHandler); // add the help handler viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage())); // get details on keyboard and mouse bindings used by the viewer. viewer.getUsage(*arguments.getApplicationUsage()); // if user request help write it out to cout. if (arguments.read("-h") || arguments.read("--help")) { arguments.getApplicationUsage()->write(std::cout); return 1; } // any option left unread are converted into errors to write out later. arguments.reportRemainingOptionsAsUnrecognized(); arguments.getApplicationUsage()->addKeyboardMouseBinding("RETURN", "Play a sound"); // report any errors if they have occured when parsing the program aguments. if (arguments.errors()) { arguments.writeErrorMessages(std::cout); return 1; } // initialize the SoundManager before loading any files osgAudio::SoundManager::instance()->init(16); osgAudio::SoundManager::instance()->getEnvironment()->setDistanceModel(osgAudio::InverseDistance); osgAudio::SoundManager::instance()->getEnvironment()->setDopplerFactor(1); osg::ref_ptr<osg::Group> rootnode = new osg::Group; // load the nodes from the commandline arguments. osg::Node* model = osgDB::readNodeFiles(arguments); //createModel(); if (!model) { osg::notify(osg::FATAL) << "Error loading models from commandline" << std::endl; return 1; } osg::ref_ptr<osg::PositionAttitudeTransform> loaded_transform = new osg::PositionAttitudeTransform; loaded_transform->addChild(model); rootnode->addChild(loaded_transform.get()); // Create ONE (only one, otherwise the transformation of the listener and update for SoundManager will be // called several times, which is not catastrophic, but unnecessary) // SoundRoot that will make sure the listener is updated and // to keep the internal state of the SoundManager updated // This could also be done manually, this is just a handy way of doing it. osg::ref_ptr<osgAudio::SoundRoot> sound_root = new osgAudio::SoundRoot; sound_root->setCamera( viewer.getCamera() ); // The position in the scenegraph of this node is not important. // Just as long as the cull traversal should be called after any changes to the SoundManager are made. rootnode->addChild(sound_root.get()); bool occlude = true; osg::ref_ptr<osg::PositionAttitudeTransform> sound_transform = createSoundNode("a.wav", occlude, rootnode.get(), false); rootnode->addChild(sound_transform.get()); // run optimization over the scene graph //osgUtil::Optimizer optimizer; //optimizer.optimize(rootnode.get()); // set the scene to render viewer.setSceneData(rootnode.get()); // create the windows and run the threads. viewer.realize(); osg::Timer_t start = osg::Timer::instance()->tick(); float rate=10; // degrees per second while( !viewer.done() ) { osg::Timer_t now = osg::Timer::instance()->tick(); double dt = osg::Timer::instance()->delta_s(start, now); double angle = rate*dt; osg::Quat quat; quat.makeRotate(osg::inDegrees(angle), osg::Vec3(0,0,1)); loaded_transform->setAttitude(quat); // update the scene by traversing it with the the update visitor which will // call all node update callbacks and animations. // fire off the cull and draw traversals of the scene. viewer.frame(); } } catch (std::exception& e) { osg::notify(osg::WARN) << "Caught: " << e.what() << std::endl; } // Very important to call this before end of main. // Otherwise OpenAL will do all sorts of strange things after end of main // in the destructor of soundmanager. if (osg::Referenced::getDeleteHandler()) { osg::Referenced::getDeleteHandler()->setNumFramesToRetainObjects(0); osg::Referenced::getDeleteHandler()->flushAll(); } osgAudio::SoundManager::instance()->shutdown(); return 0; }
void VoiceReceiver::update( float deltaTime ) { assert( _p_udpTransport && "network transport is not available!" ); // update sound system _p_soundSystem->update(); static char s_buffer[ 512 ]; VoicePaket* p_data = NULL; unsigned int senderID = 0xFFFFFFFF; // check for new connecting senders RNReplicaNet::Transport* p_sender = _p_udpTransport->Accept(); if ( p_sender ) { log_debug << " <- connection accepted from sender: " << p_sender->GetPeerURL() << std::endl; SoundNode* p_soundnode = createSoundNode(); _soundNodeMap[ p_sender ] = p_soundnode; } SenderMap::iterator p_beg = _soundNodeMap.begin(), p_end = _soundNodeMap.end(); for ( ; p_beg != p_end; ++p_beg ) { SoundNode* p_sendernode = p_beg->second; p_sender = p_beg->first; // first check for dead senders if ( ( p_sendernode->_pingTimer += deltaTime ) > VOICE_LIFESIGN_PERIOD ) { // removing sender log_verbose << " <- remove sender from receiver list!" << std::endl; // remove senders which do not respond anymore delete p_sendernode; delete p_sender; _soundNodeMap.erase( p_beg ); break; } // poll incoming data from senders if ( p_sender->Recv( s_buffer, 512 ) ) { p_data = reinterpret_cast< VoicePaket* >( s_buffer ); senderID = p_data->_senderID; } else { continue; } // check if the incoming voice paket belogs to current sender node if ( senderID != p_sendernode->_senderID ) { log_error << "internal error on voice paket receiver! sender id mismatch" << std::endl; continue; } switch( p_data->_typeId ) { case NETWORKSOUND_PAKET_TYPE_CON_REQ: { // get the network id of connecting sender int sid = *( reinterpret_cast< int* >( p_data->_p_buffer ) ); // find the ghost of the sender in voice enabled player list using its network id EnPlayer* p_player = NULL; EnPlayer* p_senderplayer = NULL; const std::vector< yaf3d::BaseEntity* >& players = gameutils::PlayerUtils::get()->getRemotePlayersVoiceChat(); std::vector< yaf3d::BaseEntity* >::const_iterator p_beg = players.begin(), p_end = players.end(); for ( ; p_beg != p_end; ++p_beg ) { p_player = dynamic_cast< EnPlayer* >( *p_beg ); if ( p_player->getNetworkID() == sid ) { p_senderplayer = p_player; } } if ( !p_senderplayer ) log_error << "Voice Receiver cannot find sending player!" << std::endl; p_sendernode->_p_senderPlayer = p_senderplayer; p_data->_length = 0; // send back a GRANT if less senders exit then the max allowed if ( _soundNodeMap.size() > MAX_SENDERS_CONNECTED ) { p_data->_typeId = NETWORKSOUND_PAKET_TYPE_CON_DENY; } else { p_data->_typeId = NETWORKSOUND_PAKET_TYPE_CON_GRANT; } // assign a unique ID to new sender ++_senderID; // check the id overflow ( this is very uncommon, but we want to be on safe side ) if ( _senderID > 0xFFFFFFFE ) _senderID = 1; p_data->_senderID = _senderID; // store the sender ID into node p_sendernode->_senderID = _senderID; p_sender->SendReliable( reinterpret_cast< char* >( p_data ), VOICE_PAKET_HEADER_SIZE + p_data->_length ); log_debug << " <- joining request granted ( " << _soundNodeMap.size() << " )" << std::endl; } break; case NETWORKSOUND_PAKET_TYPE_CON_CLOSE: { delete p_beg->first; delete p_beg->second; _soundNodeMap.erase( p_beg ); p_beg = _soundNodeMap.begin(), p_end = _soundNodeMap.end(); log_debug << " <- voice sender leaves ( " << _soundNodeMap.size() << " )" << std::endl; break; } break; case NETWORKSOUND_PAKET_TYPE_VOICE_DATA: { // drop obsolete packets if ( p_data->_paketStamp < p_sendernode->_lastPaketStamp ) { std::stringstream msg; msg << " <- *** paket loss detected (stamps received/current)" << p_data->_paketStamp << "/" << p_sendernode->_lastPaketStamp; log_debug << msg.str() << std::endl; // update our stamp also when a loss has been detected // currently we cannot know if there was an actual loss or an addition overflow occured in stamp variable // one possible way to handle this issue would be that the protocol would support a sort of "reset stamp number" p_sendernode->_lastPaketStamp = p_data->_paketStamp; continue; } // udpate sound node's stamp p_sendernode->_lastPaketStamp = p_data->_paketStamp; // attenuate the voice volume considering a cutoff area where the volume is at maximum float attenuation = 1.0; if ( p_sendernode->_p_senderPlayer ) { yaf3d::BaseEntity* p_localplayer = gameutils::PlayerUtils::get()->getLocalPlayer(); assert( p_localplayer && "local player is not set in PlayerUtils!" ); osg::Vec3f diff = p_sendernode->_p_senderPlayer->getPosition() - p_localplayer->getPosition(); float distance = diff.length(); attenuation = ( distance < _cutoffRange ) ? 1.0f : std::max( 1.0f - ( ( distance - _cutoffRange ) / ( _spotRange - _cutoffRange ) ), 0.0f ); } // decode and enqueue the samples if ( !p_sendernode->_p_codec->decode( p_data->_p_buffer, p_data->_length, *p_sendernode->_p_sampleQueue, _outputGain * attenuation ) ) { log_debug << "decoder queue overrun, flushing queue!" << std::endl; delete p_sendernode->_p_sampleQueue; p_sendernode->_p_sampleQueue = new SoundSampleQueue; } } break; case NETWORKSOUND_PAKET_TYPE_CON_PING: { // send back a pong p_data->_length = 0; p_data->_typeId = NETWORKSOUND_PAKET_TYPE_CON_PONG; p_sender->SendReliable( reinterpret_cast< char* >( p_data ), VOICE_PAKET_HEADER_SIZE + p_data->_length ); // reset the ping timer p_sendernode->_pingTimer = 0.0f; } break; default: ; } } }