mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-09 15:52:42 +02:00
cleanup Agent recording handling, make loadRecording async
This commit is contained in:
parent
6ed4295b8b
commit
c7a28a527a
10 changed files with 107 additions and 37 deletions
|
@ -33,6 +33,7 @@
|
|||
#include <ScriptEngines.h>
|
||||
#include <UUID.h>
|
||||
|
||||
#include <recording/ClipCache.h>
|
||||
#include <recording/Deck.h>
|
||||
#include <recording/Recorder.h>
|
||||
#include <recording/Frame.h>
|
||||
|
@ -53,7 +54,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
|
|||
|
||||
Agent::Agent(ReceivedMessage& message) :
|
||||
ThreadedAssignment(message),
|
||||
_receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES) {
|
||||
_receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES)
|
||||
{
|
||||
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
|
||||
|
||||
ResourceManager::init();
|
||||
|
@ -64,12 +66,16 @@ Agent::Agent(ReceivedMessage& message) :
|
|||
DependencyManager::set<SoundCache>();
|
||||
DependencyManager::set<AudioScriptingInterface>();
|
||||
DependencyManager::set<AudioInjectorManager>();
|
||||
|
||||
DependencyManager::set<recording::Deck>();
|
||||
DependencyManager::set<recording::Recorder>();
|
||||
DependencyManager::set<RecordingScriptingInterface>();
|
||||
DependencyManager::set<recording::ClipCache>();
|
||||
|
||||
DependencyManager::set<ScriptCache>();
|
||||
DependencyManager::set<ScriptEngines>(ScriptEngine::AGENT_SCRIPT);
|
||||
|
||||
DependencyManager::set<RecordingScriptingInterface>();
|
||||
|
||||
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
|
||||
|
||||
packetReceiver.registerListenerForTypes(
|
||||
|
@ -327,6 +333,8 @@ void Agent::executeScript() {
|
|||
_scriptEngine = std::unique_ptr<ScriptEngine>(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload));
|
||||
_scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do
|
||||
|
||||
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine.get());
|
||||
|
||||
// setup an Avatar for the script to use
|
||||
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
||||
|
||||
|
@ -470,6 +478,8 @@ void Agent::executeScript() {
|
|||
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
|
||||
Frame::clearFrameHandler(AVATAR_FRAME_TYPE);
|
||||
|
||||
DependencyManager::destroy<RecordingScriptingInterface>();
|
||||
|
||||
setFinished(true);
|
||||
}
|
||||
|
||||
|
@ -753,8 +763,19 @@ void Agent::aboutToFinish() {
|
|||
|
||||
// cleanup the AudioInjectorManager (and any still running injectors)
|
||||
DependencyManager::destroy<AudioInjectorManager>();
|
||||
|
||||
// destroy all other created dependencies
|
||||
DependencyManager::destroy<ScriptCache>();
|
||||
DependencyManager::destroy<ScriptEngines>();
|
||||
|
||||
DependencyManager::destroy<ResourceCacheSharedItems>();
|
||||
DependencyManager::destroy<SoundCache>();
|
||||
DependencyManager::destroy<AudioScriptingInterface>();
|
||||
|
||||
DependencyManager::destroy<recording::Deck>();
|
||||
DependencyManager::destroy<recording::Recorder>();
|
||||
DependencyManager::destroy<recording::ClipCache>();
|
||||
|
||||
emit stopAvatarAudioTimer();
|
||||
_avatarAudioTimerThread.quit();
|
||||
|
||||
|
|
|
@ -46,9 +46,6 @@ class Agent : public ThreadedAssignment {
|
|||
public:
|
||||
Agent(ReceivedMessage& message);
|
||||
|
||||
void setIsAvatar(bool isAvatar);
|
||||
bool isAvatar() const { return _isAvatar; }
|
||||
|
||||
bool isPlayingAvatarSound() const { return _avatarSound != NULL; }
|
||||
|
||||
bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
|
||||
|
@ -65,6 +62,9 @@ public:
|
|||
public slots:
|
||||
void run() override;
|
||||
void playAvatarSound(SharedSoundPointer avatarSound);
|
||||
|
||||
void setIsAvatar(bool isAvatar);
|
||||
bool isAvatar() const { return _isAvatar; }
|
||||
|
||||
private slots:
|
||||
void requestScript();
|
||||
|
|
|
@ -118,6 +118,7 @@
|
|||
#include <udt/PacketHeaders.h>
|
||||
#include <UserActivityLogger.h>
|
||||
#include <UsersScriptingInterface.h>
|
||||
#include <recording/ClipCache.h>
|
||||
#include <recording/Deck.h>
|
||||
#include <recording/Recorder.h>
|
||||
#include <shared/StringHelpers.h>
|
||||
|
@ -464,6 +465,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
DependencyManager::set<StatTracker>();
|
||||
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
|
||||
DependencyManager::set<Preferences>();
|
||||
DependencyManager::set<recording::ClipCache>();
|
||||
DependencyManager::set<recording::Deck>();
|
||||
DependencyManager::set<recording::Recorder>();
|
||||
DependencyManager::set<AddressManager>();
|
||||
|
@ -5437,6 +5439,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
// AvatarManager has some custom types
|
||||
AvatarManager::registerMetaTypes(scriptEngine);
|
||||
|
||||
// give the script engine to the RecordingScriptingInterface for its callbacks
|
||||
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(scriptEngine);
|
||||
|
||||
if (property(hifi::properties::TEST).isValid()) {
|
||||
scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance());
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ QThreadStorage<QNetworkAccessManager*> networkAccessManagers;
|
|||
QNetworkAccessManager& NetworkAccessManager::getInstance() {
|
||||
if (!networkAccessManagers.hasLocalData()) {
|
||||
networkAccessManagers.setLocalData(new QNetworkAccessManager());
|
||||
|
||||
}
|
||||
|
||||
return *networkAccessManagers.localData();
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include <QThread>
|
||||
|
||||
#include "ClipCache.h"
|
||||
#include "impl/PointerClip.h"
|
||||
|
||||
|
@ -21,18 +24,28 @@ void NetworkClip::init(const QByteArray& clipData) {
|
|||
void NetworkClipLoader::downloadFinished(const QByteArray& data) {
|
||||
_clip->init(data);
|
||||
finishedLoading(true);
|
||||
emit clipLoaded();
|
||||
}
|
||||
|
||||
ClipCache& ClipCache::instance() {
|
||||
static ClipCache _instance;
|
||||
return _instance;
|
||||
ClipCache::ClipCache(QObject* parent) :
|
||||
ResourceCache(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) {
|
||||
return ResourceCache::getResource(url, QUrl(), nullptr).staticCast<NetworkClipLoader>();
|
||||
if (QThread::currentThread() != thread()) {
|
||||
NetworkClipLoaderPointer result;
|
||||
QMetaObject::invokeMethod(this, "getClipLoader", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(NetworkClipLoaderPointer, result), Q_ARG(const QUrl&, url));
|
||||
return result;
|
||||
}
|
||||
|
||||
return getResource(url).staticCast<NetworkClipLoader>();
|
||||
}
|
||||
|
||||
QSharedPointer<Resource> ClipCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) {
|
||||
qDebug() << "Loading recording at" << url;
|
||||
return QSharedPointer<Resource>(new NetworkClipLoader(url), &Resource::deleter);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,26 +30,34 @@ private:
|
|||
};
|
||||
|
||||
class NetworkClipLoader : public Resource {
|
||||
Q_OBJECT
|
||||
public:
|
||||
NetworkClipLoader(const QUrl& url);
|
||||
virtual void downloadFinished(const QByteArray& data) override;
|
||||
ClipPointer getClip() { return _clip; }
|
||||
bool completed() { return _failedToLoad || isLoaded(); }
|
||||
|
||||
signals:
|
||||
void clipLoaded();
|
||||
|
||||
private:
|
||||
const NetworkClip::Pointer _clip;
|
||||
};
|
||||
|
||||
using NetworkClipLoaderPointer = QSharedPointer<NetworkClipLoader>;
|
||||
|
||||
class ClipCache : public ResourceCache {
|
||||
public:
|
||||
static ClipCache& instance();
|
||||
|
||||
class ClipCache : public ResourceCache, public Dependency {
|
||||
Q_OBJECT
|
||||
SINGLETON_DEPENDENCY
|
||||
|
||||
public slots:
|
||||
NetworkClipLoaderPointer getClipLoader(const QUrl& url);
|
||||
|
||||
protected:
|
||||
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) override;
|
||||
|
||||
private:
|
||||
ClipCache(QObject* parent = nullptr);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -52,32 +52,48 @@ float RecordingScriptingInterface::playerLength() const {
|
|||
return _player->length();
|
||||
}
|
||||
|
||||
bool RecordingScriptingInterface::loadRecording(const QString& url) {
|
||||
using namespace recording;
|
||||
void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue callback) {
|
||||
auto clipLoader = DependencyManager::get<recording::ClipCache>()->getClipLoader(url);
|
||||
|
||||
auto loader = ClipCache::instance().getClipLoader(url);
|
||||
if (!loader) {
|
||||
qWarning() << "Clip failed to load from " << url;
|
||||
return false;
|
||||
}
|
||||
// hold a strong pointer to the loading clip so that it has a chance to load
|
||||
_clipLoaders.insert(clipLoader);
|
||||
|
||||
if (!loader->isLoaded()) {
|
||||
QEventLoop loop;
|
||||
QObject::connect(loader.data(), &Resource::loaded, &loop, &QEventLoop::quit);
|
||||
QObject::connect(loader.data(), &Resource::failed, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
}
|
||||
auto weakClipLoader = clipLoader.toWeakRef();
|
||||
|
||||
if (!loader->isLoaded()) {
|
||||
qWarning() << "Clip failed to load from " << url;
|
||||
return false;
|
||||
}
|
||||
// when clip loaded, call the callback with the URL and success boolean
|
||||
connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, this, [this, weakClipLoader, url, callback]() mutable {
|
||||
|
||||
_player->queueClip(loader->getClip());
|
||||
return true;
|
||||
if (auto clipLoader = weakClipLoader.toStrongRef()) {
|
||||
qCDebug(scriptengine) << "Loaded recording from" << url;
|
||||
|
||||
_player->queueClip(clipLoader->getClip());
|
||||
|
||||
if (callback.isFunction()) {
|
||||
QScriptValueList args { true, url };
|
||||
callback.call(_scriptEngine->globalObject(), args);
|
||||
}
|
||||
|
||||
// drop our strong pointer to this clip so it is cleaned up
|
||||
_clipLoaders.remove(clipLoader);
|
||||
}
|
||||
});
|
||||
|
||||
// when clip load fails, call the callback with the URL and failure boolean
|
||||
connect(clipLoader.data(), &recording::NetworkClipLoader::failed, this, [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable {
|
||||
qCDebug(scriptengine) << "Failed to load recording from" << url;
|
||||
|
||||
if (callback.isFunction()) {
|
||||
QScriptValueList args { false, url };
|
||||
callback.call(_scriptEngine->currentContext()->thisObject(), args);
|
||||
}
|
||||
|
||||
if (auto clipLoader = weakClipLoader.toStrongRef()) {
|
||||
// drop out strong pointer to this clip so it is cleaned up
|
||||
_clipLoaders.remove(clipLoader);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
void RecordingScriptingInterface::startPlaying() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "startPlaying", Qt::BlockingQueuedConnection);
|
||||
|
|
|
@ -15,9 +15,11 @@
|
|||
#include <QtCore/QObject>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <recording/ClipCache.h>
|
||||
#include <recording/Forward.h>
|
||||
#include <recording/Frame.h>
|
||||
|
||||
class QScriptEngine;
|
||||
class QScriptValue;
|
||||
|
||||
class RecordingScriptingInterface : public QObject, public Dependency {
|
||||
|
@ -26,8 +28,11 @@ class RecordingScriptingInterface : public QObject, public Dependency {
|
|||
public:
|
||||
RecordingScriptingInterface();
|
||||
|
||||
void setScriptEngine(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
|
||||
|
||||
public slots:
|
||||
bool loadRecording(const QString& url);
|
||||
|
||||
void loadRecording(const QString& url, QScriptValue callback = QScriptValue());
|
||||
|
||||
void startPlaying();
|
||||
void pausePlayer();
|
||||
|
@ -79,6 +84,9 @@ protected:
|
|||
Flag _useAttachments { false };
|
||||
Flag _useSkeletonModel { false };
|
||||
recording::ClipPointer _lastClip;
|
||||
|
||||
QScriptEngine* _scriptEngine;
|
||||
QSet<recording::NetworkClipLoaderPointer> _clipLoaders;
|
||||
};
|
||||
|
||||
#endif // hifi_RecordingScriptingInterface_h
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include <typeinfo>
|
||||
|
||||
#define SINGLETON_DEPENDENCY \
|
||||
friend class DependencyManager;
|
||||
friend class ::DependencyManager;
|
||||
|
||||
class Dependency {
|
||||
public:
|
||||
|
|
|
@ -769,7 +769,7 @@ bool similarStrings(const QString& stringA, const QString& stringB) {
|
|||
|
||||
void disableQtBearerPoll() {
|
||||
// to work around the Qt constant wireless scanning, set the env for polling interval very high
|
||||
const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT_MAX).toLocal8Bit();
|
||||
const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT16_MAX).toLocal8Bit();
|
||||
qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue