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