summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRider Linden <rider@lindenlab.com>2015-12-04 14:27:22 -0800
committerRider Linden <rider@lindenlab.com>2015-12-04 14:27:22 -0800
commit2763bbd97519d35a43aedf279751e7b1045581dc (patch)
tree270e75d1a006b06e0987838ea1f6f0a5979698ef
parent5d897443a9e50843ac562da8972bfe2f9f8f1129 (diff)
Initial changes for Vivox/Azumarill merge. Lots of temporary code and conditional compile switches. Begin switch from statemachine to coroutine.
-rwxr-xr-xindra/llcommon/lleventcoro.cpp10
-rwxr-xr-xindra/llcommon/lleventcoro.h5
-rwxr-xr-xindra/llcommon/llevents.cpp11
-rwxr-xr-xindra/llcommon/llevents.h12
-rw-r--r--indra/llmessage/llexperiencecache.cpp5
-rwxr-xr-xindra/newview/lleventpoll.cpp4
-rwxr-xr-xindra/newview/llfloaterperms.cpp5
-rwxr-xr-xindra/newview/llviewerregion.cpp2
-rwxr-xr-xindra/newview/llvoicevivox.cpp740
-rwxr-xr-xindra/newview/llvoicevivox.h17
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();