Merge branch 'master' of https://github.com/FirestormViewer/phoenix-firestorm
commit
574dc5b65a
|
|
@ -39,6 +39,10 @@
|
|||
#include "llframetimer.h"
|
||||
#include "llassettype.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"
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,9 @@
|
|||
|
||||
#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;
|
||||
|
||||
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;
|
||||
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;
|
||||
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());
|
||||
audio_engine->OnOutputDeviceListChanged(audio_engine->getDevices());
|
||||
}
|
||||
|
|
@ -132,6 +152,34 @@ FMOD_RESULT F_CALL systemCallback(FMOD_SYSTEM *system, FMOD_SYSTEM_CALLBACK_TYPE
|
|||
break;
|
||||
}
|
||||
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)
|
||||
|
|
@ -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;
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
// <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)
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ set(llcommon_HEADER_FILES
|
|||
fsyspath.h
|
||||
function_types.h
|
||||
indra_constants.h
|
||||
inlinemutexs.h
|
||||
lazyeventapi.h
|
||||
linden_common.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 <algorithm>
|
||||
#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_encoder_factory.h"
|
||||
|
|
@ -39,6 +44,14 @@
|
|||
#include "modules/audio_mixer/audio_mixer_impl.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
|
||||
{
|
||||
#if WEBRTC_WIN
|
||||
|
|
@ -269,7 +282,11 @@ void LLWebRTCImpl::init()
|
|||
webrtc::InitializeSSL();
|
||||
|
||||
// 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_VERBOSE);
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
webrtc::LogMessage::SetLogToStderr(true);
|
||||
webrtc::LogMessage::AddLogToStream(mLogSink, webrtc::LS_VERBOSE);
|
||||
|
||||
|
|
@ -457,8 +474,24 @@ void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer)
|
|||
// must be run in the worker thread.
|
||||
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)
|
||||
{
|
||||
// <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;
|
||||
}
|
||||
|
||||
|
|
@ -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->ForceStopRecording();
|
||||
#if WEBRTC_WIN
|
||||
|
|
@ -546,6 +583,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.
|
||||
gWebRTCUpdateDevices = false;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
mSignalingThread->PostTask(
|
||||
[this]
|
||||
{
|
||||
|
|
@ -566,6 +607,38 @@ void LLWebRTCImpl::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)
|
||||
|
|
@ -584,11 +657,27 @@ void LLWebRTCImpl::setRenderDevice(const std::string &id)
|
|||
// updateDevices needs to happen on the worker thread.
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
mPlayoutDeviceList.clear();
|
||||
|
|
@ -625,10 +714,46 @@ 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.
|
||||
gWebRTCUpdateDevices = false;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
for (auto &observer : mVoiceDevicesObserverList)
|
||||
{
|
||||
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()
|
||||
|
|
@ -726,7 +851,56 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms)
|
|||
{
|
||||
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();
|
||||
// <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));
|
||||
|
|
@ -738,8 +912,57 @@ void LLWebRTCImpl::intSetMute(bool mute, int delay_ms)
|
|||
{
|
||||
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->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 <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> gWebRTCUpdateDevices = false;
|
||||
// </FS:minerjr> [FIRE-36022]
|
||||
namespace llwebrtc
|
||||
{
|
||||
|
||||
|
|
|
|||
|
|
@ -1016,6 +1016,11 @@ bool LLAppViewerWin32::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)
|
||||
{
|
||||
FreeConsole();
|
||||
|
|
@ -1056,6 +1061,19 @@ bool LLAppViewerWin32::initWindow()
|
|||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ class LLVOAvatar;
|
|||
#include "llcallingcard.h" // for LLFriendObserver
|
||||
#include "llsecapi.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
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ extern void handle_voice_morphing_subscribe();
|
|||
|
||||
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 {
|
||||
const F32 VOLUME_SCALE_VIVOX = 0.01f;
|
||||
|
||||
|
|
@ -2413,6 +2416,19 @@ void LLVivoxVoiceClient::sendCaptureAndRenderDevices()
|
|||
{
|
||||
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;
|
||||
|
||||
buildSetCaptureDevice(stream);
|
||||
|
|
@ -2424,6 +2440,35 @@ void LLVivoxVoiceClient::sendCaptureAndRenderDevices()
|
|||
}
|
||||
|
||||
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";
|
||||
|
||||
// <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 {
|
||||
|
||||
const F32 MAX_AUDIO_DIST = 50.0f;
|
||||
|
|
@ -506,6 +509,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 +600,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 (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,
|
||||
[=, this] {
|
||||
|
|
@ -731,6 +760,19 @@ void LLWebRTCVoiceClient::OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceLi
|
|||
void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDeviceList &render_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)
|
||||
{
|
||||
return;
|
||||
|
|
@ -774,6 +816,34 @@ void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDevi
|
|||
}
|
||||
|
||||
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()
|
||||
|
|
@ -848,6 +918,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