From 3670a04d8e73343a090cd9bcd22e2b8fa57c7f87 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Tue, 11 Jul 2017 14:24:58 -0700 Subject: [PATCH] switch bare pointers to AudioInjector objects to be QSharedPointers --- interface/src/Application.h | 2 +- interface/src/avatar/AvatarManager.cpp | 3 +- interface/src/avatar/AvatarManager.h | 4 +- libraries/audio-client/src/AudioClient.cpp | 64 +++++++++---------- libraries/audio-client/src/AudioClient.h | 4 +- libraries/audio/src/AbstractAudioInterface.h | 3 +- libraries/audio/src/AudioInjector.cpp | 34 +++++++--- libraries/audio/src/AudioInjector.h | 46 +++++++------ libraries/audio/src/AudioInjectorManager.cpp | 58 ++++++++--------- libraries/audio/src/AudioInjectorManager.h | 25 ++++---- .../script-engine/src/ScriptAudioInjector.cpp | 6 +- .../script-engine/src/ScriptAudioInjector.h | 16 ++--- libraries/ui/src/ui/types/SoundEffect.h | 3 +- 13 files changed, 148 insertions(+), 120 deletions(-) diff --git a/interface/src/Application.h b/interface/src/Application.h index cf0ae91a0f..ce27c4a70a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -678,7 +678,7 @@ private: QTimer _addAssetToWorldErrorTimer; FileScriptingInterface* _fileDownload; - AudioInjector* _snapshotSoundInjector { nullptr }; + AudioInjectorPointer _snapshotSoundInjector; SharedSoundPointer _snapshotSound; DisplayPluginPointer _autoSwitchDisplayModeSupportedHMDPlugin; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index c46d61cf68..b63816eb4f 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -434,8 +434,7 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents // but most avatars are roughly the same size, so let's not be so fancy yet. const float AVATAR_STRETCH_FACTOR = 1.0f; - - _collisionInjectors.remove_if([](QPointer& injector) { + _collisionInjectors.remove_if([](AudioInjectorPointer injector) { return !injector || injector->isFinished(); }); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index f1e71f7367..d6f140ea74 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -25,8 +25,8 @@ #include "AvatarMotionState.h" #include "MyAvatar.h" +#include "AudioInjector.h" -class AudioInjector; class AvatarManager : public AvatarHashMap { Q_OBJECT @@ -104,7 +104,7 @@ private: std::shared_ptr _myAvatar; quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate. - std::list> _collisionInjectors; + std::list _collisionInjectors; RateCounter<> _myAvatarSendRate; int _numAvatarsUpdated { 0 }; diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp index c630fe09e4..d532b18836 100644 --- a/libraries/audio-client/src/AudioClient.cpp +++ b/libraries/audio-client/src/AudioClient.cpp @@ -210,9 +210,9 @@ AudioClient::AudioClient() : connect(&_receivedAudioStream, &MixedProcessedAudioStream::processSamples, this, &AudioClient::processReceivedSamples, Qt::DirectConnection); - connect(this, &AudioClient::changeDevice, this, [=](const QAudioDeviceInfo& outputDeviceInfo) { + connect(this, &AudioClient::changeDevice, this, [=](const QAudioDeviceInfo& outputDeviceInfo) { qCDebug(audioclient) << "got AudioClient::changeDevice signal, about to call switchOutputToAudioDevice() outputDeviceInfo: [" << outputDeviceInfo.deviceName() << "]"; - switchOutputToAudioDevice(outputDeviceInfo); + switchOutputToAudioDevice(outputDeviceInfo); }); connect(&_receivedAudioStream, &InboundAudioStream::mismatchedAudioCodec, this, &AudioClient::handleMismatchAudioFormat); @@ -261,10 +261,10 @@ void AudioClient::cleanupBeforeQuit() { // so this must be explicitly, synchronously stopped static ConditionalGuard guard; if (QThread::currentThread() != thread()) { - // This will likely be called from the main thread, but we don't want to do blocking queued calls - // from the main thread, so we use a normal auto-connection invoke, and then use a conditional to wait + // This will likely be called from the main thread, but we don't want to do blocking queued calls + // from the main thread, so we use a normal auto-connection invoke, and then use a conditional to wait // for completion - // The effect is the same, yes, but we actually want to avoid the use of Qt::BlockingQueuedConnection + // The effect is the same, yes, but we actually want to avoid the use of Qt::BlockingQueuedConnection // in the code QMetaObject::invokeMethod(this, "cleanupBeforeQuit"); guard.wait(); @@ -630,7 +630,7 @@ void AudioClient::handleAudioEnvironmentDataPacket(QSharedPointerreadPrimitive(&bitset); bool hasReverb = oneAtBit(bitset, HAS_REVERB_BIT); - + if (hasReverb) { float reverbTime, wetLevel; message->readPrimitive(&reverbTime); @@ -728,7 +728,7 @@ void AudioClient::Gate::flush() { void AudioClient::handleNoisyMutePacket(QSharedPointer message) { if (!_muted) { toggleMute(); - + // have the audio scripting interface emit a signal to say we were muted by the mixer emit mutedByMixer(); } @@ -737,7 +737,7 @@ void AudioClient::handleNoisyMutePacket(QSharedPointer message) void AudioClient::handleMuteEnvironmentPacket(QSharedPointer message) { glm::vec3 position; float radius; - + message->readPrimitive(&position); message->readPrimitive(&radius); @@ -770,7 +770,7 @@ void AudioClient::handleSelectedAudioFormat(QSharedPointer mess } void AudioClient::selectAudioFormat(const QString& selectedCodecName) { - + _selectedCodecName = selectedCodecName; qCDebug(audioclient) << "Selected Codec:" << _selectedCodecName; @@ -787,7 +787,7 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) { for (auto& plugin : codecPlugins) { if (_selectedCodecName == plugin->getName()) { _codec = plugin; - _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO); + _receivedAudioStream.setupCodec(plugin, _selectedCodecName, AudioConstants::STEREO); _encoder = plugin->createEncoder(AudioConstants::SAMPLE_RATE, AudioConstants::MONO); qCDebug(audioclient) << "Selected Codec Plugin:" << _codec.get(); break; @@ -795,7 +795,7 @@ void AudioClient::selectAudioFormat(const QString& selectedCodecName) { } } - + bool AudioClient::switchAudioDevice(QAudio::Mode mode, const QAudioDeviceInfo& deviceInfo) { auto device = deviceInfo; @@ -1203,11 +1203,11 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) { // lock the injectors Lock lock(_injectorsMutex); - QVector injectorsToRemove; + QVector injectorsToRemove; memset(mixBuffer, 0, AudioConstants::NETWORK_FRAME_SAMPLES_STEREO * sizeof(float)); - for (AudioInjector* injector : _activeLocalAudioInjectors) { + for (AudioInjectorPointer injector : _activeLocalAudioInjectors) { // the lock guarantees that injectorBuffer, if found, is invariant AudioInjectorLocalBuffer* injectorBuffer = injector->getLocalBuffer(); if (injectorBuffer) { @@ -1220,7 +1220,7 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) { // get one frame from the injector memset(_localScratchBuffer, 0, bytesToRead); if (0 < injectorBuffer->readData((char*)_localScratchBuffer, bytesToRead)) { - + if (injector->isAmbisonic()) { // no distance attenuation @@ -1249,36 +1249,36 @@ bool AudioClient::mixLocalAudioInjectors(float* mixBuffer) { for (int i = 0; i < AudioConstants::NETWORK_FRAME_SAMPLES_STEREO; i++) { mixBuffer[i] += convertToFloat(_localScratchBuffer[i]) * gain; } - + } else { // calculate distance, gain and azimuth for hrtf glm::vec3 relativePosition = injector->getPosition() - _positionGetter(); float distance = glm::max(glm::length(relativePosition), EPSILON); - float gain = gainForSource(distance, injector->getVolume()); + float gain = gainForSource(distance, injector->getVolume()); float azimuth = azimuthForSource(relativePosition); - + // mono gets spatialized into mixBuffer - injector->getLocalHRTF().render(_localScratchBuffer, mixBuffer, HRTF_DATASET_INDEX, + injector->getLocalHRTF().render(_localScratchBuffer, mixBuffer, HRTF_DATASET_INDEX, azimuth, distance, gain, AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL); } - + } else { - + qCDebug(audioclient) << "injector has no more data, marking finished for removal"; injector->finishLocalInjection(); injectorsToRemove.append(injector); } } else { - + qCDebug(audioclient) << "injector has no local buffer, marking as finished for removal"; injector->finishLocalInjection(); injectorsToRemove.append(injector); } } - - for (AudioInjector* injector : injectorsToRemove) { + + for (AudioInjectorPointer injector : injectorsToRemove) { qCDebug(audioclient) << "removing injector"; _activeLocalAudioInjectors.removeOne(injector); } @@ -1369,7 +1369,7 @@ void AudioClient::setIsStereoInput(bool isStereoInput) { } } -bool AudioClient::outputLocalInjector(AudioInjector* injector) { +bool AudioClient::outputLocalInjector(AudioInjectorPointer injector) { AudioInjectorLocalBuffer* injectorBuffer = injector->getLocalBuffer(); if (injectorBuffer) { // local injectors are on the AudioInjectorsThread, so we must guard access @@ -1711,9 +1711,9 @@ int AudioClient::calculateNumberOfFrameSamples(int numBytes) const { float AudioClient::azimuthForSource(const glm::vec3& relativePosition) { glm::quat inverseOrientation = glm::inverse(_orientationGetter()); - + glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition; - + // project the rotated source position vector onto the XZ plane rotatedSourcePosition.y = 0.0f; @@ -1721,15 +1721,15 @@ float AudioClient::azimuthForSource(const glm::vec3& relativePosition) { float rotatedSourcePositionLength2 = glm::length2(rotatedSourcePosition); if (rotatedSourcePositionLength2 > SOURCE_DISTANCE_THRESHOLD) { - + // produce an oriented angle about the y-axis glm::vec3 direction = rotatedSourcePosition * (1.0f / fastSqrtf(rotatedSourcePositionLength2)); float angle = fastAcosf(glm::clamp(-direction.z, -1.0f, 1.0f)); // UNIT_NEG_Z is "forward" return (direction.x < 0.0f) ? -angle : angle; - } else { + } else { // no azimuth if they are in same spot - return 0.0f; + return 0.0f; } } @@ -1869,9 +1869,9 @@ void AudioClient::startThread() { moveToNewNamedThread(this, "Audio Thread", [this] { start(); }); } -void AudioClient::setInputVolume(float volume) { - if (_audioInput && volume != (float)_audioInput->volume()) { - _audioInput->setVolume(volume); +void AudioClient::setInputVolume(float volume) { + if (_audioInput && volume != (float)_audioInput->volume()) { + _audioInput->setVolume(volume); emit inputVolumeChanged(_audioInput->volume()); } } diff --git a/libraries/audio-client/src/AudioClient.h b/libraries/audio-client/src/AudioClient.h index 62b99d2443..7fbfcc25d6 100644 --- a/libraries/audio-client/src/AudioClient.h +++ b/libraries/audio-client/src/AudioClient.h @@ -143,7 +143,7 @@ public: Q_INVOKABLE void setAvatarBoundingBoxParameters(glm::vec3 corner, glm::vec3 scale); - bool outputLocalInjector(AudioInjector* injector) override; + bool outputLocalInjector(AudioInjectorPointer injector) override; QAudioDeviceInfo getActiveAudioDevice(QAudio::Mode mode) const; QList getAudioDevices(QAudio::Mode mode) const; @@ -380,7 +380,7 @@ private: bool _hasReceivedFirstPacket { false }; - QVector _activeLocalAudioInjectors; + QVector _activeLocalAudioInjectors; bool _isPlayingBackRecording { false }; diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 2e14b9956b..314884a67a 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -18,6 +18,7 @@ #include #include "AudioInjectorOptions.h" +#include "AudioInjector.h" class AudioInjector; class AudioInjectorLocalBuffer; @@ -35,7 +36,7 @@ public: // threadsafe // moves injector->getLocalBuffer() to another thread (so removes its parent) // take care to delete it when ~AudioInjector, as parenting Qt semantics will not work - virtual bool outputLocalInjector(AudioInjector* injector) = 0; + virtual bool outputLocalInjector(AudioInjectorPointer injector) = 0; public slots: virtual bool shouldLoopbackInjectors() { return false; } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 47e6c98144..5b42168bdd 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -132,7 +132,7 @@ void AudioInjector::restart() { } } -bool AudioInjector::inject(bool(AudioInjectorManager::*injection)(AudioInjector*)) { +bool AudioInjector::inject(bool(AudioInjectorManager::*injection)(AudioInjectorPointer)) { _state = AudioInjectorState::NotFinished; int byteOffset = 0; @@ -150,7 +150,7 @@ bool AudioInjector::inject(bool(AudioInjectorManager::*injection)(AudioInjector* bool success = true; if (!_options.localOnly) { auto injectorManager = DependencyManager::get(); - if (!(*injectorManager.*injection)(this)) { + if (!(*injectorManager.*injection)(getThisPointer())) { success = false; finishNetworkInjection(); } @@ -173,7 +173,7 @@ bool AudioInjector::injectLocally() { // call this function on the AudioClient's thread // this will move the local buffer's thread to the LocalInjectorThread - success = _localAudioInterface->outputLocalInjector(this); + success = _localAudioInterface->outputLocalInjector(getThisPointer()); if (!success) { qCDebug(audio) << "AudioInjector::injectLocally could not output locally via _localAudioInterface"; @@ -429,7 +429,8 @@ void AudioInjector::stopAndDeleteLater() { QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection); } -AudioInjector* AudioInjector::playSound(SharedSoundPointer sound, const float volume, const float stretchFactor, const glm::vec3 position) { +AudioInjectorPointer AudioInjector::playSound(SharedSoundPointer sound, const float volume, + const float stretchFactor, const glm::vec3 position) { if (!sound || !sound->isReady()) { return nullptr; } @@ -462,8 +463,8 @@ AudioInjector* AudioInjector::playSound(SharedSoundPointer sound, const float vo return playSoundAndDelete(resampled, options); } -AudioInjector* AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options) { - AudioInjector* sound = playSound(buffer, options); +AudioInjectorPointer AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options) { + AudioInjectorPointer sound = playSound(buffer, options); if (sound) { sound->_state |= AudioInjectorState::PendingDelete; @@ -473,10 +474,27 @@ AudioInjector* AudioInjector::playSoundAndDelete(const QByteArray& buffer, const } -AudioInjector* AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options) { - AudioInjector* injector = new AudioInjector(buffer, options); +AudioInjectorPointer AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options) { + AudioInjectorPointer injector = AudioInjectorPointer(new AudioInjector(buffer, options)); + injector->setThisPointer(injector); + if (!injector->inject(&AudioInjectorManager::threadInjector)) { qWarning() << "AudioInjector::playSound failed to thread injector"; } return injector; } + +AudioInjectorPointer AudioInjector::getThisPointer() { + std::lock_guard lock(_refLock); + QSharedPointer this_ref(_self); + if (this_ref.isNull()) { + this_ref = QSharedPointer(this); + _self = this_ref.toWeakRef(); + } + return this_ref; +} + +void AudioInjector::setThisPointer(AudioInjectorPointer self) { + std::lock_guard lock(_refLock); + _self = self.toWeakRef(); +} diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index a901c2520f..056f498b3a 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -32,6 +32,8 @@ class AbstractAudioInterface; class AudioInjectorManager; +class AudioInjector; +using AudioInjectorPointer = QSharedPointer; enum class AudioInjectorState : uint8_t { @@ -46,19 +48,19 @@ AudioInjectorState operator& (AudioInjectorState lhs, AudioInjectorState rhs); AudioInjectorState& operator|= (AudioInjectorState& lhs, AudioInjectorState rhs); // In order to make scripting cleaner for the AudioInjector, the script now holds on to the AudioInjector object -// until it dies. +// until it dies. class AudioInjector : public QObject { Q_OBJECT public: AudioInjector(const Sound& sound, const AudioInjectorOptions& injectorOptions); AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions); ~AudioInjector(); - + bool isFinished() const { return (stateHas(AudioInjectorState::Finished)); } - + int getCurrentSendOffset() const { return _currentSendOffset; } void setCurrentSendOffset(int currentSendOffset) { _currentSendOffset = currentSendOffset; } - + AudioInjectorLocalBuffer* getLocalBuffer() const { return _localBuffer; } AudioHRTF& getLocalHRTF() { return _localHRTF; } AudioFOA& getLocalFOA() { return _localFOA; } @@ -72,36 +74,41 @@ public: bool stateHas(AudioInjectorState state) const ; static void setLocalAudioInterface(AbstractAudioInterface* audioInterface) { _localAudioInterface = audioInterface; } - static AudioInjector* playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options); - static AudioInjector* playSound(const QByteArray& buffer, const AudioInjectorOptions options); - static AudioInjector* playSound(SharedSoundPointer sound, const float volume, const float stretchFactor, const glm::vec3 position); + static AudioInjectorPointer playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options); + static AudioInjectorPointer playSound(const QByteArray& buffer, const AudioInjectorOptions options); + static AudioInjectorPointer playSound(SharedSoundPointer sound, const float volume, + const float stretchFactor, const glm::vec3 position); + + QWeakPointer weakRef() const { return _self; } + AudioInjectorPointer getThisPointer(); + void setThisPointer(AudioInjectorPointer self); public slots: void restart(); - + void stop(); void triggerDeleteAfterFinish(); void stopAndDeleteLater(); - + const AudioInjectorOptions& getOptions() const { return _options; } void setOptions(const AudioInjectorOptions& options); - + float getLoudness() const { return _loudness; } bool isPlaying() const { return !stateHas(AudioInjectorState::Finished); } void finish(); void finishLocalInjection(); void finishNetworkInjection(); - + signals: void finished(); void restarting(); - + private: int64_t injectNextFrame(); - bool inject(bool(AudioInjectorManager::*injection)(AudioInjector*)); + bool inject(bool(AudioInjectorManager::*injection)(AudioInjectorPointer)); bool injectLocally(); void deleteLocalBuffer(); - + static AbstractAudioInterface* _localAudioInterface; QByteArray _audioData; @@ -112,17 +119,20 @@ private: int _currentSendOffset { 0 }; std::unique_ptr _currentPacket { nullptr }; AudioInjectorLocalBuffer* _localBuffer { nullptr }; - + int64_t _nextFrame { 0 }; std::unique_ptr _frameTimer { nullptr }; quint16 _outgoingSequenceNumber { 0 }; - + // when the injector is local, we need this AudioHRTF _localHRTF; AudioFOA _localFOA; friend class AudioInjectorManager; + + QWeakPointer _self; + mutable std::mutex _refLock; }; -Q_DECLARE_METATYPE(AudioInjector*) - +Q_DECLARE_METATYPE(AudioInjectorPointer) + #endif // hifi_AudioInjector_h diff --git a/libraries/audio/src/AudioInjectorManager.cpp b/libraries/audio/src/AudioInjectorManager.cpp index c66e209ea9..f9f45987d4 100644 --- a/libraries/audio/src/AudioInjectorManager.cpp +++ b/libraries/audio/src/AudioInjectorManager.cpp @@ -21,26 +21,26 @@ AudioInjectorManager::~AudioInjectorManager() { _shouldStop = true; - + Lock lock(_injectorsMutex); - + // make sure any still living injectors are stopped and deleted while (!_injectors.empty()) { // grab the injector at the front auto& timePointerPair = _injectors.top(); - + // ask it to stop and be deleted timePointerPair.second->stopAndDeleteLater(); - + _injectors.pop(); } - + // get rid of the lock now that we've stopped all living injectors lock.unlock(); - + // in case the thread is waiting for injectors wake it up now _injectorReady.notify_one(); - + // quit and wait on the manager thread, if we ever created it if (_thread) { _thread->quit(); @@ -51,10 +51,10 @@ AudioInjectorManager::~AudioInjectorManager() { void AudioInjectorManager::createThread() { _thread = new QThread; _thread->setObjectName("Audio Injector Thread"); - + // when the thread is started, have it call our run to handle injection of audio connect(_thread, &QThread::started, this, &AudioInjectorManager::run, Qt::DirectConnection); - + // start the thread _thread->start(); } @@ -63,20 +63,20 @@ void AudioInjectorManager::run() { while (!_shouldStop) { // wait until the next injector is ready, or until we get a new injector given to us Lock lock(_injectorsMutex); - + if (_injectors.size() > 0) { // when does the next injector need to send a frame? // do we get to wait or should we just go for it now? - + auto timeInjectorPair = _injectors.top(); - + auto nextTimestamp = timeInjectorPair.first; int64_t difference = int64_t(nextTimestamp - usecTimestampNow()); - + if (difference > 0) { _injectorReady.wait_for(lock, std::chrono::microseconds(difference)); } - + if (_injectors.size() > 0) { // loop through the injectors in the map and send whatever frames need to go out auto front = _injectors.top(); @@ -90,7 +90,7 @@ void AudioInjectorManager::run() { // either way we're popping this injector off - get a copy first auto injector = front.second; _injectors.pop(); - + if (!injector.isNull()) { // this is an injector that's ready to go, have it send a frame now auto nextCallDelta = injector->injectNextFrame(); @@ -100,7 +100,7 @@ void AudioInjectorManager::run() { heldInjectors.emplace(heldInjectors.end(), usecTimestampNow() + nextCallDelta, injector); } } - + if (_injectors.size() > 0) { front = _injectors.top(); } else { @@ -120,10 +120,10 @@ void AudioInjectorManager::run() { // we have no current injectors, wait until we get at least one before we do anything _injectorReady.wait(lock); } - + // unlock the lock in case something in process events needs to modify the queue lock.unlock(); - + QCoreApplication::processEvents(); } } @@ -139,36 +139,36 @@ bool AudioInjectorManager::wouldExceedLimits() { // Should be called inside of a return false; } -bool AudioInjectorManager::threadInjector(AudioInjector* injector) { +bool AudioInjectorManager::threadInjector(AudioInjectorPointer injector) { if (_shouldStop) { qCDebug(audio) << "AudioInjectorManager::threadInjector asked to thread injector but is shutting down."; return false; } - + // guard the injectors vector with a mutex Lock lock(_injectorsMutex); - + if (wouldExceedLimits()) { return false; } else { if (!_thread) { createThread(); } - + // move the injector to the QThread injector->moveToThread(_thread); - + // add the injector to the queue with a send timestamp of now - _injectors.emplace(usecTimestampNow(), InjectorQPointer { injector }); - + _injectors.emplace(usecTimestampNow(), AudioInjectorPointer { injector }); + // notify our wait condition so we can inject two frames for this injector immediately _injectorReady.notify_one(); - + return true; } } -bool AudioInjectorManager::restartFinishedInjector(AudioInjector* injector) { +bool AudioInjectorManager::restartFinishedInjector(AudioInjectorPointer injector) { if (_shouldStop) { qCDebug(audio) << "AudioInjectorManager::threadInjector asked to thread injector but is shutting down."; return false; @@ -181,8 +181,8 @@ bool AudioInjectorManager::restartFinishedInjector(AudioInjector* injector) { return false; } else { // add the injector to the queue with a send timestamp of now - _injectors.emplace(usecTimestampNow(), InjectorQPointer { injector }); - + _injectors.emplace(usecTimestampNow(), injector->getThisPointer()); + // notify our wait condition so we can inject two frames for this injector immediately _injectorReady.notify_one(); } diff --git a/libraries/audio/src/AudioInjectorManager.h b/libraries/audio/src/AudioInjectorManager.h index de5537856e..ac1d364b86 100644 --- a/libraries/audio/src/AudioInjectorManager.h +++ b/libraries/audio/src/AudioInjectorManager.h @@ -23,7 +23,7 @@ #include -class AudioInjector; +#include "AudioInjector.h" class AudioInjectorManager : public QObject, public Dependency { Q_OBJECT @@ -33,39 +33,38 @@ public: private slots: void run(); private: - - using InjectorQPointer = QPointer; - using TimeInjectorPointerPair = std::pair; - + + using TimeInjectorPointerPair = std::pair; + struct greaterTime { bool operator() (const TimeInjectorPointerPair& x, const TimeInjectorPointerPair& y) const { return x.first > y.first; } }; - + using InjectorQueue = std::priority_queue, greaterTime>; using Mutex = std::mutex; using Lock = std::unique_lock; - - bool threadInjector(AudioInjector* injector); - bool restartFinishedInjector(AudioInjector* injector); + + bool threadInjector(AudioInjectorPointer injector); + bool restartFinishedInjector(AudioInjectorPointer injector); void notifyInjectorReadyCondition() { _injectorReady.notify_one(); } bool wouldExceedLimits(); - + AudioInjectorManager() {}; AudioInjectorManager(const AudioInjectorManager&) = delete; AudioInjectorManager& operator=(const AudioInjectorManager&) = delete; - + void createThread(); - + QThread* _thread { nullptr }; bool _shouldStop { false }; InjectorQueue _injectors; Mutex _injectorsMutex; std::condition_variable _injectorReady; - + friend class AudioInjector; }; diff --git a/libraries/script-engine/src/ScriptAudioInjector.cpp b/libraries/script-engine/src/ScriptAudioInjector.cpp index c0ad2debd9..37a9ad65d7 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.cpp +++ b/libraries/script-engine/src/ScriptAudioInjector.cpp @@ -21,7 +21,7 @@ QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* c // when the script goes down we want to cleanup the injector QObject::connect(engine, &QScriptEngine::destroyed, in, &ScriptAudioInjector::stopInjectorImmediately, Qt::DirectConnection); - + return engine->newQObject(in, QScriptEngine::ScriptOwnership); } @@ -29,10 +29,10 @@ void injectorFromScriptValue(const QScriptValue& object, ScriptAudioInjector*& o out = qobject_cast(object.toQObject()); } -ScriptAudioInjector::ScriptAudioInjector(AudioInjector* injector) : +ScriptAudioInjector::ScriptAudioInjector(AudioInjectorPointer injector) : _injector(injector) { - QObject::connect(injector, &AudioInjector::finished, this, &ScriptAudioInjector::finished); + QObject::connect(injector.data(), &AudioInjector::finished, this, &ScriptAudioInjector::finished); } ScriptAudioInjector::~ScriptAudioInjector() { diff --git a/libraries/script-engine/src/ScriptAudioInjector.h b/libraries/script-engine/src/ScriptAudioInjector.h index 4de12af62c..018fbe5110 100644 --- a/libraries/script-engine/src/ScriptAudioInjector.h +++ b/libraries/script-engine/src/ScriptAudioInjector.h @@ -18,31 +18,31 @@ class ScriptAudioInjector : public QObject { Q_OBJECT - + Q_PROPERTY(bool playing READ isPlaying) Q_PROPERTY(float loudness READ getLoudness) Q_PROPERTY(AudioInjectorOptions options WRITE setOptions READ getOptions) public: - ScriptAudioInjector(AudioInjector* injector); + ScriptAudioInjector(AudioInjectorPointer injector); ~ScriptAudioInjector(); public slots: void restart() { _injector->restart(); } void stop() { _injector->stop(); } - + const AudioInjectorOptions& getOptions() const { return _injector->getOptions(); } void setOptions(const AudioInjectorOptions& options) { _injector->setOptions(options); } - + float getLoudness() const { return _injector->getLoudness(); } bool isPlaying() const { return _injector->isPlaying(); } - + signals: void finished(); - + protected slots: void stopInjectorImmediately(); private: - QPointer _injector; - + AudioInjectorPointer _injector; + friend QScriptValue injectorToScriptValue(QScriptEngine* engine, ScriptAudioInjector* const& in); }; diff --git a/libraries/ui/src/ui/types/SoundEffect.h b/libraries/ui/src/ui/types/SoundEffect.h index 656f98dd8d..a7e29d86f9 100644 --- a/libraries/ui/src/ui/types/SoundEffect.h +++ b/libraries/ui/src/ui/types/SoundEffect.h @@ -15,6 +15,7 @@ #include class AudioInjector; +using AudioInjectorPointer = QSharedPointer; // SoundEffect object, exposed to qml only, not interface JavaScript. // This is used to play spatial sound effects on tablets/web entities from within QML. @@ -38,7 +39,7 @@ protected: QUrl _url; float _volume { 1.0f }; SharedSoundPointer _sound; - AudioInjector* _injector { nullptr }; + AudioInjectorPointer _injector; }; #endif // hifi_SoundEffect_h