OboeTester: cleanup pull mechanism in flowgraph

Use external monotonic frameCounter.
Keep vector of input ports for pulling from.
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.cpp
index 207b851..8148195 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.cpp
@@ -22,9 +22,15 @@
 
 /***************************************************************************/
 int32_t AudioProcessorBase::pullData(int64_t framePosition, int32_t numFrames) {
+    int32_t frameCount = numFrames;
     if (framePosition > mLastFramePosition) {
         mLastFramePosition = framePosition;
-        mFramesValid = onProcess(framePosition, numFrames);
+        for (auto &port : mInputPorts) {
+            frameCount = port.get().pullData(framePosition, frameCount);
+        }
+        if (frameCount > 0) {
+            mFramesValid = onProcess(frameCount);
+        }
     }
     return mFramesValid;
 }
@@ -69,10 +75,3 @@
         return mConnected->getBuffer();
     }
 }
-
-/***************************************************************************/
-int32_t AudioSink::pull(int32_t numFrames) {
-    int32_t actualFrames = input.pullData(mFramePosition, numFrames);
-    mFramePosition += actualFrames;
-    return actualFrames;
-}
\ No newline at end of file
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.h b/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.h
index 21bd3ad..fee5093 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/AudioProcessorBase.h
@@ -30,6 +30,7 @@
 #include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
+#include <vector>
 
 // TODO Move these classes into separate files.
 // TODO Maybe remove "Audio" prefix from these class names: AudioProcessorBase to ProcessorNode
@@ -47,6 +48,7 @@
 // If it is too high then we will thrash the caches.
 constexpr int kDefaultBufferSize = 8; // arbitrary
 
+class AudioPort;
 class AudioFloatInputPort;
 
 /***************************************************************************/
@@ -61,11 +63,10 @@
      * Read from the input ports,
      * generate multiple frames of data then write the results to the output ports.
      *
-     * @param framePosition index of first frame to be processed
      * @param numFrames maximum number of frames requested for processing
      * @return number of frames actually processed
      */
-    virtual int32_t onProcess(int64_t framePosition, int32_t numFrames) = 0;
+    virtual int32_t onProcess(int32_t numFrames) = 0;
 
     /**
      * If the framePosition is at or after the last frame position then call onProcess().
@@ -78,15 +79,19 @@
      */
     int32_t pullData(int64_t framePosition, int32_t numFrames);
 
-    virtual void start() {
-        mLastFramePosition = 0;
-    }
+    virtual void start() {}
 
     virtual void stop() {}
 
+    void addInputPort(AudioPort &port) {
+        mInputPorts.push_back(port);
+    }
+
 protected:
     int64_t  mLastFramePosition = -1; // Start at -1 so that the first pull works.
 
+    std::vector<std::reference_wrapper<AudioPort>> mInputPorts;
+
 private:
     int32_t  mFramesValid = 0; // num valid frames in the block
 };
@@ -114,6 +119,8 @@
         return mSamplesPerFrame;
     }
 
+    virtual int32_t pullData(int64_t framePosition, int32_t numFrames) = 0;
+
 protected:
     AudioProcessorBase &mParent;
 
@@ -150,7 +157,6 @@
         return mBuffer.get();
     }
 
-
 private:
     const int32_t    mFramesPerBuffer = 1;
     std::unique_ptr<float[]> mBuffer; // allocated in constructor
@@ -171,14 +177,6 @@
     using AudioFloatBufferPort::getBuffer;
 
     /**
-     * Call the parent module's onProcess() method.
-     * That may pull data from its inputs and recursively
-     * process the entire graph.
-     * @return number of frames actually pulled
-     */
-    int32_t pullData(int64_t framePosition, int32_t numFrames);
-
-    /**
      * Connect to the input of another module.
      * An input port can only have one connection.
      * An output port can have multiple connections.
@@ -195,6 +193,15 @@
      * This not thread safe.
      */
     void disconnect(AudioFloatInputPort *port);
+
+    /**
+     * Call the parent module's onProcess() method.
+     * That may pull data from its inputs and recursively
+     * process the entire graph.
+     * @return number of frames actually pulled
+     */
+    int32_t pullData(int64_t framePosition, int32_t numFrames) override;
+
 };
 
 /***************************************************************************/
