summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/newview/llvoiceclient.cpp98
-rw-r--r--indra/newview/llvoiceclient.h34
-rw-r--r--indra/newview/llvoicevivox.cpp114
-rw-r--r--indra/newview/llvoicevivox.h6
4 files changed, 164 insertions, 88 deletions
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp
index 250e366087..91353281a8 100644
--- a/indra/newview/llvoiceclient.cpp
+++ b/indra/newview/llvoiceclient.cpp
@@ -42,6 +42,10 @@
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";
@@ -802,23 +806,85 @@ LLSpeakerVolumeStorage::~LLSpeakerVolumeStorage()
void LLSpeakerVolumeStorage::storeSpeakerVolume(const LLUUID& speaker_id, F32 volume)
{
- mSpeakersData[speaker_id] = 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);
+ }
}
-S32 LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id)
+bool LLSpeakerVolumeStorage::getSpeakerVolume(const LLUUID& speaker_id, F32& volume)
{
- // Return value of -1 indicates no level is stored for this speaker
- S32 ret_val = -1;
speaker_data_map_t::const_iterator it = mSpeakersData.find(speaker_id);
if (it != mSpeakersData.end())
{
- F32 f_val = it->second;
- // volume can amplify by as much as 4x!
- S32 ivol = (S32)(400.f * f_val * f_val);
- ret_val = llclamp(ivol, 0, 400);
+ 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 ret_val;
+
+ 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()
@@ -826,6 +892,8 @@ 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);
@@ -837,7 +905,10 @@ void LLSpeakerVolumeStorage::load()
for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
iter != settings_llsd.endMap(); ++iter)
{
- mSpeakersData.insert(std::make_pair(LLUUID(iter->first), (F32)iter->second.asReal()));
+ // Maintain compatibility with 1.23 non-linear saved volume levels
+ F32 volume = transformFromLegacyVolume((F32)iter->second.asReal());
+
+ storeSpeakerVolume(LLUUID(iter->first), volume);
}
}
@@ -852,9 +923,14 @@ void LLSpeakerVolumeStorage::save()
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)
{
- settings_llsd[iter->first.asString()] = iter->second;
+ // Maintain compatibility with 1.23 non-linear saved volume levels
+ F32 volume = transformToLegacyVolume(iter->second);
+
+ settings_llsd[iter->first.asString()] = volume;
}
llofstream file;
diff --git a/indra/newview/llvoiceclient.h b/indra/newview/llvoiceclient.h
index 7427ea323f..674fe317db 100644
--- a/indra/newview/llvoiceclient.h
+++ b/indra/newview/llvoiceclient.h
@@ -273,7 +273,11 @@ public:
const LLVoiceVersionInfo getVersion();
-static const F32 OVERDRIVEN_POWER_LEVEL;
+ static const F32 OVERDRIVEN_POWER_LEVEL;
+
+ static const F32 VOLUME_MIN;
+ static const F32 VOLUME_DEFAULT;
+ static const F32 VOLUME_MAX;
void updateSettings(); // call after loading settings and whenever they change
@@ -408,31 +412,34 @@ protected:
/**
* Speaker volume storage helper class
**/
-
class LLSpeakerVolumeStorage : public LLSingleton<LLSpeakerVolumeStorage>
{
LOG_CLASS(LLSpeakerVolumeStorage);
public:
/**
- * Sets internal voluem level for specified user.
+ * Stores volume level for specified user.
*
- * @param[in] speaker_id - LLUUID of user to store volume level for
- * @param[in] volume - external volume level to be stored for user.
+ * @param[in] speaker_id - LLUUID of user to store volume level for.
+ * @param[in] volume - volume level to be stored for user.
*/
void storeSpeakerVolume(const LLUUID& speaker_id, F32 volume);
/**
- * Gets stored external volume level for specified speaker.
+ * Gets stored volume level for specified speaker
*
- * If specified user is not found default level will be returned. It is equivalent of
- * external level 0.5 from the 0.0..1.0 range.
- * Default external level is calculated as: internal = 400 * external^2
- * Maps 0.0 to 1.0 to internal values 0-400 with default 0.5 == 100
+ * @param[in] speaker_id - LLUUID of user to retrieve volume level for.
+ * @param[out] volume - set to stored volume if found, otherwise unmodified.
+ * @return - true if a stored volume is found.
+ */
+ bool getSpeakerVolume(const LLUUID& speaker_id, F32& volume);
+
+ /**
+ * Removes stored volume level for specified user.
*
- * @param[in] speaker_id - LLUUID of user to get his volume level
+ * @param[in] speaker_id - LLUUID of user to remove.
*/
- S32 getSpeakerVolume(const LLUUID& speaker_id);
+ void removeSpeakerVolume(const LLUUID& speaker_id);
private:
friend class LLSingleton<LLSpeakerVolumeStorage>;
@@ -444,6 +451,9 @@ private:
void load();
void save();
+ static F32 LLSpeakerVolumeStorage::transformFromLegacyVolume(F32 volume_in);
+ static F32 LLSpeakerVolumeStorage::transformToLegacyVolume(F32 volume_in);
+
typedef std::map<LLUUID, F32> speaker_data_map_t;
speaker_data_map_t mSpeakersData;
};
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index dbecf11597..16898ad172 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -78,6 +78,8 @@
#define USE_SESSION_GROUPS 0
+const F32 VOLUME_SCALE_VIVOX = 0.01f;
+
const F32 SPEAKING_TIMEOUT = 1.f;
static const std::string VOICE_SERVER_TYPE = "Vivox";
@@ -1476,9 +1478,10 @@ void LLVivoxVoiceClient::stateMachine()
enforceTether();
}
- // Send an update if the ptt state has changed (which shouldn't be able to happen that often -- the user can only click so fast)
- // or every 10hz, whichever is sooner.
- if((mAudioSession && mAudioSession->mVolumeDirty) || mPTTDirty || mSpeakerVolumeDirty || mUpdateTimer.hasExpired())
+ // Send an update only if the ptt or mute state has changed (which shouldn't be able to happen that often
+ // -- the user can only click so fast) or every 10hz, whichever is sooner.
+ // Sending for every volume update causes an excessive flood of messages whenever a volume slider is dragged.
+ if((mAudioSession && mAudioSession->mMuteDirty) || mPTTDirty || mUpdateTimer.hasExpired())
{
mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS);
sendPositionalUpdate();
@@ -2475,11 +2478,12 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void)
stream << "</Request>\n\n\n";
}
- if(mAudioSession && mAudioSession->mVolumeDirty)
+ if(mAudioSession && (mAudioSession->mVolumeDirty || mAudioSession->mMuteDirty))
{
participantMap::iterator iter = mAudioSession->mParticipantsByURI.begin();
mAudioSession->mVolumeDirty = false;
+ mAudioSession->mMuteDirty = false;
for(; iter != mAudioSession->mParticipantsByURI.end(); iter++)
{
@@ -2490,7 +2494,8 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void)
// Can't set volume/mute for yourself
if(!p->mIsSelf)
{
- int volume = 56; // nominal default value
+ // scale from the range 0.0-1.0 to vivox volume in the range 0-100
+ S32 volume = llround(p->mVolume / VOLUME_SCALE_VIVOX);
bool mute = p->mOnMuteList;
if(p->mUserVolume != -1)
@@ -2514,10 +2519,15 @@ void LLVivoxVoiceClient::sendPositionalUpdate(void)
// If we want the user to be muted, set their volume to 0 as well.
// This isn't perfect, but it will at least reduce their volume to a minimum.
volume = 0;
+ // Mark the current volume level as set to prevent incoming events
+ // changing it to 0, so that we can return to it when unmuting.
+ p->mVolumeSet = true;
}
if(volume == 0)
+ {
mute = true;
+ }
LL_DEBUGS("Voice") << "Setting volume/mute for avatar " << p->mAvatarID << " to " << volume << (mute?"/true":"/false") << LL_ENDL;
@@ -3671,15 +3681,12 @@ void LLVivoxVoiceClient::participantUpdatedEvent(
participant->mPower = 0.0f;
}
- // *HACK: Minimal hack to fix EXT-6508, ignore the incoming volume if it is zero.
- // This happens because we send volume zero to Vivox when someone is muted,
- // Vivox then send it back to us, overwriting the previous volume.
- // Remove this hack once volume refactoring from EXT-6031 is applied.
- if (volume != 0)
- {
- participant->mVolume = volume;
- }
-
+ // Ignore incoming volume level if it has been explicitly set, or there
+ // is a volume or mute change pending.
+ if ( !participant->mVolumeSet && !participant->mVolumeDirty)
+ {
+ participant->mVolume = (F32)volume * VOLUME_SCALE_VIVOX;
+ }
// *HACK: mantipov: added while working on EXT-3544
/*
@@ -4089,7 +4096,7 @@ LLVivoxVoiceClient::participantState::participantState(const std::string &uri) :
mIsModeratorMuted(false),
mLastSpokeTimestamp(0.f),
mPower(0.f),
- mVolume(-1),
+ mVolume(LLVoiceClient::VOLUME_DEFAULT),
mOnMuteList(false),
mUserVolume(-1),
mVolumeDirty(false),
@@ -4141,7 +4148,7 @@ LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParti
result->mAvatarID = id;
if(result->updateMuteState())
- mVolumeDirty = true;
+ mMuteDirty = true;
}
else
{
@@ -4153,7 +4160,11 @@ LLVivoxVoiceClient::participantState *LLVivoxVoiceClient::sessionState::addParti
mParticipantsByUUID.insert(participantUUIDMap::value_type(result->mAvatarID, result));
- result->mUserVolume = LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID);
+ if (LLSpeakerVolumeStorage::getInstance()->getSpeakerVolume(result->mAvatarID, result->mVolume))
+ {
+ result->mVolumeDirty = true;
+ mVolumeDirty = true;
+ }
LL_DEBUGS("Voice") << "participant \"" << result->mURI << "\" added." << LL_ENDL;
}
@@ -5355,51 +5366,21 @@ BOOL LLVivoxVoiceClient::getOnMuteList(const LLUUID& id)
return result;
}
-// External accessiors. Maps 0.0 to 1.0 to internal values 0-400 with .5 == 100
-// internal = 400 * external^2
+// External accessors.
F32 LLVivoxVoiceClient::getUserVolume(const LLUUID& id)
{
- F32 result = 0.0f;
+ // Minimum volume will be returned for users with voice disabled
+ F32 result = LLVoiceClient::VOLUME_MIN;
- participantState *participant = findParticipantByID(id);
- if(participant)
+ participantState *participant = findParticipantByID(id);
+ if(participant)
{
- S32 ires = 100; // nominal default volume
-
- if(participant->mIsSelf)
- {
- // Always make it look like the user's own volume is set at the default.
- }
- else if(participant->mUserVolume != -1)
- {
- // Use the internal volume
- ires = participant->mUserVolume;
-
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
-// LL_DEBUGS("Voice") << "mapping from mUserVolume " << ires << LL_ENDL;
- }
- else if(participant->mVolume != -1)
- {
- // Map backwards from vivox volume
+ result = participant->mVolume;
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
-// LL_DEBUGS("Voice") << "mapping from mVolume " << participant->mVolume << LL_ENDL;
-
- if(participant->mVolume < 56)
- {
- ires = (participant->mVolume * 100) / 56;
- }
- else
- {
- ires = (((participant->mVolume - 56) * 300) / (100 - 56)) + 100;
- }
- }
- result = sqrtf(((F32)ires) / 400.f);
+ // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
+ // LL_DEBUGS("Voice") << "mVolume = " << result << " for " << id << LL_ENDL;
}
- // Enable this when debugging voice slider issues. It's way to spammy even for debug-level logging.
-// LL_DEBUGS("Voice") << "returning " << result << LL_ENDL;
-
return result;
}
@@ -5408,16 +5389,23 @@ void LLVivoxVoiceClient::setUserVolume(const LLUUID& id, F32 volume)
if(mAudioSession)
{
participantState *participant = findParticipantByID(id);
- if (participant)
+ if (participant && !participant->mIsSelf)
{
- // store this volume setting for future sessions
- LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume);
- // volume can amplify by as much as 4x!
- S32 ivol = (S32)(400.f * volume * volume);
- participant->mUserVolume = llclamp(ivol, 0, 400);
- participant->mVolumeDirty = TRUE;
- mAudioSession->mVolumeDirty = TRUE;
+ if (!is_approx_equal(volume, LLVoiceClient::VOLUME_DEFAULT))
+ {
+ // Store this volume setting for future sessions if it has been
+ // changed from the default
+ LLSpeakerVolumeStorage::getInstance()->storeSpeakerVolume(id, volume);
+ }
+ else
+ {
+ // Remove stored volume setting if it is returned to the default
+ LLSpeakerVolumeStorage::getInstance()->removeSpeakerVolume(id);
+ }
+ participant->mVolume = llclamp(volume, LLVoiceClient::VOLUME_MIN, LLVoiceClient::VOLUME_MAX);
+ participant->mVolumeDirty = true;
+ mAudioSession->mVolumeDirty = true;
}
}
}
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 9f6c6232fd..59fec8b954 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -261,7 +261,7 @@ protected:
public:
participantState(const std::string &uri);
- bool updateMuteState();
+ bool updateMuteState(); // true if mute state has changed
bool isAvatar();
std::string mURI;
@@ -271,13 +271,14 @@ protected:
LLFrameTimer mSpeakingTimeout;
F32 mLastSpokeTimestamp;
F32 mPower;
- int mVolume;
+ F32 mVolume;
std::string mGroupID;
int mUserVolume;
bool mPTT;
bool mIsSpeaking;
bool mIsModeratorMuted;
bool mOnMuteList; // true if this avatar is on the user's mute list (and should be muted)
+ bool mVolumeSet; // true if incoming volume messages should not change the volume
bool mVolumeDirty; // true if this participant needs a volume command sent (either mOnMuteList or mUserVolume has changed)
bool mAvatarIDValid;
bool mIsSelf;
@@ -334,6 +335,7 @@ protected:
// Set to true when the mute state of someone in the participant list changes.
// The code will have to walk the list to find the changed participant(s).
bool mVolumeDirty;
+ bool mMuteDirty;
bool mParticipantsChanged;
participantMap mParticipantsByURI;