diff --git a/indra/newview/llspeakers.cpp b/indra/newview/llspeakers.cpp index db1042031..fa4313ebd 100644 --- a/indra/newview/llspeakers.cpp +++ b/indra/newview/llspeakers.cpp @@ -111,7 +111,6 @@ LLSD LLSpeakerUpdateModeratorEvent::getValue() return ret; } - LLSpeakerTextModerationEvent::LLSpeakerTextModerationEvent(LLSpeaker* source) : LLEvent(source, "Speaker text moderation event") { @@ -254,15 +253,58 @@ bool LLSpeakersDelayActionsStorage::onTimerActionCallback(const LLUUID& speaker_ return true; } +// +// ModerationResponder +// + +class ModerationResponder : public LLHTTPClient::ResponderIgnoreBody +{ +public: + ModerationResponder(const LLUUID& session_id) + { + mSessionID = session_id; + } + + /*virtual*/ void error(U32 status, const std::string& reason) + { + llwarns << "ModerationResponder error [status:" << status << "]: " << reason << llendl; + + if ( gIMMgr ) + { + LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(mSessionID); + if (!floaterp) return; + + //403 == you're not a mod + //should be disabled if you're not a moderator + if ( 403 == status ) + { + floaterp->showSessionEventError( + "mute", + "not_a_mod_error"); + } + else + { + floaterp->showSessionEventError( + "mute", + "generic_request_error"); + } + } + } + /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return moderationResponder_timeout; } + /*virtual*/ char const* getName(void) const { return "ModerationResponder"; } + +private: + LLUUID mSessionID; +}; // // LLSpeakerMgr // LLSpeakerMgr::LLSpeakerMgr(LLVoiceChannel* channelp) : - mVoiceChannel(channelp) -, mVoiceModerated(false) -, mModerateModeHandledFirstTime(false) + mVoiceChannel(channelp), + mVoiceModerated(false), + mModerateModeHandledFirstTime(false) { static LLUICachedControl remove_delay ("SpeakerParticipantRemoveDelay", 10.0); @@ -276,7 +318,10 @@ LLSpeakerMgr::~LLSpeakerMgr() LLPointer LLSpeakerMgr::setSpeaker(const LLUUID& id, const std::string& name, LLSpeaker::ESpeakerStatus status, LLSpeaker::ESpeakerType type) { - if (id.isNull()) return NULL; + if (id.isNull()) + { + return NULL; + } LLPointer speakerp; if (mSpeakers.find(id) == mSpeakers.end()) @@ -358,13 +403,11 @@ void LLSpeakerMgr::update(BOOL resort_ok) // update status of all current speakers BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive()); - for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();) + for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end(); speaker_it++) { LLUUID speaker_id = speaker_it->first; LLSpeaker* speakerp = speaker_it->second; - speaker_it++; - if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id)) { speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id); @@ -461,22 +504,18 @@ void LLSpeakerMgr::update(BOOL resort_ok) void LLSpeakerMgr::updateSpeakerList() { - // are we bound to the currently active voice channel? + // Are we bound to the currently active voice channel? if ((!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive())) { std::set participants; LLVoiceClient::getInstance()->getParticipantList(participants); - // add new participants to our list of known speakers - for (std::set::iterator participant_it = participants.begin(); - participant_it != participants.end(); - ++participant_it) + // If we are, add all voice client participants to our list of known speakers + for (std::set::iterator participant_it = participants.begin(); participant_it != participants.end(); ++participant_it) { setSpeaker(*participant_it, LLVoiceClient::getInstance()->getDisplayName(*participant_it), LLSpeaker::STATUS_VOICE_ACTIVE, (LLVoiceClient::getInstance()->isParticipantAvatar(*participant_it)?LLSpeaker::SPEAKER_AGENT:LLSpeaker::SPEAKER_EXTERNAL)); - - } } } @@ -730,47 +769,10 @@ void LLIMSpeakerMgr::updateSpeakers(const LLSD& update) } } } - -class ModerationResponder : public LLHTTPClient::ResponderIgnoreBody -{ -public: - ModerationResponder(const LLUUID& session_id) - { - mSessionID = session_id; - } - - /*virtual*/ void error(U32 status, const std::string& reason) - { - llwarns << "ModerationResponder error [status:" << status << "]: " << reason << llendl; - - if ( gIMMgr ) - { - LLFloaterIMPanel* floaterp = gIMMgr->findFloaterBySession(mSessionID); - if (!floaterp) return; - - //403 == you're not a mod - //should be disabled if you're not a moderator - if ( 403 == status ) - { - floaterp->showSessionEventError( - "mute", - "not_a_mod_error"); - } - else - { - floaterp->showSessionEventError( - "mute", - "generic_request_error"); - } - } - } - /*virtual*/ AIHTTPTimeoutPolicy const& getHTTPTimeoutPolicy(void) const { return moderationResponder_timeout; } - /*virtual*/ char const* getName(void) const { return "ModerationResponder"; } - -private: - LLUUID mSessionID; -}; - +/*prep# + virtual void errorWithContent(U32 status, const std::string& reason, const LLSD& content) + llwarns << "ModerationResponder error [status:" << status << "]: " << content << llendl; + */ void LLIMSpeakerMgr::toggleAllowTextChat(const LLUUID& speaker_id) { LLPointer speakerp = findSpeaker(speaker_id); @@ -957,4 +959,3 @@ void LLLocalSpeakerMgr::updateSpeakerList() } } } - diff --git a/indra/newview/llvoicechannel.cpp b/indra/newview/llvoicechannel.cpp index 4ce04b028..1e4c68b79 100644 --- a/indra/newview/llvoicechannel.cpp +++ b/indra/newview/llvoicechannel.cpp @@ -964,4 +964,3 @@ void LLVoiceChannelP2P::setState(EState state) LLRecentPeople::instance().add(mOtherUserID); } }*/ - diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 40cdfa175..dd1b7c662 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -30,6 +30,7 @@ #include "llviewerwindow.h" #include "llvoicevivox.h" #include "llviewernetwork.h" +#include "llcommandhandler.h" #include "llhttpnode.h" #include "llnotificationsutil.h" #include "llsdserialize.h" @@ -42,6 +43,38 @@ const F32 LLVoiceClient::VOLUME_DEFAULT = 0.5f; const F32 LLVoiceClient::VOLUME_MAX = 1.0f; +// Support for secondlife:///app/voice SLapps +class LLVoiceHandler : public LLCommandHandler +{ +public: + // requests will be throttled from a non-trusted browser + LLVoiceHandler() : LLCommandHandler("voice", UNTRUSTED_THROTTLE) {} + + bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web) + { + if (params[0].asString() == "effects") + { + LLVoiceEffectInterface* effect_interface = LLVoiceClient::instance().getVoiceEffectInterface(); + // If the voice client doesn't support voice effects, we can't handle effects SLapps + if (!effect_interface) + { + return false; + } + + // Support secondlife:///app/voice/effects/refresh to update the voice effect list with new effects + if (params[1].asString() == "refresh") + { + effect_interface->refreshVoiceEffectLists(false); + return true; + } + } + return false; + } +}; +LLVoiceHandler gVoiceHandler; + + + std::string LLVoiceClientStatusObserver::status2string(LLVoiceClientStatusObserver::EStatusType inStatus) { std::string result = "UNKNOWN"; diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index d74c3a061..45526cd96 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -330,6 +330,7 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mCaptureDeviceDirty(false), mRenderDeviceDirty(false), mSpatialCoordsDirty(false), + mIsInitialized(false), mMuteMic(false), mMuteMicDirty(false), @@ -354,7 +355,9 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : mCaptureBufferRecording(false), mCaptureBufferRecorded(false), mCaptureBufferPlaying(false), - mPlayRequestCount(0) + mPlayRequestCount(0), + + mAvatarNameCacheConnection() { mSpeakerVolume = scale_speaker_volume(0); @@ -387,6 +390,10 @@ LLVivoxVoiceClient::LLVivoxVoiceClient() : LLVivoxVoiceClient::~LLVivoxVoiceClient() { + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } } //--------------------------------------------------- @@ -568,7 +575,7 @@ void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries) { LLViewerRegion *region = gAgent.getRegion(); - if ( region && mVoiceEnabled ) + if ( region && (mVoiceEnabled || !mIsInitialized)) { std::string url = region->getCapability("ProvisionVoiceAccountRequest"); @@ -739,7 +746,7 @@ void LLVivoxVoiceClient::stateMachine() setVoiceEnabled(false); } - if(mVoiceEnabled) + if(mVoiceEnabled || !mIsInitialized) { updatePosition(); } @@ -784,7 +791,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateDisabled case stateDisabled: - if(mTuningMode || (mVoiceEnabled && !mAccountName.empty())) + if(mTuningMode || ((mVoiceEnabled || !mIsInitialized) && !mAccountName.empty())) { setState(stateStart); } @@ -1039,7 +1046,7 @@ void LLVivoxVoiceClient::stateMachine() mTuningExitState = stateIdle; setState(stateMicTuningStart); } - else if(!mVoiceEnabled) + else if(!mVoiceEnabled && mIsInitialized) { // We never started up the connector. This will shut down the daemon. setState(stateConnectorStopped); @@ -1233,7 +1240,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateConnectorStart case stateConnectorStart: - if(!mVoiceEnabled) + if(!mVoiceEnabled && mIsInitialized) { // We were never logged in. This will shut down the connector. setState(stateLoggedOut); @@ -1251,7 +1258,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateConnectorStarted case stateConnectorStarted: // connector handle received - if(!mVoiceEnabled) + if(!mVoiceEnabled && mIsInitialized) { // We were never logged in. This will shut down the connector. setState(stateLoggedOut); @@ -1388,7 +1395,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateCreatingSessionGroup case stateCreatingSessionGroup: - if(mSessionTerminateRequested || !mVoiceEnabled) + if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)) { // *TODO: Question: is this the right way out of this state setState(stateSessionTerminated); @@ -1404,7 +1411,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateRetrievingParcelVoiceInfo case stateRetrievingParcelVoiceInfo: // wait until parcel voice info is received. - if(mSessionTerminateRequested || !mVoiceEnabled) + if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)) { // if a terminate request has been received, // bail and go to the stateSessionTerminated @@ -1424,7 +1431,7 @@ void LLVivoxVoiceClient::stateMachine() // Otherwise, if you log in but don't join a proximal channel (such as when your login location has voice disabled), your friends list won't sync. sendFriendsListUpdates(); - if(mSessionTerminateRequested || !mVoiceEnabled) + if(mSessionTerminateRequested || (!mVoiceEnabled && mIsInitialized)) { // TODO: Question: Is this the right way out of this state? setState(stateSessionTerminated); @@ -1505,7 +1512,7 @@ void LLVivoxVoiceClient::stateMachine() } // joinedAudioSession() will transition from here to stateSessionJoined. - if(!mVoiceEnabled) + if(!mVoiceEnabled && mIsInitialized) { // User bailed out during connect -- jump straight to teardown. setState(stateSessionTerminated); @@ -1552,7 +1559,7 @@ void LLVivoxVoiceClient::stateMachine() notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINED); } - else if(!mVoiceEnabled) + else if(!mVoiceEnabled && mIsInitialized) { // User bailed out during connect -- jump straight to teardown. setState(stateSessionTerminated); @@ -1572,7 +1579,7 @@ void LLVivoxVoiceClient::stateMachine() //MARK: stateRunning case stateRunning: // steady state // Disabling voice or disconnect requested. - if(!mVoiceEnabled || mSessionTerminateRequested) + if((!mVoiceEnabled && mIsInitialized) || mSessionTerminateRequested) { leaveAudioSession(); } @@ -1619,6 +1626,8 @@ void LLVivoxVoiceClient::stateMachine() mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); sendPositionalUpdate(); } + + mIsInitialized = true; } break; @@ -1652,7 +1661,7 @@ void LLVivoxVoiceClient::stateMachine() // Always reset the terminate request flag when we get here. mSessionTerminateRequested = false; - if(mVoiceEnabled && !mRelogRequested) + if((mVoiceEnabled || !mIsInitialized) && !mRelogRequested) { // Just leaving a channel, go back to stateNoChannel (the "logged in but have no channel" state). setState(stateNoChannel); @@ -1680,7 +1689,7 @@ void LLVivoxVoiceClient::stateMachine() mAccountHandle.clear(); cleanUp(); - if(mVoiceEnabled && !mRelogRequested) + if((mVoiceEnabled || !mIsInitialized) && !mRelogRequested) { // User was logged out, but wants to be logged in. Send a new login request. setState(stateNeedsLogin); @@ -2804,29 +2813,15 @@ void LLVivoxVoiceClient::checkFriend(const LLUUID& id) LLAvatarName av_name; if(LLAvatarNameCache::get(id, &av_name)) { - // *NOTE: For now, we feed legacy names to Vivox because I don't know - // if their service can support a mix of new and old clients with - // different sorts of names. + // *NOTE: We feed legacy names to Vivox because we don't know if their service + // can support a mix of new and old clients with different sorts of names. std::string name = av_name.getLegacyName(); - const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id); - bool canSeeMeOnline = false; - if(relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)) - canSeeMeOnline = true; - - // When we get here, mNeedsSend is true and mInSLFriends is false. Change them as necessary. - if(buddy) { - // This buddy is already in both lists. - - if(name != buddy->mDisplayName) - { - // The buddy is in the list with the wrong name. Update it with the correct name. - LL_WARNS("Voice") << "Buddy " << id << " has wrong name (\"" << buddy->mDisplayName << "\" should be \"" << name << "\"), updating."<< LL_ENDL; + // This buddy is already in both lists (vivox buddies and avatar cache). + // Trust the avatar cache more for the display name (vivox display name are notoriously wrong) buddy->mDisplayName = name; - buddy->mNeedsNameUpdate = true; // This will cause the buddy to be resent. - } } else { @@ -2835,20 +2830,19 @@ void LLVivoxVoiceClient::checkFriend(const LLUUID& id) buddy->mUUID = id; } - // In all the above cases, the buddy is in the SL friends list (which is how we got here). - buddy->mInSLFriends = true; - buddy->mCanSeeMeOnline = canSeeMeOnline; + const LLRelationship* relationInfo = LLAvatarTracker::instance().getBuddyInfo(id); + buddy->mCanSeeMeOnline = (relationInfo && relationInfo->isRightGrantedTo(LLRelationship::GRANT_ONLINE_STATUS)); + // In all the above cases, the buddy is in the SL friends list and tha name has been resolved (which is how we got here). buddy->mNameResolved = true; - + buddy->mInSLFriends = true; } else { - // This name hasn't been looked up yet. Don't do anything with this buddy list entry until it has. + // This name hasn't been looked up yet in the avatar cache. Don't do anything with this buddy list entry until it has. if(buddy) { buddy->mNameResolved = false; } - // Initiate a lookup. // The "lookup completed" callback will ensure that the friends list is rechecked after it completes. lookupName(id); @@ -2956,13 +2950,12 @@ void LLVivoxVoiceClient::sendFriendsListUpdates() { std::ostringstream stream; - if(buddy->mInSLFriends && (!buddy->mInVivoxBuddies || buddy->mNeedsNameUpdate)) + if(buddy->mInSLFriends && !buddy->mInVivoxBuddies) { if(mNumberOfAliases > 0) { // Add (or update) this entry in the vivox buddy list buddy->mInVivoxBuddies = true; - buddy->mNeedsNameUpdate = false; LL_DEBUGS("Voice") << "add/update " << buddy->mURI << " (" << buddy->mDisplayName << ")" << LL_ENDL; stream << "" @@ -3847,8 +3840,7 @@ void LLVivoxVoiceClient::participantUpdatedEvent( voice participant mIsModeratorMuted is changed after speakers are updated in Speaker Manager and event is not fired. - So, we have to call LLSpeakerMgr::update() here. In any case it is better than call it - in LLCallFloater::draw() + So, we have to call LLSpeakerMgr::update() here. */ LLVoiceChannel* voice_cnl = LLVoiceChannel::getCurrentVoiceChannel(); @@ -4078,7 +4070,7 @@ void LLVivoxVoiceClient::messageEvent( sessionState *session = findSession(sessionHandle); if(session) { - bool is_busy = gAgent.getBusy(); + bool is_do_not_disturb = gAgent.getBusy(); bool is_muted = LLMuteList::getInstance()->isMuted(session->mCallerID, session->mName, LLMute::flagTextChat); bool is_linden = LLMuteList::getInstance()->isLinden(session->mName); LLChat chat; @@ -4091,9 +4083,9 @@ void LLVivoxVoiceClient::messageEvent( chat.mFromName = session->mName; chat.mSourceType = CHAT_SOURCE_AGENT; - if(is_busy && !is_linden) + if(is_do_not_disturb && !is_linden) { - // TODO: Question: Return busy mode response here? Or maybe when session is started instead? + // TODO: Question: Return do not disturb mode response here? Or maybe when session is started instead? } LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL; @@ -5985,7 +5977,6 @@ LLVivoxVoiceClient::buddyListEntry::buddyListEntry(const std::string &uri) : mNameResolved = false; mInVivoxBuddies = false; mInSLFriends = false; - mNeedsNameUpdate = false; } void LLVivoxVoiceClient::processBuddyListEntry(const std::string &uri, const std::string &displayName) @@ -6024,11 +6015,7 @@ LLVivoxVoiceClient::buddyListEntry *LLVivoxVoiceClient::addBuddy(const std::stri result = new buddyListEntry(uri); result->mDisplayName = displayName; - if(IDFromName(uri, result->mUUID)) - { - // Extracted UUID from name successfully. - } - else + if (!IDFromName(uri, result->mUUID)) { LL_DEBUGS("Voice") << "Couldn't find ID for buddy " << uri << " (\"" << displayName << "\")" << LL_ENDL; } @@ -6328,18 +6315,19 @@ void LLVivoxVoiceClient::notifyFriendObservers() void LLVivoxVoiceClient::lookupName(const LLUUID &id) { - LLAvatarNameCache::get(id, - boost::bind(&LLVivoxVoiceClient::onAvatarNameCache, - this, _1, _2)); + if (mAvatarNameCacheConnection.connected()) + { + mAvatarNameCacheConnection.disconnect(); + } + mAvatarNameCacheConnection = LLAvatarNameCache::get(id, boost::bind(&LLVivoxVoiceClient::onAvatarNameCache, this, _1, _2)); } void LLVivoxVoiceClient::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name) { - // For Vivox, we use the legacy name because I'm uncertain whether or - // not their service can tolerate switching to Username or Display Name - std::string legacy_name = av_name.getLegacyName(); - avatarNameResolved(agent_id, legacy_name); + mAvatarNameCacheConnection.disconnect(); + std::string display_name = av_name.mDisplayName; + avatarNameResolved(agent_id, display_name); } void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string &name) @@ -7401,6 +7389,8 @@ void LLVivoxProtocolParser::EndTag(const char *tag) } else if (!stricmp("Buddy", tag)) { + // NOTE : Vivox does *not* give reliable display name for Buddy tags + // We don't take those very seriously as a result... LLVivoxVoiceClient::getInstance()->processBuddyListEntry(uriString, displayNameString); } else if (!stricmp("BlockRule", tag)) diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index a270c2315..49b2132ac 100644 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -564,7 +564,6 @@ protected: bool mNameResolved; bool mInSLFriends; bool mInVivoxBuddies; - bool mNeedsNameUpdate; }; typedef std::map buddyListMap; @@ -623,6 +622,7 @@ protected: void lookupName(const LLUUID &id); void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name); void avatarNameResolved(const LLUUID &id, const std::string &name); + boost::signals2::connection mAvatarNameCacheConnection; ///////////////////////////// // Voice fonts @@ -724,6 +724,8 @@ private: bool mCaptureDeviceDirty; bool mRenderDeviceDirty; + bool mIsInitialized; + bool checkParcelChanged(bool update = false); // This should be called when the code detects we have changed parcels. @@ -1014,3 +1016,4 @@ protected: #endif //LL_VIVOX_VOICE_CLIENT_H +