From e10d132f754ced8e0b75f66e523151f3550486cb Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 13 Nov 2014 14:47:28 -0800 Subject: [PATCH] avoid Qt QTimer thread bug by putting SoundCache on same thread --- examples/birdSongs.js | 9 ++-- interface/src/Application.cpp | 2 + .../audio/src/AudioScriptingInterface.cpp | 48 ++++++++++--------- libraries/audio/src/Sound.cpp | 15 +++--- libraries/audio/src/Sound.h | 13 ++++- libraries/audio/src/SoundCache.cpp | 14 +++++- libraries/audio/src/SoundCache.h | 11 ++--- libraries/avatars/src/Player.cpp | 2 +- libraries/networking/src/ResourceCache.cpp | 6 ++- libraries/script-engine/src/ScriptEngine.cpp | 13 ----- libraries/shared/src/LogHandler.cpp | 2 - 11 files changed, 74 insertions(+), 61 deletions(-) diff --git a/examples/birdSongs.js b/examples/birdSongs.js index 680cb025ad..267fa20b49 100644 --- a/examples/birdSongs.js +++ b/examples/birdSongs.js @@ -67,7 +67,7 @@ function maybePlaySound(deltaTime) { lifetime: 10 }); } - + playing.push({ audioId: Audio.playSound(birds[whichBird].sound, options), entityId: entityId, lightId: lightId, color: birds[whichBird].color }); } if (playing.length != numPlaying) { @@ -159,8 +159,9 @@ function loadBirds() { var SOUND_BASE_URL = "http://public.highfidelity.io/sounds/Animals/"; for (var i = 0; i < sound_filenames.length; i++) { - birds.push({ sound: new Sound(SOUND_BASE_URL + sound_filenames[i]), - color: colors[i] - } ); + birds.push({ + sound: SoundCache.getSound(SOUND_BASE_URL + sound_filenames[i]), + color: colors[i] + }); } } \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f11ac14d40..6188811442 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -65,6 +65,7 @@ #include #include #include +#include #include #include @@ -3916,6 +3917,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri scriptEngine->registerGlobalObject("Settings", SettingsScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AudioDevice", AudioDeviceScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("AnimationCache", &_animationCache); + scriptEngine->registerGlobalObject("SoundCache", &SoundCache::getInstance()); scriptEngine->registerGlobalObject("AudioReflector", &_audioReflector); scriptEngine->registerGlobalObject("Account", AccountScriptingInterface::getInstance()); scriptEngine->registerGlobalObject("Metavoxels", &_metavoxels); diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/audio/src/AudioScriptingInterface.cpp index cb010ef11d..35a11f4dd4 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/audio/src/AudioScriptingInterface.cpp @@ -43,28 +43,32 @@ void AudioScriptingInterface::stopAllInjectors() { } AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { - - AudioInjector* injector = new AudioInjector(sound, injectorOptions); - injector->setLocalAudioInterface(_localAudioInterface); - - QThread* injectorThread = new QThread(); - - injector->moveToThread(injectorThread); - - // start injecting when the injector thread starts - connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio); - - // connect the right slots and signals so that the AudioInjector is killed once the injection is complete - connect(injector, &AudioInjector::finished, injector, &AudioInjector::deleteLater); - connect(injector, &AudioInjector::finished, injectorThread, &QThread::quit); - connect(injector, &AudioInjector::finished, this, &AudioScriptingInterface::injectorStopped); - connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater); - - injectorThread->start(); - - _activeInjectors.append(QPointer(injector)); - - return injector; + if (sound) { + AudioInjector* injector = new AudioInjector(sound, injectorOptions); + injector->setLocalAudioInterface(_localAudioInterface); + + QThread* injectorThread = new QThread(); + + injector->moveToThread(injectorThread); + + // start injecting when the injector thread starts + connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio); + + // connect the right slots and signals so that the AudioInjector is killed once the injection is complete + connect(injector, &AudioInjector::finished, injector, &AudioInjector::deleteLater); + connect(injector, &AudioInjector::finished, injectorThread, &QThread::quit); + connect(injector, &AudioInjector::finished, this, &AudioScriptingInterface::injectorStopped); + connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater); + + injectorThread->start(); + + _activeInjectors.append(QPointer(injector)); + + return injector; + } else { + qDebug() << "AudioScriptingInterface::playSound called with null Sound object."; + return NULL; + } } void AudioScriptingInterface::stopInjector(AudioInjector* injector) { diff --git a/libraries/audio/src/Sound.cpp b/libraries/audio/src/Sound.cpp index 8f858e6d3c..ff54e262f8 100644 --- a/libraries/audio/src/Sound.cpp +++ b/libraries/audio/src/Sound.cpp @@ -29,18 +29,19 @@ #include "AudioEditBuffer.h" #include "Sound.h" - -QScriptValue soundToScriptValue(QScriptEngine* engine, Sound* const& in) { - return engine->newQObject(in); +QScriptValue soundToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in) { + return engine->newQObject(in.data()); } -void soundFromScriptValue(const QScriptValue& object, Sound*& out) { - out = qobject_cast(object.toQObject()); +void soundFromScriptValue(const QScriptValue &object, SharedSoundPointer &out) { + out = SharedSoundPointer(qobject_cast(object.toQObject())); + qDebug() << "Sound from script value" << out.data(); } Sound::Sound(const QUrl& url, bool isStereo) : Resource(url), - _isStereo(isStereo) + _isStereo(isStereo), + _isReady(false) { } @@ -70,6 +71,8 @@ void Sound::downloadFinished(QNetworkReply* reply) { } else { qDebug() << "Network reply without 'Content-Type'."; } + + _isReady = true; } void Sound::downSample(const QByteArray& rawAudioByteArray) { diff --git a/libraries/audio/src/Sound.h b/libraries/audio/src/Sound.h index 2880781ac6..c78bf72ff7 100644 --- a/libraries/audio/src/Sound.h +++ b/libraries/audio/src/Sound.h @@ -21,17 +21,19 @@ class Sound : public Resource { Q_OBJECT - Q_PROPERTY(bool downloaded READ isLoaded) + Q_PROPERTY(bool downloaded READ isReady) public: Sound(const QUrl& url, bool isStereo = false); bool isStereo() const { return _isStereo; } - + bool isReady() const { return _isReady; } + const QByteArray& getByteArray() { return _byteArray; } private: QByteArray _byteArray; bool _isStereo; + bool _isReady; void trimFrames(); void downSample(const QByteArray& rawAudioByteArray); @@ -40,4 +42,11 @@ private: virtual void downloadFinished(QNetworkReply* reply); }; +typedef QSharedPointer SharedSoundPointer; + +Q_DECLARE_METATYPE(SharedSoundPointer) + +QScriptValue soundToScriptValue(QScriptEngine* engine, SharedSoundPointer const& in); +void soundFromScriptValue(const QScriptValue& object, SharedSoundPointer& out); + #endif // hifi_Sound_h diff --git a/libraries/audio/src/SoundCache.cpp b/libraries/audio/src/SoundCache.cpp index 09b9cfe330..68a35e3c48 100644 --- a/libraries/audio/src/SoundCache.cpp +++ b/libraries/audio/src/SoundCache.cpp @@ -13,8 +13,17 @@ #include "SoundCache.h" +static int soundPointerMetaTypeId = qRegisterMetaType(); + +SoundCache& SoundCache::getInstance() { + static SoundCache staticInstance; + return staticInstance; +} + SoundCache::SoundCache(QObject* parent) : - ResourceCache(parent) { + ResourceCache(parent) +{ + } SharedSoundPointer SoundCache::getSound(const QUrl& url) { @@ -24,10 +33,11 @@ SharedSoundPointer SoundCache::getSound(const QUrl& url) { Q_RETURN_ARG(SharedSoundPointer, result), Q_ARG(const QUrl&, url)); return result; } + qDebug() << "Requesting sound at" << url.toString() << "from SoundCache"; return getResource(url).staticCast(); } QSharedPointer SoundCache::createResource(const QUrl& url, const QSharedPointer& fallback, - bool delayLoad, const void* extra) { + bool delayLoad, const void* extra) { return QSharedPointer(new Sound(url), &Resource::allReferencesCleared); } \ No newline at end of file diff --git a/libraries/audio/src/SoundCache.h b/libraries/audio/src/SoundCache.h index 4146171794..f9fbf51c10 100644 --- a/libraries/audio/src/SoundCache.h +++ b/libraries/audio/src/SoundCache.h @@ -16,22 +16,19 @@ #include "Sound.h" -typedef QSharedPointer SharedSoundPointer; - -/// Scriptable interface for FBX animation loading. +/// Scriptable interface for sound loading. class SoundCache : public ResourceCache { Q_OBJECT public: - SoundCache(QObject* parent = NULL); + static SoundCache& getInstance(); Q_INVOKABLE SharedSoundPointer getSound(const QUrl& url); protected: - virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, bool delayLoad, const void* extra); +private: + SoundCache(QObject* parent = NULL); }; -Q_DECLARE_METATYPE(SharedSoundPointer) - #endif // hifi_SoundCache_h \ No newline at end of file diff --git a/libraries/avatars/src/Player.cpp b/libraries/avatars/src/Player.cpp index 63384371bd..9f01e98730 100644 --- a/libraries/avatars/src/Player.cpp +++ b/libraries/avatars/src/Player.cpp @@ -168,7 +168,7 @@ void Player::setupAudioThread() { _audioThread = new QThread(); _options.position = _avatar->getPosition(); _options.orientation = _avatar->getOrientation(); - _injector.reset(new AudioInjector(_recording->getAudio(), _options), &QObject::deleteLater); + _injector.reset(new AudioInjector(_recording->getAudioData(), _options), &QObject::deleteLater); _injector->moveToThread(_audioThread); _audioThread->start(); QMetaObject::invokeMethod(_injector.data(), "injectAudio", Qt::QueuedConnection); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index bd0f1cae01..097ede23d0 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -22,7 +22,9 @@ ResourceCache::ResourceCache(QObject* parent) : QObject(parent), - _lastLRUKey(0) { + _lastLRUKey(0) +{ + } ResourceCache::~ResourceCache() { @@ -291,7 +293,7 @@ void Resource::makeRequest() { connect(_reply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleDownloadProgress(qint64,qint64))); connect(_reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleReplyError())); connect(_reply, SIGNAL(finished()), SLOT(handleReplyFinished())); - + _replyTimer = new QTimer(this); connect(_replyTimer, SIGNAL(timeout()), SLOT(handleReplyTimeout())); _replyTimer->setSingleShot(true); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 2691b10273..e6002d7c10 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -47,14 +46,6 @@ VoxelsScriptingInterface ScriptEngine::_voxelsScriptingInterface; EntityScriptingInterface ScriptEngine::_entityScriptingInterface; -static QScriptValue soundConstructor(QScriptContext* context, QScriptEngine* engine) { - QUrl soundURL = QUrl(context->argument(0).toString()); - bool isStereo = context->argument(1).toBool(); - QScriptValue soundScriptValue = engine->newQObject(new Sound(soundURL, isStereo), QScriptEngine::ScriptOwnership); - - return soundScriptValue; -} - static QScriptValue debugPrint(QScriptContext* context, QScriptEngine* engine){ qDebug() << "script:print()<<" << context->argument(0).toString(); QString message = context->argument(0).toString() @@ -263,10 +254,6 @@ void ScriptEngine::init() { QScriptValue printConstructorValue = newFunction(debugPrint); globalObject().setProperty("print", printConstructorValue); - QScriptValue soundConstructorValue = newFunction(soundConstructor); - QScriptValue soundMetaObject = newQMetaObject(&Sound::staticMetaObject, soundConstructorValue); - globalObject().setProperty("Sound", soundMetaObject); - QScriptValue localVoxelsValue = scriptValueFromQMetaObject(); globalObject().setProperty("LocalVoxels", localVoxelsValue); diff --git a/libraries/shared/src/LogHandler.cpp b/libraries/shared/src/LogHandler.cpp index a13f3a9dad..dfac02b912 100644 --- a/libraries/shared/src/LogHandler.cpp +++ b/libraries/shared/src/LogHandler.cpp @@ -119,8 +119,6 @@ QString LogHandler::printMessage(LogMsgType type, const QMessageLogContext& cont char dateString[100]; strftime(dateString, sizeof(dateString), DATE_STRING_FORMAT, localTime); - prefixString.append(QString(" [%1]").arg(dateString)); - if (_shouldOutputPID) { prefixString.append(QString(" [%1").arg(getpid()));