# Conflicts:
#	autobuild.xml
#	indra/llcommon/llprofilercategories.h
#	indra/llwebrtc/llwebrtc.cpp
#	indra/newview/app_settings/settings.xml
#	indra/newview/llimview.cpp
#	indra/newview/skins/default/xui/en/panel_preferences_sound.xml
master
Ansariel 2024-04-16 12:53:16 +02:00
commit 89b5410d0c
13 changed files with 965 additions and 541 deletions

View File

@ -3256,11 +3256,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>8b0191fae0860782a3e79b886364129c433cfd6b</string>
<string>a49fb3bb8aaf8325e7c6c4b6036db3da16afa2c9</string>
<key>hash_algorithm</key>
<string>md5</string>
<key>url</key>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.52/webrtc-m114.5735.08.52.8319849783-darwin64-8319849783.tar.zst</string>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.53/webrtc-m114.5735.08.53.8337236647-darwin64-8337236647.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3270,11 +3270,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>699b4fb87e20bdc05e76a32c84688fa21a16785d</string>
<string>598baa054f63624a8e16883541c1f3dc7aa15a8a</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.55/webrtc-m114.5735.08.55.8404951738-linux64-8404951738.tar.zst</string>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.53/webrtc-m114.5735.08.53.8337236647-linux64-8337236647.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@ -3284,11 +3284,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>64eccac933cee532dc065d9f9729a21d8347aae4</string>
<string>59d5f2e40612ab7b0b1a5da8ba288f48d5979216</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.52/webrtc-m114.5735.08.52.8319849783-windows64-8319849783.tar.zst</string>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.53/webrtc-m114.5735.08.53.8337236647-windows64-8337236647.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@ -3301,7 +3301,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>vcs_url</key>
<string>https://github.com/secondlife/3p-webrtc-build</string>
<key>version</key>
<string>m114.5735.08.52.8319849783</string>
<string>m114.5735.08.53.8337236647</string>
</map>
<key>xmlrpc-epi</key>
<map>

View File

