Merge branch 'master' of https://github.com/FirestormViewer/phoenix-firestorm
commit
574dc5b65a
|
|
@ -39,6 +39,10 @@
|
||||||
#include "llframetimer.h"
|
#include "llframetimer.h"
|
||||||
#include "llassettype.h"
|
#include "llassettype.h"
|
||||||
#include "llextendedstatus.h"
|
#include "llextendedstatus.h"
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Need to include for audio device mutex shared with other audio/voice systems.
|
||||||
|
#include "inlinemutexs.h"
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
|
|
||||||
#include "lllistener.h"
|
#include "lllistener.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,9 @@
|
||||||
|
|
||||||
#include "sound_ids.h"
|
#include "sound_ids.h"
|
||||||
|
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
using namespace std::chrono_literals; // Needed for shared timed mutex to use time
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
constexpr U32 EXTRA_SOUND_CHANNELS = 10;
|
constexpr U32 EXTRA_SOUND_CHANNELS = 10;
|
||||||
|
|
||||||
FMOD_RESULT F_CALL windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels);
|
FMOD_RESULT F_CALL windCallback(FMOD_DSP_STATE *dsp_state, float *inbuffer, float *outbuffer, unsigned int length, int inchannels, int *outchannels);
|
||||||
|
|
@ -113,8 +116,14 @@ static void set_device(FMOD::System* system, const LLUUID& device_uuid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata)
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// According to FMOD, not having this method static is very bad.
|
||||||
|
//FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata)
|
||||||
|
static FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE type, void *commanddata1, void *commanddata2, void* userdata)
|
||||||
{
|
{
|
||||||
|
try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
|
||||||
|
{
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
FMOD::System* sys = (FMOD::System*)system;
|
FMOD::System* sys = (FMOD::System*)system;
|
||||||
LLAudioEngine_FMODSTUDIO* audio_engine = (LLAudioEngine_FMODSTUDIO*)userdata;
|
LLAudioEngine_FMODSTUDIO* audio_engine = (LLAudioEngine_FMODSTUDIO*)userdata;
|
||||||
|
|
||||||
|
|
@ -124,6 +133,17 @@ FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE
|
||||||
LL_DEBUGS("FMOD") << "FMOD system callback FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED" << LL_ENDL;
|
LL_DEBUGS("FMOD") << "FMOD system callback FMOD_SYSTEM_CALLBACK_DEVICELISTCHANGED" << LL_ENDL;
|
||||||
if (sys && audio_engine)
|
if (sys && audio_engine)
|
||||||
{
|
{
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
|
||||||
|
std::unique_lock lock(gAudioDeviceMutex, 1s);
|
||||||
|
// If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
|
||||||
|
// Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
{
|
||||||
|
LL_INFOS() << "Could not access the audio device mutex, trying again later" << LL_ENDL;
|
||||||
|
return FMOD_OK; // Could be a FMOD_ERR_ALREADY_LOCKED;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
set_device(sys, audio_engine->getSelectedDeviceUUID());
|
set_device(sys, audio_engine->getSelectedDeviceUUID());
|
||||||
audio_engine->OnOutputDeviceListChanged(audio_engine->getDevices());
|
audio_engine->OnOutputDeviceListChanged(audio_engine->getDevices());
|
||||||
}
|
}
|
||||||
|
|
@ -132,6 +152,34 @@ FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return FMOD_OK;
|
return FMOD_OK;
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
}
|
||||||
|
// There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
|
||||||
|
catch (const std::system_error& e)
|
||||||
|
{
|
||||||
|
if (e.code() == std::errc::resource_deadlock_would_occur)
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
return FMOD_ERR_ALREADY_LOCKED;
|
||||||
|
}
|
||||||
|
else if (e.code() == std::errc::operation_not_permitted)
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
return FMOD_ERR_ALREADY_LOCKED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FMOD_ERR_ALREADY_LOCKED;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception FMOD: " << " " << e.what() << LL_ENDL;
|
||||||
|
return FMOD_ERR_ALREADY_LOCKED;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
}
|
}
|
||||||
|
|
||||||
LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 resample_method)
|
LLAudioEngine_FMODSTUDIO::LLAudioEngine_FMODSTUDIO(bool enable_profiler, U32 resample_method)
|
||||||
|
|
@ -311,6 +359,11 @@ bool LLAudioEngine_FMODSTUDIO::init(void* userdata, const std::string &app_title
|
||||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL;
|
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init() FMOD Studio initialized correctly" << LL_ENDL;
|
||||||
|
|
||||||
FMOD_ADVANCEDSETTINGS settings_dump = { };
|
FMOD_ADVANCEDSETTINGS settings_dump = { };
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// With the FMOD debug library used, turns out this object needs to have a size assigned to it otherwise it will fail.
|
||||||
|
// So the viewer never got any advanced settings for the info below.
|
||||||
|
settings_dump.cbSize = sizeof(FMOD_ADVANCEDSETTINGS);
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
mSystem->getAdvancedSettings(&settings_dump);
|
mSystem->getAdvancedSettings(&settings_dump);
|
||||||
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): resampler=" << settings_dump.resamplerMethod << " bytes" << LL_ENDL;
|
LL_INFOS("AppInit") << "LLAudioEngine_FMODSTUDIO::init(): resampler=" << settings_dump.resamplerMethod << " bytes" << LL_ENDL;
|
||||||
|
|
||||||
|
|
@ -373,7 +426,47 @@ LLAudioEngine_FMODSTUDIO::output_device_map_t LLAudioEngine_FMODSTUDIO::getDevic
|
||||||
void LLAudioEngine_FMODSTUDIO::setDevice(const LLUUID& device_uuid)
|
void LLAudioEngine_FMODSTUDIO::setDevice(const LLUUID& device_uuid)
|
||||||
{
|
{
|
||||||
mSelectedDeviceUUID = device_uuid;
|
mSelectedDeviceUUID = device_uuid;
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
|
||||||
|
{
|
||||||
|
// Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
|
||||||
|
std::unique_lock lock(gAudioDeviceMutex, 1s);
|
||||||
|
// If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
|
||||||
|
// Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
{
|
||||||
|
LL_INFOS() << "Could not access the audio device mutex, trying again later" << LL_ENDL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
set_device(mSystem, device_uuid);
|
set_device(mSystem, device_uuid);
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
}
|
||||||
|
// There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
|
||||||
|
catch (const std::system_error& e)
|
||||||
|
{
|
||||||
|
if (e.code() == std::errc::resource_deadlock_would_occur)
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
else if (e.code() == std::errc::operation_not_permitted)
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception FMOD: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception FMOD: " << " " << e.what() << LL_ENDL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose)
|
std::string LLAudioEngine_FMODSTUDIO::getDriverName(bool verbose)
|
||||||
|
|
|
||||||
|
|
@ -122,6 +122,7 @@ set(llcommon_HEADER_FILES
|
||||||
fsyspath.h
|
fsyspath.h
|
||||||
function_types.h
|
function_types.h
|
||||||
indra_constants.h
|
indra_constants.h
|
||||||
|
inlinemutexs.h
|
||||||
lazyeventapi.h
|
lazyeventapi.h
|
||||||
linden_common.h
|
linden_common.h
|
||||||
llalignedarray.h
|
llalignedarray.h
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* @file inlinemutexs.h
|
||||||
|
* @brief Declaration of inline mutexs
|
||||||
|
* @author minerjr@firestorm
|
||||||
|
*
|
||||||
|
* $LicenseInfo:firstyear=2025&license=fsviewerlgpl$
|
||||||
|
* Phoenix Firestorm Viewer Source Code
|
||||||
|
* Copyright (C) 2025, Minerjr
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation;
|
||||||
|
* version 2.1 of the License only.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
|
||||||
|
* http://www.firestormviewer.org
|
||||||
|
* $/LicenseInfo$
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INLINE_MUTEXS_HEADER
|
||||||
|
#define INLINE_MUTEXS_HEADER
|
||||||
|
#include <mutex>
|
||||||
|
#include <chrono>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
// Audio device mutex to be shared between audio engine and Voice systems to
|
||||||
|
// syncronize on when audio hardware accessed for disconnected/connecting hardware
|
||||||
|
// Uses Timed Mutex so as to not lockup the threads forever.
|
||||||
|
inline std::timed_mutex gAudioDeviceMutex;
|
||||||
|
#endif
|
||||||
|
|
@ -27,6 +27,11 @@
|
||||||
#include "llwebrtc_impl.h"
|
#include "llwebrtc_impl.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Needed for accessing the inline timed mutex for accessing audio hardware.
|
||||||
|
#include <mutex>
|
||||||
|
#include <chrono>
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
|
|
||||||
#include "api/audio_codecs/audio_decoder_factory.h"
|
#include "api/audio_codecs/audio_decoder_factory.h"
|
||||||
#include "api/audio_codecs/audio_encoder_factory.h"
|
#include "api/audio_codecs/audio_encoder_factory.h"
|
||||||
|
|
@ -39,6 +44,14 @@
|
||||||
#include "modules/audio_mixer/audio_mixer_impl.h"
|
#include "modules/audio_mixer/audio_mixer_impl.h"
|
||||||
#include "api/environment/environment_factory.h"
|
#include "api/environment/environment_factory.h"
|
||||||
|
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Audio device mutex to be shared between audio engine and Voice systems to
|
||||||
|
// syncronize on when audio hardware accessed for disconnected/connecting hardware
|
||||||
|
// Uses Timed Mutex so as to not lockup the threads forever.
|
||||||
|
inline std::timed_mutex gAudioDeviceMutex;
|
||||||
|
// Need to use to access the 3 second timeout for the lock.
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
namespace llwebrtc
|
namespace llwebrtc
|
||||||
{
|
{
|
||||||
#if WEBRTC_WIN
|
#if WEBRTC_WIN
|
||||||
|
|
@ -269,7 +282,11 @@ void LLWebRTCImpl::init()
|
||||||
webrtc::InitializeSSL();
|
webrtc::InitializeSSL();
|
||||||
|
|
||||||
// Normal logging is rather spammy, so turn it off.
|
// Normal logging is rather spammy, so turn it off.
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Turn on more verbose logging as we are looking for crashes.
|
||||||
webrtc::LogMessage::LogToDebug(webrtc::LS_NONE);
|
webrtc::LogMessage::LogToDebug(webrtc::LS_NONE);
|
||||||
|
//webrtc::LogMessage::LogToDebug(webrtc::LS_VERBOSE);
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
webrtc::LogMessage::SetLogToStderr(true);
|
webrtc::LogMessage::SetLogToStderr(true);
|
||||||
webrtc::LogMessage::AddLogToStream(mLogSink, webrtc::LS_VERBOSE);
|
webrtc::LogMessage::AddLogToStream(mLogSink, webrtc::LS_VERBOSE);
|
||||||
|
|
||||||
|
|
@ -457,8 +474,24 @@ void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer)
|
||||||
// must be run in the worker thread.
|
// must be run in the worker thread.
|
||||||
void LLWebRTCImpl::workerDeployDevices()
|
void LLWebRTCImpl::workerDeployDevices()
|
||||||
{
|
{
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
|
||||||
|
{
|
||||||
|
// Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
|
||||||
|
std::unique_lock lock(gAudioDeviceMutex, 1s);
|
||||||
|
// If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
|
||||||
|
// Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
if (!mDeviceModule)
|
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
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
// </FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -483,6 +516,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.
|
||||||
|
gWebRTCUpdateDevices = true;
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
mDeviceModule->StopPlayout();
|
mDeviceModule->StopPlayout();
|
||||||
mDeviceModule->ForceStopRecording();
|
mDeviceModule->ForceStopRecording();
|
||||||
#if WEBRTC_WIN
|
#if WEBRTC_WIN
|
||||||
|
|
@ -546,6 +583,10 @@ void LLWebRTCImpl::workerDeployDevices()
|
||||||
{
|
{
|
||||||
mDeviceModule->StartPlayout();
|
mDeviceModule->StartPlayout();
|
||||||
}
|
}
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Finally signal to the co-routine everyting is OK.
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
mSignalingThread->PostTask(
|
mSignalingThread->PostTask(
|
||||||
[this]
|
[this]
|
||||||
{
|
{
|
||||||
|
|
@ -566,6 +607,38 @@ void LLWebRTCImpl::workerDeployDevices()
|
||||||
mWorkerThread->PostTask([this] { workerDeployDevices(); });
|
mWorkerThread->PostTask([this] { workerDeployDevices(); });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
}
|
||||||
|
// There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
|
||||||
|
catch (const std::system_error& e)
|
||||||
|
{
|
||||||
|
if (e.code() == std::errc::resource_deadlock_would_occur)
|
||||||
|
{
|
||||||
|
// Another thead may have alreayd called this method
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
else if (e.code() == std::errc::operation_not_permitted)
|
||||||
|
{
|
||||||
|
// This should not be reached
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Log any other message
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
// Device no longer being interacted with
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
// Device no longer being interacted with
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLWebRTCImpl::setCaptureDevice(const std::string &id)
|
void LLWebRTCImpl::setCaptureDevice(const std::string &id)
|
||||||
|
|
@ -584,11 +657,27 @@ void LLWebRTCImpl::setRenderDevice(const std::string &id)
|
||||||
// updateDevices needs to happen on the worker thread.
|
// updateDevices needs to happen on the worker thread.
|
||||||
void LLWebRTCImpl::updateDevices()
|
void LLWebRTCImpl::updateDevices()
|
||||||
{
|
{
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
|
||||||
|
{
|
||||||
|
// Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
|
||||||
|
std::unique_lock lock(gAudioDeviceMutex, 1s);
|
||||||
|
// If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
|
||||||
|
// Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
if (!mDeviceModule)
|
if (!mDeviceModule)
|
||||||
{
|
{
|
||||||
return;
|
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.
|
||||||
|
gWebRTCUpdateDevices = true;
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
int16_t renderDeviceCount = mDeviceModule->PlayoutDevices();
|
int16_t renderDeviceCount = mDeviceModule->PlayoutDevices();
|
||||||
|
|
||||||
mPlayoutDeviceList.clear();
|
mPlayoutDeviceList.clear();
|
||||||
|
|
@ -625,10 +714,46 @@ void LLWebRTCImpl::updateDevices()
|
||||||
mRecordingDeviceList.emplace_back(name, guid);
|
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.
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
for (auto &observer : mVoiceDevicesObserverList)
|
for (auto &observer : mVoiceDevicesObserverList)
|
||||||
{
|
{
|
||||||
observer->OnDevicesChanged(mPlayoutDeviceList, mRecordingDeviceList);
|
observer->OnDevicesChanged(mPlayoutDeviceList, mRecordingDeviceList);
|
||||||
}
|
}
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
}
|
||||||
|
// There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
|
||||||
|
catch (const std::system_error& e)
|
||||||
|
{
|
||||||
|
if (e.code() == std::errc::resource_deadlock_would_occur)
|
||||||
|
{
|
||||||
|
// Another thead may have alreayd called this method
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
else if (e.code() == std::errc::operation_not_permitted)
|
||||||
|
{
|
||||||
|
// This should not be reached
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Log any other message
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
// Device no longer being interacted with
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
// Device no longer being interacted with
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLWebRTCImpl::OnDevicesUpdated()
|
void LLWebRTCImpl::OnDevicesUpdated()
|
||||||
|
|
@ -726,7 +851,56 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms)
|
||||||
{
|
{
|
||||||
if (mDeviceModule)
|
if (mDeviceModule)
|
||||||
{
|
{
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is
|
||||||
|
// invalid
|
||||||
|
{
|
||||||
|
// Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
|
||||||
|
std::unique_lock lock(gAudioDeviceMutex, 1s);
|
||||||
|
// If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
|
||||||
|
// Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Flag the device is being interacted with for the Co-routine in case something goes wrong.
|
||||||
|
gWebRTCUpdateDevices = true;
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
mDeviceModule->ForceStopRecording();
|
mDeviceModule->ForceStopRecording();
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Finally signal to the co-routine everyting is OK.
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
}
|
||||||
|
// There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
|
||||||
|
catch (const std::system_error& e)
|
||||||
|
{
|
||||||
|
if (e.code() == std::errc::resource_deadlock_would_occur)
|
||||||
|
{
|
||||||
|
// Another thead may have alreayd called this method
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
else if (e.code() == std::errc::operation_not_permitted)
|
||||||
|
{
|
||||||
|
// This should not be reached
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Log any other message
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
// Device no longer being interacted with
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
// Device no longer being interacted with
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
webrtc::TimeDelta::Millis(delay_ms));
|
webrtc::TimeDelta::Millis(delay_ms));
|
||||||
|
|
@ -738,8 +912,57 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms)
|
||||||
{
|
{
|
||||||
if (mDeviceModule)
|
if (mDeviceModule)
|
||||||
{
|
{
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is
|
||||||
|
// invalid
|
||||||
|
{
|
||||||
|
// Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
|
||||||
|
std::unique_lock lock(gAudioDeviceMutex, 1s);
|
||||||
|
// If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
|
||||||
|
// Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Flag the device is being interacted with for the Co-routine in case something goes wrong.
|
||||||
|
gWebRTCUpdateDevices = true;
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
mDeviceModule->InitRecording();
|
mDeviceModule->InitRecording();
|
||||||
mDeviceModule->ForceStartRecording();
|
mDeviceModule->ForceStartRecording();
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Finally signal to the co-routine everyting is OK.
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
}
|
||||||
|
// There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
|
||||||
|
catch (const std::system_error& e)
|
||||||
|
{
|
||||||
|
if (e.code() == std::errc::resource_deadlock_would_occur)
|
||||||
|
{
|
||||||
|
// Another thead may have alreayd called this method
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
else if (e.code() == std::errc::operation_not_permitted)
|
||||||
|
{
|
||||||
|
// This should not be reached
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Log any other message
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
}
|
||||||
|
// Device no longer being interacted with
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
mLogSink->OnLogMessage(std::string("Excepton: WebRTC: ") + e.what());
|
||||||
|
// Device no longer being interacted with
|
||||||
|
gWebRTCUpdateDevices = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,10 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#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 LL_MAKEDLL
|
||||||
#ifdef WEBRTC_WIN
|
#ifdef WEBRTC_WIN
|
||||||
|
|
@ -53,6 +57,12 @@
|
||||||
#define LLSYMEXPORT /**/
|
#define LLSYMEXPORT /**/
|
||||||
#endif // LL_MAKEDLL
|
#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> gWebRTCUpdateDevices = false;
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
namespace llwebrtc
|
namespace llwebrtc
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1016,6 +1016,11 @@ bool LLAppViewerWin32::cleanup()
|
||||||
|
|
||||||
gDXHardware.cleanup();
|
gDXHardware.cleanup();
|
||||||
|
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Need to unilitialize connection to COM, otherwise it will be treated as a memroy leak.
|
||||||
|
CoUninitialize();
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
|
|
||||||
if (mIsConsoleAllocated)
|
if (mIsConsoleAllocated)
|
||||||
{
|
{
|
||||||
FreeConsole();
|
FreeConsole();
|
||||||
|
|
@ -1056,6 +1061,19 @@ bool LLAppViewerWin32::initWindow()
|
||||||
LL_WARNS("AppInit") << "Unable to set WindowWidth and WindowHeight for FullScreen mode" << LL_ENDL;
|
LL_WARNS("AppInit") << "Unable to set WindowWidth and WindowHeight for FullScreen mode" << LL_ENDL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Acccording to the FMOD spec, you are suppose to initalize COM on the thead that will talk to FMOD. IE the main thread.
|
||||||
|
// There is a coorisponding CoUninitialize in the shutdown code. Otherwise, FMOD will force the initalize with a warning, but does not clean up COM
|
||||||
|
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
LL_INFOS() << "WIN32: CoInitializeEx COM as COINIT_APARTMENTTHREADED Successful" << LL_ENDL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LL_INFOS() << "WIN32: CoInitializeEx COM as COINIT_APARTMENTTHREADED Failed" << LL_ENDL;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
|
|
||||||
return LLAppViewer::initWindow();
|
return LLAppViewer::initWindow();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,10 @@ class LLVOAvatar;
|
||||||
#include "llcallingcard.h" // for LLFriendObserver
|
#include "llcallingcard.h" // for LLFriendObserver
|
||||||
#include "llsecapi.h"
|
#include "llsecapi.h"
|
||||||
#include "llcontrol.h"
|
#include "llcontrol.h"
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// Need to include for audio device mutex shared with other audio/voice systems.
|
||||||
|
#include "inlinemutexs.h"
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
|
|
||||||
// devices
|
// devices
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,9 @@ extern void handle_voice_morphing_subscribe();
|
||||||
|
|
||||||
const std::string VIVOX_VOICE_SERVER_TYPE = "vivox";
|
const std::string VIVOX_VOICE_SERVER_TYPE = "vivox";
|
||||||
|
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
using namespace std::chrono_literals; // Needed for shared timed mutex to use time
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
namespace {
|
namespace {
|
||||||
const F32 VOLUME_SCALE_VIVOX = 0.01f;
|
const F32 VOLUME_SCALE_VIVOX = 0.01f;
|
||||||
|
|
||||||
|
|
@ -2413,6 +2416,19 @@ void LLVivoxVoiceClient::sendCaptureAndRenderDevices()
|
||||||
{
|
{
|
||||||
if (mCaptureDeviceDirty || mRenderDeviceDirty)
|
if (mCaptureDeviceDirty || mRenderDeviceDirty)
|
||||||
{
|
{
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
|
||||||
|
{
|
||||||
|
// Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
|
||||||
|
std::unique_lock lock(gAudioDeviceMutex, 1s);
|
||||||
|
// If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
|
||||||
|
// Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
{
|
||||||
|
LL_INFOS() << "Could not access the audio device mutex, trying again later" << LL_ENDL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
std::ostringstream stream;
|
std::ostringstream stream;
|
||||||
|
|
||||||
buildSetCaptureDevice(stream);
|
buildSetCaptureDevice(stream);
|
||||||
|
|
@ -2424,6 +2440,35 @@ void LLVivoxVoiceClient::sendCaptureAndRenderDevices()
|
||||||
}
|
}
|
||||||
|
|
||||||
llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
|
llcoro::suspendUntilTimeout(UPDATE_THROTTLE_SECONDS);
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
}
|
||||||
|
// There are two exceptions that unique_lock can trigger, operation_not_permitted or resource_deadlock_would_occur
|
||||||
|
catch (const std::system_error& e)
|
||||||
|
{
|
||||||
|
if (e.code() == std::errc::resource_deadlock_would_occur)
|
||||||
|
{
|
||||||
|
// When trying to lock the same lock a second time
|
||||||
|
LL_WARNS() << "Exception Vinvox: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
else if (e.code() == std::errc::operation_not_permitted)
|
||||||
|
{
|
||||||
|
// When the mutex is invalid
|
||||||
|
LL_WARNS() << "Exception Vinvox: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Everything else
|
||||||
|
LL_WARNS() << "Exception Vinvox: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception Vinvox: " << " " << e.what() << LL_ENDL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,9 @@
|
||||||
|
|
||||||
const std::string WEBRTC_VOICE_SERVER_TYPE = "webrtc";
|
const std::string WEBRTC_VOICE_SERVER_TYPE = "webrtc";
|
||||||
|
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
using namespace std::chrono_literals; // Needed for shared timed mutex to use time
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
const F32 MAX_AUDIO_DIST = 50.0f;
|
const F32 MAX_AUDIO_DIST = 50.0f;
|
||||||
|
|
@ -506,6 +509,12 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LLMuteList::getInstance()->addObserver(this);
|
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)
|
while (!sShuttingDown)
|
||||||
{
|
{
|
||||||
LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE("voiceConnectionCoroLoop")
|
LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE("voiceConnectionCoroLoop")
|
||||||
|
|
@ -591,6 +600,26 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
|
||||||
// to send position updates.
|
// to send position updates.
|
||||||
updatePosition();
|
updatePosition();
|
||||||
}
|
}
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
// If the device locked, count up by 1
|
||||||
|
if (gWebRTCUpdateDevices)
|
||||||
|
{
|
||||||
|
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,
|
LL::WorkQueue::postMaybe(mMainQueue,
|
||||||
[=, this] {
|
[=, this] {
|
||||||
|
|
@ -731,6 +760,19 @@ void LLWebRTCVoiceClient::OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceLi
|
||||||
void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices,
|
void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices,
|
||||||
const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices)
|
const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices)
|
||||||
{
|
{
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
try // Try catch needed for uniquie lock as will throw an exception if a second lock is attempted or the mutex is invalid
|
||||||
|
{
|
||||||
|
// Attempt to lock the access to the audio device, wait up to 1 second for other threads to unlock.
|
||||||
|
std::unique_lock lock(gAudioDeviceMutex, 1s);
|
||||||
|
// If the lock could not be accessed, return as we don't have hardware access and will need to try again another pass.
|
||||||
|
// Prevents threads from interacting with the hardware at the same time as other audio/voice threads.
|
||||||
|
if (!lock.owns_lock())
|
||||||
|
{
|
||||||
|
LL_INFOS() << "Could not access the audio device mutex, trying again later" << LL_ENDL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
if (sShuttingDown)
|
if (sShuttingDown)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
|
@ -774,6 +816,34 @@ void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDevi
|
||||||
}
|
}
|
||||||
|
|
||||||
setDevicesListUpdated(true);
|
setDevicesListUpdated(true);
|
||||||
|
// <FS:minerjr> [FIRE-36022] - Removing my USB headset crashes entire viewer
|
||||||
|
}
|
||||||
|
catch (const std::system_error& e)
|
||||||
|
{
|
||||||
|
if (e.code() == std::errc::resource_deadlock_would_occur)
|
||||||
|
{
|
||||||
|
// When trying to lock the same lock a second time
|
||||||
|
LL_WARNS() << "Exception WebRTC: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
else if (e.code() == std::errc::operation_not_permitted)
|
||||||
|
{
|
||||||
|
// When the mutex is invalid
|
||||||
|
LL_WARNS() << "Exception WebRTC: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Everything else
|
||||||
|
LL_WARNS() << "Exception WebRTC: " << e.code() << " " << e.what() << LL_ENDL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
LL_WARNS() << "Exception WebRTC: " << " " << e.what() << LL_ENDL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// </FS:minerjr> [FIRE-36022]
|
||||||
}
|
}
|
||||||
|
|
||||||
void LLWebRTCVoiceClient::clearRenderDevices()
|
void LLWebRTCVoiceClient::clearRenderDevices()
|
||||||
|
|
@ -848,6 +918,11 @@ void LLWebRTCVoiceClient::tuningSetSpeakerVolume(float volume)
|
||||||
|
|
||||||
float LLWebRTCVoiceClient::tuningGetEnergy(void)
|
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();
|
float rms = mWebRTCDeviceInterface->getTuningAudioLevel();
|
||||||
return TUNING_LEVEL_START_POINT - TUNING_LEVEL_SCALE * rms;
|
return TUNING_LEVEL_START_POINT - TUNING_LEVEL_SCALE * rms;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue