audiopolicy: Add patch creation tests

Add a test that verifies rejection of bad parameters for
'createAudioPatch'.

Add a test that creates a patch between mixPort and devicePort.

No bugs have been found this time.

Test: audiopolicy_tests
Change-Id: I431e225d9dba0097e3d73796585dbe7f404d1cec
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index de26ab0..a9593b8 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#include <memory>
+#include <set>
+
 #include <gtest/gtest.h>
 
 #include "AudioPolicyTestClient.h"
@@ -21,7 +24,7 @@
 
 using namespace android;
 
-TEST(AudioPolicyManager, InitFailure) {
+TEST(AudioPolicyManagerTestInit, Failure) {
     AudioPolicyTestClient client;
     AudioPolicyTestManager manager(&client);
     manager.getConfig().setDefault();
@@ -32,12 +35,13 @@
 }
 
 
-// A client that provides correct module and IO handles for inputs and outputs.
-class AudioPolicyTestClientWithModulesIoHandles : public AudioPolicyTestClient {
+class AudioPolicyManagerTestClient : public AudioPolicyTestClient {
   public:
+    // AudioPolicyClientInterface implementation
     audio_module_handle_t loadHwModule(const char* /*name*/) override {
-        return mNextModule++;
+        return mNextModuleHandle++;
     }
+
     status_t openOutput(audio_module_handle_t module,
                         audio_io_handle_t* output,
                         audio_config_t* /*config*/,
@@ -45,14 +49,15 @@
                         const String8& /*address*/,
                         uint32_t* /*latencyMs*/,
                         audio_output_flags_t /*flags*/) override {
-        if (module >= mNextModule) {
+        if (module >= mNextModuleHandle) {
             ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
-                    __func__, module, mNextModule);
+                    __func__, module, mNextModuleHandle);
             return BAD_VALUE;
         }
         *output = mNextIoHandle++;
         return NO_ERROR;
     }
+
     status_t openInput(audio_module_handle_t module,
                        audio_io_handle_t* input,
                        audio_config_t* /*config*/,
@@ -60,23 +65,132 @@
                        const String8& /*address*/,
                        audio_source_t /*source*/,
                        audio_input_flags_t /*flags*/) override {
-        if (module >= mNextModule) {
+        if (module >= mNextModuleHandle) {
             ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
-                    __func__, module, mNextModule);
+                    __func__, module, mNextModuleHandle);
             return BAD_VALUE;
         }
         *input = mNextIoHandle++;
         return NO_ERROR;
     }
+
+    status_t createAudioPatch(const struct audio_patch* /*patch*/,
+                              audio_patch_handle_t* handle,
+                              int /*delayMs*/) override {
+        *handle = mNextPatchHandle++;
+        mActivePatches.insert(*handle);
+        return NO_ERROR;
+    }
+
+    status_t releaseAudioPatch(audio_patch_handle_t handle,
+                               int /*delayMs*/) override {
+        if (mActivePatches.erase(handle) != 1) {
+            if (handle >= mNextPatchHandle) {
+                ALOGE("%s: Patch handle %d has not been allocated yet (next is %d)",
+                        __func__, handle, mNextPatchHandle);
+            } else {
+                ALOGE("%s: Attempt to release patch %d twice", __func__, handle);
+            }
+            return BAD_VALUE;
+        }
+        return NO_ERROR;
+    }
+
+    // Helper methods for tests
+    size_t getActivePatchesCount() const { return mActivePatches.size(); }
+
   private:
-    audio_module_handle_t mNextModule = AUDIO_MODULE_HANDLE_NONE + 1;
+    audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
     audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
+    audio_patch_handle_t mNextPatchHandle = AUDIO_PATCH_HANDLE_NONE + 1;
+    std::set<audio_patch_handle_t> mActivePatches;
 };
 
