summaryrefslogtreecommitdiff
path: root/indra/newview/llvoicevivox.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview/llvoicevivox.cpp')
-rw-r--r--indra/newview/llvoicevivox.cpp280
1 files changed, 192 insertions, 88 deletions
diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp
index 4d2eac8c09..4aa6f2c6b2 100644
--- a/indra/newview/llvoicevivox.cpp
+++ b/indra/newview/llvoicevivox.cpp
@@ -658,120 +658,205 @@ void LLVivoxVoiceClient::idle(void* user_data)
// of a coroutine.
//
//
+
+typedef enum e_voice_control_coro_state
+{
+ VOICE_STATE_ERROR = -1,
+ VOICE_STATE_DONE = 0,
+ VOICE_STATE_TP_WAIT, // entry point
+ VOICE_STATE_START_DAEMON,
+ VOICE_STATE_PROVISION_ACCOUNT,
+ VOICE_STATE_START_SESSION,
+ VOICE_STATE_SESSION_RETRY,
+ VOICE_STATE_SESSION_ESTABLISHED,
+ VOICE_STATE_WAIT_FOR_CHANNEL,
+ VOICE_STATE_DISCONNECT,
+ VOICE_STATE_WAIT_FOR_EXIT,
+} EVoiceControlCoroState;
+
void LLVivoxVoiceClient::voiceControlCoro()
{
+ int state = 0;
+ try
+ {
+ // state is passed as a reference instead of being
+ // a member due to unresolved issues with coroutine
+ // surviving longer than LLVivoxVoiceClient
+ voiceControlStateMachine(state);
+ }
+ catch (const LLContinueError&)
+ {
+ LOG_UNHANDLED_EXCEPTION("LLVivoxVoiceClient");
+ }
+ catch (...)
+ {
+ // Ideally for Windows need to log SEH exception instead or to set SEH
+ // handlers but bugsplat shows local variables for windows, which should
+ // be enough
+ LL_WARNS("Voice") << "voiceControlStateMachine crashed in state " << state << LL_ENDL;
+ throw;
+ }
+}
+
+void LLVivoxVoiceClient::voiceControlStateMachine(S32 &coro_state)
+{
LL_DEBUGS("Voice") << "starting" << LL_ENDL;
mIsCoroutineActive = true;
LLCoros::set_consuming(true);
U32 retry = 0;
- while (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE && !sShuttingDown)
- {
- LL_DEBUGS("Voice") << "Suspending voiceControlCoro() momentarily for teleport. Tuning: " << mTuningMode << ". Relog: " << mRelogRequested << LL_ENDL;
- llcoro::suspendUntilTimeout(1.0);
- }
-
- if (sShuttingDown)
- {
- mIsCoroutineActive = false;
- return;
- }
+ coro_state = VOICE_STATE_TP_WAIT;
do
{
- bool success = startAndConnectSession();
- if (success)
+ if (sShuttingDown)
{
- // enable/disable the automatic VAD and explicitly set the initial values of
- // the VAD variables ourselves when it is off - see SL-15072 for more details
- // note: we set the other parameters too even if the auto VAD is on which is ok
- unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto");
- unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover");
- unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor");
- unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity");
- setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity);
-
- // watch for changes to the VAD settings via Debug Settings UI and act on them accordingly
- gSavedSettings.getControl("VivoxVadAuto")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
- gSavedSettings.getControl("VivoxVadHangover")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
- gSavedSettings.getControl("VivoxVadNoiseFloor")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
- gSavedSettings.getControl("VivoxVadSensitivity")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
+ // Vivox singleton performed the exit, logged out,
+ // cleaned sockets, gateway and no longer cares
+ // about state of coroutine, so just stop
+ return;
+ }
- if (mTuningMode && !sShuttingDown)
+ switch (coro_state)
+ {
+ case VOICE_STATE_TP_WAIT:
+ // starting point for voice
+ if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
{
- performMicTuning();
+ LL_DEBUGS("Voice") << "Suspending voiceControlCoro() momentarily for teleport. Tuning: " << mTuningMode << ". Relog: " << mRelogRequested << LL_ENDL;
+ llcoro::suspendUntilTimeout(1.0);
}
+ else
+ {
+ coro_state = VOICE_STATE_START_DAEMON;
+ }
+ break;
- if (!sShuttingDown)
+ case VOICE_STATE_START_DAEMON:
+ LL_DEBUGS("Voice") << "Launching daemon" << LL_ENDL;
+ LLVoiceVivoxStats::getInstance()->reset();
+ if (startAndLaunchDaemon())
{
- waitForChannel(); // this doesn't normally return unless relog is needed or shutting down
+ coro_state = VOICE_STATE_PROVISION_ACCOUNT;
}
-
- LL_DEBUGS("Voice") << "lost channel RelogRequested=" << mRelogRequested << LL_ENDL;
- endAndDisconnectSession();
- retry = 0;
- }
-
- // if we hit this and mRelogRequested is true, that indicates
- // that we attempted to relog into Vivox and were rejected.
- // Rather than just quit out of voice, we will tear it down (above)
- // and then reconstruct the voice connecion from scratch.
- LL_DEBUGS("Voice")
- << "disconnected"
- << " RelogRequested=" << mRelogRequested
- << LL_ENDL;
- if (mRelogRequested && !sShuttingDown)
- {
- if (!success)
+ else
+ {
+ coro_state = VOICE_STATE_SESSION_RETRY;
+ }
+ break;
+
+ case VOICE_STATE_PROVISION_ACCOUNT:
+ if (provisionVoiceAccount())
+ {
+ coro_state = VOICE_STATE_START_SESSION;
+ }
+ else
+ {
+ coro_state = VOICE_STATE_SESSION_RETRY;
+ }
+ break;
+
+ case VOICE_STATE_START_SESSION:
+ if (establishVoiceConnection())
+ {
+ coro_state = VOICE_STATE_SESSION_ESTABLISHED;
+ }
+ else
+ {
+ coro_state = VOICE_STATE_SESSION_RETRY;
+ }
+ break;
+
+ case VOICE_STATE_SESSION_RETRY:
+ giveUp(); // cleans sockets and session
+ if (mRelogRequested)
{
// We failed to connect, give it a bit time before retrying.
retry++;
- F32 delay = llmin(5.f * (F32)retry, 60.f);
- llcoro::suspendUntilTimeout(delay);
- LL_INFOS("Voice") << "Voice failed to establish session after " << retry << " tries. Will attempt to reconnect." << LL_ENDL;
+ F32 full_delay = llmin(5.f * (F32)retry, 60.f);
+ F32 current_delay = 0.f;
+ LL_INFOS("Voice") << "Voice failed to establish session after " << retry
+ << " tries. Will attempt to reconnect in " << full_delay
+ << " seconds" << LL_ENDL;
+ while (current_delay < full_delay && !sShuttingDown)
+ {
+ // Assuming that a second has passed is not accurate,
+ // but we don't need accurancy here, just to make sure
+ // that some time passed and not to outlive voice itself
+ current_delay++;
+ llcoro::suspendUntilTimeout(1.f);
+ }
+ coro_state = VOICE_STATE_WAIT_FOR_EXIT;
}
else
{
- LL_INFOS("Voice") << "will attempt to reconnect to voice" << LL_ENDL;
+ coro_state = VOICE_STATE_DONE;
}
+ break;
- while (isGatewayRunning() || (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE && !sShuttingDown))
+ case VOICE_STATE_SESSION_ESTABLISHED:
{
- LL_INFOS("Voice") << "waiting for SLVoice to exit" << LL_ENDL;
- llcoro::suspendUntilTimeout(1.0);
+ // enable/disable the automatic VAD and explicitly set the initial values of
+ // the VAD variables ourselves when it is off - see SL-15072 for more details
+ // note: we set the other parameters too even if the auto VAD is on which is ok
+ unsigned int vad_auto = gSavedSettings.getU32("VivoxVadAuto");
+ unsigned int vad_hangover = gSavedSettings.getU32("VivoxVadHangover");
+ unsigned int vad_noise_floor = gSavedSettings.getU32("VivoxVadNoiseFloor");
+ unsigned int vad_sensitivity = gSavedSettings.getU32("VivoxVadSensitivity");
+ setupVADParams(vad_auto, vad_hangover, vad_noise_floor, vad_sensitivity);
+
+ // watch for changes to the VAD settings via Debug Settings UI and act on them accordingly
+ gSavedSettings.getControl("VivoxVadAuto")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
+ gSavedSettings.getControl("VivoxVadHangover")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
+ gSavedSettings.getControl("VivoxVadNoiseFloor")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
+ gSavedSettings.getControl("VivoxVadSensitivity")->getSignal()->connect(boost::bind(&LLVivoxVoiceClient::onVADSettingsChange, this));
+
+ if (mTuningMode)
+ {
+ performMicTuning();
+ }
+
+ coro_state = VOICE_STATE_WAIT_FOR_CHANNEL;
}
- }
- }
- while (mVoiceEnabled && mRelogRequested && !sShuttingDown);
- mIsCoroutineActive = false;
- LL_INFOS("Voice") << "exiting" << LL_ENDL;
-}
+ break;
-bool LLVivoxVoiceClient::startAndConnectSession()
-{
- bool ok = false;
- LL_DEBUGS("Voice") << LL_ENDL;
+ case VOICE_STATE_WAIT_FOR_CHANNEL:
+ waitForChannel(); // todo: split into more states like login/fonts
+ coro_state = VOICE_STATE_DISCONNECT;
+ break;
- LLVoiceVivoxStats::getInstance()->reset();
+ case VOICE_STATE_DISCONNECT:
+ LL_DEBUGS("Voice") << "lost channel RelogRequested=" << mRelogRequested << LL_ENDL;
+ endAndDisconnectSession();
+ retry = 0; // Connected without issues
+ coro_state = VOICE_STATE_WAIT_FOR_EXIT;
+ break;
- if (startAndLaunchDaemon())
- {
- if (provisionVoiceAccount())
- {
- if (establishVoiceConnection())
+ case VOICE_STATE_WAIT_FOR_EXIT:
+ if (isGatewayRunning())
{
- ok = true;
+ LL_INFOS("Voice") << "waiting for SLVoice to exit" << LL_ENDL;
+ llcoro::suspendUntilTimeout(1.0);
}
- }
- }
+ else if (mRelogRequested && mVoiceEnabled)
+ {
+ LL_INFOS("Voice") << "will attempt to reconnect to voice" << LL_ENDL;
+ coro_state = VOICE_STATE_TP_WAIT;
+ }
+ else
+ {
+ coro_state = VOICE_STATE_DONE;
+ }
+ break;
- if (!ok)
- {
- giveUp();
- }
+ case VOICE_STATE_DONE:
+ break;
+ }
+ } while (coro_state > 0);
- return ok;
+ mIsCoroutineActive = false;
+ LL_INFOS("Voice") << "exiting" << LL_ENDL;
}
bool LLVivoxVoiceClient::endAndDisconnectSession()
@@ -1047,7 +1132,7 @@ bool LLVivoxVoiceClient::provisionVoiceAccount()
if (status == LLCore::HttpStatus(404))
{
F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast<float>(retryCount));
- LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds." << LL_ENDL;
+ LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds. Retries: " << (S32)retryCount << LL_ENDL;
if (sShuttingDown)
{
return false;
@@ -1798,7 +1883,6 @@ bool LLVivoxVoiceClient::waitForChannel()
if (sShuttingDown)
{
- logoutOfVivox(false);
return false;
}
@@ -1806,6 +1890,11 @@ bool LLVivoxVoiceClient::waitForChannel()
{
retrieveVoiceFonts();
+ if (sShuttingDown)
+ {
+ return false;
+ }
+
// Request the set of available voice fonts.
refreshVoiceEffectLists(false);
}
@@ -1880,13 +1969,22 @@ bool LLVivoxVoiceClient::waitForChannel()
break;
}
- } while (mVoiceEnabled && !mRelogRequested && !sShuttingDown);
+ } while (!sShuttingDown && mVoiceEnabled && !mRelogRequested);
- LL_DEBUGS("Voice")
- << "leaving inner waitForChannel loop"
- << " RelogRequested=" << mRelogRequested
- << " VoiceEnabled=" << mVoiceEnabled
- << LL_ENDL;
+ if (!sShuttingDown)
+ {
+ LL_DEBUGS("Voice")
+ << "leaving inner waitForChannel loop"
+ << " RelogRequested=" << mRelogRequested
+ << " VoiceEnabled=" << mVoiceEnabled
+ << LL_ENDL;
+ }
+ else
+ {
+ // if sShuttingDown is set, we already logged out
+ LL_DEBUGS("Voice") << "leaving inner waitForChannel loop." << LL_ENDL;
+ return false;
+ }
mIsProcessingChannels = false;
@@ -1902,7 +2000,7 @@ bool LLVivoxVoiceClient::waitForChannel()
return false;
}
}
- } while (mVoiceEnabled && mRelogRequested && isGatewayRunning() && !sShuttingDown);
+ } while (!sShuttingDown && mVoiceEnabled && mRelogRequested && isGatewayRunning());
LL_DEBUGS("Voice")
<< "exiting"
@@ -4718,6 +4816,12 @@ bool LLVivoxVoiceClient::switchChannel(
// The old session may now need to be deleted.
reapSession(oldSession);
+ // If voice was on, turn it off
+ if (LLVoiceClient::getInstance()->getUserPTTState())
+ {
+ LLVoiceClient::getInstance()->setUserPTTState(false);
+ }
+
notifyStatusObservers(LLVoiceClientStatusObserver::STATUS_VOICE_DISABLED);
}
else