diff -r 04e2a3ddca51 -r 875c3e3b1d4a doc/contributions.txt --- a/doc/contributions.txt Thu Jun 23 09:47:43 2011 -0400 +++ b/doc/contributions.txt Fri Jun 24 12:08:40 2011 +0200 @@ -166,6 +166,7 @@ VWR-68 Armin Weatherwax VWR-8436 + VWR-25923 Asuka Neely VWR-3434 VWR-8179 @@ -446,6 +447,7 @@ STORM-1313 STORM-899 STORM-1273 + VWR-25923 Kage Pixel VWR-11 Ken March diff -r 04e2a3ddca51 -r 875c3e3b1d4a indra/newview/llviewerregion.h --- a/indra/newview/llviewerregion.h Thu Jun 23 09:47:43 2011 -0400 +++ b/indra/newview/llviewerregion.h Fri Jun 24 12:08:40 2011 +0200 @@ -30,6 +30,7 @@ // A ViewerRegion is a class that contains a bunch of objects and surfaces // that are in to a particular region. #include +#include #include "lldarray.h" #include "llwind.h" @@ -90,6 +91,8 @@ NUM_PARTITIONS } eObjectPartitions; + typedef boost::signals2::signal caps_received_signal_t; + LLViewerRegion(const U64 &handle, const LLHost &host, const U32 surface_grid_width, @@ -237,6 +240,7 @@ // has region received its final (not seed) capability list? bool capabilitiesReceived() const; void setCapabilitiesReceived(bool received); + boost::signals2::connection setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb); static bool isSpecialCapabilityName(const std::string &name); void logActiveCapabilities() const; @@ -404,6 +408,7 @@ bool mAlive; // can become false if circuit disconnects bool mCapabilitiesReceived; + caps_received_signal_t mCapabilitiesReceivedSignal; BOOL mReleaseNotesRequested; diff -r 04e2a3ddca51 -r 875c3e3b1d4a indra/newview/llviewerregion.cpp --- a/indra/newview/llviewerregion.cpp Thu Jun 23 09:47:43 2011 -0400 +++ b/indra/newview/llviewerregion.cpp Fri Jun 24 12:08:40 2011 +0200 @@ -1660,6 +1660,21 @@ void LLViewerRegion::setCapabilitiesReceived(bool received) { mCapabilitiesReceived = received; + + // Tell interested parties that we've received capabilities, + // so that they can safely use getCapability(). + if (received) + { + mCapabilitiesReceivedSignal(getRegionID()); + + // This is a single-shot signal. Forget callbacks to save resources. + mCapabilitiesReceivedSignal.disconnect_all_slots(); + } +} + +boost::signals2::connection LLViewerRegion::setCapabilitiesReceivedCallback(const caps_received_signal_t::slot_type& cb) +{ + return mCapabilitiesReceivedSignal.connect(cb); } void LLViewerRegion::logActiveCapabilities() const diff -r 04e2a3ddca51 -r 875c3e3b1d4a indra/newview/llvoicevivox.h --- a/indra/newview/llvoicevivox.h Thu Jun 23 09:47:43 2011 -0400 +++ b/indra/newview/llvoicevivox.h Fri Jun 24 12:08:40 2011 +0200 @@ -704,9 +704,23 @@ // std::string mSessionURI; // URI of the session we're in. // std::string mSessionHandle; // returned by ? - S32 mCurrentParcelLocalID; // Used to detect parcel boundary crossings - std::string mCurrentRegionName; // Used to detect parcel boundary crossings - + LLViewerRegion* mCurrentRegion; //Region in which ParcelInfoRequest is requested + + + // Setting mRegionHasVoiceCaps to false keeps the voice client staying in stateDisabled. + // It is set to false if at least one of the capabilities is definitely not available. + // For consistency it is also set to false if the user disables voice in preferences. + // Setting to true allows escaping stateDisabled and with that the lookup of the capabilities. + // It is set to true if the user enables voice in preferences, and when a new channel is set. + bool mRegionHasVoiceCaps; + + // The request is pending if true + bool mVoiceAccountProvisionRequestPending; + + // Allow the response so long to arrive + LLTimer mVoiceAccountProvisionRequestTimeout; + + std::string mConnectorHandle; // returned by "Create Connector" message std::string mAccountHandle; // returned by login message int mNumberOfAliases; @@ -732,9 +746,13 @@ std::string mRenderDevice; bool mCaptureDeviceDirty; bool mRenderDeviceDirty; + + // actually fire the cap request initiated by parcelChanged() -either directly if the region already has the cap response + // or as callback set in LLViewerRegion::setCapabilitiesReceivedCallback + void doParcelInfoRequest(); - // This should be called when the code detects we have changed parcels. - // It initiates the call to the server that gets the parcel channel. + // This is called when the code detects we have changed parcels. + // It initiates the call to the server that gets the parcel channel in doParcelInfoRequest(). void parcelChanged(); void switchChannel(std::string uri = std::string(), bool spatial = true, bool no_reconnect = false, bool is_p2p = false, std::string hash = ""); diff -r 04e2a3ddca51 -r 875c3e3b1d4a indra/newview/llvoicevivox.cpp --- a/indra/newview/llvoicevivox.cpp Thu Jun 23 09:47:43 2011 -0400 +++ b/indra/newview/llvoicevivox.cpp Fri Jun 24 12:08:40 2011 +0200 @@ -312,7 +312,6 @@ mAudioSessionChanged(false), mNextAudioSession(NULL), - mCurrentParcelLocalID(0), mNumberOfAliases(0), mCommandCookie(0), mLoginRetryCount(0), @@ -336,6 +335,11 @@ mMicVolumeDirty(true), mVoiceEnabled(false), + + mCurrentRegion(NULL), + mRegionHasVoiceCaps(false), + mVoiceAccountProvisionRequestPending(false), + mWriteInProgress(false), mLipSyncEnabled(false), @@ -375,6 +379,8 @@ setState(stateDisabled); gIdleCallbacks.addFunction(idle, this); + + LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&LLVivoxVoiceClient::parcelChanged, this)); } //--------------------------------------------------- @@ -551,13 +557,22 @@ void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries) { - if ( gAgent.getRegion() && mVoiceEnabled ) + LLViewerRegion* region = gAgent.getRegion(); + + if (mVoiceEnabled && region && region->capabilitiesReceived()) { std::string url = gAgent.getRegion()->getCapability( "ProvisionVoiceAccountRequest"); - if ( url == "" ) return; + if (url.empty()) + { + LL_WARNS("Voice") << "The current region doesn't have the ProvisionVoiceAccountRequest capability, voice isn't available here." << LL_ENDL; + mRegionHasVoiceCaps = false; + mVoiceAccountProvisionRequestPending = false; + setState(stateDisableCleanup); + return; + } LLHTTPClient::post( url, @@ -572,6 +587,9 @@ const std::string& voice_sip_uri_hostname, const std::string& voice_account_server_uri) { + // Not pending anymore: The request was successful, and the response arrived. + mVoiceAccountProvisionRequestPending = false; + mVoiceSIPURIHostName = voice_sip_uri_hostname; mVoiceAccountServerURI = voice_account_server_uri; @@ -740,43 +758,7 @@ setState(stateDisableCleanup); } } - - // 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()) { @@ -789,13 +771,15 @@ mAccountHandle.clear(); mAccountPassword.clear(); mVoiceAccountServerURI.clear(); - + mVoiceAccountProvisionRequestPending = false; + mVoiceAccountProvisionRequestTimeout.reset(); + setState(stateDisabled); break; //MARK: stateDisabled case stateDisabled: - if(mTuningMode || (mVoiceEnabled && !mAccountName.empty())) + if (mTuningMode || (mVoiceEnabled && !mAccountName.empty() && mRegionHasVoiceCaps)) { setState(stateStart); } @@ -1028,19 +1012,36 @@ { LLViewerRegion *region = gAgent.getRegion(); - if(region) + if (region && region->capabilitiesReceived()) { - if ( region->getCapability("ProvisionVoiceAccountRequest") != "" ) + if (mAccountPassword.empty()) { - if ( mAccountPassword.empty() ) + + if (!mVoiceAccountProvisionRequestPending) { + mVoiceAccountProvisionRequestTimeout.start(); + mVoiceAccountProvisionRequestTimeout.setTimerExpirySec(23.f); + mVoiceAccountProvisionRequestPending = true; requestVoiceAccountProvision(); } - setState(stateConnectorStart); + else + { + if (mVoiceAccountProvisionRequestTimeout.hasExpired()) + { + mVoiceAccountProvisionRequestPending = false; + mVoiceAccountProvisionRequestTimeout.reset(); + // The region has the capability, + // and the capability was requested. + // But the response didn't arrive within + // 23 seconds. We could retry. + // Or give up until next parcel change: + setState(stateDisableCleanup); + } + } } else { - LL_WARNS_ONCE("Voice") << "region doesn't have ProvisionVoiceAccountRequest capability!" << LL_ENDL; + setState(stateConnectorStart); } } } @@ -4446,26 +4447,76 @@ return result; } - -void LLVivoxVoiceClient::parcelChanged() -{ - if(getState() >= stateNoChannel) - { - // If the user is logged in, start a channel lookup. - LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << mCurrentRegionName << ", " << mCurrentParcelLocalID << ")" << LL_ENDL; - - std::string url = gAgent.getRegion()->getCapability("ParcelVoiceInfoRequest"); +void LLVivoxVoiceClient::doParcelInfoRequest() +{ + LLViewerRegion* region = gAgent.getRegion(); + + if (mCurrentRegion != region) + { + LL_DEBUGS("Voice") << "changed region before the region cap response arrived" << LL_ENDL; + return; + } + + S32 parcelLocalID = 0; + LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel(); + if (parcel) + { + parcelLocalID = parcel->getLocalID(); + } + + // Start a channel lookup. + + LL_DEBUGS("Voice") << "sending ParcelVoiceInfoRequest (" << region->getName() << ", " << parcelLocalID << ")" << LL_ENDL; + + std::string url = region->getCapability("ParcelVoiceInfoRequest"); + if (url.empty()) + { + LL_WARNS("Voice") << "The current region doesn't have the ParcelVoiceInfoRequest capability, voice isn't available here." << LL_ENDL; + + mRegionHasVoiceCaps = false; + setState(stateDisableCleanup); + } + else + { LLSD data; + + // TODO: have an ID with it, so if a response arrives + // late (after a more recent request, user changes regions quickly) it can be discarded LLHTTPClient::post( url, data, new LLVivoxVoiceClientCapResponder); } - else - { - // The transition to stateNoChannel needs to kick this off again. - LL_INFOS("Voice") << "not logged in yet, deferring" << LL_ENDL; - } +} + +void LLVivoxVoiceClient::parcelChanged() +{ + if (mVoiceEnabled) + { + LLViewerRegion* region = gAgent.getRegion(); + mCurrentRegion = region; + + // allow the state engine to leave stateDisabled - this is necessary + // to get connected after leaving a region without the voice capabilities + mRegionHasVoiceCaps = true; + + if (getState() >= stateNoChannel && region && !region->capabilitiesReceived()) + { + LL_INFOS("Voice") << "Region didn't receive capabilities yet - deferring" << LL_ENDL; + region->setCapabilitiesReceivedCallback(boost::bind(&LLVivoxVoiceClient::doParcelInfoRequest, this)); + } + else if (getState() >= stateNoChannel && region && region->capabilitiesReceived()) + { + doParcelInfoRequest(); + } + else + { + // The transition to stateNoChannel needs to kick this off again. + LL_INFOS("Voice") << "not logged in yet, deferring" << LL_ENDL; + } + + } + } void LLVivoxVoiceClient::switchChannel( @@ -4602,6 +4653,11 @@ mSpatialSessionCredentials = credentials; mAreaVoiceDisabled = mSpatialSessionURI.empty(); + // mRegionHasVoiceCaps is set to true here, so that also the "ParcelVoiceInfo" message allows + // the state engine to get out of stateDisabled if it was there because of the absence of the + // voice capabilities. + mRegionHasVoiceCaps = true; + LL_DEBUGS("Voice") << "got spatial channel uri: \"" << uri << "\"" << LL_ENDL; if((mAudioSession && !(mAudioSession->mIsSpatial)) || (mNextAudioSession && !(mNextAudioSession->mIsSpatial))) @@ -5211,8 +5267,11 @@ // use the status observer mVoiceEnabled = enabled; LLVoiceClientStatusObserver::EStatusType status; - - + + // setting mRegionHasVoiceCaps false keeps the voice client staying in stateDisabled + // setting true allows the lookup again. + mRegionHasVoiceCaps = enabled; + if (enabled) { LLVoiceChannel::getCurrentVoiceChannel()->activate();