PageRenderTime 37ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/indra/newview/llvoiceclient.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 1078 lines | 809 code | 166 blank | 103 comment | 105 complexity | d7ef7d97b2698ebcb45cac1a6109a516 MD5 | raw file
Possible License(s): LGPL-2.1
  1. /**
  2. * @file llvoiceclient.cpp
  3. * @brief Voice client delegation class implementation.
  4. *
  5. * $LicenseInfo:firstyear=2001&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 "llvoiceclient.h"
  28. #include "llviewercontrol.h"
  29. #include "llviewerwindow.h"
  30. #include "llvoicevivox.h"
  31. #include "llviewernetwork.h"
  32. #include "llcommandhandler.h"
  33. #include "llhttpnode.h"
  34. #include "llnotificationsutil.h"
  35. #include "llsdserialize.h"
  36. #include "llui.h"
  37. #include "llkeyboard.h"
  38. const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f;
  39. const F32 LLVoiceClient::VOLUME_MIN = 0.f;
  40. const F32 LLVoiceClient::VOLUME_DEFAULT = 0.5f;
  41. const F32 LLVoiceClient::VOLUME_MAX = 1.0f;
  42. // Support for secondlife:///app/voice SLapps
  43. class LLVoiceHandler : public LLCommandHandler
  44. {
  45. public:
  46. // requests will be throttled from a non-trusted browser
  47. LLVoiceHandler() : LLCommandHandler("voice", UNTRUSTED_THROTTLE) {}
  48. bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
  49. {
  50. if (params[0].asString() == "effects")
  51. {
  52. LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface();
  53. // If the voice client doesn't support voice effects, we can't handle effects SLapps
  54. if (!effect_interface)
  55. {
  56. return false;
  57. }
  58. // Support secondlife:///app/voice/effects/refresh to update the voice effect list with new effects
  59. if (params[1].asString() == "refresh")
  60. {
  61. effect_interface->refreshVoiceEffectLists(false);
  62. return true;
  63. }
  64. }
  65. return false;
  66. }
  67. };
  68. LLVoiceHandler gVoiceHandler;
  69. std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus)
  70. {
  71. std::string result = "UNKNOWN";
  72. // Prevent copy-paste errors when updating this list...
  73. #define CASE(x) case x: result = #x; break
  74. switch(inStatus)
  75. {
  76. CASE(STATUS_LOGIN_RETRY);
  77. CASE(STATUS_LOGGED_IN);
  78. CASE(STATUS_JOINING);
  79. CASE(STATUS_JOINED);
  80. CASE(STATUS_LEFT_CHANNEL);
  81. CASE(STATUS_VOICE_DISABLED);
  82. CASE(BEGIN_ERROR_STATUS);
  83. CASE(ERROR_CHANNEL_FULL);
  84. CASE(ERROR_CHANNEL_LOCKED);
  85. CASE(ERROR_NOT_AVAILABLE);
  86. CASE(ERROR_UNKNOWN);
  87. default:
  88. break;
  89. }
  90. #undef CASE
  91. return result;
  92. }
  93. ///////////////////////////////////////////////////////////////////////////////////////////////
  94. LLVoiceClient::LLVoiceClient()
  95. :
  96. mVoiceModule(NULL),
  97. m_servicePump(NULL),
  98. mVoiceEffectEnabled(LLCachedControl<bool>(gSavedSettings, "VoiceMorphingEnabled")),
  99. mVoiceEffectDefault(LLCachedControl<std::string>(gSavedPerAccountSettings, "VoiceEffectDefault")),
  100. mPTTDirty(true),
  101. mPTT(true),
  102. mUsePTT(true),
  103. mPTTIsMiddleMouse(false),
  104. mPTTKey(0),
  105. mPTTIsToggle(false),
  106. mUserPTTState(false),
  107. mMuteMic(false),
  108. mDisableMic(false)
  109. {
  110. updateSettings();
  111. }
  112. //---------------------------------------------------
  113. // Basic setup/shutdown
  114. LLVoiceClient::~LLVoiceClient()
  115. {
  116. }
  117. void LLVoiceClient::init(LLPumpIO *pump)
  118. {
  119. // Initialize all of the voice modules
  120. m_servicePump = pump;
  121. }
  122. void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID)
  123. {
  124. // In the future, we should change this to allow voice module registration
  125. // with a table lookup of sorts.
  126. std::string voice_server = gSavedSettings.getString("VoiceServerType");
  127. LL_DEBUGS("Voice") << "voice server type " << voice_server << LL_ENDL;
  128. if(voice_server == "vivox")
  129. {
  130. mVoiceModule = (LLVoiceModuleInterface *)LLVivoxVoiceClient::getInstance();
  131. }
  132. else
  133. {
  134. mVoiceModule = NULL;
  135. return;
  136. }
  137. mVoiceModule->init(m_servicePump);
  138. mVoiceModule->userAuthorized(user_id, agentID);
  139. }
  140. void LLVoiceClient::terminate()
  141. {
  142. if (mVoiceModule) mVoiceModule->terminate();
  143. mVoiceModule = NULL;
  144. }
  145. const LLVoiceVersionInfo LLVoiceClient::getVersion()
  146. {
  147. if (mVoiceModule)
  148. {
  149. return mVoiceModule->getVersion();
  150. }
  151. else
  152. {
  153. LLVoiceVersionInfo result;
  154. result.serverVersion = std::string();
  155. result.serverType = std::string();
  156. return result;
  157. }
  158. }
  159. void LLVoiceClient::updateSettings()
  160. {
  161. setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
  162. std::string keyString = gSavedSettings.getString("PushToTalkButton");
  163. setPTTKey(keyString);
  164. setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
  165. mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic");
  166. updateMicMuteLogic();
  167. if (mVoiceModule) mVoiceModule->updateSettings();
  168. }
  169. //--------------------------------------------------
  170. // tuning
  171. void LLVoiceClient::tuningStart()
  172. {
  173. if (mVoiceModule) mVoiceModule->tuningStart();
  174. }
  175. void LLVoiceClient::tuningStop()
  176. {
  177. if (mVoiceModule) mVoiceModule->tuningStop();
  178. }
  179. bool LLVoiceClient::inTuningMode()
  180. {
  181. if (mVoiceModule)
  182. {
  183. return mVoiceModule->inTuningMode();
  184. }
  185. else
  186. {
  187. return false;
  188. }
  189. }
  190. void LLVoiceClient::tuningSetMicVolume(float volume)
  191. {
  192. if (mVoiceModule) mVoiceModule->tuningSetMicVolume(volume);
  193. }
  194. void LLVoiceClient::tuningSetSpeakerVolume(float volume)
  195. {
  196. if (mVoiceModule) mVoiceModule->tuningSetSpeakerVolume(volume);
  197. }
  198. float LLVoiceClient::tuningGetEnergy(void)
  199. {
  200. if (mVoiceModule)
  201. {
  202. return mVoiceModule->tuningGetEnergy();
  203. }
  204. else
  205. {
  206. return 0.0;
  207. }
  208. }
  209. //------------------------------------------------
  210. // devices
  211. bool LLVoiceClient::deviceSettingsAvailable()
  212. {
  213. if (mVoiceModule)
  214. {
  215. return mVoiceModule->deviceSettingsAvailable();
  216. }
  217. else
  218. {
  219. return false;
  220. }
  221. }
  222. void LLVoiceClient::refreshDeviceLists(bool clearCurrentList)
  223. {
  224. if (mVoiceModule) mVoiceModule->refreshDeviceLists(clearCurrentList);
  225. }
  226. void LLVoiceClient::setCaptureDevice(const std::string& name)
  227. {
  228. if (mVoiceModule) mVoiceModule->setCaptureDevice(name);
  229. }
  230. void LLVoiceClient::setRenderDevice(const std::string& name)
  231. {
  232. if (mVoiceModule) mVoiceModule->setRenderDevice(name);
  233. }
  234. const LLVoiceDeviceList& LLVoiceClient::getCaptureDevices()
  235. {
  236. static LLVoiceDeviceList nullCaptureDevices;
  237. if (mVoiceModule)
  238. {
  239. return mVoiceModule->getCaptureDevices();
  240. }
  241. else
  242. {
  243. return nullCaptureDevices;
  244. }
  245. }
  246. const LLVoiceDeviceList& LLVoiceClient::getRenderDevices()
  247. {
  248. static LLVoiceDeviceList nullRenderDevices;
  249. if (mVoiceModule)
  250. {
  251. return mVoiceModule->getRenderDevices();
  252. }
  253. else
  254. {
  255. return nullRenderDevices;
  256. }
  257. }
  258. //--------------------------------------------------
  259. // participants
  260. void LLVoiceClient::getParticipantList(std::set<LLUUID> &participants)
  261. {
  262. if (mVoiceModule)
  263. {
  264. mVoiceModule->getParticipantList(participants);
  265. }
  266. else
  267. {
  268. participants = std::set<LLUUID>();
  269. }
  270. }
  271. bool LLVoiceClient::isParticipant(const LLUUID &speaker_id)
  272. {
  273. if(mVoiceModule)
  274. {
  275. return mVoiceModule->isParticipant(speaker_id);
  276. }
  277. return false;
  278. }
  279. //--------------------------------------------------
  280. // text chat
  281. BOOL LLVoiceClient::isSessionTextIMPossible(const LLUUID& id)
  282. {
  283. if (mVoiceModule)
  284. {
  285. return mVoiceModule->isSessionTextIMPossible(id);
  286. }
  287. else
  288. {
  289. return FALSE;
  290. }
  291. }
  292. BOOL LLVoiceClient::isSessionCallBackPossible(const LLUUID& id)
  293. {
  294. if (mVoiceModule)
  295. {
  296. return mVoiceModule->isSessionCallBackPossible(id);
  297. }
  298. else
  299. {
  300. return FALSE;
  301. }
  302. }
  303. BOOL LLVoiceClient::sendTextMessage(const LLUUID& participant_id, const std::string& message)
  304. {
  305. if (mVoiceModule)
  306. {
  307. return mVoiceModule->sendTextMessage(participant_id, message);
  308. }
  309. else
  310. {
  311. return FALSE;
  312. }
  313. }
  314. void LLVoiceClient::endUserIMSession(const LLUUID& participant_id)
  315. {
  316. if (mVoiceModule)
  317. {
  318. mVoiceModule->endUserIMSession(participant_id);
  319. }
  320. }
  321. //----------------------------------------------
  322. // channels
  323. bool LLVoiceClient::inProximalChannel()
  324. {
  325. if (mVoiceModule)
  326. {
  327. return mVoiceModule->inProximalChannel();
  328. }
  329. else
  330. {
  331. return false;
  332. }
  333. }
  334. void LLVoiceClient::setNonSpatialChannel(
  335. const std::string &uri,
  336. const std::string &credentials)
  337. {
  338. if (mVoiceModule) mVoiceModule->setNonSpatialChannel(uri, credentials);
  339. }
  340. void LLVoiceClient::setSpatialChannel(
  341. const std::string &uri,
  342. const std::string &credentials)
  343. {
  344. if (mVoiceModule) mVoiceModule->setSpatialChannel(uri, credentials);
  345. }
  346. void LLVoiceClient::leaveNonSpatialChannel()
  347. {
  348. if (mVoiceModule) mVoiceModule->leaveNonSpatialChannel();
  349. }
  350. void LLVoiceClient::leaveChannel(void)
  351. {
  352. if (mVoiceModule) mVoiceModule->leaveChannel();
  353. }
  354. std::string LLVoiceClient::getCurrentChannel()
  355. {
  356. if (mVoiceModule)
  357. {
  358. return mVoiceModule->getCurrentChannel();
  359. }
  360. else
  361. {
  362. return std::string();
  363. }
  364. }
  365. //---------------------------------------
  366. // invitations
  367. void LLVoiceClient::callUser(const LLUUID &uuid)
  368. {
  369. if (mVoiceModule) mVoiceModule->callUser(uuid);
  370. }
  371. bool LLVoiceClient::isValidChannel(std::string &session_handle)
  372. {
  373. if (mVoiceModule)
  374. {
  375. return mVoiceModule->isValidChannel(session_handle);
  376. }
  377. else
  378. {
  379. return false;
  380. }
  381. }
  382. bool LLVoiceClient::answerInvite(std::string &channelHandle)
  383. {
  384. if (mVoiceModule)
  385. {
  386. return mVoiceModule->answerInvite(channelHandle);
  387. }
  388. else
  389. {
  390. return false;
  391. }
  392. }
  393. void LLVoiceClient::declineInvite(std::string &channelHandle)
  394. {
  395. if (mVoiceModule) mVoiceModule->declineInvite(channelHandle);
  396. }
  397. //------------------------------------------
  398. // Volume/gain
  399. void LLVoiceClient::setVoiceVolume(F32 volume)
  400. {
  401. if (mVoiceModule) mVoiceModule->setVoiceVolume(volume);
  402. }
  403. void LLVoiceClient::setMicGain(F32 volume)
  404. {
  405. if (mVoiceModule) mVoiceModule->setMicGain(volume);
  406. }
  407. //------------------------------------------
  408. // enable/disable voice features
  409. bool LLVoiceClient::voiceEnabled()
  410. {
  411. if (mVoiceModule)
  412. {
  413. return mVoiceModule->voiceEnabled();
  414. }
  415. else
  416. {
  417. return false;
  418. }
  419. }
  420. void LLVoiceClient::setVoiceEnabled(bool enabled)
  421. {
  422. if (mVoiceModule) mVoiceModule->setVoiceEnabled(enabled);
  423. }
  424. void LLVoiceClient::updateMicMuteLogic()
  425. {
  426. // If not configured to use PTT, the mic should be open (otherwise the user will be unable to speak).
  427. bool new_mic_mute = false;
  428. if(mUsePTT)
  429. {
  430. // If configured to use PTT, track the user state.
  431. new_mic_mute = !mUserPTTState;
  432. }
  433. if(mMuteMic || mDisableMic)
  434. {
  435. // Either of these always overrides any other PTT setting.
  436. new_mic_mute = true;
  437. }
  438. if (mVoiceModule) mVoiceModule->setMuteMic(new_mic_mute);
  439. }
  440. void LLVoiceClient::setLipSyncEnabled(BOOL enabled)
  441. {
  442. if (mVoiceModule) mVoiceModule->setLipSyncEnabled(enabled);
  443. }
  444. BOOL LLVoiceClient::lipSyncEnabled()
  445. {
  446. if (mVoiceModule)
  447. {
  448. return mVoiceModule->lipSyncEnabled();
  449. }
  450. else
  451. {
  452. return false;
  453. }
  454. }
  455. void LLVoiceClient::setMuteMic(bool muted)
  456. {
  457. mMuteMic = muted;
  458. updateMicMuteLogic();
  459. }
  460. // ----------------------------------------------
  461. // PTT
  462. void LLVoiceClient::setUserPTTState(bool ptt)
  463. {
  464. mUserPTTState = ptt;
  465. updateMicMuteLogic();
  466. }
  467. bool LLVoiceClient::getUserPTTState()
  468. {
  469. return mUserPTTState;
  470. }
  471. void LLVoiceClient::setUsePTT(bool usePTT)
  472. {
  473. if(usePTT && !mUsePTT)
  474. {
  475. // When the user turns on PTT, reset the current state.
  476. mUserPTTState = false;
  477. }
  478. mUsePTT = usePTT;
  479. updateMicMuteLogic();
  480. }
  481. void LLVoiceClient::setPTTIsToggle(bool PTTIsToggle)
  482. {
  483. if(!PTTIsToggle && mPTTIsToggle)
  484. {
  485. // When the user turns off toggle, reset the current state.
  486. mUserPTTState = false;
  487. }
  488. mPTTIsToggle = PTTIsToggle;
  489. updateMicMuteLogic();
  490. }
  491. bool LLVoiceClient::getPTTIsToggle()
  492. {
  493. return mPTTIsToggle;
  494. }
  495. void LLVoiceClient::setPTTKey(std::string &key)
  496. {
  497. if(key == "MiddleMouse")
  498. {
  499. mPTTIsMiddleMouse = true;
  500. }
  501. else
  502. {
  503. mPTTIsMiddleMouse = false;
  504. if(!LLKeyboard::keyFromString(key, &mPTTKey))
  505. {
  506. // If the call failed, don't match any key.
  507. key = KEY_NONE;
  508. }
  509. }
  510. }
  511. void LLVoiceClient::inputUserControlState(bool down)
  512. {
  513. if(mPTTIsToggle)
  514. {
  515. if(down) // toggle open-mic state on 'down'
  516. {
  517. toggleUserPTTState();
  518. }
  519. }
  520. else // set open-mic state as an absolute
  521. {
  522. setUserPTTState(down);
  523. }
  524. }
  525. void LLVoiceClient::toggleUserPTTState(void)
  526. {
  527. setUserPTTState(!getUserPTTState());
  528. }
  529. void LLVoiceClient::keyDown(KEY key, MASK mask)
  530. {
  531. if (gKeyboard->getKeyRepeated(key))
  532. {
  533. // ignore auto-repeat keys
  534. return;
  535. }
  536. if(!mPTTIsMiddleMouse)
  537. {
  538. bool down = (mPTTKey != KEY_NONE)
  539. && gKeyboard->getKeyDown(mPTTKey);
  540. inputUserControlState(down);
  541. }
  542. }
  543. void LLVoiceClient::keyUp(KEY key, MASK mask)
  544. {
  545. if(!mPTTIsMiddleMouse)
  546. {
  547. bool down = (mPTTKey != KEY_NONE)
  548. && gKeyboard->getKeyDown(mPTTKey);
  549. inputUserControlState(down);
  550. }
  551. }
  552. void LLVoiceClient::middleMouseState(bool down)
  553. {
  554. if(mPTTIsMiddleMouse)
  555. {
  556. if(mPTTIsMiddleMouse)
  557. {
  558. inputUserControlState(down);
  559. }
  560. }
  561. }
  562. //-------------------------------------------
  563. // nearby speaker accessors
  564. BOOL LLVoiceClient::getVoiceEnabled(const LLUUID& id)
  565. {
  566. if (mVoiceModule)
  567. {
  568. return mVoiceModule->getVoiceEnabled(id);
  569. }
  570. else
  571. {
  572. return FALSE;
  573. }
  574. }
  575. std::string LLVoiceClient::getDisplayName(const LLUUID& id)
  576. {
  577. if (mVoiceModule)
  578. {
  579. return mVoiceModule->getDisplayName(id);
  580. }
  581. else
  582. {
  583. return std::string();
  584. }
  585. }
  586. bool LLVoiceClient::isVoiceWorking() const
  587. {
  588. if (mVoiceModule)
  589. {
  590. return mVoiceModule->isVoiceWorking();
  591. }
  592. return false;
  593. }
  594. BOOL LLVoiceClient::isParticipantAvatar(const LLUUID& id)
  595. {
  596. if (mVoiceModule)
  597. {
  598. return mVoiceModule->isParticipantAvatar(id);
  599. }
  600. else
  601. {
  602. return FALSE;
  603. }
  604. }
  605. BOOL LLVoiceClient::isOnlineSIP(const LLUUID& id)
  606. {
  607. if (mVoiceModule)
  608. {
  609. return mVoiceModule->isOnlineSIP(id);
  610. }
  611. else
  612. {
  613. return FALSE;
  614. }
  615. }
  616. BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id)
  617. {
  618. if (mVoiceModule)
  619. {
  620. return mVoiceModule->getIsSpeaking(id);
  621. }
  622. else
  623. {
  624. return FALSE;
  625. }
  626. }
  627. BOOL LLVoiceClient::getIsModeratorMuted(const LLUUID& id)
  628. {
  629. if (mVoiceModule)
  630. {
  631. return mVoiceModule->getIsModeratorMuted(id);
  632. }
  633. else
  634. {
  635. return FALSE;
  636. }
  637. }
  638. F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
  639. {
  640. if (mVoiceModule)
  641. {
  642. return mVoiceModule->getCurrentPower(id);
  643. }
  644. else
  645. {
  646. return 0.0;
  647. }
  648. }
  649. BOOL LLVoiceClient::getOnMuteList(const LLUUID& id)
  650. {
  651. if (mVoiceModule)
  652. {
  653. return mVoiceModule->getOnMuteList(id);
  654. }
  655. else
  656. {
  657. return FALSE;
  658. }
  659. }
  660. F32 LLVoiceClient::getUserVolume(const LLUUID& id)
  661. {
  662. if (mVoiceModule)
  663. {
  664. return mVoiceModule->getUserVolume(id);
  665. }
  666. else
  667. {
  668. return 0.0;
  669. }
  670. }
  671. void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
  672. {
  673. if (mVoiceModule) mVoiceModule->setUserVolume(id, volume);
  674. }
  675. //--------------------------------------------------
  676. // status observers
  677. void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
  678. {
  679. if (mVoiceModule) mVoiceModule->addObserver(observer);
  680. }
  681. void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
  682. {
  683. if (mVoiceModule) mVoiceModule->removeObserver(observer);
  684. }
  685. void LLVoiceClient::addObserver(LLFriendObserver* observer)
  686. {
  687. if (mVoiceModule) mVoiceModule->addObserver(observer);
  688. }
  689. void LLVoiceClient::removeObserver(LLFriendObserver* observer)
  690. {
  691. if (mVoiceModule) mVoiceModule->removeObserver(observer);
  692. }
  693. void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
  694. {
  695. if (mVoiceModule) mVoiceModule->addObserver(observer);
  696. }
  697. void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
  698. {
  699. if (mVoiceModule) mVoiceModule->removeObserver(observer);
  700. }
  701. std::string LLVoiceClient::sipURIFromID(const LLUUID &id)
  702. {
  703. if (mVoiceModule)
  704. {
  705. return mVoiceModule->sipURIFromID(id);
  706. }
  707. else
  708. {
  709. return std::string();
  710. }
  711. }
  712. LLVoiceEffectInterface* LLVoiceClient::getVoiceEffectInterface() const
  713. {
  714. return getVoiceEffectEnabled() ? dynamic_cast<LLVoiceEffectInterface*>(mVoiceModule) : NULL;
  715. }
  716. ///////////////////
  717. // version checking
  718. class LLViewerRequiredVoiceVersion : public LLHTTPNode
  719. {
  720. static BOOL sAlertedUser;
  721. virtual void post(
  722. LLHTTPNode::ResponsePtr response,
  723. const LLSD& context,
  724. const LLSD& input) const
  725. {
  726. //You received this messsage (most likely on region cross or
  727. //teleport)
  728. if ( input.has("body") && input["body"].has("major_version") )
  729. {
  730. int major_voice_version =
  731. input["body"]["major_version"].asInteger();
  732. // int minor_voice_version =
  733. // input["body"]["minor_version"].asInteger();
  734. LLVoiceVersionInfo versionInfo = LLVoiceClient::getInstance()->getVersion();
  735. if (major_voice_version > 1)
  736. {
  737. if (!sAlertedUser)
  738. {
  739. //sAlertedUser = TRUE;
  740. LLNotificationsUtil::add("VoiceVersionMismatch");
  741. gSavedSettings.setBOOL("EnableVoiceChat", FALSE); // toggles listener
  742. }
  743. }
  744. }
  745. }
  746. };
  747. class LLViewerParcelVoiceInfo : public LLHTTPNode
  748. {
  749. virtual void post(
  750. LLHTTPNode::ResponsePtr response,
  751. const LLSD& context,
  752. const LLSD& input) const
  753. {
  754. //the parcel you are in has changed something about its
  755. //voice information
  756. //this is a misnomer, as it can also be when you are not in
  757. //a parcel at all. Should really be something like
  758. //LLViewerVoiceInfoChanged.....
  759. if ( input.has("body") )
  760. {
  761. LLSD body = input["body"];
  762. //body has "region_name" (str), "parcel_local_id"(int),
  763. //"voice_credentials" (map).
  764. //body["voice_credentials"] has "channel_uri" (str),
  765. //body["voice_credentials"] has "channel_credentials" (str)
  766. //if we really wanted to be extra careful,
  767. //we'd check the supplied
  768. //local parcel id to make sure it's for the same parcel
  769. //we believe we're in
  770. if ( body.has("voice_credentials") )
  771. {
  772. LLSD voice_credentials = body["voice_credentials"];
  773. std::string uri;
  774. std::string credentials;
  775. if ( voice_credentials.has("channel_uri") )
  776. {
  777. uri = voice_credentials["channel_uri"].asString();
  778. }
  779. if ( voice_credentials.has("channel_credentials") )
  780. {
  781. credentials =
  782. voice_credentials["channel_credentials"].asString();
  783. }
  784. LLVoiceClient::getInstance()->setSpatialChannel(uri, credentials);
  785. }
  786. }
  787. }
  788. };
  789. const std::string LLSpeakerVolumeStorage::SETTINGS_FILE_NAME = "volume_settings.xml";
  790. LLSpeakerVolumeStorage::LLSpeakerVolumeStorage()
  791. {
  792. load();
  793. }
  794. LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage()
  795. {
  796. save();
  797. }
  798. void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 volume)
  799. {
  800. if ((volume >= LLVoiceClient::VOLUME_MIN) && (volume <= LLVoiceClient::VOLUME_MAX))
  801. {
  802. mSpeakersData[speaker_id] = volume;
  803. // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
  804. // LL_DEBUGS("Voice") << "Stored volume = " << volume << " for " << id << LL_ENDL;
  805. }
  806. else
  807. {
  808. LL_WARNS("Voice") << "Attempted to store out of range volume " << volume << " for " << speaker_id << LL_ENDL;
  809. llassert(0);
  810. }
  811. }
  812. bool LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id, F32& volume)
  813. {
  814. speaker_data_map_t::const_iterator it = mSpeakersData.find(speaker_id);
  815. if (it != mSpeakersData.end())
  816. {
  817. volume = it->second;
  818. // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
  819. // LL_DEBUGS("Voice") << "Retrieved stored volume = " << volume << " for " << id << LL_ENDL;
  820. return true;
  821. }
  822. return false;
  823. }
  824. void LLSpeakerVolumeStorage::removeSpeakerVolume(const LLUUID& speaker_id)
  825. {
  826. mSpeakersData.erase(speaker_id);
  827. // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
  828. // LL_DEBUGS("Voice") << "Removing stored volume for " << id << LL_ENDL;
  829. }
  830. /* static */ F32 LLSpeakerVolumeStorage::transformFromLegacyVolume(F32 volume_in)
  831. {
  832. // Convert to linear-logarithmic [0.0..1.0] with 0.5 = 0dB
  833. // from legacy characteristic composed of two square-curves
  834. // that intersect at volume_in = 0.5, volume_out = 0.56
  835. F32 volume_out = 0.f;
  836. volume_in = llclamp(volume_in, 0.f, 1.0f);
  837. if (volume_in <= 0.5f)
  838. {
  839. volume_out = volume_in * volume_in * 4.f * 0.56f;
  840. }
  841. else
  842. {
  843. volume_out = (1.f - 0.56f) * (4.f * volume_in * volume_in - 1.f) / 3.f + 0.56f;
  844. }
  845. return volume_out;
  846. }
  847. /* static */ F32 LLSpeakerVolumeStorage::transformToLegacyVolume(F32 volume_in)
  848. {
  849. // Convert from linear-logarithmic [0.0..1.0] with 0.5 = 0dB
  850. // to legacy characteristic composed of two square-curves
  851. // that intersect at volume_in = 0.56, volume_out = 0.5
  852. F32 volume_out = 0.f;
  853. volume_in = llclamp(volume_in, 0.f, 1.0f);
  854. if (volume_in <= 0.56f)
  855. {
  856. volume_out = sqrt(volume_in / (4.f * 0.56f));
  857. }
  858. else
  859. {
  860. volume_out = sqrt((3.f * (volume_in - 0.56f) / (1.f - 0.56f) + 1.f) / 4.f);
  861. }
  862. return volume_out;
  863. }
  864. void LLSpeakerVolumeStorage::load()
  865. {
  866. // load per-resident voice volume information
  867. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME);
  868. LL_INFOS("Voice") << "Loading stored speaker volumes from: " << filename << LL_ENDL;
  869. LLSD settings_llsd;
  870. llifstream file;
  871. file.open(filename);
  872. if (file.is_open())
  873. {
  874. LLSDSerialize::fromXML(settings_llsd, file);
  875. }
  876. for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
  877. iter != settings_llsd.endMap(); ++iter)
  878. {
  879. // Maintain compatibility with 1.23 non-linear saved volume levels
  880. F32 volume = transformFromLegacyVolume((F32)iter->second.asReal());
  881. storeSpeakerVolume(LLUUID(iter->first), volume);
  882. }
  883. }
  884. void LLSpeakerVolumeStorage::save()
  885. {
  886. // If we quit from the login screen we will not have an SL account
  887. // name. Don't try to save, otherwise we'll dump a file in
  888. // C:\Program Files\SecondLife\ or similar. JC
  889. std::string user_dir = gDirUtilp->getLindenUserDir();
  890. if (!user_dir.empty())
  891. {
  892. std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME);
  893. LLSD settings_llsd;
  894. LL_INFOS("Voice") << "Saving stored speaker volumes to: " << filename << LL_ENDL;
  895. for(speaker_data_map_t::const_iterator iter = mSpeakersData.begin(); iter != mSpeakersData.end(); ++iter)
  896. {
  897. // Maintain compatibility with 1.23 non-linear saved volume levels
  898. F32 volume = transformToLegacyVolume(iter->second);
  899. settings_llsd[iter->first.asString()] = volume;
  900. }
  901. llofstream file;
  902. file.open(filename);
  903. LLSDSerialize::toPrettyXML(settings_llsd, file);
  904. }
  905. }
  906. BOOL LLViewerRequiredVoiceVersion::sAlertedUser = FALSE;
  907. LLHTTPRegistration<LLViewerParcelVoiceInfo>
  908. gHTTPRegistrationMessageParcelVoiceInfo(
  909. "/message/ParcelVoiceInfo");
  910. LLHTTPRegistration<LLViewerRequiredVoiceVersion>
  911. gHTTPRegistrationMessageRequiredVoiceVersion(
  912. "/message/RequiredVoiceVersion");