Merge branch 'release/2025.07' of https://github.com/secondlife/viewer

# Conflicts:
#	indra/newview/skins/default/xui/en/menu_inventory.xml
master
Ansariel 2025-09-16 18:33:02 +02:00
commit 5fdef7863e
42 changed files with 1072 additions and 635 deletions

View File

@ -42,7 +42,7 @@ jobs:
needs: setup
strategy:
matrix:
runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-2022","macos-15"]') }}
runner: ${{ fromJson((github.ref_type == 'tag' && startsWith(github.ref, 'refs/tags/Second_Life')) && '["windows-large","macos-15-xlarge"]' || '["windows-2022","macos-15-xlarge"]') }}
configuration: ${{ fromJson(needs.setup.outputs.configurations) }}
runs-on: ${{ matrix.runner }}
outputs:
@ -93,7 +93,6 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Checkout build variables
uses: actions/checkout@v5
with:

View File

@ -3030,11 +3030,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>6314fdcee81a3538a7d960178ade66301c2fa002</string>
<string>43c5f93517794aeade550e4266b959d1f0cfcb7f</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.73-alpha/webrtc-m114.5735.08.73-alpha.11958809572-darwin64-11958809572.tar.zst</string>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-darwin64-17630578914.tar.zst</string>
</map>
<key>name</key>
<string>darwin64</string>
@ -3044,11 +3044,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>95d7730a3d6955697e043f3fdf20ebdcc0c71fc0</string>
<string>efc5b176d878cfc16b8f82445d82ddb96815b6ab</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.73-alpha/webrtc-m114.5735.08.73-alpha.11958809572-linux64-11958809572.tar.zst</string>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-linux64-17630578914.tar.zst</string>
</map>
<key>name</key>
<string>linux64</string>
@ -3058,11 +3058,11 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>archive</key>
<map>
<key>hash</key>
<string>c7b329d6409576af6eb5b80655b007f52639c43b</string>
<string>1e36f100de32c7c71325497a672fb1659b3f206d</string>
<key>hash_algorithm</key>
<string>sha1</string>
<key>url</key>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m114.5735.08.73-alpha/webrtc-m114.5735.08.73-alpha.11958809572-windows64-11958809572.tar.zst</string>
<string>https://github.com/secondlife/3p-webrtc-build/releases/download/m137.7151.04.20-universal/webrtc-m137.7151.04.20-universal.17630578914-windows64-17630578914.tar.zst</string>
</map>
<key>name</key>
<string>windows64</string>
@ -3075,7 +3075,7 @@ Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors</string>
<key>copyright</key>
<string>Copyright (c) 2011, The WebRTC project authors. All rights reserved.</string>
<key>version</key>
<string>m114.5735.08.73-alpha.11958809572</string>
<string>m137.7151.04.20-universal.17630578914</string>
<key>name</key>
<string>webrtc</string>
<key>vcs_branch</key>

View File

@ -41,7 +41,7 @@ if (WINDOWS)
iphlpapi
libcmt)
# as the webrtc libraries are release, build this binary as release as well.
target_compile_options(llwebrtc PRIVATE "/MT")
target_compile_options(llwebrtc PRIVATE "/MT" "/Zc:wchar_t")
if (USE_BUGSPLAT)
set_target_properties(llwebrtc PROPERTIES PDB_OUTPUT_DIRECTORY "${SYMBOLS_STAGING_DIR}")
endif (USE_BUGSPLAT)

File diff suppressed because it is too large Load Diff

View File

@ -159,7 +159,10 @@ class LLWebRTCDeviceInterface
virtual void setTuningMode(bool enable) = 0;
virtual float getTuningAudioLevel() = 0; // for use during tuning
virtual float getPeerConnectionAudioLevel() = 0; // for use when not tuning
virtual void setPeerConnectionGain(float gain) = 0;
virtual void setMicGain(float gain) = 0;
virtual void setTuningMicGain(float gain) = 0;
virtual void setMute(bool mute, int delay_ms = 0) = 0;
};
// LLWebRTCAudioInterface provides the viewer with a way

View File

