aboutsummaryrefslogtreecommitdiff
path: root/externals/oboe/samples/LiveEffect/src/main/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'externals/oboe/samples/LiveEffect/src/main/cpp')
-rw-r--r--externals/oboe/samples/LiveEffect/src/main/cpp/CMakeLists.txt46
-rw-r--r--externals/oboe/samples/LiveEffect/src/main/cpp/FullDuplexPass.h54
-rw-r--r--externals/oboe/samples/LiveEffect/src/main/cpp/LiveEffectEngine.cpp245
-rw-r--r--externals/oboe/samples/LiveEffect/src/main/cpp/LiveEffectEngine.h83
-rw-r--r--externals/oboe/samples/LiveEffect/src/main/cpp/jni_bridge.cpp134
-rw-r--r--externals/oboe/samples/LiveEffect/src/main/cpp/ndk-stl-config.cmake40
6 files changed, 602 insertions, 0 deletions
diff --git a/externals/oboe/samples/LiveEffect/src/main/cpp/CMakeLists.txt b/externals/oboe/samples/LiveEffect/src/main/cpp/CMakeLists.txt
new file mode 100644
index 0000000000..916edc0cf7
--- /dev/null
+++ b/externals/oboe/samples/LiveEffect/src/main/cpp/CMakeLists.txt
@@ -0,0 +1,46 @@
+#
+# 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.
+#
+cmake_minimum_required(VERSION 3.4.1)
+project(liveEffect LANGUAGES C CXX)
+
+get_filename_component(SAMPLE_ROOT_DIR
+ ${CMAKE_CURRENT_SOURCE_DIR}/../../../.. ABSOLUTE)
+
+### INCLUDE OBOE LIBRARY ###
+set (OBOE_DIR ${SAMPLE_ROOT_DIR}/..)
+add_subdirectory(${OBOE_DIR} ./oboe-bin)
+
+add_library(liveEffect
+ SHARED
+ LiveEffectEngine.cpp
+ jni_bridge.cpp
+ ${SAMPLE_ROOT_DIR}/debug-utils/trace.cpp)
+target_include_directories(liveEffect
+ PRIVATE
+ ${SAMPLE_ROOT_DIR}/debug-utils
+ ${OBOE_DIR}/include)
+target_link_libraries(liveEffect
+ PRIVATE
+ oboe
+ android
+ atomic
+ log)
+target_link_options(liveEffect PRIVATE "-Wl,-z,max-page-size=16384")
+
+# Enable optimization flags: if having problems with source level debugging,
+# disable -Ofast ( and debug ), re-enable it after done debugging.
+target_compile_options(liveEffect PRIVATE -Wall -Werror "$<$<CONFIG:RELEASE>:-Ofast>")
+
diff --git a/externals/oboe/samples/LiveEffect/src/main/cpp/FullDuplexPass.h b/externals/oboe/samples/LiveEffect/src/main/cpp/FullDuplexPass.h
new file mode 100644
index 0000000000..4c8bbd6db4
--- /dev/null
+++ b/externals/oboe/samples/LiveEffect/src/main/cpp/FullDuplexPass.h
@@ -0,0 +1,54 @@
+/*
+ * 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_FULLDUPLEXPASS_H
+#define SAMPLES_FULLDUPLEXPASS_H
+
+class FullDuplexPass : public oboe::FullDuplexStream {
+public:
+ virtual oboe::DataCallbackResult
+ onBothStreamsReady(
+ const void *inputData,
+ int numInputFrames,
+ void *outputData,
+ int numOutputFrames) {
+ // Copy the input samples to the output with a little arbitrary gain change.
+
+ // This code assumes the data format for both streams is Float.
+ const float *inputFloats = static_cast<const float *>(inputData);
+ float *outputFloats = static_cast<float *>(outputData);
+
+ // It also assumes the channel count for each stream is the same.
+ int32_t samplesPerFrame = getOutputStream()->getChannelCount();
+ int32_t numInputSamples = numInputFrames * samplesPerFrame;
+ int32_t numOutputSamples = numOutputFrames * samplesPerFrame;
+
+ // It is possible that there may be fewer input than output samples.
+ int32_t samplesToProcess = std::min(numInputSamples, numOutputSamples);
+ for (int32_t i = 0; i < samplesToProcess; i++) {
+ *outputFloats++ = *inputFloats++ * 0.95; // do some arbitrary processing
+ }
+
+ // If there are fewer input samples then clear the rest of the buffer.
+ int32_t samplesLeft = numOutputSamples - numInputSamples;
+ for (int32_t i = 0; i < samplesLeft; i++) {
+ *outputFloats++ = 0.0; // silence
+ }
+
+ return oboe::DataCallbackResult::Continue;
+ }
+};
+#endif //SAMPLES_FULLDUPLEXPASS_H
diff --git a/externals/oboe/samples/LiveEffect/src/main/cpp/LiveEffectEngine.cpp b/externals/oboe/samples/LiveEffect/src/main/cpp/LiveEffectEngine.cpp
new file mode 100644
index 0000000000..63d0a55a47
--- /dev/null
+++ b/externals/oboe/samples/LiveEffect/src/main/cpp/LiveEffectEngine.cpp
@@ -0,0 +1,245 @@
+/**
+ * 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 <cassert>
+#include <logging_macros.h>
+
+#include "LiveEffectEngine.h"
+
+LiveEffectEngine::LiveEffectEngine() {
+ assert(mOutputChannelCount == mInputChannelCount);
+}
+
+void LiveEffectEngine::setRecordingDeviceId(int32_t deviceId) {
+ mRecordingDeviceId = deviceId;
+}
+
+void LiveEffectEngine::setPlaybackDeviceId(int32_t deviceId) {
+ mPlaybackDeviceId = deviceId;
+}
+
+bool LiveEffectEngine::isAAudioRecommended() {
+ return oboe::AudioStreamBuilder::isAAudioRecommended();
+}
+
+bool LiveEffectEngine::setAudioApi(oboe::AudioApi api) {
+ if (mIsEffectOn) return false;
+ mAudioApi = api;
+ return true;
+}
+
+bool LiveEffectEngine::setEffectOn(bool isOn) {
+ bool success = true;
+ if (isOn != mIsEffectOn) {
+ if (isOn) {
+ success = openStreams() == oboe::Result::OK;
+ if (success) {
+ mIsEffectOn = isOn;
+ }
+ } else {
+ closeStreams();
+ mIsEffectOn = isOn;
+ }
+ }
+ return success;
+}
+
+void LiveEffectEngine::closeStreams() {
+ /*
+ * Note: The order of events is important here.
+ * The playback stream must be closed before the recording stream. If the
+ * recording stream were to be closed first the playback stream's
+ * callback may attempt to read from the recording stream
+ * which would cause the app to crash since the recording stream would be
+ * null.
+ */
+ mDuplexStream->stop();
+ closeStream(mPlayStream);
+ closeStream(mRecordingStream);
+ mDuplexStream.reset();
+}
+
+oboe::Result LiveEffectEngine::openStreams() {
+ // Note: The order of stream creation is important. We create the playback
+ // stream first, then use properties from the playback stream
+ // (e.g. sample rate) to create the recording stream. By matching the
+ // properties we should get the lowest latency path
+ oboe::AudioStreamBuilder inBuilder, outBuilder;
+ setupPlaybackStreamParameters(&outBuilder);
+ oboe::Result result = outBuilder.openStream(mPlayStream);
+ if (result != oboe::Result::OK) {
+ LOGE("Failed to open output stream. Error %s", oboe::convertToText(result));
+ mSampleRate = oboe::kUnspecified;
+ return result;
+ } else {
+ // The input stream needs to run at the same sample rate as the output.
+ mSampleRate = mPlayStream->getSampleRate();
+ }
+ warnIfNotLowLatency(mPlayStream);
+
+ setupRecordingStreamParameters(&inBuilder, mSampleRate);
+ result = inBuilder.openStream(mRecordingStream);
+ if (result != oboe::Result::OK) {
+ LOGE("Failed to open input stream. Error %s", oboe::convertToText(result));
+ closeStream(mPlayStream);
+ return result;
+ }
+ warnIfNotLowLatency(mRecordingStream);
+
+ mDuplexStream = std::make_unique<FullDuplexPass>();
+ mDuplexStream->setSharedInputStream(mRecordingStream);
+ mDuplexStream->setSharedOutputStream(mPlayStream);
+ mDuplexStream->start();
+ return result;
+}
+
+/**
+ * Sets the stream parameters which are specific to recording,
+ * including the sample rate which is determined from the
+ * playback stream.
+ *
+ * @param builder The recording stream builder
+ * @param sampleRate The desired sample rate of the recording stream
+ */
+oboe::AudioStreamBuilder *LiveEffectEngine::setupRecordingStreamParameters(
+ oboe::AudioStreamBuilder *builder, int32_t sampleRate) {
+ // This sample uses blocking read() because we don't specify a callback
+ builder->setDeviceId(mRecordingDeviceId)
+ ->setDirection(oboe::Direction::Input)
+ ->setSampleRate(sampleRate)
+ ->setChannelCount(mInputChannelCount);
+ return setupCommonStreamParameters(builder);
+}
+
+/**
+ * Sets the stream parameters which are specific to playback, including device
+ * id and the dataCallback function, which must be set for low latency
+ * playback.
+ * @param builder The playback stream builder
+ */
+oboe::AudioStreamBuilder *LiveEffectEngine::setupPlaybackStreamParameters(
+ oboe::AudioStreamBuilder *builder) {
+ builder->setDataCallback(this)
+ ->setErrorCallback(this)
+ ->setDeviceId(mPlaybackDeviceId)
+ ->setDirection(oboe::Direction::Output)
+ ->setChannelCount(mOutputChannelCount);
+
+ return setupCommonStreamParameters(builder);
+}
+
+/**
+ * Set the stream parameters which are common to both recording and playback
+ * streams.
+ * @param builder The playback or recording stream builder
+ */
+oboe::AudioStreamBuilder *LiveEffectEngine::setupCommonStreamParameters(
+ oboe::AudioStreamBuilder *builder) {
+ // We request EXCLUSIVE mode since this will give us the lowest possible
+ // latency.
+ // If EXCLUSIVE mode isn't available the builder will fall back to SHARED
+ // mode.
+ builder->setAudioApi(mAudioApi)
+ ->setFormat(mFormat)
+ ->setFormatConversionAllowed(true)
+ ->setSharingMode(oboe::SharingMode::Exclusive)
+ ->setPerformanceMode(oboe::PerformanceMode::LowLatency);
+ return builder;
+}
+
+/**
+ * Close the stream. AudioStream::close() is a blocking call so
+ * the application does not need to add synchronization between
+ * onAudioReady() function and the thread calling close().
+ * [the closing thread is the UI thread in this sample].
+ * @param stream the stream to close
+ */
+void LiveEffectEngine::closeStream(std::shared_ptr<oboe::AudioStream> &stream) {
+ if (stream) {
+ oboe::Result result = stream->stop();
+ if (result != oboe::Result::OK) {
+ LOGW("Error stopping stream: %s", oboe::convertToText(result));
+ }
+ result = stream->close();
+ if (result != oboe::Result::OK) {
+ LOGE("Error closing stream: %s", oboe::convertToText(result));
+ } else {
+ LOGW("Successfully closed streams");
+ }
+ stream.reset();
+ }
+}
+
+/**
+ * Warn in logcat if non-low latency stream is created
+ * @param stream: newly created stream
+ *
+ */
+void LiveEffectEngine::warnIfNotLowLatency(std::shared_ptr<oboe::AudioStream> &stream) {
+ if (stream->getPerformanceMode() != oboe::PerformanceMode::LowLatency) {
+ LOGW(
+ "Stream is NOT low latency."
+ "Check your requested format, sample rate and channel count");
+ }
+}
+
+/**
+ * Handles playback stream's audio request. In this sample, we simply block-read
+ * from the record stream for the required samples.
+ *
+ * @param oboeStream: the playback stream that requesting additional samples
+ * @param audioData: the buffer to load audio samples for playback stream
+ * @param numFrames: number of frames to load to audioData buffer
+ * @return: DataCallbackResult::Continue.
+ */
+oboe::DataCallbackResult LiveEffectEngine::onAudioReady(
+ oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) {
+ return mDuplexStream->onAudioReady(oboeStream, audioData, numFrames);
+}
+
+/**
+ * Oboe notifies the application for "about to close the stream".
+ *
+ * @param oboeStream: the stream to close
+ * @param error: oboe's reason for closing the stream
+ */
+void LiveEffectEngine::onErrorBeforeClose(oboe::AudioStream *oboeStream,
+ oboe::Result error) {
+ LOGE("%s stream Error before close: %s",
+ oboe::convertToText(oboeStream->getDirection()),
+ oboe::convertToText(error));
+}
+
+/**
+ * Oboe notifies application that "the stream is closed"
+ *
+ * @param oboeStream
+ * @param error
+ */
+void LiveEffectEngine::onErrorAfterClose(oboe::AudioStream *oboeStream,
+ oboe::Result error) {
+ LOGE("%s stream Error after close: %s",
+ oboe::convertToText(oboeStream->getDirection()),
+ oboe::convertToText(error));
+
+ closeStreams();
+
+ // Restart the stream if the error is a disconnect.
+ if (error == oboe::Result::ErrorDisconnected) {
+ LOGI("Restarting AudioStream");
+ openStreams();
+ }
+}
diff --git a/externals/oboe/samples/LiveEffect/src/main/cpp/LiveEffectEngine.h b/externals/oboe/samples/LiveEffect/src/main/cpp/LiveEffectEngine.h
new file mode 100644
index 0000000000..faea3b07d9
--- /dev/null
+++ b/externals/oboe/samples/LiveEffect/src/main/cpp/LiveEffectEngine.h
@@ -0,0 +1,83 @@
+/*
+ * 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 OBOE_LIVEEFFECTENGINE_H
+#define OBOE_LIVEEFFECTENGINE_H
+
+#include <jni.h>
+#include <oboe/Oboe.h>
+#include <string>
+#include <thread>
+#include "FullDuplexPass.h"
+
+class LiveEffectEngine : public oboe::AudioStreamCallback {
+public:
+ LiveEffectEngine();
+
+ void setRecordingDeviceId(int32_t deviceId);
+ void setPlaybackDeviceId(int32_t deviceId);
+
+ /**
+ * @param isOn
+ * @return true if it succeeds
+ */
+ bool setEffectOn(bool isOn);
+
+ /*
+ * oboe::AudioStreamDataCallback interface implementation
+ */
+ oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream,
+ void *audioData, int32_t numFrames) override;
+
+ /*
+ * oboe::AudioStreamErrorCallback interface implementation
+ */
+ void onErrorBeforeClose(oboe::AudioStream *oboeStream, oboe::Result error) override;
+ void onErrorAfterClose(oboe::AudioStream *oboeStream, oboe::Result error) override;
+
+ bool setAudioApi(oboe::AudioApi);
+ bool isAAudioRecommended(void);
+
+private:
+ bool mIsEffectOn = false;
+ int32_t mRecordingDeviceId = oboe::kUnspecified;
+ int32_t mPlaybackDeviceId = oboe::kUnspecified;
+ const oboe::AudioFormat mFormat = oboe::AudioFormat::Float; // for easier processing
+ oboe::AudioApi mAudioApi = oboe::AudioApi::AAudio;
+ int32_t mSampleRate = oboe::kUnspecified;
+ const int32_t mInputChannelCount = oboe::ChannelCount::Stereo;
+ const int32_t mOutputChannelCount = oboe::ChannelCount::Stereo;
+
+ std::unique_ptr<FullDuplexPass> mDuplexStream;
+ std::shared_ptr<oboe::AudioStream> mRecordingStream;
+ std::shared_ptr<oboe::AudioStream> mPlayStream;
+
+ oboe::Result openStreams();
+
+ void closeStreams();
+
+ void closeStream(std::shared_ptr<oboe::AudioStream> &stream);
+
+ oboe::AudioStreamBuilder *setupCommonStreamParameters(
+ oboe::AudioStreamBuilder *builder);
+ oboe::AudioStreamBuilder *setupRecordingStreamParameters(
+ oboe::AudioStreamBuilder *builder, int32_t sampleRate);
+ oboe::AudioStreamBuilder *setupPlaybackStreamParameters(
+ oboe::AudioStreamBuilder *builder);
+ void warnIfNotLowLatency(std::shared_ptr<oboe::AudioStream> &stream);
+};
+
+#endif // OBOE_LIVEEFFECTENGINE_H
diff --git a/externals/oboe/samples/LiveEffect/src/main/cpp/jni_bridge.cpp b/externals/oboe/samples/LiveEffect/src/main/cpp/jni_bridge.cpp
new file mode 100644
index 0000000000..ad9172e809
--- /dev/null
+++ b/externals/oboe/samples/LiveEffect/src/main/cpp/jni_bridge.cpp
@@ -0,0 +1,134 @@
+/**
+ * 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 <jni.h>
+#include <logging_macros.h>
+#include "LiveEffectEngine.h"
+
+static const int kOboeApiAAudio = 0;
+static const int kOboeApiOpenSLES = 1;
+
+static LiveEffectEngine *engine = nullptr;
+
+extern "C" {
+
+JNIEXPORT jboolean JNICALL
+Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_create(JNIEnv *env,
+ jclass) {
+ if (engine == nullptr) {
+ engine = new LiveEffectEngine();
+ }
+
+ return (engine != nullptr) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_delete(JNIEnv *env,
+ jclass) {
+ if (engine) {
+ engine->setEffectOn(false);
+ delete engine;
+ engine = nullptr;
+ }
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_setEffectOn(
+ JNIEnv *env, jclass, jboolean isEffectOn) {
+ if (engine == nullptr) {
+ LOGE(
+ "Engine is null, you must call createEngine before calling this "
+ "method");
+ return JNI_FALSE;
+ }
+
+ return engine->setEffectOn(isEffectOn) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_setRecordingDeviceId(
+ JNIEnv *env, jclass, jint deviceId) {
+ if (engine == nullptr) {
+ LOGE(
+ "Engine is null, you must call createEngine before calling this "
+ "method");
+ return;
+ }
+
+ engine->setRecordingDeviceId(deviceId);
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_setPlaybackDeviceId(
+ JNIEnv *env, jclass, jint deviceId) {
+ if (engine == nullptr) {
+ LOGE(
+ "Engine is null, you must call createEngine before calling this "
+ "method");
+ return;
+ }
+
+ engine->setPlaybackDeviceId(deviceId);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_setAPI(JNIEnv *env,
+ jclass type,
+ jint apiType) {
+ if (engine == nullptr) {
+ LOGE(
+ "Engine is null, you must call createEngine "
+ "before calling this method");
+ return JNI_FALSE;
+ }
+
+ oboe::AudioApi audioApi;
+ switch (apiType) {
+ case kOboeApiAAudio:
+ audioApi = oboe::AudioApi::AAudio;
+ break;
+ case kOboeApiOpenSLES:
+ audioApi = oboe::AudioApi::OpenSLES;
+ break;
+ default:
+ LOGE("Unknown API selection to setAPI() %d", apiType);
+ return JNI_FALSE;
+ }
+
+ return engine->setAudioApi(audioApi) ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT jboolean JNICALL
+Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_isAAudioRecommended(
+ JNIEnv *env, jclass type) {
+ if (engine == nullptr) {
+ LOGE(
+ "Engine is null, you must call createEngine "
+ "before calling this method");
+ return JNI_FALSE;
+ }
+ return engine->isAAudioRecommended() ? JNI_TRUE : JNI_FALSE;
+}
+
+JNIEXPORT void JNICALL
+Java_com_google_oboe_samples_liveEffect_LiveEffectEngine_native_1setDefaultStreamValues(JNIEnv *env,
+ jclass type,
+ jint sampleRate,
+ jint framesPerBurst) {
+ oboe::DefaultStreamValues::SampleRate = (int32_t) sampleRate;
+ oboe::DefaultStreamValues::FramesPerBurst = (int32_t) framesPerBurst;
+}
+} // extern "C"
diff --git a/externals/oboe/samples/LiveEffect/src/main/cpp/ndk-stl-config.cmake b/externals/oboe/samples/LiveEffect/src/main/cpp/ndk-stl-config.cmake
new file mode 100644
index 0000000000..72f0f8d4d4
--- /dev/null
+++ b/externals/oboe/samples/LiveEffect/src/main/cpp/ndk-stl-config.cmake
@@ -0,0 +1,40 @@
+# Copy shared STL files to Android Studio output directory so they can be
+# packaged in the APK.
+# Usage:
+#
+# find_package(ndk-stl REQUIRED)
+#
+# or
+#
+# find_package(ndk-stl REQUIRED PATHS ".")
+
+if(NOT ${ANDROID_STL} MATCHES "_shared")
+ return()
+endif()
+
+function(configure_shared_stl lib_path so_base)
+ message("Configuring STL ${so_base} for ${ANDROID_ABI}")
+ configure_file(
+ "${ANDROID_NDK}/sources/cxx-stl/${lib_path}/libs/${ANDROID_ABI}/lib${so_base}.so"
+ "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/lib${so_base}.so"
+ COPYONLY)
+endfunction()
+
+if("${ANDROID_STL}" STREQUAL "libstdc++")
+ # The default minimal system C++ runtime library.
+elseif("${ANDROID_STL}" STREQUAL "gabi++_shared")
+ # The GAbi++ runtime (shared).
+ message(FATAL_ERROR "gabi++_shared was not configured by ndk-stl package")
+elseif("${ANDROID_STL}" STREQUAL "stlport_shared")
+ # The STLport runtime (shared).
+ configure_shared_stl("stlport" "stlport_shared")
+elseif("${ANDROID_STL}" STREQUAL "gnustl_shared")
+ # The GNU STL (shared).
+ configure_shared_stl("gnu-libstdc++/4.9" "gnustl_shared")
+elseif("${ANDROID_STL}" STREQUAL "c++_shared")
+ # The LLVM libc++ runtime (shared).
+ configure_shared_stl("llvm-libc++" "c++_shared")
+else()
+ message(FATAL_ERROR "STL configuration ANDROID_STL=${ANDROID_STL} is not supported")
+endif()
+