From c12f153b68a37f4d42e5b97f05e08ef2f2043b40 Mon Sep 17 00:00:00 2001 From: Drake Arconis Date: Tue, 16 Jun 2015 17:01:40 -0400 Subject: [PATCH] Audio Engine and FMOD Ex improvements and fixes from Shyotl Kuhr and Drake Arconis --- indra/llaudio/llaudioengine.cpp | 6 + indra/llaudio/llaudioengine_fmodex.cpp | 93 +++++------ indra/llaudio/llstreamingaudio_fmodex.cpp | 182 +++++++++++++--------- indra/llaudio/llstreamingaudio_fmodex.h | 5 +- indra/newview/llappviewer.cpp | 8 +- 5 files changed, 165 insertions(+), 129 deletions(-) diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index f750128fbb..4190ee41e7 100755 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -72,6 +72,8 @@ LLStreamingAudioInterface* LLAudioEngine::getStreamingAudioImpl() void LLAudioEngine::setStreamingAudioImpl(LLStreamingAudioInterface *impl) { + if (mStreamingAudioImpl) + delete mStreamingAudioImpl; mStreamingAudioImpl = impl; } @@ -134,6 +136,10 @@ bool LLAudioEngine::init(const S32 num_channels, void* userdata) void LLAudioEngine::shutdown() { + // Clean up streaming audio + delete mStreamingAudioImpl; + mStreamingAudioImpl = NULL; + // Clean up decode manager delete gAudioDecodeMgrp; gAudioDecodeMgrp = NULL; diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp index 9867d06cbd..33e9db39ad 100644 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ b/indra/llaudio/llaudioengine_fmodex.cpp @@ -118,7 +118,7 @@ void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const cha } else if(type & FMOD_MEMORY_STREAM_FILE) { - LL_INFOS() << "Strean buffer size: " << size << LL_ENDL; + LL_INFOS() << "Stream buffer size: " << size << LL_ENDL; } return new char[size]; } @@ -180,10 +180,6 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) if(mEnableProfiler) { fmod_flags |= FMOD_INIT_ENABLE_PROFILE; - mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]); - mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]); - mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]); - mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]); } #if LL_LINUX @@ -194,7 +190,7 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/ { LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; - if(mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK && + if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK && (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) { LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; @@ -215,7 +211,7 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ { LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; - if(mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK && + if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA)) == FMOD_OK && (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) { LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; @@ -236,7 +232,7 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/ { LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL; - if(mSystem->setOutput(FMOD_OUTPUTTYPE_OSS) == FMOD_OK && + if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_OSS)) == FMOD_OK && (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) { LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL; @@ -261,20 +257,22 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) // We're interested in logging which output method we // ended up with, for QA purposes. FMOD_OUTPUTTYPE output_type; - mSystem->getOutput(&output_type); - switch (output_type) + if(!Check_FMOD_Error(mSystem->getOutput(&output_type), "FMOD::System::getOutput")) { - case FMOD_OUTPUTTYPE_NOSOUND: - LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_PULSEAUDIO: - LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_ALSA: - LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_OSS: - LL_INFOS("AppInit") << "Audio output: OSS" << LL_ENDL; break; - default: - LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; - }; + switch (output_type) + { + case FMOD_OUTPUTTYPE_NOSOUND: + LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_PULSEAUDIO: + LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_ALSA: + LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_OSS: + LL_INFOS("AppInit") << "Audio output: OSS" << LL_ENDL; break; + default: + LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; + }; + } #else // LL_LINUX // initialize the FMOD engine @@ -296,6 +294,14 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) return false; #endif + if (mEnableProfiler) + { + Check_FMOD_Error(mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]), "FMOD::System::createChannelGroup"); + } + // set up our favourite FMOD-native streaming audio implementation if none has already been added if (!getStreamingAudioImpl()) // no existing implementation added setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem)); @@ -358,18 +364,16 @@ void LLAudioEngine_FMODEX::allocateListener(void) void LLAudioEngine_FMODEX::shutdown() { - stopInternetStream(); - LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; LLAudioEngine::shutdown(); LL_INFOS() << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << LL_ENDL; if ( mSystem ) // speculative fix for MAINT-2657 { - mSystem->close(); - // Additional debug message; viewer might hang somewhere in here - LL_INFOS() << "LLAudioEngine_FMODEX::shutdown() FMOD Ex system closed. Now releasing..." << LL_ENDL; - mSystem->release(); + Check_FMOD_Error(mSystem->close(), "FMOD::System::close"); + // Additional debug message; viewer might hang somewhere in here + LL_INFOS() << "LLAudioEngine_FMODEX::shutdown() FMOD Ex system closed. Now releasing..." << LL_ENDL; + Check_FMOD_Error(mSystem->release(), "FMOD::System::release"); } LL_INFOS() << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << LL_ENDL; @@ -425,8 +429,8 @@ void LLAudioEngine_FMODEX::cleanupWind() { if (mWindDSP) { - mWindDSP->remove(); - mWindDSP->release(); + Check_FMOD_Error(mWindDSP->remove(), "FMOD::DSP::remove"); + Check_FMOD_Error(mWindDSP->release(), "FMOD::DSP::release"); mWindDSP = NULL; } @@ -478,8 +482,8 @@ void LLAudioEngine_FMODEX::setInternalGain(F32 gain) gain = llclamp( gain, 0.0f, 1.0f ); FMOD::ChannelGroup *master_group; - mSystem->getMasterChannelGroup(&master_group); - + if(Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")) + return; master_group->setVolume(gain); LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); @@ -607,7 +611,7 @@ void LLAudioChannelFMODEX::updateLoop() // yield false negatives. // U32 cur_pos; - mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES); + Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES),"FMOD::Channel::getPosition"); if (cur_pos < (U32)mLastSamplePos) { @@ -641,12 +645,12 @@ void LLAudioChannelFMODEX::play() return; } - Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause"); + Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused"); getSource()->setPlayedOnce(true); if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]) - mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]); + Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]),"FMOD::Channel::setChannelGroup"); } @@ -681,8 +685,8 @@ bool LLAudioChannelFMODEX::isPlaying() } bool paused, playing; - mChannelp->getPaused(&paused); - mChannelp->isPlaying(&playing); + Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused"); + Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying"); return !paused && playing; } @@ -701,7 +705,7 @@ LLAudioBufferFMODEX::~LLAudioBufferFMODEX() { if(mSoundp) { - mSoundp->release(); + Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release"); mSoundp = NULL; } } @@ -717,7 +721,7 @@ bool LLAudioBufferFMODEX::loadWAV(const std::string& filename) return false; } - if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) + if (!gDirUtilp->fileExists(filename)) { // File not found, abort. return false; @@ -726,7 +730,7 @@ bool LLAudioBufferFMODEX::loadWAV(const std::string& filename) if (mSoundp) { // If there's already something loaded in this buffer, clean it up. - mSoundp->release(); + Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release"); mSoundp = NULL; } @@ -769,7 +773,7 @@ U32 LLAudioBufferFMODEX::getLength() } U32 length; - mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES); + Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength"); return length; } @@ -777,7 +781,7 @@ U32 LLAudioBufferFMODEX::getLength() void LLAudioChannelFMODEX::set3DMode(bool use3d) { FMOD_MODE current_mode; - if(mChannelp->getMode(¤t_mode) != FMOD_OK) + if(Check_FMOD_Error(mChannelp->getMode(¤t_mode),"FMOD::Channel::getMode")) return; FMOD_MODE new_mode = current_mode; new_mode &= ~(use3d ? FMOD_2D : FMOD_3D); @@ -785,7 +789,7 @@ void LLAudioChannelFMODEX::set3DMode(bool use3d) if(current_mode != new_mode) { - mChannelp->setMode(new_mode); + Check_FMOD_Error(mChannelp->setMode(new_mode),"FMOD::Channel::setMode"); } } @@ -804,10 +808,9 @@ FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbu FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; thisdsp->getUserData((void **)&windgen); - S32 channels, configwidth, configheight; - thisdsp->getInfo(0, 0, &channels, &configwidth, &configheight); - windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length); + if (windgen) + windgen->windGenerate((LLAudioEngine_FMODEX::MIXBUFFERFORMAT *)newbuffer, length); return FMOD_OK; } diff --git a/indra/llaudio/llstreamingaudio_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp index cc942e636a..9f7a3875d2 100644 --- a/indra/llaudio/llstreamingaudio_fmodex.cpp +++ b/indra/llaudio/llstreamingaudio_fmodex.cpp @@ -33,18 +33,13 @@ #include "llstreamingaudio_fmodex.h" -// FmodEX Error checking -bool fmod_error_check(FMOD_RESULT result) +inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) { - if (result != FMOD_OK) - { - LL_DEBUGS("FmodEX") << result << " " << FMOD_ErrorString(result) << LL_ENDL; - return false; - } - else - return true; + if (result == FMOD_OK) + return false; + LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + return true; } -// class LLAudioStreamManagerFMODEX { @@ -56,7 +51,7 @@ public: const std::string& getURL() { return mInternetStreamURL; } - FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL); + FMOD_RESULT getOpenState(FMOD_OPENSTATE& openstate, unsigned int* percentbuffered = NULL, bool* starving = NULL, bool* diskbusy = NULL); protected: FMOD::System* mSystem; FMOD::Channel* mStreamChannel; @@ -77,28 +72,30 @@ LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) : mFMODInternetStreamChannelp(NULL), mGain(1.0f) { + FMOD_RESULT result; + // Number of milliseconds of audio to buffer for the audio card. // Must be larger than the usual Second Life frame stutter time. const U32 buffer_seconds = 10; //sec const U32 estimated_bitrate = 128; //kbit/sec - mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); - - // Here's where we set the size of the network buffer and some buffering - // parameters. In this case we want a network buffer of 16k, we want it - // to prebuffer 40% of that when we first connect, and we want it - // to rebuffer 80% of that whenever we encounter a buffer underrun. - - // Leave the net buffer properties at the default. - //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); + result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); + Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize"); } LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX() { - // nothing interesting/safe to do. + LL_INFOS() << "LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX() destructing FMOD Ex Streaming" << LL_ENDL; + stop(); + for (U32 i = 0; i < 100; ++i) + { + if (releaseDeadStreams()) + break; + ms_sleep(10); + } + LL_INFOS() << "LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX() finished" << LL_ENDL; } - void LLStreamingAudio_FMODEX::start(const std::string& url) { //if (!mInited) @@ -112,9 +109,17 @@ void LLStreamingAudio_FMODEX::start(const std::string& url) if (!url.empty()) { - LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url); - mURL = url; + if(mDeadStreams.empty()) + { + LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url); + mURL = url; + } + else + { + LL_INFOS() << "Deferring stream load until buffer release: " << url << LL_ENDL; + mPendingURL = url; + } } else { @@ -126,21 +131,19 @@ void LLStreamingAudio_FMODEX::start(const std::string& url) void LLStreamingAudio_FMODEX::update() { - // Kill dead internet streams, if possible - std::list::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + if (!releaseDeadStreams()) { - LLAudioStreamManagerFMODEX *streamp = *iter; - if (streamp->stopStream()) - { - LL_INFOS() << "Closed dead stream" << LL_ENDL; - delete streamp; - mDeadStreams.erase(iter++); - } - else - { - iter++; - } + llassert_always(mCurrentInternetStreamp == NULL); + return; + } + + if(!mPendingURL.empty()) + { + llassert_always(mCurrentInternetStreamp == NULL); + LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,mPendingURL); + mURL = mPendingURL; + mPendingURL.clear(); } // Don't do anything if there are no streams playing @@ -152,9 +155,15 @@ void LLStreamingAudio_FMODEX::update() unsigned int progress; bool starving; bool diskbusy; - FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy); + FMOD_OPENSTATE open_state; + FMOD_RESULT result = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy); - if (open_state == FMOD_OPENSTATE_READY) + if (result != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR) + { + stop(); + return; + } + else if (open_state == FMOD_OPENSTATE_READY) { // Stream is live @@ -164,14 +173,9 @@ void LLStreamingAudio_FMODEX::update() { // Reset volume to previously set volume setGain(getGain()); - mFMODInternetStreamChannelp->setPaused(false); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); } } - else if(open_state == FMOD_OPENSTATE_ERROR) - { - stop(); - return; - } if(mFMODInternetStreamChannelp) { @@ -179,7 +183,7 @@ void LLStreamingAudio_FMODEX::update() // FmodEX Error checking //if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound) - if (fmod_error_check(mFMODInternetStreamChannelp->getCurrentSound(&sound)) && sound) + if (!Check_FMOD_Error(mFMODInternetStreamChannelp->getCurrentSound(&sound), "FMOD::Channel::getCurrentSound") && sound) // { FMOD_TAG tag; @@ -187,7 +191,7 @@ void LLStreamingAudio_FMODEX::update() // FmodEX Error checking //if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount) - if(fmod_error_check(sound->getNumTags(&tagcount, &dirtytagcount)) && dirtytagcount) + if (!Check_FMOD_Error(sound->getNumTags(&tagcount, &dirtytagcount), "FMOD::Sound::getNumTags") && dirtytagcount) // { // Stream metadata - originally by Shyotl Khur @@ -284,18 +288,17 @@ void LLStreamingAudio_FMODEX::update() if(starving) { bool paused = false; - mFMODInternetStreamChannelp->getPaused(&paused); - if(!paused) + if (mFMODInternetStreamChannelp->getPaused(&paused) == FMOD_OK && !paused) { LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; LL_INFOS() << " (diskbusy="<setPaused(true); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused"); } } else if(progress > 80) { - mFMODInternetStreamChannelp->setPaused(false); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); } } } @@ -303,10 +306,12 @@ void LLStreamingAudio_FMODEX::update() void LLStreamingAudio_FMODEX::stop() { + mPendingURL.clear(); + if (mFMODInternetStreamChannelp) { - mFMODInternetStreamChannelp->setPaused(true); - mFMODInternetStreamChannelp->setPriority(0); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused"); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPriority(0), "FMOD::Channel::setPriority"); mFMODInternetStreamChannelp = NULL; } @@ -323,7 +328,6 @@ void LLStreamingAudio_FMODEX::stop() mDeadStreams.push_back(mCurrentInternetStreamp); } mCurrentInternetStreamp = NULL; - //mURL.clear(); } } @@ -356,7 +360,7 @@ int LLStreamingAudio_FMODEX::isPlaying() { return 1; // Active and playing } - else if (!mURL.empty()) + else if (!mURL.empty() || !mPendingURL.empty()) { return 2; // "Paused" } @@ -387,7 +391,7 @@ void LLStreamingAudio_FMODEX::setGain(F32 vol) { vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? - mFMODInternetStreamChannelp->setVolume(vol); + Check_FMOD_Error(mFMODInternetStreamChannelp->setVolume(vol), "FMOD::Channel::setVolume"); } } @@ -440,7 +444,8 @@ LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, con FMOD::Channel *LLAudioStreamManagerFMODEX::startStream() { // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY) + FMOD_OPENSTATE open_state; + if (getOpenState(open_state) != FMOD_OK || open_state != FMOD_OPENSTATE_READY) { LL_WARNS() << "No internet stream to start playing!" << LL_ENDL; return NULL; @@ -449,7 +454,7 @@ FMOD::Channel *LLAudioStreamManagerFMODEX::startStream() if(mStreamChannel) return mStreamChannel; //Already have a channel for this stream. - mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel); + Check_FMOD_Error(mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel), "FMOD::System::playSound"); return mStreamChannel; } @@ -457,21 +462,22 @@ bool LLAudioStreamManagerFMODEX::stopStream() { if (mInternetStream) { - - bool close = true; - switch (getOpenState()) + FMOD_OPENSTATE open_state; + if (getOpenState(open_state) == FMOD_OK) { - case FMOD_OPENSTATE_CONNECTING: - close = false; - break; - default: - close = true; + switch (open_state) + { + case FMOD_OPENSTATE_CONNECTING: + close = false; + break; + default: + close = true; + } } - if (close) + if (close && mInternetStream->release() == FMOD_OK) { - mInternetStream->release(); mStreamChannel = NULL; mInternetStream = NULL; return true; @@ -487,19 +493,43 @@ bool LLAudioStreamManagerFMODEX::stopStream() } } -FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy) +FMOD_RESULT LLAudioStreamManagerFMODEX::getOpenState(FMOD_OPENSTATE& state, unsigned int* percentbuffered, bool* starving, bool* diskbusy) { - FMOD_OPENSTATE state; - mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); - return state; + if (!mInternetStream) + return FMOD_ERR_INVALID_HANDLE; + FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); + Check_FMOD_Error(result, "FMOD::Sound::getOpenState"); + return result; } void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) { - mSystem->setStreamBufferSize(streambuffertime/1000*128*128, FMOD_TIMEUNIT_RAWBYTES); + Check_FMOD_Error(mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES), "FMOD::System::setStreamBufferSize"); FMOD_ADVANCEDSETTINGS settings; memset(&settings,0,sizeof(settings)); settings.cbsize=sizeof(settings); settings.defaultDecodeBufferSize = decodebuffertime;//ms - mSystem->setAdvancedSettings(&settings); + Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings"); +} + +bool LLStreamingAudio_FMODEX::releaseDeadStreams() +{ + // Kill dead internet streams, if possible + std::list::iterator iter; + for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + { + LLAudioStreamManagerFMODEX *streamp = *iter; + if (streamp->stopStream()) + { + LL_INFOS() << "Closed dead stream" << LL_ENDL; + delete streamp; + mDeadStreams.erase(iter++); + } + else + { + iter++; + } + } + + return mDeadStreams.empty(); } diff --git a/indra/llaudio/llstreamingaudio_fmodex.h b/indra/llaudio/llstreamingaudio_fmodex.h index 56a1a2f6f2..47d25a71c7 100644 --- a/indra/llaudio/llstreamingaudio_fmodex.h +++ b/indra/llaudio/llstreamingaudio_fmodex.h @@ -64,6 +64,8 @@ class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface // private: + bool releaseDeadStreams(); + FMOD::System *mSystem; LLAudioStreamManagerFMODEX *mCurrentInternetStreamp; @@ -71,8 +73,9 @@ private: std::list mDeadStreams; std::string mURL; + std::string mPendingURL; F32 mGain; - + // Streamtitle display bool mNewMetadata; LLSD mMetadata; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 3e0e46a208..dbc2721749 100755 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -2135,14 +2135,8 @@ bool LLAppViewer::cleanup() if (gAudiop) { - // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem. - - LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl(); - delete sai; - gAudiop->setStreamingAudioImpl(NULL); - // shut down the audio subsystem - gAudiop->shutdown(); + gAudiop->shutdown(); delete gAudiop; gAudiop = NULL;