mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-03 07:28:14 +00:00
Merge "Merge android13-tests-dev"
This commit is contained in:
@@ -14,7 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <numeric>
|
||||
|
||||
#include <android-base/chrono_utils.h>
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#include "Generators.h"
|
||||
|
||||
@@ -517,20 +521,10 @@ class PcmOnlyConfigOutputStreamTest : public OutputStreamTest {
|
||||
}
|
||||
|
||||
bool canQueryPresentationPosition() const {
|
||||
auto maybeSinkAddress =
|
||||
getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName());
|
||||
// Returning 'true' when no sink is found so the test can fail later with a more clear
|
||||
// problem description.
|
||||
return !maybeSinkAddress.has_value() ||
|
||||
!xsd::isTelephonyDevice(maybeSinkAddress.value().deviceType);
|
||||
return !xsd::isTelephonyDevice(address.deviceType);
|
||||
}
|
||||
|
||||
void createPatchIfNeeded() {
|
||||
auto maybeSinkAddress =
|
||||
getCachedPolicyConfig().getSinkDeviceForMixPort(getDeviceName(), getMixPortName());
|
||||
ASSERT_TRUE(maybeSinkAddress.has_value())
|
||||
<< "No sink device found for mix port " << getMixPortName() << " (module "
|
||||
<< getDeviceName() << ")";
|
||||
if (areAudioPatchesSupported()) {
|
||||
AudioPortConfig source;
|
||||
source.base.format.value(getConfig().base.format);
|
||||
@@ -540,13 +534,13 @@ class PcmOnlyConfigOutputStreamTest : public OutputStreamTest {
|
||||
source.ext.mix().ioHandle = helper.getIoHandle();
|
||||
source.ext.mix().useCase.stream({});
|
||||
AudioPortConfig sink;
|
||||
sink.ext.device(maybeSinkAddress.value());
|
||||
sink.ext.device(address);
|
||||
EXPECT_OK(getDevice()->createAudioPatch(hidl_vec<AudioPortConfig>{source},
|
||||
hidl_vec<AudioPortConfig>{sink},
|
||||
returnIn(res, mPatchHandle)));
|
||||
mHasPatch = res == Result::OK;
|
||||
} else {
|
||||
EXPECT_OK(stream->setDevices({maybeSinkAddress.value()}));
|
||||
EXPECT_OK(stream->setDevices({address}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,10 +550,6 @@ class PcmOnlyConfigOutputStreamTest : public OutputStreamTest {
|
||||
EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
|
||||
mHasPatch = false;
|
||||
}
|
||||
} else {
|
||||
if (stream) {
|
||||
EXPECT_OK(stream->setDevices({address}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,16 +565,22 @@ class PcmOnlyConfigOutputStreamTest : public OutputStreamTest {
|
||||
// Sometimes HAL doesn't have enough information until the audio data actually gets
|
||||
// consumed by the hardware.
|
||||
bool timedOut = false;
|
||||
res = Result::INVALID_STATE;
|
||||
for (android::base::Timer elapsed;
|
||||
res != Result::OK && !writer.hasError() &&
|
||||
!(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
|
||||
usleep(kWriteDurationUs);
|
||||
ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts)));
|
||||
ASSERT_RESULT(okOrInvalidState, res);
|
||||
if (!firstPosition || *firstPosition == std::numeric_limits<uint64_t>::max()) {
|
||||
res = Result::INVALID_STATE;
|
||||
for (android::base::Timer elapsed;
|
||||
res != Result::OK && !writer.hasError() &&
|
||||
!(timedOut = (elapsed.duration() >= kPositionChangeTimeout));) {
|
||||
usleep(kWriteDurationUs);
|
||||
ASSERT_OK(stream->getPresentationPosition(returnIn(res, framesInitial, ts)));
|
||||
ASSERT_RESULT(okOrInvalidState, res);
|
||||
}
|
||||
ASSERT_FALSE(writer.hasError());
|
||||
ASSERT_FALSE(timedOut);
|
||||
} else {
|
||||
// Use `firstPosition` instead of querying it from the HAL. This is used when
|
||||
// `waitForPresentationPositionAdvance` is called in a loop.
|
||||
framesInitial = *firstPosition;
|
||||
}
|
||||
ASSERT_FALSE(writer.hasError());
|
||||
ASSERT_FALSE(timedOut);
|
||||
|
||||
uint64_t frames = framesInitial;
|
||||
for (android::base::Timer elapsed;
|
||||
@@ -646,7 +642,7 @@ TEST_P(PcmOnlyConfigOutputStreamTest, PresentationPositionPreservedOnStandby) {
|
||||
ASSERT_OK(stream->standby());
|
||||
writer.resume();
|
||||
|
||||
uint64_t frames;
|
||||
uint64_t frames = std::numeric_limits<uint64_t>::max();
|
||||
ASSERT_NO_FATAL_FAILURE(waitForPresentationPositionAdvance(writer, &frames));
|
||||
EXPECT_GT(frames, framesInitial);
|
||||
|
||||
@@ -691,24 +687,12 @@ class PcmOnlyConfigInputStreamTest : public InputStreamTest {
|
||||
InputStreamTest::TearDown();
|
||||
}
|
||||
|
||||
bool canQueryCapturePosition() const {
|
||||
auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
|
||||
getDeviceName(), getMixPortName());
|
||||
// Returning 'true' when no source is found so the test can fail later with a more clear
|
||||
// problem description.
|
||||
return !maybeSourceAddress.has_value() ||
|
||||
!xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType);
|
||||
}
|
||||
bool canQueryCapturePosition() const { return !xsd::isTelephonyDevice(address.deviceType); }
|
||||
|
||||
void createPatchIfNeeded() {
|
||||
auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
|
||||
getDeviceName(), getMixPortName());
|
||||
ASSERT_TRUE(maybeSourceAddress.has_value())
|
||||
<< "No source device found for mix port " << getMixPortName() << " (module "
|
||||
<< getDeviceName() << ")";
|
||||
if (areAudioPatchesSupported()) {
|
||||
AudioPortConfig source;
|
||||
source.ext.device(maybeSourceAddress.value());
|
||||
source.ext.device(address);
|
||||
AudioPortConfig sink;
|
||||
sink.base.format.value(getConfig().base.format);
|
||||
sink.base.sampleRateHz.value(getConfig().base.sampleRateHz);
|
||||
@@ -721,7 +705,7 @@ class PcmOnlyConfigInputStreamTest : public InputStreamTest {
|
||||
returnIn(res, mPatchHandle)));
|
||||
mHasPatch = res == Result::OK;
|
||||
} else {
|
||||
EXPECT_OK(stream->setDevices({maybeSourceAddress.value()}));
|
||||
EXPECT_OK(stream->setDevices({address}));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -731,10 +715,6 @@ class PcmOnlyConfigInputStreamTest : public InputStreamTest {
|
||||
EXPECT_OK(getDevice()->releaseAudioPatch(mPatchHandle));
|
||||
mHasPatch = false;
|
||||
}
|
||||
} else {
|
||||
if (stream) {
|
||||
EXPECT_OK(stream->setDevices({address}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -864,14 +844,8 @@ TEST_P(MicrophoneInfoInputStreamTest, GetActiveMicrophones) {
|
||||
}
|
||||
ASSERT_OK(res);
|
||||
|
||||
auto maybeSourceAddress =
|
||||
getCachedPolicyConfig().getSourceDeviceForMixPort(getDeviceName(), getMixPortName());
|
||||
ASSERT_TRUE(maybeSourceAddress.has_value())
|
||||
<< "No source device found for mix port " << getMixPortName() << " (module "
|
||||
<< getDeviceName() << ")";
|
||||
|
||||
for (auto microphone : microphones) {
|
||||
if (microphone.deviceAddress == maybeSourceAddress.value()) {
|
||||
if (microphone.deviceAddress == address) {
|
||||
StreamReader reader(stream.get(), stream->getBufferSize());
|
||||
ASSERT_TRUE(reader.start());
|
||||
reader.pause(); // This ensures that at least one read has happened.
|
||||
@@ -889,3 +863,176 @@ INSTANTIATE_TEST_CASE_P(MicrophoneInfoInputStream, MicrophoneInfoInputStreamTest
|
||||
::testing::ValuesIn(getBuiltinMicConfigParameters()),
|
||||
&DeviceConfigParameterToString);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(MicrophoneInfoInputStreamTest);
|
||||
|
||||
static const std::vector<DeviceConfigParameter>& getOutputDeviceCompressedConfigParameters(
|
||||
const AudioConfigBase& configToMatch) {
|
||||
static const std::vector<DeviceConfigParameter> parameters = [&] {
|
||||
auto allParams = getOutputDeviceConfigParameters();
|
||||
std::vector<DeviceConfigParameter> compressedParams;
|
||||
std::copy_if(allParams.begin(), allParams.end(), std::back_inserter(compressedParams),
|
||||
[&](auto cfg) {
|
||||
if (std::get<PARAM_CONFIG>(cfg).base != configToMatch) return false;
|
||||
const auto& flags = std::get<PARAM_FLAGS>(cfg);
|
||||
return std::find_if(flags.begin(), flags.end(), [](const auto& flag) {
|
||||
return flag ==
|
||||
toString(xsd::AudioInOutFlag::
|
||||
AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
|
||||
}) != flags.end();
|
||||
});
|
||||
return compressedParams;
|
||||
}();
|
||||
return parameters;
|
||||
}
|
||||
|
||||
class CompressedOffloadOutputStreamTest : public PcmOnlyConfigOutputStreamTest {
|
||||
public:
|
||||
void loadData(const std::string& fileName, std::vector<uint8_t>* data) {
|
||||
std::ifstream is(fileName, std::ios::in | std::ios::binary);
|
||||
ASSERT_TRUE(is.good()) << "Failed to open file " << fileName;
|
||||
is.seekg(0, is.end);
|
||||
data->reserve(data->size() + is.tellg());
|
||||
is.seekg(0, is.beg);
|
||||
data->insert(data->end(), std::istreambuf_iterator<char>(is),
|
||||
std::istreambuf_iterator<char>());
|
||||
ASSERT_TRUE(!is.fail()) << "Failed to read from file " << fileName;
|
||||
}
|
||||
};
|
||||
|
||||
class OffloadCallbacks : public IStreamOutCallback {
|
||||
public:
|
||||
Return<void> onDrainReady() override {
|
||||
ALOGI("onDrainReady");
|
||||
{
|
||||
std::lock_guard lg(mLock);
|
||||
mOnDrainReady = true;
|
||||
}
|
||||
mCondVar.notify_one();
|
||||
return {};
|
||||
}
|
||||
Return<void> onWriteReady() override { return {}; }
|
||||
Return<void> onError() override {
|
||||
ALOGW("onError");
|
||||
{
|
||||
std::lock_guard lg(mLock);
|
||||
mOnError = true;
|
||||
}
|
||||
mCondVar.notify_one();
|
||||
return {};
|
||||
}
|
||||
bool waitForDrainReadyOrError() {
|
||||
std::unique_lock l(mLock);
|
||||
if (!mOnDrainReady && !mOnError) {
|
||||
mCondVar.wait(l, [&]() { return mOnDrainReady || mOnError; });
|
||||
}
|
||||
const bool success = !mOnError;
|
||||
mOnDrainReady = mOnError = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
private:
|
||||
std::mutex mLock;
|
||||
bool mOnDrainReady = false;
|
||||
bool mOnError = false;
|
||||
std::condition_variable mCondVar;
|
||||
};
|
||||
|
||||
TEST_P(CompressedOffloadOutputStreamTest, Mp3FormatGaplessOffload) {
|
||||
doc::test("Check that compressed offload mix ports for MP3 implement gapless offload");
|
||||
const auto& flags = getOutputFlags();
|
||||
const bool isNewDeviceLaunchingOnTPlus = property_get_int32("ro.vendor.api_level", 0) >= 33;
|
||||
// See test instantiation, only offload MP3 mix ports are used.
|
||||
if (std::find_if(flags.begin(), flags.end(), [](const auto& flag) {
|
||||
return flag == toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD);
|
||||
}) == flags.end()) {
|
||||
if (isNewDeviceLaunchingOnTPlus) {
|
||||
FAIL() << "New devices launching on Android T+ must support gapless offload, "
|
||||
<< "see VSR-4.3-001";
|
||||
} else {
|
||||
GTEST_SKIP() << "Compressed offload mix port does not support gapless offload";
|
||||
}
|
||||
}
|
||||
std::vector<uint8_t> offloadData;
|
||||
ASSERT_NO_FATAL_FAILURE(loadData("/data/local/tmp/sine882hz3s.mp3", &offloadData));
|
||||
ASSERT_FALSE(offloadData.empty());
|
||||
ASSERT_NO_FATAL_FAILURE(createPatchIfNeeded());
|
||||
const int presentationeEndPrecisionMs = 1000;
|
||||
const int sampleRate = 44100;
|
||||
const int significantSampleNumber = (presentationeEndPrecisionMs * sampleRate) / 1000;
|
||||
const int delay = 576 + 1000;
|
||||
const int padding = 756 + 1000;
|
||||
const int durationMs = 3000 - 44;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
auto callbacks = sp<OffloadCallbacks>::make();
|
||||
std::mutex presentationEndLock;
|
||||
std::vector<float> presentationEndTimes;
|
||||
// StreamWriter plays 'offloadData' in a loop, possibly using multiple calls to 'write', this
|
||||
// depends on the relative sizes of 'offloadData' and the HAL buffer. Writer calls 'onDataStart'
|
||||
// each time it starts writing the buffer from the beginning, and 'onDataWrap' callback each
|
||||
// time it wraps around the buffer.
|
||||
StreamWriter writer(
|
||||
stream.get(), stream->getBufferSize(), std::move(offloadData),
|
||||
[&]() /* onDataStart */ { start = std::chrono::steady_clock::now(); },
|
||||
[&]() /* onDataWrap */ {
|
||||
Return<Result> ret(Result::OK);
|
||||
// Decrease the volume since the test plays a loud sine wave.
|
||||
ret = stream->setVolume(0.1, 0.1);
|
||||
if (!ret.isOk() || ret != Result::OK) {
|
||||
ALOGE("%s: setVolume failed: %s", __func__, toString(ret).c_str());
|
||||
return false;
|
||||
}
|
||||
ret = Parameters::set(
|
||||
stream, {{AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, std::to_string(delay)},
|
||||
{AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, std::to_string(padding)}});
|
||||
if (!ret.isOk() || ret != Result::OK) {
|
||||
ALOGE("%s: setParameters failed: %s", __func__, toString(ret).c_str());
|
||||
return false;
|
||||
}
|
||||
ret = stream->drain(AudioDrain::EARLY_NOTIFY);
|
||||
if (!ret.isOk() || ret != Result::OK) {
|
||||
ALOGE("%s: drain failed: %s", __func__, toString(ret).c_str());
|
||||
return false;
|
||||
}
|
||||
// FIXME: On some SoCs intermittent errors are possible, ignore them.
|
||||
if (callbacks->waitForDrainReadyOrError()) {
|
||||
const float duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start)
|
||||
.count();
|
||||
std::lock_guard lg(presentationEndLock);
|
||||
presentationEndTimes.push_back(duration);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
ASSERT_OK(stream->setCallback(callbacks));
|
||||
ASSERT_TRUE(writer.start());
|
||||
// How many times to loop the track so that the sum of gapless delay and padding from
|
||||
// the first presentation end to the last is at least 'presentationeEndPrecisionMs'.
|
||||
const int playbackNumber = (int)(significantSampleNumber / ((float)delay + padding) + 1);
|
||||
for (bool done = false; !done;) {
|
||||
usleep(presentationeEndPrecisionMs * 1000);
|
||||
{
|
||||
std::lock_guard lg(presentationEndLock);
|
||||
done = presentationEndTimes.size() >= playbackNumber;
|
||||
}
|
||||
ASSERT_FALSE(writer.hasError()) << "Recent write or drain operation has failed";
|
||||
}
|
||||
const float avgDuration =
|
||||
std::accumulate(presentationEndTimes.begin(), presentationEndTimes.end(), 0.0) /
|
||||
presentationEndTimes.size();
|
||||
std::stringstream observedEndTimes;
|
||||
std::copy(presentationEndTimes.begin(), presentationEndTimes.end(),
|
||||
std::ostream_iterator<float>(observedEndTimes, ", "));
|
||||
EXPECT_NEAR(durationMs, avgDuration, presentationeEndPrecisionMs * 0.1)
|
||||
<< "Observed durations: " << observedEndTimes.str();
|
||||
writer.stop();
|
||||
EXPECT_OK(stream->clearCallback());
|
||||
releasePatchIfNeeded();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
CompressedOffloadOutputStream, CompressedOffloadOutputStreamTest,
|
||||
::testing::ValuesIn(getOutputDeviceCompressedConfigParameters(AudioConfigBase{
|
||||
.format = xsd::toString(xsd::AudioFormat::AUDIO_FORMAT_MP3),
|
||||
.sampleRateHz = 44100,
|
||||
.channelMask = xsd::toString(xsd::AudioChannelMask::AUDIO_CHANNEL_OUT_STEREO)})),
|
||||
&DeviceConfigParameterToString);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CompressedOffloadOutputStreamTest);
|
||||
|
||||
@@ -57,9 +57,6 @@ static std::vector<AudioConfig> combineAudioConfig(std::vector<xsd::AudioChannel
|
||||
|
||||
static std::tuple<std::vector<AudioInOutFlag>, bool> generateOutFlags(
|
||||
const xsd::MixPorts::MixPort& mixPort) {
|
||||
static const std::vector<AudioInOutFlag> offloadFlags = {
|
||||
toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
|
||||
toString(xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_DIRECT)};
|
||||
std::vector<AudioInOutFlag> flags;
|
||||
bool isOffload = false;
|
||||
if (mixPort.hasFlags()) {
|
||||
@@ -67,14 +64,10 @@ static std::tuple<std::vector<AudioInOutFlag>, bool> generateOutFlags(
|
||||
isOffload = std::find(xsdFlags.begin(), xsdFlags.end(),
|
||||
xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) !=
|
||||
xsdFlags.end();
|
||||
if (!isOffload) {
|
||||
for (auto flag : xsdFlags) {
|
||||
if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
|
||||
flags.push_back(toString(flag));
|
||||
}
|
||||
for (auto flag : xsdFlags) {
|
||||
if (flag != xsd::AudioInOutFlag::AUDIO_OUTPUT_FLAG_PRIMARY) {
|
||||
flags.push_back(toString(flag));
|
||||
}
|
||||
} else {
|
||||
flags = offloadFlags;
|
||||
}
|
||||
}
|
||||
return {flags, isOffload};
|
||||
@@ -85,10 +78,10 @@ static AudioOffloadInfo generateOffloadInfo(const AudioConfigBase& base) {
|
||||
.base = base,
|
||||
.streamType = toString(xsd::AudioStreamType::AUDIO_STREAM_MUSIC),
|
||||
.usage = toString(xsd::AudioUsage::AUDIO_USAGE_MEDIA),
|
||||
.bitRatePerSecond = 320,
|
||||
.bitRatePerSecond = 192, // as in sine882hz3s.mp3
|
||||
.durationMicroseconds = -1,
|
||||
.bitWidth = 16,
|
||||
.bufferSize = 256 // arbitrary value
|
||||
.bufferSize = 72000 // 3 seconds at 192 kbps, as in sine882hz3s.mp3
|
||||
};
|
||||
}
|
||||
|
||||
@@ -100,11 +93,10 @@ std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(bool one
|
||||
if (!module || !module->getFirstMixPorts()) break;
|
||||
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
|
||||
if (mixPort.getRole() != xsd::Role::source) continue; // not an output profile
|
||||
if (getCachedPolicyConfig()
|
||||
.getAttachedSinkDeviceForMixPort(moduleName, mixPort.getName())
|
||||
.empty()) {
|
||||
continue; // no attached device
|
||||
}
|
||||
const auto attachedDeviceAddress =
|
||||
getCachedPolicyConfig().getDeviceAddressOfSinkDeviceAttachedToMixPort(
|
||||
moduleName, mixPort.getName());
|
||||
if (!attachedDeviceAddress.has_value()) continue;
|
||||
auto [flags, isOffload] = generateOutFlags(mixPort);
|
||||
for (const auto& profile : mixPort.getProfile()) {
|
||||
if (!profile.hasFormat() || !profile.hasSamplingRates() ||
|
||||
@@ -118,7 +110,8 @@ std::vector<DeviceConfigParameter> generateOutputDeviceConfigParameters(bool one
|
||||
if (isOffload) {
|
||||
config.offloadInfo.info(generateOffloadInfo(config.base));
|
||||
}
|
||||
result.emplace_back(device, mixPort.getName(), config, flags);
|
||||
result.emplace_back(device, mixPort.getName(), attachedDeviceAddress.value(),
|
||||
config, flags);
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
@@ -162,13 +155,16 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters
|
||||
profile.getFormat(),
|
||||
static_cast<uint32_t>(profile.getSamplingRates()[0]),
|
||||
toString(profile.getChannelMasks()[0])};
|
||||
DeviceAddress defaultDevice = {
|
||||
toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT), {}};
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.base.channelMask = "random_string";
|
||||
if (isOffload) {
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
}
|
||||
result.emplace_back(device, mixPort.getName(), config, validFlags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
validFlags);
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
@@ -176,7 +172,8 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters
|
||||
if (isOffload) {
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
}
|
||||
result.emplace_back(device, mixPort.getName(), config, validFlags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
validFlags);
|
||||
}
|
||||
if (generateInvalidFlags) {
|
||||
AudioConfig config{.base = validBase};
|
||||
@@ -184,32 +181,37 @@ const std::vector<DeviceConfigParameter>& getOutputDeviceInvalidConfigParameters
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
}
|
||||
std::vector<AudioInOutFlag> flags = {"random_string", ""};
|
||||
result.emplace_back(device, mixPort.getName(), config, flags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
flags);
|
||||
}
|
||||
if (isOffload) {
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
config.offloadInfo.info().base.channelMask = "random_string";
|
||||
result.emplace_back(device, mixPort.getName(), config, validFlags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
validFlags);
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
config.offloadInfo.info().base.format = "random_string";
|
||||
result.emplace_back(device, mixPort.getName(), config, validFlags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
validFlags);
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
config.offloadInfo.info().streamType = "random_string";
|
||||
result.emplace_back(device, mixPort.getName(), config, validFlags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
validFlags);
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.offloadInfo.info(generateOffloadInfo(validBase));
|
||||
config.offloadInfo.info().usage = "random_string";
|
||||
result.emplace_back(device, mixPort.getName(), config, validFlags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
validFlags);
|
||||
}
|
||||
hasOffloadConfig = true;
|
||||
} else {
|
||||
@@ -233,11 +235,10 @@ std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneP
|
||||
if (!module || !module->getFirstMixPorts()) break;
|
||||
for (const auto& mixPort : module->getFirstMixPorts()->getMixPort()) {
|
||||
if (mixPort.getRole() != xsd::Role::sink) continue; // not an input profile
|
||||
if (getCachedPolicyConfig()
|
||||
.getAttachedSourceDeviceForMixPort(moduleName, mixPort.getName())
|
||||
.empty()) {
|
||||
continue; // no attached device
|
||||
}
|
||||
const auto attachedDeviceAddress =
|
||||
getCachedPolicyConfig().getDeviceAddressOfSourceDeviceAttachedToMixPort(
|
||||
moduleName, mixPort.getName());
|
||||
if (!attachedDeviceAddress.has_value()) continue;
|
||||
std::vector<AudioInOutFlag> flags;
|
||||
if (mixPort.hasFlags()) {
|
||||
std::transform(mixPort.getFlags().begin(), mixPort.getFlags().end(),
|
||||
@@ -250,7 +251,8 @@ std::vector<DeviceConfigParameter> generateInputDeviceConfigParameters(bool oneP
|
||||
auto configs = combineAudioConfig(profile.getChannelMasks(),
|
||||
profile.getSamplingRates(), profile.getFormat());
|
||||
for (const auto& config : configs) {
|
||||
result.emplace_back(device, mixPort.getName(), config, flags);
|
||||
result.emplace_back(device, mixPort.getName(), attachedDeviceAddress.value(),
|
||||
config, flags);
|
||||
if (oneProfilePerDevice) break;
|
||||
}
|
||||
if (oneProfilePerDevice) break;
|
||||
@@ -298,20 +300,25 @@ const std::vector<DeviceConfigParameter>& getInputDeviceInvalidConfigParameters(
|
||||
profile.getFormat(),
|
||||
static_cast<uint32_t>(profile.getSamplingRates()[0]),
|
||||
toString(profile.getChannelMasks()[0])};
|
||||
DeviceAddress defaultDevice = {
|
||||
toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT), {}};
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.base.channelMask = "random_string";
|
||||
result.emplace_back(device, mixPort.getName(), config, validFlags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
validFlags);
|
||||
}
|
||||
{
|
||||
AudioConfig config{.base = validBase};
|
||||
config.base.format = "random_string";
|
||||
result.emplace_back(device, mixPort.getName(), config, validFlags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
validFlags);
|
||||
}
|
||||
if (generateInvalidFlags) {
|
||||
AudioConfig config{.base = validBase};
|
||||
std::vector<AudioInOutFlag> flags = {"random_string", ""};
|
||||
result.emplace_back(device, mixPort.getName(), config, flags);
|
||||
result.emplace_back(device, mixPort.getName(), defaultDevice, config,
|
||||
flags);
|
||||
}
|
||||
hasConfig = true;
|
||||
break;
|
||||
|
||||
@@ -61,6 +61,18 @@ class PolicyConfig {
|
||||
const std::set<std::string>& getModulesWithDevicesNames() const {
|
||||
return mModulesWithDevicesNames;
|
||||
}
|
||||
std::optional<DeviceAddress> getDeviceAddressOfSinkDeviceAttachedToMixPort(
|
||||
const std::string& moduleName, const std::string& mixPortName) const {
|
||||
const auto attachedDevicePort = getAttachedSinkDeviceForMixPort(moduleName, mixPortName);
|
||||
if (attachedDevicePort.empty()) return {};
|
||||
return getDeviceAddressOfDevicePort(moduleName, attachedDevicePort);
|
||||
}
|
||||
std::optional<DeviceAddress> getDeviceAddressOfSourceDeviceAttachedToMixPort(
|
||||
const std::string& moduleName, const std::string& mixPortName) const {
|
||||
const auto attachedDevicePort = getAttachedSourceDeviceForMixPort(moduleName, mixPortName);
|
||||
if (attachedDevicePort.empty()) return {};
|
||||
return getDeviceAddressOfDevicePort(moduleName, attachedDevicePort);
|
||||
}
|
||||
std::string getAttachedSinkDeviceForMixPort(const std::string& moduleName,
|
||||
const std::string& mixPortName) const {
|
||||
return findAttachedDevice(getAttachedDevices(moduleName),
|
||||
@@ -84,8 +96,6 @@ class PolicyConfig {
|
||||
const std::vector<std::string>& getAttachedDevices(const std::string& moduleName) const;
|
||||
std::optional<DeviceAddress> getDeviceAddressOfDevicePort(
|
||||
const std::string& moduleName, const std::string& devicePortName) const;
|
||||
std::string getDevicePortTagNameFromType(const std::string& moduleName,
|
||||
const AudioDevice& deviceType) const;
|
||||
std::set<std::string> getSinkDevicesForMixPort(const std::string& moduleName,
|
||||
const std::string& mixPortName) const;
|
||||
std::set<std::string> getSourceDevicesForMixPort(const std::string& moduleName,
|
||||
|
||||
@@ -34,6 +34,7 @@ cc_defaults {
|
||||
],
|
||||
shared_libs: [
|
||||
"libbinder",
|
||||
"libcutils",
|
||||
"libfmq",
|
||||
"libxml2",
|
||||
],
|
||||
@@ -190,6 +191,7 @@ cc_test {
|
||||
],
|
||||
data: [
|
||||
":audio_policy_configuration_V7_0",
|
||||
"data/sine882hz3s.mp3",
|
||||
],
|
||||
// Use test_config for vts suite.
|
||||
// TODO(b/146104851): Add auto-gen rules and remove it.
|
||||
@@ -223,6 +225,7 @@ cc_test {
|
||||
],
|
||||
data: [
|
||||
":audio_policy_configuration_V7_1",
|
||||
"data/sine882hz3s.mp3",
|
||||
],
|
||||
// Use test_config for vts suite.
|
||||
// TODO(b/146104851): Add auto-gen rules and remove it.
|
||||
|
||||
@@ -617,7 +617,8 @@ static std::string DeviceConfigParameterToString(
|
||||
std::get<PARAM_FLAGS>(info.param)));
|
||||
#elif MAJOR_VERSION >= 7
|
||||
const auto configPart =
|
||||
std::to_string(config.base.sampleRateHz) + "_" +
|
||||
::testing::PrintToString(std::get<PARAM_ATTACHED_DEV_ADDR>(info.param).deviceType) +
|
||||
"_" + std::to_string(config.base.sampleRateHz) + "_" +
|
||||
// The channel masks and flags are vectors of strings, just need to sanitize them.
|
||||
SanitizeStringForGTestName(::testing::PrintToString(config.base.channelMask)) + "_" +
|
||||
SanitizeStringForGTestName(::testing::PrintToString(std::get<PARAM_FLAGS>(info.param)));
|
||||
@@ -658,6 +659,9 @@ class AudioHidlTestWithDeviceConfigParameter
|
||||
std::get<INDEX_OUTPUT>(std::get<PARAM_FLAGS>(GetParam())));
|
||||
}
|
||||
#elif MAJOR_VERSION >= 7
|
||||
DeviceAddress getAttachedDeviceAddress() const {
|
||||
return std::get<PARAM_ATTACHED_DEV_ADDR>(GetParam());
|
||||
}
|
||||
hidl_vec<AudioInOutFlag> getInputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
|
||||
hidl_vec<AudioInOutFlag> getOutputFlags() const { return std::get<PARAM_FLAGS>(GetParam()); }
|
||||
#endif
|
||||
@@ -933,6 +937,15 @@ class StreamWriter : public StreamWorker<StreamWriter> {
|
||||
|
||||
StreamWriter(IStreamOut* stream, size_t bufferSize)
|
||||
: mStream(stream), mBufferSize(bufferSize), mData(mBufferSize) {}
|
||||
StreamWriter(IStreamOut* stream, size_t bufferSize, std::vector<uint8_t>&& data,
|
||||
std::function<void()> onDataStart, std::function<bool()> onDataWrap)
|
||||
: mStream(stream),
|
||||
mBufferSize(bufferSize),
|
||||
mData(std::move(data)),
|
||||
mOnDataStart(onDataStart),
|
||||
mOnDataWrap(onDataWrap) {
|
||||
ALOGI("StreamWriter data size: %d", (int)mData.size());
|
||||
}
|
||||
~StreamWriter() {
|
||||
stop();
|
||||
if (mEfGroup) {
|
||||
@@ -998,9 +1011,12 @@ class StreamWriter : public StreamWorker<StreamWriter> {
|
||||
ALOGE("command message queue write failed");
|
||||
return false;
|
||||
}
|
||||
const size_t dataSize = std::min(mData.size(), mDataMQ->availableToWrite());
|
||||
bool success = mDataMQ->write(mData.data(), dataSize);
|
||||
if (mDataPosition == 0) mOnDataStart();
|
||||
const size_t dataSize = std::min(mData.size() - mDataPosition, mDataMQ->availableToWrite());
|
||||
bool success = mDataMQ->write(mData.data() + mDataPosition, dataSize);
|
||||
ALOGE_IF(!success, "data message queue write failed");
|
||||
mDataPosition += dataSize;
|
||||
if (mDataPosition >= mData.size()) mDataPosition = 0;
|
||||
mEfGroup->wake(static_cast<uint32_t>(MessageQueueFlagBits::NOT_EMPTY));
|
||||
|
||||
uint32_t efState = 0;
|
||||
@@ -1026,6 +1042,9 @@ class StreamWriter : public StreamWorker<StreamWriter> {
|
||||
ALOGE("bad wait status: %d", ret);
|
||||
success = false;
|
||||
}
|
||||
if (success && mDataPosition == 0) {
|
||||
success = mOnDataWrap();
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -1033,6 +1052,9 @@ class StreamWriter : public StreamWorker<StreamWriter> {
|
||||
IStreamOut* const mStream;
|
||||
const size_t mBufferSize;
|
||||
std::vector<uint8_t> mData;
|
||||
std::function<void()> mOnDataStart = []() {};
|
||||
std::function<bool()> mOnDataWrap = []() { return true; };
|
||||
size_t mDataPosition = 0;
|
||||
std::unique_ptr<CommandMQ> mCommandMQ;
|
||||
std::unique_ptr<DataMQ> mDataMQ;
|
||||
std::unique_ptr<StatusMQ> mStatusMQ;
|
||||
@@ -1047,7 +1069,7 @@ class OutputStreamTest
|
||||
#if MAJOR_VERSION <= 6
|
||||
address.device = AudioDevice::OUT_DEFAULT;
|
||||
#elif MAJOR_VERSION >= 7
|
||||
address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_OUT_DEFAULT);
|
||||
address = getAttachedDeviceAddress();
|
||||
#endif
|
||||
const AudioConfig& config = getConfig();
|
||||
auto flags = getOutputFlags();
|
||||
@@ -1243,16 +1265,11 @@ class InputStreamTest
|
||||
#if MAJOR_VERSION <= 6
|
||||
address.device = AudioDevice::IN_DEFAULT;
|
||||
#elif MAJOR_VERSION >= 7
|
||||
auto maybeSourceAddress = getCachedPolicyConfig().getSourceDeviceForMixPort(
|
||||
getDeviceName(), getMixPortName());
|
||||
address = getAttachedDeviceAddress();
|
||||
auto& metadata = initMetadata.tracks[0];
|
||||
if (maybeSourceAddress.has_value() &&
|
||||
!xsd::isTelephonyDevice(maybeSourceAddress.value().deviceType)) {
|
||||
address = maybeSourceAddress.value();
|
||||
if (!xsd::isTelephonyDevice(address.deviceType)) {
|
||||
metadata.source = toString(xsd::AudioSource::AUDIO_SOURCE_UNPROCESSED);
|
||||
metadata.channelMask = getConfig().base.channelMask;
|
||||
} else {
|
||||
address.deviceType = toString(xsd::AudioDevice::AUDIO_DEVICE_IN_DEFAULT);
|
||||
}
|
||||
#if MAJOR_VERSION == 7 && MINOR_VERSION >= 1
|
||||
auto flagsIt = std::find(flags.begin(), flags.end(),
|
||||
|
||||
@@ -39,9 +39,10 @@ using DeviceConfigParameter = std::tuple<
|
||||
std::variant<android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::AudioInputFlag,
|
||||
android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::AudioOutputFlag>>;
|
||||
#elif MAJOR_VERSION >= 7
|
||||
enum { PARAM_DEVICE, PARAM_PORT_NAME, PARAM_CONFIG, PARAM_FLAGS };
|
||||
enum { PARAM_DEVICE, PARAM_PORT_NAME, PARAM_ATTACHED_DEV_ADDR, PARAM_CONFIG, PARAM_FLAGS };
|
||||
using DeviceConfigParameter =
|
||||
std::tuple<DeviceParameter, std::string,
|
||||
android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::DeviceAddress,
|
||||
android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::AudioConfig,
|
||||
std::vector<android::hardware::audio::CORE_TYPES_CPP_VERSION::AudioInOutFlag>>;
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push" value="VtsHalAudioV7_0TargetTest->/data/local/tmp/VtsHalAudioV7_0TargetTest" />
|
||||
<option name="push" value="audio_policy_configuration_V7_0.xsd->/data/local/tmp/audio_policy_configuration_V7_0.xsd" />
|
||||
<option name="push" value="sine882hz3s.mp3->/data/local/tmp/sine882hz3s.mp3" />
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.GTest" >
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push" value="VtsHalAudioV7_1TargetTest->/data/local/tmp/VtsHalAudioV7_1TargetTest" />
|
||||
<option name="push" value="audio_policy_configuration_V7_1.xsd->/data/local/tmp/audio_policy_configuration_V7_1.xsd" />
|
||||
<option name="push" value="sine882hz3s.mp3->/data/local/tmp/sine882hz3s.mp3" />
|
||||
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.GTest" >
|
||||
|
||||
BIN
audio/core/all-versions/vts/functional/data/sine882hz3s.mp3
Normal file
BIN
audio/core/all-versions/vts/functional/data/sine882hz3s.mp3
Normal file
Binary file not shown.
@@ -18,6 +18,7 @@
|
||||
#include "HandleImporter.h"
|
||||
|
||||
#include <gralloctypes/Gralloc4.h>
|
||||
#include "aidl/android/hardware/graphics/common/Smpte2086.h"
|
||||
#include <log/log.h>
|
||||
|
||||
namespace android {
|
||||
@@ -30,6 +31,7 @@ namespace helper {
|
||||
using aidl::android::hardware::graphics::common::PlaneLayout;
|
||||
using aidl::android::hardware::graphics::common::PlaneLayoutComponent;
|
||||
using aidl::android::hardware::graphics::common::PlaneLayoutComponentType;
|
||||
using aidl::android::hardware::graphics::common::Smpte2086;
|
||||
using MetadataType = android::hardware::graphics::mapper::V4_0::IMapper::MetadataType;
|
||||
using MapperErrorV2 = android::hardware::graphics::mapper::V2_0::Error;
|
||||
using MapperErrorV3 = android::hardware::graphics::mapper::V3_0::Error;
|
||||
@@ -127,16 +129,35 @@ YCbCrLayout HandleImporter::lockYCbCrInternal(const sp<M> mapper, buffer_handle_
|
||||
bool isMetadataPesent(const sp<IMapperV4> mapper, const buffer_handle_t& buf,
|
||||
MetadataType metadataType) {
|
||||
auto buffer = const_cast<native_handle_t*>(buf);
|
||||
mapper->get(buffer, metadataType, [] (const auto& tmpError,
|
||||
bool ret = false;
|
||||
hidl_vec<uint8_t> vec;
|
||||
mapper->get(buffer, metadataType, [&] (const auto& tmpError,
|
||||
const auto& tmpMetadata) {
|
||||
if (tmpError == MapperErrorV4::NONE) {
|
||||
return tmpMetadata.size() > 0;
|
||||
vec = tmpMetadata;
|
||||
} else {
|
||||
ALOGE("%s: failed to get metadata %d!", __FUNCTION__, tmpError);
|
||||
return false;
|
||||
}});
|
||||
|
||||
return false;
|
||||
if (vec.size() > 0) {
|
||||
if (metadataType == gralloc4::MetadataType_Smpte2086){
|
||||
std::optional<Smpte2086> realSmpte2086;
|
||||
gralloc4::decodeSmpte2086(vec, &realSmpte2086);
|
||||
ret = realSmpte2086.has_value();
|
||||
} else if (metadataType == gralloc4::MetadataType_Smpte2094_10) {
|
||||
std::optional<std::vector<uint8_t>> realSmpte2094_10;
|
||||
gralloc4::decodeSmpte2094_10(vec, &realSmpte2094_10);
|
||||
ret = realSmpte2094_10.has_value();
|
||||
} else if (metadataType == gralloc4::MetadataType_Smpte2094_40) {
|
||||
std::optional<std::vector<uint8_t>> realSmpte2094_40;
|
||||
gralloc4::decodeSmpte2094_40(vec, &realSmpte2094_40);
|
||||
ret = realSmpte2094_40.has_value();
|
||||
} else {
|
||||
ALOGE("%s: Unknown metadata type!", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::vector<PlaneLayout> getPlaneLayouts(const sp<IMapperV4> mapper, buffer_handle_t& buf) {
|
||||
|
||||
@@ -1739,6 +1739,10 @@ TEST_P(CameraAidlTest, processUltraHighResolutionRequest) {
|
||||
|
||||
std::list<PixelFormat> pixelFormats = {PixelFormat::YCBCR_420_888, PixelFormat::RAW16};
|
||||
for (PixelFormat format : pixelFormats) {
|
||||
previewStream.usage =
|
||||
static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
|
||||
GRALLOC1_CONSUMER_USAGE_CPU_READ);
|
||||
previewStream.dataSpace = Dataspace::UNKNOWN;
|
||||
configureStreams(name, mProvider, format, &mSession, &previewStream, &halStreams,
|
||||
&supportsPartialResults, &partialResultCount, &useHalBufManager, &cb,
|
||||
0, /*maxResolution*/ true);
|
||||
@@ -1843,7 +1847,6 @@ TEST_P(CameraAidlTest, processUltraHighResolutionRequest) {
|
||||
TEST_P(CameraAidlTest, process10BitDynamicRangeRequest) {
|
||||
std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
|
||||
int64_t bufferId = 1;
|
||||
int32_t frameNumber = 1;
|
||||
CameraMetadata settings;
|
||||
|
||||
for (const auto& name : cameraDeviceNames) {
|
||||
@@ -1866,7 +1869,7 @@ TEST_P(CameraAidlTest, process10BitDynamicRangeRequest) {
|
||||
CameraMetadata req;
|
||||
android::hardware::camera::common::V1_0::helper::CameraMetadata defaultSettings;
|
||||
ndk::ScopedAStatus ret =
|
||||
mSession->constructDefaultRequestSettings(RequestTemplate::STILL_CAPTURE, &req);
|
||||
mSession->constructDefaultRequestSettings(RequestTemplate::PREVIEW, &req);
|
||||
ASSERT_TRUE(ret.isOk());
|
||||
|
||||
const camera_metadata_t* metadata =
|
||||
@@ -1896,6 +1899,10 @@ TEST_P(CameraAidlTest, process10BitDynamicRangeRequest) {
|
||||
Stream previewStream;
|
||||
std::shared_ptr<DeviceCb> cb;
|
||||
for (const auto& profile : profileList) {
|
||||
previewStream.usage =
|
||||
static_cast<aidl::android::hardware::graphics::common::BufferUsage>(
|
||||
GRALLOC1_CONSUMER_USAGE_HWCOMPOSER);
|
||||
previewStream.dataSpace = getDataspace(PixelFormat::IMPLEMENTATION_DEFINED);
|
||||
configureStreams(name, mProvider, PixelFormat::IMPLEMENTATION_DEFINED, &mSession,
|
||||
&previewStream, &halStreams, &supportsPartialResults,
|
||||
&partialResultCount, &useHalBufManager, &cb, 0,
|
||||
@@ -1916,63 +1923,75 @@ TEST_P(CameraAidlTest, process10BitDynamicRangeRequest) {
|
||||
// Don't use the queue onwards.
|
||||
}
|
||||
|
||||
std::vector<buffer_handle_t> graphicBuffers;
|
||||
graphicBuffers.reserve(halStreams.size());
|
||||
mInflightMap.clear();
|
||||
// Stream as long as needed to fill the Hal inflight queue
|
||||
std::vector<CaptureRequest> requests(halStreams[0].maxBuffers);
|
||||
|
||||
std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
|
||||
static_cast<ssize_t>(halStreams.size()), false, supportsPartialResults,
|
||||
partialResultCount, std::unordered_set<std::string>(), resultQueue);
|
||||
for (int32_t frameNumber = 0; frameNumber < requests.size(); frameNumber++) {
|
||||
std::shared_ptr<InFlightRequest> inflightReq = std::make_shared<InFlightRequest>(
|
||||
static_cast<ssize_t>(halStreams.size()), false, supportsPartialResults,
|
||||
partialResultCount, std::unordered_set<std::string>(), resultQueue);
|
||||
|
||||
std::vector<CaptureRequest> requests(1);
|
||||
CaptureRequest& request = requests[0];
|
||||
std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
|
||||
outputBuffers.resize(halStreams.size());
|
||||
CaptureRequest& request = requests[frameNumber];
|
||||
std::vector<StreamBuffer>& outputBuffers = request.outputBuffers;
|
||||
outputBuffers.resize(halStreams.size());
|
||||
|
||||
size_t k = 0;
|
||||
for (const auto& halStream : halStreams) {
|
||||
buffer_handle_t buffer_handle;
|
||||
if (useHalBufManager) {
|
||||
outputBuffers[k] = {halStream.id, 0,
|
||||
NativeHandle(), BufferStatus::OK,
|
||||
NativeHandle(), NativeHandle()};
|
||||
} else {
|
||||
allocateGraphicBuffer(previewStream.width, previewStream.height,
|
||||
android_convertGralloc1To0Usage(
|
||||
static_cast<uint64_t>(halStream.producerUsage),
|
||||
static_cast<uint64_t>(halStream.consumerUsage)),
|
||||
halStream.overrideFormat, &buffer_handle);
|
||||
size_t k = 0;
|
||||
inflightReq->mOutstandingBufferIds.resize(halStreams.size());
|
||||
std::vector<buffer_handle_t> graphicBuffers;
|
||||
graphicBuffers.reserve(halStreams.size());
|
||||
|
||||
graphicBuffers.push_back(buffer_handle);
|
||||
outputBuffers[k] = {
|
||||
halStream.id, bufferId, android::makeToAidl(buffer_handle),
|
||||
BufferStatus::OK, NativeHandle(), NativeHandle()};
|
||||
bufferId++;
|
||||
for (const auto& halStream : halStreams) {
|
||||
buffer_handle_t buffer_handle;
|
||||
if (useHalBufManager) {
|
||||
outputBuffers[k] = {halStream.id, 0,
|
||||
NativeHandle(), BufferStatus::OK,
|
||||
NativeHandle(), NativeHandle()};
|
||||
} else {
|
||||
auto usage = android_convertGralloc1To0Usage(
|
||||
static_cast<uint64_t>(halStream.producerUsage),
|
||||
static_cast<uint64_t>(halStream.consumerUsage));
|
||||
allocateGraphicBuffer(previewStream.width, previewStream.height, usage,
|
||||
halStream.overrideFormat, &buffer_handle);
|
||||
|
||||
inflightReq->mOutstandingBufferIds[halStream.id][bufferId] = buffer_handle;
|
||||
graphicBuffers.push_back(buffer_handle);
|
||||
outputBuffers[k] = {halStream.id, bufferId,
|
||||
android::makeToAidl(buffer_handle), BufferStatus::OK, NativeHandle(),
|
||||
NativeHandle()};
|
||||
bufferId++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
k++;
|
||||
}
|
||||
|
||||
request.inputBuffer = {
|
||||
-1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
|
||||
request.frameNumber = frameNumber;
|
||||
request.fmqSettingsSize = 0;
|
||||
request.settings = settings;
|
||||
request.inputWidth = 0;
|
||||
request.inputHeight = 0;
|
||||
request.inputBuffer = {
|
||||
-1, 0, NativeHandle(), BufferStatus::ERROR, NativeHandle(), NativeHandle()};
|
||||
request.frameNumber = frameNumber;
|
||||
request.fmqSettingsSize = 0;
|
||||
request.settings = settings;
|
||||
request.inputWidth = 0;
|
||||
request.inputHeight = 0;
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mLock);
|
||||
mInflightMap[frameNumber] = inflightReq;
|
||||
}
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> l(mLock);
|
||||
mInflightMap.clear();
|
||||
mInflightMap[frameNumber] = inflightReq;
|
||||
}
|
||||
|
||||
int32_t numRequestProcessed = 0;
|
||||
std::vector<BufferCache> cachesToRemove;
|
||||
ndk::ScopedAStatus returnStatus =
|
||||
mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
|
||||
mSession->processCaptureRequest(requests, cachesToRemove, &numRequestProcessed);
|
||||
ASSERT_TRUE(returnStatus.isOk());
|
||||
ASSERT_EQ(numRequestProcessed, 1u);
|
||||
ASSERT_EQ(numRequestProcessed, requests.size());
|
||||
|
||||
{
|
||||
returnStatus = mSession->repeatingRequestEnd(requests.size() - 1,
|
||||
std::vector<int32_t> {halStreams[0].id});
|
||||
ASSERT_TRUE(returnStatus.isOk());
|
||||
|
||||
for (int32_t frameNumber = 0; frameNumber < requests.size(); frameNumber++) {
|
||||
const auto& inflightReq = mInflightMap[frameNumber];
|
||||
std::unique_lock<std::mutex> l(mLock);
|
||||
while (!inflightReq->errorCodeValid &&
|
||||
((0 < inflightReq->numBuffersLeft) || (!inflightReq->haveResultMetadata))) {
|
||||
@@ -1985,6 +2004,7 @@ TEST_P(CameraAidlTest, process10BitDynamicRangeRequest) {
|
||||
ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
|
||||
verify10BitMetadata(mHandleImporter, *inflightReq, profile);
|
||||
}
|
||||
|
||||
if (useHalBufManager) {
|
||||
std::vector<int32_t> streamIds(halStreams.size());
|
||||
for (size_t i = 0; i < streamIds.size(); i++) {
|
||||
|
||||
@@ -2639,8 +2639,20 @@ void CameraAidlTest::configureStreams(const std::string& name,
|
||||
|
||||
outputStreams.clear();
|
||||
Size maxSize;
|
||||
auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
|
||||
ASSERT_EQ(Status::OK, rc);
|
||||
if (maxResolution) {
|
||||
auto rc = getMaxOutputSizeForFormat(staticMeta, format, &maxSize, maxResolution);
|
||||
ASSERT_EQ(Status::OK, rc);
|
||||
} else {
|
||||
AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
|
||||
static_cast<int32_t>(format)};
|
||||
auto rc = getAvailableOutputStreams(staticMeta, outputStreams, &previewThreshold);
|
||||
|
||||
ASSERT_EQ(Status::OK, rc);
|
||||
ASSERT_FALSE(outputStreams.empty());
|
||||
maxSize.width = outputStreams[0].width;
|
||||
maxSize.height = outputStreams[0].height;
|
||||
}
|
||||
|
||||
|
||||
std::vector<Stream> streams(1);
|
||||
streams[0] = {0,
|
||||
@@ -2648,9 +2660,8 @@ void CameraAidlTest::configureStreams(const std::string& name,
|
||||
maxSize.width,
|
||||
maxSize.height,
|
||||
format,
|
||||
static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
|
||||
GRALLOC1_CONSUMER_USAGE_CPU_READ),
|
||||
Dataspace::UNKNOWN,
|
||||
previewStream->usage,
|
||||
previewStream->dataSpace,
|
||||
StreamRotation::ROTATION_0,
|
||||
"",
|
||||
0,
|
||||
@@ -2736,7 +2747,8 @@ void CameraAidlTest::verify10BitMetadata(
|
||||
HandleImporter& importer, const InFlightRequest& request,
|
||||
aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap
|
||||
profile) {
|
||||
for (const auto& b : request.resultOutputBuffers) {
|
||||
for (auto b : request.resultOutputBuffers) {
|
||||
importer.importBuffer(b.buffer.buffer);
|
||||
bool smpte2086Present = importer.isSmpte2086Present(b.buffer.buffer);
|
||||
bool smpte2094_10Present = importer.isSmpte2094_10Present(b.buffer.buffer);
|
||||
bool smpte2094_40Present = importer.isSmpte2094_40Present(b.buffer.buffer);
|
||||
@@ -2753,7 +2765,6 @@ void CameraAidlTest::verify10BitMetadata(
|
||||
ASSERT_FALSE(smpte2094_40Present);
|
||||
break;
|
||||
case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
|
||||
ASSERT_FALSE(smpte2086Present);
|
||||
ASSERT_FALSE(smpte2094_10Present);
|
||||
ASSERT_TRUE(smpte2094_40Present);
|
||||
break;
|
||||
@@ -2774,6 +2785,7 @@ void CameraAidlTest::verify10BitMetadata(
|
||||
profile);
|
||||
ADD_FAILURE();
|
||||
}
|
||||
importer.freeBuffer(b.buffer.buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -399,6 +399,10 @@ class CameraAidlTest : public ::testing::TestWithParam<std::string> {
|
||||
// Result metadata
|
||||
::android::hardware::camera::common::V1_0::helper::CameraMetadata collectedResult;
|
||||
|
||||
// Inflight buffers
|
||||
using OutstandingBuffers = std::unordered_map<uint64_t, buffer_handle_t>;
|
||||
std::vector<OutstandingBuffers> mOutstandingBufferIds;
|
||||
|
||||
// A copy-able StreamBuffer using buffer_handle_t instead of AIDLs NativeHandle
|
||||
struct NativeStreamBuffer {
|
||||
int32_t streamId;
|
||||
|
||||
@@ -155,7 +155,7 @@ ScopedAStatus DeviceCb::requestStreamBuffers(const std::vector<BufferRequest>& b
|
||||
BufferStatus::OK, NativeHandle(), NativeHandle(),
|
||||
};
|
||||
|
||||
mOutstandingBufferIds[idx][mNextBufferId++] = ::android::dupToAidl(handle);
|
||||
mOutstandingBufferIds[idx][mNextBufferId++] = handle;
|
||||
}
|
||||
atLeastOneStreamOk = true;
|
||||
bufRets[i].streamId = stream.id;
|
||||
@@ -427,9 +427,13 @@ bool DeviceCb::processCaptureResultLocked(
|
||||
}
|
||||
|
||||
CameraAidlTest::InFlightRequest::StreamBufferAndTimestamp streamBufferAndTimestamp;
|
||||
auto outstandingBuffers = mUseHalBufManager ? mOutstandingBufferIds :
|
||||
request->mOutstandingBufferIds;
|
||||
auto outputBuffer = outstandingBuffers.empty() ? ::android::makeFromAidl(buffer.buffer) :
|
||||
outstandingBuffers[buffer.streamId][buffer.bufferId];
|
||||
streamBufferAndTimestamp.buffer = {buffer.streamId,
|
||||
buffer.bufferId,
|
||||
::android::makeFromAidl(buffer.buffer),
|
||||
outputBuffer,
|
||||
buffer.status,
|
||||
::android::makeFromAidl(buffer.acquireFence),
|
||||
::android::makeFromAidl(buffer.releaseFence)};
|
||||
|
||||
@@ -73,7 +73,7 @@ class DeviceCb : public BnCameraDeviceCallback {
|
||||
std::vector<Stream> mStreams;
|
||||
std::vector<HalStream> mHalStreams;
|
||||
int64_t mNextBufferId = 1;
|
||||
using OutstandingBuffers = std::unordered_map<uint64_t, NativeHandle>;
|
||||
using OutstandingBuffers = std::unordered_map<uint64_t, buffer_handle_t>;
|
||||
// size == mStreams.size(). Tracking each streams outstanding buffers
|
||||
std::vector<OutstandingBuffers> mOutstandingBufferIds;
|
||||
std::condition_variable mFlushedCondition;
|
||||
|
||||
34
sensors/aidl/vts/AndroidTest.xml
Normal file
34
sensors/aidl/vts/AndroidTest.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2022 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.
|
||||
-->
|
||||
<configuration description="Runs VtsAidlHalSensorsTargetTest.">
|
||||
<option name="test-suite-tag" value="apct" />
|
||||
<option name="test-suite-tag" value="apct-native" />
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
|
||||
<target_preparer class="com.android.tradefed.targetprep.StopServicesSetup"/>
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push" value="VtsAidlHalSensorsTargetTest->/data/local/tmp/VtsAidlHalSensorsTargetTest" />
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.GTest" >
|
||||
<option name="native-test-timeout" value="900000" />
|
||||
<option name="runtime-hint" value="300000"/>
|
||||
<option name="native-test-device-path" value="/data/local/tmp" />
|
||||
<option name="module-name" value="VtsAidlHalSensorsTargetTest" />
|
||||
</test>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user