-TEST(AudioPolicyManager, InitSuccess) {
-    AudioPolicyTestClientWithModulesIoHandles client;
-    AudioPolicyTestManager manager(&client);
-    manager.getConfig().setDefault();
-    ASSERT_EQ(NO_ERROR, manager.initialize());
-    ASSERT_EQ(NO_ERROR, manager.initCheck());
+class AudioPolicyManagerTest : public testing::Test {
+  protected:
+    virtual void SetUp();
+    virtual void TearDown();
+
+    std::unique_ptr<AudioPolicyManagerTestClient> mClient;
+    std::unique_ptr<AudioPolicyTestManager> mManager;
+};
+
+void AudioPolicyManagerTest::SetUp() {
+    mClient.reset(new AudioPolicyManagerTestClient);
+    mManager.reset(new AudioPolicyTestManager(mClient.get()));
+    mManager->getConfig().setDefault();
+    ASSERT_EQ(NO_ERROR, mManager->initialize());
+    ASSERT_EQ(NO_ERROR, mManager->initCheck());
 }
+
+void AudioPolicyManagerTest::TearDown() {
+    mManager.reset();
+    mClient.reset();
+}
+
+TEST_F(AudioPolicyManagerTest, InitSuccess) {
+    // SetUp must finish with no assertions.
+}
+
+TEST_F(AudioPolicyManagerTest, CreateAudioPatchFailure) {
+    audio_patch patch{};
+    audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
+    const size_t patchCountBefore = mClient->getActivePatchesCount();
+    ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(nullptr, &handle, 0));
+    ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, nullptr, 0));
+    ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, &handle, 0));
+    patch.num_sources = AUDIO_PATCH_PORTS_MAX + 1;
+    patch.num_sinks = 1;
+    ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, &handle, 0));
+    patch.num_sources = 1;
+    patch.num_sinks = AUDIO_PATCH_PORTS_MAX + 1;
+    ASSERT_EQ(BAD_VALUE, mManager->createAudioPatch(&patch, &handle, 0));
+    patch.num_sources = 2;
+    patch.num_sinks = 1;
+    ASSERT_EQ(INVALID_OPERATION, mManager->createAudioPatch(&patch, &handle, 0));
+    patch = {};
+    patch.num_sources = 1;
+    patch.sources[0].role = AUDIO_PORT_ROLE_SINK;
+    patch.num_sinks = 1;
+    patch.sinks[0].role = AUDIO_PORT_ROLE_SINK;
+    ASSERT_EQ(INVALID_OPERATION, mManager->createAudioPatch(&patch, &handle, 0));
+    patch = {};
+    patch.num_sources = 1;
+    patch.sources[0].role = AUDIO_PORT_ROLE_SOURCE;
+    patch.num_sinks = 1;
+    patch.sinks[0].role = AUDIO_PORT_ROLE_SOURCE;
+    ASSERT_EQ(INVALID_OPERATION, mManager->createAudioPatch(&patch, &handle, 0));
+    // Verify that the handle is left unchanged.
+    ASSERT_EQ(AUDIO_PATCH_HANDLE_NONE, handle);
+    ASSERT_EQ(patchCountBefore, mClient->getActivePatchesCount());
+}
+
+TEST_F(AudioPolicyManagerTest, CreateAudioPatchFromMix) {
+    audio_patch patch{};
+    audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
+    uid_t uid = 42;
+    const size_t patchCountBefore = mClient->getActivePatchesCount();
+    patch.num_sources = 1;
+    {
+        auto& src = patch.sources[0];
+        src.role = AUDIO_PORT_ROLE_SOURCE;
+        src.type = AUDIO_PORT_TYPE_MIX;
+        src.id = mManager->getConfig().getAvailableInputDevices()[0]->getId();
+        // Note: these are the parameters of the output device.
+        src.sample_rate = 44100;
+        src.format = AUDIO_FORMAT_PCM_16_BIT;
+        src.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+    }
+    patch.num_sinks = 1;
+    {
+        auto& sink = patch.sinks[0];
+        sink.role = AUDIO_PORT_ROLE_SINK;
+        sink.type = AUDIO_PORT_TYPE_DEVICE;
+        sink.id = mManager->getConfig().getDefaultOutputDevice()->getId();
+    }
+    ASSERT_EQ(NO_ERROR, mManager->createAudioPatch(&patch, &handle, uid));
+    ASSERT_NE(AUDIO_PATCH_HANDLE_NONE, handle);
+    ASSERT_EQ(patchCountBefore + 1, mClient->getActivePatchesCount());
+}
+
+// TODO: Add patch creation tests that involve already existing patch