Merge changes I651202ac,I939e2d9f
* changes:
Update audio playback session for fast compatible effects
Add audiosystem unit tests
diff --git a/media/libaudioclient/TEST_MAPPING b/media/libaudioclient/TEST_MAPPING
index d36cf10..2214bca 100644
--- a/media/libaudioclient/TEST_MAPPING
+++ b/media/libaudioclient/TEST_MAPPING
@@ -31,5 +31,10 @@
{
"name": "trackplayerbase_tests"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "audiosystem_tests"
+ }
]
}
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 6535b5b..e861932 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -118,7 +118,7 @@
"libshmemcompat",
"libstagefright_foundation",
"libutils",
- "libvibrator",
+ "libxml2",
"mediametricsservice-aidl-cpp",
"packagemanager_aidl-cpp",
"shared-file-region-aidl-cpp",
@@ -178,9 +178,6 @@
"audiorouting_tests.cpp",
"audio_test_utils.cpp",
],
- shared_libs: [
- "libxml2",
- ],
}
cc_test {
@@ -197,3 +194,12 @@
defaults: ["libaudioclient_gtests_defaults"],
srcs: ["trackplayerbase_tests.cpp"],
}
+
+cc_test {
+ name: "audiosystem_tests",
+ defaults: ["libaudioclient_gtests_defaults"],
+ srcs: [
+ "audiosystem_tests.cpp",
+ "audio_test_utils.cpp",
+ ],
+}
diff --git a/media/libaudioclient/tests/audio_test_utils.cpp b/media/libaudioclient/tests/audio_test_utils.cpp
index 018d920..44f0f50 100644
--- a/media/libaudioclient/tests/audio_test_utils.cpp
+++ b/media/libaudioclient/tests/audio_test_utils.cpp
@@ -17,10 +17,26 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioTestUtils"
+#include <system/audio_config.h>
#include <utils/Log.h>
#include "audio_test_utils.h"
+template <class T>
+constexpr void (*xmlDeleter)(T* t);
+template <>
+constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
+template <>
+constexpr auto xmlDeleter<xmlChar> = [](xmlChar* s) { xmlFree(s); };
+
+/** @return a unique_ptr with the correct deleter for the libxml2 object. */
+template <class T>
+constexpr auto make_xmlUnique(T* t) {
+ // Wrap deleter in lambda to enable empty base optimization
+ auto deleter = [](T* t) { xmlDeleter<T>(t); };
+ return std::unique_ptr<T, decltype(deleter)>{t, deleter};
+}
+
// Generates a random string.
void CreateRandomFile(int& fd) {
std::string filename = "/data/local/tmp/record-XXXXXX";
@@ -466,6 +482,11 @@
status_t status = OK;
mStopRecording = true;
if (mState != REC_STOPPED) {
+ if (mInputSource != AUDIO_SOURCE_DEFAULT) {
+ bool state = false;
+ status = AudioSystem::isSourceActive(mInputSource, &state);
+ if (status == OK && !state) status = BAD_VALUE;
+ }
mRecord->stopAndJoinCallbacks();
mState = REC_STOPPED;
LOG_FATAL_IF(true != mRecord->stopped());
@@ -793,3 +814,91 @@
result << dumpPortConfig(port.active_config);
return result.str();
}
+
+std::string getXmlAttribute(const xmlNode* cur, const char* attribute) {
+ auto charPtr = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
+ if (charPtr == NULL) {
+ return "";
+ }
+ std::string value(reinterpret_cast<const char*>(charPtr.get()));
+ return value;
+}
+
+status_t parse_audio_policy_configuration_xml(std::vector<std::string>& attachedDevices,
+ std::vector<MixPort>& mixPorts,
+ std::vector<Route>& routes) {
+ std::string path = audio_find_readable_configuration_file("audio_policy_configuration.xml");
+ if (path.length() == 0) return UNKNOWN_ERROR;
+ auto doc = make_xmlUnique(xmlParseFile(path.c_str()));
+ if (doc == nullptr) return UNKNOWN_ERROR;
+ xmlNode* root = xmlDocGetRootElement(doc.get());
+ if (root == nullptr) return UNKNOWN_ERROR;
+ if (xmlXIncludeProcess(doc.get()) < 0) return UNKNOWN_ERROR;
+ mixPorts.clear();
+ if (!xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>("audioPolicyConfiguration"))) {
+ std::string raw{getXmlAttribute(root, "version")};
+ for (auto* child = root->xmlChildrenNode; child != nullptr; child = child->next) {
+ if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>("modules"))) {
+ xmlNode* root = child;
+ for (auto* child = root->xmlChildrenNode; child != nullptr; child = child->next) {
+ if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>("module"))) {
+ xmlNode* root = child;
+ for (auto* child = root->xmlChildrenNode; child != nullptr;
+ child = child->next) {
+ if (!xmlStrcmp(child->name,
+ reinterpret_cast<const xmlChar*>("mixPorts"))) {
+ xmlNode* root = child;
+ for (auto* child = root->xmlChildrenNode; child != nullptr;
+ child = child->next) {
+ if (!xmlStrcmp(child->name,
+ reinterpret_cast<const xmlChar*>("mixPort"))) {
+ MixPort mixPort;
+ xmlNode* root = child;
+ mixPort.name = getXmlAttribute(root, "name");
+ mixPort.role = getXmlAttribute(root, "role");
+ mixPort.flags = getXmlAttribute(root, "flags");
+ if (mixPort.role == "source") mixPorts.push_back(mixPort);
+ }
+ }
+ } else if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(
+ "attachedDevices"))) {
+ xmlNode* root = child;
+ for (auto* child = root->xmlChildrenNode; child != nullptr;
+ child = child->next) {
+ if (!xmlStrcmp(child->name,
+ reinterpret_cast<const xmlChar*>("item"))) {
+ auto xmlValue = make_xmlUnique(xmlNodeListGetString(
+ child->doc, child->xmlChildrenNode, 1));
+ if (xmlValue == nullptr) {
+ raw = "";
+ } else {
+ raw = reinterpret_cast<const char*>(xmlValue.get());
+ }
+ std::string& value = raw;
+ attachedDevices.push_back(std::move(value));
+ }
+ }
+ } else if (!xmlStrcmp(child->name,
+ reinterpret_cast<const xmlChar*>("routes"))) {
+ xmlNode* root = child;
+ for (auto* child = root->xmlChildrenNode; child != nullptr;
+ child = child->next) {
+ if (!xmlStrcmp(child->name,
+ reinterpret_cast<const xmlChar*>("route"))) {
+ Route route;
+ xmlNode* root = child;
+ route.name = getXmlAttribute(root, "name");
+ route.sources = getXmlAttribute(root, "sources");
+ route.sink = getXmlAttribute(root, "sink");
+ routes.push_back(route);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return OK;
+}
diff --git a/media/libaudioclient/tests/audio_test_utils.h b/media/libaudioclient/tests/audio_test_utils.h
index 526d5c4..f35b65d 100644
--- a/media/libaudioclient/tests/audio_test_utils.h
+++ b/media/libaudioclient/tests/audio_test_utils.h
@@ -28,6 +28,8 @@
#include <thread>
#include <binder/MemoryDealer.h>
+#include <libxml/parser.h>
+#include <libxml/xinclude.h>
#include <media/AidlConversion.h>
#include <media/AudioRecord.h>
#include <media/AudioTrack.h>
@@ -36,6 +38,21 @@
using namespace android;
+struct MixPort {
+ std::string name;
+ std::string role;
+ std::string flags;
+};
+
+struct Route {
+ std::string name;
+ std::string sources;
+ std::string sink;
+};
+
+status_t parse_audio_policy_configuration_xml(std::vector<std::string>& attachedDevices,
+ std::vector<MixPort>& mixPorts,
+ std::vector<Route>& routes);
void CreateRandomFile(int& fd);
status_t listAudioPorts(std::vector<audio_port_v7>& portsVec);
status_t listAudioPatches(std::vector<struct audio_patch>& patchesVec);
diff --git a/media/libaudioclient/tests/audioeffect_tests.cpp b/media/libaudioclient/tests/audioeffect_tests.cpp
index 93fe306..e6149e4 100644
--- a/media/libaudioclient/tests/audioeffect_tests.cpp
+++ b/media/libaudioclient/tests/audioeffect_tests.cpp
@@ -19,19 +19,43 @@
#include <gtest/gtest.h>
#include <media/AudioEffect.h>
+#include <system/audio_effects/effect_hapticgenerator.h>
+#include <system/audio_effects/effect_spatializer.h>
#include <system/audio_effects/effect_visualizer.h>
#include "audio_test_utils.h"
using namespace android;
+class AudioEffectCallback : public AudioEffect::IAudioEffectCallback {
+ public:
+ bool receivedFramesProcessed = false;
+
+ void onFramesProcessed(int32_t framesProcessed) override {
+ ALOGE("number of frames processed %d", framesProcessed);
+ receivedFramesProcessed = true;
+ }
+};
+
static constexpr int kDefaultInputEffectPriority = -1;
static constexpr int kDefaultOutputEffectPriority = 0;
static const char* gPackageName = "AudioEffectTest";
-bool isEffectExistsOnAudioSession(const effect_uuid_t* type, int priority,
- audio_session_t sessionId) {
+bool doesDeviceSupportLowLatencyMode(std::vector<struct audio_port_v7>& ports) {
+ for (const auto& port : ports) {
+ if (port.role == AUDIO_PORT_ROLE_SOURCE && port.type == AUDIO_PORT_TYPE_MIX) {
+ if ((port.active_config.flags.output & AUDIO_OUTPUT_FLAG_FAST) != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+sp<AudioEffect> createEffect(const effect_uuid_t* type, const effect_uuid_t* uuid = nullptr,
+ int priority = 0, audio_session_t sessionId = AUDIO_SESSION_OUTPUT_MIX,
+ const wp<AudioEffectCallback>& callback = nullptr) {
std::string packageName{gPackageName};
AttributionSourceState attributionSource;
attributionSource.packageName = packageName;
@@ -39,11 +63,19 @@
attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
attributionSource.token = sp<BBinder>::make();
sp<AudioEffect> effect = new AudioEffect(attributionSource);
- effect->set(type, nullptr /* uid */, priority, nullptr /* callback */, sessionId);
- return effect->initCheck() == ALREADY_EXISTS;
+ effect->set(type, uuid, priority, callback, sessionId, AUDIO_IO_HANDLE_NONE, {}, false,
+ (callback != nullptr));
+ return effect;
}
-bool isEffectDefaultOnRecord(const effect_uuid_t* type, const sp<AudioRecord>& audioRecord) {
+status_t isEffectExistsOnAudioSession(const effect_uuid_t* type, const effect_uuid_t* uuid,
+ int priority, audio_session_t sessionId) {
+ sp<AudioEffect> effect = createEffect(type, uuid, priority, sessionId);
+ return effect->initCheck();
+}
+
+bool isEffectDefaultOnRecord(const effect_uuid_t* type, const effect_uuid_t* uuid,
+ const sp<AudioRecord>& audioRecord) {
effect_descriptor_t descriptors[AudioEffect::kMaxPreProcessing];
uint32_t numEffects = AudioEffect::kMaxPreProcessing;
status_t ret = AudioEffect::queryDefaultPreProcessing(audioRecord->getSessionId(), descriptors,
@@ -52,7 +84,8 @@
return false;
}
for (int i = 0; i < numEffects; i++) {
- if (memcmp(&descriptors[i].type, type, sizeof(effect_uuid_t)) == 0) {
+ if ((memcmp(&descriptors[i].type, type, sizeof(effect_uuid_t)) == 0) &&
+ (memcmp(&descriptors[i].uuid, uuid, sizeof(effect_uuid_t)) == 0)) {
return true;
}
}
@@ -61,11 +94,11 @@
void listEffectsAvailable(std::vector<effect_descriptor_t>& descriptors) {
uint32_t numEffects = 0;
- if (NO_ERROR == AudioEffect::queryNumberEffects(&numEffects)) {
- for (auto i = 0; i < numEffects; i++) {
- effect_descriptor_t des;
- if (NO_ERROR == AudioEffect::queryEffect(i, &des)) descriptors.push_back(des);
- }
+ ASSERT_EQ(NO_ERROR, AudioEffect::queryNumberEffects(&numEffects));
+ for (auto i = 0; i < numEffects; i++) {
+ effect_descriptor_t des;
+ ASSERT_EQ(NO_ERROR, AudioEffect::queryEffect(i, &des));
+ descriptors.push_back(des);
}
}
@@ -81,11 +114,31 @@
return ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY);
}
+bool isPostproc(effect_descriptor_t& descriptor) {
+ return ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC);
+}
+
bool isFastCompatible(effect_descriptor_t& descriptor) {
return !(((descriptor.flags & EFFECT_FLAG_HW_ACC_MASK) == 0) &&
((descriptor.flags & EFFECT_FLAG_NO_PROCESS) == 0));
}
+bool isSpatializer(effect_descriptor_t& descriptor) {
+ return (memcmp(&descriptor.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0);
+}
+
+bool isHapticGenerator(effect_descriptor_t& descriptor) {
+ return (memcmp(&descriptor.type, FX_IID_HAPTICGENERATOR, sizeof(effect_uuid_t)) == 0);
+}
+
+std::tuple<std::string, std::string> typeAndUuidToString(const effect_descriptor_t& desc) {
+ char type[512];
+ AudioEffect::guidToString(&desc.type, type, sizeof(type));
+ char uuid[512];
+ AudioEffect::guidToString(&desc.uuid, uuid, sizeof(uuid));
+ return std::make_tuple(type, uuid);
+}
+
// UNIT TESTS
TEST(AudioEffectTest, getEffectDescriptor) {
effect_uuid_t randomType = {
@@ -99,7 +152,7 @@
EFFECT_FLAG_TYPE_MASK, &descriptor));
std::vector<effect_descriptor_t> descriptors;
- listEffectsAvailable(descriptors);
+ ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
for (auto i = 0; i < descriptors.size(); i++) {
EXPECT_EQ(NO_ERROR,
@@ -124,15 +177,7 @@
}
TEST(AudioEffectTest, DISABLED_GetSetParameterForEffect) {
- std::string packageName{gPackageName};
- AttributionSourceState attributionSource;
- attributionSource.packageName = packageName;
- attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
- attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
- attributionSource.token = sp<BBinder>::make();
- sp<AudioEffect> visualizer = new AudioEffect(attributionSource);
- ASSERT_NE(visualizer, nullptr) << "effect not created";
- visualizer->set(SL_IID_VISUALIZATION);
+ sp<AudioEffect> visualizer = createEffect(SL_IID_VISUALIZATION);
status_t status = visualizer->initCheck();
ASSERT_TRUE(status == NO_ERROR || status == ALREADY_EXISTS) << "Init check error";
ASSERT_EQ(NO_ERROR, visualizer->setEnabled(true)) << "visualizer not enabled";
@@ -195,51 +240,58 @@
sp<AudioCapture> capture = nullptr;
std::vector<effect_descriptor_t> descriptors;
- listEffectsAvailable(descriptors);
+ ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
for (auto i = 0; i < descriptors.size(); i++) {
if (isPreprocessing(descriptors[i])) {
capture = new AudioCapture(AUDIO_SOURCE_MIC, sampleRate, format, channelMask);
ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
EXPECT_EQ(NO_ERROR, capture->create());
EXPECT_EQ(NO_ERROR, capture->start());
- if (!isEffectDefaultOnRecord(&descriptors[i].type, capture->getAudioRecordHandle())) {
+ if (!isEffectDefaultOnRecord(&descriptors[i].type, &descriptors[i].uuid,
+ capture->getAudioRecordHandle())) {
selectedEffect = i;
break;
}
}
}
if (selectedEffect == -1) GTEST_SKIP() << " expected at least one preprocessing effect";
- effect_uuid_t selectedEffectType = descriptors[selectedEffect].type;
- char type[512];
- AudioEffect::guidToString(&selectedEffectType, type, sizeof(type));
-
+ effect_uuid_t* selectedEffectType = &descriptors[selectedEffect].type;
+ effect_uuid_t* selectedEffectUuid = &descriptors[selectedEffect].uuid;
+ auto [type, uuid] = typeAndUuidToString(descriptors[selectedEffect]);
capture = new AudioCapture(AUDIO_SOURCE_MIC, sampleRate, format, channelMask);
ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
EXPECT_EQ(NO_ERROR, capture->create());
EXPECT_EQ(NO_ERROR, capture->start());
- EXPECT_FALSE(isEffectDefaultOnRecord(&selectedEffectType, capture->getAudioRecordHandle()))
+ EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
+ capture->getAudioRecordHandle()))
<< "Effect should not have been default on record. " << type;
- EXPECT_FALSE(isEffectExistsOnAudioSession(&selectedEffectType, kDefaultInputEffectPriority - 1,
- capture->getAudioRecordHandle()->getSessionId()))
+ EXPECT_EQ(NO_ERROR,
+ isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
+ kDefaultInputEffectPriority - 1,
+ capture->getAudioRecordHandle()->getSessionId()))
<< "Effect should not have been added. " << type;
EXPECT_EQ(OK, capture->audioProcess());
EXPECT_EQ(OK, capture->stop());
String16 name{gPackageName};
audio_unique_id_t effectId;
- status_t status = AudioEffect::addSourceDefaultEffect(
- type, name, nullptr, kDefaultInputEffectPriority, AUDIO_SOURCE_MIC, &effectId);
+ status_t status = AudioEffect::addSourceDefaultEffect(type.c_str(), name, uuid.c_str(),
+ kDefaultInputEffectPriority,
+ AUDIO_SOURCE_MIC, &effectId);
EXPECT_EQ(NO_ERROR, status) << "Adding default effect failed: " << type;
capture = new AudioCapture(AUDIO_SOURCE_MIC, sampleRate, format, channelMask);
ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
EXPECT_EQ(NO_ERROR, capture->create());
EXPECT_EQ(NO_ERROR, capture->start());
- EXPECT_TRUE(isEffectDefaultOnRecord(&selectedEffectType, capture->getAudioRecordHandle()))
+ EXPECT_TRUE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
+ capture->getAudioRecordHandle()))
<< "Effect should have been default on record. " << type;
- EXPECT_TRUE(isEffectExistsOnAudioSession(&selectedEffectType, kDefaultInputEffectPriority - 1,
- capture->getAudioRecordHandle()->getSessionId()))
+ EXPECT_EQ(ALREADY_EXISTS,
+ isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
+ kDefaultInputEffectPriority - 1,
+ capture->getAudioRecordHandle()->getSessionId()))
<< "Effect should have been added. " << type;
EXPECT_EQ(OK, capture->audioProcess());
EXPECT_EQ(OK, capture->stop());
@@ -250,86 +302,258 @@
ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
EXPECT_EQ(NO_ERROR, capture->create());
EXPECT_EQ(NO_ERROR, capture->start());
- EXPECT_FALSE(isEffectDefaultOnRecord(&selectedEffectType, capture->getAudioRecordHandle()))
+ EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
+ capture->getAudioRecordHandle()))
<< "Effect should not have been default on record. " << type;
- EXPECT_FALSE(isEffectExistsOnAudioSession(&selectedEffectType, kDefaultInputEffectPriority - 1,
- capture->getAudioRecordHandle()->getSessionId()))
+ EXPECT_EQ(NO_ERROR,
+ isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
+ kDefaultInputEffectPriority - 1,
+ capture->getAudioRecordHandle()->getSessionId()))
<< "Effect should not have been added. " << type;
EXPECT_EQ(OK, capture->audioProcess());
EXPECT_EQ(OK, capture->stop());
}
-TEST(AudioEffectTest, ManageStreamDefaultEffects) {
+TEST(AudioEffectTest, AuxEffectSanityTest) {
int32_t selectedEffect = -1;
-
std::vector<effect_descriptor_t> descriptors;
- listEffectsAvailable(descriptors);
+ ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
for (auto i = 0; i < descriptors.size(); i++) {
if (isAux(descriptors[i])) {
selectedEffect = i;
break;
}
}
- if (selectedEffect == -1) GTEST_SKIP() << " expected at least one Aux effect";
+ if (selectedEffect == -1) GTEST_SKIP() << "expected at least one aux effect";
effect_uuid_t* selectedEffectType = &descriptors[selectedEffect].type;
+ effect_uuid_t* selectedEffectUuid = &descriptors[selectedEffect].uuid;
+ auto [type, uuid] = typeAndUuidToString(descriptors[selectedEffect]);
+ String16 name{gPackageName};
+ audio_session_t sessionId =
+ (audio_session_t)AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+ sp<AudioEffect> audioEffect = createEffect(selectedEffectType, selectedEffectUuid,
+ kDefaultInputEffectPriority, sessionId);
+ EXPECT_EQ(NO_INIT, audioEffect->initCheck())
+ << "error, creating auxiliary effect (" << type << ") on session id " << (int)sessionId
+ << " successful ";
+ audio_unique_id_t id;
+ status_t status = AudioEffect::addStreamDefaultEffect(
+ type.c_str(), name, uuid.c_str(), kDefaultOutputEffectPriority, AUDIO_USAGE_MEDIA, &id);
+ if (status == NO_ERROR) {
+ EXPECT_EQ(NO_ERROR, AudioEffect::removeStreamDefaultEffect(id));
+ EXPECT_NE(NO_ERROR, status) << "error, adding auxiliary effect (" << type
+ << ") as stream default effect is successful";
+ }
+}
- char type[512];
- AudioEffect::guidToString(selectedEffectType, type, sizeof(type));
+class AudioPlaybackEffectTest : public ::testing::TestWithParam<bool> {
+ public:
+ AudioPlaybackEffectTest() : mSelectFastMode(GetParam()){};
+
+ const bool mSelectFastMode;
+
+ bool mIsFastCompatibleEffect;
+ effect_uuid_t mType;
+ effect_uuid_t mUuid;
+ std::string mTypeStr;
+ std::string mUuidStr;
+
+ void SetUp() override {
+ if (mSelectFastMode) {
+ std::vector<struct audio_port_v7> ports;
+ ASSERT_EQ(OK, listAudioPorts(ports));
+ if (!doesDeviceSupportLowLatencyMode(ports)) {
+ GTEST_SKIP() << "device does not support low latency mode";
+ }
+ }
+
+ int32_t selectedEffect = -1;
+ std::vector<effect_descriptor_t> descriptors;
+ ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
+ for (auto i = 0; i < descriptors.size(); i++) {
+ if (isSpatializer(descriptors[i])) continue;
+ if (isHapticGenerator(descriptors[i]) && !AudioSystem::isHapticPlaybackSupported())
+ continue;
+ if (!isInsert(descriptors[i])) continue;
+ selectedEffect = i;
+ mIsFastCompatibleEffect = isFastCompatible(descriptors[i]);
+ // in fast mode, pick fast compatible effect if available
+ if (mSelectFastMode == mIsFastCompatibleEffect) break;
+ }
+ if (selectedEffect == -1) {
+ GTEST_SKIP() << "expected at least one valid effect";
+ }
+
+ mType = descriptors[selectedEffect].type;
+ mUuid = descriptors[selectedEffect].uuid;
+ std::tie(mTypeStr, mUuidStr) = typeAndUuidToString(descriptors[selectedEffect]);
+ }
+};
+
+TEST_P(AudioPlaybackEffectTest, StreamDefaultEffectTest) {
+ SCOPED_TRACE(testing::Message()
+ << "\n selected effect type is :: " << mTypeStr
+ << "\n selected effect uuid is :: " << mUuidStr
+ << "\n audiotrack output flag : " << (mSelectFastMode ? "fast" : "default")
+ << "\n audio effect is fast compatible : "
+ << (mIsFastCompatibleEffect ? "yes" : "no"));
+
+ bool compatCheck = !mSelectFastMode || (mSelectFastMode && mIsFastCompatibleEffect);
+
// create track
audio_attributes_t attributes;
attributes.usage = AUDIO_USAGE_MEDIA;
attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
auto playback = sp<AudioPlayback>::make(
- 44100 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_SHARED, &attributes);
+ 0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ mSelectFastMode ? AUDIO_OUTPUT_FLAG_FAST : AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE,
+ AudioTrack::TRANSFER_SHARED, &attributes);
ASSERT_NE(nullptr, playback);
ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
EXPECT_EQ(NO_ERROR, playback->create());
EXPECT_EQ(NO_ERROR, playback->start());
- EXPECT_FALSE(isEffectExistsOnAudioSession(selectedEffectType, kDefaultOutputEffectPriority - 1,
- playback->getAudioTrackHandle()->getSessionId()))
- << "Effect should not have been added. " << type;
+ EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT,
+ isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
+ playback->getAudioTrackHandle()->getSessionId()))
+ << "Effect should not have been added. " << mTypeStr;
EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
playback->stop();
playback.clear();
String16 name{gPackageName};
audio_unique_id_t id;
- status_t status = AudioEffect::addStreamDefaultEffect(
- type, name, nullptr, kDefaultOutputEffectPriority, AUDIO_USAGE_MEDIA, &id);
- EXPECT_EQ(NO_ERROR, status) << "Adding default effect failed: " << type;
+ status_t status = AudioEffect::addStreamDefaultEffect(mTypeStr.c_str(), name, mUuidStr.c_str(),
+ kDefaultOutputEffectPriority,
+ AUDIO_USAGE_MEDIA, &id);
+ EXPECT_EQ(NO_ERROR, status) << "Adding default effect failed: " << mTypeStr;
playback = sp<AudioPlayback>::make(
- 44100 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_SHARED, &attributes);
+ 0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ mSelectFastMode ? AUDIO_OUTPUT_FLAG_FAST : AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE,
+ AudioTrack::TRANSFER_SHARED, &attributes);
ASSERT_NE(nullptr, playback);
ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
EXPECT_EQ(NO_ERROR, playback->create());
- float level = 0.2f, levelGot;
- playback->getAudioTrackHandle()->setAuxEffectSendLevel(level);
EXPECT_EQ(NO_ERROR, playback->start());
- EXPECT_TRUE(isEffectExistsOnAudioSession(selectedEffectType, kDefaultOutputEffectPriority - 1,
- playback->getAudioTrackHandle()->getSessionId()))
- << "Effect should have been added. " << type;
+ // If effect chosen is not compatible with the session, then effect won't be applied
+ EXPECT_EQ(compatCheck ? ALREADY_EXISTS : NO_INIT,
+ isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
+ playback->getAudioTrackHandle()->getSessionId()))
+ << "Effect should have been added. " << mTypeStr;
EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
- playback->getAudioTrackHandle()->getAuxEffectSendLevel(&levelGot);
- EXPECT_EQ(level, levelGot);
+ if (mSelectFastMode) {
+ EXPECT_EQ(AUDIO_OUTPUT_FLAG_FAST,
+ playback->getAudioTrackHandle()->getFlags() & AUDIO_OUTPUT_FLAG_FAST);
+ }
playback->stop();
playback.clear();
status = AudioEffect::removeStreamDefaultEffect(id);
EXPECT_EQ(NO_ERROR, status);
playback = sp<AudioPlayback>::make(
- 44100 /*sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE, AudioTrack::TRANSFER_SHARED, &attributes);
+ 0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ mSelectFastMode ? AUDIO_OUTPUT_FLAG_FAST : AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE,
+ AudioTrack::TRANSFER_SHARED, &attributes);
ASSERT_NE(nullptr, playback);
ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
EXPECT_EQ(NO_ERROR, playback->create());
EXPECT_EQ(NO_ERROR, playback->start());
- EXPECT_FALSE(isEffectExistsOnAudioSession(selectedEffectType, kDefaultOutputEffectPriority - 1,
- playback->getAudioTrackHandle()->getSessionId()))
- << "Effect should not have been added. " << type;
+ EXPECT_EQ(compatCheck ? NO_ERROR : NO_INIT,
+ isEffectExistsOnAudioSession(&mType, &mUuid, kDefaultOutputEffectPriority - 1,
+ playback->getAudioTrackHandle()->getSessionId()))
+ << "Effect should not have been added. " << mTypeStr;
EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
playback->stop();
playback.clear();
}
+
+TEST_P(AudioPlaybackEffectTest, CheckOutputFlagCompatibility) {
+ SCOPED_TRACE(testing::Message()
+ << "\n selected effect type is :: " << mTypeStr
+ << "\n selected effect uuid is :: " << mUuidStr
+ << "\n audiotrack output flag : " << (mSelectFastMode ? "fast" : "default")
+ << "\n audio effect is fast compatible : "
+ << (mIsFastCompatibleEffect ? "yes" : "no"));
+
+ audio_attributes_t attributes;
+ attributes.usage = AUDIO_USAGE_MEDIA;
+ attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
+ audio_session_t sessionId =
+ (audio_session_t)AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+ sp<AudioEffectCallback> cb = sp<AudioEffectCallback>::make();
+ sp<AudioEffect> audioEffect =
+ createEffect(&mType, &mUuid, kDefaultOutputEffectPriority, sessionId, cb);
+ ASSERT_EQ(OK, audioEffect->initCheck());
+ ASSERT_EQ(NO_ERROR, audioEffect->setEnabled(true));
+ auto playback = sp<AudioPlayback>::make(
+ 0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_MONO,
+ mSelectFastMode ? AUDIO_OUTPUT_FLAG_FAST : AUDIO_OUTPUT_FLAG_NONE, sessionId,
+ AudioTrack::TRANSFER_SHARED, &attributes);
+ ASSERT_NE(nullptr, playback);
+ ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_1ch_8kHz_s16le.raw"));
+ EXPECT_EQ(NO_ERROR, playback->create());
+ EXPECT_EQ(NO_ERROR, playback->start());
+
+ EXPECT_EQ(ALREADY_EXISTS, isEffectExistsOnAudioSession(
+ &mType, &mUuid, kDefaultOutputEffectPriority - 1, sessionId))
+ << "Effect should have been added. " << mTypeStr;
+ if (mSelectFastMode) {
+ EXPECT_EQ(mIsFastCompatibleEffect ? AUDIO_OUTPUT_FLAG_FAST : 0,
+ playback->getAudioTrackHandle()->getFlags() & AUDIO_OUTPUT_FLAG_FAST);
+ }
+ EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
+ EXPECT_EQ(NO_ERROR, playback->getAudioTrackHandle()->attachAuxEffect(0));
+ playback->stop();
+ playback.clear();
+ EXPECT_TRUE(cb->receivedFramesProcessed)
+ << "AudioEffect frames processed callback not received";
+}
+
+INSTANTIATE_TEST_SUITE_P(EffectParameterizedTests, AudioPlaybackEffectTest, ::testing::Bool());
+
+TEST(AudioEffectTest, TestHapticEffect) {
+ if (!AudioSystem::isHapticPlaybackSupported())
+ GTEST_SKIP() << "Haptic playback is not supported";
+ int32_t selectedEffect = -1;
+ std::vector<effect_descriptor_t> descriptors;
+ ASSERT_NO_FATAL_FAILURE(listEffectsAvailable(descriptors));
+ for (auto i = 0; i < descriptors.size(); i++) {
+ if (!isHapticGenerator(descriptors[i])) continue;
+ selectedEffect = i;
+ break;
+ }
+ if (selectedEffect == -1) GTEST_SKIP() << "expected at least one valid effect";
+
+ effect_uuid_t* selectedEffectType = &descriptors[selectedEffect].type;
+ effect_uuid_t* selectedEffectUuid = &descriptors[selectedEffect].uuid;
+ auto [type, uuid] = typeAndUuidToString(descriptors[selectedEffect]);
+
+ SCOPED_TRACE(testing::Message() << "\n selected effect type is :: " << type
+ << "\n selected effect uuid is :: " << uuid);
+
+ audio_attributes_t attributes;
+ attributes.usage = AUDIO_USAGE_MEDIA;
+ attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
+ audio_session_t sessionId =
+ (audio_session_t)AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+ sp<AudioEffectCallback> cb = sp<AudioEffectCallback>::make();
+ sp<AudioEffect> audioEffect = createEffect(selectedEffectType, selectedEffectUuid,
+ kDefaultOutputEffectPriority, sessionId, cb);
+ ASSERT_EQ(OK, audioEffect->initCheck());
+ ASSERT_EQ(NO_ERROR, audioEffect->setEnabled(true));
+ auto playback = sp<AudioPlayback>::make(0 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_CHANNEL_OUT_STEREO, AUDIO_OUTPUT_FLAG_NONE,
+ sessionId, AudioTrack::TRANSFER_SHARED, &attributes);
+ ASSERT_NE(nullptr, playback);
+ ASSERT_EQ(NO_ERROR, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
+ EXPECT_EQ(NO_ERROR, playback->create());
+ EXPECT_EQ(NO_ERROR, playback->start());
+ EXPECT_TRUE(isEffectExistsOnAudioSession(selectedEffectType, selectedEffectUuid,
+ kDefaultOutputEffectPriority - 1, sessionId))
+ << "Effect should have been added. " << type;
+ EXPECT_EQ(NO_ERROR, playback->waitForConsumption());
+ playback->stop();
+ playback.clear();
+ EXPECT_TRUE(cb->receivedFramesProcessed)
+ << "AudioEffect frames processed callback not received";
+}
diff --git a/media/libaudioclient/tests/audiorecord_tests.cpp b/media/libaudioclient/tests/audiorecord_tests.cpp
index 754e6cc..8c63a6d 100644
--- a/media/libaudioclient/tests/audiorecord_tests.cpp
+++ b/media/libaudioclient/tests/audiorecord_tests.cpp
@@ -81,8 +81,8 @@
TEST_F(AudioRecordTest, TestAudioCbNotifier) {
EXPECT_EQ(BAD_VALUE, mAC->getAudioRecordHandle()->addAudioDeviceCallback(nullptr));
- sp<OnAudioDeviceUpdateNotifier> cb = new OnAudioDeviceUpdateNotifier();
- sp<OnAudioDeviceUpdateNotifier> cbOld = new OnAudioDeviceUpdateNotifier();
+ sp<OnAudioDeviceUpdateNotifier> cb = sp<OnAudioDeviceUpdateNotifier>::make();
+ sp<OnAudioDeviceUpdateNotifier> cbOld = sp<OnAudioDeviceUpdateNotifier>::make();
EXPECT_EQ(OK, mAC->getAudioRecordHandle()->addAudioDeviceCallback(cbOld));
EXPECT_EQ(INVALID_OPERATION, mAC->getAudioRecordHandle()->addAudioDeviceCallback(cbOld));
EXPECT_EQ(OK, mAC->getAudioRecordHandle()->addAudioDeviceCallback(cb));
diff --git a/media/libaudioclient/tests/audiorouting_tests.cpp b/media/libaudioclient/tests/audiorouting_tests.cpp
index 32ba597..445633b 100644
--- a/media/libaudioclient/tests/audiorouting_tests.cpp
+++ b/media/libaudioclient/tests/audiorouting_tests.cpp
@@ -18,130 +18,12 @@
#include <cutils/properties.h>
#include <gtest/gtest.h>
-#include <libxml/parser.h>
-#include <libxml/xinclude.h>
#include <string.h>
-#include <system/audio_config.h>
#include "audio_test_utils.h"
using namespace android;
-template <class T>
-constexpr void (*xmlDeleter)(T* t);
-template <>
-constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
-template <>
-constexpr auto xmlDeleter<xmlChar> = [](xmlChar* s) { xmlFree(s); };
-
-/** @return a unique_ptr with the correct deleter for the libxml2 object. */
-template <class T>
-constexpr auto make_xmlUnique(T* t) {
- // Wrap deleter in lambda to enable empty base optimization
- auto deleter = [](T* t) { xmlDeleter<T>(t); };
- return std::unique_ptr<T, decltype(deleter)>{t, deleter};
-}
-
-std::string getXmlAttribute(const xmlNode* cur, const char* attribute) {
- auto charPtr = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
- if (charPtr == NULL) {
- return "";
- }
- std::string value(reinterpret_cast<const char*>(charPtr.get()));
- return value;
-}
-
-struct MixPort {
- std::string name;
- std::string role;
- std::string flags;
-};
-
-struct Route {
- std::string name;
- std::string sources;
- std::string sink;
-};
-
-status_t parse_audio_policy_configuration_xml(std::vector<std::string>& attachedDevices,
- std::vector<MixPort>& mixPorts,
- std::vector<Route>& routes) {
- std::string path = audio_find_readable_configuration_file("audio_policy_configuration.xml");
- if (path.length() == 0) return UNKNOWN_ERROR;
- auto doc = make_xmlUnique(xmlParseFile(path.c_str()));
- if (doc == nullptr) return UNKNOWN_ERROR;
- xmlNode* root = xmlDocGetRootElement(doc.get());
- if (root == nullptr) return UNKNOWN_ERROR;
- if (xmlXIncludeProcess(doc.get()) < 0) return UNKNOWN_ERROR;
- mixPorts.clear();
- if (!xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>("audioPolicyConfiguration"))) {
- std::string raw{getXmlAttribute(root, "version")};
- for (auto* child = root->xmlChildrenNode; child != nullptr; child = child->next) {
- if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>("modules"))) {
- xmlNode* root = child;
- for (auto* child = root->xmlChildrenNode; child != nullptr; child = child->next) {
- if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>("module"))) {
- xmlNode* root = child;
- for (auto* child = root->xmlChildrenNode; child != nullptr;
- child = child->next) {
- if (!xmlStrcmp(child->name,
- reinterpret_cast<const xmlChar*>("mixPorts"))) {
- xmlNode* root = child;
- for (auto* child = root->xmlChildrenNode; child != nullptr;
- child = child->next) {
- if (!xmlStrcmp(child->name,
- reinterpret_cast<const xmlChar*>("mixPort"))) {
- MixPort mixPort;
- xmlNode* root = child;
- mixPort.name = getXmlAttribute(root, "name");
- mixPort.role = getXmlAttribute(root, "role");
- mixPort.flags = getXmlAttribute(root, "flags");
- if (mixPort.role == "source") mixPorts.push_back(mixPort);
- }
- }
- } else if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(
- "attachedDevices"))) {
- xmlNode* root = child;
- for (auto* child = root->xmlChildrenNode; child != nullptr;
- child = child->next) {
- if (!xmlStrcmp(child->name,
- reinterpret_cast<const xmlChar*>("item"))) {
- auto xmlValue = make_xmlUnique(xmlNodeListGetString(
- child->doc, child->xmlChildrenNode, 1));
- if (xmlValue == nullptr) {
- raw = "";
- } else {
- raw = reinterpret_cast<const char*>(xmlValue.get());
- }
- std::string& value = raw;
- attachedDevices.push_back(std::move(value));
- }
- }
- } else if (!xmlStrcmp(child->name,
- reinterpret_cast<const xmlChar*>("routes"))) {
- xmlNode* root = child;
- for (auto* child = root->xmlChildrenNode; child != nullptr;
- child = child->next) {
- if (!xmlStrcmp(child->name,
- reinterpret_cast<const xmlChar*>("route"))) {
- Route route;
- xmlNode* root = child;
- route.name = getXmlAttribute(root, "name");
- route.sources = getXmlAttribute(root, "sources");
- route.sink = getXmlAttribute(root, "sink");
- routes.push_back(route);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- return OK;
-}
-
// UNIT TEST
TEST(AudioTrackTest, TestPerformanceMode) {
std::vector<std::string> attachedDevices;
@@ -185,7 +67,7 @@
ASSERT_EQ(OK, ap->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
<< "Unable to open Resource";
EXPECT_EQ(OK, ap->create()) << "track creation failed";
- sp<OnAudioDeviceUpdateNotifier> cb = new OnAudioDeviceUpdateNotifier();
+ sp<OnAudioDeviceUpdateNotifier> cb = sp<OnAudioDeviceUpdateNotifier>::make();
EXPECT_EQ(OK, ap->getAudioTrackHandle()->addAudioDeviceCallback(cb));
EXPECT_EQ(OK, ap->start()) << "audio track start failed";
EXPECT_EQ(OK, ap->onProcess());
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
new file mode 100644
index 0000000..aed847c
--- /dev/null
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -0,0 +1,573 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#define LOG_TAG "AudioSystemTest"
+
+#include <string.h>
+
+#include <gtest/gtest.h>
+#include <media/IAudioFlinger.h>
+#include <utils/Log.h>
+
+#include "audio_test_utils.h"
+
+using namespace android;
+
+void anyPatchContainsInputDevice(audio_port_handle_t deviceId, bool& res) {
+ std::vector<struct audio_patch> patches;
+ status_t status = listAudioPatches(patches);
+ ASSERT_EQ(OK, status);
+ res = false;
+ for (const auto& patch : patches) {
+ if (patchContainsInputDevice(deviceId, patch)) {
+ res = true;
+ return;
+ }
+ }
+}
+
+class AudioSystemTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ mAF = AudioSystem::get_audio_flinger();
+ ASSERT_NE(mAF, nullptr) << "Permission denied";
+ }
+
+ void TearDown() override {
+ if (mPlayback) {
+ mPlayback->stop();
+ mPlayback->getAudioTrackHandle()->removeAudioDeviceCallback(mCbPlayback);
+ mPlayback.clear();
+ }
+ if (mCapture) {
+ mCapture->stop();
+ mCapture->getAudioRecordHandle()->removeAudioDeviceCallback(mCbRecord);
+ mCapture.clear();
+ }
+ }
+
+ void createPlaybackSession(void);
+ void createRecordSession(void);
+
+ sp<IAudioFlinger> mAF;
+ sp<AudioPlayback> mPlayback;
+ sp<OnAudioDeviceUpdateNotifier> mCbPlayback;
+ sp<AudioCapture> mCapture;
+ sp<OnAudioDeviceUpdateNotifier> mCbRecord;
+};
+
+void AudioSystemTest::createPlaybackSession(void) {
+ audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
+ attributes.usage = AUDIO_USAGE_MEDIA;
+ attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
+ mPlayback = sp<AudioPlayback>::make(48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ AUDIO_OUTPUT_FLAG_FAST, AUDIO_SESSION_NONE,
+ AudioTrack::TRANSFER_SHARED, &attributes);
+ ASSERT_NE(nullptr, mPlayback);
+ ASSERT_EQ(NO_ERROR, mPlayback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"));
+ EXPECT_EQ(NO_ERROR, mPlayback->create());
+ mCbPlayback = sp<OnAudioDeviceUpdateNotifier>::make();
+ EXPECT_EQ(OK, mPlayback->getAudioTrackHandle()->addAudioDeviceCallback(mCbPlayback));
+ EXPECT_EQ(NO_ERROR, mPlayback->start());
+ EXPECT_EQ(OK, mPlayback->onProcess());
+ EXPECT_EQ(OK, mCbPlayback->waitForAudioDeviceCb());
+}
+
+void AudioSystemTest::createRecordSession(void) {
+ mCapture = new AudioCapture(AUDIO_SOURCE_DEFAULT, 44100, AUDIO_FORMAT_PCM_8_24_BIT,
+ AUDIO_CHANNEL_IN_MONO, AUDIO_INPUT_FLAG_FAST);
+ ASSERT_NE(nullptr, mCapture);
+ ASSERT_EQ(OK, mCapture->create()) << "record creation failed";
+ mCbRecord = sp<OnAudioDeviceUpdateNotifier>::make();
+ EXPECT_EQ(OK, mCapture->getAudioRecordHandle()->addAudioDeviceCallback(mCbRecord));
+ EXPECT_EQ(OK, mCapture->start()) << "record creation failed";
+ EXPECT_EQ(OK, mCbRecord->waitForAudioDeviceCb());
+}
+
+// UNIT TESTS
+TEST_F(AudioSystemTest, CheckServerSideValues) {
+ ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
+ EXPECT_GT(mAF->sampleRate(mCbPlayback->mAudioIo), 0);
+ EXPECT_NE(mAF->format(mCbPlayback->mAudioIo), AUDIO_FORMAT_INVALID);
+ EXPECT_GT(mAF->frameCount(mCbPlayback->mAudioIo), 0);
+ size_t frameCountHal, frameCountHalCache;
+ frameCountHal = mAF->frameCountHAL(mCbPlayback->mAudioIo);
+ EXPECT_GT(frameCountHal, 0);
+ EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(mCbPlayback->mAudioIo, &frameCountHalCache));
+ EXPECT_EQ(frameCountHal, frameCountHalCache);
+ EXPECT_GT(mAF->latency(mCbPlayback->mAudioIo), 0);
+ // client side latency is at least server side latency
+ EXPECT_LE(mAF->latency(mCbPlayback->mAudioIo), mPlayback->getAudioTrackHandle()->latency());
+
+ ASSERT_NO_FATAL_FAILURE(createRecordSession());
+ EXPECT_GT(mAF->sampleRate(mCbRecord->mAudioIo), 0);
+ // EXPECT_NE(mAF->format(mCbRecord->mAudioIo), AUDIO_FORMAT_INVALID);
+ EXPECT_GT(mAF->frameCount(mCbRecord->mAudioIo), 0);
+ EXPECT_GT(mAF->frameCountHAL(mCbRecord->mAudioIo), 0);
+ frameCountHal = mAF->frameCountHAL(mCbRecord->mAudioIo);
+ EXPECT_GT(frameCountHal, 0);
+ EXPECT_EQ(OK, AudioSystem::getFrameCountHAL(mCbRecord->mAudioIo, &frameCountHalCache));
+ EXPECT_EQ(frameCountHal, frameCountHalCache);
+ // EXPECT_GT(mAF->latency(mCbRecord->mAudioIo), 0);
+ // client side latency is at least server side latency
+ // EXPECT_LE(mAF->latency(mCbRecord->mAudioIo), mCapture->getAudioRecordHandle()->latency());
+
+ EXPECT_GT(AudioSystem::getPrimaryOutputSamplingRate(), 0); // first fast mixer sample rate
+ EXPECT_GT(AudioSystem::getPrimaryOutputFrameCount(), 0); // fast mixer frame count
+}
+
+TEST_F(AudioSystemTest, GetSetMasterVolume) {
+ ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
+ float origVol, tstVol;
+ EXPECT_EQ(NO_ERROR, AudioSystem::getMasterVolume(&origVol));
+ float newVol;
+ if (origVol + 0.2f > 1.0f) {
+ newVol = origVol - 0.2f;
+ } else {
+ newVol = origVol + 0.2f;
+ }
+ EXPECT_EQ(NO_ERROR, AudioSystem::setMasterVolume(newVol));
+ EXPECT_EQ(NO_ERROR, AudioSystem::getMasterVolume(&tstVol));
+ EXPECT_EQ(newVol, tstVol);
+ EXPECT_EQ(NO_ERROR, AudioSystem::setMasterVolume(origVol));
+ EXPECT_EQ(NO_ERROR, AudioSystem::getMasterVolume(&tstVol));
+ EXPECT_EQ(origVol, tstVol);
+}
+
+TEST_F(AudioSystemTest, GetSetMasterMute) {
+ ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
+ bool origMuteState, tstMuteState;
+ EXPECT_EQ(NO_ERROR, AudioSystem::getMasterMute(&origMuteState));
+ EXPECT_EQ(NO_ERROR, AudioSystem::setMasterMute(!origMuteState));
+ EXPECT_EQ(NO_ERROR, AudioSystem::getMasterMute(&tstMuteState));
+ EXPECT_EQ(!origMuteState, tstMuteState);
+ EXPECT_EQ(NO_ERROR, AudioSystem::setMasterMute(origMuteState));
+ EXPECT_EQ(NO_ERROR, AudioSystem::getMasterMute(&tstMuteState));
+ EXPECT_EQ(origMuteState, tstMuteState);
+}
+
+TEST_F(AudioSystemTest, GetSetMicMute) {
+ ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
+ bool origMuteState, tstMuteState;
+ EXPECT_EQ(NO_ERROR, AudioSystem::isMicrophoneMuted(&origMuteState));
+ EXPECT_EQ(NO_ERROR, AudioSystem::muteMicrophone(!origMuteState));
+ EXPECT_EQ(NO_ERROR, AudioSystem::isMicrophoneMuted(&tstMuteState));
+ EXPECT_EQ(!origMuteState, tstMuteState);
+ EXPECT_EQ(NO_ERROR, AudioSystem::muteMicrophone(origMuteState));
+ EXPECT_EQ(NO_ERROR, AudioSystem::isMicrophoneMuted(&tstMuteState));
+ EXPECT_EQ(origMuteState, tstMuteState);
+}
+
+TEST_F(AudioSystemTest, GetSetMasterBalance) {
+ ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
+ float origBalance, tstBalance;
+ EXPECT_EQ(OK, AudioSystem::getMasterBalance(&origBalance));
+ float newBalance;
+ if (origBalance + 0.2f > 1.0f) {
+ newBalance = origBalance - 0.2f;
+ } else {
+ newBalance = origBalance + 0.2f;
+ }
+ EXPECT_EQ(OK, AudioSystem::setMasterBalance(newBalance));
+ EXPECT_EQ(OK, AudioSystem::getMasterBalance(&tstBalance));
+ EXPECT_EQ(newBalance, tstBalance);
+ EXPECT_EQ(OK, AudioSystem::setMasterBalance(origBalance));
+ EXPECT_EQ(OK, AudioSystem::getMasterBalance(&tstBalance));
+ EXPECT_EQ(origBalance, tstBalance);
+}
+
+TEST_F(AudioSystemTest, GetStreamVolume) {
+ ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
+ float origStreamVol;
+ EXPECT_EQ(NO_ERROR, AudioSystem::getStreamVolume(AUDIO_STREAM_MUSIC, &origStreamVol,
+ mCbPlayback->mAudioIo));
+}
+
+TEST_F(AudioSystemTest, GetStreamMute) {
+ ASSERT_NO_FATAL_FAILURE(createPlaybackSession());
+ bool origMuteState;
+ EXPECT_EQ(NO_ERROR, AudioSystem::getStreamMute(AUDIO_STREAM_MUSIC, &origMuteState));
+}
+
+TEST_F(AudioSystemTest, StartAndStopAudioSource) {
+ std::vector<struct audio_port_v7> ports;
+ audio_port_config sourcePortConfig;
+ audio_attributes_t attributes = AudioSystem::streamTypeToAttributes(AUDIO_STREAM_MUSIC);
+ audio_port_handle_t sourcePortHandle = AUDIO_PORT_HANDLE_NONE;
+
+ status_t status = listAudioPorts(ports);
+ ASSERT_EQ(OK, status);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No ports returned by the audio system";
+ }
+
+ for (const auto& port : ports) {
+ if (port.role != AUDIO_PORT_ROLE_SOURCE || port.type != AUDIO_PORT_TYPE_DEVICE) continue;
+ sourcePortConfig = port.active_config;
+
+ bool patchFound;
+
+ // start audio source.
+ status_t ret =
+ AudioSystem::startAudioSource(&sourcePortConfig, &attributes, &sourcePortHandle);
+ EXPECT_EQ(OK, ret) << "AudioSystem::startAudioSource for source " << port.ext.device.address
+ << " failed";
+
+ // verify that patch is established by the source port.
+ ASSERT_NO_FATAL_FAILURE(anyPatchContainsInputDevice(port.id, patchFound));
+ EXPECT_EQ(true, patchFound);
+ EXPECT_NE(sourcePortHandle, AUDIO_PORT_HANDLE_NONE);
+
+ if (sourcePortHandle != AUDIO_PORT_HANDLE_NONE) {
+ ret = AudioSystem::stopAudioSource(sourcePortHandle);
+ EXPECT_EQ(OK, ret) << "AudioSystem::stopAudioSource for handle failed";
+ }
+
+ // verify that no source port patch exists.
+ ASSERT_NO_FATAL_FAILURE(anyPatchContainsInputDevice(port.id, patchFound));
+ EXPECT_EQ(false, patchFound);
+ }
+}
+
+TEST_F(AudioSystemTest, CreateAndReleaseAudioPatch) {
+ status_t status;
+ struct audio_patch audioPatch;
+ std::vector<struct audio_port_v7> ports;
+ audio_patch_handle_t audioPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+
+ bool patchFound = false;
+ audio_port_v7 sourcePort{};
+ audio_port_v7 sinkPort{};
+
+ audioPatch.id = 0;
+ audioPatch.num_sources = 1;
+ audioPatch.num_sinks = 1;
+
+ status = listAudioPorts(ports);
+ ASSERT_EQ(OK, status);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No output devices returned by the audio system";
+ }
+
+ for (const auto& port : ports) {
+ if (port.role == AUDIO_PORT_ROLE_SOURCE && port.type == AUDIO_PORT_TYPE_DEVICE) {
+ sourcePort = port;
+ }
+ if (port.role == AUDIO_PORT_ROLE_SINK && port.type == AUDIO_PORT_TYPE_DEVICE &&
+ port.ext.device.type == AUDIO_DEVICE_OUT_SPEAKER) {
+ sinkPort = port;
+ }
+ }
+
+ audioPatch.sources[0] = sourcePort.active_config;
+ audioPatch.sinks[0] = sinkPort.active_config;
+
+ status = AudioSystem::createAudioPatch(&audioPatch, &audioPatchHandle);
+ EXPECT_EQ(OK, status) << "AudioSystem::createAudiopatch failed between source "
+ << sourcePort.ext.device.address << " and sink "
+ << sinkPort.ext.device.address;
+
+ // verify that patch is established between source and the sink.
+ ASSERT_NO_FATAL_FAILURE(anyPatchContainsInputDevice(sourcePort.id, patchFound));
+ EXPECT_EQ(true, patchFound);
+
+ EXPECT_NE(AUDIO_PORT_HANDLE_NONE, audioPatchHandle);
+ status = AudioSystem::releaseAudioPatch(audioPatchHandle);
+ EXPECT_EQ(OK, status) << "AudioSystem::releaseAudioPatch failed between source "
+ << sourcePort.ext.device.address << " and sink "
+ << sinkPort.ext.device.address;
+
+ // verify that no patch is established between source and the sink after releaseAudioPatch.
+ ASSERT_NO_FATAL_FAILURE(anyPatchContainsInputDevice(sourcePort.id, patchFound));
+ EXPECT_EQ(false, patchFound);
+}
+
+TEST_F(AudioSystemTest, GetAudioPort) {
+ std::vector<struct audio_port_v7> ports;
+ status_t status = listAudioPorts(ports);
+ ASSERT_EQ(OK, status);
+ for (const auto& port : ports) {
+ audio_port_v7 portTest{.id = port.id};
+ EXPECT_EQ(OK, AudioSystem::getAudioPort(&portTest));
+ EXPECT_TRUE(audio_ports_v7_are_equal(&portTest, &port));
+ }
+}
+
+TEST_F(AudioSystemTest, TestPhoneState) {
+ uid_t uid = getuid();
+ EXPECT_EQ(OK, AudioSystem::setPhoneState(AUDIO_MODE_RINGTONE, uid));
+ audio_mode_t state = AudioSystem::getPhoneState();
+ EXPECT_EQ(AUDIO_MODE_RINGTONE, state);
+ EXPECT_EQ(OK, AudioSystem::setPhoneState(AUDIO_MODE_IN_COMMUNICATION, uid));
+ state = AudioSystem::getPhoneState();
+ EXPECT_EQ(AUDIO_MODE_IN_COMMUNICATION, state);
+ EXPECT_EQ(OK, AudioSystem::setPhoneState(AUDIO_MODE_NORMAL, uid));
+ state = AudioSystem::getPhoneState();
+ EXPECT_EQ(AUDIO_MODE_NORMAL, state);
+}
+
+TEST_F(AudioSystemTest, GetDirectProfilesForAttributes) {
+ std::vector<audio_profile> audioProfiles;
+ audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
+ attributes.usage = AUDIO_USAGE_MEDIA;
+ attributes.content_type = AUDIO_CONTENT_TYPE_MUSIC;
+ EXPECT_EQ(BAD_VALUE, AudioSystem::getDirectProfilesForAttributes(nullptr, nullptr));
+ EXPECT_EQ(BAD_VALUE, AudioSystem::getDirectProfilesForAttributes(nullptr, &audioProfiles));
+ EXPECT_EQ(BAD_VALUE, AudioSystem::getDirectProfilesForAttributes(&attributes, nullptr));
+ EXPECT_EQ(NO_ERROR, AudioSystem::getDirectProfilesForAttributes(&attributes, &audioProfiles));
+}
+
+bool isPublicStrategy(const AudioProductStrategy& strategy) {
+ bool result = true;
+ for (auto& attribute : strategy.getAudioAttributes()) {
+ if (attribute.getAttributes() == AUDIO_ATTRIBUTES_INITIALIZER &&
+ (uint32_t(attribute.getStreamType()) >= AUDIO_STREAM_PUBLIC_CNT)) {
+ result = false;
+ break;
+ }
+ }
+ return result;
+}
+
+TEST_F(AudioSystemTest, DevicesForRoleAndStrategy) {
+ std::vector<struct audio_port_v7> ports;
+ status_t status = listAudioPorts(ports);
+ ASSERT_EQ(OK, status);
+
+ std::vector<struct audio_port_v7> devicePorts;
+ for (const auto& port : ports) {
+ if (port.type == AUDIO_PORT_TYPE_DEVICE && audio_is_output_device(port.ext.device.type)) {
+ devicePorts.push_back(port);
+ }
+ }
+ if (devicePorts.empty()) {
+ GTEST_SKIP() << "No output devices returned by the audio system";
+ }
+
+ AudioProductStrategyVector strategies;
+ EXPECT_EQ(OK, AudioSystem::listAudioProductStrategies(strategies));
+ if (strategies.empty()) {
+ GTEST_SKIP() << "No strategies returned by the audio system";
+ }
+
+ audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
+ attributes.usage = AUDIO_USAGE_MEDIA;
+
+ bool hasStrategyForMedia = false;
+ AudioProductStrategy mediaStrategy;
+ for (const auto& strategy : strategies) {
+ if (!isPublicStrategy(strategy)) continue;
+
+ for (const auto& att : strategy.getAudioAttributes()) {
+ if (strategy.attributesMatches(att.getAttributes(), attributes)) {
+ hasStrategyForMedia = true;
+ mediaStrategy = strategy;
+ break;
+ }
+ }
+ }
+
+ if (!hasStrategyForMedia) {
+ GTEST_SKIP() << "No strategies returned for music media";
+ }
+
+ AudioDeviceTypeAddrVector devices;
+ EXPECT_EQ(BAD_VALUE, AudioSystem::getDevicesForRoleAndStrategy(PRODUCT_STRATEGY_NONE,
+ DEVICE_ROLE_PREFERRED, devices));
+ EXPECT_EQ(BAD_VALUE, AudioSystem::getDevicesForRoleAndStrategy(mediaStrategy.getId(),
+ DEVICE_ROLE_NONE, devices));
+ status = AudioSystem::getDevicesForRoleAndStrategy(mediaStrategy.getId(), DEVICE_ROLE_PREFERRED,
+ devices);
+ if (status == NAME_NOT_FOUND) {
+ AudioDeviceTypeAddrVector outputDevices;
+ for (const auto& port : devicePorts) {
+ if (port.ext.device.type == AUDIO_DEVICE_OUT_SPEAKER) {
+ const AudioDeviceTypeAddr outputDevice(port.ext.device.type,
+ port.ext.device.address);
+ outputDevices.push_back(outputDevice);
+ }
+ }
+ EXPECT_EQ(OK, AudioSystem::setDevicesRoleForStrategy(mediaStrategy.getId(),
+ DEVICE_ROLE_PREFERRED, outputDevices));
+ EXPECT_EQ(OK, AudioSystem::getDevicesForRoleAndStrategy(mediaStrategy.getId(),
+ DEVICE_ROLE_PREFERRED, devices));
+ EXPECT_EQ(devices, outputDevices);
+ EXPECT_EQ(OK, AudioSystem::removeDevicesRoleForStrategy(mediaStrategy.getId(),
+ DEVICE_ROLE_PREFERRED));
+ EXPECT_EQ(NAME_NOT_FOUND, AudioSystem::getDevicesForRoleAndStrategy(
+ mediaStrategy.getId(), DEVICE_ROLE_PREFERRED, devices));
+ }
+}
+
+TEST_F(AudioSystemTest, VolumeIndexForAttributes) {
+ AudioVolumeGroupVector groups;
+ EXPECT_EQ(OK, AudioSystem::listAudioVolumeGroups(groups));
+ for (const auto& group : groups) {
+ if (group.getAudioAttributes().empty()) continue;
+ const audio_attributes_t attr = group.getAudioAttributes()[0];
+ if (attr == AUDIO_ATTRIBUTES_INITIALIZER) continue;
+ audio_stream_type_t streamType = AudioSystem::attributesToStreamType(attr);
+ if (streamType >= AUDIO_STREAM_PUBLIC_CNT) continue;
+
+ volume_group_t vg;
+ EXPECT_EQ(OK, AudioSystem::getVolumeGroupFromAudioAttributes(attr, vg));
+ EXPECT_EQ(group.getId(), vg);
+
+ int index;
+ EXPECT_EQ(OK,
+ AudioSystem::getVolumeIndexForAttributes(attr, index, AUDIO_DEVICE_OUT_SPEAKER));
+
+ int indexTest;
+ EXPECT_EQ(OK, AudioSystem::getStreamVolumeIndex(streamType, &indexTest,
+ AUDIO_DEVICE_OUT_SPEAKER));
+ EXPECT_EQ(index, indexTest);
+ }
+}
+
+TEST_F(AudioSystemTest, DevicesRoleForCapturePreset) {
+ std::vector<struct audio_port_v7> ports;
+ status_t status = listAudioPorts(ports);
+ ASSERT_EQ(OK, status);
+
+ if (ports.empty()) {
+ GTEST_SKIP() << "No ports returned by the audio system";
+ }
+
+ audio_devices_t inDeviceA = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ audio_devices_t inDeviceB = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ for (const auto& port : ports) {
+ if (port.role != AUDIO_PORT_ROLE_SOURCE || port.type != AUDIO_PORT_TYPE_DEVICE) continue;
+ if (port.ext.device.type == inDeviceA) continue;
+ inDeviceB = port.ext.device.type;
+ break;
+ }
+ const audio_source_t audioSource = AUDIO_SOURCE_MIC;
+ const device_role_t role = DEVICE_ROLE_PREFERRED;
+ const AudioDeviceTypeAddr inputDevice(inDeviceA, "");
+ const AudioDeviceTypeAddrVector inputDevices = {inputDevice};
+ const AudioDeviceTypeAddr outputDevice(AUDIO_DEVICE_OUT_SPEAKER, "");
+ const AudioDeviceTypeAddrVector outputDevices = {outputDevice};
+
+ // Test invalid device when setting
+ EXPECT_EQ(BAD_VALUE,
+ AudioSystem::setDevicesRoleForCapturePreset(audioSource, role, outputDevices));
+ EXPECT_EQ(BAD_VALUE,
+ AudioSystem::addDevicesRoleForCapturePreset(audioSource, role, outputDevices));
+ EXPECT_EQ(BAD_VALUE,
+ AudioSystem::removeDevicesRoleForCapturePreset(audioSource, role, outputDevices));
+
+ // Test invalid role
+ AudioDeviceTypeAddrVector devices;
+ EXPECT_EQ(BAD_VALUE, AudioSystem::getDevicesForRoleAndCapturePreset(audioSource,
+ DEVICE_ROLE_NONE, devices));
+ EXPECT_EQ(BAD_VALUE, AudioSystem::setDevicesRoleForCapturePreset(audioSource, DEVICE_ROLE_NONE,
+ inputDevices));
+ EXPECT_EQ(BAD_VALUE, AudioSystem::addDevicesRoleForCapturePreset(audioSource, DEVICE_ROLE_NONE,
+ inputDevices));
+ EXPECT_EQ(BAD_VALUE, AudioSystem::removeDevicesRoleForCapturePreset(
+ audioSource, DEVICE_ROLE_NONE, inputDevices));
+ EXPECT_EQ(BAD_VALUE,
+ AudioSystem::clearDevicesRoleForCapturePreset(audioSource, DEVICE_ROLE_NONE));
+
+ // Without setting, call get/remove/clear must fail
+ EXPECT_EQ(NAME_NOT_FOUND,
+ AudioSystem::getDevicesForRoleAndCapturePreset(audioSource, role, devices));
+ EXPECT_TRUE(devices.empty());
+ EXPECT_EQ(NAME_NOT_FOUND,
+ AudioSystem::removeDevicesRoleForCapturePreset(audioSource, role, devices));
+ EXPECT_EQ(NAME_NOT_FOUND, AudioSystem::clearDevicesRoleForCapturePreset(audioSource, role));
+
+ // Test set/get devices role
+ EXPECT_EQ(NO_ERROR,
+ AudioSystem::setDevicesRoleForCapturePreset(audioSource, role, inputDevices));
+ ASSERT_EQ(NO_ERROR, AudioSystem::getDevicesForRoleAndCapturePreset(audioSource, role, devices));
+ EXPECT_EQ(devices, inputDevices);
+
+ // Test setting will change the previously set devices
+ const AudioDeviceTypeAddr inputDevice2 = AudioDeviceTypeAddr(inDeviceB, "");
+ AudioDeviceTypeAddrVector inputDevices2 = {inputDevice2};
+ EXPECT_EQ(NO_ERROR,
+ AudioSystem::setDevicesRoleForCapturePreset(audioSource, role, inputDevices2));
+ devices.clear();
+ EXPECT_EQ(NO_ERROR, AudioSystem::getDevicesForRoleAndCapturePreset(audioSource, role, devices));
+ EXPECT_EQ(devices, inputDevices2);
+
+ // Test add devices
+ EXPECT_EQ(NO_ERROR,
+ AudioSystem::addDevicesRoleForCapturePreset(audioSource, role, inputDevices));
+ devices.clear();
+ EXPECT_EQ(NO_ERROR, AudioSystem::getDevicesForRoleAndCapturePreset(audioSource, role, devices));
+ EXPECT_EQ(2, devices.size());
+ EXPECT_TRUE(std::find(devices.begin(), devices.end(), inputDevice) != devices.end());
+ EXPECT_TRUE(std::find(devices.begin(), devices.end(), inputDevice2) != devices.end());
+
+ // Test remove devices
+ EXPECT_EQ(NO_ERROR,
+ AudioSystem::removeDevicesRoleForCapturePreset(audioSource, role, inputDevices));
+ devices.clear();
+ EXPECT_EQ(NO_ERROR, AudioSystem::getDevicesForRoleAndCapturePreset(audioSource, role, devices));
+ EXPECT_EQ(devices, inputDevices2);
+
+ // Test remove devices that are not set as the device role
+ EXPECT_EQ(BAD_VALUE,
+ AudioSystem::removeDevicesRoleForCapturePreset(audioSource, role, inputDevices));
+
+ // Test clear devices
+ EXPECT_EQ(NO_ERROR, AudioSystem::clearDevicesRoleForCapturePreset(audioSource, role));
+ devices.clear();
+ EXPECT_EQ(NAME_NOT_FOUND,
+ AudioSystem::getDevicesForRoleAndCapturePreset(audioSource, role, devices));
+
+ AudioDeviceTypeAddrVector inputDevices3 = {inputDevice, inputDevice2};
+ EXPECT_EQ(NO_ERROR,
+ AudioSystem::setDevicesRoleForCapturePreset(audioSource, role, inputDevices3));
+ devices.clear();
+ EXPECT_EQ(NO_ERROR, AudioSystem::getDevicesForRoleAndCapturePreset(audioSource, role, devices));
+ EXPECT_EQ(2, devices.size());
+ EXPECT_TRUE(std::find(devices.begin(), devices.end(), inputDevice) != devices.end());
+ EXPECT_TRUE(std::find(devices.begin(), devices.end(), inputDevice2) != devices.end());
+ EXPECT_EQ(NO_ERROR, AudioSystem::clearDevicesRoleForCapturePreset(audioSource, role));
+}
+
+TEST_F(AudioSystemTest, UidDeviceAffinities) {
+ uid_t uid = getuid();
+
+ // Test invalid device for example audio_is_input_device
+ AudioDeviceTypeAddr inputDevice(AUDIO_DEVICE_IN_BUILTIN_MIC, "");
+ AudioDeviceTypeAddrVector inputDevices = {inputDevice};
+ EXPECT_EQ(BAD_VALUE, AudioSystem::setUidDeviceAffinities(uid, inputDevices));
+
+ // Test valid device for example audio_is_output_device
+ AudioDeviceTypeAddr outputDevice(AUDIO_DEVICE_OUT_SPEAKER, "");
+ AudioDeviceTypeAddrVector outputDevices = {outputDevice};
+ EXPECT_EQ(NO_ERROR, AudioSystem::setUidDeviceAffinities(uid, outputDevices));
+ EXPECT_EQ(NO_ERROR, AudioSystem::removeUidDeviceAffinities(uid));
+}
+
+TEST_F(AudioSystemTest, UserIdDeviceAffinities) {
+ int userId = 200;
+
+ // Test invalid device for example audio_is_input_device
+ AudioDeviceTypeAddr inputDevice(AUDIO_DEVICE_IN_BUILTIN_MIC, "");
+ AudioDeviceTypeAddrVector inputDevices = {inputDevice};
+ EXPECT_EQ(BAD_VALUE, AudioSystem::setUserIdDeviceAffinities(userId, inputDevices));
+
+ // Test valid device for ezample audio_is_output_device
+ AudioDeviceTypeAddr outputDevice(AUDIO_DEVICE_OUT_SPEAKER, "");
+ AudioDeviceTypeAddrVector outputDevices = {outputDevice};
+ EXPECT_EQ(NO_ERROR, AudioSystem::setUserIdDeviceAffinities(userId, outputDevices));
+ EXPECT_EQ(NO_ERROR, AudioSystem::removeUserIdDeviceAffinities(userId));
+}
diff --git a/media/libaudioclient/tests/audiotrack_tests.cpp b/media/libaudioclient/tests/audiotrack_tests.cpp
index 1b42a49..8daba0a 100644
--- a/media/libaudioclient/tests/audiotrack_tests.cpp
+++ b/media/libaudioclient/tests/audiotrack_tests.cpp
@@ -128,8 +128,8 @@
<< "Unable to open Resource";
EXPECT_EQ(OK, ap->create()) << "track creation failed";
EXPECT_EQ(BAD_VALUE, ap->getAudioTrackHandle()->addAudioDeviceCallback(nullptr));
- sp<OnAudioDeviceUpdateNotifier> cb = new OnAudioDeviceUpdateNotifier();
- sp<OnAudioDeviceUpdateNotifier> cbOld = new OnAudioDeviceUpdateNotifier();
+ sp<OnAudioDeviceUpdateNotifier> cb = sp<OnAudioDeviceUpdateNotifier>::make();
+ sp<OnAudioDeviceUpdateNotifier> cbOld = sp<OnAudioDeviceUpdateNotifier>::make();
EXPECT_EQ(OK, ap->getAudioTrackHandle()->addAudioDeviceCallback(cbOld));
EXPECT_EQ(INVALID_OPERATION, ap->getAudioTrackHandle()->addAudioDeviceCallback(cbOld));
EXPECT_EQ(OK, ap->getAudioTrackHandle()->addAudioDeviceCallback(cb));