@ -1,5 +1,5 @@
/**
* @file llprofiler_ategories.h
* @file llprofilercategories.h
* @brief Profiling categories to minimize Tracy memory usage when viewing captures.
*
* $LicenseInfo:firstyear=2022&license=viewerlgpl$
@ -33,7 +33,7 @@
// LL_PROFILER_CATEGORY_ENABLE_DRAWPOOL
// LL_PROFILER_CATEGORY_ENABLE_LLSD
// LL_PROFILER_CATEGORY_ENABLE_MEMORY
// LL_PROFILER_CATEGORY_ENABLE_SHADERS
// LL_PROFILER_CATEGORY_ENABLE_SHADER
//
// NOTE: You can still manually use:
// LL_PROFILE_ZONE_SCOPED();
@ -68,6 +68,7 @@
#define LL_PROFILER_CATEGORY_ENABLE_VERTEX 1
#define LL_PROFILER_CATEGORY_ENABLE_VOLUME 1
#define LL_PROFILER_CATEGORY_ENABLE_WIN32 0 // <FS:Beq/> Rationalise this silliness
#define LL_PROFILER_CATEGORY_ENABLE_VOICE 1
#if LL_PROFILER_CATEGORY_ENABLE_APP
#define LL_PROFILE_ZONE_NAMED_CATEGORY_APP LL_PROFILE_ZONE_NAMED
@ -287,5 +288,13 @@
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_WIN32
#endif
#if LL_PROFILER_CATEGORY_ENABLE_VOICE
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE LL_PROFILE_ZONE_NAMED
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE LL_PROFILE_ZONE_SCOPED
#else
#define LL_PROFILE_ZONE_NAMED_CATEGORY_VOICE(name)
#define LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE
#endif
#endif // LL_PROFILER_CATEGORIES_H

View File

@ -26,14 +26,6 @@
#include "llwebrtc_impl.h"
#include <algorithm>
/*<FS:PC> Only available for much newer compilers on linux (fine with GCC 13).
This causes grief with some older compilers (like GCC 10). Since it doesnt appear
to be needed (at least when building the viewer on linux, dont try and include it*/
#ifndef __linux__
#include <format>
#endif
#include <string.h>
#include "api/audio_codecs/audio_decoder_factory.h"
@ -47,6 +39,11 @@ to be needed (at least when building the viewer on linux, dont try and include i
namespace llwebrtc
{
static int16_t PLAYOUT_DEVICE_DEFAULT = -1;
static int16_t PLAYOUT_DEVICE_BAD = -2;
static int16_t RECORD_DEVICE_DEFAULT = -1;
static int16_t RECORD_DEVICE_BAD = -2;
LLAudioDeviceObserver::LLAudioDeviceObserver() : mSumVector {0}, mMicrophoneEnergy(0.0) {}
float LLAudioDeviceObserver::getMicrophoneEnergy() { return mMicrophoneEnergy; }
@ -164,7 +161,6 @@ LLWebRTCImpl::LLWebRTCImpl() :
void LLWebRTCImpl::init()
{
RTC_DCHECK(mPeerConnectionFactory);
mPlayoutDevice = 0;
mRecordingDevice = 0;
rtc::InitializeSSL();
@ -197,10 +193,16 @@ void LLWebRTCImpl::init()
std::unique_ptr<webrtc::AudioDeviceDataObserver>(mTuningAudioDeviceObserver));
mTuningDeviceModule->Init();
mTuningDeviceModule->SetStereoRecording(true);
mTuningDeviceModule->SetStereoPlayout(true);
mTuningDeviceModule->SetPlayoutDevice(mPlayoutDevice);
mTuningDeviceModule->SetRecordingDevice(mRecordingDevice);
mTuningDeviceModule->EnableBuiltInAEC(false);
mTuningDeviceModule->SetAudioDeviceSink(this);
mTuningDeviceModule->InitMicrophone();
mTuningDeviceModule->InitSpeaker();
mTuningDeviceModule->InitRecording();
mTuningDeviceModule->InitPlayout();
mTuningDeviceModule->SetStereoRecording(true);
mTuningDeviceModule->SetStereoPlayout(true);
updateDevices();
});
@ -215,13 +217,13 @@ void LLWebRTCImpl::init()
mPeerDeviceModule->Init();
mPeerDeviceModule->SetPlayoutDevice(mPlayoutDevice);
mPeerDeviceModule->SetRecordingDevice(mRecordingDevice);
mPeerDeviceModule->SetStereoRecording(true);
mPeerDeviceModule->SetStereoPlayout(true);
mPeerDeviceModule->EnableBuiltInAEC(false);
mPeerDeviceModule->InitMicrophone();
mPeerDeviceModule->InitSpeaker();
mPeerDeviceModule->InitRecording();
mPeerDeviceModule->InitPlayout();
mPeerDeviceModule->SetStereoRecording(true);
mPeerDeviceModule->SetStereoPlayout(true);
});
// The custom processor allows us to retrieve audio data (and levels)
@ -229,12 +231,10 @@ void LLWebRTCImpl::init()
mPeerCustomProcessor = new LLCustomProcessor;
webrtc::AudioProcessingBuilder apb;
apb.SetCapturePostProcessing(std::unique_ptr<webrtc::CustomProcessing>(mPeerCustomProcessor));
rtc::scoped_refptr<webrtc::AudioProcessing> apm = apb.Create();
mAudioProcessingModule = apb.Create();
// TODO: wire some of these to the primary interface and ultimately
// to the UI to allow user config.
webrtc::AudioProcessing::Config apm_config;
apm_config.echo_canceller.enabled = true;
apm_config.echo_canceller.enabled = false;
apm_config.echo_canceller.mobile_mode = false;
apm_config.gain_controller1.enabled = true;
apm_config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kAdaptiveAnalog;
@ -249,16 +249,16 @@ void LLWebRTCImpl::init()
webrtc::ProcessingConfig processing_config;
processing_config.input_stream().set_num_channels(2);
processing_config.input_stream().set_sample_rate_hz(8000);
processing_config.input_stream().set_sample_rate_hz(48000);
processing_config.output_stream().set_num_channels(2);
processing_config.output_stream().set_sample_rate_hz(8000);
processing_config.output_stream().set_sample_rate_hz(48000);
processing_config.reverse_input_stream().set_num_channels(2);
processing_config.reverse_input_stream().set_sample_rate_hz(48000);
processing_config.reverse_output_stream().set_num_channels(2);
processing_config.reverse_output_stream().set_sample_rate_hz(48000);
apm->Initialize(processing_config);
apm->ApplyConfig(apm_config);
mAudioProcessingModule->ApplyConfig(apm_config);
mAudioProcessingModule->Initialize(processing_config);
mPeerConnectionFactory = webrtc::CreatePeerConnectionFactory(mNetworkThread.get(),
mWorkerThread.get(),
@ -269,7 +269,7 @@ void LLWebRTCImpl::init()
nullptr /* video_encoder_factory */,
nullptr /* video_decoder_factory */,
nullptr /* audio_mixer */,
apm);
mAudioProcessingModule);
mWorkerThread->BlockingCall([this]() { mPeerDeviceModule->StartPlayout(); });
}
@ -325,6 +325,49 @@ void LLWebRTCImpl::setRecording(bool recording)
});
}
void LLWebRTCImpl::setAudioConfig(LLWebRTCDeviceInterface::AudioConfig config)
{
webrtc::AudioProcessing::Config apm_config;
apm_config.echo_canceller.enabled = config.mEchoCancellation;
apm_config.echo_canceller.mobile_mode = false;
apm_config.gain_controller1.enabled = true;
apm_config.gain_controller1.mode = webrtc::AudioProcessing::Config::GainController1::kAdaptiveAnalog;
apm_config.gain_controller2.enabled = true;
apm_config.high_pass_filter.enabled = true;
apm_config.transient_suppression.enabled = true;
apm_config.pipeline.multi_channel_render = true;
apm_config.pipeline.multi_channel_capture = true;
apm_config.pipeline.multi_channel_capture = true;
switch (config.mNoiseSuppressionLevel)
{
case LLWebRTCDeviceInterface::AudioConfig::NOISE_SUPPRESSION_LEVEL_NONE:
apm_config.noise_suppression.enabled = false;
apm_config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kLow;
break;
case LLWebRTCDeviceInterface::AudioConfig::NOISE_SUPPRESSION_LEVEL_LOW:
apm_config.noise_suppression.enabled = true;
apm_config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kLow;
break;
case LLWebRTCDeviceInterface::AudioConfig::NOISE_SUPPRESSION_LEVEL_MODERATE:
apm_config.noise_suppression.enabled = true;
apm_config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kModerate;
break;
case LLWebRTCDeviceInterface::AudioConfig::NOISE_SUPPRESSION_LEVEL_HIGH:
apm_config.noise_suppression.enabled = true;
apm_config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kHigh;
break;
case LLWebRTCDeviceInterface::AudioConfig::NOISE_SUPPRESSION_LEVEL_VERY_HIGH:
apm_config.noise_suppression.enabled = true;
apm_config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kVeryHigh;
break;
default:
apm_config.noise_suppression.enabled = false;
apm_config.noise_suppression.level = webrtc::AudioProcessing::Config::NoiseSuppression::kLow;
}
mAudioProcessingModule->ApplyConfig(apm_config);
}
void LLWebRTCImpl::refreshDevices()
{
mWorkerThread->PostTask([this]() { updateDevices(); });
@ -342,145 +385,169 @@ void LLWebRTCImpl::unsetDevicesObserver(LLWebRTCDevicesObserver *observer)
}
}
static int16_t ll_get_device_module_capture_device(rtc::scoped_refptr<webrtc::AudioDeviceModule> device_module, const std::string &id)
{
int16_t recordingDevice = 0;
int16_t captureDeviceCount = device_module->RecordingDevices();
for (int16_t i = 0; i < captureDeviceCount; i++)
{
char name[webrtc::kAdmMaxDeviceNameSize];
char guid[webrtc::kAdmMaxGuidSize];
device_module->RecordingDeviceName(i, name, guid);
if (id == guid || id == "Default") // first one in list is default
{
RTC_LOG(LS_INFO) << __FUNCTION__ << "Set recording device to " << name << " " << guid << " " << i;
recordingDevice = i;
break;
}
}
return recordingDevice;
}
void ll_set_device_module_capture_device(rtc::scoped_refptr<webrtc::AudioDeviceModule> device_module, int16_t device)
{
device_module->StopRecording();
device_module->SetRecordingDevice(device);
#if WEBRTC_WIN
if (device < 0)
{
device_module->SetRecordingDevice(webrtc::AudioDeviceModule::kDefaultDevice);
}
else
{
device_module->SetRecordingDevice(device);
}
#else
// passed in default is -1, but the device list
// has it at 0
device_module->SetRecordingDevice(device + 1);
#endif
device_module->InitMicrophone();
device_module->SetStereoRecording(false);
device_module->InitRecording();
device_module->SetStereoRecording(false);
device_module->StartRecording();
}
void LLWebRTCImpl::setCaptureDevice(const std::string &id)
{
mWorkerThread->PostTask(
[this, id]()
{
int16_t recordingDevice = ll_get_device_module_capture_device(mTuningDeviceModule, id);
if (recordingDevice != mRecordingDevice)
{
mRecordingDevice = recordingDevice;
if (mTuningMode)
{
ll_set_device_module_capture_device(mTuningDeviceModule, recordingDevice);
}
else
{
ll_set_device_module_capture_device(mPeerDeviceModule, recordingDevice);
}
}
});
}
static int16_t ll_get_device_module_render_device(
rtc::scoped_refptr<webrtc::AudioDeviceModule> device_module,
const std::string &id)
{
int16_t playoutDevice = 0;
int16_t playoutDeviceCount = device_module->PlayoutDevices();
for (int16_t i = 0; i < playoutDeviceCount; i++)
int16_t recordingDevice = RECORD_DEVICE_DEFAULT;
if (id != "Default")
{
char name[webrtc::kAdmMaxDeviceNameSize];
char guid[webrtc::kAdmMaxGuidSize];
device_module->PlayoutDeviceName(i, name, guid);
if (id == guid || id == "Default") // first one in list is default
for (int16_t i = 0; i < mRecordingDeviceList.size(); i++)
{
RTC_LOG(LS_INFO) << __FUNCTION__ << "Set recording device to " << name << " " << guid << " " << i;
playoutDevice = i;
break;
if (mRecordingDeviceList[i].mID == id)
{
recordingDevice = i;
break;
}
}
}
return playoutDevice;
if (recordingDevice == mRecordingDevice)
{
return;
}
mRecordingDevice = recordingDevice;
if (mTuningMode)
{
mWorkerThread->PostTask([this, recordingDevice]() { ll_set_device_module_capture_device(mTuningDeviceModule, recordingDevice); });
}
else
{
mWorkerThread->PostTask([this, recordingDevice]() { ll_set_device_module_capture_device(mPeerDeviceModule, recordingDevice); });
}
}
void ll_set_device_module_render_device(rtc::scoped_refptr<webrtc::AudioDeviceModule> device_module, int16_t device)
{
device_module->StopPlayout();
device_module->SetPlayoutDevice(device);
#if WEBRTC_WIN
if (device < 0)
{
device_module->SetPlayoutDevice(webrtc::AudioDeviceModule::kDefaultDevice);
}
else
{
device_module->SetPlayoutDevice(device);
}
#else
device_module->SetPlayoutDevice(device + 1);
#endif
device_module->InitSpeaker();
device_module->SetStereoPlayout(false);
device_module->InitPlayout();
device_module->StartPlayout();
device_module->SetStereoPlayout(true);
}
void LLWebRTCImpl::setRenderDevice(const std::string &id)
{
mWorkerThread->PostTask(
[this, id]()
{
int16_t playoutDevice = ll_get_device_module_render_device(mTuningDeviceModule, id);
if (playoutDevice != mPlayoutDevice)
int16_t playoutDevice = PLAYOUT_DEVICE_DEFAULT;
if (id != "Default")
{
for (int16_t i = 0; i < mPlayoutDeviceList.size(); i++)
{
if (mPlayoutDeviceList[i].mID == id)
{
mPlayoutDevice = playoutDevice;
if (mTuningMode)
{
ll_set_device_module_render_device(mTuningDeviceModule, playoutDevice);
}
else
{
ll_set_device_module_render_device(mPeerDeviceModule, playoutDevice);
}
playoutDevice = i;
break;
}
});
}
}
if (playoutDevice == mPlayoutDevice)
{
return;
}
mPlayoutDevice = playoutDevice;
if (mTuningMode)
{
mWorkerThread->PostTask(
[this, playoutDevice]()
{
ll_set_device_module_render_device(mTuningDeviceModule, playoutDevice);
});
}
else
{
mWorkerThread->PostTask(
[this, playoutDevice]()
{
ll_set_device_module_render_device(mPeerDeviceModule, playoutDevice);
mPeerDeviceModule->StartPlayout();
});
}
}
// updateDevices needs to happen on the worker thread.
void LLWebRTCImpl::updateDevices()
{
int16_t renderDeviceCount = mTuningDeviceModule->PlayoutDevices();
int16_t currentRenderDeviceIndex = mTuningDeviceModule->GetPlayoutDevice();
int16_t renderDeviceCount = mTuningDeviceModule->PlayoutDevices();
LLWebRTCVoiceDeviceList renderDeviceList;
for (int16_t index = 0; index < renderDeviceCount; index++)
mPlayoutDeviceList.clear();
#if WEBRTC_WIN
int16_t index = 0;
#else
// index zero is always "Default" for darwin/linux,
// which is a special case, so skip it.
int16_t index = 1;
#endif
for (; index < renderDeviceCount; index++)
{
char name[webrtc::kAdmMaxDeviceNameSize];
char guid[webrtc::kAdmMaxGuidSize];
mTuningDeviceModule->PlayoutDeviceName(index, name, guid);
renderDeviceList.emplace_back(name, guid);
mPlayoutDeviceList.emplace_back(name, guid);
}
int16_t captureDeviceCount = mTuningDeviceModule->RecordingDevices();
int16_t currentCaptureDeviceIndex = mTuningDeviceModule->GetRecordingDevice();
int16_t captureDeviceCount = mTuningDeviceModule->RecordingDevices();
LLWebRTCVoiceDeviceList captureDeviceList;
for (int16_t index = 0; index < captureDeviceCount; index++)
mRecordingDeviceList.clear();
#if WEBRTC_WIN
index = 0;
#else
// index zero is always "Default" for darwin/linux,
// which is a special case, so skip it.
index = 1;
#endif
for (; index < captureDeviceCount; index++)
{
char name[webrtc::kAdmMaxDeviceNameSize];
char guid[webrtc::kAdmMaxGuidSize];
mTuningDeviceModule->RecordingDeviceName(index, name, guid);
captureDeviceList.emplace_back(name, guid);
mRecordingDeviceList.emplace_back(name, guid);
}
for (auto &observer : mVoiceDevicesObserverList)
{
observer->OnDevicesChanged(renderDeviceList,
captureDeviceList);
observer->OnDevicesChanged(mPlayoutDeviceList, mRecordingDeviceList);
}
}
void LLWebRTCImpl::OnDevicesUpdated()
{
// reset these to a bad value so an update is forced
mRecordingDevice = RECORD_DEVICE_BAD;
mPlayoutDevice = PLAYOUT_DEVICE_BAD;
updateDevices();
}
@ -496,17 +563,24 @@ void LLWebRTCImpl::setTuningMode(bool enable)
mPeerDeviceModule->StopPlayout();
ll_set_device_module_render_device(mTuningDeviceModule, mPlayoutDevice);
ll_set_device_module_capture_device(mTuningDeviceModule, mRecordingDevice);
mTuningDeviceModule->InitPlayout();
mTuningDeviceModule->InitRecording();
mTuningDeviceModule->StartRecording();
mTuningDeviceModule->StartPlayout();
// TODO: Starting Playout on the TDM appears to create an audio artifact (click)
// in this case, so disabling it for now. We may have to do something different
// if we enable 'echo playback' via the TDM when tuning.
//mTuningDeviceModule->StartPlayout();
}
else
{
mTuningDeviceModule->StopRecording();
mTuningDeviceModule->StopPlayout();
//mTuningDeviceModule->StopPlayout();
ll_set_device_module_render_device(mPeerDeviceModule, mPlayoutDevice);
ll_set_device_module_capture_device(mPeerDeviceModule, mRecordingDevice);
mPeerDeviceModule->StartRecording();
mPeerDeviceModule->InitPlayout();
mPeerDeviceModule->InitRecording();
mPeerDeviceModule->StartPlayout();
mPeerDeviceModule->StartRecording();
}
}
);
@ -569,8 +643,10 @@ void LLWebRTCImpl::freePeerConnection(LLWebRTCPeerConnectionInterface* peer_conn
// Most peer connection (signaling) happens on
// the signaling thread.
LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() :
LLWebRTCPeerConnectionImpl::LLWebRTCPeerConnectionImpl() :
mWebRTCImpl(nullptr),
mClosing(false),
mPeerConnection(nullptr),
mMute(false),
mAnswerReceived(false)
{
@ -587,13 +663,27 @@ void LLWebRTCPeerConnectionImpl::init(LLWebRTCImpl * webrtc_impl)
}
void LLWebRTCPeerConnectionImpl::terminate()
{
mWebRTCImpl->SignalingBlockingCall(
[this]()
rtc::scoped_refptr<webrtc::PeerConnectionInterface> connection;
mPeerConnection.swap(connection);
rtc::scoped_refptr<webrtc::DataChannelInterface> dataChannel;
mDataChannel.swap(dataChannel);
rtc::scoped_refptr<webrtc::MediaStreamInterface> localStream;
mLocalStream.swap(localStream);
mSignalingObserverList.clear();
mDataObserverList.clear();
mWebRTCImpl->PostSignalingTask(
[=]()
{
if (mPeerConnection)
if (connection)
{
mPeerConnection->Close();
mPeerConnection = nullptr;
connection->Close();
}
if (dataChannel)
{
dataChannel->UnregisterObserver();
dataChannel->Close();
}
});
}
@ -610,32 +700,28 @@ void LLWebRTCPeerConnectionImpl::unsetSignalingObserver(LLWebRTCSignalingObserve
}
}
// TODO: Add initialization structure through which
// stun and turn servers may be passed in from
// the sim or login.
bool LLWebRTCPeerConnectionImpl::initializeConnection()
bool LLWebRTCPeerConnectionImpl::initializeConnection(const LLWebRTCPeerConnectionInterface::InitOptions& options)
{
RTC_DCHECK(!mPeerConnection);
mAnswerReceived = false;
mWebRTCImpl->PostSignalingTask(
[this]()
[this,options]()
{
webrtc::PeerConnectionInterface::RTCConfiguration config;
for (auto server : options.mServers)
{
webrtc::PeerConnectionInterface::IceServer ice_server;
for (auto url : server.mUrls)
{
ice_server.urls.push_back(url);
}
ice_server.username = server.mUserName;
ice_server.password = server.mPassword;
config.servers.push_back(ice_server);
}
config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
webrtc::PeerConnectionInterface::IceServer server;
server.uri = "stun:roxie-turn.staging.secondlife.io:3478";
config.servers.push_back(server);
server.uri = "stun:stun.l.google.com:19302";
config.servers.push_back(server);
server.uri = "stun:stun1.l.google.com:19302";
config.servers.push_back(server);
server.uri = "stun:stun2.l.google.com:19302";
config.servers.push_back(server);
server.uri = "stun:stun3.l.google.com:19302";
config.servers.push_back(server);
server.uri = "stun:stun4.l.google.com:19302";
config.servers.push_back(server);
config.set_min_port(60000);
config.set_max_port(60100);
@ -665,7 +751,7 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection()
cricket::AudioOptions audioOptions;
audioOptions.auto_gain_control = true;
audioOptions.echo_cancellation = true; // incompatible with opus stereo
audioOptions.echo_cancellation = true;
audioOptions.noise_suppression = true;
mLocalStream = mPeerConnectionFactory->CreateLocalMediaStream("SLStream");
@ -717,24 +803,9 @@ bool LLWebRTCPeerConnectionImpl::initializeConnection()
bool LLWebRTCPeerConnectionImpl::shutdownConnection()
{
if (mPeerConnection)
{
mWebRTCImpl->PostSignalingTask(
[this]()
{
if (mPeerConnection)
{
mPeerConnection->Close();
mPeerConnection = nullptr;
}
for (auto &observer : mSignalingObserverList)
{
observer->OnPeerConnectionShutdown();
}
});
return true;
}
return false;
mClosing = true;
terminate();
return true;
}
void LLWebRTCPeerConnectionImpl::enableSenderTracks(bool enable)
@ -1064,19 +1135,25 @@ void LLWebRTCPeerConnectionImpl::OnSuccess(webrtc::SessionDescriptionInterface *
}
RTC_LOG(LS_INFO) << __FUNCTION__ << " Local SDP: " << sdp_mangled_stream.str();
std::string mangled_sdp = sdp_mangled_stream.str();
for (auto &observer : mSignalingObserverList)
{
observer->OnOfferAvailable(sdp_mangled_stream.str());
observer->OnOfferAvailable(mangled_sdp);
}
mPeerConnection->SetLocalDescription(std::unique_ptr<webrtc::SessionDescriptionInterface>(
webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, mangled_sdp)),
rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface>(this));
mPeerConnection->SetLocalDescription(std::unique_ptr<webrtc::SessionDescriptionInterface>(webrtc::CreateSessionDescription(webrtc::SdpType::kOffer, sdp_mangled_stream.str())),
rtc::scoped_refptr<webrtc::SetLocalDescriptionObserverInterface>(this));
}
void LLWebRTCPeerConnectionImpl::OnFailure(webrtc::RTCError error)
{
RTC_LOG(LS_ERROR) << ToString(error.type()) << ": " << error.message();
for (auto &observer : mSignalingObserverList)
{
observer->OnRenegotiationNeeded();
}
}
//
@ -1090,6 +1167,10 @@ void LLWebRTCPeerConnectionImpl::OnSetRemoteDescriptionComplete(webrtc::RTCError
if (!error.ok())
{
RTC_LOG(LS_ERROR) << ToString(error.type()) << ": " << error.message();
for (auto &observer : mSignalingObserverList)
{
observer->OnRenegotiationNeeded();
}
return;
}
mAnswerReceived = true;
@ -1107,7 +1188,10 @@ void LLWebRTCPeerConnectionImpl::OnSetRemoteDescriptionComplete(webrtc::RTCError
}
}
mCachedIceCandidates.clear();
OnIceGatheringChange(mPeerConnection->ice_gathering_state());
if (mPeerConnection)
{
OnIceGatheringChange(mPeerConnection->ice_gathering_state());
}
}
@ -1124,6 +1208,10 @@ void LLWebRTCPeerConnectionImpl::OnSetLocalDescriptionComplete(webrtc::RTCError
void LLWebRTCPeerConnectionImpl::OnStateChange()
{
if (!mDataChannel)
{
return;
}
RTC_LOG(LS_INFO) << __FUNCTION__ << " Data Channel State: " << webrtc::DataChannelInterface::DataStateString(mDataChannel->state());
switch (mDataChannel->state())
{
@ -1167,7 +1255,12 @@ void LLWebRTCPeerConnectionImpl::sendData(const std::string& data, bool binary)
{
rtc::CopyOnWriteBuffer cowBuffer(data.data(), data.length());
webrtc::DataBuffer buffer(cowBuffer, binary);
mDataChannel->Send(buffer);
mWebRTCImpl->PostNetworkTask([this, buffer]() {
if (mDataChannel)
{
mDataChannel->Send(buffer);
}
});
}
}

View File

@ -78,7 +78,12 @@ class LLWebRTCVoiceDevice
LLWebRTCVoiceDevice(const std::string &display_name, const std::string &id) :
mDisplayName(display_name),
mID(id)
{};
{
if (mID.empty())
{
mID = display_name;
}
};
};
typedef std::vector<LLWebRTCVoiceDevice> LLWebRTCVoiceDeviceList;
@ -99,10 +104,32 @@ class LLWebRTCDevicesObserver
// to enumerate, set, and get notifications of changes
// for both capture (microphone) and render (speaker)
// devices.
class LLWebRTCDeviceInterface
{
public:
struct AudioConfig {
bool mAGC { true };
bool mEchoCancellation { true };
// TODO: The various levels of noise suppression are configured
// on the APM which would require setting config on the APM.
// We should pipe the various values through
// later.
typedef enum {
NOISE_SUPPRESSION_LEVEL_NONE = 0,
NOISE_SUPPRESSION_LEVEL_LOW,
NOISE_SUPPRESSION_LEVEL_MODERATE,
NOISE_SUPPRESSION_LEVEL_HIGH,
NOISE_SUPPRESSION_LEVEL_VERY_HIGH
} ENoiseSuppressionLevel;
ENoiseSuppressionLevel mNoiseSuppressionLevel { NOISE_SUPPRESSION_LEVEL_VERY_HIGH };
};
virtual void setAudioConfig(AudioConfig config) = 0;
// instructs webrtc to refresh the device list.
virtual void refreshDevices() = 0;
@ -192,24 +219,38 @@ class LLWebRTCSignalingObserver
// Called when the data channel has been established and data
// transfer can begin.
virtual void OnDataChannelReady(LLWebRTCDataInterface *data_interface) = 0;
// Called when a peer connection has finished shutting down.
virtual void OnPeerConnectionShutdown() = 0;
};
// LLWebRTCPeerConnectionInterface representsd a connection to a peer,
// in most cases a Secondlife WebRTC server. This interface
// allows for management of this peer connection.
class LLWebRTCPeerConnectionInterface
{
public:
struct InitOptions
{
// equivalent of PeerConnectionInterface::IceServer
struct IceServers {
// Valid formats are described in RFC7064 and RFC7065.
// Urls should containe dns hostnames (not IP addresses)
// as the TLS certificate policy is 'secure.'
// and we do not currentply support TLS extensions.
std::vector<std::string> mUrls;
std::string mUserName;
std::string mPassword;
};
std::vector<IceServers> mServers;
};
virtual bool initializeConnection(const InitOptions& options) = 0;
virtual bool shutdownConnection() = 0;
virtual void setSignalingObserver(LLWebRTCSignalingObserver* observer) = 0;
virtual void unsetSignalingObserver(LLWebRTCSignalingObserver* observer) = 0;
virtual bool initializeConnection() = 0;
virtual bool shutdownConnection() = 0;
virtual void AnswerAvailable(const std::string &sdp) = 0;
};

View File

@ -146,6 +146,8 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS
// LLWebRTCDeviceInterface
//
void setAudioConfig(LLWebRTCDeviceInterface::AudioConfig config = LLWebRTCDeviceInterface::AudioConfig()) override;
void refreshDevices() override;
void setDevicesObserver(LLWebRTCDevicesObserver *observer) override;
@ -228,6 +230,8 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS
// The factory that allows creation of native webrtc PeerConnections.
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory;
rtc::scoped_refptr<webrtc::AudioProcessing> mAudioProcessingModule;
// more native webrtc stuff
std::unique_ptr<webrtc::TaskQueueFactory> mTaskQueueFactory;
@ -241,8 +245,12 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS
// accessors in native webrtc for devices aren't apparently implemented yet.
bool mTuningMode;
int32_t mPlayoutDevice;
int32_t mRecordingDevice;
LLWebRTCVoiceDeviceList mRecordingDeviceList;
int32_t mPlayoutDevice;
LLWebRTCVoiceDeviceList mPlayoutDeviceList;
bool mMute;
LLAudioDeviceObserver * mTuningAudioDeviceObserver;
@ -279,11 +287,11 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
//
// LLWebRTCPeerConnection
//
bool initializeConnection(const InitOptions& options) override;
bool shutdownConnection() override;
void setSignalingObserver(LLWebRTCSignalingObserver *observer) override;
void unsetSignalingObserver(LLWebRTCSignalingObserver *observer) override;
bool initializeConnection() override;
bool shutdownConnection() override;
void AnswerAvailable(const std::string &sdp) override;
//
@ -347,21 +355,23 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
LLWebRTCImpl * mWebRTCImpl;
bool mClosing;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory;
bool mMute;
bool mMute;
// signaling
std::vector<LLWebRTCSignalingObserver *> mSignalingObserverList;
std::vector<LLWebRTCSignalingObserver *> mSignalingObserverList;
std::vector<std::unique_ptr<webrtc::IceCandidateInterface>> mCachedIceCandidates;
bool mAnswerReceived;
bool mAnswerReceived;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> mPeerConnection;
rtc::scoped_refptr<webrtc::MediaStreamInterface> mLocalStream;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> mPeerConnection;
rtc::scoped_refptr<webrtc::MediaStreamInterface> mLocalStream;
// data
std::vector<LLWebRTCDataObserver *> mDataObserverList;
rtc::scoped_refptr<webrtc::DataChannelInterface> mDataChannel;
std::vector<LLWebRTCDataObserver *> mDataObserverList;
rtc::scoped_refptr<webrtc::DataChannelInterface> mDataChannel;
};
}

