Merge branch 'master' of github.com:highfidelity/hifi into bullet-constraints-1

This commit is contained in:
Seth Alves 2017-04-14 12:49:03 -07:00
commit d17d12446b
20 changed files with 219 additions and 110 deletions

View file

@ -33,6 +33,7 @@
#include <SoundCache.h> #include <SoundCache.h>
#include <UUID.h> #include <UUID.h>
#include <recording/ClipCache.h>
#include <recording/Deck.h> #include <recording/Deck.h>
#include <recording/Recorder.h> #include <recording/Recorder.h>
#include <recording/Frame.h> #include <recording/Frame.h>
@ -53,7 +54,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10;
Agent::Agent(ReceivedMessage& message) : Agent::Agent(ReceivedMessage& message) :
ThreadedAssignment(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); DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
ResourceManager::init(); ResourceManager::init();
@ -64,12 +66,16 @@ Agent::Agent(ReceivedMessage& message) :
DependencyManager::set<SoundCache>(); DependencyManager::set<SoundCache>();
DependencyManager::set<AudioScriptingInterface>(); DependencyManager::set<AudioScriptingInterface>();
DependencyManager::set<AudioInjectorManager>(); DependencyManager::set<AudioInjectorManager>();
DependencyManager::set<recording::Deck>(); DependencyManager::set<recording::Deck>();
DependencyManager::set<recording::Recorder>(); DependencyManager::set<recording::Recorder>();
DependencyManager::set<RecordingScriptingInterface>(); DependencyManager::set<recording::ClipCache>();
DependencyManager::set<ScriptCache>(); DependencyManager::set<ScriptCache>();
DependencyManager::set<ScriptEngines>(ScriptEngine::AGENT_SCRIPT); DependencyManager::set<ScriptEngines>(ScriptEngine::AGENT_SCRIPT);
DependencyManager::set<RecordingScriptingInterface>();
auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver(); auto& packetReceiver = DependencyManager::get<NodeList>()->getPacketReceiver();
packetReceiver.registerListenerForTypes( packetReceiver.registerListenerForTypes(
@ -327,6 +333,8 @@ void Agent::executeScript() {
_scriptEngine = std::unique_ptr<ScriptEngine>(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload)); _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 _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 // setup an Avatar for the script to use
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>(); auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
@ -470,6 +478,8 @@ void Agent::executeScript() {
Frame::clearFrameHandler(AUDIO_FRAME_TYPE); Frame::clearFrameHandler(AUDIO_FRAME_TYPE);
Frame::clearFrameHandler(AVATAR_FRAME_TYPE); Frame::clearFrameHandler(AVATAR_FRAME_TYPE);
DependencyManager::destroy<RecordingScriptingInterface>();
setFinished(true); setFinished(true);
} }
@ -753,8 +763,19 @@ void Agent::aboutToFinish() {
// cleanup the AudioInjectorManager (and any still running injectors) // cleanup the AudioInjectorManager (and any still running injectors)
DependencyManager::destroy<AudioInjectorManager>(); DependencyManager::destroy<AudioInjectorManager>();
// destroy all other created dependencies
DependencyManager::destroy<ScriptCache>();
DependencyManager::destroy<ScriptEngines>(); 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(); emit stopAvatarAudioTimer();
_avatarAudioTimerThread.quit(); _avatarAudioTimerThread.quit();

View file

@ -46,9 +46,6 @@ class Agent : public ThreadedAssignment {
public: public:
Agent(ReceivedMessage& message); Agent(ReceivedMessage& message);
void setIsAvatar(bool isAvatar);
bool isAvatar() const { return _isAvatar; }
bool isPlayingAvatarSound() const { return _avatarSound != NULL; } bool isPlayingAvatarSound() const { return _avatarSound != NULL; }
bool isListeningToAudioStream() const { return _isListeningToAudioStream; } bool isListeningToAudioStream() const { return _isListeningToAudioStream; }
@ -66,6 +63,9 @@ public slots:
void run() override; void run() override;
void playAvatarSound(SharedSoundPointer avatarSound); void playAvatarSound(SharedSoundPointer avatarSound);
void setIsAvatar(bool isAvatar);
bool isAvatar() const { return _isAvatar; }
private slots: private slots:
void requestScript(); void requestScript();
void scriptRequestFinished(); void scriptRequestFinished();

View file

@ -67,15 +67,13 @@ void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) {
int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) {
int bytesSent = 0;
QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray();
auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size());
individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious
bytesSent += individualData.size(); auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true);
identityPacket->write(individualData); identityPackets->write(individualData);
DependencyManager::get<NodeList>()->sendPacket(std::move(identityPacket), *destinationNode); DependencyManager::get<NodeList>()->sendPacketList(std::move(identityPackets), *destinationNode);
_stats.numIdentityPackets++; _stats.numIdentityPackets++;
return bytesSent; return individualData.size();
} }
static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45; static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45;
@ -265,8 +263,16 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) {
// make sure we haven't already sent this data from this sender to this receiver // make sure we haven't already sent this data from this sender to this receiver
// or that somehow we haven't sent // or that somehow we haven't sent
if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) {
// don't ignore this avatar if we haven't sent any update for a long while
// in an effort to prevent other interfaces from deleting a stale avatar instance
uint64_t lastBroadcastTime = nodeData->getLastBroadcastTime(avatarNode->getUUID());
const AvatarMixerClientData* otherNodeData = reinterpret_cast<const AvatarMixerClientData*>(avatarNode->getLinkedData());
const uint64_t AVATAR_UPDATE_STALE = AVATAR_UPDATE_TIMEOUT - USECS_PER_SECOND;
if (lastBroadcastTime > otherNodeData->getIdentityChangeTimestamp() &&
lastBroadcastTime + AVATAR_UPDATE_STALE > startIgnoreCalculation) {
++numAvatarsHeldBack; ++numAvatarsHeldBack;
shouldIgnore = true; shouldIgnore = true;
}
} else if (lastSeqFromSender - lastSeqToReceiver > 1) { } else if (lastSeqFromSender - lastSeqToReceiver > 1) {
// this is a skip - we still send the packet but capture the presence of the skip so we see it happening // this is a skip - we still send the packet but capture the presence of the skip so we see it happening
++numAvatarsWithSkippedFrames; ++numAvatarsWithSkippedFrames;

View file

@ -118,6 +118,7 @@
#include <udt/PacketHeaders.h> #include <udt/PacketHeaders.h>
#include <UserActivityLogger.h> #include <UserActivityLogger.h>
#include <UsersScriptingInterface.h> #include <UsersScriptingInterface.h>
#include <recording/ClipCache.h>
#include <recording/Deck.h> #include <recording/Deck.h>
#include <recording/Recorder.h> #include <recording/Recorder.h>
#include <shared/StringHelpers.h> #include <shared/StringHelpers.h>
@ -467,6 +468,7 @@ bool setupEssentials(int& argc, char** argv) {
DependencyManager::set<StatTracker>(); DependencyManager::set<StatTracker>();
DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT); DependencyManager::set<ScriptEngines>(ScriptEngine::CLIENT_SCRIPT);
DependencyManager::set<Preferences>(); DependencyManager::set<Preferences>();
DependencyManager::set<recording::ClipCache>();
DependencyManager::set<recording::Deck>(); DependencyManager::set<recording::Deck>();
DependencyManager::set<recording::Recorder>(); DependencyManager::set<recording::Recorder>();
DependencyManager::set<AddressManager>(); DependencyManager::set<AddressManager>();
@ -5439,6 +5441,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
// AvatarManager has some custom types // AvatarManager has some custom types
AvatarManager::registerMetaTypes(scriptEngine); AvatarManager::registerMetaTypes(scriptEngine);
// give the script engine to the RecordingScriptingInterface for its callbacks
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(scriptEngine);
if (property(hifi::properties::TEST).isValid()) { if (property(hifi::properties::TEST).isValid()) {
scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance());
} }

