audio: Parametrize core VTS tests am: ccd484bb80
am: 51a1ee3c24
Change-Id: I9acd77cca413c95ceea6538ae04206999b2243d5
This commit is contained in:
commit
c88b96fe3e
7 changed files with 537 additions and 202 deletions
|
@ -20,9 +20,6 @@
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include <VtsHalHidlTargetTestEnvBase.h>
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
|
|
||||||
namespace android {
|
namespace android {
|
||||||
namespace hardware {
|
namespace hardware {
|
||||||
namespace audio {
|
namespace audio {
|
||||||
|
@ -34,18 +31,20 @@ namespace utility {
|
||||||
* Avoid destroying static objects after main return.
|
* Avoid destroying static objects after main return.
|
||||||
* Post main return destruction leads to incorrect gtest timing measurements as
|
* Post main return destruction leads to incorrect gtest timing measurements as
|
||||||
* well as harder debuging if anything goes wrong during destruction. */
|
* well as harder debuging if anything goes wrong during destruction. */
|
||||||
class Environment : public ::testing::VtsHalHidlTargetTestEnvBase {
|
class EnvironmentTearDown {
|
||||||
public:
|
public:
|
||||||
using TearDownFunc = std::function<void()>;
|
using TearDownFunc = std::function<void()>;
|
||||||
void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_front(std::move(tearDown)); }
|
void registerTearDown(TearDownFunc&& tearDown) { tearDowns.push_front(std::move(tearDown)); }
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void HidlTearDown() override {
|
void executeAllTearDowns() {
|
||||||
// Call the tear downs in reverse order of insertion
|
// Call the tear downs in reverse order of insertion
|
||||||
for (auto& tearDown : tearDowns) {
|
for (auto& tearDown : tearDowns) {
|
||||||
tearDown();
|
tearDown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
std::list<TearDownFunc> tearDowns;
|
std::list<TearDownFunc> tearDowns;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -60,19 +60,20 @@ TEST_IO_STREAM(SetConnectedState,
|
||||||
"deconnection",
|
"deconnection",
|
||||||
testConnectedState(stream.get()))
|
testConnectedState(stream.get()))
|
||||||
|
|
||||||
TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", ASSERT_IS_OK(device->getHwAvSync()));
|
TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail",
|
||||||
|
ASSERT_IS_OK(getDevice()->getHwAvSync()));
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, setMode) {
|
TEST_P(AudioPrimaryHidlTest, setMode) {
|
||||||
doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
|
doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
|
||||||
// Test Invalid values
|
// Test Invalid values
|
||||||
for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) {
|
for (AudioMode mode : {AudioMode::INVALID, AudioMode::CURRENT, AudioMode::CNT}) {
|
||||||
SCOPED_TRACE("mode=" + toString(mode));
|
SCOPED_TRACE("mode=" + toString(mode));
|
||||||
ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(mode));
|
ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(mode));
|
||||||
}
|
}
|
||||||
// Test valid values
|
// Test valid values
|
||||||
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
|
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
|
||||||
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
|
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
|
||||||
SCOPED_TRACE("mode=" + toString(mode));
|
SCOPED_TRACE("mode=" + toString(mode));
|
||||||
ASSERT_OK(device->setMode(mode));
|
ASSERT_OK(getDevice()->setMode(mode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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 ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
|
||||||
|
#define ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
|
||||||
|
|
||||||
|
#include <VtsHalHidlTargetTestEnvBase.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "utility/EnvironmentTearDown.h"
|
||||||
|
|
||||||
|
class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
|
||||||
|
public ::testing::VtsHalHidlTargetTestEnvBase {
|
||||||
|
private:
|
||||||
|
void HidlTearDown() override {
|
||||||
|
executeAllTearDowns();
|
||||||
|
VtsHalHidlTargetTestEnvBase::HidlTearDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ANDROID_HARDWARE_AUDIO_CORE_2_0_ENVIRONMENT_TEARDOWN_H
|
|
@ -16,25 +16,14 @@
|
||||||
|
|
||||||
#include "AudioPrimaryHidlHalTest.h"
|
#include "AudioPrimaryHidlHalTest.h"
|
||||||
|
|
||||||
static void waitForDeviceDestruction() {
|
TEST_P(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
|
||||||
// FIXME: there is no way to know when the remote IDevice is being destroyed
|
|
||||||
// Binder does not support testing if an object is alive, thus
|
|
||||||
// wait for 100ms to let the binder destruction propagates and
|
|
||||||
// the remote device has the time to be destroyed.
|
|
||||||
// flushCommand makes sure all local command are sent, thus should reduce
|
|
||||||
// the latency between local and remote destruction.
|
|
||||||
IPCThreadState::self()->flushCommands();
|
|
||||||
usleep(100 * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
|
|
||||||
doc::test("Calling openDevice(\"primary\") should return the primary device.");
|
doc::test("Calling openDevice(\"primary\") should return the primary device.");
|
||||||
struct WaitExecutor {
|
struct WaitExecutor {
|
||||||
~WaitExecutor() { waitForDeviceDestruction(); }
|
~WaitExecutor() { DeviceManager::waitForInstanceDestruction(); }
|
||||||
} waitExecutor; // Make sure we wait for the device destruction on exiting from the test.
|
} waitExecutor; // Make sure we wait for the device destruction on exiting from the test.
|
||||||
Result result;
|
Result result;
|
||||||
sp<IDevice> baseDevice;
|
sp<IDevice> baseDevice;
|
||||||
ASSERT_OK(devicesFactory->openDevice("primary", returnIn(result, baseDevice)));
|
ASSERT_OK(getDevicesFactory()->openDevice("primary", returnIn(result, baseDevice)));
|
||||||
if (result != Result::OK && isPrimaryDeviceOptional()) {
|
if (result != Result::OK && isPrimaryDeviceOptional()) {
|
||||||
GTEST_SKIP() << "No primary device on this factory"; // returns
|
GTEST_SKIP() << "No primary device on this factory"; // returns
|
||||||
}
|
}
|
||||||
|
@ -50,10 +39,10 @@ TEST_F(AudioHidlTest, OpenPrimaryDeviceUsingGetDevice) {
|
||||||
/////////////////////////// get(Active)Microphones ///////////////////////////
|
/////////////////////////// get(Active)Microphones ///////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) {
|
TEST_P(AudioPrimaryHidlTest, GetMicrophonesTest) {
|
||||||
doc::test("Make sure getMicrophones always succeeds");
|
doc::test("Make sure getMicrophones always succeeds");
|
||||||
hidl_vec<MicrophoneInfo> microphones;
|
hidl_vec<MicrophoneInfo> microphones;
|
||||||
ASSERT_OK(device->getMicrophones(returnIn(res, microphones)));
|
ASSERT_OK(getDevice()->getMicrophones(returnIn(res, microphones)));
|
||||||
ASSERT_OK(res);
|
ASSERT_OK(res);
|
||||||
if (microphones.size() > 0) {
|
if (microphones.size() > 0) {
|
||||||
// When there is microphone on the phone, try to open an input stream
|
// When there is microphone on the phone, try to open an input stream
|
||||||
|
@ -75,15 +64,15 @@ TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) {
|
||||||
}
|
}
|
||||||
sp<IStreamIn> stream;
|
sp<IStreamIn> stream;
|
||||||
AudioConfig suggestedConfig{};
|
AudioConfig suggestedConfig{};
|
||||||
ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress, config, flags,
|
ASSERT_OK(getDevice()->openInputStream(ioHandle, microphone.deviceAddress, config,
|
||||||
initMetadata,
|
flags, initMetadata,
|
||||||
returnIn(res, stream, suggestedConfig)));
|
returnIn(res, stream, suggestedConfig)));
|
||||||
if (res != Result::OK) {
|
if (res != Result::OK) {
|
||||||
ASSERT_TRUE(stream == nullptr);
|
ASSERT_TRUE(stream == nullptr);
|
||||||
AudioConfig suggestedConfigRetry{};
|
AudioConfig suggestedConfigRetry{};
|
||||||
ASSERT_OK(device->openInputStream(ioHandle, microphone.deviceAddress,
|
ASSERT_OK(getDevice()->openInputStream(
|
||||||
suggestedConfig, flags, initMetadata,
|
ioHandle, microphone.deviceAddress, suggestedConfig, flags, initMetadata,
|
||||||
returnIn(res, stream, suggestedConfigRetry)));
|
returnIn(res, stream, suggestedConfigRetry)));
|
||||||
}
|
}
|
||||||
ASSERT_OK(res);
|
ASSERT_OK(res);
|
||||||
hidl_vec<MicrophoneInfo> activeMicrophones;
|
hidl_vec<MicrophoneInfo> activeMicrophones;
|
||||||
|
@ -131,7 +120,7 @@ TEST_F(AudioPrimaryHidlTest, GetMicrophonesTest) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
|
TEST_P(AudioPrimaryHidlTest, SetConnectedState) {
|
||||||
doc::test("Check that the HAL can be notified of device connection and deconnection");
|
doc::test("Check that the HAL can be notified of device connection and deconnection");
|
||||||
using AD = AudioDevice;
|
using AD = AudioDevice;
|
||||||
for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
|
for (auto deviceType : {AD::OUT_HDMI, AD::OUT_WIRED_HEADPHONE, AD::IN_USB_HEADSET}) {
|
||||||
|
@ -140,7 +129,7 @@ TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
|
||||||
SCOPED_TRACE("state=" + ::testing::PrintToString(state));
|
SCOPED_TRACE("state=" + ::testing::PrintToString(state));
|
||||||
DeviceAddress address = {};
|
DeviceAddress address = {};
|
||||||
address.device = deviceType;
|
address.device = deviceType;
|
||||||
auto ret = device->setConnectedState(address, state);
|
auto ret = getDevice()->setConnectedState(address, state);
|
||||||
ASSERT_TRUE(ret.isOk());
|
ASSERT_TRUE(ret.isOk());
|
||||||
if (ret == Result::NOT_SUPPORTED) {
|
if (ret == Result::NOT_SUPPORTED) {
|
||||||
doc::partialTest("setConnectedState is not supported");
|
doc::partialTest("setConnectedState is not supported");
|
||||||
|
@ -153,9 +142,7 @@ TEST_F(AudioPrimaryHidlTest, SetConnectedState) {
|
||||||
// Because there is no way of knowing if the devices were connected before
|
// Because there is no way of knowing if the devices were connected before
|
||||||
// calling setConnectedState, there is no way to restore the HAL to its
|
// calling setConnectedState, there is no way to restore the HAL to its
|
||||||
// initial state. To workaround this, destroy the HAL at the end of this test.
|
// initial state. To workaround this, destroy the HAL at the end of this test.
|
||||||
device.clear();
|
ASSERT_TRUE(DeviceManager::getInstance().resetPrimary(getFactoryName()));
|
||||||
waitForDeviceDestruction();
|
|
||||||
ASSERT_NO_FATAL_FAILURE(initPrimaryDevice());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
|
static void testGetDevices(IStream* stream, AudioDevice expectedDevice) {
|
||||||
|
@ -199,7 +186,7 @@ static void checkGetHwAVSync(IDevice* device) {
|
||||||
}
|
}
|
||||||
ASSERT_OK(res);
|
ASSERT_OK(res);
|
||||||
}
|
}
|
||||||
TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(device.get()));
|
TEST_IO_STREAM(GetHwAvSync, "Get hardware sync can not fail", checkGetHwAVSync(getDevice().get()));
|
||||||
|
|
||||||
TEST_P(InputStreamTest, updateSinkMetadata) {
|
TEST_P(InputStreamTest, updateSinkMetadata) {
|
||||||
doc::test("The HAL should not crash on metadata change");
|
doc::test("The HAL should not crash on metadata change");
|
||||||
|
@ -259,58 +246,58 @@ TEST_P(OutputStreamTest, updateSourceMetadata) {
|
||||||
ASSERT_OK(stream->updateSourceMetadata(initMetadata));
|
ASSERT_OK(stream->updateSourceMetadata(initMetadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, setMode) {
|
TEST_P(AudioPrimaryHidlTest, setMode) {
|
||||||
doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
|
doc::test("Make sure setMode always succeeds if mode is valid and fails otherwise");
|
||||||
// Test Invalid values
|
// Test Invalid values
|
||||||
for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
|
for (int mode : {-2, -1, int(AudioMode::IN_COMMUNICATION) + 1}) {
|
||||||
ASSERT_RESULT(Result::INVALID_ARGUMENTS, device->setMode(AudioMode(mode)))
|
ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
|
||||||
<< "mode=" << mode;
|
<< "mode=" << mode;
|
||||||
}
|
}
|
||||||
// Test valid values
|
// Test valid values
|
||||||
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
|
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
|
||||||
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
|
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
|
||||||
ASSERT_OK(device->setMode(mode)) << "mode=" << toString(mode);
|
ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, setBtHfpSampleRate) {
|
TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {
|
||||||
doc::test(
|
doc::test(
|
||||||
"Make sure setBtHfpSampleRate either succeeds or "
|
"Make sure setBtHfpSampleRate either succeeds or "
|
||||||
"indicates that it is not supported at all, or that the provided value is invalid");
|
"indicates that it is not supported at all, or that the provided value is invalid");
|
||||||
for (auto samplingRate : {8000, 16000, 22050, 24000}) {
|
for (auto samplingRate : {8000, 16000, 22050, 24000}) {
|
||||||
ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, device->setBtHfpSampleRate(samplingRate));
|
ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setBtHfpSampleRate(samplingRate));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, setBtHfpVolume) {
|
TEST_P(AudioPrimaryHidlTest, setBtHfpVolume) {
|
||||||
doc::test(
|
doc::test(
|
||||||
"Make sure setBtHfpVolume is either not supported or "
|
"Make sure setBtHfpVolume is either not supported or "
|
||||||
"only succeed if volume is in [0,1]");
|
"only succeed if volume is in [0,1]");
|
||||||
auto ret = device->setBtHfpVolume(0.0);
|
auto ret = getDevice()->setBtHfpVolume(0.0);
|
||||||
ASSERT_TRUE(ret.isOk());
|
ASSERT_TRUE(ret.isOk());
|
||||||
if (ret == Result::NOT_SUPPORTED) {
|
if (ret == Result::NOT_SUPPORTED) {
|
||||||
doc::partialTest("setBtHfpVolume is not supported");
|
doc::partialTest("setBtHfpVolume is not supported");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
testUnitaryGain([](float volume) { return device->setBtHfpVolume(volume); });
|
testUnitaryGain([this](float volume) { return getDevice()->setBtHfpVolume(volume); });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
|
TEST_P(AudioPrimaryHidlTest, setBtScoHeadsetDebugName) {
|
||||||
doc::test(
|
doc::test(
|
||||||
"Make sure setBtScoHeadsetDebugName either succeeds or "
|
"Make sure setBtScoHeadsetDebugName either succeeds or "
|
||||||
"indicates that it is not supported");
|
"indicates that it is not supported");
|
||||||
ASSERT_RESULT(okOrNotSupported, device->setBtScoHeadsetDebugName("test"));
|
ASSERT_RESULT(okOrNotSupported, getDevice()->setBtScoHeadsetDebugName("test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, updateRotation) {
|
TEST_P(AudioPrimaryHidlTest, updateRotation) {
|
||||||
doc::test("Check that the hal can receive the current rotation");
|
doc::test("Check that the hal can receive the current rotation");
|
||||||
for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180,
|
for (Rotation rotation : {Rotation::DEG_0, Rotation::DEG_90, Rotation::DEG_180,
|
||||||
Rotation::DEG_270, Rotation::DEG_0}) {
|
Rotation::DEG_270, Rotation::DEG_0}) {
|
||||||
ASSERT_RESULT(okOrNotSupported, device->updateRotation(rotation));
|
ASSERT_RESULT(okOrNotSupported, getDevice()->updateRotation(rotation));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
|
TEST_P(BoolAccessorPrimaryHidlTest, setGetBtHfpEnabled) {
|
||||||
doc::test("Query and set the BT HFP state");
|
doc::test("Query and set the BT HFP state");
|
||||||
testAccessors<OPTIONAL>("BtHfpEnabled", Initial{false, OPTIONAL}, {true},
|
testAccessors<OPTIONAL>("BtHfpEnabled", Initial{false, OPTIONAL}, {true},
|
||||||
&IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled);
|
&IPrimaryDevice::setBtHfpEnabled, &IPrimaryDevice::getBtHfpEnabled);
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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 ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
|
||||||
|
#define ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include "utility/EnvironmentTearDown.h"
|
||||||
|
|
||||||
|
class Environment : public ::android::hardware::audio::common::test::utility::EnvironmentTearDown,
|
||||||
|
public ::testing::Environment {
|
||||||
|
public:
|
||||||
|
void init(int* /*argc*/, char** /*argv*/) {} // emulate VtsHalHidlTargetTestEnvBase
|
||||||
|
private:
|
||||||
|
void TearDown() override { executeAllTearDowns(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// FIXME: Will be removed while making getDeviceParameters to use the config
|
||||||
|
static constexpr const char* kDefaultServiceName = "default";
|
||||||
|
|
||||||
|
#endif // ANDROID_HARDWARE_AUDIO_CORE_6_0_ENVIRONMENT_TEARDOWN_H
|
|
@ -23,6 +23,7 @@
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -31,7 +32,9 @@
|
||||||
|
|
||||||
#include <hwbinder/IPCThreadState.h>
|
#include <hwbinder/IPCThreadState.h>
|
||||||
|
|
||||||
|
#if MAJOR_VERSION <= 5
|
||||||
#include <VtsHalHidlTargetTestBase.h>
|
#include <VtsHalHidlTargetTestBase.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <android-base/logging.h>
|
#include <android-base/logging.h>
|
||||||
|
|
||||||
|
@ -44,16 +47,25 @@
|
||||||
#include <Serializer.h>
|
#include <Serializer.h>
|
||||||
#include <fmq/EventFlag.h>
|
#include <fmq/EventFlag.h>
|
||||||
#include <fmq/MessageQueue.h>
|
#include <fmq/MessageQueue.h>
|
||||||
|
#if MAJOR_VERSION >= 6
|
||||||
|
#include <hidl/GtestPrinter.h>
|
||||||
|
#include <hidl/ServiceManagement.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <common/all-versions/VersionUtils.h>
|
#include <common/all-versions/VersionUtils.h>
|
||||||
|
|
||||||
#include "utility/AssertOk.h"
|
#include "utility/AssertOk.h"
|
||||||
#include "utility/Documentation.h"
|
#include "utility/Documentation.h"
|
||||||
#include "utility/EnvironmentTearDown.h"
|
|
||||||
#include "utility/PrettyPrintAudioTypes.h"
|
#include "utility/PrettyPrintAudioTypes.h"
|
||||||
#include "utility/ReturnIn.h"
|
#include "utility/ReturnIn.h"
|
||||||
#include "utility/ValidateXml.h"
|
#include "utility/ValidateXml.h"
|
||||||
|
|
||||||
|
#if MAJOR_VERSION <= 5
|
||||||
|
#include "2.0/EnvironmentTearDown.h"
|
||||||
|
#elif MAJOR_VERSION >= 6
|
||||||
|
#include "6.0/EnvironmentTearDown.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
/** Provide version specific functions that are used in the generic tests */
|
/** Provide version specific functions that are used in the generic tests */
|
||||||
#if MAJOR_VERSION == 2
|
#if MAJOR_VERSION == 2
|
||||||
#include "2.0/AudioPrimaryHidlHalUtils.h"
|
#include "2.0/AudioPrimaryHidlHalUtils.h"
|
||||||
|
@ -105,14 +117,23 @@ static auto invalidStateOrNotSupported = {Result::INVALID_STATE, Result::NOT_SUP
|
||||||
|
|
||||||
class AudioHidlTestEnvironment : public ::Environment {
|
class AudioHidlTestEnvironment : public ::Environment {
|
||||||
public:
|
public:
|
||||||
virtual void registerTestServices() override { registerTestService<IDevicesFactory>(); }
|
#if MAJOR_VERSION <= 5
|
||||||
|
void registerTestServices() override { registerTestService<IDevicesFactory>(); }
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// Instance to register global tearDown
|
// Instance to register global tearDown
|
||||||
static AudioHidlTestEnvironment* environment;
|
static AudioHidlTestEnvironment* environment;
|
||||||
|
|
||||||
|
#define AUDIO_PRIMARY_HIDL_HAL_TEST
|
||||||
|
#include "DeviceManager.h"
|
||||||
|
|
||||||
|
#if MAJOR_VERSION <= 5
|
||||||
class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
|
class HidlTest : public ::testing::VtsHalHidlTargetTestBase {
|
||||||
protected:
|
#elif MAJOR_VERSION >= 6
|
||||||
|
class HidlTest : public ::testing::Test {
|
||||||
|
#endif
|
||||||
|
protected:
|
||||||
// Convenient member to store results
|
// Convenient member to store results
|
||||||
Result res;
|
Result res;
|
||||||
};
|
};
|
||||||
|
@ -201,6 +222,21 @@ class AudioPolicyConfigTest : public HidlTest {
|
||||||
ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: "
|
ASSERT_TRUE(mPrimaryConfig) << "Could not find primary module in configuration file: "
|
||||||
<< policyConfig.getFilePath();
|
<< policyConfig.getFilePath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
sp<IDevicesFactory> getDevicesFactory(const std::string& factoryName) const {
|
||||||
|
return DevicesFactoryManager::getInstance().get(factoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<IPrimaryDevice> getPrimaryDevice(const std::string& factoryName) const {
|
||||||
|
return DeviceManager::getInstance().getPrimary(factoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isPrimaryDeviceOptional(const std::string& factoryName) const {
|
||||||
|
// It's OK not to have "primary" device on non-default audio HAL service.
|
||||||
|
return factoryName != kDefaultServiceName;
|
||||||
|
}
|
||||||
|
|
||||||
sp<const HwModule> mPrimaryConfig = nullptr;
|
sp<const HwModule> mPrimaryConfig = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -208,42 +244,86 @@ TEST_F(AudioPolicyConfigTest, LoadAudioPolicyXMLConfiguration) {
|
||||||
doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)");
|
doc::test("Test parsing audio_policy_configuration.xml (called in SetUp)");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//////////////////// Test parameter types and definitions ////////////////////
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
enum { PARAM_FACTORY_NAME, PARAM_DEVICE_NAME };
|
||||||
|
using DeviceParameter = std::tuple<std::string, std::string>;
|
||||||
|
|
||||||
|
static inline std::string DeviceParameterToString(
|
||||||
|
const ::testing::TestParamInfo<DeviceParameter>& info) {
|
||||||
|
#if MAJOR_VERSION <= 5
|
||||||
|
return std::get<PARAM_DEVICE_NAME>(info.param);
|
||||||
|
#elif MAJOR_VERSION >= 6
|
||||||
|
const auto factoryName =
|
||||||
|
::android::hardware::PrintInstanceNameToString(::testing::TestParamInfo<std::string>{
|
||||||
|
std::get<PARAM_FACTORY_NAME>(info.param), info.index});
|
||||||
|
const auto& deviceName = std::get<PARAM_DEVICE_NAME>(info.param);
|
||||||
|
return !deviceName.empty() ? factoryName + "_" + deviceName : factoryName;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MAJOR_VERSION <= 5
|
||||||
|
// For V2..5 the factory is looked up using the instance name passed
|
||||||
|
// in the environment, only one factory is returned. This is because the VTS
|
||||||
|
// framework will call the test for each instance. Only the primary device of
|
||||||
|
// the factory specified in the environment is tested.
|
||||||
|
const std::vector<DeviceParameter>& getDeviceParameters() {
|
||||||
|
static std::vector<DeviceParameter> parameters = {
|
||||||
|
{environment->getServiceName<IDevicesFactory>(), DeviceManager::kPrimaryDevice}};
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
#elif MAJOR_VERSION >= 6
|
||||||
|
// FIXME: Will be replaced with code that analyzes the audio policy config file.
|
||||||
|
const std::vector<DeviceParameter>& getDeviceParameters() {
|
||||||
|
static std::vector<DeviceParameter> parameters = [] {
|
||||||
|
const auto instances =
|
||||||
|
::android::hardware::getAllHalInstanceNames(IDevicesFactory::descriptor);
|
||||||
|
std::vector<DeviceParameter> result;
|
||||||
|
result.reserve(instances.size());
|
||||||
|
for (const auto& instance : instances) {
|
||||||
|
result.emplace_back(instance, DeviceManager::kPrimaryDevice);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}();
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class AudioHidlTestWithDeviceParameter : public AudioPolicyConfigTest,
|
||||||
|
public ::testing::WithParamInterface<DeviceParameter> {
|
||||||
|
protected:
|
||||||
|
const std::string& getFactoryName() const { return std::get<PARAM_FACTORY_NAME>(GetParam()); }
|
||||||
|
bool isPrimaryDeviceOptional() const {
|
||||||
|
return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName());
|
||||||
|
}
|
||||||
|
sp<IDevicesFactory> getDevicesFactory() const {
|
||||||
|
return AudioPolicyConfigTest::getDevicesFactory(getFactoryName());
|
||||||
|
}
|
||||||
|
sp<IPrimaryDevice> getPrimaryDevice() const {
|
||||||
|
return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////// getService audio_devices_factory //////////////////////
|
////////////////////// getService audio_devices_factory //////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Test all audio devices
|
// Test all audio devices
|
||||||
class AudioHidlTest : public AudioPolicyConfigTest {
|
class AudioHidlTest : public AudioHidlTestWithDeviceParameter {
|
||||||
public:
|
public:
|
||||||
static void SetUpTestSuite() {
|
void SetUp() override {
|
||||||
devicesFactory = ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(
|
ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceParameter::SetUp()); // setup base
|
||||||
environment->getServiceName<IDevicesFactory>());
|
ASSERT_TRUE(getDevicesFactory() != nullptr);
|
||||||
}
|
|
||||||
|
|
||||||
static void TearDownTestSuite() { devicesFactory.clear(); }
|
|
||||||
|
|
||||||
void SetUp() override {
|
|
||||||
ASSERT_NO_FATAL_FAILURE(AudioPolicyConfigTest::SetUp()); // setup base
|
|
||||||
// Failures during SetUpTestSuite do not cause test termination.
|
|
||||||
ASSERT_TRUE(devicesFactory != nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// Cache the devicesFactory retrieval to speed up each test by ~0.5s
|
|
||||||
static sp<IDevicesFactory> devicesFactory;
|
|
||||||
|
|
||||||
static bool isPrimaryDeviceOptional() {
|
|
||||||
// It's OK not to have "primary" device on non-default audio HAL service.
|
|
||||||
return environment->getServiceName<IDevicesFactory>() != kDefaultServiceName;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
sp<IDevicesFactory> AudioHidlTest::devicesFactory;
|
|
||||||
|
|
||||||
TEST_F(AudioHidlTest, GetAudioDevicesFactoryService) {
|
TEST_P(AudioHidlTest, GetAudioDevicesFactoryService) {
|
||||||
doc::test("Test the getService");
|
doc::test("Test the getService");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
|
TEST_P(AudioHidlTest, OpenDeviceInvalidParameter) {
|
||||||
doc::test("Test passing an invalid parameter to openDevice");
|
doc::test("Test passing an invalid parameter to openDevice");
|
||||||
Result result;
|
Result result;
|
||||||
sp<IDevice> device;
|
sp<IDevice> device;
|
||||||
|
@ -252,11 +332,14 @@ TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
|
||||||
#elif MAJOR_VERSION >= 4
|
#elif MAJOR_VERSION >= 4
|
||||||
auto invalidDevice = "Non existing device";
|
auto invalidDevice = "Non existing device";
|
||||||
#endif
|
#endif
|
||||||
ASSERT_OK(devicesFactory->openDevice(invalidDevice, returnIn(result, device)));
|
ASSERT_OK(getDevicesFactory()->openDevice(invalidDevice, returnIn(result, device)));
|
||||||
ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
|
ASSERT_EQ(Result::INVALID_ARGUMENTS, result);
|
||||||
ASSERT_TRUE(device == nullptr);
|
ASSERT_TRUE(device == nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(AudioHidl, AudioHidlTest, ::testing::ValuesIn(getDeviceParameters()),
|
||||||
|
&DeviceParameterToString);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/////////////////////////////// openDevice primary ///////////////////////////
|
/////////////////////////////// openDevice primary ///////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -264,57 +347,30 @@ TEST_F(AudioHidlTest, OpenDeviceInvalidParameter) {
|
||||||
// Test the primary device
|
// Test the primary device
|
||||||
class AudioPrimaryHidlTest : public AudioHidlTest {
|
class AudioPrimaryHidlTest : public AudioHidlTest {
|
||||||
public:
|
public:
|
||||||
static void SetUpTestSuite() {
|
|
||||||
ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUpTestSuite());
|
|
||||||
ASSERT_NO_FATAL_FAILURE(initPrimaryDevice());
|
|
||||||
}
|
|
||||||
|
|
||||||
static void TearDownTestSuite() {
|
|
||||||
device.clear();
|
|
||||||
AudioHidlTest::TearDownTestSuite();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetUp() override {
|
void SetUp() override {
|
||||||
ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base
|
ASSERT_NO_FATAL_FAILURE(AudioHidlTest::SetUp()); // setup base
|
||||||
if (device == nullptr && isPrimaryDeviceOptional()) {
|
if (getDevice() == nullptr && isPrimaryDeviceOptional()) {
|
||||||
GTEST_SKIP() << "No primary device on this factory";
|
GTEST_SKIP() << "No primary device on this factory";
|
||||||
}
|
}
|
||||||
ASSERT_TRUE(device != nullptr);
|
ASSERT_TRUE(getDevice() != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Cache the device opening to speed up each test by ~0.5s
|
sp<IPrimaryDevice> getDevice() const { return getPrimaryDevice(); }
|
||||||
static sp<IPrimaryDevice> device;
|
|
||||||
|
|
||||||
static void initPrimaryDevice() {
|
|
||||||
// Failures during test suite set up do not cause test termination.
|
|
||||||
ASSERT_TRUE(devicesFactory != nullptr);
|
|
||||||
Result result;
|
|
||||||
#if MAJOR_VERSION == 2
|
|
||||||
sp<IDevice> baseDevice;
|
|
||||||
ASSERT_OK(devicesFactory->openDevice(IDevicesFactory::Device::PRIMARY,
|
|
||||||
returnIn(result, baseDevice)));
|
|
||||||
ASSERT_OK(result);
|
|
||||||
ASSERT_TRUE(baseDevice != nullptr);
|
|
||||||
|
|
||||||
device = IPrimaryDevice::castFrom(baseDevice);
|
|
||||||
#elif MAJOR_VERSION >= 4
|
|
||||||
ASSERT_OK(devicesFactory->openPrimaryDevice(returnIn(result, device)));
|
|
||||||
ASSERT_OK(result);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
sp<IPrimaryDevice> AudioPrimaryHidlTest::device;
|
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, OpenPrimaryDevice) {
|
TEST_P(AudioPrimaryHidlTest, OpenPrimaryDevice) {
|
||||||
doc::test("Test the openDevice (called during setup)");
|
doc::test("Test the openDevice (called during setup)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, Init) {
|
TEST_P(AudioPrimaryHidlTest, Init) {
|
||||||
doc::test("Test that the audio primary hal initialized correctly");
|
doc::test("Test that the audio primary hal initialized correctly");
|
||||||
ASSERT_OK(device->initCheck());
|
ASSERT_OK(getDevice()->initCheck());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(AudioPrimaryHidl, AudioPrimaryHidlTest,
|
||||||
|
::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
|
///////////////////// {set,get}{Master,Mic}{Mute,Volume} /////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -339,7 +395,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
|
||||||
optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
|
optionality == OPTIONAL ? Result::NOT_SUPPORTED : Result::OK};
|
||||||
|
|
||||||
Property initialValue = expectedInitial.value;
|
Property initialValue = expectedInitial.value;
|
||||||
ASSERT_OK((device.get()->*getter)(returnIn(res, initialValue)));
|
ASSERT_OK((getDevice().get()->*getter)(returnIn(res, initialValue)));
|
||||||
ASSERT_RESULT(expectedResults, res);
|
ASSERT_RESULT(expectedResults, res);
|
||||||
if (res == Result::OK && expectedInitial.check == REQUIRED) {
|
if (res == Result::OK && expectedInitial.check == REQUIRED) {
|
||||||
EXPECT_EQ(expectedInitial.value, initialValue);
|
EXPECT_EQ(expectedInitial.value, initialValue);
|
||||||
|
@ -350,7 +406,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
|
||||||
for (Property setValue : valuesToTest) {
|
for (Property setValue : valuesToTest) {
|
||||||
SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
|
SCOPED_TRACE("Test " + propertyName + " getter and setter for " +
|
||||||
testing::PrintToString(setValue));
|
testing::PrintToString(setValue));
|
||||||
auto ret = (device.get()->*setter)(setValue);
|
auto ret = (getDevice().get()->*setter)(setValue);
|
||||||
ASSERT_RESULT(expectedResults, ret);
|
ASSERT_RESULT(expectedResults, ret);
|
||||||
if (ret == Result::NOT_SUPPORTED) {
|
if (ret == Result::NOT_SUPPORTED) {
|
||||||
doc::partialTest(propertyName + " setter is not supported");
|
doc::partialTest(propertyName + " setter is not supported");
|
||||||
|
@ -358,7 +414,7 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
|
||||||
}
|
}
|
||||||
Property getValue;
|
Property getValue;
|
||||||
// Make sure the getter returns the same value just set
|
// Make sure the getter returns the same value just set
|
||||||
ASSERT_OK((device.get()->*getter)(returnIn(res, getValue)));
|
ASSERT_OK((getDevice().get()->*getter)(returnIn(res, getValue)));
|
||||||
ASSERT_RESULT(expectedResults, res);
|
ASSERT_RESULT(expectedResults, res);
|
||||||
if (res == Result::NOT_SUPPORTED) {
|
if (res == Result::NOT_SUPPORTED) {
|
||||||
doc::partialTest(propertyName + " getter is not supported");
|
doc::partialTest(propertyName + " getter is not supported");
|
||||||
|
@ -370,31 +426,34 @@ class AccessorPrimaryHidlTest : public AudioPrimaryHidlTest {
|
||||||
for (Property invalidValue : invalidValues) {
|
for (Property invalidValue : invalidValues) {
|
||||||
SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
|
SCOPED_TRACE("Try to set " + propertyName + " with the invalid value " +
|
||||||
testing::PrintToString(invalidValue));
|
testing::PrintToString(invalidValue));
|
||||||
EXPECT_RESULT(invalidArgsOrNotSupported, (device.get()->*setter)(invalidValue));
|
EXPECT_RESULT(invalidArgsOrNotSupported, (getDevice().get()->*setter)(invalidValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore initial value
|
// Restore initial value
|
||||||
EXPECT_RESULT(expectedResults, (device.get()->*setter)(initialValue));
|
EXPECT_RESULT(expectedResults, (getDevice().get()->*setter)(initialValue));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
|
using BoolAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<bool>;
|
||||||
|
|
||||||
TEST_F(BoolAccessorPrimaryHidlTest, MicMuteTest) {
|
TEST_P(BoolAccessorPrimaryHidlTest, MicMuteTest) {
|
||||||
doc::test("Check that the mic can be muted and unmuted");
|
doc::test("Check that the mic can be muted and unmuted");
|
||||||
testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute);
|
testAccessors("mic mute", Initial{false}, {true}, &IDevice::setMicMute, &IDevice::getMicMute);
|
||||||
// TODO: check that the mic is really muted (all sample are 0)
|
// TODO: check that the mic is really muted (all sample are 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
|
TEST_P(BoolAccessorPrimaryHidlTest, MasterMuteTest) {
|
||||||
doc::test("If master mute is supported, try to mute and unmute the master output");
|
doc::test("If master mute is supported, try to mute and unmute the master output");
|
||||||
testAccessors<OPTIONAL>("master mute", Initial{false}, {true}, &IDevice::setMasterMute,
|
testAccessors<OPTIONAL>("master mute", Initial{false}, {true}, &IDevice::setMasterMute,
|
||||||
&IDevice::getMasterMute);
|
&IDevice::getMasterMute);
|
||||||
// TODO: check that the master volume is really muted
|
// TODO: check that the master volume is really muted
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(BoolAccessorPrimaryHidl, BoolAccessorPrimaryHidlTest,
|
||||||
|
::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
|
||||||
|
|
||||||
using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
|
using FloatAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<float>;
|
||||||
TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
|
TEST_P(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
|
||||||
doc::test("Test the master volume if supported");
|
doc::test("Test the master volume if supported");
|
||||||
testAccessors<OPTIONAL>(
|
testAccessors<OPTIONAL>(
|
||||||
"master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
|
"master volume", Initial{1}, {0, 0.5}, &IDevice::setMasterVolume, &IDevice::getMasterVolume,
|
||||||
|
@ -402,16 +461,19 @@ TEST_F(FloatAccessorPrimaryHidlTest, MasterVolumeTest) {
|
||||||
// TODO: check that the master volume is really changed
|
// TODO: check that the master volume is really changed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(FloatAccessorPrimaryHidl, FloatAccessorPrimaryHidlTest,
|
||||||
|
::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////////////////////// AudioPatches ////////////////////////////////
|
//////////////////////////////// AudioPatches ////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
|
class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
|
||||||
protected:
|
protected:
|
||||||
bool areAudioPatchesSupported() { return extract(device->supportsAudioPatches()); }
|
bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
|
TEST_P(AudioPatchPrimaryHidlTest, AudioPatches) {
|
||||||
doc::test("Test if audio patches are supported");
|
doc::test("Test if audio patches are supported");
|
||||||
if (!areAudioPatchesSupported()) {
|
if (!areAudioPatchesSupported()) {
|
||||||
doc::partialTest("Audio patches are not supported");
|
doc::partialTest("Audio patches are not supported");
|
||||||
|
@ -420,6 +482,9 @@ TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
|
||||||
// TODO: test audio patches
|
// TODO: test audio patches
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(AudioPatchPrimaryHidl, AudioPatchPrimaryHidlTest,
|
||||||
|
::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
//////////////// Required and recommended audio format support ///////////////
|
//////////////// Required and recommended audio format support ///////////////
|
||||||
// From:
|
// From:
|
||||||
|
@ -429,8 +494,7 @@ TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
|
||||||
/////////// TODO: move to the beginning of the file for easier update ////////
|
/////////// TODO: move to the beginning of the file for easier update ////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
|
struct ConfigHelper {
|
||||||
public:
|
|
||||||
// for retro compatibility only test the primary device IN_BUILTIN_MIC
|
// for retro compatibility only test the primary device IN_BUILTIN_MIC
|
||||||
// FIXME: in the next audio HAL version, test all available devices
|
// FIXME: in the next audio HAL version, test all available devices
|
||||||
static bool primaryHasMic() {
|
static bool primaryHasMic() {
|
||||||
|
@ -502,21 +566,51 @@ class AudioConfigPrimaryTest : public AudioPatchPrimaryHidlTest {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Nesting a tuple in another tuple allows to use GTest Combine function to generate
|
||||||
|
// all combinations of devices and configs.
|
||||||
|
enum { PARAM_DEVICE, PARAM_CONFIG };
|
||||||
|
using DeviceConfigParameter = std::tuple<DeviceParameter, AudioConfig>;
|
||||||
|
|
||||||
/** Generate a test name based on an audio config.
|
/** Generate a test name based on an audio config.
|
||||||
*
|
*
|
||||||
* As the only parameter changing are channel mask and sample rate,
|
* As the only parameter changing are channel mask and sample rate,
|
||||||
* only print those ones in the test name.
|
* only print those ones in the test name.
|
||||||
*/
|
*/
|
||||||
static string generateTestName(const testing::TestParamInfo<AudioConfig>& info) {
|
static string DeviceConfigParameterToString(
|
||||||
const AudioConfig& config = info.param;
|
const testing::TestParamInfo<DeviceConfigParameter>& info) {
|
||||||
return to_string(info.index) + "__" + to_string(config.sampleRateHz) + "_" +
|
const AudioConfig& config = std::get<PARAM_CONFIG>(info.param);
|
||||||
|
const auto deviceName = DeviceParameterToString(::testing::TestParamInfo<DeviceParameter>{
|
||||||
|
std::get<PARAM_DEVICE>(info.param), info.index});
|
||||||
|
return (deviceName.empty() ? "" : deviceName + "_") + to_string(info.index) + "__" +
|
||||||
|
to_string(config.sampleRateHz) + "_" +
|
||||||
// "MONO" is more clear than "FRONT_LEFT"
|
// "MONO" is more clear than "FRONT_LEFT"
|
||||||
((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
|
((config.channelMask == mkEnumBitfield(AudioChannelMask::OUT_MONO) ||
|
||||||
config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO))
|
config.channelMask == mkEnumBitfield(AudioChannelMask::IN_MONO))
|
||||||
? "MONO"
|
? "MONO"
|
||||||
: ::testing::PrintToString(config.channelMask));
|
: ::testing::PrintToString(config.channelMask));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AudioHidlTestWithDeviceConfigParameter
|
||||||
|
: public AudioPolicyConfigTest,
|
||||||
|
public ::testing::WithParamInterface<DeviceConfigParameter> {
|
||||||
|
protected:
|
||||||
|
const std::string& getFactoryName() const {
|
||||||
|
return std::get<PARAM_FACTORY_NAME>(std::get<PARAM_DEVICE>(GetParam()));
|
||||||
|
}
|
||||||
|
bool isPrimaryDeviceOptional() const {
|
||||||
|
return AudioPolicyConfigTest::isPrimaryDeviceOptional(getFactoryName());
|
||||||
|
}
|
||||||
|
sp<IDevicesFactory> getDevicesFactory() const {
|
||||||
|
return AudioPolicyConfigTest::getDevicesFactory(getFactoryName());
|
||||||
|
}
|
||||||
|
sp<IPrimaryDevice> getPrimaryDevice() const {
|
||||||
|
return AudioPolicyConfigTest::getPrimaryDevice(getFactoryName());
|
||||||
|
}
|
||||||
|
const AudioConfig& getConfig() const { return std::get<PARAM_CONFIG>(GetParam()); }
|
||||||
|
// FIXME: Split out tests that don't require primary device
|
||||||
|
sp<IPrimaryDevice> getDevice() const { return getPrimaryDevice(); }
|
||||||
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
///////////////////////////// getInputBufferSize /////////////////////////////
|
///////////////////////////// getInputBufferSize /////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -525,12 +619,21 @@ static string generateTestName(const testing::TestParamInfo<AudioConfig>& info)
|
||||||
// android.hardware.microphone
|
// android.hardware.microphone
|
||||||
// how to get this value ? is it a property ???
|
// how to get this value ? is it a property ???
|
||||||
|
|
||||||
class AudioCaptureConfigPrimaryTest : public AudioConfigPrimaryTest,
|
class AudioCaptureConfigPrimaryTest : public AudioHidlTestWithDeviceConfigParameter {
|
||||||
public ::testing::WithParamInterface<AudioConfig> {
|
public:
|
||||||
protected:
|
void SetUp() override {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base
|
||||||
|
ASSERT_TRUE(getDevicesFactory() != nullptr);
|
||||||
|
if (getDevice() == nullptr && isPrimaryDeviceOptional()) {
|
||||||
|
GTEST_SKIP() << "No primary device on this factory";
|
||||||
|
}
|
||||||
|
ASSERT_TRUE(getDevice() != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
|
void inputBufferSizeTest(const AudioConfig& audioConfig, bool supportRequired) {
|
||||||
uint64_t bufferSize;
|
uint64_t bufferSize;
|
||||||
ASSERT_OK(device->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
|
ASSERT_OK(getDevice()->getInputBufferSize(audioConfig, returnIn(res, bufferSize)));
|
||||||
|
|
||||||
switch (res) {
|
switch (res) {
|
||||||
case Result::INVALID_ARGUMENTS:
|
case Result::INVALID_ARGUMENTS:
|
||||||
|
@ -554,16 +657,19 @@ TEST_P(RequiredInputBufferSizeTest, RequiredInputBufferSizeTest) {
|
||||||
doc::test(
|
doc::test(
|
||||||
"Input buffer size must be retrievable for a format with required "
|
"Input buffer size must be retrievable for a format with required "
|
||||||
"support.");
|
"support.");
|
||||||
inputBufferSizeTest(GetParam(), true);
|
inputBufferSizeTest(getConfig(), true);
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
RequiredInputBufferSize, RequiredInputBufferSizeTest,
|
RequiredInputBufferSize, RequiredInputBufferSizeTest,
|
||||||
::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
|
::testing::Combine(
|
||||||
&generateTestName);
|
::testing::ValuesIn(getDeviceParameters()),
|
||||||
|
::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())),
|
||||||
|
&DeviceConfigParameterToString);
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
SupportedInputBufferSize, RequiredInputBufferSizeTest,
|
SupportedInputBufferSize, RequiredInputBufferSizeTest,
|
||||||
::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
|
::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
|
||||||
&generateTestName);
|
::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())),
|
||||||
|
&DeviceConfigParameterToString);
|
||||||
|
|
||||||
// Test that the recommended capture config are supported or lead to a
|
// Test that the recommended capture config are supported or lead to a
|
||||||
// INVALID_ARGUMENTS return
|
// INVALID_ARGUMENTS return
|
||||||
|
@ -572,21 +678,23 @@ TEST_P(OptionalInputBufferSizeTest, OptionalInputBufferSizeTest) {
|
||||||
doc::test(
|
doc::test(
|
||||||
"Input buffer size should be retrievable for a format with recommended "
|
"Input buffer size should be retrievable for a format with recommended "
|
||||||
"support.");
|
"support.");
|
||||||
inputBufferSizeTest(GetParam(), false);
|
inputBufferSizeTest(getConfig(), false);
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
|
RecommendedCaptureAudioConfigSupport, OptionalInputBufferSizeTest,
|
||||||
::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
|
::testing::Combine(
|
||||||
&generateTestName);
|
::testing::ValuesIn(getDeviceParameters()),
|
||||||
|
::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())),
|
||||||
|
&DeviceConfigParameterToString);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
/////////////////////////////// setScreenState ///////////////////////////////
|
/////////////////////////////// setScreenState ///////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, setScreenState) {
|
TEST_P(AudioPrimaryHidlTest, setScreenState) {
|
||||||
doc::test("Check that the hal can receive the screen state");
|
doc::test("Check that the hal can receive the screen state");
|
||||||
for (bool turnedOn : {false, true, true, false, false}) {
|
for (bool turnedOn : {false, true, true, false, false}) {
|
||||||
ASSERT_RESULT(okOrNotSupported, device->setScreenState(turnedOn));
|
ASSERT_RESULT(okOrNotSupported, getDevice()->setScreenState(turnedOn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -594,15 +702,15 @@ TEST_F(AudioPrimaryHidlTest, setScreenState) {
|
||||||
//////////////////////////// {get,set}Parameters /////////////////////////////
|
//////////////////////////// {get,set}Parameters /////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, getParameters) {
|
TEST_P(AudioPrimaryHidlTest, getParameters) {
|
||||||
doc::test("Check that the hal can set and get parameters");
|
doc::test("Check that the hal can set and get parameters");
|
||||||
hidl_vec<ParameterValue> context;
|
hidl_vec<ParameterValue> context;
|
||||||
hidl_vec<hidl_string> keys;
|
hidl_vec<hidl_string> keys;
|
||||||
hidl_vec<ParameterValue> values;
|
hidl_vec<ParameterValue> values;
|
||||||
ASSERT_OK(Parameters::get(device, keys, returnIn(res, values)));
|
ASSERT_OK(Parameters::get(getDevice(), keys, returnIn(res, values)));
|
||||||
ASSERT_OK(Parameters::set(device, values));
|
ASSERT_OK(Parameters::set(getDevice(), values));
|
||||||
values.resize(0);
|
values.resize(0);
|
||||||
ASSERT_OK(Parameters::set(device, values));
|
ASSERT_OK(Parameters::set(getDevice(), values));
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -643,14 +751,14 @@ static void testDebugDump(DebugDump debugDump) {
|
||||||
EXPECT_EQ(0, close(fds[1])) << errno;
|
EXPECT_EQ(0, close(fds[1])) << errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, DebugDump) {
|
TEST_P(AudioPrimaryHidlTest, DebugDump) {
|
||||||
doc::test("Check that the hal can dump its state without error");
|
doc::test("Check that the hal can dump its state without error");
|
||||||
testDebugDump([](const auto& handle) { return dump(device, handle); });
|
testDebugDump([this](const auto& handle) { return dump(getDevice(), handle); });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
|
TEST_P(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
|
||||||
doc::test("Check that the hal dump doesn't crash on invalid arguments");
|
doc::test("Check that the hal dump doesn't crash on invalid arguments");
|
||||||
ASSERT_OK(dump(device, hidl_handle()));
|
ASSERT_OK(dump(getDevice(), hidl_handle()));
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -658,9 +766,17 @@ TEST_F(AudioPrimaryHidlTest, DebugDumpInvalidArguments) {
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
template <class Stream>
|
template <class Stream>
|
||||||
class OpenStreamTest : public AudioConfigPrimaryTest,
|
class OpenStreamTest : public AudioHidlTestWithDeviceConfigParameter {
|
||||||
public ::testing::WithParamInterface<AudioConfig> {
|
protected:
|
||||||
protected:
|
void SetUp() override {
|
||||||
|
ASSERT_NO_FATAL_FAILURE(AudioHidlTestWithDeviceConfigParameter::SetUp()); // setup base
|
||||||
|
ASSERT_TRUE(getDevicesFactory() != nullptr);
|
||||||
|
if (getDevice() == nullptr && isPrimaryDeviceOptional()) {
|
||||||
|
GTEST_SKIP() << "No primary device on this factory";
|
||||||
|
}
|
||||||
|
ASSERT_TRUE(getDevice() != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
template <class Open>
|
template <class Open>
|
||||||
void testOpen(Open openStream, const AudioConfig& config) {
|
void testOpen(Open openStream, const AudioConfig& config) {
|
||||||
// FIXME: Open a stream without an IOHandle
|
// FIXME: Open a stream without an IOHandle
|
||||||
|
@ -701,7 +817,7 @@ class OpenStreamTest : public AudioConfigPrimaryTest,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void waitForStreamDestruction() {
|
static void waitForStreamDestruction() {
|
||||||
// FIXME: there is no way to know when the remote IStream is being destroyed
|
// FIXME: there is no way to know when the remote IStream is being destroyed
|
||||||
// Binder does not support testing if an object is alive, thus
|
// Binder does not support testing if an object is alive, thus
|
||||||
// wait for 100ms to let the binder destruction propagates and
|
// wait for 100ms to let the binder destruction propagates and
|
||||||
|
@ -712,12 +828,14 @@ class OpenStreamTest : public AudioConfigPrimaryTest,
|
||||||
usleep(100 * 1000);
|
usleep(100 * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
bool areAudioPatchesSupported() { return extract(getDevice()->supportsAudioPatches()); }
|
||||||
|
|
||||||
|
private:
|
||||||
void TearDown() override {
|
void TearDown() override {
|
||||||
if (open) {
|
if (open) {
|
||||||
ASSERT_OK(closeStream());
|
ASSERT_OK(closeStream());
|
||||||
}
|
}
|
||||||
AudioConfigPrimaryTest::TearDown();
|
AudioPolicyConfigTest::TearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -734,18 +852,19 @@ class OutputStreamTest : public OpenStreamTest<IStreamOut> {
|
||||||
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
|
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
|
||||||
if (IsSkipped()) return; // do not attempt to use 'device'
|
if (IsSkipped()) return; // do not attempt to use 'device'
|
||||||
address.device = AudioDevice::OUT_DEFAULT;
|
address.device = AudioDevice::OUT_DEFAULT;
|
||||||
const AudioConfig& config = GetParam();
|
const AudioConfig& config = getConfig();
|
||||||
// TODO: test all flag combination
|
// TODO: test all flag combination
|
||||||
auto flags = mkEnumBitfield(AudioOutputFlag::NONE);
|
auto flags = mkEnumBitfield(AudioOutputFlag::NONE);
|
||||||
testOpen(
|
testOpen(
|
||||||
[&](AudioIoHandle handle, AudioConfig config, auto cb) {
|
[&](AudioIoHandle handle, AudioConfig config, auto cb) {
|
||||||
#if MAJOR_VERSION == 2
|
#if MAJOR_VERSION == 2
|
||||||
return device->openOutputStream(handle, address, config, flags, cb);
|
return getDevice()->openOutputStream(handle, address, config, flags, cb);
|
||||||
#elif MAJOR_VERSION >= 4
|
#elif MAJOR_VERSION >= 4
|
||||||
return device->openOutputStream(handle, address, config, flags, initMetadata, cb);
|
return getDevice()->openOutputStream(handle, address, config, flags,
|
||||||
|
initMetadata, cb);
|
||||||
#endif
|
#endif
|
||||||
},
|
},
|
||||||
config);
|
config);
|
||||||
}
|
}
|
||||||
#if MAJOR_VERSION >= 4
|
#if MAJOR_VERSION >= 4
|
||||||
|
|
||||||
|
@ -763,18 +882,23 @@ TEST_P(OutputStreamTest, OpenOutputStreamTest) {
|
||||||
// Open done in SetUp
|
// Open done in SetUp
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
RequiredOutputStreamConfigSupport, OutputStreamTest,
|
RequiredOutputStreamConfigSupport, OutputStreamTest,
|
||||||
::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportPlaybackAudioConfig()),
|
::testing::Combine(
|
||||||
&generateTestName);
|
::testing::ValuesIn(getDeviceParameters()),
|
||||||
|
::testing::ValuesIn(ConfigHelper::getRequiredSupportPlaybackAudioConfig())),
|
||||||
|
&DeviceConfigParameterToString);
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
SupportedOutputStreamConfig, OutputStreamTest,
|
SupportedOutputStreamConfig, OutputStreamTest,
|
||||||
::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedPlaybackAudioConfig()),
|
::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
|
||||||
&generateTestName);
|
::testing::ValuesIn(ConfigHelper::getSupportedPlaybackAudioConfig())),
|
||||||
|
&DeviceConfigParameterToString);
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
RecommendedOutputStreamConfigSupport, OutputStreamTest,
|
RecommendedOutputStreamConfigSupport, OutputStreamTest,
|
||||||
::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportPlaybackAudioConfig()),
|
::testing::Combine(
|
||||||
&generateTestName);
|
::testing::ValuesIn(getDeviceParameters()),
|
||||||
|
::testing::ValuesIn(ConfigHelper::getRecommendedSupportPlaybackAudioConfig())),
|
||||||
|
&DeviceConfigParameterToString);
|
||||||
|
|
||||||
////////////////////////////// openInputStream //////////////////////////////
|
////////////////////////////// openInputStream //////////////////////////////
|
||||||
|
|
||||||
|
@ -783,14 +907,15 @@ class InputStreamTest : public OpenStreamTest<IStreamIn> {
|
||||||
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
|
ASSERT_NO_FATAL_FAILURE(OpenStreamTest::SetUp()); // setup base
|
||||||
if (IsSkipped()) return; // do not attempt to use 'device'
|
if (IsSkipped()) return; // do not attempt to use 'device'
|
||||||
address.device = AudioDevice::IN_DEFAULT;
|
address.device = AudioDevice::IN_DEFAULT;
|
||||||
const AudioConfig& config = GetParam();
|
const AudioConfig& config = getConfig();
|
||||||
// TODO: test all supported flags and source
|
// TODO: test all supported flags and source
|
||||||
auto flags = mkEnumBitfield(AudioInputFlag::NONE);
|
auto flags = mkEnumBitfield(AudioInputFlag::NONE);
|
||||||
testOpen(
|
testOpen(
|
||||||
[&](AudioIoHandle handle, AudioConfig config, auto cb) {
|
[&](AudioIoHandle handle, AudioConfig config, auto cb) {
|
||||||
return device->openInputStream(handle, address, config, flags, initMetadata, cb);
|
return getDevice()->openInputStream(handle, address, config, flags,
|
||||||
},
|
initMetadata, cb);
|
||||||
config);
|
},
|
||||||
|
config);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -808,18 +933,23 @@ TEST_P(InputStreamTest, OpenInputStreamTest) {
|
||||||
// Open done in setup
|
// Open done in setup
|
||||||
}
|
}
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
RequiredInputStreamConfigSupport, InputStreamTest,
|
RequiredInputStreamConfigSupport, InputStreamTest,
|
||||||
::testing::ValuesIn(AudioConfigPrimaryTest::getRequiredSupportCaptureAudioConfig()),
|
::testing::Combine(
|
||||||
&generateTestName);
|
::testing::ValuesIn(getDeviceParameters()),
|
||||||
|
::testing::ValuesIn(ConfigHelper::getRequiredSupportCaptureAudioConfig())),
|
||||||
|
&DeviceConfigParameterToString);
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
SupportedInputStreamConfig, InputStreamTest,
|
SupportedInputStreamConfig, InputStreamTest,
|
||||||
::testing::ValuesIn(AudioConfigPrimaryTest::getSupportedCaptureAudioConfig()),
|
::testing::Combine(::testing::ValuesIn(getDeviceParameters()),
|
||||||
&generateTestName);
|
::testing::ValuesIn(ConfigHelper::getSupportedCaptureAudioConfig())),
|
||||||
|
&DeviceConfigParameterToString);
|
||||||
|
|
||||||
INSTANTIATE_TEST_CASE_P(
|
INSTANTIATE_TEST_CASE_P(
|
||||||
RecommendedInputStreamConfigSupport, InputStreamTest,
|
RecommendedInputStreamConfigSupport, InputStreamTest,
|
||||||
::testing::ValuesIn(AudioConfigPrimaryTest::getRecommendedSupportCaptureAudioConfig()),
|
::testing::Combine(
|
||||||
&generateTestName);
|
::testing::ValuesIn(getDeviceParameters()),
|
||||||
|
::testing::ValuesIn(ConfigHelper::getRecommendedSupportCaptureAudioConfig())),
|
||||||
|
&DeviceConfigParameterToString);
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
////////////////////////////// IStream getters ///////////////////////////////
|
////////////////////////////// IStream getters ///////////////////////////////
|
||||||
|
@ -1332,19 +1462,19 @@ TEST_P(OutputStreamTest, GetPresentationPositionStop) {
|
||||||
/////////////////////////////// PrimaryDevice ////////////////////////////////
|
/////////////////////////////// PrimaryDevice ////////////////////////////////
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TEST_F(AudioPrimaryHidlTest, setVoiceVolume) {
|
TEST_P(AudioPrimaryHidlTest, setVoiceVolume) {
|
||||||
doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
|
doc::test("Make sure setVoiceVolume only succeed if volume is in [0,1]");
|
||||||
testUnitaryGain([](float volume) { return device->setVoiceVolume(volume); });
|
testUnitaryGain([this](float volume) { return getDevice()->setVoiceVolume(volume); });
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
|
TEST_P(BoolAccessorPrimaryHidlTest, BtScoNrecEnabled) {
|
||||||
doc::test("Query and set the BT SCO NR&EC state");
|
doc::test("Query and set the BT SCO NR&EC state");
|
||||||
testAccessors<OPTIONAL>("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true},
|
testAccessors<OPTIONAL>("BtScoNrecEnabled", Initial{false, OPTIONAL}, {true},
|
||||||
&IPrimaryDevice::setBtScoNrecEnabled,
|
&IPrimaryDevice::setBtScoNrecEnabled,
|
||||||
&IPrimaryDevice::getBtScoNrecEnabled);
|
&IPrimaryDevice::getBtScoNrecEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
|
TEST_P(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
|
||||||
doc::test("Query and set the SCO whideband state");
|
doc::test("Query and set the SCO whideband state");
|
||||||
testAccessors<OPTIONAL>("BtScoWideband", Initial{false, OPTIONAL}, {true},
|
testAccessors<OPTIONAL>("BtScoWideband", Initial{false, OPTIONAL}, {true},
|
||||||
&IPrimaryDevice::setBtScoWidebandEnabled,
|
&IPrimaryDevice::setBtScoWidebandEnabled,
|
||||||
|
@ -1352,15 +1482,17 @@ TEST_F(BoolAccessorPrimaryHidlTest, setGetBtScoWidebandEnabled) {
|
||||||
}
|
}
|
||||||
|
|
||||||
using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<IPrimaryDevice::TtyMode>;
|
using TtyModeAccessorPrimaryHidlTest = AccessorPrimaryHidlTest<IPrimaryDevice::TtyMode>;
|
||||||
TEST_F(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
|
TEST_P(TtyModeAccessorPrimaryHidlTest, setGetTtyMode) {
|
||||||
doc::test("Query and set the TTY mode state");
|
doc::test("Query and set the TTY mode state");
|
||||||
testAccessors<OPTIONAL>(
|
testAccessors<OPTIONAL>(
|
||||||
"TTY mode", Initial{IPrimaryDevice::TtyMode::OFF},
|
"TTY mode", Initial{IPrimaryDevice::TtyMode::OFF},
|
||||||
{IPrimaryDevice::TtyMode::HCO, IPrimaryDevice::TtyMode::VCO, IPrimaryDevice::TtyMode::FULL},
|
{IPrimaryDevice::TtyMode::HCO, IPrimaryDevice::TtyMode::VCO, IPrimaryDevice::TtyMode::FULL},
|
||||||
&IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
|
&IPrimaryDevice::setTtyMode, &IPrimaryDevice::getTtyMode);
|
||||||
}
|
}
|
||||||
|
INSTANTIATE_TEST_CASE_P(TtyModeAccessorPrimaryHidl, TtyModeAccessorPrimaryHidlTest,
|
||||||
|
::testing::ValuesIn(getDeviceParameters()), &DeviceParameterToString);
|
||||||
|
|
||||||
TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
|
TEST_P(BoolAccessorPrimaryHidlTest, setGetHac) {
|
||||||
doc::test("Query and set the HAC state");
|
doc::test("Query and set the HAC state");
|
||||||
testAccessors<OPTIONAL>("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled,
|
testAccessors<OPTIONAL>("HAC", Initial{false}, {true}, &IPrimaryDevice::setHacEnabled,
|
||||||
&IPrimaryDevice::getHacEnabled);
|
&IPrimaryDevice::getHacEnabled);
|
||||||
|
@ -1372,9 +1504,13 @@ TEST_F(BoolAccessorPrimaryHidlTest, setGetHac) {
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char** argv) {
|
||||||
environment = new AudioHidlTestEnvironment;
|
environment = new AudioHidlTestEnvironment;
|
||||||
|
// For V2..5 it's critical to initialize environment before GTest.
|
||||||
|
// The environment parses the service name from the command line,
|
||||||
|
// then it can be used in GTest parameter generators which are
|
||||||
|
// initialized during the call to InitGoogleTest.
|
||||||
|
environment->init(&argc, argv);
|
||||||
::testing::AddGlobalTestEnvironment(environment);
|
::testing::AddGlobalTestEnvironment(environment);
|
||||||
::testing::InitGoogleTest(&argc, argv);
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
environment->init(&argc, argv);
|
|
||||||
int status = RUN_ALL_TESTS();
|
int status = RUN_ALL_TESTS();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
143
audio/core/all-versions/vts/functional/DeviceManager.h
Normal file
143
audio/core/all-versions/vts/functional/DeviceManager.h
Normal file
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Code in this file uses 'environment'
|
||||||
|
#ifndef AUDIO_PRIMARY_HIDL_HAL_TEST
|
||||||
|
#error Must be included from AudioPrimaryHidlTest.h
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class Derived, class Key, class Interface>
|
||||||
|
class InterfaceManager {
|
||||||
|
public:
|
||||||
|
sp<Interface> get(const Key& name) {
|
||||||
|
auto existing = instances.find(name);
|
||||||
|
if (existing != instances.end()) return existing->second;
|
||||||
|
auto [inserted, _] = instances.emplace(name, Derived::createInterfaceInstance(name));
|
||||||
|
if (inserted->second) {
|
||||||
|
environment->registerTearDown([name]() { (void)Derived::getInstance().reset(name); });
|
||||||
|
}
|
||||||
|
return inserted->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The test must check that reset was successful. Reset failure means that the test code
|
||||||
|
// is holding a strong reference to the device.
|
||||||
|
bool reset(const Key& name) __attribute__((warn_unused_result)) {
|
||||||
|
auto iter = instances.find(name);
|
||||||
|
if (iter == instances.end()) return true;
|
||||||
|
::android::wp<Interface> weak = iter->second;
|
||||||
|
instances.erase(iter);
|
||||||
|
if (weak.promote() != nullptr) return false;
|
||||||
|
waitForInstanceDestruction();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void waitForInstanceDestruction() {
|
||||||
|
// FIXME: there is no way to know when the remote IDevice is being destroyed
|
||||||
|
// Binder does not support testing if an object is alive, thus
|
||||||
|
// wait for 100ms to let the binder destruction propagates and
|
||||||
|
// the remote device has the time to be destroyed.
|
||||||
|
// flushCommand makes sure all local command are sent, thus should reduce
|
||||||
|
// the latency between local and remote destruction.
|
||||||
|
IPCThreadState::self()->flushCommands();
|
||||||
|
usleep(100 * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::map<Key, sp<Interface>> instances;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DevicesFactoryManager
|
||||||
|
: public InterfaceManager<DevicesFactoryManager, std::string, IDevicesFactory> {
|
||||||
|
public:
|
||||||
|
static DevicesFactoryManager& getInstance() {
|
||||||
|
static DevicesFactoryManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
static sp<IDevicesFactory> createInterfaceInstance(const std::string& name) {
|
||||||
|
#if MAJOR_VERSION <= 5
|
||||||
|
return ::testing::VtsHalHidlTargetTestBase::getService<IDevicesFactory>(name);
|
||||||
|
#elif MAJOR_VERSION >= 6
|
||||||
|
return IDevicesFactory::getService(name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using FactoryAndDevice = std::tuple<std::string, std::string>;
|
||||||
|
class DeviceManager : public InterfaceManager<DeviceManager, FactoryAndDevice, IDevice> {
|
||||||
|
public:
|
||||||
|
static DeviceManager& getInstance() {
|
||||||
|
static DeviceManager instance;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
static sp<IDevice> createInterfaceInstance(const FactoryAndDevice& factoryAndDevice) {
|
||||||
|
auto [factoryName, name] = factoryAndDevice;
|
||||||
|
sp<IDevicesFactory> factory = DevicesFactoryManager::getInstance().get(factoryName);
|
||||||
|
return name == kPrimaryDevice ? openPrimaryDevice(factory) : openDevice(factory, name);
|
||||||
|
}
|
||||||
|
using InterfaceManager::reset;
|
||||||
|
|
||||||
|
static constexpr const char* kPrimaryDevice = "primary";
|
||||||
|
|
||||||
|
sp<IDevice> get(const std::string& factoryName, const std::string& name) {
|
||||||
|
return InterfaceManager::get(std::make_tuple(factoryName, name));
|
||||||
|
}
|
||||||
|
sp<IPrimaryDevice> getPrimary(const std::string& factoryName) {
|
||||||
|
sp<IDevice> device = get(factoryName, kPrimaryDevice);
|
||||||
|
return device != nullptr ? IPrimaryDevice::castFrom(device) : nullptr;
|
||||||
|
}
|
||||||
|
bool reset(const std::string& factoryName, const std::string& name)
|
||||||
|
__attribute__((warn_unused_result)) {
|
||||||
|
return InterfaceManager::reset(std::make_tuple(factoryName, name));
|
||||||
|
}
|
||||||
|
bool resetPrimary(const std::string& factoryName) __attribute__((warn_unused_result)) {
|
||||||
|
return reset(factoryName, kPrimaryDevice);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static sp<IDevice> openDevice(const sp<IDevicesFactory>& factory, const std::string& name) {
|
||||||
|
if (factory == nullptr) return nullptr;
|
||||||
|
sp<IDevice> device;
|
||||||
|
#if MAJOR_VERSION >= 4
|
||||||
|
Result result;
|
||||||
|
auto ret = factory->openDevice(name, returnIn(result, device));
|
||||||
|
if (!ret.isOk() || result != Result::OK || device == nullptr) {
|
||||||
|
ALOGW("Device %s can not be opened, transaction: %s, result %d, device %p",
|
||||||
|
name.c_str(), ret.description().c_str(), result, device.get());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
(void)name;
|
||||||
|
#endif
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
|
||||||
|
static sp<IDevice> openPrimaryDevice(const sp<IDevicesFactory>& factory) {
|
||||||
|
if (factory == nullptr) return nullptr;
|
||||||
|
Result result;
|
||||||
|
sp<IDevice> device;
|
||||||
|
#if MAJOR_VERSION == 2
|
||||||
|
auto ret = factory->openDevice(IDevicesFactory::Device::PRIMARY, returnIn(result, device));
|
||||||
|
#elif MAJOR_VERSION >= 4
|
||||||
|
auto ret = factory->openPrimaryDevice(returnIn(result, device));
|
||||||
|
#endif
|
||||||
|
if (!ret.isOk() || result != Result::OK || device == nullptr) {
|
||||||
|
ALOGW("Primary device can not be opened, transaction: %s, result %d, device %p",
|
||||||
|
ret.description().c_str(), result, device.get());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
};
|
Loading…
Reference in a new issue