diff --git a/indra/llwebrtc/llwebrtc.cpp b/indra/llwebrtc/llwebrtc.cpp index d686082878..eea5c92b76 100644 --- a/indra/llwebrtc/llwebrtc.cpp +++ b/indra/llwebrtc/llwebrtc.cpp @@ -459,6 +459,10 @@ void LLWebRTCImpl::workerDeployDevices() { if (!mDeviceModule) { + // [FIRE-36022] + // If the device is not avaiable, then make sure the flag for the WebRTC updated devices flag is turned off for the co-routine + iWebRTCUpdateDevices = false; + // [FIRE-36022] - Removing my USB headset crashes entire viewer return; } @@ -483,6 +487,10 @@ void LLWebRTCImpl::workerDeployDevices() } } + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // Flag the device is being interacted with for the Co-routine in case something goes wrong. + iWebRTCUpdateDevices = true; + // [FIRE-36022] mDeviceModule->StopPlayout(); mDeviceModule->ForceStopRecording(); #if WEBRTC_WIN @@ -546,6 +554,10 @@ void LLWebRTCImpl::workerDeployDevices() { mDeviceModule->StartPlayout(); } + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // Finally signal to the co-routine everyting is OK. + iWebRTCUpdateDevices = false; + // [FIRE-36022] mSignalingThread->PostTask( [this] { @@ -589,6 +601,10 @@ void LLWebRTCImpl::updateDevices() return; } + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // Flag the device is being interacted with for the Co-routine in case something goes wrong. + iWebRTCUpdateDevices = true; + // [FIRE-36022] int16_t renderDeviceCount = mDeviceModule->PlayoutDevices(); mPlayoutDeviceList.clear(); @@ -625,6 +641,10 @@ void LLWebRTCImpl::updateDevices() mRecordingDeviceList.emplace_back(name, guid); } + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // Flag the device is no longer being interacted with for the Co-routine in case something goes wrong. + iWebRTCUpdateDevices = false; + // [FIRE-36022] for (auto &observer : mVoiceDevicesObserverList) { observer->OnDevicesChanged(mPlayoutDeviceList, mRecordingDeviceList); @@ -726,7 +746,14 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms) { if (mDeviceModule) { + // Flag the device is being interacted with for the Co-routine in case something goes wrong. + iWebRTCUpdateDevices = true; + // [FIRE-36022] mDeviceModule->ForceStopRecording(); + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // Finally signal to the co-routine everyting is OK. + iWebRTCUpdateDevices = false; + // [FIRE-36022] } }, webrtc::TimeDelta::Millis(delay_ms)); @@ -738,8 +765,16 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms) { if (mDeviceModule) { + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // Flag the device is being interacted with for the Co-routine in case something goes wrong. + iWebRTCUpdateDevices = true; + // [FIRE-36022] mDeviceModule->InitRecording(); mDeviceModule->ForceStartRecording(); + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // Finally signal to the co-routine everyting is OK. + iWebRTCUpdateDevices = false; + // [FIRE-36022] } }); } diff --git a/indra/llwebrtc/llwebrtc.h b/indra/llwebrtc/llwebrtc.h index 7d06b7d2b4..572f5ecce9 100644 --- a/indra/llwebrtc/llwebrtc.h +++ b/indra/llwebrtc/llwebrtc.h @@ -40,6 +40,10 @@ #include #include +// [FIRE-36022] - Removing my USB headset crashes entire viewer +// Needed for inline variable for the crash check +#include +// [FIRE-36022] #ifdef LL_MAKEDLL #ifdef WEBRTC_WIN @@ -53,6 +57,12 @@ #define LLSYMEXPORT /**/ #endif // LL_MAKEDLL +// [FIRE-36022] - Removing my USB headset crashes entire viewer +// Create an atomic inline flag that will be shared between the various WebRTC threads and co-routines +// to track of when the audio hardware is being talked to. The co-routine can use it to +// exit if it too many iterations with the hardware locked indicating that the worker thread died. +inline std::atomic iWebRTCUpdateDevices = false; +// [FIRE-36022] namespace llwebrtc { diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 5ff1b0c498..a00e736d05 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -506,6 +506,12 @@ void LLWebRTCVoiceClient::voiceConnectionCoro() try { LLMuteList::getInstance()->addObserver(this); + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // Add a counter to check if the main thread locked up + // to prevent this thread/corutine form filling up + // the mMainQueue. + static U32 crash_check = 0; + // [FIRE-36022] while (!sShuttingDown) { LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE("voiceConnectionCoroLoop") @@ -591,6 +597,26 @@ void LLWebRTCVoiceClient::voiceConnectionCoro() // to send position updates. updatePosition(); } + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // If the device locked, count up by 1 + if (iWebRTCUpdateDevices) + { + crash_check++; + } + // Else if the device is not locked, then reset the counter back to 0 + else + { + crash_check = 0; + } + // If there are over 10 cycles of the devices being locked, there is a good + // chance that the thread failed due to hardware/audio engine issue. + if (crash_check > 10) + { + LL_WARNS() << "WebRTC detected locked worker thread, will shutdown to prevent total viewer lockup." << LL_ENDL; + // Exit out of the thread and flag WebRTC to shutdown, hopefully clearing the lock and allowing the viewer to continue. + sShuttingDown = true; + } + // [FIRE-36022] } LL::WorkQueue::postMaybe(mMainQueue, [=, this] { @@ -848,6 +874,11 @@ void LLWebRTCVoiceClient::tuningSetSpeakerVolume(float volume) float LLWebRTCVoiceClient::tuningGetEnergy(void) { + // [FIRE-36022] - Removing my USB headset crashes entire viewer + // This can cause an error if device interface can be NULL. + if (!mWebRTCDeviceInterface) + return 1.0f; + // [FIRE-36022] float rms = mWebRTCDeviceInterface->getTuningAudioLevel(); return TUNING_LEVEL_START_POINT - TUNING_LEVEL_SCALE * rms; }