aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2021-02-09 16:44:15 -0800
committerHaibo Huang <hhb@google.com>2021-03-01 23:38:54 +0000
commitc0d5f475d0c6c2d4d2d9dd100921191cf0be7e4d (patch)
treebec6d2aa3965d92073723d9f41bd28813556c9fa /src
parent97157061e8c3535f4d4633bd59b04af12f35d416 (diff)
downloadoboe-c0d5f475d0c6c2d4d2d9dd100921191cf0be7e4d.tar.gz
Upgrade oboe to bab1c7de64aa1395c83be384056e2bad061ea272
Test: make Merged-In: I0e69766948e6da6cf547eaf36e880ca08a487d3d Change-Id: I0e69766948e6da6cf547eaf36e880ca08a487d3d
Diffstat (limited to 'src')
-rw-r--r--src/aaudio/AAudioExtensions.h172
-rw-r--r--src/aaudio/AAudioLoader.cpp23
-rw-r--r--src/aaudio/AAudioLoader.h11
-rw-r--r--src/aaudio/AudioStreamAAudio.cpp3
-rw-r--r--src/common/AudioStreamBuilder.cpp18
-rw-r--r--src/common/FilterAudioStream.h5
-rw-r--r--src/common/QuirksManager.cpp25
-rw-r--r--src/common/QuirksManager.h10
-rw-r--r--src/flowgraph/resampler/README.md12
9 files changed, 258 insertions, 21 deletions
diff --git a/src/aaudio/AAudioExtensions.h b/src/aaudio/AAudioExtensions.h
new file mode 100644
index 00000000..51a37ae0
--- /dev/null
+++ b/src/aaudio/AAudioExtensions.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2019 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_AAUDIO_EXTENSIONS_H
+#define OBOE_AAUDIO_EXTENSIONS_H
+
+#include <dlfcn.h>
+#include <stdint.h>
+
+#include <sys/system_properties.h>
+
+#include "common/OboeDebug.h"
+#include "oboe/Oboe.h"
+#include "AAudioLoader.h"
+
+namespace oboe {
+
+#define LIB_AAUDIO_NAME "libaaudio.so"
+#define FUNCTION_IS_MMAP "AAudioStream_isMMapUsed"
+#define FUNCTION_SET_MMAP_POLICY "AAudio_setMMapPolicy"
+#define FUNCTION_GET_MMAP_POLICY "AAudio_getMMapPolicy"
+
+#define AAUDIO_ERROR_UNAVAILABLE static_cast<aaudio_result_t>(Result::ErrorUnavailable)
+
+typedef struct AAudioStreamStruct AAudioStream;
+
+/**
+ * Call some AAudio test routines that are not part of the normal API.
+ */
+class AAudioExtensions {
+public:
+ AAudioExtensions() {
+ int32_t policy = getIntegerProperty("aaudio.mmap_policy", 0);
+ mMMapSupported = isPolicyEnabled(policy);
+
+ policy = getIntegerProperty("aaudio.mmap_exclusive_policy", 0);
+ mMMapExclusiveSupported = isPolicyEnabled(policy);
+ }
+
+ static bool isPolicyEnabled(int32_t policy) {
+ return (policy == AAUDIO_POLICY_AUTO || policy == AAUDIO_POLICY_ALWAYS);
+ }
+
+ static AAudioExtensions &getInstance() {
+ static AAudioExtensions instance;
+ return instance;
+ }
+
+ bool isMMapUsed(oboe::AudioStream *oboeStream) {
+ AAudioStream *aaudioStream = (AAudioStream *) oboeStream->getUnderlyingStream();
+ return isMMapUsed(aaudioStream);
+ }
+
+ bool isMMapUsed(AAudioStream *aaudioStream) {
+ if (loadSymbols()) return false;
+ if (mAAudioStream_isMMap == nullptr) return false;
+ return mAAudioStream_isMMap(aaudioStream);
+ }
+
+ /**
+ * Controls whether the MMAP data path can be selected when opening a stream.
+ * It has no effect after the stream has been opened.
+ * It only affects the application that calls it. Other apps are not affected.
+ *
+ * @param enabled
+ * @return 0 or a negative error code
+ */
+ int32_t setMMapEnabled(bool enabled) {
+ if (loadSymbols()) return AAUDIO_ERROR_UNAVAILABLE;
+ if (mAAudio_setMMapPolicy == nullptr) return false;
+ return mAAudio_setMMapPolicy(enabled ? AAUDIO_POLICY_AUTO : AAUDIO_POLICY_NEVER);
+ }
+
+ bool isMMapEnabled() {
+ if (loadSymbols()) return false;
+ if (mAAudio_getMMapPolicy == nullptr) return false;
+ int32_t policy = mAAudio_getMMapPolicy();
+ return isPolicyEnabled(policy);
+ }
+
+ bool isMMapSupported() {
+ return mMMapSupported;
+ }
+
+ bool isMMapExclusiveSupported() {
+ return mMMapExclusiveSupported;
+ }
+
+private:
+
+ enum {
+ AAUDIO_POLICY_NEVER = 1,
+ AAUDIO_POLICY_AUTO,
+ AAUDIO_POLICY_ALWAYS
+ };
+ typedef int32_t aaudio_policy_t;
+
+ int getIntegerProperty(const char *name, int defaultValue) {
+ int result = defaultValue;
+ char valueText[PROP_VALUE_MAX] = {0};
+ if (__system_property_get(name, valueText) != 0) {
+ result = atoi(valueText);
+ }
+ return result;
+ }
+
+ /**
+ * Load the function pointers.
+ * This can be called multiple times.
+ * It should only be called from one thread.
+ *
+ * @return 0 if successful or negative error.
+ */
+ aaudio_result_t loadSymbols() {
+ if (mAAudio_getMMapPolicy != nullptr) {
+ return 0;
+ }
+
+ void *libHandle = AAudioLoader::getInstance()->getLibHandle();
+ if (libHandle == nullptr) {
+ LOGI("%s() could not find " LIB_AAUDIO_NAME, __func__);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ mAAudioStream_isMMap = (bool (*)(AAudioStream *stream))
+ dlsym(libHandle, FUNCTION_IS_MMAP);
+ if (mAAudioStream_isMMap == nullptr) {
+ LOGI("%s() could not find " FUNCTION_IS_MMAP, __func__);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ mAAudio_setMMapPolicy = (int32_t (*)(aaudio_policy_t policy))
+ dlsym(libHandle, FUNCTION_SET_MMAP_POLICY);
+ if (mAAudio_setMMapPolicy == nullptr) {
+ LOGI("%s() could not find " FUNCTION_SET_MMAP_POLICY, __func__);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ mAAudio_getMMapPolicy = (aaudio_policy_t (*)())
+ dlsym(libHandle, FUNCTION_GET_MMAP_POLICY);
+ if (mAAudio_getMMapPolicy == nullptr) {
+ LOGI("%s() could not find " FUNCTION_GET_MMAP_POLICY, __func__);
+ return AAUDIO_ERROR_UNAVAILABLE;
+ }
+
+ return 0;
+ }
+
+ bool mMMapSupported = false;
+ bool mMMapExclusiveSupported = false;
+
+ bool (*mAAudioStream_isMMap)(AAudioStream *stream) = nullptr;
+ int32_t (*mAAudio_setMMapPolicy)(aaudio_policy_t policy) = nullptr;
+ aaudio_policy_t (*mAAudio_getMMapPolicy)() = nullptr;
+};
+
+} // namespace oboe
+
+#endif //OBOE_AAUDIO_EXTENSIONS_H
diff --git a/src/aaudio/AAudioLoader.cpp b/src/aaudio/AAudioLoader.cpp
index 064633c6..ec97a26e 100644
--- a/src/aaudio/AAudioLoader.cpp
+++ b/src/aaudio/AAudioLoader.cpp
@@ -24,10 +24,17 @@
namespace oboe {
AAudioLoader::~AAudioLoader() {
- if (mLibHandle != nullptr) {
- dlclose(mLibHandle);
- mLibHandle = nullptr;
- }
+ // Issue 360: thread_local variables with non-trivial destructors
+ // will cause segfaults if the containing library is dlclose()ed on
+ // devices running M or newer, or devices before M when using a static STL.
+ // The simple workaround is to not call dlclose.
+ // https://github.com/android/ndk/wiki/Changelog-r22#known-issues
+ //
+ // The libaaudio and libaaudioclient do not use thread_local.
+ // But, to be safe, we should avoid dlclose() if possible.
+ // Because AAudioLoader is a static Singleton, we can safely skip
+ // calling dlclose() without causing a resource leak.
+ LOGI("%s() dlclose(%s) not called, OK", __func__, LIB_AAUDIO_NAME);
}
AAudioLoader* AAudioLoader::getInstance() {
@@ -90,8 +97,6 @@ int AAudioLoader::open() {
stream_getTimestamp = load_I_PSKPLPL("AAudioStream_getTimestamp");
- stream_isMMapUsed = load_B_PS("AAudioStream_isMMapUsed");
-
stream_getChannelCount = load_I_PS("AAudioStream_getChannelCount");
if (stream_getChannelCount == nullptr) {
// Use old alias if needed.
@@ -304,7 +309,6 @@ AAudioLoader::signature_I_PSKPLPL AAudioLoader::load_I_PSKPLPL(const char *funct
== AAUDIO_PERFORMANCE_MODE_POWER_SAVING, ERRMSG);
static_assert((int32_t)PerformanceMode::LowLatency
== AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, ERRMSG);
-#endif
// The aaudio_ usage, content and input_preset types were added in NDK 17,
// which is the first version to support Android Pie (API 28).
@@ -343,6 +347,9 @@ AAudioLoader::signature_I_PSKPLPL AAudioLoader::load_I_PSKPLPL(const char *funct
static_assert((int32_t)SessionId::None == AAUDIO_SESSION_ID_NONE, ERRMSG);
static_assert((int32_t)SessionId::Allocate == AAUDIO_SESSION_ID_ALLOCATE, ERRMSG);
-#endif
+
+#endif // __NDK_MAJOR__ >= 17
+
+#endif // AAUDIO_AAUDIO_H
} // namespace oboe
diff --git a/src/aaudio/AAudioLoader.h b/src/aaudio/AAudioLoader.h
index 6f5bb950..a07c5391 100644
--- a/src/aaudio/AAudioLoader.h
+++ b/src/aaudio/AAudioLoader.h
@@ -52,6 +52,12 @@ typedef int32_t aaudio_usage_t;
typedef int32_t aaudio_content_type_t;
typedef int32_t aaudio_input_preset_t;
typedef int32_t aaudio_session_id_t;
+
+// There are a few definitions used by Oboe.
+#define AAUDIO_OK static_cast<aaudio_result_t>(Result::OK)
+#define AAUDIO_ERROR_TIMEOUT static_cast<aaudio_result_t>(Result::ErrorTimeout)
+#define AAUDIO_STREAM_STATE_STARTING static_cast<aaudio_stream_state_t>(StreamState::Starting)
+#define AAUDIO_STREAM_STATE_STARTED static_cast<aaudio_stream_state_t>(StreamState::Started)
#else
#include <aaudio/AAudio.h>
#include <android/ndk-version.h>
@@ -63,7 +69,6 @@ typedef int32_t aaudio_session_id_t;
namespace oboe {
-
/**
* The AAudio API was not available in early versions of Android.
* To avoid linker errors, we dynamically link with the functions by name using dlsym().
@@ -133,6 +138,8 @@ class AAudioLoader {
*/
int open();
+ void *getLibHandle() const { return mLibHandle; }
+
// Function pointers into the AAudio shared library.
signature_I_PPB createStreamBuilder = nullptr;
@@ -167,8 +174,6 @@ class AAudioLoader {
signature_I_PSKPLPL stream_getTimestamp = nullptr;
- signature_B_PS stream_isMMapUsed = nullptr;
-
signature_I_PS stream_close = nullptr;
signature_I_PS stream_getChannelCount = nullptr;
diff --git a/src/aaudio/AudioStreamAAudio.cpp b/src/aaudio/AudioStreamAAudio.cpp
index cb817623..bc535aeb 100644
--- a/src/aaudio/AudioStreamAAudio.cpp
+++ b/src/aaudio/AudioStreamAAudio.cpp
@@ -23,6 +23,7 @@
#include "common/AudioClock.h"
#include "common/OboeDebug.h"
#include "oboe/Utilities.h"
+#include "AAudioExtensions.h"
#ifdef __ANDROID__
#include <sys/system_properties.h>
@@ -677,7 +678,7 @@ ResultWithValue<double> AudioStreamAAudio::calculateLatencyMillis() {
bool AudioStreamAAudio::isMMapUsed() {
AAudioStream *stream = mAAudioStream.load();
if (stream != nullptr) {
- return mLibLoader->stream_isMMapUsed(stream);
+ return AAudioExtensions::getInstance().isMMapUsed(stream);
} else {
return false;
}
diff --git a/src/common/AudioStreamBuilder.cpp b/src/common/AudioStreamBuilder.cpp
index dffcd75e..b9f04b85 100644
--- a/src/common/AudioStreamBuilder.cpp
+++ b/src/common/AudioStreamBuilder.cpp
@@ -16,6 +16,8 @@
#include <sys/types.h>
+
+#include "aaudio/AAudioExtensions.h"
#include "aaudio/AudioStreamAAudio.h"
#include "FilterAudioStream.h"
#include "OboeDebug.h"
@@ -109,7 +111,6 @@ Result AudioStreamBuilder::openStream(AudioStream **streamPP) {
// Do we need to make a child stream and convert.
if (conversionNeeded) {
AudioStream *tempStream;
-
result = childBuilder.openStream(&tempStream);
if (result != Result::OK) {
return result;
@@ -156,7 +157,20 @@ Result AudioStreamBuilder::openStream(AudioStream **streamPP) {
}
}
- result = streamP->open(); // TODO review API
+ // If MMAP has a problem in this case then disable it temporarily.
+ bool wasMMapOriginallyEnabled = AAudioExtensions::getInstance().isMMapEnabled();
+ bool wasMMapTemporarilyDisabled = false;
+ if (wasMMapOriginallyEnabled) {
+ bool isMMapSafe = QuirksManager::getInstance().isMMapSafe(childBuilder);
+ if (!isMMapSafe) {
+ AAudioExtensions::getInstance().setMMapEnabled(false);
+ wasMMapTemporarilyDisabled = true;
+ }
+ }
+ result = streamP->open();
+ if (wasMMapTemporarilyDisabled) {
+ AAudioExtensions::getInstance().setMMapEnabled(wasMMapOriginallyEnabled); // restore original
+ }
if (result == Result::OK) {
int32_t optimalBufferSize = -1;
diff --git a/src/common/FilterAudioStream.h b/src/common/FilterAudioStream.h
index 210e9d11..5428db5b 100644
--- a/src/common/FilterAudioStream.h
+++ b/src/common/FilterAudioStream.h
@@ -173,7 +173,10 @@ public:
int64_t *timeNanoseconds) override {
int64_t childPosition = 0;
Result result = mChildStream->getTimestamp(clockId, &childPosition, timeNanoseconds);
- *framePosition = childPosition * mRateScaler;
+ // It is OK if framePosition is null.
+ if (framePosition) {
+ *framePosition = childPosition * mRateScaler;
+ }
return result;
}
diff --git a/src/common/QuirksManager.cpp b/src/common/QuirksManager.cpp
index aa285de0..5d35c71b 100644
--- a/src/common/QuirksManager.cpp
+++ b/src/common/QuirksManager.cpp
@@ -20,10 +20,6 @@
#include "OboeDebug.h"
#include "QuirksManager.h"
-#ifndef __ANDROID_API_R__
-#define __ANDROID_API_R__ 30
-#endif
-
using namespace oboe;
int32_t QuirksManager::DeviceQuirks::clipBufferSize(AudioStream &stream,
@@ -74,6 +70,9 @@ public:
std::string chipname = getPropertyString("ro.hardware.chipname");
isExynos9810 = (chipname == "exynos9810");
+ isExynos990 = (chipname == "exynos990");
+
+ mBuildChangelist = getPropertyInteger("ro.build.changelist", 0);
}
virtual ~SamsungDeviceQuirks() = default;
@@ -98,6 +97,17 @@ public:
&& builder.getInputPreset() != oboe::InputPreset::Camcorder;
}
+ bool isMMapSafe(const AudioStreamBuilder &builder) override {
+ const bool isInput = builder.getDirection() == Direction::Input;
+ // This detects b/159066712 , S20 LSI has corrupt low latency audio recording
+ // and turns off MMAP.
+ // See also https://github.com/google/oboe/issues/892
+ bool mRecordingCorrupted = isInput
+ && isExynos990
+ && mBuildChangelist < 19350896;
+ return !mRecordingCorrupted;
+ }
+
private:
// Stay farther away from DSP position on Exynos devices.
static constexpr int32_t kBottomMarginExynos = 2;
@@ -105,6 +115,8 @@ private:
static constexpr int32_t kTopMargin = 1;
bool isExynos = false;
bool isExynos9810 = false;
+ bool isExynos990 = false;
+ int mBuildChangelist = 0;
};
QuirksManager::QuirksManager() {
@@ -203,3 +215,8 @@ bool QuirksManager::isConversionNeeded(
return conversionNeeded;
}
+
+bool QuirksManager::isMMapSafe(AudioStreamBuilder &builder) {
+ if (!OboeGlobals::areWorkaroundsEnabled()) return true;
+ return mDeviceQuirks->isMMapSafe(builder);
+}
diff --git a/src/common/QuirksManager.h b/src/common/QuirksManager.h
index b4e38ded..aeca270a 100644
--- a/src/common/QuirksManager.h
+++ b/src/common/QuirksManager.h
@@ -21,6 +21,10 @@
#include <oboe/AudioStreamBuilder.h>
#include <aaudio/AudioStreamAAudio.h>
+#ifndef __ANDROID_API_R__
+#define __ANDROID_API_R__ 30
+#endif
+
namespace oboe {
/**
@@ -98,6 +102,10 @@ public:
virtual bool isAAudioMMapPossible(const AudioStreamBuilder &builder) const;
+ virtual bool isMMapSafe(const AudioStreamBuilder & /* builder */ ) {
+ return true;
+ }
+
static constexpr int32_t kDefaultBottomMarginInBursts = 0;
static constexpr int32_t kDefaultTopMarginInBursts = 0;
@@ -108,6 +116,8 @@ public:
static constexpr int32_t kCommonNativeRate = 48000; // very typical native sample rate
};
+ bool isMMapSafe(AudioStreamBuilder &builder);
+
private:
static constexpr int32_t kChannelCountMono = 1;
diff --git a/src/flowgraph/resampler/README.md b/src/flowgraph/resampler/README.md
index 5ea97dc8..eaea99f2 100644
--- a/src/flowgraph/resampler/README.md
+++ b/src/flowgraph/resampler/README.md
@@ -1,12 +1,20 @@
# Sample Rate Converter
This folder contains a sample rate converter, or "resampler".
-It is part of [Oboe](https://github.com/google/oboe) but has no dependencies on Oboe.
-So the contents of this folder can be used outside of Oboe.
The converter is based on a sinc function that has been windowed by a hyperbolic cosine.
We found this had fewer artifacts than the more traditional Kaiser window.
+## Building the Resampler
+
+It is part of [Oboe](https://github.com/google/oboe) but has no dependencies on Oboe.
+So the contents of this folder can be used outside of Oboe.
+
+To build it for use outside of Oboe:
+
+1. Copy the "resampler" folder to a folder in your project that is in the include path.
+2. Add all of the \*.cpp files in the resampler folder to your project IDE or Makefile.
+
## Creating a Resampler
Include the [main header](MultiChannelResampler.h) for the resampler.