View File

@ -18612,6 +18612,39 @@ Change of this parameter will affect the layout of buttons in notification toast
<key>Backup</key>
<integer>0</integer>
</map>
<key>VoiceEchoCancellation</key>
<map>
<key>Comment</key>
<string>Voice Echo Cancellation</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>VoiceAutomaticGainControl</key>
<map>
<key>Comment</key>
<string>Voice Automatic Gain Control</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>Boolean</string>
<key>Value</key>
<integer>1</integer>
</map>
<key>VoiceNoiseSuppressionLevel</key>
<map>
<key>Comment</key>
<string>Voice Noise Suppression Level</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>U32</string>
<key>Value</key>
<integer>4</integer>
</map>
<key>WarningsAsChat</key>
<map>
<key>Comment</key>

View File

@ -123,7 +123,7 @@ enum EMultiAgentChatSessionType
void startConferenceCoro(std::string url, LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId, LLSD agents);
void startP2PCoro(std::string url, LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId);
void startP2PVoiceCoro(std::string url, LLUUID tempSessionId, LLUUID creatorId, LLUUID otherParticipantId);
void chatterBoxInvitationCoro(std::string url, LLUUID sessionId, LLIMMgr::EInvitationType invitationType);
void chatterBoxHistoryCoro(std::string url, LLUUID sessionId, std::string from, std::string message, U32 timestamp);
@ -591,14 +591,14 @@ void startConferenceCoro(std::string url,
}
}
void startP2PCoro(std::string url, LLUUID sessionID, LLUUID creatorId, LLUUID otherParticipantId)
void startP2PVoiceCoro(std::string url, LLUUID sessionID, LLUUID creatorId, LLUUID otherParticipantId)
{
LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID);
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("ConferenceChatStart", httpPolicy));
LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("StartP2PVoiceCoro", httpPolicy));
LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest);
LLSD postData;
postData["method"] = "start p2p";
postData["method"] = "start p2p voice";
postData["session-id"] = sessionID;
postData["params"] = otherParticipantId;
LLSD altParams;
@ -2422,7 +2422,7 @@ bool LLIMModel::sendStartSession(
if (region)
{
std::string url = region->getCapability("ChatSessionRequest");
LLCoros::instance().launch("startP2P", boost::bind(&startP2PCoro, url, temp_session_id, gAgent.getID(), other_participant_id));
LLCoros::instance().launch("startP2PVoiceCoro", boost::bind(&startP2PVoiceCoro, url, temp_session_id, gAgent.getID(), other_participant_id));
}
return true;
}
@ -3027,7 +3027,7 @@ LLIncomingCallDialog::LLIncomingCallDialog(const LLSD& payload) :
void LLIncomingCallDialog::onLifetimeExpired()
{
LLVoiceP2PIncomingCallInterfacePtr call = LLVoiceClient::getInstance()->getIncomingCallInterface(mPayload["voice_session_info"]);
LLVoiceP2PIncomingCallInterfacePtr call = LLVoiceClient::getInstance()->getIncomingCallInterface(mPayload["voice_channel_info"]);
if (call)
{
// restart notification's timer if call is still valid
@ -3308,24 +3308,42 @@ void LLIncomingCallDialog::processCallResponse(S32 response, const LLSD &payload
{
if (type == IM_SESSION_P2P_INVITE)
{
LLVoiceP2PIncomingCallInterfacePtr call = LLVoiceClient::getInstance()->getIncomingCallInterface(payload["voice_session_info"]);
// decline p2p voice, either via the vivox-style call mechanism
// or via the webrtc-style "decline p2p" mechanism.
LLVoiceP2PIncomingCallInterfacePtr call = LLVoiceClient::getInstance()->getIncomingCallInterface(payload["voice_channel_info"]);
if (call)
{
call->declineInvite();
}
else
{
// webrtc-style decline.
LLViewerRegion *region = gAgent.getRegion();
if (region)
{
std::string url = region->getCapability("ChatSessionRequest");
LLSD data;
data["method"] = "decline p2p voice";
data["session-id"] = session_id;
LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, "P2P declined", "P2P decline failed.");
}
}
}
else
{
std::string url = gAgent.getRegion()->getCapability(
"ChatSessionRequest");
LLViewerRegion *region = gAgent.getRegion();
if (region)
{
std::string url = region->getCapability("ChatSessionRequest");
LLSD data;
data["method"] = "decline invitation";
data["session-id"] = session_id;
LLSD data;
data["method"] = "decline invitation";
data["session-id"] = session_id;
LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data,
"Invitation declined",
"Invitation decline failed.");
LLCoreHttpUtil::HttpCoroutineAdapter::messageHttpPost(url, data, "Invitation declined", "Invitation decline failed.");
}
}
}
@ -4134,6 +4152,40 @@ void LLIMMgr::clearPendingInvitation(const LLUUID& session_id)
void LLIMMgr::processAgentListUpdates(const LLUUID& session_id, const LLSD& body)
{
if (body.isMap() && body.has("agent_updates") && body["agent_updates"].isMap())
{
LLSD::map_const_iterator update_it;
for (update_it = body["agent_updates"].beginMap(); update_it != body["agent_updates"].endMap(); ++update_it)
{
LLUUID agent_id = LLUUID(update_it->first);
LLSD agent_data = update_it->second;
if (agent_data.has("transition") && agent_data["transition"].asString() == "LEAVE")
{
// ignore actual leaves as those will be handled separately.
continue;
}
if (agent_id != gAgentID && agent_data.isMap() && agent_data.has("info") && agent_data["info"].isMap())
{
// Is one of the participants leaving a P2P Chat?
if (agent_data["info"].has("can_voice_chat") && !agent_data["info"]["can_voice_chat"].asBoolean())
{
LLVoiceChannelGroup *channelp = dynamic_cast < LLVoiceChannelGroup*>(LLVoiceChannel::getChannelByID(session_id));
if (channelp && channelp->isP2P())
{
// it's an adhoc-style P2P channel, and the peer has declined voice. notify the user
// and shut down the voice channel.
LLSD notifyArgs = LLSD::emptyMap();
notifyArgs["VOICE_CHANNEL_NAME"] = channelp->getSessionName();
LLNotificationsUtil::add("P2PCallDeclined", notifyArgs);
endCall(session_id);
break;
}
}
}
}
}
// <FS:Ansariel> [FS communication UI]
//LLFloaterIMSession* im_floater = LLFloaterIMSession::findInstance(session_id);
FSFloaterIM* im_floater = FSFloaterIM::findInstance(session_id);

View File

@ -1269,6 +1269,9 @@ void settings_setup_listeners()
setting_setup_signal_listener(gSavedSettings, "PushToTalkButton", handleVoiceClientPrefsChanged);
setting_setup_signal_listener(gSavedSettings, "PushToTalkToggle", handleVoiceClientPrefsChanged);
setting_setup_signal_listener(gSavedSettings, "VoiceEarLocation", handleVoiceClientPrefsChanged);
setting_setup_signal_listener(gSavedSettings, "VoiceEchoCancellation", handleVoiceClientPrefsChanged);
setting_setup_signal_listener(gSavedSettings, "VoiceAutomaticGainControl", handleVoiceClientPrefsChanged);
setting_setup_signal_listener(gSavedSettings, "VoiceNoiseSuppressionLevel", handleVoiceClientPrefsChanged);
setting_setup_signal_listener(gSavedSettings, "VoiceInputAudioDevice", handleVoiceClientPrefsChanged);
setting_setup_signal_listener(gSavedSettings, "VoiceOutputAudioDevice", handleVoiceClientPrefsChanged);
setting_setup_signal_listener(gSavedSettings, "AudioLevelMic", handleVoiceClientPrefsChanged);

View File

@ -147,6 +147,8 @@ public:
void setChannelInfo(const LLSD &channelInfo) override;
void requestChannelInfo() override;
bool isP2P() { return mIsP2P; }
protected:
void setState(EState state) override;

View File

@ -1273,7 +1273,9 @@ bool LLVivoxVoiceClient::provisionVoiceAccount()
do
{
LLVoiceVivoxStats::getInstance()->provisionAttemptStart();
result = httpAdapter->postAndSuspend(httpRequest, url, LLSD(), httpOpts);
LLSD body;
body["voice_server_type"] = "vivox";
result = httpAdapter->postAndSuspend(httpRequest, url, body, httpOpts);
if (sShuttingDown)
{
@ -5248,7 +5250,7 @@ bool LLVivoxVoiceClient::isCurrentChannel(const LLSD &channelInfo)
}
if (mAudioSession)
{
if (!channelInfo["sessionHandle"].asString().empty())
if (!channelInfo["session_handle"].asString().empty())
{
return mAudioSession->mHandle == channelInfo["session_handle"].asString();
}

File diff suppressed because it is too large Load Diff

View File

@ -203,7 +203,9 @@ public:
void OnConnectionEstablished(const std::string& channelID, const LLUUID& regionID);
void OnConnectionShutDown(const std::string &channelID, const LLUUID &regionID);
void OnConnectionFailure(const std::string &channelID, const LLUUID& regionID);
void OnConnectionFailure(const std::string &channelID,
const LLUUID &regionID,
LLVoiceClientStatusObserver::EStatusType status_type = LLVoiceClientStatusObserver::ERROR_UNKNOWN);
void sendPositionUpdate(bool force);
void updateOwnVolume();
@ -225,7 +227,8 @@ public:
void OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices,
const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices) override;
//@}
void OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDeviceList &render_devices,
const llwebrtc::LLWebRTCVoiceDeviceList &capture_devices);
struct participantState
{
@ -271,7 +274,7 @@ public:
participantStatePtr_t findParticipantByID(const LLUUID& id);
static ptr_t matchSessionByChannelID(const std::string& channel_id);
void shutdownAllConnections();
void revive();
@ -445,6 +448,8 @@ private:
/// Clean up objects created during a voice session.
void cleanUp();
LL::WorkQueue::weak_t mMainQueue;
bool mTuningMode;
F32 mTuningMicGain;
int mTuningSpeakerVolume;
@ -585,7 +590,6 @@ class LLVoiceWebRTCConnection :
void OnOfferAvailable(const std::string &sdp) override;
void OnRenegotiationNeeded() override;
void OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface *audio_interface) override;
void OnPeerConnectionShutdown() override;
//@}
/////////////////////////
@ -596,13 +600,15 @@ class LLVoiceWebRTCConnection :
void OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface) override;
//@}
void OnDataReceivedImpl(const std::string &data, bool binary);
void sendJoin();
void sendData(const std::string &data);
virtual void processIceUpdates();
virtual void onIceUpdateComplete(bool ice_completed, const LLSD &result);
virtual void onIceUpdateError(int retries, std::string url, LLSD body, bool ice_completed, const LLSD &result);
void processIceUpdates();
void processIceUpdatesCoro();
virtual void setMuteMic(bool muted);
virtual void setMicGain(F32 volume);
virtual void setSpeakerVolume(F32 volume);
@ -618,12 +624,10 @@ class LLVoiceWebRTCConnection :
void shutDown()
{
LLMutexLock lock(&mVoiceStateMutex);
mShutDown = true;
}
void OnVoiceConnectionRequestSuccess(const LLSD &body);
void OnVoiceConnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result);
protected:
typedef enum e_voice_connection_state
@ -644,11 +648,10 @@ class LLVoiceWebRTCConnection :
} EVoiceConnectionState;
EVoiceConnectionState mVoiceConnectionState;
LLMutex mVoiceStateMutex;
LL::WorkQueue::weak_t mMainQueue;
void setVoiceConnectionState(EVoiceConnectionState new_voice_connection_state)
{
LLMutexLock lock(&mVoiceStateMutex);
if (new_voice_connection_state & VOICE_STATE_SESSION_STOPPING)
{
// the new state is shutdown or restart.
@ -666,19 +669,15 @@ class LLVoiceWebRTCConnection :
}
EVoiceConnectionState getVoiceConnectionState()
{
if (mVoiceStateMutex.isLocked())
{
LL_WARNS("Voice") << "LOCKED." << LL_ENDL;
}
LLMutexLock lock(&mVoiceStateMutex);
return mVoiceConnectionState;
}
virtual bool requestVoiceConnection() = 0;
virtual void requestVoiceConnection() = 0;
void requestVoiceConnectionCoro() { requestVoiceConnection(); }
bool breakVoiceConnection(bool wait);
void OnVoiceDisconnectionRequestSuccess(const LLSD &body);
void OnVoiceDisconnectionRequestFailure(std::string url, int retries, LLSD body, const LLSD &result);
void breakVoiceConnectionCoro();
LLVoiceClientStatusObserver::EStatusType mCurrentStatus;
LLUUID mRegionID;
LLUUID mViewerSession;
@ -702,7 +701,6 @@ class LLVoiceWebRTCConnection :
std::vector<llwebrtc::LLWebRTCIceCandidate> mIceCandidates;
bool mIceCompleted;
bool mTrickling;
llwebrtc::LLWebRTCPeerConnectionInterface *mWebRTCPeerConnectionInterface;
llwebrtc::LLWebRTCAudioInterface *mWebRTCAudioInterface;
@ -725,7 +723,7 @@ class LLVoiceWebRTCSpatialConnection :
protected:
bool requestVoiceConnection() override;
void requestVoiceConnection() override;
S32 mParcelLocalID;
};
@ -740,7 +738,7 @@ class LLVoiceWebRTCAdHocConnection : public LLVoiceWebRTCConnection
bool isSpatial() override { return false; }
protected:
bool requestVoiceConnection() override;
void requestVoiceConnection() override;
std::string mCredentials;
};