@ -54,12 +54,12 @@
#include "rtc_base/ref_counted_object.h"
#include "rtc_base/ssl_adapter.h"
#include "rtc_base/thread.h"
#include "rtc_base/logging.h"
#include "api/peer_connection_interface.h"
#include "api/media_stream_interface.h"
#include "api/create_peerconnection_factory.h"
#include "modules/audio_device/include/audio_device.h"
#include "modules/audio_device/include/audio_device_data_observer.h"
#include "rtc_base/task_queue.h"
#include "api/task_queue/task_queue_factory.h"
#include "api/task_queue/default_task_queue_factory.h"
#include "modules/audio_device/include/audio_device_defines.h"
@ -69,35 +69,30 @@ namespace llwebrtc
class LLWebRTCPeerConnectionImpl;
class LLWebRTCLogSink : public rtc::LogSink {
class LLWebRTCLogSink : public webrtc::LogSink
{
public:
LLWebRTCLogSink(LLWebRTCLogCallback* callback) :
mCallback(callback)
{
}
LLWebRTCLogSink(LLWebRTCLogCallback* callback) : mCallback(callback) {}
// Destructor: close the log file
~LLWebRTCLogSink() override
{
}
~LLWebRTCLogSink() override {}
void OnLogMessage(const std::string& msg,
rtc::LoggingSeverity severity) override
void OnLogMessage(const std::string& msg, webrtc::LoggingSeverity severity) override
{
if (mCallback)
{
switch(severity)
switch (severity)
{
case rtc::LS_VERBOSE:
case webrtc::LS_VERBOSE:
mCallback->LogMessage(LLWebRTCLogCallback::LOG_LEVEL_VERBOSE, msg);
break;
case rtc::LS_INFO:
case webrtc::LS_INFO:
mCallback->LogMessage(LLWebRTCLogCallback::LOG_LEVEL_VERBOSE, msg);
break;
case rtc::LS_WARNING:
case webrtc::LS_WARNING:
mCallback->LogMessage(LLWebRTCLogCallback::LOG_LEVEL_VERBOSE, msg);
break;
case rtc::LS_ERROR:
case webrtc::LS_ERROR:
mCallback->LogMessage(LLWebRTCLogCallback::LOG_LEVEL_VERBOSE, msg);
break;
default:
@ -118,73 +113,307 @@ private:
LLWebRTCLogCallback* mCallback;
};
// Implements a class allowing capture of audio data
// to determine audio level of the microphone.
class LLAudioDeviceObserver : public webrtc::AudioDeviceDataObserver
// -----------------------------------------------------------------------------
// A proxy transport that forwards capture data to two AudioTransport sinks:
// - the "engine" (libwebrtc's VoiceEngine)
// - the "user" (your app's listener)
//
// Playout (NeedMorePlayData) goes only to the engine by default to avoid
// double-writing into the output buffer. See notes below if you want a tap.
// -----------------------------------------------------------------------------
class LLWebRTCAudioTransport : public webrtc::AudioTransport
{
public:
LLAudioDeviceObserver();
public:
LLWebRTCAudioTransport();
// Retrieve the RMS audio loudness
float getMicrophoneEnergy();
void SetEngineTransport(webrtc::AudioTransport* t);
// Data retrieved from the caputure device is
// passed in here for processing.
void OnCaptureData(const void *audio_samples,
const size_t num_samples,
const size_t bytes_per_sample,
const size_t num_channels,
const uint32_t samples_per_sec) override;
// -------- Capture path: fan out to both sinks --------
int32_t RecordedDataIsAvailable(const void* audio_data,
size_t number_of_samples,
size_t bytes_per_sample,
size_t number_of_channels,
uint32_t samples_per_sec,
uint32_t total_delay_ms,
int32_t clock_drift,
uint32_t current_mic_level,
bool key_pressed,
uint32_t& new_mic_level) override;
// This is for data destined for the render device.
// not currently used.
void OnRenderData(const void *audio_samples,
const size_t num_samples,
const size_t bytes_per_sample,
const size_t num_channels,
const uint32_t samples_per_sec) override;
// -------- Playout path: delegate to engine only --------
int32_t NeedMorePlayData(size_t number_of_samples,
size_t bytes_per_sample,
size_t number_of_channels,
uint32_t samples_per_sec,
void* audio_data,
size_t& number_of_samples_out,
int64_t* elapsed_time_ms,
int64_t* ntp_time_ms) override;
// Method to pull mixed render audio data from all active VoE channels.
// The data will not be passed as reference for audio processing internally.
void PullRenderData(int bits_per_sample,
int sample_rate,
size_t number_of_channels,
size_t number_of_frames,
void* audio_data,
int64_t* elapsed_time_ms,
int64_t* ntp_time_ms) override;
float GetMicrophoneEnergy() { return mMicrophoneEnergy.load(std::memory_order_relaxed); }
void SetGain(float gain) { mGain.store(gain, std::memory_order_relaxed); }
private:
std::atomic<webrtc::AudioTransport*> engine_{ nullptr };
static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing (30 frames)
float mSumVector[NUM_PACKETS_TO_FILTER];
std::atomic<float> mMicrophoneEnergy;
std::atomic<float> mGain{ 0.0f };
protected:
static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing (30 frames)
float mSumVector[NUM_PACKETS_TO_FILTER];
float mMicrophoneEnergy;
};
// -----------------------------------------------------------------------------
// LLWebRTCAudioDeviceModule
// - Wraps a real ADM to provide microphone energy for tuning
// -----------------------------------------------------------------------------
class LLWebRTCAudioDeviceModule : public webrtc::AudioDeviceModule
{
public:
explicit LLWebRTCAudioDeviceModule(webrtc::scoped_refptr<webrtc::AudioDeviceModule> inner) : inner_(std::move(inner)), tuning_(false)
{
RTC_CHECK(inner_);
}
// ----- AudioDeviceModule interface: we mostly forward to |inner_| -----
int32_t ActiveAudioLayer(AudioLayer* audioLayer) const override { return inner_->ActiveAudioLayer(audioLayer); }
int32_t RegisterAudioCallback(webrtc::AudioTransport* engine_transport) override
{
// The engine registers its transport here. We put our audio transport between engine and ADM.
audio_transport_.SetEngineTransport(engine_transport);
// Register our proxy with the real ADM.
return inner_->RegisterAudioCallback(&audio_transport_);
}
int32_t Init() override { return inner_->Init(); }
int32_t Terminate() override { return inner_->Terminate(); }
bool Initialized() const override { return inner_->Initialized(); }
// --- Device enumeration/selection (forward) ---
int16_t PlayoutDevices() override { return inner_->PlayoutDevices(); }
int16_t RecordingDevices() override { return inner_->RecordingDevices(); }
int32_t PlayoutDeviceName(uint16_t index, char name[webrtc::kAdmMaxDeviceNameSize], char guid[webrtc::kAdmMaxGuidSize]) override
{
return inner_->PlayoutDeviceName(index, name, guid);
}
int32_t RecordingDeviceName(uint16_t index, char name[webrtc::kAdmMaxDeviceNameSize], char guid[webrtc::kAdmMaxGuidSize]) override
{
return inner_->RecordingDeviceName(index, name, guid);
}
int32_t SetPlayoutDevice(uint16_t index) override { return inner_->SetPlayoutDevice(index); }
int32_t SetRecordingDevice(uint16_t index) override { return inner_->SetRecordingDevice(index); }
// Windows default/communications selectors, if your branch exposes them:
int32_t SetPlayoutDevice(WindowsDeviceType type) override { return inner_->SetPlayoutDevice(type); }
int32_t SetRecordingDevice(WindowsDeviceType type) override { return inner_->SetRecordingDevice(type); }
// --- Init/start/stop (forward) ---
int32_t InitPlayout() override { return inner_->InitPlayout(); }
bool PlayoutIsInitialized() const override { return inner_->PlayoutIsInitialized(); }
int32_t StartPlayout() override {
if (tuning_) return 0; // For tuning, don't allow playout
return inner_->StartPlayout();
}
int32_t StopPlayout() override { return inner_->StopPlayout(); }
bool Playing() const override { return inner_->Playing(); }
int32_t InitRecording() override { return inner_->InitRecording(); }
bool RecordingIsInitialized() const override { return inner_->RecordingIsInitialized(); }
int32_t StartRecording() override {
// ignore start recording as webrtc.lib will
// send one when streams first connect, resulting
// in an inadvertant 'recording' when mute is on.
// We take full control of StartRecording via
// ForceStartRecording below.
return 0;
}
int32_t StopRecording() override {
if (tuning_) return 0; // if we're tuning, disregard the StopRecording we get from disabling the streams
return inner_->StopRecording();
}
int32_t ForceStartRecording() { return inner_->StartRecording(); }
int32_t ForceStopRecording() { return inner_->StopRecording(); }
bool Recording() const override { return inner_->Recording(); }
// --- Stereo opts (forward if available on your branch) ---
int32_t SetStereoPlayout(bool enable) override { return inner_->SetStereoPlayout(enable); }
int32_t SetStereoRecording(bool enable) override { return inner_->SetStereoRecording(enable); }
int32_t PlayoutIsAvailable(bool* available) override { return inner_->PlayoutIsAvailable(available); }
int32_t RecordingIsAvailable(bool* available) override { return inner_->RecordingIsAvailable(available); }
// --- AGC/Volume/Mute/etc. (forward) ---
int32_t SetMicrophoneVolume(uint32_t volume) override { return inner_->SetMicrophoneVolume(volume); }
int32_t MicrophoneVolume(uint32_t* volume) const override { return inner_->MicrophoneVolume(volume); }
// --- Speaker/Microphone init (forward) ---
int32_t InitSpeaker() override { return inner_->InitSpeaker(); }
bool SpeakerIsInitialized() const override { return inner_->SpeakerIsInitialized(); }
int32_t InitMicrophone() override { return inner_->InitMicrophone(); }
bool MicrophoneIsInitialized() const override { return inner_->MicrophoneIsInitialized(); }
// --- Speaker Volume (forward) ---
int32_t SpeakerVolumeIsAvailable(bool* available) override { return inner_->SpeakerVolumeIsAvailable(available); }
int32_t SetSpeakerVolume(uint32_t volume) override { return inner_->SetSpeakerVolume(volume); }
int32_t SpeakerVolume(uint32_t* volume) const override { return inner_->SpeakerVolume(volume); }
int32_t MaxSpeakerVolume(uint32_t* maxVolume) const override { return inner_->MaxSpeakerVolume(maxVolume); }
int32_t MinSpeakerVolume(uint32_t* minVolume) const override { return inner_->MinSpeakerVolume(minVolume); }
// --- Microphone Volume (forward) ---
int32_t MicrophoneVolumeIsAvailable(bool* available) override { return inner_->MicrophoneVolumeIsAvailable(available); }
int32_t MaxMicrophoneVolume(uint32_t* maxVolume) const override { return inner_->MaxMicrophoneVolume(maxVolume); }
int32_t MinMicrophoneVolume(uint32_t* minVolume) const override { return inner_->MinMicrophoneVolume(minVolume); }
// --- Speaker Mute (forward) ---
int32_t SpeakerMuteIsAvailable(bool* available) override { return inner_->SpeakerMuteIsAvailable(available); }
int32_t SetSpeakerMute(bool enable) override { return inner_->SetSpeakerMute(enable); }
int32_t SpeakerMute(bool* enabled) const override { return inner_->SpeakerMute(enabled); }
// --- Microphone Mute (forward) ---
int32_t MicrophoneMuteIsAvailable(bool* available) override { return inner_->MicrophoneMuteIsAvailable(available); }
int32_t SetMicrophoneMute(bool enable) override { return inner_->SetMicrophoneMute(enable); }
int32_t MicrophoneMute(bool* enabled) const override { return inner_->MicrophoneMute(enabled); }
// --- Stereo Support (forward) ---
int32_t StereoPlayoutIsAvailable(bool* available) const override { return inner_->StereoPlayoutIsAvailable(available); }
int32_t StereoPlayout(bool* enabled) const override { return inner_->StereoPlayout(enabled); }
int32_t StereoRecordingIsAvailable(bool* available) const override { return inner_->StereoRecordingIsAvailable(available); }
int32_t StereoRecording(bool* enabled) const override { return inner_->StereoRecording(enabled); }
// --- Delay/Timing (forward) ---
int32_t PlayoutDelay(uint16_t* delayMS) const override { return inner_->PlayoutDelay(delayMS); }
// --- Built-in Audio Processing (forward) ---
bool BuiltInAECIsAvailable() const override { return inner_->BuiltInAECIsAvailable(); }
bool BuiltInAGCIsAvailable() const override { return inner_->BuiltInAGCIsAvailable(); }
bool BuiltInNSIsAvailable() const override { return inner_->BuiltInNSIsAvailable(); }
int32_t EnableBuiltInAEC(bool enable) override { return inner_->EnableBuiltInAEC(enable); }
int32_t EnableBuiltInAGC(bool enable) override { return inner_->EnableBuiltInAGC(enable); }
int32_t EnableBuiltInNS(bool enable) override { return inner_->EnableBuiltInNS(enable); }
// --- Additional AudioDeviceModule methods (forward) ---
int32_t GetPlayoutUnderrunCount() const override { return inner_->GetPlayoutUnderrunCount(); }
// Used to generate RTC stats. If not implemented, RTCAudioPlayoutStats will
// not be present in the stats.
std::optional<Stats> GetStats() const override { return inner_->GetStats(); }
// Only supported on iOS.
#if defined(WEBRTC_IOS)
virtual int GetPlayoutAudioParameters(AudioParameters* params) const override { return inner_->GetPlayoutAudioParameters(params); }
virtual int GetRecordAudioParameters(AudioParameters* params) override { return inner_->GetRecordAudioParameters(params); }
#endif // WEBRTC_IOS
virtual int32_t GetPlayoutDevice() const override { return inner_->GetPlayoutDevice(); }
virtual int32_t GetRecordingDevice() const override { return inner_->GetRecordingDevice(); }
virtual int32_t SetObserver(webrtc::AudioDeviceObserver* observer) override { return inner_->SetObserver(observer); }
// tuning microphone energy calculations
float GetMicrophoneEnergy() { return audio_transport_.GetMicrophoneEnergy(); }
void SetTuningMicGain(float gain) { audio_transport_.SetGain(gain); }
void SetTuning(bool tuning, bool mute)
{
tuning_ = tuning;
if (tuning)
{
inner_->InitRecording();
inner_->StartRecording();
inner_->StopPlayout();
}
else
{
if (mute)
{
inner_->StopRecording();
}
else
{
inner_->InitRecording();
inner_->StartRecording();
}
inner_->StartPlayout();
}
}
protected:
~LLWebRTCAudioDeviceModule() override = default;
private:
webrtc::scoped_refptr<webrtc::AudioDeviceModule> inner_;
LLWebRTCAudioTransport audio_transport_;
bool tuning_;
};
class LLCustomProcessorState
{
public:
float getMicrophoneEnergy() { return mMicrophoneEnergy.load(std::memory_order_relaxed); }
void setMicrophoneEnergy(float energy) { mMicrophoneEnergy.store(energy, std::memory_order_relaxed); }
void setGain(float gain)
{
mGain.store(gain, std::memory_order_relaxed);
mDirty.store(true, std::memory_order_relaxed);
}
float getGain() { return mGain.load(std::memory_order_relaxed); }
bool getDirty() { return mDirty.exchange(false, std::memory_order_relaxed); }
protected:
std::atomic<bool> mDirty{ true };
std::atomic<float> mMicrophoneEnergy{ 0.0f };
std::atomic<float> mGain{ 0.0f };
};
using LLCustomProcessorStatePtr = std::shared_ptr<LLCustomProcessorState>;
// Used to process/retrieve audio levels after
// all of the processing (AGC, AEC, etc.) for display in-world to the user.
class LLCustomProcessor : public webrtc::CustomProcessing
{
public:
LLCustomProcessor();
public:
LLCustomProcessor(LLCustomProcessorStatePtr state);
~LLCustomProcessor() override {}
// (Re-) Initializes the submodule.
void Initialize(int sample_rate_hz, int num_channels) override;
// Analyzes the given capture or render signal.
void Process(webrtc::AudioBuffer *audio) override;
void Process(webrtc::AudioBuffer* audio) override;
// Returns a string representation of the module state.
std::string ToString() const override { return ""; }
float getMicrophoneEnergy() { return mMicrophoneEnergy; }
void setGain(float gain) { mGain = gain; }
protected:
static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing
int mSampleRateHz;
int mNumChannels;
protected:
static const int NUM_PACKETS_TO_FILTER = 30; // 300 ms of smoothing
int mSampleRateHz{ 48000 };
int mNumChannels{ 2 };
int mRampFrames{ 2 };
float mCurrentGain{ 0.0f };
float mGainStep{ 0.0f };
float mSumVector[NUM_PACKETS_TO_FILTER];
float mMicrophoneEnergy;
float mGain;
friend LLCustomProcessorState;
LLCustomProcessorStatePtr mState;
};
// Primary singleton implementation for interfacing
// with the native webrtc library.
class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceSink
class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceObserver
{
public:
LLWebRTCImpl(LLWebRTCLogCallback* logCallback);
@ -214,10 +443,15 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS
float getTuningAudioLevel() override;
float getPeerConnectionAudioLevel() override;
void setPeerConnectionGain(float gain) override;
void setMicGain(float gain) override;
void setTuningMicGain(float gain) override;
void setMute(bool mute, int delay_ms = 20) override;
void intSetMute(bool mute, int delay_ms = 20);
//
// AudioDeviceSink
// AudioDeviceObserver
//
void OnDevicesUpdated() override;
@ -246,19 +480,19 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS
mNetworkThread->PostTask(std::move(task), location);
}
void WorkerBlockingCall(rtc::FunctionView<void()> functor,
void WorkerBlockingCall(webrtc::FunctionView<void()> functor,
const webrtc::Location& location = webrtc::Location::Current())
{
mWorkerThread->BlockingCall(std::move(functor), location);
}
void SignalingBlockingCall(rtc::FunctionView<void()> functor,
void SignalingBlockingCall(webrtc::FunctionView<void()> functor,
const webrtc::Location& location = webrtc::Location::Current())
{
mSignalingThread->BlockingCall(std::move(functor), location);
}
void NetworkBlockingCall(rtc::FunctionView<void()> functor,
void NetworkBlockingCall(webrtc::FunctionView<void()> functor,
const webrtc::Location& location = webrtc::Location::Current())
{
mNetworkThread->BlockingCall(std::move(functor), location);
@ -266,7 +500,7 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS
// Allows the LLWebRTCPeerConnectionImpl class to retrieve the
// native webrtc PeerConnectionFactory.
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> getPeerConnectionFactory()
webrtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> getPeerConnectionFactory()
{
return mPeerConnectionFactory;
}
@ -275,49 +509,47 @@ class LLWebRTCImpl : public LLWebRTCDeviceInterface, public webrtc::AudioDeviceS
LLWebRTCPeerConnectionInterface* newPeerConnection();
void freePeerConnection(LLWebRTCPeerConnectionInterface* peer_connection);
// enables/disables capture via the capture device
void setRecording(bool recording);
void setPlayout(bool playing);
protected:
void workerDeployDevices();
LLWebRTCLogSink* mLogSink;
// The native webrtc threads
std::unique_ptr<rtc::Thread> mNetworkThread;
std::unique_ptr<rtc::Thread> mWorkerThread;
std::unique_ptr<rtc::Thread> mSignalingThread;
std::unique_ptr<webrtc::Thread> mNetworkThread;
std::unique_ptr<webrtc::Thread> mWorkerThread;
std::unique_ptr<webrtc::Thread> mSignalingThread;
// The factory that allows creation of native webrtc PeerConnections.
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory;
webrtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory;
rtc::scoped_refptr<webrtc::AudioProcessing> mAudioProcessingModule;
webrtc::scoped_refptr<webrtc::AudioProcessing> mAudioProcessingModule;
// more native webrtc stuff
std::unique_ptr<webrtc::TaskQueueFactory> mTaskQueueFactory;
std::unique_ptr<webrtc::TaskQueueFactory> mTaskQueueFactory;
// Devices
void updateDevices();
rtc::scoped_refptr<webrtc::AudioDeviceModule> mTuningDeviceModule;
rtc::scoped_refptr<webrtc::AudioDeviceModule> mPeerDeviceModule;
void deployDevices();
std::atomic<int> mDevicesDeploying;
webrtc::scoped_refptr<LLWebRTCAudioDeviceModule> mDeviceModule;
std::vector<LLWebRTCDevicesObserver *> mVoiceDevicesObserverList;
// accessors in native webrtc for devices aren't apparently implemented yet.
bool mTuningMode;
int32_t mRecordingDevice;
std::string mRecordingDevice;
LLWebRTCVoiceDeviceList mRecordingDeviceList;
int32_t mPlayoutDevice;
std::string mPlayoutDevice;
LLWebRTCVoiceDeviceList mPlayoutDeviceList;
bool mMute;
float mGain;
LLAudioDeviceObserver * mTuningAudioDeviceObserver;
LLCustomProcessor * mPeerCustomProcessor;
LLCustomProcessorStatePtr mPeerCustomProcessor;
// peer connections
std::vector<rtc::scoped_refptr<LLWebRTCPeerConnectionImpl>> mPeerConnections;
std::vector<webrtc::scoped_refptr<LLWebRTCPeerConnectionImpl>> mPeerConnections;
};
@ -342,7 +574,7 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
void terminate();
virtual void AddRef() const override = 0;
virtual rtc::RefCountReleaseStatus Release() const override = 0;
virtual webrtc::RefCountReleaseStatus Release() const override = 0;
//
// LLWebRTCPeerConnection
@ -373,10 +605,10 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
//
void OnSignalingChange(webrtc::PeerConnectionInterface::SignalingState new_state) override {}
void OnAddTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
const std::vector<rtc::scoped_refptr<webrtc::MediaStreamInterface>> &streams) override;
void OnRemoveTrack(rtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) override;
void OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> channel) override;
void OnAddTrack(webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver,
const std::vector<webrtc::scoped_refptr<webrtc::MediaStreamInterface>> &streams) override;
void OnRemoveTrack(webrtc::scoped_refptr<webrtc::RtpReceiverInterface> receiver) override;
void OnDataChannel(webrtc::scoped_refptr<webrtc::DataChannelInterface> channel) override;
void OnRenegotiationNeeded() override {}
void OnIceConnectionChange(webrtc::PeerConnectionInterface::IceConnectionState new_state) override {};
void OnIceGatheringChange(webrtc::PeerConnectionInterface::IceGatheringState new_state) override;
@ -415,7 +647,7 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
LLWebRTCImpl * mWebRTCImpl;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory;
webrtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> mPeerConnectionFactory;
typedef enum {
MUTE_INITIAL,
@ -429,12 +661,12 @@ class LLWebRTCPeerConnectionImpl : public LLWebRTCPeerConnectionInterface,
std::vector<std::unique_ptr<webrtc::IceCandidateInterface>> mCachedIceCandidates;
bool mAnswerReceived;
rtc::scoped_refptr<webrtc::PeerConnectionInterface> mPeerConnection;
rtc::scoped_refptr<webrtc::MediaStreamInterface> mLocalStream;
webrtc::scoped_refptr<webrtc::PeerConnectionInterface> mPeerConnection;
webrtc::scoped_refptr<webrtc::MediaStreamInterface> mLocalStream;
// data
std::vector<LLWebRTCDataObserver *> mDataObserverList;
rtc::scoped_refptr<webrtc::DataChannelInterface> mDataChannel;
webrtc::scoped_refptr<webrtc::DataChannelInterface> mDataChannel;
};
}

View File

@ -545,7 +545,7 @@ void LLConversationViewSession::onCurrentVoiceSessionChanged(const LLUUID& sessi
{
bool old_value = mIsInActiveVoiceChannel;
mIsInActiveVoiceChannel = vmi->getUUID() == session_id;
mCallIconLayoutPanel->setVisible(mIsInActiveVoiceChannel);
mCallIconLayoutPanel->setVisible(mIsInActiveVoiceChannel && !LLVoiceChannel::isSuspended());
if (old_value != mIsInActiveVoiceChannel)
{
refresh();

View File

@ -4241,6 +4241,31 @@ void LLInventoryAction::fileUploadLocation(const LLUUID& dest_id, const std::str
}
}
bool LLInventoryAction::isFileUploadLocation(const LLUUID& dest_id, const std::string& action)
{
if (action == "def_model")
{
return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_OBJECT) == dest_id;
}
else if (action == "def_texture")
{
return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_TEXTURE) == dest_id;
}
else if (action == "def_sound")
{
return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_SOUND) == dest_id;
}
else if (action == "def_animation")
{
return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_ANIMATION) == dest_id;
}
else if (action == "def_pbr_material")
{
return gInventory.findUserDefinedCategoryUUIDForType(LLFolderType::FT_MATERIAL) == dest_id;
}
return false;
}
void LLInventoryAction::onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root)
{
S32 option = LLNotificationsUtil::getSelectedOption(notification, response);

View File

@ -680,6 +680,7 @@ struct LLInventoryAction
static void onItemsRemovalConfirmation(const LLSD& notification, const LLSD& response, LLHandle<LLFolderView> root);
static void removeItemFromDND(LLFolderView* root);
static void fileUploadLocation(const LLUUID& dest_id, const std::string& action);
static bool isFileUploadLocation(const LLUUID& dest_id, const std::string& action);
static void saveMultipleTextures(const std::vector<std::string>& filenames, std::set<LLFolderViewItem*> selected_items, LLInventoryModel* model);

View File

@ -110,6 +110,7 @@ LLContextMenu* LLInventoryGalleryContextMenu::createMenu()
registrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, uuids, gFloaterView->getParentFloater(mGallery)));
enable_registrar.add("Inventory.CanSetUploadLocation", boost::bind(&LLInventoryGalleryContextMenu::canSetUploadLocation, this, _2));
enable_registrar.add("Inventory.FileUploadLocation.Check", boost::bind(&LLInventoryGalleryContextMenu::isUploadLocationSelected, this, _2));
enable_registrar.add("Inventory.EnvironmentEnabled", [](LLUICtrl*, const LLSD&)
{
@ -501,6 +502,12 @@ void LLInventoryGalleryContextMenu::fileUploadLocation(const LLSD& userdata)
LLInventoryAction::fileUploadLocation(mUUIDs.front(), param);
}
bool LLInventoryGalleryContextMenu::isUploadLocationSelected(const LLSD& userdata)
{
const std::string param = userdata.asString();
return LLInventoryAction::isFileUploadLocation(mUUIDs.front(), param);
}
bool LLInventoryGalleryContextMenu::canSetUploadLocation(const LLSD& userdata)
{
if (mUUIDs.size() != 1)

View File

@ -47,6 +47,7 @@ protected:
void updateMenuItemsVisibility(LLContextMenu* menu);
void fileUploadLocation(const LLSD& userdata);
bool isUploadLocationSelected(const LLSD& userdata);
bool canSetUploadLocation(const LLSD& userdata);
static void onRename(const LLSD& notification, const LLSD& response);

View File

@ -199,6 +199,7 @@ LLInventoryPanel::LLInventoryPanel(const LLInventoryPanel::Params& p) :
mCommitCallbackRegistrar.add("Inventory.BeginIMSession", boost::bind(&LLInventoryPanel::beginIMSession, this));
mCommitCallbackRegistrar.add("Inventory.Share", boost::bind(&LLAvatarActions::shareWithAvatars, this));
mCommitCallbackRegistrar.add("Inventory.FileUploadLocation", boost::bind(&LLInventoryPanel::fileUploadLocation, this, _2));
mEnableCallbackRegistrar.add("Inventory.FileUploadLocation.Check", boost::bind(&LLInventoryPanel::isUploadLocationSelected, this, _2));
mCommitCallbackRegistrar.add("Inventory.OpenNewFolderWindow", boost::bind(&LLInventoryPanel::openSingleViewInventory, this, LLUUID()));
mCommitCallbackRegistrar.add("Inventory.CustomAction", boost::bind(&LLInventoryPanel::onCustomAction, this, _2)); // <FS:Ansariel> Prevent warning "No callback found for: 'Inventory.CustomAction' in control: Find Links"
}
@ -2032,6 +2033,13 @@ void LLInventoryPanel::fileUploadLocation(const LLSD& userdata)
LLInventoryAction::fileUploadLocation(dest, param);
}
bool LLInventoryPanel::isUploadLocationSelected(const LLSD& userdata)
{
const std::string param = userdata.asString();
const LLUUID dest = LLFolderBridge::sSelf.get()->getUUID();
return LLInventoryAction::isFileUploadLocation(dest, param);
}
void LLInventoryPanel::openSingleViewInventory(LLUUID folder_id)
{
LLPanelMainInventory::newFolderWindow(folder_id.isNull() ? LLFolderBridge::sSelf.get()->getUUID() : folder_id);

View File

@ -236,6 +236,7 @@ public:
void doCreate(const LLSD& userdata);
bool beginIMSession();
void fileUploadLocation(const LLSD& userdata);
bool isUploadLocationSelected(const LLSD& userdata);
void openSingleViewInventory(LLUUID folder_id = LLUUID());
void purgeSelectedItems();
bool attachObject(const LLSD& userdata);

View File

@ -200,8 +200,17 @@ void SpeakingIndicatorManager::cleanupSingleton()
void SpeakingIndicatorManager::sOnCurrentChannelChanged(const LLUUID& /*session_id*/)
{
switchSpeakerIndicators(mSwitchedIndicatorsOn, false);
mSwitchedIndicatorsOn.clear();
if (LLVoiceChannel::isSuspended())
{
switchSpeakerIndicators(mSwitchedIndicatorsOn, false);
mSwitchedIndicatorsOn.clear();
}
else
{
// Multiple onParticipantsChanged can arrive at the same time
// from different sources, might want to filter by some factor.
onParticipantsChanged();
}
}
void SpeakingIndicatorManager::onParticipantsChanged()

View File

@ -4286,13 +4286,10 @@ void send_agent_update(bool force_send, bool send_reliable)
static F32 last_draw_disatance_step = 1024;
F32 memory_limited_draw_distance = gAgentCamera.mDrawDistance;
if (LLViewerTexture::sDesiredDiscardBias > 2.f && LLViewerTexture::isSystemMemoryLow())
if (LLViewerTexture::isSystemMemoryCritical())
{
// If we are low on memory, reduce requested draw distance
// Discard's bias is clamped to 4 so we need to check 2 to 4 range
// Factor is intended to go from 1.0 to 2.0
F32 factor = 1.f + (LLViewerTexture::sDesiredDiscardBias - 2.f) / 2.f;
memory_limited_draw_distance = llmax(gAgentCamera.mDrawDistance / factor, gAgentCamera.mDrawDistance / 2.f);
memory_limited_draw_distance = llmax(gAgentCamera.mDrawDistance / LLViewerTexture::getSystemMemoryBudgetFactor(), gAgentCamera.mDrawDistance / 2.f);
}
if (tp_state == LLAgent::TELEPORT_ARRIVING || LLStartUp::getStartupState() < STATE_MISC)

View File

@ -680,23 +680,35 @@ U32Megabytes LLViewerTexture::getFreeSystemMemory()
return physical_res;
}
//static
bool LLViewerTexture::isSystemMemoryLow()
S32Megabytes get_render_free_main_memory_treshold()
{
static LLCachedControl<U32> min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512);
const U32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory);
return getFreeSystemMemory() < MIN_FREE_MAIN_MEMORY;
return MIN_FREE_MAIN_MEMORY;
}
//static
bool LLViewerTexture::isSystemMemoryLow()
{
return getFreeSystemMemory() < get_render_free_main_memory_treshold();
}
//static
bool LLViewerTexture::isSystemMemoryCritical()
{
return getFreeSystemMemory() < get_render_free_main_memory_treshold() / 2;
}
F32 LLViewerTexture::getSystemMemoryBudgetFactor()
{
static LLCachedControl<U32> min_free_main_memory(gSavedSettings, "RenderMinFreeMainMemoryThreshold", 512);
const S32Megabytes MIN_FREE_MAIN_MEMORY(min_free_main_memory);
const S32Megabytes MIN_FREE_MAIN_MEMORY(get_render_free_main_memory_treshold() / 2);
S32 free_budget = (S32Megabytes)getFreeSystemMemory() - MIN_FREE_MAIN_MEMORY;
if (free_budget < 0)
{
// Result should range from 1 (0 free budget) to 2 (-512 free budget)
return 1.f - free_budget / MIN_FREE_MAIN_MEMORY;
// Leave some padding, otherwise we will crash out of memory before hitting factor 2.
const S32Megabytes PAD_BUFFER(32);
// Result should range from 1 at 0 free budget to 2 at -224 free budget, 2.14 at -256MB
return 1.f - free_budget / (MIN_FREE_MAIN_MEMORY - PAD_BUFFER);
}
return 1.f;
}