View file

@ -110,6 +110,8 @@ const char LEFT_HAND_POINTING_FLAG = 1;
const char RIGHT_HAND_POINTING_FLAG = 2; const char RIGHT_HAND_POINTING_FLAG = 2;
const char IS_FINGER_POINTING_FLAG = 4; const char IS_FINGER_POINTING_FLAG = 4;
const qint64 AVATAR_UPDATE_TIMEOUT = 5 * USECS_PER_SECOND;
// AvatarData state flags - we store the details about the packet encoding in the first byte, // AvatarData state flags - we store the details about the packet encoding in the first byte,
// before the "header" structure // before the "header" structure
const char AVATARDATA_FLAGS_MINIMUM = 0; const char AVATARDATA_FLAGS_MINIMUM = 0;
@ -599,10 +601,7 @@ public:
} }
bool shouldDie() const { bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_UPDATE_TIMEOUT; }
const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND;
return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS;
}
static const float OUT_OF_VIEW_PENALTY; static const float OUT_OF_VIEW_PENALTY;

View file

@ -19,7 +19,6 @@ QThreadStorage<QNetworkAccessManager*> networkAccessManagers;
QNetworkAccessManager& NetworkAccessManager::getInstance() { QNetworkAccessManager& NetworkAccessManager::getInstance() {
if (!networkAccessManagers.hasLocalData()) { if (!networkAccessManagers.hasLocalData()) {
networkAccessManagers.setLocalData(new QNetworkAccessManager()); networkAccessManagers.setLocalData(new QNetworkAccessManager());
} }
return *networkAccessManagers.localData(); return *networkAccessManagers.localData();

View file

@ -5,8 +5,12 @@
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include <QThread>
#include "ClipCache.h" #include "ClipCache.h"
#include "impl/PointerClip.h" #include "impl/PointerClip.h"
#include "Logging.h"
using namespace recording; using namespace recording;
NetworkClipLoader::NetworkClipLoader(const QUrl& url) : NetworkClipLoader::NetworkClipLoader(const QUrl& url) :
@ -21,18 +25,28 @@ void NetworkClip::init(const QByteArray& clipData) {
void NetworkClipLoader::downloadFinished(const QByteArray& data) { void NetworkClipLoader::downloadFinished(const QByteArray& data) {
_clip->init(data); _clip->init(data);
finishedLoading(true); finishedLoading(true);
emit clipLoaded();
} }
ClipCache& ClipCache::instance() { ClipCache::ClipCache(QObject* parent) :
static ClipCache _instance; ResourceCache(parent)
return _instance; {
} }
NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) { 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) { QSharedPointer<Resource> ClipCache::createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) {
qCDebug(recordingLog) << "Loading recording at" << url;
return QSharedPointer<Resource>(new NetworkClipLoader(url), &Resource::deleter); return QSharedPointer<Resource>(new NetworkClipLoader(url), &Resource::deleter);
} }

View file

@ -30,26 +30,34 @@ private:
}; };
class NetworkClipLoader : public Resource { class NetworkClipLoader : public Resource {
Q_OBJECT
public: public:
NetworkClipLoader(const QUrl& url); NetworkClipLoader(const QUrl& url);
virtual void downloadFinished(const QByteArray& data) override; virtual void downloadFinished(const QByteArray& data) override;
ClipPointer getClip() { return _clip; } ClipPointer getClip() { return _clip; }
bool completed() { return _failedToLoad || isLoaded(); } bool completed() { return _failedToLoad || isLoaded(); }
signals:
void clipLoaded();
private: private:
const NetworkClip::Pointer _clip; const NetworkClip::Pointer _clip;
}; };
using NetworkClipLoaderPointer = QSharedPointer<NetworkClipLoader>; using NetworkClipLoaderPointer = QSharedPointer<NetworkClipLoader>;
class ClipCache : public ResourceCache { class ClipCache : public ResourceCache, public Dependency {
public: Q_OBJECT
static ClipCache& instance(); SINGLETON_DEPENDENCY
public slots:
NetworkClipLoaderPointer getClipLoader(const QUrl& url); NetworkClipLoaderPointer getClipLoader(const QUrl& url);
protected: protected:
virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) override; virtual QSharedPointer<Resource> createResource(const QUrl& url, const QSharedPointer<Resource>& fallback, const void* extra) override;
private:
ClipCache(QObject* parent = nullptr);
}; };
} }

