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
30fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#include <media/nbaio/MonoPipe.h>
31fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#include <media/nbaio/MonoPipeReader.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
64fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kastenstatic android::MonoPipeReader *pipeReader;
65fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kastenstatic android::MonoPipe *pipeWriter;
66fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
677126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Called after audio recorder fills a buffer with data
687126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic void recorderCallback(SLAndroidSimpleBufferQueueItf caller, void *context)
690ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten{
707126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    SLresult result;
717126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
727126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_lock(&mutex);
737126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
747126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // We should only be called when a recording buffer is done
757126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(rxFront <= rxBufCount);
767126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(rxRear <= rxBufCount);
777126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(rxFront != rxRear);
787126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    char *buffer = rxBuffers[rxFront];
797126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
807126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Remove buffer from record queue
817126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (++rxFront > rxBufCount) {
827126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxFront = 0;
837126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
847126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
85fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#if 1
86fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    ssize_t actual = pipeWriter->write(buffer, (size_t) bufSizeInFrames);
87fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    if (actual != (ssize_t) bufSizeInFrames) {
88fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        write(1, "?", 1);
89fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
90fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
91fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Enqueue this same buffer for the recorder to fill again.
92fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
93fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
94fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
95fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Update our model of the record queue
96fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    SLuint32 rxRearNext = rxRear+1;
97fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    if (rxRearNext > rxBufCount) {
98fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        rxRearNext = 0;
99fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
100fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(rxRearNext != rxFront);
101fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    rxBuffers[rxRear] = buffer;
102fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    rxRear = rxRearNext;
103fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
104fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#else
1057126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Enqueue the just-filled buffer for the player
1067126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
1077126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (SL_RESULT_SUCCESS == result) {
1087126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1097126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // There was room in the play queue, update our model of it
1107126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(txFront <= txBufCount);
1117126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(txRear <= txBufCount);
1127126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 txRearNext = txRear+1;
1137126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (txRearNext > txBufCount) {
1147126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            txRearNext = 0;
1157126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
1167126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(txRearNext != txFront);
1177126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        txBuffers[txRear] = buffer;
1187126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        txRear = txRearNext;
1197126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1207126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    } else {
1217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1227126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Here if record has a filled buffer to play, but play queue is full.
1237126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
1247126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        write(1, "?", 1);
1257126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1267126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // We could either try again later, or discard. For now we discard and re-use buffer.
1277126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Enqueue this same buffer for the recorder to fill again.
1287126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
1297126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
1307126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1317126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Update our model of the record queue
1327126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 rxRearNext = rxRear+1;
1337126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (rxRearNext > rxBufCount) {
1347126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            rxRearNext = 0;
1357126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
1367126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRearNext != rxFront);
1377126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxBuffers[rxRear] = buffer;
1387126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxRear = rxRearNext;
1397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1407126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
141fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#endif
1427126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1437126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_unlock(&mutex);
1440ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten}
1450ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten
1467126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1477126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Called after audio player empties a buffer of data
1487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastenstatic void playerCallback(SLBufferQueueItf caller, void *context)
149f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten{
150f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLresult result;
1517126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1527126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_lock(&mutex);
1537126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1547126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Get the buffer that just finished playing
1557126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(txFront <= txBufCount);
1567126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(txRear <= txBufCount);
1577126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    assert(txFront != txRear);
1587126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    char *buffer = txBuffers[txFront];
1597126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (++txFront > txBufCount) {
1607126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        txFront = 0;
161e5d006b298ce7683d66f7ec86136403cf5fb20d6Glenn Kasten    }
162f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
163fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#if 1
164fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    ssize_t actual = pipeReader->read(buffer, bufSizeInFrames, (int64_t) -1);
165fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    if (actual != (ssize_t) bufSizeInFrames) {
166fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        write(1, "/", 1);
167fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        // on underrun from pipe, substitute silence
168fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        memset(buffer, 0, bufSizeInFrames * channels * sizeof(short));
169fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
170fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
171fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Enqueue the filled buffer for playing
172fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
173fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
174fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
175fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Update our model of the player queue
176fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(txFront <= txBufCount);
177fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(txRear <= txBufCount);
178fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    SLuint32 txRearNext = txRear+1;
179fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    if (txRearNext > txBufCount) {
180fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        txRearNext = 0;
181fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
182fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(txRearNext != txFront);
183fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    txBuffers[txRear] = buffer;
184fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    txRear = txRearNext;
185fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
186fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#else
1877126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // First try to enqueue the free buffer for recording
1880ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
1895ef8af762b27b4fa45f59d944b11ad00311cb14bGlenn Kasten    if (SL_RESULT_SUCCESS == result) {
1907126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
1917126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // There was room in the record queue, update our model of it
1927126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxFront <= rxBufCount);
1937126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRear <= rxBufCount);
1947126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 rxRearNext = rxRear+1;
1957126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (rxRearNext > rxBufCount) {
1967126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            rxRearNext = 0;
1977126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
1987126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRearNext != rxFront);
1997126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxBuffers[rxRear] = buffer;
2007126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxRear = rxRearNext;
2017126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2020ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    } else {
2037126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2047126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Here if record queue is full
2057126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
2067126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2077126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // Instead enqueue the free buffer on the free queue
2087126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeFront <= freeBufCount);
2097126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeRear <= freeBufCount);
2107126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 freeRearNext = freeRear+1;
2117126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (freeRearNext > freeBufCount) {
2127126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            freeRearNext = 0;
2137126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
2147126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // There must always be room in the free queue
2157126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeRearNext != freeFront);
2167126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        freeBuffers[freeRear] = buffer;
2177126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        freeRear = freeRearNext;
2187126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
2195ef8af762b27b4fa45f59d944b11ad00311cb14bGlenn Kasten    }
220fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#endif
221f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
2227126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    pthread_mutex_unlock(&mutex);
223f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten}
224f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
2257126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten// Main program
226f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kastenint main(int argc, char **argv)
227f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten{
2280ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    // process command-line options
2290ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    int i;
2300ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    for (i = 1; i < argc; ++i) {
2310ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        char *arg = argv[i];
2327126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (arg[0] != '-') {
2330ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            break;
2347126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
2357126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // -r# number of slots in receive buffer queue
2360ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        if (!strncmp(arg, "-r", 2)) {
2370ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            rxBufCount = atoi(&arg[2]);
2387126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            if (rxBufCount < 1 || rxBufCount > 16) {
2397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten                fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)\n", argv[0],
2400ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) rxBufCount);
2417126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            }
2427126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // -t# number of slots in transmit buffer queue
2430ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-t", 2)) {
2440ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            txBufCount = atoi(&arg[2]);
2457126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            if (txBufCount < 1 || txBufCount > 16) {
2467126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten                fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)\n", argv[0],
2470ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) txBufCount);
2487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            }
2490ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        // -f# size of each buffer in frames
2500ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-f", 2)) {
2510ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            bufSizeInFrames = atoi(&arg[2]);
2520ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            if (bufSizeInFrames == 0) {
2530ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                fprintf(stderr, "%s: unusual buffer size (%u frames)\n", argv[0],
2540ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) bufSizeInFrames);
2550ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            }
2560ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        // -c1 mono or -c2 stereo
2570ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-c", 2)) {
2580ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            channels = atoi(&arg[2]);
2590ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            if (channels < 1 || channels > 2) {
2600ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                fprintf(stderr, "%s: unusual channel count ignored (%u)\n", argv[0],
2610ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) channels);
2620ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                channels = 2;
2630ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            }
2640ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        // -s# sample rate in Hz
2650ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else if (!strncmp(arg, "-s", 2)) {
2660ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            sampleRate = atoi(&arg[2]);
2670ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            switch (sampleRate) {
2680ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 8000:
2690ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 11025:
2707126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            case 12000:
2710ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 16000:
2720ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 22050:
2737126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            case 24000:
2740ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 32000:
2750ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            case 44100:
2767126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            case 48000:
2770ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                break;
2780ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            default:
2790ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                fprintf(stderr, "%s: unusual sample rate (%u Hz)\n", argv[0],
2800ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                    (unsigned) sampleRate);
2810ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten                break;
2820ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            }
2837126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // -e# exit after this many seconds
2847126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        } else if (!strncmp(arg, "-e", 2)) {
2857126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            exitAfterSeconds = atoi(&arg[2]);
2860ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        } else
2870ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten            fprintf(stderr, "%s: unknown option %s\n", argv[0], arg);
2880ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    }
2897126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // no other arguments allowed
2900ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    if (i < argc) {
2917126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        fprintf(stderr, "usage: %s -r# -t# -f# -s# -c#\n", argv[0]);
2920ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -r# receive buffer queue count for microphone input, default 1\n");
2930ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -t# transmit buffer queue count for speaker output, default 2\n");
2940ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -f# number of frames per buffer, default 512\n");
2950ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -s# sample rate in Hz, default 44100\n");
2960ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -c1 mono\n");
2970ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        fprintf(stderr, "  -c2 stereo, default\n");
2980ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    }
2997126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // compute total free buffers as -r plus -t
3007126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeBufCount = rxBufCount + txBufCount;
3017126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // compute buffer size
3020ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    bufSizeInBytes = channels * bufSizeInFrames * sizeof(short);
3037126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
3047126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Initialize free buffers
3057126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeBuffers = (char **) calloc(freeBufCount+1, sizeof(char *));
3067126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    unsigned j;
3077126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    for (j = 0; j < freeBufCount; ++j) {
3087126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        freeBuffers[j] = (char *) malloc(bufSizeInBytes);
3097126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
3107126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeFront = 0;
3117126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeRear = freeBufCount;
3127126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    freeBuffers[j] = NULL;
3137126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
3147126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Initialize record queue
3157126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    rxBuffers = (char **) calloc(rxBufCount+1, sizeof(char *));
3167126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    rxFront = 0;
3177126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    rxRear = 0;
3187126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
3197126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Initialize play queue
3207126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    txBuffers = (char **) calloc(txBufCount+1, sizeof(char *));
3217126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    txFront = 0;
3227126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    txRear = 0;
3237126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
324fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    const android::NBAIO_Format nbaio_format = android::Format_from_SR_C(sampleRate, channels,
325fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten            AUDIO_FORMAT_PCM_16_BIT);
326fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    pipeWriter = new android::MonoPipe(1024, nbaio_format, false /*writeCanBlock*/);
327fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    android::NBAIO_Format offer = nbaio_format;
328fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    size_t numCounterOffers = 0;
329fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    ssize_t neg = pipeWriter->negotiate(&offer, 1, NULL, numCounterOffers);
330fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(0 == neg);
331fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    pipeReader = new android::MonoPipeReader(pipeWriter);
332fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    numCounterOffers = 0;
333fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    neg = pipeReader->negotiate(&offer, 1, NULL, numCounterOffers);
334fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    assert(0 == neg);
335fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
336f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLresult result;
337f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
338f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // create engine
339f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLObjectItf engineObject;
340f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
341f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
342f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
343f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
344f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLEngineItf engineEngine;
345f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
346f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
347f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
348f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // create output mix
349f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLObjectItf outputmixObject;
350f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL);
351f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
352f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE);
353f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
354f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
355f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // create an audio player with buffer queue source and output mix sink
356f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataSource audiosrc;
357f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataSink audiosnk;
358f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataFormat_PCM pcm;
359f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataLocator_OutputMix locator_outputmix;
36001e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLDataLocator_BufferQueue locator_bufferqueue_tx;
36101e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
36201e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_tx.numBuffers = txBufCount;
363f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
364f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_outputmix.outputMix = outputmixObject;
365f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.formatType = SL_DATAFORMAT_PCM;
3660ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    pcm.numChannels = channels;
3670ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    pcm.samplesPerSec = sampleRate * 1000;
368f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
369f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.containerSize = 16;
3700ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    pcm.channelMask = channels == 1 ? SL_SPEAKER_FRONT_CENTER :
3710ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
372f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
37301e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    audiosrc.pLocator = &locator_bufferqueue_tx;
374f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosrc.pFormat = &pcm;
375f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosnk.pLocator = &locator_outputmix;
376f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosnk.pFormat = NULL;
3777126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    SLObjectItf playerObject = NULL;
3787126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    SLObjectItf recorderObject = NULL;
37901e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE};
38001e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE};
3810ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk,
38201e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten        1, ids_tx, flags_tx);
3837126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
38458432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten        fprintf(stderr, "Could not create audio player (result %x), check sample rate\n", result);
3857126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        goto cleanup;
3867126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
387f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
388f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
389f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
390f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLPlayItf playerPlay;
391f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
392f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
393f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue);
394f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
3957126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, playerCallback, NULL);
3967126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
397fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
398fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // Enqueue some zero buffers for the player
399fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    for (j = 0; j < txBufCount; ++j) {
400fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
401fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        // allocate a free buffer
402fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        assert(freeFront != freeRear);
403fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        char *buffer = freeBuffers[freeFront];
404fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        if (++freeFront > freeBufCount) {
405fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten            freeFront = 0;
406fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        }
407fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
408fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        // put on play queue
409fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        SLuint32 txRearNext = txRear + 1;
410fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        if (txRearNext > txBufCount) {
411fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten            txRearNext = 0;
412fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        }
413fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        assert(txRearNext != txFront);
414fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        txBuffers[txRear] = buffer;
415fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        txRear = txRearNext;
416fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        result = (*playerBufferQueue)->Enqueue(playerBufferQueue,
417fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten            buffer, bufSizeInBytes);
418fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
419fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    }
420fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
421f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
422f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
423f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
424f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Create an audio recorder with microphone device source and buffer queue sink.
425f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // The buffer queue as sink is an Android-specific extension.
426f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
427f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLDataLocator_IODevice locator_iodevice;
42801e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
429f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
430f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
431f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
432f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    locator_iodevice.device = NULL;
433f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosrc.pLocator = &locator_iodevice;
43435c82a8173d1fcc18ae0bc08954a018bfce041deGlenn Kasten    audiosrc.pFormat = NULL;
43501e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
43601e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    locator_bufferqueue_rx.numBuffers = rxBufCount;
43701e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    audiosnk.pLocator = &locator_bufferqueue_rx;
438f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    audiosnk.pFormat = &pcm;
4397126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    {
44001e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLInterfaceID ids_rx[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
44101e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    SLboolean flags_rx[1] = {SL_BOOLEAN_TRUE};
4420ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten    result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audiosrc,
44301e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten        &audiosnk, 1, ids_rx, flags_rx);
4447126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (SL_RESULT_SUCCESS != result) {
44558432eb9cea995c69b4f905e68b38c1b8216edebGlenn Kasten        fprintf(stderr, "Could not create audio recorder (result %x), "
4467126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten                "check sample rate and channel count\n", result);
4477126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        goto cleanup;
4487126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
4497126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
450f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
451f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
452f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
453f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    SLRecordItf recorderRecord;
454f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
455f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
45601e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten    result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
4570ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        &recorderBufferQueue);
458f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
459f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, recorderCallback, NULL);
460f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
461f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
462f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Enqueue some empty buffers for the recorder
4637126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    for (j = 0; j < rxBufCount; ++j) {
4647126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
4657126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // allocate a free buffer
4667126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(freeFront != freeRear);
4677126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        char *buffer = freeBuffers[freeFront];
4687126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (++freeFront > freeBufCount) {
4697126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            freeFront = 0;
4707126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
4717126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
4727126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        // put on record queue
4737126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        SLuint32 rxRearNext = rxRear + 1;
4747126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        if (rxRearNext > rxBufCount) {
4757126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            rxRearNext = 0;
4767126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        }
4777126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        assert(rxRearNext != rxFront);
4787126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxBuffers[rxRear] = buffer;
4797126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        rxRear = rxRearNext;
4800ac2a7d4343d98e3cb02180e548a5a4737ba0df1Glenn Kasten        result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue,
4817126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten            buffer, bufSizeInBytes);
482f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
483f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    }
484f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
485f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Kick off the recorder
486f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
487f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    ASSERT_EQ(SL_RESULT_SUCCESS, result);
488f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
489fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#if 0
490fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    // give recorder a head start so that the pipe is initially filled
491fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten    sleep(1);
492fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten#endif
493fdef5de17abc6c30b293861ca276259a7dd93837Glenn Kasten
494f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    // Wait patiently
4957126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    do {
496f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        usleep(1000000);
4977126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        write(1, ".", 1);
498f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        SLBufferQueueState playerBQState;
499f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        result = (*playerBufferQueue)->GetState(playerBufferQueue, &playerBQState);
500f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
50101e9f5fa4698856f92bcfd88188ee4c8397b22dbGlenn Kasten        SLAndroidSimpleBufferQueueState recorderBQState;
502f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &recorderBQState);
503f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten        ASSERT_EQ(SL_RESULT_SUCCESS, result);
5047126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    } while (--exitAfterSeconds);
5057126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten
5067126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    // Tear down the objects and exit
5077126c25d7c037e5086216cf540ecf40779c3585aGlenn Kastencleanup:
5087126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (NULL != playerObject) {
5097126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        (*playerObject)->Destroy(playerObject);
5107126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    }
5117126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    if (NULL != recorderObject) {
5127126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten        (*recorderObject)->Destroy(recorderObject);
513f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten    }
5147126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    (*outputmixObject)->Destroy(outputmixObject);
5157126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    (*engineObject)->Destroy(engineObject);
516f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten
5177126c25d7c037e5086216cf540ecf40779c3585aGlenn Kasten    return EXIT_SUCCESS;
518f460ec604707d0bdaf8124d84c5f8595cba9c804Glenn Kasten}
519