DRTVWR-476: Merge branch 'master' of bitbucket.org:lindenlab/viewer into d476.
commit
50a8c2e41a
|
|
@ -3,6 +3,7 @@
|
|||
*.bak
|
||||
*.diff
|
||||
*.orig
|
||||
*.patch
|
||||
*.pyc
|
||||
*.rej
|
||||
*.swp
|
||||
|
|
|
|||
|
|
@ -729,38 +729,28 @@
|
|||
<key>version</key>
|
||||
<string>2.1.1.538990</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 by Firelight Technologies Pty Ltd.</string>
|
||||
<key>description</key>
|
||||
<string>FMOD Studio API</string>
|
||||
<key>license</key>
|
||||
<string>fmodex</string>
|
||||
<string>fmod</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>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>ed0d8767652aecd65a7fef3e28645bad</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>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin</string>
|
||||
</map>
|
||||
<key>darwin64</key>
|
||||
<map>
|
||||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>6c2e1e440d6759d9a471db62c6ce5919</string>
|
||||
<string>dc4c9122de8bf77f34cfc8227d10a272</string>
|
||||
<key>url</key>
|
||||
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54852/510148/fmodex-4.44.64.538982-darwin64-538982.tar.bz2</string>
|
||||
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/59038/554626/fmodstudio-2.00.07.541681-darwin64-541681.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>darwin64</string>
|
||||
|
|
@ -770,9 +760,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>b847ec838da1ad1dd646df9d74e9b395</string>
|
||||
<string>c491bdc1690f3d920c66be509ccc6ef2</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>
|
||||
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/59039/554632/fmodstudio-2.00.07.541681-linux-541681.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux</string>
|
||||
|
|
@ -782,9 +772,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>89a75d8719f7b2cbe1e54cd8407bb992</string>
|
||||
<string>ae75cdb1cc9da824c9e270bf97bfdd6c</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>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/54589/506866/fmodstudio-2.00.07.538806-linux64-538806.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>linux64</string>
|
||||
|
|
@ -794,9 +784,9 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>8efdba2373be883e7536bcc8a82e55f2</string>
|
||||
<string>7f0294b038eab2d89ecc73bbf08b6d94</string>
|
||||
<key>url</key>
|
||||
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55018/511934/fmodex-4.44.64.538982-windows-538982.tar.bz2</string>
|
||||
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/59042/554668/fmodstudio-2.00.07.541681-windows-541681.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows</string>
|
||||
|
|
@ -806,16 +796,16 @@
|
|||
<key>archive</key>
|
||||
<map>
|
||||
<key>hash</key>
|
||||
<string>d724e50266dd5a565a263d2867df421e</string>
|
||||
<string>da2e8e2b809d8fe635ee437baa2a7386</string>
|
||||
<key>url</key>
|
||||
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/55016/511920/fmodex-4.44.64.538982-windows64-538982.tar.bz2</string>
|
||||
<string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/ct2/59041/554656/fmodstudio-2.00.07.541681-windows64-541681.tar.bz2</string>
|
||||
</map>
|
||||
<key>name</key>
|
||||
<string>windows64</string>
|
||||
</map>
|
||||
</map>
|
||||
<key>version</key>
|
||||
<string>4.44.64.538982</string>
|
||||
<string>2.00.07.541681</string>
|
||||
</map>
|
||||
<key>fontconfig</key>
|
||||
<map>
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ set(cmake_SOURCE_FILES
|
|||
FindAPR.cmake
|
||||
FindAutobuild.cmake
|
||||
FindBerkeleyDB.cmake
|
||||
FindFMODEX.cmake
|
||||
FindGLH.cmake
|
||||
FindGoogleBreakpad.cmake
|
||||
FindHUNSPELL.cmake
|
||||
|
|
@ -38,7 +37,7 @@ set(cmake_SOURCE_FILES
|
|||
FindURIPARSER.cmake
|
||||
FindXmlRpcEpi.cmake
|
||||
FindZLIB.cmake
|
||||
FMODEX.cmake
|
||||
FMODSTUDIO.cmake
|
||||
FreeType.cmake
|
||||
GLEXT.cmake
|
||||
GLH.cmake
|
||||
|
|
|
|||
|
|
@ -77,14 +77,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 (FMODSTUDIO)
|
||||
set(debug_files ${debug_files} fmodL.dll)
|
||||
set(release_files ${release_files} fmod.dll)
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
#*******************************
|
||||
# Copy MS C runtime dlls, required for packaging.
|
||||
|
|
@ -167,10 +163,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 (FMODSTUDIO)
|
||||
set(debug_files ${debug_files} libfmodL.dylib)
|
||||
set(release_files ${release_files} libfmod.dylib)
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
elseif(LINUX)
|
||||
# linux is weird, multiple side by side configurations aren't supported
|
||||
|
|
@ -217,10 +213,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 (FMODSTUDIO)
|
||||
set(debug_files ${debug_files} "libfmodL.so")
|
||||
set(release_files ${release_files} "libfmod.so")
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
else(WINDOWS)
|
||||
message(STATUS "WARNING: unrecognized platform for staging 3rd party libs, skipping...")
|
||||
|
|
|
|||
|
|
@ -1,46 +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)
|
||||
set(FMODEX_LIBRARY
|
||||
debug fmodexL_vc
|
||||
optimized fmodex_vc)
|
||||
elseif (DARWIN)
|
||||
set(FMODEX_LIBRARY
|
||||
debug fmodexL
|
||||
optimized fmodex)
|
||||
elseif (LINUX)
|
||||
set(FMODEX_LIBRARY
|
||||
debug fmodexL
|
||||
optimized fmodex)
|
||||
endif (WINDOWS)
|
||||
set(FMODEX_LIBRARIES ${FMODEX_LIBRARY})
|
||||
set(FMODEX_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/fmodex)
|
||||
endif (FMODEX_LIBRARY AND FMODEX_INCLUDE_DIR)
|
||||
endif (USESYSTEMLIBS)
|
||||
endif (FMODEX)
|
||||
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
# -*- cmake -*-
|
||||
|
||||
# FMODSTUDIO can be set when launching the make using the argument -DFMODSTUDIO:BOOL=ON
|
||||
# When building using proprietary binaries though (i.e. having access to LL private servers),
|
||||
# we always build with FMODSTUDIO.
|
||||
if (INSTALL_PROPRIETARY)
|
||||
set(FMODSTUDIO ON CACHE BOOL "Using FMODSTUDIO sound library.")
|
||||
endif (INSTALL_PROPRIETARY)
|
||||
|
||||
if (FMODSTUDIO)
|
||||
if (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR)
|
||||
# If the path have been specified in the arguments, use that
|
||||
set(FMODSTUDIO_LIBRARIES ${FMODSTUDIO_LIBRARY})
|
||||
else (FMODSTUDIO_LIBRARY AND FMODSTUDIO_INCLUDE_DIR)
|
||||
# If not, we're going to try to get the package listed in autobuild.xml
|
||||
# Note: if you're not using INSTALL_PROPRIETARY, the package URL should be local (file:/// URL)
|
||||
# as accessing the private LL location will fail if you don't have the credential
|
||||
include(Prebuilt)
|
||||
use_prebuilt_binary(fmodstudio)
|
||||
if (WINDOWS)
|
||||
set(FMODSTUDIO_LIBRARY
|
||||
debug fmodL_vc
|
||||
optimized fmod_vc)
|
||||
elseif (DARWIN)
|
||||
#despite files being called libfmod.dylib, we are searching for fmod
|
||||
set(FMODSTUDIO_LIBRARY
|
||||
debug fmodL
|
||||
optimized fmod)
|
||||
elseif (LINUX)
|
||||
set(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 (FMODSTUDIO)
|
||||
|
||||
|
|
@ -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
|
||||
)
|
||||
|
|
@ -4,7 +4,7 @@ project(llaudio)
|
|||
|
||||
include(00-Common)
|
||||
include(LLAudio)
|
||||
include(FMODEX)
|
||||
include(FMODSTUDIO)
|
||||
include(OPENAL)
|
||||
include(LLCommon)
|
||||
include(LLMath)
|
||||
|
|
@ -42,22 +42,22 @@ set(llaudio_HEADER_FILES
|
|||
llwindgen.h
|
||||
)
|
||||
|
||||
if (FMODEX)
|
||||
if (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 (FMODSTUDIO)
|
||||
|
||||
if (OPENAL)
|
||||
list(APPEND llaudio_SOURCE_FILES
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ void LLAudioEngine::setDefaults()
|
|||
}
|
||||
|
||||
|
||||
bool LLAudioEngine::init(const S32 num_channels, void* userdata)
|
||||
bool LLAudioEngine::init(const S32 num_channels, void* userdata, const std::string &app_title)
|
||||
{
|
||||
setDefaults();
|
||||
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ public:
|
|||
virtual ~LLAudioEngine();
|
||||
|
||||
// initialization/startup/shutdown
|
||||
virtual bool init(const S32 num_channels, void *userdata);
|
||||
virtual bool init(const S32 num_channels, void *userdata, const std::string &app_title);
|
||||
virtual std::string getDriverName(bool verbose) = 0;
|
||||
virtual void shutdown();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,753 @@
|
|||
/**
|
||||
* @file audioengine_fmodstudio.cpp
|
||||
* @brief Implementation of LLAudioEngine class abstracting the audio
|
||||
* support as a FMODSTUDIO implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2020&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2020, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
#include "llstreamingaudio_fmodstudio.h"
|
||||
|
||||
#include "llaudioengine_fmodstudio.h"
|
||||
#include "lllistener_fmodstudio.h"
|
||||
|
||||
#include "llerror.h"
|
||||
#include "llmath.h"
|
||||
#include "llrand.h"
|
||||
|
||||
#include "fmodstudio/fmod.hpp"
|
||||
#include "fmodstudio/fmod_errors.h"
|
||||
#include "lldir.h"
|
||||
#include "llapr.h"
|
||||
|
||||
#include "sound_ids.h"
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels);
|
||||
|
||||
FMOD::ChannelGroup *LLAudioEngine_FMODSTUDIO::mChannelGroups[LLAudioEngine::AUDIO_TYPE_COUNT] = {0};
|
||||
|
||||
LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler)
|
||||
: mInited(false),
|
||||
mWindGen(NULL),
|
||||
mWindDSP(NULL),
|
||||
mSystem(NULL),
|
||||
mEnableProfiler(enable_profiler),
|
||||
mWindDSPDesc(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioEngine_FMODSTUDIO::~LLAudioEngine_FMODSTUDIO()
|
||||
{
|
||||
// mWindDSPDesc, mWindGen and mWindDSP get cleaned up on cleanupWind in LLAudioEngine::shutdown()
|
||||
// mSystem gets cleaned up at shutdown()
|
||||
}
|
||||
|
||||
|
||||
static inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
|
||||
{
|
||||
if (result == FMOD_OK)
|
||||
return false;
|
||||
LL_DEBUGS("FMOD") << string << " Error: " << FMOD_ErrorString(result) << LL_ENDL;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODSTUDIO::init(const S32 num_channels, void* userdata, const std::string &app_title)
|
||||
{
|
||||
U32 version;
|
||||
FMOD_RESULT result;
|
||||
|
||||
LL_DEBUGS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() initializing FMOD" << LL_ENDL;
|
||||
|
||||
result = FMOD::System_Create(&mSystem);
|
||||
if (Check_FMOD_Error(result, "FMOD::System_Create"))
|
||||
return false;
|
||||
|
||||
//will call LLAudioEngine_FMODSTUDIO::allocateListener, which needs a valid mSystem pointer.
|
||||
LLAudioEngine::init(num_channels, userdata, app_title);
|
||||
|
||||
result = mSystem->getVersion(&version);
|
||||
Check_FMOD_Error(result, "FMOD::System::getVersion");
|
||||
|
||||
if (version < FMOD_VERSION)
|
||||
{
|
||||
LL_WARNS("AppInit") << "FMOD Studio version mismatch, actual: " << version
|
||||
<< " expected:" << FMOD_VERSION << LL_ENDL;
|
||||
}
|
||||
|
||||
// In this case, all sounds, PLUS wind and stream will be software.
|
||||
result = mSystem->setSoftwareChannels(num_channels + 2);
|
||||
Check_FMOD_Error(result, "FMOD::System::setSoftwareChannels");
|
||||
|
||||
FMOD_ADVANCEDSETTINGS settings;
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
settings.cbSize = sizeof(FMOD_ADVANCEDSETTINGS);
|
||||
settings.resamplerMethod = FMOD_DSP_RESAMPLER_LINEAR;
|
||||
|
||||
result = mSystem->setAdvancedSettings(&settings);
|
||||
Check_FMOD_Error(result, "FMOD::System::setAdvancedSettings");
|
||||
|
||||
// FMOD_INIT_THREAD_UNSAFE Disables thread safety for API calls.
|
||||
// Only use this if FMOD is being called from a single thread, and if Studio API is not being used.
|
||||
U32 fmod_flags = FMOD_INIT_NORMAL | FMOD_INIT_3D_RIGHTHANDED | FMOD_INIT_THREAD_UNSAFE;
|
||||
if (mEnableProfiler)
|
||||
{
|
||||
fmod_flags |= FMOD_INIT_PROFILE_ENABLE;
|
||||
}
|
||||
|
||||
#if LL_LINUX
|
||||
bool audio_ok = false;
|
||||
|
||||
if (!audio_ok)
|
||||
{
|
||||
const char* env_string = getenv("LL_BAD_FMOD_PULSEAUDIO");
|
||||
if (NULL == env_string)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying PulseAudio audio output..." << LL_ENDL;
|
||||
if (mSystem->setOutput(FMOD_OUTPUTTYPE_PULSEAUDIO) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels + 2, fmod_flags, const_cast<char*>(app_title.c_str()))) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "PulseAudio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "PulseAudio audio output FAILED to initialize");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "PulseAudio audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
const char* env_string = getenv("LL_BAD_FMOD_ALSA");
|
||||
if (NULL == env_string)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "Trying ALSA audio output..." << LL_ENDL;
|
||||
if (mSystem->setOutput(FMOD_OUTPUTTYPE_ALSA) == FMOD_OK &&
|
||||
(result = mSystem->init(num_channels + 2, fmod_flags, 0)) == FMOD_OK)
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ALSA audio output initialized OKAY" << LL_ENDL;
|
||||
audio_ok = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check_FMOD_Error(result, "ALSA audio output FAILED to initialize");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_DEBUGS("AppInit") << "ALSA audio output SKIPPED" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
if (!audio_ok)
|
||||
{
|
||||
LL_WARNS("AppInit") << "Overall audio init failure." << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're interested in logging which output method we
|
||||
// ended up with, for QA purposes.
|
||||
FMOD_OUTPUTTYPE output_type;
|
||||
mSystem->getOutput(&output_type);
|
||||
switch (output_type)
|
||||
{
|
||||
case FMOD_OUTPUTTYPE_NOSOUND:
|
||||
LL_INFOS("AppInit") << "Audio output: NoSound" << LL_ENDL; break;
|
||||
case FMOD_OUTPUTTYPE_PULSEAUDIO:
|
||||
LL_INFOS("AppInit") << "Audio output: PulseAudio" << LL_ENDL; break;
|
||||
case FMOD_OUTPUTTYPE_ALSA:
|
||||
LL_INFOS("AppInit") << "Audio output: ALSA" << LL_ENDL; break;
|
||||
default:
|
||||
LL_INFOS("AppInit") << "Audio output: Unknown!" << LL_ENDL; break;
|
||||
};
|
||||
#else // LL_LINUX
|
||||
|
||||
// initialize the FMOD engine
|
||||
// number of channel in this case looks to be identiacal to number of max simultaneously
|
||||
// playing objects and we can set practically any number
|
||||
result = mSystem->init(num_channels + 2, fmod_flags, 0);
|
||||
if (Check_FMOD_Error(result, "Error initializing FMOD Studio with default settins, retrying with other format"))
|
||||
{
|
||||
result = mSystem->setSoftwareFormat(44100, FMOD_SPEAKERMODE_STEREO, 0/*- ignore*/);
|
||||
if (Check_FMOD_Error(result, "Error setting sotware format. Can't init."))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
result = mSystem->init(num_channels + 2, fmod_flags, 0);
|
||||
}
|
||||
if (Check_FMOD_Error(result, "Error initializing FMOD Studio"))
|
||||
{
|
||||
// If it fails here and (result == FMOD_ERR_OUTPUT_CREATEBUFFER),
|
||||
// we can retry with other settings
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// set up our favourite FMOD-native streaming audio implementation if none has already been added
|
||||
if (!getStreamingAudioImpl()) // no existing implementation added
|
||||
setStreamingAudioImpl(new LLStreamingAudio_FMODSTUDIO(mSystem));
|
||||
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL;
|
||||
|
||||
int r_numbuffers, r_samplerate, r_channels;
|
||||
unsigned int r_bufferlength;
|
||||
char r_name[512];
|
||||
int latency = 100;
|
||||
mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers);
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL;
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_numbuffers=" << r_numbuffers << LL_ENDL;
|
||||
|
||||
mSystem->getDriverInfo(0, r_name, 511, NULL, &r_samplerate, NULL, &r_channels);
|
||||
r_name[511] = '\0';
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): r_name=\"" << r_name << "\"" << LL_ENDL;
|
||||
|
||||
if (r_samplerate != 0)
|
||||
latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate);
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): latency=" << latency << "ms" << LL_ENDL;
|
||||
|
||||
mInited = true;
|
||||
|
||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): initialization complete." << LL_ENDL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose)
|
||||
{
|
||||
llassert_always(mSystem);
|
||||
if (verbose)
|
||||
{
|
||||
U32 version;
|
||||
if (!Check_FMOD_Error(mSystem->getVersion(&version), "FMOD::System::getVersion"))
|
||||
{
|
||||
return llformat("FMOD Studio %1x.%02x.%02x", version >> 16, version >> 8 & 0x000000FF, version & 0x000000FF);
|
||||
}
|
||||
}
|
||||
return "FMOD STUDIO";
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODSTUDIO::allocateListener(void)
|
||||
{
|
||||
mListenerp = (LLListener *) new LLListener_FMODSTUDIO(mSystem);
|
||||
if (!mListenerp)
|
||||
{
|
||||
LL_WARNS("FMOD") << "Listener creation failed" << LL_ENDL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODSTUDIO::shutdown()
|
||||
{
|
||||
stopInternetStream();
|
||||
|
||||
LL_INFOS("FMOD") << "About to LLAudioEngine::shutdown()" << LL_ENDL;
|
||||
LLAudioEngine::shutdown();
|
||||
|
||||
LL_INFOS("FMOD") << "LLAudioEngine_FMODSTUDIO::shutdown() closing FMOD Studio" << LL_ENDL;
|
||||
if (mSystem)
|
||||
{
|
||||
mSystem->close();
|
||||
mSystem->release();
|
||||
}
|
||||
LL_INFOS("FMOD") << "LLAudioEngine_FMODSTUDIO::shutdown() done closing FMOD Studio" << LL_ENDL;
|
||||
|
||||
delete mListenerp;
|
||||
mListenerp = NULL;
|
||||
}
|
||||
|
||||
|
||||
LLAudioBuffer * LLAudioEngine_FMODSTUDIO::createBuffer()
|
||||
{
|
||||
return new LLAudioBufferFMODSTUDIO(mSystem);
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannel * LLAudioEngine_FMODSTUDIO::createChannel()
|
||||
{
|
||||
return new LLAudioChannelFMODSTUDIO(mSystem);
|
||||
}
|
||||
|
||||
bool LLAudioEngine_FMODSTUDIO::initWind()
|
||||
{
|
||||
mNextWindUpdate = 0.0;
|
||||
|
||||
if (!mWindDSPDesc)
|
||||
{
|
||||
mWindDSPDesc = new FMOD_DSP_DESCRIPTION();
|
||||
}
|
||||
|
||||
if (!mWindDSP)
|
||||
{
|
||||
memset(mWindDSPDesc, 0, sizeof(*mWindDSPDesc)); //Set everything to zero
|
||||
strncpy(mWindDSPDesc->name, "Wind Unit", sizeof(mWindDSPDesc->name));
|
||||
mWindDSPDesc->pluginsdkversion = FMOD_PLUGIN_SDK_VERSION;
|
||||
mWindDSPDesc->read = &windCallback; // Assign callback - may be called from arbitrary threads
|
||||
if (Check_FMOD_Error(mSystem->createDSP(mWindDSPDesc, &mWindDSP), "FMOD::createDSP"))
|
||||
return false;
|
||||
|
||||
if (mWindGen)
|
||||
delete mWindGen;
|
||||
|
||||
int frequency = 44100;
|
||||
|
||||
FMOD_SPEAKERMODE mode;
|
||||
if (Check_FMOD_Error(mSystem->getSoftwareFormat(&frequency, &mode, nullptr), "FMOD::System::getSoftwareFormat"))
|
||||
{
|
||||
cleanupWind();
|
||||
return false;
|
||||
}
|
||||
|
||||
mWindGen = new LLWindGen<MIXBUFFERFORMAT>((U32)frequency);
|
||||
|
||||
if (Check_FMOD_Error(mWindDSP->setUserData((void*)mWindGen), "FMOD::DSP::setUserData"))
|
||||
{
|
||||
cleanupWind();
|
||||
return false;
|
||||
}
|
||||
if (Check_FMOD_Error(mWindDSP->setChannelFormat(FMOD_CHANNELMASK_STEREO, 2, mode), "FMOD::DSP::setChannelFormat"))
|
||||
{
|
||||
cleanupWind();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// *TODO: Should this guard against multiple plays?
|
||||
if (Check_FMOD_Error(mSystem->playDSP(mWindDSP, nullptr, false, nullptr), "FMOD::System::playDSP"))
|
||||
{
|
||||
cleanupWind();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioEngine_FMODSTUDIO::cleanupWind()
|
||||
{
|
||||
if (mWindDSP)
|
||||
{
|
||||
FMOD::ChannelGroup* master_group = NULL;
|
||||
if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")
|
||||
&& master_group)
|
||||
{
|
||||
master_group->removeDSP(mWindDSP);
|
||||
}
|
||||
mWindDSP->release();
|
||||
mWindDSP = NULL;
|
||||
}
|
||||
|
||||
delete mWindDSPDesc;
|
||||
mWindDSPDesc = NULL;
|
||||
|
||||
delete mWindGen;
|
||||
mWindGen = NULL;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLAudioEngine_FMODSTUDIO::updateWind(LLVector3 wind_vec, F32 camera_height_above_water)
|
||||
{
|
||||
LLVector3 wind_pos;
|
||||
F64 pitch;
|
||||
F64 center_freq;
|
||||
|
||||
if (!mEnableWind)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
|
||||
{
|
||||
|
||||
// wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
|
||||
// need to convert this to the conventional orientation DS3D and OpenAL use
|
||||
// where +X = right, +Y = up, +Z = backwards
|
||||
|
||||
wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
|
||||
|
||||
// cerr << "Wind update" << endl;
|
||||
|
||||
pitch = 1.0 + mapWindVecToPitch(wind_vec);
|
||||
center_freq = 80.0 * pow(pitch, 2.5*(mapWindVecToGain(wind_vec) + 1.0));
|
||||
|
||||
mWindGen->mTargetFreq = (F32)center_freq;
|
||||
mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
|
||||
mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLAudioEngine_FMODSTUDIO::setInternalGain(F32 gain)
|
||||
{
|
||||
if (!mInited)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
gain = llclamp(gain, 0.0f, 1.0f);
|
||||
|
||||
FMOD::ChannelGroup* master_group = NULL;
|
||||
if (!Check_FMOD_Error(mSystem->getMasterChannelGroup(&master_group), "FMOD::System::getMasterChannelGroup")
|
||||
&& master_group)
|
||||
{
|
||||
master_group->setVolume(gain);
|
||||
}
|
||||
|
||||
LLStreamingAudioInterface *saimpl = getStreamingAudioImpl();
|
||||
if (saimpl)
|
||||
{
|
||||
// fmod likes its streaming audio channel gain re-asserted after
|
||||
// master volume change.
|
||||
saimpl->setGain(saimpl->getGain());
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODSTUDIO implementation
|
||||
//
|
||||
|
||||
LLAudioChannelFMODSTUDIO::LLAudioChannelFMODSTUDIO(FMOD::System *system) : LLAudioChannel(), mSystemp(system), mChannelp(NULL), mLastSamplePos(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioChannelFMODSTUDIO::~LLAudioChannelFMODSTUDIO()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
bool LLAudioChannelFMODSTUDIO::updateBuffer()
|
||||
{
|
||||
if (!mCurrentSourcep)
|
||||
{
|
||||
// This channel isn't associated with any source, nothing
|
||||
// to be updated
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LLAudioChannel::updateBuffer())
|
||||
{
|
||||
// Base class update returned true, which means that we need to actually
|
||||
// set up the channel for a different buffer.
|
||||
|
||||
LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentSourcep->getCurrentBuffer();
|
||||
|
||||
// Grab the FMOD sample associated with the buffer
|
||||
FMOD::Sound *soundp = bufferp->getSound();
|
||||
if (!soundp)
|
||||
{
|
||||
// This is bad, there should ALWAYS be a sound associated with a legit
|
||||
// buffer.
|
||||
LL_ERRS() << "No FMOD sound!" << LL_ENDL;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Actually play the sound. Start it off paused so we can do all the necessary
|
||||
// setup.
|
||||
if (!mChannelp)
|
||||
{
|
||||
FMOD_RESULT result = getSystem()->playSound(soundp, NULL /*free channel?*/, true, &mChannelp);
|
||||
Check_FMOD_Error(result, "FMOD::System::playSound");
|
||||
}
|
||||
|
||||
// Setting up channel mChannelID
|
||||
}
|
||||
|
||||
// If we have a source for the channel, we need to update its gain.
|
||||
if (mCurrentSourcep)
|
||||
{
|
||||
// SJB: warnings can spam and hurt framerate, disabling
|
||||
//FMOD_RESULT result;
|
||||
|
||||
mChannelp->setVolume(getSecondaryGain() * mCurrentSourcep->getGain());
|
||||
//Check_FMOD_Error(result, "FMOD::Channel::setVolume");
|
||||
|
||||
mChannelp->setMode(mCurrentSourcep->isLoop() ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
|
||||
/*if(Check_FMOD_Error(result, "FMOD::Channel::setMode"))
|
||||
{
|
||||
S32 index;
|
||||
mChannelp->getIndex(&index);
|
||||
LL_WARNS() << "Channel " << index << "Source ID: " << mCurrentSourcep->getID()
|
||||
<< " at " << mCurrentSourcep->getPositionGlobal() << LL_ENDL;
|
||||
}*/
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::update3DPosition()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// We're not actually a live channel (i.e., we're not playing back anything)
|
||||
return;
|
||||
}
|
||||
|
||||
LLAudioBufferFMODSTUDIO *bufferp = (LLAudioBufferFMODSTUDIO *)mCurrentBufferp;
|
||||
if (!bufferp)
|
||||
{
|
||||
// We don't have a buffer associated with us (should really have been picked up
|
||||
// by the above if.
|
||||
return;
|
||||
}
|
||||
|
||||
if (mCurrentSourcep->isAmbient())
|
||||
{
|
||||
// Ambient sound, don't need to do any positional updates.
|
||||
set3DMode(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Localized sound. Update the position and velocity of the sound.
|
||||
set3DMode(true);
|
||||
|
||||
LLVector3 float_pos;
|
||||
float_pos.setVec(mCurrentSourcep->getPositionGlobal());
|
||||
FMOD_RESULT result = mChannelp->set3DAttributes((FMOD_VECTOR*)float_pos.mV, (FMOD_VECTOR*)mCurrentSourcep->getVelocity().mV);
|
||||
Check_FMOD_Error(result, "FMOD::Channel::set3DAttributes");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::updateLoop()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// May want to clear up the loop/sample counters.
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Hack: We keep track of whether we looped or not by seeing when the
|
||||
// sample position looks like it's going backwards. Not reliable; may
|
||||
// yield false negatives.
|
||||
//
|
||||
U32 cur_pos;
|
||||
mChannelp->getPosition(&cur_pos, FMOD_TIMEUNIT_PCMBYTES);
|
||||
|
||||
if (cur_pos < (U32)mLastSamplePos)
|
||||
{
|
||||
mLoopedThisFrame = true;
|
||||
}
|
||||
mLastSamplePos = cur_pos;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::cleanup()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
// Aborting cleanup with no channel handle.
|
||||
return;
|
||||
}
|
||||
|
||||
//Cleaning up channel mChannelID
|
||||
Check_FMOD_Error(mChannelp->stop(), "FMOD::Channel::stop");
|
||||
|
||||
mCurrentBufferp = NULL;
|
||||
mChannelp = NULL;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::play()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
LL_WARNS() << "Playing without a channel handle, aborting" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
Check_FMOD_Error(mChannelp->setPaused(false), "FMOD::Channel::pause");
|
||||
|
||||
getSource()->setPlayedOnce(true);
|
||||
|
||||
if (LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()])
|
||||
mChannelp->setChannelGroup(LLAudioEngine_FMODSTUDIO::mChannelGroups[getSource()->getType()]);
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::playSynced(LLAudioChannel *channelp)
|
||||
{
|
||||
LLAudioChannelFMODSTUDIO *fmod_channelp = (LLAudioChannelFMODSTUDIO*)channelp;
|
||||
if (!(fmod_channelp->mChannelp && mChannelp))
|
||||
{
|
||||
// Don't have channels allocated to both the master and the slave
|
||||
return;
|
||||
}
|
||||
|
||||
U32 cur_pos;
|
||||
if (Check_FMOD_Error(mChannelp->getPosition(&cur_pos, FMOD_TIMEUNIT_PCMBYTES), "Unable to retrieve current position"))
|
||||
return;
|
||||
|
||||
cur_pos %= mCurrentBufferp->getLength();
|
||||
|
||||
// Try to match the position of our sync master
|
||||
Check_FMOD_Error(mChannelp->setPosition(cur_pos, FMOD_TIMEUNIT_PCMBYTES), "Unable to set current position");
|
||||
|
||||
// Start us playing
|
||||
play();
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioChannelFMODSTUDIO::isPlaying()
|
||||
{
|
||||
if (!mChannelp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool paused, playing;
|
||||
mChannelp->getPaused(&paused);
|
||||
mChannelp->isPlaying(&playing);
|
||||
return !paused && playing;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// LLAudioChannelFMODSTUDIO implementation
|
||||
//
|
||||
|
||||
|
||||
LLAudioBufferFMODSTUDIO::LLAudioBufferFMODSTUDIO(FMOD::System *system) : mSystemp(system), mSoundp(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
LLAudioBufferFMODSTUDIO::~LLAudioBufferFMODSTUDIO()
|
||||
{
|
||||
if (mSoundp)
|
||||
{
|
||||
mSoundp->release();
|
||||
mSoundp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLAudioBufferFMODSTUDIO::loadWAV(const std::string& filename)
|
||||
{
|
||||
// Try to open a wav file from disk. This will eventually go away, as we don't
|
||||
// really want to block doing this.
|
||||
if (filename.empty())
|
||||
{
|
||||
// invalid filename, abort.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!LLAPRFile::isExist(filename, NULL, LL_APR_RPB))
|
||||
{
|
||||
// File not found, abort.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSoundp)
|
||||
{
|
||||
// If there's already something loaded in this buffer, clean it up.
|
||||
mSoundp->release();
|
||||
mSoundp = NULL;
|
||||
}
|
||||
|
||||
FMOD_MODE base_mode = FMOD_LOOP_NORMAL;
|
||||
FMOD_CREATESOUNDEXINFO exinfo;
|
||||
memset(&exinfo, 0, sizeof(exinfo));
|
||||
exinfo.cbsize = sizeof(exinfo);
|
||||
exinfo.suggestedsoundtype = FMOD_SOUND_TYPE_WAV; //Hint to speed up loading.
|
||||
// Load up the wav file into an fmod sample (since 1.05 fmod studio expects everything in UTF-8)
|
||||
FMOD_RESULT result = getSystem()->createSound(filename.c_str(), base_mode, &exinfo, &mSoundp);
|
||||
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
// We failed to load the file for some reason.
|
||||
LL_WARNS() << "Could not load data '" << filename << "': " << FMOD_ErrorString(result) << LL_ENDL;
|
||||
|
||||
//
|
||||
// If we EVER want to load wav files provided by end users, we need
|
||||
// to rethink this!
|
||||
//
|
||||
// file is probably corrupt - remove it.
|
||||
LLFile::remove(filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Everything went well, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
U32 LLAudioBufferFMODSTUDIO::getLength()
|
||||
{
|
||||
if (!mSoundp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
U32 length;
|
||||
mSoundp->getLength(&length, FMOD_TIMEUNIT_PCMBYTES);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
void LLAudioChannelFMODSTUDIO::set3DMode(bool use3d)
|
||||
{
|
||||
FMOD_MODE current_mode;
|
||||
if (mChannelp->getMode(¤t_mode) != FMOD_OK)
|
||||
return;
|
||||
FMOD_MODE new_mode = current_mode;
|
||||
new_mode &= ~(use3d ? FMOD_2D : FMOD_3D);
|
||||
new_mode |= use3d ? FMOD_3D : FMOD_2D;
|
||||
|
||||
if (current_mode != new_mode)
|
||||
{
|
||||
mChannelp->setMode(new_mode);
|
||||
}
|
||||
}
|
||||
|
||||
// *NOTE: This is almost certainly being called on the mixer thread,
|
||||
// not the main thread. May have implications for callees or audio
|
||||
// engine shutdown.
|
||||
|
||||
FMOD_RESULT F_CALLBACK windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels)
|
||||
{
|
||||
// inbuffer = fmod's original mixbuffer.
|
||||
// outbuffer = the buffer passed from the previous DSP unit.
|
||||
// length = length in samples at this mix time.
|
||||
|
||||
LLWindGen<LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT> *windgen = NULL;
|
||||
FMOD::DSP *thisdsp = (FMOD::DSP *)dsp_state->instance;
|
||||
|
||||
thisdsp->getUserData((void **)&windgen);
|
||||
|
||||
if (windgen)
|
||||
{
|
||||
windgen->windGenerate((LLAudioEngine_FMODSTUDIO::MIXBUFFERFORMAT *)outbuffer, length);
|
||||
}
|
||||
|
||||
return FMOD_OK;
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
* @file audioengine_fmodex.h
|
||||
* @file audioengine_fmodstudio.h
|
||||
* @brief Definition of LLAudioEngine class abstracting the audio
|
||||
* support as a FMODEX implementation
|
||||
* support as a FMODSTUDIO implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* $LicenseInfo:firstyear=2020&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2014, Linden Research, Inc.
|
||||
* Copyright (C) 2020, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
|
@ -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,14 +44,14 @@ namespace FMOD
|
|||
typedef struct FMOD_DSP_DESCRIPTION FMOD_DSP_DESCRIPTION;
|
||||
|
||||
//Interfaces
|
||||
class LLAudioEngine_FMODEX : public LLAudioEngine
|
||||
class LLAudioEngine_FMODSTUDIO : public LLAudioEngine
|
||||
{
|
||||
public:
|
||||
LLAudioEngine_FMODEX(bool enable_profiler);
|
||||
virtual ~LLAudioEngine_FMODEX();
|
||||
LLAudioEngine_FMODSTUDIO(bool enable_profiler);
|
||||
virtual ~LLAudioEngine_FMODSTUDIO();
|
||||
|
||||
// initialization/startup/shutdown
|
||||
virtual bool init(const S32 num_channels, void *user_data);
|
||||
virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title);
|
||||
virtual std::string getDriverName(bool verbose);
|
||||
virtual void allocateListener();
|
||||
|
||||
|
|
@ -85,11 +85,11 @@ public:
|
|||
};
|
||||
|
||||
|
||||
class LLAudioChannelFMODEX : public LLAudioChannel
|
||||
class LLAudioChannelFMODSTUDIO : public LLAudioChannel
|
||||
{
|
||||
public:
|
||||
LLAudioChannelFMODEX(FMOD::System *audioengine);
|
||||
virtual ~LLAudioChannelFMODEX();
|
||||
LLAudioChannelFMODSTUDIO(FMOD::System *audioengine);
|
||||
virtual ~LLAudioChannelFMODSTUDIO();
|
||||
|
||||
protected:
|
||||
/*virtual*/ void play();
|
||||
|
|
@ -110,15 +110,15 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
class LLAudioBufferFMODEX : public LLAudioBuffer
|
||||
class LLAudioBufferFMODSTUDIO : 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;
|
||||
friend class LLAudioChannelFMODSTUDIO;
|
||||
protected:
|
||||
FMOD::System *getSystem() const {return mSystemp;}
|
||||
FMOD::System *mSystemp;
|
||||
|
|
@ -127,4 +127,4 @@ protected:
|
|||
};
|
||||
|
||||
|
||||
#endif // LL_AUDIOENGINE_FMODEX_H
|
||||
#endif // LL_AUDIOENGINE_FMODSTUDIO_H
|
||||
|
|
@ -52,7 +52,7 @@ LLAudioEngine_OpenAL::~LLAudioEngine_OpenAL()
|
|||
}
|
||||
|
||||
// virtual
|
||||
bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata)
|
||||
bool LLAudioEngine_OpenAL::init(const S32 num_channels, void* userdata, const std::string &app_title)
|
||||
{
|
||||
mWindGen = NULL;
|
||||
LLAudioEngine::init(num_channels, userdata);
|
||||
|
|
@ -239,6 +239,13 @@ bool LLAudioChannelOpenAL::isPlaying()
|
|||
|
||||
bool LLAudioChannelOpenAL::updateBuffer()
|
||||
{
|
||||
if (!mCurrentSourcep)
|
||||
{
|
||||
// This channel isn't associated with any source, nothing
|
||||
// to be updated
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LLAudioChannel::updateBuffer())
|
||||
{
|
||||
// Base class update returned true, which means that we need to actually
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ class LLAudioEngine_OpenAL : public LLAudioEngine
|
|||
LLAudioEngine_OpenAL();
|
||||
virtual ~LLAudioEngine_OpenAL();
|
||||
|
||||
virtual bool init(const S32 num_channels, void *user_data);
|
||||
virtual std::string getDriverName(bool verbose);
|
||||
virtual bool init(const S32 num_channels, void *user_data, const std::string &app_title);
|
||||
virtual std::string getDriverName(bool verbose);
|
||||
virtual void allocateListener();
|
||||
|
||||
virtual void shutdown();
|
||||
|
|
|
|||
|
|
@ -1,140 +0,0 @@
|
|||
/**
|
||||
* @file listener_fmodex.cpp
|
||||
* @brief Implementation of LISTENER class abstracting the audio
|
||||
* support as a FMODEX implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llaudioengine.h"
|
||||
#include "lllistener_fmodex.h"
|
||||
#include "fmod.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// constructor
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODEX::LLListener_FMODEX(FMOD::System *system)
|
||||
{
|
||||
mSystem = system;
|
||||
init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODEX::~LLListener_FMODEX()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::init(void)
|
||||
{
|
||||
// do inherited
|
||||
LLListener::init();
|
||||
mDopplerFactor = 1.0f;
|
||||
mRolloffFactor = 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::translate(LLVector3 offset)
|
||||
{
|
||||
LLListener::translate(offset);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::setPosition(LLVector3 pos)
|
||||
{
|
||||
LLListener::setPosition(pos);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::setVelocity(LLVector3 vel)
|
||||
{
|
||||
LLListener::setVelocity(vel);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::orient(LLVector3 up, LLVector3 at)
|
||||
{
|
||||
LLListener::orient(up, at);
|
||||
|
||||
// Welcome to the transition between right and left
|
||||
// (coordinate systems, that is)
|
||||
// Leaving the at vector alone results in a L/R reversal
|
||||
// since DX is left-handed and we (LL, OpenGL, OpenAL) are right-handed
|
||||
at = -at;
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODEX::commitDeferredChanges()
|
||||
{
|
||||
if(!mSystem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mSystem->update();
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODEX::setRolloffFactor(F32 factor)
|
||||
{
|
||||
//An internal FMODEx optimization skips 3D updates if there have not been changes to the 3D sound environment.
|
||||
//Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well.
|
||||
//In short: Changing the position ticks a dirtyflag inside fmodex, which makes it not skip 3D processing next update call.
|
||||
if(mRolloffFactor != factor)
|
||||
{
|
||||
LLVector3 pos = mVelocity - LLVector3(0.f,0.f,.1f);
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL);
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mVelocity.mV, NULL, NULL, NULL);
|
||||
}
|
||||
mRolloffFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODEX::getRolloffFactor()
|
||||
{
|
||||
return mRolloffFactor;
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODEX::setDopplerFactor(F32 factor)
|
||||
{
|
||||
mDopplerFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODEX::getDopplerFactor()
|
||||
{
|
||||
return mDopplerFactor;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* @file listener_fmodstudio.cpp
|
||||
* @brief Implementation of LISTENER class abstracting the audio
|
||||
* support as a FMODSTUDIO implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2020&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2020, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llaudioengine.h"
|
||||
#include "lllistener_fmodstudio.h"
|
||||
#include "fmodstudio/fmod.hpp"
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// constructor
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODSTUDIO::LLListener_FMODSTUDIO(FMOD::System *system)
|
||||
{
|
||||
mSystem = system;
|
||||
init();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
LLListener_FMODSTUDIO::~LLListener_FMODSTUDIO()
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::init(void)
|
||||
{
|
||||
// do inherited
|
||||
LLListener::init();
|
||||
mDopplerFactor = 1.0f;
|
||||
mRolloffFactor = 1.0f;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::translate(LLVector3 offset)
|
||||
{
|
||||
LLListener::translate(offset);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::setPosition(LLVector3 pos)
|
||||
{
|
||||
LLListener::setPosition(pos);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::setVelocity(LLVector3 vel)
|
||||
{
|
||||
LLListener::setVelocity(vel);
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, (FMOD_VECTOR*)mVelocity.mV, (FMOD_VECTOR*)mListenAt.mV, (FMOD_VECTOR*)mListenUp.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::orient(LLVector3 up, LLVector3 at)
|
||||
{
|
||||
LLListener::orient(up, at);
|
||||
|
||||
// at = -at; by default Fmod studio is 'left-handed' but we are providing
|
||||
// flag FMOD_INIT_3D_RIGHTHANDED so no correction are needed
|
||||
|
||||
mSystem->set3DListenerAttributes(0, NULL, NULL, (FMOD_VECTOR*)at.mV, (FMOD_VECTOR*)up.mV);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void LLListener_FMODSTUDIO::commitDeferredChanges()
|
||||
{
|
||||
if (!mSystem)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mSystem->update();
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODSTUDIO::setRolloffFactor(F32 factor)
|
||||
{
|
||||
//An internal FMOD optimization skips 3D updates if there have not been changes to the 3D sound environment.
|
||||
// (this was true for FMODex, looks to be still true for FMOD STUDIO, but needs a recheck)
|
||||
//Sadly, a change in rolloff is not accounted for, thus we must touch the listener properties as well.
|
||||
//In short: Changing the position ticks a dirtyflag inside fmod, which makes it not skip 3D processing next update call.
|
||||
if (mRolloffFactor != factor)
|
||||
{
|
||||
LLVector3 pos = mPosition - LLVector3(0.f, 0.f, .1f);
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)pos.mV, NULL, NULL, NULL);
|
||||
mSystem->set3DListenerAttributes(0, (FMOD_VECTOR*)mPosition.mV, NULL, NULL, NULL);
|
||||
}
|
||||
mRolloffFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODSTUDIO::getRolloffFactor()
|
||||
{
|
||||
return mRolloffFactor;
|
||||
}
|
||||
|
||||
|
||||
void LLListener_FMODSTUDIO::setDopplerFactor(F32 factor)
|
||||
{
|
||||
mDopplerFactor = factor;
|
||||
mSystem->set3DSettings(mDopplerFactor, 1.f, mRolloffFactor);
|
||||
}
|
||||
|
||||
|
||||
F32 LLListener_FMODSTUDIO::getDopplerFactor()
|
||||
{
|
||||
return mDopplerFactor;
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
* @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 3D implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* $LicenseInfo:firstyear=2020&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
* Copyright (C) 2020, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
|
|
@ -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,27 +37,27 @@ namespace FMOD
|
|||
}
|
||||
|
||||
//Interfaces
|
||||
class LLListener_FMODEX : public LLListener
|
||||
class LLListener_FMODSTUDIO : public LLListener
|
||||
{
|
||||
public:
|
||||
LLListener_FMODEX(FMOD::System *system);
|
||||
virtual ~LLListener_FMODEX();
|
||||
virtual void init();
|
||||
public:
|
||||
LLListener_FMODSTUDIO(FMOD::System *system);
|
||||
virtual ~LLListener_FMODSTUDIO();
|
||||
virtual void init();
|
||||
|
||||
virtual void translate(LLVector3 offset);
|
||||
virtual void setPosition(LLVector3 pos);
|
||||
virtual void setVelocity(LLVector3 vel);
|
||||
virtual void orient(LLVector3 up, LLVector3 at);
|
||||
virtual void commitDeferredChanges();
|
||||
virtual void translate(LLVector3 offset);
|
||||
virtual void setPosition(LLVector3 pos);
|
||||
virtual void setVelocity(LLVector3 vel);
|
||||
virtual void orient(LLVector3 up, LLVector3 at);
|
||||
virtual void commitDeferredChanges();
|
||||
|
||||
virtual void setDopplerFactor(F32 factor);
|
||||
virtual F32 getDopplerFactor();
|
||||
virtual void setRolloffFactor(F32 factor);
|
||||
virtual F32 getRolloffFactor();
|
||||
protected:
|
||||
FMOD::System *mSystem;
|
||||
F32 mDopplerFactor;
|
||||
F32 mRolloffFactor;
|
||||
virtual void setDopplerFactor(F32 factor);
|
||||
virtual F32 getDopplerFactor();
|
||||
virtual void setRolloffFactor(F32 factor);
|
||||
virtual F32 getRolloffFactor();
|
||||
protected:
|
||||
FMOD::System *mSystem;
|
||||
F32 mDopplerFactor;
|
||||
F32 mRolloffFactor;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,392 @@
|
|||
/**
|
||||
* @file streamingaudio_fmodstudio.cpp
|
||||
* @brief LLStreamingAudio_FMODSTUDIO implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2020&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2020, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llmath.h"
|
||||
|
||||
#include "fmodstudio/fmod.hpp"
|
||||
#include "fmodstudio/fmod_errors.h"
|
||||
|
||||
#include "llstreamingaudio_fmodstudio.h"
|
||||
|
||||
|
||||
class LLAudioStreamManagerFMODSTUDIO
|
||||
{
|
||||
public:
|
||||
LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url);
|
||||
FMOD::Channel* startStream();
|
||||
bool stopStream(); // Returns true if the stream was successfully stopped.
|
||||
bool ready();
|
||||
|
||||
const std::string& getURL() { return mInternetStreamURL; }
|
||||
|
||||
FMOD_OPENSTATE getOpenState(unsigned int* percentbuffered = NULL, bool* starving = NULL, bool* diskbusy = NULL);
|
||||
protected:
|
||||
FMOD::System* mSystem;
|
||||
FMOD::Channel* mStreamChannel;
|
||||
FMOD::Sound* mInternetStream;
|
||||
bool mReady;
|
||||
|
||||
std::string mInternetStreamURL;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Internet Streaming
|
||||
//---------------------------------------------------------------------------
|
||||
LLStreamingAudio_FMODSTUDIO::LLStreamingAudio_FMODSTUDIO(FMOD::System *system) :
|
||||
mSystem(system),
|
||||
mCurrentInternetStreamp(NULL),
|
||||
mFMODInternetStreamChannelp(NULL),
|
||||
mGain(1.0f)
|
||||
{
|
||||
// Number of milliseconds of audio to buffer for the audio card.
|
||||
// Must be larger than the usual Second Life frame stutter time.
|
||||
const U32 buffer_seconds = 10; //sec
|
||||
const U32 estimated_bitrate = 128; //kbit/sec
|
||||
mSystem->setStreamBufferSize(estimated_bitrate * buffer_seconds * 128/*bytes/kbit*/, FMOD_TIMEUNIT_RAWBYTES);
|
||||
|
||||
// Here's where we set the size of the network buffer and some buffering
|
||||
// parameters. In this case we want a network buffer of 16k, we want it
|
||||
// to prebuffer 40% of that when we first connect, and we want it
|
||||
// to rebuffer 80% of that whenever we encounter a buffer underrun.
|
||||
|
||||
// Leave the net buffer properties at the default.
|
||||
//FSOUND_Stream_Net_SetBufferProperties(20000, 40, 80);
|
||||
}
|
||||
|
||||
|
||||
LLStreamingAudio_FMODSTUDIO::~LLStreamingAudio_FMODSTUDIO()
|
||||
{
|
||||
// nothing interesting/safe to do.
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::start(const std::string& url)
|
||||
{
|
||||
//if (!mInited)
|
||||
//{
|
||||
// LL_WARNS() << "startInternetStream before audio initialized" << LL_ENDL;
|
||||
// return;
|
||||
//}
|
||||
|
||||
// "stop" stream but don't clear url, etc. in case url == mInternetStreamURL
|
||||
stop();
|
||||
|
||||
if (!url.empty())
|
||||
{
|
||||
LL_INFOS() << "Starting internet stream: " << url << LL_ENDL;
|
||||
mCurrentInternetStreamp = new LLAudioStreamManagerFMODSTUDIO(mSystem, url);
|
||||
mURL = url;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_INFOS() << "Set internet stream to null" << LL_ENDL;
|
||||
mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::update()
|
||||
{
|
||||
// Kill dead internet streams, if possible
|
||||
std::list<LLAudioStreamManagerFMODSTUDIO *>::iterator iter;
|
||||
for (iter = mDeadStreams.begin(); iter != mDeadStreams.end();)
|
||||
{
|
||||
LLAudioStreamManagerFMODSTUDIO *streamp = *iter;
|
||||
if (streamp->stopStream())
|
||||
{
|
||||
LL_INFOS() << "Closed dead stream" << LL_ENDL;
|
||||
delete streamp;
|
||||
mDeadStreams.erase(iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter++;
|
||||
}
|
||||
}
|
||||
|
||||
// Don't do anything if there are no streams playing
|
||||
if (!mCurrentInternetStreamp)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int progress;
|
||||
bool starving;
|
||||
bool diskbusy;
|
||||
FMOD_OPENSTATE open_state = mCurrentInternetStreamp->getOpenState(&progress, &starving, &diskbusy);
|
||||
|
||||
if (open_state == FMOD_OPENSTATE_READY)
|
||||
{
|
||||
// Stream is live
|
||||
|
||||
// start the stream if it's ready
|
||||
if (!mFMODInternetStreamChannelp &&
|
||||
(mFMODInternetStreamChannelp = mCurrentInternetStreamp->startStream()))
|
||||
{
|
||||
// Reset volume to previously set volume
|
||||
setGain(getGain());
|
||||
mFMODInternetStreamChannelp->setPaused(false);
|
||||
}
|
||||
}
|
||||
else if (open_state == FMOD_OPENSTATE_ERROR)
|
||||
{
|
||||
stop();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
FMOD::Sound *sound = NULL;
|
||||
|
||||
if (mFMODInternetStreamChannelp->getCurrentSound(&sound) == FMOD_OK && sound)
|
||||
{
|
||||
FMOD_TAG tag;
|
||||
S32 tagcount, dirtytagcount;
|
||||
|
||||
if (sound->getNumTags(&tagcount, &dirtytagcount) == FMOD_OK && dirtytagcount)
|
||||
{
|
||||
for (S32 i = 0; i < tagcount; ++i)
|
||||
{
|
||||
if (sound->getTag(NULL, i, &tag) != FMOD_OK)
|
||||
continue;
|
||||
|
||||
if (tag.type == FMOD_TAGTYPE_FMOD)
|
||||
{
|
||||
if (!strcmp(tag.name, "Sample Rate Change"))
|
||||
{
|
||||
LL_INFOS() << "Stream forced changing sample rate to " << *((float *)tag.data) << LL_ENDL;
|
||||
mFMODInternetStreamChannelp->setFrequency(*((float *)tag.data));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (starving)
|
||||
{
|
||||
bool paused = false;
|
||||
mFMODInternetStreamChannelp->getPaused(&paused);
|
||||
if (!paused)
|
||||
{
|
||||
LL_INFOS() << "Stream starvation detected! Pausing stream until buffer nearly full." << LL_ENDL;
|
||||
LL_INFOS() << " (diskbusy=" << diskbusy << ")" << LL_ENDL;
|
||||
LL_INFOS() << " (progress=" << progress << ")" << LL_ENDL;
|
||||
mFMODInternetStreamChannelp->setPaused(true);
|
||||
}
|
||||
}
|
||||
else if (progress > 80)
|
||||
{
|
||||
mFMODInternetStreamChannelp->setPaused(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::stop()
|
||||
{
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
mFMODInternetStreamChannelp->setPaused(true);
|
||||
mFMODInternetStreamChannelp->setPriority(0);
|
||||
mFMODInternetStreamChannelp = NULL;
|
||||
}
|
||||
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
LL_INFOS() << "Stopping internet stream: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
|
||||
if (mCurrentInternetStreamp->stopStream())
|
||||
{
|
||||
delete mCurrentInternetStreamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
LL_WARNS() << "Pushing stream to dead list: " << mCurrentInternetStreamp->getURL() << LL_ENDL;
|
||||
mDeadStreams.push_back(mCurrentInternetStreamp);
|
||||
}
|
||||
mCurrentInternetStreamp = NULL;
|
||||
//mURL.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::pause(int pauseopt)
|
||||
{
|
||||
if (pauseopt < 0)
|
||||
{
|
||||
pauseopt = mCurrentInternetStreamp ? 1 : 0;
|
||||
}
|
||||
|
||||
if (pauseopt)
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
stop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
start(getURL());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// A stream is "playing" if it has been requested to start. That
|
||||
// doesn't necessarily mean audio is coming out of the speakers.
|
||||
int LLStreamingAudio_FMODSTUDIO::isPlaying()
|
||||
{
|
||||
if (mCurrentInternetStreamp)
|
||||
{
|
||||
return 1; // Active and playing
|
||||
}
|
||||
else if (!mURL.empty())
|
||||
{
|
||||
return 2; // "Paused"
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
F32 LLStreamingAudio_FMODSTUDIO::getGain()
|
||||
{
|
||||
return mGain;
|
||||
}
|
||||
|
||||
|
||||
std::string LLStreamingAudio_FMODSTUDIO::getURL()
|
||||
{
|
||||
return mURL;
|
||||
}
|
||||
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::setGain(F32 vol)
|
||||
{
|
||||
mGain = vol;
|
||||
|
||||
if (mFMODInternetStreamChannelp)
|
||||
{
|
||||
vol = llclamp(vol * vol, 0.f, 1.f); //should vol be squared here?
|
||||
|
||||
mFMODInternetStreamChannelp->setVolume(vol);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
// manager of possibly-multiple internet audio streams
|
||||
|
||||
LLAudioStreamManagerFMODSTUDIO::LLAudioStreamManagerFMODSTUDIO(FMOD::System *system, const std::string& url) :
|
||||
mSystem(system),
|
||||
mStreamChannel(NULL),
|
||||
mInternetStream(NULL),
|
||||
mReady(false)
|
||||
{
|
||||
mInternetStreamURL = url;
|
||||
|
||||
FMOD_RESULT result = mSystem->createStream(url.c_str(), FMOD_2D | FMOD_NONBLOCKING | FMOD_IGNORETAGS, 0, &mInternetStream);
|
||||
|
||||
if (result != FMOD_OK)
|
||||
{
|
||||
LL_WARNS() << "Couldn't open fmod stream, error "
|
||||
<< FMOD_ErrorString(result)
|
||||
<< LL_ENDL;
|
||||
mReady = false;
|
||||
return;
|
||||
}
|
||||
|
||||
mReady = true;
|
||||
}
|
||||
|
||||
FMOD::Channel *LLAudioStreamManagerFMODSTUDIO::startStream()
|
||||
{
|
||||
// We need a live and opened stream before we try and play it.
|
||||
if (!mInternetStream || getOpenState() != FMOD_OPENSTATE_READY)
|
||||
{
|
||||
LL_WARNS() << "No internet stream to start playing!" << LL_ENDL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (mStreamChannel)
|
||||
return mStreamChannel; //Already have a channel for this stream.
|
||||
|
||||
mSystem->playSound(mInternetStream, NULL, true, &mStreamChannel);
|
||||
return mStreamChannel;
|
||||
}
|
||||
|
||||
bool LLAudioStreamManagerFMODSTUDIO::stopStream()
|
||||
{
|
||||
if (mInternetStream)
|
||||
{
|
||||
|
||||
|
||||
bool close = true;
|
||||
switch (getOpenState())
|
||||
{
|
||||
case FMOD_OPENSTATE_CONNECTING:
|
||||
close = false;
|
||||
break;
|
||||
default:
|
||||
close = true;
|
||||
}
|
||||
|
||||
if (close)
|
||||
{
|
||||
mInternetStream->release();
|
||||
mStreamChannel = NULL;
|
||||
mInternetStream = NULL;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
FMOD_OPENSTATE LLAudioStreamManagerFMODSTUDIO::getOpenState(unsigned int* percentbuffered, bool* starving, bool* diskbusy)
|
||||
{
|
||||
FMOD_OPENSTATE state;
|
||||
mInternetStream->getOpenState(&state, percentbuffered, starving, diskbusy);
|
||||
return state;
|
||||
}
|
||||
|
||||
void LLStreamingAudio_FMODSTUDIO::setBufferSizes(U32 streambuffertime, U32 decodebuffertime)
|
||||
{
|
||||
mSystem->setStreamBufferSize(streambuffertime / 1000 * 128 * 128, FMOD_TIMEUNIT_RAWBYTES);
|
||||
FMOD_ADVANCEDSETTINGS settings;
|
||||
memset(&settings, 0, sizeof(settings));
|
||||
settings.cbSize = sizeof(settings);
|
||||
settings.defaultDecodeBufferSize = decodebuffertime;//ms
|
||||
mSystem->setAdvancedSettings(&settings);
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* @file streamingaudio_fmodstudio.h
|
||||
* @brief Definition of LLStreamingAudio_FMODSTUDIO implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2020&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2020, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_STREAMINGAUDIO_FMODSTUDIO_H
|
||||
#define LL_STREAMINGAUDIO_FMODSTUDIO_H
|
||||
|
||||
#include "stdtypes.h" // from llcommon
|
||||
|
||||
#include "llstreamingaudio.h"
|
||||
#include "lltimer.h"
|
||||
|
||||
//Stubs
|
||||
class LLAudioStreamManagerFMODSTUDIO;
|
||||
namespace FMOD
|
||||
{
|
||||
class System;
|
||||
class Channel;
|
||||
}
|
||||
|
||||
//Interfaces
|
||||
class LLStreamingAudio_FMODSTUDIO : public LLStreamingAudioInterface
|
||||
{
|
||||
public:
|
||||
LLStreamingAudio_FMODSTUDIO(FMOD::System *system);
|
||||
/*virtual*/ ~LLStreamingAudio_FMODSTUDIO();
|
||||
|
||||
/*virtual*/ void start(const std::string& url);
|
||||
/*virtual*/ void stop();
|
||||
/*virtual*/ void pause(S32 pause);
|
||||
/*virtual*/ void update();
|
||||
/*virtual*/ S32 isPlaying();
|
||||
/*virtual*/ void setGain(F32 vol);
|
||||
/*virtual*/ F32 getGain();
|
||||
/*virtual*/ std::string getURL();
|
||||
|
||||
/*virtual*/ bool supportsAdjustableBufferSizes(){return true;}
|
||||
/*virtual*/ void setBufferSizes(U32 streambuffertime, U32 decodebuffertime);
|
||||
private:
|
||||
FMOD::System *mSystem;
|
||||
|
||||
LLAudioStreamManagerFMODSTUDIO *mCurrentInternetStreamp;
|
||||
FMOD::Channel *mFMODInternetStreamChannelp;
|
||||
std::list<LLAudioStreamManagerFMODSTUDIO *> mDeadStreams;
|
||||
|
||||
std::string mURL;
|
||||
F32 mGain;
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_STREAMINGAUDIO_FMODSTUDIO_H
|
||||
|
|
@ -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(FMODSTUDIO)
|
||||
include_directories(${FMODSTUDIO_INCLUDE_DIR})
|
||||
endif(FMODSTUDIO)
|
||||
|
||||
include_directories(
|
||||
${DBUSGLIB_INCLUDE_DIRS}
|
||||
|
|
@ -1713,12 +1713,13 @@ 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 (FMODSTUDIO)
|
||||
set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODSTUDIO")
|
||||
set(FMODWRAPPER_LIBRARY ${FMODSTUDIO_LIBRARY})
|
||||
endif (FMODSTUDIO)
|
||||
|
||||
set_source_files_properties(llstartup.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
|
||||
set_source_files_properties(llprogressview.cpp PROPERTIES COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS}")
|
||||
|
||||
list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES})
|
||||
|
||||
|
|
@ -1832,13 +1833,13 @@ if (WINDOWS)
|
|||
)
|
||||
endif (ADDRESS_SIZE EQUAL 64)
|
||||
|
||||
if (FMODEX)
|
||||
if (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 (FMODSTUDIO)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CFG_INTDIR}/copy_touched.bat
|
||||
|
|
@ -1849,6 +1850,7 @@ if (WINDOWS)
|
|||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
"--bugsplat=${BUGSPLAT_DB}"
|
||||
"--fmodstudio=${FMODSTUDIO}"
|
||||
--build=${CMAKE_CURRENT_BINARY_DIR}
|
||||
--buildtype=${CMAKE_BUILD_TYPE}
|
||||
"--channel=${VIEWER_CHANNEL}"
|
||||
|
|
@ -1910,6 +1912,7 @@ if (WINDOWS)
|
|||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
"--bugsplat=${BUGSPLAT_DB}"
|
||||
"--fmodstudio=${FMODSTUDIO}"
|
||||
--build=${CMAKE_CURRENT_BINARY_DIR}
|
||||
--buildtype=${CMAKE_BUILD_TYPE}
|
||||
"--channel=${VIEWER_CHANNEL}"
|
||||
|
|
@ -2056,6 +2059,7 @@ if (LINUX)
|
|||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
"--bugsplat=${BUGSPLAT_DB}"
|
||||
"--fmodstudio=${FMODSTUDIO}"
|
||||
--build=${CMAKE_CURRENT_BINARY_DIR}
|
||||
--buildtype=${CMAKE_BUILD_TYPE}
|
||||
"--channel=${VIEWER_CHANNEL}"
|
||||
|
|
@ -2082,6 +2086,7 @@ if (LINUX)
|
|||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
"--bugsplat=${BUGSPLAT_DB}"
|
||||
"--fmodstudio=${FMODSTUDIO}"
|
||||
--build=${CMAKE_CURRENT_BINARY_DIR}
|
||||
--buildtype=${CMAKE_BUILD_TYPE}
|
||||
"--channel=${VIEWER_CHANNEL}"
|
||||
|
|
@ -2158,6 +2163,7 @@ if (DARWIN)
|
|||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
"--bugsplat=${BUGSPLAT_DB}"
|
||||
"--fmodstudio=${FMODSTUDIO}"
|
||||
--build=${CMAKE_CURRENT_BINARY_DIR}
|
||||
--buildtype=${CMAKE_BUILD_TYPE}
|
||||
--bundleid=${MACOSX_BUNDLE_GUI_IDENTIFIER}
|
||||
|
|
@ -2192,6 +2198,7 @@ if (DARWIN)
|
|||
--arch=${ARCH}
|
||||
--artwork=${ARTWORK_DIR}
|
||||
"--bugsplat=${BUGSPLAT_DB}"
|
||||
"--fmodstudio=${FMODSTUDIO}"
|
||||
--build=${CMAKE_CURRENT_BINARY_DIR}
|
||||
--buildtype=${CMAKE_BUILD_TYPE}
|
||||
"--channel=${VIEWER_CHANNEL}"
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
6.4.3
|
||||
6.4.4
|
||||
|
|
|
|||
|
|
@ -16384,7 +16384,7 @@
|
|||
<key>FMODExProfilerEnable</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Enable profiler tool if using FMOD Ex</string>
|
||||
<string>Enable profiler tool if using FMOD Ex or FMOD Studio</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
|
|
@ -16395,7 +16395,7 @@
|
|||
<key>FMODExDecodeBufferSize</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Sets the streaming decode buffer size (in milliseconds)</string>
|
||||
<string>Sets the streaming decode buffer size (in milliseconds) for FMOD Ex or FMOD Studio</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
|
|
@ -16406,7 +16406,7 @@
|
|||
<key>FMODExStreamBufferSize</key>
|
||||
<map>
|
||||
<key>Comment</key>
|
||||
<string>Sets the streaming buffer size (in milliseconds)</string>
|
||||
<string>Sets the streaming buffer size (in milliseconds) for FMOD Ex or FMOD Studio</string>
|
||||
<key>Persist</key>
|
||||
<integer>1</integer>
|
||||
<key>Type</key>
|
||||
|
|
|
|||
|
|
@ -187,8 +187,8 @@ The 'secondlife' script which launches Second Life contains some
|
|||
configuration options for advanced troubleshooters.
|
||||
|
||||
* AUDIO - Edit the 'secondlife' script and you will see these audio
|
||||
options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMOD_ESD, LL_BAD_FMOD_OSS, and
|
||||
LL_BAD_FMOD_ALSA. Second Life tries to use OpenAL, ESD, OSS, then ALSA
|
||||
options: LL_BAD_OPENAL_DRIVER, LL_BAD_FMODSTUDIO_DRIVER.
|
||||
Second Life tries to use OpenAL, FMODSTUDIO (PULSEAUDIO, ALSA)
|
||||
audio drivers in this order; you may uncomment the corresponding LL_BAD_*
|
||||
option to skip an audio driver which you believe may be causing you trouble.
|
||||
|
||||
|
|
|
|||
|
|
@ -4,17 +4,15 @@
|
|||
## These options are for self-assisted troubleshooting during this beta
|
||||
## testing phase; you should not usually need to touch them.
|
||||
|
||||
## - Avoids using any FMOD Ex audio driver.
|
||||
#export LL_BAD_FMODEX_DRIVER=x
|
||||
## - Avoids using any FMOD STUDIO audio driver.
|
||||
#export LL_BAD_FMODSTUDIO_DRIVER=x
|
||||
## - Avoids using any OpenAL audio driver.
|
||||
#export LL_BAD_OPENAL_DRIVER=x
|
||||
|
||||
## - Avoids using the FMOD Ex PulseAudio audio driver.
|
||||
## - Avoids using the FMOD Studio or FMOD Ex PulseAudio audio driver.
|
||||
#export LL_BAD_FMOD_PULSEAUDIO=x
|
||||
## - Avoids using the FMOD or FMOD Ex ALSA audio driver.
|
||||
## - Avoids using the FMOD Studio or FMOD Ex ALSA audio driver.
|
||||
#export LL_BAD_FMOD_ALSA=x
|
||||
## - Avoids using the FMOD or FMOD Ex OSS audio driver.
|
||||
#export LL_BAD_FMOD_OSS=x
|
||||
|
||||
## - Avoids the optional OpenGL extensions which have proven most problematic
|
||||
## on some hardware. Disabling this option may cause BETTER PERFORMANCE but
|
||||
|
|
|
|||
|
|
@ -229,6 +229,33 @@ void LLProgressView::drawStartTexture(F32 alpha)
|
|||
gGL.popMatrix();
|
||||
}
|
||||
|
||||
void LLProgressView::drawLogos(F32 alpha)
|
||||
{
|
||||
if (mLogosList.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// logos are tied to label,
|
||||
// due to potential resizes we have to figure offsets out on draw or resize
|
||||
LLTextBox *logos_label = getChild<LLTextBox>("logos_lbl");
|
||||
S32 offset_x, offset_y;
|
||||
logos_label->localPointToScreen(0, 0, &offset_x, &offset_y);
|
||||
std::vector<TextureData>::const_iterator iter = mLogosList.begin();
|
||||
std::vector<TextureData>::const_iterator end = mLogosList.end();
|
||||
for (; iter != end; iter++)
|
||||
{
|
||||
gl_draw_scaled_image_with_border(iter->mDrawRect.mLeft + offset_x,
|
||||
iter->mDrawRect.mBottom + offset_y,
|
||||
iter->mDrawRect.getWidth(),
|
||||
iter->mDrawRect.getHeight(),
|
||||
iter->mTexturep.get(),
|
||||
UI_VERTEX_COLOR % alpha,
|
||||
FALSE,
|
||||
iter->mClipRect,
|
||||
iter->mOffsetRect);
|
||||
}
|
||||
}
|
||||
|
||||
void LLProgressView::draw()
|
||||
{
|
||||
|
|
@ -245,6 +272,7 @@ void LLProgressView::draw()
|
|||
}
|
||||
|
||||
LLPanel::draw();
|
||||
drawLogos(alpha);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -257,6 +285,7 @@ void LLProgressView::draw()
|
|||
|
||||
drawStartTexture(alpha);
|
||||
LLPanel::draw();
|
||||
drawLogos(alpha);
|
||||
|
||||
// faded out completely - remove panel and reveal world
|
||||
if (mFadeToWorldTimer.getElapsedTimeF32() > FADE_TO_WORLD_TIME )
|
||||
|
|
@ -283,7 +312,7 @@ void LLProgressView::draw()
|
|||
// FIXME: this causes a crash that i haven't been able to fix
|
||||
mMediaCtrl->unloadMediaSource();
|
||||
|
||||
gStartTexture = NULL;
|
||||
releaseTextures();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -291,6 +320,7 @@ void LLProgressView::draw()
|
|||
drawStartTexture(1.0f);
|
||||
// draw children
|
||||
LLPanel::draw();
|
||||
drawLogos(1.0f);
|
||||
}
|
||||
|
||||
void LLProgressView::setText(const std::string& text)
|
||||
|
|
@ -309,6 +339,196 @@ void LLProgressView::setMessage(const std::string& msg)
|
|||
getChild<LLUICtrl>("message_text")->setValue(mMessage);
|
||||
}
|
||||
|
||||
void LLProgressView::loadLogo(const std::string &path,
|
||||
const U8 image_codec,
|
||||
const LLRect &pos_rect,
|
||||
const LLRectf &clip_rect,
|
||||
const LLRectf &offset_rect)
|
||||
{
|
||||
// We need these images very early, so we have to force-load them, otherwise they might not load in time.
|
||||
if (!gDirUtilp->fileExists(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLPointer<LLImageFormatted> start_image_frmted = LLImageFormatted::createFromType(image_codec);
|
||||
if (!start_image_frmted->load(path))
|
||||
{
|
||||
LL_WARNS("AppInit") << "Image load failed: " << path << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
|
||||
LLPointer<LLImageRaw> raw = new LLImageRaw;
|
||||
if (!start_image_frmted->decode(raw, 0.0f))
|
||||
{
|
||||
LL_WARNS("AppInit") << "Image decode failed " << path << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
// HACK: getLocalTexture allows only power of two dimentions
|
||||
raw->expandToPowerOfTwo();
|
||||
|
||||
TextureData data;
|
||||
data.mTexturep = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
|
||||
data.mDrawRect = pos_rect;
|
||||
data.mClipRect = clip_rect;
|
||||
data.mOffsetRect = offset_rect;
|
||||
mLogosList.push_back(data);
|
||||
}
|
||||
|
||||
void LLProgressView::initLogos()
|
||||
{
|
||||
mLogosList.clear();
|
||||
|
||||
const U8 image_codec = IMG_CODEC_PNG;
|
||||
const LLRectf default_clip(0.f, 1.f, 1.f, 0.f);
|
||||
const S32 default_height = 28;
|
||||
const S32 default_pad = 15;
|
||||
|
||||
S32 icon_width, icon_height;
|
||||
|
||||
// We don't know final screen rect yet, so we can't precalculate position fully
|
||||
LLTextBox *logos_label = getChild<LLTextBox>("logos_lbl");
|
||||
S32 texture_start_x = logos_label->getFont()->getWidthF32(logos_label->getText()) + default_pad;
|
||||
S32 texture_start_y = -7;
|
||||
|
||||
// Normally we would just preload these textures from textures.xml,
|
||||
// and display them via icon control, but they are only needed on
|
||||
// startup and preloaded/UI ones stay forever
|
||||
// (and this code was done already so simply reused it)
|
||||
std::string temp_str = gDirUtilp->getExpandedFilename(LL_PATH_DEFAULT_SKIN, "textures", "3p_icons");
|
||||
|
||||
temp_str += gDirUtilp->getDirDelimiter();
|
||||
|
||||
#ifdef LL_FMODSTUDIO
|
||||
// original image size is 264x96, it is on longer side but
|
||||
// with no internal paddings so it gets additional padding
|
||||
icon_width = 77;
|
||||
icon_height = 21;
|
||||
S32 pad_y = 4;
|
||||
texture_start_x++;
|
||||
loadLogo(temp_str + "fmod_logo.png",
|
||||
image_codec,
|
||||
LLRect(texture_start_x, texture_start_y + pad_y + icon_height, texture_start_x + icon_width, texture_start_y + pad_y),
|
||||
default_clip,
|
||||
default_clip);
|
||||
|
||||
texture_start_x += icon_width + default_pad + 1;
|
||||
#endif
|
||||
// original image size is 342x113, central element is on a larger side
|
||||
// plus internal padding, so it gets slightly more height than desired 32
|
||||
icon_width = 88;
|
||||
icon_height = 29;
|
||||
pad_y = -1;
|
||||
loadLogo(temp_str + "havok_logo.png",
|
||||
image_codec,
|
||||
LLRect(texture_start_x, texture_start_y + pad_y + icon_height, texture_start_x + icon_width, texture_start_y + pad_y),
|
||||
default_clip,
|
||||
default_clip);
|
||||
|
||||
texture_start_x += icon_width + default_pad;
|
||||
|
||||
// 108x41
|
||||
icon_width = 74;
|
||||
loadLogo(temp_str + "vivox_logo.png",
|
||||
image_codec,
|
||||
LLRect(texture_start_x, texture_start_y + default_height, texture_start_x + icon_width, texture_start_y),
|
||||
default_clip,
|
||||
default_clip);
|
||||
}
|
||||
|
||||
void LLProgressView::initStartTexture(S32 location_id, bool is_in_production)
|
||||
{
|
||||
if (gStartTexture.notNull())
|
||||
{
|
||||
gStartTexture = NULL;
|
||||
LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL;
|
||||
}
|
||||
|
||||
LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL;
|
||||
|
||||
U8 image_codec = IMG_CODEC_PNG;
|
||||
std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter();
|
||||
|
||||
if ((S32)START_LOCATION_ID_LAST == location_id)
|
||||
{
|
||||
temp_str += LLStartUp::getScreenLastFilename();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string path = temp_str + LLStartUp::getScreenHomeFilename();
|
||||
|
||||
if (!gDirUtilp->fileExists(path) && is_in_production)
|
||||
{
|
||||
// Fallback to old file, can be removed later
|
||||
// Home image only sets when user changes home, so it will take time for users to switch to pngs
|
||||
temp_str += "screen_home.bmp";
|
||||
image_codec = IMG_CODEC_BMP;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_str = path;
|
||||
}
|
||||
}
|
||||
|
||||
LLPointer<LLImageFormatted> start_image_frmted = LLImageFormatted::createFromType(image_codec);
|
||||
|
||||
// Turn off start screen to get around the occasional readback
|
||||
// driver bug
|
||||
if (!gSavedSettings.getBOOL("UseStartScreen"))
|
||||
{
|
||||
LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
else if (!start_image_frmted->load(temp_str))
|
||||
{
|
||||
LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL;
|
||||
gStartTexture = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
gStartImageWidth = start_image_frmted->getWidth();
|
||||
gStartImageHeight = start_image_frmted->getHeight();
|
||||
|
||||
LLPointer<LLImageRaw> raw = new LLImageRaw;
|
||||
if (!start_image_frmted->decode(raw, 0.0f))
|
||||
{
|
||||
LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL;
|
||||
gStartTexture = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
// HACK: getLocalTexture allows only power of two dimentions
|
||||
raw->expandToPowerOfTwo();
|
||||
gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
if (gStartTexture.isNull())
|
||||
{
|
||||
gStartTexture = LLViewerTexture::sBlackImagep;
|
||||
gStartImageWidth = gStartTexture->getWidth();
|
||||
gStartImageHeight = gStartTexture->getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
void LLProgressView::initTextures(S32 location_id, bool is_in_production)
|
||||
{
|
||||
initStartTexture(location_id, is_in_production);
|
||||
initLogos();
|
||||
|
||||
childSetVisible("panel_icons", mLogosList.empty() ? FALSE : TRUE);
|
||||
childSetVisible("panel_top_spacer", mLogosList.empty() ? TRUE : FALSE);
|
||||
}
|
||||
|
||||
void LLProgressView::releaseTextures()
|
||||
{
|
||||
gStartTexture = NULL;
|
||||
mLogosList.clear();
|
||||
|
||||
childSetVisible("panel_top_spacer", TRUE);
|
||||
childSetVisible("panel_icons", FALSE);
|
||||
}
|
||||
|
||||
void LLProgressView::setCancelButtonVisible(BOOL b, const std::string& label)
|
||||
{
|
||||
mCancelBtn->setVisible( b );
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
class LLImageRaw;
|
||||
class LLButton;
|
||||
class LLProgressBar;
|
||||
class LLViewerTexture;
|
||||
|
||||
class LLProgressView :
|
||||
public LLPanel,
|
||||
|
|
@ -51,6 +52,7 @@ public:
|
|||
|
||||
/*virtual*/ void draw();
|
||||
void drawStartTexture(F32 alpha);
|
||||
void drawLogos(F32 alpha);
|
||||
|
||||
/*virtual*/ BOOL handleHover(S32 x, S32 y, MASK mask);
|
||||
/*virtual*/ BOOL handleKeyHere(KEY key, MASK mask);
|
||||
|
|
@ -70,6 +72,10 @@ public:
|
|||
|
||||
void setStartupComplete();
|
||||
|
||||
// we have to preload local textures to make sure they won't be grey
|
||||
void initTextures(S32 location_id, bool is_in_production);
|
||||
void releaseTextures();
|
||||
|
||||
void setCancelButtonVisible(BOOL b, const std::string& label);
|
||||
|
||||
static void onCancelButtonClicked( void* );
|
||||
|
|
@ -95,6 +101,25 @@ protected:
|
|||
|
||||
bool handleUpdate(const LLSD& event_data);
|
||||
static void onIdle(void* user_data);
|
||||
void loadLogo(const std::string &path, const U8 image_codec, const LLRect &pos_rect, const LLRectf &clip_rect, const LLRectf &offset_rect);
|
||||
// logos have unusual location and need to be preloaded to not appear grey, then deleted
|
||||
void initLogos();
|
||||
// Loads a bitmap to display during load
|
||||
void initStartTexture(S32 location_id, bool is_in_production);
|
||||
|
||||
private:
|
||||
// We need to draw textures on login, but only once.
|
||||
// So this vector gets filled up for textures to render and gets cleaned later
|
||||
// Some textures have unusual requirements, so we are rendering directly
|
||||
class TextureData
|
||||
{
|
||||
public:
|
||||
LLPointer<LLViewerTexture> mTexturep;
|
||||
LLRect mDrawRect;
|
||||
LLRectf mClipRect;
|
||||
LLRectf mOffsetRect;
|
||||
};
|
||||
std::vector<TextureData> mLogosList;
|
||||
};
|
||||
|
||||
#endif // LL_LLPROGRESSVIEW_H
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@
|
|||
#include "llviewermedia_streamingaudio.h"
|
||||
#include "llaudioengine.h"
|
||||
|
||||
#ifdef LL_FMODEX
|
||||
# include "llaudioengine_fmodex.h"
|
||||
#ifdef LL_FMODSTUDIO
|
||||
# include "llaudioengine_fmodstudio.h"
|
||||
#endif
|
||||
|
||||
#ifdef LL_OPENAL
|
||||
|
|
@ -623,13 +623,13 @@ bool idle_startup()
|
|||
delete gAudiop;
|
||||
gAudiop = NULL;
|
||||
|
||||
#ifdef LL_FMODEX
|
||||
#ifdef LL_FMODSTUDIO
|
||||
#if !LL_WINDOWS
|
||||
if (NULL == getenv("LL_BAD_FMODEX_DRIVER"))
|
||||
if (NULL == getenv("LL_BAD_FMODSTUDIO_DRIVER"))
|
||||
#endif // !LL_WINDOWS
|
||||
{
|
||||
gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODEX(gSavedSettings.getBOOL("FMODExProfilerEnable"));
|
||||
}
|
||||
{
|
||||
gAudiop = (LLAudioEngine *) new LLAudioEngine_FMODSTUDIO(gSavedSettings.getBOOL("FMODExProfilerEnable"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef LL_OPENAL
|
||||
|
|
@ -650,7 +650,7 @@ bool idle_startup()
|
|||
#else
|
||||
void* window_handle = NULL;
|
||||
#endif
|
||||
bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle);
|
||||
bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle, LLAppViewer::instance()->getSecondLifeTitle());
|
||||
if(init)
|
||||
{
|
||||
gAudiop->setMuted(TRUE);
|
||||
|
|
@ -994,9 +994,8 @@ bool idle_startup()
|
|||
|
||||
gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
|
||||
|
||||
init_start_screen(agent_location_id);
|
||||
|
||||
// Display the startup progress bar.
|
||||
gViewerWindow->initTextures(agent_location_id);
|
||||
gViewerWindow->setShowProgress(TRUE);
|
||||
gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit"));
|
||||
|
||||
|
|
@ -2737,81 +2736,6 @@ std::string LLStartUp::getUserId()
|
|||
return gUserCredential->userID();
|
||||
}
|
||||
|
||||
// Loads a bitmap to display during load
|
||||
void init_start_screen(S32 location_id)
|
||||
{
|
||||
if (gStartTexture.notNull())
|
||||
{
|
||||
gStartTexture = NULL;
|
||||
LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL;
|
||||
}
|
||||
|
||||
LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL;
|
||||
|
||||
U8 image_codec = IMG_CODEC_PNG;
|
||||
std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter();
|
||||
|
||||
if ((S32)START_LOCATION_ID_LAST == location_id)
|
||||
{
|
||||
temp_str += LLStartUp::getScreenLastFilename();
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string path = temp_str + LLStartUp::getScreenHomeFilename();
|
||||
|
||||
if (!gDirUtilp->fileExists(path) && LLGridManager::getInstance()->isInProductionGrid())
|
||||
{
|
||||
// Fallback to old file, can be removed later
|
||||
// Home image only sets when user changes home, so it will take time for users to switch to pngs
|
||||
temp_str += "screen_home.bmp";
|
||||
image_codec = IMG_CODEC_BMP;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_str = path;
|
||||
}
|
||||
}
|
||||
|
||||
LLPointer<LLImageFormatted> start_image_frmted = LLImageFormatted::createFromType(image_codec);
|
||||
|
||||
// Turn off start screen to get around the occasional readback
|
||||
// driver bug
|
||||
if(!gSavedSettings.getBOOL("UseStartScreen"))
|
||||
{
|
||||
LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL;
|
||||
return;
|
||||
}
|
||||
else if(!start_image_frmted->load(temp_str) )
|
||||
{
|
||||
LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL;
|
||||
gStartTexture = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
gStartImageWidth = start_image_frmted->getWidth();
|
||||
gStartImageHeight = start_image_frmted->getHeight();
|
||||
|
||||
LLPointer<LLImageRaw> raw = new LLImageRaw;
|
||||
if (!start_image_frmted->decode(raw, 0.0f))
|
||||
{
|
||||
LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL;
|
||||
gStartTexture = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
raw->expandToPowerOfTwo();
|
||||
gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE) ;
|
||||
}
|
||||
}
|
||||
|
||||
if(gStartTexture.isNull())
|
||||
{
|
||||
gStartTexture = LLViewerTexture::sBlackImagep ;
|
||||
gStartImageWidth = gStartTexture->getWidth() ;
|
||||
gStartImageHeight = gStartTexture->getHeight() ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// frees the bitmap
|
||||
void release_start_screen()
|
||||
|
|
|
|||
|
|
@ -1902,7 +1902,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use
|
|||
// If there is a new music URL and it's valid, play it.
|
||||
if (music_url.size() > 12)
|
||||
{
|
||||
if (music_url.substr(0, 7) == "http://")
|
||||
if (music_url.substr(0, 7) == "http://"
|
||||
|| music_url.substr(0, 8) == "https://")
|
||||
{
|
||||
LLViewerRegion *region = LLWorld::getInstance()->getRegion(msg->getSender());
|
||||
optionally_start_music(music_url, parcel->mLocalID, region->getRegionID());
|
||||
|
|
|
|||
|
|
@ -5119,6 +5119,14 @@ void LLViewerWindow::revealIntroPanel()
|
|||
}
|
||||
}
|
||||
|
||||
void LLViewerWindow::initTextures(S32 location_id)
|
||||
{
|
||||
if (mProgressView)
|
||||
{
|
||||
mProgressView->initTextures(location_id, LLGridManager::getInstance()->isInProductionGrid());
|
||||
}
|
||||
}
|
||||
|
||||
void LLViewerWindow::setShowProgress(const BOOL show)
|
||||
{
|
||||
if (mProgressView)
|
||||
|
|
@ -5172,7 +5180,6 @@ void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string&
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
LLProgressView *LLViewerWindow::getProgressView() const
|
||||
{
|
||||
return mProgressView;
|
||||
|
|
|
|||
|
|
@ -303,6 +303,7 @@ public:
|
|||
BOOL getCursorHidden() { return mCursorHidden; }
|
||||
void moveCursorToCenter(); // move to center of window
|
||||
|
||||
void initTextures(S32 location_id);
|
||||
void setShowProgress(const BOOL show);
|
||||
BOOL getShowProgress() const;
|
||||
void setProgressString(const std::string& string);
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
|
|
@ -497,6 +497,7 @@ with the same filename but different name
|
|||
<texture name="Play_Press" file_name="icons/Play_Press.png" preload="false" />
|
||||
|
||||
<texture name="ProgressBar" file_name="widgets/ProgressBar.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />
|
||||
<texture name="ProgressBarSolid" file_name="widgets/ProgressBarSolid.png" preload="true" scale.left="4" scale.top="11" scale.right="48" scale.bottom="3" />
|
||||
<texture name="ProgressTrack" file_name="widgets/ProgressTrack.png" preload="true" scale.left="4" scale.top="13" scale.right="148" scale.bottom="2" />
|
||||
|
||||
<texture name="PushButton_Disabled" file_name="widgets/PushButton_Disabled.png" preload="true" scale.left="4" scale.top="19" scale.right="28" scale.bottom="4" />
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 208 B |
|
|
@ -2,7 +2,7 @@
|
|||
<floater
|
||||
legacy_header_height="18"
|
||||
can_minimize="false"
|
||||
height="488"
|
||||
height="466"
|
||||
layout="topleft"
|
||||
name="Inventory Finder"
|
||||
help_topic="inventory_finder"
|
||||
|
|
@ -202,7 +202,7 @@
|
|||
left="8"
|
||||
mouse_opaque="true"
|
||||
name="icon_settings"
|
||||
top="262"
|
||||
top="242"
|
||||
width="16" />
|
||||
<check_box
|
||||
height="16"
|
||||
|
|
@ -220,7 +220,7 @@
|
|||
layout="topleft"
|
||||
left="8"
|
||||
name="All"
|
||||
top="282"
|
||||
top="262"
|
||||
width="100" />
|
||||
<button
|
||||
height="20"
|
||||
|
|
@ -368,6 +368,6 @@
|
|||
layout="topleft"
|
||||
name="Close"
|
||||
right="-6"
|
||||
top="454"
|
||||
top="434"
|
||||
width="76" />
|
||||
</floater>
|
||||
|
|
|
|||
|
|
@ -44,68 +44,129 @@
|
|||
width="670" />
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
height="250"
|
||||
height="275"
|
||||
layout="topleft"
|
||||
min_height="250"
|
||||
min_height="275"
|
||||
name="panel4"
|
||||
width="670">
|
||||
<icon
|
||||
color="LoginProgressBoxCenterColor"
|
||||
follows="left|right|bottom|top"
|
||||
height="250"
|
||||
height="275"
|
||||
image_name="Rounded_Square"
|
||||
layout="topleft"
|
||||
left="0"
|
||||
top="0"
|
||||
width="670" />
|
||||
<text
|
||||
follows="left|right|top"
|
||||
font="SansSerifHuge"
|
||||
font_shadow="none"
|
||||
halign="left"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
left_delta="47"
|
||||
name="title_text"
|
||||
text_color="LoginProgressBoxTextColor"
|
||||
top_delta="50"
|
||||
right="-47"/>
|
||||
<text
|
||||
follows="left|right|top"
|
||||
font="SansSerif"
|
||||
font_shadow="none"
|
||||
halign="left"
|
||||
height="20"
|
||||
layout="topleft"
|
||||
left_delta="0"
|
||||
name="progress_text"
|
||||
text_color="LoginProgressBoxTextColor"
|
||||
top_pad="5"
|
||||
right="-47"
|
||||
word_wrap="true"/>
|
||||
<progress_bar
|
||||
bottom="115"
|
||||
color_bar="1 1 1 0.96"
|
||||
follows="left|right|top"
|
||||
height="16"
|
||||
layout="topleft"
|
||||
left="45"
|
||||
name="login_progress_bar"
|
||||
right="-45" />
|
||||
<text
|
||||
<layout_stack
|
||||
follows="left|right|top|bottom"
|
||||
font="SansSerifLarge"
|
||||
font_shadow="none"
|
||||
halign="left"
|
||||
height="100"
|
||||
height="275"
|
||||
layout="topleft"
|
||||
left="45"
|
||||
line_spacing.pixels="2"
|
||||
name="message_text"
|
||||
text_color="LoginProgressBoxTextColor"
|
||||
top="145"
|
||||
right="-90"
|
||||
word_wrap="true"/>
|
||||
left="0"
|
||||
orientation="vertical"
|
||||
name="vertical_centering"
|
||||
animate="false"
|
||||
top="0"
|
||||
width="670">
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
height="30"
|
||||
layout="topleft"
|
||||
min_height="30"
|
||||
name="panel_top_spacer"
|
||||
width="670">
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
height="100"
|
||||
layout="topleft"
|
||||
min_height="100"
|
||||
name="panel_login"
|
||||
width="670">
|
||||
<text
|
||||
follows="left|right|top"
|
||||
layout="topleft"
|
||||
font="SansSerifHuge"
|
||||
font_shadow="none"
|
||||
halign="left"
|
||||
height="20"
|
||||
left="47"
|
||||
top="32"
|
||||
right="-47"
|
||||
name="title_text"
|
||||
text_color="LoginProgressBoxTextColor"/>
|
||||
<text
|
||||
follows="left|right|top"
|
||||
layout="topleft"
|
||||
font="SansSerif"
|
||||
font_shadow="none"
|
||||
halign="left"
|
||||
height="20"
|
||||
top_pad="5"
|
||||
right="-47"
|
||||
left_delta="0"
|
||||
name="progress_text"
|
||||
text_color="LoginProgressBoxTextColor"
|
||||
word_wrap="true"/>
|
||||
<progress_bar
|
||||
color_bar="0 0.67 0.9 0.96"
|
||||
follows="left|right|top"
|
||||
layout="topleft"
|
||||
image_fill="ProgressBarSolid"
|
||||
height="16"
|
||||
left="45"
|
||||
top_pad="5"
|
||||
name="login_progress_bar"
|
||||
right="-45" />
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
height="110"
|
||||
layout="topleft"
|
||||
min_height="110"
|
||||
name="panel_motd"
|
||||
width="670">
|
||||
<text
|
||||
follows="left|right|top|bottom"
|
||||
font="SansSerifLarge"
|
||||
font_shadow="none"
|
||||
halign="left"
|
||||
valign="center"
|
||||
height="100"
|
||||
layout="topleft"
|
||||
left="45"
|
||||
line_spacing.pixels="2"
|
||||
name="message_text"
|
||||
text_color="LoginProgressBoxTextColor"
|
||||
top="7"
|
||||
right="-90"
|
||||
word_wrap="true"/>
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
auto_resize="false"
|
||||
height="40"
|
||||
layout="topleft"
|
||||
min_height="40"
|
||||
name="panel_icons"
|
||||
width="670">
|
||||
<!--Logos are tied to following label from code-->
|
||||
<text
|
||||
follows="left|right|top"
|
||||
layout="topleft"
|
||||
font="SansSerifLarge"
|
||||
font_shadow="none"
|
||||
halign="left"
|
||||
height="16"
|
||||
width="240"
|
||||
left="47"
|
||||
top="6"
|
||||
line_spacing.pixels="2"
|
||||
name="logos_lbl"
|
||||
text_color="LoginProgressBoxTextColor">
|
||||
Second Life uses
|
||||
</text>
|
||||
</layout_panel>
|
||||
</layout_stack>
|
||||
</layout_panel>
|
||||
<layout_panel
|
||||
height="200"
|
||||
|
|
|
|||
|
|
@ -516,14 +516,12 @@ class WindowsManifest(ViewerManifest):
|
|||
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")
|
||||
# Get fmodstudio dll if needed
|
||||
if self.args['fmodstudio'] == 'ON':
|
||||
if(self.args['configuration'].lower() == 'debug'):
|
||||
self.path("fmodL.dll")
|
||||
else:
|
||||
self.path("fmodex.dll")
|
||||
except:
|
||||
print "Skipping fmodex audio library(assuming other audio engine)"
|
||||
self.path("fmod.dll")
|
||||
|
||||
# For textures
|
||||
self.path("openjpeg.dll")
|
||||
|
|
@ -1045,17 +1043,18 @@ class DarwinManifest(ViewerManifest):
|
|||
):
|
||||
self.path2basename(relpkgdir, libfile)
|
||||
|
||||
# dylibs that vary based on configuration
|
||||
if self.args['configuration'].lower() == 'debug':
|
||||
for libfile in (
|
||||
"libfmodexL.dylib",
|
||||
):
|
||||
dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile)
|
||||
else:
|
||||
for libfile in (
|
||||
"libfmodex.dylib",
|
||||
):
|
||||
dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
|
||||
# Fmod studio dylibs (vary based on configuration)
|
||||
if self.args['fmodstudio'] == 'ON':
|
||||
if self.args['configuration'].lower() == 'debug':
|
||||
for libfile in (
|
||||
"libfmodL.dylib",
|
||||
):
|
||||
dylibs += path_optional(os.path.join(debpkgdir, libfile), libfile)
|
||||
else:
|
||||
for libfile in (
|
||||
"libfmod.dylib",
|
||||
):
|
||||
dylibs += path_optional(os.path.join(relpkgdir, libfile), libfile)
|
||||
|
||||
# our apps
|
||||
executable_path = {}
|
||||
|
|
@ -1498,13 +1497,15 @@ class Linux_i686_Manifest(LinuxManifest):
|
|||
print "tcmalloc files not found, skipping"
|
||||
pass
|
||||
|
||||
try:
|
||||
self.path("libfmodex-*.so")
|
||||
self.path("libfmodex.so")
|
||||
pass
|
||||
except:
|
||||
print "Skipping libfmodex.so - not found"
|
||||
pass
|
||||
if self.args['fmodstudio'] == 'ON':
|
||||
try:
|
||||
self.path("libfmod.so.11.7")
|
||||
self.path("libfmod.so.11")
|
||||
self.path("libfmod.so")
|
||||
pass
|
||||
except:
|
||||
print "Skipping libfmod.so - not found"
|
||||
pass
|
||||
|
||||
|
||||
# Vivox runtimes
|
||||
|
|
@ -1539,6 +1540,7 @@ if __name__ == "__main__":
|
|||
extra_arguments = [
|
||||
dict(name='bugsplat', description="""BugSplat database to which to post crashes,
|
||||
if BugSplat crash reporting is desired""", default=''),
|
||||
dict(name='fmodstudio', description="""Indication if fmod studio libraries are needed""", default='OFF'),
|
||||
]
|
||||
try:
|
||||
main(extra=extra_arguments)
|
||||
|
|
|
|||
Loading…
Reference in New Issue