Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d20bfb5f authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

Add AudioTrackTest#OffloadCompletion to audiotrack_tests

This test executes scenario of the offloaded playback
and verifies that the client receives "on stream end"
callback after drain completes.

Currently only APE compressed format is used, so the
test is ignored on most devices except CVD. Will add
other formats later.

Fixed up StreamHalAidl::drain to avoid returning error
when called multiple times by the client.

Bug: 373872271
Bug: 384431822
Test: atest audiotrack_tests
Change-Id: Idfbdf02bbda0e8823eaa76348767d7c99e2322bd
parent 05b848a2
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -136,7 +136,10 @@ cc_defaults {
    cflags: [
        "-Wthread-safety",
    ],
    data: ["bbb*.raw"],
    data: [
        "bbb*.raw",
        "sine960hz_48000_3s.ape",
    ],
    srcs: [
        "audio_test_utils.cpp",
        "test_execution_tracer.cpp",
+1 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
        <!-- Files used for audio testing -->
        <option name="push-file" key="bbb_1ch_8kHz_s16le.raw" value="/data/local/tmp/bbb_1ch_8kHz_s16le.raw" />
        <option name="push-file" key="bbb_2ch_24kHz_s16le.raw" value="/data/local/tmp/bbb_2ch_24kHz_s16le.raw" />
        <option name="push-file" key="sine960hz_48000_3s.ape" value="/data/local/tmp/sine960hz_48000_3s.ape" />
    </target_preparer>

    <test class="com.android.tradefed.testtype.GTest" >
+51 −22
Original line number Diff line number Diff line
@@ -14,6 +14,8 @@
 * limitations under the License.
 */

#include <thread>

//#define LOG_NDEBUG 0
#define LOG_TAG "AudioTestUtils"

@@ -22,12 +24,16 @@
#include <binder/IServiceManager.h>
#include <system/audio_config.h>
#include <utils/Log.h>
#include <utils/SystemClock.h>

#include "audio_test_utils.h"

#define WAIT_PERIOD_MS 10  // from AudioTrack.cpp
#define MAX_WAIT_TIME_MS 5000

static constexpr auto kShortCallbackTimeout = std::chrono::milliseconds(500);
static constexpr auto kLongCallbackTimeout = std::chrono::seconds(10);

void OnAudioDeviceUpdateNotifier::onAudioDeviceUpdate(audio_io_handle_t audioIo,
                                                      audio_port_handle_t deviceId) {
    ALOGI("%s: audioIo=%d deviceId=%d", __func__, audioIo, deviceId);
@@ -41,7 +47,7 @@ void OnAudioDeviceUpdateNotifier::onAudioDeviceUpdate(audio_io_handle_t audioIo,

status_t OnAudioDeviceUpdateNotifier::waitForAudioDeviceCb(audio_port_handle_t expDeviceId) {
    std::unique_lock lock(mMutex);
    android::base::ScopedLockAssertion lock_assertion(mMutex);
    base::ScopedLockAssertion lock_assertion(mMutex);
    if (mAudioIo == AUDIO_IO_HANDLE_NONE ||
        (expDeviceId != AUDIO_PORT_HANDLE_NONE && expDeviceId != mDeviceId)) {
        mCondition.wait_for(lock, std::chrono::milliseconds(500));
@@ -70,14 +76,7 @@ AudioPlayback::AudioPlayback(uint32_t sampleRate, audio_format_t format,
      mSessionId(sessionId),
      mTransferType(transferType),
      mAttributes(attributes),
      mOffloadInfo(info) {
    mStopPlaying = false;
    mBytesUsedSoFar = 0;
    mState = PLAY_NO_INIT;
    mMemCapacity = 0;
    mMemoryDealer = nullptr;
    mMemory = nullptr;
}
      mOffloadInfo(info) {}

AudioPlayback::~AudioPlayback() {
    stop();
@@ -92,15 +91,16 @@ status_t AudioPlayback::create() {
    attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(getpid()));
    attributionSource.token = sp<BBinder>::make();
    if (mTransferType == AudioTrack::TRANSFER_OBTAIN) {
        mTrack = new AudioTrack(attributionSource);
        mTrack = sp<TestAudioTrack>::make(attributionSource);
        mTrack->set(AUDIO_STREAM_MUSIC, mSampleRate, mFormat, mChannelMask, 0 /* frameCount */,
                    mFlags, nullptr /* callback */, 0 /* notificationFrames */,
                    nullptr /* sharedBuffer */, false /*canCallJava */, mSessionId, mTransferType,
                    mOffloadInfo, attributionSource, mAttributes);
                    mFlags, wp<AudioTrack::IAudioTrackCallback>::fromExisting(this),
                    0 /* notificationFrames */, nullptr /* sharedBuffer */, false /*canCallJava */,
                    mSessionId, mTransferType, mOffloadInfo, attributionSource, mAttributes);
    } else if (mTransferType == AudioTrack::TRANSFER_SHARED) {
        mTrack = new AudioTrack(AUDIO_STREAM_MUSIC, mSampleRate, mFormat, mChannelMask, mMemory,
                                mFlags, wp<AudioTrack::IAudioTrackCallback>::fromExisting(this), 0,
                                mSessionId, mTransferType, nullptr, attributionSource, mAttributes);
        mTrack = sp<TestAudioTrack>::make(
                AUDIO_STREAM_MUSIC, mSampleRate, mFormat, mChannelMask, mMemory, mFlags,
                wp<AudioTrack::IAudioTrackCallback>::fromExisting(this), 0, mSessionId,
                mTransferType, nullptr, attributionSource, mAttributes);
    } else {
        ALOGE("Test application is not handling transfer type %s",
              AudioTrack::convertTransferToText(mTransferType));
@@ -153,6 +153,8 @@ status_t AudioPlayback::start() {
        if (OK == status) {
            mState = PLAY_STARTED;
            LOG_FATAL_IF(false != mTrack->stopped());
            std::lock_guard l(mMutex);
            mStreamEndReceived = false;
        }
    }
    return status;
@@ -163,6 +165,15 @@ void AudioPlayback::onBufferEnd() {
    mStopPlaying = true;
}

void AudioPlayback::onStreamEnd() {
    ALOGD("%s", __func__);
    {
        std::lock_guard lock(mMutex);
        mStreamEndReceived = true;
    }
    mCondition.notify_all();
}

status_t AudioPlayback::fillBuffer() {
    if (PLAY_STARTED != mState) return INVALID_OPERATION;
    const int maxTries = MAX_WAIT_TIME_MS / WAIT_PERIOD_MS;
@@ -189,6 +200,7 @@ status_t AudioPlayback::fillBuffer() {
            counter++;
        }
    }
    mBytesUsedSoFar = 0;
    return OK;
}

@@ -254,7 +266,7 @@ void AudioPlayback::stop() {
    if (mState != PLAY_STOPPED && mState != PLAY_NO_INIT) {
        int32_t msec = 0;
        (void)mTrack->pendingDuration(&msec);
        mTrack->stopAndJoinCallbacks();
        mTrack->stop();  // Do not join the callback thread, drain may be ongoing.
        LOG_FATAL_IF(true != mTrack->stopped());
        mState = PLAY_STOPPED;
        if (msec > 0) {
@@ -264,6 +276,23 @@ void AudioPlayback::stop() {
    }
}

bool AudioPlayback::waitForStreamEnd() {
    ALOGD("%s", __func__);
    const int64_t endMs = uptimeMillis() + std::chrono::milliseconds(kLongCallbackTimeout).count();
    while (uptimeMillis() < endMs) {
        // Wake up the AudioPlaybackThread to get notifications.
        mTrack->wakeCallbackThread();
        std::unique_lock lock(mMutex);
        base::ScopedLockAssertion lock_assertion(mMutex);
        mCondition.wait_for(lock, kShortCallbackTimeout, [this]() {
            base::ScopedLockAssertion lock_assertion(mMutex);
            return mStreamEndReceived;
        });
        if (mStreamEndReceived) return true;
    }
    return false;
}

// hold pcm data sent by AudioRecord
RawBuffer::RawBuffer(int64_t ptsPipeline, int64_t ptsManual, int32_t capacity)
    : mData(capacity > 0 ? new uint8_t[capacity] : nullptr),
@@ -565,7 +594,7 @@ status_t AudioCapture::obtainBufferCb(RawBuffer& buffer) {
    const int maxTries = MAX_WAIT_TIME_MS / WAIT_PERIOD_MS;
    int counter = 0;
    std::unique_lock lock(mMutex);
    android::base::ScopedLockAssertion lock_assertion(mMutex);
    base::ScopedLockAssertion lock_assertion(mMutex);
    while (mBuffersReceived.empty() && !mStopRecording && counter < maxTries) {
        mCondition.wait_for(lock, std::chrono::milliseconds(WAIT_PERIOD_MS));
        counter++;
@@ -625,9 +654,9 @@ void AudioCapture::setMarkerPosition(uint32_t markerPosition) {

uint32_t AudioCapture::waitAndGetReceivedCbMarkerAtPosition() const {
    std::unique_lock lock(mMutex);
    android::base::ScopedLockAssertion lock_assertion(mMutex);
    base::ScopedLockAssertion lock_assertion(mMutex);
    mMarkerCondition.wait_for(lock, std::chrono::seconds(3), [this]() {
        android::base::ScopedLockAssertion lock_assertion(mMutex);
        base::ScopedLockAssertion lock_assertion(mMutex);
        return mReceivedCbMarkerAtPosition.has_value();
    });
    return mReceivedCbMarkerAtPosition.value_or(~0);
@@ -635,9 +664,9 @@ uint32_t AudioCapture::waitAndGetReceivedCbMarkerAtPosition() const {

uint32_t AudioCapture::waitAndGetReceivedCbMarkerCount() const {
    std::unique_lock lock(mMutex);
    android::base::ScopedLockAssertion lock_assertion(mMutex);
    base::ScopedLockAssertion lock_assertion(mMutex);
    mMarkerCondition.wait_for(lock, std::chrono::seconds(3), [this]() {
        android::base::ScopedLockAssertion lock_assertion(mMutex);
        base::ScopedLockAssertion lock_assertion(mMutex);
        return mReceivedCbMarkerCount.has_value();
    });
    return mReceivedCbMarkerCount.value_or(0);
+46 −9
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@
#include <deque>
#include <memory>
#include <mutex>
#include <thread>
#include <utility>

#include <android-base/thread_annotations.h>
@@ -75,6 +74,39 @@ class OnAudioDeviceUpdateNotifier : public AudioSystem::AudioDeviceCallback {
    std::condition_variable mCondition;
};

namespace {

class TestAudioTrack : public AudioTrack {
  public:
    explicit TestAudioTrack(const AttributionSourceState& attributionSourceState = {})
        : AudioTrack(attributionSourceState) {}
    TestAudioTrack(audio_stream_type_t streamType, uint32_t sampleRate, audio_format_t format,
                   audio_channel_mask_t channelMask, const sp<IMemory>& sharedBuffer,
                   audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
                   const wp<IAudioTrackCallback>& callback = nullptr,
                   int32_t notificationFrames = 0,
                   audio_session_t sessionId = AUDIO_SESSION_ALLOCATE,
                   transfer_type transferType = TRANSFER_DEFAULT,
                   const audio_offload_info_t* offloadInfo = nullptr,
                   const AttributionSourceState& attributionSource = AttributionSourceState(),
                   const audio_attributes_t* pAttributes = nullptr, bool doNotReconnect = false,
                   float maxRequiredSpeed = 1.0f)
        : AudioTrack(streamType, sampleRate, format, channelMask, sharedBuffer, flags, callback,
                     notificationFrames, sessionId, transferType, offloadInfo, attributionSource,
                     pAttributes, doNotReconnect, maxRequiredSpeed) {}
    // The callback thread is normally used for TRANSFER_SYNC_NOTIF_CALLBACK
    // in order to deliver "more data" callback. However, for offload we are
    // interested in the "stream end" event which is also served via the same
    // callback interface.
    void wakeCallbackThread() {
        if (sp<AudioTrackThread> t = mAudioTrackThread; t != nullptr) {
            t->wake();
        }
    }
};

}  // namespace

// Simple AudioPlayback class.
class AudioPlayback : public AudioTrack::IAudioTrackCallback {
    friend sp<AudioPlayback>;
@@ -92,11 +124,14 @@ class AudioPlayback : public AudioTrack::IAudioTrackCallback {
    status_t waitForConsumption(bool testSeek = false) EXCLUDES(mMutex);
    status_t fillBuffer();
    status_t onProcess(bool testSeek = false);
    void onBufferEnd() override EXCLUDES(mMutex);
    void stop() EXCLUDES(mMutex);
    bool waitForStreamEnd();

    bool mStopPlaying GUARDED_BY(mMutex);
    mutable std::mutex mMutex;
    // IAudioTrackCallback
    void onBufferEnd() override EXCLUDES(mMutex);
    void onStreamEnd() override EXCLUDES(mMutex);

    bool mStopPlaying GUARDED_BY(mMutex) = false;

    enum State {
        PLAY_NO_INIT,
@@ -116,13 +151,15 @@ class AudioPlayback : public AudioTrack::IAudioTrackCallback {
    const audio_attributes_t* mAttributes;
    const audio_offload_info_t* mOffloadInfo;

    size_t mBytesUsedSoFar;
    State mState;
    size_t mMemCapacity;
    size_t mBytesUsedSoFar = 0;
    State mState = PLAY_NO_INIT;
    size_t mMemCapacity = 0;
    sp<MemoryDealer> mMemoryDealer;
    sp<IMemory> mMemory;

    sp<AudioTrack> mTrack;
    sp<TestAudioTrack> mTrack;
    mutable std::mutex mMutex;
    bool mStreamEndReceived GUARDED_BY(mMutex) = false;
    std::condition_variable mCondition;
};

// hold pcm data sent by AudioRecord
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
#include <fstream>
#include <iostream>
#include <string>
#include <thread>
#include <tuple>
#include <vector>

Loading