1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Oboe: Updated to release 1.5.1

This commit is contained in:
ed 2021-04-27 10:44:34 +01:00
parent 433750941b
commit 8aa84abd7c
9 changed files with 249 additions and 20 deletions

View file

@ -429,7 +429,8 @@ public:
/** /**
* Create and open a stream object based on the current settings. * Create and open a stream object based on the current settings.
* *
* The caller owns the pointer to the AudioStream object. * The caller owns the pointer to the AudioStream object
* and must delete it when finished.
* *
* @deprecated Use openStream(std::shared_ptr<oboe::AudioStream> &stream) instead. * @deprecated Use openStream(std::shared_ptr<oboe::AudioStream> &stream) instead.
* @param stream pointer to a variable to receive the stream address * @param stream pointer to a variable to receive the stream address
@ -455,6 +456,8 @@ public:
* The caller must create a unique ptr, and pass by reference so it can be * The caller must create a unique ptr, and pass by reference so it can be
* modified to point to an opened stream. The caller owns the unique ptr, * modified to point to an opened stream. The caller owns the unique ptr,
* and it will be automatically closed and deleted when going out of scope. * and it will be automatically closed and deleted when going out of scope.
*
* @deprecated Use openStream(std::shared_ptr<oboe::AudioStream> &stream) instead.
* @param stream Reference to the ManagedStream (uniqueptr) used to keep track of stream * @param stream Reference to the ManagedStream (uniqueptr) used to keep track of stream
* @return OBOE_OK if successful or a negative error code. * @return OBOE_OK if successful or a negative error code.
*/ */

View file

@ -37,7 +37,7 @@
#define OBOE_VERSION_MINOR 5 #define OBOE_VERSION_MINOR 5
// Type: 16-bit unsigned int. Min value: 0 Max value: 65535. See below for description. // Type: 16-bit unsigned int. Min value: 0 Max value: 65535. See below for description.
#define OBOE_VERSION_PATCH 0 #define OBOE_VERSION_PATCH 1
#define OBOE_STRINGIFY(x) #x #define OBOE_STRINGIFY(x) #x
#define OBOE_TOSTRING(x) OBOE_STRINGIFY(x) #define OBOE_TOSTRING(x) OBOE_STRINGIFY(x)

View file

@ -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

View file

