diff options
| author | Glenn Kasten <gkasten@google.com> | 2012-10-31 12:13:02 -0700 |
|---|---|---|
| committer | Glenn Kasten <gkasten@google.com> | 2013-01-07 14:35:09 -0800 |
| commit | ad6c970f500cf99dd1eb23b9f5b2360948db90e7 (patch) | |
| tree | cba4791c007d15ab086af8a5279959df93596fe4 /tests | |
| parent | 1cde2eac95a1d76731bdf162db7ec42b584f0bc5 (diff) | |
| download | android_frameworks_wilhelm-ad6c970f500cf99dd1eb23b9f5b2360948db90e7.tar.gz android_frameworks_wilhelm-ad6c970f500cf99dd1eb23b9f5b2360948db90e7.tar.bz2 android_frameworks_wilhelm-ad6c970f500cf99dd1eb23b9f5b2360948db90e7.zip | |
Use libnbaio to avoid file I/O in audio callback
Bug: 7142834
Change-Id: I4f78f029ac6bfe27bea4dfe1f00812a2bdf8785d
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/sandbox/Android.mk | 3 | ||||
| -rw-r--r-- | tests/sandbox/playbq.c | 85 | ||||
| l--------- | tests/sandbox/playbq.cpp | 1 |
3 files changed, 84 insertions, 5 deletions
diff --git a/tests/sandbox/Android.mk b/tests/sandbox/Android.mk index 9145503..4425c2d 100644 --- a/tests/sandbox/Android.mk +++ b/tests/sandbox/Android.mk @@ -326,10 +326,11 @@ LOCAL_C_INCLUDES:= \ $(call include-path-for, audio-utils) LOCAL_SRC_FILES:= \ - playbq.c + playbq.cpp LOCAL_SHARED_LIBRARIES := \ libaudioutils \ + libnbaio \ libutils \ libOpenSLES diff --git a/tests/sandbox/playbq.c b/tests/sandbox/playbq.c index e1a7639..9a33f4d 100644 --- a/tests/sandbox/playbq.c +++ b/tests/sandbox/playbq.c @@ -18,6 +18,7 @@ #include <assert.h> #include <math.h> +#include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -31,6 +32,9 @@ #include <sndfile.h> #endif +#include <media/nbaio/MonoPipe.h> +#include <media/nbaio/MonoPipeReader.h> + #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) @@ -71,6 +75,10 @@ static void squeeze(const short *from, unsigned char *to, ssize_t n) } } +static android::MonoPipeReader *pipeReader; +static android::MonoPipe *pipeWriter; +static unsigned underruns = 0; + // This callback is called each time a buffer finishes playing static void callback(SLBufferQueueItf bufq, void *param) @@ -78,11 +86,14 @@ static void callback(SLBufferQueueItf bufq, void *param) assert(NULL == param); if (!eof) { short *buffer = &buffers[framesPerBuffer * sfinfo.channels * which]; - sf_count_t count; - count = sf_readf_short(sndfile, buffer, (sf_count_t) framesPerBuffer); + ssize_t count = pipeReader->read(buffer, framesPerBuffer, (int64_t) -1); + // on underrun from pipe, substitute silence if (0 >= count) { - eof = SL_BOOLEAN_TRUE; - } else { + memset(buffer, 0, framesPerBuffer * sfinfo.channels * sizeof(short)); + count = framesPerBuffer; + ++underruns; + } + if (count > 0) { SLuint32 nbytes = count * sfinfo.channels * sizeof(short); if (byteOrder != nativeByteOrder) { swab(buffer, buffer, nbytes); @@ -99,6 +110,43 @@ static void callback(SLBufferQueueItf bufq, void *param) } } +// This thread reads from a (slow) filesystem with unpredictable latency and writes to pipe + +static void *file_reader_loop(void *arg) +{ +#define READ_FRAMES 256 + short *temp = (short *) malloc(READ_FRAMES * sfinfo.channels * sizeof(short)); + sf_count_t total = 0; + for (;;) { + sf_count_t count = sf_readf_short(sndfile, temp, (sf_count_t) READ_FRAMES); + if (0 >= count) { + eof = SL_BOOLEAN_TRUE; + break; + } + const short *ptr = temp; + while (count > 0) { + ssize_t actual = pipeWriter->write(ptr, (size_t) count); + if (actual < 0) { + break; + } + if ((sf_count_t) actual < count) { + usleep(10000); + } + ptr += actual * sfinfo.channels; + count -= actual; + total += actual; + } + // simulate occasional filesystem latency + if ((total & 0xFF00) == 0xFF00) { + usleep(100000); + } + } + free(temp); + return NULL; +} + +// Main program + int main(int argc, char **argv) { // Determine the native byte order (SL_BYTEORDER_NATIVE not available until 1.1) @@ -188,6 +236,9 @@ int main(int argc, char **argv) return EXIT_FAILURE; } + // The sample rate is a lie, but it doesn't actually matter + const android::NBAIO_Format nbaio_format = android::Format_from_SR_C(44100, sfinfo.channels); + // verify the file format switch (sfinfo.channels) { case 1: @@ -231,6 +282,8 @@ int main(int argc, char **argv) goto close_sndfile; } + { + buffers = (short *) malloc(framesPerBuffer * sfinfo.channels * sizeof(short) * numBuffers); // create engine @@ -302,6 +355,8 @@ int main(int argc, char **argv) goto no_player; } + { + // realize the player result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE); assert(SL_RESULT_SUCCESS == result); @@ -400,6 +455,24 @@ int main(int argc, char **argv) result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, callback, NULL); assert(SL_RESULT_SUCCESS == result); + pipeWriter = new android::MonoPipe(16384, nbaio_format, false /*writeCanBlock*/); + android::NBAIO_Format offer = nbaio_format; + size_t numCounterOffers = 0; + ssize_t neg = pipeWriter->negotiate(&offer, 1, NULL, numCounterOffers); + assert(0 == neg); + pipeReader = new android::MonoPipeReader(pipeWriter); + numCounterOffers = 0; + neg = pipeReader->negotiate(&offer, 1, NULL, numCounterOffers); + assert(0 == neg); + + // create thread to read from file + pthread_t thread; + int ok = pthread_create(&thread, (const pthread_attr_t *) NULL, file_reader_loop, NULL); + assert(0 == ok); + + // give thread a head start so that the pipe is initially filled + sleep(1); + // set the player's state to playing result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING); assert(SL_RESULT_SUCCESS == result); @@ -455,6 +528,8 @@ int main(int argc, char **argv) // destroy audio player (*playerObject)->Destroy(playerObject); + } + no_player: // destroy output mix @@ -463,6 +538,8 @@ no_player: // destroy engine (*engineObject)->Destroy(engineObject); + } + close_sndfile: (void) sf_close(sndfile); diff --git a/tests/sandbox/playbq.cpp b/tests/sandbox/playbq.cpp new file mode 120000 index 0000000..a438ce1 --- /dev/null +++ b/tests/sandbox/playbq.cpp @@ -0,0 +1 @@ +playbq.c
\ No newline at end of file |
