Add libaudiousecasevalidation library
This library will verify the audio attributes usage for a track
that is connected to the specified stream.
It will only update the audio attributes usage for AUDIO_USAGE_MEDIA or
AUDIO_USAGE_UNKNOWN, to AUDIO_USAGE_GAME if output flags AUDIO_OUTPUT_FLAG_FAST
or AUDIO_OUTPUT_FLAG_MMAP_NOIRQ have been set for specified stream.
Bug: 257922898
Test: atest libaudiousecasevalidation-test
Change-Id: Ic2d89fa05467538abbc97d707478df1d70901fdb
diff --git a/media/libaudiousecasevalidation/Android.bp b/media/libaudiousecasevalidation/Android.bp
new file mode 100644
index 0000000..3ee7e32
--- /dev/null
+++ b/media/libaudiousecasevalidation/Android.bp
@@ -0,0 +1,49 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_library {
+ name: "libaudiousecasevalidation",
+ host_supported: true,
+ srcs: [
+ "UsecaseLookup.cpp",
+ "UsecaseValidator.cpp",
+ ],
+ header_libs: [
+ "liberror_headers",
+ ],
+ shared_libs: [
+ "framework-permission-aidl-cpp",
+ "libaudioutils",
+ "libbase",
+ "liblog",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_test_host {
+ name: "libaudiousecasevalidation-test",
+ srcs: [
+ "tests/UsecaseValidator-test.cpp",
+ ],
+ header_libs: [
+ "liberror_headers",
+ ],
+ shared_libs: [
+ "framework-permission-aidl-cpp",
+ "libaudiousecasevalidation",
+ "libutils",
+ ],
+}
diff --git a/media/libaudiousecasevalidation/UsecaseLookup.cpp b/media/libaudiousecasevalidation/UsecaseLookup.cpp
new file mode 100644
index 0000000..9def180
--- /dev/null
+++ b/media/libaudiousecasevalidation/UsecaseLookup.cpp
@@ -0,0 +1,79 @@
+#define LOG_TAG "UsecaseLookup"
+// #define LOG_NDEBUG 0
+
+#include "media/UsecaseLookup.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace media {
+
+/**
+ * Add streamId and outputFlags to stream list.
+ */
+void UsecaseLookup::addStream(STREAMID streamId, bool outputFlagGame) {
+ ALOGV("%s streamId: %d outputFlagGame: %d", __func__, streamId, outputFlagGame);
+
+ mutex_lock lock(m_mutex);
+ m_streams[streamId] = outputFlagGame;
+}
+
+/**
+ * Remove streamId from stream list.
+ */
+void UsecaseLookup::removeStream(STREAMID streamId) {
+ ALOGV("%s streamId: %d ", __func__, streamId);
+
+ mutex_lock lock(m_mutex);
+ m_streams.erase(streamId);
+
+ // Shouldn't happen but it might.
+ for (auto it = m_tracks.begin(); it != m_tracks.end();) {
+ if (it->second == streamId) {
+ it = m_tracks.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
+/**
+ * Add streamId and portId to track list.
+ */
+void UsecaseLookup::addTrack(STREAMID streamId, PORTID portId) {
+ ALOGV("%s streamId: %d portId: %d", __func__, streamId, portId);
+
+ mutex_lock lock(m_mutex);
+
+ if (m_tracks.find(portId) == m_tracks.end()) {
+ m_tracks[portId] = streamId;
+ }
+}
+
+/**
+ * Remove streamId and portId from track list.
+ */
+void UsecaseLookup::removeTrack(STREAMID streamId, PORTID portId) {
+ ALOGV("%s streamId: %d portId: %d", __func__, streamId, portId);
+
+ mutex_lock lock(m_mutex);
+ auto it = m_tracks.find(portId);
+
+ if (it != m_tracks.end() && it->second == streamId) {
+ m_tracks.erase(portId);
+ }
+}
+
+/**
+ * Check if stream list contains streamId with Game outputFlag.
+ */
+bool UsecaseLookup::isGameStream(STREAMID streamId) {
+ ALOGV("%s streamId: %d ", __func__, streamId);
+ mutex_lock lock(m_mutex);
+ auto it = m_streams.find(streamId);
+
+ return (it != m_streams.end()) ? it->second : false;
+}
+
+} // namespace media
+} // namespace android
diff --git a/media/libaudiousecasevalidation/UsecaseValidator.cpp b/media/libaudiousecasevalidation/UsecaseValidator.cpp
new file mode 100644
index 0000000..3a8a9c1
--- /dev/null
+++ b/media/libaudiousecasevalidation/UsecaseValidator.cpp
@@ -0,0 +1,128 @@
+#define LOG_TAG "UsecaseValidator"
+// #define LOG_NDEBUG 0
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+
+#include "media/UsecaseValidator.h"
+#include "media/UsecaseLookup.h"
+
+namespace android {
+namespace media {
+namespace {
+
+class UsecaseValidatorImpl : public UsecaseValidator {
+ public:
+ UsecaseValidatorImpl() {}
+
+ /**
+ * Register a new mixer/stream.
+ * Called when the stream is opened at the HAL and communicates
+ * immutable stream attributes like flags, sampling rate, format.
+ */
+ status_t registerStream(audio_io_handle_t streamId,
+ const audio_config_base_t& audioConfig __attribute__((unused)),
+ const audio_output_flags_t outputFlags) override {
+ ALOGV("%s output: %d flags: %#x", __func__, streamId, outputFlags);
+
+ // Check if FAST or MMAP output flag has been set.
+ bool outputFlagGame = outputFlags & (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);
+ m_lookup.addStream(streamId, outputFlagGame);
+ return OK;
+ };
+
+ /**
+ * Unregister a stream/mixer.
+ * Called when the stream is closed.
+ */
+ status_t unregisterStream(audio_io_handle_t streamId) override {
+ ALOGV("%s output: %d", __func__, streamId);
+
+ m_lookup.removeStream(streamId);
+ return OK;
+ };
+
+ /**
+ * Indicates that some playback activity started on the stream.
+ * Called each time an audio track starts or resumes.
+ */
+ error::Result<audio_attributes_t> startClient(audio_io_handle_t streamId,
+ audio_port_handle_t portId, const content::AttributionSourceState& attributionSource,
+ const audio_attributes_t& attributes,
+ const AttributesChangedCallback *callback __attribute__((unused))) override {
+ ALOGV("%s output: %d portId: %d usage: %d pid: %d package: %s",
+ __func__, streamId, portId, attributes.usage, attributionSource.pid,
+ attributionSource.packageName.value_or("").c_str());
+
+ m_lookup.addTrack(streamId, portId);
+
+ return verifyAudioAttributes(streamId, attributionSource, attributes);
+ };
+
+ /**
+ * Indicates that some playback activity stopped on the stream.
+ * Called each time an audio track stops or pauses.
+ */
+ status_t stopClient(audio_io_handle_t streamId, audio_port_handle_t portId) override {
+ ALOGV("%s output: %d portId: %d", __func__, streamId, portId);
+
+ m_lookup.removeTrack(streamId, portId);
+ return OK;
+ };
+
+ /**
+ * Called to verify and update audio attributes for a track that is connected
+ * to the specified stream.
+ */
+ error::Result<audio_attributes_t> verifyAudioAttributes(audio_io_handle_t streamId,
+ const content::AttributionSourceState& attributionSource,
+ const audio_attributes_t& attributes) override {
+ ALOGV("%s output: %d usage: %d pid: %d package: %s",
+ __func__, streamId, attributes.usage, attributionSource.pid,
+ attributionSource.packageName.value_or("").c_str());
+
+ audio_attributes_t attrRet = attributes;
+
+ // Check if attribute usage media or unknown has been set.
+ bool isUsageValid = this->isUsageValid(attributes);
+
+ if (isUsageValid && m_lookup.isGameStream(streamId)) {
+ ALOGI("%s update usage: %d to AUDIO_USAGE_GAME for output: %d pid: %d package: %s",
+ __func__, attributes.usage, streamId, attributionSource.pid,
+ attributionSource.packageName.value_or("").c_str());
+ // Set attribute usage Game.
+ attrRet.usage = AUDIO_USAGE_GAME;
+ }
+
+ return {attrRet};
+ };
+
+ protected:
+ /**
+ * Check if attribute usage valid.
+ */
+ bool isUsageValid(const audio_attributes_t& attr) {
+ ALOGV("isUsageValid attr.usage: %d", attr.usage);
+ switch (attr.usage) {
+ case AUDIO_USAGE_MEDIA:
+ case AUDIO_USAGE_UNKNOWN:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ protected:
+ UsecaseLookup m_lookup;
+};
+
+} // namespace
+
+std::unique_ptr<UsecaseValidator> createUsecaseValidator() {
+ return std::make_unique<UsecaseValidatorImpl>();
+}
+
+} // namespace media
+} // namespace android
diff --git a/media/libaudiousecasevalidation/include/media/UsecaseLookup.h b/media/libaudiousecasevalidation/include/media/UsecaseLookup.h
new file mode 100644
index 0000000..9d1c987
--- /dev/null
+++ b/media/libaudiousecasevalidation/include/media/UsecaseLookup.h
@@ -0,0 +1,68 @@
+#ifndef MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASELOOKUP_H_
+#define MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASELOOKUP_H_
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+
+namespace android {
+namespace media {
+
+typedef int STREAMID;
+typedef int PORTID;
+
+// List of streamId and outputFlag state.
+typedef std::map<STREAMID, bool> STREAMLIST;
+// List of portId and streamId.
+typedef std::map<PORTID, STREAMID> TRACKLIST;
+typedef std::lock_guard<std::mutex> mutex_lock;
+
+class UsecaseLookup {
+ public:
+ UsecaseLookup() { }
+ virtual ~UsecaseLookup() { }
+
+ // Required for testing.
+ void clear() {
+ m_streams.clear();
+ m_tracks.clear();
+ }
+
+ /**
+ * Add streamId and outputFlag to stream list.
+ */
+ void addStream(STREAMID streamId, bool outputFlagGame = false);
+
+ /**
+ * Remove streamId from stream list.
+ */
+ void removeStream(STREAMID streamId);
+
+ /**
+ * Add streamId and portId to track list.
+ */
+ void addTrack(STREAMID streamId, PORTID portId);
+
+ /**
+ * Remove streamId and portId from track list.
+ */
+ void removeTrack(STREAMID streamId, PORTID portId);
+
+ /**
+ * Check if stream list contains streamId with Game output flag.
+ */
+ bool isGameStream(STREAMID streamId);
+
+ protected:
+ STREAMLIST m_streams;
+ TRACKLIST m_tracks;
+ std::mutex m_mutex;
+};
+
+} // namespace media
+} // namespace android
+
+#endif // MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASELOOKUP_H_
diff --git a/media/libaudiousecasevalidation/include/media/UsecaseValidator.h b/media/libaudiousecasevalidation/include/media/UsecaseValidator.h
new file mode 100644
index 0000000..3f98423
--- /dev/null
+++ b/media/libaudiousecasevalidation/include/media/UsecaseValidator.h
@@ -0,0 +1,82 @@
+#ifndef MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASEVALIDATOR_H_
+#define MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASEVALIDATOR_H_
+
+#pragma once
+
+#include <error/Result.h>
+#include <system/audio.h>
+#include <android/content/AttributionSourceState.h>
+
+#include <limits>
+#include <memory>
+
+namespace android {
+namespace media {
+
+/**
+ * Main entry-point for this library.
+ */
+class UsecaseValidator {
+ public:
+ virtual ~UsecaseValidator() = default;
+
+ /**
+ * A callback called by the module when the audio attributes for
+ * an active portId changes.
+ */
+ class AttributesChangedCallback {
+ public:
+ virtual ~AttributesChangedCallback() = default;
+ virtual void onAttributesChanged(audio_port_handle_t portId,
+ const audio_attributes_t& attributes) = 0;
+ };
+
+ /**
+ * Register a new mixer/stream.
+ * Called when the stream is opened at the HAL and communicates
+ * immutable stream attributes like flags, sampling rate, format.
+ */
+ virtual status_t registerStream(audio_io_handle_t streamId,
+ const audio_config_base_t& audioConfig,
+ const audio_output_flags_t outputFlags) = 0;
+
+ /**
+ * Unregister a stream/mixer.
+ * Called when the stream is closed.
+ */
+ virtual status_t unregisterStream(audio_io_handle_t streamId) = 0;
+
+ /**
+ * Indicates that some playback activity started on the stream.
+ * Called each time an audio track starts or resumes.
+ */
+ virtual error::Result<audio_attributes_t> startClient(audio_io_handle_t streamId,
+ audio_port_handle_t portId,
+ const content::AttributionSourceState& attributionSource,
+ const audio_attributes_t& attributes,
+ const AttributesChangedCallback *callback) = 0;
+
+ /**
+ * Indicates that some playback activity stopped on the stream.
+ * Called each time an audio track stops or pauses.
+ */
+ virtual status_t stopClient(audio_io_handle_t streamId, audio_port_handle_t portId) = 0;
+
+ /**
+ * Called to verify and update audio attributes for a track that is connected
+ * to the specified stream.
+ */
+ virtual error::Result<audio_attributes_t> verifyAudioAttributes(audio_io_handle_t streamId,
+ const content::AttributionSourceState& attributionSource,
+ const audio_attributes_t& attributes) = 0;
+};
+
+/**
+ * Creates an instance featuring a default implementation of the UsecaseValidator interface.
+ */
+std::unique_ptr<UsecaseValidator> createUsecaseValidator();
+
+} // namespace media
+} // namespace android
+
+#endif // MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASEVALIDATOR_H_
diff --git a/media/libaudiousecasevalidation/tests/UsecaseValidator-test.cpp b/media/libaudiousecasevalidation/tests/UsecaseValidator-test.cpp
new file mode 100644
index 0000000..f014068
--- /dev/null
+++ b/media/libaudiousecasevalidation/tests/UsecaseValidator-test.cpp
@@ -0,0 +1,215 @@
+#include "tests/UsecaseValidator-test.h"
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace media {
+
+/**
+ * Helper test functions.
+ */
+
+/**
+ * Register a mock stream.
+ */
+audio_io_handle_t UsecaseValidatorTest::testRegisterStream(bool outputFlagGame) {
+ static int streamId = 0;
+ status_t result;
+ static audio_config_base_t audioConfig = AUDIO_CONFIG_BASE_INITIALIZER;
+ audio_output_flags_t outputFlags = outputFlagGame ? GAME_OUTPUT_FLAGS : MEDIA_OUTPUT_FLAGS;
+
+ result = m_validator->registerStream(++streamId, audioConfig, outputFlags);
+
+ return result == OK ? streamId : 0;
+}
+
+/**
+ * Create a mock portId.
+ */
+audio_port_handle_t UsecaseValidatorTest::testCreatePortId(audio_io_handle_t streamId) {
+ static int portId = 0;
+
+ return (streamId << 8) | (++portId);
+}
+
+/**
+ * Add a mock portId to a stream and verify.
+ */
+error::Result<audio_attributes_t> UsecaseValidatorTest::testStartClient(audio_io_handle_t streamId,
+ audio_port_handle_t portId,
+ audio_usage_t usage) {
+ content::AttributionSourceState attributionSource;
+ audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
+ attributes.usage = usage;
+
+ return m_validator->startClient(streamId, portId, attributionSource, attributes, NULL);
+}
+
+/**
+ * Verify a mock stream.
+ */
+error::Result<audio_attributes_t> UsecaseValidatorTest::testVerifyAudioAttributes(
+ audio_io_handle_t streamId,
+ audio_usage_t usage) {
+ content::AttributionSourceState attributionSource;
+ audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
+ attributes.usage = usage;
+
+ return m_validator->verifyAudioAttributes(streamId, attributionSource, attributes);
+}
+
+/**
+ * Test functions.
+ */
+
+/**
+ * Test adding and removing streams.
+ */
+TEST_F(UsecaseLookupTest, testAddAndRemoveStream) {
+ addStream(1, false);
+ addStream(2, true);
+
+ EXPECT_NE(m_streams.find(1), m_streams.end());
+ EXPECT_NE(m_streams.find(2), m_streams.end());
+ EXPECT_EQ(m_streams.find(3), m_streams.end());
+
+ EXPECT_FALSE(isGameStream(1));
+ EXPECT_TRUE(isGameStream(2));
+ EXPECT_FALSE(isGameStream(3));
+
+ removeStream(2);
+
+ EXPECT_FALSE(isGameStream(2));
+}
+
+/**
+ * Verify attributes usage for stream.
+ */
+TEST_F(UsecaseValidatorTest, testAttributesUsage) {
+ audio_io_handle_t gameStreamId, mediaStreamId;
+
+ // Register game and media stream.
+ gameStreamId = testRegisterStream(true);
+ mediaStreamId = testRegisterStream(false);
+ EXPECT_NE(gameStreamId, 0);
+ EXPECT_NE(mediaStreamId, 0);
+ EXPECT_NE(gameStreamId, mediaStreamId);
+
+ // Verify attributes on game stream.
+ auto attr = testVerifyAudioAttributes(gameStreamId, AUDIO_USAGE_GAME);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_GAME);
+
+ // Verify attributes on media stream.
+ attr = testVerifyAudioAttributes(mediaStreamId, AUDIO_USAGE_MEDIA);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_MEDIA);
+
+ EXPECT_EQ(m_validator->unregisterStream(gameStreamId), 0);
+ EXPECT_EQ(m_validator->unregisterStream(mediaStreamId), 0);
+}
+
+/**
+ * Test hanging client.
+ */
+TEST_F(UsecaseValidatorTest, testHangingClient) {
+ audio_io_handle_t gameStreamId, mediaStreamId;
+ audio_port_handle_t gamePortId, mediaPortId;
+
+ // Register game and media stream.
+ gameStreamId = testRegisterStream(true);
+ EXPECT_NE(gameStreamId, 0);
+ mediaStreamId = testRegisterStream(false);
+ EXPECT_NE(mediaStreamId, 0);
+
+ // Assign portId.
+ gamePortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(gamePortId, 0);
+ mediaPortId = testCreatePortId(mediaStreamId);
+ EXPECT_NE(mediaPortId, 0);
+
+ // Start client on game stream.
+ testStartClient(gameStreamId, gamePortId, AUDIO_USAGE_GAME);
+
+ // Start client on media stream.
+ testStartClient(mediaStreamId, mediaPortId, AUDIO_USAGE_MEDIA);
+
+ // Unregister media stream before stopClient.
+ EXPECT_EQ(m_validator->unregisterStream(gameStreamId), 0);
+ EXPECT_EQ(m_validator->unregisterStream(mediaStreamId), 0);
+}
+
+/**
+ * Verify attributes usage does not change.
+ */
+TEST_F(UsecaseValidatorTest, testAttributesUsageUnchanged) {
+ audio_io_handle_t gameStreamId, mediaStreamId;
+ audio_port_handle_t gamePortId, mediaPortId, unknownPortId, voiceCommPortId;
+
+ // Register game and media stream.
+ gameStreamId = testRegisterStream(true);
+ EXPECT_NE(gameStreamId, 0);
+ mediaStreamId = testRegisterStream(false);
+ EXPECT_NE(mediaStreamId, 0);
+
+ // Assign portId.
+ gamePortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(gamePortId, 0);
+ mediaPortId = testCreatePortId(mediaStreamId);
+ EXPECT_NE(mediaPortId, 0);
+ unknownPortId = testCreatePortId(mediaStreamId);
+ EXPECT_NE(unknownPortId, 0);
+ voiceCommPortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(voiceCommPortId, 0);
+
+ // Verify attributes on game stream.
+ auto attr = testStartClient(gameStreamId, gamePortId, AUDIO_USAGE_GAME);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_GAME);
+
+ attr = testStartClient(gameStreamId, voiceCommPortId, AUDIO_USAGE_VOICE_COMMUNICATION);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_VOICE_COMMUNICATION);
+
+ // Verify attributes on media stream.
+ attr = testStartClient(mediaStreamId, mediaPortId, AUDIO_USAGE_MEDIA);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_MEDIA);
+
+ attr = testStartClient(mediaStreamId, unknownPortId, AUDIO_USAGE_UNKNOWN);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_UNKNOWN);
+
+ // Stop client on game and media stream.
+ EXPECT_EQ(m_validator->stopClient(gameStreamId, gamePortId), 0);
+ EXPECT_EQ(m_validator->stopClient(mediaStreamId, mediaPortId), 0);
+
+ // Unregister game and media stream.
+ EXPECT_EQ(m_validator->unregisterStream(gameStreamId), 0);
+ EXPECT_EQ(m_validator->unregisterStream(mediaStreamId), 0);
+}
+
+/**
+ * Verify attributes usage changes.
+ */
+TEST_F(UsecaseValidatorTest, testAttributesUsageChanged) {
+ audio_io_handle_t gameStreamId;
+ audio_port_handle_t mediaPortId, unknownPortId;
+
+ // Register game and media stream.
+ gameStreamId = testRegisterStream(true);
+ EXPECT_NE(gameStreamId, 0);
+
+ // Assign portId.
+ mediaPortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(mediaPortId, 0);
+ unknownPortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(unknownPortId, 0);
+
+ // Verify attributes on game stream.
+ auto attr = testStartClient(gameStreamId, mediaPortId, AUDIO_USAGE_MEDIA);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_GAME);
+
+ attr = testStartClient(gameStreamId, unknownPortId, AUDIO_USAGE_UNKNOWN);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_GAME);
+
+ // Unregister game stream.
+ EXPECT_EQ(m_validator->unregisterStream(gameStreamId), 0);
+}
+
+} // namespace media
+} // namespace android
diff --git a/media/libaudiousecasevalidation/tests/UsecaseValidator-test.h b/media/libaudiousecasevalidation/tests/UsecaseValidator-test.h
new file mode 100644
index 0000000..89296ac
--- /dev/null
+++ b/media/libaudiousecasevalidation/tests/UsecaseValidator-test.h
@@ -0,0 +1,67 @@
+#ifndef MEDIA_LIBAUDIOUSECASEVALIDATION_TESTS_USECASEVALIDATOR_TEST_H_
+#define MEDIA_LIBAUDIOUSECASEVALIDATION_TESTS_USECASEVALIDATOR_TEST_H_
+
+#include <gtest/gtest.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+
+#include "media/UsecaseLookup.h"
+#include "media/UsecaseValidator.h"
+
+namespace android {
+namespace media {
+
+#define MEDIA_OUTPUT_FLAGS (audio_output_flags_t)(0xFFFFF &\
+ ~(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ))
+
+#define GAME_OUTPUT_FLAGS (audio_output_flags_t)\
+ (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)
+
+class TestCallback : public UsecaseValidator::AttributesChangedCallback {
+ public:
+ TestCallback() {
+ m_iCallCnt = 0;
+ }
+ virtual ~TestCallback() { }
+ virtual void onAttributesChanged(audio_port_handle_t /*portId*/,
+ const audio_attributes_t& /*attributes*/) {
+ ++m_iCallCnt;
+ }
+
+ public:
+ int m_iCallCnt;
+};
+
+class UsecaseLookupTest : public UsecaseLookup, public ::testing::Test {
+ public:
+ UsecaseLookupTest() { }
+ virtual ~UsecaseLookupTest() = default;
+};
+
+class UsecaseValidatorTest : public ::testing::Test {
+ public:
+ UsecaseValidatorTest() {
+ m_validator = createUsecaseValidator();
+ }
+
+ virtual ~UsecaseValidatorTest() = default;
+
+ protected:
+ audio_io_handle_t testRegisterStream(bool outputFlagGame);
+ audio_port_handle_t testCreatePortId(audio_io_handle_t streamId);
+ error::Result<audio_attributes_t> testStartClient(audio_io_handle_t streamId,
+ audio_port_handle_t portId,
+ audio_usage_t usage);
+ error::Result<audio_attributes_t> testVerifyAudioAttributes(audio_io_handle_t streamId,
+ audio_usage_t usage);
+
+ std::unique_ptr<UsecaseValidator> m_validator;
+};
+
+} // namespace media
+} // namespace android
+
+#endif // MEDIA_LIBAUDIOUSECASEVALIDATION_TESTS_USECASEVALIDATOR_TEST_H_