@ -24,10 +24,17 @@
namespace oboe { namespace oboe {
AAudioLoader::~AAudioLoader() { AAudioLoader::~AAudioLoader() {
if (mLibHandle != nullptr) { // Issue 360: thread_local variables with non-trivial destructors
dlclose(mLibHandle); // will cause segfaults if the containing library is dlclose()ed on
mLibHandle = nullptr; // 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() { AAudioLoader* AAudioLoader::getInstance() {
@ -90,8 +97,6 @@ int AAudioLoader::open() {
stream_getTimestamp = load_I_PSKPLPL("AAudioStream_getTimestamp"); stream_getTimestamp = load_I_PSKPLPL("AAudioStream_getTimestamp");
stream_isMMapUsed = load_B_PS("AAudioStream_isMMapUsed");
stream_getChannelCount = load_I_PS("AAudioStream_getChannelCount"); stream_getChannelCount = load_I_PS("AAudioStream_getChannelCount");
if (stream_getChannelCount == nullptr) { if (stream_getChannelCount == nullptr) {
// Use old alias if needed. // 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); == AAUDIO_PERFORMANCE_MODE_POWER_SAVING, ERRMSG);
static_assert((int32_t)PerformanceMode::LowLatency static_assert((int32_t)PerformanceMode::LowLatency
== AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, ERRMSG); == AAUDIO_PERFORMANCE_MODE_LOW_LATENCY, ERRMSG);
#endif
// The aaudio_ usage, content and input_preset types were added in NDK 17, // The aaudio_ usage, content and input_preset types were added in NDK 17,
// which is the first version to support Android Pie (API 28). // 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::None == AAUDIO_SESSION_ID_NONE, ERRMSG);
static_assert((int32_t)SessionId::Allocate == AAUDIO_SESSION_ID_ALLOCATE, ERRMSG); static_assert((int32_t)SessionId::Allocate == AAUDIO_SESSION_ID_ALLOCATE, ERRMSG);
#endif
#endif // __NDK_MAJOR__ >= 17
#endif // AAUDIO_AAUDIO_H
} // namespace oboe } // namespace oboe

View file

@ -52,6 +52,12 @@ typedef int32_t aaudio_usage_t;
typedef int32_t aaudio_content_type_t; typedef int32_t aaudio_content_type_t;
typedef int32_t aaudio_input_preset_t; typedef int32_t aaudio_input_preset_t;
typedef int32_t aaudio_session_id_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 #else
#include <aaudio/AAudio.h> #include <aaudio/AAudio.h>
#include <android/ndk-version.h> #include <android/ndk-version.h>
@ -63,7 +69,6 @@ typedef int32_t aaudio_session_id_t;
namespace oboe { namespace oboe {
/** /**
* The AAudio API was not available in early versions of Android. * 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(). * To avoid linker errors, we dynamically link with the functions by name using dlsym().
@ -133,6 +138,8 @@ class AAudioLoader {
*/ */
int open(); int open();
void *getLibHandle() const { return mLibHandle; }
// Function pointers into the AAudio shared library. // Function pointers into the AAudio shared library.
signature_I_PPB createStreamBuilder = nullptr; signature_I_PPB createStreamBuilder = nullptr;
@ -167,8 +174,6 @@ class AAudioLoader {
signature_I_PSKPLPL stream_getTimestamp = nullptr; signature_I_PSKPLPL stream_getTimestamp = nullptr;
signature_B_PS stream_isMMapUsed = nullptr;
signature_I_PS stream_close = nullptr; signature_I_PS stream_close = nullptr;
signature_I_PS stream_getChannelCount = nullptr; signature_I_PS stream_getChannelCount = nullptr;

View file

@ -23,6 +23,7 @@
#include "common/AudioClock.h" #include "common/AudioClock.h"
#include "common/OboeDebug.h" #include "common/OboeDebug.h"
#include "oboe/Utilities.h" #include "oboe/Utilities.h"
#include "AAudioExtensions.h"
#ifdef __ANDROID__ #ifdef __ANDROID__
#include <sys/system_properties.h> #include <sys/system_properties.h>
@ -677,7 +678,7 @@ ResultWithValue<double> AudioStreamAAudio::calculateLatencyMillis() {
bool AudioStreamAAudio::isMMapUsed() { bool AudioStreamAAudio::isMMapUsed() {
AAudioStream *stream = mAAudioStream.load(); AAudioStream *stream = mAAudioStream.load();
if (stream != nullptr) { if (stream != nullptr) {
return mLibLoader->stream_isMMapUsed(stream); return AAudioExtensions::getInstance().isMMapUsed(stream);
} else { } else {
return false; return false;
} }

View file

@ -16,6 +16,8 @@
#include <sys/types.h> #include <sys/types.h>
#include "aaudio/AAudioExtensions.h"
#include "aaudio/AudioStreamAAudio.h" #include "aaudio/AudioStreamAAudio.h"
#include "FilterAudioStream.h" #include "FilterAudioStream.h"
#include "OboeDebug.h" #include "OboeDebug.h"
@ -109,7 +111,6 @@ Result AudioStreamBuilder::openStream(AudioStream **streamPP) {
// Do we need to make a child stream and convert. // Do we need to make a child stream and convert.
if (conversionNeeded) { if (conversionNeeded) {
AudioStream *tempStream; AudioStream *tempStream;
result = childBuilder.openStream(&tempStream); result = childBuilder.openStream(&tempStream);
if (result != Result::OK) { if (result != Result::OK) {
return result; 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) { if (result == Result::OK) {
int32_t optimalBufferSize = -1; int32_t optimalBufferSize = -1;

View file

@ -20,10 +20,6 @@
#include "OboeDebug.h" #include "OboeDebug.h"
#include "QuirksManager.h" #include "QuirksManager.h"
#ifndef __ANDROID_API_R__
#define __ANDROID_API_R__ 30
#endif
using namespace oboe; using namespace oboe;
int32_t QuirksManager::DeviceQuirks::clipBufferSize(AudioStream &stream, int32_t QuirksManager::DeviceQuirks::clipBufferSize(AudioStream &stream,
@ -74,6 +70,9 @@ public:
std::string chipname = getPropertyString("ro.hardware.chipname"); std::string chipname = getPropertyString("ro.hardware.chipname");
isExynos9810 = (chipname == "exynos9810"); isExynos9810 = (chipname == "exynos9810");
isExynos990 = (chipname == "exynos990");
mBuildChangelist = getPropertyInteger("ro.build.changelist", 0);
} }
virtual ~SamsungDeviceQuirks() = default; virtual ~SamsungDeviceQuirks() = default;
@ -98,6 +97,17 @@ public:
&& builder.getInputPreset() != oboe::InputPreset::Camcorder; && 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: private:
// Stay farther away from DSP position on Exynos devices. // Stay farther away from DSP position on Exynos devices.
static constexpr int32_t kBottomMarginExynos = 2; static constexpr int32_t kBottomMarginExynos = 2;
@ -105,6 +115,8 @@ private:
static constexpr int32_t kTopMargin = 1; static constexpr int32_t kTopMargin = 1;
bool isExynos = false; bool isExynos = false;
bool isExynos9810 = false; bool isExynos9810 = false;
bool isExynos990 = false;
int mBuildChangelist = 0;
}; };
QuirksManager::QuirksManager() { QuirksManager::QuirksManager() {
@ -203,3 +215,8 @@ bool QuirksManager::isConversionNeeded(
return conversionNeeded; return conversionNeeded;
} }
bool QuirksManager::isMMapSafe(AudioStreamBuilder &builder) {
if (!OboeGlobals::areWorkaroundsEnabled()) return true;
return mDeviceQuirks->isMMapSafe(builder);
}

View file

@ -21,6 +21,10 @@
#include <oboe/AudioStreamBuilder.h> #include <oboe/AudioStreamBuilder.h>
#include <aaudio/AudioStreamAAudio.h> #include <aaudio/AudioStreamAAudio.h>
#ifndef __ANDROID_API_R__
#define __ANDROID_API_R__ 30
#endif
namespace oboe { namespace oboe {
/** /**
@ -98,6 +102,10 @@ public:
virtual bool isAAudioMMapPossible(const AudioStreamBuilder &builder) const; 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 kDefaultBottomMarginInBursts = 0;
static constexpr int32_t kDefaultTopMarginInBursts = 0; static constexpr int32_t kDefaultTopMarginInBursts = 0;
@ -108,6 +116,8 @@ public:
static constexpr int32_t kCommonNativeRate = 48000; // very typical native sample rate static constexpr int32_t kCommonNativeRate = 48000; // very typical native sample rate
}; };
bool isMMapSafe(AudioStreamBuilder &builder);
private: private:
static constexpr int32_t kChannelCountMono = 1; static constexpr int32_t kChannelCountMono = 1;