FIRE-12077; Contribution by Gibson Firehawk to fix the bug that Linux clients freeze ocassionaly when the stream changes or stops.
From his original commit: OPEN-279 Potential fix for the BUG-3214 stream stopping issue Here is what the FMOD documentation says about the stream state FMOD_OPENSTATE_Ready and playing, but not possible to release at this time without stalling the main Since the FMOD Ex implementation (not sure about the old FMOD 3.75), streams have been released while the stream state is FMOD_OPENSTATE_PLAYING. Before release is called, the stream would only be paused, not stopped. The stream must be stopped for it to no longer be in playing state. Also, there usually needs to be just a little time between when a stream is stopped for it to exit playing state before releasing it. The viewer has been calling release almost instantly after just pausing the stream. I think s quite possible that, even though releasing streams while they are in playing state t appear to be problematic most of the time, that some of the stream stopping issues such as BUG-3214 are a result of it. In the net streaming example program that comes with the FMOD API, when a stream is to be stopped, stop is called for the channel and then right before release, the program waits not only for the stream to exit playing state, but also for the stream to return to FMOD_OPENSTATE_READY before releasing. Due to the differences in how the viewer has been stopping and releasing streams compared to how FMOD does it in their example program, along with what they say in their documentation about the stream state FMOD_OPENSTATE_PLAYING, i have made the following changes to how streams are stopped and released by the viewer. 1.) Stop the stream channel instead of just pausing it before release so the stream can exit FMOD_OPENSTATE_PLAYING state and return (usually very quickly after stop is called) to FMOD_OPENSTATE_READY. 2.) Converted the dead streams list into a delayed release list. If a s state is not FMOD_OPENSTATE_READY when s checked right before release, push the stream to the delayed release list. Check for delayed release streams during each update like how was done before with the dead streams list and release streams that are in ready state. 3.) During viewer shutdown, call stop on the currently playing stream. After that, check if any streams are in the delayed release list, and, if so, release them when their stream state is ready state. If an unlikely edge case occurs where the streams in the delayed release list are not released in a timely fashion, force release them. The force release added in this change is actually pretty much the equivalent of how streams used to be stopped previously. The main difference, and advantage, is that regardless of which state the stream might be in during force release besides FMOD_OPENSTATE_READY, it won't be in FMOD_OPENSTATE_PLAYING when released.itstreamdoesnitthread.PLAYING -meow-7.2.2
parent
996de24dbc
commit
b9150394a7
|
|
@ -358,7 +358,9 @@ void LLAudioEngine_FMODEX::allocateListener(void)
|
|||
|
||||
void LLAudioEngine_FMODEX::shutdown()
|
||||
{
|
||||
stopInternetStream();
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
//stopInternetStream();
|
||||
// <FS:GF>
|
||||
|
||||
LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL;
|
||||
LLAudioEngine::shutdown();
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ class LLStreamingAudioInterface
|
|||
virtual void setGain(F32 vol) = 0;
|
||||
virtual F32 getGain() = 0;
|
||||
virtual std::string getURL() = 0;
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
virtual bool delayedRelease(bool force = false){return false;}
|
||||
// <FS:GF>
|
||||
virtual bool supportsAdjustableBufferSizes(){return false;}
|
||||
virtual void setBufferSizes(U32 streambuffertime, U32 decodebuffertime){};
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ public:
|
|||
LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url);
|
||||
FMOD::Channel* startStream();
|
||||
bool stopStream(); // Returns true if the stream was successfully stopped.
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
void forceReleaseStream(); // This should rarely if ever be called.
|
||||
// <FS:GF>
|
||||
bool ready();
|
||||
|
||||
const std::string& getURL() { return mInternetStreamURL; }
|
||||
|
|
@ -126,22 +129,31 @@ void LLStreamingAudio_FMODEX::start(const std::string& url)
|
|||
|
||||
void LLStreamingAudio_FMODEX::update()
|
||||
{
|
||||
// Kill dead internet streams, if possible
|
||||
std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
|
||||
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
//// Kill dead internet streams, if possible
|
||||
//std::list<LLAudioStreamManagerFMODEX *>::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++;
|
||||
// }
|
||||
//}
|
||||
|
||||
// Doesn't matter if this returns true or false here. Calling it is what kills delayed release streams
|
||||
// if safe to do so. Returning true or false only matters when called from llappviewer during shutdown
|
||||
if (delayedRelease())
|
||||
{
|
||||
LLAudioStreamManagerFMODEX *streamp = *iter;
|
||||
if (streamp->stopStream())
|
||||
{
|
||||
LL_INFOS() << "Closed dead stream" << LL_ENDL;
|
||||
delete streamp;
|
||||
mDeadStreams.erase(iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
// Do nothing.
|
||||
}
|
||||
// <FS:GF>
|
||||
|
||||
// Don't do anything if there are no streams playing
|
||||
if (!mCurrentInternetStreamp)
|
||||
|
|
@ -305,8 +317,11 @@ void LLStreamingAudio_FMODEX::stop()
|
|||
{
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
mFMODInternetStreamChannelp->setPaused(true);
|
||||
mFMODInternetStreamChannelp->setPriority(0);
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
//mFMODInternetStreamChannelp->setPaused(true);
|
||||
//mFMODInternetStreamChannelp->setPriority(0);
|
||||
mFMODInternetStreamChannelp->stop();
|
||||
// <FS:GF>
|
||||
mFMODInternetStreamChannelp = NULL;
|
||||
}
|
||||
|
||||
|
|
@ -315,18 +330,60 @@ void LLStreamingAudio_FMODEX::stop()
|
|||
LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
|
||||
if (mCurrentInternetStreamp->stopStream())
|
||||
{
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
LL_INFOS() << "Successfully released internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
|
||||
// <FS:GF>
|
||||
delete mCurrentInternetStreamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
|
||||
mDeadStreams.push_back(mCurrentInternetStreamp);
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
//LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
|
||||
//mDeadStreams.push_back(mCurrentInternetStreamp);
|
||||
LL_INFOS() << "Delaying release of internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
|
||||
mDelayedReleaseStreams.push_back(mCurrentInternetStreamp);
|
||||
// <FS:GF>
|
||||
}
|
||||
mCurrentInternetStreamp = NULL;
|
||||
//mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
bool LLStreamingAudio_FMODEX::delayedRelease(bool force)
|
||||
{
|
||||
bool streams = false;
|
||||
std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
|
||||
for (iter = mDelayedReleaseStreams.begin(); iter != mDelayedReleaseStreams.end();)
|
||||
{
|
||||
streams = true;
|
||||
LLAudioStreamManagerFMODEX *streamp = *iter;
|
||||
|
||||
if (!force)
|
||||
{
|
||||
if (streamp->stopStream())
|
||||
{
|
||||
LL_INFOS() << "Successfully released internet stream: " << streamp->getURL() << LL_ENDL;
|
||||
delete streamp;
|
||||
mDelayedReleaseStreams.erase(iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
streamp->forceReleaseStream();
|
||||
LL_INFOS() << "Force released internet stream: " << streamp->getURL() << LL_ENDL;
|
||||
delete streamp;
|
||||
mDelayedReleaseStreams.erase(iter++);
|
||||
}
|
||||
}
|
||||
return streams;
|
||||
}
|
||||
// <FS:GF>
|
||||
|
||||
void LLStreamingAudio_FMODEX::pause(int pauseopt)
|
||||
{
|
||||
if (pauseopt < 0)
|
||||
|
|
@ -457,16 +514,25 @@ bool LLAudioStreamManagerFMODEX::stopStream()
|
|||
{
|
||||
if (mInternetStream)
|
||||
{
|
||||
|
||||
|
||||
bool close = true;
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
mSystem->update();
|
||||
|
||||
//bool close = true;
|
||||
bool close = false;
|
||||
switch (getOpenState())
|
||||
{
|
||||
case FMOD_OPENSTATE_CONNECTING:
|
||||
close = false;
|
||||
//case FMOD_OPENSTATE_CONNECTING:
|
||||
case FMOD_OPENSTATE_READY:
|
||||
//close = false;
|
||||
close = true;
|
||||
break;
|
||||
case FMOD_OPENSTATE_ERROR:
|
||||
close = true;
|
||||
break;
|
||||
default:
|
||||
close = true;
|
||||
//close = true;
|
||||
close = false;
|
||||
// <FS:GF>
|
||||
}
|
||||
|
||||
if (close)
|
||||
|
|
@ -487,6 +553,18 @@ bool LLAudioStreamManagerFMODEX::stopStream()
|
|||
}
|
||||
}
|
||||
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
void LLAudioStreamManagerFMODEX::forceReleaseStream()
|
||||
{
|
||||
if (mInternetStream)
|
||||
{
|
||||
mInternetStream->release();
|
||||
mStreamChannel = NULL;
|
||||
mInternetStream = NULL;
|
||||
}
|
||||
}
|
||||
// <FS:GF>
|
||||
|
||||
FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy)
|
||||
{
|
||||
FMOD_OPENSTATE state;
|
||||
|
|
|
|||
|
|
@ -55,6 +55,9 @@ class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface
|
|||
/*virtual*/ void setGain(F32 vol);
|
||||
/*virtual*/ F32 getGain();
|
||||
/*virtual*/ std::string getURL();
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
/*virtual*/ bool delayedRelease(bool force = false);
|
||||
// <FS:GF>
|
||||
|
||||
/*virtual*/ bool supportsAdjustableBufferSizes(){return true;}
|
||||
/*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime);
|
||||
|
|
@ -68,7 +71,10 @@ private:
|
|||
|
||||
LLAudioStreamManagerFMODEX *mCurrentInternetStreamp;
|
||||
FMOD::Channel *mFMODInternetStreamChannelp;
|
||||
std::list<LLAudioStreamManagerFMODEX *> mDeadStreams;
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
//std::list<LLAudioStreamManagerFMODEX *> mDeadStreams;
|
||||
std::list<LLAudioStreamManagerFMODEX *> mDelayedReleaseStreams;
|
||||
// <FS:GF>
|
||||
|
||||
std::string mURL;
|
||||
F32 mGain;
|
||||
|
|
|
|||
|
|
@ -2135,11 +2135,40 @@ bool LLAppViewer::cleanup()
|
|||
// 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);
|
||||
// <FS:GF> Safe stop and release for FMOD Ex music streams
|
||||
if (sai)
|
||||
{
|
||||
sai->stop();
|
||||
|
||||
LLTimer streamReleaseTimer;
|
||||
streamReleaseTimer.start();
|
||||
|
||||
// Kill delayed release streams if any. Most streams will release almost instantly
|
||||
// but there is a timeout in place just in case.
|
||||
while (sai->delayedRelease() && streamReleaseTimer.getElapsedTimeF32() < 5.0f);
|
||||
{
|
||||
// Do nothing while waiting for delayedRelease to kill the streams.
|
||||
}
|
||||
streamReleaseTimer.stop();
|
||||
|
||||
// We should rarely if ever enter this loop, but we will if there are streams that
|
||||
// were not released before the 5 second timeout above. Show no mercy and call release
|
||||
// on them right away.
|
||||
while (sai->delayedRelease(true));
|
||||
{
|
||||
// Do nothing again while delayedRelease force kills the streams.
|
||||
}
|
||||
}
|
||||
|
||||
//delete sai;
|
||||
//gAudiop->setStreamingAudioImpl(NULL);
|
||||
|
||||
// shut down the audio subsystem
|
||||
gAudiop->shutdown();
|
||||
gAudiop->shutdown();
|
||||
|
||||
delete sai;
|
||||
gAudiop->setStreamingAudioImpl(NULL);
|
||||
// <FS:GF>
|
||||
|
||||
delete gAudiop;
|
||||
gAudiop = NULL;
|
||||
|
|
|
|||
Loading…
Reference in New Issue