Add audiotrack unit tests

Bug: 215781479
Test: atest audiotrack_tests

Merged-In: I63511129d5716b4fff18161692f195442b4ed16c
Change-Id: I63511129d5716b4fff18161692f195442b4ed16c
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 48a5078..b44c3c9 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -151,3 +151,12 @@
         "audio_test_utils.cpp",
     ],
 }
+
+cc_test {
+    name: "audiotrack_tests",
+    defaults: ["libaudioclient_gtests_defaults"],
+    srcs: [
+        "audiotrack_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 df36b62..45b76d5 100644
--- a/media/libaudioclient/tests/audio_test_utils.cpp
+++ b/media/libaudioclient/tests/audio_test_utils.cpp
@@ -188,11 +188,36 @@
     return OK;
 }
 
-status_t AudioPlayback::waitForConsumption() {
+status_t AudioPlayback::waitForConsumption(bool testSeek) {
     if (PLAY_STARTED != mState) return INVALID_OPERATION;
     // in static buffer mode, lets not play clips with duration > 30 sec
     int retry = 30;
+    // Total number of frames in the input file.
+    size_t totalFrameCount = mMemCapacity / mTrack->frameSize();
     while (!mStopPlaying && retry > 0) {
+        // Get the total numbers of frames played.
+        uint32_t currPosition;
+        mTrack->getPosition(&currPosition);
+        if (testSeek && (currPosition > totalFrameCount * 0.6)) {
+            testSeek = false;
+            if (!mTrack->hasStarted()) return BAD_VALUE;
+            mTrack->pauseAndWait(std::chrono::seconds(2));
+            if (mTrack->hasStarted()) return BAD_VALUE;
+            mTrack->reload();
+            mTrack->getPosition(&currPosition);
+            if (currPosition != 0) return BAD_VALUE;
+            mTrack->start();
+            while (currPosition < totalFrameCount * 0.3) {
+                mTrack->getPosition(&currPosition);
+            }
+            mTrack->pauseAndWait(std::chrono::seconds(2));
+            uint32_t setPosition = totalFrameCount * 0.9;
+            mTrack->setPosition(setPosition);
+            uint32_t bufferPosition;
+            mTrack->getBufferPosition(&bufferPosition);
+            if (bufferPosition != setPosition) return BAD_VALUE;
+            mTrack->start();
+        }
         std::this_thread::sleep_for(std::chrono::milliseconds(300));
         retry--;
     }
@@ -200,9 +225,9 @@
     return OK;
 }
 
-status_t AudioPlayback::onProcess() {
+status_t AudioPlayback::onProcess(bool testSeek) {
     if (mTransferType == AudioTrack::TRANSFER_SHARED)
-        return waitForConsumption();
+        return waitForConsumption(testSeek);
     else if (mTransferType == AudioTrack::TRANSFER_OBTAIN)
         return fillBuffer();
     else
diff --git a/media/libaudioclient/tests/audio_test_utils.h b/media/libaudioclient/tests/audio_test_utils.h
index 2e0d14d..8885059 100644
--- a/media/libaudioclient/tests/audio_test_utils.h
+++ b/media/libaudioclient/tests/audio_test_utils.h
@@ -62,9 +62,9 @@
     status_t create();
     sp<AudioTrack> getAudioTrackHandle();
     status_t start();
-    status_t waitForConsumption();
+    status_t waitForConsumption(bool testSeek = false);
     status_t fillBuffer();
-    status_t onProcess();
+    status_t onProcess(bool testSeek = false);
     void stop();
 
     bool mStopPlaying;
diff --git a/media/libaudioclient/tests/audiotrack_tests.cpp b/media/libaudioclient/tests/audiotrack_tests.cpp
new file mode 100644
index 0000000..d08e150
--- /dev/null
+++ b/media/libaudioclient/tests/audiotrack_tests.cpp
@@ -0,0 +1,131 @@
+/*
+ * 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_NDEBUG 0
+
+#include <gtest/gtest.h>
+
+#include "audio_test_utils.h"
+
+using namespace android;
+
+TEST(AudioTrackTest, TestPlayTrack) {
+    std::unique_ptr<AudioPlayback> ap(new AudioPlayback(
+            44100, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, AUDIO_OUTPUT_FLAG_NONE,
+            AUDIO_SESSION_NONE, AudioTrack::TRANSFER_OBTAIN));
+    ASSERT_NE(nullptr, ap);
+    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";
+    EXPECT_EQ(OK, ap->start()) << "audio track start failed";
+    EXPECT_EQ(OK, ap->onProcess());
+    ap->stop();
+}
+
+TEST(AudioTrackTest, TestSeek) {
+    std::unique_ptr<AudioPlayback> ap(
+            new AudioPlayback(44100, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO));
+    ASSERT_NE(nullptr, ap);
+    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";
+    EXPECT_EQ(OK, ap->start()) << "audio track start failed";
+    EXPECT_EQ(OK, ap->onProcess(true));
+    ap->stop();
+}
+
+TEST(AudioTrackTest, TestAudioCbNotifier) {
+    std::unique_ptr<AudioPlayback> ap(new AudioPlayback(
+            0, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, AUDIO_OUTPUT_FLAG_FAST,
+            AUDIO_SESSION_NONE, AudioTrack::TRANSFER_SHARED));
+    ASSERT_NE(nullptr, ap);
+    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";
+    EXPECT_EQ(BAD_VALUE, ap->getAudioTrackHandle()->addAudioDeviceCallback(nullptr));
+    sp<OnAudioDeviceUpdateNotifier> cb = new OnAudioDeviceUpdateNotifier();
+    sp<OnAudioDeviceUpdateNotifier> cbOld = new OnAudioDeviceUpdateNotifier();
+    EXPECT_EQ(OK, ap->getAudioTrackHandle()->addAudioDeviceCallback(cbOld));
+    EXPECT_EQ(INVALID_OPERATION, ap->getAudioTrackHandle()->addAudioDeviceCallback(cbOld));
+    EXPECT_EQ(OK, ap->getAudioTrackHandle()->addAudioDeviceCallback(cb));
+    EXPECT_EQ(OK, ap->start()) << "audio track start failed";
+    EXPECT_EQ(OK, ap->onProcess());
+    EXPECT_EQ(OK, cb->waitForAudioDeviceCb());
+    EXPECT_EQ(AUDIO_IO_HANDLE_NONE, cbOld->mAudioIo);
+    EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, cbOld->mDeviceId);
+    EXPECT_NE(AUDIO_IO_HANDLE_NONE, cb->mAudioIo);
+    EXPECT_NE(AUDIO_PORT_HANDLE_NONE, cb->mDeviceId);
+    EXPECT_EQ(BAD_VALUE, ap->getAudioTrackHandle()->removeAudioDeviceCallback(nullptr));
+    EXPECT_EQ(INVALID_OPERATION, ap->getAudioTrackHandle()->removeAudioDeviceCallback(cbOld));
+    EXPECT_EQ(OK, ap->getAudioTrackHandle()->removeAudioDeviceCallback(cb));
+    ap->stop();
+}
+
+class AudioTrackCreateTest
+    : public ::testing::TestWithParam<std::tuple<uint32_t, audio_format_t, audio_channel_mask_t,
+                                                 audio_output_flags_t, audio_session_t>> {
+  public:
+    AudioTrackCreateTest()
+        : mSampleRate(std::get<0>(GetParam())),
+          mFormat(std::get<1>(GetParam())),
+          mChannelMask(std::get<2>(GetParam())),
+          mFlags(std::get<3>(GetParam())),
+          mSessionId(std::get<4>(GetParam())){};
+
+    const uint32_t mSampleRate;
+    const audio_format_t mFormat;
+    const audio_channel_mask_t mChannelMask;
+    const audio_output_flags_t mFlags;
+    const audio_session_t mSessionId;
+
+    std::unique_ptr<AudioPlayback> mAP;
+
+    virtual void SetUp() override {
+        mAP = std::make_unique<AudioPlayback>(mSampleRate, mFormat, mChannelMask, mFlags,
+                                              mSessionId);
+        ASSERT_NE(nullptr, mAP);
+        ASSERT_EQ(OK, mAP->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
+                << "Unable to open Resource";
+        ASSERT_EQ(OK, mAP->create()) << "track creation failed";
+    }
+
+    virtual void TearDown() override {
+        if (mAP) mAP->stop();
+    }
+};
+
+TEST_P(AudioTrackCreateTest, TestCreateTrack) {
+    EXPECT_EQ(mFormat, mAP->getAudioTrackHandle()->format());
+    EXPECT_EQ(audio_channel_count_from_out_mask(mChannelMask),
+              mAP->getAudioTrackHandle()->channelCount());
+    if (mSampleRate != 0) EXPECT_EQ(mSampleRate, mAP->getAudioTrackHandle()->getSampleRate());
+    if (mSessionId != AUDIO_SESSION_NONE)
+        EXPECT_EQ(mSessionId, mAP->getAudioTrackHandle()->getSessionId());
+    EXPECT_EQ(mSampleRate, mAP->getAudioTrackHandle()->getOriginalSampleRate());
+    EXPECT_EQ(OK, mAP->start()) << "audio track start failed";
+    EXPECT_EQ(OK, mAP->onProcess());
+}
+
+// sampleRate, format, channelMask, flags, sessionId
+INSTANTIATE_TEST_SUITE_P(
+        AudioTrackParameterizedTest, AudioTrackCreateTest,
+        ::testing::Combine(::testing::Values(48000), ::testing::Values(AUDIO_FORMAT_PCM_16_BIT),
+                           ::testing::Values(AUDIO_CHANNEL_OUT_STEREO),
+                           ::testing::Values(AUDIO_OUTPUT_FLAG_NONE,
+                                             AUDIO_OUTPUT_FLAG_PRIMARY | AUDIO_OUTPUT_FLAG_FAST,
+                                             AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_FAST,
+                                             AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+                           ::testing::Values(AUDIO_SESSION_NONE)));