Files
SingularityViewer/indra/newview/llvoiceclient.cpp
Lirusaito c273e34ed8 [Voice Update] LLVoiceClient
Migrate a bunch of classes out of llvoiceclient.* and into new llvoicevivox.*
Update most of these to match their counterparts
Introduce VoiceFonts support (voice morphing, floater still to come)
Support for a bunch of v3 voice settings.
Move volume settings management from LLMutelist into LLSpeakerVolumeStorage
Support for Avaline mutes (WIP)
Adds voice section to LLAgent
Moved llfloatervoicedevicesettings to llpanelvoicedevicesettings, v3's voice device panel design is more intuitive.
2013-06-03 22:20:27 -04:00

1045 lines
21 KiB
C++

/**
* @file llvoiceclient.cpp
* @brief Voice client delegation class implementation.
*
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License only.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
#include "llviewerprecompiledheaders.h"
#include "llvoiceclient.h"
#include "llviewercontrol.h"
#include "llviewerwindow.h"
#include "llvoicevivox.h"
#include "llviewernetwork.h"
#include "llhttpnode.h"
#include "llnotificationsutil.h"
#include "llsdserialize.h"
#include "llkeyboard.h"
const F32 LLVoiceClient::OVERDRIVEN_POWER_LEVEL = 0.7f;
const F32 LLVoiceClient::VOLUME_MIN = 0.f;
const F32 LLVoiceClient::VOLUME_DEFAULT = 0.5f;
const F32 LLVoiceClient::VOLUME_MAX = 1.0f;
std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus)
{
std::string result = "UNKNOWN";
// Prevent copy-paste errors when updating this list...
#define CASE(x) case x: result = #x; break
switch(inStatus)
{
CASE(STATUS_LOGIN_RETRY);
CASE(STATUS_LOGGED_IN);
CASE(STATUS_JOINING);
CASE(STATUS_JOINED);
CASE(STATUS_LEFT_CHANNEL);
CASE(STATUS_VOICE_DISABLED);
CASE(BEGIN_ERROR_STATUS);
CASE(ERROR_CHANNEL_FULL);
CASE(ERROR_CHANNEL_LOCKED);
CASE(ERROR_NOT_AVAILABLE);
CASE(ERROR_UNKNOWN);
default:
break;
}
#undef CASE
return result;
}
///////////////////////////////////////////////////////////////////////////////////////////////
LLVoiceClient::LLVoiceClient()
:
mVoiceModule(NULL),
m_servicePump(NULL),
mVoiceEffectEnabled(LLCachedControl<bool>(gSavedSettings, "VoiceMorphingEnabled")),
mVoiceEffectDefault(LLCachedControl<std::string>(gSavedPerAccountSettings, "VoiceEffectDefault")),
mPTTDirty(true),
mPTT(true),
mUsePTT(true),
mPTTIsMiddleMouse(false),
mPTTKey(0),
mPTTIsToggle(false),
mUserPTTState(false),
mMuteMic(false),
mDisableMic(false)
{
updateSettings();
}
//---------------------------------------------------
// Basic setup/shutdown
LLVoiceClient::~LLVoiceClient()
{
}
void LLVoiceClient::init(LLPumpIO *pump)
{
// Initialize all of the voice modules
m_servicePump = pump;
}
void LLVoiceClient::userAuthorized(const std::string& user_id, const LLUUID &agentID)
{
// In the future, we should change this to allow voice module registration
// with a table lookup of sorts.
std::string voice_server = gSavedSettings.getString("VoiceServerType");
LL_DEBUGS("Voice") << "voice server type " << voice_server << LL_ENDL;
if(voice_server == "vivox")
{
mVoiceModule = (LLVoiceModuleInterface *)LLVivoxVoiceClient::getInstance();
}
else
{
mVoiceModule = NULL;
return;
}
mVoiceModule->init(m_servicePump);
mVoiceModule->userAuthorized(user_id, agentID);
}
void LLVoiceClient::terminate()
{
if (mVoiceModule) mVoiceModule->terminate();
mVoiceModule = NULL;
}
const LLVoiceVersionInfo LLVoiceClient::getVersion()
{
if (mVoiceModule)
{
return mVoiceModule->getVersion();
}
else
{
LLVoiceVersionInfo result;
result.serverVersion = std::string();
result.serverType = std::string();
return result;
}
}
void LLVoiceClient::updateSettings()
{
setUsePTT(gSavedSettings.getBOOL("PTTCurrentlyEnabled"));
std::string keyString = gSavedSettings.getString("PushToTalkButton");
setPTTKey(keyString);
setPTTIsToggle(gSavedSettings.getBOOL("PushToTalkToggle"));
mDisableMic = gSavedSettings.getBOOL("VoiceDisableMic");
updateMicMuteLogic();
if (mVoiceModule) mVoiceModule->updateSettings();
}
//--------------------------------------------------
// tuning
void LLVoiceClient::tuningStart()
{
if (mVoiceModule) mVoiceModule->tuningStart();
}
void LLVoiceClient::tuningStop()
{
if (mVoiceModule) mVoiceModule->tuningStop();
}
bool LLVoiceClient::inTuningMode()
{
if (mVoiceModule)
{
return mVoiceModule->inTuningMode();
}
else
{
return false;
}
}
void LLVoiceClient::tuningSetMicVolume(float volume)
{
if (mVoiceModule) mVoiceModule->tuningSetMicVolume(volume);
}
void LLVoiceClient::tuningSetSpeakerVolume(float volume)
{
if (mVoiceModule) mVoiceModule->tuningSetSpeakerVolume(volume);
}
float LLVoiceClient::tuningGetEnergy(void)
{
if (mVoiceModule)
{
return mVoiceModule->tuningGetEnergy();
}
else
{
return 0.0;
}
}
//------------------------------------------------
// devices
bool LLVoiceClient::deviceSettingsAvailable()
{
if (mVoiceModule)
{
return mVoiceModule->deviceSettingsAvailable();
}
else
{
return false;
}
}
void LLVoiceClient::refreshDeviceLists(bool clearCurrentList)
{
if (mVoiceModule) mVoiceModule->refreshDeviceLists(clearCurrentList);
}
void LLVoiceClient::setCaptureDevice(const std::string& name)
{
if (mVoiceModule) mVoiceModule->setCaptureDevice(name);
}
void LLVoiceClient::setRenderDevice(const std::string& name)
{
if (mVoiceModule) mVoiceModule->setRenderDevice(name);
}
const LLVoiceDeviceList& LLVoiceClient::getCaptureDevices()
{
static LLVoiceDeviceList nullCaptureDevices;
if (mVoiceModule)
{
return mVoiceModule->getCaptureDevices();
}
else
{
return nullCaptureDevices;
}
}
const LLVoiceDeviceList& LLVoiceClient::getRenderDevices()
{
static LLVoiceDeviceList nullRenderDevices;
if (mVoiceModule)
{
return mVoiceModule->getRenderDevices();
}
else
{
return nullRenderDevices;
}
}
//--------------------------------------------------
// participants
void LLVoiceClient::getParticipantList(std::set<LLUUID> &participants)
{
if (mVoiceModule)
{
mVoiceModule->getParticipantList(participants);
}
else
{
participants = std::set<LLUUID>();
}
}
bool LLVoiceClient::isParticipant(const LLUUID &speaker_id)
{
if(mVoiceModule)
{
return mVoiceModule->isParticipant(speaker_id);
}
return false;
}
//--------------------------------------------------
// text chat
BOOL LLVoiceClient::isSessionTextIMPossible(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->isSessionTextIMPossible(id);
}
else
{
return FALSE;
}
}
BOOL LLVoiceClient::isSessionCallBackPossible(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->isSessionCallBackPossible(id);
}
else
{
return FALSE;
}
}
BOOL LLVoiceClient::sendTextMessage(const LLUUID& participant_id, const std::string& message)
{
if (mVoiceModule)
{
return mVoiceModule->sendTextMessage(participant_id, message);
}
else
{
return FALSE;
}
}
void LLVoiceClient::endUserIMSession(const LLUUID& participant_id)
{
if (mVoiceModule)
{
mVoiceModule->endUserIMSession(participant_id);
}
}
//----------------------------------------------
// channels
bool LLVoiceClient::inProximalChannel()
{
if (mVoiceModule)
{
return mVoiceModule->inProximalChannel();
}
else
{
return false;
}
}
void LLVoiceClient::setNonSpatialChannel(
const std::string &uri,
const std::string &credentials)
{
if (mVoiceModule) mVoiceModule->setNonSpatialChannel(uri, credentials);
}
void LLVoiceClient::setSpatialChannel(
const std::string &uri,
const std::string &credentials)
{
if (mVoiceModule) mVoiceModule->setSpatialChannel(uri, credentials);
}
void LLVoiceClient::leaveNonSpatialChannel()
{
if (mVoiceModule) mVoiceModule->leaveNonSpatialChannel();
}
void LLVoiceClient::leaveChannel(void)
{
if (mVoiceModule) mVoiceModule->leaveChannel();
}
std::string LLVoiceClient::getCurrentChannel()
{
if (mVoiceModule)
{
return mVoiceModule->getCurrentChannel();
}
else
{
return std::string();
}
}
//---------------------------------------
// invitations
void LLVoiceClient::callUser(const LLUUID &uuid)
{
if (mVoiceModule) mVoiceModule->callUser(uuid);
}
bool LLVoiceClient::isValidChannel(std::string &session_handle)
{
if (mVoiceModule)
{
return mVoiceModule->isValidChannel(session_handle);
}
else
{
return false;
}
}
bool LLVoiceClient::answerInvite(std::string &channelHandle)
{
if (mVoiceModule)
{
return mVoiceModule->answerInvite(channelHandle);
}
else
{
return false;
}
}
void LLVoiceClient::declineInvite(std::string &channelHandle)
{
if (mVoiceModule) mVoiceModule->declineInvite(channelHandle);
}
//------------------------------------------
// Volume/gain
void LLVoiceClient::setVoiceVolume(F32 volume)
{
if (mVoiceModule) mVoiceModule->setVoiceVolume(volume);
}
void LLVoiceClient::setMicGain(F32 volume)
{
if (mVoiceModule) mVoiceModule->setMicGain(volume);
}
//------------------------------------------
// enable/disable voice features
bool LLVoiceClient::voiceEnabled()
{
if (mVoiceModule)
{
return mVoiceModule->voiceEnabled();
}
else
{
return false;
}
}
void LLVoiceClient::setVoiceEnabled(bool enabled)
{
if (mVoiceModule) mVoiceModule->setVoiceEnabled(enabled);
}
void LLVoiceClient::updateMicMuteLogic()
{
// If not configured to use PTT, the mic should be open (otherwise the user will be unable to speak).
bool new_mic_mute = false;
if(mUsePTT)
{
// If configured to use PTT, track the user state.
new_mic_mute = !mUserPTTState;
}
if(mMuteMic || mDisableMic)
{
// Either of these always overrides any other PTT setting.
new_mic_mute = true;
}
if (mVoiceModule) mVoiceModule->setMuteMic(new_mic_mute);
}
void LLVoiceClient::setLipSyncEnabled(BOOL enabled)
{
if (mVoiceModule) mVoiceModule->setLipSyncEnabled(enabled);
}
BOOL LLVoiceClient::lipSyncEnabled()
{
if (mVoiceModule)
{
return mVoiceModule->lipSyncEnabled();
}
else
{
return false;
}
}
void LLVoiceClient::setMuteMic(bool muted)
{
mMuteMic = muted;
updateMicMuteLogic();
}
// ----------------------------------------------
// PTT
void LLVoiceClient::setUserPTTState(bool ptt)
{
mUserPTTState = ptt;
updateMicMuteLogic();
}
bool LLVoiceClient::getUserPTTState()
{
return mUserPTTState;
}
void LLVoiceClient::setUsePTT(bool usePTT)
{
if(usePTT && !mUsePTT)
{
// When the user turns on PTT, reset the current state.
mUserPTTState = false;
}
mUsePTT = usePTT;
updateMicMuteLogic();
}
void LLVoiceClient::setPTTIsToggle(bool PTTIsToggle)
{
if(!PTTIsToggle && mPTTIsToggle)
{
// When the user turns off toggle, reset the current state.
mUserPTTState = false;
}
mPTTIsToggle = PTTIsToggle;
updateMicMuteLogic();
}
bool LLVoiceClient::getPTTIsToggle()
{
return mPTTIsToggle;
}
void LLVoiceClient::setPTTKey(std::string &key)
{
if(key == "MiddleMouse")
{
mPTTIsMiddleMouse = true;
}
else
{
mPTTIsMiddleMouse = false;
if(!LLKeyboard::keyFromString(key, &mPTTKey))
{
// If the call failed, don't match any key.
key = KEY_NONE;
}
}
}
void LLVoiceClient::inputUserControlState(bool down)
{
if(mPTTIsToggle)
{
if(down) // toggle open-mic state on 'down'
{
toggleUserPTTState();
}
}
else // set open-mic state as an absolute
{
setUserPTTState(down);
}
}
void LLVoiceClient::toggleUserPTTState(void)
{
setUserPTTState(!getUserPTTState());
}
void LLVoiceClient::keyDown(KEY key, MASK mask)
{
if (gKeyboard->getKeyRepeated(key))
{
// ignore auto-repeat keys
return;
}
if(!mPTTIsMiddleMouse)
{
bool down = (mPTTKey != KEY_NONE)
&& gKeyboard->getKeyDown(mPTTKey);
inputUserControlState(down);
}
}
void LLVoiceClient::keyUp(KEY key, MASK mask)
{
if(!mPTTIsMiddleMouse)
{
bool down = (mPTTKey != KEY_NONE)
&& gKeyboard->getKeyDown(mPTTKey);
inputUserControlState(down);
}
}
void LLVoiceClient::middleMouseState(bool down)
{
if(mPTTIsMiddleMouse)
{
if(mPTTIsMiddleMouse)
{
inputUserControlState(down);
}
}
}
//-------------------------------------------
// nearby speaker accessors
BOOL LLVoiceClient::getVoiceEnabled(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->getVoiceEnabled(id);
}
else
{
return FALSE;
}
}
std::string LLVoiceClient::getDisplayName(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->getDisplayName(id);
}
else
{
return std::string();
}
}
bool LLVoiceClient::isVoiceWorking() const
{
if (mVoiceModule)
{
return mVoiceModule->isVoiceWorking();
}
return false;
}
BOOL LLVoiceClient::isParticipantAvatar(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->isParticipantAvatar(id);
}
else
{
return FALSE;
}
}
BOOL LLVoiceClient::isOnlineSIP(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->isOnlineSIP(id);
}
else
{
return FALSE;
}
}
BOOL LLVoiceClient::getIsSpeaking(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->getIsSpeaking(id);
}
else
{
return FALSE;
}
}
BOOL LLVoiceClient::getIsModeratorMuted(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->getIsModeratorMuted(id);
}
else
{
return FALSE;
}
}
F32 LLVoiceClient::getCurrentPower(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->getCurrentPower(id);
}
else
{
return 0.0;
}
}
BOOL LLVoiceClient::getOnMuteList(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->getOnMuteList(id);
}
else
{
return FALSE;
}
}
F32 LLVoiceClient::getUserVolume(const LLUUID& id)
{
if (mVoiceModule)
{
return mVoiceModule->getUserVolume(id);
}
else
{
return 0.0;
}
}
void LLVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
{
if (mVoiceModule) mVoiceModule->setUserVolume(id, volume);
}
//--------------------------------------------------
// status observers
void LLVoiceClient::addObserver(LLVoiceClientStatusObserver* observer)
{
if (mVoiceModule) mVoiceModule->addObserver(observer);
}
void LLVoiceClient::removeObserver(LLVoiceClientStatusObserver* observer)
{
if (mVoiceModule) mVoiceModule->removeObserver(observer);
}
void LLVoiceClient::addObserver(LLFriendObserver* observer)
{
if (mVoiceModule) mVoiceModule->addObserver(observer);
}
void LLVoiceClient::removeObserver(LLFriendObserver* observer)
{
if (mVoiceModule) mVoiceModule->removeObserver(observer);
}
void LLVoiceClient::addObserver(LLVoiceClientParticipantObserver* observer)
{
if (mVoiceModule) mVoiceModule->addObserver(observer);
}
void LLVoiceClient::removeObserver(LLVoiceClientParticipantObserver* observer)
{
if (mVoiceModule) mVoiceModule->removeObserver(observer);
}
std::string LLVoiceClient::sipURIFromID(const LLUUID &id)
{
if (mVoiceModule)
{
return mVoiceModule->sipURIFromID(id);
}
else
{
return std::string();
}
}
LLVoiceEffectInterface* LLVoiceClient::getVoiceEffectInterface() const
{
return getVoiceEffectEnabled() ? dynamic_cast<LLVoiceEffectInterface*>(mVoiceModule) : NULL;
}
///////////////////
// version checking
class LLViewerRequiredVoiceVersion : public LLHTTPNode
{
static BOOL sAlertedUser;
virtual void post(
LLHTTPNode::ResponsePtr response,
const LLSD& context,
const LLSD& input) const
{
//You received this messsage (most likely on region cross or
//teleport)
if ( input.has("body") && input["body"].has("major_version") )
{
int major_voice_version =
input["body"]["major_version"].asInteger();
// int minor_voice_version =
// input["body"]["minor_version"].asInteger();
LLVoiceVersionInfo versionInfo = LLVoiceClient::getInstance()->getVersion();
if (major_voice_version > 1)
{
if (!sAlertedUser)
{
//sAlertedUser = TRUE;
LLNotificationsUtil::add("VoiceVersionMismatch");
gSavedSettings.setBOOL("EnableVoiceChat", FALSE); // toggles listener
}
}
}
}
};
class LLViewerParcelVoiceInfo : public LLHTTPNode
{
virtual void post(
LLHTTPNode::ResponsePtr response,
const LLSD& context,
const LLSD& input) const
{
//the parcel you are in has changed something about its
//voice information
//this is a misnomer, as it can also be when you are not in
//a parcel at all. Should really be something like
//LLViewerVoiceInfoChanged.....
if ( input.has("body") )
{
LLSD body = input["body"];
//body has "region_name" (str), "parcel_local_id"(int),
//"voice_credentials" (map).
//body["voice_credentials"] has "channel_uri" (str),
//body["voice_credentials"] has "channel_credentials" (str)
//if we really wanted to be extra careful,
//we'd check the supplied
//local parcel id to make sure it's for the same parcel
//we believe we're in
if ( body.has("voice_credentials") )
{
LLSD voice_credentials = body["voice_credentials"];
std::string uri;
std::string credentials;
if ( voice_credentials.has("channel_uri") )
{
uri = voice_credentials["channel_uri"].asString();
}
if ( voice_credentials.has("channel_credentials") )
{
credentials =
voice_credentials["channel_credentials"].asString();
}
LLVoiceClient::getInstance()->setSpatialChannel(uri, credentials);
}
}
}
};
const std::string LLSpeakerVolumeStorage::SETTINGS_FILE_NAME = "volume_settings.xml";
LLSpeakerVolumeStorage::LLSpeakerVolumeStorage()
{
load();
}
LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage()
{
save();
}
void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 volume)
{
if ((volume >= LLVoiceClient::VOLUME_MIN) && (volume <= LLVoiceClient::VOLUME_MAX))
{
mSpeakersData[speaker_id] = volume;
// Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
// LL_DEBUGS("Voice") << "Stored volume = " << volume << " for " << id << LL_ENDL;
}
else
{
LL_WARNS("Voice") << "Attempted to store out of range volume " << volume << " for " << speaker_id << LL_ENDL;
llassert(0);
}
}
bool LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id, F32& volume)
{
speaker_data_map_t::const_iterator it = mSpeakersData.find(speaker_id);
if (it != mSpeakersData.end())
{
volume = it->second;
// Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
// LL_DEBUGS("Voice") << "Retrieved stored volume = " << volume << " for " << id << LL_ENDL;
return true;
}
return false;
}
void LLSpeakerVolumeStorage::removeSpeakerVolume(const LLUUID& speaker_id)
{
mSpeakersData.erase(speaker_id);
// Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
// LL_DEBUGS("Voice") << "Removing stored volume for " << id << LL_ENDL;
}
/* static */ F32 LLSpeakerVolumeStorage::transformFromLegacyVolume(F32 volume_in)
{
// Convert to linear-logarithmic [0.0..1.0] with 0.5 = 0dB
// from legacy characteristic composed of two square-curves
// that intersect at volume_in = 0.5, volume_out = 0.56
F32 volume_out = 0.f;
volume_in = llclamp(volume_in, 0.f, 1.0f);
if (volume_in <= 0.5f)
{
volume_out = volume_in * volume_in * 4.f * 0.56f;
}
else
{
volume_out = (1.f - 0.56f) * (4.f * volume_in * volume_in - 1.f) / 3.f + 0.56f;
}
return volume_out;
}
/* static */ F32 LLSpeakerVolumeStorage::transformToLegacyVolume(F32 volume_in)
{
// Convert from linear-logarithmic [0.0..1.0] with 0.5 = 0dB
// to legacy characteristic composed of two square-curves
// that intersect at volume_in = 0.56, volume_out = 0.5
F32 volume_out = 0.f;
volume_in = llclamp(volume_in, 0.f, 1.0f);
if (volume_in <= 0.56f)
{
volume_out = sqrt(volume_in / (4.f * 0.56f));
}
else
{
volume_out = sqrt((3.f * (volume_in - 0.56f) / (1.f - 0.56f) + 1.f) / 4.f);
}
return volume_out;
}
void LLSpeakerVolumeStorage::load()
{
// load per-resident voice volume information
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME);
LL_INFOS("Voice") << "Loading stored speaker volumes from: " << filename << LL_ENDL;
LLSD settings_llsd;
llifstream file;
file.open(filename);
if (file.is_open())
{
LLSDSerialize::fromXML(settings_llsd, file);
}
for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
iter != settings_llsd.endMap(); ++iter)
{
// Maintain compatibility with 1.23 non-linear saved volume levels
F32 volume = transformFromLegacyVolume((F32)iter->second.asReal());
storeSpeakerVolume(LLUUID(iter->first), volume);
}
}
void LLSpeakerVolumeStorage::save()
{
// If we quit from the login screen we will not have an SL account
// name. Don't try to save, otherwise we'll dump a file in
// C:\Program Files\SecondLife\ or similar. JC
std::string user_dir = gDirUtilp->getLindenUserDir(true);
if (!user_dir.empty())
{
std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SETTINGS_FILE_NAME);
LLSD settings_llsd;
LL_INFOS("Voice") << "Saving stored speaker volumes to: " << filename << LL_ENDL;
for(speaker_data_map_t::const_iterator iter = mSpeakersData.begin(); iter != mSpeakersData.end(); ++iter)
{
// Maintain compatibility with 1.23 non-linear saved volume levels
F32 volume = transformToLegacyVolume(iter->second);
settings_llsd[iter->first.asString()] = volume;
}
llofstream file;
file.open(filename);
LLSDSerialize::toPrettyXML(settings_llsd, file);
}
}
BOOL LLViewerRequiredVoiceVersion::sAlertedUser = FALSE;
LLHTTPRegistration<LLViewerParcelVoiceInfo>
gHTTPRegistrationMessageParcelVoiceInfo(
"/message/ParcelVoiceInfo");
LLHTTPRegistration<LLViewerRequiredVoiceVersion>
gHTTPRegistrationMessageRequiredVoiceVersion(
"/message/RequiredVoiceVersion");