• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 
18 // FIXME taken from OpenSLES_AndroidConfiguration.h
19 #define SL_ANDROID_KEY_PERFORMANCE_MODE  ((const SLchar*) "androidPerformanceMode")
20 
21 ////////////////////////////////////////////
22 /// Actual sles functions.
23 
24 
25 // Test program to record from default audio input and playback to default audio output.
26 // It will generate feedback (Larsen effect) if played through on-device speakers,
27 // or acts as a delay if played through headset.
28 
29 #define _USE_MATH_DEFINES
30 #include <cmath>
31 #include "sles.h"
32 #include "audio_utils/atomic.h"
33 #include <stdio.h>
34 #include <assert.h>
35 #include <unistd.h>
36 #include <string.h>
37 
slesInit(sles_data ** ppSles,int samplingRate,int frameCount,int micSource,int performanceMode,int testType,double frequency1,char * byteBufferPtr,int byteBufferLength,short * loopbackTone,int maxRecordedLateCallbacks,int ignoreFirstFrames)38 int slesInit(sles_data ** ppSles, int samplingRate, int frameCount, int micSource,
39              int performanceMode,
40              int testType, double frequency1, char* byteBufferPtr, int byteBufferLength,
41              short* loopbackTone, int maxRecordedLateCallbacks, int ignoreFirstFrames) {
42     int status = SLES_FAIL;
43     if (ppSles != NULL) {
44         sles_data * pSles = (sles_data*) malloc(sizeof(sles_data));
45 
46         memset(pSles, 0, sizeof(sles_data));
47 
48         SLES_PRINTF("pSles malloc %zu bytes at %p", sizeof(sles_data), pSles);
49         //__android_log_print(ANDROID_LOG_INFO, "sles_jni",
50         //"malloc %d bytes at %p", sizeof(sles_data), pSles);//Or ANDROID_LOG_INFO, ...
51         *ppSles = pSles;
52         if (pSles != NULL)
53         {
54             SLES_PRINTF("creating server. Sampling rate =%d, frame count = %d",
55                         samplingRate, frameCount);
56             status = slesCreateServer(pSles, samplingRate, frameCount, micSource,
57                                       performanceMode, testType,
58                                       frequency1, byteBufferPtr, byteBufferLength, loopbackTone,
59                                       maxRecordedLateCallbacks, ignoreFirstFrames);
60             SLES_PRINTF("slesCreateServer =%d", status);
61         }
62     }
63 
64     return status;
65 }
slesDestroy(sles_data ** ppSles)66 int slesDestroy(sles_data ** ppSles) {
67     int status = SLES_FAIL;
68     if (ppSles != NULL) {
69         slesDestroyServer(*ppSles);
70 
71         if (*ppSles != NULL)
72         {
73             SLES_PRINTF("free memory at %p",*ppSles);
74             free(*ppSles);
75             *ppSles = 0;
76         }
77         status = SLES_SUCCESS;
78     }
79     return status;
80 }
81 
82 #define ASSERT_EQ(x, y) do { if ((x) == (y)) ; else { fprintf(stderr, "0x%x != 0x%x\n", \
83     (unsigned) (x), (unsigned) (y)); assert((x) == (y)); } } while (0)
84 
85 // Called after audio recorder fills a buffer with data, then we can read from this filled buffer
recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused,void * context)86 static void recorderCallback(SLAndroidSimpleBufferQueueItf caller __unused, void *context) {
87     sles_data *pSles = (sles_data*) context;
88     if (pSles != NULL) {
89         collectBufferPeriod(&pSles->recorderBufferStats, NULL /*fdpStats*/, &pSles->recorderTimeStamps,
90                             pSles->expectedBufferPeriod);
91 
92         //__android_log_print(ANDROID_LOG_INFO, "sles_jni", "in recorderCallback");
93         SLresult result;
94 
95         //ee  SLES_PRINTF("<R");
96 
97         // We should only be called when a recording buffer is done
98         assert(pSles->rxFront <= pSles->rxBufCount);
99         assert(pSles->rxRear <= pSles->rxBufCount);
100         assert(pSles->rxFront != pSles->rxRear);
101         char *buffer = pSles->rxBuffers[pSles->rxFront]; //pSles->rxBuffers stores the data recorded
102 
103 
104         // Remove buffer from record queue
105         if (++pSles->rxFront > pSles->rxBufCount) {
106             pSles->rxFront = 0;
107         }
108 
109         if (pSles->testType == TEST_TYPE_LATENCY) {
110             // Throw out first frames
111             if (pSles->ignoreFirstFrames) {
112                 int framesToErase = pSles->ignoreFirstFrames;
113                 if (framesToErase > (int) pSles->bufSizeInFrames) {
114                     framesToErase = pSles->bufSizeInFrames;
115                 }
116                 pSles->ignoreFirstFrames -= framesToErase;
117                 memset(buffer, 0, framesToErase * pSles->channels * sizeof(short));
118             }
119 
120             ssize_t actual = audio_utils_fifo_write(&(pSles->fifo), buffer,
121                     (size_t) pSles->bufSizeInFrames);
122 
123             if (actual != (ssize_t) pSles->bufSizeInFrames) {
124                 write(1, "?", 1);
125             }
126 
127             // This is called by a realtime (SCHED_FIFO) thread,
128             // and it is unsafe to do I/O as it could block for unbounded time.
129             // Flash filesystem is especially notorious for blocking.
130             if (pSles->fifo2Buffer != NULL) {
131                 actual = audio_utils_fifo_write(&(pSles->fifo2), buffer,
132                         (size_t) pSles->bufSizeInFrames);
133                 if (actual != (ssize_t) pSles->bufSizeInFrames) {
134                     write(1, "?", 1);
135                 }
136             }
137         } else if (pSles->testType == TEST_TYPE_BUFFER_PERIOD) {
138             if (pSles->fifo2Buffer != NULL) {
139                 ssize_t actual = byteBuffer_write(pSles, buffer, (size_t) pSles->bufSizeInFrames);
140 
141                 //FIXME should log errors using other methods instead of printing to terminal
142                 if (actual != (ssize_t) pSles->bufSizeInFrames) {
143                     write(1, "?", 1);
144                 }
145             }
146         }
147 
148 
149         // Enqueue this same buffer for the recorder to fill again.
150         result = (*(pSles->recorderBufferQueue))->Enqueue(pSles->recorderBufferQueue, buffer,
151                                                           pSles->bufSizeInBytes);
152         //__android_log_print(ANDROID_LOG_INFO, "recorderCallback", "recorder buffer size: %i",
153         //                    pSles->bufSizeInBytes);
154         ASSERT_EQ(SL_RESULT_SUCCESS, result);
155 
156 
157         // Update our model of the record queue
158         SLuint32 rxRearNext = pSles->rxRear + 1;
159         if (rxRearNext > pSles->rxBufCount) {
160             rxRearNext = 0;
161         }
162         assert(rxRearNext != pSles->rxFront);
163         pSles->rxBuffers[pSles->rxRear] = buffer;
164         pSles->rxRear = rxRearNext;
165 
166 
167 
168       //ee  SLES_PRINTF("r>");
169 
170     } //pSles not null
171 }
172 
173 
174 // Write "count" amount of short from buffer to pSles->byteBufferPtr. This byteBuffer will read by
175 // java code.
byteBuffer_write(sles_data * pSles,char * buffer,size_t count)176 ssize_t byteBuffer_write(sles_data *pSles, char *buffer, size_t count) {
177     // bytebufferSize is in byte
178     int32_t rear; // rear should not exceed 2^31 - 1, or else overflow will happen
179     memcpy(&rear, (char *) (pSles->byteBufferPtr + pSles->byteBufferLength - 4), sizeof(rear));
180 
181     size_t frameSize = pSles->channels * sizeof(short); // only one channel
182     int32_t maxLengthInShort = (pSles->byteBufferLength - 4) / frameSize;
183     // mask the upper bits to get the correct position in the pipe
184     int32_t tempRear = rear & (maxLengthInShort - 1);
185     size_t part1 = maxLengthInShort - tempRear;
186 
187     if (part1 > count) {
188         part1 = count;
189     }
190 
191     if (part1 > 0) {
192         memcpy(pSles->byteBufferPtr + (tempRear * frameSize), buffer,
193                part1 * frameSize);
194 
195         size_t part2 = count - part1;
196         if (part2 > 0) {
197             memcpy(pSles->byteBufferPtr, (buffer + (part1 * frameSize)),
198                    part2 * frameSize);
199         }
200 
201         //TODO do we need something similar to the below function call?
202         //android_atomic_release_store(audio_utils_fifo_sum(fifo, fifo->mRear, availToWrite),
203         //        &fifo->mRear);
204     }
205 
206     // increase value of rear
207     int32_t* rear2 = (int32_t *) (pSles->byteBufferPtr + pSles->byteBufferLength - 4);
208     *rear2 += count;
209     return count;
210 }
211 
212 // Calculate nanosecond difference between two timespec structs from clock_gettime(CLOCK_MONOTONIC)
213 // tv_sec [0, max time_t] , tv_nsec [0, 999999999]
diffInNano(struct timespec previousTime,struct timespec currentTime)214 int64_t diffInNano(struct timespec previousTime, struct timespec currentTime) {
215     return (int64_t) (currentTime.tv_sec - previousTime.tv_sec) * (int64_t) NANOS_PER_SECOND +
216             currentTime.tv_nsec - previousTime.tv_nsec;
217 }
218 
219 // Called after audio player empties a buffer of data
playerCallback(SLBufferQueueItf caller __unused,void * context)220 static void playerCallback(SLBufferQueueItf caller __unused, void *context) {
221     sles_data *pSles = (sles_data*) context;
222     if (pSles != NULL) {
223         collectBufferPeriod(&pSles->playerBufferStats, &pSles->recorderBufferStats /*fdpStats*/,
224                             &pSles->playerTimeStamps, pSles->expectedBufferPeriod);
225         SLresult result;
226 
227         //ee  SLES_PRINTF("<P");
228 
229         // Get the buffer that just finished playing
230         assert(pSles->txFront <= pSles->txBufCount);
231         assert(pSles->txRear <= pSles->txBufCount);
232         assert(pSles->txFront != pSles->txRear);
233         char *buffer = pSles->txBuffers[pSles->txFront];
234         if (++pSles->txFront > pSles->txBufCount) {
235             pSles->txFront = 0;
236         }
237 
238         if (pSles->testType == TEST_TYPE_LATENCY) {
239             // Jitter buffer should have strictly less than 2 buffers worth of data in it.
240             // This is to prevent the test itself from adding too much latency.
241             size_t discardedInputFrames = 0;
242             for (;;) {
243                 size_t availToRead = audio_utils_fifo_availToRead(&pSles->fifo);
244                 if (availToRead < pSles->bufSizeInFrames * 2) {
245                     break;
246                 }
247                 ssize_t actual = audio_utils_fifo_read(&pSles->fifo, buffer, pSles->bufSizeInFrames);
248                 if (actual > 0) {
249                     discardedInputFrames += actual;
250                 }
251                 if (actual != (ssize_t) pSles->bufSizeInFrames) {
252                     break;
253                 }
254             }
255             if (discardedInputFrames > 0) {
256                 if (pSles->totalDiscardedInputFrames > 0) {
257                     __android_log_print(ANDROID_LOG_WARN, "sles_jni",
258                         "Discarded an additional %zu input frames after a total of %zu input frames"
259                         " had previously been discarded",
260                         discardedInputFrames, pSles->totalDiscardedInputFrames);
261                 }
262                 pSles->totalDiscardedInputFrames += discardedInputFrames;
263             }
264 
265             ssize_t actual = audio_utils_fifo_read(&(pSles->fifo), buffer, pSles->bufSizeInFrames);
266             if (actual != (ssize_t) pSles->bufSizeInFrames) {
267                 write(1, "/", 1);
268                 // on underrun from pipe, substitute silence
269                 memset(buffer, 0, pSles->bufSizeInFrames * pSles->channels * sizeof(short));
270             }
271 
272             if (pSles->injectImpulse == -1) {   // here we inject pulse
273 
274                 /*// Experimentally, a single frame impulse was insufficient to trigger feedback.
275                 // Also a Nyquist frequency signal was also insufficient, probably because
276                 // the response of output and/or input path was not adequate at high frequencies.
277                 // This short burst of a few cycles of square wave at Nyquist/4 found to work well.
278                 for (unsigned i = 0; i < pSles->bufSizeInFrames / 8; i += 8) {
279                     for (int j = 0; j < 8; j++) {
280                         for (unsigned k = 0; k < pSles->channels; k++) {
281                             ((short *) buffer)[(i + j) * pSles->channels + k] =
282                                                                             j < 4 ? 0x7FFF : 0x8000;
283                         }
284                     }
285                 }*/
286 
287                 //inject java generated tone
288                 for (unsigned i = 0; i < pSles->bufSizeInFrames; ++i) {
289                     for (unsigned k = 0; k < pSles->channels; ++k) {
290                         ((short *) buffer)[i * pSles->channels + k] = pSles->loopbackTone[i];
291                     }
292                 }
293 
294                 pSles->injectImpulse = 0;
295                 pSles->totalDiscardedInputFrames = 0;
296             }
297         } else if (pSles->testType == TEST_TYPE_BUFFER_PERIOD) {
298             double twoPi = M_PI * 2;
299             int maxShort = 32767;
300             float amplitude = 0.8;
301             short value;
302             double phaseIncrement = pSles->frequency1 / pSles->sampleRate;
303             bool isGlitchEnabled = false;
304             for (unsigned i = 0; i < pSles->bufSizeInFrames; i++) {
305                 value = (short) (sin(pSles->bufferTestPhase1) * maxShort * amplitude);
306                 for (unsigned k = 0; k < pSles->channels; ++k) {
307                     ((short *) buffer)[i* pSles->channels + k] = value;
308                 }
309 
310                 pSles->bufferTestPhase1 += twoPi * phaseIncrement;
311                 // insert glitches if isGlitchEnabled == true, and insert it for every second
312                 if (isGlitchEnabled && (pSles->count % pSles->sampleRate == 0)) {
313                     pSles->bufferTestPhase1 += twoPi * phaseIncrement;
314                 }
315 
316                 pSles->count++;
317 
318                 while (pSles->bufferTestPhase1 > twoPi) {
319                     pSles->bufferTestPhase1 -= twoPi;
320                 }
321             }
322         }
323 
324         // Enqueue the filled buffer for playing
325         result = (*(pSles->playerBufferQueue))->Enqueue(pSles->playerBufferQueue, buffer,
326                                                         pSles->bufSizeInBytes);
327         ASSERT_EQ(SL_RESULT_SUCCESS, result);
328 
329         // Update our model of the player queue
330         assert(pSles->txFront <= pSles->txBufCount);
331         assert(pSles->txRear <= pSles->txBufCount);
332         SLuint32 txRearNext = pSles->txRear + 1;
333         if (txRearNext > pSles->txBufCount) {
334             txRearNext = 0;
335         }
336         assert(txRearNext != pSles->txFront);
337         pSles->txBuffers[pSles->txRear] = buffer;
338         pSles->txRear = txRearNext;
339 
340     } //pSles not null
341 }
342 
343 // Used to set initial values for the bufferStats struct before values can be recorded.
initBufferStats(bufferStats * stats)344 void initBufferStats(bufferStats *stats) {
345     stats->buffer_period = new int[RANGE](); // initialized to zeros
346     stats->previous_time = {0,0};
347     stats->current_time = {0,0};
348 
349     stats->buffer_count = 0;
350     stats->max_buffer_period = 0;
351 
352     stats->measurement_count = 0;
353     stats->SDM = 0;
354     stats->var = 0;
355 }
356 
357 // Called in the beginning of playerCallback() to collect the interval between each callback.
358 // fdpStats is either NULL or a pointer to the buffer statistics for the full-duplex partner.
collectBufferPeriod(bufferStats * stats,bufferStats * fdpStats,callbackTimeStamps * timeStamps,short expectedBufferPeriod)359 void collectBufferPeriod(bufferStats *stats, bufferStats *fdpStats, callbackTimeStamps *timeStamps,
360                          short expectedBufferPeriod) {
361     clock_gettime(CLOCK_MONOTONIC, &(stats->current_time));
362 
363     if (timeStamps->startTime.tv_sec == 0 && timeStamps->startTime.tv_nsec == 0) {
364         timeStamps->startTime = stats->current_time;
365     }
366 
367     (stats->buffer_count)++;
368 
369     if (stats->previous_time.tv_sec != 0 && stats->buffer_count > BUFFER_PERIOD_DISCARD &&
370          (fdpStats == NULL || fdpStats->buffer_count > BUFFER_PERIOD_DISCARD_FULL_DUPLEX_PARTNER)) {
371 
372         int64_t callbackDuration = diffInNano(stats->previous_time, stats->current_time);
373 
374         bool outlier = updateBufferStats(stats, callbackDuration, expectedBufferPeriod);
375 
376         //recording timestamps of buffer periods not at expected buffer period
377         if (outlier) {
378             int64_t timeStamp = diffInNano(timeStamps->startTime, stats->current_time);
379             recordTimeStamp(timeStamps, callbackDuration, timeStamp);
380         }
381     }
382 
383     stats->previous_time = stats->current_time;
384 }
385 
386 // Records an outlier given the duration in nanoseconds and the number of nanoseconds
387 // between it and the start of the test.
recordTimeStamp(callbackTimeStamps * timeStamps,int64_t callbackDuration,int64_t timeStamp)388 void recordTimeStamp(callbackTimeStamps *timeStamps,
389                      int64_t callbackDuration, int64_t timeStamp) {
390     if (timeStamps->exceededCapacity) {
391         return;
392     }
393 
394     //only marked as exceeded if attempting to record a late callback after arrays full
395     if (timeStamps->index == timeStamps->capacity){
396         timeStamps->exceededCapacity = true;
397     } else {
398         timeStamps->callbackDurations[timeStamps->index] =
399                 (short) ((callbackDuration + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI);
400         timeStamps->timeStampsMs[timeStamps->index] =
401                 (int) ((timeStamp + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI);
402         timeStamps->index++;
403     }
404 }
405 
atomicSetIfGreater(volatile int32_t * addr,int32_t val)406 void atomicSetIfGreater(volatile int32_t *addr, int32_t val) {
407     // TODO: rewrite this to avoid the need for unbounded spinning
408     int32_t old;
409     do {
410         old = *addr;
411         if (val < old) return;
412     } while(!android_atomic_compare_exchange(&old, val, addr));
413 }
414 
415 // Updates the stats being collected about buffer periods. Returns true if this is an outlier.
updateBufferStats(bufferStats * stats,int64_t diff_in_nano,int expectedBufferPeriod)416 bool updateBufferStats(bufferStats *stats, int64_t diff_in_nano, int expectedBufferPeriod) {
417     stats->measurement_count++;
418 
419     // round up to nearest millisecond
420     int diff_in_milli = (int) ((diff_in_nano + NANOS_PER_MILLI - 1) / NANOS_PER_MILLI);
421 
422     if (diff_in_milli > stats->max_buffer_period) {
423         stats->max_buffer_period = diff_in_milli;
424     }
425 
426     // from 0 ms to 1000 ms, plus a sum of all instances > 1000ms
427     if (diff_in_milli >= (RANGE - 1)) {
428         (stats->buffer_period)[RANGE-1]++;
429     } else if (diff_in_milli >= 0) {
430         (stats->buffer_period)[diff_in_milli]++;
431     } else { // for diff_in_milli < 0
432         __android_log_print(ANDROID_LOG_INFO, "sles_player", "Having negative BufferPeriod.");
433     }
434 
435     int64_t delta = diff_in_nano - (int64_t) expectedBufferPeriod * NANOS_PER_MILLI;
436     stats->SDM += delta * delta;
437     if (stats->measurement_count > 1) {
438         stats->var = stats->SDM / stats->measurement_count;
439     }
440 
441     // check if the lateness is so bad that a systrace should be captured
442     // TODO: replace static threshold of lateness with a dynamic determination
443     if (diff_in_milli > expectedBufferPeriod + LATE_CALLBACK_CAPTURE_THRESHOLD) {
444         // TODO: log in a non-blocking way
445         //__android_log_print(ANDROID_LOG_INFO, "buffer_stats", "Callback late by %d ms",
446         //                    diff_in_milli - expectedBufferPeriod);
447         atomicSetIfGreater(&(stats->captureRank), diff_in_milli - expectedBufferPeriod);
448     }
449     return diff_in_milli > expectedBufferPeriod + LATE_CALLBACK_OUTLIER_THRESHOLD;
450 }
451 
slesCreateServer(sles_data * pSles,int samplingRate,int frameCount,int micSource,int performanceMode,int testType,double frequency1,char * byteBufferPtr,int byteBufferLength,short * loopbackTone,int maxRecordedLateCallbacks,int ignoreFirstFrames)452 int slesCreateServer(sles_data *pSles, int samplingRate, int frameCount, int micSource,
453                      int performanceMode,
454                      int testType, double frequency1, char *byteBufferPtr, int byteBufferLength,
455                      short *loopbackTone, int maxRecordedLateCallbacks, int ignoreFirstFrames) {
456     int status = SLES_FAIL;
457 
458     if (pSles != NULL) {
459 
460         //        adb shell slesTest_feedback -r1 -t1 -s48000 -f240 -i300 -e3 -o/sdcard/log.wav
461         //            r1 and t1 are the receive and transmit buffer counts, typically 1
462         //            s is the sample rate, typically 48000 or 44100
463         //            f is the frame count per buffer, typically 240 or 256
464         //            i is the number of milliseconds before impulse.  You may need to adjust this.
465         //            e is number of seconds to record
466         //            o is output .wav file name
467 
468 
469         //        // default values
470         //        SLuint32 rxBufCount = 1;     // -r#
471         //        SLuint32 txBufCount = 1;     // -t#
472         //        SLuint32 bufSizeInFrames = 240;  // -f#
473         //        SLuint32 channels = 1;       // -c#
474         //        SLuint32 sampleRate = 48000; // -s#
475         //        SLuint32 exitAfterSeconds = 3; // -e#
476         //        SLuint32 freeBufCount = 0;   // calculated
477         //        SLuint32 bufSizeInBytes = 0; // calculated
478         //        int injectImpulse = 300; // -i#i
479         //
480         //        // Storage area for the buffer queues
481         //        char **rxBuffers;
482         //        char **txBuffers;
483         //        char **freeBuffers;
484         //
485         //        // Buffer indices
486         //        SLuint32 rxFront;    // oldest recording
487         //        SLuint32 rxRear;     // next to be recorded
488         //        SLuint32 txFront;    // oldest playing
489         //        SLuint32 txRear;     // next to be played
490         //        SLuint32 freeFront;  // oldest free
491         //        SLuint32 freeRear;   // next to be freed
492         //
493         //        audio_utils_fifo fifo; //(*)
494         //        SLAndroidSimpleBufferQueueItf recorderBufferQueue;
495         //        SLBufferQueueItf playerBufferQueue;
496 
497         // default values
498         pSles->rxBufCount = 1;     // -r#
499         pSles->txBufCount = 1;     // -t#
500         pSles->bufSizeInFrames = frameCount;//240;  // -f#
501         pSles->channels = 1;       // -c#
502         pSles->sampleRate = samplingRate;//48000; // -s#
503         pSles->exitAfterSeconds = 3; // -e#
504         pSles->freeBufCount = 0;   // calculated
505         pSles->bufSizeInBytes = 0; // calculated
506         pSles->injectImpulse = 300; // -i#i
507         pSles->totalDiscardedInputFrames = 0;
508         pSles->ignoreFirstFrames = ignoreFirstFrames;
509 
510         // Storage area for the buffer queues
511         //        char **rxBuffers;
512         //        char **txBuffers;
513         //        char **freeBuffers;
514 
515         // Buffer indices
516         pSles->rxFront;    // oldest recording
517         pSles->rxRear;     // next to be recorded
518         pSles->txFront;    // oldest playing
519         pSles->txRear;     // next to be played
520         pSles->freeFront;  // oldest free
521         pSles->freeRear;   // next to be freed
522 
523         pSles->fifo; //(*)
524         pSles->fifo2Buffer = NULL;  //this fifo is for sending data to java code (to plot it)
525         pSles->recorderBufferQueue;
526         pSles->playerBufferQueue;
527 
528 
529 
530         // compute total free buffers as -r plus -t
531         pSles->freeBufCount = pSles->rxBufCount + pSles->txBufCount;
532         // compute buffer size
533         pSles->bufSizeInBytes = pSles->channels * pSles->bufSizeInFrames * sizeof(short);
534 
535         // Initialize free buffers
536         pSles->freeBuffers = (char **) calloc(pSles->freeBufCount + 1, sizeof(char *));
537         SLES_PRINTF("  calloc freeBuffers %zu bytes at %p",pSles->freeBufCount + 1,
538                     pSles->freeBuffers);
539         unsigned j;
540         for (j = 0; j < pSles->freeBufCount; ++j) {
541             pSles->freeBuffers[j] = (char *) malloc(pSles->bufSizeInBytes);
542             SLES_PRINTF(" buff%d malloc %zu bytes at %p",j, pSles->bufSizeInBytes,
543                         pSles->freeBuffers[j]);
544         }
545         pSles->freeFront = 0;
546         pSles->freeRear = pSles->freeBufCount;
547         pSles->freeBuffers[j] = NULL;
548 
549         // Initialize record queue
550         pSles->rxBuffers = (char **) calloc(pSles->rxBufCount + 1, sizeof(char *));
551         SLES_PRINTF("  calloc rxBuffers %zu bytes at %p",pSles->rxBufCount + 1, pSles->rxBuffers);
552         pSles->rxFront = 0;
553         pSles->rxRear = 0;
554 
555         // Initialize play queue
556         pSles->txBuffers = (char **) calloc(pSles->txBufCount + 1, sizeof(char *));
557         SLES_PRINTF("  calloc txBuffers %zu bytes at %p",pSles->txBufCount + 1, pSles->txBuffers);
558         pSles->txFront = 0;
559         pSles->txRear = 0;
560 
561         size_t frameSize = pSles->channels * sizeof(short);
562 #define FIFO_FRAMES 1024
563         pSles->fifoBuffer = new short[FIFO_FRAMES * pSles->channels];
564         audio_utils_fifo_init(&(pSles->fifo), FIFO_FRAMES, frameSize, pSles->fifoBuffer);
565 
566         //        SNDFILE *sndfile;
567         //        if (outFileName != NULL) {
568         // create .wav writer
569         //            SF_INFO info;
570         //            info.frames = 0;
571         //            info.samplerate = sampleRate;
572         //            info.channels = channels;
573         //            info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
574         //            sndfile = sf_open(outFileName, SFM_WRITE, &info);
575         //            if (sndfile != NULL) {
576 #define FIFO2_FRAMES 65536
577         pSles->fifo2Buffer = new short[FIFO2_FRAMES * pSles->channels];
578         audio_utils_fifo_init(&(pSles->fifo2), FIFO2_FRAMES, frameSize, pSles->fifo2Buffer);
579         //            } else {
580         //                fprintf(stderr, "sf_open failed\n");
581         //            }
582         //        } else {
583         //            sndfile = NULL;
584         //        }
585 
586         initBufferStats(&pSles->recorderBufferStats);
587         initBufferStats(&pSles->playerBufferStats);
588 
589         // init other variables needed for buffer test
590         pSles->testType = testType;
591         pSles->frequency1 = frequency1;
592         pSles->bufferTestPhase1 = 0;
593         pSles->count = 0;
594         pSles->byteBufferPtr = byteBufferPtr;
595         pSles->byteBufferLength = byteBufferLength;
596 
597         //init loopback tone
598         pSles->loopbackTone = loopbackTone;
599 
600         pSles->recorderTimeStamps = {
601             new int[maxRecordedLateCallbacks],      //int* timeStampsMs
602             new short[maxRecordedLateCallbacks],    //short* callbackDurations
603             0,                                      //short index
604             {0,0},                                  //struct timespec startTime;
605             maxRecordedLateCallbacks,               //int capacity
606             false                                   //bool exceededCapacity
607         };
608 
609         pSles->playerTimeStamps = {
610             new int[maxRecordedLateCallbacks],      //int* timeStampsMs
611             new short[maxRecordedLateCallbacks],    //short* callbackDurations;
612             0,                                      //short index
613             {0,0},                                  //struct timespec startTime;
614             maxRecordedLateCallbacks,               //int capacity
615             false                                   //bool exceededCapacity
616         };
617 
618         pSles->expectedBufferPeriod = (short) (
619                 round(pSles->bufSizeInFrames * MILLIS_PER_SECOND / (float) pSles->sampleRate));
620 
621         SLresult result;
622 
623         // create engine
624         pSles->engineObject;
625         result = slCreateEngine(&(pSles->engineObject), 0, NULL, 0, NULL, NULL);
626         ASSERT_EQ(SL_RESULT_SUCCESS, result);
627         result = (*(pSles->engineObject))->Realize(pSles->engineObject, SL_BOOLEAN_FALSE);
628         ASSERT_EQ(SL_RESULT_SUCCESS, result);
629         SLEngineItf engineEngine;
630         result = (*(pSles->engineObject))->GetInterface(pSles->engineObject, SL_IID_ENGINE,
631                 &engineEngine);
632         ASSERT_EQ(SL_RESULT_SUCCESS, result);
633 
634         // create output mix
635         pSles->outputmixObject;
636         result = (*engineEngine)->CreateOutputMix(engineEngine, &(pSles->outputmixObject), 0, NULL,
637                 NULL);
638         ASSERT_EQ(SL_RESULT_SUCCESS, result);
639         result = (*(pSles->outputmixObject))->Realize(pSles->outputmixObject, SL_BOOLEAN_FALSE);
640         ASSERT_EQ(SL_RESULT_SUCCESS, result);
641 
642         // create an audio player with buffer queue source and output mix sink
643         SLDataSource audiosrc;
644         SLDataSink audiosnk;
645         SLDataFormat_PCM pcm;
646         SLDataLocator_OutputMix locator_outputmix;
647         SLDataLocator_BufferQueue locator_bufferqueue_tx;
648         locator_bufferqueue_tx.locatorType = SL_DATALOCATOR_BUFFERQUEUE;
649         locator_bufferqueue_tx.numBuffers = pSles->txBufCount;
650         locator_outputmix.locatorType = SL_DATALOCATOR_OUTPUTMIX;
651         locator_outputmix.outputMix = pSles->outputmixObject;
652         pcm.formatType = SL_DATAFORMAT_PCM;
653         pcm.numChannels = pSles->channels;
654         pcm.samplesPerSec = pSles->sampleRate * 1000;
655         pcm.bitsPerSample = SL_PCMSAMPLEFORMAT_FIXED_16;
656         pcm.containerSize = 16;
657         pcm.channelMask = pSles->channels == 1 ? SL_SPEAKER_FRONT_CENTER :
658                 (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT);
659         pcm.endianness = SL_BYTEORDER_LITTLEENDIAN;
660         audiosrc.pLocator = &locator_bufferqueue_tx;
661         audiosrc.pFormat = &pcm;
662         audiosnk.pLocator = &locator_outputmix;
663         audiosnk.pFormat = NULL;
664         pSles->playerObject = NULL;
665         pSles->recorderObject = NULL;
666         SLInterfaceID ids_tx[2] = {SL_IID_BUFFERQUEUE, SL_IID_ANDROIDCONFIGURATION};
667         SLboolean flags_tx[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
668         result = (*engineEngine)->CreateAudioPlayer(engineEngine, &(pSles->playerObject),
669                 &audiosrc, &audiosnk, 2, ids_tx, flags_tx);
670         if (SL_RESULT_CONTENT_UNSUPPORTED == result) {
671             fprintf(stderr, "Could not create audio player (result %x), check sample rate\n",
672                     result);
673             SLES_PRINTF("ERROR: Could not create audio player (result %x), check sample rate\n",
674                                                      result);
675             goto cleanup;
676         }
677         ASSERT_EQ(SL_RESULT_SUCCESS, result);
678 
679         {
680            /* Get the Android configuration interface which is explicit */
681             SLAndroidConfigurationItf configItf;
682             result = (*(pSles->playerObject))->GetInterface(pSles->playerObject,
683                                                  SL_IID_ANDROIDCONFIGURATION, (void*)&configItf);
684             ASSERT_EQ(SL_RESULT_SUCCESS, result);
685 
686             /* Use the configuration interface to configure the player before it's realized */
687             if (performanceMode != -1) {
688                 SLuint32 performanceMode32 = performanceMode;
689                 result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
690                         &performanceMode32, sizeof(SLuint32));
691                 ASSERT_EQ(SL_RESULT_SUCCESS, result);
692             }
693 
694         }
695 
696         result = (*(pSles->playerObject))->Realize(pSles->playerObject, SL_BOOLEAN_FALSE);
697         ASSERT_EQ(SL_RESULT_SUCCESS, result);
698         SLPlayItf playerPlay;
699         result = (*(pSles->playerObject))->GetInterface(pSles->playerObject, SL_IID_PLAY,
700                 &playerPlay);
701         ASSERT_EQ(SL_RESULT_SUCCESS, result);
702         result = (*(pSles->playerObject))->GetInterface(pSles->playerObject, SL_IID_BUFFERQUEUE,
703                 &(pSles->playerBufferQueue));
704         ASSERT_EQ(SL_RESULT_SUCCESS, result);
705         result = (*(pSles->playerBufferQueue))->RegisterCallback(pSles->playerBufferQueue,
706                 playerCallback, pSles); //playerCallback is the name of callback function
707         ASSERT_EQ(SL_RESULT_SUCCESS, result);
708 
709         // Enqueue some zero buffers for the player
710         for (j = 0; j < pSles->txBufCount; ++j) {
711 
712             // allocate a free buffer
713             assert(pSles->freeFront != pSles->freeRear);
714             char *buffer = pSles->freeBuffers[pSles->freeFront];
715             if (++pSles->freeFront > pSles->freeBufCount) {
716                 pSles->freeFront = 0;
717             }
718 
719             // put on play queue
720             SLuint32 txRearNext = pSles->txRear + 1;
721             if (txRearNext > pSles->txBufCount) {
722                 txRearNext = 0;
723             }
724             assert(txRearNext != pSles->txFront);
725             pSles->txBuffers[pSles->txRear] = buffer;
726             pSles->txRear = txRearNext;
727             result = (*(pSles->playerBufferQueue))->Enqueue(pSles->playerBufferQueue,
728                     buffer, pSles->bufSizeInBytes);
729             ASSERT_EQ(SL_RESULT_SUCCESS, result);
730         }
731 
732         result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
733         ASSERT_EQ(SL_RESULT_SUCCESS, result);
734 
735         // Create an audio recorder with microphone device source and buffer queue sink.
736         // The buffer queue as sink is an Android-specific extension.
737         SLDataLocator_IODevice locator_iodevice;
738         SLDataLocator_AndroidSimpleBufferQueue locator_bufferqueue_rx;
739 
740         locator_iodevice.locatorType = SL_DATALOCATOR_IODEVICE;
741         locator_iodevice.deviceType = SL_IODEVICE_AUDIOINPUT;
742         locator_iodevice.deviceID = SL_DEFAULTDEVICEID_AUDIOINPUT;
743         locator_iodevice.device = NULL;
744 
745         audiosrc.pLocator = &locator_iodevice;
746         audiosrc.pFormat = NULL;
747 
748         locator_bufferqueue_rx.locatorType = SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE;
749         locator_bufferqueue_rx.numBuffers = pSles->rxBufCount;
750 
751         audiosnk.pLocator = &locator_bufferqueue_rx;
752         audiosnk.pFormat = &pcm;
753 
754         {   //why brackets here?
755             SLInterfaceID ids_rx[2] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
756                                        SL_IID_ANDROIDCONFIGURATION};
757             SLboolean flags_rx[2] = {SL_BOOLEAN_TRUE, SL_BOOLEAN_TRUE};
758             result = (*engineEngine)->CreateAudioRecorder(engineEngine, &(pSles->recorderObject),
759                     &audiosrc, &audiosnk, 2, ids_rx, flags_rx);
760             if (SL_RESULT_SUCCESS != result) {
761                 fprintf(stderr, "Could not create audio recorder (result %x), "
762                         "check sample rate and channel count\n", result);
763                 status = SLES_FAIL;
764 
765                 SLES_PRINTF("ERROR: Could not create audio recorder (result %x), "
766                              "check sample rate and channel count\n", result);
767                 goto cleanup;
768             }
769         }
770         ASSERT_EQ(SL_RESULT_SUCCESS, result);
771 
772         {
773            /* Get the Android configuration interface which is explicit */
774             SLAndroidConfigurationItf configItf;
775             result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
776                                                  SL_IID_ANDROIDCONFIGURATION, (void*)&configItf);
777             ASSERT_EQ(SL_RESULT_SUCCESS, result);
778 
779             SLuint32 presetValue = micSource;
780             //SL_ANDROID_RECORDING_PRESET_CAMCORDER;//SL_ANDROID_RECORDING_PRESET_NONE;
781 
782             /* Use the configuration interface to configure the recorder before it's realized */
783             if (presetValue != SL_ANDROID_RECORDING_PRESET_NONE) {
784                 result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_RECORDING_PRESET,
785                         &presetValue, sizeof(SLuint32));
786                 ASSERT_EQ(SL_RESULT_SUCCESS, result);
787             }
788             if (performanceMode != -1) {
789                 SLuint32 performanceMode32 = performanceMode;
790                 result = (*configItf)->SetConfiguration(configItf, SL_ANDROID_KEY_PERFORMANCE_MODE,
791                         &performanceMode32, sizeof(SLuint32));
792                 ASSERT_EQ(SL_RESULT_SUCCESS, result);
793             }
794 
795         }
796 
797         result = (*(pSles->recorderObject))->Realize(pSles->recorderObject, SL_BOOLEAN_FALSE);
798         ASSERT_EQ(SL_RESULT_SUCCESS, result);
799 
800         SLRecordItf recorderRecord;
801         result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject, SL_IID_RECORD,
802                 &recorderRecord);
803         ASSERT_EQ(SL_RESULT_SUCCESS, result);
804 
805         result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
806                 SL_IID_ANDROIDSIMPLEBUFFERQUEUE, &(pSles->recorderBufferQueue));
807         ASSERT_EQ(SL_RESULT_SUCCESS, result);
808 
809         result = (*(pSles->recorderBufferQueue))->RegisterCallback(pSles->recorderBufferQueue,
810                 recorderCallback, pSles);
811         ASSERT_EQ(SL_RESULT_SUCCESS, result);
812 
813         // Enqueue some empty buffers for the recorder
814         for (j = 0; j < pSles->rxBufCount; ++j) {
815 
816             // allocate a free buffer
817             assert(pSles->freeFront != pSles->freeRear);
818             char *buffer = pSles->freeBuffers[pSles->freeFront];
819             if (++pSles->freeFront > pSles->freeBufCount) {
820                 pSles->freeFront = 0;
821             }
822 
823             // put on record queue
824             SLuint32 rxRearNext = pSles->rxRear + 1;
825             if (rxRearNext > pSles->rxBufCount) {
826                 rxRearNext = 0;
827             }
828             assert(rxRearNext != pSles->rxFront);
829             pSles->rxBuffers[pSles->rxRear] = buffer;
830             pSles->rxRear = rxRearNext;
831             result = (*(pSles->recorderBufferQueue))->Enqueue(pSles->recorderBufferQueue,
832                     buffer, pSles->bufSizeInBytes);
833             ASSERT_EQ(SL_RESULT_SUCCESS, result);
834         }
835 
836         // Kick off the recorder
837         result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_RECORDING);
838         ASSERT_EQ(SL_RESULT_SUCCESS, result);
839 
840 
841 
842         // Tear down the objects and exit
843         status = SLES_SUCCESS;
844         cleanup:
845 
846         SLES_PRINTF("Finished initialization with status: %d", status);
847 
848         int xx = 1;
849 
850     }
851     return status;
852 }
853 
854 // Read data from fifo2Buffer and store into pSamples.
slesProcessNext(sles_data * pSles,double * pSamples,long maxSamples)855 int slesProcessNext(sles_data *pSles, double *pSamples, long maxSamples) {
856     //int status = SLES_FAIL;
857 
858     SLES_PRINTF("slesProcessNext: pSles = %p, currentSample: %p,  maxSamples = %ld",
859                 pSles, pSamples, maxSamples);
860 
861     int samplesRead = 0;
862 
863     int currentSample = 0;
864     double *pCurrentSample = pSamples;
865     int maxValue = 32768;
866 
867     if (pSles != NULL) {
868 
869         SLresult result;
870         for (int i = 0; i < 10; i++) {
871             usleep(100000);         // sleep for 0.1s
872             if (pSles->fifo2Buffer != NULL) {
873                 for (;;) {
874                     short buffer[pSles->bufSizeInFrames * pSles->channels];
875                     ssize_t actual = audio_utils_fifo_read(&(pSles->fifo2), buffer,
876                             pSles->bufSizeInFrames);
877                     if (actual <= 0)
878                         break;
879                     {
880                         for (int jj = 0; jj < actual && currentSample < maxSamples; jj++) {
881                             *(pCurrentSample++) = ((double) buffer[jj]) / maxValue;
882                             currentSample++;
883                         }
884                     }
885                     samplesRead += actual;
886                 }
887             }
888             if (pSles->injectImpulse > 0) {
889                 if (pSles->injectImpulse <= 100) {
890                     pSles->injectImpulse = -1;
891                     write(1, "I", 1);
892                 } else {
893                     if ((pSles->injectImpulse % 1000) < 100) {
894                         write(1, "i", 1);
895                     }
896                     pSles->injectImpulse -= 100;
897                 }
898             } else if (i == 9) {
899                 write(1, ".", 1);
900             }
901         }
902         SLBufferQueueState playerBQState;
903         result = (*(pSles->playerBufferQueue))->GetState(pSles->playerBufferQueue,
904                   &playerBQState);
905         ASSERT_EQ(SL_RESULT_SUCCESS, result);
906         SLAndroidSimpleBufferQueueState recorderBQState;
907         result = (*(pSles->recorderBufferQueue))->GetState(pSles->recorderBufferQueue,
908                   &recorderBQState);
909         ASSERT_EQ(SL_RESULT_SUCCESS, result);
910 
911         SLES_PRINTF("End of slesProcessNext: pSles = %p, samplesRead = %d, maxSamples = %ld",
912                     pSles, samplesRead, maxSamples);
913     }
914     return samplesRead;
915 }
916 
917 
slesDestroyServer(sles_data * pSles)918 int slesDestroyServer(sles_data *pSles) {
919     int status = SLES_FAIL;
920 
921      SLES_PRINTF("Start slesDestroyServer: pSles = %p", pSles);
922 
923     if (pSles != NULL) {
924         if (NULL != pSles->playerObject) {
925             SLES_PRINTF("stopping player...");
926             SLPlayItf playerPlay;
927             SLresult result = (*(pSles->playerObject))->GetInterface(pSles->playerObject,
928                                                         SL_IID_PLAY, &playerPlay);
929 
930             ASSERT_EQ(SL_RESULT_SUCCESS, result);
931 
932             //stop player and recorder if they exist
933              result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_STOPPED);
934             ASSERT_EQ(SL_RESULT_SUCCESS, result);
935         }
936 
937         if (NULL != pSles->recorderObject) {
938             SLES_PRINTF("stopping recorder...");
939             SLRecordItf recorderRecord;
940             SLresult result = (*(pSles->recorderObject))->GetInterface(pSles->recorderObject,
941                                                           SL_IID_RECORD, &recorderRecord);
942             ASSERT_EQ(SL_RESULT_SUCCESS, result);
943 
944             result = (*recorderRecord)->SetRecordState(recorderRecord, SL_RECORDSTATE_STOPPED);
945             ASSERT_EQ(SL_RESULT_SUCCESS, result);
946         }
947 
948         usleep(1000);
949 
950         audio_utils_fifo_deinit(&(pSles->fifo));
951         delete[] pSles->fifoBuffer;
952 
953         SLES_PRINTF("slesDestroyServer 2");
954 
955         //        if (sndfile != NULL) {
956         audio_utils_fifo_deinit(&(pSles->fifo2));
957         delete[] pSles->fifo2Buffer;
958 
959         SLES_PRINTF("slesDestroyServer 3");
960 
961         //            sf_close(sndfile);
962         //        }
963         if (NULL != pSles->playerObject) {
964             (*(pSles->playerObject))->Destroy(pSles->playerObject);
965         }
966 
967         SLES_PRINTF("slesDestroyServer 4");
968 
969         if (NULL != pSles->recorderObject) {
970             (*(pSles->recorderObject))->Destroy(pSles->recorderObject);
971         }
972 
973         SLES_PRINTF("slesDestroyServer 5");
974 
975         (*(pSles->outputmixObject))->Destroy(pSles->outputmixObject);
976         SLES_PRINTF("slesDestroyServer 6");
977         (*(pSles->engineObject))->Destroy(pSles->engineObject);
978         SLES_PRINTF("slesDestroyServer 7");
979 
980         //free buffers
981         if (NULL != pSles->freeBuffers) {
982             for (unsigned j = 0; j < pSles->freeBufCount; ++j) {
983                 if (NULL != pSles->freeBuffers[j]) {
984                     SLES_PRINTF(" free buff%d at %p",j, pSles->freeBuffers[j]);
985                     free (pSles->freeBuffers[j]);
986                 }
987             }
988             SLES_PRINTF("  free freeBuffers at %p", pSles->freeBuffers);
989             free(pSles->freeBuffers);
990         } else {
991             SLES_PRINTF("  freeBuffers NULL, no need to free");
992         }
993 
994 
995         if (NULL != pSles->rxBuffers) {
996             SLES_PRINTF("  free rxBuffers at %p", pSles->rxBuffers);
997             free(pSles->rxBuffers);
998         } else {
999             SLES_PRINTF("  rxBuffers NULL, no need to free");
1000         }
1001 
1002         if (NULL != pSles->txBuffers) {
1003             SLES_PRINTF("  free txBuffers at %p", pSles->txBuffers);
1004             free(pSles->txBuffers);
1005         } else {
1006             SLES_PRINTF("  txBuffers NULL, no need to free");
1007         }
1008 
1009 
1010         status = SLES_SUCCESS;
1011     }
1012     SLES_PRINTF("End slesDestroyServer: status = %d", status);
1013     return status;
1014 }
1015 
1016 
slesGetRecorderBufferPeriod(sles_data * pSles)1017 int* slesGetRecorderBufferPeriod(sles_data *pSles) {
1018     return pSles->recorderBufferStats.buffer_period;
1019 }
1020 
slesGetRecorderMaxBufferPeriod(sles_data * pSles)1021 int slesGetRecorderMaxBufferPeriod(sles_data *pSles) {
1022     return pSles->recorderBufferStats.max_buffer_period;
1023 }
1024 
slesGetRecorderVarianceBufferPeriod(sles_data * pSles)1025 int64_t slesGetRecorderVarianceBufferPeriod(sles_data *pSles) {
1026     return pSles->recorderBufferStats.var;
1027 }
1028 
slesGetPlayerBufferPeriod(sles_data * pSles)1029 int* slesGetPlayerBufferPeriod(sles_data *pSles) {
1030     return pSles->playerBufferStats.buffer_period;
1031 }
1032 
slesGetPlayerMaxBufferPeriod(sles_data * pSles)1033 int slesGetPlayerMaxBufferPeriod(sles_data *pSles) {
1034     return pSles->playerBufferStats.max_buffer_period;
1035 }
1036 
slesGetPlayerVarianceBufferPeriod(sles_data * pSles)1037 int64_t slesGetPlayerVarianceBufferPeriod(sles_data *pSles) {
1038     return pSles->playerBufferStats.var;
1039 }
1040 
slesGetCaptureRank(sles_data * pSles)1041 int slesGetCaptureRank(sles_data *pSles) {
1042     // clear the capture flags since they're being handled now
1043     int recorderRank = android_atomic_exchange(0, &pSles->recorderBufferStats.captureRank);
1044     int playerRank = android_atomic_exchange(0, &pSles->playerBufferStats.captureRank);
1045 
1046     if (recorderRank > playerRank) {
1047         return recorderRank;
1048     } else {
1049         return playerRank;
1050     }
1051 }
1052