PageRenderTime 54ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llvieweraudio.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 504 lines | 349 code | 64 blank | 91 comment | 55 complexity | 8ef9989609345a39555f18a5d44b3acf MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llvieweraudio.cpp
  3. * @brief Audio functions that used to be in viewer.cpp
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewerlgpl$
  6. * Second Life Viewer Source Code
  7. * Copyright (C) 2010, Linden Research, Inc.
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Lesser General Public
  11. * License as published by the Free Software Foundation;
  12. * version 2.1 of the License only.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public
  20. * License along with this library; if not, write to the Free Software
  21. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  22. *
  23. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  24. * $/LicenseInfo$
  25. */
  26. #include "llviewerprecompiledheaders.h"
  27. #include "llaudioengine.h"
  28. #include "llagent.h"
  29. #include "llagentcamera.h"
  30. #include "llappviewer.h"
  31. #include "llvieweraudio.h"
  32. #include "llviewercamera.h"
  33. #include "llviewercontrol.h"
  34. #include "llviewerwindow.h"
  35. #include "llvoiceclient.h"
  36. #include "llviewermedia.h"
  37. #include "llprogressview.h"
  38. #include "llcallbacklist.h"
  39. #include "llstartup.h"
  40. #include "llviewerparcelmgr.h"
  41. #include "llparcel.h"
  42. /////////////////////////////////////////////////////////
  43. LLViewerAudio::LLViewerAudio() :
  44. mDone(true),
  45. mFadeState(FADE_IDLE),
  46. mFadeTime(),
  47. mIdleListnerActive(false),
  48. mForcedTeleportFade(false)
  49. {
  50. mTeleportFailedConnection = LLViewerParcelMgr::getInstance()->
  51. setTeleportFailedCallback(boost::bind(&LLViewerAudio::onTeleportFailed, this));
  52. }
  53. LLViewerAudio::~LLViewerAudio()
  54. {
  55. mTeleportFailedConnection.disconnect();
  56. }
  57. void LLViewerAudio::registerIdleListener()
  58. {
  59. if(mIdleListnerActive==false)
  60. {
  61. mIdleListnerActive = true;
  62. doOnIdleRepeating(boost::bind(boost::bind(&LLViewerAudio::onIdleUpdate, this)));
  63. }
  64. }
  65. void LLViewerAudio::startInternetStreamWithAutoFade(std::string streamURI)
  66. {
  67. // Old and new stream are identical
  68. if (mNextStreamURI == streamURI)
  69. {
  70. return;
  71. }
  72. // Record the URI we are going to be switching to
  73. mNextStreamURI = streamURI;
  74. switch (mFadeState)
  75. {
  76. case FADE_IDLE:
  77. // If a stream is playing fade it out first
  78. if (!gAudiop->getInternetStreamURL().empty())
  79. {
  80. // The order of these tests is important, state FADE_OUT will be processed below
  81. mFadeState = FADE_OUT;
  82. }
  83. // Otherwise the new stream can be faded in
  84. else
  85. {
  86. mFadeState = FADE_IN;
  87. gAudiop->startInternetStream(mNextStreamURI);
  88. startFading();
  89. registerIdleListener();
  90. break;
  91. }
  92. case FADE_OUT:
  93. startFading();
  94. registerIdleListener();
  95. break;
  96. case FADE_IN:
  97. registerIdleListener();
  98. break;
  99. default:
  100. llwarns << "Unknown fading state: " << mFadeState << llendl;
  101. break;
  102. }
  103. }
  104. // A return of false from onIdleUpdate means it will be called again next idle update.
  105. // A return of true means we have finished with it and the callback will be deleted.
  106. bool LLViewerAudio::onIdleUpdate()
  107. {
  108. bool fadeIsFinished = false;
  109. // There is a delay in the login sequence between when the parcel information has
  110. // arrived and the music stream is started and when the audio system is called to set
  111. // initial volume levels. This code extends the fade time so you hear a full fade in.
  112. if ((LLStartUp::getStartupState() < STATE_STARTED))
  113. {
  114. stream_fade_timer.reset();
  115. stream_fade_timer.setTimerExpirySec(mFadeTime);
  116. }
  117. if (mDone)
  118. {
  119. // This should be a rare or never occurring state.
  120. if (mFadeState == FADE_IDLE)
  121. {
  122. deregisterIdleListener();
  123. fadeIsFinished = true; // Stop calling onIdleUpdate
  124. }
  125. // we have finished the current fade operation
  126. if (mFadeState == FADE_OUT)
  127. {
  128. // Clear URI
  129. gAudiop->startInternetStream(LLStringUtil::null);
  130. gAudiop->stopInternetStream();
  131. if (!mNextStreamURI.empty())
  132. {
  133. mFadeState = FADE_IN;
  134. gAudiop->startInternetStream(mNextStreamURI);
  135. startFading();
  136. }
  137. else
  138. {
  139. mFadeState = FADE_IDLE;
  140. deregisterIdleListener();
  141. fadeIsFinished = true; // Stop calling onIdleUpdate
  142. }
  143. }
  144. else if (mFadeState == FADE_IN)
  145. {
  146. if (mNextStreamURI != gAudiop->getInternetStreamURL())
  147. {
  148. mFadeState = FADE_OUT;
  149. startFading();
  150. }
  151. else
  152. {
  153. mFadeState = FADE_IDLE;
  154. deregisterIdleListener();
  155. fadeIsFinished = true; // Stop calling onIdleUpdate
  156. }
  157. }
  158. }
  159. return fadeIsFinished;
  160. }
  161. void LLViewerAudio::stopInternetStreamWithAutoFade()
  162. {
  163. mFadeState = FADE_IDLE;
  164. mNextStreamURI = LLStringUtil::null;
  165. mDone = true;
  166. gAudiop->startInternetStream(LLStringUtil::null);
  167. gAudiop->stopInternetStream();
  168. }
  169. void LLViewerAudio::startFading()
  170. {
  171. const F32 AUDIO_MUSIC_FADE_IN_TIME = 3.0f;
  172. const F32 AUDIO_MUSIC_FADE_OUT_TIME = 2.0f;
  173. // This minimum fade time prevents divide by zero and negative times
  174. const F32 AUDIO_MUSIC_MINIMUM_FADE_TIME = 0.01f;
  175. if(mDone)
  176. {
  177. // The fade state here should only be one of FADE_IN or FADE_OUT, but, in case it is not,
  178. // rather than check for both states assume a fade in and check for the fade out case.
  179. mFadeTime = AUDIO_MUSIC_FADE_IN_TIME;
  180. if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
  181. {
  182. mFadeTime = AUDIO_MUSIC_FADE_OUT_TIME;
  183. }
  184. // Prevent invalid fade time
  185. mFadeTime = llmax(mFadeTime, AUDIO_MUSIC_MINIMUM_FADE_TIME);
  186. stream_fade_timer.reset();
  187. stream_fade_timer.setTimerExpirySec(mFadeTime);
  188. mDone = false;
  189. }
  190. }
  191. F32 LLViewerAudio::getFadeVolume()
  192. {
  193. F32 fade_volume = 1.0f;
  194. if (stream_fade_timer.hasExpired())
  195. {
  196. mDone = true;
  197. // If we have been fading out set volume to 0 until the next fade state occurs to prevent
  198. // an audio transient.
  199. if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
  200. {
  201. fade_volume = 0.0f;
  202. }
  203. }
  204. if (!mDone)
  205. {
  206. // Calculate how far we are into the fade time
  207. fade_volume = stream_fade_timer.getElapsedTimeF32() / mFadeTime;
  208. if (LLViewerAudio::getInstance()->getFadeState() == LLViewerAudio::FADE_OUT)
  209. {
  210. // If we are not fading in then we are fading out, so invert the fade
  211. // direction; start loud and move towards zero volume.
  212. fade_volume = 1.0f - fade_volume;
  213. }
  214. }
  215. return fade_volume;
  216. }
  217. void LLViewerAudio::onTeleportFailed()
  218. {
  219. if (gAudiop)
  220. {
  221. LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
  222. if (parcel)
  223. {
  224. mNextStreamURI = parcel->getMusicURL();
  225. }
  226. }
  227. }
  228. void init_audio()
  229. {
  230. if (!gAudiop)
  231. {
  232. llwarns << "Failed to create an appropriate Audio Engine" << llendl;
  233. return;
  234. }
  235. LLVector3d lpos_global = gAgentCamera.getCameraPositionGlobal();
  236. LLVector3 lpos_global_f;
  237. lpos_global_f.setVec(lpos_global);
  238. gAudiop->setListener(lpos_global_f,
  239. LLVector3::zero, // LLViewerCamera::getInstance()->getVelocity(), // !!! BUG need to replace this with smoothed velocity!
  240. LLViewerCamera::getInstance()->getUpAxis(),
  241. LLViewerCamera::getInstance()->getAtAxis());
  242. // load up our initial set of sounds we'll want so they're in memory and ready to be played
  243. BOOL mute_audio = gSavedSettings.getBOOL("MuteAudio");
  244. if (!mute_audio && FALSE == gSavedSettings.getBOOL("NoPreload"))
  245. {
  246. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndAlert")));
  247. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndBadKeystroke")));
  248. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndChatFromObject")));
  249. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClick")));
  250. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndClickRelease")));
  251. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionF")));
  252. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndHealthReductionM")));
  253. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingChat")));
  254. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndIncomingIM")));
  255. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvApplyToObject")));
  256. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInvalidOp")));
  257. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndInventoryCopyToInv")));
  258. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeDown")));
  259. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndMoneyChangeUp")));
  260. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCopyToInv")));
  261. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectCreate")));
  262. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectDelete")));
  263. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezIn")));
  264. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndObjectRezOut")));
  265. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndSnapshot")));
  266. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartAutopilot")));
  267. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartFollowpilot")));
  268. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStartIM")));
  269. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndStopAutopilot")));
  270. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTeleportOut")));
  271. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureApplyToObject")));
  272. //gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTextureCopyToInv")));
  273. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndTyping")));
  274. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowClose")));
  275. gAudiop->preloadSound(LLUUID(gSavedSettings.getString("UISndWindowOpen")));
  276. }
  277. audio_update_volume(true);
  278. }
  279. void audio_update_volume(bool force_update)
  280. {
  281. F32 master_volume = gSavedSettings.getF32("AudioLevelMaster");
  282. BOOL mute_audio = gSavedSettings.getBOOL("MuteAudio");
  283. LLProgressView* progress = gViewerWindow->getProgressView();
  284. BOOL progress_view_visible = FALSE;
  285. if (progress)
  286. {
  287. progress_view_visible = progress->getVisible();
  288. }
  289. if (!gViewerWindow->getActive() && gSavedSettings.getBOOL("MuteWhenMinimized"))
  290. {
  291. mute_audio = TRUE;
  292. }
  293. F32 mute_volume = mute_audio ? 0.0f : 1.0f;
  294. // Sound Effects
  295. if (gAudiop)
  296. {
  297. gAudiop->setMasterGain ( master_volume );
  298. gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler"));
  299. gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
  300. gAudiop->setMuted(mute_audio || progress_view_visible);
  301. if (force_update)
  302. {
  303. audio_update_wind(true);
  304. }
  305. // handle secondary gains
  306. gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_SFX,
  307. gSavedSettings.getBOOL("MuteSounds") ? 0.f : gSavedSettings.getF32("AudioLevelSFX"));
  308. gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_UI,
  309. gSavedSettings.getBOOL("MuteUI") ? 0.f : gSavedSettings.getF32("AudioLevelUI"));
  310. gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_AMBIENT,
  311. gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient"));
  312. }
  313. // Streaming Music
  314. if (gAudiop)
  315. {
  316. if (progress_view_visible && !LLViewerAudio::getInstance()->getForcedTeleportFade())
  317. {
  318. LLViewerAudio::getInstance()->setForcedTeleportFade(true);
  319. LLViewerAudio::getInstance()->startInternetStreamWithAutoFade(LLStringUtil::null);
  320. LLViewerAudio::getInstance()->setNextStreamURI(LLStringUtil::null);
  321. }
  322. if (!progress_view_visible && LLViewerAudio::getInstance()->getForcedTeleportFade() == true)
  323. {
  324. LLViewerAudio::getInstance()->setForcedTeleportFade(false);
  325. }
  326. F32 music_volume = gSavedSettings.getF32("AudioLevelMusic");
  327. BOOL music_muted = gSavedSettings.getBOOL("MuteMusic");
  328. F32 fade_volume = LLViewerAudio::getInstance()->getFadeVolume();
  329. music_volume = mute_volume * master_volume * music_volume * fade_volume;
  330. gAudiop->setInternetStreamGain (music_muted ? 0.f : music_volume);
  331. }
  332. // Streaming Media
  333. F32 media_volume = gSavedSettings.getF32("AudioLevelMedia");
  334. BOOL media_muted = gSavedSettings.getBOOL("MuteMedia");
  335. media_volume = mute_volume * master_volume * media_volume;
  336. LLViewerMedia::setVolume( media_muted ? 0.0f : media_volume );
  337. // Voice
  338. if (LLVoiceClient::getInstance())
  339. {
  340. F32 voice_volume = gSavedSettings.getF32("AudioLevelVoice");
  341. voice_volume = mute_volume * master_volume * voice_volume;
  342. BOOL voice_mute = gSavedSettings.getBOOL("MuteVoice");
  343. LLVoiceClient::getInstance()->setVoiceVolume(voice_mute ? 0.f : voice_volume);
  344. LLVoiceClient::getInstance()->setMicGain(voice_mute ? 0.f : gSavedSettings.getF32("AudioLevelMic"));
  345. if (!gViewerWindow->getActive() && (gSavedSettings.getBOOL("MuteWhenMinimized")))
  346. {
  347. LLVoiceClient::getInstance()->setMuteMic(true);
  348. }
  349. else
  350. {
  351. LLVoiceClient::getInstance()->setMuteMic(false);
  352. }
  353. }
  354. }
  355. void audio_update_listener()
  356. {
  357. if (gAudiop)
  358. {
  359. // update listener position because agent has moved
  360. LLVector3d lpos_global = gAgentCamera.getCameraPositionGlobal();
  361. LLVector3 lpos_global_f;
  362. lpos_global_f.setVec(lpos_global);
  363. gAudiop->setListener(lpos_global_f,
  364. // LLViewerCamera::getInstance()VelocitySmoothed,
  365. // LLVector3::zero,
  366. gAgent.getVelocity(), // !!! *TODO: need to replace this with smoothed velocity!
  367. LLViewerCamera::getInstance()->getUpAxis(),
  368. LLViewerCamera::getInstance()->getAtAxis());
  369. }
  370. }
  371. void audio_update_wind(bool force_update)
  372. {
  373. #ifdef kAUDIO_ENABLE_WIND
  374. //
  375. // Extract height above water to modulate filter by whether above/below water
  376. //
  377. LLViewerRegion* region = gAgent.getRegion();
  378. if (region)
  379. {
  380. static F32 last_camera_water_height = -1000.f;
  381. LLVector3 camera_pos = gAgentCamera.getCameraPositionAgent();
  382. F32 camera_water_height = camera_pos.mV[VZ] - region->getWaterHeight();
  383. //
  384. // Don't update rolloff factor unless water surface has been crossed
  385. //
  386. if (force_update || (last_camera_water_height * camera_water_height) < 0.f)
  387. {
  388. static LLUICachedControl<F32> rolloff("AudioLevelRolloff", 1.0f);
  389. if (camera_water_height < 0.f)
  390. {
  391. gAudiop->setRolloffFactor(rolloff * LL_ROLLOFF_MULTIPLIER_UNDER_WATER);
  392. }
  393. else
  394. {
  395. gAudiop->setRolloffFactor(rolloff);
  396. }
  397. }
  398. // Scale down the contribution of weather-simulation wind to the
  399. // ambient wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s
  400. // whereas steady-state avatar walk velocity is only 3.2 m/s.
  401. // Without this the world feels desolate on first login when you are
  402. // standing still.
  403. static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f);
  404. LLVector3 scaled_wind_vec = gWindVec * wind_level;
  405. // Mix in the avatar's motion, subtract because when you walk north,
  406. // the apparent wind moves south.
  407. LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity();
  408. // rotate the wind vector to be listener (agent) relative
  409. gRelativeWindVec = gAgent.getFrameAgent().rotateToLocal( final_wind_vec );
  410. // don't use the setter setMaxWindGain() because we don't
  411. // want to screw up the fade-in on startup by setting actual source gain
  412. // outside the fade-in.
  413. F32 master_volume = gSavedSettings.getBOOL("MuteAudio") ? 0.f : gSavedSettings.getF32("AudioLevelMaster");
  414. F32 ambient_volume = gSavedSettings.getBOOL("MuteAmbient") ? 0.f : gSavedSettings.getF32("AudioLevelAmbient");
  415. F32 max_wind_volume = master_volume * ambient_volume;
  416. const F32 WIND_SOUND_TRANSITION_TIME = 2.f;
  417. // amount to change volume this frame
  418. F32 volume_delta = (LLFrameTimer::getFrameDeltaTimeF32() / WIND_SOUND_TRANSITION_TIME) * max_wind_volume;
  419. if (force_update)
  420. {
  421. // initialize wind volume (force_update) by using large volume_delta
  422. // which is sufficient to completely turn off or turn on wind noise
  423. volume_delta = 1.f;
  424. }
  425. // mute wind when not flying
  426. if (gAgent.getFlying())
  427. {
  428. // volume increases by volume_delta, up to no more than max_wind_volume
  429. gAudiop->mMaxWindGain = llmin(gAudiop->mMaxWindGain + volume_delta, max_wind_volume);
  430. }
  431. else
  432. {
  433. // volume decreases by volume_delta, down to no less than 0
  434. gAudiop->mMaxWindGain = llmax(gAudiop->mMaxWindGain - volume_delta, 0.f);
  435. }
  436. last_camera_water_height = camera_water_height;
  437. gAudiop->updateWind(gRelativeWindVec, camera_water_height);
  438. }
  439. #endif
  440. }