PageRenderTime 471ms CodeModel.GetById 110ms app.highlight 269ms RepoModel.GetById 83ms app.codeStats 1ms

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