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
21c6853892c94800e72c0bd676d5d2136d48cea76eGlenn Kasten#include <SLES/OpenSLES.h>
22c6853892c94800e72c0bd676d5d2136d48cea76eGlenn 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
306e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten#include <audio_utils/fifo.h>
3185079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten#include <audio_utils/sndfile.h>
32fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
330ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten#define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \
340ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0)
35f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
360ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten// default values
3758432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kastenstatic SLuint32 rxBufCount = 2;     // -r#
380ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kastenstatic SLuint32 txBufCount = 2;     // -t#
39fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kastenstatic SLuint32 bufSizeInFrames = 240;  // -f#
4058432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kastenstatic SLuint32 channels = 1;       // -c#
41fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kastenstatic SLuint32 sampleRate = 48000; // -s#
427126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 exitAfterSeconds = 60; // -e#
437126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 freeBufCount = 0;   // calculated
44e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kastenstatic SLuint32 bufSizeInBytes = 0; // calculated
450ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten
467126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Storage area for the buffer queues
477126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic char **rxBuffers;
487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic char **txBuffers;
497126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic char **freeBuffers;
50f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
517126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Buffer indices
527126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 rxFront;    // oldest recording
537126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 rxRear;     // next to be recorded
547126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 txFront;    // oldest playing
557126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 txRear;     // next to be played
567126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 freeFront;  // oldest free
577126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLuint32 freeRear;   // next to be freed
58f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
597126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLAndroidSimpleBufferQueueItf recorderBufferQueue;
607126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic SLBufferQueueItf playerBufferQueue;
61f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
627126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
630ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten
646e55f367758180f2f76694f9dcfbbab269a25162Glenn Kastenstatic audio_utils_fifo fifo;
65fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
666e55f367758180f2f76694f9dcfbbab269a25162Glenn Kastenstatic audio_utils_fifo fifo2;
676e55f367758180f2f76694f9dcfbbab269a25162Glenn Kastenstatic short *fifo2Buffer = NULL;
6885079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten
6985079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kastenstatic int injectImpulse;
7085079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten
717126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Called after audio recorder fills a buffer with data
72086a6f51a7b12880ed114962136972f89ed70da2Glenn Kastenstatic void recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused, void *context __unused)
730ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten{
747126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    SLresult result;
757126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
767126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_lock(&mutex);
777126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
787126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // We should only be called when a recording buffer is done
797126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(rxFront <= rxBufCount);
807126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(rxRear <= rxBufCount);
817126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(rxFront != rxRear);
827126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    char *buffer = rxBuffers[rxFront];
837126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
847126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Remove buffer from record queue
857126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (++rxFront > rxBufCount) {
867126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxFront = 0;
877126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
887126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
89fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#if 1
906e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten    ssize_t actual = audio_utils_fifo_write(&fifo, buffer, (size_t) bufSizeInFrames);
91fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    if (actual != (ssize_t) bufSizeInFrames) {
92fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        write(1, "?", 1);
93fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
94fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
9585079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    // This is called by a realtime (SCHED_FIFO) thread,
9685079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    // and it is unsafe to do I/O as it could block for unbounded time.
9785079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    // Flash filesystem is especially notorious for blocking.
986e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten    if (fifo2Buffer != NULL) {
996e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten        actual = audio_utils_fifo_write(&fifo2, buffer, (size_t) bufSizeInFrames);
10085079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        if (actual != (ssize_t) bufSizeInFrames) {
10185079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten            write(1, "?", 1);
10285079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        }
10385079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    }
10485079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten
105fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Enqueue this same buffer for the recorder to fill again.
106fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
107fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
108fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
109fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Update our model of the record queue
110fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    SLuint32 rxRearNext = rxRear+1;
111fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    if (rxRearNext > rxBufCount) {
112fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        rxRearNext = 0;
113fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
114fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(rxRearNext != rxFront);
115fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    rxBuffers[rxRear] = buffer;
116fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    rxRear = rxRearNext;
117fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
118fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#else
1197126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Enqueue the just-filled buffer for the player
1207126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
1217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (SL_RESULT_SUCCESS == result) {
1227126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1237126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // There was room in the play queue, update our model of it
1247126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(txFront <= txBufCount);
1257126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(txRear <= txBufCount);
1267126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 txRearNext = txRear+1;
1277126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (txRearNext > txBufCount) {
1287126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            txRearNext = 0;
1297126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
1307126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(txRearNext != txFront);
1317126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        txBuffers[txRear] = buffer;
1327126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        txRear = txRearNext;
1337126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1347126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    } else {
1357126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1367126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Here if record has a filled buffer to play, but play queue is full.
1377126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
1387126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        write(1, "?", 1);
1397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1407126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // We could either try again later, or discard. For now we discard and re-use buffer.
1417126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Enqueue this same buffer for the recorder to fill again.
1427126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
1437126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
1447126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1457126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Update our model of the record queue
1467126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 rxRearNext = rxRear+1;
1477126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (rxRearNext > rxBufCount) {
1487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            rxRearNext = 0;
1497126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
1507126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRearNext != rxFront);
1517126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxBuffers[rxRear] = buffer;
1527126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxRear = rxRearNext;
1537126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1547126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
155fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#endif
1567126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1577126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_unlock(&mutex);
1580ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten}
1590ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten
1607126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1617126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Called after audio player empties a buffer of data
162086a6f51a7b12880ed114962136972f89ed70da2Glenn Kastenstatic void playerCallback(SLBufferQueueItf caller __unused, void *context __unused)
163f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten{
164f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLresult result;
1657126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1667126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_lock(&mutex);
1677126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1687126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Get the buffer that just finished playing
1697126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(txFront <= txBufCount);
1707126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(txRear <= txBufCount);
1717126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(txFront != txRear);
1727126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    char *buffer = txBuffers[txFront];
1737126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (++txFront > txBufCount) {
1747126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        txFront = 0;
175e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten    }
176f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
177fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#if 1
1786e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten    ssize_t actual = audio_utils_fifo_read(&fifo, buffer, bufSizeInFrames);
179fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    if (actual != (ssize_t) bufSizeInFrames) {
180fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        write(1, "/", 1);
181fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        // on underrun from pipe, substitute silence
182fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        memset(buffer, 0, bufSizeInFrames * channels * sizeof(short));
183fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
184fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
18585079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    if (injectImpulse == -1) {
18685079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        // Experimentally, a single frame impulse was insufficient to trigger feedback.
18785079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        // Also a Nyquist frequency signal was also insufficient, probably because
18885079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        // the response of output and/or input path was not adequate at high frequencies.
18985079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        // This short burst of a few cycles of square wave at Nyquist/4 was found to work well.
190086a6f51a7b12880ed114962136972f89ed70da2Glenn Kasten        for (unsigned i = 0; i < bufSizeInFrames / 8; i += 8) {
19185079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten            for (int j = 0; j < 8; j++) {
192086a6f51a7b12880ed114962136972f89ed70da2Glenn Kasten                for (unsigned k = 0; k < channels; k++) {
19385079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten                    ((short *)buffer)[(i+j)*channels+k] = j < 4 ? 0x7FFF : 0x8000;
19485079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten                }
19585079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten            }
19685079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        }
19785079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        injectImpulse = 0;
19885079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    }
19985079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten
200fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Enqueue the filled buffer for playing
201fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
202fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
203fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
204fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Update our model of the player queue
205fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(txFront <= txBufCount);
206fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(txRear <= txBufCount);
207fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    SLuint32 txRearNext = txRear+1;
208fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    if (txRearNext > txBufCount) {
209fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        txRearNext = 0;
210fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
211fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(txRearNext != txFront);
212fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    txBuffers[txRear] = buffer;
213fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    txRear = txRearNext;
214fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
215fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#else
2167126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // First try to enqueue the free buffer for recording
2170ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
2185ef8af762b27b4fa45f59d944b11ad00311cb14bGlenn Kasten    if (SL_RESULT_SUCCESS == result) {
2197126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2207126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // There was room in the record queue, update our model of it
2217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxFront <= rxBufCount);
2227126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRear <= rxBufCount);
2237126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 rxRearNext = rxRear+1;
2247126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (rxRearNext > rxBufCount) {
2257126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            rxRearNext = 0;
2267126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
2277126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRearNext != rxFront);
2287126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxBuffers[rxRear] = buffer;
2297126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxRear = rxRearNext;
2307126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2310ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    } else {
2327126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2337126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Here if record queue is full
2347126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
2357126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2367126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Instead enqueue the free buffer on the free queue
2377126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeFront <= freeBufCount);
2387126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeRear <= freeBufCount);
2397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 freeRearNext = freeRear+1;
2407126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (freeRearNext > freeBufCount) {
2417126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            freeRearNext = 0;
2427126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
2437126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // There must always be room in the free queue
2447126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeRearNext != freeFront);
2457126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        freeBuffers[freeRear] = buffer;
2467126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        freeRear = freeRearNext;
2477126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2485ef8af762b27b4fa45f59d944b11ad00311cb14bGlenn Kasten    }
249fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#endif
250f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
2517126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_unlock(&mutex);
252f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten}
253f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
2547126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Main program
255f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kastenint main(int argc, char **argv)
256f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten{
25785079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    const char *outFileName = NULL;
2580ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    // process command-line options
2590ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    int i;
2600ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    for (i = 1; i < argc; ++i) {
2610ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        char *arg = argv[i];
2627126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (arg[0] != '-') {
2630ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            break;
2647126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
2657126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // -r# number of slots in receive buffer queue
2660ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        if (!strncmp(arg, "-r", 2)) {
2670ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            rxBufCount = atoi(&arg[2]);
2687126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            if (rxBufCount < 1 || rxBufCount > 16) {
2697126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten                fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)\n", argv[0],
2700ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) rxBufCount);
2717126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            }
2727126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // -t# number of slots in transmit buffer queue
2730ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-t", 2)) {
2740ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            txBufCount = atoi(&arg[2]);
2757126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            if (txBufCount < 1 || txBufCount > 16) {
2767126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten                fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)\n", argv[0],
2770ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) txBufCount);
2787126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            }
2790ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        // -f# size of each buffer in frames
2800ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-f", 2)) {
2810ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            bufSizeInFrames = atoi(&arg[2]);
2820ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            if (bufSizeInFrames == 0) {
2830ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                fprintf(stderr, "%s: unusual buffer size (%u frames)\n", argv[0],
2840ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) bufSizeInFrames);
2850ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            }
2860ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        // -c1 mono or -c2 stereo
2870ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-c", 2)) {
2880ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            channels = atoi(&arg[2]);
2890ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            if (channels < 1 || channels > 2) {
2900ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                fprintf(stderr, "%s: unusual channel count ignored (%u)\n", argv[0],
2910ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) channels);
2920ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                channels = 2;
2930ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            }
2940ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        // -s# sample rate in Hz
2950ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-s", 2)) {
2960ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            sampleRate = atoi(&arg[2]);
2970ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            switch (sampleRate) {
2980ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 8000:
2990ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 11025:
3007126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            case 12000:
3010ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 16000:
3020ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 22050:
3037126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            case 24000:
3040ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 32000:
3050ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 44100:
3067126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            case 48000:
3070ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                break;
3080ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            default:
3090ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                fprintf(stderr, "%s: unusual sample rate (%u Hz)\n", argv[0],
3100ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) sampleRate);
3110ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                break;
3120ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            }
3137126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // -e# exit after this many seconds
3147126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        } else if (!strncmp(arg, "-e", 2)) {
3157126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            exitAfterSeconds = atoi(&arg[2]);
31685079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        // -ofile log to output file also
31785079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        } else if (!strncmp(arg, "-o", 2)) {
31885079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten            outFileName = &arg[2];
31985079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        // -i# inject an impulse after # milliseconds
32085079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        } else if (!strncmp(arg, "-i", 2)) {
32185079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten            injectImpulse = atoi(&arg[2]);
3220ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else
3230ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            fprintf(stderr, "%s: unknown option %s\n", argv[0], arg);
3240ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    }
3257126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // no other arguments allowed
3260ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    if (i < argc) {
32785079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        fprintf(stderr, "usage: %s -r# -t# -f# -s# -c# -i# -ofile\n", argv[0]);
3280ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -r# receive buffer queue count for microphone input, default 1\n");
3290ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -t# transmit buffer queue count for speaker output, default 2\n");
3300ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -f# number of frames per buffer, default 512\n");
3310ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -s# sample rate in Hz, default 44100\n");
3320ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -c1 mono\n");
3330ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -c2 stereo, default\n");
33485079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        fprintf(stderr, "  -i# inject impulse after # milliseconds\n");
33585079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        fprintf(stderr, "  -ofile log input to specified .wav file also\n");
3360ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    }
33785079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten
3387126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // compute total free buffers as -r plus -t
3397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeBufCount = rxBufCount + txBufCount;
3407126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // compute buffer size
3410ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    bufSizeInBytes = channels * bufSizeInFrames * sizeof(short);
3427126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
3437126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Initialize free buffers
3447126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeBuffers = (char **) calloc(freeBufCount+1, sizeof(char *));
3457126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    unsigned j;
3467126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    for (j = 0; j < freeBufCount; ++j) {
3477126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        freeBuffers[j] = (char *) malloc(bufSizeInBytes);
3487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
3497126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeFront = 0;
3507126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeRear = freeBufCount;
3517126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeBuffers[j] = NULL;
3527126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
3537126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Initialize record queue
3547126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    rxBuffers = (char **) calloc(rxBufCount+1, sizeof(char *));
3557126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    rxFront = 0;
3567126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    rxRear = 0;
3577126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
3587126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Initialize play queue
3597126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    txBuffers = (char **) calloc(txBufCount+1, sizeof(char *));
3607126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    txFront = 0;
3617126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    txRear = 0;
3627126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
3636e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten    size_t frameSize = channels * sizeof(short);
3646e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten#define FIFO_FRAMES 1024
3656e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten    short *fifoBuffer = new short[FIFO_FRAMES * channels];
3666e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten    audio_utils_fifo_init(&fifo, FIFO_FRAMES, frameSize, fifoBuffer);
367fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
36885079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    SNDFILE *sndfile;
36985079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    if (outFileName != NULL) {
37085079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        // create .wav writer
37185079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        SF_INFO info;
37285079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        info.frames = 0;
37385079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        info.samplerate = sampleRate;
37485079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        info.channels = channels;
37585079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
37685079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        sndfile = sf_open(outFileName, SFM_WRITE, &info);
37785079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        if (sndfile != NULL) {
3786e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten#define FIFO2_FRAMES 65536
3796e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten            fifo2Buffer = new short[FIFO2_FRAMES * channels];
3806e55f367758180f2f76694f9dcfbbab269a25162Glenn Kasten            audio_utils_fifo_init(&fifo2, FIFO2_FRAMES, frameSize, fifo2Buffer);
38185079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        } else {
38285079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten            fprintf(stderr, "sf_open failed\n");
38385079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        }
38485079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    } else {
38585079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten        sndfile = NULL;
38685079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten    }
38785079ea0cc7592029762b7c44a6def84c43bebb0Glenn Kasten
388f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLresult result;
389f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
390f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // create engine
391f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLObjectItf engineObject;
392f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
393f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
394f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
395f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
396f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLEngineItf engineEngine;
397f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
398f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
399f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
400f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // create output mix
401f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLObjectItf outputmixObject;
402f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL);
403f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
404f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE);
405f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
406f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
407f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // create an audio player with buffer queue source and output mix sink
408f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataSource audiosrc;
409f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataSink audiosnk;
410f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataFormat_PCM pcm;
411f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataLocator_OutputMix locator_outputmix;
41201e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLDataLocator_BufferQueue locator_bufferqueue_tx;
41301e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
41401e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_tx.numBuffers = txBufCount;
415f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
416f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_outputmix.outputMix = outputmixObject;
417f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.formatType = SL_DATAFORMAT_PCM;
4180ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    pcm.numChannels = channels;
4190ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    pcm.samplesPerSec = sampleRate * 1000;
420f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
421f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.containerSize = 16;
4220ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    pcm.channelMask = channels == 1 ? SL_SPEAKER_FRONT_CENTER :
4230ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
424f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
42501e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    audiosrc.pLocator = &locator_bufferqueue_tx;
426f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosrc.pFormat = &pcm;
427f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosnk.pLocator = &locator_outputmix;
428f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosnk.pFormat = NULL;
4297126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    SLObjectItf playerObject = NULL;
4307126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    SLObjectItf recorderObject = NULL;
43101e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE};
43201e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE};
4330ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk,
43401e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten        1, ids_tx, flags_tx);
4357126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
43658432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten        fprintf(stderr, "Could not create audio player (result %x), check sample rate\n", result);
4377126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        goto cleanup;
4387126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
439f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
440f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
441f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
442f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLPlayItf playerPlay;
443f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
444f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
445f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue);
446f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
4477126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, playerCallback, NULL);
4487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
449fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
450fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Enqueue some zero buffers for the player
451fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    for (j = 0; j < txBufCount; ++j) {
452fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
453fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        // allocate a free buffer
454fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        assert(freeFront != freeRear);
455fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        char *buffer = freeBuffers[freeFront];
456fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        if (++freeFront > freeBufCount) {
457fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten            freeFront = 0;
458fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        }
459fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
460fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        // put on play queue
461fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        SLuint32 txRearNext = txRear + 1;
462fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        if (txRearNext > txBufCount) {
463fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten            txRearNext = 0;
464fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        }
465fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        assert(txRearNext != txFront);
466fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        txBuffers[txRear] = buffer;
467fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        txRear = txRearNext;
468fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        result = (*playerBufferQueue)->Enqueue(playerBufferQueue,
469fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten            buffer, bufSizeInBytes);
470fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
471fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
472fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
473f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
474f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
475f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
476f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Create an audio recorder with microphone device source and buffer queue sink.
477f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // The buffer queue as sink is an Android-specific extension.
478f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
479f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataLocator_IODevice locator_iodevice;
48001e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
481f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
482f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
483f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
484f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.device = NULL;
485f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosrc.pLocator = &locator_iodevice;
48635c82a8173d1fcc18ae0bc08954a018bfce041deGlenn Kasten    audiosrc.pFormat = NULL;
48701e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
48801e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_rx.numBuffers = rxBufCount;
48901e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    audiosnk.pLocator = &locator_bufferqueue_rx;
490f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosnk.pFormat = &pcm;
4917126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    {
49201e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLInterfaceID ids_rx[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
49301e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLboolean flags_rx[1] = {SL_BOOLEAN_TRUE};
4940ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audiosrc,
49501e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten        &audiosnk, 1, ids_rx, flags_rx);
4967126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (SL_RESULT_SUCCESS != result) {
49758432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten        fprintf(stderr, "Could not create audio recorder (result %x), "
4987126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten                "check sample rate and channel count\n", result);
4997126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        goto cleanup;
5007126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
5017126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
502f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
503f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
504f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
505f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLRecordItf recorderRecord;
506f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
507f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
50801e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
5090ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        &recorderBufferQueue);
510f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
511f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, recorderCallback, NULL);
512f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
513f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
514f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Enqueue some empty buffers for the recorder
5157126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    for (j = 0; j < rxBufCount; ++j) {
5167126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
5177126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // allocate a free buffer
5187126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeFront != freeRear);
5197126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        char *buffer = freeBuffers[freeFront];
5207126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (++freeFront > freeBufCount) {
5217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            freeFront = 0;
5227126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
5237126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
5247126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // put on record queue
5257126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 rxRearNext = rxRear + 1;
5267126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (rxRearNext > rxBufCount) {
5277126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            rxRearNext = 0;
5287126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
5297126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRearNext != rxFront);
5307126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxBuffers[rxRear] = buffer;
531