From 6b2e66f086ca3f5a15c3baad1af094bce0e43c98 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 24 May 2021 23:41:17 +0300 Subject: SL-15292 waitForChannel crash --- indra/newview/llvoicevivox.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index f9ffefd4a2..f9c8da26a6 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -1759,7 +1759,7 @@ bool LLVivoxVoiceClient::waitForChannel() if (sShuttingDown) { - logoutOfVivox(true); + logoutOfVivox(false); return false; } @@ -1851,9 +1851,9 @@ bool LLVivoxVoiceClient::waitForChannel() mIsProcessingChannels = false; - logoutOfVivox(true); + logoutOfVivox(!sShuttingDown /*bool wait*/); - if (mRelogRequested) + if (mRelogRequested && !sShuttingDown) { LL_DEBUGS("Voice") << "Relog Requested, restarting provisioning" << LL_ENDL; if (!provisionVoiceAccount()) -- cgit v1.2.3 From 8e862032d1fb0a75dfc07de1f674fb61422b9f37 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 26 May 2021 01:32:52 +0300 Subject: SL-15292 waitForChannel crash #2 --- indra/newview/llvoicevivox.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index f9c8da26a6..96b7dac59d 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -1326,6 +1326,11 @@ void LLVivoxVoiceClient::logoutOfVivox(bool wait) result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); + if (sShuttingDown) + { + break; + } + LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; // Don't get confused by prior queued events -- note that it's // very important that mVivoxPump is an LLEventMailDrop, which -- cgit v1.2.3 From 261ba33537235fc0ed88e2fea169dbae793ba7ff Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Mon, 7 Jun 2021 21:02:44 +0300 Subject: SL-15351 'Speak' button remains active on the parcel with disabled voice --- indra/newview/llvoicevivox.cpp | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 04d84ad905..91c6a9d4f9 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -4609,6 +4609,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 -- cgit v1.2.3 From f9c587535035b3a945edcff4ac09ab22ec4dbde2 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Fri, 13 Aug 2021 22:45:33 +0300 Subject: SL-15292 waitForChannel crash This code needs to be turned into a state machine (switch-case between states) with clean exit and each state clean and separate. Right now it passes through all stages on exit and relies onto multiple bools instead of just transitioning to 'exit' state. In some cases coroutine still lives longer than voice singletone, it also needs to be adressed. --- indra/newview/llvoicevivox.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index e4d528ece5..e6da5c5939 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -1880,13 +1880,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 +1911,7 @@ bool LLVivoxVoiceClient::waitForChannel() return false; } } - } while (mVoiceEnabled && mRelogRequested && isGatewayRunning() && !sShuttingDown); + } while (!sShuttingDown && mVoiceEnabled && mRelogRequested && isGatewayRunning()); LL_DEBUGS("Voice") << "exiting" -- cgit v1.2.3 From 241881309a568c2521ef773bf43544298ff1fd61 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 18 Aug 2021 20:44:12 +0300 Subject: SL-15462 Refactor voiceControlCoro() into a state machine #1 --- indra/newview/llvoicevivox.cpp | 221 ++++++++++++++++++++++++++--------------- 1 file changed, 140 insertions(+), 81 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index e6da5c5939..a8d5ef627f 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -658,6 +658,22 @@ 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() { LL_DEBUGS("Voice") << "starting" << LL_ENDL; @@ -666,112 +682,156 @@ void LLVivoxVoiceClient::voiceControlCoro() 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; - } + EVoiceControlCoroState 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, 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(); + 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 +1107,7 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() if (status == LLCore::HttpStatus(404)) { F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast(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 +1858,6 @@ bool LLVivoxVoiceClient::waitForChannel() if (sShuttingDown) { - logoutOfVivox(false); return false; } -- cgit v1.2.3 From 1e7fd6302aa39f1a011e2e4d711bca7a88a62076 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 18 Aug 2021 22:27:19 +0300 Subject: SL-15462 Refactor voiceControlCoro() into a state machine #2 --- indra/newview/llvoicevivox.cpp | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index a8d5ef627f..4aa6f2c6b2 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -675,6 +675,30 @@ typedef enum e_voice_control_coro_state } 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; @@ -682,14 +706,15 @@ void LLVivoxVoiceClient::voiceControlCoro() U32 retry = 0; - EVoiceControlCoroState coro_state = VOICE_STATE_TP_WAIT; + coro_state = VOICE_STATE_TP_WAIT; do { if (sShuttingDown) { - // Vivox singleton performed the exit, and no longer - // cares about state of coroutine, so just stop + // Vivox singleton performed the exit, logged out, + // cleaned sockets, gateway and no longer cares + // about state of coroutine, so just stop return; } @@ -797,7 +822,7 @@ void LLVivoxVoiceClient::voiceControlCoro() break; case VOICE_STATE_WAIT_FOR_CHANNEL: - waitForChannel(); + waitForChannel(); // todo: split into more states like login/fonts coro_state = VOICE_STATE_DISCONNECT; break; @@ -1865,6 +1890,11 @@ bool LLVivoxVoiceClient::waitForChannel() { retrieveVoiceFonts(); + if (sShuttingDown) + { + return false; + } + // Request the set of available voice fonts. refreshVoiceEffectLists(false); } -- cgit v1.2.3 From 404e69e5945d357d70bd2da684b7a3dbedd1579d Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 28 Oct 2021 18:41:10 +0300 Subject: SL-15462 Convert waitForChannel() into state machine --- indra/newview/llvoicevivox.cpp | 232 +++++++++++++++++++++++++++++------------ 1 file changed, 165 insertions(+), 67 deletions(-) (limited to 'indra/newview/llvoicevivox.cpp') diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index 4aa6f2c6b2..c7a544f8eb 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -400,6 +400,11 @@ void LLVivoxVoiceClient::init(LLPumpIO *pump) void LLVivoxVoiceClient::terminate() { + if (sShuttingDown) + { + return; + } + // needs to be done manually here since we will not get another pass in // coroutines... that mechanism is long since gone. if (mIsLoggedIn) @@ -1126,6 +1131,11 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() LLVoiceVivoxStats::getInstance()->provisionAttemptStart(); result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts); + if (sShuttingDown) + { + return false; + } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -1133,14 +1143,12 @@ bool LLVivoxVoiceClient::provisionVoiceAccount() { F32 timeout = pow(PROVISION_RETRY_TIMEOUT, static_cast(retryCount)); LL_WARNS("Voice") << "Provision CAP 404. Retrying in " << timeout << " seconds. Retries: " << (S32)retryCount << LL_ENDL; + llcoro::suspendUntilTimeout(timeout); + if (sShuttingDown) { return false; } - else - { - llcoro::suspendUntilTimeout(timeout); - } } else if (!status) { @@ -1515,6 +1523,11 @@ bool LLVivoxVoiceClient::requestParcelVoiceInfo() LLSD result = httpAdapter->postAndSuspend(httpRequest, url, LLSD()); + if (sShuttingDown) + { + return false; + } + LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); @@ -1620,6 +1633,11 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) llcoro::suspend(); + if (sShuttingDown) + { + return false; + } + LLSD result; if (mSpatialJoiningNum == MAX_NORMAL_JOINING_SPATIAL_NUM) @@ -1685,7 +1703,6 @@ bool LLVivoxVoiceClient::addAndJoinSession(const sessionStatePtr_t &nextSession) if (sShuttingDown) { - mIsJoiningSession = false; return false; } @@ -1808,6 +1825,11 @@ bool LLVivoxVoiceClient::terminateAudioSession(bool wait) result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, LOGOUT_ATTEMPT_TIMEOUT, timeoutResult); + if (sShuttingDown) + { + return false; + } + LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; if (result.has("session")) { @@ -1870,54 +1892,76 @@ bool LLVivoxVoiceClient::terminateAudioSession(bool wait) return status; } + +typedef enum e_voice_wait_for_channel_state +{ + VOICE_CHANNEL_STATE_LOGIN = 0, // entry point + VOICE_CHANNEL_STATE_CHECK_EFFECTS, + VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING, + VOICE_CHANNEL_STATE_PROCESS_CHANNEL, + VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY, + VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK, + VOICE_CHANNEL_STATE_LOGOUT, + VOICE_CHANNEL_STATE_RELOG, + VOICE_CHANNEL_STATE_DONE, +} EVoiceWaitForChannelState; + bool LLVivoxVoiceClient::waitForChannel() { LL_INFOS("Voice") << "Waiting for channel" << LL_ENDL; + EVoiceWaitForChannelState state = VOICE_CHANNEL_STATE_LOGIN; + do { - if (!loginToVivox()) - { - return false; - } - if (sShuttingDown) { + // terminate() forcefully disconects voice, no need for cleanup return false; } - if (LLVoiceClient::instance().getVoiceEffectEnabled()) + switch (state) { - retrieveVoiceFonts(); - - if (sShuttingDown) + case VOICE_CHANNEL_STATE_LOGIN: + if (!loginToVivox()) { return false; } + state = VOICE_CHANNEL_STATE_CHECK_EFFECTS; + break; - // Request the set of available voice fonts. - refreshVoiceEffectLists(false); - } + case VOICE_CHANNEL_STATE_CHECK_EFFECTS: + if (LLVoiceClient::instance().getVoiceEffectEnabled()) + { + retrieveVoiceFonts(); -#if USE_SESSION_GROUPS - // Rider: This code is completely unchanged from the original state machine - // It does not seem to be in active use... but I'd rather not rip it out. - // create the main session group - setState(stateCreatingSessionGroup); - sessionGroupCreateSendMessage(); + if (sShuttingDown) + { + return false; + } + + // Request the set of available voice fonts. + refreshVoiceEffectLists(false); + } + +#if USE_SESSION_GROUPS + // Rider: This code is completely unchanged from the original state machine + // It does not seem to be in active use... but I'd rather not rip it out. + // create the main session group + setState(stateCreatingSessionGroup); + sessionGroupCreateSendMessage(); #endif - do - { + state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING; + break; + + case VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING: mIsProcessingChannels = true; llcoro::suspend(); + state = VOICE_CHANNEL_STATE_PROCESS_CHANNEL; + break; - if (sShuttingDown) - { - mRelogRequested = false; - break; - } - + case VOICE_CHANNEL_STATE_PROCESS_CHANNEL: if (mTuningMode) { performMicTuning(); @@ -1958,63 +2002,91 @@ bool LLVivoxVoiceClient::waitForChannel() } } - if (!mNextAudioSession && !sShuttingDown) + state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY; + break; + + case VOICE_CHANNEL_STATE_NEXT_CHANNEL_DELAY: + if (!mNextAudioSession) { llcoro::suspendUntilTimeout(1.0); } + state = VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK; + break; - if (sShuttingDown) + case VOICE_CHANNEL_STATE_NEXT_CHANNEL_CHECK: + if (mVoiceEnabled && !mRelogRequested) { - mRelogRequested = false; + state = VOICE_CHANNEL_STATE_START_CHANNEL_PROCESSING; + break; + } + else + { + mIsProcessingChannels = false; + LL_DEBUGS("Voice") + << "leaving inner waitForChannel loop" + << " RelogRequested=" << mRelogRequested + << " VoiceEnabled=" << mVoiceEnabled + << LL_ENDL; + state = VOICE_CHANNEL_STATE_LOGOUT; break; } - } while (!sShuttingDown && mVoiceEnabled && !mRelogRequested); - - 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; - - logoutOfVivox(!sShuttingDown /*bool wait*/); + case VOICE_CHANNEL_STATE_LOGOUT: + logoutOfVivox(true /*bool wait*/); + if (mRelogRequested) + { + state = VOICE_CHANNEL_STATE_RELOG; + } + else + { + state = VOICE_CHANNEL_STATE_DONE; + } + break; - if (mRelogRequested && !sShuttingDown) - { + case VOICE_CHANNEL_STATE_RELOG: LL_DEBUGS("Voice") << "Relog Requested, restarting provisioning" << LL_ENDL; if (!provisionVoiceAccount()) { + if (sShuttingDown) + { + return false; + } LL_WARNS("Voice") << "provisioning voice failed; giving up" << LL_ENDL; giveUp(); return false; } + if (mVoiceEnabled && mRelogRequested && isGatewayRunning()) + { + state = VOICE_CHANNEL_STATE_LOGIN; + } + else + { + state = VOICE_CHANNEL_STATE_DONE; + } + break; + case VOICE_CHANNEL_STATE_DONE: + LL_DEBUGS("Voice") + << "exiting" + << " RelogRequested=" << mRelogRequested + << " VoiceEnabled=" << mVoiceEnabled + << LL_ENDL; + return !sShuttingDown; } - } while (!sShuttingDown && mVoiceEnabled && mRelogRequested && isGatewayRunning()); - - LL_DEBUGS("Voice") - << "exiting" - << " RelogRequested=" << mRelogRequested - << " VoiceEnabled=" << mVoiceEnabled - << LL_ENDL; - return !sShuttingDown; + } while (true); } bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) { LL_INFOS("Voice") << "running new voice session " << session->mHandle << LL_ENDL; - if (!addAndJoinSession(session)) + bool joined_session = addAndJoinSession(session); + + if (sShuttingDown) + { + return false; + } + + if (!joined_session) { notifyStatusObservers(LLVoiceClientStatusObserver::ERROR_UNKNOWN); @@ -2038,9 +2110,19 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) mIsInChannel = true; mMuteMicDirty = true; - while (mVoiceEnabled && isGatewayRunning() && !mSessionTerminateRequested && !mTuningMode) + while (!sShuttingDown + && mVoiceEnabled + && isGatewayRunning() + && !mSessionTerminateRequested + && !mTuningMode) { sendCaptureAndRenderDevices(); // suspends + + if (sShuttingDown) + { + return false; + } + if (mSessionTerminateRequested) { break; @@ -2070,10 +2152,15 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) // cap for the parcel voice info. If we can't request it // then we don't have the cap URL so we do nothing and will // recheck next time around - if (requestParcelVoiceInfo()) + if (requestParcelVoiceInfo()) // suspends { // The parcel voice URI has changed.. break out and reconnect. break; } + + if (sShuttingDown) + { + return false; + } } // Do the calculation that enforces the listener<->speaker tether (and also updates the real camera position) enforceTether(); @@ -2092,6 +2179,12 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) mIsInitialized = true; LLSD result = llcoro::suspendUntilEventOnWithTimeout(mVivoxPump, UPDATE_THROTTLE_SECONDS, timeoutEvent); + + if (sShuttingDown) + { + return false; + } + if (!result.has("timeout")) // logging the timeout event spams the log { LL_DEBUGS("Voice") << "event=" << ll_stream_notation_sd(result) << LL_ENDL; @@ -2134,6 +2227,11 @@ bool LLVivoxVoiceClient::runSession(const sessionStatePtr_t &session) } } + if (sShuttingDown) + { + return false; + } + mIsInChannel = false; LL_DEBUGS("Voice") << "terminating at end of runSession" << LL_ENDL; terminateAudioSession(true); -- cgit v1.2.3