diff --git a/autobuild.xml b/autobuild.xml index d75b007d0e660a6ff6dcb79725d38f590cc8e180..a8967e56099cfbca7b5a0bd61571cbf7c177d1ab 100644 --- a/autobuild.xml +++ b/autobuild.xml @@ -729,16 +729,18 @@ <key>version</key> <string>2.1.1.500375</string> </map> - <key>fmodex</key> + <key>fmodstudio</key> <map> <key>copyright</key> - <string>COPYRIGHT 2014 FIRELIGHT TECHNOLOGIES PTY LTD. ALL RIGHTS RESERVED</string> + <string>FMOD Studio, Copyright (c) Firelight Technologies Pty Ltd.</string> + <key>description</key> + <string>FMOD Studio audio system library</string> <key>license</key> - <string>fmodex</string> + <string>fmodstudio</string> <key>license_file</key> - <string>LICENSES/fmodex.txt</string> + <string>LICENSES/fmodstudio.txt</string> <key>name</key> - <string>fmodex</string> + <string>fmodstudio</string> <key>platforms</key> <map> <key>darwin</key> @@ -746,45 +748,25 @@ <key>archive</key> <map> <key>hash</key> - <string>ed0d8767652aecd65a7fef3e28645bad</string> + <string>21610bcca4e2ff76b6483c1faae8b152</string> + <key>hash_algorithm</key> + <string>md5</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/fmodex_3p-update-fmodex/rev/297261/arch/Darwin/installer/fmodex-4.44.31.297261-darwin-297261.tar.bz2</string> + <string>https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/darwin/fmodstudio-2.00.07.4-darwin-4.tar.bz2</string> </map> <key>name</key> <string>darwin</string> </map> - <key>darwin64</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>cba1feed7f6bb671d791a517fddf205a</string> - <key>url</key> - <string>https://downloads.catznip.com/packages/fmodex-44461-darwin-201601300040-r23.tar.bz2</string> - </map> - <key>name</key> - <string>darwin64</string> - </map> - <key>linux</key> - <map> - <key>archive</key> - <map> - <key>hash</key> - <string>b847ec838da1ad1dd646df9d74e9b395</string> - <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/p64_3p-fmodex/rev/314207/arch/Linux/installer/fmodex-4.44.61.314207-linux-314207.tar.bz2</string> - </map> - <key>name</key> - <string>linux</string> - </map> <key>linux64</key> <map> <key>archive</key> <map> <key>hash</key> - <string>89a75d8719f7b2cbe1e54cd8407bb992</string> + <string>54dbd41322a08a1fc333ca6d96af5502</string> + <key>hash_algorithm</key> + <string>md5</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/1544/3476/fmodex-4.44.64.501533-linux64-501533.tar.bz2</string> + <string>https://depot.alchemyviewer.org/pub/linux64/lib/fmodstudio-1.10.00-linux64-201709282320.tar.bz2</string> </map> <key>name</key> <string>linux64</string> @@ -794,9 +776,11 @@ <key>archive</key> <map> <key>hash</key> - <string>2038da4ab71da8dc086738007c0acdd3</string> + <string>d32efb193ffcd73bcba4875ddfd17bf0</string> + <key>hash_algorithm</key> + <string>md5</string> <key>url</key> - <string>http://viewer.catznip.com/downloads/packages/fmodex-4.44.61-windows-171261212.tar.bz2</string> + <string>https://pkg.alchemyviewer.org/repository/autobuild-internal/fmodstudio/windows/fmodstudio-2.00.07.4-windows-4.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -806,16 +790,18 @@ <key>archive</key> <map> <key>hash</key> - <string>b4b73cd64bfd72e7ae84aad429d69cf6</string> + <string>0604fd6b53ceaf14ce04d0de1bea51b8</string> + <key>hash_algorithm</key> + <string>md5</string> <key>url</key> - <string>http://viewer.catznip.com/downloads/packages/fmodex-4.44.61-windows64-171261211.tar.bz2</string> + <string>file:///c:/bld/fmodstudio-2.00.07.4-windows64-4.tar.bz2</string> </map> <key>name</key> <string>windows64</string> </map> </map> <key>version</key> - <string>4.44.64.501533</string> + <string>2.00.07.4</string> </map> <key>fontconfig</key> <map> @@ -1748,9 +1734,11 @@ <key>archive</key> <map> <key>hash</key> - <string>da3b1ea90797b189d80ab5d50fdf05d4</string> + <string>6bb48e878e7f4e7b6630a6f3a5fd2f89</string> + <key>hash_algorithm</key> + <string>md5</string> <key>url</key> - <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/15260/98469/kdu-7.10.4.513518-windows64-513518.tar.bz2</string> + <string>file:///c:/bld/kdu-7.10.4.200681608-windows64-200681608.tar.bz2</string> </map> <key>name</key> <string>windows64</string> @@ -2706,9 +2694,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>545954e46a316e469f6b68ecbcb76573</string> + <string>8a7f0be5647e07235d205ac00805fb78</string> <key>url</key> - <string>http://viewer.catznip.com/downloads/packages/openjpeg-1.5.2.171271050-windows-171271050.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1116/2586/openjpeg-1.5.1.501102-windows-501102.tar.bz2</string> </map> <key>name</key> <string>windows</string> @@ -2718,9 +2706,9 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string> <key>archive</key> <map> <key>hash</key> - <string>a68103651741c8b66356153ee5668d6b</string> + <string>398544058036bc27097fcff208934d11</string> <key>url</key> - <string>http://viewer.catznip.com/downloads/packages/openjpeg-1.5.2.171271046-windows64-171271046.tar.bz2</string> + <string>http://automated-builds-secondlife-com.s3.amazonaws.com/ct2/1115/2581/openjpeg-1.5.1.501102-windows64-501102.tar.bz2</string> </map> <key>name</key> <string>windows64</string> diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt index 7864271c02847fef2b75bf76a9ad1d14fcb08c56..3e7b48e6bf73428262a7a7f73ecd9ea85f7d21eb 100644 --- a/indra/cmake/CMakeLists.txt +++ b/indra/cmake/CMakeLists.txt @@ -27,7 +27,7 @@ set(cmake_SOURCE_FILES FindAPR.cmake FindAutobuild.cmake FindBerkeleyDB.cmake - FindFMODEX.cmake + FindFMODSTUDIO.cmake FindGLH.cmake FindGoogleBreakpad.cmake FindHUNSPELL.cmake @@ -38,7 +38,7 @@ set(cmake_SOURCE_FILES FindURIPARSER.cmake FindXmlRpcEpi.cmake FindZLIB.cmake - FMODEX.cmake + FMODSTUDIO.cmake FreeType.cmake GLEXT.cmake GLH.cmake diff --git a/indra/cmake/Copy3rdPartyLibs.cmake b/indra/cmake/Copy3rdPartyLibs.cmake index c73a1fdb47b3e78f5de6bfe751d0d76a8b73eb06..da5143631a0724a3430953e4ae73683be380d970 100644 --- a/indra/cmake/Copy3rdPartyLibs.cmake +++ b/indra/cmake/Copy3rdPartyLibs.cmake @@ -62,14 +62,10 @@ if(WINDOWS) endif(ADDRESS_SIZE EQUAL 32) endif (BUGSPLAT_DB) - if (FMODEX) - - if(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} fmodex.dll) - else(ADDRESS_SIZE EQUAL 32) - set(release_files ${release_files} fmodex64.dll) - endif(ADDRESS_SIZE EQUAL 32) - endif (FMODEX) + if (USE_FMODSTUDIO) + list(APPEND debug_files fmodL.dll) + list(APPEND release_files fmod.dll) + endif (USE_FMODSTUDIO) #******************************* # Copy MS C runtime dlls, required for packaging. @@ -192,10 +188,10 @@ elseif(DARWIN) libnghttp2.14.14.0.dylib ) - if (FMODEX) - set(debug_files ${debug_files} libfmodexL.dylib) - set(release_files ${release_files} libfmodex.dylib) - endif (FMODEX) + if (USE_FMODSTUDIO) + list(APPEND debug_files libfmodL.dylib) + list(APPEND release_files libfmod.dylib) + endif (USE_FMODSTUDIO) elseif(LINUX) # linux is weird, multiple side by side configurations aren't supported @@ -242,10 +238,10 @@ elseif(LINUX) libfontconfig.so.1 ) - if (FMODEX) - set(debug_files ${debug_files} "libfmodexL.so") - set(release_files ${release_files} "libfmodex.so") - endif (FMODEX) + if (USE_FMODSTUDIO) + list(APPEND debug_files "libfmodL.so") + list(APPEND release_files "libfmod.so") + endif (USE_FMODSTUDIO) else(WINDOWS) message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...") diff --git a/indra/cmake/FMODEX.cmake b/indra/cmake/FMODEX.cmake deleted file mode 100644 index 69d6dd5f6d6a8b77cd4dc11f89f30f366b5f56c6..0000000000000000000000000000000000000000 --- a/indra/cmake/FMODEX.cmake +++ /dev/null @@ -1,52 +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 FMODEX. -# Open source devs should use the -DFMODEX:BOOL=ON then if they want to build with FMOD, whether -# they are using USESYSTEMLIBS or not. -if (INSTALL_PROPRIETARY) - set(FMODEX ON CACHE BOOL "Using FMOD Ex sound library.") -endif (INSTALL_PROPRIETARY) - -if (FMODEX) - if (USESYSTEMLIBS) - # In that case, we use the version of the library installed on the system - set(FMODEX_FIND_REQUIRED ON) - include(FindFMODEX) - else (USESYSTEMLIBS) - if (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - # If the path have been specified in the arguments, use that - set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - MESSAGE(STATUS "Using FMODEX path: ${FMODEX_LIBRARIES}, ${FMODEX_INCLUDE_DIR}") - else (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - # If not, we're going to try to get the package listed in autobuild.xml - # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) - # as accessing the private LL location will fail if you don't have the credential - include(Prebuilt) - use_prebuilt_binary(fmodex) - if (WINDOWS) - if (ADDRESS_SIZE EQUAL 32) - set(FMODEX_LIBRARY - debug fmodexL_vc - optimized fmodex_vc) - else (ADDRESS_SIZE EQUAL 64) - set(FMODEX_LIBRARY - debug fmodexL64_vc - optimized fmodex64_vc) - endif (ADDRESS_SIZE EQUAL 32) - elseif (DARWIN) - set(FMODEX_LIBRARY - debug fmodexL - optimized fmodex) - elseif (LINUX) - set(FMODEX_LIBRARY - debug fmodexL - optimized fmodex) - endif (WINDOWS) - set(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - set(FMODEX_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodex) - endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - endif (USESYSTEMLIBS) -endif (FMODEX) - diff --git a/indra/cmake/FMODSTUDIO.cmake b/indra/cmake/FMODSTUDIO.cmake new file mode 100644 index 0000000000000000000000000000000000000000..c067ea3fee3fc45ba537d42d6030fb53ab9ad338 --- /dev/null +++ b/indra/cmake/FMODSTUDIO.cmake @@ -0,0 +1,46 @@ +# -*- cmake -*- + +# FMOD can be set when launching the make using the argument -DUSE_FMODSTUDIO:BOOL=ON +# When building using proprietary binaries though (i.e. having access to LL private servers), +# we always build with FMODSTUDIO. +# Open source devs should use the -DFMODSTUDIO:BOOL=ON then if they want to build with FMOD, whether +# they are using STANDALONE or not. +if (INSTALL_PROPRIETARY) + set(USE_FMODSTUDIO ON) +endif (INSTALL_PROPRIETARY) + +if (USE_FMODSTUDIO) + if (STANDALONE) + # In that case, we use the version of the library installed on the system + set(FMODSTUDIO_FIND_REQUIRED ON) + include(FindFMODSTUDIO) + else (STANDALONE) + if (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + # If the path have been specified in the arguments, use that + set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + MESSAGE(STATUS "Using FMODSTUDIO path: ${FMODSTUDIO_LIBRARIES}, ${FMODSTUDIO_INCLUDE_DIR}") + else (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + # If not, we're going to try to get the package listed in autobuild.xml + # Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL) + # as accessing the private LL location will fail if you don't have the credential + include(Prebuilt) + use_prebuilt_binary(fmodstudio) + if (WINDOWS) + set(FMODSTUDIO_LIBRARY + debug fmodL_vc + optimized fmod_vc) + elseif (DARWIN) + set(FMODSTUDIO_LIBRARY + debug fmodL + optimized fmod) + elseif (LINUX) + set(FMODSTUDIO_LIBRARY + debug fmodL + optimized fmod) + endif (WINDOWS) + set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + set(FMODSTUDIO_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodstudio) + endif (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + endif (STANDALONE) +endif (USE_FMODSTUDIO) + diff --git a/indra/cmake/FindFMODEX.cmake b/indra/cmake/FindFMODEX.cmake deleted file mode 100644 index b621727c0ea490c8d55c7d89f243813ab698bda6..0000000000000000000000000000000000000000 --- a/indra/cmake/FindFMODEX.cmake +++ /dev/null @@ -1,65 +0,0 @@ -# -*- cmake -*- - -# - Find FMODEX -# Find the FMODEX includes and library -# This module defines -# FMODEX_INCLUDE_DIR, where to find fmod.h and fmod_errors.h -# FMODEX_LIBRARIES, the libraries needed to use FMODEX. -# FMODEX, If false, do not try to use FMODEX. -# also defined, but not for general use are -# FMODEX_LIBRARY, where to find the FMODEX library. - -FIND_PATH(FMODEX_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod) - -SET(FMODEX_NAMES ${FMODEX_NAMES} fmodex fmodvc fmodexL_vc) -FIND_LIBRARY(FMODEX_LIBRARY - NAMES ${FMODEX_NAMES} - PATH_SUFFIXES fmodex - ) - -IF (FMODEX_SDK_DIR OR WINDOWS) - if(WINDOWS) - set(FMODEX_SDK_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows" CACHE PATH "Path to FMODEX") - STRING(REGEX REPLACE "\\\\" "/" FMODEX_SDK_DIR ${FMODEX_SDK_DIR}) - endif(WINDOWS) - find_library(FMODEX_LIBRARY - fmodex_vc fmodexL_vc - PATHS - ${FMODEX_SDK_DIR}/api/lib - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - find_path(FMODEX_INCLUDE_DIR fmod.h - ${FMODEX_SDK_DIR}/api/inc - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - find_path(FMODEX_INCLUDE_DIR fmod.h - ${FMODEX_SDK_DIR}/api/inc - ${FMODEX_SDK_DIR}/api - ${FMODEX_SDK_DIR} - ) - IF (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) - SET(FMODEX_LIBRARIES ${FMODEX_LIBRARY}) - SET(FMODEX_FOUND "YES") - endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR) -ENDIF (FMODEX_SDK_DIR OR WINDOWS) - -IF (FMODEX_FOUND) - IF (NOT FMODEX_FIND_QUIETLY) - MESSAGE(STATUS "Found FMODEX: ${FMODEX_LIBRARIES}") - ENDIF (NOT FMODEX_FIND_QUIETLY) -ELSE (FMODEX_FOUND) - IF (FMODEX_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "Could not find FMODEX library") - ENDIF (FMODEX_FIND_REQUIRED) -ENDIF (FMODEX_FOUND) - -# Deprecated declarations. -SET (NATIVE_FMODEX_INCLUDE_PATH ${FMODEX_INCLUDE_DIR} ) -GET_FILENAME_COMPONENT (NATIVE_FMODEX_LIB_PATH ${FMODEX_LIBRARY} PATH) - -MARK_AS_ADVANCED( - FMODEX_LIBRARY - FMODEX_INCLUDE_DIR - ) diff --git a/indra/cmake/FindFMODSTUDIO.cmake b/indra/cmake/FindFMODSTUDIO.cmake new file mode 100644 index 0000000000000000000000000000000000000000..4562b0ae450aeb2b27ad3905ead1a46ecb5c313b --- /dev/null +++ b/indra/cmake/FindFMODSTUDIO.cmake @@ -0,0 +1,65 @@ +# -*- cmake -*- + +# - Find FMODSTUDIO +# Find the FMODSTUDIO includes and library +# This module defines +# FMODSTUDIO_INCLUDE_DIR, where to find fmod.h and fmod_errors.h +# FMODSTUDIO_LIBRARIES, the libraries needed to use FMODSTUDIO. +# FMODSTUDIO, If false, do not try to use FMODSTUDIO. +# also defined, but not for general use are +# FMODSTUDIO_LIBRARY, where to find the FMODSTUDIO library. + +FIND_PATH(FMODSTUDIO_INCLUDE_DIR fmod.h PATH_SUFFIXES fmod) + +SET(FMODSTUDIO_NAMES ${FMODSTUDIO_NAMES} fmod fmod_vc) +FIND_LIBRARY(FMODSTUDIO_LIBRARY + NAMES ${FMODSTUDIO_NAMES} + PATH_SUFFIXES fmod + ) + +IF (FMODSTUDIO_SDK_DIR OR WINDOWS) + if(WINDOWS) + set(FMODSTUDIO_SDK_DIR "$ENV{PROGRAMFILES}/FMOD SoundSystem/FMOD Programmers API Windows" CACHE PATH "Path to FMODSTUDIO") + STRING(REGEX REPLACE "\\\\" "/" FMODSTUDIO_SDK_DIR ${FMODSTUDIO_SDK_DIR}) + endif(WINDOWS) + find_library(FMODSTUDIO_LIBRARY + fmod_vc fmodL_vc + PATHS + ${FMODSTUDIO_SDK_DIR}/api/lib + ${FMODSTUDIO_SDK_DIR}/api + ${FMODSTUDIO_SDK_DIR} + ) + find_path(FMODSTUDIO_INCLUDE_DIR fmod.h + ${FMODSTUDIO_SDK_DIR}/api/inc + ${FMODSTUDIO_SDK_DIR}/api + ${FMODSTUDIO_SDK_DIR} + ) + find_path(FMODSTUDIO_INCLUDE_DIR fmod.h + ${FMODSTUDIO_SDK_DIR}/api/inc + ${FMODSTUDIO_SDK_DIR}/api + ${FMODSTUDIO_SDK_DIR} + ) + IF (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) + SET(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY}) + SET(FMODSTUDIO_FOUND "YES") + endif (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR) +ENDIF (FMODSTUDIO_SDK_DIR OR WINDOWS) + +IF (FMODSTUDIO_FOUND) + IF (NOT FMODSTUDIO_FIND_QUIETLY) + MESSAGE(STATUS "Found FMODSTUDIO: ${FMODSTUDIO_LIBRARIES}") + ENDIF (NOT FMODSTUDIO_FIND_QUIETLY) +ELSE (FMODSTUDIO_FOUND) + IF (FMODSTUDIO_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find FMODSTUDIO library") + ENDIF (FMODSTUDIO_FIND_REQUIRED) +ENDIF (FMODSTUDIO_FOUND) + +# Deprecated declarations. +SET (NATIVE_FMODSTUDIO_INCLUDE_PATH ${FMODSTUDIO_INCLUDE_DIR} ) +GET_FILENAME_COMPONENT (NATIVE_FMODSTUDIO_LIB_PATH ${FMODSTUDIO_LIBRARY} PATH) + +MARK_AS_ADVANCED( + FMODSTUDIO_LIBRARY + FMODSTUDIO_INCLUDE_DIR + ) diff --git a/indra/llaudio/CMakeLists.txt b/indra/llaudio/CMakeLists.txt index e943dd5d5ccd059100c1ad41507a3f5d377b73d1..77f023f71e7c9d8c1581d8e6e33af43229fc0b47 100644 --- a/indra/llaudio/CMakeLists.txt +++ b/indra/llaudio/CMakeLists.txt @@ -4,7 +4,7 @@ project(llaudio) include(00-Common) include(LLAudio) -include(FMODEX) +include(FMODSTUDIO) include(OPENAL) include(LLCommon) include(LLMath) @@ -38,26 +38,27 @@ set(llaudio_HEADER_FILES llaudioengine.h lllistener.h llaudiodecodemgr.h + llstreamingaudio.h llvorbisencode.h llwindgen.h ) -if (FMODEX) +if (USE_FMODSTUDIO) include_directories( - ${FMODEX_INCLUDE_DIR} + ${FMODSTUDIO_INCLUDE_DIR} ) list(APPEND llaudio_SOURCE_FILES - llaudioengine_fmodex.cpp - lllistener_fmodex.cpp - llstreamingaudio_fmodex.cpp + llaudioengine_fmodstudio.cpp + lllistener_fmodstudio.cpp + llstreamingaudio_fmodstudio.cpp ) list(APPEND llaudio_HEADER_FILES - llaudioengine_fmodex.h - lllistener_fmodex.h - llstreamingaudio_fmodex.h + llaudioengine_fmodstudio.h + lllistener_fmodstudio.h + llstreamingaudio_fmodstudio.h ) -endif (FMODEX) +endif (USE_FMODSTUDIO) if (OPENAL) list(APPEND llaudio_SOURCE_FILES diff --git a/indra/llaudio/llaudioengine.cpp b/indra/llaudio/llaudioengine.cpp index f49028aad51955fbc5a606cda3ebcf9f2985e43e..493a0744652c3792c70b32261ae132d0fcd18497 100644 --- a/indra/llaudio/llaudioengine.cpp +++ b/indra/llaudio/llaudioengine.cpp @@ -69,6 +69,7 @@ LLStreamingAudioInterface* LLAudioEngine::getStreamingAudioImpl() void LLAudioEngine::setStreamingAudioImpl(LLStreamingAudioInterface *impl) { + delete mStreamingAudioImpl; mStreamingAudioImpl = impl; } @@ -133,11 +134,15 @@ void LLAudioEngine::shutdown() { // Clean up decode manager delete gAudioDecodeMgrp; - gAudioDecodeMgrp = NULL; + gAudioDecodeMgrp = nullptr; // Clean up wind source cleanupWind(); + // Clean up streaming audio + delete mStreamingAudioImpl; + mStreamingAudioImpl = nullptr; + // Clean up audio sources source_map::iterator iter_src; for (iter_src = mAllSources.begin(); iter_src != mAllSources.end(); iter_src++) diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp deleted file mode 100644 index 7e65a05e48ab561f7c65b9cdd406571c5f2bba42..0000000000000000000000000000000000000000 --- a/indra/llaudio/llaudioengine_fmodex.cpp +++ /dev/null @@ -1,767 +0,0 @@ -/** - * @file audioengine_fmodex.cpp - * @brief Implementation of LLAudioEngine class abstracting the audio - * support as a FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2014, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llstreamingaudio.h" -#include "llstreamingaudio_fmodex.h" - -#include "llaudioengine_fmodex.h" -#include "lllistener_fmodex.h" - -#include "llerror.h" -#include "llmath.h" -#include "llrand.h" - -#include "fmod.hpp" -#include "fmod_errors.h" -#include "lldir.h" -#include "llapr.h" - -#include "sound_ids.h" - -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int outchannels); - -FMOD::ChannelGroup *LLAudioEngine_FMODEX::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0}; - -LLAudioEngine_FMODEX::LLAudioEngine_FMODEX(bool enable_profiler) -{ - mInited = false; - mWindGen = NULL; - mWindDSP = NULL; - mSystem = NULL; - mEnableProfiler = enable_profiler; - mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); -} - - -LLAudioEngine_FMODEX::~LLAudioEngine_FMODEX() -{ - delete mWindDSPDesc; -} - - -inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) -{ - if(result == FMOD_OK) - return false; - LL_DEBUGS() << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; - return true; -} - -void* F_STDCALL decode_alloc(unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - if(type & FMOD_MEMORY_STREAM_DECODE) - { - LL_INFOS() << "Decode buffer size: " << size << LL_ENDL; - } - else if(type & FMOD_MEMORY_STREAM_FILE) - { - LL_INFOS() << "Strean buffer size: " << size << LL_ENDL; - } - return new char[size]; -} -void* F_STDCALL decode_realloc(void *ptr, unsigned int size, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - memset(ptr,0,size); - return ptr; -} -void F_STDCALL decode_dealloc(void *ptr, FMOD_MEMORY_TYPE type, const char *sourcestr) -{ - delete[] (char*)ptr; -} - -bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata) -{ - U32 version; - FMOD_RESULT result; - - LL_DEBUGS("AppInit") << "LLAudioEngine_FMODEX::init() initializing FMOD" << LL_ENDL; - - //result = FMOD::Memory_Initialize(NULL, 0, &decode_alloc, &decode_realloc, &decode_dealloc, FMOD_MEMORY_STREAM_DECODE | FMOD_MEMORY_STREAM_FILE); - //if(Check_FMOD_Error(result, "FMOD::Memory_Initialize")) - // return false; - - // turn off non-error log spam to fmod.log (TODO: why do we even have an fmod.log if we don't link against log lib?) - FMOD::Debug_SetLevel(FMOD_DEBUG_LEVEL_ERROR); - - result = FMOD::System_Create(&mSystem); - if(Check_FMOD_Error(result, "FMOD::System_Create")) - return false; - - //will call LLAudioEngine_FMODEX::allocateListener, which needs a valid mSystem pointer. - LLAudioEngine::init(num_channels, userdata); - - result = mSystem->getVersion(&version); - Check_FMOD_Error(result, "FMOD::System::getVersion"); - - if (version < FMOD_VERSION) - { - LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Ex version (" << version - << ")! You should be using FMOD Ex" << FMOD_VERSION << LL_ENDL; - } - - result = mSystem->setSoftwareFormat(44100, FMOD_SOUND_FORMAT_PCM16, 0, 0, FMOD_DSP_RESAMPLER_LINEAR); - Check_FMOD_Error(result,"FMOD::System::setSoftwareFormat"); - - // In this case, all sounds, PLUS wind and stream will be software. - result = mSystem->setSoftwareChannels(num_channels + 2); - Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); - - U32 fmod_flags = FMOD_INIT_NORMAL; - if(mEnableProfiler) - { - fmod_flags |= FMOD_INIT_ENABLE_PROFILE; - mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]); - mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]); - mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]); - mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]); - } - -#if LL_LINUX - bool audio_ok = false; - - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; - if(mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK && - (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; - if(mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK && - (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "ALSA audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - if (NULL == getenv("LL_BAD_FMOD_OSS")) /*Flawfinder: ignore*/ - { - LL_DEBUGS("AppInit") << "Trying OSS audio output..." << LL_ENDL; - if(mSystem->setOutput(FMOD_OUTPUTTYPE_OSS) == FMOD_OK && - (result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK) - { - LL_DEBUGS("AppInit") << "OSS audio output initialized OKAY" << LL_ENDL; - audio_ok = true; - } - else - { - Check_FMOD_Error(result, "OSS audio output FAILED to initialize"); - } - } - else - { - LL_DEBUGS("AppInit") << "OSS audio output SKIPPED" << LL_ENDL; - } - } - if (!audio_ok) - { - LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; - return false; - } - - // We're interested in logging which output method we - // ended up with, for QA purposes. - FMOD_OUTPUTTYPE output_type; - mSystem->getOutput(&output_type); - switch (output_type) - { - case FMOD_OUTPUTTYPE_NOSOUND: - LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_PULSEAUDIO: - LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_ALSA: - LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; - case FMOD_OUTPUTTYPE_OSS: - LL_INFOS("AppInit") << "Audio output: OSS" << LL_ENDL; break; - default: - LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; - }; -#else // LL_LINUX - - // initialize the FMOD engine - result = mSystem->init( num_channels + 2, fmod_flags, 0); - if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) - { - /* - Ok, the speaker mode selected isn't supported by this soundcard. Switch it - back to stereo... - */ - result = mSystem->setSpeakerMode(FMOD_SPEAKERMODE_STEREO); - Check_FMOD_Error(result,"Error falling back to stereo mode"); - /* - ... and re-init. - */ - result = mSystem->init( num_channels + 2, fmod_flags, 0); - } - if(Check_FMOD_Error(result, "Error initializing FMOD Ex")) - return false; -#endif - - // set up our favourite FMOD-native streaming audio implementation if none has already been added - if (!getStreamingAudioImpl()) // no existing implementation added - setStreamingAudioImpl(new LLStreamingAudio_FMODEX(mSystem)); - - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init() FMOD Ex initialized correctly" << LL_ENDL; - - int r_numbuffers, r_samplerate, r_channels, r_bits; - unsigned int r_bufferlength; - mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_numbuffers=" << r_numbuffers << LL_ENDL; - - mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_channels=" << r_channels << LL_ENDL; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bits =" << r_bits << LL_ENDL; - - char r_name[512]; - mSystem->getDriverInfo(0, r_name, 511, 0); - r_name[511] = '\0'; - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_name=\"" << r_name << "\"" << LL_ENDL; - - int latency = 100; // optimistic default - i suspect if sample rate is 0, everything breaks. - if ( r_samplerate != 0 ) - latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): latency=" << latency << "ms" << LL_ENDL; - - mInited = true; - - LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): initialization complete." << LL_ENDL; - - return true; -} - - -std::string LLAudioEngine_FMODEX::getDriverName(bool verbose) -{ - llassert_always(mSystem); - if (verbose) - { - U32 version; - if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion")) - { - return llformat("FMOD Ex %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); - } - } - return "FMODEx"; -} - - -void LLAudioEngine_FMODEX::allocateListener(void) -{ - mListenerp = (LLListener *) new LLListener_FMODEX(mSystem); - if (!mListenerp) - { - LL_WARNS() << "Listener creation failed" << LL_ENDL; - } -} - - -void LLAudioEngine_FMODEX::shutdown() -{ - stopInternetStream(); - - LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; - LLAudioEngine::shutdown(); - - LL_INFOS() << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << LL_ENDL; - if ( mSystem ) // speculative fix for MAINT-2657 - { - mSystem->close(); - mSystem->release(); - } - LL_INFOS() << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << LL_ENDL; - - delete mListenerp; - mListenerp = NULL; -} - - -LLAudioBuffer * LLAudioEngine_FMODEX::createBuffer() -{ - return new LLAudioBufferFMODEX(mSystem); -} - - -LLAudioChannel * LLAudioEngine_FMODEX::createChannel() -{ - return new LLAudioChannelFMODEX(mSystem); -} - -bool LLAudioEngine_FMODEX::initWind() -{ - mNextWindUpdate = 0.0; - - if (!mWindDSP) - { - memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero - strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); - mWindDSPDesc->channels = 2; - mWindDSPDesc->read = &windCallback; // Assign callback - may be called from arbitrary threads - if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP")) - return false; - - if (mWindGen) - delete mWindGen; - - float frequency = 44100; - mWindDSP->getDefaults(&frequency,0,0,0); - mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency); - mWindDSP->setUserData((void*)mWindGen); - } - - // *TODO: Should this guard against multiple plays? - if (mWindDSP) - { - mSystem->playDSP(FMOD_CHANNEL_FREE, mWindDSP, false, 0); - return true; - } - return false; -} - - -void LLAudioEngine_FMODEX::cleanupWind() -{ - if (mWindDSP) - { - mWindDSP->remove(); - mWindDSP->release(); - mWindDSP = NULL; - } - - delete mWindGen; - mWindGen = NULL; -} - - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODEX::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) -{ - LLVector3 wind_pos; - F64 pitch; - F64 center_freq; - - if (!mEnableWind) - { - return; - } - - if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) - { - - // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) - // need to convert this to the conventional orientation DS3D and OpenAL use - // where +X = right, +Y = up, +Z = backwards - - wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); - - // cerr << "Wind update" << endl; - - pitch = 1.0 + mapWindVecToPitch(wind_vec); - center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); - - mWindGen->mTargetFreq = (F32)center_freq; - mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; - mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); - } -} - -//----------------------------------------------------------------------- -void LLAudioEngine_FMODEX::setInternalGain(F32 gain) -{ - if (!mInited) - { - return; - } - - gain = llclamp( gain, 0.0f, 1.0f ); - - FMOD::ChannelGroup *master_group; - mSystem->getMasterChannelGroup(&master_group); - - master_group->setVolume(gain); - - LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); - if ( saimpl ) - { - // fmod likes its streaming audio channel gain re-asserted after - // master volume change. - saimpl->setGain(saimpl->getGain()); - } -} - -// -// LLAudioChannelFMODEX implementation -// - -LLAudioChannelFMODEX::LLAudioChannelFMODEX(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0) -{ -} - - -LLAudioChannelFMODEX::~LLAudioChannelFMODEX() -{ - cleanup(); -} - -bool LLAudioChannelFMODEX::updateBuffer() -{ - if (LLAudioChannel::updateBuffer()) - { - // Base class update returned true, which means that we need to actually - // set up the channel for a different buffer. - - LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentSourcep->getCurrentBuffer(); - - // Grab the FMOD sample associated with the buffer - FMOD::Sound *soundp = bufferp->getSound(); - if (!soundp) - { - // This is bad, there should ALWAYS be a sound associated with a legit - // buffer. - LL_ERRS() << "No FMOD sound!" << LL_ENDL; - return false; - } - - - // Actually play the sound. Start it off paused so we can do all the necessary - // setup. - if(!mChannelp) - { - FMOD_RESULT result = getSystem()->playSound(FMOD_CHANNEL_FREE, soundp, true, &mChannelp); - Check_FMOD_Error(result, "FMOD::System::playSound"); - } - - //LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL; - } - - // If we have a source for the channel, we need to update its gain. - if (mCurrentSourcep) - { - // SJB: warnings can spam and hurt framerate, disabling - //FMOD_RESULT result; - - mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); - //Check_FMOD_Error(result, "FMOD::Channel::setVolume"); - - mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); - /*if(Check_FMOD_Error(result, "FMOD::Channel::setMode")) - { - S32 index; - mChannelp->getIndex(&index); - LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID() - << " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL; - }*/ - } - - return true; -} - - -void LLAudioChannelFMODEX::update3DPosition() -{ - if (!mChannelp) - { - // We're not actually a live channel (i.e., we're not playing back anything) - return; - } - - LLAudioBufferFMODEX *bufferp = (LLAudioBufferFMODEX *)mCurrentBufferp; - if (!bufferp) - { - // We don't have a buffer associated with us (should really have been picked up - // by the above if. - return; - } - - if (mCurrentSourcep->isAmbient()) - { - // Ambient sound, don't need to do any positional updates. - set3DMode(false); - } - else - { - // Localized sound. Update the position and velocity of the sound. - set3DMode(true); - - LLVector3 float_pos; - float_pos.setVec(mCurrentSourcep->getPositionGlobal()); - FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV); - Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes"); - } -} - - -void LLAudioChannelFMODEX::updateLoop() -{ - if (!mChannelp) - { - // May want to clear up the loop/sample counters. - return; - } - - // - // Hack: We keep track of whether we looped or not by seeing when the - // sample position looks like it's going backwards. Not reliable; may - // yield false negatives. - // - U32 cur_pos; - mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES); - - if (cur_pos < (U32)mLastSamplePos) - { - mLoopedThisFrame = true; - } - mLastSamplePos = cur_pos; -} - - -void LLAudioChannelFMODEX::cleanup() -{ - if (!mChannelp) - { - //LL_INFOS() << "Aborting cleanup with no channel handle." << LL_ENDL; - return; - } - - //LL_INFOS() << "Cleaning up channel: " << mChannelID << LL_ENDL; - Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"); - - mCurrentBufferp = NULL; - mChannelp = NULL; -} - - -void LLAudioChannelFMODEX::play() -{ - if (!mChannelp) - { - LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; - return; - } - - Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause"); - - getSource()->setPlayedOnce(true); - - if(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]) - mChannelp->setChannelGroup(LLAudioEngine_FMODEX::mChannelGroups[getSource()->getType()]); -} - - -void LLAudioChannelFMODEX::playSynced(LLAudioChannel *channelp) -{ - LLAudioChannelFMODEX *fmod_channelp = (LLAudioChannelFMODEX*)channelp; - if (!(fmod_channelp->mChannelp && mChannelp)) - { - // Don't have channels allocated to both the master and the slave - return; - } - - U32 cur_pos; - if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position")) - return; - - cur_pos %= mCurrentBufferp->getLength(); - - // Try to match the position of our sync master - Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position"); - - // Start us playing - play(); -} - - -bool LLAudioChannelFMODEX::isPlaying() -{ - if (!mChannelp) - { - return false; - } - - bool paused, playing; - mChannelp->getPaused(&paused); - mChannelp->isPlaying(&playing); - return !paused && playing; -} - - -// -// LLAudioChannelFMODEX implementation -// - - -LLAudioBufferFMODEX::LLAudioBufferFMODEX(FMOD::System *system) : mSystemp(system), mSoundp(NULL) -{ -} - - -LLAudioBufferFMODEX::~LLAudioBufferFMODEX() -{ - if(mSoundp) - { - mSoundp->release(); - mSoundp = NULL; - } -} - - -bool LLAudioBufferFMODEX::loadWAV(const std::string& filename) -{ - // Try to open a wav file from disk. This will eventually go away, as we don't - // really want to block doing this. - if (filename.empty()) - { - // invalid filename, abort. - return false; - } - - if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB)) - { - // File not found, abort. - return false; - } - - if (mSoundp) - { - // If there's already something loaded in this buffer, clean it up. - mSoundp->release(); - mSoundp = NULL; - } - - FMOD_MODE base_mode = FMOD_LOOP_NORMAL | FMOD_SOFTWARE; - FMOD_CREATESOUNDEXINFO exinfo; - memset(&exinfo,0,sizeof(exinfo)); - exinfo.cbsize = sizeof(exinfo); - exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading. - // Load up the wav file into an fmod sample -#if LL_WINDOWS - FMOD_RESULT result = getSystem()->createSound((const char*)utf8str_to_utf16str(filename).c_str(), base_mode | FMOD_UNICODE, &exinfo, &mSoundp); -#else - FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); -#endif - - if (result != FMOD_OK) - { - // We failed to load the file for some reason. - LL_WARNS() << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << LL_ENDL; - - // - // If we EVER want to load wav files provided by end users, we need - // to rethink this! - // - // file is probably corrupt - remove it. - LLFile::remove(filename); - return false; - } - - // Everything went well, return true - return true; -} - - -U32 LLAudioBufferFMODEX::getLength() -{ - if (!mSoundp) - { - return 0; - } - - U32 length; - mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES); - return length; -} - - -void LLAudioChannelFMODEX::set3DMode(bool use3d) -{ - FMOD_MODE current_mode; - if(mChannelp->getMode(¤t_mode) != FMOD_OK) - return; - FMOD_MODE new_mode = current_mode; - new_mode &= ~(use3d ? FMOD_2D : FMOD_3D); - new_mode |= use3d ? FMOD_3D : FMOD_2D; - - if(current_mode != new_mode) - { - mChannelp->setMode(new_mode); - } -} - -// *NOTE: This is almost certainly being called on the mixer thread, -// not the main thread. May have implications for callees or audio -// engine shutdown. - -FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *originalbuffer, float *newbuffer, unsigned int length, int inchannels, int outchannels) -{ - // originalbuffer = fmod's original mixbuffer. - // newbuffer = the buffer passed from the previous DSP unit. - // length = length in samples at this mix time. - // userdata = user parameter passed through in FSOUND_DSP_Create. - - LLWindGen<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_fmodstudio.cpp b/indra/llaudio/llaudioengine_fmodstudio.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c1a29c4d0a00d324003dbbb0caf958ce5b0d8bb --- /dev/null +++ b/indra/llaudio/llaudioengine_fmodstudio.cpp @@ -0,0 +1,744 @@ +/** + * @file audioengine_fmodstudio.cpp + * @brief Implementation of LLAudioEngine class abstracting the audio + * support as a FMOD Studio implementation + * + * $LicenseInfo:firstyear=2014&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2014, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llstreamingaudio.h" +#include "llstreamingaudio_fmodstudio.h" + +#include "llaudioengine_fmodstudio.h" +#include <utility> +#include "lllistener_fmodstudio.h" + +#include "llerror.h" +#include "llmath.h" +#include "llrand.h" + +#include "fmod.hpp" +#include "fmod_errors.h" +#include "lldir.h" + +#include "sound_ids.h" + +const U32 EXTRA_SOUND_CHANNELS = 32; + +FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels); + +FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {nullptr}; + +LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(std::string app_name, bool enable_profiler, U32 resample_method) + : mInited(false) + , mWindGen(nullptr) + , mWindDSPDesc(nullptr) + , mWindDSP(nullptr) + , mSystem(nullptr) + , mEnableProfiler(enable_profiler) + , mResampleMethod(resample_method) + , mAppName(std::move(app_name)) +{ +} + +LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO() +{ +} + +inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string) +{ + if(result == FMOD_OK) + return false; + LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + return true; +} + +bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata) +{ + U32 version; + FMOD_RESULT result; + + LL_DEBUGS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() initializing FMOD" << LL_ENDL; + + result = FMOD::System_Create(&mSystem); + if(Check_FMOD_Error(result, "FMOD::System_Create")) + return false; + + //will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer. + LLAudioEngine::init(num_channels, userdata); + + result = mSystem->getVersion(&version); + Check_FMOD_Error(result, "FMOD::System::getVersion"); + + if (version < FMOD_VERSION) + { + LL_WARNS("AppInit") << "Error : You are using the wrong FMOD Studio version (" << version + << ")! You should be using FMOD Studio" << FMOD_VERSION << LL_ENDL; + } + + // In this case, all sounds, PLUS wind and stream will be software. + result = mSystem->setSoftwareChannels(num_channels + EXTRA_SOUND_CHANNELS); + Check_FMOD_Error(result,"FMOD::System::setSoftwareChannels"); + + FMOD_ADVANCEDSETTINGS adv_settings = { }; + adv_settings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS); + switch (mResampleMethod) + { + default: + case RESAMPLE_LINEAR: + adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_LINEAR; + break; + case RESAMPLE_CUBIC: + adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_CUBIC; + break; + case RESAMPLE_SPLINE: + adv_settings.resamplerMethod = FMOD_DSP_RESAMPLER_SPLINE; + break; + } + + result = mSystem->setAdvancedSettings(&adv_settings); + Check_FMOD_Error(result, "FMOD::System::setAdvancedSettings"); + + U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE; + if(mEnableProfiler) + { + fmod_flags |= FMOD_INIT_PROFILE_ENABLE; + } + +#if LL_LINUX + bool audio_ok = false; + + if (!audio_ok) + { + if (NULL == getenv("LL_BAD_FMOD_PULSEAUDIO")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL; + if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO)) == FMOD_OK && + (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, const_cast<char*>(mAppName.c_str()))) == FMOD_OK) + { + LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } + else + { + Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize"); + } + } + else + { + LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL; + } + } + if (!audio_ok) + { + if (NULL == getenv("LL_BAD_FMOD_ALSA")) /*Flawfinder: ignore*/ + { + LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL; + if((result = mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA)) == FMOD_OK && + (result = mSystem->init(num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, 0)) == FMOD_OK) + { + LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL; + audio_ok = true; + } + else + { + Check_FMOD_Error(result, "ALSA audio output FAILED to initialize"); + } + } + else + { + LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL; + } + } + if (!audio_ok) + { + LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL; + return false; + } + + // We're interested in logging which output method we + // ended up with, for QA purposes. + FMOD_OUTPUTTYPE output_type; + if(!Check_FMOD_Error(mSystem->getOutput(&output_type), "FMOD::System::getOutput")) + { + switch (output_type) + { + case FMOD_OUTPUTTYPE_NOSOUND: + LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_PULSEAUDIO: + LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break; + case FMOD_OUTPUTTYPE_ALSA: + LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break; + default: + LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break; + }; + } +#else // LL_LINUX + + // initialize the FMOD engine + result = mSystem->init( num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, nullptr); + if (result == FMOD_ERR_OUTPUT_CREATEBUFFER) + { + /* + Ok, the speaker mode selected isn't supported by this soundcard. Switch it + back to stereo... + */ + result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0); + Check_FMOD_Error(result,"Error falling back to stereo mode"); + /* + ... and re-init. + */ + result = mSystem->init( num_channels + EXTRA_SOUND_CHANNELS, fmod_flags, nullptr); + } + if(Check_FMOD_Error(result, "Error initializing FMOD Studio")) + return false; +#endif + + if (mEnableProfiler) + { + Check_FMOD_Error(mSystem->createChannelGroup("None", &mChannelGroups[AUDIO_TYPE_NONE]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("SFX", &mChannelGroups[AUDIO_TYPE_SFX]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("UI", &mChannelGroups[AUDIO_TYPE_UI]), "FMOD::System::createChannelGroup"); + Check_FMOD_Error(mSystem->createChannelGroup("Ambient", &mChannelGroups[AUDIO_TYPE_AMBIENT]), "FMOD::System::createChannelGroup"); + } + + // set up our favourite FMOD-native streaming audio implementation if none has already been added + if (!getStreamingAudioImpl()) // no existing implementation added + setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem)); + + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL; + + FMOD_ADVANCEDSETTINGS adv_settings_dump = { }; + mSystem->getAdvancedSettings(&adv_settings_dump); + + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): resampler=" << adv_settings.resamplerMethod << " bytes" << LL_ENDL; + + int r_numbuffers, r_samplerate, r_channels; + unsigned int r_bufferlength; + mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers); + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_numbuffers=" << r_numbuffers << LL_ENDL; + + char r_name[512]; + mSystem->getDriverInfo(0, r_name, 511, nullptr, &r_samplerate, nullptr, &r_channels); + r_name[511] = '\0'; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_name=\"" << r_name << "\"" << LL_ENDL; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL; + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_channels=" << r_channels << LL_ENDL; + + int latency = 100; // optimistic default - i suspect if sample rate is 0, everything breaks. + if ( r_samplerate != 0 ) + latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate); + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): latency=" << latency << "ms" << LL_ENDL; + + mInited = true; + + LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): initialization complete." << LL_ENDL; + + return true; +} + + +std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose) +{ + llassert_always(mSystem); + if (verbose) + { + U32 version; + if(!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion")) + { + return llformat("FMOD Studio %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF); + } + } + return "FMOD Studio"; +} + + +void LLAudioEngine_FMODSTUDIO::allocateListener(void) +{ + try + { + mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem); + } + catch (const std::bad_alloc& e) + { + LL_WARNS() << "Listener allocation failed due to: " << e.what() << LL_ENDL; + } + +} + + +void LLAudioEngine_FMODSTUDIO::shutdown() +{ + LL_INFOS() << "About to LLAudioEngine::shutdown()" << LL_ENDL; + LLAudioEngine::shutdown(); + + LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL; + if ( mSystem ) // speculative fix for MAINT-2657 + { + Check_FMOD_Error(mSystem->close(), "FMOD::System::close"); + Check_FMOD_Error(mSystem->release(), "FMOD::System::release"); + } + LL_INFOS() << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL; + + delete mListenerp; + mListenerp = nullptr; +} + + +LLAudioBuffer * LLAudioEngine_FMODSTUDIO::createBuffer() +{ + return new LLAudioBufferFMODSTUDIO(mSystem); +} + + +LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel() +{ + return new LLAudioChannelFMODSTUDIO(mSystem); +} + +bool LLAudioEngine_FMODSTUDIO::initWind() +{ + mNextWindUpdate = 0.0; + + cleanupWind(); + + mWindDSPDesc = new FMOD_DSP_DESCRIPTION(); + memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero + mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; + strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name)); //Set name to "Wind Unit" + mWindDSPDesc->numoutputbuffers = 1; + mWindDSPDesc->read = &windDSPCallback; //Assign callback. + if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP") || !mWindDSP) + return false; + + int frequency = 44100; + FMOD_SPEAKERMODE mode; + if (!Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, nullptr), "FMOD::System::getSoftwareFormat")) + { + mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency); + + if (!Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData") && + !Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat") && + !Check_FMOD_Error(mSystem->playDSP(mWindDSP, nullptr, false, nullptr), "FMOD::System::playDSP")) + return true; //Success + } + + cleanupWind(); + return false; +} + + +void LLAudioEngine_FMODSTUDIO::cleanupWind() +{ + if (mWindDSP) + { + FMOD::ChannelGroup* mastergroup = nullptr; + if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&mastergroup), "FMOD::System::getMasterChannelGroup") && mastergroup) + Check_FMOD_Error(mastergroup->removeDSP(mWindDSP), "FMOD::ChannelGroup::removeDSP"); + Check_FMOD_Error(mWindDSP->release(), "FMOD::DSP::release"); + mWindDSP = nullptr; + } + + delete mWindDSPDesc; + mWindDSPDesc = nullptr; + + delete mWindGen; + mWindGen = nullptr; +} + + +//----------------------------------------------------------------------- +void LLAudioEngine_FMODSTUDIO::updateWind(LLVector3 wind_vec, F32 camera_height_above_water) +{ + LLVector3 wind_pos; + F64 pitch; + F64 center_freq; + + if (!mEnableWind) + { + return; + } + + if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL)) + { + + // wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up) + // need to convert this to the conventional orientation DS3D and OpenAL use + // where +X = right, +Y = up, +Z = backwards + + wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]); + + // cerr << "Wind update" << endl; + + pitch = 1.0 + mapWindVecToPitch(wind_vec); + center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0)); + + mWindGen->mTargetFreq = (F32)center_freq; + mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain; + mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec); + } +} + +//----------------------------------------------------------------------- +void LLAudioEngine_FMODSTUDIO::setInternalGain(F32 gain) +{ + if (!mInited) + { + return; + } + + gain = llclamp( gain, 0.0f, 1.0f ); + + FMOD::ChannelGroup *master_group; + if(Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")) + return; + + master_group->setVolume(gain); + + LLStreamingAudioInterface *saimpl = getStreamingAudioImpl(); + if ( saimpl ) + { + // fmod likes its streaming audio channel gain re-asserted after + // master volume change. + saimpl->setGain(saimpl->getGain()); + } +} + +// +// LLAudioChannelFMODSTUDIO implementation +// + +LLAudioChannelFMODSTUDIO::LLAudioChannelFMODSTUDIO(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(nullptr), mLastSamplePos(0) +{ +} + + +LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO() +{ + cleanup(); +} + +bool LLAudioChannelFMODSTUDIO::updateBuffer() +{ + if (mCurrentSourcep) + { + if (LLAudioChannel::updateBuffer()) + { + // Base class update returned true, which means that we need to actually + // set up the channel for a different buffer. + + LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *) mCurrentSourcep->getCurrentBuffer(); + + // Grab the FMOD sample associated with the buffer + FMOD::Sound *soundp = bufferp->getSound(); + if (!soundp) + { + // This is bad, there should ALWAYS be a sound associated with a legit + // buffer. + LL_ERRS() << "No FMOD sound!" << LL_ENDL; + return false; + } + + + // Actually play the sound. Start it off paused so we can do all the necessary + // setup. + if (!mChannelp) + { + FMOD_RESULT result = getSystem()->playSound(soundp, nullptr, true, &mChannelp); + Check_FMOD_Error(result, "FMOD::System::playSound"); + } + + //LL_INFOS() << "Setting up channel " << std::hex << mChannelID << std::dec << LL_ENDL; + } + + //FMOD_RESULT result; + + mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain()); + //Check_FMOD_Error(result, "FMOD::Channel::setVolume"); + + mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); + /*if(Check_FMOD_Error(result, "FMOD::Channel::setMode")) + { + S32 index; + mChannelp->getIndex(&index); + LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID() + << " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL; + }*/ + } + else + { + LL_DEBUGS() << "No source buffer!" << LL_ENDL; + return false; + } + + return true; +} + + +void LLAudioChannelFMODSTUDIO::update3DPosition() +{ + if (!mChannelp) + { + // We're not actually a live channel (i.e., we're not playing back anything) + return; + } + + LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentBufferp; + if (!bufferp) + { + // We don't have a buffer associated with us (should really have been picked up + // by the above if. + return; + } + + if (mCurrentSourcep->isAmbient()) + { + // Ambient sound, don't need to do any positional updates. + set3DMode(false); + } + else + { + // Localized sound. Update the position and velocity of the sound. + set3DMode(true); + + LLVector3 float_pos; + float_pos.setVec(mCurrentSourcep->getPositionGlobal()); + FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV); + Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes"); + } +} + + +void LLAudioChannelFMODSTUDIO::updateLoop() +{ + if (!mChannelp) + { + // May want to clear up the loop/sample counters. + return; + } + + // + // Hack: We keep track of whether we looped or not by seeing when the + // sample position looks like it's going backwards. Not reliable; may + // yield false negatives. + // + U32 cur_pos; + Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES),"FMOD::Channel::getPosition"); + + if (cur_pos < (U32)mLastSamplePos) + { + mLoopedThisFrame = true; + } + mLastSamplePos = cur_pos; +} + + +void LLAudioChannelFMODSTUDIO::cleanup() +{ + if (!mChannelp) + { + //LL_INFOS() << "Aborting cleanup with no channel handle." << LL_ENDL; + return; + } + + //LL_INFOS() << "Cleaning up channel: " << mChannelID << LL_ENDL; + Check_FMOD_Error(mChannelp->stop(),"FMOD::Channel::stop"); + + mCurrentBufferp = nullptr; + mChannelp = nullptr; +} + + +void LLAudioChannelFMODSTUDIO::play() +{ + if (!mChannelp) + { + LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL; + return; + } + + Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::setPaused"); + + getSource()->setPlayedOnce(true); + + if(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]) + Check_FMOD_Error(mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]),"FMOD::Channel::setChannelGroup"); +} + + +void LLAudioChannelFMODSTUDIO::playSynced(LLAudioChannel *channelp) +{ + LLAudioChannelFMODSTUDIO *fmod_channelp = (LLAudioChannelFMODSTUDIO*)channelp; + if (!(fmod_channelp->mChannelp && mChannelp)) + { + // Don't have channels allocated to both the master and the slave + return; + } + + U32 cur_pos; + if(Check_FMOD_Error(mChannelp->getPosition(&cur_pos,FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position")) + return; + + cur_pos %= mCurrentBufferp->getLength(); + + // Try to match the position of our sync master + Check_FMOD_Error(mChannelp->setPosition(cur_pos,FMOD_TIMEUNIT_PCMBYTES),"Unable to set current position"); + + // Start us playing + play(); +} + + +bool LLAudioChannelFMODSTUDIO::isPlaying() +{ + if (!mChannelp) + { + return false; + } + + bool paused, playing; + Check_FMOD_Error(mChannelp->getPaused(&paused),"FMOD::Channel::getPaused"); + Check_FMOD_Error(mChannelp->isPlaying(&playing),"FMOD::Channel::isPlaying"); + return !paused && playing; +} + + +// +// LLAudioChannelFMODSTUDIO implementation +// + + +LLAudioBufferFMODSTUDIO::LLAudioBufferFMODSTUDIO(FMOD::System *system) : mSystemp(system), mSoundp(nullptr) +{ +} + + +LLAudioBufferFMODSTUDIO::~LLAudioBufferFMODSTUDIO() +{ + if(mSoundp) + { + Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::Release"); + mSoundp = nullptr; + } +} + + +bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename) +{ + // Try to open a wav file from disk. This will eventually go away, as we don't + // really want to block doing this. + if (filename.empty()) + { + // invalid filename, abort. + return false; + } + + if (!gDirUtilp->fileExists(filename)) + { + // File not found, abort. + return false; + } + + if (mSoundp) + { + // If there's already something loaded in this buffer, clean it up. + Check_FMOD_Error(mSoundp->release(),"FMOD::Sound::release"); + mSoundp = nullptr; + } + + FMOD_MODE base_mode = FMOD_LOOP_NORMAL; + FMOD_CREATESOUNDEXINFO exinfo = { }; + exinfo.cbsize = sizeof(exinfo); + exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading. + // Load up the wav file into an fmod sample + FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp); + if (result != FMOD_OK) + { + // We failed to load the file for some reason. + LL_WARNS() << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << LL_ENDL; + + // + // If we EVER want to load wav files provided by end users, we need + // to rethink this! + // + // file is probably corrupt - remove it. + LLFile::remove(filename); + return false; + } + + // Everything went well, return true + return true; +} + + +U32 LLAudioBufferFMODSTUDIO::getLength() +{ + if (!mSoundp) + { + return 0; + } + + U32 length; + Check_FMOD_Error(mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES),"FMOD::Sound::getLength"); + return length; +} + + +void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d) +{ + FMOD_MODE current_mode; + if(Check_FMOD_Error(mChannelp->getMode(¤t_mode),"FMOD::Channel::getMode")) + return; + FMOD_MODE new_mode = current_mode; + new_mode &= ~(use3d ? FMOD_2D : FMOD_3D); + new_mode |= use3d ? FMOD_3D : FMOD_2D; + + if(current_mode != new_mode) + { + Check_FMOD_Error(mChannelp->setMode(new_mode),"FMOD::Channel::setMode"); + } +} + +// *NOTE: This is almost certainly being called on the mixer thread, +// not the main thread. May have implications for callees or audio +// engine shutdown. + +FMOD_RESULT F_CALLBACK windDSPCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) +{ + // inbuffer = incomming data. + // newbuffer = outgoing data. AKA this DSP's output. + // length = length in samples at this mix time. True buffer size, in bytes, would be (length * sizeof(float) * inchannels). + // userdata = user-provided data attached this DSP via FMOD::DSP::setUserData. + + LLWindGen<LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT> *windgen; + FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance; + + thisdsp->getUserData((void **)&windgen); + + if (windgen) + windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length); + + return FMOD_OK; +} diff --git a/indra/llaudio/llaudioengine_fmodex.h b/indra/llaudio/llaudioengine_fmodstudio.h similarity index 51% rename from indra/llaudio/llaudioengine_fmodex.h rename to indra/llaudio/llaudioengine_fmodstudio.h index ca389d489fd981359e666ae50b250668a7489c90..16e287cd92db3f7bbe634802ba44d9b4d8ac894c 100644 --- a/indra/llaudio/llaudioengine_fmodex.h +++ b/indra/llaudio/llaudioengine_fmodstudio.h @@ -1,7 +1,7 @@ /** - * @file audioengine_fmodex.h + * @file audioengine_fmodstudio.h * @brief Definition of LLAudioEngine class abstracting the audio - * support as a FMODEX implementation + * support as a FMOD Studio implementation * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code @@ -25,14 +25,14 @@ * $/LicenseInfo$ */ -#ifndef LL_AUDIOENGINE_FMODEX_H -#define LL_AUDIOENGINE_FMODEX_H +#ifndef LL_AUDIOENGINE_FMODSTUDIO_H +#define LL_AUDIOENGINE_FMODSTUDIO_H #include "llaudioengine.h" #include "llwindgen.h" //Stubs -class LLAudioStreamManagerFMODEX; +class LLAudioStreamManagerFMODSTUDIO; namespace FMOD { class System; @@ -44,32 +44,38 @@ namespace FMOD typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION; //Interfaces -class LLAudioEngine_FMODEX : public LLAudioEngine +class LLAudioEngine_FMODSTUDIO final : public LLAudioEngine { public: - LLAudioEngine_FMODEX(bool enable_profiler); - virtual ~LLAudioEngine_FMODEX(); + enum + { + RESAMPLE_LINEAR=0, + RESAMPLE_CUBIC, + RESAMPLE_SPLINE + }; + LLAudioEngine_FMODSTUDIO(std::string app_name, bool enable_profiler, U32 resample_method); + virtual ~LLAudioEngine_FMODSTUDIO(); // initialization/startup/shutdown - virtual bool init(const S32 num_channels, void *user_data); - virtual std::string getDriverName(bool verbose); - virtual void allocateListener(); + bool init(const S32 num_channels, void *user_data) final override; + std::string getDriverName(bool verbose) final override; + void allocateListener() final override; - virtual void shutdown(); + void shutdown() final override; - /*virtual*/ bool initWind(); - /*virtual*/ void cleanupWind(); + /*virtual*/ bool initWind() final override; + /*virtual*/ void cleanupWind() final override; - /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water); + /*virtual*/void updateWind(LLVector3 direction, F32 camera_height_above_water) final override; 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*/ LLAudioBuffer *createBuffer() final override; // Get a free buffer, or flush an existing one if you have to. + /*virtual*/ LLAudioChannel *createChannel() final override; // Create a new audio channel. - /*virtual*/ void setInternalGain(F32 gain); + /*virtual*/ void setInternalGain(F32 gain) final override; bool mInited; @@ -79,27 +85,29 @@ class LLAudioEngine_FMODEX : public LLAudioEngine FMOD::DSP *mWindDSP; FMOD::System *mSystem; bool mEnableProfiler; + U32 mResampleMethod; + std::string mAppName; public: static FMOD::ChannelGroup *mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT]; }; -class LLAudioChannelFMODEX : public LLAudioChannel +class LLAudioChannelFMODSTUDIO final : public LLAudioChannel { public: - LLAudioChannelFMODEX(FMOD::System *audioengine); - virtual ~LLAudioChannelFMODEX(); + LLAudioChannelFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioChannelFMODSTUDIO(); protected: - /*virtual*/ void play(); - /*virtual*/ void playSynced(LLAudioChannel *channelp); - /*virtual*/ void cleanup(); - /*virtual*/ bool isPlaying(); + /*virtual*/ void play() final override; + /*virtual*/ void playSynced(LLAudioChannel *channelp) final override; + /*virtual*/ void cleanup() final override; + /*virtual*/ bool isPlaying() final override; - /*virtual*/ bool updateBuffer(); - /*virtual*/ void update3DPosition(); - /*virtual*/ void updateLoop(); + /*virtual*/ bool updateBuffer() final override; + /*virtual*/ void update3DPosition() final override; + /*virtual*/ void updateLoop() final override; void set3DMode(bool use3d); protected: @@ -110,15 +118,15 @@ class LLAudioChannelFMODEX : public LLAudioChannel }; -class LLAudioBufferFMODEX : public LLAudioBuffer +class LLAudioBufferFMODSTUDIO final : public LLAudioBuffer { public: - LLAudioBufferFMODEX(FMOD::System *audioengine); - virtual ~LLAudioBufferFMODEX(); + LLAudioBufferFMODSTUDIO(FMOD::System *audioengine); + virtual ~LLAudioBufferFMODSTUDIO(); - /*virtual*/ bool loadWAV(const std::string& filename); - /*virtual*/ U32 getLength(); - friend class LLAudioChannelFMODEX; + /*virtual*/ bool loadWAV(const std::string& filename) final override; + /*virtual*/ U32 getLength() final override; + friend class LLAudioChannelFMODSTUDIO; protected: FMOD::System *getSystem() const {return mSystemp;} FMOD::System *mSystemp; @@ -127,4 +135,4 @@ class LLAudioBufferFMODEX : public LLAudioBuffer }; -#endif // LL_AUDIOENGINE_FMODEX_H +#endif // LL_AUDIOENGINE_FMODSTUDIO_H diff --git a/indra/llaudio/llaudioengine_openal.cpp b/indra/llaudio/llaudioengine_openal.cpp index e6ac586618e3cb2855e76a3b308c2a6ab181a8c4..40600f9be0a9d34eaeefbbce8f5ff20c00fa7f1f 100644 --- a/indra/llaudio/llaudioengine_openal.cpp +++ b/indra/llaudio/llaudioengine_openal.cpp @@ -46,11 +46,6 @@ LLAudioEngine_OpenAL::LLAudioEngine_OpenAL() { } -// virtual -LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL() -{ -} - // virtual bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata) { diff --git a/indra/llaudio/llaudioengine_openal.h b/indra/llaudio/llaudioengine_openal.h index 6639d9dfe648772a5b718c552284765463cffbcf..32b652ffe1be9c9e434363f44355d15796b563b8 100644 --- a/indra/llaudio/llaudioengine_openal.h +++ b/indra/llaudio/llaudioengine_openal.h @@ -38,7 +38,7 @@ class LLAudioEngine_OpenAL : public LLAudioEngine { public: LLAudioEngine_OpenAL(); - virtual ~LLAudioEngine_OpenAL(); + virtual ~LLAudioEngine_OpenAL() = default; virtual bool init(const S32 num_channels, void *user_data); virtual std::string getDriverName(bool verbose); diff --git a/indra/llaudio/lllistener.cpp b/indra/llaudio/lllistener.cpp index df2366c8c21dda56892e436cadd8f2e4ee7580f8..08e58111d0db59b21fd57059c55a79b5f7171591 100644 --- a/indra/llaudio/lllistener.cpp +++ b/indra/llaudio/lllistener.cpp @@ -35,32 +35,21 @@ // constructor //----------------------------------------------------------------------- LLListener::LLListener() + : mPosition(LLVector3::zero), + mVelocity(LLVector3::zero), + mListenAt(DEFAULT_AT), + mListenUp(DEFAULT_UP) { - init(); } //----------------------------------------------------------------------- -LLListener::~LLListener() -{ -} - -//----------------------------------------------------------------------- -void LLListener::init(void) -{ - mPosition.zeroVec(); - mListenAt.setVec(DEFAULT_AT); - mListenUp.setVec(DEFAULT_UP); - mVelocity.zeroVec(); -} - -//----------------------------------------------------------------------- -void LLListener::translate(LLVector3 offset) +void LLListener::translate(const LLVector3& offset) { mPosition += offset; } //----------------------------------------------------------------------- -void LLListener::setPosition(LLVector3 pos) +void LLListener::setPosition(const LLVector3& pos) { mPosition = pos; } @@ -84,24 +73,21 @@ LLVector3 LLListener::getUp(void) } //----------------------------------------------------------------------- -void LLListener::setVelocity(LLVector3 vel) +void LLListener::setVelocity(const LLVector3& vel) { mVelocity = vel; } //----------------------------------------------------------------------- -void LLListener::orient(LLVector3 up, LLVector3 at) +void LLListener::orient(const LLVector3& up, const LLVector3& at) { mListenUp = up; mListenAt = at; } //----------------------------------------------------------------------- -void LLListener::set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at) +void LLListener::set(const LLVector3& pos, const LLVector3& vel, const LLVector3& up, const LLVector3& at) { - mPosition = pos; - mVelocity = vel; - setPosition(pos); setVelocity(vel); orient(up,at); diff --git a/indra/llaudio/lllistener.h b/indra/llaudio/lllistener.h index 41836bf03999cffa1d453a49f5f6619b3f6039ce..806ac9c4356eeb590109eca2dd285c71b639a3f8 100644 --- a/indra/llaudio/lllistener.h +++ b/indra/llaudio/lllistener.h @@ -44,16 +44,15 @@ class LLListener protected: public: LLListener(); - virtual ~LLListener(); - virtual void init(); + virtual ~LLListener() = default; - virtual void set(LLVector3 pos, LLVector3 vel, LLVector3 up, LLVector3 at); + virtual void set(const LLVector3& pos, const LLVector3& vel, const LLVector3& up, const LLVector3& at); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); + virtual void setPosition(const LLVector3& pos); + virtual void setVelocity(const LLVector3& vel); - virtual void orient(LLVector3 up, LLVector3 at); - virtual void translate(LLVector3 offset); + virtual void orient(const LLVector3& up, const LLVector3& at); + virtual void translate(const LLVector3& offset); virtual void setDopplerFactor(F32 factor); virtual void setRolloffFactor(F32 factor); diff --git a/indra/llaudio/lllistener_ds3d.h b/indra/llaudio/lllistener_ds3d.h deleted file mode 100644 index 9150ccd5b929a9f48c6b27467120df18ffd29e66..0000000000000000000000000000000000000000 --- a/indra/llaudio/lllistener_ds3d.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file listener_ds3d.h - * @brief Description of LISTENER class abstracting the audio support - * as a DirectSound 3D implementation (windows only) - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LISTENER_DS3D_H -#define LL_LISTENER_DS3D_H - -#include "lllistener.h" - -#include <dmusici.h> -#include <dsound.h> -#include <ks.h> - -class LLListener_DS3D : public LLListener -{ - private: - protected: - IDirectSound3DListener8 *m3DListener; - public: - - private: - protected: - public: - LLListener_DS3D(); - virtual ~LLListener_DS3D(); - virtual void init(); - - virtual void setDS3DLPtr (IDirectSound3DListener8 *listener_p); - - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); - - virtual void commitDeferredChanges(); -}; - -#endif - - diff --git a/indra/llaudio/lllistener_fmodex.cpp b/indra/llaudio/lllistener_fmodstudio.cpp similarity index 56% rename from indra/llaudio/lllistener_fmodex.cpp rename to indra/llaudio/lllistener_fmodstudio.cpp index 31ab47a635f34d93fd1ee3e85676c785affa0e28..3a9fb8f157e34cf4bfa75223c2643601e51bca3a 100644 --- a/indra/llaudio/lllistener_fmodex.cpp +++ b/indra/llaudio/lllistener_fmodstudio.cpp @@ -1,7 +1,7 @@ /** - * @file listener_fmodex.cpp + * @file listener_fmodstudio.cpp * @brief Implementation of LISTENER class abstracting the audio - * support as a FMODEX implementation + * support as a FMOD Studio implementation * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code @@ -27,72 +27,54 @@ #include "linden_common.h" #include "llaudioengine.h" -#include "lllistener_fmodex.h" +#include "lllistener_fmodstudio.h" #include "fmod.hpp" //----------------------------------------------------------------------- // constructor //----------------------------------------------------------------------- -LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system) +LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system) + : LLListener(), + mDopplerFactor(1.0f), + mRolloffFactor(1.0f) { mSystem = system; - init(); } //----------------------------------------------------------------------- -LLListener_FMODEX::~LLListener_FMODEX() -{ -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::init(void) -{ - // do inherited - LLListener::init(); - mDopplerFactor = 1.0f; - mRolloffFactor = 1.0f; -} - -//----------------------------------------------------------------------- -void LLListener_FMODEX::translate(LLVector3 offset) +void LLListener_FMODSTUDIO::translate(const LLVector3& offset) { LLListener::translate(offset); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, nullptr, nullptr, nullptr); } //----------------------------------------------------------------------- -void LLListener_FMODEX::setPosition(LLVector3 pos) +void LLListener_FMODSTUDIO::setPosition(const LLVector3& pos) { LLListener::setPosition(pos); - mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, nullptr, nullptr, nullptr); } //----------------------------------------------------------------------- -void LLListener_FMODEX::setVelocity(LLVector3 vel) +void LLListener_FMODSTUDIO::setVelocity(const LLVector3& vel) { LLListener::setVelocity(vel); - mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV); + mSystem->set3DListenerAttributes(0, nullptr, (FMOD_VECTOR*)mVelocity.mV, nullptr, nullptr); } //----------------------------------------------------------------------- -void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at) +void LLListener_FMODSTUDIO::orient(const LLVector3& up, const LLVector3& at) { LLListener::orient(up, at); - // Welcome to the transition between right and left - // (coordinate systems, that is) - // Leaving the at vector alone results in a L/R reversal - // since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed - at = -at; - - mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); + mSystem->set3DListenerAttributes(0, nullptr, nullptr, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV); } //----------------------------------------------------------------------- -void LLListener_FMODEX::commitDeferredChanges() +void LLListener_FMODSTUDIO::commitDeferredChanges() { if(!mSystem) { @@ -103,36 +85,36 @@ void LLListener_FMODEX::commitDeferredChanges() } -void LLListener_FMODEX::setRolloffFactor(F32 factor) +void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor) { - //An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment. + //An internal FMOD Studio optimization skips 3D updates if there have not been changes to the 3D sound environment. //Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well. - //In short: Changing the position ticks a dirtyflag inside fmodex, which makes it not skip 3D processing next update call. + //In short: Changing the position ticks a dirtyflag inside fmod studio, which makes it not skip 3D processing next update call. if(mRolloffFactor != factor) { - LLVector3 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); + LLVector3 tmp_pos = mPosition - LLVector3(0.f,0.f,.1f); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) tmp_pos.mV, nullptr, nullptr, nullptr); + mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*) mPosition.mV, nullptr, nullptr, nullptr); } mRolloffFactor = factor; mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); } -F32 LLListener_FMODEX::getRolloffFactor() +F32 LLListener_FMODSTUDIO::getRolloffFactor() { return mRolloffFactor; } -void LLListener_FMODEX::setDopplerFactor(F32 factor) +void LLListener_FMODSTUDIO::setDopplerFactor(F32 factor) { mDopplerFactor = factor; mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor); } -F32 LLListener_FMODEX::getDopplerFactor() +F32 LLListener_FMODSTUDIO::getDopplerFactor() { return mDopplerFactor; } diff --git a/indra/llaudio/lllistener_fmodex.h b/indra/llaudio/lllistener_fmodstudio.h similarity index 61% rename from indra/llaudio/lllistener_fmodex.h rename to indra/llaudio/lllistener_fmodstudio.h index 073b65d53adc5c68f5f486f3e2d3bc68cbdea5b0..ebc9f68d2237225347ab4f26e907fea03ec3cc3a 100644 --- a/indra/llaudio/lllistener_fmodex.h +++ b/indra/llaudio/lllistener_fmodstudio.h @@ -1,7 +1,7 @@ /** - * @file listener_fmodex.h + * @file listener_fmodstudio.h * @brief Description of LISTENER class abstracting the audio support - * as an FMOD 3D implementation (windows and Linux) + * as an FMOD Studio implementation (windows and Linux) * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code @@ -25,8 +25,8 @@ * $/LicenseInfo$ */ -#ifndef LL_LISTENER_FMODEX_H -#define LL_LISTENER_FMODEX_H +#ifndef LL_LISTENER_FMODSTUDIO_H +#define LL_LISTENER_FMODSTUDIO_H #include "lllistener.h" @@ -37,23 +37,22 @@ namespace FMOD } //Interfaces -class LLListener_FMODEX : public LLListener +class LLListener_FMODSTUDIO final : public LLListener { public: - LLListener_FMODEX(FMOD::System *system); - virtual ~LLListener_FMODEX(); - virtual void init(); + LLListener_FMODSTUDIO(FMOD::System *system); + virtual ~LLListener_FMODSTUDIO() = default; - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - virtual void commitDeferredChanges(); + void translate(const LLVector3& offset) final override; + void setPosition(const LLVector3& pos) final override; + void setVelocity(const LLVector3& vel) final override; + void orient(const LLVector3& up, const LLVector3& at) final override; + void commitDeferredChanges() final override; - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); + void setDopplerFactor(F32 factor) final override; + F32 getDopplerFactor() final override; + void setRolloffFactor(F32 factor) final override; + F32 getRolloffFactor() final override; protected: FMOD::System *mSystem; F32 mDopplerFactor; diff --git a/indra/llaudio/lllistener_openal.cpp b/indra/llaudio/lllistener_openal.cpp index 9dd4c8685460ccf29603f406405e0a94b8e39b2d..855a75b4c37977d1ce4abc0418d089c8a0a07387 100644 --- a/indra/llaudio/lllistener_openal.cpp +++ b/indra/llaudio/lllistener_openal.cpp @@ -31,32 +31,29 @@ #include "lllistener_openal.h" LLListener_OpenAL::LLListener_OpenAL() + : LLListener(), + mRolloffFactor(1.f) { - init(); } -LLListener_OpenAL::~LLListener_OpenAL() -{ -} - -void LLListener_OpenAL::translate(LLVector3 offset) +void LLListener_OpenAL::translate(const LLVector3& offset) { //LL_INFOS() << "LLListener_OpenAL::translate() : " << offset << LL_ENDL; LLListener::translate(offset); } -void LLListener_OpenAL::setPosition(LLVector3 pos) +void LLListener_OpenAL::setPosition(const LLVector3& pos) { //LL_INFOS() << "LLListener_OpenAL::setPosition() : " << pos << LL_ENDL; LLListener::setPosition(pos); } -void LLListener_OpenAL::setVelocity(LLVector3 vel) +void LLListener_OpenAL::setVelocity(const LLVector3& vel) { LLListener::setVelocity(vel); } -void LLListener_OpenAL::orient(LLVector3 up, LLVector3 at) +void LLListener_OpenAL::orient(const LLVector3& up, const LLVector3& at) { //LL_INFOS() << "LLListener_OpenAL::orient() up: " << up << " at: " << at << LL_ENDL; LLListener::orient(up, at); @@ -64,18 +61,20 @@ void LLListener_OpenAL::orient(LLVector3 up, LLVector3 at) void LLListener_OpenAL::commitDeferredChanges() { - ALfloat orientation[6]; - orientation[0] = mListenAt.mV[0]; - orientation[1] = mListenAt.mV[1]; - orientation[2] = mListenAt.mV[2]; - orientation[3] = mListenUp.mV[0]; - orientation[4] = mListenUp.mV[1]; - orientation[5] = mListenUp.mV[2]; - - ALfloat velocity[3]; - velocity[0] = mVelocity.mV[0]; - velocity[1] = mVelocity.mV[1]; - velocity[2] = mVelocity.mV[2]; + ALfloat orientation[] = { + mListenAt.mV[0], + mListenAt.mV[1], + mListenAt.mV[2], + mListenUp.mV[0], + mListenUp.mV[1], + mListenUp.mV[2], + }; + + ALfloat velocity[3] = { + mVelocity.mV[0], + mVelocity.mV[1], + mVelocity.mV[2], + }; alListenerfv(AL_ORIENTATION, orientation); alListenerfv(AL_POSITION, mPosition.mV); diff --git a/indra/llaudio/lllistener_openal.h b/indra/llaudio/lllistener_openal.h index cb163b11a52acc48760878568931c5800cb68da8..0a297b2705f0ad969b2db5d5090110782007288b 100644 --- a/indra/llaudio/lllistener_openal.h +++ b/indra/llaudio/lllistener_openal.h @@ -33,22 +33,22 @@ #include "AL/al.h" #include "AL/alut.h" -class LLListener_OpenAL : public LLListener +class LLListener_OpenAL final : public LLListener { public: LLListener_OpenAL(); - virtual ~LLListener_OpenAL(); - - virtual void translate(LLVector3 offset); - virtual void setPosition(LLVector3 pos); - virtual void setVelocity(LLVector3 vel); - virtual void orient(LLVector3 up, LLVector3 at); - virtual void commitDeferredChanges(); - - virtual void setDopplerFactor(F32 factor); - virtual F32 getDopplerFactor(); - virtual void setRolloffFactor(F32 factor); - virtual F32 getRolloffFactor(); + virtual ~LLListener_OpenAL() = default; + + virtual void translate(const LLVector3& offset) override; + virtual void setPosition(const LLVector3& pos) override; + virtual void setVelocity(const LLVector3& vel) override; + virtual void orient(const LLVector3& up, const LLVector3& at) override; + virtual void commitDeferredChanges() override; + + virtual void setDopplerFactor(F32 factor) override; + virtual F32 getDopplerFactor() override; + virtual void setRolloffFactor(F32 factor) override; + virtual F32 getRolloffFactor() override; protected: F32 mRolloffFactor; diff --git a/indra/llaudio/llstreamingaudio_fmodex.cpp b/indra/llaudio/llstreamingaudio_fmodex.cpp deleted file mode 100644 index 9c9e85c00cb6d93a924390a6b7b51633a52cf028..0000000000000000000000000000000000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/** - * @file streamingaudio_fmodex.cpp - * @brief LLStreamingAudio_FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llmath.h" - -#include "fmod.hpp" -#include "fmod_errors.h" - -#include "llstreamingaudio_fmodex.h" - - -class LLAudioStreamManagerFMODEX -{ -public: - LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url); - FMOD::Channel* startStream(); - bool stopStream(); // Returns true if the stream was successfully stopped. - bool ready(); - - const std::string& getURL() { return mInternetStreamURL; } - - FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered=NULL, bool* starving=NULL, bool* diskbusy=NULL); -protected: - FMOD::System* mSystem; - FMOD::Channel* mStreamChannel; - FMOD::Sound* mInternetStream; - bool mReady; - - std::string mInternetStreamURL; -}; - - - -//--------------------------------------------------------------------------- -// Internet Streaming -//--------------------------------------------------------------------------- -LLStreamingAudio_FMODEX::LLStreamingAudio_FMODEX(FMOD::System *system) : - mSystem(system), - mCurrentInternetStreamp(NULL), - mFMODInternetStreamChannelp(NULL), - mGain(1.0f) -{ - // Number of milliseconds of audio to buffer for the audio card. - // Must be larger than the usual Second Life frame stutter time. - const U32 buffer_seconds = 10; //sec - const U32 estimated_bitrate = 128; //kbit/sec - mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); - - // Here's where we set the size of the network buffer and some buffering - // parameters. In this case we want a network buffer of 16k, we want it - // to prebuffer 40% of that when we first connect, and we want it - // to rebuffer 80% of that whenever we encounter a buffer underrun. - - // Leave the net buffer properties at the default. - //FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80); -} - - -LLStreamingAudio_FMODEX::~LLStreamingAudio_FMODEX() -{ - // nothing interesting/safe to do. -} - - -void LLStreamingAudio_FMODEX::start(const std::string& url) -{ - //if (!mInited) - //{ - // LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL; - // return; - //} - - // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL - stop(); - - if (!url.empty()) - { - LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; - mCurrentInternetStreamp = new LLAudioStreamManagerFMODEX(mSystem,url); - mURL = url; - } - else - { - LL_INFOS() << "Set internet stream to null" << LL_ENDL; - mURL.clear(); - } -} - - -void LLStreamingAudio_FMODEX::update() -{ - // Kill dead internet streams, if possible - std::list<LLAudioStreamManagerFMODEX *>::iterator iter; - for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();) - { - LLAudioStreamManagerFMODEX *streamp = *iter; - if (streamp->stopStream()) - { - LL_INFOS() << "Closed dead stream" << LL_ENDL; - delete streamp; - mDeadStreams.erase(iter++); - } - else - { - iter++; - } - } - - // Don't do anything if there are no streams playing - if (!mCurrentInternetStreamp) - { - return; - } - - unsigned int progress; - bool starving; - bool diskbusy; - FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy); - - if (open_state == FMOD_OPENSTATE_READY) - { - // Stream is live - - // start the stream if it's ready - if (!mFMODInternetStreamChannelp && - (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream())) - { - // Reset volume to previously set volume - setGain(getGain()); - mFMODInternetStreamChannelp->setPaused(false); - } - } - else if(open_state == FMOD_OPENSTATE_ERROR) - { - stop(); - return; - } - - if(mFMODInternetStreamChannelp) - { - FMOD::Sound *sound = NULL; - - if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound) - { - FMOD_TAG tag; - S32 tagcount, dirtytagcount; - - if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount) - { - for(S32 i = 0; i < tagcount; ++i) - { - if(sound->getTag(NULL, i, &tag)!=FMOD_OK) - continue; - - if (tag.type == FMOD_TAGTYPE_FMOD) - { - if (!strcmp(tag.name, "Sample Rate Change")) - { - LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; - mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)); - } - continue; - } - } - } - - if(starving) - { - bool paused = false; - mFMODInternetStreamChannelp->getPaused(&paused); - if(!paused) - { - LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; - LL_INFOS() << " (diskbusy="<<diskbusy<<")" << LL_ENDL; - LL_INFOS() << " (progress="<<progress<<")" << LL_ENDL; - mFMODInternetStreamChannelp->setPaused(true); - } - } - else if(progress > 80) - { - mFMODInternetStreamChannelp->setPaused(false); - } - } - } -} - -void LLStreamingAudio_FMODEX::stop() -{ - if (mFMODInternetStreamChannelp) - { - mFMODInternetStreamChannelp->setPaused(true); - mFMODInternetStreamChannelp->setPriority(0); - mFMODInternetStreamChannelp = NULL; - } - - if (mCurrentInternetStreamp) - { - LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - if (mCurrentInternetStreamp->stopStream()) - { - delete mCurrentInternetStreamp; - } - else - { - LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; - mDeadStreams.push_back(mCurrentInternetStreamp); - } - mCurrentInternetStreamp = NULL; - //mURL.clear(); - } -} - -void LLStreamingAudio_FMODEX::pause(int pauseopt) -{ - if (pauseopt < 0) - { - pauseopt = mCurrentInternetStreamp ? 1 : 0; - } - - if (pauseopt) - { - if (mCurrentInternetStreamp) - { - stop(); - } - } - else - { - start(getURL()); - } -} - - -// A stream is "playing" if it has been requested to start. That -// doesn't necessarily mean audio is coming out of the speakers. -int LLStreamingAudio_FMODEX::isPlaying() -{ - if (mCurrentInternetStreamp) - { - return 1; // Active and playing - } - else if (!mURL.empty()) - { - return 2; // "Paused" - } - else - { - return 0; - } -} - - -F32 LLStreamingAudio_FMODEX::getGain() -{ - return mGain; -} - - -std::string LLStreamingAudio_FMODEX::getURL() -{ - return mURL; -} - - -void LLStreamingAudio_FMODEX::setGain(F32 vol) -{ - mGain = vol; - - if (mFMODInternetStreamChannelp) - { - vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? - - mFMODInternetStreamChannelp->setVolume(vol); - } -} - -/////////////////////////////////////////////////////// -// manager of possibly-multiple internet audio streams - -LLAudioStreamManagerFMODEX::LLAudioStreamManagerFMODEX(FMOD::System *system, const std::string& url) : - mSystem(system), - mStreamChannel(NULL), - mInternetStream(NULL), - mReady(false) -{ - mInternetStreamURL = url; - - FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream); - - if (result!= FMOD_OK) - { - LL_WARNS() << "Couldn't open fmod stream, error " - << FMOD_ErrorString(result) - << LL_ENDL; - mReady = false; - return; - } - - mReady = true; -} - -FMOD::Channel *LLAudioStreamManagerFMODEX::startStream() -{ - // We need a live and opened stream before we try and play it. - if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY) - { - LL_WARNS() << "No internet stream to start playing!" << LL_ENDL; - return NULL; - } - - if(mStreamChannel) - return mStreamChannel; //Already have a channel for this stream. - - mSystem->playSound(FMOD_CHANNEL_FREE, mInternetStream, true, &mStreamChannel); - return mStreamChannel; -} - -bool LLAudioStreamManagerFMODEX::stopStream() -{ - if (mInternetStream) - { - - - bool close = true; - switch (getOpenState()) - { - case FMOD_OPENSTATE_CONNECTING: - close = false; - break; - default: - close = true; - } - - if (close) - { - mInternetStream->release(); - mStreamChannel = NULL; - mInternetStream = NULL; - return true; - } - else - { - return false; - } - } - else - { - return true; - } -} - -FMOD_OPENSTATE LLAudioStreamManagerFMODEX::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy) -{ - FMOD_OPENSTATE state; - mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); - return state; -} - -void LLStreamingAudio_FMODEX::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) -{ - mSystem->setStreamBufferSize(streambuffertime/1000*128*128, FMOD_TIMEUNIT_RAWBYTES); - FMOD_ADVANCEDSETTINGS settings; - memset(&settings,0,sizeof(settings)); - settings.cbsize=sizeof(settings); - settings.defaultDecodeBufferSize = decodebuffertime;//ms - mSystem->setAdvancedSettings(&settings); -} diff --git a/indra/llaudio/llstreamingaudio_fmodex.h b/indra/llaudio/llstreamingaudio_fmodex.h deleted file mode 100644 index 2787840ba1a8581bba725f3574c0620fa9c7ea3e..0000000000000000000000000000000000000000 --- a/indra/llaudio/llstreamingaudio_fmodex.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file streamingaudio_fmodex.h - * @brief Definition of LLStreamingAudio_FMODEX implementation - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_STREAMINGAUDIO_FMODEX_H -#define LL_STREAMINGAUDIO_FMODEX_H - -#include "stdtypes.h" // from llcommon - -#include "llstreamingaudio.h" -#include "lltimer.h" - -//Stubs -class LLAudioStreamManagerFMODEX; -namespace FMOD -{ - class System; - class Channel; -} - -//Interfaces -class LLStreamingAudio_FMODEX : public LLStreamingAudioInterface -{ - public: - LLStreamingAudio_FMODEX(FMOD::System *system); - /*virtual*/ ~LLStreamingAudio_FMODEX(); - - /*virtual*/ void start(const std::string& url); - /*virtual*/ void stop(); - /*virtual*/ void pause(S32 pause); - /*virtual*/ void update(); - /*virtual*/ S32 isPlaying(); - /*virtual*/ void setGain(F32 vol); - /*virtual*/ F32 getGain(); - /*virtual*/ std::string getURL(); - - /*virtual*/ bool supportsAdjustableBufferSizes(){return true;} - /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime); -private: - FMOD::System *mSystem; - - LLAudioStreamManagerFMODEX *mCurrentInternetStreamp; - FMOD::Channel *mFMODInternetStreamChannelp; - std::list<LLAudioStreamManagerFMODEX *> mDeadStreams; - - std::string mURL; - F32 mGain; -}; - - -#endif // LL_STREAMINGAUDIO_FMODEX_H diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.cpp b/indra/llaudio/llstreamingaudio_fmodstudio.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0daeac7abacc414c72ef0eaf78db42c44762a225 --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.cpp @@ -0,0 +1,673 @@ +/** + * @file streamingaudio_fmodstudio.cpp + * @brief LLStreamingAudio_FMODSTUDIO 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_fmodstudio.h" + +#include "llsd.h" +#include "llmath.h" +#include "llmutex.h" + +#include "fmod.hpp" +#include "fmod_errors.h" + +inline bool Check_FMOD_Stream_Error(FMOD_RESULT result, const char *string) +{ + if (result == FMOD_OK) + return false; + LL_WARNS("AudioImpl") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL; + return true; +} + +class LLAudioStreamManagerFMODSTUDIO +{ +public: + LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url); + FMOD::Channel* startStream(); + bool stopStream(); // Returns true if the stream was successfully stopped. + + const std::string& getURL() { return mInternetStreamURL; } + + FMOD_RESULT getOpenState(FMOD_OPENSTATE& openstate, unsigned int* percentbuffered = nullptr, bool* starving = nullptr, bool* diskbusy = nullptr); +protected: + FMOD::System* mSystem; + FMOD::ChannelGroup* mChannelGroup; + FMOD::Channel* mStreamChannel; + FMOD::Sound* mInternetStream; + bool mReady; + + std::string mInternetStreamURL; +}; + +LLMutex gWaveDataMutex; //Just to be extra strict. +const U32 WAVE_BUFFER_SIZE = 1024; +U32 gWaveBufferMinSize = 0; +F32 gWaveDataBuffer[WAVE_BUFFER_SIZE] = { 0.f }; +U32 gWaveDataBufferSize = 0; + +FMOD_RESULT F_CALLBACK waveDataCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels) +{ + if (!length || !inchannels) + return FMOD_OK; + memcpy(outbuffer, inbuffer, length * inchannels * sizeof(float)); + + static std::vector<F32> local_buf; + if (local_buf.size() < length) + local_buf.resize(length, 0.f); + + for (U32 i = 0; i < length; ++i) + { + F32 total = 0.f; + for (S32 j = 0; j < inchannels; ++j) + { + total += inbuffer[i*inchannels + j]; + } + local_buf[i] = total / inchannels; + } + + { + LLMutexLock lock(&gWaveDataMutex); + + for (U32 i = length; i > 0; --i) + { + if (++gWaveDataBufferSize > WAVE_BUFFER_SIZE) + { + if (gWaveBufferMinSize) + memcpy(gWaveDataBuffer + WAVE_BUFFER_SIZE - gWaveBufferMinSize, gWaveDataBuffer, gWaveBufferMinSize * sizeof(float)); + gWaveDataBufferSize = 1 + gWaveBufferMinSize; + } + gWaveDataBuffer[WAVE_BUFFER_SIZE - gWaveDataBufferSize] = local_buf[i - 1]; + } + } + + return FMOD_OK; +} + +//--------------------------------------------------------------------------- +// Internet Streaming +//--------------------------------------------------------------------------- +LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) : + mSystem(system), + mCurrentInternetStreamp(nullptr), + mStreamDSP(nullptr), + mStreamGroup(nullptr), + mFMODInternetStreamChannelp(nullptr), + mGain(1.0f), + mMetaData(nullptr), + mNewMetadata(true) +{ + FMOD_RESULT result; + + // Number of milliseconds of audio to buffer for the audio card. + // Must be larger than the usual Second Life frame stutter time. + const U32 buffer_seconds = 10; //sec + const U32 estimated_bitrate = 128; //kbit/sec + result = mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES); + Check_FMOD_Stream_Error(result, "FMOD::System::setStreamBufferSize"); + + Check_FMOD_Stream_Error(system->createChannelGroup("stream", &mStreamGroup), "FMOD::System::createChannelGroup"); + + FMOD_DSP_DESCRIPTION dspdesc = { }; + dspdesc.pluginsdkversion = FMOD_PLUGIN_SDK_VERSION; + strncpy(dspdesc.name, "Waveform", sizeof(dspdesc.name)); + dspdesc.numoutputbuffers = 1; + dspdesc.read = &waveDataCallback; //Assign callback. + + Check_FMOD_Stream_Error(system->createDSP(&dspdesc, &mStreamDSP), "FMOD::System::createDSP"); +} + +LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO() +{ + stop(); + for (U32 i = 0; i < 100; ++i) + { + if (releaseDeadStreams()) + break; + ms_sleep(10); + } + + cleanupWaveData(); +} + +void LLStreamingAudio_FMODSTUDIO::start(const std::string& url) +{ + //if (!mInited) + //{ + // LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL; + // return; + //} + + // "stop" stream but don't clear url, etc. in case url == mInternetStreamURL + stop(); + + if (!url.empty()) + { + if(mDeadStreams.empty()) + { + LL_INFOS() << "Starting internet stream: " << url << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, url); + mURL = url; + mMetaData = new LLSD; + } + else + { + LL_INFOS() << "Deferring stream load until buffer release: " << url << LL_ENDL; + mPendingURL = url; + } + } + else + { + LL_INFOS() << "Set internet stream to null" << LL_ENDL; + mURL.clear(); + } +} + +enum utf_endian_type_t +{ + UTF16LE, + UTF16BE, + UTF16 +}; + +std::string utf16input_to_utf8(unsigned char* input, U32 len, utf_endian_type_t type) +{ + if (type == UTF16) + { + type = UTF16BE; //Default + if (len > 2) + { + //Parse and strip BOM. + if ((input[0] == 0xFE && input[1] == 0xFF) || + (input[0] == 0xFF && input[1] == 0xFE)) + { + input += 2; + len -= 2; + type = input[0] == 0xFE ? UTF16BE : UTF16LE; + } + } + } + llutf16string out_16((llutf16string::value_type*)input, len / 2); + if (len % 2) + { + out_16.push_back((input)[len - 1] << 8); + } + if (type == UTF16BE) + { + for (llutf16string::iterator i = out_16.begin(); i < out_16.end(); ++i) + { + llutf16string::value_type v = *i; + *i = ((v & 0x00FF) << 8) | ((v & 0xFF00) >> 8); + } + } + return utf16str_to_utf8str(out_16); +} + +void LLStreamingAudio_FMODSTUDIO::update() +{ + if (!releaseDeadStreams()) + { + llassert_always(mCurrentInternetStreamp == NULL); + return; + } + + if(!mPendingURL.empty()) + { + llassert_always(mCurrentInternetStreamp == NULL); + LL_INFOS() << "Starting internet stream: " << mPendingURL << LL_ENDL; + mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, mStreamGroup, mPendingURL); + mURL = mPendingURL; + mMetaData = new LLSD; + mPendingURL.clear(); + } + + // Don't do anything if there are no streams playing + if (!mCurrentInternetStreamp) + { + return; + } + + unsigned int progress; + bool starving; + bool diskbusy; + FMOD_OPENSTATE open_state; + FMOD_RESULT result = mCurrentInternetStreamp->getOpenState(open_state, &progress, &starving, &diskbusy); + + if (result != FMOD_OK || open_state == FMOD_OPENSTATE_ERROR) + { + stop(); + return; + } + else if (open_state == FMOD_OPENSTATE_READY) + { + // Stream is live + + // start the stream if it's ready + if (!mFMODInternetStreamChannelp && + (mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream())) + { + // Reset volume to previously set volume + setGain(getGain()); + if (mStreamDSP) + { + Check_FMOD_Stream_Error(mFMODInternetStreamChannelp->addDSP(FMOD_CHANNELCONTROL_DSP_TAIL, mStreamDSP), "FMOD::Channel::addDSP"); + } + Check_FMOD_Stream_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); + } + } + + + if(mFMODInternetStreamChannelp) + { + if(!mMetaData) + mMetaData = new LLSD; + + FMOD::Sound *sound = nullptr; + + if(mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound) + { + FMOD_TAG tag; + S32 tagcount, dirtytagcount; + if(sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount) + { + mMetaData->clear(); + mNewMetadata = true; + + for(S32 i = 0; i < tagcount; ++i) + { + if(sound->getTag(nullptr, i, &tag)!=FMOD_OK) + continue; + + std::string name = tag.name; + switch(tag.type) //Crappy tag translate table. + { + case(FMOD_TAGTYPE_ID3V2): + if (!LLStringUtil::compareInsensitive(name, "TIT2")) name = "TITLE"; + else if(name == "TPE1") name = "ARTIST"; + break; + case(FMOD_TAGTYPE_ASF): + if (!LLStringUtil::compareInsensitive(name, "Title")) name = "TITLE"; + else if (!LLStringUtil::compareInsensitive(name, "WM/AlbumArtist")) name = "ARTIST"; + break; + case(FMOD_TAGTYPE_FMOD): + if (!LLStringUtil::compareInsensitive(name, "Sample Rate Change")) + { + LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL; + Check_FMOD_Stream_Error(mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data)), "FMOD::Channel::setFrequency"); + } + continue; + default: + if (!LLStringUtil::compareInsensitive(name, "TITLE") || + !LLStringUtil::compareInsensitive(name, "ARTIST")) + LLStringUtil::toUpper(name); + break; + } + + switch(tag.datatype) + { + case(FMOD_TAGDATATYPE_INT): + (*mMetaData)[name]=*(LLSD::Integer*)(tag.data); + LL_INFOS() << tag.name << ": " << *(int*)(tag.data) << LL_ENDL; + break; + case(FMOD_TAGDATATYPE_FLOAT): + (*mMetaData)[name]=*(LLSD::Real*)(tag.data); + LL_INFOS() << tag.name << ": " << *(float*)(tag.data) << LL_ENDL; + break; + case(FMOD_TAGDATATYPE_STRING): + { + std::string out = rawstr_to_utf8(std::string((char*)tag.data,tag.datalen)); + if (out.length() && out[out.size() - 1] == 0) + out.erase(out.size() - 1); + (*mMetaData)[name]=out; + LL_INFOS() << tag.name << "(RAW): " << out << LL_ENDL; + } + break; + case(FMOD_TAGDATATYPE_STRING_UTF8) : + { + U8 offs = 0; + if (tag.datalen > 3 && ((unsigned char*)tag.data)[0] == 0xEF && ((unsigned char*)tag.data)[1] == 0xBB && ((unsigned char*)tag.data)[2] == 0xBF) + offs = 3; + std::string out((char*)tag.data + offs, tag.datalen - offs); + if (out.length() && out[out.size() - 1] == 0) + out.erase(out.size() - 1); + (*mMetaData)[name] = out; + LL_INFOS() << tag.name << "(UTF8): " << out << LL_ENDL; + } + break; + case(FMOD_TAGDATATYPE_STRING_UTF16): + { + std::string out = utf16input_to_utf8((unsigned char*)tag.data, tag.datalen, UTF16); + if (out.length() && out[out.size() - 1] == 0) + out.erase(out.size() - 1); + (*mMetaData)[name] = out; + LL_INFOS() << tag.name << "(UTF16): " << out << LL_ENDL; + } + break; + case(FMOD_TAGDATATYPE_STRING_UTF16BE): + { + std::string out = utf16input_to_utf8((unsigned char*)tag.data, tag.datalen, UTF16BE); + if (out.length() && out[out.size() - 1] == 0) + out.erase(out.size() - 1); + (*mMetaData)[name] = out; + LL_INFOS() << tag.name << "(UTF16BE): " << out << LL_ENDL; + } + default: + break; + } + } + } + static bool was_starved = false; + if(starving) + { + bool paused = false; + if (mFMODInternetStreamChannelp->getPaused(&paused) == FMOD_OK && !paused) + { + LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL; + LL_INFOS() << " (diskbusy="<<diskbusy<<")" << LL_ENDL; + LL_INFOS() << " (progress="<<progress<<")" << LL_ENDL; + Check_FMOD_Stream_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused"); + } + was_starved = true; + } + else if(progress > 80 && was_starved) + { + was_starved = false; + Check_FMOD_Stream_Error(mFMODInternetStreamChannelp->setPaused(false), "FMOD::Channel::setPaused"); + } + } + } +} + +void LLStreamingAudio_FMODSTUDIO::stop() +{ + mPendingURL.clear(); + + if(mMetaData) + { + delete mMetaData; + mMetaData = nullptr; + } + + if (mFMODInternetStreamChannelp) + { + Check_FMOD_Stream_Error(mFMODInternetStreamChannelp->setPaused(true), "FMOD::Channel::setPaused"); + Check_FMOD_Stream_Error(mFMODInternetStreamChannelp->setPriority(0), "FMOD::Channel::setPriority"); + if (mStreamDSP) + { + Check_FMOD_Stream_Error(mFMODInternetStreamChannelp->removeDSP(mStreamDSP), "FMOD::Channel::removeDSP"); + } + mFMODInternetStreamChannelp = nullptr; + } + + if (mCurrentInternetStreamp) + { + LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + if (mCurrentInternetStreamp->stopStream()) + { + delete mCurrentInternetStreamp; + } + else + { + LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL; + mDeadStreams.push_back(mCurrentInternetStreamp); + } + mCurrentInternetStreamp = nullptr; + } +} + +void LLStreamingAudio_FMODSTUDIO::pause(S32 pauseopt) +{ + if (pauseopt < 0) + { + pauseopt = mCurrentInternetStreamp ? 1 : 0; + } + + if (pauseopt) + { + if (mCurrentInternetStreamp) + { + stop(); + } + } + else + { + start(getURL()); + } +} + + +// A stream is "playing" if it has been requested to start. That +// doesn't necessarily mean audio is coming out of the speakers. +int LLStreamingAudio_FMODSTUDIO::isPlaying() +{ + if (mCurrentInternetStreamp) + { + return 1; // Active and playing + } + else if (!mURL.empty() || !mPendingURL.empty()) + { + return 2; // "Paused" + } + else + { + return 0; + } +} + + +F32 LLStreamingAudio_FMODSTUDIO::getGain() +{ + return mGain; +} + + +std::string LLStreamingAudio_FMODSTUDIO::getURL() +{ + return mURL; +} + + +void LLStreamingAudio_FMODSTUDIO::setGain(F32 vol) +{ + mGain = vol; + + if (mFMODInternetStreamChannelp) + { + vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here? + + Check_FMOD_Stream_Error(mFMODInternetStreamChannelp->setVolume(vol), "FMOD::Channel::setVolume"); + } +} + +bool LLStreamingAudio_FMODSTUDIO::hasNewMetaData() +{ + if (mCurrentInternetStreamp && mNewMetadata) + { + mNewMetadata = false; + return true; + } + else + { + return false; + } +} + +/* virtual */ +bool LLStreamingAudio_FMODSTUDIO::getWaveData(float* arr, S32 count, S32 stride/*=1*/) +{ + if (count > (WAVE_BUFFER_SIZE / 2)) + LL_ERRS("AudioImpl") << "Count=" << count << " exceeds WAVE_BUFFER_SIZE/2=" << WAVE_BUFFER_SIZE << LL_ENDL; + + if(!mFMODInternetStreamChannelp || !mCurrentInternetStreamp) + return false; + + bool muted = false; + FMOD_RESULT res = mFMODInternetStreamChannelp->getMute(&muted); + if(res != FMOD_OK || muted) + return false; + { + U32 buff_size; + { + LLMutexLock lock(&gWaveDataMutex); + gWaveBufferMinSize = count; + buff_size = gWaveDataBufferSize; + if (!buff_size) + return false; + memcpy(arr, gWaveDataBuffer + WAVE_BUFFER_SIZE - buff_size, llmin(U32(count), buff_size) * sizeof(float)); + } + if (buff_size < U32(count)) + memset(arr + buff_size, 0, (count - buff_size) * sizeof(float)); + } + return true; +} + +/////////////////////////////////////////////////////// +// manager of possibly-multiple internet audio streams + +LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, FMOD::ChannelGroup *group, const std::string& url) : + mSystem(system), + mChannelGroup(group), + mStreamChannel(nullptr), + mInternetStream(nullptr), + mReady(false), + mInternetStreamURL(url) +{ + FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, nullptr, &mInternetStream); + + if (result!= FMOD_OK) + { + LL_WARNS() << "Couldn't open fmod stream, error " + << FMOD_ErrorString(result) + << LL_ENDL; + mReady = false; + return; + } + + mReady = true; +} + +FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream() +{ + // We need a live and opened stream before we try and play it. + FMOD_OPENSTATE open_state; + if (getOpenState(open_state) != FMOD_OK || open_state != FMOD_OPENSTATE_READY) + { + LL_WARNS() << "No internet stream to start playing!" << LL_ENDL; + return nullptr; + } + + if(mStreamChannel) + return mStreamChannel; //Already have a channel for this stream. + + Check_FMOD_Stream_Error(mSystem->playSound(mInternetStream, mChannelGroup, true, &mStreamChannel), "FMOD::System::playSound"); + return mStreamChannel; +} + +bool LLAudioStreamManagerFMODSTUDIO::stopStream() +{ + if (mInternetStream) + { + bool close = true; + FMOD_OPENSTATE open_state; + if (getOpenState(open_state) == FMOD_OK) + { + switch (open_state) + { + case FMOD_OPENSTATE_CONNECTING: + close = false; + break; + default: + close = true; + } + } + + if (close && mInternetStream->release() == FMOD_OK) + { + mStreamChannel = nullptr; + mInternetStream = nullptr; + return true; + } + else + { + return false; + } + } + else + { + return true; + } +} + +FMOD_RESULT LLAudioStreamManagerFMODSTUDIO::getOpenState(FMOD_OPENSTATE& state, unsigned int* percentbuffered, bool* starving, bool* diskbusy) +{ + if (!mInternetStream) + return FMOD_ERR_INVALID_HANDLE; + FMOD_RESULT result = mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy); + Check_FMOD_Stream_Error(result, "FMOD::Sound::getOpenState"); + return result; +} + +void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime) +{ + Check_FMOD_Stream_Error(mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES), "FMOD::System::setStreamBufferSize"); + FMOD_ADVANCEDSETTINGS settings = { }; + settings.cbSize=sizeof(settings); + settings.defaultDecodeBufferSize = decodebuffertime;//ms + Check_FMOD_Stream_Error(mSystem->setAdvancedSettings(&settings), "FMOD::System::setAdvancedSettings"); +} + +bool LLStreamingAudio_FMODSTUDIO::releaseDeadStreams() +{ + // Kill dead internet streams, if possible + for (auto iter = mDeadStreams.begin(); iter != mDeadStreams.end();) + { + LLAudioStreamManagerFMODSTUDIO *streamp = *iter; + if (streamp->stopStream()) + { + LL_INFOS() << "Closed dead stream" << LL_ENDL; + delete streamp; + mDeadStreams.erase(iter++); + } + else + { + ++iter; + } + } + + return mDeadStreams.empty(); +} + +void LLStreamingAudio_FMODSTUDIO::cleanupWaveData() +{ + if (mStreamGroup) + { + Check_FMOD_Stream_Error(mStreamGroup->release(), "FMOD::ChannelGroup::release"); + mStreamGroup = nullptr; + } + + if(mStreamDSP) + Check_FMOD_Stream_Error(mStreamDSP->release(), "FMOD::DSP::release"); + mStreamDSP = nullptr; +} diff --git a/indra/llaudio/llstreamingaudio_fmodstudio.h b/indra/llaudio/llstreamingaudio_fmodstudio.h new file mode 100644 index 0000000000000000000000000000000000000000..ea1b5c81a8357b5bfaf7699283b47fbb5d11b724 --- /dev/null +++ b/indra/llaudio/llstreamingaudio_fmodstudio.h @@ -0,0 +1,90 @@ +/** + * @file streamingaudio_fmodstudio.h + * @brief Definition of LLStreamingAudio_FMODSTUDIO implementation + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_STREAMINGAUDIO_FMODSTUDIO_H +#define LL_STREAMINGAUDIO_FMODSTUDIO_H + +#include "stdtypes.h" // from llcommon + +#include "llstreamingaudio.h" +#include "lltimer.h" + +//Stubs +class LLAudioStreamManagerFMODSTUDIO; +namespace FMOD +{ + class System; + class Channel; + class ChannelGroup; + class DSP; +} + +//Interfaces +class LLStreamingAudio_FMODSTUDIO final : public LLStreamingAudioInterface +{ + public: + LLStreamingAudio_FMODSTUDIO(FMOD::System *system); + /*virtual*/ ~LLStreamingAudio_FMODSTUDIO(); + + /*virtual*/ void start(const std::string& url) override; + /*virtual*/ void stop() override; + /*virtual*/ void pause(S32 pause) override; + /*virtual*/ void update() override; + /*virtual*/ S32 isPlaying() override; + /*virtual*/ void setGain(F32 vol) override; + /*virtual*/ F32 getGain() override; + /*virtual*/ std::string getURL() override; + + /*virtual*/ bool supportsAdjustableBufferSizes() override {return true;} + /*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime) override; + + /*virtual*/ bool supportsMetaData() override {return true;} + /*virtual*/ const LLSD *getMetaData() override { return mMetaData; } //return NULL if not playing. + /*virtual*/ bool hasNewMetaData() override; + /*virtual*/ bool supportsWaveData() override {return true;} + /*virtual*/ bool getWaveData(float* arr, S32 count, S32 stride = 1) override; +private: + bool releaseDeadStreams(); + void cleanupWaveData(); + + FMOD::System *mSystem; + + LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp; + FMOD::DSP* mStreamDSP; + FMOD::ChannelGroup* mStreamGroup; + FMOD::Channel *mFMODInternetStreamChannelp; + std::list<LLAudioStreamManagerFMODSTUDIO *> mDeadStreams; + + std::string mURL; + std::string mPendingURL; + F32 mGain; + + LLSD *mMetaData; + bool mNewMetadata; +}; + + +#endif // LL_STREAMINGAUDIO_FMODSTUDIO_H diff --git a/indra/llaudio/llwindgen.h b/indra/llaudio/llwindgen.h index ec58f76f5fd34c48d824e3cbabac3e794fceb33d..e60e1c8ee3ff685b69e5692e521d875ddbabd355 100644 --- a/indra/llaudio/llwindgen.h +++ b/indra/llaudio/llwindgen.h @@ -74,7 +74,7 @@ class LLWindGen bool interp_freq = false; //if the frequency isn't changing much, we don't need to interpolate in the inner loop - if (llabs(mTargetFreq - mCurrentFreq) < (mCurrentFreq * 0.112)) + if (llabs(mTargetFreq - mCurrentFreq) < (mCurrentFreq * 0.112f)) { // calculate resonant filter coefficients mCurrentFreq = mTargetFreq; diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index cd564d88145f1beff0e4171324ad4139d157b03e..dbe8b1fbb5bacb82ce30c43d0ea97e48e1e00e9e 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -17,7 +17,7 @@ include(CMakeCopyIfDifferent) include(DBusGlib) include(DragDrop) include(EXPAT) -include(FMODEX) +include(FMODSTUDIO) include(GLOD) include(Hunspell) include(JsonCpp) @@ -62,9 +62,9 @@ if (NOT HAVOK_TPV) add_subdirectory(${LLPHYSICSEXTENSIONS_SRC_DIR} llphysicsextensions) endif (NOT HAVOK_TPV) -if(FMODEX) - include_directories(${FMODEX_INCLUDE_DIR}) -endif(FMODEX) +if(USE_FMODSTUDIO) + include_directories(${FMODSTUDIO_INCLUDE_DIR}) +endif(USE_FMODSTUDIO) include_directories( ${DBUSGLIB_INCLUDE_DIRS} @@ -1721,10 +1721,10 @@ if (OPENAL) set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL") endif (OPENAL) -if (FMODEX) - set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX") - set(FMODWRAPPER_LIBRARY ${FMODEX_LIBRARY}) -endif (FMODEX) +if (USE_FMODSTUDIO) + set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DUSE_FMODSTUDIO=1") + set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY}) +endif (USE_FMODSTUDIO) set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}") @@ -1841,13 +1841,13 @@ if (WINDOWS) ) endif (ADDRESS_SIZE EQUAL 64) - if (FMODEX) + if (USE_FMODSTUDIO) 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 + ${SHARED_LIB_STAGING_DIR}/Release/fmod.dll + ${SHARED_LIB_STAGING_DIR}/RelWithDebInfo/fmod.dll + ${SHARED_LIB_STAGING_DIR}/Debug/fmodL.dll ) - endif (FMODEX) + endif (USE_FMODSTUDIO) add_custom_command( OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 68252505d0c16fa5f80633d1253de97391a93f9c..a120f9ecd03c74563c75878c84b1fe0ed91ff176 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -16665,18 +16665,18 @@ <key>Value</key> <real>1.0</real> </map> - <key>FMODExProfilerEnable</key> + <key>FMODProfilerEnable</key> <map> <key>Comment</key> - <string>Enable profiler tool if using FMOD Ex</string> + <string>Enable profiler tool if using FMOD Studio</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>FMODDecodeBufferSize</key> <map> <key>Comment</key> <string>Sets the streaming decode buffer size (in milliseconds)</string> @@ -16686,8 +16686,19 @@ <string>U32</string> <key>Value</key> <integer>1000</integer> - </map> - <key>FMODExStreamBufferSize</key> + </map> + <key>FMODResampleMethod</key> + <map> + <key>Comment</key> + <string>Sets the method used for internal resampler 0(Linear), 1(Cubic), 2(Spline)</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>FMODStreamBufferSize</key> <map> <key>Comment</key> <string>Sets the streaming buffer size (in milliseconds)</string> diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 8678bf764dec2ed92780d752002c8af3183bf641..3d0360b2a377d68ed1ade446a96184336ebaf8cd 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1789,18 +1789,11 @@ bool LLAppViewer::cleanup() if (gAudiop) { - // be sure to stop the internet stream cleanly BEFORE destroying the interface to stop it. - gAudiop->stopInternetStream(); - // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem. - LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl(); - delete sai; - gAudiop->setStreamingAudioImpl(NULL); - - // shut down the audio subsystem + // shut down the audio subsystem gAudiop->shutdown(); delete gAudiop; - gAudiop = NULL; + gAudiop = nullptr; } // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 3d8c8b5201e341f4c1f46597bad281b49f0d459a..743522451d0f84de9d48f9ff7b2c60e526538dbc 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -39,8 +39,8 @@ #include "llviewermedia_streamingaudio.h" #include "llaudioengine.h" -#ifdef LL_FMODEX -# include "llaudioengine_fmodex.h" +#if USE_FMODSTUDIO +# include "llaudioengine_fmodstudio.h" #endif #ifdef LL_OPENAL @@ -625,12 +625,14 @@ bool idle_startup() delete gAudiop; gAudiop = NULL; -#ifdef LL_FMODEX +#if USE_FMODSTUDIO + if (!gAudiop #if !LL_WINDOWS - if (NULL == getenv("LL_BAD_FMODEX_DRIVER")) + && NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER") #endif // !LL_WINDOWS + ) { - gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODExProfilerEnable")); + gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(LLAppViewer::instance()->getSecondLifeTitle(), gSavedSettings.getBOOL("FMODProfilerEnable"), gSavedSettings.getU32("FMODResampleMethod")); } #endif diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index f2226b5cbdbc52c1cbdfc58adc41378aeaa02563..41a1f6a091c5b8d4e2a442d91819dbb6d4559d3a 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -113,7 +113,7 @@ void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI) LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); if(stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + stream->setBufferSizes(gSavedSettings.getU32("FMODStreamBufferSize"),gSavedSettings.getU32("FMODDecodeBufferSize")); gAudiop->startInternetStream(mNextStreamURI); startFading(); @@ -178,7 +178,7 @@ bool LLViewerAudio::onIdleUpdate() { LLStreamingAudioInterface *stream = gAudiop->getStreamingAudioImpl(); if(stream && stream->supportsAdjustableBufferSizes()) - stream->setBufferSizes(gSavedSettings.getU32("FMODExStreamBufferSize"),gSavedSettings.getU32("FMODExDecodeBufferSize")); + stream->setBufferSizes(gSavedSettings.getU32("FMODStreamBufferSize"),gSavedSettings.getU32("FMODDecodeBufferSize")); gAudiop->startInternetStream(mNextStreamURI); } diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index a403760670eeff299cf61d3b389e8fc5a054955e..c74dbb9e30230f389fa22f8e5486524747de25ce 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -513,14 +513,11 @@ def construct(self): print err.message print "Skipping GLOD library (assumming linked statically)" - # Get fmodex dll, continue if missing - try: - if(self.address_size == 64): - self.path("fmodex64.dll") - else: - self.path("fmodex.dll") - except: - print "Skipping fmodex audio library(assuming other audio engine)" + # Get fmodstudio dll, continue if missing + if self.args['configuration'].lower() == 'debug': + self.path("fmodL.dll") + else: + self.path("fmod.dll") # For textures self.path("openjpeg.dll") @@ -1049,12 +1046,12 @@ def path_optional(src, dst): # dylibs that vary based on configuration if self.args['configuration'].lower() == 'debug': for libfile in ( - "libfmodexL.dylib", + "libfmodL.dylib", ): dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile) else: for libfile in ( - "libfmodex.dylib", + "libfmod.dylib", ): dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile) @@ -1520,14 +1517,12 @@ def construct(self): pass try: - self.path("libfmodex-*.so") - self.path("libfmodex.so") + self.path_optional("libfmod.so*") pass except: - print "Skipping libfmodex.so - not found" + print "Skipping libfmod.so - not found" pass - # Vivox runtimes with self.prefix(src=relpkgdir, dst="bin"): self.path("SLVoice")