diff options
Diffstat (limited to 'indra/llaudio')
-rw-r--r-- | indra/llaudio/CMakeLists.txt | 15 | ||||
-rw-r--r-- | indra/llaudio/llaudioengine_fmodstudio.cpp | 756 | ||||
-rw-r--r-- | indra/llaudio/llaudioengine_fmodstudio.h | 131 | ||||
-rw-r--r-- | indra/llaudio/lllistener_fmodstudio.cpp | 136 | ||||
-rw-r--r-- | indra/llaudio/lllistener_fmodstudio.h | 65 | ||||
-rw-r--r-- | indra/llaudio/llstreamingaudio_fmodstudio.cpp | 481 | ||||
-rw-r--r-- | indra/llaudio/llstreamingaudio_fmodstudio.h | 76 |
7 files changed, 0 insertions, 1660 deletions
diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 4f469b9bb5..9278d3c488 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -4,7 +4,6 @@ project(llaudio) include(00-Common) include(LLAudio) -include(FMODSTUDIO) include(OPENAL) include(LLCommon) @@ -25,20 +24,6 @@ set(llaudio_HEADER_FILES llwindgen.h ) -if (TARGET ll::fmodstudio) - list(APPEND llaudio_SOURCE_FILES - llaudioengine_fmodstudio.cpp - lllistener_fmodstudio.cpp - llstreamingaudio_fmodstudio.cpp - ) - - list(APPEND llaudio_HEADER_FILES - llaudioengine_fmodstudio.h - lllistener_fmodstudio.h - llstreamingaudio_fmodstudio.h - ) -endif () - if (TARGET ll::openal) list(APPEND llaudio_SOURCE_FILES llaudioengine_openal.cpp diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp deleted file mode 100644 index c6313ea289..0000000000 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ /dev/null @@ -1,756 +0,0 @@ -/** - * @file audioengine_fmodstudio.cpp - * @brief Implementation of LLAudioEngine class abstracting the audio - * support as a FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llstreamingaudio.h" -#include "llstreamingaudio_fmodstudio.h" - -#include "llaudioengine_fmodstudio.h" -#include "lllistener_fmodstudio.h" - -#include "llerror.h" -#include "llmath.h" -#include "llrand.h" - -#include "fmodstudio/fmod.hpp" -#include "fmodstudio/fmod_errors.h" -#include "lldir.h" -#include "llapr.h" - -#include "sound_ids.h" - -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels); - -FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; - -LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler) -: mInited(false), - mWindGen(NULL), - mWindDSP(NULL), - mSystem(NULL), - mEnableProfiler(enable_profiler), - mWindDSPDesc(NULL) -{ -} - - -LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() -{ - // mWindDSPDesc, mWindGen and mWindDSP get cleaned up on cleanupWind in LLAudioEngine::shutdown() - // mSystem gets cleaned up at shutdown() -} - - -static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) -{ - if (result == FMOD_OK) - return false; - LL_DEBUGS("FMOD") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - return true; -} - -bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title) -{ - U32 version; - FMOD_RESULT result; - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() initializing FMOD" << LL_ENDL; - - result = FMOD::System_Create(&mSystem); - if (Check_FMOD_Error(result, "FMOD::System_Create")) - return false; - - //will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer. - LLAudioEngine::init(userdata, app_title); - - result = mSystem->getVersion(&version); - Check_FMOD_Error(result, "FMOD::System::getVersion"); - - if (version < FMOD_VERSION) - { - LL_WARNS("AppInit") << "FMOD Studio version mismatch, actual: " << version - << " expected:" << FMOD_VERSION << LL_ENDL; - } - - // In this case, all sounds, PLUS wind and stream will be software. - result = mSystem->setSoftwareChannels(LL_MAX_AUDIO_CHANNELS + 2); - Check_FMOD_Error(result, "FMOD::System::setSoftwareChannels"); - - FMOD_ADVANCEDSETTINGS settings; - memset(&settings, 0, sizeof(settings)); - settings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS); - settings.resamplerMethod = FMOD_DSP_RESAMPLER_LINEAR; - - result = mSystem->setAdvancedSettings(&settings); - Check_FMOD_Error(result, "FMOD::System::setAdvancedSettings"); - - // FMOD_INIT_THREAD_UNSAFE Disables thread safety for API calls. - // Only use this if FMOD is being called from a single thread, and if Studio API is not being used. - U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE; - if (mEnableProfiler) - { - fmod_flags |= FMOD_INIT_PROFILE_ENABLE; - } - -#if LL_LINUX - bool audio_ok = false; - - if (!audio_ok) - { - const char* env_string = getenv("LL_BAD_FMOD_PULSEAUDIO"); - if (NULL == env_string) - { - LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; - if (mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK && - (result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, const_cast<char*>(app_title.c_str()))) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - const char* env_string = getenv("LL_BAD_FMOD_ALSA"); - if (NULL == env_string) - { - LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; - if (mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK && - (result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0)) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "ALSA audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; - return false; - } - - // 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) - { - 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; - default: - LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; - }; -#else // LL_LINUX - - // initialize the FMOD engine - // number of channel in this case looks to be identiacal to number of max simultaneously - // playing objects and we can set practically any number - result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0); - if (Check_FMOD_Error(result, "Error initializing FMOD Studio with default settins, retrying with other format")) - { - result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0/*- ignore*/); - if (Check_FMOD_Error(result, "Error setting sotware format. Can't init.")) - { - return false; - } - result = mSystem->init(LL_MAX_AUDIO_CHANNELS + 2, fmod_flags, 0); - } - if (Check_FMOD_Error(result, "Error initializing FMOD Studio")) - { - // If it fails here and (result == FMOD_ERR_OUTPUT_CREATEBUFFER), - // we can retry with other settings - return false; - } -#endif - - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL; - - int r_numbuffers, r_samplerate, r_channels; - unsigned int r_bufferlength; - char r_name[512]; - int latency = 100; - mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_numbuffers=" << r_numbuffers << LL_ENDL; - - mSystem->getDriverInfo(0, r_name, 511, NULL, &r_samplerate, NULL, &r_channels); - r_name[511] = '\0'; - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_name=\"" << r_name << "\"" << LL_ENDL; - - if (r_samplerate != 0) - latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): latency=" << latency << "ms" << LL_ENDL; - - mInited = true; - - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): initialization complete." << LL_ENDL; - - return true; -} - - -std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose) -{ - llassert_always(mSystem); - if (verbose) - { - U32 version; - if (!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion")) - { - return llformat("FMOD Studio %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); - } - } - return "FMOD STUDIO"; -} - - -// create our favourite FMOD-native streaming audio implementation -LLStreamingAudioInterface *LLAudioEngine_FMODSTUDIO::createDefaultStreamingAudioImpl() const -{ - return new LLStreamingAudio_FMODSTUDIO(mSystem); -} - - -void LLAudioEngine_FMODSTUDIO::allocateListener(void) -{ - mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); - if (!mListenerp) - { - LL_WARNS("FMOD") << "Listener creation failed" << LL_ENDL; - } -} - - -void LLAudioEngine_FMODSTUDIO::shutdown() -{ - stopInternetStream(); - - LL_INFOS("FMOD") << "About to LLAudioEngine::shutdown()" << LL_ENDL; - LLAudioEngine::shutdown(); - - LL_INFOS("FMOD") << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; - if (mSystem) - { - mSystem->close(); - mSystem->release(); - } - LL_INFOS("FMOD") << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL; - - delete mListenerp; - mListenerp = NULL; -} - - -LLAudioBuffer * LLAudioEngine_FMODSTUDIO::createBuffer() -{ - return new LLAudioBufferFMODSTUDIO(mSystem); -} - - -LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel() -{ - return new LLAudioChannelFMODSTUDIO(mSystem); -} - -bool LLAudioEngine_FMODSTUDIO::initWind() -{ - mNextWindUpdate = 0.0; - - if (!mWindDSPDesc) - { - mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); - } - - if (!mWindDSP) - { - memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero - strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); - mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; - mWindDSPDesc->read = &windCallback; // Assign callback - may be called from arbitrary threads - if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP")) - return false; - - if (mWindGen) - delete mWindGen; - - int frequency = 44100; - - FMOD_SPEAKERMODE mode; - if (Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, nullptr), "FMOD::System::getSoftwareFormat")) - { - cleanupWind(); - return false; - } - - mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency); - - if (Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData")) - { - cleanupWind(); - return false; - } - if (Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat")) - { - cleanupWind(); - return false; - } - } - - // *TODO: Should this guard against multiple plays? - if (Check_FMOD_Error(mSystem->playDSP(mWindDSP, nullptr, false, nullptr), "FMOD::System::playDSP")) - { - cleanupWind(); - return false; - } - return true; -} - - -void LLAudioEngine_FMODSTUDIO::cleanupWind() -{ - if (mWindDSP) - { - FMOD::ChannelGroup* master_group = NULL; - if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup") - && master_group) - { - master_group->removeDSP(mWindDSP); - } - mWindDSP->release(); - mWindDSP = NULL; - } - - delete mWindDSPDesc; - mWindDSPDesc = NULL; - - delete mWindGen; - mWindGen = NULL; -} - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODSTUDIO::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) -{ - LLVector3 wind_pos; - F64 pitch; - F64 center_freq; - - if (!mEnableWind) - { - return; - } - - if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) - { - - // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) - // need to convert this to the conventional orientation DS3D and OpenAL use - // where +X = right, +Y = up, +Z = backwards - - wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); - - // cerr << "Wind update" << endl; - - pitch = 1.0 + mapWindVecToPitch(wind_vec); - center_freq = 80.0 * pow(pitch, 2.5*(mapWindVecToGain(wind_vec) + 1.0)); - - mWindGen->mTargetFreq = (F32)center_freq; - mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; - mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); - } -} - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODSTUDIO::setInternalGain(F32 gain) -{ - if (!mInited) - { - return; - } - - gain = llclamp(gain, 0.0f, 1.0f); - - FMOD::ChannelGroup* master_group = NULL; - if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup") - && master_group) - { - master_group->setVolume(gain); - } - - LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); - if (saimpl) - { - // fmod likes its streaming audio channel gain re-asserted after - // master volume change. - saimpl->setGain(saimpl->getGain()); - } -} - -// -// LLAudioChannelFMODSTUDIO implementation -// - -LLAudioChannelFMODSTUDIO::LLAudioChannelFMODSTUDIO(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) -{ -} - - -LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO() -{ - cleanup(); -} - -bool LLAudioChannelFMODSTUDIO::updateBuffer() -{ - if (!mCurrentSourcep) - { - // This channel isn't associated with any source, nothing - // to be updated - return false; - } - - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the channel for a different buffer. - - LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentSourcep->getCurrentBuffer(); - - // Grab the FMOD sample associated with the buffer - FMOD::Sound *soundp = bufferp->getSound(); - if (!soundp) - { - // This is bad, there should ALWAYS be a sound associated with a legit - // buffer. - LL_ERRS() << "No FMOD sound!" << LL_ENDL; - return false; - } - - - // Actually play the sound. Start it off paused so we can do all the necessary - // setup. - if (!mChannelp) - { - FMOD_RESULT result = getSystem()->playSound(soundp, NULL /*free channel?*/, true, &mChannelp); - Check_FMOD_Error(result, "FMOD::System::playSound"); - } - - // Setting up channel mChannelID - } - - // If we have a source for the channel, we need to update its gain. - if (mCurrentSourcep) - { - // SJB: warnings can spam and hurt framerate, disabling - //FMOD_RESULT result; - - mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); - //Check_FMOD_Error(result, "FMOD::Channel::setVolume"); - - mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); - /*if(Check_FMOD_Error(result, "FMOD::Channel::setMode")) - { - S32 index; - mChannelp->getIndex(&index); - LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID() - << " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL; - }*/ - } - - return true; -} - - -void LLAudioChannelFMODSTUDIO::update3DPosition() -{ - if (!mChannelp) - { - // We're not actually a live channel (i.e., we're not playing back anything) - return; - } - - LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentBufferp; - if (!bufferp) - { - // We don't have a buffer associated with us (should really have been picked up - // by the above if. - return; - } - - if (mCurrentSourcep->isForcedPriority()) - { - // Prioritized UI and preview sounds don't need to do any positional updates. - set3DMode(false); - } - else - { - // Localized sound. Update the position and velocity of the sound. - set3DMode(true); - - LLVector3 float_pos; - float_pos.setVec(mCurrentSourcep->getPositionGlobal()); - FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV); - Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes"); - } -} - - -void LLAudioChannelFMODSTUDIO::updateLoop() -{ - if (!mChannelp) - { - // May want to clear up the loop/sample counters. - return; - } - - // - // Hack: We keep track of whether we looped or not by seeing when the - // sample position looks like it's going backwards. Not reliable; may - // yield false negatives. - // - U32 cur_pos; - mChannelp->getPosition(&cur_pos, FMOD_TIMEUNIT_PCMBYTES); - - if (cur_pos < (U32)mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; -} - - -void LLAudioChannelFMODSTUDIO::cleanup() -{ - if (!mChannelp) - { - // Aborting cleanup with no channel handle. - return; - } - - //Cleaning up channel mChannelID - Check_FMOD_Error(mChannelp->stop(), "FMOD::Channel::stop"); - - mCurrentBufferp = NULL; - mChannelp = NULL; -} - - -void LLAudioChannelFMODSTUDIO::play() -{ - if (!mChannelp) - { - LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; - return; - } - - Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause"); - - getSource()->setPlayedOnce(true); - - if (LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]) - mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]); -} - - -void LLAudioChannelFMODSTUDIO::playSynced(LLAudioChannel *channelp) -{ - LLAudioChannelFMODSTUDIO *fmod_channelp = (LLAudioChannelFMODSTUDIO*)channelp; - if (!(fmod_channelp->mChannelp && mChannelp)) - { - // Don't have channels allocated to both the master and the slave - return; - } - - U32 cur_pos; - if (Check_FMOD_Error(mChannelp->getPosition(&cur_pos, FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position")) - return; - - cur_pos %= mCurrentBufferp->getLength(); - - // Try to match the position of our sync master - Check_FMOD_Error(mChannelp->setPosition(cur_pos, FMOD_TIMEUNIT_PCMBYTES), "Unable to set current position"); - - // Start us playing - play(); -} - - -bool LLAudioChannelFMODSTUDIO::isPlaying() -{ - if (!mChannelp) - { - return false; - } - - bool paused, playing; - mChannelp->getPaused(&paused); - mChannelp->isPlaying(&playing); - return !paused && playing; -} - - -// -// LLAudioChannelFMODSTUDIO implementation -// - - -LLAudioBufferFMODSTUDIO::LLAudioBufferFMODSTUDIO(FMOD::System *system) : mSystemp(system), mSoundp(NULL) -{ -} - - -LLAudioBufferFMODSTUDIO::~LLAudioBufferFMODSTUDIO() -{ - if (mSoundp) - { - mSoundp->release(); - mSoundp = NULL; - } -} - - -bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) -{ - // Try to open a wav file from disk. This will eventually go away, as we don't - // really want to block doing this. - if (filename.empty()) - { - // invalid filename, abort. - return false; - } - - if (!gDirUtilp->fileExists(filename)) - { - // File not found, abort. - return false; - } - - if (mSoundp) - { - // If there's already something loaded in this buffer, clean it up. - mSoundp->release(); - mSoundp = NULL; - } - - FMOD_MODE base_mode = FMOD_LOOP_NORMAL; - FMOD_CREATESOUNDEXINFO exinfo; - memset(&exinfo, 0, sizeof(exinfo)); - exinfo.cbsize = sizeof(exinfo); - exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading. - // Load up the wav file into an fmod sample (since 1.05 fmod studio expects everything in UTF-8) - FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); - - if (result != FMOD_OK) - { - // We failed to load the file for some reason. - LL_WARNS() << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << LL_ENDL; - - // - // If we EVER want to load wav files provided by end users, we need - // to rethink this! - // - // file is probably corrupt - remove it. - LLFile::remove(filename); - return false; - } - - // Everything went well, return true - return true; -} - - -U32 LLAudioBufferFMODSTUDIO::getLength() -{ - if (!mSoundp) - { - return 0; - } - - U32 length; - mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES); - return length; -} - - -void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d) -{ - FMOD_MODE current_mode; - if (mChannelp->getMode(¤t_mode) != FMOD_OK) - return; - FMOD_MODE new_mode = current_mode; - new_mode &= ~(use3d ? FMOD_2D : FMOD_3D); - new_mode |= use3d ? FMOD_3D : FMOD_2D; - - if (current_mode != new_mode) - { - mChannelp->setMode(new_mode); - } -} - -// *NOTE: This is almost certainly being called on the mixer thread, -// not the main thread. May have implications for callees or audio -// engine shutdown. - -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) -{ - // inbuffer = fmod's original mixbuffer. - // outbuffer = the buffer passed from the previous DSP unit. - // length = length in samples at this mix time. - - LLWindGen<LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT> *windgen = NULL; - FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; - - thisdsp->getUserData((void **)&windgen); - - if (windgen) - { - windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); - } - - return FMOD_OK; -} diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h deleted file mode 100644 index 29e7bc6bf0..0000000000 --- a/indra/llaudio/llaudioengine_fmodstudio.h +++ /dev/null @@ -1,131 +0,0 @@ -/** - * @file audioengine_fmodstudio.h - * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_AUDIOENGINE_FMODSTUDIO_H -#define LL_AUDIOENGINE_FMODSTUDIO_H - -#include "llaudioengine.h" -#include "llwindgen.h" - -//Stubs -class LLAudioStreamManagerFMODSTUDIO; -namespace FMOD -{ - class System; - class Channel; - class ChannelGroup; - class Sound; - class DSP; -} -typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION; - -//Interfaces -class LLAudioEngine_FMODSTUDIO : public LLAudioEngine -{ -public: - LLAudioEngine_FMODSTUDIO(bool enable_profiler); - virtual ~LLAudioEngine_FMODSTUDIO(); - - // initialization/startup/shutdown - virtual bool init(void *user_data, const std::string &app_title); - virtual std::string getDriverName(bool verbose); - virtual LLStreamingAudioInterface* createDefaultStreamingAudioImpl() const; - virtual void allocateListener(); - - virtual void shutdown(); - - /*virtual*/ bool initWind(); - /*virtual*/ void cleanupWind(); - - /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water); - - typedef F32 MIXBUFFERFORMAT; - - FMOD::System *getSystem() const {return mSystem;} -protected: - /*virtual*/ LLAudioBuffer *createBuffer(); // Get a free buffer, or flush an existing one if you have to. - /*virtual*/ LLAudioChannel *createChannel(); // Create a new audio channel. - - /*virtual*/ void setInternalGain(F32 gain); - - bool mInited; - - LLWindGen<MIXBUFFERFORMAT> *mWindGen; - - FMOD_DSP_DESCRIPTION *mWindDSPDesc; - FMOD::DSP *mWindDSP; - FMOD::System *mSystem; - bool mEnableProfiler; - -public: - static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT]; -}; - - -class LLAudioChannelFMODSTUDIO : public LLAudioChannel -{ -public: - LLAudioChannelFMODSTUDIO(FMOD::System *audioengine); - virtual ~LLAudioChannelFMODSTUDIO(); - -protected: - /*virtual*/ void play(); - /*virtual*/ void playSynced(LLAudioChannel *channelp); - /*virtual*/ void cleanup(); - /*virtual*/ bool isPlaying(); - - /*virtual*/ bool updateBuffer(); - /*virtual*/ void update3DPosition(); - /*virtual*/ void updateLoop(); - - void set3DMode(bool use3d); -protected: - FMOD::System *getSystem() const {return mSystemp;} - FMOD::System *mSystemp; - FMOD::Channel *mChannelp; - S32 mLastSamplePos; -}; - - -class LLAudioBufferFMODSTUDIO : public LLAudioBuffer -{ -public: - LLAudioBufferFMODSTUDIO(FMOD::System *audioengine); - virtual ~LLAudioBufferFMODSTUDIO(); - - /*virtual*/ bool loadWAV(const std::string& filename); - /*virtual*/ U32 getLength(); - friend class LLAudioChannelFMODSTUDIO; -protected: - FMOD::System *getSystem() const {return mSystemp;} - FMOD::System *mSystemp; - FMOD::Sound *getSound() const{ return mSoundp; } - FMOD::Sound *mSoundp; -}; - - -#endif // LL_AUDIOENGINE_FMODSTUDIO_H diff --git a/indra/llaudio/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp deleted file mode 100644 index abd5e345b5..0000000000 --- a/indra/llaudio/lllistener_fmodstudio.cpp +++ /dev/null @@ -1,136 +0,0 @@ -/** - * @file listener_fmodstudio.cpp - * @brief Implementation of LISTENER class abstracting the audio - * support as a FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llaudioengine.h" -#include "lllistener_fmodstudio.h" -#include "fmodstudio/fmod.hpp" - -//----------------------------------------------------------------------- -// constructor -//----------------------------------------------------------------------- -LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system) -{ - mSystem = system; - init(); -} - -//----------------------------------------------------------------------- -LLListener_FMODSTUDIO::~LLListener_FMODSTUDIO() -{ -} - -//----------------------------------------------------------------------- -void LLListener_FMODSTUDIO::init(void) -{ - // do inherited - LLListener::init(); - mDopplerFactor = 1.0f; - mRolloffFactor = 1.0f; -} - -//----------------------------------------------------------------------- -void LLListener_FMODSTUDIO::translate(LLVector3 offset) -{ - LLListener::translate(offset); - - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODSTUDIO::setPosition(LLVector3 pos) -{ - LLListener::setPosition(pos); - - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel) -{ - LLListener::setVelocity(vel); - - mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODSTUDIO::orient(LLVector3 up, LLVector3 at) -{ - LLListener::orient(up, at); - - // at = -at; by default Fmod studio is 'left-handed' but we are providing - // flag FMOD_INIT_3D_RIGHTHANDED so no correction are needed - - mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODSTUDIO::commitDeferredChanges() -{ - if (!mSystem) - { - return; - } - - mSystem->update(); -} - - -void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor) -{ - //An internal FMOD optimization skips 3D updates if there have not been changes to the 3D sound environment. - // (this was true for FMODex, looks to be still true for FMOD STUDIO, but needs a recheck) - //Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well. - //In short: Changing the position ticks a dirtyflag inside fmod, which makes it not skip 3D processing next update call. - if (mRolloffFactor != factor) - { - LLVector3 pos = mPosition - LLVector3(0.f, 0.f, .1f); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); - } - mRolloffFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODSTUDIO::getRolloffFactor() -{ - return mRolloffFactor; -} - - -void LLListener_FMODSTUDIO::setDopplerFactor(F32 factor) -{ - mDopplerFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODSTUDIO::getDopplerFactor() -{ - return mDopplerFactor; -} diff --git a/indra/llaudio/lllistener_fmodstudio.h b/indra/llaudio/lllistener_fmodstudio.h deleted file mode 100644 index 6ad85d9700..0000000000 --- a/indra/llaudio/lllistener_fmodstudio.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file listener_fmodstudio.h - * @brief Description of LISTENER class abstracting the audio support - * as an FMOD 3D implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LISTENER_FMODSTUDIO_H -#define LL_LISTENER_FMODSTUDIO_H - -#include "lllistener.h" - -//Stubs -namespace FMOD -{ - class System; -} - -//Interfaces -class LLListener_FMODSTUDIO : public LLListener -{ -public: - LLListener_FMODSTUDIO(FMOD::System *system); - virtual ~LLListener_FMODSTUDIO(); - virtual void init(); - - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - virtual void commitDeferredChanges(); - - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); -protected: - FMOD::System *mSystem; - F32 mDopplerFactor; - F32 mRolloffFactor; -}; - -#endif - - diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp deleted file mode 100644 index 85577992a6..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodstudio.cpp +++ /dev/null @@ -1,481 +0,0 @@ -/** - * @file streamingaudio_fmodstudio.cpp - * @brief LLStreamingAudio_FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llmath.h" - -#include "fmodstudio/fmod.hpp" -#include "fmodstudio/fmod_errors.h" - -#include "llstreamingaudio_fmodstudio.h" - - -class LLAudioStreamManagerFMODSTUDIO -{ -public: - LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url); - FMOD::Channel* startStream(); - bool stopStream(); // Returns true if the stream was successfully stopped. - bool ready(); - - const std::string& getURL() { return mInternetStreamURL; } - - FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered = NULL, bool* starving = NULL, bool* diskbusy = NULL); -protected: - FMOD::System* mSystem; - FMOD::Channel* mStreamChannel; - FMOD::Sound* mInternetStream; - bool mReady; - - std::string mInternetStreamURL; -}; - - - -//--------------------------------------------------------------------------- -// Internet Streaming -//--------------------------------------------------------------------------- -LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : -mSystem(system), -mCurrentInternetStreamp(NULL), -mFMODInternetStreamChannelp(NULL), -mGain(1.0f), -mRetryCount(0) -{ - // 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 - FMOD_RESULT result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << "setStreamBufferSize error: " << FMOD_ErrorString(result) << LL_ENDL; - } - - // 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); -} - - -LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() -{ - if (mCurrentInternetStreamp) - { - // Isn't supposed to hapen, stream should be clear by now, - // and if it does, we are likely going to crash. - LL_WARNS("FMOD") << "mCurrentInternetStreamp not null on shutdown!" << LL_ENDL; - stop(); - } - - // Kill dead internet streams, if possible - killDeadStreams(); - - if (!mDeadStreams.empty()) - { - // LLStreamingAudio_FMODSTUDIO was inited on startup - // and should be destroyed on shutdown, it should - // wait for streams to die to not cause crashes or - // leaks. - // Ideally we need to wait on some kind of callback - // to release() streams correctly, but 200 ms should - // be enough and we can't wait forever. - LL_INFOS("FMOD") << "Waiting for " << (S32)mDeadStreams.size() << " streams to stop" << LL_ENDL; - for (S32 i = 0; i < 20; i++) - { - const U32 ms_delay = 10; - ms_sleep(ms_delay); // rude, but not many options here - killDeadStreams(); - if (mDeadStreams.empty()) - { - LL_INFOS("FMOD") << "All streams stopped after " << (S32)((i + 1) * ms_delay) << "ms" << LL_ENDL; - break; - } - } - } - - if (!mDeadStreams.empty()) - { - LL_WARNS("FMOD") << "Failed to kill some audio streams" << LL_ENDL; - } -} - -void LLStreamingAudio_FMODSTUDIO::killDeadStreams() -{ - std::list<LLAudioStreamManagerFMODSTUDIO *>::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) - { - LLAudioStreamManagerFMODSTUDIO *streamp = *iter; - if (streamp->stopStream()) - { - LL_INFOS("FMOD") << "Closed dead stream" << LL_ENDL; - delete streamp; - iter = mDeadStreams.erase(iter); - } - else - { - iter++; - } - } -} - -void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) -{ - //if (!mInited) - //{ - // LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL; - // return; - //} - - // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL - stop(); - - if (!url.empty()) - { - LL_INFOS("FMOD") << "Starting internet stream: " << url << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, url); - mURL = url; - } - else - { - LL_INFOS("FMOD") << "Set internet stream to null" << LL_ENDL; - mURL.clear(); - } - - mRetryCount = 0; -} - - -void LLStreamingAudio_FMODSTUDIO::update() -{ - // Kill dead internet streams, if possible - killDeadStreams(); - - // Don't do anything if there are no streams playing - if (!mCurrentInternetStreamp) - { - return; - } - - unsigned int progress; - bool starving; - bool diskbusy; - FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy); - - if (open_state == FMOD_OPENSTATE_READY) - { - // Stream is live - - // start the stream if it's ready - if (!mFMODInternetStreamChannelp && - (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream())) - { - // Reset volume to previously set volume - setGain(getGain()); - mFMODInternetStreamChannelp->setPaused(false); - } - mRetryCount = 0; - } - else if (open_state == FMOD_OPENSTATE_ERROR) - { - LL_INFOS("FMOD") << "State: FMOD_OPENSTATE_ERROR" - << " Progress: " << U32(progress) - << " Starving: " << S32(starving) - << " Diskbusy: " << S32(diskbusy) << LL_ENDL; - if (mRetryCount < 2) - { - // Retry - std::string url = mURL; - stop(); // might drop mURL, drops mCurrentInternetStreamp - - mRetryCount++; - - if (!url.empty()) - { - LL_INFOS("FMOD") << "Restarting internet stream: " << url << ", attempt " << (mRetryCount + 1) << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, url); - mURL = url; - } - } - else - { - stop(); - } - return; - } - - if (mFMODInternetStreamChannelp) - { - FMOD::Sound *sound = NULL; - - if (mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound) - { - FMOD_TAG tag; - S32 tagcount, dirtytagcount; - - if (sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount) - { - for (S32 i = 0; i < tagcount; ++i) - { - if (sound->getTag(NULL, i, &tag) != FMOD_OK) - continue; - - if (tag.type == FMOD_TAGTYPE_FMOD) - { - if (!strcmp(tag.name, "Sample Rate Change")) - { - LL_INFOS("FMOD") << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; - mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); - } - continue; - } - } - } - - if (starving) - { - bool paused = false; - mFMODInternetStreamChannelp->getPaused(&paused); - if (!paused) - { - LL_INFOS("FMOD") << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; - LL_INFOS("FMOD") << " (diskbusy=" << diskbusy << ")" << LL_ENDL; - LL_INFOS("FMOD") << " (progress=" << progress << ")" << LL_ENDL; - mFMODInternetStreamChannelp->setPaused(true); - } - } - else if (progress > 80) - { - mFMODInternetStreamChannelp->setPaused(false); - } - } - } -} - -void LLStreamingAudio_FMODSTUDIO::stop() -{ - if (mFMODInternetStreamChannelp) - { - mFMODInternetStreamChannelp->setPaused(true); - mFMODInternetStreamChannelp->setPriority(0); - mFMODInternetStreamChannelp = NULL; - } - - if (mCurrentInternetStreamp) - { - LL_INFOS("FMOD") << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - if (mCurrentInternetStreamp->stopStream()) - { - delete mCurrentInternetStreamp; - } - else - { - LL_WARNS("FMOD") << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - mDeadStreams.push_back(mCurrentInternetStreamp); - } - mCurrentInternetStreamp = NULL; - //mURL.clear(); - } -} - -void LLStreamingAudio_FMODSTUDIO::pause(int pauseopt) -{ - if (pauseopt < 0) - { - pauseopt = mCurrentInternetStreamp ? 1 : 0; - } - - if (pauseopt) - { - if (mCurrentInternetStreamp) - { - LL_INFOS("FMOD") << "Pausing internet stream" << LL_ENDL; - stop(); - } - } - else - { - start(getURL()); - } -} - - -// A stream is "playing" if it has been requested to start. That -// doesn't necessarily mean audio is coming out of the speakers. -int LLStreamingAudio_FMODSTUDIO::isPlaying() -{ - if (mCurrentInternetStreamp) - { - return 1; // Active and playing - } - else if (!mURL.empty()) - { - return 2; // "Paused" - } - else - { - return 0; - } -} - - -F32 LLStreamingAudio_FMODSTUDIO::getGain() -{ - return mGain; -} - - -std::string LLStreamingAudio_FMODSTUDIO::getURL() -{ - return mURL; -} - - -void LLStreamingAudio_FMODSTUDIO::setGain(F32 vol) -{ - mGain = vol; - - if (mFMODInternetStreamChannelp) - { - vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? - - mFMODInternetStreamChannelp->setVolume(vol); - } -} - -/////////////////////////////////////////////////////// -// manager of possibly-multiple internet audio streams - -LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url) : -mSystem(system), -mStreamChannel(NULL), -mInternetStream(NULL), -mReady(false) -{ - mInternetStreamURL = url; - - FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream); - - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << "Couldn't open fmod stream, error " - << FMOD_ErrorString(result) - << LL_ENDL; - mReady = false; - return; - } - - mReady = true; -} - -FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream() -{ - // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY) - { - LL_WARNS("FMOD") << "No internet stream to start playing!" << LL_ENDL; - return NULL; - } - - if (mStreamChannel) - return mStreamChannel; //Already have a channel for this stream. - - FMOD_RESULT result = mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << FMOD_ErrorString(result) << LL_ENDL; - } - return mStreamChannel; -} - -bool LLAudioStreamManagerFMODSTUDIO::stopStream() -{ - if (mInternetStream) - { - - - bool close = true; - switch (getOpenState()) - { - case FMOD_OPENSTATE_CONNECTING: - close = false; - break; - default: - close = true; - } - - if (close) - { - mInternetStream->release(); - mStreamChannel = NULL; - mInternetStream = NULL; - return true; - } - else - { - return false; - } - } - else - { - return true; - } -} - -FMOD_OPENSTATE LLAudioStreamManagerFMODSTUDIO::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy) -{ - FMOD_OPENSTATE state; - FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << FMOD_ErrorString(result) << LL_ENDL; - } - return state; -} - -void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) -{ - FMOD_RESULT result = mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << "setStreamBufferSize error: " << FMOD_ErrorString(result) << LL_ENDL; - return; - } - FMOD_ADVANCEDSETTINGS settings; - memset(&settings, 0, sizeof(settings)); - settings.cbSize = sizeof(settings); - settings.defaultDecodeBufferSize = decodebuffertime;//ms - result = mSystem->setAdvancedSettings(&settings); - if (result != FMOD_OK) - { - LL_WARNS("FMOD") << "setAdvancedSettings error: " << FMOD_ErrorString(result) << LL_ENDL; - } -} diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h deleted file mode 100644 index 35a7b1226e..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodstudio.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @file streamingaudio_fmodstudio.h - * @brief Definition of LLStreamingAudio_FMODSTUDIO implementation - * - * $LicenseInfo:firstyear=2020&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2020, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_STREAMINGAUDIO_FMODSTUDIO_H -#define LL_STREAMINGAUDIO_FMODSTUDIO_H - -#include "stdtypes.h" // from llcommon - -#include "llstreamingaudio.h" -#include "lltimer.h" - -//Stubs -class LLAudioStreamManagerFMODSTUDIO; -namespace FMOD -{ - class System; - class Channel; -} - -//Interfaces -class LLStreamingAudio_FMODSTUDIO : public LLStreamingAudioInterface -{ -public: - LLStreamingAudio_FMODSTUDIO(FMOD::System *system); - /*virtual*/ ~LLStreamingAudio_FMODSTUDIO(); - - /*virtual*/ void start(const std::string& url); - /*virtual*/ void stop(); - /*virtual*/ void pause(S32 pause); - /*virtual*/ void update(); - /*virtual*/ S32 isPlaying(); - /*virtual*/ void setGain(F32 vol); - /*virtual*/ F32 getGain(); - /*virtual*/ std::string getURL(); - - /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} - /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); -private: - void killDeadStreams(); - - FMOD::System *mSystem; - - LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; - FMOD::Channel *mFMODInternetStreamChannelp; - std::list<LLAudioStreamManagerFMODSTUDIO *> mDeadStreams; - - std::string mURL; - F32 mGain; - S32 mRetryCount; -}; - - -#endif // LL_STREAMINGAUDIO_FMODSTUDIO_H |