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;
}