Loading media/libaaudio/examples/utils/AAudioSimplePlayer.h +41 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,31 @@ typedef struct Timestamp { int64_t nanoseconds; } Timestamp; static constexpr int32_t kWorkloadScaler = 500; // Linear congruential random number generator. static uint32_t s_random16() { static uint32_t seed = 1234; seed = ((seed * 31421) + 6927) & 0x0FFFF; return seed; } /** * The random number generator is good for burning CPU because the compiler cannot * easily optimize away the computation. * @param workload number of times to execute the loop * @return a white noise value between -1.0 and +1.0 */ static float s_burnCPU(int32_t workload) { uint32_t random = 0; for (int32_t i = 0; i < workload; i++) { for (int32_t j = 0; j < 10; j++) { random = random ^ s_random16(); } } return (random - 32768) * (1.0 / 32768); } /** * Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode. */ Loading Loading @@ -268,11 +293,13 @@ typedef struct SineThreadedData_s { int32_t timestampCount = 0; // in timestamps int32_t sampleRate = 48000; int32_t prefixToneFrames = 0; double workload = 0.0; bool sweepSetup = false; int scheduler = 0; bool schedulerChecked = false; int32_t hangTimeMSec = 0; int cpuAffinity = -1; AAudioSimplePlayer simplePlayer; int32_t callbackCount = 0; Loading Loading @@ -304,6 +331,14 @@ typedef struct SineThreadedData_s { } SineThreadedData_t; int setCpuAffinity(int cpuIndex) { cpu_set_t cpu_set; CPU_ZERO(&cpu_set); CPU_SET(cpuIndex, &cpu_set); int err = sched_setaffinity((pid_t) 0, sizeof(cpu_set_t), &cpu_set); return err == 0 ? 0 : -errno; } // Callback function that fills the audio output buffer. aaudio_data_callback_result_t SimplePlayerDataCallbackProc( AAudioStream *stream, Loading @@ -319,6 +354,10 @@ aaudio_data_callback_result_t SimplePlayerDataCallbackProc( } SineThreadedData_t *sineData = (SineThreadedData_t *) userData; if (sineData->cpuAffinity >= 0) { setCpuAffinity(sineData->cpuAffinity); sineData->cpuAffinity = -1; } // Play an initial high tone so we can tell whether the beginning was truncated. if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) { sineData->setupSineSweeps(); Loading Loading @@ -398,6 +437,8 @@ aaudio_data_callback_result_t SimplePlayerDataCallbackProc( return AAUDIO_CALLBACK_RESULT_STOP; } s_burnCPU((int32_t)(sineData->workload * kWorkloadScaler * numFrames)); sineData->callbackCount++; sineData->framesTotal += numFrames; return AAUDIO_CALLBACK_RESULT_CONTINUE; Loading media/libaaudio/examples/write_sine/src/write_sine_callback.cpp +50 −8 Original line number Diff line number Diff line Loading @@ -31,10 +31,10 @@ #include "AAudioSimplePlayer.h" #include "AAudioArgsParser.h" #define APP_VERSION "0.1.8" constexpr int32_t kDefaultHangTimeMSec = 10; #define APP_VERSION "0.2.1" static constexpr int32_t kDefaultHangTimeMSec = 10; static constexpr int32_t kWorkPeriodSeconds = 6; /** * Open stream, play some sine waves, then close the stream. * Loading @@ -44,7 +44,11 @@ constexpr int32_t kDefaultHangTimeMSec = 10; static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser, int32_t loopCount, int32_t prefixToneMsec, int32_t hangTimeMSec) int32_t hangTimeMSec, int cpuAffinity, double lowWorkLoad, double highWorkLoad, int32_t workPeriodSeconds) { SineThreadedData_t myData; AAudioSimplePlayer &player = myData.simplePlayer; Loading @@ -57,6 +61,7 @@ static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser, myData.schedulerChecked = false; myData.callbackCount = 0; myData.hangTimeMSec = hangTimeMSec; // test AAudioStream_getXRunCount() myData.cpuAffinity = cpuAffinity; result = player.open(argParser, SimplePlayerDataCallbackProc, Loading Loading @@ -111,8 +116,8 @@ static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser, } // Play a sine wave in the background. printf("Sleep for %d seconds while audio plays in a callback thread. %d of %d\n", argParser.getDurationSeconds(), (loopIndex + 1), loopCount); printf("Monitor for %d seconds while audio plays in a callback thread. %d of %d, %d\n", argParser.getDurationSeconds(), (loopIndex + 1), loopCount, workPeriodSeconds); startedAtNanos = getNanoseconds(CLOCK_MONOTONIC); for (int second = 0; second < durationSeconds; second++) { // Sleep a while. Wake up early if there is an error, for example a DISCONNECT. Loading @@ -123,13 +128,17 @@ static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser, const int32_t framesWritten = (int32_t) AAudioStream_getFramesWritten(player.getStream()); const int32_t framesRead = (int32_t) AAudioStream_getFramesRead(player.getStream()); const int32_t xruns = AAudioStream_getXRunCount(player.getStream()); myData.workload = ((second % (2 * workPeriodSeconds)) < workPeriodSeconds) ? lowWorkLoad : highWorkLoad; printf(" waker result = %d, at %6d millis" ", second = %3d, frames written %8d - read %8d = %8d, underruns = %d\n", ", second = %3d, frames written %8d - read %8d = %8d" ", work = %5.1f, underruns = %d\n", result, (int) millis, second, framesWritten, framesRead, framesWritten - framesRead, myData.workload, xruns); if (result != AAUDIO_OK) { disconnected = (result == AAUDIO_ERROR_DISCONNECTED); Loading Loading @@ -220,6 +229,11 @@ static void usage() { AAudioArgsParser::usage(); printf(" -l{count} loopCount start/stop, every other one is silent\n"); printf(" -t{msec} play a high pitched tone at the beginning\n"); printf(" -w{workload} set base workload, default 0.0\n"); printf(" -W{workload} alternate between this higher workload and base workload\n"); printf(" -Z{duration} number of seconds to spend at each workload, default = %d\n", kWorkPeriodSeconds); printf(" -a{cpu} set CPU affinity, default none\n"); printf(" -h{msec} force periodic underruns by hanging in callback\n"); printf(" If no value specified then %d used.\n", kDefaultHangTimeMSec); Loading @@ -232,6 +246,10 @@ int main(int argc, const char **argv) int32_t loopCount = 1; int32_t prefixToneMsec = 0; int32_t hangTimeMSec = 0; int cpuAffinity = -1; double lowWorkLoad = 0.0; double highWorkLoad = -1.0; int32_t workPeriodSeconds = kWorkPeriodSeconds; // Make printf print immediately so that debug info is not stuck // in a buffer if we hang or crash. Loading @@ -247,6 +265,9 @@ int main(int argc, const char **argv) if (arg[0] == '-') { char option = arg[1]; switch (option) { case 'a': cpuAffinity = atoi(&arg[2]); break; case 'l': loopCount = atoi(&arg[2]); break; Loading @@ -258,6 +279,15 @@ int main(int argc, const char **argv) ? atoi(&arg[2]) : kDefaultHangTimeMSec; break; case 'w': lowWorkLoad = atof(&arg[2]); break; case 'W': highWorkLoad = atof(&arg[2]); break; case 'Z': workPeriodSeconds = atoi(&arg[2]); break; default: usage(); exit(EXIT_FAILURE); Loading @@ -271,9 +301,21 @@ int main(int argc, const char **argv) } } if (highWorkLoad > 0) { if (highWorkLoad < lowWorkLoad) { printf("ERROR - -W%f workload lower than -w%f workload", highWorkLoad, lowWorkLoad); return EXIT_FAILURE; } } else { highWorkLoad = lowWorkLoad; // high not specified so use low } // Keep looping until we can complete the test without disconnecting. while((result = testOpenPlayClose(argParser, loopCount, prefixToneMsec, hangTimeMSec)) prefixToneMsec, hangTimeMSec, cpuAffinity, lowWorkLoad, highWorkLoad, workPeriodSeconds)) == AAUDIO_ERROR_DISCONNECTED); return (result) ? EXIT_FAILURE : EXIT_SUCCESS; Loading Loading
media/libaaudio/examples/utils/AAudioSimplePlayer.h +41 −0 Original line number Diff line number Diff line Loading @@ -40,6 +40,31 @@ typedef struct Timestamp { int64_t nanoseconds; } Timestamp; static constexpr int32_t kWorkloadScaler = 500; // Linear congruential random number generator. static uint32_t s_random16() { static uint32_t seed = 1234; seed = ((seed * 31421) + 6927) & 0x0FFFF; return seed; } /** * The random number generator is good for burning CPU because the compiler cannot * easily optimize away the computation. * @param workload number of times to execute the loop * @return a white noise value between -1.0 and +1.0 */ static float s_burnCPU(int32_t workload) { uint32_t random = 0; for (int32_t i = 0; i < workload; i++) { for (int32_t j = 0; j < 10; j++) { random = random ^ s_random16(); } } return (random - 32768) * (1.0 / 32768); } /** * Simple wrapper for AAudio that opens an output stream either in callback or blocking write mode. */ Loading Loading @@ -268,11 +293,13 @@ typedef struct SineThreadedData_s { int32_t timestampCount = 0; // in timestamps int32_t sampleRate = 48000; int32_t prefixToneFrames = 0; double workload = 0.0; bool sweepSetup = false; int scheduler = 0; bool schedulerChecked = false; int32_t hangTimeMSec = 0; int cpuAffinity = -1; AAudioSimplePlayer simplePlayer; int32_t callbackCount = 0; Loading Loading @@ -304,6 +331,14 @@ typedef struct SineThreadedData_s { } SineThreadedData_t; int setCpuAffinity(int cpuIndex) { cpu_set_t cpu_set; CPU_ZERO(&cpu_set); CPU_SET(cpuIndex, &cpu_set); int err = sched_setaffinity((pid_t) 0, sizeof(cpu_set_t), &cpu_set); return err == 0 ? 0 : -errno; } // Callback function that fills the audio output buffer. aaudio_data_callback_result_t SimplePlayerDataCallbackProc( AAudioStream *stream, Loading @@ -319,6 +354,10 @@ aaudio_data_callback_result_t SimplePlayerDataCallbackProc( } SineThreadedData_t *sineData = (SineThreadedData_t *) userData; if (sineData->cpuAffinity >= 0) { setCpuAffinity(sineData->cpuAffinity); sineData->cpuAffinity = -1; } // Play an initial high tone so we can tell whether the beginning was truncated. if (!sineData->sweepSetup && sineData->framesTotal >= sineData->prefixToneFrames) { sineData->setupSineSweeps(); Loading Loading @@ -398,6 +437,8 @@ aaudio_data_callback_result_t SimplePlayerDataCallbackProc( return AAUDIO_CALLBACK_RESULT_STOP; } s_burnCPU((int32_t)(sineData->workload * kWorkloadScaler * numFrames)); sineData->callbackCount++; sineData->framesTotal += numFrames; return AAUDIO_CALLBACK_RESULT_CONTINUE; Loading
media/libaaudio/examples/write_sine/src/write_sine_callback.cpp +50 −8 Original line number Diff line number Diff line Loading @@ -31,10 +31,10 @@ #include "AAudioSimplePlayer.h" #include "AAudioArgsParser.h" #define APP_VERSION "0.1.8" constexpr int32_t kDefaultHangTimeMSec = 10; #define APP_VERSION "0.2.1" static constexpr int32_t kDefaultHangTimeMSec = 10; static constexpr int32_t kWorkPeriodSeconds = 6; /** * Open stream, play some sine waves, then close the stream. * Loading @@ -44,7 +44,11 @@ constexpr int32_t kDefaultHangTimeMSec = 10; static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser, int32_t loopCount, int32_t prefixToneMsec, int32_t hangTimeMSec) int32_t hangTimeMSec, int cpuAffinity, double lowWorkLoad, double highWorkLoad, int32_t workPeriodSeconds) { SineThreadedData_t myData; AAudioSimplePlayer &player = myData.simplePlayer; Loading @@ -57,6 +61,7 @@ static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser, myData.schedulerChecked = false; myData.callbackCount = 0; myData.hangTimeMSec = hangTimeMSec; // test AAudioStream_getXRunCount() myData.cpuAffinity = cpuAffinity; result = player.open(argParser, SimplePlayerDataCallbackProc, Loading Loading @@ -111,8 +116,8 @@ static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser, } // Play a sine wave in the background. printf("Sleep for %d seconds while audio plays in a callback thread. %d of %d\n", argParser.getDurationSeconds(), (loopIndex + 1), loopCount); printf("Monitor for %d seconds while audio plays in a callback thread. %d of %d, %d\n", argParser.getDurationSeconds(), (loopIndex + 1), loopCount, workPeriodSeconds); startedAtNanos = getNanoseconds(CLOCK_MONOTONIC); for (int second = 0; second < durationSeconds; second++) { // Sleep a while. Wake up early if there is an error, for example a DISCONNECT. Loading @@ -123,13 +128,17 @@ static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser, const int32_t framesWritten = (int32_t) AAudioStream_getFramesWritten(player.getStream()); const int32_t framesRead = (int32_t) AAudioStream_getFramesRead(player.getStream()); const int32_t xruns = AAudioStream_getXRunCount(player.getStream()); myData.workload = ((second % (2 * workPeriodSeconds)) < workPeriodSeconds) ? lowWorkLoad : highWorkLoad; printf(" waker result = %d, at %6d millis" ", second = %3d, frames written %8d - read %8d = %8d, underruns = %d\n", ", second = %3d, frames written %8d - read %8d = %8d" ", work = %5.1f, underruns = %d\n", result, (int) millis, second, framesWritten, framesRead, framesWritten - framesRead, myData.workload, xruns); if (result != AAUDIO_OK) { disconnected = (result == AAUDIO_ERROR_DISCONNECTED); Loading Loading @@ -220,6 +229,11 @@ static void usage() { AAudioArgsParser::usage(); printf(" -l{count} loopCount start/stop, every other one is silent\n"); printf(" -t{msec} play a high pitched tone at the beginning\n"); printf(" -w{workload} set base workload, default 0.0\n"); printf(" -W{workload} alternate between this higher workload and base workload\n"); printf(" -Z{duration} number of seconds to spend at each workload, default = %d\n", kWorkPeriodSeconds); printf(" -a{cpu} set CPU affinity, default none\n"); printf(" -h{msec} force periodic underruns by hanging in callback\n"); printf(" If no value specified then %d used.\n", kDefaultHangTimeMSec); Loading @@ -232,6 +246,10 @@ int main(int argc, const char **argv) int32_t loopCount = 1; int32_t prefixToneMsec = 0; int32_t hangTimeMSec = 0; int cpuAffinity = -1; double lowWorkLoad = 0.0; double highWorkLoad = -1.0; int32_t workPeriodSeconds = kWorkPeriodSeconds; // Make printf print immediately so that debug info is not stuck // in a buffer if we hang or crash. Loading @@ -247,6 +265,9 @@ int main(int argc, const char **argv) if (arg[0] == '-') { char option = arg[1]; switch (option) { case 'a': cpuAffinity = atoi(&arg[2]); break; case 'l': loopCount = atoi(&arg[2]); break; Loading @@ -258,6 +279,15 @@ int main(int argc, const char **argv) ? atoi(&arg[2]) : kDefaultHangTimeMSec; break; case 'w': lowWorkLoad = atof(&arg[2]); break; case 'W': highWorkLoad = atof(&arg[2]); break; case 'Z': workPeriodSeconds = atoi(&arg[2]); break; default: usage(); exit(EXIT_FAILURE); Loading @@ -271,9 +301,21 @@ int main(int argc, const char **argv) } } if (highWorkLoad > 0) { if (highWorkLoad < lowWorkLoad) { printf("ERROR - -W%f workload lower than -w%f workload", highWorkLoad, lowWorkLoad); return EXIT_FAILURE; } } else { highWorkLoad = lowWorkLoad; // high not specified so use low } // Keep looping until we can complete the test without disconnecting. while((result = testOpenPlayClose(argParser, loopCount, prefixToneMsec, hangTimeMSec)) prefixToneMsec, hangTimeMSec, cpuAffinity, lowWorkLoad, highWorkLoad, workPeriodSeconds)) == AAUDIO_ERROR_DISCONNECTED); return (result) ? EXIT_FAILURE : EXIT_SUCCESS; Loading