diff options
| -rwxr-xr-x | indra/llcommon/lleventcoro.cpp | 10 | ||||
| -rwxr-xr-x | indra/llcommon/lleventcoro.h | 5 | ||||
| -rwxr-xr-x | indra/llcommon/llevents.cpp | 11 | ||||
| -rwxr-xr-x | indra/llcommon/llevents.h | 12 | ||||
| -rw-r--r-- | indra/llmessage/llexperiencecache.cpp | 5 | ||||
| -rwxr-xr-x | indra/newview/lleventpoll.cpp | 4 | ||||
| -rwxr-xr-x | indra/newview/llfloaterperms.cpp | 5 | ||||
| -rwxr-xr-x | indra/newview/llviewerregion.cpp | 2 | ||||
| -rwxr-xr-x | indra/newview/llvoicevivox.cpp | 740 | ||||
| -rwxr-xr-x | indra/newview/llvoicevivox.h | 17 | 
10 files changed, 762 insertions, 49 deletions
diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index c9bfcacedc..1c3fb4325d 100755 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -41,6 +41,8 @@  #include "llerror.h"  #include "llcoros.h" +#include "lleventfilter.h" +  namespace  { @@ -153,6 +155,14 @@ void llcoro::suspend()      suspendUntilEventOn("mainloop");  } +void llcoro::suspendUntilTimeout(float seconds) +{ +    LLEventTimeout timeout; + +    timeout.eventAfter(seconds, LLSD()); +    llcoro::suspendUntilEventOn(timeout); +} +  LLSD llcoro::postAndSuspend(const LLSD& event, const LLEventPumpOrPumpName& requestPump,                   const LLEventPumpOrPumpName& replyPump, const LLSD& replyPumpNamePath)  { diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index 6fda3d2572..bcc8cdda1d 100755 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -109,6 +109,11 @@ VoidListener<LISTENER> voidlistener(const LISTENER& listener)  void suspend();  /** + * Yield control from a coroutine for at least the specified number of seconds + */ +void suspendUntilTimeout(float seconds); + +/**   * Post specified LLSD event on the specified LLEventPump, then suspend for a   * response on specified other LLEventPump. This is more than mere   * convenience: the difference between this function and the sequence diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 1c928b3db8..bb3a137815 100755 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -132,6 +132,17 @@ LLEventPump& LLEventPumps::obtain(const std::string& name)      return *newInstance;  } +bool LLEventPumps::post(const std::string&name, const LLSD&message) +{ +    PumpMap::iterator found = mPumpMap.find(name); + +    if (found == mPumpMap.end()) +        return false; + +    return (*found).second->post(message); +} + +  void LLEventPumps::flush()  {      // Flush every known LLEventPump instance. Leave it up to each instance to diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 0cbd1da32d..8d4fa68350 100755 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -217,6 +217,18 @@ public:       * an instance without conferring @em ownership.       */      LLEventPump& obtain(const std::string& name); + +    /** +     * Find the named LLEventPump instance. If it exists post the message to it. +     * If the pump does not exist, do nothing. +     *  +     * returns the result of the LLEventPump::post. If no pump exists returns false. +     *  +     * This is syntactically similar to LLEventPumps::instance().post(name, message), +     * however if the pump does not already exist it will not be created. +     */ +    bool post(const std::string&, const LLSD&); +      /**       * Flush all known LLEventPump instances       */ diff --git a/indra/llmessage/llexperiencecache.cpp b/indra/llmessage/llexperiencecache.cpp index 92fcd38d3b..779d1d9d99 100644 --- a/indra/llmessage/llexperiencecache.cpp +++ b/indra/llmessage/llexperiencecache.cpp @@ -396,12 +396,9 @@ void LLExperienceCache::idleCoro()      const F32 ERASE_EXPIRED_TIMEOUT = 60.f; // seconds      LL_INFOS("ExperienceCache") << "Launching Experience cache idle coro." << LL_ENDL; -    LLEventTimeout timeout; -      do       { -        timeout.eventAfter(SECS_BETWEEN_REQUESTS, LLSD()); -        llcoro::suspendUntilEventOn(timeout); +        llcoro::suspendUntilTimeout(SECS_BETWEEN_REQUESTS);          if (mEraseExpiredTimer.checkExpirationAndReset(ERASE_EXPIRED_TIMEOUT))          { diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp index 72e159bcec..7178042b32 100755 --- a/indra/newview/lleventpoll.cpp +++ b/indra/newview/lleventpoll.cpp @@ -197,7 +197,6 @@ namespace Details                      // request. Calculate a timeout and wait for it to expire(sleep)                      // before trying again.  The sleep time is increased by 5 seconds                      // for each consecutive error. -                    LLEventTimeout timeout;                      ++errorCount;                      F32 waitToRetry = EVENT_POLL_ERROR_RETRY_SECONDS @@ -206,8 +205,7 @@ namespace Details                      LL_WARNS("LLEventPollImpl") << "<" << counter << "> Retrying in " << waitToRetry <<                          " seconds, error count is now " << errorCount << LL_ENDL; -                    timeout.eventAfter(waitToRetry, LLSD()); -                    llcoro::suspendUntilEventOn(timeout); +                    llcoro::suspendUntilTimeout(waitToRetry);                      if (mDone)                          break; diff --git a/indra/newview/llfloaterperms.cpp b/indra/newview/llfloaterperms.cpp index cb67787af3..b0b2770c6e 100755 --- a/indra/newview/llfloaterperms.cpp +++ b/indra/newview/llfloaterperms.cpp @@ -232,8 +232,6 @@ void LLFloaterPermsDefault::updateCapCoro(std::string url)          if (!status)          { -            LLEventTimeout timeout; -              const std::string& reason = status.toString();              // Do not display the same error more than once in a row              if (reason != previousReason) @@ -244,8 +242,7 @@ void LLFloaterPermsDefault::updateCapCoro(std::string url)                  LLNotificationsUtil::add("DefaultObjectPermissions", args);              } -            timeout.eventAfter(RETRY_TIMEOUT, LLSD()); -            llcoro::suspendUntilEventOn(timeout); +            llcoro::suspendUntilTimeout(RETRY_TIMEOUT);              if (retryCount < MAX_HTTP_RETRIES)                  continue; diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp index b0280ef3e0..a4109d5885 100755 --- a/indra/newview/llviewerregion.cpp +++ b/indra/newview/llviewerregion.cpp @@ -310,7 +310,7 @@ void LLViewerRegionImpl::requestBaseCapabilitiesCoro(U64 regionHandle)                  << "Capability '" << iter->first << "' is '" << iter->second << "'" << LL_ENDL;          } -#if 0 +#if 1          log_capabilities(mCapabilities);  #endif diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index c6c7d588eb..66d23f7919 100755 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -66,6 +66,7 @@  #include "llnotificationsutil.h"  #include "llcorehttputil.h" +#include "lleventfilter.h"  #include "stringize.h" @@ -377,7 +378,9 @@ void LLVivoxVoiceClient::connectorCreate()  	std::string loglevel = "0";  	// Transition to stateConnectorStarted when the connector handle comes back. +#if 0  	setState(stateConnectorStarting); +#endif  	std::string savedLogLevel = gSavedSettings.getString("VivoxDebugLevel"); @@ -435,6 +438,7 @@ void LLVivoxVoiceClient::userAuthorized(const std::string& user_id, const LLUUID  	mAccountName = nameFromID(agentID);  } +#if 0  void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries)  {  	LLViewerRegion *region = gAgent.getRegion(); @@ -453,7 +457,7 @@ void LLVivoxVoiceClient::requestVoiceAccountProvision(S32 retries)  		{              LLCoros::instance().launch("LLVivoxVoiceClient::voiceAccountProvisionCoro",                  boost::bind(&LLVivoxVoiceClient::voiceAccountProvisionCoro, this, url, retries)); -			setState(stateConnectorStart);		 +//			setState(stateConnectorStart);		  		}  	}  } @@ -465,20 +469,39 @@ void LLVivoxVoiceClient::voiceAccountProvisionCoro(std::string url, S32 retries)          httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceAccountProvision", httpPolicy));      LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);      LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); +    int retryCount(0); -    httpOpts->setRetries(retries); -    LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts); +    LLSD result; +         +    do  +    { +        result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts); -    LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; -    LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); +        LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +        LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); -    if (!status) -    { -        LL_WARNS("Voice") << "Unable to provision voice account." << LL_ENDL; -        giveUp(); -        return; -    } +        if (status == LLCore::HttpStatus(404)) +        { +            if (++retryCount > retries) +            { +                LL_WARNS("Voice") << "Could not access voice provision cap after " << retries << " attempts." << LL_ENDL; +                giveUp(); +                return; +            } +            LL_WARNS("Voice") << "Provision CAP 404.  Retrying in 1.0" << LL_ENDL; +            llcoro::suspendUntilTimeout(1.0); + +            continue; +        } +        else if (!status) +        { +            LL_WARNS("Voice") << "Unable to provision voice account." << LL_ENDL; +            giveUp(); +            return; +        } +        break; +    } while (true);      std::string voice_sip_uri_hostname;      std::string voice_account_server_uri; @@ -492,11 +515,12 @@ void LLVivoxVoiceClient::voiceAccountProvisionCoro(std::string url, S32 retries)      if (result.has("voice_account_server_name"))          voice_account_server_uri = result["voice_account_server_name"].asString(); -    login(result["username"].asString(), result["password"].asString(), +    setLoginInfo(result["username"].asString(), result["password"].asString(),          voice_sip_uri_hostname, voice_account_server_uri);  } +#endif -void LLVivoxVoiceClient::login( +void LLVivoxVoiceClient::setLoginInfo(  	const std::string& account_name,  	const std::string& password,  	const std::string& voice_sip_uri_hostname, @@ -701,10 +725,24 @@ void LLVivoxVoiceClient::stateMachine()  		case stateDisabled:  			if(mTuningMode || ((mVoiceEnabled || !mIsInitialized) && !mAccountName.empty()))  			{ +#if 1 +                LLCoros::instance().launch("LLVivoxVoiceClient::startAndConnectSession", +                    boost::bind(&LLVivoxVoiceClient::startAndConnectSession, this)); +#else  				setState(stateStart); +#endif  			}  		break; -		 + +//-------------------------------------------------------------------------- +#if 1 +        case stateStart: +        case stateDaemonLaunched: +        case stateConnecting: +        case stateConnected: +            // moved to coroutine LLVivoxVoiceClient::startAndLaunchDaemon +            break; +#else  		//MARK: stateStart  		case stateStart:  			if(gSavedSettings.getBOOL("CmdLineDisableVoice")) @@ -861,30 +899,47 @@ void LLVivoxVoiceClient::stateMachine()  			setState(stateIdle);  		break; +#endif +//--------------------------------------------------------------------------  		//MARK: stateIdle  		case stateIdle:  			// This is the idle state where we're connected to the daemon but haven't set up a connector yet.  			if(mTuningMode)  			{ -				mTuningExitState = stateIdle; -				setState(stateMicTuningStart); -			} +#if 1 +                LLCoros::instance().launch("LLVivoxVoiceClient::performMicTuning", +                    boost::bind(&LLVivoxVoiceClient::performMicTuning, this, stateIdle)); +#else +                mTuningExitState = stateIdle; +                setState(stateMicTuningStart); +#endif +            }  			else if(!mVoiceEnabled && mIsInitialized)  			{  				// We never started up the connector.  This will shut down the daemon.  				setState(stateConnectorStopped);  			} +#if 0  			else if(!mAccountName.empty())  			{  				if ( mAccountPassword.empty() )  				{ -					requestVoiceAccountProvision(); +					requestVoiceAccountProvision(5);  				}  			} +#endif  		break; -		//MARK: stateMicTuningStart +//-------------------------------------------------------------------------- +#if 1 +        case stateMicTuningStart: +        case stateMicTuningRunning: +        case stateMicTuningStop: +            // moved to coroutine LLVivoxVoiceClient::performMicTuning +            break; +#else +        //MARK: stateMicTuningStart  		case stateMicTuningStart:  			if(mUpdateTimer.hasExpired())  			{ @@ -985,6 +1040,8 @@ void LLVivoxVoiceClient::stateMachine()  		}  		break; +#endif +//--------------------------------------------------------------------------  		//MARK: stateCaptureBufferPaused  		case stateCaptureBufferPaused: @@ -1075,7 +1132,16 @@ void LLVivoxVoiceClient::stateMachine()  			}  		break; -			//MARK: stateConnectorStart +//------------------------------------------------------------------------- +#if 1 +        case stateConnectorStart: +        case stateConnectorStarting:	 +        case stateConnectorStarted:	 +            // moved to establishVoiceConnection +            break; + +#else +		//MARK: stateConnectorStart  		case stateConnectorStart:  			if(!mVoiceEnabled && mIsInitialized)  			{ @@ -1106,7 +1172,18 @@ void LLVivoxVoiceClient::stateMachine()  				setState(stateNeedsLogin);  			}  		break; -				 +#endif +//------------------------------------------------------------------------- + +#if 1 +        case stateLoginRetry: +        case stateLoginRetryWait: +        case stateNeedsLogin: +        case stateLoggingIn: +        case stateLoggedIn: +            // moved to loginToVivox +            break; +#else  		//MARK: stateLoginRetry  		case stateLoginRetry:  			if(mLoginRetryCount == 0) @@ -1194,7 +1271,14 @@ void LLVivoxVoiceClient::stateMachine()  			sendLocalAudioUpdates();  		break; +#endif +#if 1 +        case stateVoiceFontsWait:		// Await voice font list +        case stateVoiceFontsReceived:	// Voice font list received +            // moved to retrieveVoiceFonts +            break; +#else  		//MARK: stateVoiceFontsWait  		case stateVoiceFontsWait:		// Await voice font list  			// accountGetSessionFontsResponse() will transition from here to @@ -1207,15 +1291,17 @@ void LLVivoxVoiceClient::stateMachine()  			// Set up the timer to check for expiring voice fonts  			mVoiceFontExpiryTimer.start();  			mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL); -  #if USE_SESSION_GROUPS			 -			// create the main session group -			setState(stateCreatingSessionGroup); -			sessionGroupCreateSendMessage(); +            // create the main session group +            setState(stateCreatingSessionGroup); +            sessionGroupCreateSendMessage();  #else -			setState(stateNoChannel);				 +            setState(stateNoChannel);				  #endif -		break; +            break; + +#endif +  		//MARK: stateCreatingSessionGroup  		case stateCreatingSessionGroup: @@ -1260,8 +1346,13 @@ void LLVivoxVoiceClient::stateMachine()  			}  			else if(mTuningMode)  			{ -				mTuningExitState = stateNoChannel; -				setState(stateMicTuningStart); +#if 1 +                LLCoros::instance().launch("LLVivoxVoiceClient::performMicTuning", +                    boost::bind(&LLVivoxVoiceClient::performMicTuning, this, stateNoChannel)); +#else +                mTuningExitState = stateNoChannel; +                setState(stateMicTuningStart); +#endif  			}  			else if(mCaptureBufferMode)  			{ @@ -1528,7 +1619,8 @@ void LLVivoxVoiceClient::stateMachine()  			}  		break; -		//MARK: stateConnectorStopping +//------------------------------------------------------------------------- +        //MARK: stateConnectorStopping  		case stateConnectorStopping:	// waiting for connector stop  			// The handler for the Connector.InitiateShutdown response will transition from here to stateConnectorStopped.  			mShutdownComplete = true; @@ -1539,7 +1631,8 @@ void LLVivoxVoiceClient::stateMachine()  			setState(stateDisableCleanup);  		break; -		//MARK: stateConnectorFailed +//------------------------------------------------------------------------- +        //MARK: stateConnectorFailed  		case stateConnectorFailed:  			setState(stateConnectorFailedWaiting);  		break; @@ -1550,6 +1643,7 @@ void LLVivoxVoiceClient::stateMachine()  				setState(stateDisableCleanup);  			}  		break; +//-------------------------------------------------------------------------  		//MARK: stateLoginFailed  		case stateLoginFailed: @@ -1609,6 +1703,537 @@ void LLVivoxVoiceClient::stateMachine()  	}  } +//========================================================================= +// the following are methods to support the coroutine implementation of the  +// voice connection and processing.  They should only be called in the context  +// of a coroutine. +//  +// calls to setState() in these are historical and used because some of the other +// query routines will ask what state the state machine is in. +//  + +bool LLVivoxVoiceClient::startAndConnectSession() +{ +    if (!startAndLaunchDaemon()) +    { +        setState(stateJail); +        return false; +    } + +    if (!provisionVoiceAccount()) +    { +        giveUp(); +        return false; +    } + +    if (!establishVoiceConnection()) +    { +        if (getState() != stateConnectorFailed) +        { +            setState(stateLoggedOut); +        } +        giveUp(); +        return false; +    } + + +    if (!loginToVivox()) +    { +        setState(stateLoginFailed); +        return false; +    } + +    if (LLVoiceClient::instance().getVoiceEffectEnabled()) +    { +        retrieveVoiceFonts(); + +        // Request the set of available voice fonts. +        refreshVoiceEffectLists(true); +    } +    else +    { +        // If voice effects are disabled, pretend we've received them and carry on. +        setState(stateNoChannel); +    } + +#if USE_SESSION_GROUPS			 +    // create the main session group +    setState(stateCreatingSessionGroup); +    sessionGroupCreateSendMessage(); +#else +    setState(stateNoChannel); +#endif + +    return true; +} + +bool LLVivoxVoiceClient::startAndLaunchDaemon() +{ +    //--------------------------------------------------------------------- +    setState(stateStart); + +    if (gSavedSettings.getBOOL("CmdLineDisableVoice")) +    { +        // Voice is locked out, we must not launch the vivox daemon. +        setState(stateJail); +        return false; +    } + +    if (!isGatewayRunning() && gSavedSettings.getBOOL("EnableVoiceChat")) +    { +#ifndef VIVOXDAEMON_REMOTEHOST +        // Launch the voice daemon + +        // *FIX:Mani - Using the executable dir instead  +        // of mAppRODataDir, the working directory from which the app +        // is launched. +        //std::string exe_path = gDirUtilp->getAppRODataDir(); +        std::string exe_path = gDirUtilp->getExecutableDir(); +        exe_path += gDirUtilp->getDirDelimiter(); +#if LL_WINDOWS +        exe_path += "SLVoice.exe"; +#elif LL_DARWIN +        exe_path += "../Resources/SLVoice"; +#else +        exe_path += "SLVoice"; +#endif +        // See if the vivox executable exists +        llstat s; +        if (!LLFile::stat(exe_path, &s)) +        { +            // vivox executable exists.  Build the command line and launch the daemon. +            LLProcess::Params params; +            params.executable = exe_path; + +            std::string loglevel = gSavedSettings.getString("VivoxDebugLevel"); +            std::string shutdown_timeout = gSavedSettings.getString("VivoxShutdownTimeout"); +            if (loglevel.empty()) +            { +                loglevel = "-1";	// turn logging off completely, was 0 for error level logging. +            } + +            params.args.add("-ll"); +            params.args.add(loglevel); + +            std::string log_folder = gSavedSettings.getString("VivoxLogDirectory"); + +            if (log_folder.empty()) +            { +                log_folder = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ""); +            } + +            params.args.add("-lf"); +            params.args.add(log_folder); + +            if (!shutdown_timeout.empty()) +            { +                params.args.add("-st"); +                params.args.add(shutdown_timeout); +            } +            params.cwd = gDirUtilp->getAppRODataDir(); +            sGatewayPtr = LLProcess::create(params); + +            mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost").c_str(), gSavedSettings.getU32("VivoxVoicePort")); +        } +        else +        { +            LL_INFOS("Voice") << exe_path << " not found." << LL_ENDL; +            return false; +        } +#else +        // SLIM SDK: port changed from 44124 to 44125. +        // We can connect to a client gateway running on another host.  This is useful for testing. +        // To do this, launch the gateway on a nearby host like this: +        //  vivox-gw.exe -p tcp -i 0.0.0.0:44125 +        // and put that host's IP address here. +        mDaemonHost = LLHost(gSavedSettings.getString("VivoxVoiceHost"), gSavedSettings.getU32("VivoxVoicePort")); +#endif + +        mUpdateTimer.start(); +        mUpdateTimer.setTimerExpirySec(CONNECT_THROTTLE_SECONDS); + +        // Dirty the states we'll need to sync with the daemon when it comes up. +        mMuteMicDirty = true; +        mMicVolumeDirty = true; +        mSpeakerVolumeDirty = true; +        mSpeakerMuteDirty = true; +        // These only need to be set if they're not default (i.e. empty string). +        mCaptureDeviceDirty = !mCaptureDevice.empty(); +        mRenderDeviceDirty = !mRenderDevice.empty(); + +        mMainSessionGroupHandle.clear(); +    } + +    //--------------------------------------------------------------------- +    llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); +    setState(stateDaemonLaunched); + +    LL_DEBUGS("Voice") << "Connecting to vivox daemon:" << mDaemonHost << LL_ENDL; + +    int connectAttempt = 0; + +    while (!mConnected) +    { +        ++connectAttempt; +        LL_DEBUGS("Voice") << "Connecting to vivox daemon:" << mDaemonHost << " (#" << connectAttempt << ")" << LL_ENDL; +        closeSocket(); +        if (!mSocket) +        { +            mSocket = LLSocket::create(gAPRPoolp, LLSocket::STREAM_TCP); +        } + +        mConnected = mSocket->blockingConnect(mDaemonHost); +    } + +    //--------------------------------------------------------------------- +    llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); +    setState(stateConnecting); + + +    while (!mPump) +    {   // Can't do this until we have the pump available. +        llcoro::suspend(); +    } + +     +    // MBW -- Note to self: pumps and pipes examples in +    //  indra/test/io.cpp +    //  indra/test/llpipeutil.{cpp|h} + +    // Attach the pumps and pipes + +    LLPumpIO::chain_t readChain; + +    readChain.push_back(LLIOPipe::ptr_t(new LLIOSocketReader(mSocket))); +    readChain.push_back(LLIOPipe::ptr_t(new LLVivoxProtocolParser())); + +    mPump->addChain(readChain, NEVER_CHAIN_EXPIRY_SECS); + +    //--------------------------------------------------------------------- +    llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); +    setState(stateConnected); + +    // Initial devices query +    getCaptureDevicesSendMessage(); +    getRenderDevicesSendMessage(); + +    mLoginRetryCount = 0; + +    setState(stateIdle); + +    return true; +} + +bool LLVivoxVoiceClient::provisionVoiceAccount() +{ + +    while (!gAgent.getRegion()) +    { +        // *TODO* Set up a call back on agent that sends a message to a pump we can use to wake up. +        llcoro::suspend(); +    } + +    LLViewerRegion *region = gAgent.getRegion(); + +    while (!region->capabilitiesReceived()) +    { +        // *TODO* Pump a message for wake up. +        llcoro::suspend(); +    } + +    std::string url = region->getCapability("ProvisionVoiceAccountRequest"); + +    LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); +    LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t +        httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("voiceAccountProvision", httpPolicy)); +    LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); +    LLCore::HttpOptions::ptr_t httpOpts = LLCore::HttpOptions::ptr_t(new LLCore::HttpOptions); +    int retryCount(0); + +    LLSD result; + +    do +    { +        result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts); + +        LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; +        LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + +        if (status == LLCore::HttpStatus(404)) +        { +            if (++retryCount > 5) +            { +                LL_WARNS("Voice") << "Could not access voice provision cap after 5 attempts." << LL_ENDL; +                return false; +            } +            LL_WARNS("Voice") << "Provision CAP 404.  Retrying in 1.0" << LL_ENDL; +            llcoro::suspendUntilTimeout(1.0); + +            continue; +        } +        else if (!status) +        { +            LL_WARNS("Voice") << "Unable to provision voice account." << LL_ENDL; +            return false; +        } +        break; +    } while (true); + +    std::string voiceSipUriHostname; +    std::string voiceAccountServerUri; +    std::string voiceUserName = result["username"].asString(); +    std::string voicePassword = result["password"].asString(); + +    //LL_DEBUGS("Voice") << "ProvisionVoiceAccountRequest response:" << dumpResponse() << LL_ENDL; + +    if (result.has("voice_sip_uri_hostname")) +        voiceSipUriHostname = result["voice_sip_uri_hostname"].asString(); + +    // this key is actually misnamed -- it will be an entire URI, not just a hostname. +    if (result.has("voice_account_server_name")) +        voiceAccountServerUri = result["voice_account_server_name"].asString(); + +    setLoginInfo(voiceUserName, voicePassword, voiceSipUriHostname, voiceAccountServerUri); + +    return true; +} + + +bool LLVivoxVoiceClient::establishVoiceConnection() +{ +    LLEventPump &voiceConnectPump = LLEventPumps::instance().obtain("vivoxClientPump"); + +    if (!mVoiceEnabled && mIsInitialized) +        return false; + +    setState(stateConnectorStart); + +    connectorCreate(); + +    setState(stateConnectorStarting); + +    LLSD result; +    do +    { +        result = llcoro::suspendUntilEventOn(voiceConnectPump); +    }  +    while (!result.has("connector")); + +    if (!result["connector"]) +    { + +        setState(stateConnectorFailed); +        return false; +    } + +    setState(stateConnectorStarted); +    if (!mVoiceEnabled && mIsInitialized) +        return false; + +    return true; +} + +bool LLVivoxVoiceClient::loginToVivox() +{ +    int loginRetryCount(0); +    LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); + +    do  +    { +        setState(stateLoggingIn); +        loginSendMessage(); + +        LLSD result; +        do +        { +            result = llcoro::suspendUntilEventOn(voicePump); +        } while (!result.has("login")); + +        if (result["login"]) +            break; + +        if (!loginRetryCount) +        {   // on first retry notify user +            notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGIN_RETRY); +        } + +        if ((++loginRetryCount > MAX_LOGIN_RETRIES) || (!result["login_retry"]))         +        { +            LL_WARNS("Voice") << "too many login retries, giving up." << LL_ENDL; +            LLSD args; +            std::stringstream errs; +            errs << mVoiceAccountServerURI << "\n:UDP: 3478, 3479, 5060, 5062, 12000-17000"; +            args["HOSTID"] = errs.str(); +            mTerminateDaemon = true; +            if (LLGridManager::getInstance()->isSystemGrid()) +            { +                LLNotificationsUtil::add("NoVoiceConnect", args); +            } +            else +            { +                LLNotificationsUtil::add("NoVoiceConnect-GIAB", args); +            } + +            setState(stateLoginFailed); +            return false; +        } + +        LL_INFOS("Voice") << "will retry login in " << LOGIN_RETRY_SECONDS << " seconds." << LL_ENDL; +        setState(stateLoginRetryWait); +        llcoro::suspendUntilTimeout(LOGIN_RETRY_SECONDS); +    } while (true); + +    setState(stateLoggedIn); +    notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_LOGGED_IN); + + +    // Set up the mute list observer if it hasn't been set up already. +    if ((!sMuteListListener_listening)) +    { +        LLMuteList::getInstance()->addObserver(&mutelist_listener); +        sMuteListListener_listening = true; +    } + +    // Set the initial state of mic mute, local speaker volume, etc. +    sendLocalAudioUpdates(); + +    return true; +} + +bool LLVivoxVoiceClient::retrieveVoiceFonts() +{ +    LLEventPump &voicePump = LLEventPumps::instance().obtain("vivoxClientPump"); + +    // Request the set of available voice fonts. +    setState(stateVoiceFontsWait); +    refreshVoiceEffectLists(true); + +    LLSD result; +    do  +    { +        result = llcoro::suspendUntilEventOn(voicePump); + +        if (result.has("voice_fonts")) +            break; +    } while (true); + + +    mVoiceFontExpiryTimer.start(); +    mVoiceFontExpiryTimer.setTimerExpirySec(VOICE_FONT_EXPIRY_INTERVAL); + +    setState(stateNoChannel); + +    return result["voice_fonts"].asBoolean(); +} + +bool LLVivoxVoiceClient::performMicTuning(LLVivoxVoiceClient::state exitState) +{ +    //--------------------------------------------------------------------- +    setState(stateMicTuningStart); + +    while (!mUpdateTimer.hasExpired()) +    {   // do not start mic tuning before the update timer has expired. +        llcoro::suspend(); +    } + +    while (mTuningMode) +    { + +        if (mCaptureDeviceDirty || mRenderDeviceDirty) +        { +            // These can't be changed while in tuning mode.  Set them before starting. +            std::ostringstream stream; + +            buildSetCaptureDevice(stream); +            buildSetRenderDevice(stream); + +            if (!stream.str().empty()) +            { +                writeString(stream.str()); +            } + +            llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); +        } + +        // loop mic back to render device. +        //setMuteMic(0);						// make sure the mic is not muted +        std::ostringstream stream; + +        stream << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Connector.MuteLocalMic.1\">" +            << "<ConnectorHandle>" << mConnectorHandle << "</ConnectorHandle>" +            << "<Value>false</Value>" +            << "</Request>\n\n\n"; + +        // Dirty the mute mic state so that it will get reset when we finishing previewing +        mMuteMicDirty = true; +        mTuningSpeakerVolumeDirty = true; + +        writeString(stream.str()); +        tuningCaptureStartSendMessage(1);  // 1-loop, zero, don't loop + +        //--------------------------------------------------------------------- +        setState(stateMicTuningRunning); +        llcoro::suspend(); + +        while (mTuningMode && !mCaptureDeviceDirty && !mRenderDeviceDirty) +        { +            // process mic/speaker volume changes +            if (mTuningMicVolumeDirty || mTuningSpeakerVolumeDirty) +            { +                std::ostringstream stream; + +                if (mTuningMicVolumeDirty) +                { +                    LL_INFOS("Voice") << "setting tuning mic level to " << mTuningMicVolume << LL_ENDL; +                    stream +                        << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetMicLevel.1\">" +                        << "<Level>" << mTuningMicVolume << "</Level>" +                        << "</Request>\n\n\n"; +                } + +                if (mTuningSpeakerVolumeDirty) +                { +                    stream +                        << "<Request requestId=\"" << mCommandCookie++ << "\" action=\"Aux.SetSpeakerLevel.1\">" +                        << "<Level>" << mTuningSpeakerVolume << "</Level>" +                        << "</Request>\n\n\n"; +                } + +                mTuningMicVolumeDirty = false; +                mTuningSpeakerVolumeDirty = false; + +                if (!stream.str().empty()) +                { +                    writeString(stream.str()); +                } +            } +            llcoro::suspend(); +        } + +        //--------------------------------------------------------------------- +        setState(stateMicTuningStop); + +        // transition out of mic tuning +        tuningCaptureStopSendMessage(); +        if (mCaptureDeviceDirty || mRenderDeviceDirty) +        { +            llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS); +        } +    } + +    setState(mTuningExitState); + +    // if we exited just to change devices, this will keep us from re-entering too fast. +    mUpdateTimer.start(); +    mUpdateTimer.setTimerExpirySec(UPDATE_THROTTLE_SECONDS); + +    //--------------------------------------------------------------------- +    setState(exitState); +    return true; +} + +//========================================================================= +  void LLVivoxVoiceClient::closeSocket(void)  {  	mSocket.reset(); @@ -2645,10 +3270,16 @@ void LLVivoxVoiceClient::sendLocalAudioUpdates()  void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &statusString, std::string &connectorHandle, std::string &versionID)  {	 +#if 1 +    LLSD result = LLSD::emptyMap(); +#endif +  	if(statusCode != 0)  	{  		LL_WARNS("Voice") << "Connector.Create response failure: " << statusString << LL_ENDL; +#if 0  		setState(stateConnectorFailed); +#endif  		LLSD args;  		std::stringstream errs;  		errs << mVoiceAccountServerURI << "\n:UDP: 3478, 3479, 5060, 5062, 12000-17000"; @@ -2662,6 +3293,10 @@ void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &st  		{  			LLNotificationsUtil::add("NoVoiceConnect-GIAB", args);	  		} + +#if 1 +        result["connector"] = LLSD::Boolean(false); +#endif  	}  	else  	{ @@ -2670,16 +3305,28 @@ void LLVivoxVoiceClient::connectorCreateResponse(int statusCode, std::string &st  		mVoiceVersion.serverVersion = versionID;  		mConnectorHandle = connectorHandle;  		mTerminateDaemon = false; +#if 1 +        result["connector"] = LLSD::Boolean(true); +#else  		if(getState() == stateConnectorStarting)  		{  			setState(stateConnectorStarted);  		} +#endif  	} + +#if 1 +    LLEventPumps::instance().post("vivoxClientPump", result); +#endif  }  void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString, std::string &accountHandle, int numberOfAliases)  {  -	LL_DEBUGS("Voice") << "Account.Login response (" << statusCode << "): " << statusString << LL_ENDL; +#if 1 +    LLSD result = LLSD::emptyMap(); +#endif + +    LL_DEBUGS("Voice") << "Account.Login response (" << statusCode << "): " << statusString << LL_ENDL;  	// Status code of 20200 means "bad password".  We may want to special-case that at some point. @@ -2687,24 +3334,40 @@ void LLVivoxVoiceClient::loginResponse(int statusCode, std::string &statusString  	{  		// Login failure which is probably caused by the delay after a user's password being updated.  		LL_INFOS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; +#if 1 +        result["login"] = LLSD::Boolean(false); +        result["login_retry"] = LLSD::Boolean(true); +#else  		setState(stateLoginRetry); +#endif  	}  	else if(statusCode != 0)  	{  		LL_WARNS("Voice") << "Account.Login response failure (" << statusCode << "): " << statusString << LL_ENDL; -		setState(stateLoginFailed); +#if 1 +        result["login"] = LLSD::Boolean(false); +        result["login_retry"] = LLSD::Boolean(false); +#else +        setState(stateLoginFailed); +#endif  	}  	else  	{  		// Login succeeded, move forward.  		mAccountHandle = accountHandle;  		mNumberOfAliases = numberOfAliases; +        result["login"] = LLSD::Boolean(true);  		// This needs to wait until the AccountLoginStateChangeEvent is received.  //		if(getState() == stateLoggingIn)  //		{  //			setState(stateLoggedIn);  //		}  	} + +#if 1 +    LLEventPumps::instance().post("vivoxClientPump", result); +#endif +  }  void LLVivoxVoiceClient::sessionCreateResponse(std::string &requestId, int statusCode, std::string &statusString, std::string &sessionHandle) @@ -2910,7 +3573,7 @@ void LLVivoxVoiceClient::sessionGroupAddedEvent(std::string &sessionGroupHandle)  {  	LL_DEBUGS("Voice") << "handle " << sessionGroupHandle << LL_ENDL; -#if USE_SESSION_GROUPS +#if  USE_SESSION_GROUPS  	if(mMainSessionGroupHandle.empty())  	{  		// This is the first (i.e. "main") session group.  Save its handle. @@ -5970,11 +6633,20 @@ void LLVivoxVoiceClient::sessionSetVoiceFontSendMessage(sessionState *session)  void LLVivoxVoiceClient::accountGetSessionFontsResponse(int statusCode, const std::string &statusString)  { +#if 1 +    LLSD result = LLSD::emptyMap(); + +    result["voice_fonts"] = LLSD::Boolean(true); + +    LLEventPumps::instance().post("vivoxClientPump", result); + +#else  	// Voice font list entries were updated via addVoiceFont() during parsing.  	if(getState() == stateVoiceFontsWait)  	{  		setState(stateVoiceFontsReceived);  	} +#endif  	notifyVoiceFontObservers();  	mVoiceFontsReceived = true; diff --git a/indra/newview/llvoicevivox.h b/indra/newview/llvoicevivox.h index 2f671306b1..5c9a1b73a3 100755 --- a/indra/newview/llvoicevivox.h +++ b/indra/newview/llvoicevivox.h @@ -433,8 +433,8 @@ protected:  	void connectorShutdown();	  	void closeSocket(void);	 -	void requestVoiceAccountProvision(S32 retries = 3); -	void login( +//	void requestVoiceAccountProvision(S32 retries = 3); +	void setLoginInfo(  			   const std::string& account_name,  			   const std::string& password,  			   const std::string& voice_sip_uri_hostname, @@ -639,11 +639,22 @@ protected:  private: -    void voiceAccountProvisionCoro(std::string url, S32 retries); +//  void voiceAccountProvisionCoro(std::string url, S32 retries);      void parcelVoiceInfoRequestCoro(std::string url);  	LLVoiceVersionInfo mVoiceVersion; +    // Coroutine support methods +    bool startAndConnectSession(); + +    bool startAndLaunchDaemon(); +    bool provisionVoiceAccount(); +    bool establishVoiceConnection(); +    bool loginToVivox(); +    bool retrieveVoiceFonts(); + +    bool performMicTuning(state exitState); +  	/// Clean up objects created during a voice session.  	void cleanUp();  | 