View file

@ -52,32 +52,49 @@ float RecordingScriptingInterface::playerLength() const {
return _player->length(); return _player->length();
} }
bool RecordingScriptingInterface::loadRecording(const QString& url) { void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue callback) {
using namespace recording; auto clipLoader = DependencyManager::get<recording::ClipCache>()->getClipLoader(url);
auto loader = ClipCache::instance().getClipLoader(url); // hold a strong pointer to the loading clip so that it has a chance to load
if (!loader) { _clipLoaders.insert(clipLoader);
qWarning() << "Clip failed to load from " << url;
return false; auto weakClipLoader = clipLoader.toWeakRef();
// when clip loaded, call the callback with the URL and success boolean
connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, this,
[this, weakClipLoader, url, callback]() mutable {
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);
} }
if (!loader->isLoaded()) { // drop our strong pointer to this clip so it is cleaned up
QEventLoop loop; _clipLoaders.remove(clipLoader);
QObject::connect(loader.data(), &Resource::loaded, &loop, &QEventLoop::quit); }
QObject::connect(loader.data(), &Resource::failed, &loop, &QEventLoop::quit); });
loop.exec();
// 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 (!loader->isLoaded()) { if (auto clipLoader = weakClipLoader.toStrongRef()) {
qWarning() << "Clip failed to load from " << url; // drop out strong pointer to this clip so it is cleaned up
return false; _clipLoaders.remove(clipLoader);
} }
});
_player->queueClip(loader->getClip());
return true;
} }
void RecordingScriptingInterface::startPlaying() { void RecordingScriptingInterface::startPlaying() {
if (QThread::currentThread() != thread()) { if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "startPlaying", Qt::BlockingQueuedConnection); QMetaObject::invokeMethod(this, "startPlaying", Qt::BlockingQueuedConnection);

View file

@ -15,9 +15,11 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <recording/ClipCache.h>
#include <recording/Forward.h> #include <recording/Forward.h>
#include <recording/Frame.h> #include <recording/Frame.h>
class QScriptEngine;
class QScriptValue; class QScriptValue;
class RecordingScriptingInterface : public QObject, public Dependency { class RecordingScriptingInterface : public QObject, public Dependency {
@ -26,8 +28,10 @@ class RecordingScriptingInterface : public QObject, public Dependency {
public: public:
RecordingScriptingInterface(); RecordingScriptingInterface();
void setScriptEngine(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
public slots: public slots:
bool loadRecording(const QString& url); void loadRecording(const QString& url, QScriptValue callback = QScriptValue());
void startPlaying(); void startPlaying();
void pausePlayer(); void pausePlayer();
@ -79,6 +83,9 @@ protected:
Flag _useAttachments { false }; Flag _useAttachments { false };
Flag _useSkeletonModel { false }; Flag _useSkeletonModel { false };
recording::ClipPointer _lastClip; recording::ClipPointer _lastClip;
QScriptEngine* _scriptEngine;
QSet<recording::NetworkClipLoaderPointer> _clipLoaders;
}; };
#endif // hifi_RecordingScriptingInterface_h #endif // hifi_RecordingScriptingInterface_h

View file

@ -21,7 +21,7 @@
#include <typeinfo> #include <typeinfo>
#define SINGLETON_DEPENDENCY \ #define SINGLETON_DEPENDENCY \
friend class DependencyManager; friend class ::DependencyManager;
class Dependency { class Dependency {
public: public:

View file

@ -769,7 +769,7 @@ bool similarStrings(const QString& stringA, const QString& stringB) {
void disableQtBearerPoll() { void disableQtBearerPoll() {
// to work around the Qt constant wireless scanning, set the env for polling interval very high // 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); qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT);
} }

View file

@ -138,7 +138,13 @@ Agent.isAvatar = true;
Agent.isListeningToAudioStream = true; Agent.isListeningToAudioStream = true;
Avatar.skeletonModelURL = AVATAR_URL; // FIXME - currently setting an avatar while playing a recording doesn't work it will be ignored Avatar.skeletonModelURL = AVATAR_URL; // FIXME - currently setting an avatar while playing a recording doesn't work it will be ignored
Recording.loadRecording(RECORDING_URL); Recording.loadRecording(RECORDING_URL, function(success) {
if (success) {
Script.update.connect(update);
} else {
print("Failed to load recording from " + RECORDING_URL);
}
});
count = 300; // This is necessary to wait for the audio mixer to connect count = 300; // This is necessary to wait for the audio mixer to connect
function update(event) { function update(event) {
@ -179,5 +185,3 @@ function update(event) {
Script.update.disconnect(update); Script.update.disconnect(update);
} }
} }
Script.update.connect(update);

View file

@ -20,7 +20,13 @@ Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0);
Avatar.scale = 1.0; Avatar.scale = 1.0;
Agent.isAvatar = true; Agent.isAvatar = true;
Recording.loadRecording(recordingFile); Recording.loadRecording(recordingFile, function(success) {
if (success) {
Script.update.connect(update);
} else {
print("Failed to load recording from " + recordingFile);
}
});
count = 300; // This is necessary to wait for the audio mixer to connect count = 300; // This is necessary to wait for the audio mixer to connect
function update(event) { function update(event) {
@ -44,5 +50,3 @@ function update(event) {
Script.update.disconnect(update); Script.update.disconnect(update);
} }
} }
Script.update.connect(update);

View file

@ -42,10 +42,15 @@ var playRecording = function() {
Recording.setPlayerLoop(false); Recording.setPlayerLoop(false);
Recording.setPlayerTime(STARTING_TIME); Recording.setPlayerTime(STARTING_TIME);
Recording.setPlayerAudioOffset(AUDIO_OFFSET); Recording.setPlayerAudioOffset(AUDIO_OFFSET);
Recording.loadRecording(CLIP_URL); Recording.loadRecording(CLIP_URL, function(success) {
if (success) {
Recording.startPlaying(); Recording.startPlaying();
isPlaying = true; isPlaying = true;
isPlayable = false; // Set this true again after the cooldown period isPlayable = false; // Set this true again after the cooldown period
} else {
print("Failed to load recording from " + CLIP_URL);
}
});
}; };
Script.update.connect(function(deltaTime) { Script.update.connect(function(deltaTime) {

View file

@ -10,9 +10,15 @@ Agent.isAvatar = true;
Script.setTimeout(function () { Script.setTimeout(function () {
Avatar.position = origin; Avatar.position = origin;
Recording.loadRecording("d:/hifi.rec"); Recording.loadRecording("d:/hifi.rec", function(success) {
if (success) {
Recording.setPlayerLoop(true); Recording.setPlayerLoop(true);
Recording.startPlaying(); Recording.startPlaying();
} else {
print("Failed to load recording");
}
});
}, millisecondsToWaitBeforeStarting); }, millisecondsToWaitBeforeStarting);

View file

@ -52,13 +52,18 @@ function update(deltaTime) {
if (!subscribed) { if (!subscribed) {
Messages.subscribe(PLAYBACK_CHANNEL); Messages.subscribe(PLAYBACK_CHANNEL);
subscribed = true; subscribed = true;
Recording.loadRecording(clip_url); Recording.loadRecording(clip_url, function(success) {
if (success) {
Recording.setPlayFromCurrentLocation(playFromCurrentLocation); Recording.setPlayFromCurrentLocation(playFromCurrentLocation);
Recording.setPlayerUseDisplayName(useDisplayName); Recording.setPlayerUseDisplayName(useDisplayName);
Recording.setPlayerUseAttachments(useAttachments); Recording.setPlayerUseAttachments(useAttachments);
Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseHeadModel(false);
Recording.setPlayerUseSkeletonModel(useAvatarModel); Recording.setPlayerUseSkeletonModel(useAvatarModel);
Agent.isAvatar = true; Agent.isAvatar = true;
} else {
print("Failed to load recording from " + clip_url);
}
});
} }
} }

View file

@ -49,11 +49,15 @@ function getAction(channel, message, senderID) {
case SHOW: case SHOW:
print("Show"); print("Show");
Recording.loadRecording(clip_url); Recording.loadRecording(clip_url, function(success) {
if (success) {
Agent.isAvatar = true; Agent.isAvatar = true;
Recording.setPlayerTime(0.0); Recording.setPlayerTime(0.0);
Recording.startPlaying(); Recording.startPlaying();
Recording.stopPlaying(); Recording.stopPlaying();
}
});
break; break;
case HIDE: case HIDE:

View file

@ -281,8 +281,13 @@ function mousePressEvent(event) {
if (!Recording.isRecording() && !Recording.isPlaying()) { if (!Recording.isRecording() && !Recording.isPlaying()) {
recordingFile = Window.browse("Load recording from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)"); recordingFile = Window.browse("Load recording from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)");
if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) { if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) {
Recording.loadRecording(recordingFile); Recording.loadRecording(recordingFile, function(success) {
if (success) {
setDefaultPlayerOptions(); setDefaultPlayerOptions();
} else {
print("Failed to load recording from " + recordingFile);
}
});
} }
if (Recording.playerLength() > 0) { if (Recording.playerLength() > 0) {
toolBar.setAlpha(ALPHA_ON, playIcon); toolBar.setAlpha(ALPHA_ON, playIcon);

View file

@ -27,8 +27,8 @@ Script.include("/~/system/libraries/controllers.js");
// add lines where the hand ray picking is happening // add lines where the hand ray picking is happening
// //
var WANT_DEBUG = false; var WANT_DEBUG = true;
var WANT_DEBUG_STATE = false; var WANT_DEBUG_STATE = true;
var WANT_DEBUG_SEARCH_NAME = null; var WANT_DEBUG_SEARCH_NAME = null;
var FORCE_IGNORE_IK = false; var FORCE_IGNORE_IK = false;