@@ -208,6 +215,8 @@
 public:
     AudioFloatInputPort(AudioProcessorBase &parent, int32_t samplesPerFrame)
             : AudioFloatBufferPort(parent, samplesPerFrame) {
+        // Add to parent so it can pull data from each input.
+        parent.addInputPort(*this);
     }
 
     virtual ~AudioFloatInputPort() = default;
@@ -221,11 +230,6 @@
     float *getBuffer() override;
 
     /**
-     * Pull data from any output port that is connected.
-     */
-    int32_t pullData(int64_t framePosition, int32_t numFrames);
-
-    /**
      * Write every value of the float buffer.
      * This value will be ignored if an output port is connected
      * to this port.
@@ -259,6 +263,11 @@
         mConnected = nullptr;
     }
 
+    /**
+     * Pull data from any output port that is connected.
+     */
+    int32_t pullData(int64_t framePosition, int32_t numFrames) override;
+
 private:
     AudioFloatOutputPort *mConnected = nullptr;
 };
@@ -318,23 +327,15 @@
     /**
      * Dummy processor. The work happens in the read() method.
      *
-     * @param framePosition index of first frame to be processed
      * @param numFrames
      * @return number of frames actually processed
      */
-    int32_t onProcess(int64_t framePosition, int32_t numFrames) override {
-        (void) framePosition;
-        (void) numFrames;
-        return 0;
+    int32_t onProcess(int32_t numFrames) override {
+        return numFrames;
     };
 
-    virtual int32_t read(void *data, int32_t numFrames) = 0;
+    virtual int32_t read(int64_t framePosition, void *data, int32_t numFrames) = 0;
 
-protected:
-    int32_t pull(int32_t numFrames);
-
-private:
-    int64_t mFramePosition = 0;
 };
 
 } /* namespace flowgraph */
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.cpp
index 1f51085..faa95ad 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.cpp
@@ -26,15 +26,14 @@
         , output(*this, channelCount) {
 }
 