View File

@ -118,6 +118,7 @@ public:
static void initClass();
static void updateClass();
static bool isSystemMemoryLow();
static bool isSystemMemoryCritical();
static F32 getSystemMemoryBudgetFactor();
LLViewerTexture(bool usemipmaps = true);

View File

@ -505,13 +505,11 @@ void LLVOCacheEntry::updateDebugSettings()
static const F32 MIN_RADIUS = 1.0f;
F32 draw_radius = gAgentCamera.mDrawDistance;
if (LLViewerTexture::sDesiredDiscardBias > 2.f && LLViewerTexture::isSystemMemoryLow())
if (LLViewerTexture::isSystemMemoryCritical())
{
// Discard's bias maximum is 4 so we need to check 2 to 4 range
// Factor is intended to go from 1.0 to 2.0
F32 factor = 1.f + (LLViewerTexture::sDesiredDiscardBias - 2.f) / 2.f;
// For safety cap reduction at 50%, we don't want to go below half of draw distance
draw_radius = llmax(draw_radius / factor, draw_radius / 2.f);
draw_radius = llmax(draw_radius / LLViewerTexture::getSystemMemoryBudgetFactor(), draw_radius / 2.f);
}
const F32 clamped_min_radius = llclamp((F32) min_radius, MIN_RADIUS, draw_radius); // [1, mDrawDistance]
sNearRadius = MIN_RADIUS + ((clamped_min_radius - MIN_RADIUS) * adjust_factor);

