summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authordolphin <dolphin@lindenlab.com>2013-04-18 15:59:22 -0700
committerdolphin <dolphin@lindenlab.com>2013-04-18 15:59:22 -0700
commiteec08ef64c59fa7569c7418d40135d73338e1d8d (patch)
tree3b62188c704df9ea16484c497d68388ab2908b80 /indra
parent56badfe3498b5eeefb5c06c4b0d51eb1c62ded9c (diff)
parented2b5da8f1eb51e747f6d9f5a4fc535cbf7e69d9 (diff)
Merge with viewer-development
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/CMakeLists.txt4
-rw-r--r--indra/cmake/Copy3rdPartyLibs.cmake45
-rw-r--r--indra/cmake/FMOD.cmake39
-rw-r--r--indra/cmake/FMODEX.cmake46
-rw-r--r--indra/cmake/FindFMOD.cmake44
-rw-r--r--indra/cmake/FindFMODEX.cmake65
-rw-r--r--indra/llaudio/CMakeLists.txt28
-rw-r--r--indra/llaudio/llaudioengine.h1
-rw-r--r--indra/llaudio/llaudioengine_fmod.cpp781
-rw-r--r--indra/llaudio/llaudioengine_fmodex.cpp746
-rw-r--r--indra/llaudio/llaudioengine_fmodex.h (renamed from indra/llaudio/llaudioengine_fmod.h)88
-rw-r--r--indra/llaudio/lllistener_fmodex.cpp (renamed from indra/llaudio/lllistener_fmod.cpp)58
-rw-r--r--indra/llaudio/lllistener_fmodex.h (renamed from indra/llaudio/lllistener_fmod.h)21
-rw-r--r--indra/llaudio/llstreamingaudio.h2
-rw-r--r--indra/llaudio/llstreamingaudio_fmodex.cpp (renamed from indra/llaudio/llstreamingaudio_fmod.cpp)205
-rw-r--r--indra/llaudio/llstreamingaudio_fmodex.h (renamed from indra/llaudio/llstreamingaudio_fmod.h)41
-rw-r--r--indra/llaudio/llvorbisencode.cpp2
-rw-r--r--indra/llaudio/llwindgen.h34
-rw-r--r--indra/llcommon/llversionviewer.h2
-rw-r--r--indra/newview/CMakeLists.txt45
-rwxr-xr-xindra/newview/app_settings/settings.xml56
-rw-r--r--indra/newview/fmod_hidden_symbols.exp240
-rw-r--r--indra/newview/fmodwrapper.cpp37
-rwxr-xr-xindra/newview/linux_tools/wrapper.sh14
-rw-r--r--indra/newview/llappviewer.cpp14
-rw-r--r--indra/newview/llfloateravatarpicker.cpp9
-rw-r--r--indra/newview/llstartup.cpp20
-rw-r--r--indra/newview/llvieweraudio.cpp70
-rw-r--r--indra/newview/llviewercontrol.cpp1
-rw-r--r--indra/newview/llviewerobject.cpp36
-rw-r--r--indra/newview/llviewerobject.h2
-rwxr-xr-xindra/newview/llvoavatar.cpp29
-rw-r--r--indra/newview/viewer_manifest.py25
33 files changed, 1318 insertions, 1532 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index a21fa90950..10a23ea068 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -24,12 +24,11 @@ set(cmake_SOURCE_FILES
DragDrop.cmake
EXPAT.cmake
ExamplePlugin.cmake
- FMOD.cmake
FindAPR.cmake
FindAutobuild.cmake
FindBerkeleyDB.cmake
FindCARes.cmake
- FindFMOD.cmake
+ FindFMODEX.cmake
FindGLH.cmake
FindGoogleBreakpad.cmake
FindGooglePerfTools.cmake
@@ -40,6 +39,7 @@ set(cmake_SOURCE_FILES
FindSCP.cmake
FindXmlRpcEpi.cmake
FindZLIB.cmake
+ FMODEX.cmake
FreeType.cmake
GLEXT.cmake
GLH.cmake
diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake
index 338da4743e..ef529c32d3 100644
--- a/indra/cmake/Copy3rdPartyLibs.cmake
+++ b/indra/cmake/Copy3rdPartyLibs.cmake
@@ -62,10 +62,9 @@ if(WINDOWS)
set(release_files ${release_files} libtcmalloc_minimal.dll)
endif(USE_TCMALLOC)
- if (FMOD)
- set(debug_files ${debug_files} fmod.dll)
- set(release_files ${release_files} fmod.dll)
- endif (FMOD)
+ if (FMODEX)
+ set(release_files ${release_files} fmodex.dll)
+ endif (FMODEX)
#*******************************
# Copy MS C runtime dlls, required for packaging.
@@ -222,8 +221,10 @@ elseif(DARWIN)
libcollada14dom.dylib
)
- # fmod is statically linked on darwin
- set(fmod_files "")
+ 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
@@ -288,9 +289,9 @@ elseif(LINUX)
set(release_files ${release_files} "libtcmalloc_minimal.so")
endif (USE_TCMALLOC)
- if (FMOD)
- set(release_files ${release_files} "libfmod-3.75.so")
- endif (FMOD)
+ if (FMODEX)
+ set(release_file ${release_files} "libfmodex.so")
+ endif (FMODEX)
else(WINDOWS)
message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...")
@@ -305,8 +306,6 @@ else(WINDOWS)
set(release_src_dir "${CMAKE_SOURCE_DIR}/../libraries/i686-linux/lib/release")
set(release_files "")
- set(fmod_files "")
-
set(debug_llkdu_src "")
set(debug_llkdu_dst "")
set(release_llkdu_src "")
@@ -369,30 +368,6 @@ copy_if_different(
)
set(third_party_targets ${third_party_targets} ${out_targets})
-if (FMOD_SDK_DIR)
- copy_if_different(
- ${FMOD_SDK_DIR}
- "${CMAKE_CURRENT_BINARY_DIR}/Debug"
- out_targets
- ${fmod_files}
- )
- set(all_targets ${all_targets} ${out_targets})
- copy_if_different(
- ${FMOD_SDK_DIR}
- "${CMAKE_CURRENT_BINARY_DIR}/Release"
- out_targets
- ${fmod_files}
- )
- set(all_targets ${all_targets} ${out_targets})
- copy_if_different(
- ${FMOD_SDK_DIR}
- "${CMAKE_CURRENT_BINARY_DIR}/RelWithDbgInfo"
- out_targets
- ${fmod_files}
- )
- set(all_targets ${all_targets} ${out_targets})
-endif (FMOD_SDK_DIR)
-
if(NOT STANDALONE)
add_custom_target(
stage_third_party_libs ALL
diff --git a/indra/cmake/FMOD.cmake b/indra/cmake/FMOD.cmake
deleted file mode 100644
index 3586c1160a..0000000000
--- a/indra/cmake/FMOD.cmake
+++ /dev/null
@@ -1,39 +0,0 @@
-# -*- 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 FMOD.
-# Open source devs should use the -DFMOD:BOOL=ON then if they want to build with FMOD, whether
-# they are using STANDALONE or not.
-if (INSTALL_PROPRIETARY)
- set(FMOD ON CACHE BOOL "Use FMOD sound library.")
-endif (INSTALL_PROPRIETARY)
-
-if (FMOD)
- if (STANDALONE)
- # In that case, we use the version of the library installed on the system
- set(FMOD_FIND_REQUIRED ON)
- include(FindFMOD)
- else (STANDALONE)
- if (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
- # If the path have been specified in the arguments, use that
- set(FMOD_LIBRARIES ${FMOD_LIBRARY})
- MESSAGE(STATUS "Using FMOD path: ${FMOD_LIBRARIES}, ${FMOD_INCLUDE_DIR}")
- else (FMOD_LIBRARY AND FMOD_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(fmod)
- if (WINDOWS)
- set(FMOD_LIBRARY fmod)
- elseif (DARWIN)
- set(FMOD_LIBRARY fmod)
- elseif (LINUX)
- set(FMOD_LIBRARY fmod-3.75)
- endif (WINDOWS)
- set(FMOD_LIBRARIES ${FMOD_LIBRARY})
- set(FMOD_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
- endif (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
- endif (STANDALONE)
-endif (FMOD)
diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake
new file mode 100644
index 0000000000..65bc1cabeb
--- /dev/null
+++ b/indra/cmake/FMODEX.cmake
@@ -0,0 +1,46 @@
+# -*- 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
+# they are using STANDALONE or not.
+if (INSTALL_PROPRIETARY)
+ set(FMODEX ON CACHE BOOL "Using FMOD Ex sound library.")
+endif (INSTALL_PROPRIETARY)
+
+if (FMODEX)
+ if (STANDALONE)
+ # In that case, we use the version of the library installed on the system
+ set(FMODEX_FIND_REQUIRED ON)
+ include(FindFMODEX)
+ else (STANDALONE)
+ 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 (STANDALONE)
+endif (FMODEX)
+
diff --git a/indra/cmake/FindFMOD.cmake b/indra/cmake/FindFMOD.cmake
deleted file mode 100644
index 1ebbc8c96e..0000000000
--- a/indra/cmake/FindFMOD.cmake
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- cmake -*-
-
-# - Find FMOD
-# Find the FMOD includes and library
-# This module defines
-# FMOD_INCLUDE_DIR, where to find fmod.h and fmod_errors.h
-# FMOD_LIBRARIES, the libraries needed to use FMOD.
-# FMOD, If false, do not try to use FMOD.
-# also defined, but not for general use are
-# FMOD_LIBRARY, where to find the FMOD library.
-
-FIND_PATH(FMOD_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod)
-
-SET(FMOD_NAMES ${FMOD_NAMES} fmod fmodvc fmodex fmod-3.75)
-FIND_LIBRARY(FMOD_LIBRARY
- NAMES ${FMOD_NAMES}
- PATH_SUFFIXES fmod
- )
-
-IF (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
- SET(FMOD_LIBRARIES ${FMOD_LIBRARY})
- SET(FMOD_FOUND "YES")
-ELSE (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
- SET(FMOD_FOUND "NO")
-ENDIF (FMOD_LIBRARY AND FMOD_INCLUDE_DIR)
-
-IF (FMOD_FOUND)
- IF (NOT FMOD_FIND_QUIETLY)
- MESSAGE(STATUS "Found FMOD: ${FMOD_LIBRARIES}")
- ENDIF (NOT FMOD_FIND_QUIETLY)
-ELSE (FMOD_FOUND)
- IF (FMOD_FIND_REQUIRED)
- MESSAGE(FATAL_ERROR "Could not find FMOD library")
- ENDIF (FMOD_FIND_REQUIRED)
-ENDIF (FMOD_FOUND)
-
-# Deprecated declarations.
-SET (NATIVE_FMOD_INCLUDE_PATH ${FMOD_INCLUDE_DIR} )
-GET_FILENAME_COMPONENT (NATIVE_FMOD_LIB_PATH ${FMOD_LIBRARY} PATH)
-
-MARK_AS_ADVANCED(
- FMOD_LIBRARY
- FMOD_INCLUDE_DIR
- )
diff --git a/indra/cmake/FindFMODEX.cmake b/indra/cmake/FindFMODEX.cmake
new file mode 100644
index 0000000000..b621727c0e
--- /dev/null
+++ b/indra/cmake/FindFMODEX.cmake
@@ -0,0 +1,65 @@
+# -*- 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 24d2531106..1b2bdb9888 100644
--- a/indra/llaudio/CMakeLists.txt
+++ b/indra/llaudio/CMakeLists.txt
@@ -5,7 +5,7 @@ project(llaudio)
include(00-Common)
include(Audio)
include(LLAudio)
-include(FMOD)
+include(FMODEX)
include(OPENAL)
include(LLCommon)
include(LLMath)
@@ -24,7 +24,6 @@ include_directories(
${VORBIS_INCLUDE_DIRS}
${OPENAL_LIB_INCLUDE_DIRS}
${FREEAULT_LIB_INCLUDE_DIRS}
- ${FMOD_INCLUDE_DIR}
)
set(llaudio_SOURCE_FILES
@@ -44,29 +43,22 @@ set(llaudio_HEADER_FILES
llwindgen.h
)
-if (FMOD)
+if (FMODEX)
include_directories(
- ${FMOD_INCLUDE_DIR}
+ ${FMODEX_INCLUDE_DIR}
)
-
list(APPEND llaudio_SOURCE_FILES
- llaudioengine_fmod.cpp
- lllistener_fmod.cpp
- llstreamingaudio_fmod.cpp
+ llaudioengine_fmodex.cpp
+ lllistener_fmodex.cpp
+ llstreamingaudio_fmodex.cpp
)
list(APPEND llaudio_HEADER_FILES
- llaudioengine_fmod.h
- lllistener_fmod.h
- llstreamingaudio_fmod.h
+ llaudioengine_fmodex.h
+ lllistener_fmodex.h
+ llstreamingaudio_fmodex.h
)
-
- if (LINUX OR DARWIN)
- set_source_files_properties(llaudioengine_fmod.cpp
- llstreamingaudio_fmod.cpp
- COMPILE_FLAGS -Wno-write-strings)
- endif (LINUX OR DARWIN)
-endif (FMOD)
+endif (FMODEX)
if (OPENAL)
list(APPEND llaudio_SOURCE_FILES
diff --git a/indra/llaudio/llaudioengine.h b/indra/llaudio/llaudioengine.h
index 99b96c3c38..da1629a1db 100644
--- a/indra/llaudio/llaudioengine.h
+++ b/indra/llaudio/llaudioengine.h
@@ -42,7 +42,6 @@
#include "lllistener.h"
const F32 LL_WIND_UPDATE_INTERVAL = 0.1f;
-const F32 LL_ROLLOFF_MULTIPLIER_UNDER_WATER = 5.f; // How much sounds are weaker under water
const F32 LL_WIND_UNDERWATER_CENTER_FREQ = 20.f;
const F32 ATTACHED_OBJECT_TIMEOUT = 5.0f;
diff --git a/indra/llaudio/llaudioengine_fmod.cpp b/indra/llaudio/llaudioengine_fmod.cpp
deleted file mode 100644
index a40de9fa68..0000000000
--- a/indra/llaudio/llaudioengine_fmod.cpp
+++ /dev/null
@@ -1,781 +0,0 @@
-/**
- * @file audioengine_fmod.cpp
- * @brief Implementation of LLAudioEngine class abstracting the audio support as a FMOD 3D 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 "llstreamingaudio.h"
-#include "llstreamingaudio_fmod.h"
-
-#include "llaudioengine_fmod.h"
-#include "lllistener_fmod.h"
-
-#include "llerror.h"
-#include "llmath.h"
-#include "llrand.h"
-
-#include "fmod.h"
-#include "fmod_errors.h"
-#include "lldir.h"
-#include "llapr.h"
-
-#include "sound_ids.h"
-
-
-extern "C" {
- void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata);
-}
-
-
-LLAudioEngine_FMOD::LLAudioEngine_FMOD()
-{
- mInited = false;
- mWindGen = NULL;
- mWindDSP = NULL;
-}
-
-
-LLAudioEngine_FMOD::~LLAudioEngine_FMOD()
-{
-}
-
-
-bool LLAudioEngine_FMOD::init(const S32 num_channels, void* userdata)
-{
- LLAudioEngine::init(num_channels, userdata);
-
- // Reserve one extra channel for the http stream.
- if (!FSOUND_SetMinHardwareChannels(num_channels + 1))
- {
- LL_WARNS("AppInit") << "FMOD::init[0](), error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
- }
-
- LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() initializing FMOD" << LL_ENDL;
-
- F32 version = FSOUND_GetVersion();
- if (version < FMOD_VERSION)
- {
- LL_WARNS("AppInit") << "Error : You are using the wrong FMOD version (" << version
- << ")! You should be using FMOD " << FMOD_VERSION << LL_ENDL;
- //return false;
- }
-
- U32 fmod_flags = 0x0;
-
-#if LL_WINDOWS
- // Windows needs to know which window is frontmost.
- // This must be called before FSOUND_Init() per the FMOD docs.
- // This could be used to let FMOD handle muting when we lose focus,
- // but we don't actually want to do that because we want to distinguish
- // between minimized and not-focused states.
- if (!FSOUND_SetHWND(userdata))
- {
- LL_WARNS("AppInit") << "Error setting FMOD window: "
- << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
- return false;
- }
- // Play audio when we don't have focus.
- // (For example, IM client on top of us.)
- // This means we also try to play audio when minimized,
- // so we manually handle muting in that case. JC
- fmod_flags |= FSOUND_INIT_GLOBALFOCUS;
-#endif
-
-#if LL_LINUX
- // initialize the FMOD engine
-
- // This is a hack to use only FMOD's basic FPU mixer
- // when the LL_VALGRIND environmental variable is set,
- // otherwise valgrind will fall over on FMOD's MMX detection
- if (getenv("LL_VALGRIND")) /*Flawfinder: ignore*/
- {
- LL_INFOS("AppInit") << "Pacifying valgrind in FMOD init." << LL_ENDL;
- FSOUND_SetMixer(FSOUND_MIXER_QUALITY_FPU);
- }
-
- // If we don't set an output method, Linux FMOD always
- // decides on OSS and fails otherwise. So we'll manually
- // try ESD, then OSS, then ALSA.
- // Why this order? See SL-13250, but in short, OSS emulated
- // on top of ALSA is ironically more reliable than raw ALSA.
- // Ack, and ESD has more reliable failure modes - but has worse
- // latency - than all of them, so wins for now.
- bool audio_ok = false;
-
- if (!audio_ok)
- {
- if (NULL == getenv("LL_BAD_FMOD_ESD")) /*Flawfinder: ignore*/
- {
- LL_DEBUGS("AppInit") << "Trying ESD audio output..." << LL_ENDL;
- if(FSOUND_SetOutput(FSOUND_OUTPUT_ESD) &&
- FSOUND_Init(44100, num_channels, fmod_flags))
- {
- LL_DEBUGS("AppInit") << "ESD audio output initialized OKAY"
- << LL_ENDL;
- audio_ok = true;
- } else {
- LL_WARNS("AppInit") << "ESD audio output FAILED to initialize: "
- << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
- }
- } else {
- LL_DEBUGS("AppInit") << "ESD 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(FSOUND_SetOutput(FSOUND_OUTPUT_OSS) &&
- FSOUND_Init(44100, num_channels, fmod_flags))
- {
- LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL;
- audio_ok = true;
- } else {
- LL_WARNS("AppInit") << "OSS audio output FAILED to initialize: "
- << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
- }
- } else {
- LL_DEBUGS("AppInit") << "OSS 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(FSOUND_SetOutput(FSOUND_OUTPUT_ALSA) &&
- FSOUND_Init(44100, num_channels, fmod_flags))
- {
- LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
- audio_ok = true;
- } else {
- LL_WARNS("AppInit") << "ALSA audio output FAILED to initialize: "
- << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
- }
- } else {
- LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL;
- }
- }
- if (!audio_ok)
- {
- LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
- return false;
- }
-
- // On Linux, FMOD causes a SIGPIPE for some netstream error
- // conditions (an FMOD bug); ignore SIGPIPE so it doesn't crash us.
- // NOW FIXED in FMOD 3.x since 2006-10-01.
- //signal(SIGPIPE, SIG_IGN);
-
- // We're interested in logging which output method we
- // ended up with, for QA purposes.
- switch (FSOUND_GetOutput())
- {
- case FSOUND_OUTPUT_NOSOUND: LL_DEBUGS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
- case FSOUND_OUTPUT_OSS: LL_DEBUGS("AppInit") << "Audio output: OSS" << LL_ENDL; break;
- case FSOUND_OUTPUT_ESD: LL_DEBUGS("AppInit") << "Audio output: ESD" << LL_ENDL; break;
- case FSOUND_OUTPUT_ALSA: LL_DEBUGS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
- default: LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
- };
-
-#else // LL_LINUX
-
- // initialize the FMOD engine
- if (!FSOUND_Init(44100, num_channels, fmod_flags))
- {
- LL_WARNS("AppInit") << "Error initializing FMOD: "
- << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
- 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_FMOD());
-
- LL_DEBUGS("AppInit") << "LLAudioEngine_FMOD::init() FMOD initialized correctly" << LL_ENDL;
-
- mInited = true;
-
- return true;
-}
-
-
-std::string LLAudioEngine_FMOD::getDriverName(bool verbose)
-{
- if (verbose)
- {
- F32 version = FSOUND_GetVersion();
- return llformat("FMOD version %f", version);
- }
- else
- {
- return "FMOD";
- }
-}
-
-
-void LLAudioEngine_FMOD::allocateListener(void)
-{
- mListenerp = (LLListener *) new LLListener_FMOD();
- if (!mListenerp)
- {
- llwarns << "Listener creation failed" << llendl;
- }
-}
-
-
-void LLAudioEngine_FMOD::shutdown()
-{
- if (mWindDSP)
- {
- FSOUND_DSP_SetActive(mWindDSP,false);
- FSOUND_DSP_Free(mWindDSP);
- }
-
- stopInternetStream();
-
- LLAudioEngine::shutdown();
-
- llinfos << "LLAudioEngine_FMOD::shutdown() closing FMOD" << llendl;
- FSOUND_Close();
- llinfos << "LLAudioEngine_FMOD::shutdown() done closing FMOD" << llendl;
-
- delete mListenerp;
- mListenerp = NULL;
-}
-
-
-LLAudioBuffer * LLAudioEngine_FMOD::createBuffer()
-{
- return new LLAudioBufferFMOD();
-}
-
-
-LLAudioChannel * LLAudioEngine_FMOD::createChannel()
-{
- return new LLAudioChannelFMOD();
-}
-
-
-bool LLAudioEngine_FMOD::initWind()
-{
- if (!mWindGen)
- {
- bool enable;
-
- switch (FSOUND_GetMixer())
- {
- case FSOUND_MIXER_MMXP5:
- case FSOUND_MIXER_MMXP6:
- case FSOUND_MIXER_QUALITY_MMXP5:
- case FSOUND_MIXER_QUALITY_MMXP6:
- enable = (typeid(MIXBUFFERFORMAT) == typeid(S16));
- break;
- case FSOUND_MIXER_BLENDMODE:
- enable = (typeid(MIXBUFFERFORMAT) == typeid(S32));
- break;
- case FSOUND_MIXER_QUALITY_FPU:
- enable = (typeid(MIXBUFFERFORMAT) == typeid(F32));
- break;
- default:
- // FSOUND_GetMixer() does not return a valid mixer type on Darwin
- LL_INFOS("AppInit") << "Unknown FMOD mixer type, assuming default" << LL_ENDL;
- enable = true;
- break;
- }
-
- if (enable)
- {
- mWindGen = new LLWindGen<MIXBUFFERFORMAT>(FSOUND_GetOutputRate());
- }
- else
- {
- LL_WARNS("AppInit") << "Incompatible FMOD mixer type, wind noise disabled" << LL_ENDL;
- }
- }
-
- mNextWindUpdate = 0.0;
-
- if (mWindGen && !mWindDSP)
- {
- mWindDSP = FSOUND_DSP_Create(&windCallback, FSOUND_DSP_DEFAULTPRIORITY_CLEARUNIT + 20, mWindGen);
- }
- if (mWindDSP)
- {
- FSOUND_DSP_SetActive(mWindDSP, true);
- return true;
- }
-
- return false;
-}
-
-
-void LLAudioEngine_FMOD::cleanupWind()
-{
- if (mWindDSP)
- {
- FSOUND_DSP_SetActive(mWindDSP, false);
- FSOUND_DSP_Free(mWindDSP);
- mWindDSP = NULL;
- }
-
- delete mWindGen;
- mWindGen = NULL;
-}
-
-
-//-----------------------------------------------------------------------
-void LLAudioEngine_FMOD::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_FMOD::setSourceMinDistance(U16 source_num, F64 distance)
-{
- if (!mInited)
- {
- return;
- }
- if (mBuffer[source_num])
- {
- mMinDistance[source_num] = (F32) distance;
- if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num]))
- {
- llwarns << "FMOD::setSourceMinDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
- }
- }
-}
-
-//-----------------------------------------------------------------------
-void LLAudioEngine_FMOD::setSourceMaxDistance(U16 source_num, F64 distance)
-{
- if (!mInited)
- {
- return;
- }
- if (mBuffer[source_num])
- {
- mMaxDistance[source_num] = (F32) distance;
- if (!FSOUND_Sample_SetMinMaxDistance(mBuffer[source_num],mMinDistance[source_num], mMaxDistance[source_num]))
- {
- llwarns << "FMOD::setSourceMaxDistance(" << source_num << "), error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
- }
- }
-}
-
-//-----------------------------------------------------------------------
-void LLAudioEngine_FMOD::get3DParams(S32 source_num, S32 *volume, S32 *freq, S32 *inside, S32 *outside, LLVector3 *orient, S32 *out_volume, F32 *min_dist, F32 *max_dist)
-{
- *volume = 0;
- *freq = 0;
- *inside = 0;
- *outside = 0;
- *orient = LLVector3::zero;
- *out_volume = 0;
- *min_dist = 0.f;
- *max_dist = 0.f;
-}
-
-*/
-
-
-//-----------------------------------------------------------------------
-void LLAudioEngine_FMOD::setInternalGain(F32 gain)
-{
- if (!mInited)
- {
- return;
- }
-
- gain = llclamp( gain, 0.0f, 1.0f );
- FSOUND_SetSFXMasterVolume( llround( 255.0f * gain ) );
-
- LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
- if ( saimpl )
- {
- // fmod likes its streaming audio channel gain re-asserted after
- // master volume change.
- saimpl->setGain(saimpl->getGain());
- }
-}
-
-//
-// LLAudioChannelFMOD implementation
-//
-
-LLAudioChannelFMOD::LLAudioChannelFMOD() : LLAudioChannel(), mChannelID(0), mLastSamplePos(0)
-{
-}
-
-
-LLAudioChannelFMOD::~LLAudioChannelFMOD()
-{
- cleanup();
-}
-
-
-bool LLAudioChannelFMOD::updateBuffer()
-{
- if (LLAudioChannel::updateBuffer())
- {
- // Base class update returned true, which means that we need to actually
- // set up the channel for a different buffer.
-
- LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)mCurrentSourcep->getCurrentBuffer();
-
- // Grab the FMOD sample associated with the buffer
- FSOUND_SAMPLE *samplep = bufferp->getSample();
- if (!samplep)
- {
- // This is bad, there should ALWAYS be a sample associated with a legit
- // buffer.
- llerrs << "No FMOD sample!" << llendl;
- return false;
- }
-
-
- // Actually play the sound. Start it off paused so we can do all the necessary
- // setup.
- mChannelID = FSOUND_PlaySoundEx(FSOUND_FREE, samplep, FSOUND_DSP_GetSFXUnit(), true);
-
- //llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
- }
-
- // If we have a source for the channel, we need to update its gain.
- if (mCurrentSourcep)
- {
- // SJB: warnings can spam and hurt framerate, disabling
- if (!FSOUND_SetVolume(mChannelID, llround(getSecondaryGain() * mCurrentSourcep->getGain() * 255.0f)))
- {
-// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
- }
-
- if (!FSOUND_SetLoopMode(mChannelID, mCurrentSourcep->isLoop() ? FSOUND_LOOP_NORMAL : FSOUND_LOOP_OFF))
- {
-// llwarns << "Channel " << mChannelID << "Source ID: " << mCurrentSourcep->getID()
-// << " at " << mCurrentSourcep->getPositionGlobal() << llendl;
-// llwarns << "LLAudioChannelFMOD::updateBuffer error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
- }
- }
-
- return true;
-}
-
-
-void LLAudioChannelFMOD::update3DPosition()
-{
- if (!mChannelID)
- {
- // We're not actually a live channel (i.e., we're not playing back anything)
- return;
- }
-
- LLAudioBufferFMOD *bufferp = (LLAudioBufferFMOD *)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.
- bufferp->set3DMode(false);
- }
- else
- {
- // Localized sound. Update the position and velocity of the sound.
- bufferp->set3DMode(true);
-
- LLVector3 float_pos;
- float_pos.setVec(mCurrentSourcep->getPositionGlobal());
- if (!FSOUND_3D_SetAttributes(mChannelID, float_pos.mV, mCurrentSourcep->getVelocity().mV))
- {
- LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::update3DPosition error: " << FMOD_ErrorString(FSOUND_GetError()) << LL_ENDL;
- }
- }
-}
-
-
-void LLAudioChannelFMOD::updateLoop()
-{
- if (!mChannelID)
- {
- // 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 = FSOUND_GetCurrentPosition(mChannelID);
- if (cur_pos < (U32)mLastSamplePos)
- {
- mLoopedThisFrame = true;
- }
- mLastSamplePos = cur_pos;
-}
-
-
-void LLAudioChannelFMOD::cleanup()
-{
- if (!mChannelID)
- {
- //llinfos << "Aborting cleanup with no channelID." << llendl;
- return;
- }
-
- //llinfos << "Cleaning up channel: " << mChannelID << llendl;
- if (!FSOUND_StopSound(mChannelID))
- {
- LL_DEBUGS("FMOD") << "LLAudioChannelFMOD::cleanup error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
- }
-
- mCurrentBufferp = NULL;
- mChannelID = 0;
-}
-
-
-void LLAudioChannelFMOD::play()
-{
- if (!mChannelID)
- {
- llwarns << "Playing without a channelID, aborting" << llendl;
- return;
- }
-
- if (!FSOUND_SetPaused(mChannelID, false))
- {
- llwarns << "LLAudioChannelFMOD::play error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
- }
- getSource()->setPlayedOnce(true);
-}
-
-
-void LLAudioChannelFMOD::playSynced(LLAudioChannel *channelp)
-{
- LLAudioChannelFMOD *fmod_channelp = (LLAudioChannelFMOD*)channelp;
- if (!(fmod_channelp->mChannelID && mChannelID))
- {
- // Don't have channels allocated to both the master and the slave
- return;
- }
-
- U32 position = FSOUND_GetCurrentPosition(fmod_channelp->mChannelID) % mCurrentBufferp->getLength();
- // Try to match the position of our sync master
- if (!FSOUND_SetCurrentPosition(mChannelID, position))
- {
- llwarns << "LLAudioChannelFMOD::playSynced unable to set current position" << llendl;
- }
-
- // Start us playing
- play();
-}
-
-
-bool LLAudioChannelFMOD::isPlaying()
-{
- if (!mChannelID)
- {
- return false;
- }
-
- return FSOUND_IsPlaying(mChannelID) && (!FSOUND_GetPaused(mChannelID));
-}
-
-
-
-//
-// LLAudioBufferFMOD implementation
-//
-
-
-LLAudioBufferFMOD::LLAudioBufferFMOD()
-{
- mSamplep = NULL;
-}
-
-
-LLAudioBufferFMOD::~LLAudioBufferFMOD()
-{
- if (mSamplep)
- {
- // Clean up the associated FMOD sample if it exists.
- FSOUND_Sample_Free(mSamplep);
- mSamplep = NULL;
- }
-}
-
-
-bool LLAudioBufferFMOD::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 (mSamplep)
- {
- // If there's already something loaded in this buffer, clean it up.
- FSOUND_Sample_Free(mSamplep);
- mSamplep = NULL;
- }
-
- // Load up the wav file into an fmod sample
-#if LL_WINDOWS
- // MikeS. - Loading the sound file manually and then handing it over to FMOD,
- // since FMOD uses posix IO internally,
- // which doesn't work with unicode file paths.
- LLFILE* sound_file = LLFile::fopen(filename,"rb"); /* Flawfinder: ignore */
- if (sound_file)
- {
- fseek(sound_file,0,SEEK_END);
- U32 file_length = ftell(sound_file); //Find the length of the file by seeking to the end and getting the offset
- size_t read_count;
- fseek(sound_file,0,SEEK_SET); //Seek back to the beginning
- char* buffer = new char[file_length];
- llassert(buffer);
- read_count = fread((void*)buffer,file_length,1,sound_file);//Load it..
- if(ferror(sound_file)==0 && (read_count == 1)){//No read error, and we got 1 chunk of our size...
- unsigned int mode_flags = FSOUND_LOOP_NORMAL | FSOUND_LOADMEMORY;
- //FSOUND_16BITS | FSOUND_MONO | FSOUND_LOADMEMORY | FSOUND_LOOP_NORMAL;
- mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, buffer, mode_flags , 0, file_length);
- }
- delete[] buffer;
- fclose(sound_file);
- }
-#else
- mSamplep = FSOUND_Sample_Load(FSOUND_UNMANAGED, filename.c_str(), FSOUND_LOOP_NORMAL, 0, 0);
-#endif
-
- if (!mSamplep)
- {
- // We failed to load the file for some reason.
- llwarns << "Could not load data '" << filename << "': "
- << FMOD_ErrorString(FSOUND_GetError()) << llendl;
-
- //
- // 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 LLAudioBufferFMOD::getLength()
-{
- if (!mSamplep)
- {
- return 0;
- }
-
- return FSOUND_Sample_GetLength(mSamplep);
-}
-
-
-void LLAudioBufferFMOD::set3DMode(bool use3d)
-{
- U16 current_mode = FSOUND_Sample_GetMode(mSamplep);
-
- if (use3d)
- {
- if (!FSOUND_Sample_SetMode(mSamplep, (current_mode & (~FSOUND_2D))))
- {
- llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
- }
- }
- else
- {
- if (!FSOUND_Sample_SetMode(mSamplep, current_mode | FSOUND_2D))
- {
- llwarns << "LLAudioBufferFMOD::set3DMode error: " << FMOD_ErrorString(FSOUND_GetError()) << llendl;
- }
- }
-}
-
-
-void * F_CALLBACKAPI windCallback(void *originalbuffer, void *newbuffer, int length, void* userdata)
-{
- // 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<LLAudioEngine_FMOD::MIXBUFFERFORMAT> *windgen =
- (LLWindGen<LLAudioEngine_FMOD::MIXBUFFERFORMAT> *)userdata;
-
- newbuffer = windgen->windGenerate((LLAudioEngine_FMOD::MIXBUFFERFORMAT *)newbuffer, length);
-
- return newbuffer;
-}
diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp
new file mode 100644
index 0000000000..5ec30c7d1d
--- /dev/null
+++ b/indra/llaudio/llaudioengine_fmodex.cpp
@@ -0,0 +1,746 @@
+/**
+ * @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) 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 "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;
+}
+
+
+LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX()
+{
+}
+
+
+inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
+{
+ if(result == FMOD_OK)
+ return false;
+ llwarns << string << " Error: " << FMOD_ErrorString(result) << llendl;
+ return true;
+}
+
+void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr)
+{
+ if(type & FMOD_MEMORY_STREAM_DECODE)
+ {
+ llinfos << "Decode buffer size: " << size << llendl;
+ }
+ else if(type & FMOD_MEMORY_STREAM_FILE)
+ {
+ llinfos << "Strean buffer size: " << size << llendl;
+ }
+ 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;
+
+ 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;
+ char r_name[256];
+ mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers);
+ mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits);
+ mSystem->getDriverInfo(0, r_name, 255, 0);
+ r_name[255] = '\0';
+ int latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate);
+
+ LL_INFOS("AppInit") << "FMOD device: "<< r_name << "\n"
+ << "FMOD Ex parameters: " << r_samplerate << " Hz * " << r_channels << " * " <<r_bits <<" bit\n"
+ << "\tbuffer " << r_bufferlength << " * " << r_numbuffers << " (" << latency <<"ms)" << LL_ENDL;
+
+ mInited = true;
+
+ 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)
+ {
+ llwarns << "Listener creation failed" << llendl;
+ }
+}
+
+
+void LLAudioEngine_FMODEX::shutdown()
+{
+ stopInternetStream();
+
+ llinfos << "About to LLAudioEngine::shutdown()" << llendl;
+ LLAudioEngine::shutdown();
+
+ llinfos << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << llendl;
+ mSystem->close();
+ mSystem->release();
+ llinfos << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << llendl;
+
+ 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)
+ {
+ FMOD_DSP_DESCRIPTION dspdesc;
+ memset(&dspdesc, 0, sizeof(FMOD_DSP_DESCRIPTION)); //Set everything to zero
+ strncpy(dspdesc.name,"Wind Unit", sizeof(dspdesc.name)); //Set name to "Wind Unit"
+ dspdesc.channels=2;
+ dspdesc.read = &windCallback; //Assign callback.
+ if(Check_FMOD_Error(mSystem->createDSP(&dspdesc, &mWindDSP), "FMOD::createDSP"))
+ return false;
+
+ if(mWindGen)
+ delete mWindGen;
+
+ float frequency = 44100;
+ mWindDSP->getDefaults(&frequency,0,0,0);
+ mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency);
+ mWindDSP->setUserData((void*)mWindGen);
+ }
+
+ 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.
+ llerrs << "No FMOD sound!" << llendl;
+ 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");
+ }
+
+ //llinfos << "Setting up channel " << std::hex << mChannelID << std::dec << llendl;
+ }
+
+ // 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);
+ llwarns << "Channel " << index << "Source ID: " << mCurrentSourcep->getID()
+ << " at " << mCurrentSourcep->getPositionGlobal() << llendl;
+ }*/
+ }
+
+ 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)
+ {
+ //llinfos << "Aborting cleanup with no channel handle." << llendl;
+ return;
+ }
+
+ //llinfos << "Cleaning up channel: " << mChannelID << llendl;
+ Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop");
+
+ mCurrentBufferp = NULL;
+ mChannelp = NULL;
+}
+
+
+void LLAudioChannelFMODEX::play()
+{
+ if (!mChannelp)
+ {
+ llwarns << "Playing without a channel handle, aborting" << llendl;
+ 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.
+ llwarns << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << llendl;
+
+ //
+ // 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(&current_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);
+ }
+}
+
+
+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<LLAudioEngine_FMODEX::MIXBUFFERFORMAT> *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_fmod.h b/indra/llaudio/llaudioengine_fmodex.h
index 4582a5d57e..415a9ed0ef 100644
--- a/indra/llaudio/llaudioengine_fmod.h
+++ b/indra/llaudio/llaudioengine_fmodex.h
@@ -1,7 +1,7 @@
/**
- * @file audioengine_fmod.h
- * @brief Definition of LLAudioEngine class abstracting the audio
- * support as a FMOD 3D implementation
+ * @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
@@ -25,26 +25,33 @@
* $/LicenseInfo$
*/
-#ifndef LL_AUDIOENGINE_FMOD_H
-#define LL_AUDIOENGINE_FMOD_H
+#ifndef LL_AUDIOENGINE_FMODEX_H
+#define LL_AUDIOENGINE_FMODEX_H
#include "llaudioengine.h"
-#include "lllistener_fmod.h"
#include "llwindgen.h"
-#include "fmod.h"
-
-class LLAudioStreamManagerFMOD;
-
-class LLAudioEngine_FMOD : public LLAudioEngine
+//Stubs
+class LLAudioStreamManagerFMODEX;
+namespace FMOD
+{
+ class System;
+ class Channel;
+ class ChannelGroup;
+ class Sound;
+ class DSP;
+}
+
+//Interfaces
+class LLAudioEngine_FMODEX : public LLAudioEngine
{
public:
- LLAudioEngine_FMOD();
- virtual ~LLAudioEngine_FMOD();
+ 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 std::string getDriverName(bool verbose);
virtual void allocateListener();
virtual void shutdown();
@@ -54,38 +61,33 @@ public:
/*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water);
-#if LL_DARWIN
- typedef S32 MIXBUFFERFORMAT;
-#else
- typedef S16 MIXBUFFERFORMAT;
-#endif
+ 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);
-protected:
- static signed char F_CALLBACKAPI callbackMetaData(char* name, char* value, void* userdata);
-
- //F32 mMinDistance[MAX_BUFFERS];
- //F32 mMaxDistance[MAX_BUFFERS];
bool mInited;
- // On Windows, userdata is the HWND of the application window.
- void* mUserData;
-
LLWindGen<MIXBUFFERFORMAT> *mWindGen;
- FSOUND_DSPUNIT *mWindDSP;
+
+ FMOD::DSP *mWindDSP;
+ FMOD::System *mSystem;
+ bool mEnableProfiler;
+
+public:
+ static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT];
};
-class LLAudioChannelFMOD : public LLAudioChannel
+class LLAudioChannelFMODEX : public LLAudioChannel
{
public:
- LLAudioChannelFMOD();
- virtual ~LLAudioChannelFMOD();
+ LLAudioChannelFMODEX(FMOD::System *audioengine);
+ virtual ~LLAudioChannelFMODEX();
protected:
/*virtual*/ void play();
@@ -97,28 +99,30 @@ protected:
/*virtual*/ void update3DPosition();
/*virtual*/ void updateLoop();
+ void set3DMode(bool use3d);
protected:
- int mChannelID;
+ FMOD::System *getSystem() const {return mSystemp;}
+ FMOD::System *mSystemp;
+ FMOD::Channel *mChannelp;
S32 mLastSamplePos;
};
-class LLAudioBufferFMOD : public LLAudioBuffer
+class LLAudioBufferFMODEX : public LLAudioBuffer
{
public:
- LLAudioBufferFMOD();
- virtual ~LLAudioBufferFMOD();
+ LLAudioBufferFMODEX(FMOD::System *audioengine);
+ virtual ~LLAudioBufferFMODEX();
/*virtual*/ bool loadWAV(const std::string& filename);
/*virtual*/ U32 getLength();
- friend class LLAudioChannelFMOD;
-
- void set3DMode(bool use3d);
-protected:
- FSOUND_SAMPLE *getSample() { return mSamplep; }
+ friend class LLAudioChannelFMODEX;
protected:
- FSOUND_SAMPLE *mSamplep;
+ FMOD::System *getSystem() const {return mSystemp;}
+ FMOD::System *mSystemp;
+ FMOD::Sound *getSound() const{ return mSoundp; }
+ FMOD::Sound *mSoundp;
};
-#endif // LL_AUDIOENGINE_FMOD_H
+#endif // LL_AUDIOENGINE_FMODEX_H
diff --git a/indra/llaudio/lllistener_fmod.cpp b/indra/llaudio/lllistener_fmodex.cpp
index 0138f4345e..2509a7aebc 100644
--- a/indra/llaudio/lllistener_fmod.cpp
+++ b/indra/llaudio/lllistener_fmodex.cpp
@@ -1,7 +1,7 @@
/**
- * @file listener_fmod.cpp
- * @brief implementation of LISTENER class abstracting the audio
- * support as a FMOD 3D implementation (windows only)
+ * @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
@@ -27,24 +27,25 @@
#include "linden_common.h"
#include "llaudioengine.h"
-#include "lllistener_fmod.h"
-#include "fmod.h"
+#include "lllistener_fmodex.h"
+#include "fmod.hpp"
//-----------------------------------------------------------------------
// constructor
//-----------------------------------------------------------------------
-LLListener_FMOD::LLListener_FMOD()
+LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system)
{
+ mSystem = system;
init();
}
//-----------------------------------------------------------------------
-LLListener_FMOD::~LLListener_FMOD()
+LLListener_FMODEX::~LLListener_FMODEX()
{
}
//-----------------------------------------------------------------------
-void LLListener_FMOD::init(void)
+void LLListener_FMODEX::init(void)
{
// do inherited
LLListener::init();
@@ -53,31 +54,31 @@ void LLListener_FMOD::init(void)
}
//-----------------------------------------------------------------------
-void LLListener_FMOD::translate(LLVector3 offset)
+void LLListener_FMODEX::translate(LLVector3 offset)
{
LLListener::translate(offset);
- FSOUND_3D_Listener_SetAttributes(mPosition.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]);
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
}
//-----------------------------------------------------------------------
-void LLListener_FMOD::setPosition(LLVector3 pos)
+void LLListener_FMODEX::setPosition(LLVector3 pos)
{
LLListener::setPosition(pos);
- FSOUND_3D_Listener_SetAttributes(pos.mV, NULL, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]);
+ mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
}
//-----------------------------------------------------------------------
-void LLListener_FMOD::setVelocity(LLVector3 vel)
+void LLListener_FMODEX::setVelocity(LLVector3 vel)
{
LLListener::setVelocity(vel);
- FSOUND_3D_Listener_SetAttributes(NULL, vel.mV, mListenAt.mV[0],mListenAt.mV[1],mListenAt.mV[2], mListenUp.mV[0],mListenUp.mV[1],mListenUp.mV[2]);
+ mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
}
//-----------------------------------------------------------------------
-void LLListener_FMOD::orient(LLVector3 up, LLVector3 at)
+void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at)
{
LLListener::orient(up, at);
@@ -87,37 +88,46 @@ void LLListener_FMOD::orient(LLVector3 up, LLVector3 at)
// since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed
at = -at;
- FSOUND_3D_Listener_SetAttributes(NULL, NULL, at.mV[0],at.mV[1],at.mV[2], up.mV[0],up.mV[1],up.mV[2]);
+ mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
}
//-----------------------------------------------------------------------
-void LLListener_FMOD::commitDeferredChanges()
+void LLListener_FMODEX::commitDeferredChanges()
{
- FSOUND_Update();
+ mSystem->update();
}
-void LLListener_FMOD::setRolloffFactor(F32 factor)
+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;
- FSOUND_3D_SetRolloffFactor(factor);
+ mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
}
-F32 LLListener_FMOD::getRolloffFactor()
+F32 LLListener_FMODEX::getRolloffFactor()
{
return mRolloffFactor;
}
-void LLListener_FMOD::setDopplerFactor(F32 factor)
+void LLListener_FMODEX::setDopplerFactor(F32 factor)
{
mDopplerFactor = factor;
- FSOUND_3D_SetDopplerFactor(factor);
+ mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
}
-F32 LLListener_FMOD::getDopplerFactor()
+F32 LLListener_FMODEX::getDopplerFactor()
{
return mDopplerFactor;
}
diff --git a/indra/llaudio/lllistener_fmod.h b/indra/llaudio/lllistener_fmodex.h
index 818da05d51..073b65d53a 100644
--- a/indra/llaudio/lllistener_fmod.h
+++ b/indra/llaudio/lllistener_fmodex.h
@@ -1,5 +1,5 @@
/**
- * @file listener_fmod.h
+ * @file listener_fmodex.h
* @brief Description of LISTENER class abstracting the audio support
* as an FMOD 3D implementation (windows and Linux)
*
@@ -25,16 +25,23 @@
* $/LicenseInfo$
*/
-#ifndef LL_LISTENER_FMOD_H
-#define LL_LISTENER_FMOD_H
+#ifndef LL_LISTENER_FMODEX_H
+#define LL_LISTENER_FMODEX_H
#include "lllistener.h"
-class LLListener_FMOD : public LLListener
+//Stubs
+namespace FMOD
+{
+ class System;
+}
+
+//Interfaces
+class LLListener_FMODEX : public LLListener
{
public:
- LLListener_FMOD();
- virtual ~LLListener_FMOD();
+ LLListener_FMODEX(FMOD::System *system);
+ virtual ~LLListener_FMODEX();
virtual void init();
virtual void translate(LLVector3 offset);
@@ -47,8 +54,8 @@ class LLListener_FMOD : public LLListener
virtual F32 getDopplerFactor();
virtual void setRolloffFactor(F32 factor);
virtual F32 getRolloffFactor();
-
protected:
+ FMOD::System *mSystem;
F32 mDopplerFactor;
F32 mRolloffFactor;
};
diff --git a/indra/llaudio/llstreamingaudio.h b/indra/llaudio/llstreamingaudio.h
index 20104af744..93479f9d59 100644
--- a/indra/llaudio/llstreamingaudio.h
+++ b/indra/llaudio/llstreamingaudio.h
@@ -45,6 +45,8 @@ class LLStreamingAudioInterface
virtual void setGain(F32 vol) = 0;
virtual F32 getGain() = 0;
virtual std::string getURL() = 0;
+ virtual bool supportsAdjustableBufferSizes(){return false;}
+ virtual void setBufferSizes(U32 streambuffertime, U32 decodebuffertime){};
};
#endif // LL_STREAMINGAUDIO_H
diff --git a/indra/llaudio/llstreamingaudio_fmod.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp
index bcdea771a7..4a74267650 100644
--- a/indra/llaudio/llstreamingaudio_fmod.cpp
+++ b/indra/llaudio/llstreamingaudio_fmodex.cpp
@@ -1,8 +1,8 @@
/**
- * @file streamingaudio_fmod.cpp
- * @brief LLStreamingAudio_FMOD implementation
+ * @file streamingaudio_fmodex.cpp
+ * @brief LLStreamingAudio_FMODEX implementation
*
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
@@ -28,25 +28,27 @@
#include "llmath.h"
-#include "fmod.h"
+#include "fmod.hpp"
#include "fmod_errors.h"
-#include "llstreamingaudio_fmod.h"
+#include "llstreamingaudio_fmodex.h"
-class LLAudioStreamManagerFMOD
+class LLAudioStreamManagerFMODEX
{
public:
- LLAudioStreamManagerFMOD(const std::string& url);
- int startStream();
+ 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; }
- int getOpenState();
+ FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL);
protected:
- FSOUND_STREAM* mInternetStream;
+ FMOD::System* mSystem;
+ FMOD::Channel* mStreamChannel;
+ FMOD::Sound* mInternetStream;
bool mReady;
std::string mInternetStreamURL;
@@ -57,14 +59,17 @@ protected:
//---------------------------------------------------------------------------
// Internet Streaming
//---------------------------------------------------------------------------
-LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
+LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) :
+ mSystem(system),
mCurrentInternetStreamp(NULL),
- mFMODInternetStreamChannel(-1),
+ 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.
- FSOUND_Stream_SetBufferSize(200);
+ 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
@@ -76,13 +81,13 @@ LLStreamingAudio_FMOD::LLStreamingAudio_FMOD() :
}
-LLStreamingAudio_FMOD::~LLStreamingAudio_FMOD()
+LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX()
{
// nothing interesting/safe to do.
}
-void LLStreamingAudio_FMOD::start(const std::string& url)
+void LLStreamingAudio_FMODEX::start(const std::string& url)
{
//if (!mInited)
//{
@@ -96,7 +101,7 @@ void LLStreamingAudio_FMOD::start(const std::string& url)
if (!url.empty())
{
llinfos << "Starting internet stream: " << url << llendl;
- mCurrentInternetStreamp = new LLAudioStreamManagerFMOD(url);
+ mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url);
mURL = url;
}
else
@@ -107,13 +112,13 @@ void LLStreamingAudio_FMOD::start(const std::string& url)
}
-void LLStreamingAudio_FMOD::update()
+void LLStreamingAudio_FMODEX::update()
{
// Kill dead internet streams, if possible
- std::list<LLAudioStreamManagerFMOD *>::iterator iter;
+ std::list<LLAudioStreamManagerFMODEX *>::iterator iter;
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
{
- LLAudioStreamManagerFMOD *streamp = *iter;
+ LLAudioStreamManagerFMODEX *streamp = *iter;
if (streamp->stopStream())
{
llinfos << "Closed dead stream" << llendl;
@@ -132,62 +137,66 @@ void LLStreamingAudio_FMOD::update()
return;
}
- int open_state = mCurrentInternetStreamp->getOpenState();
+ unsigned int progress;
+ bool starving;
+ bool diskbusy;
+ FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy);
- if (!open_state)
+ if (open_state == FMOD_OPENSTATE_READY)
{
// Stream is live
// start the stream if it's ready
- if (mFMODInternetStreamChannel < 0)
+ if (!mFMODInternetStreamChannelp &&
+ (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream()))
{
- mFMODInternetStreamChannel = mCurrentInternetStreamp->startStream();
-
- if (mFMODInternetStreamChannel != -1)
- {
- // Reset volume to previously set volume
- setGain(getGain());
- FSOUND_SetPaused(mFMODInternetStreamChannel, false);
- }
+ // Reset volume to previously set volume
+ setGain(getGain());
+ mFMODInternetStreamChannelp->setPaused(false);
+ mLastStarved.stop();
}
}
-
- switch(open_state)
+ else if(open_state == FMOD_OPENSTATE_ERROR)
{
- default:
- case 0:
- // success
- break;
- case -1:
- // stream handle is invalid
- llwarns << "InternetStream - invalid handle" << llendl;
stop();
return;
- case -2:
- // opening
- break;
- case -3:
- // failed to open, file not found, perhaps
- llwarns << "InternetStream - failed to open" << llendl;
- stop();
- return;
- case -4:
- // connecting
- break;
- case -5:
- // buffering
- break;
}
+ if(mFMODInternetStreamChannelp)
+ {
+ FMOD::Sound *sound = NULL;
+
+ if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
+ {
+ if(starving)
+ {
+ if(!mLastStarved.getStarted())
+ {
+ llinfos << "Stream starvation detected! Muting stream audio until it clears." << llendl;
+ llinfos << " (diskbusy="<<diskbusy<<")" << llendl;
+ llinfos << " (progress="<<progress<<")" << llendl;
+ mFMODInternetStreamChannelp->setMute(true);
+ }
+ mLastStarved.start();
+ }
+ else if(mLastStarved.getStarted() && mLastStarved.getElapsedTimeF32() > 1.f)
+ {
+ mLastStarved.stop();
+ mFMODInternetStreamChannelp->setMute(false);
+ }
+ }
+ }
}
-void LLStreamingAudio_FMOD::stop()
+void LLStreamingAudio_FMODEX::stop()
{
- if (mFMODInternetStreamChannel != -1)
+ mLastStarved.stop();
+
+ if (mFMODInternetStreamChannelp)
{
- FSOUND_SetPaused(mFMODInternetStreamChannel, true);
- FSOUND_SetPriority(mFMODInternetStreamChannel, 0);
- mFMODInternetStreamChannel = -1;
+ mFMODInternetStreamChannelp->setPaused(true);
+ mFMODInternetStreamChannelp->setPriority(0);
+ mFMODInternetStreamChannelp = NULL;
}
if (mCurrentInternetStreamp)
@@ -207,7 +216,7 @@ void LLStreamingAudio_FMOD::stop()
}
}
-void LLStreamingAudio_FMOD::pause(int pauseopt)
+void LLStreamingAudio_FMODEX::pause(int pauseopt)
{
if (pauseopt < 0)
{
@@ -230,7 +239,7 @@ void LLStreamingAudio_FMOD::pause(int pauseopt)
// 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_FMOD::isPlaying()
+int LLStreamingAudio_FMODEX::isPlaying()
{
if (mCurrentInternetStreamp)
{
@@ -247,44 +256,47 @@ int LLStreamingAudio_FMOD::isPlaying()
}
-F32 LLStreamingAudio_FMOD::getGain()
+F32 LLStreamingAudio_FMODEX::getGain()
{
return mGain;
}
-std::string LLStreamingAudio_FMOD::getURL()
+std::string LLStreamingAudio_FMODEX::getURL()
{
return mURL;
}
-void LLStreamingAudio_FMOD::setGain(F32 vol)
+void LLStreamingAudio_FMODEX::setGain(F32 vol)
{
mGain = vol;
- if (mFMODInternetStreamChannel != -1)
+ if (mFMODInternetStreamChannelp)
{
- vol = llclamp(vol * vol, 0.f, 1.f);
- int vol_int = llround(vol * 255.f);
- FSOUND_SetVolumeAbsolute(mFMODInternetStreamChannel, vol_int);
+ vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here?
+
+ mFMODInternetStreamChannelp->setVolume(vol);
}
}
-
///////////////////////////////////////////////////////
// manager of possibly-multiple internet audio streams
-LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) :
+LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) :
+ mSystem(system),
+ mStreamChannel(NULL),
mInternetStream(NULL),
mReady(false)
{
mInternetStreamURL = url;
- mInternetStream = FSOUND_Stream_Open(url.c_str(), FSOUND_NORMAL | FSOUND_NONBLOCKING, 0, 0);
- if (!mInternetStream)
+
+ FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_MPEGSEARCH | FMOD_IGNORETAGS, 0, &mInternetStream);
+
+ if (result!= FMOD_OK)
{
llwarns << "Couldn't open fmod stream, error "
- << FMOD_ErrorString(FSOUND_GetError())
+ << FMOD_ErrorString(result)
<< llendl;
mReady = false;
return;
@@ -293,48 +305,42 @@ LLAudioStreamManagerFMOD::LLAudioStreamManagerFMOD(const std::string& url) :
mReady = true;
}
-int LLAudioStreamManagerFMOD::startStream()
+FMOD::Channel *LLAudioStreamManagerFMODEX::startStream()
{
// We need a live and opened stream before we try and play it.
- if (!mInternetStream || getOpenState())
+ if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY)
{
llwarns << "No internet stream to start playing!" << llendl;
- return -1;
+ return NULL;
}
- // Make sure the stream is set to 2D mode.
- FSOUND_Stream_SetMode(mInternetStream, FSOUND_2D);
+ if(mStreamChannel)
+ return mStreamChannel; //Already have a channel for this stream.
- return FSOUND_Stream_PlayEx(FSOUND_FREE, mInternetStream, NULL, true);
+ mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel);
+ return mStreamChannel;
}
-bool LLAudioStreamManagerFMOD::stopStream()
+bool LLAudioStreamManagerFMODEX::stopStream()
{
if (mInternetStream)
{
- int read_percent = 0;
- int status = 0;
- int bitrate = 0;
- unsigned int flags = 0x0;
- FSOUND_Stream_Net_GetStatus(mInternetStream, &status, &read_percent, &bitrate, &flags);
+
bool close = true;
- switch (status)
+ switch (getOpenState())
{
- case FSOUND_STREAM_NET_CONNECTING:
+ case FMOD_OPENSTATE_CONNECTING:
close = false;
break;
- case FSOUND_STREAM_NET_NOTCONNECTED:
- case FSOUND_STREAM_NET_BUFFERING:
- case FSOUND_STREAM_NET_READY:
- case FSOUND_STREAM_NET_ERROR:
default:
close = true;
}
if (close)
{
- FSOUND_Stream_Close(mInternetStream);
+ mInternetStream->release();
+ mStreamChannel = NULL;
mInternetStream = NULL;
return true;
}
@@ -349,8 +355,19 @@ bool LLAudioStreamManagerFMOD::stopStream()
}
}
-int LLAudioStreamManagerFMOD::getOpenState()
+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)
{
- int open_state = FSOUND_Stream_GetOpenState(mInternetStream);
- return open_state;
+ 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_fmod.h b/indra/llaudio/llstreamingaudio_fmodex.h
index 9970f0d03b..42b6b3aaa8 100644
--- a/indra/llaudio/llstreamingaudio_fmod.h
+++ b/indra/llaudio/llstreamingaudio_fmodex.h
@@ -1,9 +1,8 @@
/**
- * @file streamingaudio_fmod.h
- * @author Tofu Linden
- * @brief Definition of LLStreamingAudio_FMOD implementation
+ * @file streamingaudio_fmodex.h
+ * @brief Definition of LLStreamingAudio_FMODEX implementation
*
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
@@ -25,20 +24,28 @@
* $/LicenseInfo$
*/
-#ifndef LL_STREAMINGAUDIO_FMOD_H
-#define LL_STREAMINGAUDIO_FMOD_H
+#ifndef LL_STREAMINGAUDIO_FMODEX_H
+#define LL_STREAMINGAUDIO_FMODEX_H
#include "stdtypes.h" // from llcommon
#include "llstreamingaudio.h"
+#include "lltimer.h"
-class LLAudioStreamManagerFMOD;
+//Stubs
+class LLAudioStreamManagerFMODEX;
+namespace FMOD
+{
+ class System;
+ class Channel;
+}
-class LLStreamingAudio_FMOD : public LLStreamingAudioInterface
+//Interfaces
+class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface
{
public:
- LLStreamingAudio_FMOD();
- /*virtual*/ ~LLStreamingAudio_FMOD();
+ LLStreamingAudio_FMODEX(FMOD::System *system);
+ /*virtual*/ ~LLStreamingAudio_FMODEX();
/*virtual*/ void start(const std::string& url);
/*virtual*/ void stop();
@@ -49,14 +56,20 @@ class LLStreamingAudio_FMOD : public LLStreamingAudioInterface
/*virtual*/ F32 getGain();
/*virtual*/ std::string getURL();
+ /*virtual*/ bool supportsAdjustableBufferSizes(){return true;}
+ /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime);
private:
- LLAudioStreamManagerFMOD *mCurrentInternetStreamp;
- int mFMODInternetStreamChannel;
- std::list<LLAudioStreamManagerFMOD *> mDeadStreams;
+ FMOD::System *mSystem;
+
+ LLAudioStreamManagerFMODEX *mCurrentInternetStreamp;
+ FMOD::Channel *mFMODInternetStreamChannelp;
+ std::list<LLAudioStreamManagerFMODEX *> mDeadStreams;
std::string mURL;
F32 mGain;
+
+ LLTimer mLastStarved;
};
-#endif // LL_STREAMINGAUDIO_FMOD_H
+#endif // LL_STREAMINGAUDIO_FMODEX_H
diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp
index 0e0c80a456..dfd5da12b3 100644
--- a/indra/llaudio/llvorbisencode.cpp
+++ b/indra/llaudio/llvorbisencode.cpp
@@ -35,7 +35,7 @@
#include "llapr.h"
//#if LL_DARWIN
-// MBW -- XXX -- Getting rid of SecondLifeVorbis for now -- no fmod means no name collisions.
+// MBW -- XXX -- Getting rid of SecondLifeVorbis for now
#if 0
#include "VorbisFramework.h"
diff --git a/indra/llaudio/llwindgen.h b/indra/llaudio/llwindgen.h
index b9cecb60a1..719b0ecbf2 100644
--- a/indra/llaudio/llwindgen.h
+++ b/indra/llaudio/llwindgen.h
@@ -27,6 +27,7 @@
#define WINDGEN_H
#include "llcommon.h"
+#include "llrand.h"
template <class MIXBUFFERFORMAT_T>
class LLWindGen
@@ -54,7 +55,9 @@ public:
}
const U32 getInputSamplingRate() { return mInputSamplingRate; }
-
+ const F32 getNextSample();
+ const F32 getClampedSample(bool clamp, F32 sample);
+
// newbuffer = the buffer passed from the previous DSP unit.
// numsamples = length in samples-per-channel at this mix time.
// NOTE: generates L/R interleaved stereo
@@ -89,7 +92,7 @@ public:
// Start with white noise
// This expression is fragile, rearrange it and it will break!
- next_sample = (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8);
+ next_sample = getNextSample();
// Apply a pinking filter
// Magic numbers taken from PKE method at http://www.firstpr.com.au/dsp/pink-noise/
@@ -126,23 +129,13 @@ public:
for (U8 i=mSubSamples; i && numsamples; --i, --numsamples)
{
mLastSample = mLastSample + delta;
- S32 sample_right = (S32)(mLastSample * mCurrentPanGainR);
- S32 sample_left = (S32)mLastSample - sample_right;
+ MIXBUFFERFORMAT_T sample_right = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample * mCurrentPanGainR);
+ MIXBUFFERFORMAT_T sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right);
- if (!clip)
- {
- *cursamplep = (MIXBUFFERFORMAT_T)sample_left;
- ++cursamplep;
- *cursamplep = (MIXBUFFERFORMAT_T)sample_right;
- ++cursamplep;
- }
- else
- {
- *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_left, (S32)S16_MIN, (S32)S16_MAX);
- ++cursamplep;
- *cursamplep = (MIXBUFFERFORMAT_T)llclamp(sample_right, (S32)S16_MIN, (S32)S16_MAX);
- ++cursamplep;
- }
+ *cursamplep = sample_left;
+ ++cursamplep;
+ *cursamplep = sample_right;
+ ++cursamplep;
}
}
@@ -173,4 +166,9 @@ private:
F32 mLastSample;
};
+template<class T> inline const F32 LLWindGen<T>::getNextSample() { return (F32)rand() * (1.0f / (F32)(RAND_MAX / (U16_MAX / 8))) + (F32)(S16_MIN / 8); }
+template<> inline const F32 LLWindGen<F32>::getNextSample() { return ll_frand()-.5f; }
+template<class T> inline const F32 LLWindGen<T>::getClampedSample(bool clamp, F32 sample) { return clamp ? (F32)llclamp((S32)sample,(S32)S16_MIN,(S32)S16_MAX) : sample; }
+template<> inline const F32 LLWindGen<F32>::getClampedSample(bool clamp, F32 sample) { return sample; }
+
#endif
diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h
index ae5e3ecade..0ea130e86b 100644
--- a/indra/llcommon/llversionviewer.h
+++ b/indra/llcommon/llversionviewer.h
@@ -29,7 +29,7 @@
const S32 LL_VERSION_MAJOR = 3;
const S32 LL_VERSION_MINOR = 5;
-const S32 LL_VERSION_PATCH = 1;
+const S32 LL_VERSION_PATCH = 2;
const S32 LL_VERSION_BUILD = 264760;
const char * const LL_CHANNEL = "Second Life Developer";
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 2fd025cda4..f6c8e12140 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -10,7 +10,7 @@ include(DirectX)
include(OpenSSL)
include(DragDrop)
include(EXPAT)
-include(FMOD)
+include(FMODEX)
include(OPENAL)
include(OpenGL)
include(Hunspell)
@@ -53,6 +53,10 @@ if (NOT HAVOK_TPV)
add_subdirectory(${LLPHYSICSEXTENSIONS_SRC_DIR} llphysicsextensions)
endif (NOT HAVOK_TPV)
+if(FMODEX)
+ include_directories(${FMODEX_INCLUDE_DIR})
+endif(FMODEX)
+
include_directories(
${DBUSGLIB_INCLUDE_DIRS}
${JSONCPP_INCLUDE_DIR}
@@ -62,7 +66,6 @@ include_directories(
${LLCOMMON_INCLUDE_DIRS}
${LLCOREHTTP_INCLUDE_DIRS}
${LLPHYSICS_INCLUDE_DIRS}
- ${FMOD_INCLUDE_DIR}
${LLIMAGE_INCLUDE_DIRS}
${LLKDU_INCLUDE_DIRS}
${LLINVENTORY_INCLUDE_DIRS}
@@ -1537,29 +1540,12 @@ endif (WINDOWS)
if (OPENAL)
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL")
-endif (OPENAL)
-
-if (FMOD)
- set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMOD")
+endif (OPENAL)
- if (DARWIN)
- set(fmodwrapper_SOURCE_FILES fmodwrapper.cpp)
- add_library(fmodwrapper SHARED ${fmodwrapper_SOURCE_FILES})
- set(fmodwrapper_needed_LIBRARIES ${FMOD_LIBRARY} ${CARBON_LIBRARY})
- set_target_properties(
- fmodwrapper
- PROPERTIES
- BUILD_WITH_INSTALL_RPATH 1
- INSTALL_NAME_DIR "@executable_path/../Resources"
- LINK_FLAGS "-unexported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/fmod_hidden_symbols.exp"
- )
- set(FMODWRAPPER_LIBRARY fmodwrapper)
- target_link_libraries(fmodwrapper ${fmodwrapper_needed_LIBRARIES})
- else (DARWIN)
- # fmodwrapper unnecessary on linux or windows
- set(FMODWRAPPER_LIBRARY ${FMOD_LIBRARY})
- endif (DARWIN)
-endif (FMOD)
+if (FMODEX)
+ set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX")
+ set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY})
+endif (FMODEX)
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
@@ -1640,9 +1626,6 @@ if (WINDOWS)
${SHARED_LIB_STAGING_DIR}/Release/openjpeg.dll
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/openjpeg.dll
${SHARED_LIB_STAGING_DIR}/Debug/openjpegd.dll
- ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll
- ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll
- ${SHARED_LIB_STAGING_DIR}/Debug/fmod.dll
${SHARED_LIB_STAGING_DIR}/Release/msvcr100.dll
${SHARED_LIB_STAGING_DIR}/Release/msvcp100.dll
${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/msvcr100.dll
@@ -1707,6 +1690,14 @@ if (WINDOWS)
windows-updater
)
+ 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)
+
add_custom_command(
OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat
COMMAND ${PYTHON_EXECUTABLE}
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f66d8fca5b..3281d347a7 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -291,6 +291,17 @@
<key>Value</key>
<real>1.0</real>
</map>
+ <key>AudioLevelUnderwaterRolloff</key>
+ <map>
+ <key>Comment</key>
+ <string>Controls the distance-based dropoff of audio volume underwater(fraction or multiple of default audio rolloff)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>5.0</real>
+ </map>
<key>AudioLevelSFX</key>
<map>
<key>Comment</key>
@@ -14446,7 +14457,50 @@
<key>Value</key>
<integer>0</integer>
</map>
-
+ <key>DisablePrecacheDelayAfterTeleporting</key>
+ <map>
+ <key>Comment</key>
+ <string>Disables the artificial delay in the viewer that precaches some incoming assets</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FMODExProfilerEnable</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable profiler tool if using FMOD Ex</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>FMODExDecodeBufferSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Sets the streaming decode buffer size (in milliseconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>1000</integer>
+ </map>
+ <key>FMODExStreamBufferSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Sets the streaming buffer size (in milliseconds)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>7000</integer>
+ </map>
<key>DisablePrecacheDelayAfterTeleporting</key>
<map>
<key>Comment</key>
diff --git a/indra/newview/fmod_hidden_symbols.exp b/indra/newview/fmod_hidden_symbols.exp
deleted file mode 100644
index 1e790255bc..0000000000
--- a/indra/newview/fmod_hidden_symbols.exp
+++ /dev/null
@@ -1,240 +0,0 @@
-_CarbonSndPlayDoubleBuffer
-_ConvertFromIeeeExtended
-__book_maptype1_quantvals
-__book_unquantize
-__float32_pack
-__float32_unpack
-__ilog
-__make_words
-_lpc_clear
-_lpc_init
-__vorbis_block_alloc
-__vorbis_block_ripcord
-__vorbis_apply_window
-__vorbis_window_get
-_vorbis_analysis_blockout
-_vorbis_analysis_buffer
-_vorbis_analysis_wrote
-_vorbis_block_clear
-_vorbis_block_init
-_vorbis_dsp_clear
-_vorbis_synthesis_blockin
-_vorbis_synthesis_init
-_vorbis_synthesis_pcmout
-_vorbis_synthesis_read
-_vorbis_packet_blocksize
-_vorbis_synthesis
-_vorbis_book_clear
-_vorbis_book_decode
-_vorbis_book_decodev_add
-_vorbis_book_decodev_set
-_vorbis_book_decodevs_add
-_vorbis_book_decodevv_add
-_vorbis_book_init_decode
-_vorbis_comment_add
-_vorbis_comment_add_tag
-_vorbis_comment_clear
-_vorbis_comment_init
-_vorbis_comment_query
-_vorbis_comment_query_count
-_vorbis_coslook
-_vorbis_fromdBlook
-_vorbis_info_blocksize
-_vorbis_info_clear
-_vorbis_info_init
-_vorbis_invsq2explook
-_vorbis_invsqlook
-_vorbis_lpc_from_curve
-_vorbis_lpc_from_data
-_vorbis_lpc_predict
-_vorbis_lsp_to_curve
-_vorbis_staticbook_clear
-_vorbis_staticbook_destroy
-_vorbis_staticbook_unpack
-_vorbis_synthesis_headerin
-_vorbis_synthesis_lapout
-_vorbis_synthesis_restart
-_vorbis_synthesis_trackonly
-_vorbis_window
-_ogg_packet_clear
-_ogg_page_bos
-_ogg_page_checksum_set
-_ogg_page_continued
-_ogg_page_eos
-_ogg_page_granulepos
-_ogg_page_packets
-_ogg_page_pageno
-_ogg_page_serialno
-_ogg_page_version
-_ogg_stream_reset_serialno
-_ogg_stream_clear
-_ogg_stream_destroy
-_ogg_stream_eos
-_ogg_stream_flush
-_ogg_stream_init
-_ogg_stream_packetout
-_ogg_stream_packetpeek
-_ogg_stream_pagein
-_ogg_stream_pageout
-_ogg_stream_reset
-_ogg_sync_buffer
-_ogg_sync_clear
-_ogg_sync_destroy
-_ogg_sync_init
-_ogg_sync_pageout
-_ogg_sync_pageseek
-_ogg_sync_reset
-_ogg_sync_wrote
-_ov_bitrate
-_ov_bitrate_instant
-_ov_clear
-_ov_comment
-_ov_info
-_ov_open
-_ov_open_callbacks
-_ov_pcm_seek
-_ov_pcm_seek_page
-_ov_pcm_tell
-_ov_pcm_total
-_ov_raw_seek
-_ov_raw_tell
-_ov_raw_total
-_ov_read
-_ov_read_float
-_ov_seekable
-_ov_serialnumber
-_ov_streams
-_ov_test
-_ov_test_callbacks
-_ov_test_open
-_ov_time_seek
-_ov_time_seek_page
-_ov_time_tell
-_ov_time_total
-_ogg_toupper
-_oggpackB_adv
-_oggpackB_adv1
-_oggpackB_bits
-_oggpackB_bytes
-_oggpackB_get_buffer
-_oggpackB_look
-_oggpackB_look1
-_oggpackB_read
-_oggpackB_read1
-_oggpackB_readinit
-_oggpackB_reset
-_oggpack_adv
-_oggpack_adv1
-_oggpack_bits
-_oggpack_bytes
-_oggpack_get_buffer
-_oggpack_look
-_oggpack_look1
-_oggpack_read
-_oggpack_read1
-_oggpack_readinit
-_oggpack_reset
-_ov_crosslap
-_ov_pcm_seek_lap
-_ov_pcm_seek_page_lap
-_ov_raw_seek_lap
-_ov_time_seek_lap
-_ov_time_seek_page_lap
-_II_step_one
-_II_step_two
-_MyRecComp
-_SampleRates
-_Sinfo
-_ValidStepIndex
-__Z11fmodwrapperv
-__Z11fmodwrapperv.eh
-__floor_P
-__mapping_P
-__residue_P
-__ve_envelope_clear
-__ve_envelope_init
-__ve_envelope_mark
-__ve_envelope_search
-__ve_envelope_shift
-__vi_gpsy_free
-__vi_psy_free
-__vorbis_window_init
-__vp_ampmax_decay
-__vp_couple
-__vp_global_free
-__vp_global_look
-__vp_noise_normalize
-__vp_noise_normalize_sort
-__vp_noisemask
-__vp_offset_and_mix
-__vp_psy_clear
-__vp_psy_init
-__vp_quantize_couple_memo
-__vp_quantize_couple_sort
-__vp_remove_floor
-__vp_tonemask
-_alloc_0
-_alloc_1
-_alloc_2
-_alloc_3
-_alloc_4
-_bandInfo
-_cdcallback
-_cdchannel
-_cdmode
-_cdnumtracks
-_cdstream
-_cdtrack
-_drft_backward
-_drft_clear
-_drft_forward
-_drft_init
-_eatwhite
-_floor0_exportbundle
-_floor1_exportbundle
-_gFreeList
-_gNMRecBusy
-_gNMRecPtr
-_gSilenceOnes
-_gSilenceTwos
-_longLimit
-_mapping0_exportbundle
-_mdct_backward
-_mdct_clear
-_mdct_forward
-_mdct_init
-_muls
-_mystrdup
-_res0_free_info
-_res0_free_look
-_res0_inverse
-_res0_look
-_res0_unpack
-_res1_class
-_res1_inverse
-_res2_inverse
-_residue0_exportbundle
-_residue1_exportbundle
-_residue2_exportbundle
-_scale
-_shortLimit
-_tabsel_123
-_F_Free
-_F_Malloc
-_F_ReAlloc
-_F_memcmp
-_F_memmove
-_F_strcat
-_F_strchr
-_F_strcmp
-_F_strcpy
-_F_stricmp
-_F_strlen
-_F_strncat
-_F_strncmp
-_F_strncpy
-_F_strnicmp
-_F_strstr
-_F_strupr
-_F_tolower
-_F_toupper
diff --git a/indra/newview/fmodwrapper.cpp b/indra/newview/fmodwrapper.cpp
deleted file mode 100644
index 16f1d19a78..0000000000
--- a/indra/newview/fmodwrapper.cpp
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * @file fmodwrapper.cpp
- * @brief dummy source file for building a shared library to wrap libfmod.a
- *
- * $LicenseInfo:firstyear=2005&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$
- */
-
-extern "C"
-{
- void FSOUND_Init(void);
-}
-
-void* fmodwrapper(void)
-{
- // When building the fmodwrapper library, the linker doesn't seem to want to bring in libfmod.a unless I explicitly
- // reference at least one symbol in the library. This seemed like the simplest way.
- return (void*)&FSOUND_Init;
-}
diff --git a/indra/newview/linux_tools/wrapper.sh b/indra/newview/linux_tools/wrapper.sh
index 1381e49c62..48b883e999 100755
--- a/indra/newview/linux_tools/wrapper.sh
+++ b/indra/newview/linux_tools/wrapper.sh
@@ -4,17 +4,17 @@
## 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 OpenAL audio driver.
#export LL_BAD_OPENAL_DRIVER=x
-## - Avoids using any FMOD audio driver.
-#export LL_BAD_FMOD_DRIVER=x
-## - Avoids using the FMOD ESD audio driver.
-#export LL_BAD_FMOD_ESD=x
-## - Avoids using the FMOD OSS audio driver.
-#export LL_BAD_FMOD_OSS=x
-## - Avoids using the FMOD ALSA audio driver.
+## - Avoids using the FMOD Ex PulseAudio audio driver.
+#export LL_BAD_FMOD_PULSEAUDIO=x
+## - Avoids using the FMOD 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
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 03d9b683a4..49c553d0cc 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1708,19 +1708,7 @@ bool LLAppViewer::cleanup()
gAudiop->setStreamingAudioImpl(NULL);
// shut down the audio subsystem
-
- bool want_longname = false;
- if (gAudiop->getDriverName(want_longname) == "FMOD")
- {
- // This hack exists because fmod likes to occasionally
- // crash or hang forever when shutting down, for no
- // apparent reason.
- llwarns << "Hack, skipping FMOD audio engine cleanup" << llendflush;
- }
- else
- {
- gAudiop->shutdown();
- }
+ gAudiop->shutdown();
delete gAudiop;
gAudiop = NULL;
diff --git a/indra/newview/llfloateravatarpicker.cpp b/indra/newview/llfloateravatarpicker.cpp
index 3e0e82b579..113aa9a8f2 100644
--- a/indra/newview/llfloateravatarpicker.cpp
+++ b/indra/newview/llfloateravatarpicker.cpp
@@ -818,7 +818,14 @@ bool LLFloaterAvatarPicker::isSelectBtnEnabled()
uuid_vec_t avatar_ids;
std::vector<LLAvatarName> avatar_names;
getSelectedAvatarData(list, avatar_ids, avatar_names);
- return mOkButtonValidateSignal(avatar_ids);
+ if (avatar_ids.size() >= 1)
+ {
+ ret_val = mOkButtonValidateSignal(avatar_ids);
+ }
+ else
+ {
+ ret_val = false;
+ }
}
}
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 5e6175c4ed..a14a435156 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -37,8 +37,8 @@
#include "llviewermedia_streamingaudio.h"
#include "llaudioengine.h"
-#ifdef LL_FMOD
-# include "llaudioengine_fmod.h"
+#ifdef LL_FMODEX
+# include "llaudioengine_fmodex.h"
#endif
#ifdef LL_OPENAL
@@ -624,32 +624,32 @@ bool idle_startup()
{
gAudiop = NULL;
-#ifdef LL_OPENAL
+#ifdef LL_FMODEX
if (!gAudiop
#if !LL_WINDOWS
- && NULL == getenv("LL_BAD_OPENAL_DRIVER")
+ && NULL == getenv("LL_BAD_FMODEX_DRIVER")
#endif // !LL_WINDOWS
)
{
- gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL();
+ gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODExProfilerEnable"));
}
#endif
-#ifdef LL_FMOD
+#ifdef LL_OPENAL
if (!gAudiop
#if !LL_WINDOWS
- && NULL == getenv("LL_BAD_FMOD_DRIVER")
+ && NULL == getenv("LL_BAD_OPENAL_DRIVER")
#endif // !LL_WINDOWS
)
{
- gAudiop = (LLAudioEngine *) new LLAudioEngine_FMOD();
+ gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL();
}
#endif
-
+
if (gAudiop)
{
#if LL_WINDOWS
- // FMOD on Windows needs the window handle to stop playing audio
+ // FMOD Ex on Windows needs the window handle to stop playing audio
// when window is minimized. JC
void* window_handle = (HWND)gViewerWindow->getPlatformWindow();
#else
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp
index 564bf7997a..094694dc06 100644
--- a/indra/newview/llvieweraudio.cpp
+++ b/indra/newview/llvieweraudio.cpp
@@ -44,6 +44,8 @@
#include "llparcel.h"
#include "llviewermessage.h"
+#include "llstreamingaudio.h"
+
/////////////////////////////////////////////////////////
LLViewerAudio::LLViewerAudio() :
@@ -102,6 +104,11 @@ void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI)
else
{
mFadeState = FADE_IN;
+
+ LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl();
+ if(stream && stream->supportsAdjustableBufferSizes())
+ stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize"));
+
gAudiop->startInternetStream(mNextStreamURI);
startFading();
registerIdleListener();
@@ -157,6 +164,11 @@ bool LLViewerAudio::onIdleUpdate()
if (!mNextStreamURI.empty())
{
mFadeState = FADE_IN;
+
+ LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl();
+ if(stream && stream->supportsAdjustableBufferSizes())
+ stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize"));
+
gAudiop->startInternetStream(mNextStreamURI);
startFading();
}
@@ -386,7 +398,12 @@ void audio_update_volume(bool force_update)
gAudiop->setMasterGain ( master_volume );
gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler"));
- gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
+
+ if(!LLViewerCamera::getInstance()->cameraUnderWater())
+ gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
+ else
+ gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelUnderwaterRolloff"));
+
gAudiop->setMuted(mute_audio || progress_view_visible);
//Play any deferred sounds when unmuted
@@ -473,44 +490,22 @@ void audio_update_listener()
void audio_update_wind(bool force_update)
{
#ifdef kAUDIO_ENABLE_WIND
- //
- // Extract height above water to modulate filter by whether above/below water
- //
+
LLViewerRegion* region = gAgent.getRegion();
if (region)
{
- static F32 last_camera_water_height = -1000.f;
- LLVector3 camera_pos = gAgentCamera.getCameraPositionAgent();
- F32 camera_water_height = camera_pos.mV[VZ] - region->getWaterHeight();
-
- //
- // Don't update rolloff factor unless water surface has been crossed
- //
- if (force_update || (last_camera_water_height * camera_water_height) < 0.f)
- {
- static LLUICachedControl<F32> rolloff("AudioLevelRolloff", 1.0f);
- if (camera_water_height < 0.f)
- {
- gAudiop->setRolloffFactor(rolloff * LL_ROLLOFF_MULTIPLIER_UNDER_WATER);
- }
- else
- {
- gAudiop->setRolloffFactor(rolloff);
- }
- }
-
- // Scale down the contribution of weather-simulation wind to the
- // ambient wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s
- // whereas steady-state avatar walk velocity is only 3.2 m/s.
- // Without this the world feels desolate on first login when you are
- // standing still.
- static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f);
- LLVector3 scaled_wind_vec = gWindVec * wind_level;
-
- // Mix in the avatar's motion, subtract because when you walk north,
- // the apparent wind moves south.
- LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity();
-
+ // Scale down the contribution of weather-simulation wind to the
+ // ambient wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s
+ // whereas steady-state avatar walk velocity is only 3.2 m/s.
+ // Without this the world feels desolate on first login when you are
+ // standing still.
+ static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f);
+ LLVector3 scaled_wind_vec = gWindVec * wind_level;
+
+ // Mix in the avatar's motion, subtract because when you walk north,
+ // the apparent wind moves south.
+ LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity();
+
// rotate the wind vector to be listener (agent) relative
gRelativeWindVec = gAgent.getFrameAgent().rotateToLocal( final_wind_vec );
@@ -543,8 +538,7 @@ void audio_update_wind(bool force_update)
gAudiop->mMaxWindGain = llmax(gAudiop->mMaxWindGain - volume_delta, 0.f);
}
- last_camera_water_height = camera_water_height;
- gAudiop->updateWind(gRelativeWindVec, camera_water_height);
+ gAudiop->updateWind(gRelativeWindVec, gAgentCamera.getCameraPositionAgent()[VZ] - gAgent.getRegion()->getWaterHeight());
}
#endif
}
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index 051f5f4485..a62f73deef 100644
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -655,6 +655,7 @@ void settings_setup_listeners()
gSavedSettings.getControl("AudioLevelVoice")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("AudioLevelDoppler")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("AudioLevelRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
+ gSavedSettings.getControl("AudioLevelUnderwaterRolloff")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("MuteAudio")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("MuteMusic")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
gSavedSettings.getControl("MuteMedia")->getSignal()->connect(boost::bind(&handleAudioVolumeChanged, _2));
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index fcf5af76ff..670272e7be 100644
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -2697,24 +2697,33 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
if(ft && (0 == error_code) &&
(object = gObjectList.findObject(ft->mTaskID)))
{
- object->loadTaskInvFile(ft->mFilename);
+ if (object->loadTaskInvFile(ft->mFilename))
+ {
- LLInventoryObject::object_list_t::iterator it = object->mInventory->begin();
- LLInventoryObject::object_list_t::iterator end = object->mInventory->end();
- std::list<LLUUID>& pending_lst = object->mPendingInventoryItemsIDs;
+ LLInventoryObject::object_list_t::iterator it = object->mInventory->begin();
+ LLInventoryObject::object_list_t::iterator end = object->mInventory->end();
+ std::list<LLUUID>& pending_lst = object->mPendingInventoryItemsIDs;
- for (; it != end && pending_lst.size(); ++it)
- {
- LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(it->get());
- if(item && item->getType() != LLAssetType::AT_CATEGORY)
+ for (; it != end && pending_lst.size(); ++it)
{
- std::list<LLUUID>::iterator id_it = std::find(pending_lst.begin(), pending_lst.begin(), item->getAssetUUID());
- if (id_it != pending_lst.end())
+ LLViewerInventoryItem* item = dynamic_cast<LLViewerInventoryItem*>(it->get());
+ if(item && item->getType() != LLAssetType::AT_CATEGORY)
{
- pending_lst.erase(id_it);
+ std::list<LLUUID>::iterator id_it = std::find(pending_lst.begin(), pending_lst.begin(), item->getAssetUUID());
+ if (id_it != pending_lst.end())
+ {
+ pending_lst.erase(id_it);
+ }
}
}
}
+ else
+ {
+ // MAINT-2597 - crash when trying to edit a no-mod object
+ // Somehow get an contents inventory response, but with an invalid stream (possibly 0 size?)
+ // Stated repro was specific to no-mod objects so failing without user interaction should be safe.
+ llwarns << "Trying to load invalid task inventory file. Ignoring file contents." << llendl;
+ }
}
else
{
@@ -2726,7 +2735,7 @@ void LLViewerObject::processTaskInvFile(void** user_data, S32 error_code, LLExtS
delete ft;
}
-void LLViewerObject::loadTaskInvFile(const std::string& filename)
+BOOL LLViewerObject::loadTaskInvFile(const std::string& filename)
{
std::string filename_and_local_path = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, filename);
llifstream ifs(filename_and_local_path);
@@ -2773,8 +2782,11 @@ void LLViewerObject::loadTaskInvFile(const std::string& filename)
{
llwarns << "unable to load task inventory: " << filename_and_local_path
<< llendl;
+ return FALSE;
}
doInventoryCallback();
+
+ return TRUE;
}
void LLViewerObject::doInventoryCallback()
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 728d279c39..316dbce7d0 100644
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -656,7 +656,7 @@ protected:
//
static void processTaskInvFile(void** user_data, S32 error_code, LLExtStat ext_status);
- void loadTaskInvFile(const std::string& filename);
+ BOOL loadTaskInvFile(const std::string& filename);
void doInventoryCallback();
BOOL isOnMap();
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 9fb6da166e..725670d33f 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -803,14 +803,14 @@ void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string c
//------------------------------------------------------------------------
LLVOAvatar::~LLVOAvatar()
{
- if (!mFullyLoaded)
- {
+ if (!mFullyLoaded)
+ {
debugAvatarRezTime("AvatarRezLeftCloudNotification","left after ruth seconds as cloud");
- }
- else
- {
+ }
+ else
+ {
debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding");
- }
+ }
logPendingPhases();
@@ -6024,6 +6024,11 @@ void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check)
void LLVOAvatar::logPendingPhases()
{
+ if (!isAgentAvatarValid())
+ {
+ return;
+ }
+
for (LLViewerStats::phase_map_t::iterator it = getPhases().begin();
it != getPhases().end();
++it)
@@ -6058,6 +6063,11 @@ void LLVOAvatar::logPendingPhasesAllAvatars()
void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed)
{
+ if (!isAgentAvatarValid())
+ {
+ return;
+ }
+
LLSD record;
record["timer_name"] = phase_name;
record["avatar_id"] = getID();
@@ -6074,13 +6084,6 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse
record["is_using_server_bakes"] = ((bool) isUsingServerBakes());
record["is_self"] = isSelf();
-
-#if 0 // verbose logging
- std::ostringstream ostr;
- ostr << LLSDNotationStreamer(record);
- LL_DEBUGS("Avatar") << "record\n" << ostr.str() << llendl;
-#endif
-
if (isAgentAvatarValid())
{
gAgentAvatarp->addMetricsTimerRecord(record);
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 69248e26bc..e2b914aae8 100644
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -367,10 +367,14 @@ class WindowsManifest(ViewerManifest):
print err.message
print "Skipping COLLADA and GLOD libraries (assumming linked statically)"
-
- # Get fmod dll, continue if missing
- if not self.path("fmod.dll"):
- print "Skipping fmod.dll"
+ # Get fmodex dll, continue if missing
+ try:
+ if self.args['configuration'].lower() == 'debug':
+ self.path("fmodexL.dll")
+ else:
+ self.path("fmodex.dll")
+ except:
+ print "Skipping fmodex audio library(assuming other audio engine)"
# For textures
if self.args['configuration'].lower() == 'debug':
@@ -743,6 +747,7 @@ class DarwinManifest(ViewerManifest):
"libcollada14dom.dylib",
"libexpat.1.5.2.dylib",
"libexception_handler.dylib",
+ "libfmodex.dylib",
"libGLOD.dylib",
):
dylibs += path_optional(os.path.join(libdir, libfile), libfile)
@@ -757,11 +762,7 @@ class DarwinManifest(ViewerManifest):
'SLVoice',
):
self.path2basename(libdir, libfile)
-
- # FMOD for sound
- libfile = "libfmodwrapper.dylib"
- path_optional(os.path.join(self.args['configuration'], libfile), libfile)
-
+
# our apps
for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
("mac_updater", "mac-updater.app"),
@@ -1122,11 +1123,13 @@ class Linux_i686Manifest(LinuxManifest):
pass
try:
- self.path("libfmod-3.75.so")
+ self.path("libfmodex-*.so")
+ self.path("libfmodex.so")
pass
except:
- print "Skipping libfmod-3.75.so - not found"
+ print "Skipping libfmodex.so - not found"
pass
+
self.end_prefix("lib")
# Vivox runtimes