OboeTester: use new flowgraph API with simpler pullData
diff --git a/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp b/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp
index 2a3e204..6d21ebe 100644
--- a/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp
+++ b/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.cpp
@@ -17,7 +17,6 @@
#include <cstring>
#include <sched.h>
-#include "common/OboeDebug.h"
#include "oboe/Oboe.h"
#include "AudioStreamGateway.h"
@@ -31,6 +30,8 @@
{
}
+int64_t AudioStreamGateway::mFramePosition = 0;
+
oboe::DataCallbackResult AudioStreamGateway::onAudioReady(
oboe::AudioStream *audioStream,
void *audioData,
@@ -42,7 +43,8 @@
}
if (mAudioSink != nullptr) {
- mAudioSink->read(audioData, numFrames);
+ mAudioSink->read(mFramePosition, audioData, numFrames);
+ mFramePosition += numFrames;
}
return oboe::DataCallbackResult::Continue;
diff --git a/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h b/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h
index 09d69c6..8eda5d1 100644
--- a/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h
+++ b/apps/OboeTester/app/src/main/cpp/AudioStreamGateway.h
@@ -49,7 +49,10 @@
int getScheduler();
private:
- // TODO uint64_t mFramePosition;
+ // Use a static position so that it will monotonically increase.
+ // Note only one gateway can be used.
+ // TODO remove single gateway limitation. Add Graph class.
+ static int64_t mFramePosition;
bool mSchedulerChecked = false;
int mScheduler;
std::shared_ptr<flowgraph::AudioSink> mAudioSink;
diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
index d3c5ebe..a9e3501 100644
--- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
+++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.cpp
@@ -78,35 +78,35 @@
}
void NativeAudioContext::connectTone() {
- if (monoToMulti != nullptr) {
- LOGI("%s() mToneType = %d", __func__, mToneType);
- switch (mToneType) {
- case ToneType::SawPing:
- sawPingGenerator.output.connect(&(monoToMulti->input));
- monoToMulti->output.connect(&(mSinkFloat.get()->input));
- monoToMulti->output.connect(&(mSinkI16.get()->input));
- break;
- case ToneType::Sine:
- for (int i = 0; i < mChannelCount; i++) {
- sineOscillators[i].output.connect(manyToMulti->inputs[i].get());
- }
- manyToMulti->output.connect(&(mSinkFloat.get()->input));
- manyToMulti->output.connect(&(mSinkI16.get()->input));
- break;
- case ToneType::Impulse:
- impulseGenerator.output.connect(&(monoToMulti->input));
- monoToMulti->output.connect(&(mSinkFloat.get()->input));
- monoToMulti->output.connect(&(mSinkI16.get()->input));
- break;
- case ToneType::Sawtooth:
- for (int i = 0; i < mChannelCount; i++) {
- sawtoothOscillators[i].output.connect(manyToMulti->inputs[i].get());
- }
- manyToMulti->output.connect(&(mSinkFloat.get()->input));
- manyToMulti->output.connect(&(mSinkI16.get()->input));
- break;
- }
- }
+// if (monoToMulti != nullptr) {
+// LOGI("%s() mToneType = %d", __func__, mToneType);
+// switch (mToneType) {
+// case ToneType::SawPing:
+// sawPingGenerator.output.connect(&(monoToMulti->input));
+// monoToMulti->output.connect(&(mSinkFloat.get()->input));
+// monoToMulti->output.connect(&(mSinkI16.get()->input));
+// break;
+// case ToneType::Sine:
+// for (int i = 0; i < mChannelCount; i++) {
+// sineOscillators[i].output.connect(manyToMulti->inputs[i].get());
+// }
+// manyToMulti->output.connect(&(mSinkFloat.get()->input));
+// manyToMulti->output.connect(&(mSinkI16.get()->input));
+// break;
+// case ToneType::Impulse:
+// impulseGenerator.output.connect(&(monoToMulti->input));
+// monoToMulti->output.connect(&(mSinkFloat.get()->input));
+// monoToMulti->output.connect(&(mSinkI16.get()->input));
+// break;
+// case ToneType::Sawtooth:
+// for (int i = 0; i < mChannelCount; i++) {
+// sawtoothOscillators[i].output.connect(manyToMulti->inputs[i].get());
+// }
+// manyToMulti->output.connect(&(mSinkFloat.get()->input));
+// manyToMulti->output.connect(&(mSinkI16.get()->input));
+// break;
+// }
+// }
}
void NativeAudioContext::setChannelEnabled(int channelIndex, bool enabled) {
@@ -191,6 +191,8 @@
// We needed the proxy because we did not know the channelCount when we setup the Builder.
if (useCallback) {
+ LOGD("NativeAudioContext::open() set callback to use oboeCallbackProxy, size = %d",
+ callbackSize);
builder.setCallback(&oboeCallbackProxy);
builder.setFramesPerCallback(callbackSize);
}
@@ -232,9 +234,27 @@
return nullptr;
}
+oboe::AudioStream * NativeAudioContext::getInputStream() {
+ for (int32_t i = 0; i < kMaxStreams; i++) {
+ oboe::AudioStream *oboeStream = mOboeStreams[i];
+ if (oboeStream != nullptr) {
+ if (oboeStream->getDirection() == oboe::Direction::Input) {
+ return oboeStream;
+ }
+ }
+ }
+ return nullptr;
+}
+
void NativeAudioContext::configureForActivityType() {
oboe::AudioStream *outputStream = nullptr;
+ manyToMulti = std::make_unique<ManyToMultiConverter>(mChannelCount);
+ monoToMulti = std::make_unique<MonoToMultiConverter>(mChannelCount);
+
+ mSinkFloat = std::make_unique<SinkFloat>(mChannelCount);
+ mSinkI16 = std::make_unique<SinkI16>(mChannelCount);
+
switch(mActivityType) {
case ActivityType::Undefined:
break;
@@ -258,18 +278,12 @@
sineOscillators[i].frequency.setValue(frequency);
frequency *= 4.0 / 3.0; // each sine is at a higher frequency
sineOscillators[i].amplitude.setValue(AMPLITUDE_SINE);
- }
- for (int i = 0; i < mChannelCount; i++) {
- sawtoothOscillators[i].setSampleRate(outputStream->getSampleRate());
- sawtoothOscillators[i].frequency.setValue(frequency);
- frequency *= 4.0 / 3.0; // each sawtooth is at a higher frequency
- sawtoothOscillators[i].amplitude.setValue(AMPLITUDE_SAWTOOTH);
+ sineOscillators[i].output.connect(manyToMulti->inputs[i].get());
}
}
- impulseGenerator.setSampleRate(outputStream->getSampleRate());
- impulseGenerator.frequency.setValue(440.0);
- impulseGenerator.amplitude.setValue(AMPLITUDE_IMPULSE);
+ manyToMulti->output.connect(&(mSinkFloat.get()->input));
+ manyToMulti->output.connect(&(mSinkI16.get()->input));
break;
case ActivityType::TapToTone:
@@ -277,6 +291,12 @@
sawPingGenerator.setSampleRate(outputStream->getSampleRate());
sawPingGenerator.frequency.setValue(FREQUENCY_SAW_PING);
sawPingGenerator.amplitude.setValue(AMPLITUDE_SAW_PING);
+
+ sawPingGenerator.output.connect(&(monoToMulti->input));
+ monoToMulti->output.connect(&(mSinkFloat.get()->input));
+ monoToMulti->output.connect(&(mSinkI16.get()->input));
+
+ sawPingGenerator.setEnabled(false);
break;
case ActivityType::Echo:
@@ -284,11 +304,9 @@
}
if (outputStream != nullptr) {
- manyToMulti = std::make_unique<ManyToMultiConverter>(mChannelCount);
- monoToMulti = std::make_unique<MonoToMultiConverter>(mChannelCount);
- mSinkFloat = std::make_unique<SinkFloat>(mChannelCount);
- mSinkI16 = std::make_unique<SinkI16>(mChannelCount);
+ mSinkFloat->start();
+ mSinkI16->start();
// We needed the proxy because we did not know the channelCount
// when we setup the Builder.
@@ -299,8 +317,6 @@
audioStreamGateway->setAudioSink(mSinkFloat);
}
- connectTone();
-
if (useCallback) {
oboeCallbackProxy.setCallback(audioStreamGateway.get());
}
@@ -322,6 +338,56 @@
}
}
+oboe::Result NativeAudioContext::start() {
+ oboe::Result result = oboe::Result::OK;
+ oboe::AudioStream *inputStream = getInputStream();
+ oboe::AudioStream *outputStream = getOutputStream();
+ if (inputStream == nullptr && outputStream == nullptr) {
+ return oboe::Result::ErrorInvalidState; // not open
+ }
+
+ stop();
+
+ LOGD("NativeAudioContext: %s() called", __func__);
+ configureForActivityType();
+
+ switch(mActivityType) {
+ case ActivityType::Undefined:
+ break;
+ case ActivityType::TestInput:
+ case ActivityType::RecordPlay:
+ result = inputStream->requestStart();
+ if (!useCallback && result == oboe::Result::OK) {
+ LOGD("start thread for blocking I/O");
+ // Instead of using the callback, start a thread that readsthe stream.
+ threadEnabled.store(true);
+ dataThread = new std::thread(threadCallback, this);
+ }
+ break;
+
+ case ActivityType::TestOutput:
+ case ActivityType::TapToTone:
+ result = outputStream->requestStart();
+ if (!useCallback && result == oboe::Result::OK) {
+ LOGD("start thread for blocking I/O");
+ // Instead of using the callback, start a thread that writes the stream.
+ threadEnabled.store(true);
+ dataThread = new std::thread(threadCallback, this);
+ }
+ break;
+
+ case ActivityType::Echo:
+ inputStream = getInputStream();
+ outputStream = getOutputStream();
+ result = inputStream->requestStart(); // FIXME use full duplex object
+ result = outputStream->requestStart();
+ break;
+ }
+
+ LOGD("OboeAudioStream_start: start returning %d", result);
+ return result;
+}
+
void NativeAudioContext::runBlockingIO() {
int32_t framesPerBlock = getFramesPerBlock();
oboe::DataCallbackResult callbackResult = oboe::DataCallbackResult::Continue;
diff --git a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
index 1fc41be..718ae1c 100644
--- a/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
+++ b/apps/OboeTester/app/src/main/cpp/NativeAudioContext.h
@@ -89,7 +89,7 @@
void setToneType(int toneType) {
LOGI("%s(%d)", __func__, toneType);
mToneType = (ToneType) toneType;
- connectTone();
+ // connectTone();
}
int32_t getFramesPerBlock() {
@@ -103,7 +103,6 @@
}
}
-
oboe::Result pause() {
LOGD("NativeAudioContext::%s() called", __func__);
oboe::Result result = oboe::Result::OK;
@@ -203,61 +202,11 @@
LOGD("%s: exiting", __func__);
}
- oboe::Result start() {
-
- LOGD("NativeAudioContext: %s() called", __func__);
- configureForActivityType();
-
- bool gotOne = false;
- for (int32_t i = 0; i < kMaxStreams; i++) {
- gotOne = (mOboeStreams[i] != nullptr);
- if (gotOne) break;
- }
- if (!gotOne) {
- LOGD("NativeAudioContext: %s() did not find a stream", __func__);
- return oboe::Result::ErrorNull;
- }
-
- stop();
-
- LOGD("NativeAudioContext: %s() start modules", __func__);
- for (int i = 0; i < mChannelCount; i++) {
- sineOscillators[i].start();
- sawtoothOscillators[i].start();
- }
- impulseGenerator.start();
- sawPingGenerator.start();
- if (mSinkFloat) {
- mSinkFloat->start();
- }
- if (mSinkI16) {
- mSinkI16->start();
- }
-
- LOGD("NativeAudioContext: %s start stream", __func__);
- oboe::Result result = oboe::Result::OK;
- for (int32_t i = 0; i < kMaxStreams; i++) {
- oboe::AudioStream *oboeStream = mOboeStreams[i];
- if (oboeStream != nullptr) {
- result = oboeStream->requestStart();
-
- if (!useCallback && result == oboe::Result::OK) {
- LOGD("OboeAudioStream_start: start thread for blocking I/O");
- // Instead of using the callback, start a thread that reads or writes the stream. // FIXME
- threadEnabled.store(true);
- dataThread = new std::thread(threadCallback, this);
- }
- }
- }
- LOGD("OboeAudioStream_start: start returning %d", result);
- return result;
- }
+ oboe::Result start();
void setToneEnabled(bool enabled) {
LOGD("%s(%d)", __func__, enabled ? 1 : 0);
- // sineGenerator.setEnabled(enabled); // not needed
sawPingGenerator.setEnabled(enabled);
- // impulseGenerator.setEnabled(enabled); // not needed
}
void setAmplitude(double amplitude) {
@@ -310,6 +259,7 @@
Echo = 4
};
+ oboe::AudioStream * getInputStream();
oboe::AudioStream * getOutputStream();
int32_t allocateStreamIndex();
diff --git a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp
index be08e78..6e3156a 100644
--- a/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp
+++ b/apps/OboeTester/app/src/main/cpp/OboeStreamCallbackProxy.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "common/OboeDebug.h"
#include "OboeStreamCallbackProxy.h"
OboeStreamCallbackProxy::~OboeStreamCallbackProxy() {
@@ -30,6 +31,8 @@
if (mCallback != nullptr) {
return mCallback->onAudioReady(audioStream, audioData, numFrames);
}
+ LOGD("OboeStreamCallbackProxy: %s() called", __func__);
+// memset(audioData, 0, numFrames * audioStream->getChannelCount() * audioStream->getBytesPerSample()); // FIXME
return oboe::DataCallbackResult::Stop;
}
diff --git a/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp b/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp
index 22c80f9..64c2323 100644
--- a/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp
+++ b/apps/OboeTester/app/src/main/cpp/SawPingGenerator.cpp
@@ -31,12 +31,7 @@
SawPingGenerator::~SawPingGenerator() { }
-int32_t SawPingGenerator::onProcess(
- int64_t framePosition,
- int numFrames) {
-
- frequency.pullData(framePosition, numFrames);
- amplitude.pullData(framePosition, numFrames);
+int32_t SawPingGenerator::onProcess(int numFrames) {
const float *frequencies = frequency.getBuffer();
const float *amplitudes = amplitude.getBuffer();
@@ -69,6 +64,8 @@
LOGD("%s(%d)", __func__, enabled ? 1 : 0);
if (enabled) {
mRequestCount++;
+ } else {
+ mAcknowledgeCount.store(mRequestCount.load());
}
}
diff --git a/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h b/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h
index 05bb745..49bfc2e 100644
--- a/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h
+++ b/apps/OboeTester/app/src/main/cpp/SawPingGenerator.h
@@ -30,17 +30,10 @@
virtual ~SawPingGenerator();
- int32_t onProcess(
- int64_t framePosition,
- int numFrames) override;
+ int32_t onProcess(int numFrames) override;
void setEnabled(bool enabled);
- void start() override {
- OscillatorBase::start();
- mAcknowledgeCount.store(mRequestCount.load());
- }
-
private:
std::atomic<int> mRequestCount; // external thread increments this to request a beep
std::atomic<int> mAcknowledgeCount; // audio thread sets this to acknowledge