186938671ea9cf95e3742659924189a1d016dfd59Phil Burk/*
286938671ea9cf95e3742659924189a1d016dfd59Phil Burk * Copyright (C) 2017 The Android Open Source Project
386938671ea9cf95e3742659924189a1d016dfd59Phil Burk *
486938671ea9cf95e3742659924189a1d016dfd59Phil Burk * Licensed under the Apache License, Version 2.0 (the "License");
586938671ea9cf95e3742659924189a1d016dfd59Phil Burk * you may not use this file except in compliance with the License.
686938671ea9cf95e3742659924189a1d016dfd59Phil Burk * You may obtain a copy of the License at
786938671ea9cf95e3742659924189a1d016dfd59Phil Burk *
886938671ea9cf95e3742659924189a1d016dfd59Phil Burk *      http://www.apache.org/licenses/LICENSE-2.0
986938671ea9cf95e3742659924189a1d016dfd59Phil Burk *
1086938671ea9cf95e3742659924189a1d016dfd59Phil Burk * Unless required by applicable law or agreed to in writing, software
1186938671ea9cf95e3742659924189a1d016dfd59Phil Burk * distributed under the License is distributed on an "AS IS" BASIS,
1286938671ea9cf95e3742659924189a1d016dfd59Phil Burk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1386938671ea9cf95e3742659924189a1d016dfd59Phil Burk * See the License for the specific language governing permissions and
1486938671ea9cf95e3742659924189a1d016dfd59Phil Burk * limitations under the License.
1586938671ea9cf95e3742659924189a1d016dfd59Phil Burk */
1686938671ea9cf95e3742659924189a1d016dfd59Phil Burk
1786938671ea9cf95e3742659924189a1d016dfd59Phil Burk// Try to trigger bugs by playing randomly on multiple streams.
1886938671ea9cf95e3742659924189a1d016dfd59Phil Burk
1986938671ea9cf95e3742659924189a1d016dfd59Phil Burk#include <stdio.h>
2086938671ea9cf95e3742659924189a1d016dfd59Phil Burk#include <stdlib.h>
2186938671ea9cf95e3742659924189a1d016dfd59Phil Burk#include <vector>
2286938671ea9cf95e3742659924189a1d016dfd59Phil Burk
2386938671ea9cf95e3742659924189a1d016dfd59Phil Burk#include <aaudio/AAudio.h>
2486938671ea9cf95e3742659924189a1d016dfd59Phil Burk#include "AAudioArgsParser.h"
2586938671ea9cf95e3742659924189a1d016dfd59Phil Burk#include "AAudioExampleUtils.h"
2686938671ea9cf95e3742659924189a1d016dfd59Phil Burk#include "AAudioSimplePlayer.h"
2786938671ea9cf95e3742659924189a1d016dfd59Phil Burk#include "SineGenerator.h"
2886938671ea9cf95e3742659924189a1d016dfd59Phil Burk
2986938671ea9cf95e3742659924189a1d016dfd59Phil Burk#define DEFAULT_TIMEOUT_NANOS  (1 * NANOS_PER_SECOND)
3086938671ea9cf95e3742659924189a1d016dfd59Phil Burk
3186938671ea9cf95e3742659924189a1d016dfd59Phil Burk#define NUM_LOOPS          1000
3286938671ea9cf95e3742659924189a1d016dfd59Phil Burk#define MAX_MICROS_DELAY   (2 * 1000 * 1000)
3386938671ea9cf95e3742659924189a1d016dfd59Phil Burk
3486938671ea9cf95e3742659924189a1d016dfd59Phil Burk// TODO Consider adding an input stream.
3586938671ea9cf95e3742659924189a1d016dfd59Phil Burk#define PROB_START   (0.20)
3686938671ea9cf95e3742659924189a1d016dfd59Phil Burk#define PROB_PAUSE   (PROB_START + 0.10)
3786938671ea9cf95e3742659924189a1d016dfd59Phil Burk#define PROB_FLUSH   (PROB_PAUSE + 0.10)
3886938671ea9cf95e3742659924189a1d016dfd59Phil Burk#define PROB_STOP    (PROB_FLUSH + 0.10)
3986938671ea9cf95e3742659924189a1d016dfd59Phil Burk#define PROB_CLOSE   (PROB_STOP + 0.10)
4086938671ea9cf95e3742659924189a1d016dfd59Phil Burkstatic_assert(PROB_CLOSE < 0.9, "Probability sum too high.");
4186938671ea9cf95e3742659924189a1d016dfd59Phil Burk
4286938671ea9cf95e3742659924189a1d016dfd59Phil Burkaaudio_data_callback_result_t AAudioMonkeyDataCallback(
4386938671ea9cf95e3742659924189a1d016dfd59Phil Burk        AAudioStream *stream,
4486938671ea9cf95e3742659924189a1d016dfd59Phil Burk        void *userData,
4586938671ea9cf95e3742659924189a1d016dfd59Phil Burk        void *audioData,
4686938671ea9cf95e3742659924189a1d016dfd59Phil Burk        int32_t numFrames);
4786938671ea9cf95e3742659924189a1d016dfd59Phil Burk
4886938671ea9cf95e3742659924189a1d016dfd59Phil Burkvoid AAudioMonkeyErrorCallbackProc(
4986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        AAudioStream *stream __unused,
5086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        void *userData __unused,
5186938671ea9cf95e3742659924189a1d016dfd59Phil Burk        aaudio_result_t error) {
5286938671ea9cf95e3742659924189a1d016dfd59Phil Burk    printf("Error Callback, error: %d\n",(int)error);
5386938671ea9cf95e3742659924189a1d016dfd59Phil Burk}
5486938671ea9cf95e3742659924189a1d016dfd59Phil Burk
5586938671ea9cf95e3742659924189a1d016dfd59Phil Burk// This function is not thread safe. Only use this from a single thread.
5686938671ea9cf95e3742659924189a1d016dfd59Phil Burkdouble nextRandomDouble() {
5786938671ea9cf95e3742659924189a1d016dfd59Phil Burk    return drand48();
5886938671ea9cf95e3742659924189a1d016dfd59Phil Burk}
5986938671ea9cf95e3742659924189a1d016dfd59Phil Burk
6086938671ea9cf95e3742659924189a1d016dfd59Phil Burkclass AAudioMonkey : public AAudioSimplePlayer {
6186938671ea9cf95e3742659924189a1d016dfd59Phil Burkpublic:
6286938671ea9cf95e3742659924189a1d016dfd59Phil Burk
6386938671ea9cf95e3742659924189a1d016dfd59Phil Burk    AAudioMonkey(int index, AAudioArgsParser *argParser)
6486938671ea9cf95e3742659924189a1d016dfd59Phil Burk            : mArgParser(argParser)
6586938671ea9cf95e3742659924189a1d016dfd59Phil Burk            , mIndex(index) {}
6686938671ea9cf95e3742659924189a1d016dfd59Phil Burk
6786938671ea9cf95e3742659924189a1d016dfd59Phil Burk    aaudio_result_t open() {
6886938671ea9cf95e3742659924189a1d016dfd59Phil Burk        printf("Monkey # %d ---------------------------------------------- OPEN\n", mIndex);
6986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        double offset = mIndex * 50;
7086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        mSine1.setup(440.0, 48000);
7186938671ea9cf95e3742659924189a1d016dfd59Phil Burk        mSine1.setSweep(300.0 + offset, 600.0 + offset, 5.0);
7286938671ea9cf95e3742659924189a1d016dfd59Phil Burk        mSine2.setup(660.0, 48000);
7386938671ea9cf95e3742659924189a1d016dfd59Phil Burk        mSine2.setSweep(350.0 + offset, 900.0 + offset, 7.0);
7486938671ea9cf95e3742659924189a1d016dfd59Phil Burk
7586938671ea9cf95e3742659924189a1d016dfd59Phil Burk        aaudio_result_t result = AAudioSimplePlayer::open(*mArgParser,
7686938671ea9cf95e3742659924189a1d016dfd59Phil Burk                                      AAudioMonkeyDataCallback,
7786938671ea9cf95e3742659924189a1d016dfd59Phil Burk                                      AAudioMonkeyErrorCallbackProc,
7886938671ea9cf95e3742659924189a1d016dfd59Phil Burk                                      this);
7986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (result != AAUDIO_OK) {
8086938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("ERROR -  player.open() returned %d\n", result);
8186938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
8286938671ea9cf95e3742659924189a1d016dfd59Phil Burk
8386938671ea9cf95e3742659924189a1d016dfd59Phil Burk        mArgParser->compareWithStream(getStream());
8486938671ea9cf95e3742659924189a1d016dfd59Phil Burk        return result;
8586938671ea9cf95e3742659924189a1d016dfd59Phil Burk    }
8686938671ea9cf95e3742659924189a1d016dfd59Phil Burk
8786938671ea9cf95e3742659924189a1d016dfd59Phil Burk    bool isOpen() {
8886938671ea9cf95e3742659924189a1d016dfd59Phil Burk        return (getStream() != nullptr);
8986938671ea9cf95e3742659924189a1d016dfd59Phil Burk
9086938671ea9cf95e3742659924189a1d016dfd59Phil Burk    }
9186938671ea9cf95e3742659924189a1d016dfd59Phil Burk    /**
9286938671ea9cf95e3742659924189a1d016dfd59Phil Burk     *
9386938671ea9cf95e3742659924189a1d016dfd59Phil Burk     * @return true if stream passes tests
9486938671ea9cf95e3742659924189a1d016dfd59Phil Burk     */
9586938671ea9cf95e3742659924189a1d016dfd59Phil Burk    bool validate() {
9686938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (!isOpen()) return true; // closed is OK
9786938671ea9cf95e3742659924189a1d016dfd59Phil Burk
9886938671ea9cf95e3742659924189a1d016dfd59Phil Burk        // update and query stream state
9986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        aaudio_stream_state_t state = AAUDIO_STREAM_STATE_UNKNOWN;
10086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        aaudio_result_t result = AAudioStream_waitForStateChange(getStream(),
10186938671ea9cf95e3742659924189a1d016dfd59Phil Burk            AAUDIO_STREAM_STATE_UNKNOWN, &state, 0);
10286938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (result != AAUDIO_OK) {
10386938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("ERROR - AAudioStream_waitForStateChange returned %d\n", result);
10486938671ea9cf95e3742659924189a1d016dfd59Phil Burk            return false;
10586938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
10686938671ea9cf95e3742659924189a1d016dfd59Phil Burk
10786938671ea9cf95e3742659924189a1d016dfd59Phil Burk        int64_t framesRead = AAudioStream_getFramesRead(getStream());
10886938671ea9cf95e3742659924189a1d016dfd59Phil Burk        int64_t framesWritten = AAudioStream_getFramesWritten(getStream());
10986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        int32_t xRuns = AAudioStream_getXRunCount(getStream());
11086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        // Print status
11186938671ea9cf95e3742659924189a1d016dfd59Phil Burk        printf("%30s, framesWritten = %8lld, framesRead = %8lld, xRuns = %d\n",
11286938671ea9cf95e3742659924189a1d016dfd59Phil Burk               AAudio_convertStreamStateToText(state),
11386938671ea9cf95e3742659924189a1d016dfd59Phil Burk               (unsigned long long) framesWritten,
11486938671ea9cf95e3742659924189a1d016dfd59Phil Burk               (unsigned long long) framesRead,
11586938671ea9cf95e3742659924189a1d016dfd59Phil Burk               xRuns);
11686938671ea9cf95e3742659924189a1d016dfd59Phil Burk
11786938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (framesWritten < framesRead) {
11886938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("WARNING - UNDERFLOW - diff = %d !!!!!!!!!!!!\n",
11986938671ea9cf95e3742659924189a1d016dfd59Phil Burk                   (int) (framesWritten - framesRead));
12086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
12186938671ea9cf95e3742659924189a1d016dfd59Phil Burk        return true;
12286938671ea9cf95e3742659924189a1d016dfd59Phil Burk    }
12386938671ea9cf95e3742659924189a1d016dfd59Phil Burk
12486938671ea9cf95e3742659924189a1d016dfd59Phil Burk    aaudio_result_t invoke() {
12586938671ea9cf95e3742659924189a1d016dfd59Phil Burk        aaudio_result_t result = AAUDIO_OK;
12686938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (!isOpen()) {
12786938671ea9cf95e3742659924189a1d016dfd59Phil Burk            result = open();
12886938671ea9cf95e3742659924189a1d016dfd59Phil Burk            if (result != AAUDIO_OK) return result;
12986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
13086938671ea9cf95e3742659924189a1d016dfd59Phil Burk
13186938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (!validate()) {
13286938671ea9cf95e3742659924189a1d016dfd59Phil Burk            return -1;
13386938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
13486938671ea9cf95e3742659924189a1d016dfd59Phil Burk
13586938671ea9cf95e3742659924189a1d016dfd59Phil Burk        double dice = nextRandomDouble();
13686938671ea9cf95e3742659924189a1d016dfd59Phil Burk        // Select an action based on a weighted probability.
13786938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (dice < PROB_START) {
13886938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("start\n");
13986938671ea9cf95e3742659924189a1d016dfd59Phil Burk            result = AAudioStream_requestStart(getStream());
14086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        } else if (dice < PROB_PAUSE) {
14186938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("pause\n");
14286938671ea9cf95e3742659924189a1d016dfd59Phil Burk            result = AAudioStream_requestPause(getStream());
14386938671ea9cf95e3742659924189a1d016dfd59Phil Burk        } else if (dice < PROB_FLUSH) {
14486938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("flush\n");
14586938671ea9cf95e3742659924189a1d016dfd59Phil Burk            result = AAudioStream_requestFlush(getStream());
14686938671ea9cf95e3742659924189a1d016dfd59Phil Burk        } else if (dice < PROB_STOP) {
14786938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("stop\n");
14886938671ea9cf95e3742659924189a1d016dfd59Phil Burk            result = AAudioStream_requestStop(getStream());
14986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        } else if (dice < PROB_CLOSE) {
15086938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("close\n");
15186938671ea9cf95e3742659924189a1d016dfd59Phil Burk            result = close();
15286938671ea9cf95e3742659924189a1d016dfd59Phil Burk        } else {
15386938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("do nothing\n");
15486938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
15586938671ea9cf95e3742659924189a1d016dfd59Phil Burk
15686938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (result == AAUDIO_ERROR_INVALID_STATE) {
15786938671ea9cf95e3742659924189a1d016dfd59Phil Burk            printf("    got AAUDIO_ERROR_INVALID_STATE - expected from a monkey\n");
15886938671ea9cf95e3742659924189a1d016dfd59Phil Burk            result = AAUDIO_OK;
15986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
16086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (result == AAUDIO_OK && isOpen()) {
16186938671ea9cf95e3742659924189a1d016dfd59Phil Burk            if (!validate()) {
16286938671ea9cf95e3742659924189a1d016dfd59Phil Burk                result = -1;
16386938671ea9cf95e3742659924189a1d016dfd59Phil Burk            }
16486938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
16586938671ea9cf95e3742659924189a1d016dfd59Phil Burk        return result;
16686938671ea9cf95e3742659924189a1d016dfd59Phil Burk    }
16786938671ea9cf95e3742659924189a1d016dfd59Phil Burk
16886938671ea9cf95e3742659924189a1d016dfd59Phil Burk    aaudio_data_callback_result_t renderAudio(
16986938671ea9cf95e3742659924189a1d016dfd59Phil Burk            AAudioStream *stream,
17086938671ea9cf95e3742659924189a1d016dfd59Phil Burk            void *audioData,
17186938671ea9cf95e3742659924189a1d016dfd59Phil Burk            int32_t numFrames) {
17286938671ea9cf95e3742659924189a1d016dfd59Phil Burk
17386938671ea9cf95e3742659924189a1d016dfd59Phil Burk        int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
17486938671ea9cf95e3742659924189a1d016dfd59Phil Burk        // This code only plays on the first one or two channels.
17586938671ea9cf95e3742659924189a1d016dfd59Phil Burk        // TODO Support arbitrary number of channels.
17686938671ea9cf95e3742659924189a1d016dfd59Phil Burk        switch (AAudioStream_getFormat(stream)) {
17786938671ea9cf95e3742659924189a1d016dfd59Phil Burk            case AAUDIO_FORMAT_PCM_I16: {
17886938671ea9cf95e3742659924189a1d016dfd59Phil Burk                int16_t *audioBuffer = (int16_t *) audioData;
17986938671ea9cf95e3742659924189a1d016dfd59Phil Burk                // Render sine waves as shorts to first channel.
18086938671ea9cf95e3742659924189a1d016dfd59Phil Burk                mSine1.render(&audioBuffer[0], samplesPerFrame, numFrames);
18186938671ea9cf95e3742659924189a1d016dfd59Phil Burk                // Render sine waves to second channel if there is one.
18286938671ea9cf95e3742659924189a1d016dfd59Phil Burk                if (samplesPerFrame > 1) {
18386938671ea9cf95e3742659924189a1d016dfd59Phil Burk                    mSine2.render(&audioBuffer[1], samplesPerFrame, numFrames);
18486938671ea9cf95e3742659924189a1d016dfd59Phil Burk                }
18586938671ea9cf95e3742659924189a1d016dfd59Phil Burk            }
18686938671ea9cf95e3742659924189a1d016dfd59Phil Burk                break;
18786938671ea9cf95e3742659924189a1d016dfd59Phil Burk            case AAUDIO_FORMAT_PCM_FLOAT: {
18886938671ea9cf95e3742659924189a1d016dfd59Phil Burk                float *audioBuffer = (float *) audioData;
18986938671ea9cf95e3742659924189a1d016dfd59Phil Burk                // Render sine waves as floats to first channel.
19086938671ea9cf95e3742659924189a1d016dfd59Phil Burk                mSine1.render(&audioBuffer[0], samplesPerFrame, numFrames);
19186938671ea9cf95e3742659924189a1d016dfd59Phil Burk                // Render sine waves to second channel if there is one.
19286938671ea9cf95e3742659924189a1d016dfd59Phil Burk                if (samplesPerFrame > 1) {
19386938671ea9cf95e3742659924189a1d016dfd59Phil Burk                    mSine2.render(&audioBuffer[1], samplesPerFrame, numFrames);
19486938671ea9cf95e3742659924189a1d016dfd59Phil Burk                }
19586938671ea9cf95e3742659924189a1d016dfd59Phil Burk            }
19686938671ea9cf95e3742659924189a1d016dfd59Phil Burk                break;
19786938671ea9cf95e3742659924189a1d016dfd59Phil Burk            default:
19886938671ea9cf95e3742659924189a1d016dfd59Phil Burk                return AAUDIO_CALLBACK_RESULT_STOP;
19986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
20086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        return AAUDIO_CALLBACK_RESULT_CONTINUE;
20186938671ea9cf95e3742659924189a1d016dfd59Phil Burk    }
20286938671ea9cf95e3742659924189a1d016dfd59Phil Burk
20386938671ea9cf95e3742659924189a1d016dfd59Phil Burkprivate:
20486938671ea9cf95e3742659924189a1d016dfd59Phil Burk    const AAudioArgsParser  *mArgParser;
20586938671ea9cf95e3742659924189a1d016dfd59Phil Burk    const int                mIndex;
20686938671ea9cf95e3742659924189a1d016dfd59Phil Burk    SineGenerator            mSine1;
20786938671ea9cf95e3742659924189a1d016dfd59Phil Burk    SineGenerator            mSine2;
20886938671ea9cf95e3742659924189a1d016dfd59Phil Burk};
20986938671ea9cf95e3742659924189a1d016dfd59Phil Burk
21086938671ea9cf95e3742659924189a1d016dfd59Phil Burk// Callback function that fills the audio output buffer.
21186938671ea9cf95e3742659924189a1d016dfd59Phil Burkaaudio_data_callback_result_t AAudioMonkeyDataCallback(
21286938671ea9cf95e3742659924189a1d016dfd59Phil Burk        AAudioStream *stream,
21386938671ea9cf95e3742659924189a1d016dfd59Phil Burk        void *userData,
21486938671ea9cf95e3742659924189a1d016dfd59Phil Burk        void *audioData,
21586938671ea9cf95e3742659924189a1d016dfd59Phil Burk        int32_t numFrames
21686938671ea9cf95e3742659924189a1d016dfd59Phil Burk) {
21786938671ea9cf95e3742659924189a1d016dfd59Phil Burk    // should not happen but just in case...
21886938671ea9cf95e3742659924189a1d016dfd59Phil Burk    if (userData == nullptr) {
21986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        printf("ERROR - AAudioMonkeyDataCallback needs userData\n");
22086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        return AAUDIO_CALLBACK_RESULT_STOP;
22186938671ea9cf95e3742659924189a1d016dfd59Phil Burk    }
22286938671ea9cf95e3742659924189a1d016dfd59Phil Burk    AAudioMonkey *monkey = (AAudioMonkey *) userData;
22386938671ea9cf95e3742659924189a1d016dfd59Phil Burk    return monkey->renderAudio(stream, audioData, numFrames);
22486938671ea9cf95e3742659924189a1d016dfd59Phil Burk}
22586938671ea9cf95e3742659924189a1d016dfd59Phil Burk
22686938671ea9cf95e3742659924189a1d016dfd59Phil Burk
22786938671ea9cf95e3742659924189a1d016dfd59Phil Burkstatic void usage() {
22886938671ea9cf95e3742659924189a1d016dfd59Phil Burk    AAudioArgsParser::usage();
22986938671ea9cf95e3742659924189a1d016dfd59Phil Burk    printf("      -i{seed}  Initial random seed\n");
23086938671ea9cf95e3742659924189a1d016dfd59Phil Burk    printf("      -t{count} number of monkeys in the Troop\n");
23186938671ea9cf95e3742659924189a1d016dfd59Phil Burk}
23286938671ea9cf95e3742659924189a1d016dfd59Phil Burk
23386938671ea9cf95e3742659924189a1d016dfd59Phil Burkint main(int argc, const char **argv) {
23486938671ea9cf95e3742659924189a1d016dfd59Phil Burk    AAudioArgsParser argParser;
23586938671ea9cf95e3742659924189a1d016dfd59Phil Burk    std::vector<AAudioMonkey> monkeys;
23686938671ea9cf95e3742659924189a1d016dfd59Phil Burk    aaudio_result_t result;
23786938671ea9cf95e3742659924189a1d016dfd59Phil Burk    int numMonkeys = 1;
23886938671ea9cf95e3742659924189a1d016dfd59Phil Burk
23986938671ea9cf95e3742659924189a1d016dfd59Phil Burk    // Make printf print immediately so that debug info is not stuck
24086938671ea9cf95e3742659924189a1d016dfd59Phil Burk    // in a buffer if we hang or crash.
24186938671ea9cf95e3742659924189a1d016dfd59Phil Burk    setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
24286938671ea9cf95e3742659924189a1d016dfd59Phil Burk
24386938671ea9cf95e3742659924189a1d016dfd59Phil Burk    printf("%s - Monkeys\n", argv[0]);
24486938671ea9cf95e3742659924189a1d016dfd59Phil Burk
24586938671ea9cf95e3742659924189a1d016dfd59Phil Burk    long int seed = (long int)getNanoseconds();  // different every time by default
24686938671ea9cf95e3742659924189a1d016dfd59Phil Burk
24786938671ea9cf95e3742659924189a1d016dfd59Phil Burk    for (int i = 1; i < argc; i++) {
24886938671ea9cf95e3742659924189a1d016dfd59Phil Burk        const char *arg = argv[i];
24986938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (argParser.parseArg(arg)) {
25086938671ea9cf95e3742659924189a1d016dfd59Phil Burk            // Handle options that are not handled by the ArgParser
25186938671ea9cf95e3742659924189a1d016dfd59Phil Burk            if (arg[0] == '-') {
25286938671ea9cf95e3742659924189a1d016dfd59Phil Burk                char option = arg[1];
25386938671ea9cf95e3742659924189a1d016dfd59Phil Burk                switch (option) {
25486938671ea9cf95e3742659924189a1d016dfd59Phil Burk                    case 'i':
25586938671ea9cf95e3742659924189a1d016dfd59Phil Burk                        seed = atol(&arg[2]);
25686938671ea9cf95e3742659924189a1d016dfd59Phil Burk                        break;
25786938671ea9cf95e3742659924189a1d016dfd59Phil Burk                    case 't':
25886938671ea9cf95e3742659924189a1d016dfd59Phil Burk                        numMonkeys = atoi(&arg[2]);
25986938671ea9cf95e3742659924189a1d016dfd59Phil Burk                        break;
26086938671ea9cf95e3742659924189a1d016dfd59Phil Burk                    default:
26186938671ea9cf95e3742659924189a1d016dfd59Phil Burk                        usage();
26286938671ea9cf95e3742659924189a1d016dfd59Phil Burk                        exit(EXIT_FAILURE);
26386938671ea9cf95e3742659924189a1d016dfd59Phil Burk                        break;
26486938671ea9cf95e3742659924189a1d016dfd59Phil Burk                }
26586938671ea9cf95e3742659924189a1d016dfd59Phil Burk            } else {
26686938671ea9cf95e3742659924189a1d016dfd59Phil Burk                usage();
26786938671ea9cf95e3742659924189a1d016dfd59Phil Burk                exit(EXIT_FAILURE);
26886938671ea9cf95e3742659924189a1d016dfd59Phil Burk                break;
26986938671ea9cf95e3742659924189a1d016dfd59Phil Burk            }
27086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
27186938671ea9cf95e3742659924189a1d016dfd59Phil Burk    }
27286938671ea9cf95e3742659924189a1d016dfd59Phil Burk
27386938671ea9cf95e3742659924189a1d016dfd59Phil Burk    srand48(seed);
27486938671ea9cf95e3742659924189a1d016dfd59Phil Burk    printf("seed = %ld, nextRandomDouble() = %f\n", seed, nextRandomDouble());
27586938671ea9cf95e3742659924189a1d016dfd59Phil Burk
27686938671ea9cf95e3742659924189a1d016dfd59Phil Burk    for (int m = 0; m < numMonkeys; m++) {
27786938671ea9cf95e3742659924189a1d016dfd59Phil Burk        monkeys.emplace_back(m, &argParser);
27886938671ea9cf95e3742659924189a1d016dfd59Phil Burk    }
27986938671ea9cf95e3742659924189a1d016dfd59Phil Burk
28086938671ea9cf95e3742659924189a1d016dfd59Phil Burk    for (int i = 0; i < NUM_LOOPS; i++) {
28186938671ea9cf95e3742659924189a1d016dfd59Phil Burk        // pick a random monkey and invoke it
28286938671ea9cf95e3742659924189a1d016dfd59Phil Burk        double dice = nextRandomDouble();
28386938671ea9cf95e3742659924189a1d016dfd59Phil Burk        int monkeyIndex = floor(dice * numMonkeys);
28486938671ea9cf95e3742659924189a1d016dfd59Phil Burk        printf("----------- Monkey #%d\n", monkeyIndex);
28586938671ea9cf95e3742659924189a1d016dfd59Phil Burk        result = monkeys[monkeyIndex].invoke();
28686938671ea9cf95e3742659924189a1d016dfd59Phil Burk        if (result != AAUDIO_OK) {
28786938671ea9cf95e3742659924189a1d016dfd59Phil Burk            goto error;
28886938671ea9cf95e3742659924189a1d016dfd59Phil Burk        }
28986938671ea9cf95e3742659924189a1d016dfd59Phil Burk
29086938671ea9cf95e3742659924189a1d016dfd59Phil Burk        // sleep some random time
29186938671ea9cf95e3742659924189a1d016dfd59Phil Burk        dice = nextRandomDouble();
29286938671ea9cf95e3742659924189a1d016dfd59Phil Burk        dice = dice * dice * dice; // skew towards smaller delays
29386938671ea9cf95e3742659924189a1d016dfd59Phil Burk        int micros = (int) (dice * MAX_MICROS_DELAY);
29486938671ea9cf95e3742659924189a1d016dfd59Phil Burk        usleep(micros);
29586938671ea9cf95e3742659924189a1d016dfd59Phil Burk
29686938671ea9cf95e3742659924189a1d016dfd59Phil Burk        // TODO consider making this multi-threaded, one thread per monkey, to catch more bugs
29786938671ea9cf95e3742659924189a1d016dfd59Phil Burk    }
29886938671ea9cf95e3742659924189a1d016dfd59Phil Burk
29986938671ea9cf95e3742659924189a1d016dfd59Phil Burk    printf("PASS\n");
30086938671ea9cf95e3742659924189a1d016dfd59Phil Burk    return EXIT_SUCCESS;
30186938671ea9cf95e3742659924189a1d016dfd59Phil Burk
30286938671ea9cf95e3742659924189a1d016dfd59Phil Burkerror:
30386938671ea9cf95e3742659924189a1d016dfd59Phil Burk    printf("FAIL - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
30486938671ea9cf95e3742659924189a1d016dfd59Phil Burk    usleep(1000 * 1000); // give me time to stop the logcat
30586938671ea9cf95e3742659924189a1d016dfd59Phil Burk    return EXIT_FAILURE;
30686938671ea9cf95e3742659924189a1d016dfd59Phil Burk}
30786938671ea9cf95e3742659924189a1d016dfd59Phil Burk
308