View File

@ -971,6 +971,17 @@
name="enable_lip_sync"
top_pad="5"
width="237"/>
<check_box
follows="top|left"
control_name="VoiceEchoCancellation"
height="15"
tool_tip="Check to enable voice echo cancellation"
label="Echo Cancellation"
layout="topleft"
left="25"
name="enable_echo_cancellation"
top_pad="3"
width="237"/>
<check_box
enabled_control="EnableVoiceChat"
control_name="FSShowVoiceVisualizer"
@ -1070,13 +1081,64 @@
enabled_control="EnableVoiceChat"
control_name="PushToTalkToggle"
height="15"
label="Toggle speak on/off when I press button in toolbar"
label="Toggle speak on/off with toolbar button"
layout="topleft"
left="25"
name="push_to_talk_toggle_check"
width="237"
tool_tip="When in toggle mode, press and release the trigger key ONCE to switch your microphone on or off. When not in toggle mode, the microphone broadcasts your voice only while the trigger is being held down."
top_pad="10"/>
<check_box
follows="top|left"
control_name="VoiceAutomaticGainControl"
height="15"
tool_tip="Check to enable automatic gain control"
label="Automatic Gain Control"
layout="topleft"
name="voice_automatic_gain_control"
left="25"
top_pad="3"
width="237"/>
<text
follows="top|left"
layout="topleft"
height="15"
left="25"
top_pad="5"
width="100"
name="noise_suppression_label">
Noise Suppression
</text>
<combo_box
control_name="VoiceNoiseSuppressionLevel"
enabled_control="AudioStreamingMedia"
layout="topleft"
height="23"
left_pad="10"
top_pad="-18"
name="noise_suppression_combo"
width="100">
<item
label="Off"
name="noise_suppression_none"
value="0"/>
<item
label="Low"
name="noise_suppression_low"
value="1"/>
<item
label="Moderate"
name="noise_suppression_moderate"
value="2"/>
<item
label="High"
name="noise_suppression_high"
value="3"/>
<item
label="Max"
name="noise_suppression_max"
value="4"/>
</combo_box>
<button
control_name="ShowDeviceSettings"