llvieweraudio.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /**
  2. * @file llvieweraudio.cpp
  3. * @brief Audio functions that used to be in viewer.cpp
  4. *
  5. * $LicenseInfo:firstyear=2002&license=viewergpl$
  6. *
  7. * Copyright (c) 2002-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #include "llviewerprecompiledheaders.h"
  33. #include <stack>
  34. #include "llvieweraudio.h"
  35. #include "llaudioengine.h"
  36. #include "lldir.h"
  37. #include "llagent.h"
  38. #include "llappviewer.h"
  39. #include "llstartup.h"
  40. #include "llviewercamera.h"
  41. #include "llviewercontrol.h"
  42. #include "llviewermedia.h"
  43. #include "llviewerregion.h"
  44. #include "llviewerwindow.h"
  45. #include "llvoiceclient.h"
  46. static void get_ui_sounds_list(std::stack<std::string>& ui_sounds)
  47. {
  48. ui_sounds.emplace("UISndAlert");
  49. ui_sounds.emplace("UISndBadKeystroke");
  50. ui_sounds.emplace("UISndClick");
  51. ui_sounds.emplace("UISndClickRelease");
  52. ui_sounds.emplace("UISndHealthReductionF");
  53. ui_sounds.emplace("UISndHealthReductionM");
  54. ui_sounds.emplace("UISndInvalidOp");
  55. ui_sounds.emplace("UISndMoneyChangeDown");
  56. ui_sounds.emplace("UISndMoneyChangeUp");
  57. ui_sounds.emplace("UISndNewIncomingIMSession");
  58. ui_sounds.emplace("UISndObjectCreate");
  59. ui_sounds.emplace("UISndObjectDelete");
  60. ui_sounds.emplace("UISndObjectRezIn");
  61. ui_sounds.emplace("UISndObjectRezOut");
  62. ui_sounds.emplace("UISndPieMenuAppear");
  63. ui_sounds.emplace("UISndPieMenuHide");
  64. // UISndPieMenuSliceHighlight = d9f73cf8-17b4-6f7a-1565-7951226c305d
  65. // Also exists (same sound, different UUID) as:
  66. // f6ba9816-dcaf-f755-7b67-51b31b6233e5
  67. // 7aff2265-d05b-8b72-63c7-dbf96dc2f21f
  68. // 09b2184e-8601-44e2-afbb-ce37434b8ba1
  69. // bbe4c7fc-7044-b05e-7b89-36924a67593c
  70. // d166039b-b4f5-c2ec-4911-c85c727b016c
  71. // 242af82b-43c2-9a3b-e108-3b0c7e384981
  72. // c1f334fb-a5be-8fe7-22b3-29631c21cf0b
  73. ui_sounds.emplace("UISndPieMenuSliceHighlight");
  74. ui_sounds.emplace("UISndSnapshot");
  75. ui_sounds.emplace("UISndStartIM");
  76. ui_sounds.emplace("UISndTeleportOut");
  77. ui_sounds.emplace("UISndTyping");
  78. ui_sounds.emplace("UISndWindowClose");
  79. ui_sounds.emplace("UISndWindowOpen");
  80. }
  81. std::string get_valid_sounds()
  82. {
  83. std::stack<std::string> ui_sounds;
  84. get_ui_sounds_list(ui_sounds);
  85. std::string name, sound_list;
  86. while (!ui_sounds.empty())
  87. {
  88. sound_list += ";" + ui_sounds.top();
  89. ui_sounds.pop();
  90. }
  91. return sound_list + ";";
  92. }
  93. void audio_preload_ui_sounds(bool force_decode)
  94. {
  95. if (!gAudiop)
  96. {
  97. llwarns << "Audio Engine not initialized. Could not preload the UI sounds."
  98. << llendl;
  99. return;
  100. }
  101. std::stack<std::string> ui_sounds;
  102. get_ui_sounds_list(ui_sounds);
  103. F32 audio_level = gSavedSettings.getF32("AudioLevelUI") *
  104. gSavedSettings.getF32("AudioLevelMaster");
  105. if (!force_decode || audio_level == 0.f ||
  106. gSavedSettings.getBool("MuteAudio") ||
  107. gSavedSettings.getBool("MuteUI"))
  108. {
  109. audio_level = 0.f;
  110. if (force_decode)
  111. {
  112. llwarns << "UI muted: cannot force-decode UI sounds." << llendl;
  113. }
  114. }
  115. else
  116. {
  117. // Normalize to 25% combined volume, or the highest possible volume
  118. // if 25% can't be reached.
  119. audio_level = 0.25f / audio_level;
  120. if (audio_level > 1.f)
  121. {
  122. audio_level = 1.f;
  123. }
  124. }
  125. LLUUID uuid;
  126. std::string sound_file;
  127. while (!ui_sounds.empty())
  128. {
  129. uuid.set(gSavedSettings.getString(ui_sounds.top().c_str()));
  130. ui_sounds.pop();
  131. if (uuid.isNull()) continue;
  132. if (!LLAudioEngine::getUISoundFile(uuid, sound_file))
  133. {
  134. // This sound is not part of the pre-decoded UI sounds and must be
  135. // fetched. Make sure they are at least pre-fetched.
  136. gAudiop->preloadSound(uuid);
  137. if (audio_level > 0.f)
  138. {
  139. // Try to force-decode them (will depend on actual audio level)
  140. // by playing them.
  141. gAudiop->triggerSound(uuid, gAgentID, audio_level,
  142. LLAudioEngine::AUDIO_TYPE_UI);
  143. }
  144. }
  145. }
  146. }
  147. void copy_pre_decoded_ui_sounds(void*)
  148. {
  149. std::string ui_sounds_dir = gDirUtil.getFullPath(LL_PATH_USER_SETTINGS,
  150. "ui_sounds");
  151. LLFile::mkdir(ui_sounds_dir);
  152. ui_sounds_dir += LL_DIR_DELIM_STR;
  153. std::stack<std::string> ui_sounds;
  154. get_ui_sounds_list(ui_sounds);
  155. LLUUID uuid;
  156. std::string filename, sound_file;
  157. bool missing = false;
  158. while (!ui_sounds.empty())
  159. {
  160. bool copy = false;
  161. uuid.set(gSavedSettings.getString(ui_sounds.top().c_str()));
  162. ui_sounds.pop();
  163. if (uuid.isNull()) continue;
  164. filename = uuid.asString() + ".dsf";
  165. #if LL_SEARCH_UI_SOUNDS_IN_SKINS
  166. bool in_user_settings = false;
  167. if (LLAudioEngine::getUISoundFile(uuid, sound_file,
  168. &in_user_settings))
  169. {
  170. // This pre-decoded sound file exists: let's see where:
  171. if (in_user_settings)
  172. {
  173. llinfos << "Decoded sound file '" << filename
  174. << "' already present in '" << ui_sounds_dir << "'"
  175. << llendl;
  176. }
  177. else
  178. {
  179. copy = true;
  180. }
  181. }
  182. else
  183. {
  184. // Search among cached sound files
  185. sound_file = gDirUtil.getFullPath(LL_PATH_CACHE, filename);
  186. copy = LLFile::exists(sound_file);
  187. if (!copy)
  188. {
  189. llwarns << "UI sound file '" << filename << "' not found."
  190. << llendl;
  191. missing = true;
  192. }
  193. }
  194. #else
  195. if (LLAudioEngine::getUISoundFile(uuid, sound_file))
  196. {
  197. llinfos << "Decoded sound file '" << filename
  198. << "' already present in '" << ui_sounds_dir << "'"
  199. << llendl;
  200. continue;
  201. }
  202. // Then search in the viewer installation LL_PATH_SKINS/default/sounds/
  203. // sub-directory (old location, no more used).
  204. sound_file = gDirUtil.getFullPath(LL_PATH_SKINS, "default", "sounds",
  205. filename);
  206. if (LLFile::exists(sound_file))
  207. {
  208. copy = true;
  209. }
  210. else
  211. {
  212. // Finally, search among cached sound files
  213. sound_file = gDirUtil.getFullPath(LL_PATH_CACHE, filename);
  214. copy = LLFile::exists(sound_file);
  215. if (!copy)
  216. {
  217. llwarns << "UI sound file '" << filename << "' not found."
  218. << llendl;
  219. missing = true;
  220. }
  221. }
  222. #endif
  223. if (copy)
  224. {
  225. llinfos << "Copying decoded sound file '" << filename << "' into '"
  226. << ui_sounds_dir << "'" << llendl;
  227. LLFile::copy(sound_file, ui_sounds_dir + filename);
  228. }
  229. }
  230. if (missing)
  231. {
  232. gNotifications.add("SomeUISoundsMissing");
  233. }
  234. else
  235. {
  236. gNotifications.add("AllUISoundsSaved");
  237. }
  238. }
  239. void clear_pre_decoded_ui_sounds()
  240. {
  241. std::stack<std::string> ui_sounds;
  242. get_ui_sounds_list(ui_sounds);
  243. LLUUID uuid;
  244. std::string sound_file;
  245. while (!ui_sounds.empty())
  246. {
  247. uuid.set(gSavedSettings.getString(ui_sounds.top().c_str()));
  248. ui_sounds.pop();
  249. if (uuid.isNull()) continue;
  250. // Search in the user's account LL_PATH_USER_SETTINGS/ui_sounds/
  251. // directory.
  252. sound_file = gDirUtil.getFullPath(LL_PATH_USER_SETTINGS, "ui_sounds",
  253. uuid.asString()) + ".dsf";
  254. if (LLFile::exists(sound_file))
  255. {
  256. llinfos << "Removing pre-decoded UI sound file: " << sound_file
  257. << llendl;
  258. LLFile::remove(sound_file);
  259. }
  260. }
  261. }
  262. void init_audio()
  263. {
  264. // Clear the saved pre-decoded UI sounds from user settings if it was
  265. // requested in previous session (i.e. before relog); on the condition we
  266. // are the only running instance of our viewer !
  267. if (gSavedSettings.getBool("ClearSavedUISounds") &&
  268. !gAppViewerp->isSecondInstanceSiblingViewer())
  269. {
  270. gSavedSettings.setBool("ClearSavedUISounds", false);
  271. clear_pre_decoded_ui_sounds();
  272. }
  273. if (!gAudiop) return;
  274. setup_audio_listener();
  275. // Load up our initial set of sounds so they are ready to be played
  276. if (!gSavedSettings.getBool("NoPreload"))
  277. {
  278. audio_preload_ui_sounds();
  279. }
  280. audio_update_volume(true);
  281. }
  282. void setup_audio_listener()
  283. {
  284. LLVector3d lpos_global = gAgent.getCameraPositionGlobal();
  285. LLVector3 lpos_global_f;
  286. lpos_global_f.set(lpos_global);
  287. gAudiop->setListener(lpos_global_f,
  288. #if 0 // *FIXME: need to replace this with smoothed velocity
  289. gViewerCamera.getVelocity(),
  290. #else
  291. LLVector3::zero,
  292. #endif
  293. gViewerCamera.getUpAxis(),
  294. gViewerCamera.getAtAxis());
  295. }
  296. // A callback set in LLAppViewer::init()
  297. void ui_audio_callback(const LLUUID& uuid)
  298. {
  299. if (gAudiop)
  300. {
  301. if (!LLStartUp::isLoggedIn())
  302. {
  303. // If we are not yet connected, we can only play pre-decoded UI
  304. // sounds, if any. Else we get a sound loading failure and the
  305. // viewer will never retry and load that sound for the rest of the
  306. // session !
  307. std::string sound_file;
  308. if (!LLAudioEngine::getUISoundFile(uuid, sound_file))
  309. {
  310. return;
  311. }
  312. }
  313. gAudiop->triggerSound(uuid, gAgentID, 1.f,
  314. LLAudioEngine::AUDIO_TYPE_UI);
  315. }
  316. }
  317. void audio_update_volume(bool force_update)
  318. {
  319. static LLCachedControl<bool> sMuteAudio(gSavedSettings, "MuteAudio");
  320. static LLCachedControl<bool> sMuteAmbient(gSavedSettings, "MuteAmbient");
  321. static LLCachedControl<bool> sMuteSounds(gSavedSettings, "MuteSounds");
  322. static LLCachedControl<bool> sMuteUI(gSavedSettings, "MuteUI");
  323. static LLCachedControl<bool> sMuteMusic(gSavedSettings, "MuteMusic");
  324. static LLCachedControl<bool> sMuteMedia(gSavedSettings, "MuteMedia");
  325. static LLCachedControl<bool> sMuteVoice(gSavedSettings, "MuteVoice");
  326. static LLCachedControl<bool> sMuteWhenMinimized(gSavedSettings, "MuteWhenMinimized");
  327. static LLCachedControl<bool> sDisableWindAudio(gSavedSettings, "DisableWindAudio");
  328. static LLCachedControl<F32> sAudioLevelMaster(gSavedSettings, "AudioLevelMaster");
  329. static LLCachedControl<F32> sAudioLevelAmbient(gSavedSettings, "AudioLevelAmbient");
  330. static LLCachedControl<F32> sAudioLevelUI(gSavedSettings, "AudioLevelUI");
  331. static LLCachedControl<F32> sAudioLevelSFX(gSavedSettings, "AudioLevelSFX");
  332. static LLCachedControl<F32> sAudioLevelMusic(gSavedSettings, "AudioLevelMusic");
  333. static LLCachedControl<F32> sAudioLevelMedia(gSavedSettings, "AudioLevelMedia");
  334. static LLCachedControl<F32> sAudioLevelVoice(gSavedSettings, "AudioLevelVoice");
  335. static LLCachedControl<F32> sAudioLevelMic(gSavedSettings, "AudioLevelMic");
  336. static LLCachedControl<F32> sAudioLevelDoppler(gSavedSettings, "AudioLevelDoppler");
  337. static LLCachedControl<F32> sAudioLevelRolloff(gSavedSettings, "AudioLevelRolloff");
  338. static LLCachedControl<F32> sAudioLevelUnderwaterRolloff(gSavedSettings,
  339. "AudioLevelUnderwaterRolloff");
  340. bool mute = sMuteAudio;
  341. if (sMuteWhenMinimized && gViewerWindowp && !gViewerWindowp->getActive())
  342. {
  343. mute = true;
  344. }
  345. F32 mute_volume = mute ? 0.f : 1.f;
  346. if (gAudiop)
  347. {
  348. // Sound Effects
  349. gAudiop->setMasterGain(sAudioLevelMaster);
  350. gAudiop->setDopplerFactor(sAudioLevelDoppler);
  351. if (gViewerCamera.cameraUnderWater())
  352. {
  353. gAudiop->setRolloffFactor(sAudioLevelUnderwaterRolloff);
  354. }
  355. else
  356. {
  357. gAudiop->setRolloffFactor(sAudioLevelRolloff);
  358. }
  359. gAudiop->setMuted(mute);
  360. gAudiop->enableWind(!mute && !sMuteAmbient && !sDisableWindAudio &&
  361. sAudioLevelMaster * sAudioLevelAmbient > 0.01f);
  362. if (force_update)
  363. {
  364. audio_update_wind(true);
  365. }
  366. // Handle secondary gains
  367. gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_SFX,
  368. sMuteSounds ? 0.f : sAudioLevelSFX);
  369. gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_UI,
  370. sMuteUI ? 0.f : sAudioLevelUI);
  371. gAudiop->setSecondaryGain(LLAudioEngine::AUDIO_TYPE_AMBIENT,
  372. sMuteAmbient ? 0.f : sAudioLevelAmbient);
  373. // Streaming Music
  374. F32 music_volume = sAudioLevelMusic;
  375. music_volume = mute_volume * sAudioLevelMaster * music_volume * music_volume;
  376. gAudiop->setInternetStreamGain(sMuteMusic ? 0.f : music_volume);
  377. }
  378. // Streaming Media
  379. F32 media_volume = sAudioLevelMedia;
  380. media_volume = mute_volume * sAudioLevelMaster * media_volume * media_volume;
  381. LLViewerMedia::setVolume(sMuteMedia ? 0.f : media_volume);
  382. // Voice
  383. if (gVoiceClient.ready())
  384. {
  385. F32 voice_volume = sAudioLevelVoice;
  386. voice_volume = mute_volume * sAudioLevelMaster * voice_volume;
  387. gVoiceClient.setVoiceVolume(sMuteVoice ? 0.f : voice_volume);
  388. gVoiceClient.setMicGain(sMuteVoice ? 0.f : sAudioLevelMic);
  389. if (sMuteWhenMinimized && gViewerWindowp && !gViewerWindowp->getActive())
  390. {
  391. gVoiceClient.setMuteMic(true);
  392. }
  393. else
  394. {
  395. gVoiceClient.setMuteMic(false);
  396. }
  397. }
  398. }
  399. void audio_update_listener()
  400. {
  401. if (!gAudiop)
  402. {
  403. return;
  404. }
  405. // Update listener position because agent has moved
  406. LLVector3 pos_global;
  407. pos_global.set(gAgent.getCameraPositionGlobal());
  408. // *TODO: replace gAgent.getVelocity() with smoothed velocity
  409. gAudiop->setListener(pos_global, gAgent.getVelocity(),
  410. gViewerCamera.getUpAxis(), gViewerCamera.getAtAxis());
  411. }
  412. void audio_update_wind(bool force_update)
  413. {
  414. static LLCachedControl<bool> sMuteAudio(gSavedSettings, "MuteAudio");
  415. static LLCachedControl<bool> sMuteAmbient(gSavedSettings, "MuteAmbient");
  416. static LLCachedControl<F32> sAudioLevelMaster(gSavedSettings, "AudioLevelMaster");
  417. static LLCachedControl<F32> sAudioLevelAmbient(gSavedSettings, "AudioLevelAmbient");
  418. static LLCachedControl<F32> sAudioLevelWind(gSavedSettings, "AudioLevelWind");
  419. static LLCachedControl<F32> sAudioLevelRolloff(gSavedSettings, "AudioLevelRolloff");
  420. static LLCachedControl<F32> sAudioLevelUnderwaterRolloff(gSavedSettings,
  421. "AudioLevelUnderwaterRolloff");
  422. if (!gAudiop || !gAudiop->isWindEnabled())
  423. {
  424. return;
  425. }
  426. LLViewerRegion* region = gAgent.getRegion();
  427. if (!region)
  428. {
  429. return; // Probably disconnected
  430. }
  431. // Determine whether we are underwater or not
  432. const LLVector3& camera_pos = gAgent.getCameraPositionAgent();
  433. F32 camera_water_height = camera_pos.mV[VZ] - region->getWaterHeight();
  434. if (camera_water_height < 0.f)
  435. {
  436. gRelativeWindVec.clear(); // There is no wind underwater !
  437. gAudiop->updateWind(gRelativeWindVec, camera_water_height);
  438. return;
  439. }
  440. // This line rotates the wind vector to be listener (agent) relative.
  441. gRelativeWindVec =
  442. gAgent.getFrameAgent().rotateToLocal(gWindVec - gAgent.getVelocity());
  443. // Scale down the contribution of weather-simulation wind to the ambient
  444. // wind noise. Wind velocity averages 3.5 m/s, with gusts to 7 m/s whereas
  445. // steady-state avatar walk velocity is only 3.2 m/s. Without this the
  446. // world feels desolate on first login when you are/ standing still.
  447. gRelativeWindVec *= llclamp((F32)sAudioLevelWind, 0.f, 1.f);
  448. // Do not use the setter setMaxWindGain() because we do not want to screw
  449. // up the fade-in on startup by setting actual source gain outside the
  450. // fade-in.
  451. F32 master_volume = sMuteAudio ? 0.f : sAudioLevelMaster;
  452. F32 ambient_volume = sMuteAmbient ? 0.f : sAudioLevelAmbient;
  453. F32 wind_volume = master_volume * ambient_volume;
  454. gAudiop->mMaxWindGain = wind_volume;
  455. gAudiop->updateWind(gRelativeWindVec, camera_water_height);
  456. }