diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index aa24711509..69d43eac1e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -542,9 +542,6 @@ Application::~Application() { _nodeThread->quit(); _nodeThread->wait(); - // kill any audio injectors that are still around - AudioScriptingInterface::getInstance().stopAllInjectors(); - auto audioIO = DependencyManager::get(); // stop the audio process diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 5568a7e372..aa4b99c30d 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -9,6 +9,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include @@ -22,6 +23,9 @@ #include "AudioInjector.h" QScriptValue injectorToScriptValue(QScriptEngine* engine, AudioInjector* const& in) { + // when the script goes down we want to cleanup the injector + QObject::connect(engine, &QScriptEngine::destroyed, in, &AudioInjector::stopAndDeleteLater); + return engine->newQObject(in); } @@ -236,6 +240,14 @@ void AudioInjector::injectToMixer() { // send two packets before the first sleep so the mixer can start playback right away if (_currentSendPosition != bytesToCopy && _currentSendPosition < _audioData.size()) { + + // process events in case we have been told to stop and be deleted + QCoreApplication::processEvents(); + + if (_shouldStop) { + break; + } + // not the first packet and not done // sleep for the appropriate time int usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000; @@ -264,3 +276,8 @@ void AudioInjector::stop() { emit finished(); } } + +void AudioInjector::stopAndDeleteLater() { + stop(); + QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); +} diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 257b538c11..05850c4f47 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -13,6 +13,7 @@ #define hifi_AudioInjector_h #include +#include #include #include @@ -42,6 +43,7 @@ public: public slots: void injectAudio(); void stop(); + void stopAndDeleteLater(); void setOptions(AudioInjectorOptions& options); void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; } float getLoudness(); diff --git a/libraries/audio/src/AudioScriptingInterface.cpp b/libraries/script-engine/src/AudioScriptingInterface.cpp similarity index 54% rename from libraries/audio/src/AudioScriptingInterface.cpp rename to libraries/script-engine/src/AudioScriptingInterface.cpp index 58b72f3fcd..6182e6926d 100644 --- a/libraries/audio/src/AudioScriptingInterface.cpp +++ b/libraries/script-engine/src/AudioScriptingInterface.cpp @@ -28,80 +28,47 @@ AudioScriptingInterface::AudioScriptingInterface() : } -void AudioScriptingInterface::stopAllInjectors() { - QList >::iterator injector = _activeInjectors.begin(); - while (injector != _activeInjectors.end()) { - if (!injector->isNull()) { - injector->data()->stop(); - - while (injector->data() && !injector->data()->isFinished()) { - // wait for this injector to go down - } - } - - injector = _activeInjectors.erase(injector); - } +AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { + AudioInjector* injector = NULL; + QMetaObject::invokeMethod(this, "invokedPlaySound", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(AudioInjector*, injector), + Q_ARG(Sound*, sound), Q_ARG(const AudioInjectorOptions&, injectorOptions)); + return injector; } -AudioInjector* AudioScriptingInterface::playSound(Sound* sound, const AudioInjectorOptions& injectorOptions) { +AudioInjector* AudioScriptingInterface::invokedPlaySound(Sound* sound, const AudioInjectorOptions& injectorOptions) { if (sound) { // stereo option isn't set from script, this comes from sound metadata or filename AudioInjectorOptions optionsCopy = injectorOptions; optionsCopy.stereo = sound->isStereo(); - AudioInjector* injector = new AudioInjector(sound, optionsCopy); - injector->setLocalAudioInterface(_localAudioInterface); - QThread* injectorThread = new QThread(); injectorThread->setObjectName("Audio Injector Thread"); + AudioInjector* injector = new AudioInjector(sound, optionsCopy); + injector->setLocalAudioInterface(_localAudioInterface); + 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 the right slots and signals for AudioInjector and thread cleanup + connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit); connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater); + connect(injectorThread, &QThread::destroyed, this, &AudioScriptingInterface::threadDead); injectorThread->start(); - _activeInjectors.append(QPointer(injector)); - return injector; + } else { qDebug() << "AudioScriptingInterface::playSound called with null Sound object."; return NULL; } } -void AudioScriptingInterface::stopInjector(AudioInjector* injector) { - if (injector) { - injector->stop(); - } -} - -bool AudioScriptingInterface::isInjectorPlaying(AudioInjector* injector) { - return (injector != NULL); -} - -void AudioScriptingInterface::setInjectorOptions(AudioInjector* injector, const AudioInjectorOptions& injectorOptions) { - AudioInjectorOptions optionsCopy = injectorOptions; - if (injector) { - injector->setOptions(optionsCopy); - } -} - -float AudioScriptingInterface::getLoudness(AudioInjector* injector) { - if (injector) { - return injector->getLoudness(); - } else { - return 0.0f; - } -} - -void AudioScriptingInterface::injectorStopped() { - _activeInjectors.removeAll(QPointer(reinterpret_cast(sender()))); +void AudioScriptingInterface::threadDead() { + qDebug() << "The audio thread has gone down"; } diff --git a/libraries/audio/src/AudioScriptingInterface.h b/libraries/script-engine/src/AudioScriptingInterface.h similarity index 60% rename from libraries/audio/src/AudioScriptingInterface.h rename to libraries/script-engine/src/AudioScriptingInterface.h index b437286ecf..8cbb515d7f 100644 --- a/libraries/audio/src/AudioScriptingInterface.h +++ b/libraries/script-engine/src/AudioScriptingInterface.h @@ -12,40 +12,33 @@ #ifndef hifi_AudioScriptingInterface_h #define hifi_AudioScriptingInterface_h -#include - -#include "AbstractAudioInterface.h" -#include "AudioInjector.h" -#include "Sound.h" +#include +#include +#include class AudioScriptingInterface : public QObject { Q_OBJECT public: static AudioScriptingInterface& getInstance(); - void stopAllInjectors(); - void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } -public slots: - - static float getLoudness(AudioInjector* injector); - - AudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); - void stopInjector(AudioInjector* injector); - bool isInjectorPlaying(AudioInjector* injector); - - void setInjectorOptions(AudioInjector* injector, const AudioInjectorOptions& injectorOptions); - - void injectorStopped(); +protected: + // this method is protected to stop C++ callers from calling, but invokable from script + Q_INVOKABLE AudioInjector* playSound(Sound* sound, const AudioInjectorOptions& injectorOptions = AudioInjectorOptions()); signals: void mutedByMixer(); void environmentMuted(); +public slots: + void threadDead(); + +private slots: + AudioInjector* invokedPlaySound(Sound* sound, const AudioInjectorOptions& injectorOptions); + private: AudioScriptingInterface(); - QList< QPointer > _activeInjectors; AbstractAudioInterface* _localAudioInterface; }; diff --git a/libraries/script-engine/src/ScriptEngine.h b/libraries/script-engine/src/ScriptEngine.h index f78a14bffa..6cc9f64d4c 100644 --- a/libraries/script-engine/src/ScriptEngine.h +++ b/libraries/script-engine/src/ScriptEngine.h @@ -19,13 +19,13 @@ #include #include -#include #include #include #include #include "AbstractControllerScriptingInterface.h" #include "ArrayBufferClass.h" +#include "AudioScriptingInterface.h" #include "Quat.h" #include "ScriptUUID.h" #include "Vec3.h"