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

Commit 095ef4c8 authored by jiabin's avatar jiabin Committed by Android Build Cherrypicker Worker
Browse files

Add test for pcm offload.

Bug: 385140034
Test: test_pcm_offload
Flag: TEST_ONLY
(cherry picked from https://googleplex-android-review.googlesource.com/q/commit:65f03b7ff872215dffbf14665a4448dea5733292)
Merged-In: I6357dbfb329eda4ac19a587be80ba87d9ce2d034
Change-Id: I6357dbfb329eda4ac19a587be80ba87d9ce2d034
parent 266c5d50
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -435,6 +435,7 @@ public:
        printf("          n for _NONE\n");
        printf("          l for _LATENCY\n");
        printf("          p for _POWER_SAVING;\n");
        printf("          o for _POWER_SAVING_OFFLOADED;\n");
        printf("      -r{sampleRate} for example 44100\n");
        printf("      -s{duration} in seconds, default is %d\n", DEFAULT_DURATION_SECONDS);
        printf("      -u{usage} eg. 14 for AAUDIO_USAGE_GAME\n");
@@ -477,6 +478,9 @@ public:
            case 'p':
                mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING;
                break;
            case 'o':
                mode = AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED;
                break;
            default:
                printf("ERROR: invalid performance mode %c\n", c);
                break;
+18 −0
Original line number Diff line number Diff line
@@ -271,6 +271,24 @@ public:
        return result;
    }

    aaudio_result_t setOffloadDelayPadding(int delay, int padding) {
        aaudio_result_t result = AAudioStream_setOffloadDelayPadding(mStream, delay, padding);
        if (result != AAUDIO_OK) {
            printf("WARNING - AAudioStream_setOffloadDelayPadding(%d, %d) returned %d %s\n",
                   delay, padding, result, AAudio_convertResultToText(result));
        }
        return result;
    }

    aaudio_result_t setOffloadEndOfStream() {
        aaudio_result_t result = AAudioStream_setOffloadEndOfStream(mStream);
        if (result != AAUDIO_OK) {
            printf("ERROR - AAudioStream_setOffloadEndOfStream() returned %d %s\n",
                   result, AAudio_convertResultToText(result));
        }
        return result;
    }

    AAudioStream *getStream() const {
        return mStream;
    }
+8 −0
Original line number Diff line number Diff line
@@ -276,3 +276,11 @@ cc_test {
        ],
    },
}

cc_binary {
    name: "test_pcm_offload",
    defaults: ["libaaudio_tests_defaults"],
    srcs: ["test_pcm_offload.cpp"],
    header_libs: ["libaaudio_example_utils"],
    shared_libs: ["libaaudio"],
}
+180 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.
 */

// PCM offload

#include <stdio.h>
#include <stdlib.h>
#include <vector>

#include <aaudio/AAudio.h>

#include "AAudioArgsParser.h"
#include "AAudioSimplePlayer.h"
#include "SineGenerator.h"

const static int DEFAULT_TIME_TO_RUN_IN_SECOND = 5;

aaudio_data_callback_result_t MyDatacallback(AAudioStream* stream,
                                             void* userData,
                                             void* audioData,
                                             int32_t numFrames);

void MyErrorCallback(AAudioStream* /*stream*/, void* /*userData*/, aaudio_result_t error);

class OffloadPlayer : public AAudioSimplePlayer {
public:
    OffloadPlayer(AAudioArgsParser& argParser, int delay, int padding, int streamFrames)
            : mArgParser(argParser), mDelay(delay), mPadding(padding), mStreamFrames(streamFrames) {
    }

    aaudio_result_t open() {
        aaudio_result_t result = AAudioSimplePlayer::open(mArgParser,
                                                          &MyDatacallback,
                                                          &MyErrorCallback,
                                                          this);
        if (result != AAUDIO_OK) {
            return result;
        }
        mChannelCount = getChannelCount();
        for (int i = 0; i < mChannelCount; ++i) {
            SineGenerator sine;
            sine.setup(440.0, 48000.0);
            mSines.push_back(sine);
        }
        return result;
    }

