• 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 package org.drrickorang.loopback;
18 
19 import java.nio.ByteBuffer;
20 import java.util.Arrays;
21 
22 import android.content.Context;
23 import android.media.AudioManager;
24 import android.media.AudioTrack;
25 import android.os.Build;
26 import android.os.Handler;
27 import android.os.Message;
28 import android.util.Log;
29 
30 
31 /**
32  * A thread/audio track based audio synth.
33  */
34 
35 public class NativeAudioThread extends Thread {
36     private static final String TAG = "NativeAudioThread";
37 
38     // for latency test
39     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_STARTED = 891;
40     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_ERROR = 892;
41     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_COMPLETE = 893;
42     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_COMPLETE_ERRORS = 894;
43     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_STOP = 895;
44 
45     // for buffer test
46     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_STARTED = 896;
47     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_ERROR = 897;
48     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_COMPLETE = 898;
49     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_COMPLETE_ERRORS = 899;
50     static final int LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_STOP = 900;
51 
52     public boolean  mIsRunning = false;
53     public int      mSessionId;
54     public double[] mSamples; // store samples that will be shown on WavePlotView
55     int             mSamplesIndex;
56 
57     private int mThreadType;
58     private int mTestType;
59     private int mSamplingRate;
60     private int mMinPlayerBufferSizeInBytes = 0;
61     private int mMinRecorderBuffSizeInBytes = 0; // currently not used
62     private int mMicSource;
63     private int mPerformanceMode = -1;
64     private int mIgnoreFirstFrames;
65 
66     private boolean mIsRequestStop = false;
67     private Handler mMessageHandler;
68     private boolean isDestroying = false;
69     private boolean hasDestroyingErrors = false;
70 
71     // for buffer test
72     private int[]   mRecorderBufferPeriod;
73     private int     mRecorderMaxBufferPeriod;
74     private double  mRecorderStdDevBufferPeriod;
75     private int[]   mPlayerBufferPeriod;
76     private int     mPlayerMaxBufferPeriod;
77     private double  mPlayerStdDevBufferPeriod;
78     private BufferCallbackTimes mPlayerCallbackTimes;
79     private BufferCallbackTimes mRecorderCallbackTimes;
80     private int     mBufferTestWavePlotDurationInSeconds;
81     private double  mFrequency1 = Constant.PRIME_FREQUENCY_1;
82     private double  mFrequency2 = Constant.PRIME_FREQUENCY_2; // not actually used
83     private int     mBufferTestDurationInSeconds;
84     private int     mFFTSamplingSize;
85     private int     mFFTOverlapSamples;
86     private int[]   mAllGlitches;
87     private boolean mGlitchingIntervalTooLong;
88     private final CaptureHolder mCaptureHolder;
89 
90     private PipeByteBuffer        mPipeByteBuffer;
91     private GlitchDetectionThread mGlitchDetectionThread;
92 
93     /** Check if it's safe to use getProperty(). */
isSafeToUseGetProperty()94     static boolean isSafeToUseGetProperty() {
95         return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1;
96     }
97 
computeDefaultSettings(Context context, int threadType, int performanceMode)98     public static TestSettings computeDefaultSettings(Context context,
99             int threadType, int performanceMode) {
100         TestSettings nativeResult = nativeComputeDefaultSettings(
101                 Constant.BYTES_PER_FRAME, threadType, performanceMode);
102         if (nativeResult != null) {
103             return nativeResult;
104         }
105 
106         int samplingRate = AudioTrack.getNativeOutputSampleRate(AudioManager.STREAM_MUSIC);
107         int minBufferSizeInFrames = 1024;
108         if (isSafeToUseGetProperty()) {
109             AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
110             String value = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
111             minBufferSizeInFrames = Integer.parseInt(value);
112         }
113         int minBufferSizeInBytes = Constant.BYTES_PER_FRAME * minBufferSizeInFrames;
114         return new TestSettings(samplingRate, minBufferSizeInBytes, minBufferSizeInBytes);
115     }
116 
NativeAudioThread(int threadType, int samplingRate, int playerBufferInBytes, int recorderBufferInBytes, int micSource, int performanceMode, int testType, int bufferTestDurationInSeconds, int bufferTestWavePlotDurationInSeconds, int ignoreFirstFrames, CaptureHolder captureHolder)117     public NativeAudioThread(int threadType, int samplingRate, int playerBufferInBytes,
118                              int recorderBufferInBytes, int micSource, int performanceMode,
119                              int testType, int bufferTestDurationInSeconds,
120                              int bufferTestWavePlotDurationInSeconds, int ignoreFirstFrames,
121                              CaptureHolder captureHolder) {
122         mThreadType = threadType;
123         mSamplingRate = samplingRate;
124         mMinPlayerBufferSizeInBytes = playerBufferInBytes;
125         mMinRecorderBuffSizeInBytes = recorderBufferInBytes;
126         mMicSource = micSource;
127         mPerformanceMode = performanceMode;
128         mTestType = testType;
129         mBufferTestDurationInSeconds = bufferTestDurationInSeconds;
130         mBufferTestWavePlotDurationInSeconds = bufferTestWavePlotDurationInSeconds;
131         mIgnoreFirstFrames = ignoreFirstFrames;
132         mCaptureHolder = captureHolder;
133         setName("Loopback_NativeAudio");
134     }
135 
NativeAudioThread(NativeAudioThread old)136     public NativeAudioThread(NativeAudioThread old) {
137         mThreadType = old.mThreadType;
138         mSamplingRate = old.mSamplingRate;
139         mMinPlayerBufferSizeInBytes = old.mMinPlayerBufferSizeInBytes;
140         mMinRecorderBuffSizeInBytes = old.mMinRecorderBuffSizeInBytes;
141         mMicSource = old.mMicSource;
142         mPerformanceMode = old.mPerformanceMode;
143         mTestType = old.mTestType;
144         mBufferTestDurationInSeconds = old.mBufferTestDurationInSeconds;
145         mBufferTestWavePlotDurationInSeconds = old.mBufferTestWavePlotDurationInSeconds;
146         mIgnoreFirstFrames = old.mIgnoreFirstFrames;
147         mCaptureHolder = old.mCaptureHolder;
148         setName("Loopback_NativeAudio");
149     }
150 
151     //JNI load
152     static {
153         try {
154             System.loadLibrary("loopback");
155         } catch (UnsatisfiedLinkError e) {
156             log("Error loading loopback JNI library");
157             e.printStackTrace();
158         }
159         /* TODO: gracefully fail/notify if the library can't be loaded */
160     }
161 
162 
163     //jni calls
nativeComputeDefaultSettings( int bytesPerFrame, int threadType, int performanceMode)164     public static native TestSettings nativeComputeDefaultSettings(
165             int bytesPerFrame, int threadType, int performanceMode);
nativeInit(int threadType, int samplingRate, int frameCount, int micSource, int performanceMode, int testType, double frequency1, ByteBuffer byteBuffer, short[] sincTone, int maxRecordedLateCallbacks, int ignoreFirstFrames)166     public native long  nativeInit(int threadType,
167                                  int samplingRate, int frameCount, int micSource,
168                                  int performanceMode,
169                                  int testType, double frequency1, ByteBuffer byteBuffer,
170                                  short[] sincTone, int maxRecordedLateCallbacks,
171                                  int ignoreFirstFrames);
nativeProcessNext(long nativeHandle, double[] samples, long offset)172     public native int   nativeProcessNext(long nativeHandle, double[] samples, long offset);
nativeDestroy(long nativeHandle)173     public native int   nativeDestroy(long nativeHandle);
174 
175     // to get buffer period data
nativeGetRecorderBufferPeriod(long nativeHandle)176     public native int[]  nativeGetRecorderBufferPeriod(long nativeHandle);
nativeGetRecorderMaxBufferPeriod(long nativeHandle)177     public native int    nativeGetRecorderMaxBufferPeriod(long nativeHandle);
nativeGetRecorderVarianceBufferPeriod(long nativeHandle)178     public native double nativeGetRecorderVarianceBufferPeriod(long nativeHandle);
nativeGetPlayerBufferPeriod(long nativeHandle)179     public native int[]  nativeGetPlayerBufferPeriod(long nativeHandle);
nativeGetPlayerMaxBufferPeriod(long nativeHandle)180     public native int    nativeGetPlayerMaxBufferPeriod(long nativeHandle);
nativeGetPlayerVarianceBufferPeriod(long nativeHandle)181     public native double nativeGetPlayerVarianceBufferPeriod(long nativeHandle);
nativeGetPlayerCallbackTimeStamps(long nativeHandle)182     public native BufferCallbackTimes nativeGetPlayerCallbackTimeStamps(long nativeHandle);
nativeGetRecorderCallbackTimeStamps(long nativeHandle)183     public native BufferCallbackTimes nativeGetRecorderCallbackTimeStamps(long nativeHandle);
184 
nativeGetCaptureRank(long nativeHandle)185     public native int nativeGetCaptureRank(long nativeHandle);
186 
187 
run()188     public void run() {
189         setPriority(Thread.MAX_PRIORITY);
190         mIsRunning = true;
191 
192         //erase output buffer
193         if (mSamples != null)
194             mSamples = null;
195 
196         //start playing
197         log(" Started capture test");
198         if (mMessageHandler != null) {
199             Message msg = Message.obtain();
200             switch (mTestType) {
201             case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY:
202                 msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_STARTED;
203                 break;
204             case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD:
205                 msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_STARTED;
206                 break;
207             }
208             mMessageHandler.sendMessage(msg);
209         }
210 
211         // generate windowed tone use for loopback test
212         short loopbackTone[] = new short[mMinPlayerBufferSizeInBytes / Constant.BYTES_PER_FRAME];
213         if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY) {
214             ToneGeneration sincToneGen = new RampedSineTone(mSamplingRate,
215                     Constant.LOOPBACK_FREQUENCY);
216             int sincLength = Math.min(Constant.LOOPBACK_SAMPLE_FRAMES, loopbackTone.length);
217             sincToneGen.generateTone(loopbackTone, sincLength);
218         }
219 
220         log(String.format("about to init, sampling rate: %d, buffer:%d", mSamplingRate,
221                 mMinPlayerBufferSizeInBytes / Constant.BYTES_PER_FRAME));
222 
223         // mPipeByteBuffer is only used in buffer test
224         mPipeByteBuffer = new PipeByteBuffer(Constant.MAX_SHORTS);
225         long startTimeMs = System.currentTimeMillis();
226         long nativeHandle = nativeInit(mThreadType, mSamplingRate,
227                 mMinPlayerBufferSizeInBytes / Constant.BYTES_PER_FRAME, mMicSource,
228                 mPerformanceMode, mTestType,
229                 mFrequency1, mPipeByteBuffer.getByteBuffer(), loopbackTone,
230                 mBufferTestDurationInSeconds * Constant.MAX_RECORDED_LATE_CALLBACKS_PER_SECOND,
231                 mIgnoreFirstFrames);
232         log(String.format("nativeHandle = 0x%X", nativeHandle));
233 
234         if (nativeHandle == 0) {
235             //notify error!!
236             log(" ERROR at JNI initialization");
237             if (mMessageHandler != null) {
238                 Message msg = Message.obtain();
239                 switch (mTestType) {
240                 case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY:
241                     msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_ERROR;
242                     break;
243                 case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD:
244                     msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_ERROR;
245                     break;
246                 }
247                 mMessageHandler.sendMessage(msg);
248             }
249         } else {
250             // wait a little bit
251             try {
252                 final int setUpTime = 10;
253                 sleep(setUpTime); //just to let it start properly
254             } catch (InterruptedException e) {
255                 e.printStackTrace();
256             }
257 
258 
259             int totalSamplesRead = 0;
260             switch (mTestType) {
261             case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY:
262                 final int latencyTestDurationInSeconds = 2;
263                 int nNewSize = (int) (1.1 * mSamplingRate * latencyTestDurationInSeconds);
264                 mSamples = new double[nNewSize];
265                 mSamplesIndex = 0; //reset index
266                 Arrays.fill(mSamples, 0);
267 
268                 //TODO use a ByteBuffer to retrieve recorded data instead
269                 long offset = 0;
270                 // retrieve native recorder's recorded data
271                 for (int ii = 0; ii < latencyTestDurationInSeconds; ii++) {
272                     log(String.format("block %d...", ii));
273                     int samplesRead = nativeProcessNext(nativeHandle, mSamples, offset);
274                     totalSamplesRead += samplesRead;
275                     offset += samplesRead;
276                     log(" [" + ii + "] jni samples read:" + samplesRead +
277                         "  currentOffset:" + offset);
278                 }
279 
280                 log(String.format(" samplesRead: %d, sampleOffset:%d", totalSamplesRead, offset));
281                 log("about to destroy...");
282                 break;
283             case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD:
284                 setUpGlitchDetectionThread();
285                 long testDurationMs = mBufferTestDurationInSeconds * Constant.MILLIS_PER_SECOND;
286                 long elapsedTimeMs = System.currentTimeMillis() - startTimeMs;
287                 while (elapsedTimeMs < testDurationMs) {
288                     if (mIsRequestStop) {
289                         break;
290                     } else {
291                         int rank = nativeGetCaptureRank(nativeHandle);
292                         if (rank > 0) {
293                             //log("Late callback detected");
294                             mCaptureHolder.captureState(rank);
295                         }
296                         try {
297                             final int setUpTime = 100;
298                             sleep(setUpTime); //just to let it start properly
299                         } catch (InterruptedException e) {
300                             e.printStackTrace();
301                         }
302                         elapsedTimeMs = System.currentTimeMillis() - startTimeMs;
303                     }
304 
305                 }
306                 break;
307 
308 
309             }
310 
311             // collect buffer period data
312             mRecorderBufferPeriod = nativeGetRecorderBufferPeriod(nativeHandle);
313             mRecorderMaxBufferPeriod = nativeGetRecorderMaxBufferPeriod(nativeHandle);
314             mRecorderStdDevBufferPeriod = Math.sqrt(nativeGetRecorderVarianceBufferPeriod(
315                     nativeHandle));
316             mPlayerBufferPeriod = nativeGetPlayerBufferPeriod(nativeHandle);
317             mPlayerMaxBufferPeriod = nativeGetPlayerMaxBufferPeriod(nativeHandle);
318             mPlayerStdDevBufferPeriod = Math.sqrt(nativeGetPlayerVarianceBufferPeriod(
319                     nativeHandle));
320 
321             mPlayerCallbackTimes = nativeGetPlayerCallbackTimeStamps(nativeHandle);
322             mRecorderCallbackTimes = nativeGetRecorderCallbackTimeStamps(nativeHandle);
323 
324             // get glitches data only for buffer test
325             if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD) {
326                 mAllGlitches = mGlitchDetectionThread.getGlitches();
327                 mSamples = mGlitchDetectionThread.getWaveData();
328                 mGlitchingIntervalTooLong = mGlitchDetectionThread.getGlitchingIntervalTooLong();
329                 endDetecting();
330             }
331 
332             if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY) {
333                 mCaptureHolder.captureState(0);
334             }
335 
336             runDestroy(nativeHandle);
337 
338             final int maxTry = 20;
339             int tryCount = 0;
340             while (isDestroying) {
341                 try {
342                     sleep(40);
343                 } catch (InterruptedException e) {
344                     e.printStackTrace();
345                 }
346 
347                 tryCount++;
348                 log("destroy try: " + tryCount);
349 
350                 if (tryCount >= maxTry) {
351                     hasDestroyingErrors = true;
352                     log("WARNING: waited for max time to properly destroy JNI.");
353                     break;
354                 }
355             }
356             log(String.format("after destroying. TotalSamplesRead = %d", totalSamplesRead));
357 
358             // for buffer test samples won't be read into here
359             if (mTestType == Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY
360                 && totalSamplesRead == 0) {
361                 //hasDestroyingErrors = true;
362                 log("Warning: Latency test reads no sample from native recorder!");
363             }
364 
365             endTest();
366         }
367     }
368 
369 
requestStopTest()370     public void requestStopTest() {
371         mIsRequestStop = true;
372     }
373 
374 
375     /** Set up parameters needed for GlitchDetectionThread, then create and run this thread. */
setUpGlitchDetectionThread()376     private void setUpGlitchDetectionThread() {
377         final int targetFFTMs = 20; // we want each FFT to cover 20ms of samples
378         mFFTSamplingSize = targetFFTMs * mSamplingRate / Constant.MILLIS_PER_SECOND;
379         // round to the nearest power of 2
380         mFFTSamplingSize = (int) Math.pow(2, Math.round(Math.log(mFFTSamplingSize) / Math.log(2)));
381 
382         if (mFFTSamplingSize < 2) {
383             mFFTSamplingSize = 2; // mFFTSamplingSize should be at least 2
384         }
385         mFFTOverlapSamples = mFFTSamplingSize / 2; // mFFTOverlapSamples is half of mFFTSamplingSize
386 
387         mGlitchDetectionThread = new GlitchDetectionThread(mFrequency1, mFrequency2, mSamplingRate,
388             mFFTSamplingSize, mFFTOverlapSamples, mBufferTestDurationInSeconds,
389             mBufferTestWavePlotDurationInSeconds, mPipeByteBuffer, mCaptureHolder);
390         mGlitchDetectionThread.start();
391     }
392 
393 
endDetecting()394     public void endDetecting() {
395         mPipeByteBuffer.flush();
396         mPipeByteBuffer = null;
397         mGlitchDetectionThread.requestStop();
398         GlitchDetectionThread tempThread = mGlitchDetectionThread;
399         mGlitchDetectionThread = null;
400         try {
401             tempThread.join(Constant.JOIN_WAIT_TIME_MS);
402         } catch (InterruptedException e) {
403             e.printStackTrace();
404         }
405     }
406 
407 
setMessageHandler(Handler messageHandler)408     public void setMessageHandler(Handler messageHandler) {
409         mMessageHandler = messageHandler;
410     }
411 
412 
runDestroy(final long localNativeHandle)413     private void runDestroy(final long localNativeHandle) {
414         isDestroying = true;
415 
416         //start thread
417         Thread thread = new Thread(new Runnable() {
418             public void run() {
419                 isDestroying = true;
420                 log("**Start runnable destroy");
421 
422                 int status = nativeDestroy(localNativeHandle);
423                 log(String.format("**End runnable destroy native delete status: %d", status));
424                 isDestroying = false;
425             }
426         });
427 
428         thread.start();
429         log("end of runDestroy()");
430     }
431 
432 
433     /** not doing real work, just to keep consistency with LoopbackAudioThread. */
runTest()434     public void runTest() {
435 
436     }
437 
438 
439     /** not doing real work, just to keep consistency with LoopbackAudioThread. */
runBufferTest()440     public void runBufferTest() {
441 
442     }
443 
444 
endTest()445     public void endTest() {
446        log("--Ending capture test--");
447        if (mMessageHandler != null) {
448            Message msg = Message.obtain();
449            if (hasDestroyingErrors) {
450                switch (mTestType) {
451                    case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY:
452                        msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_COMPLETE_ERRORS;
453                        break;
454                    case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD:
455                        msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_COMPLETE_ERRORS;
456                        break;
457                }
458            } else if (mIsRequestStop) {
459                switch (mTestType) {
460                    case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY:
461                        msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_STOP;
462                        break;
463                    case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD:
464                        msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_STOP;
465                        break;
466                }
467            } else {
468                switch (mTestType) {
469                case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_LATENCY:
470                    msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_LATENCY_REC_COMPLETE;
471                    break;
472                case Constant.LOOPBACK_PLUG_AUDIO_THREAD_TEST_TYPE_BUFFER_PERIOD:
473                    msg.what = LOOPBACK_NATIVE_AUDIO_THREAD_MESSAGE_BUFFER_REC_COMPLETE;
474                    break;
475                }
476            }
477 
478            mMessageHandler.sendMessage(msg);
479        }
480     }
481 
482 
finish()483     public void finish() {
484         mIsRunning = false;
485     }
486 
487 
log(String msg)488     private static void log(String msg) {
489         Log.v(TAG, msg);
490     }
491 
492 
getWaveData()493     double[] getWaveData() {
494         return mSamples;
495     }
496 
497 
getRecorderBufferPeriod()498     public int[] getRecorderBufferPeriod() {
499         return mRecorderBufferPeriod;
500     }
501 
getRecorderMaxBufferPeriod()502     public int getRecorderMaxBufferPeriod() {
503         return mRecorderMaxBufferPeriod;
504     }
505 
getRecorderStdDevBufferPeriod()506     public double getRecorderStdDevBufferPeriod() {
507         return mRecorderStdDevBufferPeriod;
508     }
509 
getPlayerBufferPeriod()510     public int[] getPlayerBufferPeriod() {
511         return mPlayerBufferPeriod;
512     }
513 
getPlayerMaxBufferPeriod()514     public int getPlayerMaxBufferPeriod() {
515         return mPlayerMaxBufferPeriod;
516     }
517 
getPlayerStdDevBufferPeriod()518     public double getPlayerStdDevBufferPeriod() {
519         return mPlayerStdDevBufferPeriod;
520     }
521 
getNativeAllGlitches()522     public int[] getNativeAllGlitches() {
523         return mAllGlitches;
524     }
525 
526 
getGlitchingIntervalTooLong()527     public boolean getGlitchingIntervalTooLong() {
528         return mGlitchingIntervalTooLong;
529     }
530 
531 
getNativeFFTSamplingSize()532     public int getNativeFFTSamplingSize() {
533         return mFFTSamplingSize;
534     }
535 
536 
getNativeFFTOverlapSamples()537     public int getNativeFFTOverlapSamples() {
538         return mFFTOverlapSamples;
539     }
540 
541 
getDurationInSeconds()542     public int getDurationInSeconds() {
543         return mBufferTestDurationInSeconds;
544     }
545 
getPlayerCallbackTimes()546     public BufferCallbackTimes getPlayerCallbackTimes() {
547         return mPlayerCallbackTimes;
548     }
549 
getRecorderCallbackTimes()550     public BufferCallbackTimes getRecorderCallbackTimes() {
551         return mRecorderCallbackTimes;
552     }
553 }
554