From db8661f1524548cefb1c9e867af2783c2c11f305 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Tue, 17 Dec 2013 14:13:23 -0800 Subject: [PATCH 01/16] add a stubbed AudioInjectionManager --- libraries/audio/src/AudioInjectionManager.cpp | 9 +++++++++ libraries/audio/src/AudioInjectionManager.h | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 libraries/audio/src/AudioInjectionManager.cpp create mode 100644 libraries/audio/src/AudioInjectionManager.h diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp new file mode 100644 index 0000000000..79ad0b4889 --- /dev/null +++ b/libraries/audio/src/AudioInjectionManager.cpp @@ -0,0 +1,9 @@ +// +// AudioInjectionManager.cpp +// hifi +// +// Created by Stephen Birarda on 12/17/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#include "AudioInjectionManager.h" diff --git a/libraries/audio/src/AudioInjectionManager.h b/libraries/audio/src/AudioInjectionManager.h new file mode 100644 index 0000000000..badbdabf95 --- /dev/null +++ b/libraries/audio/src/AudioInjectionManager.h @@ -0,0 +1,18 @@ +// +// AudioInjectionManager.h +// hifi +// +// Created by Stephen Birarda on 12/17/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__AudioInjectionManager__ +#define __hifi__AudioInjectionManager__ + +#include <QtCore/QObject> + +class AudioInjectionManager : public QObject { + +}; + +#endif /* defined(__hifi__AudioInjectionManager__) */ From 589dde5139d0e0ddd7351be7d99c9040e80b1ab5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Tue, 17 Dec 2013 16:07:18 -0800 Subject: [PATCH 02/16] more stubbing of AudioInjectionManager --- libraries/audio/src/AudioInjectionManager.cpp | 8 +++++++- libraries/audio/src/AudioInjectionManager.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp index 79ad0b4889..0e44e61b93 100644 --- a/libraries/audio/src/AudioInjectionManager.cpp +++ b/libraries/audio/src/AudioInjectionManager.cpp @@ -3,7 +3,13 @@ // hifi // // Created by Stephen Birarda on 12/17/2013. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // #include "AudioInjectionManager.h" + +AudioInjectionManager::AudioInjectionManager(QObject* parent) : + QObject(parent) +{ + +} diff --git a/libraries/audio/src/AudioInjectionManager.h b/libraries/audio/src/AudioInjectionManager.h index badbdabf95..47cde76167 100644 --- a/libraries/audio/src/AudioInjectionManager.h +++ b/libraries/audio/src/AudioInjectionManager.h @@ -12,7 +12,7 @@ #include <QtCore/QObject> class AudioInjectionManager : public QObject { - + AudioInjectionManager(QObject* parent = 0); }; #endif /* defined(__hifi__AudioInjectionManager__) */ From eac3b6be65c8648b4155cbcb5704c6033e8fc189 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 12:28:37 -0800 Subject: [PATCH 03/16] add AudioInjector class to pull samples from URL and inject --- interface/src/Audio.cpp | 27 ++++++++++ interface/src/Audio.h | 10 ++-- libraries/audio/src/AbstractAudioInterface.h | 5 +- libraries/audio/src/AudioInjectionManager.cpp | 15 ------ libraries/audio/src/AudioInjectionManager.h | 18 ------- libraries/audio/src/AudioInjector.cpp | 49 +++++++++++++++++++ libraries/audio/src/AudioInjector.h | 31 ++++++++++++ 7 files changed, 118 insertions(+), 37 deletions(-) delete mode 100644 libraries/audio/src/AudioInjectionManager.cpp delete mode 100644 libraries/audio/src/AudioInjectionManager.h create mode 100644 libraries/audio/src/AudioInjector.cpp create mode 100644 libraries/audio/src/AudioInjector.h diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 400ff534df..6d3e415e4f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -458,9 +458,31 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { int16_t ringBufferSamples[NETWORK_BUFFER_LENGTH_SAMPLES_STEREO]; _ringBuffer.readSamples(ringBufferSamples, NETWORK_BUFFER_LENGTH_SAMPLES_STEREO); + // add the next NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL from each QByteArray + // in our _localInjectionByteArrays QVector to the _localInjectedSamples + // add to the output samples whatever is in the _localAudioOutput byte array // that lets this user hear sound effects and loopback (if enabled) + for (int b = 0; b < _localInjectionByteArrays.size(); b++) { + QByteArray audioByteArray = _localInjectionByteArrays.at(b); + + int16_t* byteArraySamples = (int16_t*) audioByteArray.data(); + + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { + _localInjectedSamples[i] = glm::clamp(_localInjectedSamples[i] + byteArraySamples[i], + MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); + } + + // pull out the bytes we just read for outputs + audioByteArray.remove(0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); + + if (audioByteArray.size() == 0) { + // if there isn't anything left to inject from this byte array, remove it from the vector + _localInjectionByteArrays.remove(b); + } + } + for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { ringBufferSamples[i * 2] = glm::clamp(ringBufferSamples[i * 2] + _localInjectedSamples[i], MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); @@ -696,6 +718,11 @@ void Audio::startDrumSound(float volume, float frequency, float duration, float _drumSoundSample = 0; } +void Audio::handleAudioByteArray(const QByteArray& audioByteArray) { + // add this byte array to our QVector + _localInjectionByteArrays.append(audioByteArray); +} + void Audio::renderToolIcon(int screenHeight) { _iconBounds = QRect(ICON_LEFT, screenHeight - BOTTOM_PADDING, ICON_SIZE, ICON_SIZE); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 6eb3cd92f3..ecc864445f 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -15,6 +15,7 @@ #include "InterfaceConfig.h" #include <QtCore/QObject> +#include <QtCore/QVector> #include <QtMultimedia/QAudioFormat> #include <AbstractAudioInterface.h> @@ -31,7 +32,7 @@ class QAudioInput; class QAudioOutput; class QIODevice; -class Audio : public QObject, public AbstractAudioInterface { +class Audio : public AbstractAudioInterface { Q_OBJECT public: // setup for audio I/O @@ -51,7 +52,7 @@ public: virtual void startCollisionSound(float magnitude, float frequency, float noise, float duration, bool flashScreen); virtual void startDrumSound(float volume, float frequency, float duration, float decay); - + float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; } bool getCollisionFlashesScreen() { return _collisionFlashesScreen; } @@ -65,14 +66,17 @@ public slots: void handleAudioInput(); void reset(); + virtual void handleAudioByteArray(const QByteArray& audioByteArray); + private: QByteArray firstInputFrame; QAudioInput* _audioInput; QAudioFormat _desiredInputFormat; QAudioFormat _inputFormat; QIODevice* _inputDevice; - int16_t _localInjectedSamples[NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL]; int _numInputCallbackBytes; + int16_t _localInjectedSamples[NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL]; + QVector<QByteArray> _localInjectionByteArrays; QAudioOutput* _audioOutput; QAudioFormat _desiredOutputFormat; QAudioFormat _outputFormat; diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 3662572a9a..26e2ebe997 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -10,10 +10,13 @@ #ifndef __hifi__AbstractAudioInterface__ #define __hifi__AbstractAudioInterface__ -class AbstractAudioInterface { +class AbstractAudioInterface : public QObject { + Q_OBJECT 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 void handleAudioByteArray(const QByteArray& audioByteArray) = 0; }; #endif /* defined(__hifi__AbstractAudioInterface__) */ \ No newline at end of file diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp deleted file mode 100644 index 0e44e61b93..0000000000 --- a/libraries/audio/src/AudioInjectionManager.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// AudioInjectionManager.cpp -// hifi -// -// Created by Stephen Birarda on 12/17/2013. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// - -#include "AudioInjectionManager.h" - -AudioInjectionManager::AudioInjectionManager(QObject* parent) : - QObject(parent) -{ - -} diff --git a/libraries/audio/src/AudioInjectionManager.h b/libraries/audio/src/AudioInjectionManager.h deleted file mode 100644 index 47cde76167..0000000000 --- a/libraries/audio/src/AudioInjectionManager.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// AudioInjectionManager.h -// hifi -// -// Created by Stephen Birarda on 12/17/2013. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// - -#ifndef __hifi__AudioInjectionManager__ -#define __hifi__AudioInjectionManager__ - -#include <QtCore/QObject> - -class AudioInjectionManager : public QObject { - AudioInjectionManager(QObject* parent = 0); -}; - -#endif /* defined(__hifi__AudioInjectionManager__) */ diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp new file mode 100644 index 0000000000..05cf34e765 --- /dev/null +++ b/libraries/audio/src/AudioInjector.cpp @@ -0,0 +1,49 @@ +// +// AudioInjector.cpp +// hifi +// +// Created by Stephen Birarda on 12/19/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#include <QtNetwork/QNetworkAccessManager> +#include <QtNetwork/QNetworkReply> +#include <QtNetwork/QNetworkRequest> + +#include "AbstractAudioInterface.h" + +#include "AudioInjector.h" + +AudioInjector::AudioInjector(const QUrl& sampleURL, QObject* parent) : + QObject(parent) +{ + // assume we have a QApplication or QCoreApplication instance and use the + // QNetworkAccess manager to grab the raw audio file at the given URL + + QNetworkAccessManager *manager = new QNetworkAccessManager(this); + connect(manager, SIGNAL(finished(QNetworkReply*)), + this, SLOT(replyFinished(QNetworkReply*))); + + manager->get(QNetworkRequest(sampleURL)); +} + +void AudioInjector::replyFinished(QNetworkReply* reply) { + // replace our samples array with the downloaded data + _sampleByteArray = reply->readAll(); +} + +void AudioInjector::injectViaThread(AbstractAudioInterface* localAudioInterface) { + // make sure we actually have samples downloaded to inject + if (_sampleByteArray.size()) { + // give our sample byte array to the local audio interface, if we have it, so it can be handled locally + if (localAudioInterface) { + // assume that localAudioInterface could be on a separate thread + QMetaObject::invokeMethod(localAudioInterface, "handleAudioByteArray", + Qt::QueuedConnection, + Q_ARG(QByteArray, _sampleByteArray)); + + } + + // setup a new thread we can use for the injection + } +} \ No newline at end of file diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h new file mode 100644 index 0000000000..2d8109289b --- /dev/null +++ b/libraries/audio/src/AudioInjector.h @@ -0,0 +1,31 @@ +// +// AudioInjector.h +// hifi +// +// Created by Stephen Birarda on 12/19/2013. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. +// + +#ifndef __hifi__AudioInjector__ +#define __hifi__AudioInjector__ + +#include <QtCore/QObject> + +class AbstractAudioInterface; +class QNetworkReply; + +class AudioInjector : public QObject { + Q_OBJECT +public: + AudioInjector(const QUrl& sampleURL, QObject* parent = 0); + ~AudioInjector(); + + void injectViaThread(AbstractAudioInterface* localAudioInterface = NULL); + +private: + QByteArray _sampleByteArray; +private slots: + void replyFinished(QNetworkReply* reply); +}; + +#endif /* defined(__hifi__AudioInjector__) */ From b035f74f94afd10d808b94a5b1c8101a6bfea07a Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 12:39:57 -0800 Subject: [PATCH 04/16] fix for build busters with changed AbstractAudioInterface --- interface/src/Audio.cpp | 20 +++++++++++++------- libraries/audio/src/AbstractAudioInterface.h | 4 ++++ libraries/audio/src/AudioInjector.h | 1 - 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 6d3e415e4f..429b0ec66a 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -42,7 +42,7 @@ static const int ICON_LEFT = 20; static const int BOTTOM_PADDING = 110; Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples, QObject* parent) : - QObject(parent), + AbstractAudioInterface(parent), _audioInput(NULL), _desiredInputFormat(), _inputFormat(), @@ -469,17 +469,23 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { int16_t* byteArraySamples = (int16_t*) audioByteArray.data(); - for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { + int samplesToRead = MIN(audioByteArray.size() / sizeof(int16_t), + NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + + for (int i = 0; i < samplesToRead; i++) { _localInjectedSamples[i] = glm::clamp(_localInjectedSamples[i] + byteArraySamples[i], MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); } - // pull out the bytes we just read for outputs - audioByteArray.remove(0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL); - - if (audioByteArray.size() == 0) { - // if there isn't anything left to inject from this byte array, remove it from the vector + if (samplesToRead < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL) { + // there isn't anything left to inject from this byte array, remove it from the vector _localInjectionByteArrays.remove(b); + } else { + // pull out the bytes we just read for outputs + audioByteArray.remove(0, samplesToRead * sizeof(int16_t)); + + // still data left to read - replace the byte array in the QVector with the smaller one + _localInjectionByteArrays.replace(b, audioByteArray); } } diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index 26e2ebe997..d2cb0c3360 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -10,9 +10,13 @@ #ifndef __hifi__AbstractAudioInterface__ #define __hifi__AbstractAudioInterface__ +#include <QtCore/QObject> + class AbstractAudioInterface : public QObject { Q_OBJECT public: + AbstractAudioInterface(QObject* parent = 0) : QObject(parent) {}; + 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: diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 2d8109289b..0a920077f1 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -18,7 +18,6 @@ class AudioInjector : public QObject { Q_OBJECT public: AudioInjector(const QUrl& sampleURL, QObject* parent = 0); - ~AudioInjector(); void injectViaThread(AbstractAudioInterface* localAudioInterface = NULL); From 2409b5f784574279fc66c118b11cb3bda6324fc5 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 13:46:37 -0800 Subject: [PATCH 05/16] complete inital test of AudioInjector API --- assignment-client/src/AssignmentClient.cpp | 3 +- interface/src/Application.cpp | 7 +++++ libraries/audio/src/AbstractAudioInterface.h | 2 ++ libraries/audio/src/AudioInjector.cpp | 29 ++++++++++++++------ libraries/audio/src/AudioInjector.h | 11 +++++++- 5 files changed, 42 insertions(+), 10 deletions(-) diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 17b1b6099e..cc4292ad15 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -22,6 +22,8 @@ const char ASSIGNMENT_CLIENT_TARGET_NAME[] = "assignment-client"; const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000; +int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr"); + AssignmentClient::AssignmentClient(int &argc, char **argv, Assignment::Type requestAssignmentType, const HifiSockAddr& customAssignmentServerSocket, @@ -31,7 +33,6 @@ AssignmentClient::AssignmentClient(int &argc, char **argv, _currentAssignment(NULL) { // register meta type is required for queued invoke method on Assignment subclasses - qRegisterMetaType<HifiSockAddr>("HifiSockAddr"); // set the logging target to the the CHILD_TARGET_NAME Logging::setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 24cdabe772..370d9cda4e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -38,6 +38,7 @@ #include <QFileDialog> #include <QDesktopServices> +#include <AudioInjector.h> #include <NodeTypes.h> #include <Logging.h> #include <OctalCode.h> @@ -1317,6 +1318,12 @@ void Application::timer() { // ask the node list to check in with the domain server NodeList::getInstance()->sendDomainServerCheckIn(); + static AudioInjector testInjector(QUrl("https://dl.dropboxusercontent.com/u/1864924/throw.raw")); + + if (testInjector.size()) { + testInjector.injectViaThread(&_audio); + } + // give the MyAvatar object position to the Profile so it can propagate to the data-server _profile.updatePosition(_myAvatar.getPosition()); } diff --git a/libraries/audio/src/AbstractAudioInterface.h b/libraries/audio/src/AbstractAudioInterface.h index d2cb0c3360..dc3872efd5 100644 --- a/libraries/audio/src/AbstractAudioInterface.h +++ b/libraries/audio/src/AbstractAudioInterface.h @@ -23,4 +23,6 @@ public slots: virtual void handleAudioByteArray(const QByteArray& audioByteArray) = 0; }; +Q_DECLARE_METATYPE(AbstractAudioInterface*) + #endif /* defined(__hifi__AbstractAudioInterface__) */ \ No newline at end of file diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 05cf34e765..9aaa39c84d 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -14,9 +14,18 @@ #include "AudioInjector.h" -AudioInjector::AudioInjector(const QUrl& sampleURL, QObject* parent) : - QObject(parent) +int abstractAudioPointerMeta = qRegisterMetaType<AbstractAudioInterface*>("AbstractAudioInterface*"); + +AudioInjector::AudioInjector(const QUrl& sampleURL) : + _sourceURL(sampleURL) { + // we want to live on our own thread + moveToThread(&_thread); + connect(&_thread, SIGNAL(started()), this, SLOT(startDownload())); + _thread.start(); +} + +void AudioInjector::startDownload() { // assume we have a QApplication or QCoreApplication instance and use the // QNetworkAccess manager to grab the raw audio file at the given URL @@ -24,7 +33,7 @@ AudioInjector::AudioInjector(const QUrl& sampleURL, QObject* parent) : connect(manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*))); - manager->get(QNetworkRequest(sampleURL)); + manager->get(QNetworkRequest(_sourceURL)); } void AudioInjector::replyFinished(QNetworkReply* reply) { @@ -33,17 +42,21 @@ void AudioInjector::replyFinished(QNetworkReply* reply) { } void AudioInjector::injectViaThread(AbstractAudioInterface* localAudioInterface) { + // use Qt::AutoConnection so that this is called on our thread, if appropriate + QMetaObject::invokeMethod(this, "injectAudio", Qt::AutoConnection, Q_ARG(AbstractAudioInterface*, localAudioInterface)); +} + +void AudioInjector::injectAudio(AbstractAudioInterface* localAudioInterface) { + // make sure we actually have samples downloaded to inject if (_sampleByteArray.size()) { // give our sample byte array to the local audio interface, if we have it, so it can be handled locally if (localAudioInterface) { - // assume that localAudioInterface could be on a separate thread + // assume that localAudioInterface could be on a separate thread, use Qt::AutoConnection to handle properly QMetaObject::invokeMethod(localAudioInterface, "handleAudioByteArray", - Qt::QueuedConnection, + Qt::AutoConnection, Q_ARG(QByteArray, _sampleByteArray)); - + } - - // setup a new thread we can use for the injection } } \ No newline at end of file diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 0a920077f1..bbe8301a78 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -10,6 +10,8 @@ #define __hifi__AudioInjector__ #include <QtCore/QObject> +#include <QtCore/QThread> +#include <QtCore/QUrl> class AbstractAudioInterface; class QNetworkReply; @@ -17,14 +19,21 @@ class QNetworkReply; class AudioInjector : public QObject { Q_OBJECT public: - AudioInjector(const QUrl& sampleURL, QObject* parent = 0); + AudioInjector(const QUrl& sampleURL); + int size() const { return _sampleByteArray.size(); } +public slots: void injectViaThread(AbstractAudioInterface* localAudioInterface = NULL); private: QByteArray _sampleByteArray; + QThread _thread; + QUrl _sourceURL; + private slots: + void startDownload(); void replyFinished(QNetworkReply* reply); + void injectAudio(AbstractAudioInterface* localAudioInterface); }; #endif /* defined(__hifi__AudioInjector__) */ From 98e511a71c66f9333269da82fcfdcf23313e6d90 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Thu, 19 Dec 2013 15:16:43 -0800 Subject: [PATCH 06/16] removed extra debug messages --- libraries/particles/src/ParticleTreeElement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/particles/src/ParticleTreeElement.cpp b/libraries/particles/src/ParticleTreeElement.cpp index b7bc89172e..2f59c924fa 100644 --- a/libraries/particles/src/ParticleTreeElement.cpp +++ b/libraries/particles/src/ParticleTreeElement.cpp @@ -128,7 +128,7 @@ bool ParticleTreeElement::containsParticle(const Particle& particle) const { } bool ParticleTreeElement::updateParticle(const Particle& particle) { - const bool wantDebug = true; + const bool wantDebug = false; uint16_t numberOfParticles = _particles.size(); for (uint16_t i = 0; i < numberOfParticles; i++) { if (_particles[i].getID() == particle.getID()) { From bdf8c4b9b206c233fe74d9113eab36d176882f06 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 15:17:03 -0800 Subject: [PATCH 07/16] implement threaded send for AudioInjector --- assignment-client/src/audio/AudioMixer.cpp | 2 - interface/src/Application.cpp | 4 +- libraries/audio/src/AudioInjector.cpp | 96 ++++++++++++++++++- libraries/audio/src/AudioInjector.h | 9 ++ libraries/audio/src/AudioRingBuffer.h | 3 + .../audio/src/InjectedAudioRingBuffer.cpp | 2 + 6 files changed, 112 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 19a592754a..c2c8e618bf 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -53,8 +53,6 @@ const short JITTER_BUFFER_MSECS = 12; const short JITTER_BUFFER_SAMPLES = JITTER_BUFFER_MSECS * (SAMPLE_RATE / 1000.0); -const unsigned int BUFFER_SEND_INTERVAL_USECS = floorf((NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE) * 1000 * 1000); - const char AUDIO_MIXER_LOGGING_TARGET_NAME[] = "audio-mixer"; void attachNewBufferToNode(Node *newNode) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 370d9cda4e..ae71f12fb5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1321,7 +1321,9 @@ void Application::timer() { static AudioInjector testInjector(QUrl("https://dl.dropboxusercontent.com/u/1864924/throw.raw")); if (testInjector.size()) { - testInjector.injectViaThread(&_audio); + testInjector.setPosition(_myAvatar.getHead().getPosition()); + testInjector.setOrientation(_myAvatar.getOrientation()); + testInjector.injectViaThread(); } // give the MyAvatar object position to the Profile so it can propagate to the data-server diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 9aaa39c84d..606c7f37e6 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -6,18 +6,29 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // +#include <sys/time.h> + #include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkReply> #include <QtNetwork/QNetworkRequest> +#include <NodeList.h> +#include <PacketHeaders.h> +#include <SharedUtil.h> +#include <UUID.h> + #include "AbstractAudioInterface.h" +#include "AudioRingBuffer.h" #include "AudioInjector.h" int abstractAudioPointerMeta = qRegisterMetaType<AbstractAudioInterface*>("AbstractAudioInterface*"); AudioInjector::AudioInjector(const QUrl& sampleURL) : - _sourceURL(sampleURL) + _currentSendPosition(0), + _sourceURL(sampleURL), + _position(0,0,0), + _orientation() { // we want to live on our own thread moveToThread(&_thread); @@ -58,5 +69,88 @@ void AudioInjector::injectAudio(AbstractAudioInterface* localAudioInterface) { Q_ARG(QByteArray, _sampleByteArray)); } + + NodeList* nodeList = NodeList::getInstance(); + + // reset the current send position to the beginning + _currentSendPosition = 0; + + // setup the packet for injected audio + unsigned char injectedAudioPacket[MAX_PACKET_SIZE]; + unsigned char* currentPacketPosition = injectedAudioPacket; + + int numBytesPacketHeader = populateTypeAndVersion(injectedAudioPacket, PACKET_TYPE_INJECT_AUDIO); + currentPacketPosition += numBytesPacketHeader; + + // pack the session UUID for this Node + QByteArray rfcSessionUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122(); + memcpy(currentPacketPosition, rfcSessionUUID.constData(), rfcSessionUUID.size()); + currentPacketPosition += rfcSessionUUID.size(); + + // pick a random UUID to use for this stream + QUuid randomStreamUUID; + QByteArray rfcStreamUUID = randomStreamUUID.toRfc4122(); + memcpy(currentPacketPosition, rfcStreamUUID, rfcStreamUUID.size()); + currentPacketPosition += rfcStreamUUID.size(); + + // pack the position for injected audio + memcpy(currentPacketPosition, &_position, sizeof(_position)); + currentPacketPosition += sizeof(_position); + + // pack a zero orientation for injected audio + memcpy(currentPacketPosition, &_orientation, sizeof(_orientation)); + currentPacketPosition += sizeof(_orientation); + + // pack zero for radius + float radius = 0; + memcpy(currentPacketPosition, &radius, sizeof(radius)); + currentPacketPosition += sizeof(radius); + + // pack 255 for attenuation byte + uchar volume = 1; + memcpy(currentPacketPosition, &volume, sizeof(volume)); + currentPacketPosition += sizeof(volume); + + timeval startTime = {}; + gettimeofday(&startTime, NULL); + int nextFrame = 0; + + // loop to send off our audio in NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL byte chunks + while (_currentSendPosition < _sampleByteArray.size()) { + + int bytesToCopy = std::min(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, + _sampleByteArray.size() - _currentSendPosition); + + // copy the next NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL bytes to the packet + memcpy(currentPacketPosition, _sampleByteArray.data() + _currentSendPosition, + bytesToCopy); + + + // grab our audio mixer from the NodeList, if it exists + Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER); + + if (audioMixer && nodeList->getNodeActiveSocketOrPing(audioMixer)) { + // send off this audio packet + nodeList->getNodeSocket().writeDatagram((char*) injectedAudioPacket, + (currentPacketPosition - injectedAudioPacket) + bytesToCopy, + audioMixer->getActiveSocket()->getAddress(), + audioMixer->getActiveSocket()->getPort()); + } + + _currentSendPosition += bytesToCopy; + + // send two packets before the first sleep so the mixer can start playback right away + + if (_currentSendPosition != bytesToCopy && _currentSendPosition < _sampleByteArray.size()) { + // not the first packet and not done + // sleep for the appropriate time + int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); + + if (usecToSleep > 0) { + usleep(usecToSleep); + } + } + } + } } \ No newline at end of file diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index bbe8301a78..37413fda7a 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -13,6 +13,9 @@ #include <QtCore/QThread> #include <QtCore/QUrl> +#include <glm/glm.hpp> +#include <glm/gtx/quaternion.hpp> + class AbstractAudioInterface; class QNetworkReply; @@ -22,13 +25,19 @@ public: AudioInjector(const QUrl& sampleURL); int size() const { return _sampleByteArray.size(); } + + void setPosition(const glm::vec3& position) { _position = position; } + void setOrientation(const glm::quat& orientation) { _orientation = orientation; } public slots: void injectViaThread(AbstractAudioInterface* localAudioInterface = NULL); private: QByteArray _sampleByteArray; + int _currentSendPosition; QThread _thread; QUrl _sourceURL; + glm::vec3 _position; + glm::quat _orientation; private slots: void startDownload(); diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index addad13146..4860b47af2 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -25,6 +25,9 @@ const int NETWORK_BUFFER_LENGTH_SAMPLES_STEREO = NETWORK_BUFFER_LENGTH_BYTES_STE const int NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL = 512; const int NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL = NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL / sizeof(int16_t); +const unsigned int BUFFER_SEND_INTERVAL_USECS = floorf((NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL + / (float) SAMPLE_RATE) * 1000 * 1000); + const short RING_BUFFER_LENGTH_FRAMES = 10; const int MAX_SAMPLE_VALUE = std::numeric_limits<int16_t>::max(); diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index d66a24672a..b089a20b83 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -42,6 +42,8 @@ int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes unsigned int attenuationByte = *(currentBuffer++); _attenuationRatio = attenuationByte / (float) MAX_INJECTOR_VOLUME; + qDebug() << "Copying" << numBytes - (currentBuffer - sourceBuffer) << "for injected ring buffer\n"; + currentBuffer += writeData((char*) currentBuffer, numBytes - (currentBuffer - sourceBuffer)); return currentBuffer - sourceBuffer; From 90a2fd31ef3d774cd73c2b90e2e07e0af8939f02 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Thu, 19 Dec 2013 15:17:29 -0800 Subject: [PATCH 08/16] fixed spacing --- libraries/shared/src/NodeList.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index c7e7a2c3f0..cded2f7d4e 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -118,7 +118,7 @@ void NodeList::timePingReply(const HifiSockAddr& nodeAddress, unsigned char *pac uint64_t othersReplyTime = *(uint64_t*)(dataAt); uint64_t now = usecTimestampNow(); int pingTime = now - ourOriginalTime; - int oneWayFlightTime = pingTime/2; // half of the ping is our one way flight + int oneWayFlightTime = pingTime / 2; // half of the ping is our one way flight // The other node's expected time should be our original time plus the one way flight time // anything other than that is clock skew From 7ed609633afaba09c3323ad6429826845efa2583 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 15:23:31 -0800 Subject: [PATCH 09/16] complete the test injector stub --- interface/src/Application.cpp | 1 - libraries/audio/src/AudioInjector.cpp | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 23c24b1207..eed5c2e503 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1320,7 +1320,6 @@ void Application::timer() { if (testInjector.size()) { testInjector.setPosition(_myAvatar.getHead().getPosition()); - testInjector.setOrientation(_myAvatar.getOrientation()); testInjector.injectViaThread(); } diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 606c7f37e6..b99e352445 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -97,7 +97,7 @@ void AudioInjector::injectAudio(AbstractAudioInterface* localAudioInterface) { memcpy(currentPacketPosition, &_position, sizeof(_position)); currentPacketPosition += sizeof(_position); - // pack a zero orientation for injected audio + // pack our orientation for injected audio memcpy(currentPacketPosition, &_orientation, sizeof(_orientation)); currentPacketPosition += sizeof(_orientation); @@ -107,7 +107,7 @@ void AudioInjector::injectAudio(AbstractAudioInterface* localAudioInterface) { currentPacketPosition += sizeof(radius); // pack 255 for attenuation byte - uchar volume = 1; + uchar volume = 255; memcpy(currentPacketPosition, &volume, sizeof(volume)); currentPacketPosition += sizeof(volume); From 3f4b4178ff7a34ea5adc623a4eb2c06d3840c892 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 15:25:39 -0800 Subject: [PATCH 10/16] remove the test injector code from Application --- interface/src/Application.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eed5c2e503..08ffa436dc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1316,13 +1316,6 @@ void Application::timer() { // ask the node list to check in with the domain server NodeList::getInstance()->sendDomainServerCheckIn(); - static AudioInjector testInjector(QUrl("https://dl.dropboxusercontent.com/u/1864924/throw.raw")); - - if (testInjector.size()) { - testInjector.setPosition(_myAvatar.getHead().getPosition()); - testInjector.injectViaThread(); - } - // give the MyAvatar object position to the Profile so it can propagate to the data-server _profile.updatePosition(_myAvatar.getPosition()); } From 534010347b75b56693e35ba05a34c93465a18e95 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 15:28:10 -0800 Subject: [PATCH 11/16] add a volume setter to the AudioInjector --- libraries/audio/src/AudioInjector.cpp | 2 +- libraries/audio/src/AudioInjector.h | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index b99e352445..2950441f64 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -107,7 +107,7 @@ void AudioInjector::injectAudio(AbstractAudioInterface* localAudioInterface) { currentPacketPosition += sizeof(radius); // pack 255 for attenuation byte - uchar volume = 255; + uchar volume = MAX_INJECTOR_VOLUME * _volume; memcpy(currentPacketPosition, &volume, sizeof(volume)); currentPacketPosition += sizeof(volume); diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 37413fda7a..07b943f1c7 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -19,6 +19,8 @@ class AbstractAudioInterface; class QNetworkReply; +const uchar MAX_INJECTOR_VOLUME = 0xFF; + class AudioInjector : public QObject { Q_OBJECT public: @@ -28,6 +30,7 @@ public: void setPosition(const glm::vec3& position) { _position = position; } void setOrientation(const glm::quat& orientation) { _orientation = orientation; } + void setVolume(float volume) { _volume = std::max(fabsf(volume), 1.0f); } public slots: void injectViaThread(AbstractAudioInterface* localAudioInterface = NULL); @@ -38,6 +41,7 @@ private: QUrl _sourceURL; glm::vec3 _position; glm::quat _orientation; + float _volume; private slots: void startDownload(); From 8681e66ed312250422857019aea308320d510556 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 15:30:33 -0800 Subject: [PATCH 12/16] default to max volume, add a bool flag for loopback --- libraries/audio/src/AudioInjector.cpp | 4 +++- libraries/audio/src/AudioInjector.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 2950441f64..fe7b26e6db 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -28,7 +28,9 @@ AudioInjector::AudioInjector(const QUrl& sampleURL) : _currentSendPosition(0), _sourceURL(sampleURL), _position(0,0,0), - _orientation() + _orientation(), + _volume(1.0f), + _shouldLoopback(false) { // we want to live on our own thread moveToThread(&_thread); diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 07b943f1c7..ae4c923248 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -42,6 +42,7 @@ private: glm::vec3 _position; glm::quat _orientation; float _volume; + bool _shouldLoopback; private slots: void startDownload(); From 80a2bd0844968885165ed8ab1b7b4ae21cfc3cd1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 15:44:04 -0800 Subject: [PATCH 13/16] move _shouldLoopbackForNode to PositionalAudioRingBuffer for access in injector --- assignment-client/src/audio/AudioMixer.cpp | 3 +-- assignment-client/src/audio/AvatarAudioRingBuffer.cpp | 3 +-- assignment-client/src/audio/AvatarAudioRingBuffer.h | 4 ---- libraries/audio/src/AudioInjector.cpp | 4 ++++ libraries/audio/src/AudioInjector.h | 3 ++- libraries/audio/src/InjectedAudioRingBuffer.cpp | 6 ++++++ libraries/audio/src/PositionalAudioRingBuffer.cpp | 3 ++- libraries/audio/src/PositionalAudioRingBuffer.h | 3 +++ libraries/shared/src/PacketHeaders.cpp | 2 +- 9 files changed, 20 insertions(+), 11 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index c2c8e618bf..d8e0580cc9 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -200,8 +200,7 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { PositionalAudioRingBuffer* otherNodeBuffer = otherNodeClientData->getRingBuffers()[i]; if ((*otherNode != *node - || otherNodeBuffer->getType() != PositionalAudioRingBuffer::Microphone - || nodeRingBuffer->shouldLoopbackForNode()) + || otherNodeBuffer->shouldLoopbackForNode()) && otherNodeBuffer->willBeAddedToMix()) { addBufferToMixForListeningNodeWithBuffer(otherNodeBuffer, nodeRingBuffer); } diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp index 584dd319f5..64d71d9836 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.cpp +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.cpp @@ -11,8 +11,7 @@ #include "AvatarAudioRingBuffer.h" AvatarAudioRingBuffer::AvatarAudioRingBuffer() : - PositionalAudioRingBuffer(PositionalAudioRingBuffer::Microphone), - _shouldLoopbackForNode(false) { + PositionalAudioRingBuffer(PositionalAudioRingBuffer::Microphone) { } diff --git a/assignment-client/src/audio/AvatarAudioRingBuffer.h b/assignment-client/src/audio/AvatarAudioRingBuffer.h index 30097f3812..15542383fb 100644 --- a/assignment-client/src/audio/AvatarAudioRingBuffer.h +++ b/assignment-client/src/audio/AvatarAudioRingBuffer.h @@ -18,14 +18,10 @@ public: AvatarAudioRingBuffer(); int parseData(unsigned char* sourceBuffer, int numBytes); - - bool shouldLoopbackForNode() const { return _shouldLoopbackForNode; } private: // disallow copying of AvatarAudioRingBuffer objects AvatarAudioRingBuffer(const AvatarAudioRingBuffer&); AvatarAudioRingBuffer& operator= (const AvatarAudioRingBuffer&); - - bool _shouldLoopbackForNode; }; #endif /* defined(__hifi__AvatarAudioRingBuffer__) */ diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index fe7b26e6db..f0d81230b4 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -95,6 +95,10 @@ void AudioInjector::injectAudio(AbstractAudioInterface* localAudioInterface) { memcpy(currentPacketPosition, rfcStreamUUID, rfcStreamUUID.size()); currentPacketPosition += rfcStreamUUID.size(); + // pack the flag for loopback + memcpy(currentPacketPosition, &_shouldLoopback, sizeof(_shouldLoopback)); + currentPacketPosition += sizeof(_shouldLoopback); + // pack the position for injected audio memcpy(currentPacketPosition, &_position, sizeof(_position)); currentPacketPosition += sizeof(_position); diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index ae4c923248..425ae7477f 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -31,6 +31,7 @@ public: void setPosition(const glm::vec3& position) { _position = position; } void setOrientation(const glm::quat& orientation) { _orientation = orientation; } void setVolume(float volume) { _volume = std::max(fabsf(volume), 1.0f); } + void setShouldLoopback(bool shouldLoopback) { _shouldLoopback = shouldLoopback; } public slots: void injectViaThread(AbstractAudioInterface* localAudioInterface = NULL); @@ -42,7 +43,7 @@ private: glm::vec3 _position; glm::quat _orientation; float _volume; - bool _shouldLoopback; + uchar _shouldLoopback; private slots: void startDownload(); diff --git a/libraries/audio/src/InjectedAudioRingBuffer.cpp b/libraries/audio/src/InjectedAudioRingBuffer.cpp index b089a20b83..3d4d8a1834 100644 --- a/libraries/audio/src/InjectedAudioRingBuffer.cpp +++ b/libraries/audio/src/InjectedAudioRingBuffer.cpp @@ -32,6 +32,12 @@ int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes // push past the UUID for this node and the stream identifier currentBuffer += (NUM_BYTES_RFC4122_UUID * 2); + // pull the loopback flag and set our boolean + uchar shouldLoopback; + memcpy(&shouldLoopback, currentBuffer, sizeof(shouldLoopback)); + currentBuffer += sizeof(shouldLoopback); + _shouldLoopbackForNode = (shouldLoopback == 1); + // use parsePositionalData in parent PostionalAudioRingBuffer class to pull common positional data currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer)); diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index 0b7c26dc7d..4be6b80265 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -19,7 +19,8 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer:: _type(type), _position(0.0f, 0.0f, 0.0f), _orientation(0.0f, 0.0f, 0.0f, 0.0f), - _willBeAddedToMix(false) + _willBeAddedToMix(false), + _shouldLoopbackForNode(false) { } diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index f4ccdc59bb..189ac34058 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -33,6 +33,8 @@ public: bool willBeAddedToMix() const { return _willBeAddedToMix; } void setWillBeAddedToMix(bool willBeAddedToMix) { _willBeAddedToMix = willBeAddedToMix; } + bool shouldLoopbackForNode() const { return _shouldLoopbackForNode; } + PositionalAudioRingBuffer::Type getType() const { return _type; } const glm::vec3& getPosition() const { return _position; } const glm::quat& getOrientation() const { return _orientation; } @@ -46,6 +48,7 @@ protected: glm::vec3 _position; glm::quat _orientation; bool _willBeAddedToMix; + bool _shouldLoopbackForNode; }; #endif /* defined(__hifi__PositionalAudioRingBuffer__) */ diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 07cdbf76fa..ec5e8ee692 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -18,7 +18,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) { case PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO: case PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO: return 2; - + case PACKET_TYPE_HEAD_DATA: return 12; From 0446aeb4d301c3f46529d4d01bc9be097a6a8979 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 15:44:47 -0800 Subject: [PATCH 14/16] loopback injected sound effects to the node by default --- libraries/audio/src/AudioInjector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index f0d81230b4..00c1fa2b21 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -30,7 +30,7 @@ AudioInjector::AudioInjector(const QUrl& sampleURL) : _position(0,0,0), _orientation(), _volume(1.0f), - _shouldLoopback(false) + _shouldLoopback(true) { // we want to live on our own thread moveToThread(&_thread); From 87e5579e527f95f67854ed4dac3ba2b370e5b415 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 15:51:14 -0800 Subject: [PATCH 15/16] reinstate delete for starved but started audio ring buffers --- assignment-client/src/audio/AudioMixerClientData.cpp | 9 ++++----- libraries/audio/src/AudioRingBuffer.h | 2 ++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 4827fbc918..fa171f252d 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -94,11 +94,10 @@ void AudioMixerClientData::pushBuffersAfterFrameSend() { audioBuffer->shiftReadPosition(NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); audioBuffer->setWillBeAddedToMix(false); - } else if (audioBuffer->isStarved()) { - // this was previously the kill for injected audio from a client - // fix when that is added back - // delete audioBuffer; - // _ringBuffers.erase(_ringBuffers.begin() + i); + } else if (audioBuffer->hasStarted() && audioBuffer->isStarved()) { + // this is an empty audio buffer that has starved, safe to delete + delete audioBuffer; + _ringBuffers.erase(_ringBuffers.begin() + i); } } } diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 4860b47af2..0bcd127a2e 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -62,6 +62,8 @@ public: bool isStarved() const { return _isStarved; } void setIsStarved(bool isStarved) { _isStarved = isStarved; } + + bool hasStarted() const { return _hasStarted; } protected: // disallow copying of AudioRingBuffer objects AudioRingBuffer(const AudioRingBuffer&); From a01a17c30ae277d0755539477be8c6cac3b44367 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 19 Dec 2013 17:24:30 -0800 Subject: [PATCH 16/16] hook throw and catch sounds to Hand class ball tests --- interface/src/avatar/Hand.cpp | 20 ++++++++++++++++---- interface/src/avatar/Hand.h | 5 ++++- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index a25fa086de..3dfcc88807 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -53,7 +53,9 @@ Hand::Hand(Avatar* owningAvatar) : _collisionDuration(0), _pitchUpdate(0), _grabDelta(0, 0, 0), - _grabDeltaVelocity(0, 0, 0) + _grabDeltaVelocity(0, 0, 0), + _throwInjector(QUrl("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/throw.raw")), + _catchInjector(QUrl("https://dl.dropboxusercontent.com/u/1864924/hifi-sounds/catch.raw")) { for (int i = 0; i < MAX_HANDS; i++) { _toyBallInHand[i] = false; @@ -61,6 +63,10 @@ Hand::Hand(Avatar* owningAvatar) : _whichBallColor[i] = 0; } _lastControllerButtons = 0; + + // the throw and catch sounds should not loopback, we'll play them locally + _throwInjector.setShouldLoopback(false); + _catchInjector.setShouldLoopback(false); } void Hand::init() { @@ -119,7 +125,10 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f _ballParticleEditHandles[handID] = caughtParticle; caughtParticle = NULL; // Play a catch sound! - app->getAudio()->startDrumSound(1.0, 300, 0.5, 0.05); + _catchInjector.setPosition(targetPosition); + + // inject the catch sound to the mixer and play it locally + _catchInjector.injectViaThread(app->getAudio()); } } @@ -222,8 +231,11 @@ void Hand::simulateToyBall(PalmData& palm, const glm::vec3& fingerTipPosition, f delete _ballParticleEditHandles[handID]; _ballParticleEditHandles[handID] = NULL; - // Play a throw sound - app->getAudio()->startDrumSound(1.0, 3000, 0.5, 0.02); + // move the throw injector to inject from the position of the ball + _throwInjector.setPosition(ballPosition); + + // inject the throw sound and play it locally + _throwInjector.injectViaThread(app->getAudio()); } } diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index d7acba6a3e..884d710381 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -17,6 +17,7 @@ #include <SharedUtil.h> #include <AvatarData.h> +#include <AudioInjector.h> #include <HandData.h> #include <ParticleEditHandle.h> @@ -110,7 +111,9 @@ private: glm::vec3 _grabDelta; glm::vec3 _grabDeltaVelocity; - + + AudioInjector _throwInjector; + AudioInjector _catchInjector; }; #endif