-int32_t ClipToRange::onProcess(int64_t framePosition, int32_t numFrames) {
-    int32_t framesToProcess = input.pullData(framePosition, numFrames);
+int32_t ClipToRange::onProcess(int32_t numFrames) {
     const float *inputBuffer = input.getBuffer();
     float *outputBuffer = output.getBuffer();
 
-    int32_t numSamples = framesToProcess * output.getSamplesPerFrame();
+    int32_t numSamples = numFrames * output.getSamplesPerFrame();
     for (int32_t i = 0; i < numSamples; i++) {
         *outputBuffer++ = std::min(mMaximum, std::max(mMinimum, *inputBuffer++));
     }
 
-    return framesToProcess;
+    return numFrames;
 }
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.h b/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.h
index 9eef254..99b3a95 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ClipToRange.h
@@ -36,7 +36,7 @@
 
     virtual ~ClipToRange() = default;
 
-    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+    int32_t onProcess(int32_t numFrames) override;
 
     void setMinimum(float min) {
         mMinimum = min;
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.cpp
index 2c3a542..a42ee22 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.cpp
@@ -23,13 +23,7 @@
         : OscillatorBase() {
 }
 
-int32_t ImpulseOscillator::onProcess(
-        int64_t framePosition,
-        int numFrames) {
-
-    frequency.pullData(framePosition, numFrames);
-    amplitude.pullData(framePosition, numFrames);
-
+int32_t ImpulseOscillator::onProcess(int numFrames) {
     const float *frequencies = frequency.getBuffer();
     const float *amplitudes = amplitude.getBuffer();
     float *buffer = output.getBuffer();
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.h
index 2492c1f..4a3e161 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ImpulseOscillator.h
@@ -33,9 +33,7 @@
 public:
     ImpulseOscillator();
 
-    int32_t onProcess(
-            int64_t framePosition,
-            int numFrames) override;
+    int32_t onProcess(int numFrames) override;
 };
 
 #endif //NATIVEOBOE_IMPULSE_GENERATOR_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.cpp
index 8ffd2dd..f51384c 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.cpp
@@ -28,15 +28,9 @@
     }
 }
 
-int32_t ManyToMultiConverter::onProcess(
-        int64_t framePosition,
-        int numFrames) {
+int32_t ManyToMultiConverter::onProcess(int32_t numFrames) {
     int32_t channelCount = output.getSamplesPerFrame();
 
-    for (int i = 0; i < channelCount; i++) {
-        inputs[i]->pullData(framePosition, numFrames);
-    }
-
     for (int ch = 0; ch < channelCount; ch++) {
         const float *inputBuffer = inputs[ch]->getBuffer();
         float *outputBuffer = output.getBuffer() + ch;
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.h b/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.h
index d2f39a3..1773bbf 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/ManyToMultiConverter.h
@@ -32,9 +32,7 @@
 
     virtual ~ManyToMultiConverter() = default;
 
-    int32_t onProcess(
-            int64_t framePosition,
-            int numFrames) override;
+    int32_t onProcess(int numFrames) override;
 
     void setEnabled(bool enabled) {};
 
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.cpp
index a63c7b1..93321a2 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.cpp
@@ -28,20 +28,18 @@
 
 MonoToMultiConverter::~MonoToMultiConverter() { }
 
-int32_t MonoToMultiConverter::onProcess(int64_t framePosition, int32_t numFrames) {
-    int32_t framesToProcess = input.pullData(framePosition, numFrames);
-
+int32_t MonoToMultiConverter::onProcess(int32_t numFrames) {
     const float *inputBuffer = input.getBuffer();
     float *outputBuffer = output.getBuffer();
     int32_t channelCount = output.getSamplesPerFrame();
     // TODO maybe move to audio_util as audio_mono_to_multi()
-    for (int i = 0; i < framesToProcess; i++) {
+    for (int i = 0; i < numFrames; i++) {
         // read one, write many
         float sample = *inputBuffer++;
         for (int channel = 0; channel < channelCount; channel++) {
             *outputBuffer++ = sample;
         }
     }
-    return framesToProcess;
+    return numFrames;
 }
 
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.h b/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.h
index 0a1eb4f..21972a7 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/MonoToMultiConverter.h
@@ -34,7 +34,7 @@
 
     virtual ~MonoToMultiConverter();
 
-    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+    int32_t onProcess(int32_t numFrames) override;
 
     AudioFloatInputPort input;
     AudioFloatOutputPort output;
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.cpp
index 7403a5c..b93237a 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.cpp
@@ -39,8 +39,7 @@
     return mLevelTo - (mRemaining * mScaler);
 }
 
-int32_t RampLinear::onProcess(int64_t framePosition, int32_t numFrames) {
-    int32_t framesToProcess = input.pullData(framePosition, numFrames);
+int32_t RampLinear::onProcess(int32_t numFrames) {
     const float *inputBuffer = input.getBuffer();
     float *outputBuffer = output.getBuffer();
     int32_t channelCount = output.getSamplesPerFrame();
@@ -54,7 +53,7 @@
         mScaler = (mLevelTo - mLevelFrom) / mLengthInFrames; // for interpolation
     }
 
-    int32_t framesLeft = framesToProcess;
+    int32_t framesLeft = numFrames;
 
     if (mRemaining > 0) { // Ramping? This doesn't happen very often.
         int32_t framesToRamp = std::min(framesLeft, mRemaining);
@@ -75,5 +74,5 @@
         *outputBuffer++ = *inputBuffer++ * mLevelTo;
     }
 
-    return framesToProcess;
+    return numFrames;
 }
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.h b/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.h
index 0d5ed10..44debf6 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/RampLinear.h
@@ -39,7 +39,7 @@
 
     virtual ~RampLinear() = default;
 
-    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+    int32_t onProcess(int32_t numFrames) override;
 
     /**
      * This is used for the next ramp.
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.cpp
index 300cdff..ec5bd34 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.cpp
@@ -23,13 +23,7 @@
         : OscillatorBase() {
 }
 
-int32_t SawtoothOscillator::onProcess(
-        int64_t framePosition,
-        int numFrames) {
-
-    frequency.pullData(framePosition, numFrames);
-    amplitude.pullData(framePosition, numFrames);
-
+int32_t SawtoothOscillator::onProcess(int numFrames) {
     const float *frequencies = frequency.getBuffer();
     const float *amplitudes = amplitude.getBuffer();
     float *buffer = output.getBuffer();
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.h
index 6d444ae..97ecb6e 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SawtoothOscillator.h
@@ -30,9 +30,7 @@
 public:
     SawtoothOscillator();
 
-    int32_t onProcess(
-            int64_t framePosition,
-            int numFrames) override;
+    int32_t onProcess(int numFrames) override;
 };
 
 #endif //FLOWGRAPH_SAWTOOTH_OSCILLATOR_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.cpp
index 10de24f..6f3975d 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.cpp
@@ -27,13 +27,7 @@
         : OscillatorBase() {
 }
 
-int32_t SineOscillator::onProcess(
-        int64_t framePosition,
-        int numFrames) {
-
-    frequency.pullData(framePosition, numFrames);
-    amplitude.pullData(framePosition, numFrames);
-
+int32_t SineOscillator::onProcess(int numFrames) {
     const float *frequencies = frequency.getBuffer();
     const float *amplitudes = amplitude.getBuffer();
     float *buffer = output.getBuffer();
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.h
index a7ab8a7..8290bfa 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SineOscillator.h
@@ -28,9 +28,7 @@
 public:
     SineOscillator();
 
-    int32_t onProcess(
-            int64_t framePosition,
-            int numFrames) override;
+    int32_t onProcess(int numFrames) override;
 };
 
 #endif //FLOWGRAPH_SINE_OSCILLATOR_H
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.cpp
index 652fd5f..39d2542 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.cpp
@@ -25,22 +25,23 @@
         : AudioSink(channelCount) {
 }
 
-int32_t SinkFloat::read(void *data, int32_t numFrames) {
+int32_t SinkFloat::read(int64_t framePosition, void *data, int32_t numFrames) {
     float *floatData = (float *) data;
     int32_t channelCount = input.getSamplesPerFrame();
 
     int32_t framesLeft = numFrames;
     while (framesLeft > 0) {
         // Run the graph and pull data through the input port.
-        int32_t framesRead = pull(framesLeft);
-        if (framesRead <= 0) {
+        int32_t framePulled = pullData(framePosition, framesLeft);
+        if (framePulled <= 0) {
             break;
         }
         const float *signal = input.getBuffer();
-        int32_t numSamples = framesRead * channelCount;
+        int32_t numSamples = framePulled * channelCount;
         memcpy(floatData, signal, numSamples * sizeof(float));
         floatData += numSamples;
-        framesLeft -= framesRead;
+        framesLeft -= framePulled;
+        framePosition += framePulled;
     }
     return numFrames - framesLeft;
 }
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.h
index be3fc88..9ff31e9 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkFloat.h
@@ -32,7 +32,7 @@
 public:
     explicit SinkFloat(int32_t channelCount);
 
-    int32_t read(void *data, int32_t numFrames) override;
+    int32_t read(int64_t framePosition, void *data, int32_t numFrames) override;
 
 };
 
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.cpp
index cfacf6d..3cb7b45 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.cpp
@@ -28,14 +28,14 @@
 SinkI16::SinkI16(int32_t channelCount)
         : AudioSink(channelCount) {}
 
-int32_t SinkI16::read(void *data, int32_t numFrames) {
+int32_t SinkI16::read(int64_t framePosition, void *data, int32_t numFrames) {
     int16_t *shortData = (int16_t *) data;
     const int32_t channelCount = input.getSamplesPerFrame();
 
     int32_t framesLeft = numFrames;
     while (framesLeft > 0) {
         // Run the graph and pull data through the input port.
-        int32_t framesRead = pull(framesLeft);
+        int32_t framesRead = pullData(framePosition, framesLeft);
         if (framesRead <= 0) {
             break;
         }
@@ -52,6 +52,7 @@
         }
 #endif
         framesLeft -= framesRead;
+        framePosition += framesRead;
     }
     return numFrames - framesLeft;
 }
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.h
index f861544..faea5ba 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI16.h
@@ -31,7 +31,7 @@
 public:
     explicit SinkI16(int32_t channelCount);
 
-    int32_t read(void *data, int32_t numFrames) override;
+    int32_t read(int64_t framePosition, void *data, int32_t numFrames) override;
 };
 
 } /* namespace flowgraph */
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.cpp
index 410f58c..d2b948c 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.cpp
@@ -30,14 +30,14 @@
 SinkI24::SinkI24(int32_t channelCount)
         : AudioSink(channelCount) {}
 
-int32_t SinkI24::read(void *data, int32_t numFrames) {
+int32_t SinkI24::read(int64_t framePosition, void *data, int32_t numFrames) {
     uint8_t *byteData = (uint8_t *) data;
     const int32_t channelCount = input.getSamplesPerFrame();
 
     int32_t framesLeft = numFrames;
     while (framesLeft > 0) {
         // Run the graph and pull data through the input port.
-        int32_t framesRead = pull(framesLeft);
+        int32_t framesRead = pullData(framePosition, framesLeft);
         if (framesRead <= 0) {
             break;
         }
@@ -61,6 +61,7 @@
         }
 #endif
         framesLeft -= framesRead;
+        framePosition += framesRead;
     }
     return numFrames - framesLeft;
 }
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.h
index 682b16f..93fdadb 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SinkI24.h
@@ -32,7 +32,7 @@
 public:
     explicit SinkI24(int32_t channelCount);
 
-    int32_t read(void *data, int32_t numFrames) override;
+    int32_t read(int64_t framePosition, void *data, int32_t numFrames) override;
 };
 
 } /* namespace flowgraph */
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.cpp
index c36373a..c0900e5 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.cpp
@@ -25,7 +25,7 @@
         : AudioSource(channelCount) {
 }
 
-int32_t SourceFloat::onProcess(int64_t framePosition, int32_t numFrames) {
+int32_t SourceFloat::onProcess(int32_t numFrames) {
 
     float *outputBuffer = output.getBuffer();
     int32_t channelCount = output.getSamplesPerFrame();
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.h
index efede25..b87a27b 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceFloat.h
@@ -31,7 +31,7 @@
 public:
     explicit SourceFloat(int32_t channelCount);
 
-    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+    int32_t onProcess(int32_t numFrames) override;
 };
 
 } /* namespace flowgraph */
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.cpp
index 91a6bc1..9e2ea16 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.cpp
@@ -30,7 +30,7 @@
         : AudioSource(channelCount) {
 }
 
-int32_t SourceI16::onProcess(int64_t framePosition, int32_t numFrames) {
+int32_t SourceI16::onProcess(int32_t numFrames) {
     float *floatData = output.getBuffer();
     int32_t channelCount = output.getSamplesPerFrame();
 
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.h
index 9481e0b..34055c5 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI16.h
@@ -30,7 +30,7 @@
 public:
     explicit SourceI16(int32_t channelCount);
 
-    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+    int32_t onProcess(int32_t numFrames) override;
 };
 
 } /* namespace flowgraph */
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.cpp b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.cpp
index df55c55..6769373 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.cpp
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.cpp
@@ -32,7 +32,7 @@
         : AudioSource(channelCount) {
 }
 
-int32_t SourceI24::onProcess(int64_t framePosition, int32_t numFrames) {
+int32_t SourceI24::onProcess(int32_t numFrames) {
     float *floatData = output.getBuffer();
     int32_t channelCount = output.getSamplesPerFrame();
 
diff --git a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.h b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.h
index c76b82d..9176506 100644
--- a/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.h
+++ b/apps/OboeTester/app/src/main/cpp/flowgraph/SourceI24.h
@@ -31,7 +31,7 @@
 public:
     explicit SourceI24(int32_t channelCount);
 
-    int32_t onProcess(int64_t framePosition, int32_t numFrames) override;
+    int32_t onProcess(int32_t numFrames) override;
 };
 
 } /* namespace flowgraph */