//// Audio.cpp// interface/src/scripting//// Created by Zach Pomerantz on 28/5/2017.// Copyright 2017 High Fidelity, Inc.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// #include "Audio.h" #include <shared/QtHelpers.h> #include "Application.h"#include "AudioClient.h"#include "AudioHelpers.h"#include "ui/AvatarInputs.h"#include "ui/Snapshot.h"#include "AccountManager.h" using namespace scripting; QString Audio::AUDIO { "Audio" };QString Audio::DESKTOP { "Desktop" };QString Audio::HMD { "VR" }; Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true };Setting::Handle<bool> enableNoiseReductionAutomaticSetting { QStringList { Audio::AUDIO, "NoiseReductionAutomatic" }, true };Setting::Handle<float> setNoiseReductionThresholdSetting { QStringList { Audio::AUDIO, "NoiseReductionThreshold" }, 0.1f };Setting::Handle<bool> enableWarnWhenMutedSetting { QStringList { Audio::AUDIO, "WarnWhenMuted" }, true };Setting::Handle<bool> enableAcousticEchoCancellationSetting { QStringList { Audio::AUDIO, "AcousticEchoCancellation" }, true }; float Audio::loudnessToLevel(float loudness) { float level = loudness * (1/32768.0f); // level in [0, 1] level = 6.02059991f * fastLog2f(level); // convert to dBFS level = (level + 48.0f) * (1/42.0f); // map [-48, -6] dBFS to [0, 1] return glm::clamp(level, 0.0f, 1.0f);} Audio::Audio() : _devices(_contextIsHMD) { auto client = DependencyManager::get<AudioClient>().data(); connect(client, &AudioClient::muteToggled, this, &Audio::setMuted); connect(client, &AudioClient::noiseReductionChanged, this, &Audio::enableNoiseReduction); connect(client, &AudioClient::noiseReductionAutomaticChanged, this, &Audio::enableNoiseReductionAutomatic); connect(client, &AudioClient::noiseReductionThresholdChanged, this, &Audio::setNoiseReductionThreshold); connect(client, &AudioClient::warnWhenMutedChanged, this, &Audio::enableWarnWhenMuted); connect(client, &AudioClient::acousticEchoCancellationChanged, this, &Audio::enableAcousticEchoCancellation); connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged); connect(client, &AudioClient::inputVolumeChanged, this, &Audio::setInputVolume); connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged); connect(this, &Audio::pushingToTalkChanged, this, &Audio::handlePushedToTalk); enableNoiseReduction(enableNoiseReductionSetting.get()); enableNoiseReductionAutomatic(enableNoiseReductionAutomaticSetting.get()); setNoiseReductionThreshold(setNoiseReductionThresholdSetting.get()); enableWarnWhenMuted(enableWarnWhenMutedSetting.get()); enableAcousticEchoCancellation(enableAcousticEchoCancellationSetting.get());} QUuid Audio::startRecording() { return resultWithWriteLock<QUuid>([&] { const QString FILENAME_PREFIX = "overte-audio-"; const QString AUDIO_FORMAT = "wav"; QUuid id = QUuid::createUuid(); QString filepath = DependencyManager::get<Snapshot>()->_snapshotsLocation.get(); QString filename = FILENAME_PREFIX + id.toString() + "." + AUDIO_FORMAT; if (DependencyManager::get<AudioClient>()->startRecording(filepath + "/" + filename)) { return id; } else { return QUuid(); } });} bool Audio::getRecording() { return resultWithReadLock<bool>([&] { return DependencyManager::get<AudioClient>()->getRecording(); });} void Audio::stopRecording() { withWriteLock([&] { DependencyManager::get<AudioClient>()->stopRecording(); });} bool Audio::isMuted() const { bool isHMD = qApp->isHMDMode(); if (isHMD) { return getMutedHMD(); } else { return getMutedDesktop(); }} void Audio::setMuted(bool isMuted) { bool isHMD = qApp->isHMDMode(); if (isHMD) { setMutedHMD(isMuted); } else { setMutedDesktop(isMuted); }} void Audio::setMutedDesktop(bool isMuted) { bool changed = false; bool isHMD = qApp->isHMDMode(); withWriteLock([&] { if (_mutedDesktop != isMuted) { changed = true; _mutedDesktop = isMuted; if (!isHMD) { auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); } } }); if (!isMuted && _settingsLoaded && !_pushingToTalk) { // If the user is not pushing to talk and muted is changed to false, disable Push-To-Talk. Settings also need to be loaded. setPTTDesktop(isMuted); } if (changed) { if (!isHMD) { emit mutedChanged(isMuted); } emit mutedDesktopChanged(isMuted); }} bool Audio::getMutedDesktop() const { return resultWithReadLock<bool>([&] { return _mutedDesktop; });} void Audio::setMutedHMD(bool isMuted) { bool changed = false; bool isHMD = qApp->isHMDMode(); withWriteLock([&] { if (_mutedHMD != isMuted) { changed = true; _mutedHMD = isMuted; if (isHMD) { auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); } } }); if (!isMuted && _settingsLoaded && !_pushingToTalk) { // If the user is not pushing to talk and muted is changed to false, disable Push-To-Talk. Settings also need to be loaded. setPTTHMD(isMuted); } if (changed) { if (isHMD) { emit mutedChanged(isMuted); } emit mutedHMDChanged(isMuted); }} bool Audio::getMutedHMD() const { return resultWithReadLock<bool>([&] { return _mutedHMD; });} bool Audio::getPTT() { bool isHMD = qApp->isHMDMode(); if (isHMD) { return getPTTHMD(); } else { return getPTTDesktop(); }} void scripting::Audio::setPushingToTalk(bool pushingToTalk) { bool changed = false; withWriteLock([&] { if (_pushingToTalk != pushingToTalk) { changed = true; _pushingToTalk = pushingToTalk; } }); if (changed) { emit pushingToTalkChanged(pushingToTalk); }} bool Audio::getPushingToTalk() const { return resultWithReadLock<bool>([&] { return _pushingToTalk; });} void Audio::setPTT(bool enabled) { bool isHMD = qApp->isHMDMode(); if (isHMD) { setPTTHMD(enabled); } else { setPTTDesktop(enabled); }} void Audio::setPTTDesktop(bool enabled) { bool changed = false; withWriteLock([&] { if (_pttDesktop != enabled) { changed = true; _pttDesktop = enabled; } }); if (enabled && _settingsLoaded) { // Set to default behavior (muted for Desktop) on Push-To-Talk disable or when enabled. Settings also need to be loaded. setMutedDesktop(enabled); } if (changed) { emit pushToTalkChanged(enabled); emit pushToTalkDesktopChanged(enabled); }} bool Audio::getPTTDesktop() const { return resultWithReadLock<bool>([&] { return _pttDesktop; });} void Audio::setPTTHMD(bool enabled) { bool changed = false; withWriteLock([&] { if (_pttHMD != enabled) { changed = true; _pttHMD = enabled; } }); if (enabled && _settingsLoaded) { // Set to default behavior (unmuted for HMD) on Push-To-Talk disable or muted for when PTT is enabled. setMutedHMD(enabled); } if (changed) { emit pushToTalkChanged(enabled); emit pushToTalkHMDChanged(enabled); }} void Audio::saveData() { _avatarGainSetting.set(getAvatarGain()); _injectorGainSetting.set(getInjectorGain()); _localInjectorGainSetting.set(getLocalInjectorGain()); _systemInjectorGainSetting.set(getSystemInjectorGain()); _mutedDesktopSetting.set(getMutedDesktop()); _mutedHMDSetting.set(getMutedHMD()); _pttDesktopSetting.set(getPTTDesktop()); _pttHMDSetting.set(getPTTHMD());} void Audio::loadData() { setAvatarGain(_avatarGainSetting.get()); setInjectorGain(_injectorGainSetting.get()); setLocalInjectorGain(_localInjectorGainSetting.get()); setSystemInjectorGain(_systemInjectorGainSetting.get()); setMutedDesktop(_mutedDesktopSetting.get()); setMutedHMD(_mutedHMDSetting.get()); setPTTDesktop(_pttDesktopSetting.get()); setPTTHMD(_pttHMDSetting.get()); auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted()), Q_ARG(bool, false)); _settingsLoaded = true;} bool Audio::getPTTHMD() const { return resultWithReadLock<bool>([&] { return _pttHMD; });} bool Audio::noiseReductionEnabled() const { return resultWithReadLock<bool>([&] { return _enableNoiseReduction; });} void Audio::enableNoiseReduction(bool enable) { bool changed = false; withWriteLock([&] { if (_enableNoiseReduction != enable) { _enableNoiseReduction = enable; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setNoiseReduction", Q_ARG(bool, enable), Q_ARG(bool, false)); enableNoiseReductionSetting.set(enable); changed = true; } }); if (changed) { emit noiseReductionChanged(enable); }} bool Audio::noiseReductionAutomatic() const { return resultWithReadLock<bool>([&] { return _noiseReductionAutomatic; });} void Audio::enableNoiseReductionAutomatic(bool enable) { bool changed = false; withWriteLock([&] { if (_noiseReductionAutomatic != enable) { _noiseReductionAutomatic = enable; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setNoiseReductionAutomatic", Q_ARG(bool, enable), Q_ARG(bool, false)); enableNoiseReductionAutomaticSetting.set(enable); changed = true; } }); if (changed) { emit noiseReductionAutomaticChanged(enable); }} float Audio::getNoiseReductionThreshold() { return resultWithReadLock<float>([&] { return _noiseReductionThreshold; });} void Audio::setNoiseReductionThreshold(float threshold) { bool changed = false; withWriteLock([&] { if (_noiseReductionThreshold != threshold) { _noiseReductionThreshold = threshold; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setNoiseReductionThreshold", Q_ARG(float, threshold), Q_ARG(bool, false)); setNoiseReductionThresholdSetting.set(threshold); changed = true; } }); if (changed) { emit noiseReductionThresholdChanged(threshold); }} bool Audio::warnWhenMutedEnabled() const { return resultWithReadLock<bool>([&] { return _enableWarnWhenMuted; });} void Audio::enableWarnWhenMuted(bool enable) { bool changed = false; withWriteLock([&] { if (_enableWarnWhenMuted != enable) { _enableWarnWhenMuted = enable; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setWarnWhenMuted", Q_ARG(bool, enable), Q_ARG(bool, false)); enableWarnWhenMutedSetting.set(enable); changed = true; } }); if (changed) { emit warnWhenMutedChanged(enable); }} bool Audio::acousticEchoCancellationEnabled() const { return resultWithReadLock<bool>([&] { return _enableAcousticEchoCancellation; });} void Audio::enableAcousticEchoCancellation(bool enable) { bool changed = false; withWriteLock([&] { if (_enableAcousticEchoCancellation != enable) { _enableAcousticEchoCancellation = enable; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setAcousticEchoCancellation", Q_ARG(bool, enable), Q_ARG(bool, false)); enableAcousticEchoCancellationSetting.set(enable); changed = true; } }); if (changed) { emit acousticEchoCancellationChanged(enable); }} float Audio::getInputVolume() const { return resultWithReadLock<bool>([&] { return _inputVolume; });} void Audio::setInputVolume(float volume) { // getInputVolume will not reflect changes synchronously, so clamp beforehand volume = glm::clamp(volume, 0.0f, 1.0f); bool changed = false; withWriteLock([&] { if (_inputVolume != volume) { _inputVolume = volume; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setInputVolume", Q_ARG(float, volume), Q_ARG(bool, false)); changed = true; } }); if (changed) { emit inputVolumeChanged(volume); }} float Audio::getInputLevel() const { return resultWithReadLock<float>([&] { return _inputLevel; });} bool Audio::isClipping() const { return resultWithReadLock<bool>([&] { return _isClipping; });} void Audio::onInputLoudnessChanged(float loudness, bool isClipping) { float level = loudnessToLevel(loudness); bool levelChanged = false; bool isClippingChanged = false; withWriteLock([&] { if (_inputLevel != level) { _inputLevel = level; levelChanged = true; } if (_isClipping != isClipping) { _isClipping = isClipping; isClippingChanged = true; } }); if (levelChanged) { emit inputLevelChanged(level); } if (isClippingChanged) { emit clippingChanged(isClipping); }} QString Audio::getContext() const { return resultWithReadLock<QString>([&] { return _contextIsHMD ? Audio::HMD : Audio::DESKTOP; });} void Audio::onContextChanged() { bool changed = false; bool isHMD = qApp->isHMDMode(); withWriteLock([&] { if (_contextIsHMD != isHMD) { _contextIsHMD = isHMD; changed = true; } }); if (_settingsLoaded) { bool isMuted = isHMD ? getMutedHMD() : getMutedDesktop(); setMuted(isMuted); // always set audio client muted state on context changed - sometimes setMuted does not catch it. auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); } if (changed) { emit contextChanged(isHMD ? Audio::HMD : Audio::DESKTOP); bool mutedHMD = getMutedHMD(); bool mutedDesktop = getMutedDesktop(); if (mutedHMD != mutedDesktop) { emit mutedChanged(isHMD ? mutedHMD : mutedDesktop); } }} void Audio::handlePushedToTalk(bool enabled) { if (getPTT()) { if (enabled) { if (!qApp->isHMDMode()) { float gain = resultWithReadLock<float>([&] { return _pttOutputGainDesktop; }); // convert dB to amplitude gain = fastExp2f(gain / 6.02059991f); DependencyManager::get<AudioClient>()->setOutputGain(gain); // duck the output by N dB } setMuted(false); } else { DependencyManager::get<AudioClient>()->setOutputGain(1.0f); setMuted(true); }Lines 1–500 of 653. Load more
// // Audio.cpp // interface/src/scripting // // Created by Zach Pomerantz on 28/5/2017. // Copyright 2017 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "Audio.h" #include <shared/QtHelpers.h> #include "Application.h" #include "AudioClient.h" #include "AudioHelpers.h" #include "ui/AvatarInputs.h" #include "ui/Snapshot.h" #include "AccountManager.h" using namespace scripting; QString Audio::AUDIO { "Audio" }; QString Audio::DESKTOP { "Desktop" }; QString Audio::HMD { "VR" }; Setting::Handle<bool> enableNoiseReductionSetting { QStringList { Audio::AUDIO, "NoiseReduction" }, true }; Setting::Handle<bool> enableNoiseReductionAutomaticSetting { QStringList { Audio::AUDIO, "NoiseReductionAutomatic" }, true }; Setting::Handle<float> setNoiseReductionThresholdSetting { QStringList { Audio::AUDIO, "NoiseReductionThreshold" }, 0.1f }; Setting::Handle<bool> enableWarnWhenMutedSetting { QStringList { Audio::AUDIO, "WarnWhenMuted" }, true }; Setting::Handle<bool> enableAcousticEchoCancellationSetting { QStringList { Audio::AUDIO, "AcousticEchoCancellation" }, true }; float Audio::loudnessToLevel(float loudness) { float level = loudness * (1/32768.0f); // level in [0, 1] level = 6.02059991f * fastLog2f(level); // convert to dBFS level = (level + 48.0f) * (1/42.0f); // map [-48, -6] dBFS to [0, 1] return glm::clamp(level, 0.0f, 1.0f); } Audio::Audio() : _devices(_contextIsHMD) { auto client = DependencyManager::get<AudioClient>().data(); connect(client, &AudioClient::muteToggled, this, &Audio::setMuted); connect(client, &AudioClient::noiseReductionChanged, this, &Audio::enableNoiseReduction); connect(client, &AudioClient::noiseReductionAutomaticChanged, this, &Audio::enableNoiseReductionAutomatic); connect(client, &AudioClient::noiseReductionThresholdChanged, this, &Audio::setNoiseReductionThreshold); connect(client, &AudioClient::warnWhenMutedChanged, this, &Audio::enableWarnWhenMuted); connect(client, &AudioClient::acousticEchoCancellationChanged, this, &Audio::enableAcousticEchoCancellation); connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged); connect(client, &AudioClient::inputVolumeChanged, this, &Audio::setInputVolume); connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged); connect(this, &Audio::pushingToTalkChanged, this, &Audio::handlePushedToTalk); enableNoiseReduction(enableNoiseReductionSetting.get()); enableNoiseReductionAutomatic(enableNoiseReductionAutomaticSetting.get()); setNoiseReductionThreshold(setNoiseReductionThresholdSetting.get()); enableWarnWhenMuted(enableWarnWhenMutedSetting.get()); enableAcousticEchoCancellation(enableAcousticEchoCancellationSetting.get()); } QUuid Audio::startRecording() { return resultWithWriteLock<QUuid>([&] { const QString FILENAME_PREFIX = "overte-audio-"; const QString AUDIO_FORMAT = "wav"; QUuid id = QUuid::createUuid(); QString filepath = DependencyManager::get<Snapshot>()->_snapshotsLocation.get(); QString filename = FILENAME_PREFIX + id.toString() + "." + AUDIO_FORMAT; if (DependencyManager::get<AudioClient>()->startRecording(filepath + "/" + filename)) { return id; } else { return QUuid(); } }); } bool Audio::getRecording() { return resultWithReadLock<bool>([&] { return DependencyManager::get<AudioClient>()->getRecording(); }); } void Audio::stopRecording() { withWriteLock([&] { DependencyManager::get<AudioClient>()->stopRecording(); }); } bool Audio::isMuted() const { bool isHMD = qApp->isHMDMode(); if (isHMD) { return getMutedHMD(); } else { return getMutedDesktop(); } } void Audio::setMuted(bool isMuted) { bool isHMD = qApp->isHMDMode(); if (isHMD) { setMutedHMD(isMuted); } else { setMutedDesktop(isMuted); } } void Audio::setMutedDesktop(bool isMuted) { bool changed = false; bool isHMD = qApp->isHMDMode(); withWriteLock([&] { if (_mutedDesktop != isMuted) { changed = true; _mutedDesktop = isMuted; if (!isHMD) { auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); } } }); if (!isMuted && _settingsLoaded && !_pushingToTalk) { // If the user is not pushing to talk and muted is changed to false, disable Push-To-Talk. Settings also need to be loaded. setPTTDesktop(isMuted); } if (changed) { if (!isHMD) { emit mutedChanged(isMuted); } emit mutedDesktopChanged(isMuted); } } bool Audio::getMutedDesktop() const { return resultWithReadLock<bool>([&] { return _mutedDesktop; }); } void Audio::setMutedHMD(bool isMuted) { bool changed = false; bool isHMD = qApp->isHMDMode(); withWriteLock([&] { if (_mutedHMD != isMuted) { changed = true; _mutedHMD = isMuted; if (isHMD) { auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); } } }); if (!isMuted && _settingsLoaded && !_pushingToTalk) { // If the user is not pushing to talk and muted is changed to false, disable Push-To-Talk. Settings also need to be loaded. setPTTHMD(isMuted); } if (changed) { if (isHMD) { emit mutedChanged(isMuted); } emit mutedHMDChanged(isMuted); } } bool Audio::getMutedHMD() const { return resultWithReadLock<bool>([&] { return _mutedHMD; }); } bool Audio::getPTT() { bool isHMD = qApp->isHMDMode(); if (isHMD) { return getPTTHMD(); } else { return getPTTDesktop(); } } void scripting::Audio::setPushingToTalk(bool pushingToTalk) { bool changed = false; withWriteLock([&] { if (_pushingToTalk != pushingToTalk) { changed = true; _pushingToTalk = pushingToTalk; } }); if (changed) { emit pushingToTalkChanged(pushingToTalk); } } bool Audio::getPushingToTalk() const { return resultWithReadLock<bool>([&] { return _pushingToTalk; }); } void Audio::setPTT(bool enabled) { bool isHMD = qApp->isHMDMode(); if (isHMD) { setPTTHMD(enabled); } else { setPTTDesktop(enabled); } } void Audio::setPTTDesktop(bool enabled) { bool changed = false; withWriteLock([&] { if (_pttDesktop != enabled) { changed = true; _pttDesktop = enabled; } }); if (enabled && _settingsLoaded) { // Set to default behavior (muted for Desktop) on Push-To-Talk disable or when enabled. Settings also need to be loaded. setMutedDesktop(enabled); } if (changed) { emit pushToTalkChanged(enabled); emit pushToTalkDesktopChanged(enabled); } } bool Audio::getPTTDesktop() const { return resultWithReadLock<bool>([&] { return _pttDesktop; }); } void Audio::setPTTHMD(bool enabled) { bool changed = false; withWriteLock([&] { if (_pttHMD != enabled) { changed = true; _pttHMD = enabled; } }); if (enabled && _settingsLoaded) { // Set to default behavior (unmuted for HMD) on Push-To-Talk disable or muted for when PTT is enabled. setMutedHMD(enabled); } if (changed) { emit pushToTalkChanged(enabled); emit pushToTalkHMDChanged(enabled); } } void Audio::saveData() { _avatarGainSetting.set(getAvatarGain()); _injectorGainSetting.set(getInjectorGain()); _localInjectorGainSetting.set(getLocalInjectorGain()); _systemInjectorGainSetting.set(getSystemInjectorGain()); _mutedDesktopSetting.set(getMutedDesktop()); _mutedHMDSetting.set(getMutedHMD()); _pttDesktopSetting.set(getPTTDesktop()); _pttHMDSetting.set(getPTTHMD()); } void Audio::loadData() { setAvatarGain(_avatarGainSetting.get()); setInjectorGain(_injectorGainSetting.get()); setLocalInjectorGain(_localInjectorGainSetting.get()); setSystemInjectorGain(_systemInjectorGainSetting.get()); setMutedDesktop(_mutedDesktopSetting.get()); setMutedHMD(_mutedHMDSetting.get()); setPTTDesktop(_pttDesktopSetting.get()); setPTTHMD(_pttHMDSetting.get()); auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted()), Q_ARG(bool, false)); _settingsLoaded = true; } bool Audio::getPTTHMD() const { return resultWithReadLock<bool>([&] { return _pttHMD; }); } bool Audio::noiseReductionEnabled() const { return resultWithReadLock<bool>([&] { return _enableNoiseReduction; }); } void Audio::enableNoiseReduction(bool enable) { bool changed = false; withWriteLock([&] { if (_enableNoiseReduction != enable) { _enableNoiseReduction = enable; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setNoiseReduction", Q_ARG(bool, enable), Q_ARG(bool, false)); enableNoiseReductionSetting.set(enable); changed = true; } }); if (changed) { emit noiseReductionChanged(enable); } } bool Audio::noiseReductionAutomatic() const { return resultWithReadLock<bool>([&] { return _noiseReductionAutomatic; }); } void Audio::enableNoiseReductionAutomatic(bool enable) { bool changed = false; withWriteLock([&] { if (_noiseReductionAutomatic != enable) { _noiseReductionAutomatic = enable; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setNoiseReductionAutomatic", Q_ARG(bool, enable), Q_ARG(bool, false)); enableNoiseReductionAutomaticSetting.set(enable); changed = true; } }); if (changed) { emit noiseReductionAutomaticChanged(enable); } } float Audio::getNoiseReductionThreshold() { return resultWithReadLock<float>([&] { return _noiseReductionThreshold; }); } void Audio::setNoiseReductionThreshold(float threshold) { bool changed = false; withWriteLock([&] { if (_noiseReductionThreshold != threshold) { _noiseReductionThreshold = threshold; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setNoiseReductionThreshold", Q_ARG(float, threshold), Q_ARG(bool, false)); setNoiseReductionThresholdSetting.set(threshold); changed = true; } }); if (changed) { emit noiseReductionThresholdChanged(threshold); } } bool Audio::warnWhenMutedEnabled() const { return resultWithReadLock<bool>([&] { return _enableWarnWhenMuted; }); } void Audio::enableWarnWhenMuted(bool enable) { bool changed = false; withWriteLock([&] { if (_enableWarnWhenMuted != enable) { _enableWarnWhenMuted = enable; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setWarnWhenMuted", Q_ARG(bool, enable), Q_ARG(bool, false)); enableWarnWhenMutedSetting.set(enable); changed = true; } }); if (changed) { emit warnWhenMutedChanged(enable); } } bool Audio::acousticEchoCancellationEnabled() const { return resultWithReadLock<bool>([&] { return _enableAcousticEchoCancellation; }); } void Audio::enableAcousticEchoCancellation(bool enable) { bool changed = false; withWriteLock([&] { if (_enableAcousticEchoCancellation != enable) { _enableAcousticEchoCancellation = enable; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setAcousticEchoCancellation", Q_ARG(bool, enable), Q_ARG(bool, false)); enableAcousticEchoCancellationSetting.set(enable); changed = true; } }); if (changed) { emit acousticEchoCancellationChanged(enable); } } float Audio::getInputVolume() const { return resultWithReadLock<bool>([&] { return _inputVolume; }); } void Audio::setInputVolume(float volume) { // getInputVolume will not reflect changes synchronously, so clamp beforehand volume = glm::clamp(volume, 0.0f, 1.0f); bool changed = false; withWriteLock([&] { if (_inputVolume != volume) { _inputVolume = volume; auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setInputVolume", Q_ARG(float, volume), Q_ARG(bool, false)); changed = true; } }); if (changed) { emit inputVolumeChanged(volume); } } float Audio::getInputLevel() const { return resultWithReadLock<float>([&] { return _inputLevel; }); } bool Audio::isClipping() const { return resultWithReadLock<bool>([&] { return _isClipping; }); } void Audio::onInputLoudnessChanged(float loudness, bool isClipping) { float level = loudnessToLevel(loudness); bool levelChanged = false; bool isClippingChanged = false; withWriteLock([&] { if (_inputLevel != level) { _inputLevel = level; levelChanged = true; } if (_isClipping != isClipping) { _isClipping = isClipping; isClippingChanged = true; } }); if (levelChanged) { emit inputLevelChanged(level); } if (isClippingChanged) { emit clippingChanged(isClipping); } } QString Audio::getContext() const { return resultWithReadLock<QString>([&] { return _contextIsHMD ? Audio::HMD : Audio::DESKTOP; }); } void Audio::onContextChanged() { bool changed = false; bool isHMD = qApp->isHMDMode(); withWriteLock([&] { if (_contextIsHMD != isHMD) { _contextIsHMD = isHMD; changed = true; } }); if (_settingsLoaded) { bool isMuted = isHMD ? getMutedHMD() : getMutedDesktop(); setMuted(isMuted); // always set audio client muted state on context changed - sometimes setMuted does not catch it. auto client = DependencyManager::get<AudioClient>().data(); QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false)); } if (changed) { emit contextChanged(isHMD ? Audio::HMD : Audio::DESKTOP); bool mutedHMD = getMutedHMD(); bool mutedDesktop = getMutedDesktop(); if (mutedHMD != mutedDesktop) { emit mutedChanged(isHMD ? mutedHMD : mutedDesktop); } } } void Audio::handlePushedToTalk(bool enabled) { if (getPTT()) { if (enabled) { if (!qApp->isHMDMode()) { float gain = resultWithReadLock<float>([&] { return _pttOutputGainDesktop; }); // convert dB to amplitude gain = fastExp2f(gain / 6.02059991f); DependencyManager::get<AudioClient>()->setOutputGain(gain); // duck the output by N dB } setMuted(false); } else { DependencyManager::get<AudioClient>()->setOutputGain(1.0f); setMuted(true); }