From b3d86e626bfb52e75f4dd53bc55c7c7586cc0214 Mon Sep 17 00:00:00 2001 From: Shyotl Date: Tue, 25 Nov 2014 16:32:04 -0600 Subject: [PATCH] Fixed wind dsp and implemented a DSP that mimics removed FMOD::Channel::getWaveData func. Fixed crash if fmod profiling was enabled. Fixed crash due to failing to check if resulting utf string from stream metadata was zero-length before calling std::string::back. --- indra/llaudio/llaudioengine_fmodex.cpp | 12 +- indra/llaudio/llaudioengine_fmodstudio.cpp | 84 ++++--- indra/llaudio/llstreamingaudio_fmodex.cpp | 8 + indra/llaudio/llstreamingaudio_fmodstudio.cpp | 232 ++++++++++++++---- indra/llaudio/llstreamingaudio_fmodstudio.h | 9 +- 5 files changed, 262 insertions(+), 83 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp index 972725171..c3e067c59 100644 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ b/indra/llaudio/llaudioengine_fmodex.cpp @@ -321,10 +321,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 @@ -437,6 +433,14 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) return false; #endif + if (mEnableProfiler) + { + 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]); + } + // 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)); diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 966455a46..3ff461a58 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -49,6 +49,8 @@ #include "sound_ids.h" +#include + #if LL_WINDOWS //Some ugly code to make missing fmod.dll not cause a fatal error. #define WIN32_LEAN_AND_MEAN #include "windows.h" @@ -77,7 +79,7 @@ bool attemptDelayLoad() static bool sVerboseDebugging = false; -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels); +FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int *outchannels); FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; @@ -314,14 +316,10 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) result = mSystem->setSoftwareChannels(num_channels + 2); Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); - U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED; + U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE; if(mEnableProfiler) { fmod_flags |= FMOD_INIT_PROFILE_ENABLE; - 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 @@ -423,7 +421,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) Ok, the speaker mode selected isn't supported by this soundcard. Switch it back to stereo... */ - result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 2); + result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0); Check_FMOD_Error(result,"Error falling back to stereo mode"); /* ... and re-init. @@ -434,6 +432,14 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) return false; #endif + if (mEnableProfiler) + { + 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]); + } + // set up our favourite FMOD-native streaming audio implementation if none has already been added if (!getStreamingAudioImpl()) // no existing implementation added setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem)); @@ -536,46 +542,50 @@ LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel() bool LLAudioEngine_FMODSTUDIO::initWind() { - //mNextWindUpdate = 0.0; + mNextWindUpdate = 0.0; - //if (!mWindDSP) - //{ - // FMOD_DSP_DESCRIPTION dspdesc; - // memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero - // strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit" - // dspdesc.read = &windCallback; //Assign callback. - // if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP")) - // return false; + if (!mWindDSP) + { + FMOD_DSP_DESCRIPTION dspdesc; + memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero + dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; + strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit" + dspdesc.numoutputbuffers = 1; + dspdesc.read = &windCallback; //Assign callback. + if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP")) + return false; - // if(mWindGen) - // delete mWindGen; - // - // int frequency = 44100; - // mSystem->getSoftwareFormat(&frequency, NULL, NULL); - // mWindGen = new LLWindGen((U32)frequency); - // mWindDSP->setUserData((void*)mWindGen); - //} + if(mWindGen) + delete mWindGen; + + int frequency = 44100; + mSystem->getSoftwareFormat(&frequency, NULL, NULL); + mWindGen = new LLWindGen((U32)frequency); + mWindDSP->setUserData((void*)mWindGen); + } - //if (mWindDSP) - //{ - // mSystem->playDSP(mWindDSP, NULL, false, 0); - // return true; - //} + if (mWindDSP) + { + mSystem->playDSP(mWindDSP, NULL, false, 0); + FMOD_SPEAKERMODE mode; + mSystem->getSoftwareFormat(NULL, &mode, NULL); + mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode); + return true; + } return false; } void LLAudioEngine_FMODSTUDIO::cleanupWind() { - //if (mWindDSP) - //{ - // mWindDSP->remove(); - // mWindDSP->release(); - // mWindDSP = NULL; - //} + if (mWindDSP) + { + mWindDSP->release(); + mWindDSP = NULL; + } - //delete mWindGen; - //mWindGen = NULL; + delete mWindGen; + mWindGen = NULL; } diff --git a/indra/llaudio/llstreamingaudio_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp index be5888aa5..2cfae5128 100644 --- a/indra/llaudio/llstreamingaudio_fmodex.cpp +++ b/indra/llaudio/llstreamingaudio_fmodex.cpp @@ -289,6 +289,8 @@ void LLStreamingAudio_FMODEX::update() case(FMOD_TAGDATATYPE_STRING): { std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); + if (out.length() && out.back() == 0) + out.pop_back(); (*mMetaData)[name]=out; llinfos << tag.name << "(RAW): " << out << llendl; } @@ -299,6 +301,8 @@ void LLStreamingAudio_FMODEX::update() if (tag.datalen > 3 && ((char*)tag.data)[0] == 0xEF && ((char*)tag.data)[1] == 0xBB && ((char*)tag.data)[2] == 0xBF) offs = 3; std::string out((char*)tag.data + offs, tag.datalen - offs); + if (out.length() && out.back() == 0) + out.pop_back(); (*mMetaData)[name] = out; llinfos << tag.name << "(UTF8): " << out << llendl; } @@ -306,6 +310,8 @@ void LLStreamingAudio_FMODEX::update() case(FMOD_TAGDATATYPE_STRING_UTF16): { std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16); + if (out.length() && out.back() == 0) + out.pop_back(); (*mMetaData)[name] = out; llinfos << tag.name << "(UTF16): " << out << llendl; } @@ -313,6 +319,8 @@ void LLStreamingAudio_FMODEX::update() case(FMOD_TAGDATATYPE_STRING_UTF16BE): { std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16BE); + if (out.length() && out.back() == 0) + out.pop_back(); (*mMetaData)[name] = out; llinfos << tag.name << "(UTF16BE): " << out << llendl; } diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp index a2ffe2108..0c7b3d2c4 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.cpp +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -33,17 +33,25 @@ #include "linden_common.h" #include "llmath.h" +#include "llthread.h" #include "fmod.hpp" #include "fmod_errors.h" #include "llstreamingaudio_fmodstudio.h" +inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) +{ + if (result == FMOD_OK) + return false; + LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + return true; +} class LLAudioStreamManagerFMODSTUDIO { public: - LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url); + LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url); FMOD::Channel* startStream(); bool stopStream(); // Returns true if the stream was successfully stopped. bool ready(); @@ -55,12 +63,55 @@ protected: FMOD::System* mSystem; FMOD::Channel* mStreamChannel; FMOD::Sound* mInternetStream; + FMOD::ChannelGroup* mChannelGroup; bool mReady; std::string mInternetStreamURL; }; +LLGlobalMutex gWaveDataMutex; //Just to be extra strict. +const U32 WAVE_BUFFER_SIZE = 1024; +U32 gWaveBufferMinSize = 0; +F32 gWaveDataBuffer[WAVE_BUFFER_SIZE] = { 0.f }; +U32 gWaveDataBufferSize = 0; +FMOD_RESULT F_CALLBACK waveDataCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) +{ + if (!length || !inchannels) + return FMOD_OK; + memcpy(outbuffer, inbuffer, length * inchannels * sizeof(float)); + + static std::vector local_buf; + if (local_buf.size() < length) + local_buf.resize(length, 0.f); + + for (U32 i = 0; i < length; ++i) + { + F32 total = 0.f; + for (S32 j = 0; j < inchannels; ++j) + { + total += inbuffer[i*inchannels + j]; + } + local_buf[i] = total / inchannels; + } + + { + LLMutexLock lock(gWaveDataMutex); + + for (U32 i = length; i > 0; --i) + { + if (++gWaveDataBufferSize > WAVE_BUFFER_SIZE) + { + if (gWaveBufferMinSize) + memcpy(gWaveDataBuffer + WAVE_BUFFER_SIZE - gWaveBufferMinSize, gWaveDataBuffer, gWaveBufferMinSize * sizeof(float)); + gWaveDataBufferSize = 1 + gWaveBufferMinSize; + } + gWaveDataBuffer[WAVE_BUFFER_SIZE - gWaveDataBufferSize] = local_buf[i - 1]; + } + } + + return FMOD_OK; +} //--------------------------------------------------------------------------- // Internet Streaming @@ -72,11 +123,14 @@ LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : mGain(1.0f), mMetaData(NULL) { + 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); + result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); + Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize"); // 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 @@ -85,11 +139,36 @@ LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : // Leave the net buffer properties at the default. //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); + + result = system->createChannelGroup("stream", &mStreamGroup); + Check_FMOD_Error(result,"FMOD::System::createChannelGroup"); + + FMOD_DSP_DESCRIPTION dspdesc; + memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Zero out everything + dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; + strncpy(dspdesc.name, "Waveform", sizeof(dspdesc.name)); + dspdesc.numoutputbuffers = 1; + dspdesc.read = &waveDataCallback; //Assign callback. + + result = system->createDSP(&dspdesc, &mStreamDSP); + Check_FMOD_Error(result, "FMOD::System::createDSPByType"); + result = mStreamGroup->addDSP(FMOD_CHANNELCONTROL_DSP_TAIL, mStreamDSP); + Check_FMOD_Error(result, "FMOD::ChannelGroup::addDSP"); + mStreamDSP->setActive(false); } LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() { + + if (mStreamGroup) + { + if (mStreamDSP) + mStreamGroup->removeDSP(mStreamDSP); + mStreamGroup->release(); + } + if (mStreamDSP) + mStreamDSP->release(); // nothing interesting/safe to do. } @@ -110,7 +189,7 @@ void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) if(mDeadStreams.empty()) { llinfos << "Starting internet stream: " << url << llendl; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem,url); + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, url); mURL = url; mMetaData = new LLSD; } @@ -127,6 +206,45 @@ void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) } } +enum utf_endian_type_t +{ + UTF16LE, + UTF16BE, + UTF16 +}; + +std::string utf16input_to_utf8(char* input, U32 len, utf_endian_type_t type) +{ + if (type == UTF16) + { + type = UTF16BE; //Default + if (len > 2) + { + //Parse and strip BOM. + if ((input[0] == 0xFE && input[1] == 0xFF) || + (input[0] == 0xFF && input[1] == 0xFE)) + { + input += 2; + len -= 2; + type = input[0] == 0xFE ? UTF16BE : UTF16LE; + } + } + } + llutf16string out_16((U16*)input, len / 2); + if (len % 2) + { + out_16.push_back((input)[len - 1] << 8); + } + if (type == UTF16BE) + { + for (llutf16string::iterator i = out_16.begin(); i < out_16.end(); ++i) + { + llutf16string::value_type v = *i; + *i = ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8); + } + } + return utf16str_to_utf8str(out_16); +} void LLStreamingAudio_FMODSTUDIO::update() { @@ -157,7 +275,7 @@ void LLStreamingAudio_FMODSTUDIO::update() { llassert_always(mCurrentInternetStreamp == NULL); llinfos << "Starting internet stream: " << mPendingURL << llendl; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem,mPendingURL); + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem,mStreamGroup, mPendingURL); mURL = mPendingURL; mMetaData = new LLSD; mPendingURL.clear(); @@ -184,6 +302,8 @@ void LLStreamingAudio_FMODSTUDIO::update() { // Reset volume to previously set volume setGain(getGain()); + if (mStreamDSP) + mStreamDSP->setActive(true); mFMODInternetStreamChannelp->setPaused(false); } } @@ -216,23 +336,27 @@ void LLStreamingAudio_FMODSTUDIO::update() switch(tag.type) //Crappy tag translate table. { case(FMOD_TAGTYPE_ID3V2): - if(name == "TIT2") name = "TITLE"; + if (!LLStringUtil::compareInsensitive(name, "TIT2")) name = "TITLE"; else if(name == "TPE1") name = "ARTIST"; break; case(FMOD_TAGTYPE_ASF): - if(name == "Title") name = "TITLE"; - else if(name == "WM/AlbumArtist") name = "ARTIST"; + if (!LLStringUtil::compareInsensitive(name, "Title")) name = "TITLE"; + else if (!LLStringUtil::compareInsensitive(name, "WM/AlbumArtist")) name = "ARTIST"; break; case(FMOD_TAGTYPE_FMOD): - if (!strcmp(tag.name, "Sample Rate Change")) + if (!LLStringUtil::compareInsensitive(name, "Sample Rate Change")) { llinfos << "Stream forced changing sample rate to " << *((float *)tag.data) << llendl; mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); } continue; default: + if (!LLStringUtil::compareInsensitive(name, "TITLE") || + !LLStringUtil::compareInsensitive(name, "ARTIST")) + LLStringUtil::toUpper(name); break; } + switch(tag.datatype) { case(FMOD_TAGDATATYPE_INT): @@ -246,25 +370,40 @@ void LLStreamingAudio_FMODSTUDIO::update() case(FMOD_TAGDATATYPE_STRING): { std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); + if (out.length() && out.back() == 0) + out.pop_back(); (*mMetaData)[name]=out; - llinfos << tag.name << ": " << out << llendl; + llinfos << tag.name << "(RAW): " << out << llendl; + } + break; + case(FMOD_TAGDATATYPE_STRING_UTF8) : + { + U8 offs = 0; + if (tag.datalen > 3 && ((char*)tag.data)[0] == 0xEF && ((char*)tag.data)[1] == 0xBB && ((char*)tag.data)[2] == 0xBF) + offs = 3; + std::string out((char*)tag.data + offs, tag.datalen - offs); + if (out.length() && out.back() == 0) + out.pop_back(); + (*mMetaData)[name] = out; + llinfos << tag.name << "(UTF8): " << out << llendl; } break; case(FMOD_TAGDATATYPE_STRING_UTF16): { - std::string out((char*)tag.data,tag.datalen); - (*mMetaData)[std::string(tag.name)]=out; - llinfos << tag.name << ": " << out << llendl; + std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16); + if (out.length() && out.back() == 0) + out.pop_back(); + (*mMetaData)[name] = out; + llinfos << tag.name << "(UTF16): " << out << llendl; } break; case(FMOD_TAGDATATYPE_STRING_UTF16BE): { - std::string out((char*)tag.data,tag.datalen); - U16* buf = (U16*)out.c_str(); - for(U32 j = 0; j < out.size()/2; ++j) - (((buf[j] & 0xff)<<8) | ((buf[j] & 0xff00)>>8)); - (*mMetaData)[std::string(tag.name)]=out; - llinfos << tag.name << ": " << out << llendl; + std::string out = utf16input_to_utf8((char*)tag.data, tag.datalen, UTF16BE); + if (out.length() && out.back() == 0) + out.pop_back(); + (*mMetaData)[name] = out; + llinfos << tag.name << "(UTF16BE): " << out << llendl; } default: break; @@ -300,6 +439,15 @@ void LLStreamingAudio_FMODSTUDIO::stop() delete mMetaData; mMetaData = NULL; } + + if (mStreamDSP) + { + mSystem->lockDSP(); + mStreamDSP->setActive(false); + gWaveDataBufferSize = 0; + mSystem->unlockDSP(); + } + if (mFMODInternetStreamChannelp) { mFMODInternetStreamChannelp->setPaused(true); @@ -390,38 +538,40 @@ void LLStreamingAudio_FMODSTUDIO::setGain(F32 vol) /*virtual*/ bool LLStreamingAudio_FMODSTUDIO::getWaveData(float* arr, S32 count, S32 stride/*=1*/) { - //if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp) - // return false; + if (count > (WAVE_BUFFER_SIZE / 2)) + LL_ERRS("AudioImpl") << "Count=" << count << " exceeds WAVE_BUFFER_SIZE/2=" << WAVE_BUFFER_SIZE << LL_ENDL; - //bool muted=false; - //mFMODInternetStreamChannelp->getMute(&muted); - //if(muted) - // return false; + if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp) + return false; - //static std::vector local_array(count); //Have to have an extra buffer to mix channels. Bleh. - //if(count > (S32)local_array.size()) //Expand the array if needed. Try to minimize allocation calls, so don't ever shrink. - // local_array.resize(count); - - //if( mFMODInternetStreamChannelp->getWaveData(&local_array[0],count,0) == FMOD_OK && - // mFMODInternetStreamChannelp->getWaveData(&arr[0],count,1) == FMOD_OK ) - //{ - // for(S32 i = count-1;i>=0;i-=stride) - // { - // arr[i] += local_array[i]; - // arr[i] *= .5f; - // } - // return true; - //} - return false; + bool muted = false; + mFMODInternetStreamChannelp->getMute(&muted); + if(muted) + return false; + { + U32 buff_size; + { + LLMutexLock lock(gWaveDataMutex); + gWaveBufferMinSize = count; + buff_size = gWaveDataBufferSize; + if (!buff_size) + return false; + memcpy(arr, gWaveDataBuffer + WAVE_BUFFER_SIZE - buff_size, llmin(U32(count), buff_size) * sizeof(float)); + } + if (buff_size < U32(count)) + memset(arr + buff_size, 0, (count - buff_size) * sizeof(float)); + } + return true; } /////////////////////////////////////////////////////// // manager of possibly-multiple internet audio streams -LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url) : +LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url) : mSystem(system), mStreamChannel(NULL), mInternetStream(NULL), + mChannelGroup(group), mReady(false) { mInternetStreamURL = url; @@ -452,7 +602,7 @@ FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream() if(mStreamChannel) return mStreamChannel; //Already have a channel for this stream. - mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel); + mSystem->playSound(mInternetStream, mChannelGroup, true, &mStreamChannel); return mStreamChannel; } diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h index 142256339..a71a88eba 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.h +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -45,6 +45,9 @@ namespace FMOD { class System; class Channel; + class ChannelGroup; + class ChannelGroup; + class DSP; } //Interfaces @@ -65,10 +68,11 @@ class LLStreamingAudio_FMODSTUDIO : public LLStreamingAudioInterface /*virtual*/ bool supportsMetaData(){return true;} /*virtual*/ const LLSD *getMetaData(){return mMetaData;} //return NULL if not playing. - /*virtual*/ bool supportsWaveData(){return false;} + /*virtual*/ bool supportsWaveData(){return true;} /*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1); /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); + private: FMOD::System *mSystem; @@ -81,6 +85,9 @@ private: F32 mGain; LLSD *mMetaData; + + FMOD::ChannelGroup* mStreamGroup; + FMOD::DSP* mStreamDSP; };