diff --git a/examples/lobby.js b/examples/lobby.js index e6db57bdd5..c921e744f1 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -39,6 +39,7 @@ var ORB_SHIFT = { x: 0, y: -1.4, z: -0.8}; var HELMET_ATTACHMENT_URL = HIFI_PUBLIC_BUCKET + "models/attachments/IronManMaskOnly.fbx" var droneSound = new Sound(HIFI_PUBLIC_BUCKET + "sounds/Lobby/drone.raw") +var currentDrone; function reticlePosition() { var RETICLE_DISTANCE = 1; @@ -90,7 +91,7 @@ function drawLobby() { MyAvatar.attach(HELMET_ATTACHMENT_URL, "Neck", {x: 0, y: 0, z: 0}, Quat.fromPitchYawRollDegrees(0, 0, 0), 1.15); // start the drone sound - Audio.playSound(droneSound, { stereo: true, localOnly: true }); + currentDrone = Audio.playSound(droneSound, { stereo: true, localOnly: true }); } } @@ -121,6 +122,9 @@ function cleanupLobby() { Overlays.deleteOverlay(orbShell); Overlays.deleteOverlay(reticle); + currentDrone.stop(); + currentDrone = null; + panelWall = false; orbShell = false; reticle = false; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 77cfcfd548..d2d5ff2480 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -453,23 +453,22 @@ Application::~Application() { // ask the datagram processing thread to quit and wait until it is done _nodeThread->quit(); _nodeThread->wait(); + + // kill any audio injectors that are still around + AudioScriptingInterface::getInstance().stopAllInjectors(); // stop the audio process QMetaObject::invokeMethod(&_audio, "stop"); - + // ask the audio thread to quit and wait until it is done _audio.thread()->quit(); _audio.thread()->wait(); - - // kill any audio injectors that are still around - AudioScriptingInterface::getInstance().stopAllInjectors(); _octreeProcessor.terminate(); _voxelHideShowThread.terminate(); _voxelEditSender.terminate(); _entityEditSender.terminate(); - VoxelTreeElement::removeDeleteHook(&_voxels); // we don't need to do this processing on shutdown Menu::getInstance()->deleteLater(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8fecb4ee8e..08a29a08ff 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -32,19 +32,21 @@ #include #include +#include + +#include #include #include #include #include #include -#include - -#include "Audio.h" #include "Menu.h" #include "Util.h" #include "PositionalAudioStream.h" +#include "Audio.h" + static const float AUDIO_CALLBACK_MSECS = (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float)SAMPLE_RATE * 1000.0; static const int NUMBER_OF_NOISE_SAMPLE_FRAMES = 300; @@ -1334,17 +1336,33 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } -QIODevice* Audio::newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) { +QIODevice* Audio::newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) { QAudioFormat localFormat = _desiredOutputFormat; localFormat.setChannelCount(isStereo ? 2 : 1); QAudioOutput* localOutput = new QAudioOutput(getNamedAudioDeviceForMode(QAudio::AudioOutput, _outputAudioDeviceName), localFormat, this); localOutput->setBufferSize(numBytes); + localOutput->setVolume(volume); + + // add this to our list of local injected outputs, we will need to clean it up when the injector says it is done + _injectedOutputInterfaces.insert(injector, localOutput); + + connect(injector, &AudioInjector::finished, this, &Audio::cleanupLocalOutputInterface); return localOutput->start(); } +void Audio::cleanupLocalOutputInterface() { + QAudioOutput* outputInterface = _injectedOutputInterfaces.value(sender()); + if (outputInterface) { + qDebug() << "Stopping a QAudioOutput interface since injector" << sender() << "is finished"; + + outputInterface->stop(); + outputInterface->deleteLater(); + } +} + void Audio::renderToolBox(int x, int y, bool boxed) { glEnable(GL_TEXTURE_2D); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 460be0a567..cc404723d8 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -155,7 +155,7 @@ public slots: void selectAudioFilterBassCut(); void selectAudioFilterSmiley(); - virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector); + virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector); void sendDownstreamAudioStatsPacket(); @@ -180,11 +180,11 @@ signals: void processInboundAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); void processLocalAudio(unsigned int sampleTime, const QByteArray& samples, const QAudioFormat& format); +private slots: + void cleanupLocalOutputInterface(); private: void outputFormatChanged(); -private: - QByteArray firstInputFrame; QAudioInput* _audioInput; QAudioFormat _desiredInputFormat; @@ -365,6 +365,8 @@ private: AudioOutputIODevice _audioOutputIODevice; WeakRecorderPointer _recorder; + + QHash _injectedOutputInterfaces; }; diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 5b42108430..104abae554 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -17,6 +17,8 @@ #include "AudioInjectorOptions.h" +class AudioInjector; + class AbstractAudioInterface : public QObject { Q_OBJECT public: @@ -25,7 +27,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen) = 0; virtual void startDrumSound(float volume, float frequency, float duration, float decay) = 0; public slots: - virtual QIODevice* newLocalOutputDevice(bool isStereo, int numBytes, QObject* injector) = 0; + virtual QIODevice* newLocalOutputDevice(bool isStereo, qreal volume, int numBytes, AudioInjector* injector) = 0; }; Q_DECLARE_METATYPE(AbstractAudioInterface*) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index e83cd5350a..a0914ca741 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -36,7 +36,8 @@ AudioInjector::AudioInjector(QObject* parent) : _shouldStop(false), _loudness(0.0f), _isFinished(false), - _currentSendPosition(0) + _currentSendPosition(0), + _localDevice(NULL) { } @@ -67,22 +68,21 @@ void AudioInjector::injectAudio() { } void AudioInjector::injectLocally() { - if (_localAudioInterface) { - - QIODevice* localBuffer = NULL; - + if (_localAudioInterface) { const QByteArray& soundByteArray = _sound->getByteArray(); if (soundByteArray.size() > 0) { QMetaObject::invokeMethod(_localAudioInterface, "newLocalOutputDevice", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QIODevice*, localBuffer), + Q_RETURN_ARG(QIODevice*, _localDevice), Q_ARG(bool, _options.stereo), + Q_ARG(qreal, _options.volume), Q_ARG(int, soundByteArray.size()), - Q_ARG(QObject*, this)); + Q_ARG(AudioInjector*, this)); - if (localBuffer) { + if (_localDevice) { // immediately write the byte array to the local device - qDebug() << "Writing" << localBuffer->write(soundByteArray) << "bytes to local audio device"; + qDebug() << "Writing" << soundByteArray.size() << "bytes to local audio device"; + _localDevice->write(soundByteArray); } else { qDebug() << "AudioInjector::injectLocally did not get a valid QIODevice from _localAudioInterface"; } @@ -220,3 +220,13 @@ void AudioInjector::injectToMixer() { _isFinished = true; emit finished(); } + +void AudioInjector::stop() { + _shouldStop = true; + + if (_localDevice) { + // we're only a local injector, so we can say we are finished and the AbstractAudioInterface should clean us up + _isFinished = true; + emit finished(); + } +} diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 5a0a35d599..98d391e494 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -35,7 +35,7 @@ public: void setLocalAudioInterface(AbstractAudioInterface* localAudioInterface) { _localAudioInterface = localAudioInterface; } public slots: void injectAudio(); - void stop() { _shouldStop = true; } + void stop(); void setOptions(AudioInjectorOptions& options); void setCurrentSendPosition(int currentSendPosition) { _currentSendPosition = currentSendPosition; } float getLoudness(); @@ -53,7 +53,7 @@ private: bool _isFinished; int _currentSendPosition; AbstractAudioInterface* _localAudioInterface; - + QIODevice* _localDevice; }; Q_DECLARE_METATYPE(AudioInjector*)