diff options
Diffstat (limited to 'indra')
-rw-r--r-- | indra/newview/llvoiceclient.cpp | 98 | ||||
-rw-r--r-- | indra/newview/llvoiceclient.h | 34 | ||||
-rw-r--r-- | indra/newview/llvoicevivox.cpp | 114 | ||||
-rw-r--r-- | indra/newview/llvoicevivox.h | 6 |
4 files changed, 164 insertions, 88 deletions
diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index e067754e3e..70cff3644c 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -43,6 +43,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"; @@ -795,23 +799,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() @@ -819,6 +885,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); @@ -830,7 +898,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); } } @@ -845,9 +916,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 f1a7d3dbec..5d6bcf4a72 100644 --- a/indra/newview/llvoiceclient.h +++ b/indra/newview/llvoiceclient.h @@ -272,7 +272,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 @@ -406,31 +410,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>; @@ -442,6 +449,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 a7efc49c67..6986ca0a90 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; } @@ -5351,51 +5362,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; } @@ -5404,16 +5385,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 10577254e8..e4e0b87ad0 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -260,7 +260,7 @@ protected: public: participantState(const std::string &uri); - bool updateMuteState(); + bool updateMuteState(); // true if mute state has changed bool isAvatar(); std::string mURI; @@ -270,13 +270,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; @@ -333,6 +334,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; |