FIRE-36022- Removing my USB headset crashes entire viewer - WebRTC fix
This is created to address the issue of USB headsets being removed or Bluetooth headsets with bad connections causing the viewer to lock up. First Part: WebRTC WebRTC now has an added inline atomic bool used to track when the worker thread is accessing the audio hardware. If the coroutine that is always running detects 10 consecutive true flag values, it will set WebRTC to exit and exit itself. This coroutine was what was locking up the viewer as it spammed the mMainQueue with messages every update, but the worker thread was locked up and unable to receive the messages. Once the queue reached 1024 messages, it would lock up. Underlying issue is the Windows Core Audio driver system crashes if too many threads have requests to get audio updates upon hardware changes. And with a USB headset having 2 devices in 1, it multiples the updates by 2x. The WebRTC audio system itself locks a mutex as it calls the core audio system to get set the input, but if it is already being processed by another thread, it then gets an exception to try again. The audio driver is not handling the message and crashes and does not return leaving the WebRTC worker thread locked.master
parent
44ffa1df51
commit
0cdae450d8
|
|
@ -459,6 +459,10 @@ void LLWebRTCImpl::workerDeployDevices()
|
|||
{
|
||||
if (!mDeviceModule)
|
||||
{
|
||||
// <FS:minerjr> [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;
|
||||
// </FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -483,6 +487,10 @@ void LLWebRTCImpl::workerDeployDevices()
|
|||
}
|
||||
}
|
||||
|
||||
// <FS:minerjr> [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;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
mDeviceModule->StopPlayout();
|
||||
mDeviceModule->ForceStopRecording();
|
||||
#if WEBRTC_WIN
|
||||
|
|
@ -546,6 +554,10 @@ void LLWebRTCImpl::workerDeployDevices()
|
|||
{
|
||||
mDeviceModule->StartPlayout();
|
||||
}
|
||||
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||
// Finally signal to the co-routine everyting is OK.
|
||||
iWebRTCUpdateDevices = false;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
mSignalingThread->PostTask(
|
||||
[this]
|
||||
{
|
||||
|
|
@ -589,6 +601,10 @@ void LLWebRTCImpl::updateDevices()
|
|||
return;
|
||||
}
|
||||
|
||||
// <FS:minerjr> [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;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
int16_t renderDeviceCount = mDeviceModule->PlayoutDevices();
|
||||
|
||||
mPlayoutDeviceList.clear();
|
||||
|
|
@ -625,6 +641,10 @@ void LLWebRTCImpl::updateDevices()
|
|||
mRecordingDeviceList.emplace_back(name, guid);
|
||||
}
|
||||
|
||||
// <FS:minerjr> [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;
|
||||
// </FS:minerjr> [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;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
mDeviceModule->ForceStopRecording();
|
||||
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||
// Finally signal to the co-routine everyting is OK.
|
||||
iWebRTCUpdateDevices = false;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
}
|
||||
},
|
||||
webrtc::TimeDelta::Millis(delay_ms));
|
||||
|
|
@ -738,8 +765,16 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms)
|
|||
{
|
||||
if (mDeviceModule)
|
||||
{
|
||||
// <FS:minerjr> [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;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
mDeviceModule->InitRecording();
|
||||
mDeviceModule->ForceStartRecording();
|
||||
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||
// Finally signal to the co-routine everyting is OK.
|
||||
iWebRTCUpdateDevices = false;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@
|
|||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||
// Needed for inline variable for the crash check
|
||||
#include <atomic>
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
|
||||
#ifdef LL_MAKEDLL
|
||||
#ifdef WEBRTC_WIN
|
||||
|
|
@ -53,6 +57,12 @@
|
|||
#define LLSYMEXPORT /**/
|
||||
#endif // LL_MAKEDLL
|
||||
|
||||
// <FS:minerjr> [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<bool> iWebRTCUpdateDevices = false;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
namespace llwebrtc
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -506,6 +506,12 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
|
|||
try
|
||||
{
|
||||
LLMuteList::getInstance()->addObserver(this);
|
||||
// <FS:minerjr> [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;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
while (!sShuttingDown)
|
||||
{
|
||||
LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE("voiceConnectionCoroLoop")
|
||||
|
|
@ -591,6 +597,26 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
|
|||
// to send position updates.
|
||||
updatePosition();
|
||||
}
|
||||
// <FS:minerjr> [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;
|
||||
}
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
}
|
||||
LL::WorkQueue::postMaybe(mMainQueue,
|
||||
[=, this] {
|
||||
|
|
@ -848,6 +874,11 @@ void LLWebRTCVoiceClient::tuningSetSpeakerVolume(float volume)
|
|||
|
||||
float LLWebRTCVoiceClient::tuningGetEnergy(void)
|
||||
{
|
||||
// <FS:minerjr> [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;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
float rms = mWebRTCDeviceInterface->getTuningAudioLevel();
|
||||
return TUNING_LEVEL_START_POINT - TUNING_LEVEL_SCALE * rms;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue