summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xindra/newview/llavataractions.cpp4
-rw-r--r--indra/newview/lltoolpie.cpp1
-rw-r--r--indra/newview/llviewermessage.cpp12
-rw-r--r--indra/newview/llvoicevivox.cpp303
-rw-r--r--indra/newview/llvoicevivox.h15
-rwxr-xr-xindra/newview/skins/default/xui/en/notifications.xml13
6 files changed, 225 insertions, 123 deletions
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index cbbdcb2983..955f19c82c 100755
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -773,6 +773,10 @@ bool LLAvatarActions::canOfferTeleport(const LLUUID& id)
// static
bool LLAvatarActions::canOfferTeleport(const uuid_vec_t& ids)
{
+ // We can't send more than 250 lures in a single message, so disable this
+ // button when there are too many id's selected.
+ if(ids.size() > 250) return false;
+
bool result = true;
for (uuid_vec_t::const_iterator it = ids.begin(); it != ids.end(); ++it)
{
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 9ec4d33036..c38c8bad80 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -639,6 +639,7 @@ BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
if (click_action == CLICK_ACTION_NONE // not doing 1-click action
&& gSavedSettings.getBOOL("ClickToWalk") // click to walk enabled
&& !gAgent.getFlying() // don't auto-navigate while flying until that works
+ && gAgentAvatarp
&& !gAgentAvatarp->isSitting()
&& !mBlockClickToWalk // another behavior hasn't cancelled click to walk
&& !mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index ff9533c52f..fc0e6da7a0 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -6261,6 +6261,18 @@ void send_group_notice(const LLUUID& group_id,
bool handle_lure_callback(const LLSD& notification, const LLSD& response)
{
+ static const unsigned OFFER_RECIPIENT_LIMIT = 250;
+ if(notification["payload"]["ids"].size() > OFFER_RECIPIENT_LIMIT)
+ {
+ // More than OFFER_RECIPIENT_LIMIT targets will overload the message
+ // producing an llerror.
+ LLSD args;
+ args["OFFERS"] = notification["payload"]["ids"].size();
+ args["LIMIT"] = static_cast<int>(OFFER_RECIPIENT_LIMIT);
+ LLNotificationsUtil::add("TooManyTeleportOffers", args);
+ return false;
+ }
+
std::string text = response["message"].asString();
LLSLURL slurl;
LLAgentUI::buildSLURL(slurl);
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 6ee6822e2f..cd2bbad620 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -195,12 +195,13 @@ static LLVivoxVoiceClientFriendsObserver *friendslist_listener = NULL;
class LLVivoxVoiceClientCapResponder : public LLHTTPClient::Responder
{
public:
- LLVivoxVoiceClientCapResponder(void){};
+ LLVivoxVoiceClientCapResponder(LLVivoxVoiceClient::state requesting_state) : mRequestingState(requesting_state) {};
virtual void error(U32 status, const std::string& reason); // called with bad status codes
virtual void result(const LLSD& content);
private:
+ LLVivoxVoiceClient::state mRequestingState; // state
};
void LLVivoxVoiceClientCapResponder::error(U32 status, const std::string& reason)
@@ -208,6 +209,7 @@ void LLVivoxVoiceClientCapResponder::error(U32 status, const std::string& reason
LL_WARNS("Voice") << "LLVivoxVoiceClientCapResponder::error("
<< status << ": " << reason << ")"
<< LL_ENDL;
+ LLVivoxVoiceClient::getInstance()->sessionTerminate();
}
void LLVivoxVoiceClientCapResponder::result(const LLSD& content)
@@ -216,12 +218,12 @@ void LLVivoxVoiceClientCapResponder::result(const LLSD& content)
LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest response:" << ll_pretty_print_sd(content) << LL_ENDL;
+ std::string uri;
+ std::string credentials;
+
if ( content.has("voice_credentials") )
{
LLSD voice_credentials = content["voice_credentials"];
- std::string uri;
- std::string credentials;
-
if ( voice_credentials.has("channel_uri") )
{
uri = voice_credentials["channel_uri"].asString();
@@ -231,7 +233,12 @@ void LLVivoxVoiceClientCapResponder::result(const LLSD& content)
credentials =
voice_credentials["channel_credentials"].asString();
}
-
+ }
+
+ // set the spatial channel. If no voice credentials or uri are
+ // available, then we simply drop out of voice spatially.
+ if(LLVivoxVoiceClient::getInstance()->parcelVoiceInfoReceived(mRequestingState))
+ {
LLVivoxVoiceClient::getInstance()->setSpatialChannel(uri, credentials);
}
}
@@ -551,18 +558,27 @@ void LLVivoxVoiceClient::userAuthorized(const std::string& user_id, const LLUUID
void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries)
{
- if ( gAgent.getRegion() && mVoiceEnabled )
+ LLViewerRegion *region = gAgent.getRegion();
+
+ if ( region && mVoiceEnabled )
{
std::string url =
- gAgent.getRegion()->getCapability(
- "ProvisionVoiceAccountRequest");
-
- if ( url == "" ) return;
-
+ region->getCapability("ProvisionVoiceAccountRequest");
+
+ if ( url.empty() )
+ {
+ // we've not received the capability yet, so return.
+ // the password will remain empty, so we'll remain in
+ // stateIdle
+ return;
+ }
+
LLHTTPClient::post(
- url,
- LLSD(),
- new LLVivoxVoiceAccountProvisionResponder(retries));
+ url,
+ LLSD(),
+ new LLVivoxVoiceAccountProvisionResponder(retries));
+
+ setState(stateConnectorStart);
}
}
@@ -673,7 +689,8 @@ std::string LLVivoxVoiceClient::state2string(LLVivoxVoiceClient::state inState)
CASE(stateVoiceFontsWait);
CASE(stateVoiceFontsReceived);
CASE(stateCreatingSessionGroup);
- CASE(stateNoChannel);
+ CASE(stateNoChannel);
+ CASE(stateRetrievingParcelVoiceInfo);
CASE(stateJoiningSession);
CASE(stateSessionJoined);
CASE(stateRunning);
@@ -741,42 +758,6 @@ void LLVivoxVoiceClient::stateMachine()
}
}
- // Check for parcel boundary crossing
- {
- LLViewerRegion *region = gAgent.getRegion();
- LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
-
- if(region && parcel)
- {
- S32 parcelLocalID = parcel->getLocalID();
- std::string regionName = region->getName();
- std::string capURI = region->getCapability("ParcelVoiceInfoRequest");
-
-// LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL;
-
- // The region name starts out empty and gets filled in later.
- // Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes.
- // If either is empty, wait for the next time around.
- if(!regionName.empty())
- {
- if(!capURI.empty())
- {
- if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
- {
- // We have changed parcels. Initiate a parcel channel lookup.
- mCurrentParcelLocalID = parcelLocalID;
- mCurrentRegionName = regionName;
-
- parcelChanged();
- }
- }
- else
- {
- LL_WARNS_ONCE("Voice") << "region doesn't have ParcelVoiceInfoRequest capability. This is normal for a short time after teleporting, but bad if it persists for very long." << LL_ENDL;
- }
- }
- }
- }
switch(getState())
{
@@ -1026,22 +1007,9 @@ void LLVivoxVoiceClient::stateMachine()
}
else if(!mAccountName.empty())
{
- LLViewerRegion *region = gAgent.getRegion();
-
- if(region)
+ if ( mAccountPassword.empty() )
{
- if ( region->getCapability("ProvisionVoiceAccountRequest") != "" )
- {
- if ( mAccountPassword.empty() )
- {
- requestVoiceAccountProvision();
- }
- setState(stateConnectorStart);
- }
- else
- {
- LL_WARNS_ONCE("Voice") << "region doesn't have ProvisionVoiceAccountRequest capability!" << LL_ENDL;
- }
+ requestVoiceAccountProvision();
}
}
break;
@@ -1382,11 +1350,7 @@ void LLVivoxVoiceClient::stateMachine()
setState(stateCreatingSessionGroup);
sessionGroupCreateSendMessage();
#else
- // Not using session groups -- skip the stateCreatingSessionGroup state.
- setState(stateNoChannel);
-
- // Initial kick-off of channel lookup logic
- parcelChanged();
+ setState(stateNoChannel);
#endif
break;
@@ -1399,19 +1363,29 @@ void LLVivoxVoiceClient::stateMachine()
}
else if(!mMainSessionGroupHandle.empty())
{
- setState(stateNoChannel);
-
// Start looped recording (needed for "panic button" anti-griefing tool)
recordingLoopStart();
-
- // Initial kick-off of channel lookup logic
- parcelChanged();
+ setState(stateNoChannel);
}
break;
+
+ //MARK: stateRetrievingParcelVoiceInfo
+ case stateRetrievingParcelVoiceInfo:
+ // wait until parcel voice info is received.
+ if(mSessionTerminateRequested || !mVoiceEnabled)
+ {
+ // if a terminate request has been received,
+ // bail and go to the stateSessionTerminated
+ // state. If the cap request is still pending,
+ // the responder will check to see if we've moved
+ // to a new session and won't change any state.
+ setState(stateSessionTerminated);
+ }
+ break;
+
//MARK: stateNoChannel
case stateNoChannel:
-
LL_DEBUGS("Voice") << "State No Channel" << LL_ENDL;
mSpatialJoiningNum = 0;
// Do this here as well as inside sendPositionalUpdate().
@@ -1432,6 +1406,16 @@ void LLVivoxVoiceClient::stateMachine()
{
setState(stateCaptureBufferPaused);
}
+ else if(checkParcelChanged() || (mNextAudioSession == NULL))
+ {
+ // the parcel is changed, or we have no pending audio sessions,
+ // so try to request the parcel voice info
+ // if we have the cap, we move to the appropriate state
+ if(requestParcelVoiceInfo())
+ {
+ setState(stateRetrievingParcelVoiceInfo);
+ }
+ }
else if(sessionNeedsRelog(mNextAudioSession))
{
requestRelog();
@@ -1466,32 +1450,28 @@ void LLVivoxVoiceClient::stateMachine()
notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_JOINING);
setState(stateJoiningSession);
}
- else if(!mSpatialSessionURI.empty())
- {
- // If we're not headed elsewhere and have a spatial URI, return to spatial.
- switchChannel(mSpatialSessionURI, true, false, false, mSpatialSessionCredentials);
- }
break;
-
+
//MARK: stateJoiningSession
case stateJoiningSession: // waiting for session handle
-
- // If this is true we have problem with connection to voice server (EXT-4313).
- // See descriptions of mSpatialJoiningNum and MAX_NORMAL_JOINING_SPATIAL_NUM.
- if(mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM)
+
+ // If this is true we have problem with connection to voice server (EXT-4313).
+ // See descriptions of mSpatialJoiningNum and MAX_NORMAL_JOINING_SPATIAL_NUM.
+ if(mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM)
{
- // Notify observers to let them know there is problem with voice
- notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
- llwarns << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << llendl;
+ // Notify observers to let them know there is problem with voice
+ notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
+ llwarns << "There seems to be problem with connection to voice server. Disabling voice chat abilities." << llendl;
}
-
- // Increase mSpatialJoiningNum only for spatial sessions- it's normal to reach this case for
- // example for p2p many times while waiting for response, so it can't be used to detect errors
- if(mAudioSession && mAudioSession->mIsSpatial)
+
+ // Increase mSpatialJoiningNum only for spatial sessions- it's normal to reach this case for
+ // example for p2p many times while waiting for response, so it can't be used to detect errors
+ if(mAudioSession && mAudioSession->mIsSpatial)
{
- mSpatialJoiningNum++;
+
+ mSpatialJoiningNum++;
}
-
+
// joinedAudioSession() will transition from here to stateSessionJoined.
if(!mVoiceEnabled)
{
@@ -1511,12 +1491,13 @@ void LLVivoxVoiceClient::stateMachine()
}
}
}
- break;
-
+ break;
+
//MARK: stateSessionJoined
case stateSessionJoined: // session handle received
- mSpatialJoiningNum = 0;
+
+ mSpatialJoiningNum = 0;
// It appears that I need to wait for BOTH the SessionGroup.AddSession response and the SessionStateChangeEvent with state 4
// before continuing from this state. They can happen in either order, and if I don't wait for both, things can get stuck.
// For now, the SessionGroup.AddSession response handler sets mSessionHandle and the SessionStateChangeEvent handler transitions to stateSessionJoined.
@@ -1553,7 +1534,7 @@ void LLVivoxVoiceClient::stateMachine()
sessionMediaDisconnectSendMessage(mAudioSession);
setState(stateSessionTerminated);
}
- }
+ }
break;
//MARK: stateRunning
@@ -1565,6 +1546,7 @@ void LLVivoxVoiceClient::stateMachine()
}
else
{
+
if(!inSpatialChannel())
{
// When in a non-spatial channel, never send positional updates.
@@ -1572,8 +1554,22 @@ void LLVivoxVoiceClient::stateMachine()
}
else
{
+ if(checkParcelChanged())
+ {
+ // if the parcel has changed, attempted to request the
+ // cap for the parcel voice info. If we can't request it
+ // then we don't have the cap URL so we do nothing and will
+ // recheck next time around
+ if(requestParcelVoiceInfo())
+ {
+ // we did get the cap, and we made the request,
+ // so go wait for the response.
+ setState(stateRetrievingParcelVoiceInfo);
+ }
+ }
// Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position)
enforceTether();
+
}
// Do notifications for expiring Voice Fonts.
@@ -3840,7 +3836,7 @@ void LLVivoxVoiceClient::participantUpdatedEvent(
// also initialize voice moderate_mode depend on Agent's participant. See EXT-6937.
// *TODO: remove once a way to request the current voice channel moderation mode is implemented.
- if (gAgentID == participant->mAvatarID)
+ if (gAgent.getID() == participant->mAvatarID)
{
speaker_manager->initVoiceModerateMode();
}
@@ -4073,7 +4069,7 @@ void LLVivoxVoiceClient::messageEvent(
}
LL_DEBUGS("Voice") << "adding message, name " << session->mName << " session " << session->mIMSessionID << ", target " << session->mCallerID << LL_ENDL;
- gIMMgr->addMessage(session->mIMSessionID,
+ LLIMMgr::getInstance()->addMessage(session->mIMSessionID,
session->mCallerID,
session->mName.c_str(),
message.c_str(),
@@ -4447,24 +4443,91 @@ LLVivoxVoiceClient::participantState* LLVivoxVoiceClient::findParticipantByID(co
}
-void LLVivoxVoiceClient::parcelChanged()
+
+// Check for parcel boundary crossing
+bool LLVivoxVoiceClient::checkParcelChanged(bool update)
{
- if(getState() >= stateNoChannel)
+ LLViewerRegion *region = gAgent.getRegion();
+ LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+
+ if(region && parcel)
{
- // If the user is logged in, start a channel lookup.
- LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
+ S32 parcelLocalID = parcel->getLocalID();
+ std::string regionName = region->getName();
+
+ // LL_DEBUGS("Voice") << "Region name = \"" << regionName << "\", parcel local ID = " << parcelLocalID << ", cap URI = \"" << capURI << "\"" << LL_ENDL;
+
+ // The region name starts out empty and gets filled in later.
+ // Also, the cap gets filled in a short time after the region cross, but a little too late for our purposes.
+ // If either is empty, wait for the next time around.
+ if(!regionName.empty())
+ {
+ if((parcelLocalID != mCurrentParcelLocalID) || (regionName != mCurrentRegionName))
+ {
+ // We have changed parcels. Initiate a parcel channel lookup.
+ if (update)
+ {
+ mCurrentParcelLocalID = parcelLocalID;
+ mCurrentRegionName = regionName;
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool LLVivoxVoiceClient::parcelVoiceInfoReceived(state requesting_state)
+{
+ // pop back to the state we were in when the parcel changed and we managed to
+ // do the request.
+ if(getState() == stateRetrievingParcelVoiceInfo)
+ {
+ setState(requesting_state);
+ return true;
+ }
+ else
+ {
+ // we've dropped out of stateRetrievingParcelVoiceInfo
+ // before we received the cap result, due to a terminate
+ // or transition to a non-voice channel. Don't switch channels.
+ return false;
+ }
+}
+
- std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest");
+bool LLVivoxVoiceClient::requestParcelVoiceInfo()
+{
+ LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
+
+ // grab the cap for parcel voice info from the region.
+ LLViewerRegion * region = gAgent.getRegion();
+ if (region == NULL)
+ {
+ return false;
+ }
+ // grab the cap.
+ std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest");
+ if (!url.empty())
+ {
+ // if we've already retrieved the cap from the region, go ahead and make the request,
+ // and return true so we can go into the state that waits for the response.
+ checkParcelChanged(true);
LLSD data;
+ LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL;
+
LLHTTPClient::post(
- url,
- data,
- new LLVivoxVoiceClientCapResponder);
+ url,
+ data,
+ new LLVivoxVoiceClientCapResponder(getState()));
+ return true;
}
- else
+ else
{
- // The transition to stateNoChannel needs to kick this off again.
- LL_INFOS("Voice") << "not logged in yet, deferring" << LL_ENDL;
+
+ // we don't have the cap yet, so return false so the caller can try again later.
+ LL_DEBUGS("Voice") << "ParcelVoiceInfoRequest cap not yet available, deferring" << LL_ENDL;
+ return false;
}
}
@@ -4488,6 +4551,7 @@ void LLVivoxVoiceClient::switchChannel(
case stateJoinSessionFailed:
case stateJoinSessionFailedWaiting:
case stateNoChannel:
+ case stateRetrievingParcelVoiceInfo:
// Always switch to the new URI from these states.
needsSwitch = true;
break;
@@ -4560,13 +4624,10 @@ void LLVivoxVoiceClient::switchChannel(
mNextAudioSession->mIsP2P = is_p2p;
}
- if(getState() <= stateNoChannel)
- {
- // We're already set up to join a channel, just needed to fill in the session URI
- }
- else
+ if(getState() >= stateRetrievingParcelVoiceInfo)
{
- // State machine will come around and rejoin if uri/handle is not empty.
+ // If we're already in a channel, or if we're joining one, terminate
+ // so we can rejoin with the new session data.
sessionTerminate();
}
}
@@ -6267,13 +6328,13 @@ void LLVivoxVoiceClient::avatarNameResolved(const LLUUID &id, const std::string
{
session->mTextInvitePending = false;
- // We don't need to call gIMMgr->addP2PSession() here. The first incoming message will create the panel.
+ // We don't need to call LLIMMgr::getInstance()->addP2PSession() here. The first incoming message will create the panel.
}
if(session->mVoiceInvitePending)
{
session->mVoiceInvitePending = false;
- gIMMgr->inviteToSession(
+ LLIMMgr::getInstance()->inviteToSession(
session->mIMSessionID,
session->mName,
session->mCallerID,
diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h
index 471545de56..1142a1a49c 100644
--- a/indra/newview/llvoicevivox.h
+++ b/indra/newview/llvoicevivox.h
@@ -380,7 +380,8 @@ protected:
stateVoiceFontsWait, // Awaiting the list of voice fonts
stateVoiceFontsReceived, // List of voice fonts received
stateCreatingSessionGroup, // Creating the main session group
- stateNoChannel, //
+ stateNoChannel, // Need to join a channel
+ stateRetrievingParcelVoiceInfo, // waiting for parcel voice info request to return with spatial credentials
stateJoiningSession, // waiting for session handle
stateSessionJoined, // session handle received
stateRunning, // in session, steady state
@@ -620,6 +621,8 @@ protected:
void sessionMediaDisconnectSendMessage(sessionState *session);
void sessionTextDisconnectSendMessage(sessionState *session);
+
+
// Pokes the state machine to leave the audio session next time around.
void sessionTerminate();
@@ -629,6 +632,12 @@ protected:
// Does the actual work to get out of the audio session
void leaveAudioSession();
+ // notifies the voice client that we've received parcel voice info
+ bool parcelVoiceInfoReceived(state requesting_state);
+
+ friend class LLVivoxVoiceClientCapResponder;
+
+
void lookupName(const LLUUID &id);
void onAvatarNameCache(const LLUUID& id, const LLAvatarName& av_name);
void avatarNameResolved(const LLUUID &id, const std::string &name);
@@ -733,9 +742,11 @@ private:
bool mCaptureDeviceDirty;
bool mRenderDeviceDirty;
+
+ bool checkParcelChanged(bool update = false);
// This should be called when the code detects we have changed parcels.
// It initiates the call to the server that gets the parcel channel.
- void parcelChanged();
+ bool requestParcelVoiceInfo();
void switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = "");
void joinSession(sessionState *session);
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 09105c1d28..db1cee5d08 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3698,6 +3698,19 @@ Join me in [REGION]
<notification
icon="alertmodal.tga"
+ name="TooManyTeleportOffers"
+ type="alertmodal">
+You attempted to make [OFFERS] teleport offers
+which exceeds the limit of [LIMIT].
+ <tag>group</tag>
+ <tag>fail</tag>
+ <usetemplate
+ name="okbutton"
+ yestext="OK"/>
+ </notification>
+
+ <notification
+ icon="alertmodal.tga"
name="OfferTeleportFromGod"
type="alertmodal">
God summon Resident to your location?