You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
304 lines
11 KiB
304 lines
11 KiB
/*
|
|
* 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 <set>
|
|
#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;
|
|
|
|
// The output device type collection must be updated if there is any new added output device type
|
|
const static std::set<DeviceType> ALL_OUTPUT_DEVICE_TYPES = {
|
|
DeviceType::BuiltinEarpiece,
|
|
DeviceType::BuiltinSpeaker,
|
|
DeviceType::WiredHeadset,
|
|
DeviceType::WiredHeadphones,
|
|
DeviceType::LineAnalog,
|
|
DeviceType::LineDigital,
|
|
DeviceType::BluetoothSco,
|
|
DeviceType::BluetoothA2dp,
|
|
DeviceType::Hdmi,
|
|
DeviceType::HdmiArc,
|
|
DeviceType::HdmiEarc,
|
|
DeviceType::UsbDevice,
|
|
DeviceType::UsbHeadset,
|
|
DeviceType::UsbAccessory,
|
|
DeviceType::Dock,
|
|
DeviceType::DockAnalog,
|
|
DeviceType::FM,
|
|
DeviceType::Telephony,
|
|
DeviceType::AuxLine,
|
|
DeviceType::IP,
|
|
DeviceType::Bus,
|
|
DeviceType::HearingAid,
|
|
DeviceType::BuiltinSpeakerSafe,
|
|
DeviceType::RemoteSubmix,
|
|
DeviceType::BleHeadset,
|
|
DeviceType::BleSpeaker,
|
|
DeviceType::BleBroadcast,
|
|
};
|
|
|
|
// The input device type collection must be updated if there is any new added input device type
|
|
const static std::set<DeviceType> ALL_INPUT_DEVICE_TYPES = {
|
|
DeviceType::BuiltinMic,
|
|
DeviceType::BluetoothSco,
|
|
DeviceType::WiredHeadset,
|
|
DeviceType::Hdmi,
|
|
DeviceType::Telephony,
|
|
DeviceType::Dock,
|
|
DeviceType::DockAnalog,
|
|
DeviceType::UsbAccessory,
|
|
DeviceType::UsbDevice,
|
|
DeviceType::UsbHeadset,
|
|
DeviceType::FMTuner,
|
|
DeviceType::TVTuner,
|
|
DeviceType::LineAnalog,
|
|
DeviceType::LineDigital,
|
|
DeviceType::BluetoothA2dp,
|
|
DeviceType::IP,
|
|
DeviceType::Bus,
|
|
DeviceType::RemoteSubmix,
|
|
DeviceType::BleHeadset,
|
|
DeviceType::HdmiArc,
|
|
DeviceType::HdmiEarc,
|
|
};
|
|
|
|
/**
|
|
* Call some AAudio test routines that are not part of the normal API.
|
|
*/
|
|
class AAudioExtensions {
|
|
private: // Because it is a singleton. Call getInstance() instead.
|
|
AAudioExtensions() {
|
|
mLibLoader = AAudioLoader::getInstance();
|
|
if (!initMMapPolicy()) {
|
|
int32_t policy = getIntegerProperty("aaudio.mmap_policy", 0);
|
|
mMMapSupported = isPolicyEnabled(policy);
|
|
|
|
policy = getIntegerProperty("aaudio.mmap_exclusive_policy", 0);
|
|
mMMapExclusiveSupported = isPolicyEnabled(policy);
|
|
}
|
|
}
|
|
|
|
public:
|
|
static bool isPolicyEnabled(int32_t policy) {
|
|
const MMapPolicy mmapPolicy = static_cast<MMapPolicy>(policy);
|
|
return (mmapPolicy == MMapPolicy::Auto || mmapPolicy == MMapPolicy::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 (mLibLoader != nullptr && mLibLoader->stream_isMMapUsed != nullptr) {
|
|
return mLibLoader->stream_isMMapUsed(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) {
|
|
// The API for setting mmap policy is public after API level 36.
|
|
if (mLibLoader != nullptr && mLibLoader->aaudio_setMMapPolicy != nullptr) {
|
|
return mLibLoader->aaudio_setMMapPolicy(
|
|
static_cast<aaudio_policy_t>(enabled ? MMapPolicy::Auto : MMapPolicy::Never));
|
|
}
|
|
// When there is no public API, fallback to loading the symbol from hidden API.
|
|
if (loadSymbols()) return AAUDIO_ERROR_UNAVAILABLE;
|
|
if (mAAudio_setMMapPolicy == nullptr) return false;
|
|
return mAAudio_setMMapPolicy(
|
|
static_cast<int32_t>(enabled ? MMapPolicy::Auto : MMapPolicy::Never));
|
|
}
|
|
|
|
bool isMMapEnabled() {
|
|
// The API for getting mmap policy is public after API level 36.
|
|
// Use it when it is available.
|
|
if (mLibLoader != nullptr && mLibLoader->aaudio_getMMapPolicy != nullptr) {
|
|
MMapPolicy policy = static_cast<MMapPolicy>(mLibLoader->aaudio_getMMapPolicy());
|
|
return policy == MMapPolicy::Unspecified
|
|
? mMMapSupported : isPolicyEnabled(static_cast<int32_t>(policy));
|
|
}
|
|
// When there is no public API, fallback to loading the symbol from hidden API.
|
|
if (loadSymbols()) return false;
|
|
if (mAAudio_getMMapPolicy == nullptr) return false;
|
|
int32_t policy = mAAudio_getMMapPolicy();
|
|
return (policy == Unspecified) ? mMMapSupported : isPolicyEnabled(policy);
|
|
}
|
|
|
|
bool isMMapSupported() {
|
|
return mMMapSupported;
|
|
}
|
|
|
|
bool isMMapExclusiveSupported() {
|
|
return mMMapExclusiveSupported;
|
|
}
|
|
|
|
MMapPolicy getMMapPolicy(DeviceType deviceType, Direction direction) {
|
|
if (mLibLoader == nullptr ||
|
|
mLibLoader->aaudio_getPlatformMMapPolicy == nullptr) {
|
|
return MMapPolicy::Unspecified;
|
|
}
|
|
return static_cast<MMapPolicy>(mLibLoader->aaudio_getPlatformMMapPolicy(
|
|
static_cast<AAudio_DeviceType>(deviceType),
|
|
static_cast<aaudio_direction_t>(direction)));
|
|
}
|
|
|
|
MMapPolicy getMMapExclusivePolicy(DeviceType deviceType, Direction direction) {
|
|
if (mLibLoader == nullptr ||
|
|
mLibLoader->aaudio_getPlatformMMapExclusivePolicy == nullptr) {
|
|
return MMapPolicy::Unspecified;
|
|
}
|
|
return static_cast<MMapPolicy>(mLibLoader->aaudio_getPlatformMMapExclusivePolicy(
|
|
static_cast<AAudio_DeviceType>(deviceType),
|
|
static_cast<aaudio_direction_t>(direction)));
|
|
}
|
|
|
|
private:
|
|
bool initMMapPolicy() {
|
|
if (mLibLoader == nullptr || mLibLoader->open() != 0) {
|
|
return false;
|
|
}
|
|
if (mLibLoader->aaudio_getPlatformMMapPolicy == nullptr ||
|
|
mLibLoader->aaudio_getPlatformMMapExclusivePolicy == nullptr) {
|
|
return false;
|
|
}
|
|
mMMapSupported =
|
|
std::any_of(ALL_INPUT_DEVICE_TYPES.begin(), ALL_INPUT_DEVICE_TYPES.end(),
|
|
[this](DeviceType deviceType) {
|
|
return isPolicyEnabled(static_cast<int32_t>(
|
|
getMMapPolicy(deviceType, Direction::Input)));
|
|
}) ||
|
|
std::any_of(ALL_OUTPUT_DEVICE_TYPES.begin(), ALL_OUTPUT_DEVICE_TYPES.end(),
|
|
[this](DeviceType deviceType) {
|
|
return isPolicyEnabled(static_cast<int32_t>(
|
|
getMMapPolicy(deviceType, Direction::Output)));
|
|
});
|
|
mMMapExclusiveSupported =
|
|
std::any_of(ALL_INPUT_DEVICE_TYPES.begin(), ALL_INPUT_DEVICE_TYPES.end(),
|
|
[this](DeviceType deviceType) {
|
|
return isPolicyEnabled(static_cast<int32_t>(
|
|
getMMapExclusivePolicy(deviceType, Direction::Input)));
|
|
}) ||
|
|
std::any_of(ALL_OUTPUT_DEVICE_TYPES.begin(), ALL_OUTPUT_DEVICE_TYPES.end(),
|
|
[this](DeviceType deviceType) {
|
|
return isPolicyEnabled(static_cast<int32_t>(
|
|
getMMapExclusivePolicy(deviceType, Direction::Output)));
|
|
});
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (mLibLoader == nullptr || mLibLoader->open() != 0) {
|
|
LOGD("%s() could not open " LIB_AAUDIO_NAME, __func__);
|
|
return AAUDIO_ERROR_UNAVAILABLE;
|
|
}
|
|
|
|
void *libHandle = mLibLoader->getLibHandle();
|
|
if (libHandle == nullptr) {
|
|
LOGE("%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;
|
|
|
|
AAudioLoader *mLibLoader;
|
|
};
|
|
|
|
} // namespace oboe
|
|
|
|
#endif //OBOE_AAUDIO_EXTENSIONS_H
|