    aaudio_data_callback_result_t renderAudio(AAudioStream* stream,
                                              void* audioData,
                                              int32_t numFrames) {
        // Just handle PCM_16 and PCM_FLOAT for testing
        switch (AAudioStream_getFormat(stream)) {
            case AAUDIO_FORMAT_PCM_I16: {
                int16_t *audioBuffer = static_cast<int16_t *>(audioData);
                for (int i = 0; i < mChannelCount; ++i) {
                    mSines[i].render(&audioBuffer[i], mChannelCount, numFrames);
                }
            } break;
            case AAUDIO_FORMAT_PCM_FLOAT: {
                float *audioBuffer = static_cast<float *>(audioData);
                for (int i = 0; i < mChannelCount; ++i) {
                    mSines[i].render(&audioBuffer[i], mChannelCount, numFrames);
                }
            } break;
            default:
                return AAUDIO_CALLBACK_RESULT_STOP;
        }
        mFramesWritten += numFrames;
        if (mStreamFrames > 0 && mFramesWritten >= mStreamFrames) {
            if (auto result = setOffloadEndOfStream(); result != AAUDIO_OK) {
                printf("Failed to set offload end of stream, stopping the stream now");
                return AAUDIO_CALLBACK_RESULT_STOP;
            }
            (void) setOffloadDelayPadding(mDelay, mPadding);
            mFramesWritten = 0;
        }
        return AAUDIO_CALLBACK_RESULT_CONTINUE;
    }

private:
    const AAudioArgsParser mArgParser;
    const int mDelay;
    const int mPadding;
    const int mStreamFrames;

    int mChannelCount;
    std::vector<SineGenerator> mSines;
    int mFramesWritten = 0;
};

aaudio_data_callback_result_t MyDatacallback(AAudioStream* stream,
                                             void* userData,
                                             void* audioData,
                                             int32_t numFrames) {
    OffloadPlayer* player = static_cast<OffloadPlayer*>(userData);
    return player->renderAudio(stream, audioData, numFrames);
}

void MyErrorCallback(AAudioStream* /*stream*/, void* /*userData*/, aaudio_result_t error) {
    printf("Error callback, error=%d\n", error);
}

static void usage() {
    AAudioArgsParser::usage();
    printf("      -D{delay} offload delay in frames\n");
    printf("      -P{padding} offload padding in frames\n");
    printf("      -E{frames} frames to notify end of stream\n");
    printf("      -T{seconds} time to run the test\n");
}

int main(int argc, char **argv) {
    AAudioArgsParser argParser;
    int delay = 0;
    int padding = 0;
    int streamFrames = 0;
    int timeToRun = DEFAULT_TIME_TO_RUN_IN_SECOND;
    for (int i = 1; i < argc; ++i) {
        const char *arg = argv[i];
        if (argParser.parseArg(arg)) {
            if (arg[0] == '-') {
                char option = arg[1];
                switch (option) {
                    case 'D':
                        delay = atoi(&arg[2]);
                        break;
                    case 'P':
                        padding = atoi(&arg[2]);
                        break;
                    case 'E':
                        streamFrames = atoi(&arg[2]);
                        break;
                    case 'T':
                        timeToRun = atoi(&arg[2]);
                        break;
                    default:
                        usage();
                        exit(EXIT_FAILURE);
                }
            } else {
                usage();
                exit(EXIT_FAILURE);
            }
        }
    }

    // Force to use offload mode
    argParser.setPerformanceMode(AAUDIO_PERFORMANCE_MODE_POWER_SAVING_OFFLOADED);

    OffloadPlayer player(argParser, delay, padding, streamFrames);
    if (auto result = player.open(); result != AAUDIO_OK) {
        printf("Failed to open stream, error=%d\n", result);
        exit(EXIT_FAILURE);
    }

    // Failed to set offload delay and padding will affect the gapless transition between tracks
    // but doesn't affect playback.
    (void) player.setOffloadDelayPadding(delay, padding);

    if (auto result = player.start(); result != AAUDIO_OK) {
        printf("Failed to start stream, error=%d", result);
        exit(EXIT_FAILURE);
    }

    sleep(timeToRun);

    return EXIT_SUCCESS;
}