From 192aee0f191e6070b91be066b599b8dc3302a5e1 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 31 Jan 2020 15:05:51 +0000 Subject: [PATCH 01/50] Merged in SL-11445 Upgrade Fmodex to Fmod Studio --- autobuild.xml | 78 +++ indra/cmake/CMakeLists.txt | 1 + indra/cmake/Copy3rdPartyLibs.cmake | 16 +- indra/cmake/FMODEX.cmake | 10 +- indra/cmake/FMODSTUDIO.cmake | 38 + indra/llaudio/CMakeLists.txt | 18 + indra/llaudio/llaudioengine_fmodstudio.cpp | 659 ++++++++++++++++++ indra/llaudio/llaudioengine_fmodstudio.h | 130 ++++ indra/llaudio/lllistener_fmodstudio.cpp | 138 ++++ indra/llaudio/lllistener_fmodstudio.h | 65 ++ indra/llaudio/llstreamingaudio_fmodstudio.cpp | 392 +++++++++++ indra/llaudio/llstreamingaudio_fmodstudio.h | 73 ++ indra/newview/CMakeLists.txt | 33 +- indra/newview/llstartup.cpp | 15 +- indra/newview/viewer_manifest.py | 77 +- 15 files changed, 1711 insertions(+), 32 deletions(-) create mode 100644 indra/cmake/FMODSTUDIO.cmake create mode 100644 indra/llaudio/llaudioengine_fmodstudio.cpp create mode 100644 indra/llaudio/llaudioengine_fmodstudio.h create mode 100644 indra/llaudio/lllistener_fmodstudio.cpp create mode 100644 indra/llaudio/lllistener_fmodstudio.h create mode 100644 indra/llaudio/llstreamingaudio_fmodstudio.cpp create mode 100644 indra/llaudio/llstreamingaudio_fmodstudio.h diff --git a/autobuild.xml b/autobuild.xml index 1f1db48bdc..d119746780 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -817,6 +817,84 @@ version 4.44.64.501533 + fmodstudio + + copyright + FMOD Studio by Firelight Technologies Pty Ltd. + description + FMOD Studio API + license + fmod + license_file + LICENSES/fmodstudio.txt + name + fmodstudio + platforms + + darwin64 + + archive + + hash + 5b65500b8992f96d409c79bc9a694ec6 + url + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50234/453770/fmodstudio-2.00.07.535399-darwin64-535399.tar.bz2 + + name + darwin64 + + linux + + archive + + hash + 3dec74f5af59ee8ad44bc6da77582167 + url + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50231/453756/fmodstudio-2.00.07.535399-linux-535399.tar.bz2 + + name + linux + + linux64 + + archive + + hash + 3dec74f5af59ee8ad44bc6da77582167 + url + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50231/453756/fmodstudio-2.00.07.535399-linux-535399.tar.bz2 + + name + linux64 + + windows + + archive + + hash + 6e5855d0703f496ad8d61f9d9c6ae6a9 + url + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50236/453775/fmodstudio-2.00.07.535399-windows-535399.tar.bz2 + + name + windows + + windows64 + + archive + + hash + a1677997916de45b860c20b83103ff3d + url + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50233/453772/fmodstudio-2.00.07.535399-windows64-535399.tar.bz2 + + name + windows64 + + + version + 2.00.07.535399 + fontconfig copyright diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 84e1c5d6fd..6dbf26c4a9 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -40,6 +40,7 @@ set(cmake_SOURCE_FILES FindXmlRpcEpi.cmake FindZLIB.cmake FMODEX.cmake + FMODSTUDIO.cmake FreeType.cmake GLEXT.cmake GLH.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index c73a1fdb47..f7904cc5d7 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -63,7 +63,6 @@ if(WINDOWS) endif (BUGSPLAT_DB) if (FMODEX) - if(ADDRESS_SIZE EQUAL 32) set(release_files ${release_files} fmodex.dll) else(ADDRESS_SIZE EQUAL 32) @@ -71,6 +70,11 @@ if(WINDOWS) endif(ADDRESS_SIZE EQUAL 32) endif (FMODEX) + if (FMODSTUDIO) + set(debug_files ${debug_files} fmodL.dll) + set(release_files ${release_files} fmod.dll) + endif (FMODSTUDIO) + #******************************* # Copy MS C runtime dlls, required for packaging. # *TODO - Adapt this to support VC9 @@ -197,6 +201,11 @@ elseif(DARWIN) set(release_files ${release_files} libfmodex.dylib) endif (FMODEX) + if (FMODSTUDIO) + set(debug_files ${debug_files} libfmodL.dylib) + set(release_files ${release_files} libfmod.dylib) + endif (FMODSTUDIO) + elseif(LINUX) # linux is weird, multiple side by side configurations aren't supported # and we don't seem to have any debug shared libs built yet anyways... @@ -247,6 +256,11 @@ elseif(LINUX) set(release_files ${release_files} "libfmodex.so") endif (FMODEX) + if (FMODSTUDIO) + set(debug_files ${debug_files} "libfmodL.so") + set(release_files ${release_files} "libfmod.so") + endif (FMODSTUDIO) + else(WINDOWS) message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...") set(vivox_lib_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux") diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake index 720933d1b7..25add0c8f2 100644 --- a/indra/cmake/FMODEX.cmake +++ b/indra/cmake/FMODEX.cmake @@ -1,13 +1,9 @@ # -*- cmake -*- -# FMOD can be set when launching the make using the argument -DFMOD:BOOL=ON -# When building using proprietary binaries though (i.e. having access to LL private servers), -# we always build with FMODEX. -# Open source devs should use the -DFMODEX:BOOL=ON then if they want to build with FMOD, whether +# FMODEX can be set when launching the make using the argument -DFMOD:BOOL=ON +# No longer used by default, see FMODSTRUDIO. +# Open source devs should use the -DFMODEX:BOOL=ON then if they want to build with FMODEX, whether # they are using USESYSTEMLIBS or not. -if (INSTALL_PROPRIETARY) - set(FMODEX ON CACHE BOOL "Using FMOD Ex sound library.") -endif (INSTALL_PROPRIETARY) if (FMODEX) if (USESYSTEMLIBS) diff --git a/indra/cmake/FMODSTUDIO.cmake b/indra/cmake/FMODSTUDIO.cmake new file mode 100644 index 0000000000..1539270d6c --- /dev/null +++ b/indra/cmake/FMODSTUDIO.cmake @@ -0,0 +1,38 @@ +# -*- cmake -*- + +# FMODSTUDIO can be set when launching the make using the argument -DFMODSTUDIO:BOOL=ON +# When building using proprietary binaries though (i.e. having access to LL private servers), +# we always build with FMODSTUDIO. +if (INSTALL_PROPRIETARY) + set(FMODSTUDIO ON CACHE BOOL "Using FMODSTUDIO sound library.") +endif (INSTALL_PROPRIETARY) + +if (FMODSTUDIO) + if (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + # If the path have been specified in the arguments, use that + set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + else (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + # If not, we're going to try to get the package listed in autobuild.xml + # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) + # as accessing the private LL location will fail if you don't have the credential + include(Prebuilt) + use_prebuilt_binary(fmodstudio) + if (WINDOWS) + set(FMODSTUDIO_LIBRARY + debug fmodL_vc + optimized fmod_vc) + elseif (DARWIN) + #despite files being called libfmod.dylib, we are searching for fmod + set(FMODSTUDIO_LIBRARY + debug fmodL + optimized fmod) + elseif (LINUX) + set(FMODEX_LIBRARY + debug fmodL + optimized fmod) + endif (WINDOWS) + set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + set(FMODSTUDIO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodstudio) + endif (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) +endif (FMODSTUDIO) + diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index e943dd5d5c..6d7030f548 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -5,6 +5,7 @@ project(llaudio) include(00-Common) include(LLAudio) include(FMODEX) +include(FMODSTUDIO) include(OPENAL) include(LLCommon) include(LLMath) @@ -59,6 +60,23 @@ if (FMODEX) ) endif (FMODEX) +if (FMODSTUDIO) + include_directories( + ${FMODSTUDIO_INCLUDE_DIR} + ) + 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 (FMODSTUDIO) + if (OPENAL) list(APPEND llaudio_SOURCE_FILES llaudioengine_openal.cpp diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp new file mode 100644 index 0000000000..ec66d590b7 --- /dev/null +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -0,0 +1,659 @@ +/** + * @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 = new FMOD_DSP_DESCRIPTION(); +} + + +LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() +{ + delete mWindDSPDesc; +} + + +static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) +{ + if (result == FMOD_OK) + return false; + LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + return true; +} + +bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) +{ + 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(num_channels, userdata); + + 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(num_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"); + + U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE; + if (mEnableProfiler) + { + fmod_flags |= FMOD_INIT_PROFILE_ENABLE; + } + + // 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(num_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; + } + + // 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)); + + 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 "FMODSTUDIO"; +} + + +void LLAudioEngine_FMODSTUDIO::allocateListener(void) +{ + mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); + if (!mListenerp) + { + LL_WARNS() << "Listener creation failed" << LL_ENDL; + } +} + + +void LLAudioEngine_FMODSTUDIO::shutdown() +{ + stopInternetStream(); + + LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; + LLAudioEngine::shutdown(); + + LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; + if (mSystem) + { + mSystem->close(); + mSystem->release(); + } + LL_INFOS() << "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 (!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((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; + mSystem->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 (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->isAmbient()) + { + // Ambient sound, 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 (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) + { + // 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 +#if LL_WINDOWS + FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode, &exinfo, &mSoundp); +#else + FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); +#endif + + 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 *windgen; + 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_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); + + return FMOD_OK; +} diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h new file mode 100644 index 0000000000..69276244da --- /dev/null +++ b/indra/llaudio/llaudioengine_fmodstudio.h @@ -0,0 +1,130 @@ +/** + * @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(const S32 num_channels, void *user_data); + virtual std::string getDriverName(bool verbose); + 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 *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 new file mode 100644 index 0000000000..fd88b981c4 --- /dev/null +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -0,0 +1,138 @@ +/** + * @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); + + // Welcome to the transition between right and left + // (coordinate systems, that is) + // Leaving the at vector alone results in a L/R reversal + // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed + at = -at; + + 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 FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment. + //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 fmodex, which makes it not skip 3D processing next update call. + if (mRolloffFactor != factor) + { + LLVector3 pos = mVelocity - LLVector3(0.f, 0.f, .1f); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.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 new file mode 100644 index 0000000000..6ad85d9700 --- /dev/null +++ b/indra/llaudio/lllistener_fmodstudio.h @@ -0,0 +1,65 @@ +/** + * @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 new file mode 100644 index 0000000000..08d19209aa --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -0,0 +1,392 @@ +/** + * @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) +{ + // 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); +} + + +LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() +{ + // nothing interesting/safe to do. +} + + +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() << "Starting internet stream: " << url << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, url); + mURL = url; + } + else + { + LL_INFOS() << "Set internet stream to null" << LL_ENDL; + mURL.clear(); + } +} + + +void LLStreamingAudio_FMODSTUDIO::update() +{ + // Kill dead internet streams, if possible + std::list::iterator iter; + for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + { + LLAudioStreamManagerFMODSTUDIO *streamp = *iter; + if (streamp->stopStream()) + { + LL_INFOS() << "Closed dead stream" << LL_ENDL; + delete streamp; + mDeadStreams.erase(iter++); + } + else + { + iter++; + } + } + + // 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); + } + } + else if (open_state == FMOD_OPENSTATE_ERROR) + { + 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() << "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() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; + LL_INFOS() << " (diskbusy=" << diskbusy << ")" << LL_ENDL; + LL_INFOS() << " (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() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + if (mCurrentInternetStreamp->stopStream()) + { + delete mCurrentInternetStreamp; + } + else + { + LL_WARNS() << "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) + { + 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() << "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() << "No internet stream to start playing!" << LL_ENDL; + return NULL; + } + + if (mStreamChannel) + return mStreamChannel; //Already have a channel for this stream. + + mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel); + 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; + mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); + return state; +} + +void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) +{ + mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES); + FMOD_ADVANCEDSETTINGS settings; + memset(&settings, 0, sizeof(settings)); + settings.cbSize = sizeof(settings); + settings.defaultDecodeBufferSize = decodebuffertime;//ms + mSystem->setAdvancedSettings(&settings); +} diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h new file mode 100644 index 0000000000..6637b2d155 --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -0,0 +1,73 @@ +/** + * @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: + FMOD::System *mSystem; + + LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; + FMOD::Channel *mFMODInternetStreamChannelp; + std::list mDeadStreams; + + std::string mURL; + F32 mGain; +}; + + +#endif // LL_STREAMINGAUDIO_FMODEX_H diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index cf8f99ed25..22871a9d94 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -19,6 +19,7 @@ include(DirectX) include(DragDrop) include(EXPAT) include(FMODEX) +include(FMODSTUDIO) include(GLOD) include(Hunspell) include(JsonCpp) @@ -67,6 +68,10 @@ if(FMODEX) include_directories(${FMODEX_INCLUDE_DIR}) endif(FMODEX) +if(FMODSTUDIO) + include_directories(${FMODSTUDIO_INCLUDE_DIR}) +endif(FMODSTUDIO) + include_directories( ${DBUSGLIB_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIR} @@ -1711,9 +1716,14 @@ endif (OPENAL) if (FMODEX) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") - set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) + set(FMODEXWRAPPER_LIBRARY ${FMODEX_LIBRARY}) endif (FMODEX) +if (FMODSTUDIO) + set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODSTUDIO") + set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY}) +endif (FMODSTUDIO) + set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES}) @@ -1837,6 +1847,14 @@ if (WINDOWS) ) endif (FMODEX) + if (FMODSTUDIO) + list(APPEND COPY_INPUT_DEPENDENCIES + ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll + ${SHARED_LIB_STAGING_DIR}/Debug/fmodL.dll + ) + endif (FMODSTUDIO) + add_custom_command( OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat COMMAND ${PYTHON_EXECUTABLE} @@ -1846,6 +1864,8 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodex=${FMODEX}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -1907,6 +1927,8 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodex=${FMODEX}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2004,6 +2026,7 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${BOOST_CONTEXT_LIBRARY} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} + ${FMODEXWRAPPER_LIBRARY} # must come after LLAudio ${FMODWRAPPER_LIBRARY} # must come after LLAudio ${GLOD_LIBRARIES} ${OPENGL_LIBRARIES} @@ -2052,6 +2075,8 @@ if (LINUX) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodex=${FMODEX}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2078,6 +2103,8 @@ if (LINUX) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodex=${FMODEX}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2154,6 +2181,8 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodex=${FMODEX}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER} @@ -2188,6 +2217,8 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodex=${FMODEX}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 684d3bd421..137d73fead 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -43,6 +43,10 @@ # include "llaudioengine_fmodex.h" #endif +#ifdef LL_FMODSTUDIO +# include "llaudioengine_fmodstudio.h" +#endif + #ifdef LL_OPENAL #include "llaudioengine_openal.h" #endif @@ -623,7 +627,7 @@ bool idle_startup() delete gAudiop; gAudiop = NULL; -#ifdef LL_FMODEX +#ifdef LL_FMODEX #if !LL_WINDOWS if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) #endif // !LL_WINDOWS @@ -632,6 +636,15 @@ bool idle_startup() } #endif +#ifdef LL_FMODSTUDIO +#if !LL_WINDOWS + if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) +#endif // !LL_WINDOWS + { + gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("FMODExProfilerEnable")); + } +#endif + #ifdef LL_OPENAL #if !LL_WINDOWS if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index a403760670..0140a4b928 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -513,14 +513,20 @@ class WindowsManifest(ViewerManifest): print err.message print "Skipping GLOD library (assumming linked statically)" - # Get fmodex dll, continue if missing - try: + # Get fmodex dll if needed + # Normally only fmodex or fmodstudio are needed, but just in case checkking both. + if self.args['fmodex'] == 'ON': if(self.address_size == 64): self.path("fmodex64.dll") else: self.path("fmodex.dll") - except: - print "Skipping fmodex audio library(assuming other audio engine)" + + # Get fmodstudio dll if needed + if self.args['fmodstudio'] == 'ON': + if(self.args['configuration'].lower() == 'debug'): + self.path("fmodL.dll") + else: + self.path("fmod.dll") # For textures self.path("openjpeg.dll") @@ -1046,17 +1052,31 @@ class DarwinManifest(ViewerManifest): ): self.path2basename(relpkgdir, libfile) - # dylibs that vary based on configuration - if self.args['configuration'].lower() == 'debug': - for libfile in ( - "libfmodexL.dylib", - ): - dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) - else: - for libfile in ( - "libfmodex.dylib", - ): - dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) + # Fmodex dylibs that vary based on configuration + if self.args['fmodex'] == 'ON': + if self.args['configuration'].lower() == 'debug': + for libfile in ( + "libfmodexL.dylib", + ): + dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) + else: + for libfile in ( + "libfmodex.dylib", + ): + dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) + + # Fmod studio dylibs (vary based on configuration) + if self.args['fmodstudio'] == 'ON': + if self.args['configuration'].lower() == 'debug': + for libfile in ( + "libfmodL.dylib", + ): + dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) + else: + for libfile in ( + "libfmod.dylib", + ): + dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) # our apps executable_path = {} @@ -1519,13 +1539,24 @@ class Linux_i686_Manifest(LinuxManifest): print "tcmalloc files not found, skipping" pass - try: - self.path("libfmodex-*.so") - self.path("libfmodex.so") - pass - except: - print "Skipping libfmodex.so - not found" - pass + if self.args['fmodex'] == 'ON': + try: + self.path("libfmodex-*.so") + self.path("libfmodex.so") + pass + except: + print "Skipping libfmodex.so - not found" + pass + + if self.args['fmodstudio'] == 'ON': + try: + self.path("libfmod.so.11.7") + self.path("libfmod.so.11") + self.path("libfmod.so") + pass + except: + print "Skipping libfmod.so - not found" + pass # Vivox runtimes @@ -1555,6 +1586,8 @@ if __name__ == "__main__": extra_arguments = [ dict(name='bugsplat', description="""BugSplat database to which to post crashes, if BugSplat crash reporting is desired""", default=''), + dict(name='fmodex', description="""Indication if fmodex libraries are needed""", default='OFF'), + dict(name='fmodstudio', description="""Indication if fmod studio libraries are needed""", default='OFF'), ] try: main(extra=extra_arguments) From e76f25d25fb96965fcf37a477bbf8c14ef1eccb2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 4 Feb 2020 16:19:20 +0200 Subject: [PATCH 02/50] SL-11445 Couple small fixes --- .gitignore | 1 + indra/cmake/FMODSTUDIO.cmake | 2 +- indra/llaudio/lllistener_fmodstudio.cpp | 5 +++-- indra/llaudio/llstreamingaudio_fmodstudio.h | 2 +- indra/newview/app_settings/settings.xml | 6 +++--- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 27b629a578..2d32e94c78 100755 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ *.bak *.diff *.orig +*.patch *.pyc *.rej *.swp diff --git a/indra/cmake/FMODSTUDIO.cmake b/indra/cmake/FMODSTUDIO.cmake index 1539270d6c..8840354ac6 100644 --- a/indra/cmake/FMODSTUDIO.cmake +++ b/indra/cmake/FMODSTUDIO.cmake @@ -27,7 +27,7 @@ if (FMODSTUDIO) debug fmodL optimized fmod) elseif (LINUX) - set(FMODEX_LIBRARY + set(FMODSTUDIO_LIBRARY debug fmodL optimized fmod) endif (WINDOWS) diff --git a/indra/llaudio/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp index fd88b981c4..34f3d00eae 100644 --- a/indra/llaudio/lllistener_fmodstudio.cpp +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -105,9 +105,10 @@ void LLListener_FMODSTUDIO::commitDeferredChanges() void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor) { - //An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment. + //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) //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 fmodex, which makes it not skip 3D processing next update call. + //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 = mVelocity - LLVector3(0.f, 0.f, .1f); diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h index 6637b2d155..1fc3c54d79 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.h +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -70,4 +70,4 @@ private: }; -#endif // LL_STREAMINGAUDIO_FMODEX_H +#endif // LL_STREAMINGAUDIO_FMODSTUDIO_H diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index da1e87fda4..2907d9f5b3 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16167,7 +16167,7 @@ FMODExProfilerEnable Comment - Enable profiler tool if using FMOD Ex + Enable profiler tool if using FMOD Ex or FMOD Studio Persist 1 Type @@ -16178,7 +16178,7 @@ FMODExDecodeBufferSize Comment - Sets the streaming decode buffer size (in milliseconds) + Sets the streaming decode buffer size (in milliseconds) for FMOD Ex or FMOD Studio Persist 1 Type @@ -16189,7 +16189,7 @@ FMODExStreamBufferSize Comment - Sets the streaming buffer size (in milliseconds) + Sets the streaming buffer size (in milliseconds) for FMOD Ex or FMOD Studio Persist 1 Type From 6627d684a20dbc420de7814066c31a930c0e0e10 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 4 Feb 2020 17:12:19 +0200 Subject: [PATCH 03/50] SL-12654 Remove support for building with fmod ex --- autobuild.xml | 88 --- indra/cmake/CMakeLists.txt | 2 - indra/cmake/Copy3rdPartyLibs.cmake | 18 - indra/cmake/FMODEX.cmake | 42 -- indra/cmake/FindFMODEX.cmake | 65 -- indra/llaudio/CMakeLists.txt | 18 - indra/llaudio/llaudioengine_fmodex.cpp | 767 -------------------- indra/llaudio/llaudioengine_fmodex.h | 130 ---- indra/llaudio/lllistener_fmodex.cpp | 140 ---- indra/llaudio/lllistener_fmodex.h | 65 -- indra/llaudio/llstreamingaudio_fmodex.cpp | 392 ---------- indra/llaudio/llstreamingaudio_fmodex.h | 73 -- indra/newview/CMakeLists.txt | 25 - indra/newview/linux_tools/client-readme.txt | 4 +- indra/newview/linux_tools/wrapper.sh | 2 + indra/newview/llstartup.cpp | 15 +- indra/newview/viewer_manifest.py | 31 - 17 files changed, 5 insertions(+), 1872 deletions(-) delete mode 100644 indra/cmake/FMODEX.cmake delete mode 100644 indra/cmake/FindFMODEX.cmake delete mode 100644 indra/llaudio/llaudioengine_fmodex.cpp delete mode 100644 indra/llaudio/llaudioengine_fmodex.h delete mode 100644 indra/llaudio/lllistener_fmodex.cpp delete mode 100644 indra/llaudio/lllistener_fmodex.h delete mode 100644 indra/llaudio/llstreamingaudio_fmodex.cpp delete mode 100644 indra/llaudio/llstreamingaudio_fmodex.h diff --git a/autobuild.xml b/autobuild.xml index d119746780..a4f39be595 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -729,94 +729,6 @@ version 2.1.1.500375 - fmodex - - copyright - COPYRIGHT 2014 FIRELIGHT TECHNOLOGIES PTY LTD. ALL RIGHTS RESERVED - license - fmodex - license_file - LICENSES/fmodex.txt - name - fmodex - platforms - - darwin - - archive - - hash - ed0d8767652aecd65a7fef3e28645bad - url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/fmodex_3p-update-fmodex/rev/297261/arch/Darwin/installer/fmodex-4.44.31.297261-darwin-297261.tar.bz2 - - name - darwin - - darwin64 - - archive - - hash - 93257fce19120c01751362775a01b925 - url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1545/3481/fmodex-4.44.64.501533-darwin64-501533.tar.bz2 - - name - darwin64 - - linux - - archive - - hash - b847ec838da1ad1dd646df9d74e9b395 - url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/p64_3p-fmodex/rev/314207/arch/Linux/installer/fmodex-4.44.61.314207-linux-314207.tar.bz2 - - name - linux - - linux64 - - archive - - hash - 89a75d8719f7b2cbe1e54cd8407bb992 - url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1544/3476/fmodex-4.44.64.501533-linux64-501533.tar.bz2 - - name - linux64 - - windows - - archive - - hash - 601c2fc41a18812a45678ef9a87ef772 - url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1546/3486/fmodex-4.44.64.501533-windows-501533.tar.bz2 - - name - windows - - windows64 - - archive - - hash - e5cde35ae26ebfa256cfe670986e152e - url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1547/3487/fmodex-4.44.64.501533-windows64-501533.tar.bz2 - - name - windows64 - - - version - 4.44.64.501533 - fmodstudio copyright diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 6dbf26c4a9..3a14bf522f 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -28,7 +28,6 @@ set(cmake_SOURCE_FILES FindAPR.cmake FindAutobuild.cmake FindBerkeleyDB.cmake - FindFMODEX.cmake FindGLH.cmake FindGoogleBreakpad.cmake FindHUNSPELL.cmake @@ -39,7 +38,6 @@ set(cmake_SOURCE_FILES FindURIPARSER.cmake FindXmlRpcEpi.cmake FindZLIB.cmake - FMODEX.cmake FMODSTUDIO.cmake FreeType.cmake GLEXT.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index f7904cc5d7..82cd5d62e8 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -62,14 +62,6 @@ if(WINDOWS) endif(ADDRESS_SIZE EQUAL 32) endif (BUGSPLAT_DB) - if (FMODEX) - if(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} fmodex.dll) - else(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} fmodex64.dll) - endif(ADDRESS_SIZE EQUAL 32) - endif (FMODEX) - if (FMODSTUDIO) set(debug_files ${debug_files} fmodL.dll) set(release_files ${release_files} fmod.dll) @@ -196,11 +188,6 @@ elseif(DARWIN) libnghttp2.14.14.0.dylib ) - if (FMODEX) - set(debug_files ${debug_files} libfmodexL.dylib) - set(release_files ${release_files} libfmodex.dylib) - endif (FMODEX) - if (FMODSTUDIO) set(debug_files ${debug_files} libfmodL.dylib) set(release_files ${release_files} libfmod.dylib) @@ -251,11 +238,6 @@ elseif(LINUX) libfontconfig.so.1 ) - if (FMODEX) - set(debug_files ${debug_files} "libfmodexL.so") - set(release_files ${release_files} "libfmodex.so") - endif (FMODEX) - if (FMODSTUDIO) set(debug_files ${debug_files} "libfmodL.so") set(release_files ${release_files} "libfmod.so") diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake deleted file mode 100644 index 25add0c8f2..0000000000 --- a/indra/cmake/FMODEX.cmake +++ /dev/null @@ -1,42 +0,0 @@ -# -*- cmake -*- - -# FMODEX can be set when launching the make using the argument -DFMOD:BOOL=ON -# No longer used by default, see FMODSTRUDIO. -# Open source devs should use the -DFMODEX:BOOL=ON then if they want to build with FMODEX, whether -# they are using USESYSTEMLIBS or not. - -if (FMODEX) - if (USESYSTEMLIBS) - # In that case, we use the version of the library installed on the system - set(FMODEX_FIND_REQUIRED ON) - include(FindFMODEX) - else (USESYSTEMLIBS) - if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - # If the path have been specified in the arguments, use that - set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - MESSAGE(STATUS "Using FMODEX path: ${FMODEX_LIBRARIES}, ${FMODEX_INCLUDE_DIR}") - else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - # If not, we're going to try to get the package listed in autobuild.xml - # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) - # as accessing the private LL location will fail if you don't have the credential - include(Prebuilt) - use_prebuilt_binary(fmodex) - if (WINDOWS) - set(FMODEX_LIBRARY - debug fmodexL_vc - optimized fmodex_vc) - elseif (DARWIN) - set(FMODEX_LIBRARY - debug fmodexL - optimized fmodex) - elseif (LINUX) - set(FMODEX_LIBRARY - debug fmodexL - optimized fmodex) - endif (WINDOWS) - set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - set(FMODEX_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodex) - endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - endif (USESYSTEMLIBS) -endif (FMODEX) - diff --git a/indra/cmake/FindFMODEX.cmake b/indra/cmake/FindFMODEX.cmake deleted file mode 100644 index b621727c0e..0000000000 --- a/indra/cmake/FindFMODEX.cmake +++ /dev/null @@ -1,65 +0,0 @@ -# -*- cmake -*- - -# - Find FMODEX -# Find the FMODEX includes and library -# This module defines -# FMODEX_INCLUDE_DIR, where to find fmod.h and fmod_errors.h -# FMODEX_LIBRARIES, the libraries needed to use FMODEX. -# FMODEX, If false, do not try to use FMODEX. -# also defined, but not for general use are -# FMODEX_LIBRARY, where to find the FMODEX library. - -FIND_PATH(FMODEX_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod) - -SET(FMODEX_NAMES ${FMODEX_NAMES} fmodex fmodvc fmodexL_vc) -FIND_LIBRARY(FMODEX_LIBRARY - NAMES ${FMODEX_NAMES} - PATH_SUFFIXES fmodex - ) - -IF (FMODEX_SDK_DIR OR WINDOWS) - if(WINDOWS) - set(FMODEX_SDK_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows" CACHE PATH "Path to FMODEX") - STRING(REGEX REPLACE "\\\\" "/" FMODEX_SDK_DIR ${FMODEX_SDK_DIR}) - endif(WINDOWS) - find_library(FMODEX_LIBRARY - fmodex_vc fmodexL_vc - PATHS - ${FMODEX_SDK_DIR}/api/lib - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - find_path(FMODEX_INCLUDE_DIR fmod.h - ${FMODEX_SDK_DIR}/api/inc - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - find_path(FMODEX_INCLUDE_DIR fmod.h - ${FMODEX_SDK_DIR}/api/inc - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - IF (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - SET(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - SET(FMODEX_FOUND "YES") - endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) -ENDIF (FMODEX_SDK_DIR OR WINDOWS) - -IF (FMODEX_FOUND) - IF (NOT FMODEX_FIND_QUIETLY) - MESSAGE(STATUS "Found FMODEX: ${FMODEX_LIBRARIES}") - ENDIF (NOT FMODEX_FIND_QUIETLY) -ELSE (FMODEX_FOUND) - IF (FMODEX_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find FMODEX library") - ENDIF (FMODEX_FIND_REQUIRED) -ENDIF (FMODEX_FOUND) - -# Deprecated declarations. -SET (NATIVE_FMODEX_INCLUDE_PATH ${FMODEX_INCLUDE_DIR} ) -GET_FILENAME_COMPONENT (NATIVE_FMODEX_LIB_PATH ${FMODEX_LIBRARY} PATH) - -MARK_AS_ADVANCED( - FMODEX_LIBRARY - FMODEX_INCLUDE_DIR - ) diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 6d7030f548..8b628a058e 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -4,7 +4,6 @@ project(llaudio) include(00-Common) include(LLAudio) -include(FMODEX) include(FMODSTUDIO) include(OPENAL) include(LLCommon) @@ -43,23 +42,6 @@ set(llaudio_HEADER_FILES llwindgen.h ) -if (FMODEX) - include_directories( - ${FMODEX_INCLUDE_DIR} - ) - list(APPEND llaudio_SOURCE_FILES - llaudioengine_fmodex.cpp - lllistener_fmodex.cpp - llstreamingaudio_fmodex.cpp - ) - - list(APPEND llaudio_HEADER_FILES - llaudioengine_fmodex.h - lllistener_fmodex.h - llstreamingaudio_fmodex.h - ) -endif (FMODEX) - if (FMODSTUDIO) include_directories( ${FMODSTUDIO_INCLUDE_DIR} diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp deleted file mode 100644 index 7e65a05e48..0000000000 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ /dev/null @@ -1,767 +0,0 @@ -/** - * @file audioengine_fmodex.cpp - * @brief Implementation of LLAudioEngine class abstracting the audio - * support as a FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2014, 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_fmodex.h" - -#include "llaudioengine_fmodex.h" -#include "lllistener_fmodex.h" - -#include "llerror.h" -#include "llmath.h" -#include "llrand.h" - -#include "fmod.hpp" -#include "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_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; - -LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler) -{ - mInited = false; - mWindGen = NULL; - mWindDSP = NULL; - mSystem = NULL; - mEnableProfiler = enable_profiler; - mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); -} - - -LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX() -{ - delete mWindDSPDesc; -} - - -inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) -{ - if(result == FMOD_OK) - return false; - LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - return true; -} - -void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - if(type & FMOD_MEMORY_STREAM_DECODE) - { - LL_INFOS() << "Decode buffer size: " << size << LL_ENDL; - } - else if(type & FMOD_MEMORY_STREAM_FILE) - { - LL_INFOS() << "Strean buffer size: " << size << LL_ENDL; - } - return new char[size]; -} -void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - memset(ptr,0,size); - return ptr; -} -void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - delete[] (char*)ptr; -} - -bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) -{ - U32 version; - FMOD_RESULT result; - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL; - - //result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE); - //if(Check_FMOD_Error(result, "FMOD::Memory_Initialize")) - // return false; - - // turn off non-error log spam to fmod.log (TODO: why do we even have an fmod.log if we don't link against log lib?) - FMOD::Debug_SetLevel(FMOD_DEBUG_LEVEL_ERROR); - - result = FMOD::System_Create(&mSystem); - if(Check_FMOD_Error(result, "FMOD::System_Create")) - return false; - - //will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer. - LLAudioEngine::init(num_channels, userdata); - - result = mSystem->getVersion(&version); - Check_FMOD_Error(result, "FMOD::System::getVersion"); - - if (version < FMOD_VERSION) - { - LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Ex version (" << version - << ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL; - } - - result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR); - Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat"); - - // In this case, all sounds, PLUS wind and stream will be software. - result = mSystem->setSoftwareChannels(num_channels + 2); - Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); - - U32 fmod_flags = FMOD_INIT_NORMAL; - 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 - bool audio_ok = false; - - if (!audio_ok) - { - 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 && - (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == 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) - { - 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 && - (result = mSystem->init(num_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) - { - 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 && - (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "OSS audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "OSS 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; - 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 - result = mSystem->init( num_channels + 2, fmod_flags, 0); - if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) - { - /* - Ok, the speaker mode selected isn't supported by this soundcard. Switch it - back to stereo... - */ - result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO); - Check_FMOD_Error(result,"Error falling back to stereo mode"); - /* - ... and re-init. - */ - result = mSystem->init( num_channels + 2, fmod_flags, 0); - } - if(Check_FMOD_Error(result, "Error initializing FMOD Ex")) - return false; -#endif - - // 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)); - - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD Ex initialized correctly" << LL_ENDL; - - int r_numbuffers, r_samplerate, r_channels, r_bits; - unsigned int r_bufferlength; - mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_numbuffers=" << r_numbuffers << LL_ENDL; - - mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_channels=" << r_channels << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bits =" << r_bits << LL_ENDL; - - char r_name[512]; - mSystem->getDriverInfo(0, r_name, 511, 0); - r_name[511] = '\0'; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_name=\"" << r_name << "\"" << LL_ENDL; - - int latency = 100; // optimistic default - i suspect if sample rate is 0, everything breaks. - if ( r_samplerate != 0 ) - latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): latency=" << latency << "ms" << LL_ENDL; - - mInited = true; - - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): initialization complete." << LL_ENDL; - - return true; -} - - -std::string LLAudioEngine_FMODEX::getDriverName(bool verbose) -{ - llassert_always(mSystem); - if (verbose) - { - U32 version; - if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion")) - { - return llformat("FMOD Ex %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); - } - } - return "FMODEx"; -} - - -void LLAudioEngine_FMODEX::allocateListener(void) -{ - mListenerp = (LLListener *) new LLListener_FMODEX(mSystem); - if (!mListenerp) - { - LL_WARNS() << "Listener creation failed" << LL_ENDL; - } -} - - -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(); - mSystem->release(); - } - LL_INFOS() << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << LL_ENDL; - - delete mListenerp; - mListenerp = NULL; -} - - -LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer() -{ - return new LLAudioBufferFMODEX(mSystem); -} - - -LLAudioChannel * LLAudioEngine_FMODEX::createChannel() -{ - return new LLAudioChannelFMODEX(mSystem); -} - -bool LLAudioEngine_FMODEX::initWind() -{ - mNextWindUpdate = 0.0; - - if (!mWindDSP) - { - memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero - strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); - mWindDSPDesc->channels = 2; - 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; - - float frequency = 44100; - mWindDSP->getDefaults(&frequency,0,0,0); - mWindGen = new LLWindGen((U32)frequency); - mWindDSP->setUserData((void*)mWindGen); - } - - // *TODO: Should this guard against multiple plays? - if (mWindDSP) - { - mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0); - return true; - } - return false; -} - - -void LLAudioEngine_FMODEX::cleanupWind() -{ - if (mWindDSP) - { - mWindDSP->remove(); - mWindDSP->release(); - mWindDSP = NULL; - } - - delete mWindGen; - mWindGen = NULL; -} - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODEX::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_FMODEX::setInternalGain(F32 gain) -{ - if (!mInited) - { - return; - } - - gain = llclamp( gain, 0.0f, 1.0f ); - - FMOD::ChannelGroup *master_group; - mSystem->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()); - } -} - -// -// LLAudioChannelFMODEX implementation -// - -LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) -{ -} - - -LLAudioChannelFMODEX::~LLAudioChannelFMODEX() -{ - cleanup(); -} - -bool LLAudioChannelFMODEX::updateBuffer() -{ - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the channel for a different buffer. - - LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)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(FMOD_CHANNEL_FREE, soundp, true, &mChannelp); - Check_FMOD_Error(result, "FMOD::System::playSound"); - } - - //LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL; - } - - // 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 LLAudioChannelFMODEX::update3DPosition() -{ - if (!mChannelp) - { - // We're not actually a live channel (i.e., we're not playing back anything) - return; - } - - LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)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->isAmbient()) - { - // Ambient sound, 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 LLAudioChannelFMODEX::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 LLAudioChannelFMODEX::cleanup() -{ - if (!mChannelp) - { - //LL_INFOS() << "Aborting cleanup with no channel handle." << LL_ENDL; - return; - } - - //LL_INFOS() << "Cleaning up channel: " << mChannelID << LL_ENDL; - Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"); - - mCurrentBufferp = NULL; - mChannelp = NULL; -} - - -void LLAudioChannelFMODEX::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_FMODEX::mChannelGroups[getSource()->getType()]) - mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]); -} - - -void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp) -{ - LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)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 LLAudioChannelFMODEX::isPlaying() -{ - if (!mChannelp) - { - return false; - } - - bool paused, playing; - mChannelp->getPaused(&paused); - mChannelp->isPlaying(&playing); - return !paused && playing; -} - - -// -// LLAudioChannelFMODEX implementation -// - - -LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystemp(system), mSoundp(NULL) -{ -} - - -LLAudioBufferFMODEX::~LLAudioBufferFMODEX() -{ - if(mSoundp) - { - mSoundp->release(); - mSoundp = NULL; - } -} - - -bool LLAudioBufferFMODEX::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 (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) - { - // 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_SOFTWARE; - 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 -#if LL_WINDOWS - FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp); -#else - FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); -#endif - - 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 LLAudioBufferFMODEX::getLength() -{ - if (!mSoundp) - { - return 0; - } - - U32 length; - mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES); - return length; -} - - -void LLAudioChannelFMODEX::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 *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels) -{ - // originalbuffer = fmod's original mixbuffer. - // newbuffer = the buffer passed from the previous DSP unit. - // length = length in samples at this mix time. - // userdata = user parameter passed through in FSOUND_DSP_Create. - - LLWindGen *windgen; - 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); - - return FMOD_OK; -} diff --git a/indra/llaudio/llaudioengine_fmodex.h b/indra/llaudio/llaudioengine_fmodex.h deleted file mode 100644 index ca389d489f..0000000000 --- a/indra/llaudio/llaudioengine_fmodex.h +++ /dev/null @@ -1,130 +0,0 @@ -/** - * @file audioengine_fmodex.h - * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2014, 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_FMODEX_H -#define LL_AUDIOENGINE_FMODEX_H - -#include "llaudioengine.h" -#include "llwindgen.h" - -//Stubs -class LLAudioStreamManagerFMODEX; -namespace FMOD -{ - class System; - class Channel; - class ChannelGroup; - class Sound; - class DSP; -} -typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION; - -//Interfaces -class LLAudioEngine_FMODEX : public LLAudioEngine -{ -public: - LLAudioEngine_FMODEX(bool enable_profiler); - virtual ~LLAudioEngine_FMODEX(); - - // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); - 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 *mWindGen; - - FMOD_DSP_DESCRIPTION *mWindDSPDesc; - FMOD::DSP *mWindDSP; - FMOD::System *mSystem; - bool mEnableProfiler; - -public: - static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT]; -}; - - -class LLAudioChannelFMODEX : public LLAudioChannel -{ -public: - LLAudioChannelFMODEX(FMOD::System *audioengine); - virtual ~LLAudioChannelFMODEX(); - -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 LLAudioBufferFMODEX : public LLAudioBuffer -{ -public: - LLAudioBufferFMODEX(FMOD::System *audioengine); - virtual ~LLAudioBufferFMODEX(); - - /*virtual*/ bool loadWAV(const std::string& filename); - /*virtual*/ U32 getLength(); - friend class LLAudioChannelFMODEX; -protected: - FMOD::System *getSystem() const {return mSystemp;} - FMOD::System *mSystemp; - FMOD::Sound *getSound() const{ return mSoundp; } - FMOD::Sound *mSoundp; -}; - - -#endif // LL_AUDIOENGINE_FMODEX_H diff --git a/indra/llaudio/lllistener_fmodex.cpp b/indra/llaudio/lllistener_fmodex.cpp deleted file mode 100644 index 31ab47a635..0000000000 --- a/indra/llaudio/lllistener_fmodex.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @file listener_fmodex.cpp - * @brief Implementation of LISTENER class abstracting the audio - * support as a FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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_fmodex.h" -#include "fmod.hpp" - -//----------------------------------------------------------------------- -// constructor -//----------------------------------------------------------------------- -LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system) -{ - mSystem = system; - init(); -} - -//----------------------------------------------------------------------- -LLListener_FMODEX::~LLListener_FMODEX() -{ -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::init(void) -{ - // do inherited - LLListener::init(); - mDopplerFactor = 1.0f; - mRolloffFactor = 1.0f; -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::translate(LLVector3 offset) -{ - LLListener::translate(offset); - - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::setPosition(LLVector3 pos) -{ - LLListener::setPosition(pos); - - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::setVelocity(LLVector3 vel) -{ - LLListener::setVelocity(vel); - - mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at) -{ - LLListener::orient(up, at); - - // Welcome to the transition between right and left - // (coordinate systems, that is) - // Leaving the at vector alone results in a L/R reversal - // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed - at = -at; - - mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::commitDeferredChanges() -{ - if(!mSystem) - { - return; - } - - mSystem->update(); -} - - -void LLListener_FMODEX::setRolloffFactor(F32 factor) -{ - //An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment. - //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 fmodex, which makes it not skip 3D processing next update call. - if(mRolloffFactor != factor) - { - LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL); - } - mRolloffFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODEX::getRolloffFactor() -{ - return mRolloffFactor; -} - - -void LLListener_FMODEX::setDopplerFactor(F32 factor) -{ - mDopplerFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODEX::getDopplerFactor() -{ - return mDopplerFactor; -} - - diff --git a/indra/llaudio/lllistener_fmodex.h b/indra/llaudio/lllistener_fmodex.h deleted file mode 100644 index 073b65d53a..0000000000 --- a/indra/llaudio/lllistener_fmodex.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file listener_fmodex.h - * @brief Description of LISTENER class abstracting the audio support - * as an FMOD 3D implementation (windows and Linux) - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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_FMODEX_H -#define LL_LISTENER_FMODEX_H - -#include "lllistener.h" - -//Stubs -namespace FMOD -{ - class System; -} - -//Interfaces -class LLListener_FMODEX : public LLListener -{ - public: - LLListener_FMODEX(FMOD::System *system); - virtual ~LLListener_FMODEX(); - 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_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp deleted file mode 100644 index 9c9e85c00c..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/** - * @file streamingaudio_fmodex.cpp - * @brief LLStreamingAudio_FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 "fmod.hpp" -#include "fmod_errors.h" - -#include "llstreamingaudio_fmodex.h" - - -class LLAudioStreamManagerFMODEX -{ -public: - LLAudioStreamManagerFMODEX(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_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) : - mSystem(system), - mCurrentInternetStreamp(NULL), - mFMODInternetStreamChannelp(NULL), - mGain(1.0f) -{ - // 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); -} - - -LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX() -{ - // nothing interesting/safe to do. -} - - -void LLStreamingAudio_FMODEX::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() << "Starting internet stream: " << url << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url); - mURL = url; - } - else - { - LL_INFOS() << "Set internet stream to null" << LL_ENDL; - mURL.clear(); - } -} - - -void LLStreamingAudio_FMODEX::update() -{ - // 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++; - } - } - - // 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); - } - } - else if(open_state == FMOD_OPENSTATE_ERROR) - { - 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() << "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() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; - LL_INFOS() << " (diskbusy="<setPaused(true); - } - } - else if(progress > 80) - { - mFMODInternetStreamChannelp->setPaused(false); - } - } - } -} - -void LLStreamingAudio_FMODEX::stop() -{ - if (mFMODInternetStreamChannelp) - { - mFMODInternetStreamChannelp->setPaused(true); - mFMODInternetStreamChannelp->setPriority(0); - mFMODInternetStreamChannelp = NULL; - } - - if (mCurrentInternetStreamp) - { - LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - if (mCurrentInternetStreamp->stopStream()) - { - delete mCurrentInternetStreamp; - } - else - { - LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - mDeadStreams.push_back(mCurrentInternetStreamp); - } - mCurrentInternetStreamp = NULL; - //mURL.clear(); - } -} - -void LLStreamingAudio_FMODEX::pause(int pauseopt) -{ - if (pauseopt < 0) - { - pauseopt = mCurrentInternetStreamp ? 1 : 0; - } - - if (pauseopt) - { - if (mCurrentInternetStreamp) - { - 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_FMODEX::isPlaying() -{ - if (mCurrentInternetStreamp) - { - return 1; // Active and playing - } - else if (!mURL.empty()) - { - return 2; // "Paused" - } - else - { - return 0; - } -} - - -F32 LLStreamingAudio_FMODEX::getGain() -{ - return mGain; -} - - -std::string LLStreamingAudio_FMODEX::getURL() -{ - return mURL; -} - - -void LLStreamingAudio_FMODEX::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 - -LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(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() << "Couldn't open fmod stream, error " - << FMOD_ErrorString(result) - << LL_ENDL; - mReady = false; - return; - } - - mReady = true; -} - -FMOD::Channel *LLAudioStreamManagerFMODEX::startStream() -{ - // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY) - { - LL_WARNS() << "No internet stream to start playing!" << LL_ENDL; - return NULL; - } - - if(mStreamChannel) - return mStreamChannel; //Already have a channel for this stream. - - mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel); - return mStreamChannel; -} - -bool LLAudioStreamManagerFMODEX::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 LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy) -{ - FMOD_OPENSTATE state; - mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); - return state; -} - -void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) -{ - mSystem->setStreamBufferSize(streambuffertime/1000*128*128, FMOD_TIMEUNIT_RAWBYTES); - FMOD_ADVANCEDSETTINGS settings; - memset(&settings,0,sizeof(settings)); - settings.cbsize=sizeof(settings); - settings.defaultDecodeBufferSize = decodebuffertime;//ms - mSystem->setAdvancedSettings(&settings); -} diff --git a/indra/llaudio/llstreamingaudio_fmodex.h b/indra/llaudio/llstreamingaudio_fmodex.h deleted file mode 100644 index 2787840ba1..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file streamingaudio_fmodex.h - * @brief Definition of LLStreamingAudio_FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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_FMODEX_H -#define LL_STREAMINGAUDIO_FMODEX_H - -#include "stdtypes.h" // from llcommon - -#include "llstreamingaudio.h" -#include "lltimer.h" - -//Stubs -class LLAudioStreamManagerFMODEX; -namespace FMOD -{ - class System; - class Channel; -} - -//Interfaces -class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface -{ - public: - LLStreamingAudio_FMODEX(FMOD::System *system); - /*virtual*/ ~LLStreamingAudio_FMODEX(); - - /*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: - FMOD::System *mSystem; - - LLAudioStreamManagerFMODEX *mCurrentInternetStreamp; - FMOD::Channel *mFMODInternetStreamChannelp; - std::list mDeadStreams; - - std::string mURL; - F32 mGain; -}; - - -#endif // LL_STREAMINGAUDIO_FMODEX_H diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 22871a9d94..f8ed19f884 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -18,7 +18,6 @@ include(DBusGlib) include(DirectX) include(DragDrop) include(EXPAT) -include(FMODEX) include(FMODSTUDIO) include(GLOD) include(Hunspell) @@ -64,10 +63,6 @@ if (NOT HAVOK_TPV) add_subdirectory(${LLPHYSICSEXTENSIONS_SRC_DIR} llphysicsextensions) endif (NOT HAVOK_TPV) -if(FMODEX) - include_directories(${FMODEX_INCLUDE_DIR}) -endif(FMODEX) - if(FMODSTUDIO) include_directories(${FMODSTUDIO_INCLUDE_DIR}) endif(FMODSTUDIO) @@ -1714,11 +1709,6 @@ if (OPENAL) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL") endif (OPENAL) -if (FMODEX) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") - set(FMODEXWRAPPER_LIBRARY ${FMODEX_LIBRARY}) -endif (FMODEX) - if (FMODSTUDIO) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODSTUDIO") set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY}) @@ -1839,14 +1829,6 @@ if (WINDOWS) ) endif (ADDRESS_SIZE EQUAL 64) - if (FMODEX) - list(APPEND COPY_INPUT_DEPENDENCIES - ${SHARED_LIB_STAGING_DIR}/Release/fmodex.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmodex.dll - ${SHARED_LIB_STAGING_DIR}/Debug/fmodexL.dll - ) - endif (FMODEX) - if (FMODSTUDIO) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll @@ -1864,7 +1846,6 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" - "--fmodex=${FMODEX}" "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} @@ -1927,7 +1908,6 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" - "--fmodex=${FMODEX}" "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} @@ -2026,7 +2006,6 @@ target_link_libraries(${VIEWER_BINARY_NAME} ${BOOST_CONTEXT_LIBRARY} ${DBUSGLIB_LIBRARIES} ${OPENGL_LIBRARIES} - ${FMODEXWRAPPER_LIBRARY} # must come after LLAudio ${FMODWRAPPER_LIBRARY} # must come after LLAudio ${GLOD_LIBRARIES} ${OPENGL_LIBRARIES} @@ -2075,7 +2054,6 @@ if (LINUX) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" - "--fmodex=${FMODEX}" "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} @@ -2103,7 +2081,6 @@ if (LINUX) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" - "--fmodex=${FMODEX}" "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} @@ -2181,7 +2158,6 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" - "--fmodex=${FMODEX}" "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} @@ -2217,7 +2193,6 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" - "--fmodex=${FMODEX}" "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt index e01b9e4bc6..aaa8a6b6d7 100644 --- a/indra/newview/linux_tools/client-readme.txt +++ b/indra/newview/linux_tools/client-readme.txt @@ -187,8 +187,8 @@ The 'secondlife' script which launches Second Life contains some configuration options for advanced troubleshooters. * AUDIO - Edit the 'secondlife' script and you will see these audio - options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMOD_ESD, LL_BAD_FMOD_OSS, and - LL_BAD_FMOD_ALSA. Second Life tries to use OpenAL, ESD, OSS, then ALSA + options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMODSTUDIO_DRIVER. + Second Life tries to use OpenAL, FMODSTUDIO audio drivers in this order; you may uncomment the corresponding LL_BAD_* option to skip an audio driver which you believe may be causing you trouble. diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index c23401d5a6..e04090297c 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -4,6 +4,8 @@ ## These options are for self-assisted troubleshooting during this beta ## testing phase; you should not usually need to touch them. +## - Avoids using any FMOD STUDIO audio driver. +#export LL_BAD_FMODSTUDIO_DRIVER=x ## - Avoids using any FMOD Ex audio driver. #export LL_BAD_FMODEX_DRIVER=x ## - Avoids using any OpenAL audio driver. diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 137d73fead..f5276b47ea 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -39,10 +39,6 @@ #include "llviewermedia_streamingaudio.h" #include "llaudioengine.h" -#ifdef LL_FMODEX -# include "llaudioengine_fmodex.h" -#endif - #ifdef LL_FMODSTUDIO # include "llaudioengine_fmodstudio.h" #endif @@ -627,18 +623,9 @@ bool idle_startup() delete gAudiop; gAudiop = NULL; -#ifdef LL_FMODEX -#if !LL_WINDOWS - if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) -#endif // !LL_WINDOWS - { - gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODExProfilerEnable")); - } -#endif - #ifdef LL_FMODSTUDIO #if !LL_WINDOWS - if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) + if (NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER")) #endif // !LL_WINDOWS { gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("FMODExProfilerEnable")); diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index 0140a4b928..572c84c396 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -513,14 +513,6 @@ class WindowsManifest(ViewerManifest): print err.message print "Skipping GLOD library (assumming linked statically)" - # Get fmodex dll if needed - # Normally only fmodex or fmodstudio are needed, but just in case checkking both. - if self.args['fmodex'] == 'ON': - if(self.address_size == 64): - self.path("fmodex64.dll") - else: - self.path("fmodex.dll") - # Get fmodstudio dll if needed if self.args['fmodstudio'] == 'ON': if(self.args['configuration'].lower() == 'debug'): @@ -1052,19 +1044,6 @@ class DarwinManifest(ViewerManifest): ): self.path2basename(relpkgdir, libfile) - # Fmodex dylibs that vary based on configuration - if self.args['fmodex'] == 'ON': - if self.args['configuration'].lower() == 'debug': - for libfile in ( - "libfmodexL.dylib", - ): - dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) - else: - for libfile in ( - "libfmodex.dylib", - ): - dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) - # Fmod studio dylibs (vary based on configuration) if self.args['fmodstudio'] == 'ON': if self.args['configuration'].lower() == 'debug': @@ -1539,15 +1518,6 @@ class Linux_i686_Manifest(LinuxManifest): print "tcmalloc files not found, skipping" pass - if self.args['fmodex'] == 'ON': - try: - self.path("libfmodex-*.so") - self.path("libfmodex.so") - pass - except: - print "Skipping libfmodex.so - not found" - pass - if self.args['fmodstudio'] == 'ON': try: self.path("libfmod.so.11.7") @@ -1586,7 +1556,6 @@ if __name__ == "__main__": extra_arguments = [ dict(name='bugsplat', description="""BugSplat database to which to post crashes, if BugSplat crash reporting is desired""", default=''), - dict(name='fmodex', description="""Indication if fmodex libraries are needed""", default='OFF'), dict(name='fmodstudio', description="""Indication if fmod studio libraries are needed""", default='OFF'), ] try: From 9a6dcc011c54f65e5da3c3b92074386946d8f291 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 5 Feb 2020 00:58:37 +0200 Subject: [PATCH 04/50] SL-11455 Added linux pulseaudio and alsa support --- indra/llaudio/llaudioengine_fmodstudio.cpp | 71 +++++++++++++++++++++ indra/newview/linux_tools/client-readme.txt | 2 +- indra/newview/linux_tools/wrapper.sh | 8 +-- 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index ec66d590b7..1dd9b830a6 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -114,6 +114,76 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) 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(num_channels + 2, fmod_flags, 0)) == 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(num_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 @@ -124,6 +194,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) // we can retry with other settings return false; } +#endif // set up our favourite FMOD-native streaming audio implementation if none has already been added if (!getStreamingAudioImpl()) // no existing implementation added diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt index aaa8a6b6d7..cb8d1af535 100644 --- a/indra/newview/linux_tools/client-readme.txt +++ b/indra/newview/linux_tools/client-readme.txt @@ -188,7 +188,7 @@ configuration options for advanced troubleshooters. * AUDIO - Edit the 'secondlife' script and you will see these audio options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMODSTUDIO_DRIVER. - Second Life tries to use OpenAL, FMODSTUDIO + Second Life tries to use OpenAL, FMODSTUDIO (PULSEAUDIO, ALSA) audio drivers in this order; you may uncomment the corresponding LL_BAD_* option to skip an audio driver which you believe may be causing you trouble. diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index e04090297c..eb3ead433b 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -6,17 +6,13 @@ ## - Avoids using any FMOD STUDIO audio driver. #export LL_BAD_FMODSTUDIO_DRIVER=x -## - Avoids using any FMOD Ex audio driver. -#export LL_BAD_FMODEX_DRIVER=x ## - Avoids using any OpenAL audio driver. #export LL_BAD_OPENAL_DRIVER=x -## - Avoids using the FMOD Ex PulseAudio audio driver. +## - Avoids using the FMOD Studio or FMOD Ex PulseAudio audio driver. #export LL_BAD_FMOD_PULSEAUDIO=x -## - Avoids using the FMOD or FMOD Ex ALSA audio driver. +## - Avoids using the FMOD Studio or FMOD Ex ALSA audio driver. #export LL_BAD_FMOD_ALSA=x -## - Avoids using the FMOD or FMOD Ex OSS audio driver. -#export LL_BAD_FMOD_OSS=x ## - Avoids the optional OpenGL extensions which have proven most problematic ## on some hardware. Disabling this option may cause BETTER PERFORMANCE but From f5ec281b1b578dfee17353ecf6d469a29de86d25 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 19 Mar 2020 15:47:49 +0200 Subject: [PATCH 05/50] SL-11445 Fix crash caused by wind cleanup --- indra/llaudio/llaudioengine_fmodstudio.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 1dd9b830a6..15bf8926c1 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -55,7 +55,7 @@ LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler) mWindDSP = NULL; mSystem = NULL; mEnableProfiler = enable_profiler; - mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); + mWindDSPDesc = NULL; } @@ -286,6 +286,11 @@ 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 From 6b203f2ee4bbaf893b7256e35581403b18de68f3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 19 Mar 2020 21:39:05 +0200 Subject: [PATCH 06/50] SL-12607 FMOD Logo --- autobuild.xml | 22 +++++++------- indra/llcommon/indra_constants.cpp | 2 ++ indra/llcommon/indra_constants.h | 2 ++ indra/newview/llprogressview.cpp | 14 +++++++++ indra/newview/llprogressview.h | 3 ++ indra/newview/llstartup.cpp | 1 + indra/newview/llviewertexturelist.cpp | 29 +++++++++++++++++++ indra/newview/llviewerwindow.cpp | 4 +++ indra/newview/llviewerwindow.h | 1 + .../skins/default/xui/en/panel_progress.xml | 22 ++++++++++++++ indra/newview/viewer_manifest.py | 15 ++++++++++ 11 files changed, 104 insertions(+), 11 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index a4f39be595..51259486ab 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -748,9 +748,9 @@ archive hash - 5b65500b8992f96d409c79bc9a694ec6 + 2bdcd463bb0e5f610f9af0c073f58066 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50234/453770/fmodstudio-2.00.07.535399-darwin64-535399.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54587/506858/fmodstudio-2.00.07.538806-darwin64-538806.tar.bz2 name darwin64 @@ -760,9 +760,9 @@ archive hash - 3dec74f5af59ee8ad44bc6da77582167 + ae75cdb1cc9da824c9e270bf97bfdd6c url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50231/453756/fmodstudio-2.00.07.535399-linux-535399.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54589/506866/fmodstudio-2.00.07.538806-linux64-538806.tar.bz2 name linux @@ -772,9 +772,9 @@ archive hash - 3dec74f5af59ee8ad44bc6da77582167 + ae75cdb1cc9da824c9e270bf97bfdd6c url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50231/453756/fmodstudio-2.00.07.535399-linux-535399.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54589/506866/fmodstudio-2.00.07.538806-linux64-538806.tar.bz2 name linux64 @@ -784,9 +784,9 @@ archive hash - 6e5855d0703f496ad8d61f9d9c6ae6a9 + 5bc07fe561bf8fdf9060c60e247564a9 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50236/453775/fmodstudio-2.00.07.535399-windows-535399.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54591/506881/fmodstudio-2.00.07.538806-windows-538806.tar.bz2 name windows @@ -796,16 +796,16 @@ archive hash - a1677997916de45b860c20b83103ff3d + 90cd0547c8cf6957a9d1083c83ee4a8e url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/50233/453772/fmodstudio-2.00.07.535399-windows64-535399.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54590/506880/fmodstudio-2.00.07.538806-windows64-538806.tar.bz2 name windows64 version - 2.00.07.535399 + 2.00.07.538806 fontconfig diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index e13176e8fa..53f98adbbf 100644 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -84,3 +84,5 @@ const LLUUID IMG_USE_BAKED_AUX1 ("9742065b-19b5-297c-858a-29711d539043"); const LLUUID IMG_USE_BAKED_AUX2 ("03642e83-2bd1-4eb9-34b4-4c47ed586d2d"); const LLUUID IMG_USE_BAKED_AUX3 ("edd51b77-fc10-ce7a-4b3d-011dfc349e4f"); +const LLUUID IMG_LOGO_FMOD("876982f5-f5fd-4a68-b5e7-727f3ae3487b"); + diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 0fbf4b966b..7d20286ac9 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -218,6 +218,8 @@ LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX1; LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX2; LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX3; +LL_COMMON_API extern const LLUUID IMG_LOGO_FMOD; + LL_COMMON_API extern const LLUUID DEFAULT_WATER_NORMAL; diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index 083a913ef8..dfa6c97b26 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -42,6 +42,7 @@ #include "llbutton.h" #include "llcallbacklist.h" #include "llfocusmgr.h" +#include "lliconctrl.h" #include "llnotifications.h" #include "llprogressbar.h" #include "llstartup.h" @@ -183,6 +184,7 @@ void LLProgressView::setVisible(BOOL visible) if (getVisible() && !visible) { LLPanel::setVisible(FALSE); + setShowLogos(FALSE); } // showing progress view else if (visible && (!getVisible() || mFadeToWorldTimer.getStarted())) @@ -309,6 +311,18 @@ void LLProgressView::setMessage(const std::string& msg) getChild("message_text")->setValue(mMessage); } +void LLProgressView::setShowLogos(const BOOL logos_visible) +{ + LLIconCtrl* logo = getChild("fmod_logo"); + if (logos_visible) + { + logo->setValue(IMG_LOGO_FMOD); + } + logo->setVisible(logos_visible); + getChild("fmod_text")->setVisible(logos_visible); + getChild("message_text")->setVisible(!logos_visible); +} + void LLProgressView::setCancelButtonVisible(BOOL b, const std::string& label) { mCancelBtn->setVisible( b ); diff --git a/indra/newview/llprogressview.h b/indra/newview/llprogressview.h index 813576b21d..1d4ae3a66f 100644 --- a/indra/newview/llprogressview.h +++ b/indra/newview/llprogressview.h @@ -70,6 +70,9 @@ public: void setStartupComplete(); + // turns on logos, hides message of the day + void setShowLogos(const BOOL logos_visible); + void setCancelButtonVisible(BOOL b, const std::string& label); static void onCancelButtonClicked( void* ); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index fdf0ff3506..cb76ac6f74 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -734,6 +734,7 @@ bool idle_startup() display_startup(); // LLViewerMedia::initBrowser(); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); + gViewerWindow->setShowLogos(TRUE); return FALSE; } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 06524847d1..b29e65923b 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -190,6 +190,35 @@ void LLViewerTextureList::doPreloadImages() mImagePreloads.insert(image); } + // Normally images are located in 'skins' folder in working directory, + // but 3p images were added from packages and had to stay in separate folder + // with path relative to exe. + + std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); + if (full_path.empty()) + { + LL_WARNS() << "Failed to find local image file fmod.png at " << full_path << LL_ENDL; + } + else if (gDirUtilp->fileExists(full_path)) + { + image = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + full_path, FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, + 0, 0, IMG_LOGO_FMOD); + if (image) + { + image->setAddressMode(LLTexUnit::TAM_WRAP); + mImagePreloads.insert(image); + // Speed up load (this texture will be used early) + image->setKnownDrawSize(364, 98); + image->processTextureStats(); + image->setDecodePriority(LLViewerFetchedTexture::maxDecodePriority()); + image->updateFetch(); + // Fmod logo is only needed at startup, if we will get more logos + // for startup, might be good idea to save resources and do loading + // in scope of llprogressview and then unload everything once no + // longer needed + } + } + LLPointer img_blak_square_tex(new LLImageRaw(2, 2, 3)); memset(img_blak_square_tex->getData(), 0, img_blak_square_tex->getDataSize()); LLPointer img_blak_square(new LLViewerFetchedTexture(img_blak_square_tex, FTT_DEFAULT, FALSE)); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index ff5dff1c9b..89f3b17021 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -5151,6 +5151,10 @@ void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& } } +void LLViewerWindow::setShowLogos(const BOOL show_3p_logos) +{ + mProgressView->setShowLogos(show_3p_logos); +} LLProgressView *LLViewerWindow::getProgressView() const { diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 385bbd57e5..9adfe7b5c5 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -309,6 +309,7 @@ public: void setProgressPercent(const F32 percent); void setProgressMessage(const std::string& msg); void setProgressCancelButtonVisible( BOOL b, const std::string& label = LLStringUtil::null ); + void setShowLogos(const BOOL show_3p_logos); LLProgressView *getProgressView() const; void revealIntroPanel(); void setStartupComplete(); diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml index 860caf2d21..03caf8e8ad 100644 --- a/indra/newview/skins/default/xui/en/panel_progress.xml +++ b/indra/newview/skins/default/xui/en/panel_progress.xml @@ -106,6 +106,28 @@ top="145" right="-90" word_wrap="true"/> + + + Made with FMOD Studio by Firelight Technologies Pty Ltd. + Date: Wed, 8 Apr 2020 14:42:25 +0300 Subject: [PATCH 07/50] SL-12607 FMOD Logo, small improvement --- indra/newview/CMakeLists.txt | 2 ++ indra/newview/llviewertexturelist.cpp | 37 ++++++++++++--------------- 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1c50e0551a..1ede6188fb 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1715,6 +1715,8 @@ endif (OPENAL) if (FMODSTUDIO) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODSTUDIO") + # texture list needs to load fmod icon + set_source_files_properties(llviewertexturelist.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY}) endif (FMODSTUDIO) diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index b29e65923b..1657e5153d 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -194,30 +194,25 @@ void LLViewerTextureList::doPreloadImages() // but 3p images were added from packages and had to stay in separate folder // with path relative to exe. +#ifdef LL_FMODSTUDIO std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); - if (full_path.empty()) + image = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + full_path, FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, + 0, 0, IMG_LOGO_FMOD); + if (image) { - LL_WARNS() << "Failed to find local image file fmod.png at " << full_path << LL_ENDL; - } - else if (gDirUtilp->fileExists(full_path)) - { - image = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + full_path, FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, - 0, 0, IMG_LOGO_FMOD); - if (image) - { - image->setAddressMode(LLTexUnit::TAM_WRAP); - mImagePreloads.insert(image); - // Speed up load (this texture will be used early) - image->setKnownDrawSize(364, 98); - image->processTextureStats(); - image->setDecodePriority(LLViewerFetchedTexture::maxDecodePriority()); - image->updateFetch(); - // Fmod logo is only needed at startup, if we will get more logos - // for startup, might be good idea to save resources and do loading - // in scope of llprogressview and then unload everything once no - // longer needed - } + image->setAddressMode(LLTexUnit::TAM_WRAP); + mImagePreloads.insert(image); + // Speed up load (this texture will be used early) + image->setKnownDrawSize(364, 98); + image->processTextureStats(); + image->setDecodePriority(LLViewerFetchedTexture::maxDecodePriority()); + image->updateFetch(); + // Fmod logo is only needed at startup, if we will get more logos + // for startup, might be good idea to save resources and do loading + // in scope of llprogressview and then unload everything once no + // longer needed } +#endif LLPointer img_blak_square_tex(new LLImageRaw(2, 2, 3)); memset(img_blak_square_tex->getData(), 0, img_blak_square_tex->getDataSize()); From 5e9ecc123e146bccd36232642561b5f20de37431 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 8 Apr 2020 22:50:33 +0300 Subject: [PATCH 08/50] SL-12607 Resolve grey icon on mac --- indra/newview/llviewertexturelist.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 1657e5153d..4221f941f5 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -195,7 +195,14 @@ void LLViewerTextureList::doPreloadImages() // with path relative to exe. #ifdef LL_FMODSTUDIO +#ifdef LL_WINDOWS std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); +#elif LL_DARWIN + // On MAC use resource directory + std::string full_path = gDirUtilp->add(gDirUtilp->getAppRODataDir(), "3p_icons", "fmod.png"); +#else + std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); +#endif image = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + full_path, FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, 0, 0, IMG_LOGO_FMOD); if (image) From db30295c98c5300e5f44a6ba9dff965c870324b8 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Wed, 8 Apr 2020 22:29:21 +0200 Subject: [PATCH 09/50] Remove FMOD Ex and first round sync with upcoming changes from upstream --- autobuild.xml | 52 -- indra/cmake/CMakeLists.txt | 2 - indra/cmake/Copy3rdPartyLibs.cmake | 23 - indra/cmake/FMODEX.cmake | 62 -- indra/cmake/FindFMODEX.cmake | 65 -- indra/lib/python/indra/util/llmanifest.py | 2 - indra/llaudio/CMakeLists.txt | 18 - indra/llaudio/llaudioengine_fmodex.cpp | 975 -------------------- indra/llaudio/llaudioengine_fmodex.h | 141 --- indra/llaudio/lllistener_fmodex.cpp | 140 --- indra/llaudio/lllistener_fmodex.h | 65 -- indra/llaudio/llstreamingaudio_fmodex.cpp | 667 ------------- indra/llaudio/llstreamingaudio_fmodex.h | 87 -- indra/newview/CMakeLists.txt | 36 +- indra/newview/app_settings/settings.xml | 8 +- indra/newview/linux_tools/client-readme.txt | 4 +- indra/newview/linux_tools/wrapper.sh | 11 +- indra/newview/llfloaterabout.cpp | 2 +- indra/newview/llfloaterpreference.cpp | 2 +- indra/newview/llstartup.cpp | 13 - indra/newview/viewer_manifest.py | 91 +- scripts/configure_firestorm.sh | 14 +- 22 files changed, 55 insertions(+), 2425 deletions(-) delete mode 100644 indra/cmake/FMODEX.cmake delete mode 100644 indra/cmake/FindFMODEX.cmake delete mode 100644 indra/llaudio/llaudioengine_fmodex.cpp delete mode 100644 indra/llaudio/llaudioengine_fmodex.h delete mode 100644 indra/llaudio/lllistener_fmodex.cpp delete mode 100644 indra/llaudio/lllistener_fmodex.h delete mode 100644 indra/llaudio/llstreamingaudio_fmodex.cpp delete mode 100644 indra/llaudio/llstreamingaudio_fmodex.h diff --git a/autobuild.xml b/autobuild.xml index 5301da33b1..88ee1e4cba 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1073,58 +1073,6 @@ version 2.00.08 - fmodex - - copyright - COPYRIGHT 2014 FIRELIGHT TECHNOLOGIES PTY LTD. ALL RIGHTS RESERVED - license - fmodex - license_file - LICENSES/fmodex.txt - name - fmodex - platforms - - darwin - - archive - - hash - cba1feed7f6bb671d791a517fddf205a - url - file:///opt/firestorm/fmodex-44461-darwin-201601300040-r23.tar.bz2 - - name - darwin - - linux - - archive - - hash - 9b090869508fabee82dc53cae977fb99 - url - file:///opt/firestorm/fmodex-44461-linux-201601282301-r23.tar.bz2 - - name - linux - - windows - - archive - - hash - 5b1b5ce866afd2a74e445af1fffe6a8b - url - file:///c:/cygwin/opt/firestorm/fmodex-44461-windows-201601282252-r23.tar.bz2 - - name - windows - - - version - 4.44.61 - fontconfig copyright diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 7065aa044c..4e6dd92424 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -30,7 +30,6 @@ set(cmake_SOURCE_FILES FindAutobuild.cmake FindBerkeleyDB.cmake FindFMODSTUDIO.cmake - FindFMODEX.cmake FindGLH.cmake FindGoogleBreakpad.cmake FindHUNSPELL.cmake @@ -42,7 +41,6 @@ set(cmake_SOURCE_FILES FindXmlRpcEpi.cmake FindZLIB.cmake FMODSTUDIO.cmake - FMODEX.cmake FreeType.cmake GLEXT.cmake GLH.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index 069eada980..858d32b974 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -68,14 +68,6 @@ if(WINDOWS) set(release_files ${release_files} fmod.dll) endif (FMODSTUDIO) - if (FMODEX) - if(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} fmodex.dll) - else(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} fmodex64.dll) - endif(ADDRESS_SIZE EQUAL 32) - endif (FMODEX) - if (OPENAL) set(release_files ${release_files} OpenAL32.dll alut.dll) endif (OPENAL) @@ -208,11 +200,6 @@ elseif(DARWIN) set(release_files ${release_files} libfmod.dylib) endif (FMODSTUDIO) - if (FMODEX) - set(debug_files ${debug_files} libfmodexL.dylib) - set(release_files ${release_files} libfmodex.dylib) - endif (FMODEX) - elseif(LINUX) # linux is weird, multiple side by side configurations aren't supported # and we don't seem to have any debug shared libs built yet anyways... @@ -271,16 +258,6 @@ elseif(LINUX) set(release_files ${release_files} "libfmod.so") endif (FMODSTUDIO) - if (FMODEX) - if(ADDRESS_SIZE EQUAL 32) - set(debug_files ${debug_files} "libfmodexL.so") - set(release_files ${release_files} "libfmodex.so") - else(ADDRESS_SIZE EQUAL 32) - set(debug_files ${debug_files} "libfmodexL64.so") - set(release_files ${release_files} "libfmodex64.so") - endif(ADDRESS_SIZE EQUAL 32) - endif (FMODEX) - else(WINDOWS) message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...") set(vivox_lib_dir "${CMAKE_SOURCE_DIR}/newview/vivox-runtime/i686-linux") diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake deleted file mode 100644 index 642b11e00a..0000000000 --- a/indra/cmake/FMODEX.cmake +++ /dev/null @@ -1,62 +0,0 @@ -# -*- cmake -*- - -# FMOD can be set when launching the make using the argument -DFMODEX:BOOL=ON -# When building using proprietary binaries though (i.e. having access to LL private servers), -# we always build with FMODEX. -# Open source devs should use the -DFMODEX:BOOL=ON then if they want to build with FMOD, whether -# they are using USESYSTEMLIBS or not. -if (INSTALL_PROPRIETARY) - set(FMODEX ON CACHE BOOL "Using FMOD Ex sound library.") -endif (INSTALL_PROPRIETARY) - -if (FMODEX) - if (FMODSTUDIO) - MESSAGE(FATAL_ERROR "You cannot use FMOD Ex if you are already using FMOD Studio.") - endif (FMODSTUDIO) - - if (USESYSTEMLIBS) - # In that case, we use the version of the library installed on the system - set(FMODEX_FIND_REQUIRED ON) - include(FindFMODEX) - else (USESYSTEMLIBS) - if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - # If the path have been specified in the arguments, use that - set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - MESSAGE(STATUS "Using FMODEX path: ${FMODEX_LIBRARIES}, ${FMODEX_INCLUDE_DIR}") - else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - # If not, we're going to try to get the package listed in autobuild.xml - # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) - # as accessing the private LL location will fail if you don't have the credential - include(Prebuilt) - use_prebuilt_binary(fmodex) - if (WINDOWS) - if( ADDRESS_SIZE EQUAL 32 ) - set(FMODEX_LIBRARY - debug fmodexL_vc - optimized fmodex_vc) - else( ) - set(FMODEX_LIBRARY - debug fmodexL64_vc - optimized fmodex64_vc) - endif( ) - elseif (DARWIN) - set(FMODEX_LIBRARY - debug fmodexL - optimized fmodex) - elseif (LINUX) - if( ADDRESS_SIZE EQUAL 64 ) - set(FMODEX_LIBRARY - debug fmodexL64 - optimized fmodex64) - else( ) - set(FMODEX_LIBRARY - debug fmodexL - optimized fmodex) - endif( ) - endif (WINDOWS) - set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - set(FMODEX_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodex) - endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - endif (USESYSTEMLIBS) -endif (FMODEX) - diff --git a/indra/cmake/FindFMODEX.cmake b/indra/cmake/FindFMODEX.cmake deleted file mode 100644 index b621727c0e..0000000000 --- a/indra/cmake/FindFMODEX.cmake +++ /dev/null @@ -1,65 +0,0 @@ -# -*- cmake -*- - -# - Find FMODEX -# Find the FMODEX includes and library -# This module defines -# FMODEX_INCLUDE_DIR, where to find fmod.h and fmod_errors.h -# FMODEX_LIBRARIES, the libraries needed to use FMODEX. -# FMODEX, If false, do not try to use FMODEX. -# also defined, but not for general use are -# FMODEX_LIBRARY, where to find the FMODEX library. - -FIND_PATH(FMODEX_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod) - -SET(FMODEX_NAMES ${FMODEX_NAMES} fmodex fmodvc fmodexL_vc) -FIND_LIBRARY(FMODEX_LIBRARY - NAMES ${FMODEX_NAMES} - PATH_SUFFIXES fmodex - ) - -IF (FMODEX_SDK_DIR OR WINDOWS) - if(WINDOWS) - set(FMODEX_SDK_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows" CACHE PATH "Path to FMODEX") - STRING(REGEX REPLACE "\\\\" "/" FMODEX_SDK_DIR ${FMODEX_SDK_DIR}) - endif(WINDOWS) - find_library(FMODEX_LIBRARY - fmodex_vc fmodexL_vc - PATHS - ${FMODEX_SDK_DIR}/api/lib - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - find_path(FMODEX_INCLUDE_DIR fmod.h - ${FMODEX_SDK_DIR}/api/inc - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - find_path(FMODEX_INCLUDE_DIR fmod.h - ${FMODEX_SDK_DIR}/api/inc - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - IF (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - SET(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - SET(FMODEX_FOUND "YES") - endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) -ENDIF (FMODEX_SDK_DIR OR WINDOWS) - -IF (FMODEX_FOUND) - IF (NOT FMODEX_FIND_QUIETLY) - MESSAGE(STATUS "Found FMODEX: ${FMODEX_LIBRARIES}") - ENDIF (NOT FMODEX_FIND_QUIETLY) -ELSE (FMODEX_FOUND) - IF (FMODEX_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find FMODEX library") - ENDIF (FMODEX_FIND_REQUIRED) -ENDIF (FMODEX_FOUND) - -# Deprecated declarations. -SET (NATIVE_FMODEX_INCLUDE_PATH ${FMODEX_INCLUDE_DIR} ) -GET_FILENAME_COMPONENT (NATIVE_FMODEX_LIB_PATH ${FMODEX_LIBRARY} PATH) - -MARK_AS_ADVANCED( - FMODEX_LIBRARY - FMODEX_INCLUDE_DIR - ) diff --git a/indra/lib/python/indra/util/llmanifest.py b/indra/lib/python/indra/util/llmanifest.py index f8771b5936..dd331a4556 100755 --- a/indra/lib/python/indra/util/llmanifest.py +++ b/indra/lib/python/indra/util/llmanifest.py @@ -160,8 +160,6 @@ BASE_ARGUMENTS=[ description="""The name of a file containing the full version number."""), dict(name='viewer_flavor', description='Type of viewer build. Can be oss or hvk.', default="oss"), - dict(name='fmodversion', - description='Version of FMOD used. Can be fmodstudio or fmodex.', default=None) ] def usage(arguments, srctree=""): diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index 9da9e8f27c..558ede7bf6 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -5,7 +5,6 @@ project(llaudio) include(00-Common) include(LLAudio) include(FMODSTUDIO) -include(FMODEX) include(OPENAL) include(LLCommon) include(LLMath) @@ -60,23 +59,6 @@ if (FMODSTUDIO) ) endif (FMODSTUDIO) -if (FMODEX) - include_directories( - ${FMODEX_INCLUDE_DIR} - ) - list(APPEND llaudio_SOURCE_FILES - llaudioengine_fmodex.cpp - lllistener_fmodex.cpp - llstreamingaudio_fmodex.cpp - ) - - list(APPEND llaudio_HEADER_FILES - llaudioengine_fmodex.h - lllistener_fmodex.h - llstreamingaudio_fmodex.h - ) -endif (FMODEX) - if (OPENAL) include_directories( ${OPENAL_LIBRARIES} diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp deleted file mode 100644 index d5f5b11bf7..0000000000 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ /dev/null @@ -1,975 +0,0 @@ -/** - * @file audioengine_fmodex.cpp - * @brief Implementation of LLAudioEngine class abstracting the audio - * support as a FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2014, 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_fmodex.h" - -#include "llaudioengine_fmodex.h" -#include "lllistener_fmodex.h" - -#include "llerror.h" -#include "llmath.h" -#include "llrand.h" - -#include "fmod.hpp" -#include "fmod_errors.h" -#include "lldir.h" -#include "llapr.h" - -#include "sound_ids.h" - -#include "indra_constants.h" - -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels); - -// Output device selection -static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string); - -LLUUID FMOD_GUID_to_LLUUID(FMOD_GUID guid) -{ - return LLUUID(llformat("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid.Data1, guid.Data2, guid.Data3, - guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7])); -} - -void set_device(FMOD::System* system, const LLUUID& device_uuid) -{ - LL_INFOS() << "LLAudioEngine_FMODEX::setDevice with device_uuid=" << device_uuid << LL_ENDL; - - int drivercount; - if (!Check_FMOD_Error(system->getNumDrivers(&drivercount), "FMOD::System::getNumDrivers") && drivercount > 0) - { - if (device_uuid.isNull()) - { - LL_INFOS() << "Setting driver \"Default\"" << LL_ENDL; - Check_FMOD_Error(system->setDriver(0), "FMOD::System::setDriver"); - } - else - { - FMOD_GUID guid; - - for (int i = 0; i < drivercount; ++i) - { - if (!Check_FMOD_Error(system->getDriverInfo(i, NULL, 0, &guid), "FMOD::System::getDriverInfo")) - { - LLUUID driver_guid = FMOD_GUID_to_LLUUID(guid); - - if (driver_guid == device_uuid) - { - LL_INFOS() << "Setting driver " << i << ": " << driver_guid << LL_ENDL; - Check_FMOD_Error(system->setDriver(i), "FMOD::System::setDriver"); - return; - } - } - } - - LL_INFOS() << "Device not available (anymore) - falling back to default" << LL_ENDL; - Check_FMOD_Error(system->setDriver(0), "FMOD::System::setDriver"); - } - } -} - -FMOD_RESULT F_CALLBACK systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACKTYPE type, void *commanddata1, void *commanddata2) -{ - FMOD::System* sys = (FMOD::System*)system; - LLAudioEngine_FMODEX* audio_engine = NULL; - if (sys) - { - void* userdata = NULL; - Check_FMOD_Error(sys->getUserData(&userdata), "FMOD::System::getUserData"); - audio_engine = (LLAudioEngine_FMODEX*)userdata; - } - - switch (type) - { - case FMOD_SYSTEM_CALLBACKTYPE_DEVICELISTCHANGED: - LL_DEBUGS() << "FMOD system callback FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED" << LL_ENDL; - if (sys && audio_engine) - { - set_device(sys, audio_engine->getSelectedDeviceUUID()); - audio_engine->OnOutputDeviceListChanged(audio_engine->getDevices()); - } - break; - default: - break; - } - return FMOD_OK; -} -// > - -FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; - -LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler) -{ - mInited = false; - mWindGen = NULL; - mWindDSP = NULL; - mSystem = NULL; - mEnableProfiler = enable_profiler; - mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); - mSelectedDeviceUUID = LLUUID::null; // Output device selection -} - - -LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX() -{ - delete mWindDSPDesc; -} - - -static // Make this file scope so it doesn't collide with the same function in llstreamingaudio_fmodex.cpp -inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) -{ - if(result == FMOD_OK) - return false; - // Always print out error - //LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - if (result != FMOD_ERR_INVALID_HANDLE) - { - LL_WARNS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - } - else - { - LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - } - // - return true; -} - -void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - if(type & FMOD_MEMORY_STREAM_DECODE) - { - LL_INFOS() << "Decode buffer size: " << size << LL_ENDL; - } - else if(type & FMOD_MEMORY_STREAM_FILE) - { - LL_INFOS() << "Stream buffer size: " << size << LL_ENDL; - } - return new char[size]; -} -void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - memset(ptr,0,size); - return ptr; -} -void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - delete[] (char*)ptr; -} - -bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) -{ - U32 version; - FMOD_RESULT result; - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL; - - //result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE); - //if(Check_FMOD_Error(result, "FMOD::Memory_Initialize")) - // return false; - - // turn off non-error log spam to fmod.log (TODO: why do we even have an fmod.log if we don't link against log lib?) - FMOD::Debug_SetLevel(FMOD_DEBUG_LEVEL_ERROR); - - result = FMOD::System_Create(&mSystem); - if(Check_FMOD_Error(result, "FMOD::System_Create")) - return false; - - //will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer. - LLAudioEngine::init(num_channels, userdata); - - result = mSystem->getVersion(&version); - Check_FMOD_Error(result, "FMOD::System::getVersion"); - - if (version < FMOD_VERSION) - { - LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Ex version (" << version - << ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL; - } - - result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR); - Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat"); - - // In this case, all sounds, PLUS wind and stream will be software. - result = mSystem->setSoftwareChannels(num_channels + 2); - Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); - - // Output device selection - Check_FMOD_Error(mSystem->setCallback(systemCallback), "FMOD::System::setCallback"); - Check_FMOD_Error(mSystem->setUserData(this), "FMOD::System::setUserData"); - // - - U32 fmod_flags = FMOD_INIT_NORMAL; - if(mEnableProfiler) - { - fmod_flags |= FMOD_INIT_ENABLE_PROFILE; - // FMOD fixes - //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 - bool audio_ok = false; - - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; - // FMOD fixes - //if(mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK && - // (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) - if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK && - // - (result = mSystem->init(num_channels + 2, fmod_flags, const_cast(APP_NAME.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) - { - if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; - // FMOD fixes - //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; - 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) - { - if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL; - // FMOD fixes - //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; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "OSS audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "OSS 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; - // FMOD fixes - //mSystem->getOutput(&output_type); - if(!Check_FMOD_Error(mSystem->getOutput(&output_type), "FMOD::System::getOutput")) - { - // - 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; - }; - // FMOD fixes - } - // -#else // LL_LINUX - - // initialize the FMOD engine - result = mSystem->init( num_channels + 2, fmod_flags, 0); - if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) - { - /* - Ok, the speaker mode selected isn't supported by this soundcard. Switch it - back to stereo... - */ - result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO); - Check_FMOD_Error(result,"Error falling back to stereo mode"); - /* - ... and re-init. - */ - result = mSystem->init( num_channels + 2, fmod_flags, 0); - } - if(Check_FMOD_Error(result, "Error initializing FMOD Ex")) - return false; -#endif - - // FMOD fixes - 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)); - - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD Ex initialized correctly" << LL_ENDL; - - int r_numbuffers, r_samplerate, r_channels, r_bits; - unsigned int r_bufferlength; - mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_numbuffers=" << r_numbuffers << LL_ENDL; - - mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_channels=" << r_channels << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bits =" << r_bits << LL_ENDL; - - char r_name[512]; - mSystem->getDriverInfo(0, r_name, 511, 0); - r_name[511] = '\0'; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_name=\"" << r_name << "\"" << LL_ENDL; - - int latency = 100; // optimistic default - i suspect if sample rate is 0, everything breaks. - if ( r_samplerate != 0 ) - latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): latency=" << latency << "ms" << LL_ENDL; - - mInited = true; - - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): initialization complete." << LL_ENDL; - - // Output device selection - getDevices(); // Purely to print out available devices for debugging reasons - - return true; -} - -// Output device selection -//virtual -LLAudioEngine_FMODEX::output_device_map_t LLAudioEngine_FMODEX::getDevices() -{ - output_device_map_t driver_map; - - int drivercount; - char r_name[512]; - FMOD_GUID guid; - - if (!Check_FMOD_Error(mSystem->getNumDrivers(&drivercount), "FMOD::System::getNumDrivers")) - { - for (int i = 0; i < drivercount; ++i) - { - memset(r_name, 0, sizeof(r_name)); - if (!Check_FMOD_Error(mSystem->getDriverInfo(i, r_name, 511, &guid), "FMOD::System::getDriverInfo")) - { - LLUUID driver_guid = FMOD_GUID_to_LLUUID(guid); - driver_map.insert(std::make_pair(driver_guid, r_name)); - - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::getDevices(): r_name=\"" << r_name << "\" - guid: " << driver_guid << LL_ENDL; - } - } - } - - return driver_map; -} - -//virtual -void LLAudioEngine_FMODEX::setDevice(const LLUUID& device_uuid) -{ - mSelectedDeviceUUID = device_uuid; - set_device(mSystem, device_uuid); -} -// - -std::string LLAudioEngine_FMODEX::getDriverName(bool verbose) -{ - llassert_always(mSystem); - if (verbose) - { - U32 version; - if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion")) - { - return llformat("FMOD Ex %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); - } - } - return "FMODEx"; -} - - -void LLAudioEngine_FMODEX::allocateListener(void) -{ - mListenerp = (LLListener *) new LLListener_FMODEX(mSystem); - if (!mListenerp) - { - LL_WARNS() << "Listener creation failed" << LL_ENDL; - } -} - - -void LLAudioEngine_FMODEX::shutdown() -{ - // FMOD fixes - //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 - { - // FMOD fixes - //mSystem->close(); - //mSystem->release(); - Check_FMOD_Error(mSystem->close(), "FMOD::System::close"); - 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; - - delete mListenerp; - mListenerp = NULL; -} - - -LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer() -{ - return new LLAudioBufferFMODEX(mSystem); -} - - -LLAudioChannel * LLAudioEngine_FMODEX::createChannel() -{ - return new LLAudioChannelFMODEX(mSystem); -} - -bool LLAudioEngine_FMODEX::initWind() -{ - mNextWindUpdate = 0.0; - - if (!mWindDSP) - { - memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero - strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); - mWindDSPDesc->channels = 2; - 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; - - float frequency = 44100; - mWindDSP->getDefaults(&frequency,0,0,0); - mWindGen = new LLWindGen((U32)frequency); - mWindDSP->setUserData((void*)mWindGen); - } - - // *TODO: Should this guard against multiple plays? - if (mWindDSP) - { - mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0); - return true; - } - return false; -} - - -void LLAudioEngine_FMODEX::cleanupWind() -{ - if (mWindDSP) - { - // FMOD fixes - //mWindDSP->remove(); - //mWindDSP->release(); - Check_FMOD_Error(mWindDSP->remove(), "FMOD::DSP::remove"); - Check_FMOD_Error(mWindDSP->release(), "FMOD::DSP::release"); - // - mWindDSP = NULL; - } - - delete mWindGen; - mWindGen = NULL; -} - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODEX::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_FMODEX::setInternalGain(F32 gain) -{ - if (!mInited) - { - return; - } - - gain = llclamp( gain, 0.0f, 1.0f ); - - FMOD::ChannelGroup *master_group; - // FMOD fixes - //mSystem->getMasterChannelGroup(&master_group); - if(Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")) - return; - // - 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()); - } -} - -// -// LLAudioChannelFMODEX implementation -// - -LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) -{ -} - - -LLAudioChannelFMODEX::~LLAudioChannelFMODEX() -{ - cleanup(); -} - -bool LLAudioChannelFMODEX::updateBuffer() -{ - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the channel for a different buffer. - - LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)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(FMOD_CHANNEL_FREE, soundp, true, &mChannelp); - Check_FMOD_Error(result, "FMOD::System::playSound"); - } - - //LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL; - } - - // 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 LLAudioChannelFMODEX::update3DPosition() -{ - if (!mChannelp) - { - // We're not actually a live channel (i.e., we're not playing back anything) - return; - } - - LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)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->isAmbient()) - { - // Ambient sound, 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 LLAudioChannelFMODEX::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; - // FMOD fixes - //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) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; -} - - -void LLAudioChannelFMODEX::cleanup() -{ - if (!mChannelp) - { - //LL_INFOS() << "Aborting cleanup with no channel handle." << LL_ENDL; - return; - } - - //LL_INFOS() << "Cleaning up channel: " << mChannelID << LL_ENDL; - Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"); - - mCurrentBufferp = NULL; - mChannelp = NULL; -} - - -void LLAudioChannelFMODEX::play() -{ - if (!mChannelp) - { - LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; - return; - } - - // FMOD fixes - //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()]) - // FMOD fixes - //mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]); - Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]),"FMOD::Channel::setChannelGroup"); - // -} - - -void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp) -{ - LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)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 LLAudioChannelFMODEX::isPlaying() -{ - if (!mChannelp) - { - return false; - } - - bool paused, playing; - // FMOD fixes - //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; -} - - -// -// LLAudioChannelFMODEX implementation -// - - -LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystemp(system), mSoundp(NULL) -{ -} - - -LLAudioBufferFMODEX::~LLAudioBufferFMODEX() -{ - if(mSoundp) - { - // FMOD fixes - //mSoundp->release(); - Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release"); - // - mSoundp = NULL; - } -} - - -bool LLAudioBufferFMODEX::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; - } - - // FMOD fixes - //if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) - if (!gDirUtilp->fileExists(filename)) - // - { - // File not found, abort. - return false; - } - - if (mSoundp) - { - // If there's already something loaded in this buffer, clean it up. - // FMOD fixes - //mSoundp->release(); - Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release"); - // - mSoundp = NULL; - } - - FMOD_MODE base_mode = FMOD_LOOP_NORMAL | FMOD_SOFTWARE; - 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 -#if LL_WINDOWS - FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp); -#else - FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); -#endif - - 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 LLAudioBufferFMODEX::getLength() -{ - if (!mSoundp) - { - return 0; - } - - U32 length; - // FMOD fixes - //mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES); - Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength"); - // - return length; -} - - -void LLAudioChannelFMODEX::set3DMode(bool use3d) -{ - FMOD_MODE current_mode; - // FMOD fixes - //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); - new_mode |= use3d ? FMOD_3D : FMOD_2D; - - if(current_mode != new_mode) - { - // FMOD fixes - //mChannelp->setMode(new_mode); - Check_FMOD_Error(mChannelp->setMode(new_mode),"FMOD::Channel::setMode"); - // - } -} - -// *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 *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels) -{ - // originalbuffer = fmod's original mixbuffer. - // newbuffer = the buffer passed from the previous DSP unit. - // length = length in samples at this mix time. - // userdata = user parameter passed through in FSOUND_DSP_Create. - - LLWindGen *windgen; - FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; - - thisdsp->getUserData((void **)&windgen); - // FMOD fixes - //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/llaudioengine_fmodex.h b/indra/llaudio/llaudioengine_fmodex.h deleted file mode 100644 index d0de2d602a..0000000000 --- a/indra/llaudio/llaudioengine_fmodex.h +++ /dev/null @@ -1,141 +0,0 @@ -/** - * @file audioengine_fmodex.h - * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2014, 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_FMODEX_H -#define LL_AUDIOENGINE_FMODEX_H - -#include "llaudioengine.h" -#include "llwindgen.h" - -//Stubs -class LLAudioStreamManagerFMODEX; -namespace FMOD -{ - class System; - class Channel; - class ChannelGroup; - class Sound; - class DSP; -} -typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION; - -//Interfaces -class LLAudioEngine_FMODEX : public LLAudioEngine -{ -public: - LLAudioEngine_FMODEX(bool enable_profiler); - virtual ~LLAudioEngine_FMODEX(); - - // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); - 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;} - - // Output device selection - /*virtual*/ std::map getDevices(); - /*virtual*/ void setDevice(const LLUUID& device_uuid); - - LLUUID getSelectedDeviceUUID() const { return mSelectedDeviceUUID; } - // - -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 *mWindGen; - - FMOD_DSP_DESCRIPTION *mWindDSPDesc; - FMOD::DSP *mWindDSP; - FMOD::System *mSystem; - bool mEnableProfiler; - - // Output device selection - LLUUID mSelectedDeviceUUID; - -public: - static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT]; -}; - - -class LLAudioChannelFMODEX : public LLAudioChannel -{ -public: - LLAudioChannelFMODEX(FMOD::System *audioengine); - virtual ~LLAudioChannelFMODEX(); - -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 LLAudioBufferFMODEX : public LLAudioBuffer -{ -public: - LLAudioBufferFMODEX(FMOD::System *audioengine); - virtual ~LLAudioBufferFMODEX(); - - /*virtual*/ bool loadWAV(const std::string& filename); - /*virtual*/ U32 getLength(); - friend class LLAudioChannelFMODEX; -protected: - FMOD::System *getSystem() const {return mSystemp;} - FMOD::System *mSystemp; - FMOD::Sound *getSound() const{ return mSoundp; } - FMOD::Sound *mSoundp; -}; - - -#endif // LL_AUDIOENGINE_FMODEX_H diff --git a/indra/llaudio/lllistener_fmodex.cpp b/indra/llaudio/lllistener_fmodex.cpp deleted file mode 100644 index 31ab47a635..0000000000 --- a/indra/llaudio/lllistener_fmodex.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/** - * @file listener_fmodex.cpp - * @brief Implementation of LISTENER class abstracting the audio - * support as a FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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_fmodex.h" -#include "fmod.hpp" - -//----------------------------------------------------------------------- -// constructor -//----------------------------------------------------------------------- -LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system) -{ - mSystem = system; - init(); -} - -//----------------------------------------------------------------------- -LLListener_FMODEX::~LLListener_FMODEX() -{ -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::init(void) -{ - // do inherited - LLListener::init(); - mDopplerFactor = 1.0f; - mRolloffFactor = 1.0f; -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::translate(LLVector3 offset) -{ - LLListener::translate(offset); - - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::setPosition(LLVector3 pos) -{ - LLListener::setPosition(pos); - - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::setVelocity(LLVector3 vel) -{ - LLListener::setVelocity(vel); - - mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at) -{ - LLListener::orient(up, at); - - // Welcome to the transition between right and left - // (coordinate systems, that is) - // Leaving the at vector alone results in a L/R reversal - // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed - at = -at; - - mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::commitDeferredChanges() -{ - if(!mSystem) - { - return; - } - - mSystem->update(); -} - - -void LLListener_FMODEX::setRolloffFactor(F32 factor) -{ - //An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment. - //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 fmodex, which makes it not skip 3D processing next update call. - if(mRolloffFactor != factor) - { - LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL); - } - mRolloffFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODEX::getRolloffFactor() -{ - return mRolloffFactor; -} - - -void LLListener_FMODEX::setDopplerFactor(F32 factor) -{ - mDopplerFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); -} - - -F32 LLListener_FMODEX::getDopplerFactor() -{ - return mDopplerFactor; -} - - diff --git a/indra/llaudio/lllistener_fmodex.h b/indra/llaudio/lllistener_fmodex.h deleted file mode 100644 index 073b65d53a..0000000000 --- a/indra/llaudio/lllistener_fmodex.h +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @file listener_fmodex.h - * @brief Description of LISTENER class abstracting the audio support - * as an FMOD 3D implementation (windows and Linux) - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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_FMODEX_H -#define LL_LISTENER_FMODEX_H - -#include "lllistener.h" - -//Stubs -namespace FMOD -{ - class System; -} - -//Interfaces -class LLListener_FMODEX : public LLListener -{ - public: - LLListener_FMODEX(FMOD::System *system); - virtual ~LLListener_FMODEX(); - 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_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp deleted file mode 100644 index 6d4c7df8cc..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.cpp +++ /dev/null @@ -1,667 +0,0 @@ -/** - * @file streamingaudio_fmodex.cpp - * @brief LLStreamingAudio_FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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 "fmod.hpp" -#include "fmod_errors.h" - -#include "llstreamingaudio_fmodex.h" - -// FMOD fixes -static 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 LLAudioStreamManagerFMODEX -{ -public: - LLAudioStreamManagerFMODEX(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 fixes - //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; - FMOD::Sound* mInternetStream; - bool mReady; - - std::string mInternetStreamURL; -}; - - - -//--------------------------------------------------------------------------- -// Internet Streaming -//--------------------------------------------------------------------------- -LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) : - mSystem(system), - mCurrentInternetStreamp(NULL), - mFMODInternetStreamChannelp(NULL), - mGain(1.0f) -{ - // FMOD fixes - 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 - // FMOD fixes - //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 - // 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_FMODEX::~LLStreamingAudio_FMODEX() -{ - // FMOD fixes - //// 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) - //{ - // 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()) - { - // FMOD fixes - //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 - { - LL_INFOS() << "Set internet stream to null" << LL_ENDL; - mURL.clear(); - } -} - - -void LLStreamingAudio_FMODEX::update() -{ - // FMOD fixes - //// 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++; - // } - //} - if (!releaseDeadStreams()) - { - 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 - if (!mCurrentInternetStreamp) - { - return; - } - - unsigned int progress; - bool starving; - bool diskbusy; - // FMOD fixes - //FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy); - - //if (open_state == FMOD_OPENSTATE_READY) - - FMOD_OPENSTATE open_state; - FMOD_RESULT result = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy); - - if (result != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR) - { - stop(); - return; - } - else 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()); - // FMOD fixes - //mFMODInternetStreamChannelp->setPaused(false); - Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); - // - } - } - // FMOD fixes - //else if(open_state == FMOD_OPENSTATE_ERROR) - //{ - // stop(); - // return; - //} - // - - if(mFMODInternetStreamChannelp) - { - FMOD::Sound *sound = NULL; - - // FmodEX Error checking - //if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound) - if (!Check_FMOD_Error(mFMODInternetStreamChannelp->getCurrentSound(&sound), "FMOD::Channel::getCurrentSound") && sound) - // - { - FMOD_TAG tag; - S32 tagcount, dirtytagcount; - - // FmodEX Error checking - //if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount) - if (!Check_FMOD_Error(sound->getNumTags(&tagcount, &dirtytagcount), "FMOD::Sound::getNumTags") && dirtytagcount) - // - { - // Stream metadata - originally by Shyotl Khur - LL_DEBUGS("StreamMetadata") << "Tag count: " << tagcount << " Dirty tag count: " << dirtytagcount << LL_ENDL; - - mMetadata.clear(); - mNewMetadata = true; - // - for(S32 i = 0; i < tagcount; ++i) - { - // FmodEX Error checking - //if(sound->getTag(NULL, i, &tag) != FMOD_OK) - if(Check_FMOD_Error(sound->getTag(NULL, i, &tag), "FMOD::Sound::getTag")) - // - continue; - - // Stream metadata - originally by Shyotl Khur - //if (tag.type == FMOD_TAGTYPE_FMOD) - //{ - // if (!strcmp(tag.name, "Sample Rate Change")) - // { - // LL_INFOS("FmodEX") << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; - // mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); - // } - // continue; - //} - LL_DEBUGS("StreamMetadata") << "Tag name: " << tag.name << " - Tag type: " << tag.type << " - Tag data type: " << tag.datatype << LL_ENDL; - std::string name = tag.name; - switch(tag.type) - { - case(FMOD_TAGTYPE_ID3V2): - { - if(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"; - break; - } - case(FMOD_TAGTYPE_VORBISCOMMENT): - { - if(name == "title") name = "TITLE"; - else if(name == "artist") name = "ARTIST"; - break; - } - case(FMOD_TAGTYPE_FMOD): - { - if (!strcmp(tag.name, "Sample Rate Change")) - { - LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; - mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); - } - continue; - } - default: - break; - } - switch(tag.datatype) - { - case(FMOD_TAGDATATYPE_INT): - { - (mMetadata)[name]=*(LLSD::Integer*)(tag.data); - LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(int*)(tag.data) << LL_ENDL; - break; - } - case(FMOD_TAGDATATYPE_FLOAT): - { - (mMetadata)[name]=*(LLSD::Real*)(tag.data); - LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(float*)(tag.data) << LL_ENDL; - break; - } - case(FMOD_TAGDATATYPE_STRING): - { - std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); - (mMetadata)[name]=out; - LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; - break; - } - case(FMOD_TAGDATATYPE_STRING_UTF8): - { - std::string out((char*)tag.data); - (mMetadata)[name]=out; - LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; - break; - } - case(FMOD_TAGDATATYPE_STRING_UTF16): - { - std::string out((char*)tag.data,tag.datalen); - (mMetadata)[std::string(tag.name)]=out; - LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; - 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; - LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; - break; - } - default: - break; - } - // Stream metadata - originally by Shyotl Khur - } - } - - if(starving) - { - bool paused = false; - // FMOD fixes - //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="< FMOD fixes - //mFMODInternetStreamChannelp->setPaused(true); - Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused"); - // - } - } - else if(progress > 80) - { - // FMOD fixes - //mFMODInternetStreamChannelp->setPaused(false); - Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); - // - } - } - } -} - -void LLStreamingAudio_FMODEX::stop() -{ - // FMOD fixes - mPendingURL.clear(); - - if (mFMODInternetStreamChannelp) - { - // FMOD fixes - //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; - } - - if (mCurrentInternetStreamp) - { - LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - if (mCurrentInternetStreamp->stopStream()) - { - delete mCurrentInternetStreamp; - } - else - { - LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - mDeadStreams.push_back(mCurrentInternetStreamp); - } - mCurrentInternetStreamp = NULL; - //mURL.clear(); - } -} - -void LLStreamingAudio_FMODEX::pause(int pauseopt) -{ - if (pauseopt < 0) - { - pauseopt = mCurrentInternetStreamp ? 1 : 0; - } - - if (pauseopt) - { - if (mCurrentInternetStreamp) - { - 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_FMODEX::isPlaying() -{ - if (mCurrentInternetStreamp) - { - return 1; // Active and playing - } - // FMOD fixes - //else if (!mURL.empty()) - else if (!mURL.empty() || !mPendingURL.empty()) - // - { - return 2; // "Paused" - } - else - { - return 0; - } -} - - -F32 LLStreamingAudio_FMODEX::getGain() -{ - return mGain; -} - - -std::string LLStreamingAudio_FMODEX::getURL() -{ - return mURL; -} - - -void LLStreamingAudio_FMODEX::setGain(F32 vol) -{ - mGain = vol; - - if (mFMODInternetStreamChannelp) - { - vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? - - // FMOD fixes - //mFMODInternetStreamChannelp->setVolume(vol); - Check_FMOD_Error(mFMODInternetStreamChannelp->setVolume(vol), "FMOD::Channel::setVolume"); - // - } -} - -// Streamtitle display -// virtual -bool LLStreamingAudio_FMODEX::getNewMetadata(LLSD& metadata) -{ - if (mCurrentInternetStreamp) - { - if (mNewMetadata) - { - metadata = mMetadata; - mNewMetadata = false; - return true; - } - - return mNewMetadata; - } - - metadata = LLSD(); - return false; -} -// - -/////////////////////////////////////////////////////// -// manager of possibly-multiple internet audio streams - -LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(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() << "Couldn't open fmod stream, error " - << FMOD_ErrorString(result) - << LL_ENDL; - mReady = false; - return; - } - - mReady = true; -} - -FMOD::Channel *LLAudioStreamManagerFMODEX::startStream() -{ - // We need a live and opened stream before we try and play it. - // FMOD fixes - //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; - } - - if(mStreamChannel) - return mStreamChannel; //Already have a channel for this stream. - - // FMOD fixes - //mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel); - Check_FMOD_Error(mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel), "FMOD::System::playSound"); - // - return mStreamChannel; -} - -bool LLAudioStreamManagerFMODEX::stopStream() -{ - if (mInternetStream) - { - bool close = true; - // FMOD fixes - //switch (getOpenState()) - FMOD_OPENSTATE open_state; - if (getOpenState(open_state) == FMOD_OK) - { - switch (open_state) - // - { - case FMOD_OPENSTATE_CONNECTING: - close = false; - break; - default: - close = true; - } - // FMOD fixes - } - // - - // FMOD fixes - //if (close) - //{ - // mInternetStream->release(); - if (close && mInternetStream->release() == FMOD_OK) - { - // - mStreamChannel = NULL; - mInternetStream = NULL; - return true; - } - else - { - return false; - } - } - else - { - return true; - } -} - -// FMOD fixes -//FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy) -//{ -// FMOD_OPENSTATE state; -// mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); -// return state; -//} -FMOD_RESULT LLAudioStreamManagerFMODEX::getOpenState(FMOD_OPENSTATE& state, unsigned int* percentbuffered, bool* starving, bool* diskbusy) -{ - 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) -{ - // FMOD fixes - //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 - // FMOD fixes - //mSystem->setAdvancedSettings(&settings); - Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings"); - // -} - -// FMOD fixes -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 deleted file mode 100644 index b197151f86..0000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @file streamingaudio_fmodex.h - * @brief Definition of LLStreamingAudio_FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, 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_FMODEX_H -#define LL_STREAMINGAUDIO_FMODEX_H - -#include "stdtypes.h" // from llcommon - -#include "llstreamingaudio.h" -#include "lltimer.h" - -//Stubs -class LLAudioStreamManagerFMODEX; -namespace FMOD -{ - class System; - class Channel; -} - -//Interfaces -class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface -{ - public: - LLStreamingAudio_FMODEX(FMOD::System *system); - /*virtual*/ ~LLStreamingAudio_FMODEX(); - - /*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); - - // Streamtitle display - virtual bool getNewMetadata(LLSD& metadata); - // - -private: - // FMOD fixes - bool releaseDeadStreams(); - - FMOD::System *mSystem; - - LLAudioStreamManagerFMODEX *mCurrentInternetStreamp; - FMOD::Channel *mFMODInternetStreamChannelp; - std::list mDeadStreams; - - std::string mURL; - std::string mPendingURL; // FMOD fixes - F32 mGain; - - // Streamtitle display - bool mNewMetadata; - LLSD mMetadata; - // Streamtitle display -}; - - -#endif // LL_STREAMINGAUDIO_FMODEX_H diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d57b4517cf..4278f4555f 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -19,7 +19,6 @@ include(DirectX) include(DragDrop) include(EXPAT) include(FMODSTUDIO) -include(FMODEX) include(GLOD) include(Hunspell) include(JsonCpp) @@ -79,10 +78,6 @@ if(FMODSTUDIO) include_directories(${FMODSTUDIO_INCLUDE_DIR}) endif(FMODSTUDIO) -if(FMODEX) - include_directories(${FMODEX_INCLUDE_DIR}) -endif(FMODEX) - include_directories( ${DBUSGLIB_INCLUDE_DIRS} ${JSONCPP_INCLUDE_DIR} @@ -2119,11 +2114,6 @@ if (FMODSTUDIO) set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY}) endif (FMODSTUDIO) -if (FMODEX) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") - set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) -endif (FMODEX) - # Output device selection # set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") set_source_files_properties(llstartup.cpp llfloaterpreference.cpp llfloaterabout.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") @@ -2165,12 +2155,6 @@ else (OPENSIM) set(ND_VIEWER_FLAVOR "hvk") endif (OPENSIM) -if (FMODSTUDIO) - set(FMODVERSION "fmodstudio") -elseif (FMODEX) - set(FMODVERSION "fmodex") -endif (FMODSTUDIO) - if (WINDOWS) set_target_properties(${VIEWER_BINARY_NAME} PROPERTIES @@ -2261,14 +2245,6 @@ if (WINDOWS) ) endif (FMODSTUDIO) - if (FMODEX) - list(APPEND COPY_INPUT_DEPENDENCIES - ${SHARED_LIB_STAGING_DIR}/Release/fmodex.dll - ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmodex.dll - ${SHARED_LIB_STAGING_DIR}/Debug/fmodexL.dll - ) - endif (FMODEX) - if (OPENAL) list(APPEND COPY_INPUT_DEPENDENCIES ${SHARED_LIB_STAGING_DIR}/${CMAKE_CFG_INTDIR}/OpenAL32.dll @@ -2285,6 +2261,7 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2295,7 +2272,6 @@ if (WINDOWS) --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/copy_touched.bat --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --viewer_flavor=${ND_VIEWER_FLAVOR} - --fmodversion=${FMODVERSION} --openal=${OPENAL} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py @@ -2349,6 +2325,7 @@ if (WINDOWS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2359,7 +2336,6 @@ if (WINDOWS) --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/touched.bat --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --viewer_flavor=${ND_VIEWER_FLAVOR} - --fmodversion=${FMODVERSION} --openal=${OPENAL} DEPENDS ${VIEWER_BINARY_NAME} @@ -2522,6 +2498,7 @@ endif (NOT ENABLE_MEDIA_PLUGINS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2532,7 +2509,6 @@ endif (NOT ENABLE_MEDIA_PLUGINS) --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --viewer_flavor=${ND_VIEWER_FLAVOR} - --fmodversion=${FMODVERSION} --openal=${OPENAL} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py @@ -2549,6 +2525,7 @@ endif (NOT ENABLE_MEDIA_PLUGINS) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2558,7 +2535,6 @@ endif (NOT ENABLE_MEDIA_PLUGINS) --source=${CMAKE_CURRENT_SOURCE_DIR} --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --viewer_flavor=${ND_VIEWER_FLAVOR} - --fmodversion=${FMODVERSION} --openal=${OPENAL} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/viewer_manifest.py @@ -2633,6 +2609,7 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} --bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER} @@ -2643,7 +2620,6 @@ if (DARWIN) --source=${CMAKE_CURRENT_SOURCE_DIR} --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --viewer_flavor=${ND_VIEWER_FLAVOR} - --fmodversion=${FMODVERSION} --openal=${OPENAL} DEPENDS ${VIEWER_BINARY_NAME} @@ -2670,6 +2646,7 @@ if (DARWIN) --arch=${ARCH} --artwork=${ARTWORK_DIR} "--bugsplat=${BUGSPLAT_DB}" + "--fmodstudio=${FMODSTUDIO}" --build=${CMAKE_CURRENT_BINARY_DIR} --buildtype=${CMAKE_BUILD_TYPE} "--channel=${VIEWER_CHANNEL}" @@ -2680,7 +2657,6 @@ if (DARWIN) --touch=${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/.${product}.touched --versionfile=${CMAKE_CURRENT_BINARY_DIR}/viewer_version.txt --viewer_flavor=${ND_VIEWER_FLAVOR} - --fmodversion=${FMODVERSION} --openal=${OPENAL} ${SIGNING_SETTING} DEPENDS diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 0d47172274..3467535d88 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -20485,7 +20485,7 @@ Change of this parameter will affect the layout of buttons in notification toast FMODProfilerEnable Comment - Enable profiler tool if using FMOD + Enable profiler tool if using FMOD Studio Persist 1 Type @@ -20496,7 +20496,7 @@ Change of this parameter will affect the layout of buttons in notification toast FMODDecodeBufferSize Comment - Sets the streaming decode buffer size (in milliseconds) + Sets the streaming decode buffer size (in milliseconds) for FMOD Studio Persist 1 Type @@ -20507,7 +20507,7 @@ Change of this parameter will affect the layout of buttons in notification toast FMODStreamBufferSize Comment - Sets the streaming buffer size (in milliseconds) + Sets the streaming buffer size (in milliseconds) for FMOD Studio Persist 1 Type @@ -20518,7 +20518,7 @@ Change of this parameter will affect the layout of buttons in notification toast FMODResampleMethod Comment - Sets the method used for internal resampler 0(Linear), 1(Cubic), 2(Spline) + Sets the method used for internal resampler 0(Linear), 1(Cubic), 2(Spline) for FMOD Studio Persist 1 Type diff --git a/indra/newview/linux_tools/client-readme.txt b/indra/newview/linux_tools/client-readme.txt index 71f0b65155..5290e607a7 100644 --- a/indra/newview/linux_tools/client-readme.txt +++ b/indra/newview/linux_tools/client-readme.txt @@ -180,8 +180,8 @@ The 'firestorm' script which launches Firestorm contains some configuration options for advanced troubleshooters. * AUDIO - Edit the 'secondlife' script and you will see these audio - options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMOD_ESD, LL_BAD_FMOD_OSS, and - LL_BAD_FMOD_ALSA. Firestorm tries to use OpenAL, ESD, OSS, then ALSA + options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMODSTUDIO_DRIVER. + Firestorm tries to use OpenAL, FMODSTUDIO (PULSEAUDIO, ALSA) audio drivers in this order; you may uncomment the corresponding LL_BAD_* option to skip an audio driver which you believe may be causing you trouble. diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh index 0654a07b4e..8363736f8e 100755 --- a/indra/newview/linux_tools/wrapper.sh +++ b/indra/newview/linux_tools/wrapper.sh @@ -20,18 +20,15 @@ exportMutliArchDRIPath() { ## These options are for self-assisted troubleshooting during this beta ## testing phase; you should not usually need to touch them. -## - Avoids using any FMOD Ex audio driver. -#export LL_BAD_FMODEX_DRIVER=x - +## - Avoids using any FMOD STUDIO audio driver. +#export LL_BAD_FMODSTUDIO_DRIVER=x ## - Avoids using any OpenAL audio driver. #export LL_BAD_OPENAL_DRIVER=x -## - Avoids using the FMOD Ex PulseAudio audio driver. +## - Avoids using the FMOD Studio PulseAudio audio driver. #export LL_BAD_FMOD_PULSEAUDIO=x -## - Avoids using the FMOD or FMOD Ex ALSA audio driver. +## - Avoids using the FMOD Studio ALSA audio driver. #export LL_BAD_FMOD_ALSA=x -## - Avoids using the FMOD or FMOD Ex OSS audio driver. -#export LL_BAD_FMOD_OSS=x ## - Avoids the optional OpenGL extensions which have proven most problematic ## on some hardware. Disabling this option may cause BETTER PERFORMANCE but diff --git a/indra/newview/llfloaterabout.cpp b/indra/newview/llfloaterabout.cpp index 991a68b3d7..3751fe39eb 100644 --- a/indra/newview/llfloaterabout.cpp +++ b/indra/newview/llfloaterabout.cpp @@ -143,7 +143,7 @@ BOOL LLFloaterAbout::postBuild() // boost::bind(&LLFloaterAbout::onClickUpdateCheck, this)); // -#if LL_FMODSTUDIO || LL_FMODEX +#if LL_FMODSTUDIO childSetVisible("logos_panel", true); #endif diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index fc6f24419d..9410f24f79 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -6148,7 +6148,7 @@ BOOL FSPanelPreferenceSounds::postBuild() mOutputDevicePanel = findChild("output_device_settings_panel"); mOutputDeviceComboBox = findChild("sound_output_device"); -#if LL_FMODSTUDIO || LL_FMODEX +#if LL_FMODSTUDIO if (gAudiop && mOutputDevicePanel && mOutputDeviceComboBox) { gSavedSettings.getControl("FSOutputDeviceUUID")->getSignal()->connect(boost::bind(&FSPanelPreferenceSounds::onOutputDeviceChanged, this, _2)); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 25d2bd78b8..c2afa2c038 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -43,10 +43,6 @@ # include "llaudioengine_fmodstudio.h" #endif -#ifdef LL_FMODEX -# include "llaudioengine_fmodex.h" -#endif - #ifdef LL_OPENAL #include "llaudioengine_openal.h" #endif @@ -996,15 +992,6 @@ bool idle_startup() } #endif -#ifdef LL_FMODEX -#if !LL_WINDOWS - if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) -#endif // !LL_WINDOWS - { - gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODProfilerEnable")); - } -#endif - #ifdef LL_OPENAL #if !LL_WINDOWS // if (NULL == getenv("LL_BAD_OPENAL_DRIVER")) diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index b3e07abc07..dff657391b 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -580,21 +580,14 @@ class WindowsManifest(ViewerManifest): print err.message print "Skipping GLOD library (assumming linked statically)" - # Get fmodstudio dll - if self.args['fmodversion'].lower() == 'fmodstudio': - if self.args['configuration'].lower() == 'debug': + # Get fmodstudio dll if needed + if self.args['fmodstudio'] == 'ON': + if(self.args['configuration'].lower() == 'debug'): self.path("fmodL.dll") else: self.path("fmod.dll") - # Get fmodex dll - if self.args['fmodversion'].lower() == 'fmodex': - if(self.address_size == 64): - self.path("fmodex64.dll") - else: - self.path("fmodex.dll") - - # Get openal dll + # Get openal dll if needed if self.args.get('openal') == 'ON': self.path("OpenAL32.dll") self.path("alut.dll") @@ -1166,17 +1159,18 @@ class DarwinManifest(ViewerManifest): # ): # self.path2basename(relpkgdir, libfile) - # # dylibs that vary based on configuration - # if self.args['configuration'].lower() == 'debug': - # for libfile in ( - # "libfmodexL.dylib", - # ): - # dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) - # else: - # for libfile in ( - # "libfmodex.dylib", - # ): - # dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) + # # Fmod studio dylibs (vary based on configuration) + # if self.args['fmodstudio'] == 'ON': + # if self.args['configuration'].lower() == 'debug': + # for libfile in ( + # "libfmodL.dylib", + # ): + # dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) + # else: + # for libfile in ( + # "libfmod.dylib", + # ): + # dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) # # our apps # executable_path = {} @@ -1414,8 +1408,8 @@ class DarwinManifest(ViewerManifest): ): self.path2basename(relpkgdir, libfile) - # dylibs that vary based on configuration - if self.args['fmodversion'].lower() == 'fmodstudio': + # Fmod studio dylibs (vary based on configuration) + if self.args['fmodstudio'] == 'ON': if self.args['configuration'].lower() == 'debug': for libfile in ( "libfmodL.dylib", @@ -1427,19 +1421,6 @@ class DarwinManifest(ViewerManifest): ): dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) - # dylibs that vary based on configuration - if self.args['fmodversion'].lower() == 'fmodex': - if self.args['configuration'].lower() == 'debug': - for libfile in ( - "libfmodexL.dylib", - ): - dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) - else: - for libfile in ( - "libfmodex.dylib", - ): - dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) - # our apps executable_path = {} for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"), @@ -2158,16 +2139,14 @@ class Linux_i686_Manifest(LinuxManifest): print "tcmalloc files not found, skipping" pass - if self.args['fmodversion'].lower() == 'fmodex': - self.path("libfmodex-*.so") - self.path("libfmodex.so") - self.path("libfmodex.so*") - pass - - if self.args['fmodversion'].lower() == 'fmodstudio': - self.path("libfmod.so") - self.path("libfmod.so*") - pass + if self.args['fmodstudio'] == 'ON': + try: + self.path("libfmod.so") + self.path("libfmod.so*") + pass + except: + print "Skipping libfmod.so - not found" + pass # Vivox runtimes @@ -2202,16 +2181,15 @@ class Linux_x86_64_Manifest(LinuxManifest): # No, we don't need to dink with this. A usable library # is now in the slvoice package, and we need to just use it as is. # self.path("libopenal32.so", "libvivoxoal.so.1") # vivox's sdk expects this soname - if self.args['fmodversion'].lower() == 'fmodex': - self.path("libfmodex64-*.so") - self.path("libfmodex64.so") - self.path("libfmodex64.so*") - pass - if self.args['fmodversion'].lower() == 'fmodstudio': - self.path("libfmod.so") - self.path("libfmod.so*") - pass + if self.args['fmodstudio'] == 'ON': + try: + self.path("libfmod.so") + self.path("libfmod.so*") + pass + except: + print "Skipping libfmod.so - not found" + pass with self.prefix(dst="bin"): self.path2basename("../llplugin/slplugin", "SLPlugin") @@ -2266,6 +2244,7 @@ if __name__ == "__main__": extra_arguments = [ dict(name='bugsplat', description="""BugSplat database to which to post crashes, if BugSplat crash reporting is desired""", default=''), + dict(name='fmodstudio', description="""Indication if fmod studio libraries are needed""", default='OFF'), dict(name='openal', description="""Indication openal libraries are needed""", default='OFF') ] try: diff --git a/scripts/configure_firestorm.sh b/scripts/configure_firestorm.sh index 3ce2959fec..447c931687 100755 --- a/scripts/configure_firestorm.sh +++ b/scripts/configure_firestorm.sh @@ -16,7 +16,6 @@ FALSE=1 # -DROOT_PROJECT_NAME:STRING=SecondLife # -DUSE_KDU=TRUE # -DFMODSTUDIO:BOOL=ON -# -DFMODEX:BOOL=ON # -DOPENSIM:BOOL=ON # -DUSE_AVX_OPTIMIZATION:BOOL=OFF # -DUSE_AVX2_OPTIMIZATION:BOOL=OFF @@ -34,7 +33,6 @@ WANTS_PACKAGE=$FALSE WANTS_VERSION=$FALSE WANTS_KDU=$FALSE WANTS_FMODSTUDIO=$FALSE -WANTS_FMODEX=$FALSE WANTS_OPENAL=$FALSE WANTS_OPENSIM=$TRUE WANTS_SINGLEGRID=$FALSE @@ -72,7 +70,6 @@ showUsage() echo " --package : Build installer" echo " --no-package : Build without installer (Overrides --package)" echo " --fmodstudio : Build with FMOD Studio" - echo " --fmodex : Build with FMOD Ex" echo " --openal : Build with OpenAL" echo " --opensim : Build with OpenSim support (Disables Havok features)" echo " --no-opensim : Build without OpenSim support (Overrides --opensim)" @@ -93,7 +90,7 @@ getArgs() # $* = the options passed in from main { if [ $# -gt 0 ]; then - while getoptex "clean build config version package no-package fmodstudio fmodex openal ninja jobs: platform: kdu opensim no-opensim singlegrid: avx avx2 crashreporting testbuild: help chan: btype:" "$@" ; do + while getoptex "clean build config version package no-package fmodstudio openal ninja jobs: platform: kdu opensim no-opensim singlegrid: avx avx2 crashreporting testbuild: help chan: btype:" "$@" ; do #ensure options are valid if [ -z "$OPTOPT" ] ; then @@ -112,7 +109,6 @@ getArgs() ;; kdu) WANTS_KDU=$TRUE;; fmodstudio) WANTS_FMODSTUDIO=$TRUE;; - fmodex) WANTS_FMODEX=$TRUE;; openal) WANTS_OPENAL=$TRUE;; opensim) WANTS_OPENSIM=$TRUE;; no-opensim) WANTS_OPENSIM=$FALSE;; @@ -300,7 +296,6 @@ echo -e "configure_firestorm.sh" > $LOG echo -e " PLATFORM: $PLATFORM" | tee -a $LOG echo -e " KDU: `b2a $WANTS_KDU`" | tee -a $LOG echo -e " FMODSTUDIO: `b2a $WANTS_FMODSTUDIO`" | tee -a $LOG -echo -e " FMODEX: `b2a $WANTS_FMODEX`" | tee -a $LOG echo -e " OPENAL: `b2a $WANTS_OPENAL`" | tee -a $LOG echo -e " OPENSIM: `b2a $WANTS_OPENSIM`" | tee -a $LOG if [ $WANTS_SINGLEGRID -eq $TRUE ] ; then @@ -429,11 +424,6 @@ if [ $WANTS_CONFIG -eq $TRUE ] ; then else FMODSTUDIO="-DFMODSTUDIO:BOOL=OFF" fi - if [ $WANTS_FMODEX -eq $TRUE ] ; then - FMODEX="-DFMODEX:BOOL=ON" - else - FMODEX="-DFMODEX:BOOL=OFF" - fi if [ $WANTS_OPENAL -eq $TRUE ] ; then OPENAL="-DOPENAL:BOOL=ON" else @@ -517,7 +507,7 @@ if [ $WANTS_CONFIG -eq $TRUE ] ; then UNATTENDED="-DUNATTENDED=ON" fi - cmake -G "$TARGET" ../indra $CHANNEL ${GITHASH} $FMODSTUDIO $FMODEX $OPENAL $KDU $OPENSIM $SINGLEGRID $AVX_OPTIMIZATION $AVX2_OPTIMIZATION $TESTBUILD $PACKAGE \ + cmake -G "$TARGET" ../indra $CHANNEL ${GITHASH} $FMODSTUDIO $OPENAL $KDU $OPENSIM $SINGLEGRID $AVX_OPTIMIZATION $AVX2_OPTIMIZATION $TESTBUILD $PACKAGE \ $UNATTENDED -DLL_TESTS:BOOL=OFF -DADDRESS_SIZE:STRING=$AUTOBUILD_ADDRSIZE -DCMAKE_BUILD_TYPE:STRING=$BTYPE \ $CRASH_REPORTING -DVIEWER_SYMBOL_FILE:STRING="${VIEWER_SYMBOL_FILE:-}" -DROOT_PROJECT_NAME:STRING=Firestorm $LL_ARGS_PASSTHRU | tee $LOG From 041d5a5c0be1e79d28cbe84fdf78eeea2d17600a Mon Sep 17 00:00:00 2001 From: Ansariel Date: Thu, 9 Apr 2020 00:43:56 +0200 Subject: [PATCH 10/50] Sync FMOD Studio implementation with upstream so we can keep our version when merging with upstream --- indra/llaudio/llaudioengine_fmodstudio.cpp | 1162 +++++++++-------- indra/llaudio/llaudioengine_fmodstudio.h | 14 +- indra/llaudio/lllistener_fmodstudio.cpp | 84 +- indra/llaudio/lllistener_fmodstudio.h | 37 +- indra/llaudio/llstreamingaudio_fmodstudio.cpp | 758 +++++------ indra/llaudio/llstreamingaudio_fmodstudio.h | 62 +- 6 files changed, 1079 insertions(+), 1038 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 48203b0371..90525d0549 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -1,11 +1,11 @@ /** * @file audioengine_fmodstudio.cpp * @brief Implementation of LLAudioEngine class abstracting the audio - * support as a FMOD Studio implementation + * support as a FMODSTUDIO implementation * - * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2014, Linden Research, Inc. + * 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 @@ -37,8 +37,8 @@ #include "llmath.h" #include "llrand.h" -#include "fmod.hpp" -#include "fmod_errors.h" +#include "fmodstudio/fmod.hpp" +#include "fmodstudio/fmod_errors.h" #include "lldir.h" #include "sound_ids.h" @@ -47,498 +47,532 @@ const U32 EXTRA_SOUND_CHANNELS = 10; -FMOD_RESULT F_CALLBACK windDSPCallback(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 *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels); FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) { - if (result == FMOD_OK) - { - return false; - } + if (result == FMOD_OK) + { + return false; + } - if (result != FMOD_ERR_INVALID_HANDLE) - { - LL_WARNS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - } - else - { - LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - } + if (result != FMOD_ERR_INVALID_HANDLE) + { + LL_WARNS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + } + else + { + LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + } - return true; + return true; } LLUUID FMOD_GUID_to_LLUUID(FMOD_GUID guid) { - return LLUUID(llformat("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid.Data1, guid.Data2, guid.Data3, - guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7])); + return LLUUID(llformat("%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid.Data1, guid.Data2, guid.Data3, + guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7])); } void set_device(FMOD::System* system, const LLUUID& device_uuid) { - LL_INFOS() << "LLAudioEngine_FMODSTUDIO::setDevice with device_uuid=" << device_uuid << LL_ENDL; + LL_INFOS() << "LLAudioEngine_FMODSTUDIO::setDevice with device_uuid=" << device_uuid << LL_ENDL; - int drivercount; - if (!Check_FMOD_Error(system->getNumDrivers(&drivercount), "FMOD::System::getNumDrivers") && drivercount > 0) - { - if (device_uuid.isNull()) - { - LL_INFOS() << "Setting driver \"Default\"" << LL_ENDL; - Check_FMOD_Error(system->setDriver(0), "FMOD::System::setDriver"); - } - else - { - FMOD_GUID guid; - int r_samplerate, r_channels; + int drivercount; + if (!Check_FMOD_Error(system->getNumDrivers(&drivercount), "FMOD::System::getNumDrivers") && drivercount > 0) + { + if (device_uuid.isNull()) + { + LL_INFOS() << "Setting driver \"Default\"" << LL_ENDL; + Check_FMOD_Error(system->setDriver(0), "FMOD::System::setDriver"); + } + else + { + FMOD_GUID guid; + int r_samplerate, r_channels; - for (int i = 0; i < drivercount; ++i) - { - if (!Check_FMOD_Error(system->getDriverInfo(i, NULL, 0, &guid, &r_samplerate, NULL, &r_channels), "FMOD::System::getDriverInfo")) - { - LLUUID driver_guid = FMOD_GUID_to_LLUUID(guid); + for (int i = 0; i < drivercount; ++i) + { + if (!Check_FMOD_Error(system->getDriverInfo(i, NULL, 0, &guid, &r_samplerate, NULL, &r_channels), "FMOD::System::getDriverInfo")) + { + LLUUID driver_guid = FMOD_GUID_to_LLUUID(guid); - if (driver_guid == device_uuid) - { - LL_INFOS() << "Setting driver " << i << ": " << driver_guid << LL_ENDL; - Check_FMOD_Error(system->setDriver(i), "FMOD::System::setDriver"); - return; - } - } - } + if (driver_guid == device_uuid) + { + LL_INFOS() << "Setting driver " << i << ": " << driver_guid << LL_ENDL; + Check_FMOD_Error(system->setDriver(i), "FMOD::System::setDriver"); + return; + } + } + } - LL_INFOS() << "Device not available (anymore) - falling back to default" << LL_ENDL; - Check_FMOD_Error(system->setDriver(0), "FMOD::System::setDriver"); - } - } + LL_INFOS() << "Device not available (anymore) - falling back to default" << LL_ENDL; + Check_FMOD_Error(system->setDriver(0), "FMOD::System::setDriver"); + } + } } FMOD_RESULT F_CALLBACK systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata) { - FMOD::System* sys = (FMOD::System*)system; - LLAudioEngine_FMODSTUDIO* audio_engine = (LLAudioEngine_FMODSTUDIO*)userdata; + FMOD::System* sys = (FMOD::System*)system; + LLAudioEngine_FMODSTUDIO* audio_engine = (LLAudioEngine_FMODSTUDIO*)userdata; - switch (type) - { - case FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED: - LL_DEBUGS() << "FMOD system callback FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED" << LL_ENDL; - if (sys && audio_engine) - { - set_device(sys, audio_engine->getSelectedDeviceUUID()); - audio_engine->OnOutputDeviceListChanged(audio_engine->getDevices()); - } - break; - default: - break; - } - return FMOD_OK; + switch (type) + { + case FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED: + LL_DEBUGS() << "FMOD system callback FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED" << LL_ENDL; + if (sys && audio_engine) + { + set_device(sys, audio_engine->getSelectedDeviceUUID()); + audio_engine->OnOutputDeviceListChanged(audio_engine->getDevices()); + } + break; + default: + break; + } + return FMOD_OK; } LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 resample_method) - : mInited(false) - , mWindGen(NULL) - , mWindDSPDesc(NULL) - , mWindDSP(NULL) - , mSystem(NULL) - , mEnableProfiler(enable_profiler) - , mResampleMethod(resample_method) - , mSelectedDeviceUUID() + : mInited(false), + mWindGen(nullptr), + mWindDSPDesc(nullptr), + mWindDSP(nullptr), + mSystem(nullptr), + mEnableProfiler(enable_profiler), + mResampleMethod(resample_method), + mSelectedDeviceUUID() { } LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() { + delete mWindDSPDesc; } bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) { - U32 version; - FMOD_RESULT result; + U32 version; + FMOD_RESULT result; - LL_DEBUGS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() initializing FMOD" << LL_ENDL; + 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; + 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(num_channels, userdata); - - result = mSystem->getVersion(&version); - Check_FMOD_Error(result, "FMOD::System::getVersion"); + //will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer. + LLAudioEngine::init(num_channels, userdata); - if (version < FMOD_VERSION) - { - LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Studio version (" << version - << ")! You should be using FMOD Studio" << FMOD_VERSION << LL_ENDL; - } + result = mSystem->getVersion(&version); + Check_FMOD_Error(result, "FMOD::System::getVersion"); - // In this case, all sounds, PLUS wind and stream will be software. - result = mSystem->setSoftwareChannels(num_channels + EXTRA_SOUND_CHANNELS); - Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); + if (version < FMOD_VERSION) + { + LL_WARNS("AppInit") << "FMOD Studio version mismatch, actual: " << version + << " expected:" << FMOD_VERSION << LL_ENDL; + } - Check_FMOD_Error(mSystem->setCallback(systemCallback), "FMOD::System::setCallback"); - Check_FMOD_Error(mSystem->setUserData(this), "FMOD::System::setUserData"); + // In this case, all sounds, PLUS wind and stream will be software. + result = mSystem->setSoftwareChannels(num_channels + EXTRA_SOUND_CHANNELS); + Check_FMOD_Error(result, "FMOD::System::setSoftwareChannels"); - FMOD_ADVANCEDSETTINGS adv_settings = { }; - adv_settings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS); - switch (mResampleMethod) - { - default: - case RESAMPLE_LINEAR: - adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_LINEAR; - break; - case RESAMPLE_CUBIC: - adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_CUBIC; - break; - case RESAMPLE_SPLINE: - adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_SPLINE; - break; - } + Check_FMOD_Error(mSystem->setCallback(systemCallback), "FMOD::System::setCallback"); + Check_FMOD_Error(mSystem->setUserData(this), "FMOD::System::setUserData"); - result = mSystem->setAdvancedSettings(&adv_settings); - Check_FMOD_Error(result, "FMOD::System::setAdvancedSettings"); + FMOD_ADVANCEDSETTINGS settings = { }; + settings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS); + switch (mResampleMethod) + { + default: + case RESAMPLE_LINEAR: + settings.resamplerMethod = FMOD_DSP_RESAMPLER_LINEAR; + break; + case RESAMPLE_CUBIC: + settings.resamplerMethod = FMOD_DSP_RESAMPLER_CUBIC; + break; + case RESAMPLE_SPLINE: + settings.resamplerMethod = FMOD_DSP_RESAMPLER_SPLINE; + break; + } - U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE; - if(mEnableProfiler) - { - fmod_flags |= FMOD_INIT_PROFILE_ENABLE; - } + result = mSystem->setAdvancedSettings(&settings); + Check_FMOD_Error(result, "FMOD::System::setAdvancedSettings"); + + 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; + bool audio_ok = false; - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; - if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK && - (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, const_cast(APP_NAME.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) - { - if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; - if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA)) == FMOD_OK && - (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, 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; - } + 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 ((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK && + (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, const_cast(APP_NAME.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 ((result = mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA)) == FMOD_OK && + (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, 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; - if(!Check_FMOD_Error(mSystem->getOutput(&output_type), "FMOD::System::getOutput")) - { - 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; - }; - } + // We're interested in logging which output method we + // ended up with, for QA purposes. + FMOD_OUTPUTTYPE output_type; + if (!Check_FMOD_Error(mSystem->getOutput(&output_type), "FMOD::System::getOutput")) + { + 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 - result = mSystem->init( num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0); - if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) - { - /* - Ok, the speaker mode selected isn't supported by this soundcard. Switch it - back to stereo... - */ - result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0); - Check_FMOD_Error(result,"Error falling back to stereo mode"); - /* - ... and re-init. - */ - result = mSystem->init( num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0); - } - if(Check_FMOD_Error(result, "Error initializing FMOD Studio")) - return false; + // initialize the FMOD engine + result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0); + if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) + { + /* + Ok, the speaker mode selected isn't supported by this soundcard. Switch it + back to stereo... + */ + result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0); + Check_FMOD_Error(result,"Error falling back to stereo mode"); + /* + ... and re-init. + */ + result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0); + } + if (Check_FMOD_Error(result, "Error initializing FMOD Studio")) + { + 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"); - } + 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_FMODSTUDIO(mSystem)); + // 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)); - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL; - FMOD_ADVANCEDSETTINGS adv_settings_dump = { }; - mSystem->getAdvancedSettings(&adv_settings_dump); + FMOD_ADVANCEDSETTINGS settings_dump = { }; + mSystem->getAdvancedSettings(&settings_dump); + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): resampler=" << settings_dump.resamplerMethod << " bytes" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): resampler=" << adv_settings.resamplerMethod << " bytes" << 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; - int r_numbuffers, r_samplerate, r_channels; - unsigned int r_bufferlength; - 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; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_channels=" << r_channels << LL_ENDL; - char r_name[512]; - 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; - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_channels=" << r_channels << 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; - int latency = 100; // optimistic default - i suspect if sample rate is 0, everything breaks. - 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; - mInited = true; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): initialization complete." << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): initialization complete." << LL_ENDL; + getDevices(); // Purely to print out available devices for debugging reasons - getDevices(); // Purely to print out available devices for debugging reasons - - return true; + return true; } //virtual LLAudioEngine_FMODSTUDIO::output_device_map_t LLAudioEngine_FMODSTUDIO::getDevices() { - output_device_map_t driver_map; + output_device_map_t driver_map; - int drivercount; - int r_samplerate, r_channels; - char r_name[512]; - FMOD_GUID guid; + int drivercount; + int r_samplerate, r_channels; + char r_name[512]; + FMOD_GUID guid; - if (!Check_FMOD_Error(mSystem->getNumDrivers(&drivercount), "FMOD::System::getNumDrivers")) - { - for (int i = 0; i < drivercount; ++i) - { - memset(r_name, 0, sizeof(r_name)); - if (!Check_FMOD_Error(mSystem->getDriverInfo(i, r_name, 511, &guid, &r_samplerate, NULL, &r_channels), "FMOD::System::getDriverInfo")) - { - LLUUID driver_guid = FMOD_GUID_to_LLUUID(guid); - driver_map.insert(std::make_pair(driver_guid, r_name)); + if (!Check_FMOD_Error(mSystem->getNumDrivers(&drivercount), "FMOD::System::getNumDrivers")) + { + for (int i = 0; i < drivercount; ++i) + { + memset(r_name, 0, sizeof(r_name)); + if (!Check_FMOD_Error(mSystem->getDriverInfo(i, r_name, 511, &guid, &r_samplerate, NULL, &r_channels), "FMOD::System::getDriverInfo")) + { + LLUUID driver_guid = FMOD_GUID_to_LLUUID(guid); + driver_map.insert(std::make_pair(driver_guid, r_name)); - LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::getDevices(): r_name=\"" << r_name << "\" - guid: " << driver_guid << LL_ENDL; - } - } - } + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::getDevices(): r_name=\"" << r_name << "\" - guid: " << driver_guid << LL_ENDL; + } + } + } - return driver_map; + return driver_map; } //virtual void LLAudioEngine_FMODSTUDIO::setDevice(const LLUUID& device_uuid) { - mSelectedDeviceUUID = device_uuid; - set_device(mSystem, device_uuid); + mSelectedDeviceUUID = device_uuid; + set_device(mSystem, device_uuid); } 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"; + 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"; } void LLAudioEngine_FMODSTUDIO::allocateListener(void) -{ - try - { - mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); - } - catch (const std::bad_alloc& e) - { - LL_WARNS() << "Listener allocation failed due to: " << e.what() << LL_ENDL; - } +{ + try + { + mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); + } + catch (const std::bad_alloc& e) + { + LL_WARNS() << "Listener allocation failed due to: " << e.what() << LL_ENDL; + } } void LLAudioEngine_FMODSTUDIO::shutdown() { - LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; - LLAudioEngine::shutdown(); - - LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; - if ( mSystem ) // speculative fix for MAINT-2657 - { - Check_FMOD_Error(mSystem->close(), "FMOD::System::close"); - Check_FMOD_Error(mSystem->release(), "FMOD::System::release"); - } - LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL; + stopInternetStream(); - delete mListenerp; - mListenerp = NULL; + LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; + LLAudioEngine::shutdown(); + + LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; + if (mSystem) + { + Check_FMOD_Error(mSystem->close(), "FMOD::System::close"); + Check_FMOD_Error(mSystem->release(), "FMOD::System::release"); + } + LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL; + + delete mListenerp; + mListenerp = NULL; } LLAudioBuffer * LLAudioEngine_FMODSTUDIO::createBuffer() { - return new LLAudioBufferFMODSTUDIO(mSystem); + return new LLAudioBufferFMODSTUDIO(mSystem); } LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel() { - return new LLAudioChannelFMODSTUDIO(mSystem); + return new LLAudioChannelFMODSTUDIO(mSystem); } bool LLAudioEngine_FMODSTUDIO::initWind() { - mNextWindUpdate = 0.0; + mNextWindUpdate = 0.0; - cleanupWind(); + if (!mWindDSPDesc) + { + mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); + } - mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); - memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero - mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; - strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); //Set name to "Wind Unit" - mWindDSPDesc->numoutputbuffers = 1; - mWindDSPDesc->read = &windDSPCallback; //Assign callback. - if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP") || !mWindDSP) - return false; + 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->numoutputbuffers = 1; + mWindDSPDesc->read = &windCallback; // Assign callback - may be called from arbitrary threads + if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP")) + return false; - int frequency = 44100; - FMOD_SPEAKERMODE mode; - if (!Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, nullptr), "FMOD::System::getSoftwareFormat")) - { - mWindGen = new LLWindGen((U32)frequency); + if (mWindGen) + delete mWindGen; - if (!Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData") && - !Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat") && - !Check_FMOD_Error(mSystem->playDSP(mWindDSP, nullptr, false, nullptr), "FMOD::System::playDSP")) - return true; //Success - } + int frequency = 44100; - cleanupWind(); - return false; + FMOD_SPEAKERMODE mode; + if (Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, nullptr), "FMOD::System::getSoftwareFormat")) + { + cleanupWind(); + return false; + } + + mWindGen = new LLWindGen((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* mastergroup = NULL; - if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&mastergroup), "FMOD::System::getMasterChannelGroup") && mastergroup) - Check_FMOD_Error(mastergroup->removeDSP(mWindDSP), "FMOD::ChannelGroup::removeDSP"); - Check_FMOD_Error(mWindDSP->release(), "FMOD::DSP::release"); - mWindDSP = NULL; - } + if (mWindDSP) + { + FMOD::ChannelGroup* master_group = NULL; + if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup") + && master_group) + { + Check_FMOD_Error(master_group->removeDSP(mWindDSP), "FMOD::ChannelGroup::removeDSP"); + } + Check_FMOD_Error(mWindDSP->release(), "FMOD::DSP::release"); + mWindDSP = NULL; + } - delete mWindDSPDesc; - mWindDSPDesc = NULL; + delete mWindDSPDesc; + mWindDSPDesc = NULL; - delete mWindGen; - mWindGen = 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; + 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 + if (!mEnableWind) + { + return; + } - wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); + if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) + { - // cerr << "Wind update" << endl; + // 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 - 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); - } + 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; - } + if (!mInited) + { + return; + } - gain = llclamp( gain, 0.0f, 1.0f ); + gain = llclamp(gain, 0.0f, 1.0f); - FMOD::ChannelGroup *master_group; - if(Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")) - return; + FMOD::ChannelGroup *master_group; + if (Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")) + { + return; + } - master_group->setVolume(gain); + 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()); - } + LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); + if (saimpl) + { + // fmod likes its streaming audio channel gain re-asserted after + // master volume change. + saimpl->setGain(saimpl->getGain()); + } } // @@ -552,191 +586,191 @@ LLAudioChannelFMODSTUDIO::LLAudioChannelFMODSTUDIO(FMOD::System *system) : LLAud LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO() { - cleanup(); + cleanup(); } bool LLAudioChannelFMODSTUDIO::updateBuffer() { - if (mCurrentSourcep) - { - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the channel for a different buffer. + if (mCurrentSourcep) + { + 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(); + 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; - } + // 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, nullptr, true, &mChannelp); - Check_FMOD_Error(result, "FMOD::System::playSound"); - } + // Actually play the sound. Start it off paused so we can do all the necessary + // setup. + if (!mChannelp) + { + FMOD_RESULT result = getSystem()->playSound(soundp, nullptr, true, &mChannelp); + Check_FMOD_Error(result, "FMOD::System::playSound"); + } - //LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL; - } + //LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL; + } - //FMOD_RESULT result; + //FMOD_RESULT result; - mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); - //Check_FMOD_Error(result, "FMOD::Channel::setVolume"); + 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; - }*/ - } - else - { - LL_DEBUGS() << "No source buffer!" << LL_ENDL; - return false; - } + 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; + }*/ + } + else + { + LL_DEBUGS() << "No source buffer!" << LL_ENDL; + return false; + } - return true; + return true; } void LLAudioChannelFMODSTUDIO::update3DPosition() { - if (!mChannelp) - { - // We're not actually a live channel (i.e., we're not playing back anything) - return; - } + 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; - } + 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->isAmbient()) - { - // Ambient sound, don't need to do any positional updates. - set3DMode(false); - } - else - { - // Localized sound. Update the position and velocity of the sound. - set3DMode(true); + if (mCurrentSourcep->isAmbient()) + { + // Ambient sound, 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"); - } + 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; - } + 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; - Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES),"FMOD::Channel::getPosition"); + // + // 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; + Check_FMOD_Error(mChannelp->getPosition(&cur_pos, FMOD_TIMEUNIT_PCMBYTES), "FMOD::Channel::getPosition"); - if (cur_pos < (U32)mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; + if (cur_pos < (U32)mLastSamplePos) + { + mLoopedThisFrame = true; + } + mLastSamplePos = cur_pos; } void LLAudioChannelFMODSTUDIO::cleanup() { - if (!mChannelp) - { - //LL_INFOS() << "Aborting cleanup with no channel handle." << LL_ENDL; - return; - } + if (!mChannelp) + { + // Aborting cleanup with no channel handle. + return; + } - //LL_INFOS() << "Cleaning up channel: " << mChannelID << LL_ENDL; - Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"); + //Cleaning up channel mChannelID + Check_FMOD_Error(mChannelp->stop(), "FMOD::Channel::stop"); - mCurrentBufferp = NULL; - mChannelp = NULL; + mCurrentBufferp = NULL; + mChannelp = NULL; } void LLAudioChannelFMODSTUDIO::play() { - if (!mChannelp) - { - LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; - return; - } + if (!mChannelp) + { + LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; + return; + } - Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused"); + Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused"); - getSource()->setPlayedOnce(true); + getSource()->setPlayedOnce(true); - if(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]) - Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]),"FMOD::Channel::setChannelGroup"); + if (LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]) + Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]), "FMOD::Channel::setChannelGroup"); } 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; - } + 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; + 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"); + cur_pos %= mCurrentBufferp->getLength(); - // Start us playing - play(); + // 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; - } + if (!mChannelp) + { + return false; + } - bool paused, playing; - Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused"); - Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying"); - return !paused && playing; + bool paused, playing; + Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused"); + Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying"); + return !paused && playing; } @@ -752,109 +786,109 @@ LLAudioBufferFMODSTUDIO::LLAudioBufferFMODSTUDIO(FMOD::System *system) : mSystem LLAudioBufferFMODSTUDIO::~LLAudioBufferFMODSTUDIO() { - if(mSoundp) - { - Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release"); - mSoundp = NULL; - } + if (mSoundp) + { + Check_FMOD_Error(mSoundp->release(), "FMOD::Sound::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; - } + // 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. - Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release"); - mSoundp = NULL; - } + if (!gDirUtilp->fileExists(filename)) + { + // File not found, abort. + return false; + } - 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 - 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 (mSoundp) + { + // If there's already something loaded in this buffer, clean it up. + Check_FMOD_Error(mSoundp->release(), "FMOD::Sound::release"); + mSoundp = NULL; + } - // - // 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; - } + 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 + FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); - // Everything went well, return true - return true; + 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; - } + if (!mSoundp) + { + return 0; + } - U32 length; - Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength"); - return length; + U32 length; + Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES), "FMOD::Sound::getLength"); + return length; } void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d) { - FMOD_MODE current_mode; - 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); - new_mode |= use3d ? FMOD_3D : FMOD_2D; + FMOD_MODE current_mode; + 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); + new_mode |= use3d ? FMOD_3D : FMOD_2D; - if(current_mode != new_mode) - { - Check_FMOD_Error(mChannelp->setMode(new_mode),"FMOD::Channel::setMode"); - } + if (current_mode != new_mode) + { + Check_FMOD_Error(mChannelp->setMode(new_mode), "FMOD::Channel::setMode"); + } } // *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 windDSPCallback(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 *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) { - // inbuffer = incomming data. - // newbuffer = outgoing data. AKA this DSP's output. - // length = length in samples at this mix time. True buffer size, in bytes, would be (length * sizeof(float) * inchannels). - // userdata = user-provided data attached this DSP via FMOD::DSP::setUserData. - - LLWindGen *windgen; - FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; + // inbuffer = fmod's original mixbuffer. + // outbuffer = the buffer passed from the previous DSP unit. + // length = length in samples at this mix time. - thisdsp->getUserData((void **)&windgen); - - if (windgen) - windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); + LLWindGen *windgen; + FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; - return FMOD_OK; + 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 index 3b80f45336..be283dec1c 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.h +++ b/indra/llaudio/llaudioengine_fmodstudio.h @@ -1,11 +1,11 @@ /** * @file audioengine_fmodstudio.h * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMOD Studio implementation + * support as a FMODSTUDIO implementation * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2014, Linden Research, Inc. + * 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 @@ -103,8 +103,8 @@ public: class LLAudioChannelFMODSTUDIO : public LLAudioChannel { public: - LLAudioChannelFMODSTUDIO(FMOD::System *audioengine); - virtual ~LLAudioChannelFMODSTUDIO(); + LLAudioChannelFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioChannelFMODSTUDIO(); protected: /*virtual*/ void play(); @@ -128,8 +128,8 @@ protected: class LLAudioBufferFMODSTUDIO : public LLAudioBuffer { public: - LLAudioBufferFMODSTUDIO(FMOD::System *audioengine); - virtual ~LLAudioBufferFMODSTUDIO(); + LLAudioBufferFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioBufferFMODSTUDIO(); /*virtual*/ bool loadWAV(const std::string& filename); /*virtual*/ U32 getLength(); diff --git a/indra/llaudio/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp index f5a10442dc..d2e8f4e846 100644 --- a/indra/llaudio/lllistener_fmodstudio.cpp +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -1,11 +1,11 @@ /** * @file listener_fmodstudio.cpp * @brief Implementation of LISTENER class abstracting the audio - * support as a FMOD Studio implementation + * support as a FMODSTUDIO implementation * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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 @@ -28,17 +28,15 @@ #include "linden_common.h" #include "llaudioengine.h" #include "lllistener_fmodstudio.h" -#include "fmod.hpp" +#include "fmodstudio/fmod.hpp" //----------------------------------------------------------------------- // constructor //----------------------------------------------------------------------- -LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system) - : LLListener(), - mDopplerFactor(1.0f), - mRolloffFactor(1.0f) +LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system) { - mSystem = system; + mSystem = system; + init(); } //----------------------------------------------------------------------- @@ -46,82 +44,90 @@ 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); + LLListener::translate(offset); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); } //----------------------------------------------------------------------- void LLListener_FMODSTUDIO::setPosition(LLVector3 pos) { - LLListener::setPosition(pos); + LLListener::setPosition(pos); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); } //----------------------------------------------------------------------- void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel) { - LLListener::setVelocity(vel); + LLListener::setVelocity(vel); - mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL); + mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL); } //----------------------------------------------------------------------- void LLListener_FMODSTUDIO::orient(LLVector3 up, LLVector3 at) { - LLListener::orient(up, at); + LLListener::orient(up, at); - mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); + mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); } //----------------------------------------------------------------------- void LLListener_FMODSTUDIO::commitDeferredChanges() { - if(!mSystem) - { - return; - } + if (!mSystem) + { + return; + } - mSystem->update(); + mSystem->update(); } void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor) { - //An internal FMOD Studio optimization skips 3D updates if there have not been changes to the 3D sound environment. - //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 studio, which makes it not skip 3D processing next update call. - if(mRolloffFactor != factor) - { - LLVector3 tmp_pos = mPosition - LLVector3(0.f,0.f,.1f); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) tmp_pos.mV, NULL, NULL, NULL); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) mPosition.mV, NULL, NULL, NULL); - } - mRolloffFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); + //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) + //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; + return mRolloffFactor; } void LLListener_FMODSTUDIO::setDopplerFactor(F32 factor) { - mDopplerFactor = factor; - mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); + mDopplerFactor = factor; + mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); } F32 LLListener_FMODSTUDIO::getDopplerFactor() { - return mDopplerFactor; + return mDopplerFactor; } - - diff --git a/indra/llaudio/lllistener_fmodstudio.h b/indra/llaudio/lllistener_fmodstudio.h index ebe42f0e38..2dd02fc783 100644 --- a/indra/llaudio/lllistener_fmodstudio.h +++ b/indra/llaudio/lllistener_fmodstudio.h @@ -3,9 +3,9 @@ * @brief Description of LISTENER class abstracting the audio support * as an FMOD Studio implementation (windows and Linux) * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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 @@ -39,24 +39,25 @@ namespace FMOD //Interfaces class LLListener_FMODSTUDIO : public LLListener { - public: - LLListener_FMODSTUDIO(FMOD::System *system); - virtual ~LLListener_FMODSTUDIO(); +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 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; + 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 index edf63c90c6..6d622b4e19 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.cpp +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -2,9 +2,9 @@ * @file streamingaudio_fmodstudio.cpp * @brief LLStreamingAudio_FMODSTUDIO implementation * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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 @@ -28,38 +28,38 @@ #include "llmath.h" -#include "fmod.hpp" -#include "fmod_errors.h" +#include "fmodstudio/fmod.hpp" +#include "fmodstudio/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; + 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, FMOD::ChannelGroup *group, const std::string& url); - FMOD::Channel* startStream(); - bool stopStream(); // Returns true if the stream was successfully stopped. - bool ready(); + 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(); - const std::string& getURL() { return mInternetStreamURL; } + const std::string& getURL() { return mInternetStreamURL; } - FMOD_RESULT getOpenState(FMOD_OPENSTATE& openstate, 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::ChannelGroup* mChannelGroup; - FMOD::Channel* mStreamChannel; - FMOD::Sound* mInternetStream; - bool mReady; + FMOD::System* mSystem; + FMOD::ChannelGroup* mChannelGroup; + FMOD::Channel* mStreamChannel; + FMOD::Sound* mInternetStream; + bool mReady; - std::string mInternetStreamURL; + std::string mInternetStreamURL; }; @@ -68,290 +68,290 @@ protected: // Internet Streaming //--------------------------------------------------------------------------- LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : - mSystem(system), - mCurrentInternetStreamp(NULL), - mStreamGroup(NULL), - mFMODInternetStreamChannelp(NULL), - mGain(1.0f) + mSystem(system), + mCurrentInternetStreamp(NULL), + mStreamGroup(NULL), + mFMODInternetStreamChannelp(NULL), + mGain(1.0f) { - FMOD_RESULT result; + 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 - result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); - Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize"); + // 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 + result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); + Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize"); - Check_FMOD_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup"); } LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() { - stop(); - for (U32 i = 0; i < 100; ++i) - { - if (releaseDeadStreams()) - break; - ms_sleep(10); - } + stop(); + for (U32 i = 0; i < 100; ++i) + { + if (releaseDeadStreams()) + break; + ms_sleep(10); + } } void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) { - //if (!mInited) - //{ - // LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL; - // return; - //} + //if (!mInited) + //{ + // LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL; + // return; + //} - // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL - stop(); + // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL + stop(); - if (!url.empty()) - { - if(mDeadStreams.empty()) - { - LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, url); - mURL = url; - } - else - { - LL_INFOS() << "Deferring stream load until buffer release: " << url << LL_ENDL; - mPendingURL = url; - } - } - else - { - LL_INFOS() << "Set internet stream to null" << LL_ENDL; - mURL.clear(); - } + if (!url.empty()) + { + if(mDeadStreams.empty()) + { + LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, url); + mURL = url; + } + else + { + LL_INFOS() << "Deferring stream load until buffer release: " << url << LL_ENDL; + mPendingURL = url; + } + } + else + { + LL_INFOS() << "Set internet stream to null" << LL_ENDL; + mURL.clear(); + } } void LLStreamingAudio_FMODSTUDIO::update() { - if (!releaseDeadStreams()) - { - llassert_always(mCurrentInternetStreamp == NULL); - return; - } + if (!releaseDeadStreams()) + { + llassert_always(mCurrentInternetStreamp == NULL); + return; + } - if(!mPendingURL.empty()) - { - llassert_always(mCurrentInternetStreamp == NULL); - LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, mPendingURL); - mURL = mPendingURL; - mPendingURL.clear(); - } + if(!mPendingURL.empty()) + { + llassert_always(mCurrentInternetStreamp == NULL); + LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, mPendingURL); + mURL = mPendingURL; + mPendingURL.clear(); + } - // Don't do anything if there are no streams playing - if (!mCurrentInternetStreamp) - { - return; - } + // Don't do anything if there are no streams playing + if (!mCurrentInternetStreamp) + { + return; + } - unsigned int progress; - bool starving; - bool diskbusy; - FMOD_OPENSTATE open_state; - FMOD_RESULT result = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy); + unsigned int progress; + bool starving; + bool diskbusy; + FMOD_OPENSTATE open_state; + FMOD_RESULT result = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy); - if (result != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR) - { - stop(); - return; - } - else if (open_state == FMOD_OPENSTATE_READY) - { - // Stream is live + if (result != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR) + { + stop(); + return; + } + else 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()); - Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); - } - } + // start the stream if it's ready + if (!mFMODInternetStreamChannelp && + (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream())) + { + // Reset volume to previously set volume + setGain(getGain()); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); + } + } - if(mFMODInternetStreamChannelp) - { - FMOD::Sound *sound = NULL; + if (mFMODInternetStreamChannelp) + { + FMOD::Sound *sound = NULL; - if (!Check_FMOD_Error(mFMODInternetStreamChannelp->getCurrentSound(&sound), "FMOD::Channel::getCurrentSound") && sound) - { - FMOD_TAG tag; - S32 tagcount, dirtytagcount; + if (!Check_FMOD_Error(mFMODInternetStreamChannelp->getCurrentSound(&sound), "FMOD::Channel::getCurrentSound") && sound) + { + FMOD_TAG tag; + S32 tagcount, dirtytagcount; - if (!Check_FMOD_Error(sound->getNumTags(&tagcount, &dirtytagcount), "FMOD::Sound::getNumTags") && dirtytagcount) - { - LL_DEBUGS("StreamMetadata") << "Tag count: " << tagcount << " Dirty tag count: " << dirtytagcount << LL_ENDL; + if (!Check_FMOD_Error(sound->getNumTags(&tagcount, &dirtytagcount), "FMOD::Sound::getNumTags") && dirtytagcount) + { + LL_DEBUGS("StreamMetadata") << "Tag count: " << tagcount << " Dirty tag count: " << dirtytagcount << LL_ENDL; - // Stream metadata - originally by Shyotl Khur - mMetadata.clear(); - mNewMetadata = true; - // - for(S32 i = 0; i < tagcount; ++i) - { - if(Check_FMOD_Error(sound->getTag(NULL, i, &tag), "FMOD::Sound::getTag")) - continue; + // Stream metadata - originally by Shyotl Khur + mMetadata.clear(); + mNewMetadata = true; + // + for(S32 i = 0; i < tagcount; ++i) + { + if(Check_FMOD_Error(sound->getTag(NULL, i, &tag), "FMOD::Sound::getTag")) + continue; - LL_DEBUGS("StreamMetadata") << "Tag name: " << tag.name << " - Tag type: " << tag.type << " - Tag data type: " << tag.datatype << LL_ENDL; + LL_DEBUGS("StreamMetadata") << "Tag name: " << tag.name << " - Tag type: " << tag.type << " - Tag data type: " << tag.datatype << LL_ENDL; - std::string name = tag.name; - switch(tag.type) - { - case(FMOD_TAGTYPE_ID3V2): - { - if(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"; - break; - } - case(FMOD_TAGTYPE_VORBISCOMMENT): - { - if(name == "title") name = "TITLE"; - else if(name == "artist") name = "ARTIST"; - break; - } - case(FMOD_TAGTYPE_FMOD): - { - if (!strcmp(tag.name, "Sample Rate Change")) - { - LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; - mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); - } - continue; - } - default: - break; - } - switch(tag.datatype) - { - case(FMOD_TAGDATATYPE_INT): - { - (mMetadata)[name]=*(LLSD::Integer*)(tag.data); - LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(int*)(tag.data) << LL_ENDL; - break; - } - case(FMOD_TAGDATATYPE_FLOAT): - { - (mMetadata)[name]=*(LLSD::Real*)(tag.data); - LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(float*)(tag.data) << LL_ENDL; - break; - } - case(FMOD_TAGDATATYPE_STRING): - { - std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); - (mMetadata)[name]=out; - LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; - break; - } - case(FMOD_TAGDATATYPE_STRING_UTF8): - { - std::string out((char*)tag.data); - (mMetadata)[name]=out; - LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; - break; - } - case(FMOD_TAGDATATYPE_STRING_UTF16): - { - std::string out((char*)tag.data,tag.datalen); - (mMetadata)[std::string(tag.name)]=out; - LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; - 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; - LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; - break; - } - default: - break; - } - } - } + std::string name = tag.name; + switch(tag.type) + { + case(FMOD_TAGTYPE_ID3V2): + { + if(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"; + break; + } + case(FMOD_TAGTYPE_VORBISCOMMENT): + { + if(name == "title") name = "TITLE"; + else if(name == "artist") name = "ARTIST"; + break; + } + case(FMOD_TAGTYPE_FMOD): + { + if (!strcmp(tag.name, "Sample Rate Change")) + { + LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; + mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); + } + continue; + } + default: + break; + } + switch(tag.datatype) + { + case(FMOD_TAGDATATYPE_INT): + { + (mMetadata)[name]=*(LLSD::Integer*)(tag.data); + LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(int*)(tag.data) << LL_ENDL; + break; + } + case(FMOD_TAGDATATYPE_FLOAT): + { + (mMetadata)[name]=*(LLSD::Real*)(tag.data); + LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(float*)(tag.data) << LL_ENDL; + break; + } + case(FMOD_TAGDATATYPE_STRING): + { + std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); + (mMetadata)[name]=out; + LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; + break; + } + case(FMOD_TAGDATATYPE_STRING_UTF8): + { + std::string out((char*)tag.data); + (mMetadata)[name]=out; + LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; + break; + } + case(FMOD_TAGDATATYPE_STRING_UTF16): + { + std::string out((char*)tag.data,tag.datalen); + (mMetadata)[std::string(tag.name)]=out; + LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; + 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; + LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; + break; + } + default: + break; + } + } + } - if(starving) - { - bool paused = false; - 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), "FMOD::Channel::setPaused"); - } - } - else if(progress > 80) - { - Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); - } - } - } + if (starving) + { + bool paused = false; + 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), "FMOD::Channel::setPaused"); + } + } + else if (progress > 80) + { + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); + } + } + } } void LLStreamingAudio_FMODSTUDIO::stop() { - mPendingURL.clear(); + mPendingURL.clear(); - if (mFMODInternetStreamChannelp) - { - Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused"); - Check_FMOD_Error(mFMODInternetStreamChannelp->setPriority(0), "FMOD::Channel::setPriority"); - mFMODInternetStreamChannelp = NULL; - } + if (mFMODInternetStreamChannelp) + { + Check_FMOD_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused"); + Check_FMOD_Error(mFMODInternetStreamChannelp->setPriority(0), "FMOD::Channel::setPriority"); + mFMODInternetStreamChannelp = NULL; + } - if (mCurrentInternetStreamp) - { - LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - if (mCurrentInternetStreamp->stopStream()) - { - delete mCurrentInternetStreamp; - } - else - { - LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - mDeadStreams.push_back(mCurrentInternetStreamp); - } - mCurrentInternetStreamp = NULL; - } + if (mCurrentInternetStreamp) + { + LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + if (mCurrentInternetStreamp->stopStream()) + { + delete mCurrentInternetStreamp; + } + else + { + LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + mDeadStreams.push_back(mCurrentInternetStreamp); + } + mCurrentInternetStreamp = NULL; + } } void LLStreamingAudio_FMODSTUDIO::pause(int pauseopt) { - if (pauseopt < 0) - { - pauseopt = mCurrentInternetStreamp ? 1 : 0; - } + if (pauseopt < 0) + { + pauseopt = mCurrentInternetStreamp ? 1 : 0; + } - if (pauseopt) - { - if (mCurrentInternetStreamp) - { - stop(); - } - } - else - { - start(getURL()); - } + if (pauseopt) + { + if (mCurrentInternetStreamp) + { + stop(); + } + } + else + { + start(getURL()); + } } @@ -359,179 +359,179 @@ void LLStreamingAudio_FMODSTUDIO::pause(int pauseopt) // 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() || !mPendingURL.empty()) - { - return 2; // "Paused" - } - else - { - return 0; - } + if (mCurrentInternetStreamp) + { + return 1; // Active and playing + } + else if (!mURL.empty() || !mPendingURL.empty()) + { + return 2; // "Paused" + } + else + { + return 0; + } } F32 LLStreamingAudio_FMODSTUDIO::getGain() { - return mGain; + return mGain; } std::string LLStreamingAudio_FMODSTUDIO::getURL() { - return mURL; + return mURL; } void LLStreamingAudio_FMODSTUDIO::setGain(F32 vol) { - mGain = vol; + mGain = vol; - if (mFMODInternetStreamChannelp) - { - vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? + if (mFMODInternetStreamChannelp) + { + vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? - Check_FMOD_Error(mFMODInternetStreamChannelp->setVolume(vol), "FMOD::Channel::setVolume"); - } + Check_FMOD_Error(mFMODInternetStreamChannelp->setVolume(vol), "FMOD::Channel::setVolume"); + } } // Streamtitle display // virtual bool LLStreamingAudio_FMODSTUDIO::getNewMetadata(LLSD& metadata) { - if (mCurrentInternetStreamp) - { - if (mNewMetadata) - { - metadata = mMetadata; - mNewMetadata = false; - return true; - } - - return mNewMetadata; - } + if (mCurrentInternetStreamp) + { + if (mNewMetadata) + { + metadata = mMetadata; + mNewMetadata = false; + return true; + } + + return mNewMetadata; + } - metadata = LLSD(); - return false; + metadata = LLSD(); + return false; } // /////////////////////////////////////////////////////// // manager of possibly-multiple internet audio streams LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url) : - mSystem(system), - mChannelGroup(group), - mStreamChannel(NULL), - mInternetStream(NULL), - mReady(false) + mSystem(system), + mChannelGroup(group), + mStreamChannel(NULL), + mInternetStream(NULL), + mReady(false) { - mInternetStreamURL = url; + mInternetStreamURL = url; - FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream); + FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream); - if (result!= FMOD_OK) - { - LL_WARNS() << "Couldn't open fmod stream, error " - << FMOD_ErrorString(result) - << LL_ENDL; - mReady = false; - return; - } + if (result!= FMOD_OK) + { + LL_WARNS() << "Couldn't open fmod stream, error " + << FMOD_ErrorString(result) + << LL_ENDL; + mReady = false; + return; + } - mReady = true; + mReady = true; } FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream() { - // We need a live and opened stream before we try and play it. - 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; - } + // We need a live and opened stream before we try and play it. + 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; + } - if(mStreamChannel) - return mStreamChannel; //Already have a channel for this stream. + if(mStreamChannel) + return mStreamChannel; //Already have a channel for this stream. - Check_FMOD_Error(mSystem->playSound(mInternetStream, mChannelGroup, true, &mStreamChannel), "FMOD::System::playSound"); - return mStreamChannel; + Check_FMOD_Error(mSystem->playSound(mInternetStream, mChannelGroup, true, &mStreamChannel), "FMOD::System::playSound"); + return mStreamChannel; } bool LLAudioStreamManagerFMODSTUDIO::stopStream() { - if (mInternetStream) - { - bool close = true; - FMOD_OPENSTATE open_state; - if (getOpenState(open_state) == FMOD_OK) - { - switch (open_state) - { - case FMOD_OPENSTATE_CONNECTING: - close = false; - break; - default: - close = true; - } - } + if (mInternetStream) + { + bool close = true; + FMOD_OPENSTATE open_state; + if (getOpenState(open_state) == FMOD_OK) + { + switch (open_state) + { + case FMOD_OPENSTATE_CONNECTING: + close = false; + break; + default: + close = true; + } + } - if (close && mInternetStream->release() == FMOD_OK) - { - mStreamChannel = NULL; - mInternetStream = NULL; - return true; - } - else - { - return false; - } - } - else - { - return true; - } + if (close && mInternetStream->release() == FMOD_OK) + { + mStreamChannel = NULL; + mInternetStream = NULL; + return true; + } + else + { + return false; + } + } + else + { + return true; + } } FMOD_RESULT LLAudioStreamManagerFMODSTUDIO::getOpenState(FMOD_OPENSTATE& state, unsigned int* percentbuffered, bool* starving, bool* diskbusy) { - 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; + 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_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) { - 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 - Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings"); + 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 + Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings"); } bool LLStreamingAudio_FMODSTUDIO::releaseDeadStreams() { - // Kill dead internet streams, if possible - std::list::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) - { - LLAudioStreamManagerFMODSTUDIO *streamp = *iter; - if (streamp->stopStream()) - { - LL_INFOS() << "Closed dead stream" << LL_ENDL; - delete streamp; - mDeadStreams.erase(iter++); - } - else - { - iter++; - } - } + // Kill dead internet streams, if possible + std::list::iterator iter; + for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + { + LLAudioStreamManagerFMODSTUDIO *streamp = *iter; + if (streamp->stopStream()) + { + LL_INFOS() << "Closed dead stream" << LL_ENDL; + delete streamp; + mDeadStreams.erase(iter++); + } + else + { + iter++; + } + } - return mDeadStreams.empty(); + return mDeadStreams.empty(); } diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h index d220ddd02c..7ec5a0dbf4 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.h +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -2,9 +2,9 @@ * @file streamingaudio_fmodstudio.h * @brief Definition of LLStreamingAudio_FMODSTUDIO implementation * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. + * 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 @@ -45,41 +45,41 @@ namespace FMOD //Interfaces class LLStreamingAudio_FMODSTUDIO : public LLStreamingAudioInterface { - public: - LLStreamingAudio_FMODSTUDIO(FMOD::System *system); - /*virtual*/ ~LLStreamingAudio_FMODSTUDIO(); +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*/ 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); - //Streamtitle display DKO - virtual bool getNewMetadata(LLSD& metadata); - // DKO + /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} + /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); + //Streamtitle display DKO + virtual bool getNewMetadata(LLSD& metadata); + // DKO private: - bool releaseDeadStreams(); + bool releaseDeadStreams(); - FMOD::System *mSystem; + FMOD::System *mSystem; - LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; - FMOD::ChannelGroup* mStreamGroup; - FMOD::Channel *mFMODInternetStreamChannelp; - std::list mDeadStreams; + LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; + FMOD::ChannelGroup* mStreamGroup; + FMOD::Channel *mFMODInternetStreamChannelp; + std::list mDeadStreams; - std::string mURL; - std::string mPendingURL; - F32 mGain; - // Streamtitle display - bool mNewMetadata; - LLSD mMetadata; - // Streamtitle display + std::string mURL; + std::string mPendingURL; + F32 mGain; + // Streamtitle display + bool mNewMetadata; + LLSD mMetadata; + // Streamtitle display }; From 773eeb1d378c2620ceba3678598357d4b0d5b21d Mon Sep 17 00:00:00 2001 From: Ansariel Date: Thu, 9 Apr 2020 08:30:08 +0200 Subject: [PATCH 11/50] More upstream sync --- indra/llaudio/llstreamingaudio_fmodstudio.cpp | 95 +++++++++---------- 1 file changed, 45 insertions(+), 50 deletions(-) diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp index 6d622b4e19..5fef19d6d2 100644 --- a/indra/llaudio/llstreamingaudio_fmodstudio.cpp +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -68,20 +68,17 @@ protected: // Internet Streaming //--------------------------------------------------------------------------- LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : - mSystem(system), - mCurrentInternetStreamp(NULL), - mStreamGroup(NULL), - mFMODInternetStreamChannelp(NULL), - mGain(1.0f) +mSystem(system), +mCurrentInternetStreamp(NULL), +mStreamGroup(NULL), +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 - result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); - Check_FMOD_Error(result, "FMOD::System::setStreamBufferSize"); + Check_FMOD_Error(mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES), "FMOD::System::setStreamBufferSize"); Check_FMOD_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup"); } @@ -95,7 +92,6 @@ LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() break; ms_sleep(10); } - } void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) @@ -111,7 +107,7 @@ void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) if (!url.empty()) { - if(mDeadStreams.empty()) + if (mDeadStreams.empty()) { LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, url); @@ -139,7 +135,7 @@ void LLStreamingAudio_FMODSTUDIO::update() return; } - if(!mPendingURL.empty()) + if (!mPendingURL.empty()) { llassert_always(mCurrentInternetStreamp == NULL); LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL; @@ -158,9 +154,8 @@ void LLStreamingAudio_FMODSTUDIO::update() bool starving; bool diskbusy; FMOD_OPENSTATE open_state; - FMOD_RESULT result = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy); - if (result != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR) + if (Check_FMOD_Error(mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy), "FMOD::Sound::getOpenState") || open_state == FMOD_OPENSTATE_ERROR) { stop(); return; @@ -197,39 +192,39 @@ void LLStreamingAudio_FMODSTUDIO::update() mMetadata.clear(); mNewMetadata = true; // - for(S32 i = 0; i < tagcount; ++i) + for (S32 i = 0; i < tagcount; ++i) { - if(Check_FMOD_Error(sound->getTag(NULL, i, &tag), "FMOD::Sound::getTag")) + if (Check_FMOD_Error(sound->getTag(NULL, i, &tag), "FMOD::Sound::getTag")) continue; LL_DEBUGS("StreamMetadata") << "Tag name: " << tag.name << " - Tag type: " << tag.type << " - Tag data type: " << tag.datatype << LL_ENDL; std::string name = tag.name; - switch(tag.type) + switch (tag.type) { - case(FMOD_TAGTYPE_ID3V2): + case FMOD_TAGTYPE_ID3V2: { - if(name == "TIT2") name = "TITLE"; - else if(name == "TPE1") name = "ARTIST"; + if (name == "TIT2") name = "TITLE"; + else if (name == "TPE1") name = "ARTIST"; break; } - case(FMOD_TAGTYPE_ASF): + case FMOD_TAGTYPE_ASF: { - if(name == "Title") name = "TITLE"; - else if(name == "WM/AlbumArtist") name = "ARTIST"; + if (name == "Title") name = "TITLE"; + else if (name == "WM/AlbumArtist") name = "ARTIST"; break; } - case(FMOD_TAGTYPE_VORBISCOMMENT): + case FMOD_TAGTYPE_VORBISCOMMENT: { - if(name == "title") name = "TITLE"; - else if(name == "artist") name = "ARTIST"; + if (name == "title") name = "TITLE"; + else if (name == "artist") name = "ARTIST"; break; } - case(FMOD_TAGTYPE_FMOD): + case FMOD_TAGTYPE_FMOD: { if (!strcmp(tag.name, "Sample Rate Change")) { - LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; + LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); } continue; @@ -237,42 +232,42 @@ void LLStreamingAudio_FMODSTUDIO::update() default: break; } - switch(tag.datatype) + switch (tag.datatype) { - case(FMOD_TAGDATATYPE_INT): + case FMOD_TAGDATATYPE_INT: { (mMetadata)[name]=*(LLSD::Integer*)(tag.data); LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(int*)(tag.data) << LL_ENDL; break; } - case(FMOD_TAGDATATYPE_FLOAT): + case FMOD_TAGDATATYPE_FLOAT: { (mMetadata)[name]=*(LLSD::Real*)(tag.data); LL_DEBUGS("StreamMetadata") << tag.name << ": " << *(float*)(tag.data) << LL_ENDL; break; } - case(FMOD_TAGDATATYPE_STRING): + case FMOD_TAGDATATYPE_STRING: { std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); (mMetadata)[name]=out; LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; break; } - case(FMOD_TAGDATATYPE_STRING_UTF8): + case FMOD_TAGDATATYPE_STRING_UTF8: { std::string out((char*)tag.data); (mMetadata)[name]=out; LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; break; } - case(FMOD_TAGDATATYPE_STRING_UTF16): + case FMOD_TAGDATATYPE_STRING_UTF16: { std::string out((char*)tag.data,tag.datalen); (mMetadata)[std::string(tag.name)]=out; LL_DEBUGS("StreamMetadata") << tag.name << ": " << out << LL_ENDL; break; } - case(FMOD_TAGDATATYPE_STRING_UTF16BE): + case FMOD_TAGDATATYPE_STRING_UTF16BE: { std::string out((char*)tag.data,tag.datalen); //U16* buf = (U16*)out.c_str(); @@ -291,11 +286,11 @@ void LLStreamingAudio_FMODSTUDIO::update() if (starving) { bool paused = false; - if (mFMODInternetStreamChannelp->getPaused(&paused) == FMOD_OK && !paused) + if (!Check_FMOD_Error(mFMODInternetStreamChannelp->getPaused(&paused), "FMOD:Channel::getPaused") && !paused) { LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; - LL_INFOS() << " (diskbusy="<setPaused(true), "FMOD::Channel::setPaused"); } } @@ -421,17 +416,17 @@ bool LLStreamingAudio_FMODSTUDIO::getNewMetadata(LLSD& metadata) // manager of possibly-multiple internet audio streams LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url) : - mSystem(system), - mChannelGroup(group), - mStreamChannel(NULL), - mInternetStream(NULL), - mReady(false) +mSystem(system), +mChannelGroup(group), +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) + if (result != FMOD_OK) { LL_WARNS() << "Couldn't open fmod stream, error " << FMOD_ErrorString(result) @@ -447,13 +442,13 @@ FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream() { // We need a live and opened stream before we try and play it. FMOD_OPENSTATE open_state; - if (getOpenState(open_state) != FMOD_OK || open_state != FMOD_OPENSTATE_READY) + if (!mInternetStream || Check_FMOD_Error(getOpenState(open_state), "FMOD::Sound::getOpenState") || open_state != FMOD_OPENSTATE_READY) { LL_WARNS() << "No internet stream to start playing!" << LL_ENDL; return NULL; } - if(mStreamChannel) + if (mStreamChannel) return mStreamChannel; //Already have a channel for this stream. Check_FMOD_Error(mSystem->playSound(mInternetStream, mChannelGroup, true, &mStreamChannel), "FMOD::System::playSound"); @@ -466,7 +461,7 @@ bool LLAudioStreamManagerFMODSTUDIO::stopStream() { bool close = true; FMOD_OPENSTATE open_state; - if (getOpenState(open_state) == FMOD_OK) + if (!Check_FMOD_Error(getOpenState(open_state), "FMOD::Sound::getOpenState")) { switch (open_state) { @@ -478,7 +473,7 @@ bool LLAudioStreamManagerFMODSTUDIO::stopStream() } } - if (close && mInternetStream->release() == FMOD_OK) + if (close && !Check_FMOD_Error(mInternetStream->release(), "FMOD::Sound::release")) { mStreamChannel = NULL; mInternetStream = NULL; @@ -508,8 +503,8 @@ void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decod { 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); + memset(&settings, 0, sizeof(settings)); + settings.cbSize = sizeof(settings); settings.defaultDecodeBufferSize = decodebuffertime;//ms Check_FMOD_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings"); } From 8cb9bcf1d6379afb3f0784c3741f77b5df437dea Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 9 Apr 2020 13:12:30 +0300 Subject: [PATCH 12/50] SL-11445 Fix fmod studio opening audio files --- indra/llaudio/llaudioengine_fmodstudio.cpp | 31 +++++++++++----------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 15bf8926c1..8f07c81c57 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -49,19 +49,20 @@ FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, 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) { - mInited = false; - mWindGen = NULL; - mWindDSP = NULL; - mSystem = NULL; - mEnableProfiler = enable_profiler; - mWindDSPDesc = NULL; } LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() { - delete mWindDSPDesc; + // mWindDSPDesc, mWindGen and mWindDSP get cleaned up on cleanupWind in LLAudioEngine::shutdown() + // mSystem gets cleaned up at shutdown() } @@ -400,10 +401,12 @@ void LLAudioEngine_FMODSTUDIO::setInternalGain(F32 gain) gain = llclamp(gain, 0.0f, 1.0f); - FMOD::ChannelGroup *master_group; - mSystem->getMasterChannelGroup(&master_group); - - master_group->setVolume(gain); + 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) @@ -658,12 +661,8 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) 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 -#if LL_WINDOWS - FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode, &exinfo, &mSoundp); -#else + // 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); -#endif if (result != FMOD_OK) { From c0ce2565918af03f1dabcb02dedb87c1c447008a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 9 Apr 2020 16:04:37 +0300 Subject: [PATCH 13/50] SL-11445 Fix fmod studio position and orientation attributes --- indra/llaudio/llaudioengine_fmodstudio.cpp | 2 -- indra/llaudio/lllistener_fmodstudio.cpp | 13 +++++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 8f07c81c57..49ae01b44d 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -725,8 +725,6 @@ FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, 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_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); diff --git a/indra/llaudio/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp index 34f3d00eae..abd5e345b5 100644 --- a/indra/llaudio/lllistener_fmodstudio.cpp +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -82,11 +82,8 @@ void LLListener_FMODSTUDIO::orient(LLVector3 up, LLVector3 at) { LLListener::orient(up, at); - // Welcome to the transition between right and left - // (coordinate systems, that is) - // Leaving the at vector alone results in a L/R reversal - // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed - at = -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); } @@ -106,14 +103,14 @@ void LLListener_FMODSTUDIO::commitDeferredChanges() 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) + // (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 = mVelocity - LLVector3(0.f, 0.f, .1f); + LLVector3 pos = mPosition - LLVector3(0.f, 0.f, .1f); mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); } mRolloffFactor = factor; mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); From 1598a368cd56d9129ce9b9ce6819ec508f4d7253 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 9 Apr 2020 16:57:19 +0300 Subject: [PATCH 14/50] SL-11445 On exit LLWindGen can be invalid --- indra/llaudio/llaudioengine_fmodstudio.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 49ae01b44d..32d2266fdb 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -721,12 +721,15 @@ FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, // outbuffer = the buffer passed from the previous DSP unit. // length = length in samples at this mix time. - LLWindGen *windgen; + LLWindGen *windgen = NULL; FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; thisdsp->getUserData((void **)&windgen); - windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); + if (windgen) + { + windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); + } return FMOD_OK; } From 904ee2dd907a78f7b43effa925a6b45f973ffbaf Mon Sep 17 00:00:00 2001 From: Ansariel Date: Thu, 9 Apr 2020 16:32:00 +0200 Subject: [PATCH 15/50] More FMOD Studio sync with upstream --- indra/llaudio/llaudioengine_fmodstudio.cpp | 30 ++++++++++++---------- indra/llaudio/lllistener_fmodstudio.cpp | 11 +++++--- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 90525d0549..56cfb97606 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -136,12 +136,12 @@ FMOD_RESULT F_CALLBACK systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_ } LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 resample_method) - : mInited(false), - mWindGen(nullptr), - mWindDSPDesc(nullptr), - mWindDSP(nullptr), - mSystem(nullptr), +: mInited(false), + mWindGen(NULL), + mWindDSP(NULL), + mSystem(NULL), mEnableProfiler(enable_profiler), + mWindDSPDesc(NULL), mResampleMethod(resample_method), mSelectedDeviceUUID() { @@ -149,7 +149,8 @@ LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 res LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() { - delete mWindDSPDesc; + // mWindDSPDesc, mWindGen and mWindDSP get cleaned up on cleanupWind in LLAudioEngine::shutdown() + // mSystem gets cleaned up at shutdown() } bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) @@ -558,14 +559,13 @@ void LLAudioEngine_FMODSTUDIO::setInternalGain(F32 gain) gain = llclamp(gain, 0.0f, 1.0f); - FMOD::ChannelGroup *master_group; - if (Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")) + FMOD::ChannelGroup* master_group = NULL; + if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup") + && master_group) { - return; + master_group->setVolume(gain); } - master_group->setVolume(gain); - LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); if (saimpl) { @@ -822,7 +822,7 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) 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 + // 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) @@ -882,13 +882,15 @@ FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, // outbuffer = the buffer passed from the previous DSP unit. // length = length in samples at this mix time. - LLWindGen *windgen; + LLWindGen *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/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp index d2e8f4e846..053976374f 100644 --- a/indra/llaudio/lllistener_fmodstudio.cpp +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -82,6 +82,9 @@ 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); } @@ -100,14 +103,14 @@ void LLListener_FMODSTUDIO::commitDeferredChanges() 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) + // (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); + 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); From 2542a3ed795d3a7ac664e0ca7ec4b5d8108dfce8 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 10 Apr 2020 13:58:58 +0300 Subject: [PATCH 16/50] SL-11445 Provide 'name' for Pulse Audio --- indra/llaudio/llaudioengine.cpp | 2 +- indra/llaudio/llaudioengine.h | 2 +- indra/llaudio/llaudioengine_fmodstudio.cpp | 19 +++++++++++++++---- indra/llaudio/llaudioengine_fmodstudio.h | 2 +- indra/llaudio/llaudioengine_openal.cpp | 9 ++++++++- indra/llaudio/llaudioengine_openal.h | 4 ++-- indra/newview/llstartup.cpp | 2 +- 7 files changed, 29 insertions(+), 11 deletions(-) diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index f49028aad5..1d447f32ae 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -111,7 +111,7 @@ void LLAudioEngine::setDefaults() } -bool LLAudioEngine::init(const S32 num_channels, void* userdata) +bool LLAudioEngine::init(const S32 num_channels, void* userdata, const std::string &app_title) { setDefaults(); diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h index f1e1b4e308..97674f15f7 100644 --- a/indra/llaudio/llaudioengine.h +++ b/indra/llaudio/llaudioengine.h @@ -99,7 +99,7 @@ public: virtual ~LLAudioEngine(); // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *userdata); + virtual bool init(const S32 num_channels, void *userdata, const std::string &app_title); virtual std::string getDriverName(bool verbose) = 0; virtual void shutdown(); diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 32d2266fdb..06a5776eb1 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -74,7 +74,7 @@ static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) return true; } -bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) +bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, const std::string &app_title) { U32 version; FMOD_RESULT result; @@ -86,7 +86,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) return false; //will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer. - LLAudioEngine::init(num_channels, userdata); + LLAudioEngine::init(num_channels, userdata, app_title); result = mSystem->getVersion(&version); Check_FMOD_Error(result, "FMOD::System::getVersion"); @@ -97,6 +97,8 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) << " expected:" << FMOD_VERSION << LL_ENDL; } + // In case we need to force sampling on stereo, use setSoftwareFormat here + // In this case, all sounds, PLUS wind and stream will be software. result = mSystem->setSoftwareChannels(num_channels + 2); Check_FMOD_Error(result, "FMOD::System::setSoftwareChannels"); @@ -109,6 +111,8 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) 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) { @@ -125,7 +129,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) { LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; if (mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK && - (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) + (result = mSystem->init(num_channels + 2, fmod_flags, const_cast(app_title.c_str()))) == FMOD_OK) { LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; audio_ok = true; @@ -238,7 +242,7 @@ std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose) return llformat("FMOD Studio %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); } } - return "FMODSTUDIO"; + return "FMOD STUDIO"; } @@ -433,6 +437,13 @@ LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO() 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 diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h index 69276244da..f2361df1b6 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.h +++ b/indra/llaudio/llaudioengine_fmodstudio.h @@ -51,7 +51,7 @@ public: virtual ~LLAudioEngine_FMODSTUDIO(); // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *user_data); + virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title); virtual std::string getDriverName(bool verbose); virtual void allocateListener(); diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp index e6ac586618..a38d8291fa 100644 --- a/indra/llaudio/llaudioengine_openal.cpp +++ b/indra/llaudio/llaudioengine_openal.cpp @@ -52,7 +52,7 @@ LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() } // virtual -bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata) +bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata, const std::string &app_title) { mWindGen = NULL; LLAudioEngine::init(num_channels, userdata); @@ -239,6 +239,13 @@ bool LLAudioChannelOpenAL::isPlaying() bool LLAudioChannelOpenAL::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 diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h index 6639d9dfe6..366f9259e3 100644 --- a/indra/llaudio/llaudioengine_openal.h +++ b/indra/llaudio/llaudioengine_openal.h @@ -40,8 +40,8 @@ class LLAudioEngine_OpenAL : public LLAudioEngine LLAudioEngine_OpenAL(); virtual ~LLAudioEngine_OpenAL(); - virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); + virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title); + virtual std::string getDriverName(bool verbose); virtual void allocateListener(); virtual void shutdown(); diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index cb76ac6f74..56e8000400 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -650,7 +650,7 @@ bool idle_startup() #else void* window_handle = NULL; #endif - bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle); + bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle, LLAppViewer::instance()->getSecondLifeTitle()); if(init) { gAudiop->setMuted(TRUE); From 4268cc8c21e284877241a0d0863501f48eec297d Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 10 Apr 2020 18:15:42 +0200 Subject: [PATCH 17/50] Final FMOD Studio upstream sync before merge --- indra/llaudio/llaudioengine.cpp | 2 +- indra/llaudio/llaudioengine.h | 2 +- indra/llaudio/llaudioengine_fmodstudio.cpp | 92 ++++++++++++---------- indra/llaudio/llaudioengine_fmodstudio.h | 2 +- indra/llaudio/llaudioengine_openal.cpp | 9 ++- indra/llaudio/llaudioengine_openal.h | 4 +- indra/llaudio/lllistener_fmodstudio.cpp | 6 +- indra/llaudio/lllistener_fmodstudio.h | 2 +- indra/newview/llstartup.cpp | 2 +- 9 files changed, 67 insertions(+), 54 deletions(-) diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index 77935169bb..8be13d7834 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -118,7 +118,7 @@ void LLAudioEngine::setDefaults() } -bool LLAudioEngine::init(const S32 num_channels, void* userdata) +bool LLAudioEngine::init(const S32 num_channels, void* userdata, const std::string &app_title) { setDefaults(); diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h index f685f3fc84..44ed31520f 100644 --- a/indra/llaudio/llaudioengine.h +++ b/indra/llaudio/llaudioengine.h @@ -104,7 +104,7 @@ public: virtual ~LLAudioEngine(); // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *userdata); + virtual bool init(const S32 num_channels, void *userdata, const std::string &app_title); virtual std::string getDriverName(bool verbose) = 0; virtual void shutdown(); diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 56cfb97606..6743496cdc 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -40,11 +40,10 @@ #include "fmodstudio/fmod.hpp" #include "fmodstudio/fmod_errors.h" #include "lldir.h" +#include "llapr.h" #include "sound_ids.h" -#include "indra_constants.h" - const U32 EXTRA_SOUND_CHANNELS = 10; FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels); @@ -153,7 +152,7 @@ LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() // mSystem gets cleaned up at shutdown() } -bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) +bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, const std::string &app_title) { U32 version; FMOD_RESULT result; @@ -165,7 +164,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) return false; //will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer. - LLAudioEngine::init(num_channels, userdata); + LLAudioEngine::init(num_channels, userdata, app_title); result = mSystem->getVersion(&version); Check_FMOD_Error(result, "FMOD::System::getVersion"); @@ -176,6 +175,8 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) << " expected:" << FMOD_VERSION << LL_ENDL; } + // In case we need to force sampling on stereo, use setSoftwareFormat here + // In this case, all sounds, PLUS wind and stream will be software. result = mSystem->setSoftwareChannels(num_channels + EXTRA_SOUND_CHANNELS); Check_FMOD_Error(result, "FMOD::System::setSoftwareChannels"); @@ -202,6 +203,8 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) 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) { @@ -218,7 +221,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) { LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; if ((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK && - (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, const_cast(APP_NAME.c_str()))) == FMOD_OK) + (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, const_cast(app_title.c_str()))) == FMOD_OK) { LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; audio_ok = true; @@ -454,7 +457,6 @@ bool LLAudioEngine_FMODSTUDIO::initWind() memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; - mWindDSPDesc->numoutputbuffers = 1; mWindDSPDesc->read = &windCallback; // Assign callback - may be called from arbitrary threads if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP")) return false; @@ -591,37 +593,46 @@ LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO() bool LLAudioChannelFMODSTUDIO::updateBuffer() { - if (mCurrentSourcep) + if (!mCurrentSourcep) { - if (LLAudioChannel::updateBuffer()) + // 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) { - // 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, nullptr, true, &mChannelp); - Check_FMOD_Error(result, "FMOD::System::playSound"); - } - - //LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL; + // 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()); @@ -630,17 +641,12 @@ bool LLAudioChannelFMODSTUDIO::updateBuffer() 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; + S32 index; + mChannelp->getIndex(&index); + LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID() + << " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL; }*/ } - else - { - LL_DEBUGS() << "No source buffer!" << LL_ENDL; - return false; - } return true; } @@ -804,7 +810,7 @@ bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) return false; } - if (!gDirUtilp->fileExists(filename)) + if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) { // File not found, abort. return false; diff --git a/indra/llaudio/llaudioengine_fmodstudio.h b/indra/llaudio/llaudioengine_fmodstudio.h index be283dec1c..91f7cc89e4 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.h +++ b/indra/llaudio/llaudioengine_fmodstudio.h @@ -57,7 +57,7 @@ public: virtual ~LLAudioEngine_FMODSTUDIO(); // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *user_data); + virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title); virtual std::string getDriverName(bool verbose); virtual void allocateListener(); diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp index 8067c832fd..e271f8e06d 100644 --- a/indra/llaudio/llaudioengine_openal.cpp +++ b/indra/llaudio/llaudioengine_openal.cpp @@ -52,7 +52,7 @@ LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() } // virtual -bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata) +bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata, const std::string &app_title) { mWindGen = NULL; LLAudioEngine::init(num_channels, userdata); @@ -241,6 +241,13 @@ bool LLAudioChannelOpenAL::isPlaying() bool LLAudioChannelOpenAL::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 diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h index 6639d9dfe6..366f9259e3 100644 --- a/indra/llaudio/llaudioengine_openal.h +++ b/indra/llaudio/llaudioengine_openal.h @@ -40,8 +40,8 @@ class LLAudioEngine_OpenAL : public LLAudioEngine LLAudioEngine_OpenAL(); virtual ~LLAudioEngine_OpenAL(); - virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); + virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title); + virtual std::string getDriverName(bool verbose); virtual void allocateListener(); virtual void shutdown(); diff --git a/indra/llaudio/lllistener_fmodstudio.cpp b/indra/llaudio/lllistener_fmodstudio.cpp index 053976374f..abd5e345b5 100644 --- a/indra/llaudio/lllistener_fmodstudio.cpp +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -58,7 +58,7 @@ void LLListener_FMODSTUDIO::translate(LLVector3 offset) { LLListener::translate(offset); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); } //----------------------------------------------------------------------- @@ -66,7 +66,7 @@ void LLListener_FMODSTUDIO::setPosition(LLVector3 pos) { LLListener::setPosition(pos); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); } //----------------------------------------------------------------------- @@ -74,7 +74,7 @@ void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel) { LLListener::setVelocity(vel); - mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL); + mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); } //----------------------------------------------------------------------- diff --git a/indra/llaudio/lllistener_fmodstudio.h b/indra/llaudio/lllistener_fmodstudio.h index 2dd02fc783..6ad85d9700 100644 --- a/indra/llaudio/lllistener_fmodstudio.h +++ b/indra/llaudio/lllistener_fmodstudio.h @@ -1,7 +1,7 @@ /** * @file listener_fmodstudio.h * @brief Description of LISTENER class abstracting the audio support - * as an FMOD Studio implementation (windows and Linux) + * as an FMOD 3D implementation * * $LicenseInfo:firstyear=2020&license=viewerlgpl$ * Second Life Viewer Source Code diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index c2afa2c038..c036fda386 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1011,7 +1011,7 @@ bool idle_startup() #else void* window_handle = NULL; #endif - bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle); + bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle, LLAppViewer::instance()->getSecondLifeTitle()); if(init) { // Output device selection From 9e4f70814042d3fcc6b640ec11df59498ebf7169 Mon Sep 17 00:00:00 2001 From: Ansariel Date: Fri, 10 Apr 2020 19:27:57 +0200 Subject: [PATCH 18/50] Don't show FMOD logo on login progress since we show it on the "About" window already; also comment out code that would require us adding the FMOD logo to the 3p lib --- indra/newview/llstartup.cpp | 4 +- indra/newview/llviewertexturelist.cpp | 62 ++++++++++++++------------- indra/newview/viewer_manifest.py | 30 +++++++------ 3 files changed, 53 insertions(+), 43 deletions(-) diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 16e8602741..6ce71d7808 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -1155,7 +1155,9 @@ bool idle_startup() display_startup(); // LLViewerMedia::initBrowser(); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - gViewerWindow->setShowLogos(TRUE); + // [Progress Logos] Show logos on "About" floater instead + //gViewerWindow->setShowLogos(TRUE); + // return FALSE; } diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 72261eeef9..7856475cca 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -193,36 +193,38 @@ void LLViewerTextureList::doPreloadImages() mImagePreloads.insert(image); } - // Normally images are located in 'skins' folder in working directory, - // but 3p images were added from packages and had to stay in separate folder - // with path relative to exe. - -#ifdef LL_FMODSTUDIO -#ifdef LL_WINDOWS - std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); -#elif LL_DARWIN - // On MAC use resource directory - std::string full_path = gDirUtilp->add(gDirUtilp->getAppRODataDir(), "3p_icons", "fmod.png"); -#else - std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); -#endif - image = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + full_path, FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, - 0, 0, IMG_LOGO_FMOD); - if (image) - { - image->setAddressMode(LLTexUnit::TAM_WRAP); - mImagePreloads.insert(image); - // Speed up load (this texture will be used early) - image->setKnownDrawSize(364, 98); - image->processTextureStats(); - image->setDecodePriority(LLViewerFetchedTexture::maxDecodePriority()); - image->updateFetch(); - // Fmod logo is only needed at startup, if we will get more logos - // for startup, might be good idea to save resources and do loading - // in scope of llprogressview and then unload everything once no - // longer needed - } -#endif +// [Progress Logos] Show logos on "About" floater instead +// // Normally images are located in 'skins' folder in working directory, +// // but 3p images were added from packages and had to stay in separate folder +// // with path relative to exe. +// +//#ifdef LL_FMODSTUDIO +//#ifdef LL_WINDOWS +// std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); +//#elif LL_DARWIN +// // On MAC use resource directory +// std::string full_path = gDirUtilp->add(gDirUtilp->getAppRODataDir(), "3p_icons", "fmod.png"); +//#else +// std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); +//#endif +// image = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + full_path, FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, +// 0, 0, IMG_LOGO_FMOD); +// if (image) +// { +// image->setAddressMode(LLTexUnit::TAM_WRAP); +// mImagePreloads.insert(image); +// // Speed up load (this texture will be used early) +// image->setKnownDrawSize(364, 98); +// image->processTextureStats(); +// image->setDecodePriority(LLViewerFetchedTexture::maxDecodePriority()); +// image->updateFetch(); +// // Fmod logo is only needed at startup, if we will get more logos +// // for startup, might be good idea to save resources and do loading +// // in scope of llprogressview and then unload everything once no +// // longer needed +// } +//#endif +// LLPointer img_blak_square_tex(new LLImageRaw(2, 2, 3)); memset(img_blak_square_tex->getData(), 0, img_blak_square_tex->getDataSize()); diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index ee6bec1a8d..02efeb2b80 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -565,10 +565,12 @@ class WindowsManifest(ViewerManifest): # Remove VMP - # Copy 3p icons - with self.prefix(src=os.path.join(pkgdir, "icons"), dst="3p_icons"): - if self.args['fmodstudio'] == 'ON': - self.path("fmod.png") + # [Progress Logos] Show logos on "About" floater instead + # # Copy 3p icons + # with self.prefix(src=os.path.join(pkgdir, "icons"), dst="3p_icons"): + # if self.args['fmodstudio'] == 'ON': + # self.path("fmod.png") + # # Plugin host application self.path2basename(os.path.join(os.pardir, @@ -1330,10 +1332,12 @@ class DarwinManifest(ViewerManifest): with self.prefix(src=pkgdir,dst=""): self.path("ca-bundle.crt") - # Copy 3p icons - with self.prefix(src=os.path.join(pkgdir, "icons"), dst="3p_icons"): - if self.args['fmodstudio'] == 'ON': - self.path("fmod.png") + # [Progress Logos] Show logos on "About" floater instead + # # Copy 3p icons + # with self.prefix(src=os.path.join(pkgdir, "icons"), dst="3p_icons"): + # if self.args['fmodstudio'] == 'ON': + # self.path("fmod.png") + # icon_path = self.icon_path() with self.prefix(src=icon_path) : @@ -2094,10 +2098,12 @@ class Linux_i686_Manifest(LinuxManifest): relpkgdir = os.path.join(pkgdir, "lib", "release") debpkgdir = os.path.join(pkgdir, "lib", "debug") - # Copy 3p icons - with self.prefix(src=os.path.join(pkgdir, "icons"), dst="3p_icons"): - if self.args['fmodstudio'] == 'ON': - self.path("fmod.png") + # [Progress Logos] Show logos on "About" floater instead + # # Copy 3p icons + # with self.prefix(src=os.path.join(pkgdir, "icons"), dst="3p_icons"): + # if self.args['fmodstudio'] == 'ON': + # self.path("fmod.png") + # with self.prefix(src=relpkgdir, dst="lib"): self.path("libapr-1.so") From 347c53855bb0c983e0300594772a9206f9031065 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 13 Apr 2020 22:41:55 +0300 Subject: [PATCH 19/50] SL-12607 Added more icons and draw methods to draw them --- autobuild.xml | 28 +-- indra/llcommon/indra_constants.cpp | 2 - indra/llcommon/indra_constants.h | 2 - indra/newview/CMakeLists.txt | 3 +- indra/newview/llprogressview.cpp | 221 +++++++++++++++++- indra/newview/llprogressview.h | 26 ++- indra/newview/llstartup.cpp | 79 +------ indra/newview/llviewertexturelist.cpp | 31 --- indra/newview/llviewerwindow.cpp | 13 +- indra/newview/llviewerwindow.h | 2 +- .../skins/default/xui/en/panel_progress.xml | 21 +- indra/newview/viewer_manifest.py | 6 + 12 files changed, 274 insertions(+), 160 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 51259486ab..37ffe61307 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1420,9 +1420,9 @@ archive hash - a0c4405c9e44d4a0135fe20ba8cfbace + 7e883d641b5e541c3c46fb6efbbd06ca url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4693/14627/havok_source-2012.1-2-darwin64-504680.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/51113/463266/havok_source-2012.1-2-darwin64-536003.tar.bz2 name darwin64 @@ -1456,9 +1456,9 @@ archive hash - 035572a1929be66f6c56468e0ef7fe74 + 81e15d58f3ce98f8342842b62bce08f0 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4695/14637/havok_source-2012.1-2-windows-504680.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/51115/463279/havok_source-2012.1-2-windows-536003.tar.bz2 name windows @@ -1468,9 +1468,9 @@ archive hash - d8525d2fbb9e0f7bc31427b47350e468 + df66566126db0f7b75af024b0768a541 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4694/14634/havok_source-2012.1-2-windows64-504680.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/51114/463273/havok_source-2012.1-2-windows64-536003.tar.bz2 name windows64 @@ -2930,9 +2930,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - f824d586ab5de6edd14ef6828e9e4b66 + d02241c69dc4fac8e270f9bdc0460a90 + hash_algorithm + md5 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/44719/395040/slvoice-4.10.0000.32327.5fc3fe7c.531581-darwin64-531581.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/51111/463254/slvoice-4.10.0000.32327.5fc3fe7c.536001-darwin64-536001.tar.bz2 name darwin64 @@ -2966,9 +2968,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 1941c17c81905f23b4928288bcf719fb + 6c9c0f59e4974e131456c3ced2b6b23f url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/44720/395047/slvoice-4.10.0000.32327.5fc3fe7c.531581-windows-531581.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/51107/463239/slvoice-4.10.0000.32327.5fc3fe7c.536001-windows-536001.tar.bz2 name windows @@ -2978,16 +2980,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - baa6cdc8e8762d5519996ed9faa0bf3f + 05341caee4c837fe732702fa18a7ed98 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/44721/395056/slvoice-4.10.0000.32327.5fc3fe7c.531581-windows64-531581.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/51108/463245/slvoice-4.10.0000.32327.5fc3fe7c.536001-windows64-536001.tar.bz2 name windows64 version - 4.10.0000.32327.5fc3fe7c.531581 + 4.10.0000.32327.5fc3fe7c.536001 tut diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index 53f98adbbf..e13176e8fa 100644 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -84,5 +84,3 @@ const LLUUID IMG_USE_BAKED_AUX1 ("9742065b-19b5-297c-858a-29711d539043"); const LLUUID IMG_USE_BAKED_AUX2 ("03642e83-2bd1-4eb9-34b4-4c47ed586d2d"); const LLUUID IMG_USE_BAKED_AUX3 ("edd51b77-fc10-ce7a-4b3d-011dfc349e4f"); -const LLUUID IMG_LOGO_FMOD("876982f5-f5fd-4a68-b5e7-727f3ae3487b"); - diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 7d20286ac9..0fbf4b966b 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -218,8 +218,6 @@ LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX1; LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX2; LL_COMMON_API extern const LLUUID IMG_USE_BAKED_AUX3; -LL_COMMON_API extern const LLUUID IMG_LOGO_FMOD; - LL_COMMON_API extern const LLUUID DEFAULT_WATER_NORMAL; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1ede6188fb..a5cb9bc3d3 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -1715,12 +1715,11 @@ endif (OPENAL) if (FMODSTUDIO) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODSTUDIO") - # texture list needs to load fmod icon - set_source_files_properties(llviewertexturelist.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY}) endif (FMODSTUDIO) set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") +set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES}) diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index dfa6c97b26..f745d26864 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -42,7 +42,6 @@ #include "llbutton.h" #include "llcallbacklist.h" #include "llfocusmgr.h" -#include "lliconctrl.h" #include "llnotifications.h" #include "llprogressbar.h" #include "llstartup.h" @@ -184,7 +183,6 @@ void LLProgressView::setVisible(BOOL visible) if (getVisible() && !visible) { LLPanel::setVisible(FALSE); - setShowLogos(FALSE); } // showing progress view else if (visible && (!getVisible() || mFadeToWorldTimer.getStarted())) @@ -231,6 +229,33 @@ void LLProgressView::drawStartTexture(F32 alpha) gGL.popMatrix(); } +void LLProgressView::drawLogos(F32 alpha) +{ + if (mLogosList.empty()) + { + return; + } + + // logos are tied to label, + // due to potential resizes we have to figure offsets out on draw or resize + LLTextBox *logos_label = getChild("logos_lbl"); + S32 offset_x, offset_y; + logos_label->localPointToScreen(0, 0, &offset_x, &offset_y); + std::vector::const_iterator iter = mLogosList.begin(); + std::vector::const_iterator end = mLogosList.end(); + for (; iter != end; iter++) + { + gl_draw_scaled_image_with_border(iter->mDrawRect.mLeft + offset_x, + iter->mDrawRect.mBottom + offset_y, + iter->mDrawRect.getWidth(), + iter->mDrawRect.getHeight(), + iter->mTexturep.get(), + UI_VERTEX_COLOR % alpha, + FALSE, + iter->mClipRect, + iter->mOffsetRect); + } +} void LLProgressView::draw() { @@ -247,6 +272,7 @@ void LLProgressView::draw() } LLPanel::draw(); + drawLogos(alpha); return; } @@ -259,6 +285,7 @@ void LLProgressView::draw() drawStartTexture(alpha); LLPanel::draw(); + drawLogos(alpha); // faded out completely - remove panel and reveal world if (mFadeToWorldTimer.getElapsedTimeF32() > FADE_TO_WORLD_TIME ) @@ -285,7 +312,7 @@ void LLProgressView::draw() // FIXME: this causes a crash that i haven't been able to fix mMediaCtrl->unloadMediaSource(); - gStartTexture = NULL; + releaseTextures(); } return; } @@ -293,6 +320,7 @@ void LLProgressView::draw() drawStartTexture(1.0f); // draw children LLPanel::draw(); + drawLogos(1.0f); } void LLProgressView::setText(const std::string& text) @@ -311,16 +339,189 @@ void LLProgressView::setMessage(const std::string& msg) getChild("message_text")->setValue(mMessage); } -void LLProgressView::setShowLogos(const BOOL logos_visible) +void LLProgressView::loadLogo(const std::string &path, + const U8 image_codec, + const LLRect &pos_rect, + const LLRectf &clip_rect, + const LLRectf &offset_rect) { - LLIconCtrl* logo = getChild("fmod_logo"); - if (logos_visible) + // We need these images very early, so we have to force-load them, otherwise they might not load in time. + if (!gDirUtilp->fileExists(path)) { - logo->setValue(IMG_LOGO_FMOD); + return; } - logo->setVisible(logos_visible); - getChild("fmod_text")->setVisible(logos_visible); - getChild("message_text")->setVisible(!logos_visible); + + LLPointer start_image_frmted = LLImageFormatted::createFromType(image_codec); + if (!start_image_frmted->load(path)) + { + LL_WARNS("AppInit") << "Image load failed: " << path << LL_ENDL; + return; + } + + LLPointer raw = new LLImageRaw; + if (!start_image_frmted->decode(raw, 0.0f)) + { + LL_WARNS("AppInit") << "Image decode failed " << path << LL_ENDL; + return; + } + // HACK: getLocalTexture allows only power of two dimentions + raw->expandToPowerOfTwo(); + + TextureData data; + data.mTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); + data.mDrawRect = pos_rect; + data.mClipRect = clip_rect; + data.mOffsetRect = offset_rect; + mLogosList.push_back(data); +} + +void LLProgressView::initLogos() +{ + mLogosList.clear(); + + const U8 image_codec = IMG_CODEC_PNG; + const LLRectf default_clip(0.f, 1.f, 1.f, 0.f); + const S32 default_height = 24; + const S32 default_width = 91; + const S32 default_pad = 7; + + // We don't know final screen rect yet, so we can't precalculate position fully + LLTextBox *logos_label = getChild("logos_lbl"); + S32 texture_start_x = logos_label->getFont()->getWidthF32(logos_label->getText()) + default_pad; + S32 texture_start_y = -3; + + // Normally iamges stay in skins folder, but 3p images come from package instead + // of repository and need special handling +#ifdef LL_WINDOWS + std::string temp_str = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons"); +#elif LL_DARWIN + // On MAC use resource directory + std::string temp_str = gDirUtilp->add(gDirUtilp->getAppRODataDir(), "3p_icons"); +#else + std::string temp_str = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons"); +#endif + temp_str += gDirUtilp->getDirDelimiter(); + +#ifdef LL_FMODSTUDIO + const S32 fmod_y_offset = 2; + loadLogo(temp_str + "fmod.png", + image_codec, + LLRect(texture_start_x, texture_start_y + default_height + fmod_y_offset, texture_start_x + default_width + fmod_y_offset, texture_start_y), + default_clip, + default_clip); + + texture_start_x += default_width + default_pad; +#endif + + loadLogo(temp_str + "havok_logo.png", + image_codec, + LLRect(texture_start_x, texture_start_y + default_height, texture_start_x + default_width, texture_start_y), + default_clip, + default_clip); + + texture_start_x += default_width + default_pad - 2; // offset to compensate for enormous borders for vivox + + const LLRectf vivox_clip(0.0f /*repeats*/, 0.52f /*cut starting from center*/, 0.52f, 0.0f); // non-standard icon, clip it + const LLRectf vivox_offset(0.0f, 0.23f, 0.23f, 0.0f); // keeping clipping identical to not mess up scale + const S32 vivox_y_offset = -5; + loadLogo(temp_str + "vivox_logo.png", + image_codec, + LLRect(texture_start_x, texture_start_y + default_height + vivox_y_offset, texture_start_x + default_width, texture_start_y + vivox_y_offset), + vivox_clip, + vivox_offset); +} + +void LLProgressView::initStartTexture(S32 location_id, bool is_in_production) +{ + if (gStartTexture.notNull()) + { + gStartTexture = NULL; + LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL; + } + + LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL; + + U8 image_codec = IMG_CODEC_PNG; + std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter(); + + if ((S32)START_LOCATION_ID_LAST == location_id) + { + temp_str += LLStartUp::getScreenLastFilename(); + } + else + { + std::string path = temp_str + LLStartUp::getScreenHomeFilename(); + + if (!gDirUtilp->fileExists(path) && is_in_production) + { + // Fallback to old file, can be removed later + // Home image only sets when user changes home, so it will take time for users to switch to pngs + temp_str += "screen_home.bmp"; + image_codec = IMG_CODEC_BMP; + } + else + { + temp_str = path; + } + } + + LLPointer start_image_frmted = LLImageFormatted::createFromType(image_codec); + + // Turn off start screen to get around the occasional readback + // driver bug + if (!gSavedSettings.getBOOL("UseStartScreen")) + { + LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL; + return; + } + else if (!start_image_frmted->load(temp_str)) + { + LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL; + gStartTexture = NULL; + } + else + { + gStartImageWidth = start_image_frmted->getWidth(); + gStartImageHeight = start_image_frmted->getHeight(); + + LLPointer raw = new LLImageRaw; + if (!start_image_frmted->decode(raw, 0.0f)) + { + LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL; + gStartTexture = NULL; + } + else + { + // HACK: getLocalTexture allows only power of two dimentions + raw->expandToPowerOfTwo(); + gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE); + } + } + + if (gStartTexture.isNull()) + { + gStartTexture = LLViewerTexture::sBlackImagep; + gStartImageWidth = gStartTexture->getWidth(); + gStartImageHeight = gStartTexture->getHeight(); + } +} + +void LLProgressView::initTextures(S32 location_id, bool is_in_production) +{ + initStartTexture(location_id, is_in_production); + initLogos(); + + LLTextBox *logos_label = getChild("logos_lbl"); + logos_label->setVisible(true); +} + +void LLProgressView::releaseTextures() +{ + gStartTexture = NULL; + mLogosList.clear(); + + LLTextBox *logos_label = getChild("logos_lbl"); + logos_label->setVisible(false); } void LLProgressView::setCancelButtonVisible(BOOL b, const std::string& label) diff --git a/indra/newview/llprogressview.h b/indra/newview/llprogressview.h index 1d4ae3a66f..56377a5889 100644 --- a/indra/newview/llprogressview.h +++ b/indra/newview/llprogressview.h @@ -35,6 +35,7 @@ class LLImageRaw; class LLButton; class LLProgressBar; +class LLViewerTexture; class LLProgressView : public LLPanel, @@ -51,6 +52,7 @@ public: /*virtual*/ void draw(); void drawStartTexture(F32 alpha); + void drawLogos(F32 alpha); /*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask); /*virtual*/ BOOL handleKeyHere(KEY key, MASK mask); @@ -70,8 +72,9 @@ public: void setStartupComplete(); - // turns on logos, hides message of the day - void setShowLogos(const BOOL logos_visible); + // we have to preload local textures to make sure they won't be grey + void initTextures(S32 location_id, bool is_in_production); + void releaseTextures(); void setCancelButtonVisible(BOOL b, const std::string& label); @@ -98,6 +101,25 @@ protected: bool handleUpdate(const LLSD& event_data); static void onIdle(void* user_data); + void loadLogo(const std::string &path, const U8 image_codec, const LLRect &pos_rect, const LLRectf &clip_rect, const LLRectf &offset_rect); + // logos have unusual location and need to be preloaded to not appear grey, then deleted + void initLogos(); + // Loads a bitmap to display during load + void initStartTexture(S32 location_id, bool is_in_production); + +private: + // We need to draw textures on login, but only once. + // So this vector gets filled up for textures to render and gets cleaned later + // Some textures have unusual requirements, so we are rendering directly + class TextureData + { + public: + LLPointer mTexturep; + LLRect mDrawRect; + LLRectf mClipRect; + LLRectf mOffsetRect; + }; + std::vector mLogosList; }; #endif // LL_LLPROGRESSVIEW_H diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 56e8000400..1510506cd9 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -734,7 +734,6 @@ bool idle_startup() display_startup(); // LLViewerMedia::initBrowser(); LLStartUp::setStartupState( STATE_LOGIN_SHOW ); - gViewerWindow->setShowLogos(TRUE); return FALSE; } @@ -1010,9 +1009,8 @@ bool idle_startup() gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT); - init_start_screen(agent_location_id); - // Display the startup progress bar. + gViewerWindow->initTextures(agent_location_id); gViewerWindow->setShowProgress(TRUE); gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit")); @@ -2728,81 +2726,6 @@ std::string LLStartUp::getUserId() return gUserCredential->userID(); } -// Loads a bitmap to display during load -void init_start_screen(S32 location_id) -{ - if (gStartTexture.notNull()) - { - gStartTexture = NULL; - LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL; - } - - LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL; - - U8 image_codec = IMG_CODEC_PNG; - std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter(); - - if ((S32)START_LOCATION_ID_LAST == location_id) - { - temp_str += LLStartUp::getScreenLastFilename(); - } - else - { - std::string path = temp_str + LLStartUp::getScreenHomeFilename(); - - if (!gDirUtilp->fileExists(path) && LLGridManager::getInstance()->isInProductionGrid()) - { - // Fallback to old file, can be removed later - // Home image only sets when user changes home, so it will take time for users to switch to pngs - temp_str += "screen_home.bmp"; - image_codec = IMG_CODEC_BMP; - } - else - { - temp_str = path; - } - } - - LLPointer start_image_frmted = LLImageFormatted::createFromType(image_codec); - - // Turn off start screen to get around the occasional readback - // driver bug - if(!gSavedSettings.getBOOL("UseStartScreen")) - { - LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL; - return; - } - else if(!start_image_frmted->load(temp_str) ) - { - LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL; - gStartTexture = NULL; - } - else - { - gStartImageWidth = start_image_frmted->getWidth(); - gStartImageHeight = start_image_frmted->getHeight(); - - LLPointer raw = new LLImageRaw; - if (!start_image_frmted->decode(raw, 0.0f)) - { - LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL; - gStartTexture = NULL; - } - else - { - raw->expandToPowerOfTwo(); - gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE) ; - } - } - - if(gStartTexture.isNull()) - { - gStartTexture = LLViewerTexture::sBlackImagep ; - gStartImageWidth = gStartTexture->getWidth() ; - gStartImageHeight = gStartTexture->getHeight() ; - } -} - // frees the bitmap void release_start_screen() diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 4221f941f5..06524847d1 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -190,37 +190,6 @@ void LLViewerTextureList::doPreloadImages() mImagePreloads.insert(image); } - // Normally images are located in 'skins' folder in working directory, - // but 3p images were added from packages and had to stay in separate folder - // with path relative to exe. - -#ifdef LL_FMODSTUDIO -#ifdef LL_WINDOWS - std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); -#elif LL_DARWIN - // On MAC use resource directory - std::string full_path = gDirUtilp->add(gDirUtilp->getAppRODataDir(), "3p_icons", "fmod.png"); -#else - std::string full_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons", "fmod.png"); -#endif - image = LLViewerTextureManager::getFetchedTextureFromUrl("file://" + full_path, FTT_LOCAL_FILE, MIPMAP_YES, LLViewerFetchedTexture::BOOST_UI, LLViewerTexture::FETCHED_TEXTURE, - 0, 0, IMG_LOGO_FMOD); - if (image) - { - image->setAddressMode(LLTexUnit::TAM_WRAP); - mImagePreloads.insert(image); - // Speed up load (this texture will be used early) - image->setKnownDrawSize(364, 98); - image->processTextureStats(); - image->setDecodePriority(LLViewerFetchedTexture::maxDecodePriority()); - image->updateFetch(); - // Fmod logo is only needed at startup, if we will get more logos - // for startup, might be good idea to save resources and do loading - // in scope of llprogressview and then unload everything once no - // longer needed - } -#endif - LLPointer img_blak_square_tex(new LLImageRaw(2, 2, 3)); memset(img_blak_square_tex->getData(), 0, img_blak_square_tex->getDataSize()); LLPointer img_blak_square(new LLViewerFetchedTexture(img_blak_square_tex, FTT_DEFAULT, FALSE)); diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 89f3b17021..86cb43555a 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -5098,6 +5098,14 @@ void LLViewerWindow::revealIntroPanel() } } +void LLViewerWindow::initTextures(S32 location_id) +{ + if (mProgressView) + { + mProgressView->initTextures(location_id, LLGridManager::getInstance()->isInProductionGrid()); + } +} + void LLViewerWindow::setShowProgress(const BOOL show) { if (mProgressView) @@ -5151,11 +5159,6 @@ void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& } } -void LLViewerWindow::setShowLogos(const BOOL show_3p_logos) -{ - mProgressView->setShowLogos(show_3p_logos); -} - LLProgressView *LLViewerWindow::getProgressView() const { return mProgressView; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 9adfe7b5c5..44c1fbd066 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -303,13 +303,13 @@ public: BOOL getCursorHidden() { return mCursorHidden; } void moveCursorToCenter(); // move to center of window + void initTextures(S32 location_id); void setShowProgress(const BOOL show); BOOL getShowProgress() const; void setProgressString(const std::string& string); void setProgressPercent(const F32 percent); void setProgressMessage(const std::string& msg); void setProgressCancelButtonVisible( BOOL b, const std::string& label = LLStringUtil::null ); - void setShowLogos(const BOOL show_3p_logos); LLProgressView *getProgressView() const; void revealIntroPanel(); void setStartupComplete(); diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml index 03caf8e8ad..f52422c08f 100644 --- a/indra/newview/skins/default/xui/en/panel_progress.xml +++ b/indra/newview/skins/default/xui/en/panel_progress.xml @@ -106,27 +106,20 @@ top="145" right="-90" word_wrap="true"/> - + - Made with FMOD Studio by Firelight Technologies Pty Ltd. + Second Life uses Date: Tue, 14 Apr 2020 21:32:10 +0300 Subject: [PATCH 20/50] SL-12607 WIP, take pre-sized icons from repo instead of package --- indra/llaudio/llaudioengine_fmodstudio.cpp | 21 +++++--- indra/newview/llprogressview.cpp | 51 +++++++++--------- .../default/textures/3p_icons/fmod_logo.png | Bin 0 -> 1732 bytes .../default/textures/3p_icons/havok_logo.png | Bin 0 -> 2586 bytes .../default/textures/3p_icons/vivox_logo.png | Bin 0 -> 1740 bytes indra/newview/viewer_manifest.py | 21 -------- 6 files changed, 39 insertions(+), 54 deletions(-) create mode 100644 indra/newview/skins/default/textures/3p_icons/fmod_logo.png create mode 100644 indra/newview/skins/default/textures/3p_icons/havok_logo.png create mode 100644 indra/newview/skins/default/textures/3p_icons/vivox_logo.png diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index 06a5776eb1..70b3a08473 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -70,7 +70,7 @@ static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) { if (result == FMOD_OK) return false; - LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + LL_DEBUGS("FMOD") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; return true; } @@ -97,8 +97,6 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons << " expected:" << FMOD_VERSION << LL_ENDL; } - // In case we need to force sampling on stereo, use setSoftwareFormat here - // In this case, all sounds, PLUS wind and stream will be software. result = mSystem->setSoftwareChannels(num_channels + 2); Check_FMOD_Error(result, "FMOD::System::setSoftwareChannels"); @@ -193,6 +191,15 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons // 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(num_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(num_channels + 2, fmod_flags, 0); + } if (Check_FMOD_Error(result, "Error initializing FMOD Studio")) { // If it fails here and (result == FMOD_ERR_OUTPUT_CREATEBUFFER), @@ -251,7 +258,7 @@ void LLAudioEngine_FMODSTUDIO::allocateListener(void) mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); if (!mListenerp) { - LL_WARNS() << "Listener creation failed" << LL_ENDL; + LL_WARNS("FMOD") << "Listener creation failed" << LL_ENDL; } } @@ -260,16 +267,16 @@ void LLAudioEngine_FMODSTUDIO::shutdown() { stopInternetStream(); - LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; + LL_INFOS("FMOD") << "About to LLAudioEngine::shutdown()" << LL_ENDL; LLAudioEngine::shutdown(); - LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; + LL_INFOS("FMOD") << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; if (mSystem) { mSystem->close(); mSystem->release(); } - LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL; + LL_INFOS("FMOD") << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL; delete mListenerp; mListenerp = NULL; diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index f745d26864..b51c791621 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -381,54 +381,50 @@ void LLProgressView::initLogos() const U8 image_codec = IMG_CODEC_PNG; const LLRectf default_clip(0.f, 1.f, 1.f, 0.f); - const S32 default_height = 24; - const S32 default_width = 91; + const S32 default_height = 32; const S32 default_pad = 7; + S32 icon_width; + // We don't know final screen rect yet, so we can't precalculate position fully LLTextBox *logos_label = getChild("logos_lbl"); S32 texture_start_x = logos_label->getFont()->getWidthF32(logos_label->getText()) + default_pad; S32 texture_start_y = -3; - // Normally iamges stay in skins folder, but 3p images come from package instead - // of repository and need special handling -#ifdef LL_WINDOWS - std::string temp_str = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons"); -#elif LL_DARWIN - // On MAC use resource directory - std::string temp_str = gDirUtilp->add(gDirUtilp->getAppRODataDir(), "3p_icons"); -#else - std::string temp_str = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "3p_icons"); -#endif + // Normally we would just preload these textures from textures.xml, + // and display them via icon control, but they are only needed on + // startup and preloaded/UI ones stay forever + // (and this code was done already so simply reused it) + std::string temp_str = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "textures", "3p_icons"); + temp_str += gDirUtilp->getDirDelimiter(); #ifdef LL_FMODSTUDIO - const S32 fmod_y_offset = 2; - loadLogo(temp_str + "fmod.png", + icon_width = 89; + loadLogo(temp_str + "fmod_logo.png", image_codec, - LLRect(texture_start_x, texture_start_y + default_height + fmod_y_offset, texture_start_x + default_width + fmod_y_offset, texture_start_y), + LLRect(texture_start_x, texture_start_y + default_height, texture_start_x + icon_width, texture_start_y), default_clip, default_clip); - texture_start_x += default_width + default_pad; + texture_start_x += icon_width + default_pad; #endif + icon_width = 100; loadLogo(temp_str + "havok_logo.png", image_codec, - LLRect(texture_start_x, texture_start_y + default_height, texture_start_x + default_width, texture_start_y), + LLRect(texture_start_x, texture_start_y + default_height, texture_start_x + icon_width, texture_start_y), default_clip, default_clip); - texture_start_x += default_width + default_pad - 2; // offset to compensate for enormous borders for vivox + texture_start_x += icon_width + default_pad; - const LLRectf vivox_clip(0.0f /*repeats*/, 0.52f /*cut starting from center*/, 0.52f, 0.0f); // non-standard icon, clip it - const LLRectf vivox_offset(0.0f, 0.23f, 0.23f, 0.0f); // keeping clipping identical to not mess up scale - const S32 vivox_y_offset = -5; + icon_width = 87; loadLogo(temp_str + "vivox_logo.png", image_codec, - LLRect(texture_start_x, texture_start_y + default_height + vivox_y_offset, texture_start_x + default_width, texture_start_y + vivox_y_offset), - vivox_clip, - vivox_offset); + LLRect(texture_start_x, texture_start_y + default_height, texture_start_x + icon_width, texture_start_y), + default_clip, + default_clip); } void LLProgressView::initStartTexture(S32 location_id, bool is_in_production) @@ -511,8 +507,11 @@ void LLProgressView::initTextures(S32 location_id, bool is_in_production) initStartTexture(location_id, is_in_production); initLogos(); - LLTextBox *logos_label = getChild("logos_lbl"); - logos_label->setVisible(true); + if (!mLogosList.empty()) + { + LLTextBox *logos_label = getChild("logos_lbl"); + logos_label->setVisible(true); + } } void LLProgressView::releaseTextures() diff --git a/indra/newview/skins/default/textures/3p_icons/fmod_logo.png b/indra/newview/skins/default/textures/3p_icons/fmod_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..5da146bfa923f521fe081528780aad4a98be7f4a GIT binary patch literal 1732 zcmdUv`#aMM0LH&j$&jtNgdCT-XCa(fo6B4}TNt*5<&w%U<dEWQ)Jnzr%^D;g0KPiCJK>z?K;IPhweUkUB zeMEXc@f&)X`%t61_|l1yA#}zi8U?@vM_#6A<03AFQV5hw!Ex7x6f^)xo$+)dxhyU& zLLiWtnHd=wnVp@Ty1Kd}M~=wL%WG+Aef#ze1OmNz^QNb#XKQOqRaLd4qvPGXcZ!ON zOG``h^Ya`IM=Tc4&d%D{*dUQe9UUEAUES^NZA(kb@87?7cXul*D<3_2^w_auva+%x zBO`Kha!N`{6%`fZK!NKRxpLch6heDxtc6Rpm_9iAKK0ZFi#>Upx z))p2P8X6i33JQl0A10AVB9SODF>z{YYG7bsb8~ZTZSDR0_r=A<3kwTgUS4i)ZbL&u zSS(guT|F~1v%kOp_3PIZ3dPpe*2BZY%*-q|H+ODsZen6WAP_u${J6fpJ|-q6E-vok z#fuCE!^p@eBO`-AAP|YfSFc{7P^i88(~E<#OqCdV70&ZEfxS`}bKa z7L7(rNlB@$uFlWTcXf45OG}H2ii(boCX>lsU0qBjv#P2pC@5%eZ*PBN4F&gk`)HvP z@WlP*|102+zxp2lfV4Nx8AFO4U10n85HaAp(rs4SU`N*^tiw&SKFm#sr-M>?-yzb$ zlHps+&Fi0TF}}1SIgPT26SqNjvFY1UPZt)l;T(=v+jw}z-gKPs_kV}Zk%mjHmn7*h z9lXdfu=O4@B<5!}vp5JO@7f1G%PcDFnbu3*A$>&%;u z{w#R2@g5pKJ)eA6e*|($dfD7PC{!aw9e(rgSodUXp~C z@y?&WO!{Q7PZ@Hxf=~=+P4xN&|GE%dJck=%xtR1+Cb-*;JOR3~hLMuhJS#6+u4y*M zt(nxO-6W|X3PYORTRbQ7^6xSa=;#j&m3B5bV8m&2iGgxEN_O~OT4K3w&dPw3@P~=V zv&DlLrNxr6E0A(Szq*rG$BM`=ezKSg0Jyb-Ui1Yp^p^lV%L8*I?LXqW$a1g^%|ED5 zm@!pFpjB`6dg&}xI{Z57p{I9|Emji>Q1v*@7tGGy&^+-fvYvPTU_{fVAx)u#YHgzC zY$O8{edVKG5>ITOqoJp2n8hIumJv(ZNW#m)hgSB;r|+)Y!mSp-`8Pi0uImbECvow$ z6^pG+?WP-cpBWn3l_@JOcLQv*pOI@5w??@f_JFk2g`O0w$p{6`)+@NsaXsXe>q^)+ z-9^63mU?toopNrSauu=TKaTRJKx`?lsvpJ>z8|Kp%G8G7UUC1u^og2nwZM&S@^`>W}kiGmTZwd422YgKMm&yun%RKN;v6gPNv^E9uS+ZemMx zSqEO@4CLAgsnigdpK)@-6jQiU;H=Y1TW*th|p!b3#v2_h4Im(%IV_uQjo9yh1%PwGJ3n^}y7wP)5~Xth literal 0 HcmV?d00001 diff --git a/indra/newview/skins/default/textures/3p_icons/havok_logo.png b/indra/newview/skins/default/textures/3p_icons/havok_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1b51e23ca0c9d250241aeb971d4bb983f2f0bde1 GIT binary patch literal 2586 zcmd^A`8U*y106ME&|8l8_K7DidOaH;tvSRD{S9%D$BBrG!U>XUm>-BFthL zOIahKY!6AckdnNZ&)5I)z31F}&$;LRde41GGdF^Z;6*?n5S(gkK;L)geG-KZ?(6WD z3Sr+Q{R|m?7T!1g0v+$TfGE!1H(ZERFGp7wx{IT8uy41EE(mlGL^HKC?0adq%My?C zGsYngxL=k6+E73jrm;5n+3iCpw8YzFF`yYOFLiK*XP0{y1~iMt-jo425Z64U?co(Wct&P zI}PGZv7%H>h?AMjQYEV7o-_eZq-c_I0;IJS!6G7u;BZ9bb&;}Acz!Se2^Sdq2LbS~ zKoe4#cyO^?LJ$lRh6<=Ckd%+B1Fd4Kjc0)t)E)-|aKsKvA=7-MVZs8}452>OvREuh zPZiP-Pmm!Ht0Um53X(UBgsxJFU#D_T+hvD~l7~qZeU0-iEQ=zE> zTu~TdI14e9i5tm8d}m_&^0Wuj5oHmCP+x`@O?bWpyHY8!@)E_$qWxrRQYh#0G9U3u zJ?2Uzr@5XxTuf~wdZ7#lG>L35Wp~(^Jb&0|p3JK($J<`F+`R(mmUjN$u9Li2U?Oc9sY6e zFm6Z`zY2#K)otj(h9n#>8{a^lLJ$~(E&(?Ker0^wSf#&uugv~d!~U?wuIXj2p6gTh zy~q7`)uc<|RR23ZKO?y1`F7~P+tcfNi6B2@zr(rn+=v7RhG5^1^YgRsBDp8^Gjdk9 z4$UW8jG1ZWOBCB`gQ##V`*JVj?b?(i6D@n-dV>M68CT)H2R}@aee<}r|A=U z%Q)J{v1r=ozlMm?-WP+ZlCJuXSY7Ch0fV?Z}0fs5m@o5@$`$# zPWQT0sik(Rp1WLCP9+>=ymTjG562gat({dts?=S~J!>=aZ2^a_Z8u$hwI1kI#r`>Q z*wa(G{P9v!;gg{m-xmWPp`QlHGYw=lQhuvYAWOS@ZEl-YVOi>b;}2b|uUw7MRD^HEflec*jSf7`kn(?<(t zS<#&{2~U!Bqrcj-Ib_l<(fCEXjW^3*F}RW2#U)!0sA;eEr0r#Z)M{P2f(X2B@Zv_$ z2>%RlSG5CE^wa`0Zyiy1K4bAg1myH4KPeIS>E@usfR4uQ@tp?x4f1Qr*^N#~D@5Ka zaDEL5`Ba~knAvLk9St)dGak1O9bP(hxgORgQ5iV;GcI1{w%h<~vcqpDYE9gHPJ@Qe zAq(==G@_%-AGPIhW*{@pIH<1*en z*#$iz5an;(TS)}!Gc0the@?4hk?C`Cw$f-s{pf76!QNRx`BC)wahEiYDJaXAS7k@IO+o8dLC9%?r=O7Q{v5fqi}9%chGE_KU<*&S*;{69}zGT`f^v2fl!|&9G?}S@w znOR_picA8tQc7k*84O#YUgnF}ZHg$B8s+ouUC%$C60`Mu{*`ttStkv+Q+_ndpH=C) zcY>2@NU-rWt-PjQDW5|#YY5_iRi;LX)y?MVj-1j2gE^iJT_K+i4@o6vRIw*^?=(qm zP{|a=(>|-L7Mf49suCc@T;ASzp;K(;6`>rCE6to(!5TA~I_JdiXSEE^w6JR$wx-`l j?21w{0s8Mt5dxso3kjMwGeLLvFAPLAG&iWa;1Kyg&O}9m literal 0 HcmV?d00001 diff --git a/indra/newview/skins/default/textures/3p_icons/vivox_logo.png b/indra/newview/skins/default/textures/3p_icons/vivox_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..6bbd050eae4dbe934a40e0b47ad90178429b7a0f GIT binary patch literal 1740 zcmds$`8Sjc7{}jo$Ji#+gmLJqISh^ySuRt^HZiucotaybZ7fL&CuQp-%q?*X5mOW< zbZt=#QkEI6-H1jLV;Lb!67Jxg_kHjDaQ}+?J?Hy;&Uw!Fr{_H1d*|F8F>>m1003af zP7aY+OJz4X_Q43Z!X~BLhNdp0t4ATi1JOmH@E- z_BmH?5`w^Du^19VFoIN8R)QdiMx*8A8q@*Otef;>* z%F3#@w^u_$1A<@`6%`x~CoeDG)zzh=qtn#Xq^zvm(9j?&D|_e89S;wW&dyF4g4^5M z2?TQK?QJX;d-(9-Lx&C>IB-B(S{j4FEG#UHjEoEo4Rv>S zZ)|Mr?d@r6YrlK<&eheG&1M@J87(d@^7(ud6BAWc)#2e`fk5!`otF@(TEp-@Xp>&A^6!NI{xOG_{W+1S`vSXkKF+Lo7> zJ3Bk??(Tm2^a(~_V`F1=b@kHH(y6JbH*el-ZEf**ywTCog9i^ z7k@i85tS1 zwY4rTE+7J}uB@_HEa99mGcyxGpy}!9l9H0opFekWbgZqd)z#JY_4ScRq_(!U#Kgqh z+}y#z!HS9sMMXtROUu;M)R~zX2!S3xeCX-vdH($Q!otF|v@{r&93DatMDnP09BQBh zIeY^S;J?F;Z$@3n3R8Uf)go|Lc$S<}$2ilw>Thoo)A1LKa$}afrNAyy3?f{nfWP_Vj&$)<&A(T)r z+YOU1B%Lrs;D^zk&5A>OJ$yOrC_^`It%XumyL z6Ks^0dNR5#m0Yq}tyJq`X{=aP*YlpW!j*C6;M9A$E3M{b*cJ0`(215|{HQOdhAp7d z6V;jCs_T+6ez!v1ZJKto;k)tCjwxydjI|cUl|-~g=IG;Qo@1IYR{3q|#8cml(!fiL z)hfgeapm*nQ)z%&X9l2{pG=8B<6Cg6>E#y#2T+Cwenq(f*sgL98)|hY4*hJxwj^>b zI|}uB5Z1)6F)B?>%D!Fm)&0(Hs5EFYey)*4e+j-IUs#e};6Iz1ehsS$zN>D?{wSh5 z#n#r9AE93Fuyka_5S4FI#((xaXz;1(Cd%E8h&_F47?;Zt*v^zyJpSq))GS>o|2!h; z2kpqEcWR-}Ow(m`$f@$|{%zx$eWZP9_AE^64JjI%cNHrX-xa$9R7*hPPbQsVsP{%ffz8?RNP+Ydt)1vBfavtW?hj=?K%KuS6DmgL`4#4^F>Oy(y3%i^!rq73xrm zT*5+nDUBPCh=hQk0snpXF60=PWv7%EV?!*D?y~F|DqjfIe5T$nJNN>#G4rq(&CaP% z!pT3QF7-@a3OCz4)YE>reK^I&rhU$&puz5%uW0jEjgQ?Lh5;S*S#e(V*2zG$Fzi&$ zNF$rqpl?p$Cd~5-h=2W4?78~QN7redH+ug5tI^BhESi+d)jtTxx~q|>7?1*njkewn TVP2e-)Eyv`+#PD{{8Rn~(n{wr literal 0 HcmV?d00001 diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index de71a66519..572c84c396 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -497,13 +497,6 @@ class WindowsManifest(ViewerManifest): self.path("*.png") self.path("*.gif") - # Copy 3p icons - with self.prefix(src=os.path.join(pkgdir, "icons"), dst="3p_icons"): - if self.args['fmodstudio'] == 'ON': - self.path("fmod.png") - self.path("havok_logo.png") - self.path("vivox_logo.png") - # Plugin host application self.path2basename(os.path.join(os.pardir, 'llplugin', 'slplugin', self.args['configuration']), @@ -973,13 +966,6 @@ class DarwinManifest(ViewerManifest): with self.prefix(src=pkgdir,dst=""): self.path("ca-bundle.crt") - # Copy 3p icons - with self.prefix(src=os.path.join(pkgdir, "icons"), dst="3p_icons"): - if self.args['fmodstudio'] == 'ON': - self.path("fmod.png") - self.path("havok_logo.png") - self.path("vivox_logo.png") - # Translations self.path("English.lproj/language.txt") self.replace_in(src="English.lproj/InfoPlist.strings", @@ -1480,13 +1466,6 @@ class Linux_i686_Manifest(LinuxManifest): relpkgdir = os.path.join(pkgdir, "lib", "release") debpkgdir = os.path.join(pkgdir, "lib", "debug") - # Copy 3p icons - with self.prefix(src=os.path.join(pkgdir, "icons"), dst="3p_icons"): - if self.args['fmodstudio'] == 'ON': - self.path("fmod.png") - self.path("havok_logo.png") - self.path("vivox_logo.png") - with self.prefix(src=relpkgdir, dst="lib"): self.path("libapr-1.so") self.path("libapr-1.so.0") From c49e9baa487610eb16717d6c6b01ed1d1c0426d3 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 15 Apr 2020 22:52:28 +0300 Subject: [PATCH 21/50] SL-12607 Rearrange login panel --- indra/newview/llprogressview.cpp | 19 +- .../skins/default/textures/textures.xml | 1 + .../textures/widgets/ProgressBarSolid.png | Bin 0 -> 208 bytes .../skins/default/xui/en/panel_progress.xml | 198 ++++++++++++------ 4 files changed, 148 insertions(+), 70 deletions(-) create mode 100644 indra/newview/skins/default/textures/widgets/ProgressBarSolid.png diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index b51c791621..dd44e661d6 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -382,14 +382,14 @@ void LLProgressView::initLogos() const U8 image_codec = IMG_CODEC_PNG; const LLRectf default_clip(0.f, 1.f, 1.f, 0.f); const S32 default_height = 32; - const S32 default_pad = 7; + const S32 default_pad = 25; S32 icon_width; // We don't know final screen rect yet, so we can't precalculate position fully LLTextBox *logos_label = getChild("logos_lbl"); S32 texture_start_x = logos_label->getFont()->getWidthF32(logos_label->getText()) + default_pad; - S32 texture_start_y = -3; + S32 texture_start_y = -7; // Normally we would just preload these textures from textures.xml, // and display them via icon control, but they are only needed on @@ -507,11 +507,10 @@ void LLProgressView::initTextures(S32 location_id, bool is_in_production) initStartTexture(location_id, is_in_production); initLogos(); - if (!mLogosList.empty()) - { - LLTextBox *logos_label = getChild("logos_lbl"); - logos_label->setVisible(true); - } + childSetVisible("panel_icons", mLogosList.empty() ? FALSE : TRUE); + childSetVisible("panel_login", TRUE); + childSetVisible("panel_teleport", FALSE); + childSetVisible("panel_spacer", FALSE); } void LLProgressView::releaseTextures() @@ -519,8 +518,10 @@ void LLProgressView::releaseTextures() gStartTexture = NULL; mLogosList.clear(); - LLTextBox *logos_label = getChild("logos_lbl"); - logos_label->setVisible(false); + childSetVisible("panel_login", FALSE); + childSetVisible("panel_teleport", TRUE); + childSetVisible("panel_spacer", TRUE); + childSetVisible("panel_icons", FALSE); } void LLProgressView::setCancelButtonVisible(BOOL b, const std::string& label) diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index 17340e0858..d4645cc459 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -486,6 +486,7 @@ with the same filename but different name + diff --git a/indra/newview/skins/default/textures/widgets/ProgressBarSolid.png b/indra/newview/skins/default/textures/widgets/ProgressBarSolid.png new file mode 100644 index 0000000000000000000000000000000000000000..ec0926bfa1cbc70b172f51704227bc30e418cf6b GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^CP2*3!3HE(AAQpbq!^2X+?^QKos)S9a~60+7BevL9R^{>E{-7{-fyRPb2%7tF!O%>C$6izt}Ebo z^L1~NJ&~Se&2EXzuM5(-44yv`l1eV%bY(evmGOs}i|Uo?=R!s0dJC^fO`kAx?d8SN zdwsn;1G1kAX)Rszc~|}yvsGFrEQ>{6Jm+*VJGs+syWGubj6e$+JYD@<);T3K0RT#W BMsNTC literal 0 HcmV?d00001 diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml index f52422c08f..1384e5e779 100644 --- a/indra/newview/skins/default/xui/en/panel_progress.xml +++ b/indra/newview/skins/default/xui/en/panel_progress.xml @@ -58,69 +58,145 @@ left="0" top="0" width="670" /> - - - - - - - Second Life uses - + left="0" + orientation="vertical" + name="vertical_centering" + animate="false" + top="0" + width="670"> + + + Logging in... + + + + + + + + + + + + + + + + + + Second Life uses + + + Date: Thu, 16 Apr 2020 17:34:29 +0300 Subject: [PATCH 22/50] SL-12607 Removed spacer --- indra/newview/llprogressview.cpp | 2 -- indra/newview/skins/default/xui/en/panel_progress.xml | 8 -------- 2 files changed, 10 deletions(-) diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index dd44e661d6..afda384c84 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -510,7 +510,6 @@ void LLProgressView::initTextures(S32 location_id, bool is_in_production) childSetVisible("panel_icons", mLogosList.empty() ? FALSE : TRUE); childSetVisible("panel_login", TRUE); childSetVisible("panel_teleport", FALSE); - childSetVisible("panel_spacer", FALSE); } void LLProgressView::releaseTextures() @@ -520,7 +519,6 @@ void LLProgressView::releaseTextures() childSetVisible("panel_login", FALSE); childSetVisible("panel_teleport", TRUE); - childSetVisible("panel_spacer", TRUE); childSetVisible("panel_icons", FALSE); } diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml index 1384e5e779..a0dfff3bd4 100644 --- a/indra/newview/skins/default/xui/en/panel_progress.xml +++ b/indra/newview/skins/default/xui/en/panel_progress.xml @@ -141,14 +141,6 @@ name="login_progress_bar" right="-45" /> - - Date: Thu, 23 Apr 2020 19:39:48 +0200 Subject: [PATCH 23/50] Fix merge errors --- indra/llaudio/llaudioengine_fmodstudio.cpp | 15 +-------------- indra/newview/pipeline.cpp | 2 +- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/indra/llaudio/llaudioengine_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp index f91622227b..3790107fd1 100644 --- a/indra/llaudio/llaudioengine_fmodstudio.cpp +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -283,19 +283,6 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons // initialize the FMOD engine result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0); - if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) - { - /* - Ok, the speaker mode selected isn't supported by this soundcard. Switch it - back to stereo... - */ - result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0); - Check_FMOD_Error(result,"Error falling back to stereo mode"); - /* - ... and re-init. - */ - result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, 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*/); @@ -303,7 +290,7 @@ bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, cons { return false; } - result = mSystem->init(num_channels + 2, fmod_flags, 0); + result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0); } if (Check_FMOD_Error(result, "Error initializing FMOD Studio")) { diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 03932dfdd6..6cfcfc6135 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -459,7 +459,7 @@ void LLPipeline::init() sRenderBump = gSavedSettings.getBOOL("RenderObjectBump"); sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips"); LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO"); - LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO"); + // Vertex Array Objects are required in OpenGL core profile //LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO"); LLVertexBuffer::sUseVAO = LLRender::sGLCoreProfile ? TRUE : gSavedSettings.getBOOL("RenderUseVAO"); // From 4b761c9b96ded680d4567c309a98845a2d62b7dc Mon Sep 17 00:00:00 2001 From: Ansariel Date: Thu, 23 Apr 2020 19:41:15 +0200 Subject: [PATCH 24/50] Tweak login progress --- indra/newview/llprogressview.cpp | 22 ++++++++++++------ .../skins/default/xui/de/panel_progress.xml | 23 +++++++++++++++++++ .../skins/default/xui/en/panel_progress.xml | 11 ++++----- 3 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 indra/newview/skins/default/xui/de/panel_progress.xml diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index c2c689eb4a..1be4116180 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -230,7 +230,7 @@ void LLProgressView::setStartupComplete() mFadeToWorldTimer.start(); } - // NickyD: FIRE-3063; Enable Audio for all media sources again. They got disabled during postBuild(), but as we never reach LLProgressView::draw + // FIRE-3063; Enable Audio for all media sources again. They got disabled during postBuild(), but as we never reach LLProgressView::draw // if the progress is disabled, we would never get media audio back. LLViewerMedia::getInstance()->setOnlyAudibleMediaTextureID(LLUUID::null); } @@ -255,7 +255,7 @@ void LLProgressView::setVisible(BOOL visible) } } -// ## Zi: Fade teleport screens +// Fade teleport screens void LLProgressView::fade(BOOL in) { if(in) @@ -271,7 +271,7 @@ void LLProgressView::fade(BOOL in) // set visibility will be done in the draw() method after fade } } -// ## Zi: Fade teleport screens +// Fade teleport screens void LLProgressView::drawStartTexture(F32 alpha) { @@ -489,6 +489,7 @@ void LLProgressView::initLogos() texture_start_x += icon_width + default_pad; #endif +#ifdef HAVOK_TPV // Don't show on non-Havok builds icon_width = 100; loadLogo(temp_str + "havok_logo.png", image_codec, @@ -497,6 +498,7 @@ void LLProgressView::initLogos() default_clip); texture_start_x += icon_width + default_pad; +#endif // Don't show on non-Havok builds icon_width = 87; loadLogo(temp_str + "vivox_logo.png", @@ -587,8 +589,12 @@ void LLProgressView::initTextures(S32 location_id, bool is_in_production) initLogos(); childSetVisible("panel_icons", mLogosList.empty() ? FALSE : TRUE); - childSetVisible("panel_login", TRUE); - childSetVisible("panel_teleport", FALSE); + // Show normal login progress + //childSetVisible("panel_login", TRUE); + //childSetVisible("panel_teleport", FALSE); + childSetVisible("panel_login", FALSE); + childSetVisible("panel_teleport", TRUE); + // } void LLProgressView::releaseTextures() @@ -596,9 +602,11 @@ void LLProgressView::releaseTextures() gStartTexture = NULL; mLogosList.clear(); - childSetVisible("panel_login", FALSE); - childSetVisible("panel_teleport", TRUE); + // Show normal login progress + //childSetVisible("panel_login", FALSE); + //childSetVisible("panel_teleport", TRUE); childSetVisible("panel_icons", FALSE); + // } void LLProgressView::setCancelButtonVisible(BOOL b, const std::string& label) diff --git a/indra/newview/skins/default/xui/de/panel_progress.xml b/indra/newview/skins/default/xui/de/panel_progress.xml new file mode 100644 index 0000000000..a5c5276a0d --- /dev/null +++ b/indra/newview/skins/default/xui/de/panel_progress.xml @@ -0,0 +1,23 @@ + + + + + + + + + + Anmeldung... + + + + + [APP_NAME] verwendet + + + + + + + + diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml index a0dfff3bd4..041432ff0d 100644 --- a/indra/newview/skins/default/xui/en/panel_progress.xml +++ b/indra/newview/skins/default/xui/en/panel_progress.xml @@ -92,9 +92,9 @@ @@ -131,10 +131,9 @@ name="panel_progress" width="670"> - Second Life uses + [APP_NAME] uses From a6b3b98e52d0f4a4b8376596a331613466131a89 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 30 Apr 2020 21:52:55 +0300 Subject: [PATCH 25/50] SL-12898 Added https to allowed audio links --- indra/newview/llviewerparcelmgr.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index e197591ef8..c966b7d4f9 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -1902,7 +1902,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use // If there is a new music URL and it's valid, play it. if (music_url.size() > 12) { - if (music_url.substr(0, 7) == "http://") + if (music_url.substr(0, 7) == "http://" + || music_url.substr(0, 8) == "https://") { LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender()); optionally_start_music(music_url, parcel->mLocalID, region->getRegionID()); From 2bddce7cabd525853e59c442223ab88996432d7a Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 21 Feb 2020 23:38:39 +0200 Subject: [PATCH 26/50] SL-12678 Removed auto login retry --- indra/newview/lllogininstance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp index 8a69acb8dc..873531ef22 100644 --- a/indra/newview/lllogininstance.cpp +++ b/indra/newview/lllogininstance.cpp @@ -62,7 +62,7 @@ #include #include -const S32 LOGIN_MAX_RETRIES = 3; +const S32 LOGIN_MAX_RETRIES = 0; // Viewer should not autmatically retry login const F32 LOGIN_SRV_TIMEOUT_MIN = 10; const F32 LOGIN_SRV_TIMEOUT_MAX = 120; const F32 LOGIN_DNS_TIMEOUT_FACTOR = 0.9; // make DNS wait shorter then retry time From 05bc927dd86addcdfb338dfba4045b81da8a5cbd Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 5 May 2020 19:43:10 +0300 Subject: [PATCH 27/50] SL-12607 Revert changes to no longer necessary packages This packages were needed for icons, but since icons are no longer needed, neither should packages change. --- autobuild.xml | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 37ffe61307..51259486ab 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -1420,9 +1420,9 @@ archive hash - 7e883d641b5e541c3c46fb6efbbd06ca + a0c4405c9e44d4a0135fe20ba8cfbace url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/51113/463266/havok_source-2012.1-2-darwin64-536003.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4693/14627/havok_source-2012.1-2-darwin64-504680.tar.bz2 name darwin64 @@ -1456,9 +1456,9 @@ archive hash - 81e15d58f3ce98f8342842b62bce08f0 + 035572a1929be66f6c56468e0ef7fe74 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/51115/463279/havok_source-2012.1-2-windows-536003.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4695/14637/havok_source-2012.1-2-windows-504680.tar.bz2 name windows @@ -1468,9 +1468,9 @@ archive hash - df66566126db0f7b75af024b0768a541 + d8525d2fbb9e0f7bc31427b47350e468 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/51114/463273/havok_source-2012.1-2-windows64-536003.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/4694/14634/havok_source-2012.1-2-windows64-504680.tar.bz2 name windows64 @@ -2930,11 +2930,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - d02241c69dc4fac8e270f9bdc0460a90 - hash_algorithm - md5 + f824d586ab5de6edd14ef6828e9e4b66 url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/51111/463254/slvoice-4.10.0000.32327.5fc3fe7c.536001-darwin64-536001.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/44719/395040/slvoice-4.10.0000.32327.5fc3fe7c.531581-darwin64-531581.tar.bz2 name darwin64 @@ -2968,9 +2966,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 6c9c0f59e4974e131456c3ced2b6b23f + 1941c17c81905f23b4928288bcf719fb url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/51107/463239/slvoice-4.10.0000.32327.5fc3fe7c.536001-windows-536001.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/44720/395047/slvoice-4.10.0000.32327.5fc3fe7c.531581-windows-531581.tar.bz2 name windows @@ -2980,16 +2978,16 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors archive hash - 05341caee4c837fe732702fa18a7ed98 + baa6cdc8e8762d5519996ed9faa0bf3f url - http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/51108/463245/slvoice-4.10.0000.32327.5fc3fe7c.536001-windows64-536001.tar.bz2 + http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/44721/395056/slvoice-4.10.0000.32327.5fc3fe7c.531581-windows64-531581.tar.bz2 name windows64 version - 4.10.0000.32327.5fc3fe7c.536001 + 4.10.0000.32327.5fc3fe7c.531581 tut From 53da10525ed0e7b2dc78d40ad20313d98310d1cf Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Tue, 5 May 2020 20:01:11 +0300 Subject: [PATCH 28/50] SL-11445 pulled in fresh fmod studio package --- autobuild.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/autobuild.xml b/autobuild.xml index 51259486ab..9041b8488f 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -748,9 +748,9 @@ archive hash - 2bdcd463bb0e5f610f9af0c073f58066 + dc4c9122de8bf77f34cfc8227d10a272 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54587/506858/fmodstudio-2.00.07.538806-darwin64-538806.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/59038/554626/fmodstudio-2.00.07.541681-darwin64-541681.tar.bz2 name darwin64 @@ -760,9 +760,9 @@ archive hash - ae75cdb1cc9da824c9e270bf97bfdd6c + c491bdc1690f3d920c66be509ccc6ef2 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54589/506866/fmodstudio-2.00.07.538806-linux64-538806.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/59039/554632/fmodstudio-2.00.07.541681-linux-541681.tar.bz2 name linux @@ -784,9 +784,9 @@ archive hash - 5bc07fe561bf8fdf9060c60e247564a9 + 7f0294b038eab2d89ecc73bbf08b6d94 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54591/506881/fmodstudio-2.00.07.538806-windows-538806.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/59042/554668/fmodstudio-2.00.07.541681-windows-541681.tar.bz2 name windows @@ -796,16 +796,16 @@ archive hash - 90cd0547c8cf6957a9d1083c83ee4a8e + da2e8e2b809d8fe635ee437baa2a7386 url - http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54590/506880/fmodstudio-2.00.07.538806-windows64-538806.tar.bz2 + http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/59041/554656/fmodstudio-2.00.07.541681-windows64-541681.tar.bz2 name windows64 version - 2.00.07.538806 + 2.00.07.541681 fontconfig From c47516c4421dc3736cf0dbe70a5eba02c90d9a8e Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 28 May 2020 10:09:17 +0300 Subject: [PATCH 29/50] SL-12607 Reverted to original logos --- indra/newview/llprogressview.cpp | 21 ++++++++++++------ .../default/textures/3p_icons/fmod_logo.png | Bin 1732 -> 14486 bytes .../default/textures/3p_icons/havok_logo.png | Bin 2586 -> 41488 bytes 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index afda384c84..767cdd9388 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -384,7 +384,7 @@ void LLProgressView::initLogos() const S32 default_height = 32; const S32 default_pad = 25; - S32 icon_width; + S32 icon_width, icon_height; // We don't know final screen rect yet, so we can't precalculate position fully LLTextBox *logos_label = getChild("logos_lbl"); @@ -400,20 +400,27 @@ void LLProgressView::initLogos() temp_str += gDirUtilp->getDirDelimiter(); #ifdef LL_FMODSTUDIO - icon_width = 89; + // original image size is 264x96, it is on longer side but + // with no internal paddings so it gets additional padding + icon_width = 87; + icon_height = 23; + S32 pad_y = 5; + texture_start_x++; loadLogo(temp_str + "fmod_logo.png", image_codec, - LLRect(texture_start_x, texture_start_y + default_height, texture_start_x + icon_width, texture_start_y), + LLRect(texture_start_x, texture_start_y + pad_y + icon_height, texture_start_x + icon_width, texture_start_y + pad_y), default_clip, default_clip); - texture_start_x += icon_width + default_pad; + texture_start_x += icon_width + default_pad + 1; #endif - - icon_width = 100; + // original image size is 342x113, central element is on a larger side + // plus internal padding, so it gets slightly more height than desired 32 + icon_width = 103; + icon_height = 34; loadLogo(temp_str + "havok_logo.png", image_codec, - LLRect(texture_start_x, texture_start_y + default_height, texture_start_x + icon_width, texture_start_y), + LLRect(texture_start_x, texture_start_y + icon_height, texture_start_x + icon_width, texture_start_y - 1), default_clip, default_clip); diff --git a/indra/newview/skins/default/textures/3p_icons/fmod_logo.png b/indra/newview/skins/default/textures/3p_icons/fmod_logo.png index 5da146bfa923f521fe081528780aad4a98be7f4a..5a50e0ad34b54c63357a87094a102ba26d0782d6 100644 GIT binary patch literal 14486 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 j=}QWnc@$V+@snix#7EjcYJPq literal 1732 zcmdUv`#aMM0LH&j$&jtNgdCT-XCa(fo6B4}TNt*5<&w%U<dEWQ)Jnzr%^D;g0KPiCJK>z?K;IPhweUkUB zeMEXc@f&)X`%t61_|l1yA#}zi8U?@vM_#6A<03AFQV5hw!Ex7x6f^)xo$+)dxhyU& zLLiWtnHd=wnVp@Ty1Kd}M~=wL%WG+Aef#ze1OmNz^QNb#XKQOqRaLd4qvPGXcZ!ON zOG``h^Ya`IM=Tc4&d%D{*dUQe9UUEAUES^NZA(kb@87?7cXul*D<3_2^w_auva+%x zBO`Kha!N`{6%`fZK!NKRxpLch6heDxtc6Rpm_9iAKK0ZFi#>Upx z))p2P8X6i33JQl0A10AVB9SODF>z{YYG7bsb8~ZTZSDR0_r=A<3kwTgUS4i)ZbL&u zSS(guT|F~1v%kOp_3PIZ3dPpe*2BZY%*-q|H+ODsZen6WAP_u${J6fpJ|-q6E-vok z#fuCE!^p@eBO`-AAP|YfSFc{7P^i88(~E<#OqCdV70&ZEfxS`}bKa z7L7(rNlB@$uFlWTcXf45OG}H2ii(boCX>lsU0qBjv#P2pC@5%eZ*PBN4F&gk`)HvP z@WlP*|102+zxp2lfV4Nx8AFO4U10n85HaAp(rs4SU`N*^tiw&SKFm#sr-M>?-yzb$ zlHps+&Fi0TF}}1SIgPT26SqNjvFY1UPZt)l;T(=v+jw}z-gKPs_kV}Zk%mjHmn7*h z9lXdfu=O4@B<5!}vp5JO@7f1G%PcDFnbu3*A$>&%;u z{w#R2@g5pKJ)eA6e*|($dfD7PC{!aw9e(rgSodUXp~C z@y?&WO!{Q7PZ@Hxf=~=+P4xN&|GE%dJck=%xtR1+Cb-*;JOR3~hLMuhJS#6+u4y*M zt(nxO-6W|X3PYORTRbQ7^6xSa=;#j&m3B5bV8m&2iGgxEN_O~OT4K3w&dPw3@P~=V zv&DlLrNxr6E0A(Szq*rG$BM`=ezKSg0Jyb-Ui1Yp^p^lV%L8*I?LXqW$a1g^%|ED5 zm@!pFpjB`6dg&}xI{Z57p{I9|Emji>Q1v*@7tGGy&^+-fvYvPTU_{fVAx)u#YHgzC zY$O8{edVKG5>ITOqoJp2n8hIumJv(ZNW#m)hgSB;r|+)Y!mSp-`8Pi0uImbECvow$ z6^pG+?WP-cpBWn3l_@JOcLQv*pOI@5w??@f_JFk2g`O0w$p{6`)+@NsaXsXe>q^)+ z-9^63mU?toopNrSauu=TKaTRJKx`?lsvpJ>z8|Kp%G8G7UUC1u^og2nwZM&S@^`>W}kiGmTZwd422YgKMm&yun%RKN;v6gPNv^E9uS+ZemMx zSqEO@4CLAgsnigdpK)@-6jQiU;H=Y1TW*th|p!b3#v2_h4Im(%IV_uQjo9yh1%PwGJ3n^}y7wP)5~Xth diff --git a/indra/newview/skins/default/textures/3p_icons/havok_logo.png b/indra/newview/skins/default/textures/3p_icons/havok_logo.png index 1b51e23ca0c9d250241aeb971d4bb983f2f0bde1..ff1ea3a72e8baf13cf235021482f9d57bab2ef08 100644 GIT binary patch literal 41488 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 From 205546730e437ca20c034cb49658017de2966a4b Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 28 May 2020 12:09:08 +0300 Subject: [PATCH 30/50] SL-12664 readjusted logo --- indra/newview/llprogressview.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index 767cdd9388..00f818933f 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -416,11 +416,11 @@ void LLProgressView::initLogos() #endif // original image size is 342x113, central element is on a larger side // plus internal padding, so it gets slightly more height than desired 32 - icon_width = 103; - icon_height = 34; + icon_width = 100; + icon_height = 33; loadLogo(temp_str + "havok_logo.png", image_codec, - LLRect(texture_start_x, texture_start_y + icon_height, texture_start_x + icon_width, texture_start_y - 1), + LLRect(texture_start_x, texture_start_y + icon_height, texture_start_x + icon_width, texture_start_y), default_clip, default_clip); From 36c27bf5ec5075efa8f66c70b30eb618fb3e39e2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 28 May 2020 15:34:56 +0300 Subject: [PATCH 31/50] SL-12664 readjusted logo #2 --- indra/newview/llprogressview.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index 00f818933f..3251ad3605 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -418,9 +418,10 @@ void LLProgressView::initLogos() // plus internal padding, so it gets slightly more height than desired 32 icon_width = 100; icon_height = 33; + pad_y = -1; loadLogo(temp_str + "havok_logo.png", image_codec, - LLRect(texture_start_x, texture_start_y + icon_height, texture_start_x + icon_width, texture_start_y), + LLRect(texture_start_x, texture_start_y + pad_y + icon_height, texture_start_x + icon_width, texture_start_y + pad_y), default_clip, default_clip); From 2e238f0ba85f290582cf900a9e2f76eeb8528280 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 28 May 2020 17:17:54 +0300 Subject: [PATCH 32/50] SL-12665 Readjusted all logos --- indra/newview/llprogressview.cpp | 17 +++++++++-------- .../default/textures/3p_icons/vivox_logo.png | Bin 1740 -> 2331 bytes 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index 3251ad3605..e9b1b5ea73 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -381,8 +381,8 @@ void LLProgressView::initLogos() const U8 image_codec = IMG_CODEC_PNG; const LLRectf default_clip(0.f, 1.f, 1.f, 0.f); - const S32 default_height = 32; - const S32 default_pad = 25; + const S32 default_height = 28; + const S32 default_pad = 15; S32 icon_width, icon_height; @@ -402,9 +402,9 @@ void LLProgressView::initLogos() #ifdef LL_FMODSTUDIO // original image size is 264x96, it is on longer side but // with no internal paddings so it gets additional padding - icon_width = 87; - icon_height = 23; - S32 pad_y = 5; + icon_width = 77; + icon_height = 21; + S32 pad_y = 4; texture_start_x++; loadLogo(temp_str + "fmod_logo.png", image_codec, @@ -416,8 +416,8 @@ void LLProgressView::initLogos() #endif // original image size is 342x113, central element is on a larger side // plus internal padding, so it gets slightly more height than desired 32 - icon_width = 100; - icon_height = 33; + icon_width = 88; + icon_height = 29; pad_y = -1; loadLogo(temp_str + "havok_logo.png", image_codec, @@ -427,7 +427,8 @@ void LLProgressView::initLogos() texture_start_x += icon_width + default_pad; - icon_width = 87; + // 108x41 + icon_width = 74; loadLogo(temp_str + "vivox_logo.png", image_codec, LLRect(texture_start_x, texture_start_y + default_height, texture_start_x + icon_width, texture_start_y), diff --git a/indra/newview/skins/default/textures/3p_icons/vivox_logo.png b/indra/newview/skins/default/textures/3p_icons/vivox_logo.png index 6bbd050eae4dbe934a40e0b47ad90178429b7a0f..6f20e87b7ae817116bad7d2939b545cea3029c3e 100644 GIT binary patch literal 2331 zcmV+$3FP*PP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D2(U>+K~#8N?OS<> zPF)y3V@9G+GGCG}YWT+#HByL1wk-K$vX-s*M`$ub$QqF)Ax2*)$udHgY!kBYQT8RI zvF}XyjAd;1dwxIjyxqC(ecyZE_oesiyT3ZlJASkMph%k{%kPLTHea=(B7u~o?7G?DXaEfcC0yf?p#cz-@bh_ zt5>f!vu4dQFJHc-%+A;6`}gmgNs}g-9Xocg>;|;8X3ZKibLLF*;>8P3-D>BvXV1)x z88b|Aaj|D-EBEQsr)JBREoSuS(WZU-_9iDM$8_k>!4wu2QjWINpO>jxGiT25ThT7cfgwf|N&>!A=B|(qV}9et4OnfB7%{>UBPer1xuvD0`}Wa&vPn zak8~w!2)Z_lqptrc6Q|5kt0XQcYd>$uV24TUd@^{Eg4XhsZPzGJb4mn@7AqblzH`` z4N7<~siAL&*)eY1I4Zq!=MKxx&d~C@b?eAGeE2ZSUc779u8}uy-aM9_(2vp&9yV;4 zB}*1%Zm6iJum%nsNUqEd%IqDZdSy0{)4FwQKBJx;A3uJi?cg9?x^#(hukYBsdpCKq z3a|{QUgR>f_{3`ks z%Eh}06DE**;J^XObY&?iDWM!QI3U!J;0{y6%F4>9JTEVgqY$tg4e01yym&Fo_6|@e z*N?-Ld;0Wga#yWd#j?EvRmbw>%gK@bf@L?3F4q_U060z?wTw<5Ja{nq_wL=J%*j<9 z_GRzk!-tgJy?dACtgNh`mP;Q{MRZu8C=r{aR5F>FnP$n7C1%&IT}IYozJnaljZ~Hr z=AAotX0Gq!g|^$gd2`dEMGLcXeb7P88gPbe*HQ!8Ub-8^Ff0KnHn`}L_*p`AqF!?=ncqT${cO$ zh~2kuA9Lk6p?1J#pn7$GzbN550NI@s8gCWX<~*CA8w{jofr>C2~efzR}@#01101op2W(INBt_3JZtgANARgg^r~JhI1|i4!N% zff(38LVY4i0w0_K-E?)6mt~OUPMtbg;z;Ywn>Q?ram?MIZ3H=o0otYv6xKs1jc^;! zu{L*=%Su4L?7=Jp&Ok!Tvb0$}dh{S)988(BedXeO2%bc<*7N7jDMKBJtSQHF0&wbz z0#y|MO$VR`OBhWfst{!-frfjurLUF@F4b){&*F zQsNH1=9)HbTBW2a^gD4`(63)Va`geD_5>q9Xoc6w1H;{XgCN|)~#DNek0&)Tiem=I?OQVpwax@yLXm^ z`s5uuc8oF~PE!IMhCg#Flm>7V$KNGpND2&W_}jK^V_2P=n`>INYQ+sWRz#$nM~@!y z=L!6*A)QnCHafH}ej33h58%9mn+89+0p%g=#?eHa#~Tpbmei?J$7E$?@n!{f)v8s? zvt2}*n>TMZWo2b1FE5YB4sk@4ql1=ZR-2NN5(Y2*`}g;A4upfD6la8{NpYAHemg8t zxakS1+u5;R@XG_dY>2a8syHmJu-*+Y1|JoVQTDn)06khaUfp_b(l!*%c4Ik9`O$2! z+lxFNB+X$k1|Jo)!+>Pejki8vZ$lBZUFFB(`sH~cX$}kVdti51d~-C!Zv`A?cNCt( zlzIu^GaRO~jDKt&rj$$SA4KqJ2hOi2n>Q!*s0-k>ZfETXKI~4DqXB%)jw)#n6oU+wTAX002ovPDHLkV1l*f BXaxWO literal 1740 zcmds$`8Sjc7{}jo$Ji#+gmLJqISh^ySuRt^HZiucotaybZ7fL&CuQp-%q?*X5mOW< zbZt=#QkEI6-H1jLV;Lb!67Jxg_kHjDaQ}+?J?Hy;&Uw!Fr{_H1d*|F8F>>m1003af zP7aY+OJz4X_Q43Z!X~BLhNdp0t4ATi1JOmH@E- z_BmH?5`w^Du^19VFoIN8R)QdiMx*8A8q@*Otef;>* z%F3#@w^u_$1A<@`6%`x~CoeDG)zzh=qtn#Xq^zvm(9j?&D|_e89S;wW&dyF4g4^5M z2?TQK?QJX;d-(9-Lx&C>IB-B(S{j4FEG#UHjEoEo4Rv>S zZ)|Mr?d@r6YrlK<&eheG&1M@J87(d@^7(ud6BAWc)#2e`fk5!`otF@(TEp-@Xp>&A^6!NI{xOG_{W+1S`vSXkKF+Lo7> zJ3Bk??(Tm2^a(~_V`F1=b@kHH(y6JbH*el-ZEf**ywTCog9i^ z7k@i85tS1 zwY4rTE+7J}uB@_HEa99mGcyxGpy}!9l9H0opFekWbgZqd)z#JY_4ScRq_(!U#Kgqh z+}y#z!HS9sMMXtROUu;M)R~zX2!S3xeCX-vdH($Q!otF|v@{r&93DatMDnP09BQBh zIeY^S;J?F;Z$@3n3R8Uf)go|Lc$S<}$2ilw>Thoo)A1LKa$}afrNAyy3?f{nfWP_Vj&$)<&A(T)r z+YOU1B%Lrs;D^zk&5A>OJ$yOrC_^`It%XumyL z6Ks^0dNR5#m0Yq}tyJq`X{=aP*YlpW!j*C6;M9A$E3M{b*cJ0`(215|{HQOdhAp7d z6V;jCs_T+6ez!v1ZJKto;k)tCjwxydjI|cUl|-~g=IG;Qo@1IYR{3q|#8cml(!fiL z)hfgeapm*nQ)z%&X9l2{pG=8B<6Cg6>E#y#2T+Cwenq(f*sgL98)|hY4*hJxwj^>b zI|}uB5Z1)6F)B?>%D!Fm)&0(Hs5EFYey)*4e+j-IUs#e};6Iz1ehsS$zN>D?{wSh5 z#n#r9AE93Fuyka_5S4FI#((xaXz;1(Cd%E8h&_F47?;Zt*v^zyJpSq))GS>o|2!h; z2kpqEcWR-}Ow(m`$f@$|{%zx$eWZP9_AE^64JjI%cNHrX-xa$9R7*hPPbQsVsP{%ffz8?RNP+Ydt)1vBfavtW?hj=?K%KuS6DmgL`4#4^F>Oy(y3%i^!rq73xrm zT*5+nDUBPCh=hQk0snpXF60=PWv7%EV?!*D?y~F|DqjfIe5T$nJNN>#G4rq(&CaP% z!pT3QF7-@a3OCz4)YE>reK^I&rhU$&puz5%uW0jEjgQ?Lh5;S*S#e(V*2zG$Fzi&$ zNF$rqpl?p$Cd~5-h=2W4?78~QN7redH+ug5tI^BhESi+d)jtTxx~q|>7?1*njkewn TVP2e-)Eyv`+#PD{{8Rn~(n{wr From 1fe92a9df951d37ec1373beef39dbb1bb8ae28c4 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 28 May 2020 18:22:17 +0300 Subject: [PATCH 33/50] SL-13340 Restored status display for login --- indra/newview/llprogressview.cpp | 6 +-- .../skins/default/xui/en/panel_progress.xml | 52 ++++++------------- 2 files changed, 17 insertions(+), 41 deletions(-) diff --git a/indra/newview/llprogressview.cpp b/indra/newview/llprogressview.cpp index e9b1b5ea73..e9feae3457 100644 --- a/indra/newview/llprogressview.cpp +++ b/indra/newview/llprogressview.cpp @@ -517,8 +517,7 @@ void LLProgressView::initTextures(S32 location_id, bool is_in_production) initLogos(); childSetVisible("panel_icons", mLogosList.empty() ? FALSE : TRUE); - childSetVisible("panel_login", TRUE); - childSetVisible("panel_teleport", FALSE); + childSetVisible("panel_top_spacer", mLogosList.empty() ? TRUE : FALSE); } void LLProgressView::releaseTextures() @@ -526,8 +525,7 @@ void LLProgressView::releaseTextures() gStartTexture = NULL; mLogosList.clear(); - childSetVisible("panel_login", FALSE); - childSetVisible("panel_teleport", TRUE); + childSetVisible("panel_top_spacer", TRUE); childSetVisible("panel_icons", FALSE); } diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml index a0dfff3bd4..cb7e572aff 100644 --- a/indra/newview/skins/default/xui/en/panel_progress.xml +++ b/indra/newview/skins/default/xui/en/panel_progress.xml @@ -44,15 +44,15 @@ width="670" /> + + - Logging in... - - - - - - From 952ec4bcdafd952170b7bbffc6985d61cf4966a7 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 28 May 2020 20:50:11 +0300 Subject: [PATCH 34/50] SL-12607 Bar color to blue --- indra/newview/skins/default/xui/en/panel_progress.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/indra/newview/skins/default/xui/en/panel_progress.xml b/indra/newview/skins/default/xui/en/panel_progress.xml index cb7e572aff..e77d097d5f 100644 --- a/indra/newview/skins/default/xui/en/panel_progress.xml +++ b/indra/newview/skins/default/xui/en/panel_progress.xml @@ -109,7 +109,7 @@ text_color="LoginProgressBoxTextColor" word_wrap="true"/> Date: Wed, 27 May 2020 21:15:15 +0300 Subject: [PATCH 35/50] SL-13329 Misalligned checkboxes in inventory filters --- .../default/xui/en/floater_inventory_view_finder.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml index a8342e723b..d783d1e23c 100644 --- a/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml +++ b/indra/newview/skins/default/xui/en/floater_inventory_view_finder.xml @@ -2,7 +2,7 @@