From fe6d76b935481891e72501c268ff3b0737a48530 Mon Sep 17 00:00:00 2001 From: ksuprynowicz Date: Thu, 16 May 2024 01:09:57 +0200 Subject: [PATCH] Fixed deadlocks in Recording API --- .../src/AgentScriptingInterface.h | 8 ++--- .../recording/RecordingScriptingInterface.cpp | 31 ++++++++++++------- .../recording/RecordingScriptingInterface.h | 2 ++ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/AgentScriptingInterface.h b/assignment-client/src/AgentScriptingInterface.h index cd5aa5ad65..1146c4006b 100644 --- a/assignment-client/src/AgentScriptingInterface.h +++ b/assignment-client/src/AgentScriptingInterface.h @@ -40,7 +40,7 @@ */ class AgentScriptingInterface : public QObject { Q_OBJECT - Q_PROPERTY(bool isAvatar READ isAvatar WRITE setIsAvatar) + Q_PROPERTY(bool isAvatar READ getIsAvatar WRITE setIsAvatar) Q_PROPERTY(bool isPlayingAvatarSound READ isPlayingAvatarSound) Q_PROPERTY(bool isListeningToAudioStream READ isListeningToAudioStream WRITE setIsListeningToAudioStream) Q_PROPERTY(bool isNoiseGateEnabled READ isNoiseGateEnabled WRITE setIsNoiseGateEnabled) @@ -77,15 +77,15 @@ public slots: /*@jsdoc * Checks whether the script is emulating an avatar. - * @function Agent.isAvatar + * @function Agent.getIsAvatar * @returns {boolean} true if the script is emulating an avatar, otherwise false. * @example Check whether the agent is emulating an avatar. * (function () { - * print("Agent is avatar: " + Agent.isAvatar()); + * print("Agent is avatar: " + Agent.getIsAvatar()); * print("Agent is avatar: " + Agent.isAvatar); // Same result. * }()); */ - bool isAvatar() const { return _agent->isAvatar(); } + bool getIsAvatar() const { return _agent->isAvatar(); } /*@jsdoc * Plays a sound from the position and with the orientation of the emulated avatar's head. No sound is played unless diff --git a/libraries/recording/src/recording/RecordingScriptingInterface.cpp b/libraries/recording/src/recording/RecordingScriptingInterface.cpp index 05cfa8b851..5386f823f3 100644 --- a/libraries/recording/src/recording/RecordingScriptingInterface.cpp +++ b/libraries/recording/src/recording/RecordingScriptingInterface.cpp @@ -38,27 +38,33 @@ using namespace recording; static const QString HFR_EXTENSION = "hfr"; RecordingScriptingInterface::RecordingScriptingInterface() { + Locker(_mutex); _player = DependencyManager::get(); _recorder = DependencyManager::get(); } bool RecordingScriptingInterface::isPlaying() const { + Locker(_mutex); return _player->isPlaying(); } bool RecordingScriptingInterface::isPaused() const { + Locker(_mutex); return _player->isPaused(); } float RecordingScriptingInterface::playerElapsed() const { + Locker(_mutex); return _player->position(); } float RecordingScriptingInterface::playerLength() const { + Locker(_mutex); return _player->length(); } void RecordingScriptingInterface::playClip(NetworkClipLoaderPointer clipLoader, const QString& url, const ScriptValue& callback) { + Locker(_mutex); _player->queueClip(clipLoader->getClip()); if (callback.isFunction()) { @@ -69,10 +75,7 @@ void RecordingScriptingInterface::playClip(NetworkClipLoaderPointer clipLoader, } void RecordingScriptingInterface::loadRecording(const QString& url, const ScriptValue& callback) { - if (QThread::currentThread() != thread()) { - BLOCKING_INVOKE_METHOD(this, "loadRecording", Q_ARG(const QString&, url), Q_ARG(const ScriptValue&, callback)); - return; - } + Locker(_mutex); auto clipLoader = DependencyManager::get()->getClipLoader(url); @@ -131,6 +134,7 @@ void RecordingScriptingInterface::startPlaying() { return; } + Locker(_mutex); _player->play(); } @@ -140,6 +144,7 @@ void RecordingScriptingInterface::setPlayerVolume(float volume) { return; } + Locker(_mutex); _player->setVolume(std::min(std::max(volume, 0.0f), 1.0f)); } @@ -152,6 +157,7 @@ void RecordingScriptingInterface::setPlayerTime(float time) { BLOCKING_INVOKE_METHOD(this, "setPlayerTime", Q_ARG(float, time)); return; } + Locker(_mutex); _player->seek(time); } @@ -165,6 +171,7 @@ void RecordingScriptingInterface::setPlayerLoop(bool loop) { return; } + Locker(_mutex); _player->loop(loop); } @@ -189,6 +196,7 @@ void RecordingScriptingInterface::pausePlayer() { BLOCKING_INVOKE_METHOD(this, "pausePlayer"); return; } + Locker(_mutex); _player->pause(); } @@ -197,6 +205,7 @@ void RecordingScriptingInterface::stopPlaying() { BLOCKING_INVOKE_METHOD(this, "stopPlaying"); return; } + Locker(_mutex); _player->stop(); } @@ -219,6 +228,7 @@ void RecordingScriptingInterface::startRecording() { return; } + Locker(_mutex); _recorder->start(); } @@ -233,6 +243,7 @@ void RecordingScriptingInterface::stopRecording() { return; } + Locker(_mutex); _recorder->stop(); _lastClip = _recorder->getClip(); _lastClip->seek(0); @@ -253,6 +264,7 @@ void RecordingScriptingInterface::saveRecording(const QString& filename) { return; } + Locker(_mutex); if (!_lastClip) { qWarning() << "There is no recording to save"; return; @@ -267,14 +279,7 @@ bool RecordingScriptingInterface::saveRecordingToAsset(const ScriptValue& getCli return false; } - if (QThread::currentThread() != thread()) { - bool result; - BLOCKING_INVOKE_METHOD(this, "saveRecordingToAsset", - Q_RETURN_ARG(bool, result), - Q_ARG(const ScriptValue&, getClipAtpUrl)); - return result; - } - + Locker(_mutex); if (!_lastClip) { qWarning() << "There is no recording to save"; return false; @@ -316,6 +321,8 @@ void RecordingScriptingInterface::loadLastRecording() { return; } + Locker(_mutex); + if (!_lastClip) { qCDebug(scriptengine) << "There is no recording to load"; return; diff --git a/libraries/recording/src/recording/RecordingScriptingInterface.h b/libraries/recording/src/recording/RecordingScriptingInterface.h index 42dc665706..4cc8a990cd 100644 --- a/libraries/recording/src/recording/RecordingScriptingInterface.h +++ b/libraries/recording/src/recording/RecordingScriptingInterface.h @@ -357,6 +357,8 @@ protected: using Locker = std::unique_lock; using Flag = std::atomic; + Mutex _mutex; + QSharedPointer _player; QSharedPointer _recorder;