diff options
Diffstat (limited to 'indra/newview/llvoicevivox.cpp')
-rw-r--r-- | indra/newview/llvoicevivox.cpp | 280 |
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 |