slesTestFeedback.cpp revision 58432eb9cea995c69b4f905e68b38c1b8216edeb
1f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten/*
2f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten * Copyright (C) 2010 The Android Open Source Project
3f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten *
4f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten * Licensed under the Apache License, Version 2.0 (the "License");
5f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten * you may not use this file except in compliance with the License.
6f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten * You may obtain a copy of the License at
7f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten *
8f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten *      http://www.apache.org/licenses/LICENSE-2.0
9f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten *
10f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten * Unless required by applicable law or agreed to in writing, software
11f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten * distributed under the License is distributed on an "AS IS" BASIS,
12f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten * See the License for the specific language governing permissions and
14f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten * limitations under the License.
15f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten */
16f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
177126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Test program to record from default audio input and playback to default audio output.
187126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// It will generate feedback (Larsen effect) if played through on-device speakers,
197126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// or acts as a delay if played through headset.
205ef8af762b27b4fa45f59d944b11ad00311cb14bGlenn Kasten
21f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten#include "SLES/OpenSLES.h"
2201e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten#include "SLES/OpenSLES_Android.h"
23f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten#include <assert.h>
247126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten#include <pthread.h>
25f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten#include <stdio.h>
26f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten#include <stdlib.h>
27527b7d2e606abdbde0e29fe75f7e9a67285629d2Glenn Kasten#include <string.h>
28f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten#include <unistd.h>
29f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
300ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten#define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \
310ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0)
32f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
330ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten// default values
3458432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kastenstatic SLuint32 rxBufCount = 2;     // -r#
350ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kastenstatic SLuint32 txBufCount = 2;     // -t#
360ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kastenstatic SLuint32 bufSizeInFrames = 512;  // -f#
3758432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kastenstatic SLuint32 channels = 1;       // -c#
380ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kastenstatic SLuint32 sampleRate = 44100; // -s#
397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 exitAfterSeconds = 60; // -e#
407126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 freeBufCount = 0;   // calculated
41e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kastenstatic SLuint32 bufSizeInBytes = 0; // calculated
420ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten
437126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Storage area for the buffer queues
447126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic char **rxBuffers;
457126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic char **txBuffers;
467126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic char **freeBuffers;
47f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Buffer indices
497126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 rxFront;    // oldest recording
507126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 rxRear;     // next to be recorded
517126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 txFront;    // oldest playing
527126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 txRear;     // next to be played
537126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 freeFront;  // oldest free
547126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 freeRear;   // next to be freed
55f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
567126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLAndroidSimpleBufferQueueItf recorderBufferQueue;
577126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLBufferQueueItf playerBufferQueue;
58f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
597126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
600ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten
617126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Called after audio recorder fills a buffer with data
627126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic void recorderCallback(SLAndroidSimpleBufferQueueItf caller, void *context)
630ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten{
647126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    SLresult result;
657126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
667126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_lock(&mutex);
677126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
687126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // We should only be called when a recording buffer is done
697126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(rxFront <= rxBufCount);
707126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(rxRear <= rxBufCount);
717126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(rxFront != rxRear);
727126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    char *buffer = rxBuffers[rxFront];
737126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
747126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Remove buffer from record queue
757126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (++rxFront > rxBufCount) {
767126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxFront = 0;
777126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
787126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
797126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Enqueue the just-filled buffer for the player
807126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
817126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (SL_RESULT_SUCCESS == result) {
827126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
837126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // There was room in the play queue, update our model of it
847126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(txFront <= txBufCount);
857126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(txRear <= txBufCount);
867126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 txRearNext = txRear+1;
877126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (txRearNext > txBufCount) {
887126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            txRearNext = 0;
897126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
907126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(txRearNext != txFront);
917126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        txBuffers[txRear] = buffer;
927126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        txRear = txRearNext;
937126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
947126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    } else {
957126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
967126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Here if record has a filled buffer to play, but play queue is full.
977126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
987126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        write(1, "?", 1);
997126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1007126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // We could either try again later, or discard. For now we discard and re-use buffer.
1017126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Enqueue this same buffer for the recorder to fill again.
1027126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
1037126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
1047126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1057126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Update our model of the record queue
1067126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 rxRearNext = rxRear+1;
1077126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (rxRearNext > rxBufCount) {
1087126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            rxRearNext = 0;
1097126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
1107126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRearNext != rxFront);
1117126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxBuffers[rxRear] = buffer;
1127126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxRear = rxRearNext;
1137126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1147126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
1157126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1167126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_unlock(&mutex);
1170ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten}
1180ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten
1197126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1207126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Called after audio player empties a buffer of data
1217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic void playerCallback(SLBufferQueueItf caller, void *context)
122f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten{
123f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLresult result;
1247126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1257126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_lock(&mutex);
1267126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1277126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Get the buffer that just finished playing
1287126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(txFront <= txBufCount);
1297126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(txRear <= txBufCount);
1307126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(txFront != txRear);
1317126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    char *buffer = txBuffers[txFront];
1327126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (++txFront > txBufCount) {
1337126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        txFront = 0;
134e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten    }
135f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
1367126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // First try to enqueue the free buffer for recording
1370ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
1385ef8af762b27b4fa45f59d944b11ad00311cb14bGlenn Kasten    if (SL_RESULT_SUCCESS == result) {
1397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1407126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // There was room in the record queue, update our model of it
1417126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxFront <= rxBufCount);
1427126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRear <= rxBufCount);
1437126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 rxRearNext = rxRear+1;
1447126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (rxRearNext > rxBufCount) {
1457126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            rxRearNext = 0;
1467126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
1477126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRearNext != rxFront);
1487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxBuffers[rxRear] = buffer;
1497126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxRear = rxRearNext;
1507126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1510ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    } else {
1527126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1537126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Here if record queue is full
1547126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
1557126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1567126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Instead enqueue the free buffer on the free queue
1577126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeFront <= freeBufCount);
1587126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeRear <= freeBufCount);
1597126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 freeRearNext = freeRear+1;
1607126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (freeRearNext > freeBufCount) {
1617126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            freeRearNext = 0;
1627126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
1637126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // There must always be room in the free queue
1647126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeRearNext != freeFront);
1657126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        freeBuffers[freeRear] = buffer;
1667126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        freeRear = freeRearNext;
1677126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1685ef8af762b27b4fa45f59d944b11ad00311cb14bGlenn Kasten    }
169f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
1707126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_unlock(&mutex);
171f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten}
172f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
1737126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Main program
174f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kastenint main(int argc, char **argv)
175f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten{
1760ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    // process command-line options
1770ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    int i;
1780ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    for (i = 1; i < argc; ++i) {
1790ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        char *arg = argv[i];
1807126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (arg[0] != '-') {
1810ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            break;
1827126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
1837126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // -r# number of slots in receive buffer queue
1840ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        if (!strncmp(arg, "-r", 2)) {
1850ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            rxBufCount = atoi(&arg[2]);
1867126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            if (rxBufCount < 1 || rxBufCount > 16) {
1877126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten                fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)\n", argv[0],
1880ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) rxBufCount);
1897126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            }
1907126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // -t# number of slots in transmit buffer queue
1910ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-t", 2)) {
1920ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            txBufCount = atoi(&arg[2]);
1937126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            if (txBufCount < 1 || txBufCount > 16) {
1947126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten                fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)\n", argv[0],
1950ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) txBufCount);
1967126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            }
1970ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        // -f# size of each buffer in frames
1980ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-f", 2)) {
1990ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            bufSizeInFrames = atoi(&arg[2]);
2000ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            if (bufSizeInFrames == 0) {
2010ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                fprintf(stderr, "%s: unusual buffer size (%u frames)\n", argv[0],
2020ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) bufSizeInFrames);
2030ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            }
2040ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        // -c1 mono or -c2 stereo
2050ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-c", 2)) {
2060ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            channels = atoi(&arg[2]);
2070ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            if (channels < 1 || channels > 2) {
2080ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                fprintf(stderr, "%s: unusual channel count ignored (%u)\n", argv[0],
2090ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) channels);
2100ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                channels = 2;
2110ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            }
2120ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        // -s# sample rate in Hz
2130ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-s", 2)) {
2140ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            sampleRate = atoi(&arg[2]);
2150ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            switch (sampleRate) {
2160ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 8000:
2170ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 11025:
2187126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            case 12000:
2190ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 16000:
2200ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 22050:
2217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            case 24000:
2220ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 32000:
2230ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 44100:
2247126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            case 48000:
2250ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                break;
2260ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            default:
2270ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                fprintf(stderr, "%s: unusual sample rate (%u Hz)\n", argv[0],
2280ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) sampleRate);
2290ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                break;
2300ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            }
2317126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // -e# exit after this many seconds
2327126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        } else if (!strncmp(arg, "-e", 2)) {
2337126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            exitAfterSeconds = atoi(&arg[2]);
2340ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else
2350ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            fprintf(stderr, "%s: unknown option %s\n", argv[0], arg);
2360ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    }
2377126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // no other arguments allowed
2380ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    if (i < argc) {
2397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        fprintf(stderr, "usage: %s -r# -t# -f# -s# -c#\n", argv[0]);
2400ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -r# receive buffer queue count for microphone input, default 1\n");
2410ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -t# transmit buffer queue count for speaker output, default 2\n");
2420ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -f# number of frames per buffer, default 512\n");
2430ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -s# sample rate in Hz, default 44100\n");
2440ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -c1 mono\n");
2450ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -c2 stereo, default\n");
2460ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    }
2477126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // compute total free buffers as -r plus -t
2487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeBufCount = rxBufCount + txBufCount;
2497126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // compute buffer size
2500ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    bufSizeInBytes = channels * bufSizeInFrames * sizeof(short);
2517126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2527126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Initialize free buffers
2537126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeBuffers = (char **) calloc(freeBufCount+1, sizeof(char *));
2547126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    unsigned j;
2557126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    for (j = 0; j < freeBufCount; ++j) {
2567126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        freeBuffers[j] = (char *) malloc(bufSizeInBytes);
2577126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
2587126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeFront = 0;
2597126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeRear = freeBufCount;
2607126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeBuffers[j] = NULL;
2617126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2627126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Initialize record queue
2637126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    rxBuffers = (char **) calloc(rxBufCount+1, sizeof(char *));
2647126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    rxFront = 0;
2657126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    rxRear = 0;
2667126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2677126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Initialize play queue
2687126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    txBuffers = (char **) calloc(txBufCount+1, sizeof(char *));
2697126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    txFront = 0;
2707126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    txRear = 0;
2717126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
272f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLresult result;
273f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
274f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // create engine
275f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLObjectItf engineObject;
276f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
277f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
278f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
279f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
280f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLEngineItf engineEngine;
281f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
282f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
283f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
284f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // create output mix
285f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLObjectItf outputmixObject;
286f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL);
287f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
288f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE);
289f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
290f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
291f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // create an audio player with buffer queue source and output mix sink
292f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataSource audiosrc;
293f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataSink audiosnk;
294f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataFormat_PCM pcm;
295f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataLocator_OutputMix locator_outputmix;
29601e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLDataLocator_BufferQueue locator_bufferqueue_tx;
29701e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
29801e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_tx.numBuffers = txBufCount;
299f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
300f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_outputmix.outputMix = outputmixObject;
301f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.formatType = SL_DATAFORMAT_PCM;
3020ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    pcm.numChannels = channels;
3030ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    pcm.samplesPerSec = sampleRate * 1000;
304f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
305f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.containerSize = 16;
3060ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    pcm.channelMask = channels == 1 ? SL_SPEAKER_FRONT_CENTER :
3070ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
308f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
30901e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    audiosrc.pLocator = &locator_bufferqueue_tx;
310f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosrc.pFormat = &pcm;
311f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosnk.pLocator = &locator_outputmix;
312f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosnk.pFormat = NULL;
3137126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    SLObjectItf playerObject = NULL;
3147126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    SLObjectItf recorderObject = NULL;
31501e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE};
31601e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE};
3170ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk,
31801e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten        1, ids_tx, flags_tx);
3197126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
32058432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten        fprintf(stderr, "Could not create audio player (result %x), check sample rate\n", result);
3217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        goto cleanup;
3227126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
323f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
324f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
325f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
326f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLPlayItf playerPlay;
327f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
328f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
329f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue);
330f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
3317126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, playerCallback, NULL);
3327126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
333f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
334f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
335f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
336f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Create an audio recorder with microphone device source and buffer queue sink.
337f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // The buffer queue as sink is an Android-specific extension.
338f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
339f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataLocator_IODevice locator_iodevice;
34001e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
341f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
342f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
343f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
344f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.device = NULL;
345f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosrc.pLocator = &locator_iodevice;
34635c82a8173d1fcc18ae0bc08954a018bfce041deGlenn Kasten    audiosrc.pFormat = NULL;
34701e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
34801e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_rx.numBuffers = rxBufCount;
34901e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    audiosnk.pLocator = &locator_bufferqueue_rx;
350f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosnk.pFormat = &pcm;
3517126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    {
35201e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLInterfaceID ids_rx[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
35301e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLboolean flags_rx[1] = {SL_BOOLEAN_TRUE};
3540ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audiosrc,
35501e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten        &audiosnk, 1, ids_rx, flags_rx);
3567126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (SL_RESULT_SUCCESS != result) {
35758432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten        fprintf(stderr, "Could not create audio recorder (result %x), "
3587126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten                "check sample rate and channel count\n", result);
3597126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        goto cleanup;
3607126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
3617126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
362f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
363f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
364f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
365f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLRecordItf recorderRecord;
366f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
367f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
36801e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
3690ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        &recorderBufferQueue);
370f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
371f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, recorderCallback, NULL);
372f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
373f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
374f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Enqueue some empty buffers for the recorder
3757126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    for (j = 0; j < rxBufCount; ++j) {
3767126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
3777126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // allocate a free buffer
3787126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeFront != freeRear);
3797126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        char *buffer = freeBuffers[freeFront];
3807126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (++freeFront > freeBufCount) {
3817126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            freeFront = 0;
3827126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
3837126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
3847126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // put on record queue
3857126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 rxRearNext = rxRear + 1;
3867126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (rxRearNext > rxBufCount) {
3877126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            rxRearNext = 0;
3887126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
3897126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRearNext != rxFront);
3907126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxBuffers[rxRear] = buffer;
3917126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxRear = rxRearNext;
3920ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue,
3937126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            buffer, bufSizeInBytes);
394f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
395f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    }
396f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
397f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Kick off the recorder
398f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
399f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
400f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
401f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Wait patiently
4027126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    do {
403f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        usleep(1000000);
4047126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        write(1, ".", 1);
405f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        SLBufferQueueState playerBQState;
406f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        result = (*playerBufferQueue)->GetState(playerBufferQueue, &playerBQState);
407f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
40801e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten        SLAndroidSimpleBufferQueueState recorderBQState;
409f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &recorderBQState);
410f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
4117126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    } while (--exitAfterSeconds);
4127126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
4137126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Tear down the objects and exit
4147126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastencleanup:
4157126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (NULL != playerObject) {
4167126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        (*playerObject)->Destroy(playerObject);
4177126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
4187126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (NULL != recorderObject) {
4197126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        (*recorderObject)->Destroy(recorderObject);
420f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    }
4217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    (*outputmixObject)->Destroy(outputmixObject);
4227126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    (*engineObject)->Destroy(engineObject);
423f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
4247126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    return EXIT_SUCCESS;
425f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten}
426