Merge pull request #12937 from SamGondelman/startup

Make Audio.cpp threadsafe
This commit is contained in:
Seth Alves 2018-04-20 11:36:08 -07:00 committed by GitHub
commit c20346ca53
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 134 additions and 75 deletions

View file

@ -1099,10 +1099,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>(); auto audioScriptingInterface = DependencyManager::get<AudioScriptingInterface>();
auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldPosition(); auto myAvatarPosition = DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldPosition();
float distance = glm::distance(myAvatarPosition, position); float distance = glm::distance(myAvatarPosition, position);
bool shouldMute = !audioClient->isMuted() && (distance < radius);
if (shouldMute) { if (distance < radius) {
audioClient->toggleMute(); audioClient->setMuted(true);
audioScriptingInterface->environmentMuted(); audioScriptingInterface->environmentMuted();
} }
}); });
@ -1527,7 +1526,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
if (state) { if (state) {
if (action == controller::toInt(controller::Action::TOGGLE_MUTE)) { if (action == controller::toInt(controller::Action::TOGGLE_MUTE)) {
DependencyManager::get<AudioClient>()->toggleMute(); auto audioClient = DependencyManager::get<AudioClient>();
audioClient->setMuted(!audioClient->isMuted());
} else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) { } else if (action == controller::toInt(controller::Action::CYCLE_CAMERA)) {
cycleCamera(); cycleCamera();
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) { } else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
@ -3465,7 +3465,8 @@ void Application::keyPressEvent(QKeyEvent* event) {
case Qt::Key_M: case Qt::Key_M:
if (isMeta) { if (isMeta) {
DependencyManager::get<AudioClient>()->toggleMute(); auto audioClient = DependencyManager::get<AudioClient>();
audioClient->setMuted(!audioClient->isMuted());
} }
break; break;
@ -5120,7 +5121,7 @@ void Application::update(float deltaTime) {
if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) { if (menu->isOptionChecked(MenuOption::AutoMuteAudio) && !audioClient->isMuted()) {
if (_lastFaceTrackerUpdate > 0 if (_lastFaceTrackerUpdate > 0
&& ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) { && ((usecTimestampNow() - _lastFaceTrackerUpdate) > MUTE_MICROPHONE_AFTER_USECS)) {
audioClient->toggleMute(); audioClient->setMuted(true);
_lastFaceTrackerUpdate = 0; _lastFaceTrackerUpdate = 0;
} }
} else { } else {

View file

@ -50,110 +50,162 @@ float Audio::loudnessToLevel(float loudness) {
Audio::Audio() : _devices(_contextIsHMD) { Audio::Audio() : _devices(_contextIsHMD) {
auto client = DependencyManager::get<AudioClient>().data(); auto client = DependencyManager::get<AudioClient>().data();
connect(client, &AudioClient::muteToggled, this, &Audio::onMutedChanged); connect(client, &AudioClient::muteToggled, this, &Audio::setMuted);
connect(client, &AudioClient::noiseReductionChanged, this, &Audio::onNoiseReductionChanged); connect(client, &AudioClient::noiseReductionChanged, this, &Audio::enableNoiseReduction);
connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged); connect(client, &AudioClient::inputLoudnessChanged, this, &Audio::onInputLoudnessChanged);
connect(client, &AudioClient::inputVolumeChanged, this, &Audio::onInputVolumeChanged); connect(client, &AudioClient::inputVolumeChanged, this, &Audio::setInputVolume);
connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged); connect(this, &Audio::contextChanged, &_devices, &AudioDevices::onContextChanged);
enableNoiseReduction(enableNoiseReductionSetting.get()); enableNoiseReduction(enableNoiseReductionSetting.get());
} }
bool Audio::startRecording(const QString& filepath) { bool Audio::startRecording(const QString& filepath) {
auto client = DependencyManager::get<AudioClient>().data(); auto client = DependencyManager::get<AudioClient>().data();
return client->startRecording(filepath); return resultWithWriteLock<bool>([&] {
return client->startRecording(filepath);
});
} }
bool Audio::getRecording() { bool Audio::getRecording() {
auto client = DependencyManager::get<AudioClient>().data(); auto client = DependencyManager::get<AudioClient>().data();
return client->getRecording(); return resultWithReadLock<bool>([&] {
return client->getRecording();
});
} }
void Audio::stopRecording() { void Audio::stopRecording() {
auto client = DependencyManager::get<AudioClient>().data(); auto client = DependencyManager::get<AudioClient>().data();
client->stopRecording(); withWriteLock([&] {
client->stopRecording();
});
}
bool Audio::isMuted() const {
return resultWithReadLock<bool>([&] {
return _isMuted;
});
} }
void Audio::setMuted(bool isMuted) { void Audio::setMuted(bool isMuted) {
if (_isMuted != isMuted) { bool changed = false;
auto client = DependencyManager::get<AudioClient>().data(); withWriteLock([&] {
QMetaObject::invokeMethod(client, "toggleMute"); if (_isMuted != isMuted) {
_isMuted = isMuted;
auto client = DependencyManager::get<AudioClient>().data();
QMetaObject::invokeMethod(client, "setMuted", Q_ARG(bool, isMuted), Q_ARG(bool, false));
changed = true;
}
});
if (changed) {
emit mutedChanged(isMuted);
} }
} }
void Audio::onMutedChanged() { bool Audio::noiseReductionEnabled() const {
bool isMuted = DependencyManager::get<AudioClient>()->isMuted(); return resultWithReadLock<bool>([&] {
if (_isMuted != isMuted) { return _enableNoiseReduction;
_isMuted = isMuted; });
emit mutedChanged(_isMuted);
}
} }
void Audio::enableNoiseReduction(bool enable) { void Audio::enableNoiseReduction(bool enable) {
if (_enableNoiseReduction != enable) { bool changed = false;
auto client = DependencyManager::get<AudioClient>().data(); withWriteLock([&] {
QMetaObject::invokeMethod(client, "setNoiseReduction", Q_ARG(bool, enable)); if (_enableNoiseReduction != enable) {
enableNoiseReductionSetting.set(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);
} }
} }
void Audio::onNoiseReductionChanged() { float Audio::getInputVolume() const {
bool noiseReductionEnabled = DependencyManager::get<AudioClient>()->isNoiseReductionEnabled(); return resultWithReadLock<bool>([&] {
if (_enableNoiseReduction != noiseReductionEnabled) { return _inputVolume;
_enableNoiseReduction = noiseReductionEnabled; });
emit noiseReductionChanged(_enableNoiseReduction);
}
} }
void Audio::setInputVolume(float volume) { void Audio::setInputVolume(float volume) {
// getInputVolume will not reflect changes synchronously, so clamp beforehand // getInputVolume will not reflect changes synchronously, so clamp beforehand
volume = glm::clamp(volume, 0.0f, 1.0f); volume = glm::clamp(volume, 0.0f, 1.0f);
if (_inputVolume != volume) { bool changed = false;
auto client = DependencyManager::get<AudioClient>().data(); withWriteLock([&] {
QMetaObject::invokeMethod(client, "setInputVolume", Q_ARG(float, volume)); 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);
} }
} }
void Audio::onInputVolumeChanged(float volume) { float Audio::getInputLevel() const {
if (_inputVolume != volume) { return resultWithReadLock<bool>([&] {
_inputVolume = volume; return _inputLevel;
emit inputVolumeChanged(_inputVolume); });
}
} }
void Audio::onInputLoudnessChanged(float loudness) { void Audio::onInputLoudnessChanged(float loudness) {
float level = loudnessToLevel(loudness); float level = loudnessToLevel(loudness);
bool changed = false;
if (_inputLevel != level) { withWriteLock([&] {
_inputLevel = level; if (_inputLevel != level) {
emit inputLevelChanged(_inputLevel); _inputLevel = level;
changed = true;
}
});
if (changed) {
emit inputLevelChanged(level);
} }
} }
QString Audio::getContext() const { QString Audio::getContext() const {
return _contextIsHMD ? Audio::HMD : Audio::DESKTOP; return resultWithReadLock<QString>([&] {
return _contextIsHMD ? Audio::HMD : Audio::DESKTOP;
});
} }
void Audio::onContextChanged() { void Audio::onContextChanged() {
bool changed = false;
bool isHMD = qApp->isHMDMode(); bool isHMD = qApp->isHMDMode();
if (_contextIsHMD != isHMD) { withWriteLock([&] {
_contextIsHMD = isHMD; if (_contextIsHMD != isHMD) {
emit contextChanged(getContext()); _contextIsHMD = isHMD;
changed = true;
}
});
if (changed) {
emit contextChanged(isHMD ? Audio::HMD : Audio::DESKTOP);
} }
} }
void Audio::setReverb(bool enable) { void Audio::setReverb(bool enable) {
DependencyManager::get<AudioClient>()->setReverb(enable); withWriteLock([&] {
DependencyManager::get<AudioClient>()->setReverb(enable);
});
} }
void Audio::setReverbOptions(const AudioEffectOptions* options) { void Audio::setReverbOptions(const AudioEffectOptions* options) {
DependencyManager::get<AudioClient>()->setReverbOptions(options); withWriteLock([&] {
DependencyManager::get<AudioClient>()->setReverbOptions(options);
});
} }
void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) { void Audio::setInputDevice(const QAudioDeviceInfo& device, bool isHMD) {
_devices.chooseInputDevice(device, isHMD); withWriteLock([&] {
_devices.chooseInputDevice(device, isHMD);
});
} }
void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) { void Audio::setOutputDevice(const QAudioDeviceInfo& device, bool isHMD) {
_devices.chooseOutputDevice(device, isHMD); withWriteLock([&] {
_devices.chooseOutputDevice(device, isHMD);
});
} }

View file

@ -17,10 +17,11 @@
#include "AudioEffectOptions.h" #include "AudioEffectOptions.h"
#include "SettingHandle.h" #include "SettingHandle.h"
#include "AudioFileWav.h" #include "AudioFileWav.h"
#include <shared/ReadWriteLockable.h>
namespace scripting { namespace scripting {
class Audio : public AudioScriptingInterface { class Audio : public AudioScriptingInterface, protected ReadWriteLockable {
Q_OBJECT Q_OBJECT
SINGLETON_DEPENDENCY SINGLETON_DEPENDENCY
@ -40,16 +41,13 @@ public:
virtual ~Audio() {} virtual ~Audio() {}
bool isMuted() const { return _isMuted; } bool isMuted() const;
bool noiseReductionEnabled() const { return _enableNoiseReduction; } bool noiseReductionEnabled() const;
float getInputVolume() const { return _inputVolume; } float getInputVolume() const;
float getInputLevel() const { return _inputLevel; } float getInputLevel() const;
QString getContext() const; QString getContext() const;
void setMuted(bool muted);
void enableNoiseReduction(bool enable);
void showMicMeter(bool show); void showMicMeter(bool show);
void setInputVolume(float volume);
Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD); Q_INVOKABLE void setInputDevice(const QAudioDeviceInfo& device, bool isHMD);
Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD); Q_INVOKABLE void setOutputDevice(const QAudioDeviceInfo& device, bool isHMD);
@ -72,9 +70,9 @@ public slots:
void onContextChanged(); void onContextChanged();
private slots: private slots:
void onMutedChanged(); void setMuted(bool muted);
void onNoiseReductionChanged(); void enableNoiseReduction(bool enable);
void onInputVolumeChanged(float volume); void setInputVolume(float volume);
void onInputLoudnessChanged(float loudness); void onInputLoudnessChanged(float loudness);
protected: protected:

View file

@ -757,7 +757,7 @@ void AudioClient::Gate::flush() {
void AudioClient::handleNoisyMutePacket(QSharedPointer<ReceivedMessage> message) { void AudioClient::handleNoisyMutePacket(QSharedPointer<ReceivedMessage> message) {
if (!_muted) { if (!_muted) {
toggleMute(); setMuted(true);
// have the audio scripting interface emit a signal to say we were muted by the mixer // have the audio scripting interface emit a signal to say we were muted by the mixer
emit mutedByMixer(); emit mutedByMixer();
@ -1384,15 +1384,21 @@ void AudioClient::sendMuteEnvironmentPacket() {
} }
} }
void AudioClient::toggleMute() { void AudioClient::setMuted(bool muted, bool emitSignal) {
_muted = !_muted; if (_muted != muted) {
emit muteToggled(); _muted = muted;
if (emitSignal) {
emit muteToggled(_muted);
}
}
} }
void AudioClient::setNoiseReduction(bool enable) { void AudioClient::setNoiseReduction(bool enable, bool emitSignal) {
if (_isNoiseGateEnabled != enable) { if (_isNoiseGateEnabled != enable) {
_isNoiseGateEnabled = enable; _isNoiseGateEnabled = enable;
emit noiseReductionChanged(); if (emitSignal) {
emit noiseReductionChanged(_isNoiseGateEnabled);
}
} }
} }
@ -2018,9 +2024,11 @@ void AudioClient::startThread() {
moveToNewNamedThread(this, "Audio Thread", [this] { start(); }); moveToNewNamedThread(this, "Audio Thread", [this] { start(); });
} }
void AudioClient::setInputVolume(float volume) { void AudioClient::setInputVolume(float volume, bool emitSignal) {
if (_audioInput && volume != (float)_audioInput->volume()) { if (_audioInput && volume != (float)_audioInput->volume()) {
_audioInput->setVolume(volume); _audioInput->setVolume(volume);
emit inputVolumeChanged(_audioInput->volume()); if (emitSignal) {
emit inputVolumeChanged(_audioInput->volume());
}
} }
} }

View file

@ -189,13 +189,13 @@ public slots:
void reset(); void reset();
void audioMixerKilled(); void audioMixerKilled();
void toggleMute(); void setMuted(bool muted, bool emitSignal = true);
bool isMuted() { return _muted; } bool isMuted() { return _muted; }
virtual bool setIsStereoInput(bool stereo) override; virtual bool setIsStereoInput(bool stereo) override;
virtual bool isStereoInput() override { return _isStereoInput; } virtual bool isStereoInput() override { return _isStereoInput; }
void setNoiseReduction(bool isNoiseGateEnabled); void setNoiseReduction(bool isNoiseGateEnabled, bool emitSignal = true);
bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; } bool isNoiseReductionEnabled() const { return _isNoiseGateEnabled; }
bool getLocalEcho() { return _shouldEchoLocally; } bool getLocalEcho() { return _shouldEchoLocally; }
@ -218,7 +218,7 @@ public slots:
bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName); bool switchAudioDevice(QAudio::Mode mode, const QString& deviceName);
float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; } float getInputVolume() const { return (_audioInput) ? (float)_audioInput->volume() : 0.0f; }
void setInputVolume(float volume); void setInputVolume(float volume, bool emitSignal = true);
void setReverb(bool reverb); void setReverb(bool reverb);
void setReverbOptions(const AudioEffectOptions* options); void setReverbOptions(const AudioEffectOptions* options);
@ -229,8 +229,8 @@ public slots:
signals: signals:
void inputVolumeChanged(float volume); void inputVolumeChanged(float volume);
void muteToggled(); void muteToggled(bool muted);
void noiseReductionChanged(); void noiseReductionChanged(bool noiseReductionEnabled);
void mutedByMixer(); void mutedByMixer();
void inputReceived(const QByteArray& inputSamples); void inputReceived(const QByteArray& inputSamples);
void inputLoudnessChanged(float loudness); void inputLoudnessChanged(float loudness);