/indra/newview/llvieweraudio.cpp
C++ | 504 lines | 349 code | 64 blank | 91 comment | 55 complexity | 8ef9989609345a39555f18a5d44b3acf MD5 | raw file
Possible License(s): LGPL-2.1
- /**
- * @file llvieweraudio.cpp
- * @brief Audio functions that used to be in viewer.cpp
- *
- * $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 "llviewerprecompiledheaders.h"
- #include "llaudioengine.h"
- #include "llagent.h"
- #include "llagentcamera.h"
- #include "llappviewer.h"
- #include "llvieweraudio.h"
- #include "llviewercamera.h"
- #include "llviewercontrol.h"
- #include "llviewerwindow.h"
- #include "llvoiceclient.h"
- #include "llviewermedia.h"
- #include "llprogressview.h"
- #include "llcallbacklist.h"
- #include "llstartup.h"
- #include "llviewerparcelmgr.h"
- #include "llparcel.h"
- /////////////////////////////////////////////////////////
- LLViewerAudio::LLViewerAudio() :
- mDone(true),
- mFadeState(FADE_IDLE),
- mFadeTime(),
- mIdleListnerActive(false),
- mForcedTeleportFade(false)
- {
- mTeleportFailedConnection = LLViewerParcelMgr::getInstance()->
- setTeleportFailedCallback(boost::bind(&LLViewerAudio::onTeleportFailed, this));
- }
- LLViewerAudio::~LLViewerAudio()
- {
- mTeleportFailedConnection.disconnect();
- }
- void LLViewerAudio::registerIdleListener()
- {
- if(mIdleListnerActive==false)
- {
- mIdleListnerActive = true;
- doOnIdleRepeating(boost::bind(boost::bind(&LLViewerAudio::onIdleUpdate, this)));
- }
- }
- void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI)
- {
- // Old and new stream are identical
- if (mNextStreamURI == streamURI)
- {
- return;
- }
- // Record the URI we are going to be switching to
- mNextStreamURI = streamURI;
- switch (mFadeState)
- {
- case FADE_IDLE:
- // If a stream is playing fade it out first
- if (!gAudiop->getInternetStreamURL().empty())
- {
- // The order of these tests is important, state FADE_OUT will be processed below
- mFadeState = FADE_OUT;
- }
- // Otherwise the new stream can be faded in
- else
- {
- mFadeState = FADE_IN;
- gAudiop->startInternetStream(mNextStreamURI);
- startFading();
- registerIdleListener();
- break;
- }
- case FADE_OUT:
- startFading();
- registerIdleListener();
- break;
- case FADE_IN:
- registerIdleListener();
- break;
- default:
- llwarns << "Unknown fading state: " << mFadeState << llendl;
- break;
- }
- }
- // A return of false from onIdleUpdate means it will be called again next idle update.
- // A return of true means we have finished with it and the callback will be deleted.
- bool LLViewerAudio::onIdleUpdate()
- {
- bool fadeIsFinished = false;
- // There is a delay in the login sequence between when the parcel information has
- // arrived and the music stream is started and when the audio system is called to set
- // initial volume levels. This code extends the fade time so you hear a full fade in.
- if ((LLStartUp::getStartupState() < STATE_STARTED))
- {
- stream_fade_timer.reset();
- stream_fade_timer.setTimerExpirySec(mFadeTime);
- }
- if (mDone)
- {
- // This should be a rare or never occurring state.
- if (mFadeState == FADE_IDLE)
- {
- deregisterIdleListener();
- fadeIsFinished = true; // Stop calling onIdleUpdate
- }
- // we have finished the current fade operation
- if (mFadeState == FADE_OUT)
- {
- // Clear URI
- gAudiop->startInternetStream(LLStringUtil::null);
- gAudiop->stopInternetStream();
-
- if (!mNextStreamURI.empty())
- {
- mFadeState = FADE_IN;
- gAudiop->startInternetStream(mNextStreamURI);
- startFading();
- }
- else
- {
- mFadeState = FADE_IDLE;
- deregisterIdleListener();
- fadeIsFinished = true; // Stop calling onIdleUpdate
- }
- }
- else if (mFadeState == FADE_IN)
- {
- if (mNextStreamURI != gAudiop->getInternetStreamURL())
- {
- mFadeState = FADE_OUT;
- startFading();
- }
- else
- {
- mFadeState = FADE_IDLE;
- deregisterIdleListener();
- fadeIsFinished = true; // Stop calling onIdleUpdate
- }
- }
- }
- return fadeIsFinished;
- }
- void LLViewerAudio::stopInternetStreamWithAutoFade()
- {
- mFadeState = FADE_IDLE;
- mNextStreamURI = LLStringUtil::null;
- mDone = true;
- gAudiop->startInternetStream(LLStringUtil::null);
- gAudiop->stopInternetStream();
- }
- void LLViewerAudio::startFading()
- {
- const F32 AUDIO_MUSIC_FADE_IN_TIME = 3.0f;
- const F32 AUDIO_MUSIC_FADE_OUT_TIME = 2.0f;
- // This minimum fade time prevents divide by zero and negative times
- const F32 AUDIO_MUSIC_MINIMUM_FADE_TIME = 0.01f;
- if(mDone)
- {
- // The fade state here should only be one of FADE_IN or FADE_OUT, but, in case it is not,
- // rather than check for both states assume a fade in and check for the fade out case.
- mFadeTime = AUDIO_MUSIC_FADE_IN_TIME;
- if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
- {
- mFadeTime = AUDIO_MUSIC_FADE_OUT_TIME;
- }
- // Prevent invalid fade time
- mFadeTime = llmax(mFadeTime, AUDIO_MUSIC_MINIMUM_FADE_TIME);
- stream_fade_timer.reset();
- stream_fade_timer.setTimerExpirySec(mFadeTime);
- mDone = false;
- }
- }
- F32 LLViewerAudio::getFadeVolume()
- {
- F32 fade_volume = 1.0f;
- if (stream_fade_timer.hasExpired())
- {
- mDone = true;
- // If we have been fading out set volume to 0 until the next fade state occurs to prevent
- // an audio transient.
- if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
- {
- fade_volume = 0.0f;
- }
- }
- if (!mDone)
- {
- // Calculate how far we are into the fade time
- fade_volume = stream_fade_timer.getElapsedTimeF32() / mFadeTime;
-
- if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
- {
- // If we are not fading in then we are fading out, so invert the fade
- // direction; start loud and move towards zero volume.
- fade_volume = 1.0f - fade_volume;
- }
- }
- return fade_volume;
- }
- void LLViewerAudio::onTeleportFailed()
- {
- if (gAudiop)
- {
- LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
- if (parcel)
- {
- mNextStreamURI = parcel->getMusicURL();
- }
- }
- }
- void init_audio()
- {
- if (!gAudiop)
- {
- llwarns << "Failed to create an appropriate Audio Engine" << llendl;
- return;
- }
- LLVector3d lpos_global = gAgentCamera.getCameraPositionGlobal();
- LLVector3 lpos_global_f;
- lpos_global_f.setVec(lpos_global);
-
- gAudiop->setListener(lpos_global_f,
- LLVector3::zero, // LLViewerCamera::getInstance()->getVelocity(), // !!! BUG need to replace this with smoothed velocity!
- LLViewerCamera::getInstance()->getUpAxis(),
- LLViewerCamera::getInstance()->getAtAxis());
- // load up our initial set of sounds we'll want so they're in memory and ready to be played
- BOOL mute_audio = gSavedSettings.getBOOL("MuteAudio");
- if (!mute_audio && FALSE == gSavedSettings.getBOOL("NoPreload"))
- {
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndAlert")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndBadKeystroke")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndChatFromObject")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClick")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClickRelease")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionF")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionM")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingChat")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingIM")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvApplyToObject")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvalidOp")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInventoryCopyToInv")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeDown")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeUp")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCopyToInv")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCreate")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectDelete")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezIn")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezOut")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndSnapshot")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartAutopilot")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartFollowpilot")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartIM")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStopAutopilot")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTeleportOut")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureApplyToObject")));
- //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureCopyToInv")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTyping")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowClose")));
- gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowOpen")));
- }
- audio_update_volume(true);
- }
- void audio_update_volume(bool force_update)
- {
- F32 master_volume = gSavedSettings.getF32("AudioLevelMaster");
- BOOL mute_audio = gSavedSettings.getBOOL("MuteAudio");
- LLProgressView* progress = gViewerWindow->getProgressView();
- BOOL progress_view_visible = FALSE;
- if (progress)
- {
- progress_view_visible = progress->getVisible();
- }
- if (!gViewerWindow->getActive() && gSavedSettings.getBOOL("MuteWhenMinimized"))
- {
- mute_audio = TRUE;
- }
- F32 mute_volume = mute_audio ? 0.0f : 1.0f;
- // Sound Effects
- if (gAudiop)
- {
- gAudiop->setMasterGain ( master_volume );
- gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler"));
- gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
- gAudiop->setMuted(mute_audio || progress_view_visible);
-
- if (force_update)
- {
- audio_update_wind(true);
- }
- // handle secondary gains
- gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_SFX,
- gSavedSettings.getBOOL("MuteSounds") ? 0.f : gSavedSettings.getF32("AudioLevelSFX"));
- gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_UI,
- gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI"));
- gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_AMBIENT,
- gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient"));
- }
- // Streaming Music
- if (gAudiop)
- {
- if (progress_view_visible && !LLViewerAudio::getInstance()->getForcedTeleportFade())
- {
- LLViewerAudio::getInstance()->setForcedTeleportFade(true);
- LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
- LLViewerAudio::getInstance()->setNextStreamURI(LLStringUtil::null);
- }
- if (!progress_view_visible && LLViewerAudio::getInstance()->getForcedTeleportFade() == true)
- {
- LLViewerAudio::getInstance()->setForcedTeleportFade(false);
- }
- F32 music_volume = gSavedSettings.getF32("AudioLevelMusic");
- BOOL music_muted = gSavedSettings.getBOOL("MuteMusic");
- F32 fade_volume = LLViewerAudio::getInstance()->getFadeVolume();
- music_volume = mute_volume * master_volume * music_volume * fade_volume;
- gAudiop->setInternetStreamGain (music_muted ? 0.f : music_volume);
- }
- // Streaming Media
- F32 media_volume = gSavedSettings.getF32("AudioLevelMedia");
- BOOL media_muted = gSavedSettings.getBOOL("MuteMedia");
- media_volume = mute_volume * master_volume * media_volume;
- LLViewerMedia::setVolume( media_muted ? 0.0f : media_volume );
- // Voice
- if (LLVoiceClient::getInstance())
- {
- F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice");
- voice_volume = mute_volume * master_volume * voice_volume;
- BOOL voice_mute = gSavedSettings.getBOOL("MuteVoice");
- LLVoiceClient::getInstance()->setVoiceVolume(voice_mute ? 0.f : voice_volume);
- LLVoiceClient::getInstance()->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic"));
- if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized")))
- {
- LLVoiceClient::getInstance()->setMuteMic(true);
- }
- else
- {
- LLVoiceClient::getInstance()->setMuteMic(false);
- }
- }
- }
- void audio_update_listener()
- {
- if (gAudiop)
- {
- // update listener position because agent has moved
- LLVector3d lpos_global = gAgentCamera.getCameraPositionGlobal();
- LLVector3 lpos_global_f;
- lpos_global_f.setVec(lpos_global);
-
- gAudiop->setListener(lpos_global_f,
- // LLViewerCamera::getInstance()VelocitySmoothed,
- // LLVector3::zero,
- gAgent.getVelocity(), // !!! *TODO: need to replace this with smoothed velocity!
- LLViewerCamera::getInstance()->getUpAxis(),
- LLViewerCamera::getInstance()->getAtAxis());
- }
- }
- void audio_update_wind(bool force_update)
- {
- #ifdef kAUDIO_ENABLE_WIND
- //
- // Extract height above water to modulate filter by whether above/below water
- //
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- static F32 last_camera_water_height = -1000.f;
- LLVector3 camera_pos = gAgentCamera.getCameraPositionAgent();
- F32 camera_water_height = camera_pos.mV[VZ] - region->getWaterHeight();
-
- //
- // Don't update rolloff factor unless water surface has been crossed
- //
- if (force_update || (last_camera_water_height * camera_water_height) < 0.f)
- {
- static LLUICachedControl<F32> rolloff("AudioLevelRolloff", 1.0f);
- if (camera_water_height < 0.f)
- {
- gAudiop->setRolloffFactor(rolloff * LL_ROLLOFF_MULTIPLIER_UNDER_WATER);
- }
- else
- {
- gAudiop->setRolloffFactor(rolloff);
- }
- }
-
- // Scale down the contribution of weather-simulation wind to the
- // ambient wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s
- // whereas steady-state avatar walk velocity is only 3.2 m/s.
- // Without this the world feels desolate on first login when you are
- // standing still.
- static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f);
- LLVector3 scaled_wind_vec = gWindVec * wind_level;
-
- // Mix in the avatar's motion, subtract because when you walk north,
- // the apparent wind moves south.
- LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity();
-
- // rotate the wind vector to be listener (agent) relative
- gRelativeWindVec = gAgent.getFrameAgent().rotateToLocal( final_wind_vec );
- // don't use the setter setMaxWindGain() because we don't
- // want to screw up the fade-in on startup by setting actual source gain
- // outside the fade-in.
- F32 master_volume = gSavedSettings.getBOOL("MuteAudio") ? 0.f : gSavedSettings.getF32("AudioLevelMaster");
- F32 ambient_volume = gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient");
- F32 max_wind_volume = master_volume * ambient_volume;
- const F32 WIND_SOUND_TRANSITION_TIME = 2.f;
- // amount to change volume this frame
- F32 volume_delta = (LLFrameTimer::getFrameDeltaTimeF32() / WIND_SOUND_TRANSITION_TIME) * max_wind_volume;
- if (force_update)
- {
- // initialize wind volume (force_update) by using large volume_delta
- // which is sufficient to completely turn off or turn on wind noise
- volume_delta = 1.f;
- }
- // mute wind when not flying
- if (gAgent.getFlying())
- {
- // volume increases by volume_delta, up to no more than max_wind_volume
- gAudiop->mMaxWindGain = llmin(gAudiop->mMaxWindGain + volume_delta, max_wind_volume);
- }
- else
- {
- // volume decreases by volume_delta, down to no less than 0
- gAudiop->mMaxWindGain = llmax(gAudiop->mMaxWindGain - volume_delta, 0.f);
- }
-
- last_camera_water_height = camera_water_height;
- gAudiop->updateWind(gRelativeWindVec, camera_water_height);
- }
- #endif
- }