View File

@ -357,6 +357,8 @@ void LLVoiceChannel::suspend()
{
sSuspendedVoiceChannel = sCurrentVoiceChannel;
sSuspended = true;
sCurrentVoiceChannelChangedSignal(sSuspendedVoiceChannel->mSessionID);
}
}
@ -365,6 +367,7 @@ void LLVoiceChannel::resume()
{
if (sSuspended)
{
sSuspended = false; // needs to be before activate() so that observers will be able to read state
if (LLVoiceClient::getInstance()->voiceEnabled())
{
if (sSuspendedVoiceChannel)
@ -382,7 +385,6 @@ void LLVoiceChannel::resume()
LLVoiceChannelProximal::getInstance()->activate();
}
}
sSuspended = false;
}
}

View File

@ -103,6 +103,7 @@ public:
static void suspend();
static void resume();
static bool isSuspended() { return sSuspended; }
protected:
virtual void setState(EState state);

View File

@ -82,9 +82,15 @@ const std::string WEBRTC_VOICE_SERVER_TYPE = "webrtc";
namespace {
const F32 MAX_AUDIO_DIST = 50.0f;
const F32 VOLUME_SCALE_WEBRTC = 0.01f;
const F32 LEVEL_SCALE_WEBRTC = 0.008f;
const F32 MAX_AUDIO_DIST = 50.0f;
const F32 VOLUME_SCALE_WEBRTC = 0.01f;
const F32 TUNING_LEVEL_SCALE = 0.01f;
const F32 TUNING_LEVEL_START_POINT = 0.8f;
const F32 LEVEL_SCALE = 0.005f;
const F32 LEVEL_START_POINT = 0.18f;
const uint32_t SET_HIDDEN_RESTORE_DELAY_MS = 200; // 200 ms to unmute again after hiding during teleport
const uint32_t MUTE_FADE_DELAY_MS = 500; // 20ms fade followed by 480ms silence gets rid of the click just after unmuting.
// This is because the buffers and processing is cleared by the silence.
const F32 SPEAKING_AUDIO_LEVEL = 0.30f; // <FS:minerjr> add missing f for float
@ -201,7 +207,6 @@ bool LLWebRTCVoiceClient::sShuttingDown = false;
LLWebRTCVoiceClient::LLWebRTCVoiceClient() :
mHidden(false),
mTuningMode(false),
mTuningMicGain(0.0),
mTuningSpeakerVolume(50), // Set to 50 so the user can hear themselves when he sets his mic volume
mDevicesListUpdated(false),
@ -348,25 +353,45 @@ void LLWebRTCVoiceClient::updateSettings()
static LLCachedControl<std::string> sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice");
setRenderDevice(sOutputDevice);
LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) << LL_ENDL;
LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice())
<< LL_ENDL;
static LLCachedControl<F32> sMicLevel(gSavedSettings, "AudioLevelMic");
setMicGain(sMicLevel);
llwebrtc::LLWebRTCDeviceInterface::AudioConfig config;
bool audioConfigChanged = false;
static LLCachedControl<bool> sEchoCancellation(gSavedSettings, "VoiceEchoCancellation", true);
config.mEchoCancellation = sEchoCancellation;
if (sEchoCancellation != config.mEchoCancellation)
{
config.mEchoCancellation = sEchoCancellation;
audioConfigChanged = true;
}
static LLCachedControl<bool> sAGC(gSavedSettings, "VoiceAutomaticGainControl", true);
config.mAGC = sAGC;
if (sAGC != config.mAGC)
{
config.mAGC = sAGC;
audioConfigChanged = true;
}
static LLCachedControl<U32> sNoiseSuppressionLevel(gSavedSettings,
static LLCachedControl<U32> sNoiseSuppressionLevel(
gSavedSettings,
"VoiceNoiseSuppressionLevel",
llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel::NOISE_SUPPRESSION_LEVEL_VERY_HIGH);
config.mNoiseSuppressionLevel = (llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel)(U32)sNoiseSuppressionLevel;
mWebRTCDeviceInterface->setAudioConfig(config);
auto noiseSuppressionLevel =
(llwebrtc::LLWebRTCDeviceInterface::AudioConfig::ENoiseSuppressionLevel)(U32)sNoiseSuppressionLevel;
if (noiseSuppressionLevel != config.mNoiseSuppressionLevel)
{
config.mNoiseSuppressionLevel = noiseSuppressionLevel;
audioConfigChanged = true;
}
if (audioConfigChanged)
{
mWebRTCDeviceInterface->setAudioConfig(config);
}
}
}
@ -703,21 +728,38 @@ void LLWebRTCVoiceClient::OnDevicesChangedImpl(const llwebrtc::LLWebRTCVoiceDevi
std::string outputDevice = gSavedSettings.getString("VoiceOutputAudioDevice");
LL_DEBUGS("Voice") << "Setting devices to-input: '" << inputDevice << "' output: '" << outputDevice << "'" << LL_ENDL;
clearRenderDevices();
for (auto &device : render_devices)
{
addRenderDevice(LLVoiceDevice(device.mDisplayName, device.mID));
}
setRenderDevice(outputDevice);
clearCaptureDevices();
for (auto &device : capture_devices)
// only set the render device if the device list has changed.
if (mRenderDevices.size() != render_devices.size() || !std::equal(mRenderDevices.begin(),
mRenderDevices.end(),
render_devices.begin(),
[](const LLVoiceDevice& a, const llwebrtc::LLWebRTCVoiceDevice& b) {
return a.display_name == b.mDisplayName && a.full_name == b.mID; }))
{
LL_DEBUGS("Voice") << "Checking capture device:'" << device.mID << "'" << LL_ENDL;
addCaptureDevice(LLVoiceDevice(device.mDisplayName, device.mID));
clearRenderDevices();
for (auto& device : render_devices)
{
addRenderDevice(LLVoiceDevice(device.mDisplayName, device.mID));
}
setRenderDevice(outputDevice);
}
// only set the capture device if the device list has changed.
if (mCaptureDevices.size() != capture_devices.size() ||!std::equal(mCaptureDevices.begin(),
mCaptureDevices.end(),
capture_devices.begin(),
[](const LLVoiceDevice& a, const llwebrtc::LLWebRTCVoiceDevice& b)
{ return a.display_name == b.mDisplayName && a.full_name == b.mID; }))
{
clearCaptureDevices();
for (auto& device : capture_devices)
{
LL_DEBUGS("Voice") << "Checking capture device:'" << device.mID << "'" << LL_ENDL;
addCaptureDevice(LLVoiceDevice(device.mDisplayName, device.mID));
}
setCaptureDevice(inputDevice);
}
setCaptureDevice(inputDevice);
setDevicesListUpdated(true);
}
@ -770,7 +812,14 @@ bool LLWebRTCVoiceClient::inTuningMode()
void LLWebRTCVoiceClient::tuningSetMicVolume(float volume)
{
mTuningMicGain = volume;
if (volume != mTuningMicGain)
{
mTuningMicGain = volume;
if (mWebRTCDeviceInterface)
{
mWebRTCDeviceInterface->setTuningMicGain(volume);
}
}
}
void LLWebRTCVoiceClient::tuningSetSpeakerVolume(float volume)
@ -782,21 +831,10 @@ void LLWebRTCVoiceClient::tuningSetSpeakerVolume(float volume)
}
}
float LLWebRTCVoiceClient::getAudioLevel()
{
if (mIsInTuningMode)
{
return (1.0f - mWebRTCDeviceInterface->getTuningAudioLevel() * LEVEL_SCALE_WEBRTC) * mTuningMicGain / 2.1f;
}
else
{
return (1.0f - mWebRTCDeviceInterface->getPeerConnectionAudioLevel() * LEVEL_SCALE_WEBRTC) * mMicGain / 2.1f;
}
}
float LLWebRTCVoiceClient::tuningGetEnergy(void)
{
return getAudioLevel();
float rms = mWebRTCDeviceInterface->getTuningAudioLevel();
return TUNING_LEVEL_START_POINT - TUNING_LEVEL_SCALE * rms;
}
bool LLWebRTCVoiceClient::deviceSettingsAvailable()
@ -832,6 +870,11 @@ void LLWebRTCVoiceClient::setHidden(bool hidden)
if (inSpatialChannel())
{
if (mWebRTCDeviceInterface)
{
mWebRTCDeviceInterface->setMute(mHidden || mMuteMic,
mHidden ? 0 : SET_HIDDEN_RESTORE_DELAY_MS); // delay 200ms so as to not pile up mutes/unmutes.
}
if (mHidden)
{
// get out of the channel entirely
@ -998,7 +1041,6 @@ void LLWebRTCVoiceClient::updatePosition(void)
{
if (participant->mRegion != region->getRegionID()) {
participant->mRegion = region->getRegionID();
setMuteMic(mMuteMic);
}
}
}
@ -1123,13 +1165,14 @@ void LLWebRTCVoiceClient::sendPositionUpdate(bool force)
// Update our own volume on our participant, so it'll show up
// in the UI. This is done on all sessions, so switching
// sessions retains consistent volume levels.
void LLWebRTCVoiceClient::updateOwnVolume() {
F32 audio_level = 0.0;
if (!mMuteMic && !mTuningMode)
void LLWebRTCVoiceClient::updateOwnVolume()
{
F32 audio_level = 0.0f;
if (!mMuteMic)
{
audio_level = getAudioLevel();
float rms = mWebRTCDeviceInterface->getPeerConnectionAudioLevel();
audio_level = LEVEL_START_POINT - LEVEL_SCALE * rms;
}
sessionState::for_each(boost::bind(predUpdateOwnVolume, _1, audio_level));
}
@ -1526,6 +1569,17 @@ void LLWebRTCVoiceClient::setMuteMic(bool muted)
}
mMuteMic = muted;
if (mIsInTuningMode)
{
return;
}
if (mWebRTCDeviceInterface)
{
mWebRTCDeviceInterface->setMute(muted, muted ? MUTE_FADE_DELAY_MS : 0); // delay for 40ms on mute to allow buffers to empty
}
// when you're hidden, your mic is always muted.
if (!mHidden)
{
@ -1564,7 +1618,10 @@ void LLWebRTCVoiceClient::setMicGain(F32 gain)
if (gain != mMicGain)
{
mMicGain = gain;
mWebRTCDeviceInterface->setPeerConnectionGain(gain);
if (mWebRTCDeviceInterface)
{
mWebRTCDeviceInterface->setMicGain(gain);
}
}
}

View File

@ -444,10 +444,6 @@ public:
private:
// helper function to retrieve the audio level
// Used in multiple places.
float getAudioLevel();
// Coroutine support methods
//---
void voiceConnectionCoro();
@ -458,7 +454,6 @@ private:
LL::WorkQueue::weak_t mMainQueue;
bool mTuningMode;
F32 mTuningMicGain;
int mTuningSpeakerVolume;
bool mDevicesListUpdated; // set to true when the device list has been updated

View File

@ -49,10 +49,10 @@
<menu_item_call label="Yeni gün dövrü" name="New Day Cycle"/>
</menu>
<menu label="İşlət:" name="upload_def">
<menu_item_call label="Şəkil yükləmək üçün" name="Image uploads"/>
<menu_item_call label="Səs yükləmək üçün" name="Sound uploads"/>
<menu_item_call label="Animasiya yükləmək üçün" name="Animation uploads"/>
<menu_item_call label="Model yükləmək üçün" name="Model uploads"/>
<menu_item_check label="Şəkil yükləmək üçün" name="Image uploads"/>
<menu_item_check label="Səs yükləmək üçün" name="Sound uploads"/>
<menu_item_check label="Animasiya yükləmək üçün" name="Animation uploads"/>
<menu_item_check label="Model yükləmək üçün" name="Model uploads"/>
</menu>
<menu label="Növü dəyişdir" name="Change Type">
<menu_item_call label="Susmaya görə" name="Default"/>

View File

@ -93,11 +93,11 @@
<menu_item_call label="Mehrfach-Upload..." name="Bulk Upload"/>
</menu>
<menu label="Als Standard verwenden für" name="upload_def">
<menu_item_call label="Hochgeladene Bilder" name="Image uploads"/>
<menu_item_call label="Hochgeladene Sounds" name="Sound uploads"/>
<menu_item_call label="Hochgeladene Animationen" name="Animation uploads"/>
<menu_item_call label="Hochgeladene Modelle" name="Model uploads"/>
<menu_item_call label="Hochgeladene PBR-Materialien" name="PBR uploads"/>
<menu_item_check label="Hochgeladene Bilder" name="Image uploads"/>
<menu_item_check label="Hochgeladene Sounds" name="Sound uploads"/>
<menu_item_check label="Hochgeladene Animationen" name="Animation uploads"/>
<menu_item_check label="Hochgeladene Modelle" name="Model uploads"/>
<menu_item_check label="Hochgeladene PBR-Materialien" name="PBR uploads"/>
</menu>
<menu_item_call label="In Marktplatz-Auflistungen kopieren" name="Marketplace Copy"/>
<menu_item_call label="In Marktplatz-Auflistungen verschieben" name="Marketplace Move"/>

View File

@ -52,11 +52,11 @@
<menu_item_call label="Neuer Tageszyklus" name="New Day Cycle"/>
</menu>
<menu label="Als Standard verwenden für" name="upload_def">
<menu_item_call label="Hochgeladene Bilder" name="Image uploads"/>
<menu_item_call label="Hochgeladene Sounds" name="Sound uploads"/>
<menu_item_call label="Hochgeladene Animationen" name="Animation uploads"/>
<menu_item_call label="Hochgeladene Modelle" name="Model uploads"/>
<menu_item_call label="Hochgeladene PBR-Materialien" name="PBR uploads"/>
<menu_item_check label="Hochgeladene Bilder" name="Image uploads"/>
<menu_item_check label="Hochgeladene Sounds" name="Sound uploads"/>
<menu_item_check label="Hochgeladene Animationen" name="Animation uploads"/>
<menu_item_check label="Hochgeladene Modelle" name="Model uploads"/>
<menu_item_check label="Hochgeladene PBR-Materialien" name="PBR uploads"/>
</menu>
<menu_item_call label="Als Favoriten-Ordner verwenden" name="Set Favorites folder"/>
<menu_item_call label="Favoriten-Ordner zurücksetzen" name="Reset Favorites folder"/>

View File

@ -767,54 +767,69 @@
label="Use as default for"
layout="topleft"
name="upload_def">
<menu_item_call
<menu_item_check
label="Image uploads"
layout="topleft"
name="Image uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_texture" />
<menu_item_call.on_visible
<on_visible
function="Inventory.CanSetUploadLocation" />
</menu_item_call>
<menu_item_call
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_texture" />
</menu_item_check>
<menu_item_check
label="Sound uploads"
layout="topleft"
name="Sound uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_sound" />
<menu_item_call.on_visible
<on_visible
function="Inventory.CanSetUploadLocation" />
</menu_item_call>
<menu_item_call
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_sound" />
</menu_item_check>
<menu_item_check
label="Animation uploads"
layout="topleft"
name="Animation uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_animation" />
<menu_item_call.on_visible
<on_visible
function="Inventory.CanSetUploadLocation" />
</menu_item_call>
<menu_item_call
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_animation" />
</menu_item_check>
<menu_item_check
label="Model uploads"
layout="topleft"
name="Model uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_model" />
<menu_item_call.on_visible
<on_visible
function="Inventory.CanSetUploadLocation" />
</menu_item_call>
<menu_item_call
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_model" />
</menu_item_check>
<menu_item_check
label="PBR material uploads"
layout="topleft"
name="PBR uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_pbr_material" />
</menu_item_call>
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_pbr_material" />
</menu_item_check>
</menu>
<menu_item_separator
layout="topleft"

View File

@ -394,46 +394,61 @@
label="Use as default for"
layout="topleft"
name="upload_def">
<menu_item_call
<menu_item_check
label="Image uploads"
layout="topleft"
name="Image uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_texture" />
</menu_item_call>
<menu_item_call
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_texture" />
</menu_item_check>
<menu_item_check
label="Sound uploads"
layout="topleft"
name="Sound uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_sound" />
</menu_item_call>
<menu_item_call
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_sound" />
</menu_item_check>
<menu_item_check
label="Animation uploads"
layout="topleft"
name="Animation uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_animation" />
</menu_item_call>
<menu_item_call
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_animation" />
</menu_item_check>
<menu_item_check
label="Model uploads"
layout="topleft"
name="Model uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_model" />
</menu_item_call>
<menu_item_call
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_model" />
</menu_item_check>
<menu_item_check
label="PBR material uploads"
layout="topleft"
name="PBR uploads">
<menu_item_call.on_click
<on_click
function="Inventory.FileUploadLocation"
parameter="def_pbr_material" />
</menu_item_call>
<on_check
function="Inventory.FileUploadLocation.Check"
parameter="def_pbr_material" />
</menu_item_check>
</menu>
<menu
label="Change Type"

View File

@ -48,10 +48,10 @@
<menu_item_call label="Nuevo Ciclo del día" name="New Day Cycle"/>
</menu>
<menu label="Usar como valor predeterminado para" name="upload_def">
<menu_item_call label="Imágenes subidas" name="Image uploads"/>
<menu_item_call label="Sonidos subidos" name="Sound uploads"/>
<menu_item_call label="Animaciones subidas" name="Animation uploads"/>
<menu_item_call label="Modelos subidos" name="Model uploads"/>
<menu_item_check label="Imágenes subidas" name="Image uploads"/>
<menu_item_check label="Sonidos subidos" name="Sound uploads"/>
<menu_item_check label="Animaciones subidas" name="Animation uploads"/>
<menu_item_check label="Modelos subidos" name="Model uploads"/>
</menu>
<menu label="Change Type" name="Change Type">
<menu_item_call label="Por defecto" name="Default"/>

View File

@ -52,10 +52,11 @@
<menu_item_call label="Nouveau dossier à partir de la sélection" name="New folder from selected"/>
<menu_item_call label="Annuler le regroupement par dossier" name="Ungroup folder items"/>
<menu label="Utiliser par défaut pour" name="upload_def">
<menu_item_call label="Le chargement d'images" name="Image uploads"/>
<menu_item_call label="Le chargement de sons" name="Sound uploads"/>
<menu_item_call label="Le chargement d'animations" name="Animation uploads"/>
<menu_item_call label="Le chargement de modèles" name="Model uploads"/>
<menu_item_check label="Le chargement d'images" name="Image uploads"/>
<menu_item_check label="Le chargement de sons" name="Sound uploads"/>
<menu_item_check label="Le chargement d'animations" name="Animation uploads"/>
<menu_item_check label="Le chargement de modèles" name="Model uploads"/>
<menu_item_check label="Chargements de matériaux PBR" name="PBR uploads"/>
</menu>
<menu_item_call label="Copier dans la liste de Marketplace" name="Marketplace Copy"/>
<menu_item_call label="Déplacer vers la liste de Marketplace" name="Marketplace Move"/>

View File

@ -52,11 +52,11 @@
<menu_item_call label="Nouveau cycle du jour" name="New Day Cycle"/>
</menu>
<menu label="Utiliser comme dossier par défaut pour" name="upload_def">
<menu_item_call label="Chargements dimages" name="Image uploads"/>
<menu_item_call label="Chargements de sons" name="Sound uploads"/>
<menu_item_call label="Chargements danimations" name="Animation uploads"/>
<menu_item_call label="Chargements de modèles" name="Model uploads"/>
<menu_item_call label="Chargements de matériaux PBR" name="PBR uploads"/>
<menu_item_check label="Chargements dimages" name="Image uploads"/>
<menu_item_check label="Chargements de sons" name="Sound uploads"/>
<menu_item_check label="Chargements danimations" name="Animation uploads"/>
<menu_item_check label="Chargements de modèles" name="Model uploads"/>
<menu_item_check label="Chargements de matériaux PBR" name="PBR uploads"/>
</menu>
<menu label="Changer de type" name="Change Type">
<menu_item_call label="Défaut" name="Default"/>

View File

@ -85,10 +85,11 @@
<menu_item_call label="Crea cartella dagli elementi selezionati" name="New folder from selected" />
<menu_item_call label="Separa gli elementi della cartella" name="Ungroup folder items" />
<menu label="Usa come predefinita per" name="upload_def">
<menu_item_call label="Immagini caricate" name="Image uploads"/>
<menu_item_call label="Suoni caricati" name="Sound uploads"/>
<menu_item_call label="Animazioni caricate" name="Animation uploads"/>
<menu_item_call label="Modelli mesh caricati" name="Model uploads"/>
<menu_item_check label="Immagini caricate" name="Image uploads"/>
<menu_item_check label="Suoni caricati" name="Sound uploads"/>
<menu_item_check label="Animazioni caricate" name="Animation uploads"/>
<menu_item_check label="Modelli mesh caricati" name="Model uploads"/>
<menu_item_check label="Materiali PBR caricati" name="PBR uploads"/>
</menu>
<menu_item_call label="Copia negli annunci Marketplace" name="Marketplace Copy"/>
<menu_item_call label="Sposta negli annunci Marketplace" name="Marketplace Move"/>

View File

@ -51,11 +51,11 @@
<menu_item_call label="Nuovo ciclo giornata" name="New Day Cycle" />
</menu>
<menu label="Usa come predefinita per" name="upload_def">
<menu_item_call label="Immagini caricate" name="Image uploads"/>
<menu_item_call label="Suoni caricati" name="Sound uploads"/>
<menu_item_call label="Animazioni caricate" name="Animation uploads"/>
<menu_item_call label="Modelli mesh caricati" name="Model uploads"/>
<menu_item_call label="Materiali PBR caricati" name="PBR uploads"/>
<menu_item_check label="Immagini caricate" name="Image uploads"/>
<menu_item_check label="Suoni caricati" name="Sound uploads"/>
<menu_item_check label="Animazioni caricate" name="Animation uploads"/>
<menu_item_check label="Modelli mesh caricati" name="Model uploads"/>
<menu_item_check label="Materiali PBR caricati" name="PBR uploads"/>
</menu>
<menu label="Cambia tipo" name="Change Type">
<menu_item_call label="Predefinito" name="Default"/>

View File

@ -95,11 +95,11 @@
<menu_item_call label="一括…" name="Bulk Upload"/>
</menu>
<menu label="デフォルトのアップロード先" name="upload_def">
<menu_item_call label="アップロードした画像" name="Image uploads"/>
<menu_item_call label="アップロードしたサウンド" name="Sound uploads"/>
<menu_item_call label="アップロードしたアニメーション" name="Animation uploads"/>
<menu_item_call label="アップロードしたモデル" name="Model uploads"/>
<menu_item_call label="アップロードしたPBRマテリアル" name="PBR uploads"/>
<menu_item_check label="アップロードした画像" name="Image uploads"/>
<menu_item_check label="アップロードしたサウンド" name="Sound uploads"/>
<menu_item_check label="アップロードしたアニメーション" name="Animation uploads"/>
<menu_item_check label="アップロードしたモデル" name="Model uploads"/>
<menu_item_check label="アップロードしたPBRマテリアル" name="PBR uploads"/>
</menu>
<menu_item_call label="マーケットプレイスの出品リストにコピー" name="Marketplace Copy"/>
<menu_item_call label="マーケットプレイスの出品リストに移動" name="Marketplace Move"/>

View File

@ -133,11 +133,11 @@
<menu_item_call label="お気に入りに追加" name="Add to Favorites"/>
<menu_item_call label="お気に入りから削除" name="Remove from Favorites"/>
<menu label="以下のデフォルトとして使用" name="upload_def">
<menu_item_call label="画像のアップロード" name="Image uploads"/>
<menu_item_call label="サウンドのアップロード" name="Sound uploads"/>
<menu_item_call label="アニメーションのアップロード" name="Animation uploads"/>
<menu_item_call label="モデルのアップロード" name="Model uploads"/>
<menu_item_call label="PBRマテリアルのアップロード" name="PBR uploads"/>
<menu_item_check label="画像のアップロード" name="Image uploads"/>
<menu_item_check label="サウンドのアップロード" name="Sound uploads"/>
<menu_item_check label="アニメーションのアップロード" name="Animation uploads"/>
<menu_item_check label="モデルのアップロード" name="Model uploads"/>
<menu_item_check label="PBRマテリアルのアップロード" name="PBR uploads"/>
</menu>
<menu_item_call label="マーケットプレイスの出品リストにコピー" name="Marketplace Copy"/>
<menu_item_call label="マーケットプレイスの出品リストに移動" name="Marketplace Move"/>

View File

@ -95,11 +95,11 @@
<menu_item_call label="Zbiór wielu plików..." name="Bulk Upload" />
</menu>
<menu label="Ustaw jako domyślne" name="upload_def">
<menu_item_call label="Dla nowych obrazów" name="Image uploads" />
<menu_item_call label="Dla nowych dźwięków" name="Sound uploads" />
<menu_item_call label="Dla nowych animacji" name="Animation uploads" />
<menu_item_call label="Dla nowych modeli" name="Model uploads" />
<menu_item_call label="Dla nowych materiałów PBR" name="PBR uploads" />
<menu_item_check label="Dla nowych obrazów" name="Image uploads" />
<menu_item_check label="Dla nowych dźwięków" name="Sound uploads" />
<menu_item_check label="Dla nowych animacji" name="Animation uploads" />
<menu_item_check label="Dla nowych modeli" name="Model uploads" />
<menu_item_check label="Dla nowych materiałów PBR" name="PBR uploads" />
</menu>
<menu_item_call label="Kopiuj do rzeczy Marketplace" name="Marketplace Copy" />
<menu_item_call label="Przenieś do rzeczy Marketplace" name="Marketplace Move" />

View File

@ -52,11 +52,11 @@
<menu_item_call label="Nowy cykl dnia" name="New Day Cycle" />
</menu>
<menu label="Ustaw jako domyślne" name="upload_def">
<menu_item_call label="Dla nowych obrazów" name="Image uploads" />
<menu_item_call label="Dla nowych dźwięków" name="Sound uploads" />
<menu_item_call label="Dla nowych animacji" name="Animation uploads" />
<menu_item_call label="Dla nowych modeli" name="Model uploads" />
<menu_item_call label="Dla nowych materiałów PBR" name="PBR uploads" />
<menu_item_check label="Dla nowych obrazów" name="Image uploads" />
<menu_item_check label="Dla nowych dźwięków" name="Sound uploads" />
<menu_item_check label="Dla nowych animacji" name="Animation uploads" />
<menu_item_check label="Dla nowych modeli" name="Model uploads" />
<menu_item_check label="Dla nowych materiałów PBR" name="PBR uploads" />
</menu>
<menu label="Zmień typ" name="Change Type">
<menu_item_call label="Domyślny" name="Default"/>

View File

@ -48,10 +48,10 @@
<menu_item_call label="Novo ciclo de dias" name="New Day Cycle"/>
</menu>
<menu label="Usar como padrão para" name="upload_def">
<menu_item_call label="Envios de imagem" name="Image uploads"/>
<menu_item_call label="Envios de som" name="Sound uploads"/>
<menu_item_call label="Envios de animação" name="Animation uploads"/>
<menu_item_call label="Envios de modelos" name="Model uploads"/>
<menu_item_check label="Envios de imagem" name="Image uploads"/>
<menu_item_check label="Envios de som" name="Sound uploads"/>
<menu_item_check label="Envios de animação" name="Animation uploads"/>
<menu_item_check label="Envios de modelos" name="Model uploads"/>
</menu>
<menu label="Alterar fonte" name="Change Type">
<menu_item_call label="Padrão" name="Default"/>

View File

@ -62,11 +62,11 @@
<menu_item_call label="Масса..." name="Bulk Upload"/>
</menu>
<menu label="Использовать по умолчанию для" name="upload_def">
<menu_item_call label="Загрузки изображений" name="Image uploads"/>
<menu_item_call label="Загрузки звука" name="Sound uploads"/>
<menu_item_call label="Загрузки анимации" name="Animation uploads"/>
<menu_item_call label="Загрузки модели" name="Model uploads"/>
<menu_item_call label="Загрузки PBR материала" name="PBR uploads"/>
<menu_item_check label="Загрузки изображений" name="Image uploads"/>
<menu_item_check label="Загрузки звука" name="Sound uploads"/>
<menu_item_check label="Загрузки анимации" name="Animation uploads"/>
<menu_item_check label="Загрузки модели" name="Model uploads"/>
<menu_item_check label="Загрузки PBR материала" name="PBR uploads"/>
</menu>
<menu_item_call label="Копировать в списки торговой площадки" name="Marketplace Copy"/>
<menu_item_call label="Перейти в списки торговой площадки" name="Marketplace Move"/>

View File

@ -51,11 +51,11 @@
<menu_item_call label="Новый Цикл дня" name="New Day Cycle"/>
</menu>
<menu label="Использовать для" name="upload_def">
<menu_item_call label="загрузок Изображений" name="Image uploads"/>
<menu_item_call label="загрузок Звуков" name="Sound uploads"/>
<menu_item_call label="загрузок Анимаций" name="Animation uploads"/>
<menu_item_call label="загрузок Моделей" name="Model uploads"/>
<menu_item_call label="загрузок Материалов PBR" name="PBR uploads"/>
<menu_item_check label="загрузок Изображений" name="Image uploads"/>
<menu_item_check label="загрузок Звуков" name="Sound uploads"/>
<menu_item_check label="загрузок Анимаций" name="Animation uploads"/>
<menu_item_check label="загрузок Моделей" name="Model uploads"/>
<menu_item_check label="загрузок Материалов PBR" name="PBR uploads"/>
</menu>
<menu label="Изменить тип" name="Change Type">
<menu_item_call label="По умолчанию" name="Default"/>

View File

@ -48,10 +48,10 @@
<menu_item_call label="Yeni Gün Döngüsü" name="New Day Cycle"/>
</menu>
<menu label="Şunun için varsayılan olarak kullan" name="upload_def">
<menu_item_call label="Karşıya yüklenen görüntüler" name="Image uploads"/>
<menu_item_call label="Karşıya yüklenen sesler" name="Sound uploads"/>
<menu_item_call label="Karşıya yüklenen animasyonlar" name="Animation uploads"/>
<menu_item_call label="Karşıya yüklenen modeller" name="Model uploads"/>
<menu_item_check label="Karşıya yüklenen görüntüler" name="Image uploads"/>
<menu_item_check label="Karşıya yüklenen sesler" name="Sound uploads"/>
<menu_item_check label="Karşıya yüklenen animasyonlar" name="Animation uploads"/>
<menu_item_check label="Karşıya yüklenen modeller" name="Model uploads"/>
</menu>
<menu label="Türü Değiştir" name="Change Type">
<menu_item_call label="Varsayılan" name="Default"/>

View File

@ -95,11 +95,11 @@
<menu_item_call label="批量上傳..." name="Bulk Upload" />
</menu>
<menu label="預設用作" name="upload_def">
<menu_item_call label="上傳圖像" name="Image uploads" />
<menu_item_call label="上傳聲音" name="Sound uploads" />
<menu_item_call label="上傳動畫" name="Animation uploads" />
<menu_item_call label="上傳模型" name="Model uploads" />
<menu_item_call label="上傳PBR材質" name="PBR uploads" />
<menu_item_check label="上傳圖像" name="Image uploads" />
<menu_item_check label="上傳聲音" name="Sound uploads" />
<menu_item_check label="上傳動畫" name="Animation uploads" />
<menu_item_check label="上傳模型" name="Model uploads" />
<menu_item_check label="上傳PBR材質" name="PBR uploads" />
</menu>
<menu_item_call label="複製到市場刊登" name="Marketplace Copy" />
<menu_item_call label="移到市場刊登" name="Marketplace Move" />

View File

@ -52,11 +52,11 @@
<menu_item_call label="新的晝夜循環" name="New Day Cycle" />
</menu>
<menu label="預設用作" name="upload_def">
<menu_item_call label="圖像上傳" name="Image uploads" />
<menu_item_call label="聲音上傳" name="Sound uploads" />
<menu_item_call label="動畫上傳" name="Animation uploads" />
<menu_item_call label="模型上傳" name="Model uploads" />
<menu_item_call label="PBR材質上傳" name="PBR uploads" />
<menu_item_check label="圖像上傳" name="Image uploads" />
<menu_item_check label="聲音上傳" name="Sound uploads" />
<menu_item_check label="動畫上傳" name="Animation uploads" />
<menu_item_check label="模型上傳" name="Model uploads" />
<menu_item_check label="PBR材質上傳" name="PBR uploads" />
</menu>
<menu_item_call label="作為收藏夾使用" name="Set Favorites folder" />
<menu_item_call label="重設收藏夾" name="Reset Favorites folder" />