From 2590779e25bd9ccf5a72e077421cfb8b6a83c113 Mon Sep 17 00:00:00 2001 From: ninatai Date: Thu, 14 May 2015 18:11:09 -0700 Subject: this version can now draw a simple histogram (for Java only) --- LoopbackApp/app/src/main/AndroidManifest.xml | 10 ++ .../org/drrickorang/loopback/HistogramView.java | 109 +++++++++++++++++++++ .../org/drrickorang/loopback/LatencyActivity.java | 22 ++--- .../org/drrickorang/loopback/LatencyRecord.java | 33 ++++++- .../org/drrickorang/loopback/LoopbackActivity.java | 9 ++ .../drrickorang/loopback/LoopbackAudioThread.java | 4 +- .../app/src/main/res/layout/latency_activity.xml | 32 ++++++ LoopbackApp/app/src/main/res/values/strings.xml | 1 + 8 files changed, 204 insertions(+), 16 deletions(-) create mode 100644 LoopbackApp/app/src/main/java/org/drrickorang/loopback/HistogramView.java create mode 100644 LoopbackApp/app/src/main/res/layout/latency_activity.xml diff --git a/LoopbackApp/app/src/main/AndroidManifest.xml b/LoopbackApp/app/src/main/AndroidManifest.xml index 079f6e9..7c4cf68 100644 --- a/LoopbackApp/app/src/main/AndroidManifest.xml +++ b/LoopbackApp/app/src/main/AndroidManifest.xml @@ -72,5 +72,15 @@ android:value="org.drrickorang.loopback.LoopbackActivity" /> + + + + diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/HistogramView.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/HistogramView.java new file mode 100644 index 0000000..2fce8f2 --- /dev/null +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/HistogramView.java @@ -0,0 +1,109 @@ +package org.drrickorang.loopback; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; + +/** + * Created by ninatai on 5/14/15. + */ +public class HistogramView extends View { + private Paint mPaint; + private static int[] mData; + private static int mMaxLatency = 0; + private static boolean mExceedRange = false; + + public HistogramView(Context context, AttributeSet attrs) { + super(context, attrs); + init(); + } + + // TODO when to call this? For optimization + private void init() { + mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); + mPaint.setStyle(Paint.Style.FILL); + mPaint.setColor(Color.BLUE); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + canvas.drawColor(Color.GRAY); + int arrayLength = mData.length; + if (mData == null || arrayLength == 0) { + return; + } + + // coordinate starts at (0,0), up to (right, bottom) + int right = this.getRight(); + int bottom = this.getBottom(); + + // Rect rect1 = new Rect(0, 0, width, height); + if (mMaxLatency != 0) { + int range; + if (mMaxLatency > arrayLength - 1) { + range = arrayLength; + mExceedRange = true; + } else { + range = mMaxLatency + 1; + mExceedRange = false; + } + + if (range == 0) { + return; + } + float width = ((float)right / range); + + int maxLatencyFreq = 0; + for (int i = 1; i < arrayLength; i++) { + if (mData[i] > maxLatencyFreq) { + maxLatencyFreq = mData[i]; + } + } + + if (maxLatencyFreq == 0) { + return; + } + float height =( (float)bottom / maxLatencyFreq); + + float currentLeft = 0; + float currentTop = 0; + float currentRight = 0; + float currentBottom = bottom; + for (int i = 0; i < arrayLength; i++) { + currentRight = currentLeft + width; + currentTop = bottom - (height * mData[i]); + canvas.drawRect(currentLeft, currentTop , currentRight, currentBottom, mPaint); + currentLeft = currentRight; + //currentTop = currentBottom; + } + } + int x = 1; + } + + void redraw() { + invalidate(); + } + + // Copy data into internal buffer + public static void setLatencyArray(int[] pData) { + if (mData == null || pData.length != mData.length) { + mData = new int[pData.length]; + } + System.arraycopy(pData, 0, mData, 0, pData.length); + // postInvalidate(); + } + + public static void setMaxLatency(int latency) { + mMaxLatency = latency; + } + +} + diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyActivity.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyActivity.java index 81eb122..caf9d35 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyActivity.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyActivity.java @@ -4,6 +4,7 @@ import android.app.Activity; import android.app.Notification; import android.content.Intent; import android.os.Bundle; +import android.view.View; import android.widget.TextView; import java.lang.reflect.AccessibleObject; @@ -12,23 +13,20 @@ import java.lang.reflect.AccessibleObject; * Created by ninatai on 5/13/15. */ public class LatencyActivity extends Activity { + + private HistogramView mHistogramView; + private TextView mTextView; + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - Intent intent = getIntent(); - String message = "Audio latency testing app using the Dr. Rick O'Rang audio loopback dongle.\n\n" + - "Author: Ricardo Garcia\n\n" + - "Open source project on: https://github.com/gkasten/drrickorang\n\n" + - "References: https://source.android.com/devices/audio/loopback.html\n" + - "https://source.android.com/devices/audio/latency_measure.html#loopback"; + View view = getLayoutInflater().inflate(R.layout.latency_activity, null); + setContentView(view); + mTextView = (TextView) findViewById(R.id.histogramInfo); + mHistogramView = (HistogramView) findViewById(R.id.viewHistogram); + - // Create the text view - TextView textView = new TextView(this); - textView.setTextSize(20); - textView.setText(message); - // Set the text view as the activity layout - setContentView(textView); } } diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyRecord.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyRecord.java index 23a143c..b4d4247 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyRecord.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyRecord.java @@ -8,14 +8,17 @@ import android.util.Log; import org.drrickorang.loopback.LoopbackAudioThread.RecorderRunnable; +import java.util.Arrays; import java.util.HashMap; +// TODO remember that after one record, set mPreviousTime back to zero -> done in onButtonTest public class LatencyRecord { private static long mPreviousTime = 0; private static long mCurrentTime; - private static final int range = 1002; + private static final int range = 102; //TODO adjust this value private static int mMaxLatency = 0; + private static boolean exceedRange = false; private static int[] mJavaLatency = new int[range]; @@ -25,7 +28,7 @@ public class LatencyRecord { // if = 0 it's the first time the thread runs, so don't record the interval if (mPreviousTime != 0 && mCurrentTime != 0) { long diffInNano = mCurrentTime - mPreviousTime; - int diffInMilli = (int) Math.ceil(((double) (diffInNano / 1000))); // round up + int diffInMilli = (int) Math.ceil(((double) (diffInNano / 1000000))); // round up if (diffInMilli > mMaxLatency) { mMaxLatency = diffInMilli; @@ -46,6 +49,32 @@ public class LatencyRecord { mPreviousTime = mCurrentTime; } + // Check if max latency exceeds the range of latencies that are going to be displayed on histogram + public static void setExceedRange() { + if (mMaxLatency > (range - 2)) { + exceedRange = true; + } else { + exceedRange = false; + } + } + + public static void resetRecord() { + mPreviousTime = 0; + Arrays.fill(mJavaLatency, 0); + } + + public static int[] getLatencyArray() { + return mJavaLatency; + + } + + public static int getMaxLatency() { + return mMaxLatency; + } + + + + private static void errorLog(String msg) { Log.e("LatencyTracker", msg); } diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java index 02205ec..2f02f7b 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java @@ -49,6 +49,8 @@ import java.io.File; import android.os.Build; +import org.drrickorang.loopback.LatencyRecord; + public class LoopbackActivity extends Activity { /** * Member Vars @@ -292,12 +294,16 @@ public class LoopbackActivity extends Activity { //first refresh refreshState(); } + private void resetLatencyRecord() { + LatencyRecord.resetRecord(); + } /** Called when the user clicks the button */ public void onButtonTest(View view) { if( !isBusy()) { restartAudioSystem(); + resetLatencyRecord(); try { Thread.sleep(200); } catch (InterruptedException e) { @@ -479,6 +485,9 @@ public class LoopbackActivity extends Activity { public void onButtonLatency(View view) { if(!isBusy()) { + HistogramView.setLatencyArray(LatencyRecord.getLatencyArray()); + HistogramView.setMaxLatency(LatencyRecord.getMaxLatency()); + Intent aboutIntent = new Intent(this, LatencyActivity.class); startActivity(aboutIntent); } else diff --git a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java index b17e483..e0c46f3 100644 --- a/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java +++ b/LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java @@ -430,10 +430,10 @@ public class LoopbackAudioThread extends Thread { } //long mStartTime = System.nanoTime(); - //WaitTimeRecord.collectLatency(); + //WaitTimeRecord.collectLatency(); //FIXME should it be here, if (isRecording && mRecorder != null) { - LatencyRecord.collectLatency(); + LatencyRecord.collectLatency(); // or here? int nSamplesRead = mRecorder.read(mAudioShortArray, 0, mMinRecordBuffSizeInSamples); // int nbBytesRead = mRecorder.read(mAudioByteArray, 0, diff --git a/LoopbackApp/app/src/main/res/layout/latency_activity.xml b/LoopbackApp/app/src/main/res/layout/latency_activity.xml new file mode 100644 index 0000000..99bdecd --- /dev/null +++ b/LoopbackApp/app/src/main/res/layout/latency_activity.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + diff --git a/LoopbackApp/app/src/main/res/values/strings.xml b/LoopbackApp/app/src/main/res/values/strings.xml index 652ff0b..a6f7466 100644 --- a/LoopbackApp/app/src/main/res/values/strings.xml +++ b/LoopbackApp/app/src/main/res/values/strings.xml @@ -28,6 +28,7 @@ Zoom In About Latency Plot + Distribution of Latency In Full -- cgit v1.2.3