aboutsummaryrefslogtreecommitdiff
path: root/externals/oboe/samples/hello-oboe/src/main/cpp
diff options
context:
space:
mode:
authorswurl <swurl@swurl.xyz>2025-05-31 02:33:02 -0400
committerswurl <swurl@swurl.xyz>2025-05-31 02:33:02 -0400
commit6c655321e6b04b8648802e296bb5ca11d290ae68 (patch)
tree5c906511e4a2910ce8b806bb9d763b524c28619e /externals/oboe/samples/hello-oboe/src/main/cpp
parentc0cceff365f754f8859f4c9a0362ebdba7ea388b (diff)
Move dead submodules in-tree
Signed-off-by: swurl <swurl@swurl.xyz>
Diffstat (limited to 'externals/oboe/samples/hello-oboe/src/main/cpp')
-rw-r--r--externals/oboe/samples/hello-oboe/src/main/cpp/CMakeLists.txt60
-rw-r--r--externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp175
-rw-r--r--externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h95
-rw-r--r--externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.cpp45
-rw-r--r--externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.h67
-rw-r--r--externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.cpp51
-rw-r--r--externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.h58
-rw-r--r--externals/oboe/samples/hello-oboe/src/main/cpp/jni_bridge.cpp90
8 files changed, 641 insertions, 0 deletions
diff --git a/externals/oboe/samples/hello-oboe/src/main/cpp/CMakeLists.txt b/externals/oboe/samples/hello-oboe/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000000..48fc94ef5e
--- /dev/null
+++ b/externals/oboe/samples/hello-oboe/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,60 @@
+#
+# Copyright 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+cmake_minimum_required(VERSION 3.4.1)
+
+### INCLUDE OBOE LIBRARY ###
+
+# Set the path to the Oboe library directory
+set (OBOE_DIR ../../../../../)
+
+# Add the Oboe library as a subproject. Since Oboe is an out-of-tree source library we must also
+# specify a binary directory
+add_subdirectory(${OBOE_DIR} ./oboe-bin)
+
+# Include the Oboe headers and shared sample code
+include_directories(${OBOE_DIR}/include ${OBOE_DIR}/samples/shared)
+
+# Debug utilities
+set (DEBUG_UTILS_PATH "${OBOE_DIR}/samples/debug-utils")
+set (DEBUG_UTILS_SOURCES ${DEBUG_UTILS_PATH}/trace.cpp)
+include_directories(${DEBUG_UTILS_PATH})
+
+
+### END OBOE INCLUDE SECTION ###
+
+
+# App specific sources
+set (APP_SOURCES
+ jni_bridge.cpp
+ HelloOboeEngine.cpp
+ SoundGenerator.cpp
+ LatencyTuningCallback.cpp
+)
+
+# Build the libhello-oboe library
+add_library(hello-oboe SHARED
+ ${DEBUG_UTILS_SOURCES}
+ ${APP_SOURCES}
+ )
+
+# Specify the libraries needed for hello-oboe
+target_link_libraries(hello-oboe android log oboe)
+target_link_options(hello-oboe PRIVATE "-Wl,-z,max-page-size=16384")
+
+# Enable optimization flags: if having problems with source level debugging,
+# disable -Ofast ( and debug ), re-enable after done debugging.
+target_compile_options(hello-oboe PRIVATE -Wall -Werror "$<$<CONFIG:RELEASE>:-Ofast>")
diff --git a/externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp b/externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp
new file mode 100644
index 0000000000..c27d5a419c
--- /dev/null
+++ b/externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.cpp
@@ -0,0 +1,175 @@
+/**
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#include <inttypes.h>
+#include <memory>
+
+#include <Oscillator.h>
+
+#include "HelloOboeEngine.h"
+#include "SoundGenerator.h"
+
+
+/**
+ * Main audio engine for the HelloOboe sample. It is responsible for:
+ *
+ * - Creating a callback object which is supplied when constructing the audio stream, and will be
+ * called when the stream starts
+ * - Restarting the stream when user-controllable properties (Audio API, channel count etc) are
+ * changed, and when the stream is disconnected (e.g. when headphones are attached)
+ * - Calculating the audio latency of the stream
+ *
+ */
+HelloOboeEngine::HelloOboeEngine()
+ : mLatencyCallback(std::make_shared<LatencyTuningCallback>()),
+ mErrorCallback(std::make_shared<DefaultErrorCallback>(*this)) {
+}
+
+double HelloOboeEngine::getCurrentOutputLatencyMillis() {
+ if (!mIsLatencyDetectionSupported) return -1.0;
+
+ std::lock_guard<std::mutex> lock(mLock);
+ if (!mStream) return -1.0;
+
+ oboe::ResultWithValue<double> latencyResult = mStream->calculateLatencyMillis();
+ if (latencyResult) {
+ return latencyResult.value();
+ } else {
+ LOGE("Error calculating latency: %s", oboe::convertToText(latencyResult.error()));
+ return -1.0;
+ }
+}
+
+void HelloOboeEngine::setBufferSizeInBursts(int32_t numBursts) {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (!mStream) return;
+
+ mLatencyCallback->setBufferTuneEnabled(numBursts == kBufferSizeAutomatic);
+ auto result = mStream->setBufferSizeInFrames(
+ numBursts * mStream->getFramesPerBurst());
+ if (result) {
+ LOGD("Buffer size successfully changed to %d", result.value());
+ } else {
+ LOGW("Buffer size could not be changed, %d", result.error());
+ }
+}
+
+bool HelloOboeEngine::isLatencyDetectionSupported() {
+ return mIsLatencyDetectionSupported;
+}
+
+bool HelloOboeEngine::isAAudioRecommended() {
+ return oboe::AudioStreamBuilder::isAAudioRecommended();
+}
+
+void HelloOboeEngine::tap(bool isDown) {
+ if (mAudioSource) {
+ mAudioSource->tap(isDown);
+ }
+}
+
+oboe::Result HelloOboeEngine::openPlaybackStream() {
+ oboe::AudioStreamBuilder builder;
+ oboe::Result result = builder.setSharingMode(oboe::SharingMode::Exclusive)
+ ->setPerformanceMode(oboe::PerformanceMode::LowLatency)
+ ->setFormat(oboe::AudioFormat::Float)
+ ->setFormatConversionAllowed(true)
+ ->setDataCallback(mLatencyCallback)
+ ->setErrorCallback(mErrorCallback)
+ ->setAudioApi(mAudioApi)
+ ->setChannelCount(mChannelCount)
+ ->setDeviceId(mDeviceId)
+ ->openStream(mStream);
+ if (result == oboe::Result::OK) {
+ mChannelCount = mStream->getChannelCount();
+ }
+ return result;
+}
+
+void HelloOboeEngine::restart() {
+ // The stream will have already been closed by the error callback.
+ mLatencyCallback->reset();
+ start();
+}
+
+oboe::Result HelloOboeEngine::start(oboe::AudioApi audioApi, int deviceId, int channelCount) {
+ mAudioApi = audioApi;
+ mDeviceId = deviceId;
+ mChannelCount = channelCount;
+ return start();
+}
+
+oboe::Result HelloOboeEngine::start() {
+ std::lock_guard<std::mutex> lock(mLock);
+ oboe::Result result = oboe::Result::OK;
+ // It is possible for a stream's device to become disconnected during the open or between
+ // the Open and the Start.
+ // So if it fails to start, close the old stream and try again.
+ int tryCount = 0;
+ do {
+ if (tryCount > 0) {
+ usleep(20 * 1000); // Sleep between tries to give the system time to settle.
+ }
+ mIsLatencyDetectionSupported = false;
+ result = openPlaybackStream();
+ if (result == oboe::Result::OK) {
+ mAudioSource = std::make_shared<SoundGenerator>(mStream->getSampleRate(),
+ mStream->getChannelCount());
+ mLatencyCallback->setSource(
+ std::dynamic_pointer_cast<IRenderableAudio>(mAudioSource));
+
+ LOGD("Stream opened: AudioAPI = %d, channelCount = %d, deviceID = %d",
+ mStream->getAudioApi(),
+ mStream->getChannelCount(),
+ mStream->getDeviceId());
+
+ result = mStream->requestStart();
+ if (result != oboe::Result::OK) {
+ LOGE("Error starting playback stream. Error: %s", oboe::convertToText(result));
+ mStream->close();
+ mStream.reset();
+ } else {
+ mIsLatencyDetectionSupported = (mStream->getTimestamp((CLOCK_MONOTONIC)) !=
+ oboe::Result::ErrorUnimplemented);
+ }
+ } else {
+ LOGE("Error creating playback stream. Error: %s", oboe::convertToText(result));
+ }
+ } while (result != oboe::Result::OK && tryCount++ < 3);
+ return result;
+}
+
+oboe::Result HelloOboeEngine::stop() {
+ oboe::Result result = oboe::Result::OK;
+ // Stop, close and delete in case not already closed.
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mStream) {
+ result = mStream->stop();
+ mStream->close();
+ mStream.reset();
+ }
+ return result;
+}
+
+oboe::Result HelloOboeEngine::reopenStream() {
+ if (mStream) {
+ stop();
+ return start();
+ } else {
+ return oboe::Result::OK;
+ }
+}
diff --git a/externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h b/externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h
new file mode 100644
index 0000000000..ea535b15ef
--- /dev/null
+++ b/externals/oboe/samples/hello-oboe/src/main/cpp/HelloOboeEngine.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef OBOE_HELLO_OBOE_ENGINE_H
+#define OBOE_HELLO_OBOE_ENGINE_H
+
+#include <oboe/Oboe.h>
+
+#include "SoundGenerator.h"
+#include "LatencyTuningCallback.h"
+#include "IRestartable.h"
+#include "DefaultErrorCallback.h"
+
+constexpr int32_t kBufferSizeAutomatic = 0;
+
+class HelloOboeEngine : public IRestartable {
+
+public:
+ HelloOboeEngine();
+
+ virtual ~HelloOboeEngine() = default;
+
+ void tap(bool isDown);
+
+ /**
+ * Open and start a stream.
+ * @param deviceId the audio device id, can be obtained through an {@link AudioDeviceInfo} object
+ * using Java/JNI.
+ * @return error or OK
+ */
+ oboe::Result start(oboe::AudioApi audioApi, int deviceId, int channelCount);
+ /* Start using current settings. */
+ oboe::Result start();
+
+ /**
+ * Stop and close the stream.
+ */
+ oboe::Result stop();
+
+ // From IRestartable
+ void restart() override;
+
+ void setBufferSizeInBursts(int32_t numBursts);
+
+ /**
+ * Calculate the current latency between writing a frame to the output stream and
+ * the same frame being presented to the audio hardware.
+ *
+ * Here's how the calculation works:
+ *
+ * 1) Get the time a particular frame was presented to the audio hardware
+ * @see AudioStream::getTimestamp
+ * 2) From this extrapolate the time which the *next* audio frame written to the stream
+ * will be presented
+ * 3) Assume that the next audio frame is written at the current time
+ * 4) currentLatency = nextFramePresentationTime - nextFrameWriteTime
+ *
+ * @return Output Latency in Milliseconds
+ */
+ double getCurrentOutputLatencyMillis();
+
+ bool isLatencyDetectionSupported();
+
+ bool isAAudioRecommended();
+
+private:
+ oboe::Result reopenStream();
+ oboe::Result openPlaybackStream();
+
+ std::shared_ptr<oboe::AudioStream> mStream;
+ std::shared_ptr<LatencyTuningCallback> mLatencyCallback;
+ std::shared_ptr<DefaultErrorCallback> mErrorCallback;
+ std::shared_ptr<SoundGenerator> mAudioSource;
+ bool mIsLatencyDetectionSupported = false;
+
+ int32_t mDeviceId = oboe::Unspecified;
+ int32_t mChannelCount = oboe::Unspecified;
+ oboe::AudioApi mAudioApi = oboe::AudioApi::Unspecified;
+ std::mutex mLock;
+};
+
+#endif //OBOE_HELLO_OBOE_ENGINE_H
diff --git a/externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.cpp b/externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.cpp
new file mode 100644
index 0000000000..7d53c43047
--- /dev/null
+++ b/externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.cpp
@@ -0,0 +1,45 @@
+/**
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "LatencyTuningCallback.h"
+
+oboe::DataCallbackResult LatencyTuningCallback::onAudioReady(
+ oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) {
+ if (oboeStream != mStream) {
+ mStream = oboeStream;
+ mLatencyTuner = std::make_unique<oboe::LatencyTuner>(*oboeStream);
+ }
+ if (mBufferTuneEnabled
+ && mLatencyTuner
+ && oboeStream->getAudioApi() == oboe::AudioApi::AAudio) {
+ mLatencyTuner->tune();
+ }
+ auto underrunCountResult = oboeStream->getXRunCount();
+ int bufferSize = oboeStream->getBufferSizeInFrames();
+ /**
+ * The following output can be seen by running a systrace. Tracing is preferable to logging
+ * inside the callback since tracing does not block.
+ *
+ * See https://developer.android.com/studio/profile/systrace-commandline.html
+ */
+ if (Trace::isEnabled()) Trace::beginSection("numFrames %d, Underruns %d, buffer size %d",
+ numFrames, underrunCountResult.value(), bufferSize);
+ auto result = DefaultDataCallback::onAudioReady(oboeStream, audioData, numFrames);
+ if (Trace::isEnabled()) Trace::endSection();
+ return result;
+}
+
+
diff --git a/externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.h b/externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.h
new file mode 100644
index 0000000000..16051546e9
--- /dev/null
+++ b/externals/oboe/samples/hello-oboe/src/main/cpp/LatencyTuningCallback.h
@@ -0,0 +1,67 @@
+/**
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#ifndef SAMPLES_LATENCY_TUNING_CALLBACK_H
+#define SAMPLES_LATENCY_TUNING_CALLBACK_H
+
+#include <oboe/Oboe.h>
+#include <oboe/LatencyTuner.h>
+
+#include <TappableAudioSource.h>
+#include <DefaultDataCallback.h>
+#include <trace.h>
+
+/**
+ * This callback object extends the functionality of `DefaultDataCallback` by automatically
+ * tuning the latency of the audio stream. @see onAudioReady for more details on this.
+ *
+ * It also demonstrates how to use tracing functions for logging inside the audio callback without
+ * blocking.
+ */
+class LatencyTuningCallback: public DefaultDataCallback {
+public:
+ LatencyTuningCallback() : DefaultDataCallback() {
+
+ // Initialize the trace functions, this enables you to output trace statements without
+ // blocking. See https://developer.android.com/studio/profile/systrace-commandline.html
+ Trace::initialize();
+ }
+
+ /**
+ * Every time the playback stream requires data this method will be called.
+ *
+ * @param audioStream the audio stream which is requesting data, this is the mPlayStream object
+ * @param audioData an empty buffer into which we can write our audio data
+ * @param numFrames the number of audio frames which are required
+ * @return Either oboe::DataCallbackResult::Continue if the stream should continue requesting data
+ * or oboe::DataCallbackResult::Stop if the stream should stop.
+ */
+ oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override;
+
+ void setBufferTuneEnabled(bool enabled) {mBufferTuneEnabled = enabled;}
+
+ void useStream(std::shared_ptr<oboe::AudioStream> stream);
+
+private:
+ bool mBufferTuneEnabled = true;
+
+ // This will be used to automatically tune the buffer size of the stream, obtaining optimal latency
+ std::unique_ptr<oboe::LatencyTuner> mLatencyTuner;
+ oboe::AudioStream *mStream = nullptr;
+};
+
+#endif //SAMPLES_LATENCY_TUNING_CALLBACK_H
diff --git a/externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.cpp b/externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.cpp
new file mode 100644
index 0000000000..1de9030f28
--- /dev/null
+++ b/externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SoundGenerator.h"
+
+SoundGenerator::SoundGenerator(int32_t sampleRate, int32_t channelCount) :
+ TappableAudioSource(sampleRate, channelCount)
+ , mOscillators(std::make_unique<Oscillator[]>(channelCount)){
+
+ double frequency = 440.0;
+ constexpr double interval = 110.0;
+ constexpr float amplitude = 1.0;
+
+ // Set up the oscillators
+ for (int i = 0; i < mChannelCount; ++i) {
+ mOscillators[i].setFrequency(frequency);
+ mOscillators[i].setSampleRate(mSampleRate);
+ mOscillators[i].setAmplitude(amplitude);
+ frequency += interval;
+ }
+}
+
+void SoundGenerator::renderAudio(float *audioData, int32_t numFrames) {
+ // Render each oscillator into its own channel
+ std::fill_n(mBuffer.get(), kSharedBufferSize, 0);
+ for (int i = 0; i < mChannelCount; ++i) {
+ mOscillators[i].renderAudio(mBuffer.get(), numFrames);
+ for (int j = 0; j < numFrames; ++j) {
+ audioData[(j * mChannelCount) + i] = mBuffer[j];
+ }
+ }
+}
+
+void SoundGenerator::tap(bool isOn) {
+ for (int i = 0; i < mChannelCount; ++i) {
+ mOscillators[i].setWaveOn(isOn);
+ }
+}
diff --git a/externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.h b/externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.h
new file mode 100644
index 0000000000..1ffae37f0f
--- /dev/null
+++ b/externals/oboe/samples/hello-oboe/src/main/cpp/SoundGenerator.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SAMPLES_SOUNDGENERATOR_H
+#define SAMPLES_SOUNDGENERATOR_H
+
+
+#include <Oscillator.h>
+#include <TappableAudioSource.h>
+
+/**
+ * Generates a fixed frequency tone for each channel.
+ * Implements RenderableTap (sound source with toggle) which is required for AudioEngines.
+ */
+class SoundGenerator : public TappableAudioSource {
+ static constexpr size_t kSharedBufferSize = 1024;
+public:
+ /**
+ * Create a new SoundGenerator object.
+ *
+ * @param sampleRate - The output sample rate.
+ * @param maxFrames - The maximum number of audio frames which will be rendered, this is used to
+ * calculate this object's internal buffer size.
+ * @param channelCount - The number of channels in the output, one tone will be created for each
+ * channel, the output will be interlaced.
+ *
+ */
+ SoundGenerator(int32_t sampleRate, int32_t channelCount);
+ ~SoundGenerator() = default;
+
+ SoundGenerator(SoundGenerator&& other) = default;
+ SoundGenerator& operator= (SoundGenerator&& other) = default;
+
+ // Switch the tones on
+ void tap(bool isOn) override;
+
+ void renderAudio(float *audioData, int32_t numFrames) override;
+
+private:
+ std::unique_ptr<Oscillator[]> mOscillators;
+ std::unique_ptr<float[]> mBuffer = std::make_unique<float[]>(kSharedBufferSize);
+};
+
+
+#endif //SAMPLES_SOUNDGENERATOR_H
diff --git a/externals/oboe/samples/hello-oboe/src/main/cpp/jni_bridge.cpp b/externals/oboe/samples/hello-oboe/src/main/cpp/jni_bridge.cpp
new file mode 100644
index 0000000000..8d049c5aee
--- /dev/null
+++ b/externals/oboe/samples/hello-oboe/src/main/cpp/jni_bridge.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <jni.h>
+#include <oboe/Oboe.h>
+#include "HelloOboeEngine.h"
+#include "logging_macros.h"
+
+extern "C" {
+/* We only need one HelloOboeEngine and it is needed for the entire time.
+ * So just allocate one statically. */
+static HelloOboeEngine sEngine;
+
+JNIEXPORT jint JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_startEngine(
+ JNIEnv *env,
+ jclass,
+ int audioApi, int deviceId, int channelCount) {
+ return static_cast<jint>(sEngine.start((oboe::AudioApi)audioApi, deviceId, channelCount));
+}
+
+JNIEXPORT jint JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_stopEngine(
+ JNIEnv *env,
+ jclass) {
+ return static_cast<jint>(sEngine.stop());
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_setToneOn(
+ JNIEnv *env,
+ jclass,
+ jboolean isToneOn) {
+
+ sEngine.tap(isToneOn);
+}
+
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_setBufferSizeInBursts(
+ JNIEnv *env,
+ jclass,
+ jint bufferSizeInBursts) {
+ sEngine.setBufferSizeInBursts(bufferSizeInBursts);
+}
+
+JNIEXPORT jdouble JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_getCurrentOutputLatencyMillis(
+ JNIEnv *env,
+ jclass) {
+ return static_cast<jdouble>(sEngine.getCurrentOutputLatencyMillis());
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_isLatencyDetectionSupported(
+ JNIEnv *env,
+ jclass) {
+ return (sEngine.isLatencyDetectionSupported() ? JNI_TRUE : JNI_FALSE);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_isAAudioRecommended(
+ JNIEnv *env,
+ jclass) {
+ return (sEngine.isAAudioRecommended() ? JNI_TRUE : JNI_FALSE);
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_hellooboe_PlaybackEngine_setDefaultStreamValues(
+ JNIEnv *env,
+ jclass,
+ jint sampleRate,
+ jint framesPerBurst) {
+ oboe::DefaultStreamValues::SampleRate = (int32_t) sampleRate;
+ oboe::DefaultStreamValues::FramesPerBurst = (int32_t) framesPerBurst;
+}
+} // extern "C"