xref: /aosp_15_r20/frameworks/wilhelm/tests/examples/slesTestFeedback.cpp (revision bebae9c0e76121f8312ccb50385c080b3a0b023c)
1*bebae9c0SAndroid Build Coastguard Worker /*
2*bebae9c0SAndroid Build Coastguard Worker  * Copyright (C) 2010 The Android Open Source Project
3*bebae9c0SAndroid Build Coastguard Worker  *
4*bebae9c0SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*bebae9c0SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*bebae9c0SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*bebae9c0SAndroid Build Coastguard Worker  *
8*bebae9c0SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*bebae9c0SAndroid Build Coastguard Worker  *
10*bebae9c0SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*bebae9c0SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*bebae9c0SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*bebae9c0SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*bebae9c0SAndroid Build Coastguard Worker  * limitations under the License.
15*bebae9c0SAndroid Build Coastguard Worker  */
16*bebae9c0SAndroid Build Coastguard Worker 
17*bebae9c0SAndroid Build Coastguard Worker // Test program to record from default audio input and playback to default audio output.
18*bebae9c0SAndroid Build Coastguard Worker // It will generate feedback (Larsen effect) if played through on-device speakers,
19*bebae9c0SAndroid Build Coastguard Worker // or acts as a delay if played through headset.
20*bebae9c0SAndroid Build Coastguard Worker 
21*bebae9c0SAndroid Build Coastguard Worker #include <SLES/OpenSLES.h>
22*bebae9c0SAndroid Build Coastguard Worker #include <SLES/OpenSLES_Android.h>
23*bebae9c0SAndroid Build Coastguard Worker #include <assert.h>
24*bebae9c0SAndroid Build Coastguard Worker #include <pthread.h>
25*bebae9c0SAndroid Build Coastguard Worker #include <stdio.h>
26*bebae9c0SAndroid Build Coastguard Worker #include <stdlib.h>
27*bebae9c0SAndroid Build Coastguard Worker #include <string.h>
28*bebae9c0SAndroid Build Coastguard Worker #include <unistd.h>
29*bebae9c0SAndroid Build Coastguard Worker 
30*bebae9c0SAndroid Build Coastguard Worker #include <audio_utils/fifo.h>
31*bebae9c0SAndroid Build Coastguard Worker #include <audio_utils/sndfile.h>
32*bebae9c0SAndroid Build Coastguard Worker 
33*bebae9c0SAndroid Build Coastguard Worker #define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \
34*bebae9c0SAndroid Build Coastguard Worker     (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0)
35*bebae9c0SAndroid Build Coastguard Worker 
36*bebae9c0SAndroid Build Coastguard Worker // default values
37*bebae9c0SAndroid Build Coastguard Worker static SLuint32 rxBufCount = 2;     // -r#
38*bebae9c0SAndroid Build Coastguard Worker static SLuint32 txBufCount = 2;     // -t#
39*bebae9c0SAndroid Build Coastguard Worker static SLuint32 bufSizeInFrames = 240;  // -f#
40*bebae9c0SAndroid Build Coastguard Worker static SLuint32 channels = 1;       // -c#
41*bebae9c0SAndroid Build Coastguard Worker static SLuint32 sampleRate = 48000; // -s#
42*bebae9c0SAndroid Build Coastguard Worker static SLuint32 exitAfterSeconds = 60; // -e#
43*bebae9c0SAndroid Build Coastguard Worker static SLuint32 freeBufCount = 0;   // calculated
44*bebae9c0SAndroid Build Coastguard Worker static SLuint32 bufSizeInBytes = 0; // calculated
45*bebae9c0SAndroid Build Coastguard Worker 
46*bebae9c0SAndroid Build Coastguard Worker // Storage area for the buffer queues
47*bebae9c0SAndroid Build Coastguard Worker static char **rxBuffers;
48*bebae9c0SAndroid Build Coastguard Worker static char **txBuffers;
49*bebae9c0SAndroid Build Coastguard Worker static char **freeBuffers;
50*bebae9c0SAndroid Build Coastguard Worker 
51*bebae9c0SAndroid Build Coastguard Worker // Buffer indices
52*bebae9c0SAndroid Build Coastguard Worker static SLuint32 rxFront;    // oldest recording
53*bebae9c0SAndroid Build Coastguard Worker static SLuint32 rxRear;     // next to be recorded
54*bebae9c0SAndroid Build Coastguard Worker static SLuint32 txFront;    // oldest playing
55*bebae9c0SAndroid Build Coastguard Worker static SLuint32 txRear;     // next to be played
56*bebae9c0SAndroid Build Coastguard Worker static SLuint32 freeFront;  // oldest free
57*bebae9c0SAndroid Build Coastguard Worker static SLuint32 freeRear;   // next to be freed
58*bebae9c0SAndroid Build Coastguard Worker 
59*bebae9c0SAndroid Build Coastguard Worker static SLAndroidSimpleBufferQueueItf recorderBufferQueue;
60*bebae9c0SAndroid Build Coastguard Worker static SLBufferQueueItf playerBufferQueue;
61*bebae9c0SAndroid Build Coastguard Worker 
62*bebae9c0SAndroid Build Coastguard Worker static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
63*bebae9c0SAndroid Build Coastguard Worker 
64*bebae9c0SAndroid Build Coastguard Worker static audio_utils_fifo *fifo;
65*bebae9c0SAndroid Build Coastguard Worker static audio_utils_fifo_reader *fifoReader;
66*bebae9c0SAndroid Build Coastguard Worker static audio_utils_fifo_writer *fifoWriter;
67*bebae9c0SAndroid Build Coastguard Worker 
68*bebae9c0SAndroid Build Coastguard Worker static audio_utils_fifo *fifo2;
69*bebae9c0SAndroid Build Coastguard Worker static short *fifo2Buffer = NULL;
70*bebae9c0SAndroid Build Coastguard Worker static audio_utils_fifo_reader *fifo2Reader;
71*bebae9c0SAndroid Build Coastguard Worker static audio_utils_fifo_writer *fifo2Writer;
72*bebae9c0SAndroid Build Coastguard Worker 
73*bebae9c0SAndroid Build Coastguard Worker static int injectImpulse;
74*bebae9c0SAndroid Build Coastguard Worker 
75*bebae9c0SAndroid Build Coastguard Worker // Called after audio recorder fills a buffer with data
recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused,void * context __unused)76*bebae9c0SAndroid Build Coastguard Worker static void recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused, void *context __unused)
77*bebae9c0SAndroid Build Coastguard Worker {
78*bebae9c0SAndroid Build Coastguard Worker     SLresult result;
79*bebae9c0SAndroid Build Coastguard Worker 
80*bebae9c0SAndroid Build Coastguard Worker     pthread_mutex_lock(&mutex);
81*bebae9c0SAndroid Build Coastguard Worker 
82*bebae9c0SAndroid Build Coastguard Worker     // We should only be called when a recording buffer is done
83*bebae9c0SAndroid Build Coastguard Worker     assert(rxFront <= rxBufCount);
84*bebae9c0SAndroid Build Coastguard Worker     assert(rxRear <= rxBufCount);
85*bebae9c0SAndroid Build Coastguard Worker     assert(rxFront != rxRear);
86*bebae9c0SAndroid Build Coastguard Worker     char *buffer = rxBuffers[rxFront];
87*bebae9c0SAndroid Build Coastguard Worker 
88*bebae9c0SAndroid Build Coastguard Worker     // Remove buffer from record queue
89*bebae9c0SAndroid Build Coastguard Worker     if (++rxFront > rxBufCount) {
90*bebae9c0SAndroid Build Coastguard Worker         rxFront = 0;
91*bebae9c0SAndroid Build Coastguard Worker     }
92*bebae9c0SAndroid Build Coastguard Worker 
93*bebae9c0SAndroid Build Coastguard Worker #if 1
94*bebae9c0SAndroid Build Coastguard Worker     ssize_t actual = fifoWriter->write(buffer, (size_t) bufSizeInFrames);
95*bebae9c0SAndroid Build Coastguard Worker     if (actual != (ssize_t) bufSizeInFrames) {
96*bebae9c0SAndroid Build Coastguard Worker         write(1, "?", 1);
97*bebae9c0SAndroid Build Coastguard Worker     }
98*bebae9c0SAndroid Build Coastguard Worker 
99*bebae9c0SAndroid Build Coastguard Worker     // This is called by a realtime (SCHED_FIFO) thread,
100*bebae9c0SAndroid Build Coastguard Worker     // and it is unsafe to do I/O as it could block for unbounded time.
101*bebae9c0SAndroid Build Coastguard Worker     // Flash filesystem is especially notorious for blocking.
102*bebae9c0SAndroid Build Coastguard Worker     if (fifo2Buffer != NULL) {
103*bebae9c0SAndroid Build Coastguard Worker         actual = fifo2Writer->write(buffer, (size_t) bufSizeInFrames);
104*bebae9c0SAndroid Build Coastguard Worker         if (actual != (ssize_t) bufSizeInFrames) {
105*bebae9c0SAndroid Build Coastguard Worker             write(1, "?", 1);
106*bebae9c0SAndroid Build Coastguard Worker         }
107*bebae9c0SAndroid Build Coastguard Worker     }
108*bebae9c0SAndroid Build Coastguard Worker 
109*bebae9c0SAndroid Build Coastguard Worker     // Enqueue this same buffer for the recorder to fill again.
110*bebae9c0SAndroid Build Coastguard Worker     result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
111*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
112*bebae9c0SAndroid Build Coastguard Worker 
113*bebae9c0SAndroid Build Coastguard Worker     // Update our model of the record queue
114*bebae9c0SAndroid Build Coastguard Worker     SLuint32 rxRearNext = rxRear+1;
115*bebae9c0SAndroid Build Coastguard Worker     if (rxRearNext > rxBufCount) {
116*bebae9c0SAndroid Build Coastguard Worker         rxRearNext = 0;
117*bebae9c0SAndroid Build Coastguard Worker     }
118*bebae9c0SAndroid Build Coastguard Worker     assert(rxRearNext != rxFront);
119*bebae9c0SAndroid Build Coastguard Worker     rxBuffers[rxRear] = buffer;
120*bebae9c0SAndroid Build Coastguard Worker     rxRear = rxRearNext;
121*bebae9c0SAndroid Build Coastguard Worker 
122*bebae9c0SAndroid Build Coastguard Worker #else
123*bebae9c0SAndroid Build Coastguard Worker     // Enqueue the just-filled buffer for the player
124*bebae9c0SAndroid Build Coastguard Worker     result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
125*bebae9c0SAndroid Build Coastguard Worker     if (SL_RESULT_SUCCESS == result) {
126*bebae9c0SAndroid Build Coastguard Worker 
127*bebae9c0SAndroid Build Coastguard Worker         // There was room in the play queue, update our model of it
128*bebae9c0SAndroid Build Coastguard Worker         assert(txFront <= txBufCount);
129*bebae9c0SAndroid Build Coastguard Worker         assert(txRear <= txBufCount);
130*bebae9c0SAndroid Build Coastguard Worker         SLuint32 txRearNext = txRear+1;
131*bebae9c0SAndroid Build Coastguard Worker         if (txRearNext > txBufCount) {
132*bebae9c0SAndroid Build Coastguard Worker             txRearNext = 0;
133*bebae9c0SAndroid Build Coastguard Worker         }
134*bebae9c0SAndroid Build Coastguard Worker         assert(txRearNext != txFront);
135*bebae9c0SAndroid Build Coastguard Worker         txBuffers[txRear] = buffer;
136*bebae9c0SAndroid Build Coastguard Worker         txRear = txRearNext;
137*bebae9c0SAndroid Build Coastguard Worker 
138*bebae9c0SAndroid Build Coastguard Worker     } else {
139*bebae9c0SAndroid Build Coastguard Worker 
140*bebae9c0SAndroid Build Coastguard Worker         // Here if record has a filled buffer to play, but play queue is full.
141*bebae9c0SAndroid Build Coastguard Worker         assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
142*bebae9c0SAndroid Build Coastguard Worker         write(1, "?", 1);
143*bebae9c0SAndroid Build Coastguard Worker 
144*bebae9c0SAndroid Build Coastguard Worker         // We could either try again later, or discard. For now we discard and re-use buffer.
145*bebae9c0SAndroid Build Coastguard Worker         // Enqueue this same buffer for the recorder to fill again.
146*bebae9c0SAndroid Build Coastguard Worker         result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
147*bebae9c0SAndroid Build Coastguard Worker         ASSERT_EQ(SL_RESULT_SUCCESS, result);
148*bebae9c0SAndroid Build Coastguard Worker 
149*bebae9c0SAndroid Build Coastguard Worker         // Update our model of the record queue
150*bebae9c0SAndroid Build Coastguard Worker         SLuint32 rxRearNext = rxRear+1;
151*bebae9c0SAndroid Build Coastguard Worker         if (rxRearNext > rxBufCount) {
152*bebae9c0SAndroid Build Coastguard Worker             rxRearNext = 0;
153*bebae9c0SAndroid Build Coastguard Worker         }
154*bebae9c0SAndroid Build Coastguard Worker         assert(rxRearNext != rxFront);
155*bebae9c0SAndroid Build Coastguard Worker         rxBuffers[rxRear] = buffer;
156*bebae9c0SAndroid Build Coastguard Worker         rxRear = rxRearNext;
157*bebae9c0SAndroid Build Coastguard Worker 
158*bebae9c0SAndroid Build Coastguard Worker     }
159*bebae9c0SAndroid Build Coastguard Worker #endif
160*bebae9c0SAndroid Build Coastguard Worker 
161*bebae9c0SAndroid Build Coastguard Worker     pthread_mutex_unlock(&mutex);
162*bebae9c0SAndroid Build Coastguard Worker }
163*bebae9c0SAndroid Build Coastguard Worker 
164*bebae9c0SAndroid Build Coastguard Worker 
165*bebae9c0SAndroid Build Coastguard Worker // Called after audio player empties a buffer of data
playerCallback(SLBufferQueueItf caller __unused,void * context __unused)166*bebae9c0SAndroid Build Coastguard Worker static void playerCallback(SLBufferQueueItf caller __unused, void *context __unused)
167*bebae9c0SAndroid Build Coastguard Worker {
168*bebae9c0SAndroid Build Coastguard Worker     SLresult result;
169*bebae9c0SAndroid Build Coastguard Worker 
170*bebae9c0SAndroid Build Coastguard Worker     pthread_mutex_lock(&mutex);
171*bebae9c0SAndroid Build Coastguard Worker 
172*bebae9c0SAndroid Build Coastguard Worker     // Get the buffer that just finished playing
173*bebae9c0SAndroid Build Coastguard Worker     assert(txFront <= txBufCount);
174*bebae9c0SAndroid Build Coastguard Worker     assert(txRear <= txBufCount);
175*bebae9c0SAndroid Build Coastguard Worker     assert(txFront != txRear);
176*bebae9c0SAndroid Build Coastguard Worker     char *buffer = txBuffers[txFront];
177*bebae9c0SAndroid Build Coastguard Worker     if (++txFront > txBufCount) {
178*bebae9c0SAndroid Build Coastguard Worker         txFront = 0;
179*bebae9c0SAndroid Build Coastguard Worker     }
180*bebae9c0SAndroid Build Coastguard Worker 
181*bebae9c0SAndroid Build Coastguard Worker #if 1
182*bebae9c0SAndroid Build Coastguard Worker     ssize_t actual = fifoReader->read(buffer, bufSizeInFrames);
183*bebae9c0SAndroid Build Coastguard Worker     if (actual != (ssize_t) bufSizeInFrames) {
184*bebae9c0SAndroid Build Coastguard Worker         write(1, "/", 1);
185*bebae9c0SAndroid Build Coastguard Worker         // on underrun from pipe, substitute silence
186*bebae9c0SAndroid Build Coastguard Worker         memset(buffer, 0, bufSizeInFrames * channels * sizeof(short));
187*bebae9c0SAndroid Build Coastguard Worker     }
188*bebae9c0SAndroid Build Coastguard Worker 
189*bebae9c0SAndroid Build Coastguard Worker     if (injectImpulse == -1) {
190*bebae9c0SAndroid Build Coastguard Worker         // Experimentally, a single frame impulse was insufficient to trigger feedback.
191*bebae9c0SAndroid Build Coastguard Worker         // Also a Nyquist frequency signal was also insufficient, probably because
192*bebae9c0SAndroid Build Coastguard Worker         // the response of output and/or input path was not adequate at high frequencies.
193*bebae9c0SAndroid Build Coastguard Worker         // This short burst of a few cycles of square wave at Nyquist/4 was found to work well.
194*bebae9c0SAndroid Build Coastguard Worker         for (unsigned i = 0; i < bufSizeInFrames / 8; i += 8) {
195*bebae9c0SAndroid Build Coastguard Worker             for (int j = 0; j < 8; j++) {
196*bebae9c0SAndroid Build Coastguard Worker                 for (unsigned k = 0; k < channels; k++) {
197*bebae9c0SAndroid Build Coastguard Worker                     ((short *)buffer)[(i+j)*channels+k] = j < 4 ? 0x7FFF : 0x8000;
198*bebae9c0SAndroid Build Coastguard Worker                 }
199*bebae9c0SAndroid Build Coastguard Worker             }
200*bebae9c0SAndroid Build Coastguard Worker         }
201*bebae9c0SAndroid Build Coastguard Worker         injectImpulse = 0;
202*bebae9c0SAndroid Build Coastguard Worker     }
203*bebae9c0SAndroid Build Coastguard Worker 
204*bebae9c0SAndroid Build Coastguard Worker     // Enqueue the filled buffer for playing
205*bebae9c0SAndroid Build Coastguard Worker     result = (*playerBufferQueue)->Enqueue(playerBufferQueue, buffer, bufSizeInBytes);
206*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
207*bebae9c0SAndroid Build Coastguard Worker 
208*bebae9c0SAndroid Build Coastguard Worker     // Update our model of the player queue
209*bebae9c0SAndroid Build Coastguard Worker     assert(txFront <= txBufCount);
210*bebae9c0SAndroid Build Coastguard Worker     assert(txRear <= txBufCount);
211*bebae9c0SAndroid Build Coastguard Worker     SLuint32 txRearNext = txRear+1;
212*bebae9c0SAndroid Build Coastguard Worker     if (txRearNext > txBufCount) {
213*bebae9c0SAndroid Build Coastguard Worker         txRearNext = 0;
214*bebae9c0SAndroid Build Coastguard Worker     }
215*bebae9c0SAndroid Build Coastguard Worker     assert(txRearNext != txFront);
216*bebae9c0SAndroid Build Coastguard Worker     txBuffers[txRear] = buffer;
217*bebae9c0SAndroid Build Coastguard Worker     txRear = txRearNext;
218*bebae9c0SAndroid Build Coastguard Worker 
219*bebae9c0SAndroid Build Coastguard Worker #else
220*bebae9c0SAndroid Build Coastguard Worker     // First try to enqueue the free buffer for recording
221*bebae9c0SAndroid Build Coastguard Worker     result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue, buffer, bufSizeInBytes);
222*bebae9c0SAndroid Build Coastguard Worker     if (SL_RESULT_SUCCESS == result) {
223*bebae9c0SAndroid Build Coastguard Worker 
224*bebae9c0SAndroid Build Coastguard Worker         // There was room in the record queue, update our model of it
225*bebae9c0SAndroid Build Coastguard Worker         assert(rxFront <= rxBufCount);
226*bebae9c0SAndroid Build Coastguard Worker         assert(rxRear <= rxBufCount);
227*bebae9c0SAndroid Build Coastguard Worker         SLuint32 rxRearNext = rxRear+1;
228*bebae9c0SAndroid Build Coastguard Worker         if (rxRearNext > rxBufCount) {
229*bebae9c0SAndroid Build Coastguard Worker             rxRearNext = 0;
230*bebae9c0SAndroid Build Coastguard Worker         }
231*bebae9c0SAndroid Build Coastguard Worker         assert(rxRearNext != rxFront);
232*bebae9c0SAndroid Build Coastguard Worker         rxBuffers[rxRear] = buffer;
233*bebae9c0SAndroid Build Coastguard Worker         rxRear = rxRearNext;
234*bebae9c0SAndroid Build Coastguard Worker 
235*bebae9c0SAndroid Build Coastguard Worker     } else {
236*bebae9c0SAndroid Build Coastguard Worker 
237*bebae9c0SAndroid Build Coastguard Worker         // Here if record queue is full
238*bebae9c0SAndroid Build Coastguard Worker         assert(SL_RESULT_BUFFER_INSUFFICIENT == result);
239*bebae9c0SAndroid Build Coastguard Worker 
240*bebae9c0SAndroid Build Coastguard Worker         // Instead enqueue the free buffer on the free queue
241*bebae9c0SAndroid Build Coastguard Worker         assert(freeFront <= freeBufCount);
242*bebae9c0SAndroid Build Coastguard Worker         assert(freeRear <= freeBufCount);
243*bebae9c0SAndroid Build Coastguard Worker         SLuint32 freeRearNext = freeRear+1;
244*bebae9c0SAndroid Build Coastguard Worker         if (freeRearNext > freeBufCount) {
245*bebae9c0SAndroid Build Coastguard Worker             freeRearNext = 0;
246*bebae9c0SAndroid Build Coastguard Worker         }
247*bebae9c0SAndroid Build Coastguard Worker         // There must always be room in the free queue
248*bebae9c0SAndroid Build Coastguard Worker         assert(freeRearNext != freeFront);
249*bebae9c0SAndroid Build Coastguard Worker         freeBuffers[freeRear] = buffer;
250*bebae9c0SAndroid Build Coastguard Worker         freeRear = freeRearNext;
251*bebae9c0SAndroid Build Coastguard Worker 
252*bebae9c0SAndroid Build Coastguard Worker     }
253*bebae9c0SAndroid Build Coastguard Worker #endif
254*bebae9c0SAndroid Build Coastguard Worker 
255*bebae9c0SAndroid Build Coastguard Worker     pthread_mutex_unlock(&mutex);
256*bebae9c0SAndroid Build Coastguard Worker }
257*bebae9c0SAndroid Build Coastguard Worker 
258*bebae9c0SAndroid Build Coastguard Worker // Main program
main(int argc,char ** argv)259*bebae9c0SAndroid Build Coastguard Worker int main(int argc, char **argv)
260*bebae9c0SAndroid Build Coastguard Worker {
261*bebae9c0SAndroid Build Coastguard Worker     const char *outFileName = NULL;
262*bebae9c0SAndroid Build Coastguard Worker     // process command-line options
263*bebae9c0SAndroid Build Coastguard Worker     int i;
264*bebae9c0SAndroid Build Coastguard Worker     for (i = 1; i < argc; ++i) {
265*bebae9c0SAndroid Build Coastguard Worker         char *arg = argv[i];
266*bebae9c0SAndroid Build Coastguard Worker         if (arg[0] != '-') {
267*bebae9c0SAndroid Build Coastguard Worker             break;
268*bebae9c0SAndroid Build Coastguard Worker         }
269*bebae9c0SAndroid Build Coastguard Worker         // -r# number of slots in receive buffer queue
270*bebae9c0SAndroid Build Coastguard Worker         if (!strncmp(arg, "-r", 2)) {
271*bebae9c0SAndroid Build Coastguard Worker             rxBufCount = atoi(&arg[2]);
272*bebae9c0SAndroid Build Coastguard Worker             if (rxBufCount < 1 || rxBufCount > 16) {
273*bebae9c0SAndroid Build Coastguard Worker                 fprintf(stderr, "%s: unusual receive buffer queue size (%u buffers)\n", argv[0],
274*bebae9c0SAndroid Build Coastguard Worker                     (unsigned) rxBufCount);
275*bebae9c0SAndroid Build Coastguard Worker             }
276*bebae9c0SAndroid Build Coastguard Worker         // -t# number of slots in transmit buffer queue
277*bebae9c0SAndroid Build Coastguard Worker         } else if (!strncmp(arg, "-t", 2)) {
278*bebae9c0SAndroid Build Coastguard Worker             txBufCount = atoi(&arg[2]);
279*bebae9c0SAndroid Build Coastguard Worker             if (txBufCount < 1 || txBufCount > 16) {
280*bebae9c0SAndroid Build Coastguard Worker                 fprintf(stderr, "%s: unusual transmit buffer queue size (%u buffers)\n", argv[0],
281*bebae9c0SAndroid Build Coastguard Worker                     (unsigned) txBufCount);
282*bebae9c0SAndroid Build Coastguard Worker             }
283*bebae9c0SAndroid Build Coastguard Worker         // -f# size of each buffer in frames
284*bebae9c0SAndroid Build Coastguard Worker         } else if (!strncmp(arg, "-f", 2)) {
285*bebae9c0SAndroid Build Coastguard Worker             bufSizeInFrames = atoi(&arg[2]);
286*bebae9c0SAndroid Build Coastguard Worker             if (bufSizeInFrames == 0) {
287*bebae9c0SAndroid Build Coastguard Worker                 fprintf(stderr, "%s: unusual buffer size (%u frames)\n", argv[0],
288*bebae9c0SAndroid Build Coastguard Worker                     (unsigned) bufSizeInFrames);
289*bebae9c0SAndroid Build Coastguard Worker             }
290*bebae9c0SAndroid Build Coastguard Worker         // -c1 mono or -c2 stereo
291*bebae9c0SAndroid Build Coastguard Worker         } else if (!strncmp(arg, "-c", 2)) {
292*bebae9c0SAndroid Build Coastguard Worker             channels = atoi(&arg[2]);
293*bebae9c0SAndroid Build Coastguard Worker             if (channels < 1 || channels > 2) {
294*bebae9c0SAndroid Build Coastguard Worker                 fprintf(stderr, "%s: unusual channel count ignored (%u)\n", argv[0],
295*bebae9c0SAndroid Build Coastguard Worker                     (unsigned) channels);
296*bebae9c0SAndroid Build Coastguard Worker                 channels = 2;
297*bebae9c0SAndroid Build Coastguard Worker             }
298*bebae9c0SAndroid Build Coastguard Worker         // -s# sample rate in Hz
299*bebae9c0SAndroid Build Coastguard Worker         } else if (!strncmp(arg, "-s", 2)) {
300*bebae9c0SAndroid Build Coastguard Worker             sampleRate = atoi(&arg[2]);
301*bebae9c0SAndroid Build Coastguard Worker             switch (sampleRate) {
302*bebae9c0SAndroid Build Coastguard Worker             case 8000:
303*bebae9c0SAndroid Build Coastguard Worker             case 11025:
304*bebae9c0SAndroid Build Coastguard Worker             case 12000:
305*bebae9c0SAndroid Build Coastguard Worker             case 16000:
306*bebae9c0SAndroid Build Coastguard Worker             case 22050:
307*bebae9c0SAndroid Build Coastguard Worker             case 24000:
308*bebae9c0SAndroid Build Coastguard Worker             case 32000:
309*bebae9c0SAndroid Build Coastguard Worker             case 44100:
310*bebae9c0SAndroid Build Coastguard Worker             case 48000:
311*bebae9c0SAndroid Build Coastguard Worker                 break;
312*bebae9c0SAndroid Build Coastguard Worker             default:
313*bebae9c0SAndroid Build Coastguard Worker                 fprintf(stderr, "%s: unusual sample rate (%u Hz)\n", argv[0],
314*bebae9c0SAndroid Build Coastguard Worker                     (unsigned) sampleRate);
315*bebae9c0SAndroid Build Coastguard Worker                 break;
316*bebae9c0SAndroid Build Coastguard Worker             }
317*bebae9c0SAndroid Build Coastguard Worker         // -e# exit after this many seconds
318*bebae9c0SAndroid Build Coastguard Worker         } else if (!strncmp(arg, "-e", 2)) {
319*bebae9c0SAndroid Build Coastguard Worker             exitAfterSeconds = atoi(&arg[2]);
320*bebae9c0SAndroid Build Coastguard Worker         // -ofile log to output file also
321*bebae9c0SAndroid Build Coastguard Worker         } else if (!strncmp(arg, "-o", 2)) {
322*bebae9c0SAndroid Build Coastguard Worker             outFileName = &arg[2];
323*bebae9c0SAndroid Build Coastguard Worker         // -i# inject an impulse after # milliseconds
324*bebae9c0SAndroid Build Coastguard Worker         } else if (!strncmp(arg, "-i", 2)) {
325*bebae9c0SAndroid Build Coastguard Worker             injectImpulse = atoi(&arg[2]);
326*bebae9c0SAndroid Build Coastguard Worker         } else
327*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "%s: unknown option %s\n", argv[0], arg);
328*bebae9c0SAndroid Build Coastguard Worker     }
329*bebae9c0SAndroid Build Coastguard Worker     // no other arguments allowed
330*bebae9c0SAndroid Build Coastguard Worker     if (i < argc) {
331*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "usage: %s -r# -t# -f# -s# -c# -i# -ofile\n", argv[0]);
332*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "  -r# receive buffer queue count for microphone input, default 1\n");
333*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "  -t# transmit buffer queue count for speaker output, default 2\n");
334*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "  -f# number of frames per buffer, default 512\n");
335*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "  -s# sample rate in Hz, default 44100\n");
336*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "  -c1 mono\n");
337*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "  -c2 stereo, default\n");
338*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "  -i# inject impulse after # milliseconds\n");
339*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "  -ofile log input to specified .wav file also\n");
340*bebae9c0SAndroid Build Coastguard Worker     }
341*bebae9c0SAndroid Build Coastguard Worker 
342*bebae9c0SAndroid Build Coastguard Worker     // compute total free buffers as -r plus -t
343*bebae9c0SAndroid Build Coastguard Worker     freeBufCount = rxBufCount + txBufCount;
344*bebae9c0SAndroid Build Coastguard Worker     // compute buffer size
345*bebae9c0SAndroid Build Coastguard Worker     bufSizeInBytes = channels * bufSizeInFrames * sizeof(short);
346*bebae9c0SAndroid Build Coastguard Worker 
347*bebae9c0SAndroid Build Coastguard Worker     // Initialize free buffers
348*bebae9c0SAndroid Build Coastguard Worker     freeBuffers = (char **) calloc(freeBufCount+1, sizeof(char *));
349*bebae9c0SAndroid Build Coastguard Worker     unsigned j;
350*bebae9c0SAndroid Build Coastguard Worker     for (j = 0; j < freeBufCount; ++j) {
351*bebae9c0SAndroid Build Coastguard Worker         freeBuffers[j] = (char *) malloc(bufSizeInBytes);
352*bebae9c0SAndroid Build Coastguard Worker     }
353*bebae9c0SAndroid Build Coastguard Worker     freeFront = 0;
354*bebae9c0SAndroid Build Coastguard Worker     freeRear = freeBufCount;
355*bebae9c0SAndroid Build Coastguard Worker     freeBuffers[j] = NULL;
356*bebae9c0SAndroid Build Coastguard Worker 
357*bebae9c0SAndroid Build Coastguard Worker     // Initialize record queue
358*bebae9c0SAndroid Build Coastguard Worker     rxBuffers = (char **) calloc(rxBufCount+1, sizeof(char *));
359*bebae9c0SAndroid Build Coastguard Worker     rxFront = 0;
360*bebae9c0SAndroid Build Coastguard Worker     rxRear = 0;
361*bebae9c0SAndroid Build Coastguard Worker 
362*bebae9c0SAndroid Build Coastguard Worker     // Initialize play queue
363*bebae9c0SAndroid Build Coastguard Worker     txBuffers = (char **) calloc(txBufCount+1, sizeof(char *));
364*bebae9c0SAndroid Build Coastguard Worker     txFront = 0;
365*bebae9c0SAndroid Build Coastguard Worker     txRear = 0;
366*bebae9c0SAndroid Build Coastguard Worker 
367*bebae9c0SAndroid Build Coastguard Worker     size_t frameSize = channels * sizeof(short);
368*bebae9c0SAndroid Build Coastguard Worker #define FIFO_FRAMES 1024
369*bebae9c0SAndroid Build Coastguard Worker     short *fifoBuffer = new short[FIFO_FRAMES * channels];
370*bebae9c0SAndroid Build Coastguard Worker     fifo = new audio_utils_fifo(FIFO_FRAMES, frameSize, fifoBuffer);
371*bebae9c0SAndroid Build Coastguard Worker     fifoReader = new audio_utils_fifo_reader(*fifo, true /*throttlesWriter*/);
372*bebae9c0SAndroid Build Coastguard Worker     fifoWriter = new audio_utils_fifo_writer(*fifo);
373*bebae9c0SAndroid Build Coastguard Worker 
374*bebae9c0SAndroid Build Coastguard Worker     SNDFILE *sndfile;
375*bebae9c0SAndroid Build Coastguard Worker     if (outFileName != NULL) {
376*bebae9c0SAndroid Build Coastguard Worker         // create .wav writer
377*bebae9c0SAndroid Build Coastguard Worker         SF_INFO info;
378*bebae9c0SAndroid Build Coastguard Worker         info.frames = 0;
379*bebae9c0SAndroid Build Coastguard Worker         info.samplerate = sampleRate;
380*bebae9c0SAndroid Build Coastguard Worker         info.channels = channels;
381*bebae9c0SAndroid Build Coastguard Worker         info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
382*bebae9c0SAndroid Build Coastguard Worker         sndfile = sf_open(outFileName, SFM_WRITE, &info);
383*bebae9c0SAndroid Build Coastguard Worker         if (sndfile != NULL) {
384*bebae9c0SAndroid Build Coastguard Worker #define FIFO2_FRAMES 65536
385*bebae9c0SAndroid Build Coastguard Worker             fifo2Buffer = new short[FIFO2_FRAMES * channels];
386*bebae9c0SAndroid Build Coastguard Worker             fifo2 = new audio_utils_fifo(FIFO2_FRAMES, frameSize, fifo2Buffer);
387*bebae9c0SAndroid Build Coastguard Worker             fifo2Reader = new audio_utils_fifo_reader(*fifo2, true /*throttlesWriter*/);
388*bebae9c0SAndroid Build Coastguard Worker             fifo2Writer = new audio_utils_fifo_writer(*fifo2);
389*bebae9c0SAndroid Build Coastguard Worker         } else {
390*bebae9c0SAndroid Build Coastguard Worker             fprintf(stderr, "sf_open failed\n");
391*bebae9c0SAndroid Build Coastguard Worker         }
392*bebae9c0SAndroid Build Coastguard Worker     } else {
393*bebae9c0SAndroid Build Coastguard Worker         sndfile = NULL;
394*bebae9c0SAndroid Build Coastguard Worker     }
395*bebae9c0SAndroid Build Coastguard Worker 
396*bebae9c0SAndroid Build Coastguard Worker     SLresult result;
397*bebae9c0SAndroid Build Coastguard Worker 
398*bebae9c0SAndroid Build Coastguard Worker     // create engine
399*bebae9c0SAndroid Build Coastguard Worker     SLObjectItf engineObject;
400*bebae9c0SAndroid Build Coastguard Worker     result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
401*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
402*bebae9c0SAndroid Build Coastguard Worker     result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
403*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
404*bebae9c0SAndroid Build Coastguard Worker     SLEngineItf engineEngine;
405*bebae9c0SAndroid Build Coastguard Worker     result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
406*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
407*bebae9c0SAndroid Build Coastguard Worker 
408*bebae9c0SAndroid Build Coastguard Worker     // create output mix
409*bebae9c0SAndroid Build Coastguard Worker     SLObjectItf outputmixObject;
410*bebae9c0SAndroid Build Coastguard Worker     result = (*engineEngine)->CreateOutputMix(engineEngine, &outputmixObject, 0, NULL, NULL);
411*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
412*bebae9c0SAndroid Build Coastguard Worker     result = (*outputmixObject)->Realize(outputmixObject, SL_BOOLEAN_FALSE);
413*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
414*bebae9c0SAndroid Build Coastguard Worker 
415*bebae9c0SAndroid Build Coastguard Worker     // create an audio player with buffer queue source and output mix sink
416*bebae9c0SAndroid Build Coastguard Worker     SLDataSource audiosrc;
417*bebae9c0SAndroid Build Coastguard Worker     SLDataSink audiosnk;
418*bebae9c0SAndroid Build Coastguard Worker     SLDataFormat_PCM pcm;
419*bebae9c0SAndroid Build Coastguard Worker     SLDataLocator_OutputMix locator_outputmix;
420*bebae9c0SAndroid Build Coastguard Worker     SLDataLocator_BufferQueue locator_bufferqueue_tx;
421*bebae9c0SAndroid Build Coastguard Worker     locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
422*bebae9c0SAndroid Build Coastguard Worker     locator_bufferqueue_tx.numBuffers = txBufCount;
423*bebae9c0SAndroid Build Coastguard Worker     locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
424*bebae9c0SAndroid Build Coastguard Worker     locator_outputmix.outputMix = outputmixObject;
425*bebae9c0SAndroid Build Coastguard Worker     pcm.formatType = SL_DATAFORMAT_PCM;
426*bebae9c0SAndroid Build Coastguard Worker     pcm.numChannels = channels;
427*bebae9c0SAndroid Build Coastguard Worker     pcm.samplesPerSec = sampleRate * 1000;
428*bebae9c0SAndroid Build Coastguard Worker     pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
429*bebae9c0SAndroid Build Coastguard Worker     pcm.containerSize = 16;
430*bebae9c0SAndroid Build Coastguard Worker     pcm.channelMask = channels == 1 ? SL_SPEAKER_FRONT_CENTER :
431*bebae9c0SAndroid Build Coastguard Worker         (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
432*bebae9c0SAndroid Build Coastguard Worker     pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
433*bebae9c0SAndroid Build Coastguard Worker     audiosrc.pLocator = &locator_bufferqueue_tx;
434*bebae9c0SAndroid Build Coastguard Worker     audiosrc.pFormat = &pcm;
435*bebae9c0SAndroid Build Coastguard Worker     audiosnk.pLocator = &locator_outputmix;
436*bebae9c0SAndroid Build Coastguard Worker     audiosnk.pFormat = NULL;
437*bebae9c0SAndroid Build Coastguard Worker     SLObjectItf playerObject = NULL;
438*bebae9c0SAndroid Build Coastguard Worker     SLObjectItf recorderObject = NULL;
439*bebae9c0SAndroid Build Coastguard Worker     SLInterfaceID ids_tx[1] = {SL_IID_BUFFERQUEUE};
440*bebae9c0SAndroid Build Coastguard Worker     SLboolean flags_tx[1] = {SL_BOOLEAN_TRUE};
441*bebae9c0SAndroid Build Coastguard Worker     result = (*engineEngine)->CreateAudioPlayer(engineEngine, &playerObject, &audiosrc, &audiosnk,
442*bebae9c0SAndroid Build Coastguard Worker         1, ids_tx, flags_tx);
443*bebae9c0SAndroid Build Coastguard Worker     if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
444*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "Could not create audio player (result %x), check sample rate\n", result);
445*bebae9c0SAndroid Build Coastguard Worker         goto cleanup;
446*bebae9c0SAndroid Build Coastguard Worker     }
447*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
448*bebae9c0SAndroid Build Coastguard Worker     result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
449*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
450*bebae9c0SAndroid Build Coastguard Worker     SLPlayItf playerPlay;
451*bebae9c0SAndroid Build Coastguard Worker     result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
452*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
453*bebae9c0SAndroid Build Coastguard Worker     result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue);
454*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
455*bebae9c0SAndroid Build Coastguard Worker     result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, playerCallback, NULL);
456*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
457*bebae9c0SAndroid Build Coastguard Worker 
458*bebae9c0SAndroid Build Coastguard Worker     // Enqueue some zero buffers for the player
459*bebae9c0SAndroid Build Coastguard Worker     for (j = 0; j < txBufCount; ++j) {
460*bebae9c0SAndroid Build Coastguard Worker 
461*bebae9c0SAndroid Build Coastguard Worker         // allocate a free buffer
462*bebae9c0SAndroid Build Coastguard Worker         assert(freeFront != freeRear);
463*bebae9c0SAndroid Build Coastguard Worker         char *buffer = freeBuffers[freeFront];
464*bebae9c0SAndroid Build Coastguard Worker         if (++freeFront > freeBufCount) {
465*bebae9c0SAndroid Build Coastguard Worker             freeFront = 0;
466*bebae9c0SAndroid Build Coastguard Worker         }
467*bebae9c0SAndroid Build Coastguard Worker 
468*bebae9c0SAndroid Build Coastguard Worker         // put on play queue
469*bebae9c0SAndroid Build Coastguard Worker         SLuint32 txRearNext = txRear + 1;
470*bebae9c0SAndroid Build Coastguard Worker         if (txRearNext > txBufCount) {
471*bebae9c0SAndroid Build Coastguard Worker             txRearNext = 0;
472*bebae9c0SAndroid Build Coastguard Worker         }
473*bebae9c0SAndroid Build Coastguard Worker         assert(txRearNext != txFront);
474*bebae9c0SAndroid Build Coastguard Worker         txBuffers[txRear] = buffer;
475*bebae9c0SAndroid Build Coastguard Worker         txRear = txRearNext;
476*bebae9c0SAndroid Build Coastguard Worker         result = (*playerBufferQueue)->Enqueue(playerBufferQueue,
477*bebae9c0SAndroid Build Coastguard Worker             buffer, bufSizeInBytes);
478*bebae9c0SAndroid Build Coastguard Worker         ASSERT_EQ(SL_RESULT_SUCCESS, result);
479*bebae9c0SAndroid Build Coastguard Worker     }
480*bebae9c0SAndroid Build Coastguard Worker 
481*bebae9c0SAndroid Build Coastguard Worker     result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
482*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
483*bebae9c0SAndroid Build Coastguard Worker 
484*bebae9c0SAndroid Build Coastguard Worker     // Create an audio recorder with microphone device source and buffer queue sink.
485*bebae9c0SAndroid Build Coastguard Worker     // The buffer queue as sink is an Android-specific extension.
486*bebae9c0SAndroid Build Coastguard Worker 
487*bebae9c0SAndroid Build Coastguard Worker     SLDataLocator_IODevice locator_iodevice;
488*bebae9c0SAndroid Build Coastguard Worker     SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
489*bebae9c0SAndroid Build Coastguard Worker     locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
490*bebae9c0SAndroid Build Coastguard Worker     locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
491*bebae9c0SAndroid Build Coastguard Worker     locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
492*bebae9c0SAndroid Build Coastguard Worker     locator_iodevice.device = NULL;
493*bebae9c0SAndroid Build Coastguard Worker     audiosrc.pLocator = &locator_iodevice;
494*bebae9c0SAndroid Build Coastguard Worker     audiosrc.pFormat = NULL;
495*bebae9c0SAndroid Build Coastguard Worker     locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
496*bebae9c0SAndroid Build Coastguard Worker     locator_bufferqueue_rx.numBuffers = rxBufCount;
497*bebae9c0SAndroid Build Coastguard Worker     audiosnk.pLocator = &locator_bufferqueue_rx;
498*bebae9c0SAndroid Build Coastguard Worker     audiosnk.pFormat = &pcm;
499*bebae9c0SAndroid Build Coastguard Worker     {
500*bebae9c0SAndroid Build Coastguard Worker     SLInterfaceID ids_rx[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
501*bebae9c0SAndroid Build Coastguard Worker     SLboolean flags_rx[1] = {SL_BOOLEAN_TRUE};
502*bebae9c0SAndroid Build Coastguard Worker     result = (*engineEngine)->CreateAudioRecorder(engineEngine, &recorderObject, &audiosrc,
503*bebae9c0SAndroid Build Coastguard Worker         &audiosnk, 1, ids_rx, flags_rx);
504*bebae9c0SAndroid Build Coastguard Worker     if (SL_RESULT_SUCCESS != result) {
505*bebae9c0SAndroid Build Coastguard Worker         fprintf(stderr, "Could not create audio recorder (result %x), "
506*bebae9c0SAndroid Build Coastguard Worker                 "check sample rate and channel count\n", result);
507*bebae9c0SAndroid Build Coastguard Worker         goto cleanup;
508*bebae9c0SAndroid Build Coastguard Worker     }
509*bebae9c0SAndroid Build Coastguard Worker     }
510*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
511*bebae9c0SAndroid Build Coastguard Worker     result = (*recorderObject)->Realize(recorderObject, SL_BOOLEAN_FALSE);
512*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
513*bebae9c0SAndroid Build Coastguard Worker     SLRecordItf recorderRecord;
514*bebae9c0SAndroid Build Coastguard Worker     result = (*recorderObject)->GetInterface(recorderObject, SL_IID_RECORD, &recorderRecord);
515*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
516*bebae9c0SAndroid Build Coastguard Worker     result = (*recorderObject)->GetInterface(recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
517*bebae9c0SAndroid Build Coastguard Worker         &recorderBufferQueue);
518*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
519*bebae9c0SAndroid Build Coastguard Worker     result = (*recorderBufferQueue)->RegisterCallback(recorderBufferQueue, recorderCallback, NULL);
520*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
521*bebae9c0SAndroid Build Coastguard Worker 
522*bebae9c0SAndroid Build Coastguard Worker     // Enqueue some empty buffers for the recorder
523*bebae9c0SAndroid Build Coastguard Worker     for (j = 0; j < rxBufCount; ++j) {
524*bebae9c0SAndroid Build Coastguard Worker 
525*bebae9c0SAndroid Build Coastguard Worker         // allocate a free buffer
526*bebae9c0SAndroid Build Coastguard Worker         assert(freeFront != freeRear);
527*bebae9c0SAndroid Build Coastguard Worker         char *buffer = freeBuffers[freeFront];
528*bebae9c0SAndroid Build Coastguard Worker         if (++freeFront > freeBufCount) {
529*bebae9c0SAndroid Build Coastguard Worker             freeFront = 0;
530*bebae9c0SAndroid Build Coastguard Worker         }
531*bebae9c0SAndroid Build Coastguard Worker 
532*bebae9c0SAndroid Build Coastguard Worker         // put on record queue
533*bebae9c0SAndroid Build Coastguard Worker         SLuint32 rxRearNext = rxRear + 1;
534*bebae9c0SAndroid Build Coastguard Worker         if (rxRearNext > rxBufCount) {
535*bebae9c0SAndroid Build Coastguard Worker             rxRearNext = 0;
536*bebae9c0SAndroid Build Coastguard Worker         }
537*bebae9c0SAndroid Build Coastguard Worker         assert(rxRearNext != rxFront);
538*bebae9c0SAndroid Build Coastguard Worker         rxBuffers[rxRear] = buffer;
539*bebae9c0SAndroid Build Coastguard Worker         rxRear = rxRearNext;
540*bebae9c0SAndroid Build Coastguard Worker         result = (*recorderBufferQueue)->Enqueue(recorderBufferQueue,
541*bebae9c0SAndroid Build Coastguard Worker             buffer, bufSizeInBytes);
542*bebae9c0SAndroid Build Coastguard Worker         ASSERT_EQ(SL_RESULT_SUCCESS, result);
543*bebae9c0SAndroid Build Coastguard Worker     }
544*bebae9c0SAndroid Build Coastguard Worker 
545*bebae9c0SAndroid Build Coastguard Worker     // Kick off the recorder
546*bebae9c0SAndroid Build Coastguard Worker     result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
547*bebae9c0SAndroid Build Coastguard Worker     ASSERT_EQ(SL_RESULT_SUCCESS, result);
548*bebae9c0SAndroid Build Coastguard Worker 
549*bebae9c0SAndroid Build Coastguard Worker #if 0
550*bebae9c0SAndroid Build Coastguard Worker     // give recorder a head start so that the pipe is initially filled
551*bebae9c0SAndroid Build Coastguard Worker     sleep(1);
552*bebae9c0SAndroid Build Coastguard Worker #endif
553*bebae9c0SAndroid Build Coastguard Worker 
554*bebae9c0SAndroid Build Coastguard Worker     // Wait patiently
555*bebae9c0SAndroid Build Coastguard Worker     do {
556*bebae9c0SAndroid Build Coastguard Worker         for (int i = 0; i < 10; i++) {
557*bebae9c0SAndroid Build Coastguard Worker             usleep(100000);
558*bebae9c0SAndroid Build Coastguard Worker             if (fifo2Buffer != NULL) {
559*bebae9c0SAndroid Build Coastguard Worker                 for (;;) {
560*bebae9c0SAndroid Build Coastguard Worker                     short buffer[bufSizeInFrames * channels];
561*bebae9c0SAndroid Build Coastguard Worker                     ssize_t actual = fifo2Reader->read(buffer, bufSizeInFrames);
562*bebae9c0SAndroid Build Coastguard Worker                     if (actual <= 0)
563*bebae9c0SAndroid Build Coastguard Worker                         break;
564*bebae9c0SAndroid Build Coastguard Worker                     (void) sf_writef_short(sndfile, buffer, (sf_count_t) actual);
565*bebae9c0SAndroid Build Coastguard Worker                 }
566*bebae9c0SAndroid Build Coastguard Worker             }
567*bebae9c0SAndroid Build Coastguard Worker             if (injectImpulse > 0) {
568*bebae9c0SAndroid Build Coastguard Worker                 if (injectImpulse <= 100) {
569*bebae9c0SAndroid Build Coastguard Worker                     injectImpulse = -1;
570*bebae9c0SAndroid Build Coastguard Worker                     write(1, "I", 1);
571*bebae9c0SAndroid Build Coastguard Worker                 } else {
572*bebae9c0SAndroid Build Coastguard Worker                     if ((injectImpulse % 1000) < 100) {
573*bebae9c0SAndroid Build Coastguard Worker                         write(1, "i", 1);
574*bebae9c0SAndroid Build Coastguard Worker                     }
575*bebae9c0SAndroid Build Coastguard Worker                     injectImpulse -= 100;
576*bebae9c0SAndroid Build Coastguard Worker                 }
577*bebae9c0SAndroid Build Coastguard Worker             } else if (i == 9) {
578*bebae9c0SAndroid Build Coastguard Worker                 write(1, ".", 1);
579*bebae9c0SAndroid Build Coastguard Worker             }
580*bebae9c0SAndroid Build Coastguard Worker         }
581*bebae9c0SAndroid Build Coastguard Worker         SLBufferQueueState playerBQState;
582*bebae9c0SAndroid Build Coastguard Worker         result = (*playerBufferQueue)->GetState(playerBufferQueue, &playerBQState);
583*bebae9c0SAndroid Build Coastguard Worker         ASSERT_EQ(SL_RESULT_SUCCESS, result);
584*bebae9c0SAndroid Build Coastguard Worker         SLAndroidSimpleBufferQueueState recorderBQState;
585*bebae9c0SAndroid Build Coastguard Worker         result = (*recorderBufferQueue)->GetState(recorderBufferQueue, &recorderBQState);
586*bebae9c0SAndroid Build Coastguard Worker         ASSERT_EQ(SL_RESULT_SUCCESS, result);
587*bebae9c0SAndroid Build Coastguard Worker     } while (--exitAfterSeconds);
588*bebae9c0SAndroid Build Coastguard Worker 
589*bebae9c0SAndroid Build Coastguard Worker     // Tear down the objects and exit
590*bebae9c0SAndroid Build Coastguard Worker cleanup:
591*bebae9c0SAndroid Build Coastguard Worker     delete fifoWriter;
592*bebae9c0SAndroid Build Coastguard Worker     fifoWriter = NULL;
593*bebae9c0SAndroid Build Coastguard Worker     delete fifoReader;
594*bebae9c0SAndroid Build Coastguard Worker     fifoReader = NULL;
595*bebae9c0SAndroid Build Coastguard Worker     delete fifo;
596*bebae9c0SAndroid Build Coastguard Worker     fifo = NULL;
597*bebae9c0SAndroid Build Coastguard Worker     delete[] fifoBuffer;
598*bebae9c0SAndroid Build Coastguard Worker     fifoBuffer = NULL;
599*bebae9c0SAndroid Build Coastguard Worker 
600*bebae9c0SAndroid Build Coastguard Worker     if (sndfile != NULL) {
601*bebae9c0SAndroid Build Coastguard Worker         delete fifo2Writer;
602*bebae9c0SAndroid Build Coastguard Worker         fifo2Writer = NULL;
603*bebae9c0SAndroid Build Coastguard Worker         delete fifo2Reader;
604*bebae9c0SAndroid Build Coastguard Worker         fifo2Reader = NULL;
605*bebae9c0SAndroid Build Coastguard Worker         delete fifo2;
606*bebae9c0SAndroid Build Coastguard Worker         fifo2 = NULL;
607*bebae9c0SAndroid Build Coastguard Worker         delete[] fifo2Buffer;
608*bebae9c0SAndroid Build Coastguard Worker         fifo2Buffer = NULL;
609*bebae9c0SAndroid Build Coastguard Worker         sf_close(sndfile);
610*bebae9c0SAndroid Build Coastguard Worker         sndfile = NULL;
611*bebae9c0SAndroid Build Coastguard Worker     }
612*bebae9c0SAndroid Build Coastguard Worker     if (NULL != playerObject) {
613*bebae9c0SAndroid Build Coastguard Worker         (*playerObject)->Destroy(playerObject);
614*bebae9c0SAndroid Build Coastguard Worker     }
615*bebae9c0SAndroid Build Coastguard Worker     if (NULL != recorderObject) {
616*bebae9c0SAndroid Build Coastguard Worker         (*recorderObject)->Destroy(recorderObject);
617*bebae9c0SAndroid Build Coastguard Worker     }
618*bebae9c0SAndroid Build Coastguard Worker     (*outputmixObject)->Destroy(outputmixObject);
619*bebae9c0SAndroid Build Coastguard Worker     (*engineObject)->Destroy(engineObject);
620*bebae9c0SAndroid Build Coastguard Worker 
621*bebae9c0SAndroid Build Coastguard Worker     return EXIT_SUCCESS;
622*bebae9c0SAndroid Build Coastguard Worker }
623