mirror of
https://github.com/overte-org/overte.git
synced 2025-08-08 07:37:31 +02:00
add an AudioInjectorManager for more efficient threading
This commit is contained in:
parent
52716b8f95
commit
aa77c4894c
7 changed files with 276 additions and 68 deletions
|
@ -406,7 +406,7 @@ void Agent::sendPingRequests() {
|
||||||
case NodeType::AvatarMixer:
|
case NodeType::AvatarMixer:
|
||||||
case NodeType::AudioMixer:
|
case NodeType::AudioMixer:
|
||||||
case NodeType::EntityServer:
|
case NodeType::EntityServer:
|
||||||
case NodeType::AssetClient:
|
case NodeType::AssetServer:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
|
42
examples/tests/injectorTest.js
Normal file
42
examples/tests/injectorTest.js
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
//
|
||||||
|
// injectorTests.js
|
||||||
|
// examples
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 11/16/15.
|
||||||
|
// Copyright 2014 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
var soundURL = "atp:44a83a788ccfd2924e35c902c34808b24dbd0309d000299ce01a355f91cf8115.wav";
|
||||||
|
var audioOptions = {
|
||||||
|
position: MyAvatar.position,
|
||||||
|
volume: 0.5
|
||||||
|
};
|
||||||
|
|
||||||
|
var sound = SoundCache.getSound(soundURL);
|
||||||
|
var injector = null;
|
||||||
|
var restarting = false;
|
||||||
|
|
||||||
|
Script.update.connect(function(){
|
||||||
|
if (sound.downloaded) {
|
||||||
|
if (!injector) {
|
||||||
|
injector = Audio.playSound(sound, audioOptions);
|
||||||
|
} else if (!injector.isPlaying && !restarting) {
|
||||||
|
restarting = true;
|
||||||
|
|
||||||
|
Script.setTimeout(function(){
|
||||||
|
print("Calling restart for a stopped injector from script.");
|
||||||
|
injector.restart();
|
||||||
|
}, 1000);
|
||||||
|
} else if (injector.isPlaying) {
|
||||||
|
restarting = false;
|
||||||
|
|
||||||
|
if (Math.random() < 0.0001) {
|
||||||
|
print("Calling restart for a running injector from script.");
|
||||||
|
injector.restart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
|
@ -50,6 +50,7 @@
|
||||||
#include <AssetClient.h>
|
#include <AssetClient.h>
|
||||||
#include <AssetUpload.h>
|
#include <AssetUpload.h>
|
||||||
#include <AutoUpdater.h>
|
#include <AutoUpdater.h>
|
||||||
|
#include <AudioInjectorManager.h>
|
||||||
#include <CursorManager.h>
|
#include <CursorManager.h>
|
||||||
#include <DeferredLightingEffect.h>
|
#include <DeferredLightingEffect.h>
|
||||||
#include <display-plugins/DisplayPlugin.h>
|
#include <display-plugins/DisplayPlugin.h>
|
||||||
|
@ -332,6 +333,7 @@ bool setupEssentials(int& argc, char** argv) {
|
||||||
DependencyManager::set<PathUtils>();
|
DependencyManager::set<PathUtils>();
|
||||||
DependencyManager::set<InterfaceActionFactory>();
|
DependencyManager::set<InterfaceActionFactory>();
|
||||||
DependencyManager::set<AssetClient>();
|
DependencyManager::set<AssetClient>();
|
||||||
|
DependencyManager::set<AudioInjectorManager>();
|
||||||
DependencyManager::set<UserInputMapper>();
|
DependencyManager::set<UserInputMapper>();
|
||||||
DependencyManager::set<controller::ScriptingInterface, ControllerScriptingInterface>();
|
DependencyManager::set<controller::ScriptingInterface, ControllerScriptingInterface>();
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include <UUID.h>
|
#include <UUID.h>
|
||||||
|
|
||||||
#include "AbstractAudioInterface.h"
|
#include "AbstractAudioInterface.h"
|
||||||
|
#include "AudioInjectorManager.h"
|
||||||
#include "AudioRingBuffer.h"
|
#include "AudioRingBuffer.h"
|
||||||
#include "AudioLogging.h"
|
#include "AudioLogging.h"
|
||||||
#include "SoundCache.h"
|
#include "SoundCache.h"
|
||||||
|
@ -35,6 +36,7 @@ AudioInjector::AudioInjector(Sound* sound, const AudioInjectorOptions& injectorO
|
||||||
_audioData(sound->getByteArray()),
|
_audioData(sound->getByteArray()),
|
||||||
_options(injectorOptions)
|
_options(injectorOptions)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions) :
|
AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions) :
|
||||||
|
@ -44,32 +46,27 @@ AudioInjector::AudioInjector(const QByteArray& audioData, const AudioInjectorOpt
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioInjector::setIsFinished(bool isFinished) {
|
void AudioInjector::finish() {
|
||||||
_isFinished = isFinished;
|
State oldState = std::atomic_exchange(&_state, State::Finished);
|
||||||
// In all paths, regardless of isFinished argument. restart() passes false to prepare for new play, and injectToMixer() needs _shouldStop reset.
|
bool shouldDelete = (oldState == State::NotFinishedWithPendingDelete);
|
||||||
_shouldStop = false;
|
|
||||||
|
emit finished();
|
||||||
if (_isFinished) {
|
|
||||||
emit finished();
|
if (_localBuffer) {
|
||||||
|
_localBuffer->stop();
|
||||||
if (_localBuffer) {
|
_localBuffer->deleteLater();
|
||||||
_localBuffer->stop();
|
_localBuffer = NULL;
|
||||||
_localBuffer->deleteLater();
|
}
|
||||||
_localBuffer = NULL;
|
|
||||||
}
|
if (shouldDelete) {
|
||||||
|
// we've been asked to delete after finishing, trigger a queued deleteLater here
|
||||||
_isStarted = false;
|
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
|
||||||
|
|
||||||
if (_shouldDeleteAfterFinish) {
|
|
||||||
// we've been asked to delete after finishing, trigger a queued deleteLater here
|
|
||||||
QMetaObject::invokeMethod(this, "deleteLater", Qt::QueuedConnection);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioInjector::injectAudio() {
|
void AudioInjector::injectAudio() {
|
||||||
if (!_isStarted) {
|
if (!_hasStarted) {
|
||||||
_isStarted = true;
|
_hasStarted = true;
|
||||||
// check if we need to offset the sound by some number of seconds
|
// check if we need to offset the sound by some number of seconds
|
||||||
if (_options.secondOffset > 0.0f) {
|
if (_options.secondOffset > 0.0f) {
|
||||||
|
|
||||||
|
@ -85,6 +82,7 @@ void AudioInjector::injectAudio() {
|
||||||
if (_options.localOnly) {
|
if (_options.localOnly) {
|
||||||
injectLocally();
|
injectLocally();
|
||||||
} else {
|
} else {
|
||||||
|
qDebug() << "Calling inject to mixer from" << QThread::currentThread();
|
||||||
injectToMixer();
|
injectToMixer();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,18 +91,26 @@ void AudioInjector::injectAudio() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioInjector::restart() {
|
void AudioInjector::restart() {
|
||||||
_isPlaying = true;
|
if (thread() != QThread::currentThread()) {
|
||||||
connect(this, &AudioInjector::finished, this, &AudioInjector::restartPortionAfterFinished);
|
QMetaObject::invokeMethod(this, "restart");
|
||||||
if (!_isStarted || _isFinished) {
|
return;
|
||||||
emit finished();
|
}
|
||||||
} else {
|
|
||||||
stop();
|
// reset the current send offset to zero
|
||||||
|
_currentSendOffset = 0;
|
||||||
|
|
||||||
|
// check our state to decide if we need extra handling for the restart request
|
||||||
|
if (!isPlaying()) {
|
||||||
|
// we finished playing, need to reset state so we can get going again
|
||||||
|
_hasStarted = false;
|
||||||
|
_shouldStop = false;
|
||||||
|
_state = State::NotFinished;
|
||||||
|
|
||||||
|
qDebug() << "Calling inject audio again to restart an injector";
|
||||||
|
|
||||||
|
// call inject audio to start injection over again
|
||||||
|
injectAudio();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
void AudioInjector::restartPortionAfterFinished() {
|
|
||||||
disconnect(this, &AudioInjector::finished, this, &AudioInjector::restartPortionAfterFinished);
|
|
||||||
setIsFinished(false);
|
|
||||||
QMetaObject::invokeMethod(this, "injectAudio", Qt::QueuedConnection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioInjector::injectLocally() {
|
void AudioInjector::injectLocally() {
|
||||||
|
@ -252,16 +258,17 @@ void AudioInjector::injectToMixer() {
|
||||||
|
|
||||||
if (_currentSendOffset != bytesToCopy && _currentSendOffset < _audioData.size()) {
|
if (_currentSendOffset != bytesToCopy && _currentSendOffset < _audioData.size()) {
|
||||||
|
|
||||||
// process events in case we have been told to stop and be deleted
|
|
||||||
QCoreApplication::processEvents();
|
|
||||||
|
|
||||||
if (_shouldStop) {
|
if (_shouldStop) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not the first packet and not done
|
// not the first packet and not done
|
||||||
// sleep for the appropriate time
|
// sleep for the appropriate time
|
||||||
int usecToSleep = (++nextFrame * (_options.stereo ? 2 : 1) * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000;
|
int usecToSleep = (++nextFrame * AudioConstants::NETWORK_FRAME_USECS) - timer.nsecsElapsed() / 1000;
|
||||||
|
|
||||||
|
qDebug() << "AudioInjector" << this << "will sleep on thread" << QThread::currentThread() << "for" << usecToSleep;
|
||||||
|
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
|
@ -274,8 +281,7 @@ void AudioInjector::injectToMixer() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsFinished(true);
|
finish();
|
||||||
_isPlaying = !_isFinished; // Which can be false if a restart was requested
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioInjector::stop() {
|
void AudioInjector::stop() {
|
||||||
|
@ -283,8 +289,14 @@ void AudioInjector::stop() {
|
||||||
|
|
||||||
if (_options.localOnly) {
|
if (_options.localOnly) {
|
||||||
// we're only a local injector, so we can say we are finished right away too
|
// we're only a local injector, so we can say we are finished right away too
|
||||||
_isPlaying = false;
|
finish();
|
||||||
setIsFinished(true);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioInjector::triggerDeleteAfterFinish() {
|
||||||
|
auto expectedState = State::NotFinished;
|
||||||
|
if (!_state.compare_exchange_strong(expectedState, State::NotFinishedWithPendingDelete)) {
|
||||||
|
stopAndDeleteLater();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,28 +348,26 @@ AudioInjector* AudioInjector::playSound(const QString& soundUrl, const float vol
|
||||||
|
|
||||||
AudioInjector* AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {
|
AudioInjector* AudioInjector::playSoundAndDelete(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {
|
||||||
AudioInjector* sound = playSound(buffer, options, localInterface);
|
AudioInjector* sound = playSound(buffer, options, localInterface);
|
||||||
sound->triggerDeleteAfterFinish();
|
sound->_state = AudioInjector::State::NotFinishedWithPendingDelete;
|
||||||
return sound;
|
return sound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AudioInjector* AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {
|
AudioInjector* AudioInjector::playSound(const QByteArray& buffer, const AudioInjectorOptions options, AbstractAudioInterface* localInterface) {
|
||||||
QThread* injectorThread = new QThread();
|
|
||||||
injectorThread->setObjectName("Audio Injector Thread");
|
|
||||||
|
|
||||||
AudioInjector* injector = new AudioInjector(buffer, options);
|
AudioInjector* injector = new AudioInjector(buffer, options);
|
||||||
injector->_isPlaying = true;
|
|
||||||
injector->setLocalAudioInterface(localInterface);
|
injector->setLocalAudioInterface(localInterface);
|
||||||
|
|
||||||
injector->moveToThread(injectorThread);
|
// grab the AudioInjectorManager
|
||||||
|
auto injectorManager = DependencyManager::get<AudioInjectorManager>();
|
||||||
// start injecting when the injector thread starts
|
|
||||||
connect(injectorThread, &QThread::started, injector, &AudioInjector::injectAudio);
|
// attempt to thread the new injector
|
||||||
|
if (injectorManager->threadInjector(injector)) {
|
||||||
// connect the right slots and signals for AudioInjector and thread cleanup
|
// call inject audio on the correct thread
|
||||||
connect(injector, &AudioInjector::destroyed, injectorThread, &QThread::quit);
|
QMetaObject::invokeMethod(injector, "injectAudio", Qt::QueuedConnection);
|
||||||
connect(injectorThread, &QThread::finished, injectorThread, &QThread::deleteLater);
|
|
||||||
|
return injector;
|
||||||
injectorThread->start();
|
} else {
|
||||||
return injector;
|
// we failed to thread the new injector (we are at the max number of injector threads)
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#ifndef hifi_AudioInjector_h
|
#ifndef hifi_AudioInjector_h
|
||||||
#define hifi_AudioInjector_h
|
#define hifi_AudioInjector_h
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QtCore/QSharedPointer>
|
#include <QtCore/QSharedPointer>
|
||||||
#include <QtCore/QThread>
|
#include <QtCore/QThread>
|
||||||
|
@ -32,11 +34,17 @@ class AudioInjector : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum class State : uint8_t {
|
||||||
|
NotFinished,
|
||||||
|
NotFinishedWithPendingDelete,
|
||||||
|
Finished
|
||||||
|
};
|
||||||
|
|
||||||
AudioInjector(QObject* parent);
|
AudioInjector(QObject* parent);
|
||||||
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
AudioInjector(Sound* sound, const AudioInjectorOptions& injectorOptions);
|
||||||
AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions);
|
AudioInjector(const QByteArray& audioData, const AudioInjectorOptions& injectorOptions);
|
||||||
|
|
||||||
bool isFinished() const { return _isFinished; }
|
bool isFinished() const { return _state == State::Finished; }
|
||||||
|
|
||||||
int getCurrentSendOffset() const { return _currentSendOffset; }
|
int getCurrentSendOffset() const { return _currentSendOffset; }
|
||||||
void setCurrentSendOffset(int currentSendOffset) { _currentSendOffset = currentSendOffset; }
|
void setCurrentSendOffset(int currentSendOffset) { _currentSendOffset = currentSendOffset; }
|
||||||
|
@ -55,15 +63,14 @@ public slots:
|
||||||
void restart();
|
void restart();
|
||||||
|
|
||||||
void stop();
|
void stop();
|
||||||
void triggerDeleteAfterFinish() { _shouldDeleteAfterFinish = true; }
|
void triggerDeleteAfterFinish();
|
||||||
void stopAndDeleteLater();
|
void stopAndDeleteLater();
|
||||||
|
|
||||||
const AudioInjectorOptions& getOptions() const { return _options; }
|
const AudioInjectorOptions& getOptions() const { return _options; }
|
||||||
void setOptions(const AudioInjectorOptions& options) { _options = options; }
|
void setOptions(const AudioInjectorOptions& options) { _options = options; }
|
||||||
|
|
||||||
float getLoudness() const { return _loudness; }
|
float getLoudness() const { return _loudness; }
|
||||||
bool isPlaying() const { return _isPlaying; }
|
bool isPlaying() const { return _state == State::NotFinished || _state == State::NotFinishedWithPendingDelete; }
|
||||||
void restartPortionAfterFinished();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void finished();
|
void finished();
|
||||||
|
@ -72,16 +79,14 @@ private:
|
||||||
void injectToMixer();
|
void injectToMixer();
|
||||||
void injectLocally();
|
void injectLocally();
|
||||||
|
|
||||||
void setIsFinished(bool isFinished);
|
void finish();
|
||||||
|
|
||||||
QByteArray _audioData;
|
QByteArray _audioData;
|
||||||
AudioInjectorOptions _options;
|
AudioInjectorOptions _options;
|
||||||
|
std::atomic<State> _state { State::NotFinished };
|
||||||
|
bool _hasStarted = false;
|
||||||
bool _shouldStop = false;
|
bool _shouldStop = false;
|
||||||
float _loudness = 0.0f;
|
float _loudness = 0.0f;
|
||||||
bool _isPlaying = false;
|
|
||||||
bool _isStarted = false;
|
|
||||||
bool _isFinished = false;
|
|
||||||
bool _shouldDeleteAfterFinish = false;
|
|
||||||
int _currentSendOffset = 0;
|
int _currentSendOffset = 0;
|
||||||
AbstractAudioInterface* _localAudioInterface = NULL;
|
AbstractAudioInterface* _localAudioInterface = NULL;
|
||||||
AudioInjectorLocalBuffer* _localBuffer = NULL;
|
AudioInjectorLocalBuffer* _localBuffer = NULL;
|
||||||
|
|
96
libraries/audio/src/AudioInjectorManager.cpp
Normal file
96
libraries/audio/src/AudioInjectorManager.cpp
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
//
|
||||||
|
// AudioInjectorManager.cpp
|
||||||
|
// libraries/audio/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2015-11-16.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "AudioInjectorManager.h"
|
||||||
|
|
||||||
|
#include <QtCore/QCoreApplication>
|
||||||
|
|
||||||
|
#include "AudioInjector.h"
|
||||||
|
|
||||||
|
AudioInjectorManager::~AudioInjectorManager() {
|
||||||
|
_shouldStop = true;
|
||||||
|
|
||||||
|
// make sure any still living injectors are stopped and deleted
|
||||||
|
for (auto injector : _injectors) {
|
||||||
|
injector->stopAndDeleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
// quit and wait on the injector thread, if we ever created it
|
||||||
|
if (_thread) {
|
||||||
|
_thread->quit();
|
||||||
|
_thread->wait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// start the thread
|
||||||
|
_thread->start();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioInjectorManager::run() {
|
||||||
|
while (!_shouldStop) {
|
||||||
|
// process events in case we have been told to stop or our injectors have been told to stop
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int MAX_INJECTORS_PER_THREAD = 50; // calculated based on AudioInjector while loop time, with sufficient padding
|
||||||
|
|
||||||
|
bool AudioInjectorManager::threadInjector(AudioInjector* injector) {
|
||||||
|
// guard the injectors vector with a mutex
|
||||||
|
std::unique_lock<std::mutex> lock(_injectorsMutex);
|
||||||
|
|
||||||
|
// check if we'll be able to thread this injector (do we have < MAX concurrent injectors)
|
||||||
|
if (_injectors.size() < MAX_INJECTORS_PER_THREAD) {
|
||||||
|
if (!_thread) {
|
||||||
|
createThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto it = nextInjectorIterator();
|
||||||
|
qDebug() << "Inserting injector at" << it - _injectors.begin();
|
||||||
|
|
||||||
|
// store a QPointer to this injector
|
||||||
|
_injectors.insert(it, QPointer<AudioInjector>(injector));
|
||||||
|
|
||||||
|
qDebug() << "Moving injector to thread" << _thread;
|
||||||
|
|
||||||
|
// move the injector to the QThread
|
||||||
|
injector->moveToThread(_thread);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// unable to thread this injector, at the max
|
||||||
|
qDebug() << "AudioInjectorManager::threadInjector could not thread AudioInjector - at max of"
|
||||||
|
<< MAX_INJECTORS_PER_THREAD << "current audio injectors.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioInjectorVector::iterator AudioInjectorManager::nextInjectorIterator() {
|
||||||
|
// find the next usable iterator for an injector
|
||||||
|
auto it = _injectors.begin();
|
||||||
|
|
||||||
|
while (it != _injectors.end()) {
|
||||||
|
if (it->isNull()) {
|
||||||
|
return it;
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return it;
|
||||||
|
}
|
53
libraries/audio/src/AudioInjectorManager.h
Normal file
53
libraries/audio/src/AudioInjectorManager.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//
|
||||||
|
// AudioInjectorManager.h
|
||||||
|
// libraries/audio/src
|
||||||
|
//
|
||||||
|
// Created by Stephen Birarda on 2015-11-16.
|
||||||
|
// Copyright 2015 High Fidelity, Inc.
|
||||||
|
//
|
||||||
|
// Distributed under the Apache License, Version 2.0.
|
||||||
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef hifi_AudioInjectorManager_h
|
||||||
|
#define hifi_AudioInjectorManager_h
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
#include <QtCore/QPointer>
|
||||||
|
#include <QtCore/QThread>
|
||||||
|
|
||||||
|
#include <DependencyManager.h>
|
||||||
|
|
||||||
|
class AudioInjector;
|
||||||
|
using AudioInjectorVector = std::vector<QPointer<AudioInjector>>;
|
||||||
|
|
||||||
|
class AudioInjectorManager : public QObject, public Dependency {
|
||||||
|
Q_OBJECT
|
||||||
|
SINGLETON_DEPENDENCY
|
||||||
|
public:
|
||||||
|
~AudioInjectorManager();
|
||||||
|
private slots:
|
||||||
|
void run();
|
||||||
|
private:
|
||||||
|
bool threadInjector(AudioInjector* injector);
|
||||||
|
|
||||||
|
AudioInjectorManager() {};
|
||||||
|
AudioInjectorManager(const AudioInjectorManager&) = delete;
|
||||||
|
AudioInjectorManager& operator=(const AudioInjectorManager&) = delete;
|
||||||
|
|
||||||
|
void createThread();
|
||||||
|
AudioInjectorVector::iterator nextInjectorIterator();
|
||||||
|
|
||||||
|
QThread* _thread { nullptr };
|
||||||
|
bool _shouldStop { false };
|
||||||
|
AudioInjectorVector _injectors;
|
||||||
|
std::mutex _injectorsMutex;
|
||||||
|
|
||||||
|
friend class AudioInjector;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // hifi_AudioInjectorManager_h
|
Loading…
Reference in a new issue