summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorninatai <ninatai@google.com>2015-05-14 18:11:09 -0700
committerninatai <ninatai@google.com>2015-05-14 18:11:09 -0700
commit2590779e25bd9ccf5a72e077421cfb8b6a83c113 (patch)
treec8d4ce5bc8db8c7a2d475606a436c9959226263c
parent8962f3e75b483cf4e46a5c6ef1ab1677fc22f266 (diff)
downloaddrrickorang-2590779e25bd9ccf5a72e077421cfb8b6a83c113.tar.gz
this version can now draw a simple histogram (for Java only)
-rw-r--r--LoopbackApp/app/src/main/AndroidManifest.xml10
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/HistogramView.java109
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyActivity.java22
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/LatencyRecord.java33
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackActivity.java9
-rw-r--r--LoopbackApp/app/src/main/java/org/drrickorang/loopback/LoopbackAudioThread.java4
-rw-r--r--LoopbackApp/app/src/main/res/layout/latency_activity.xml32
-rw-r--r--LoopbackApp/app/src/main/res/values/strings.xml1
8 files changed, 204 insertions, 16 deletions
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" />
</activity>
+ <activity
+ android:name="org.drrickorang.loopback.LatencyActivity"
+ android:label="Latency Histogram"
+ android:parentActivityName="org.drrickorang.loopback.LoopbackActivity"
+ android:theme="@android:style/Theme.Holo.Light">
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="org.drrickorang.loopback.LoopbackActivity" />
+ </activity>
+
</application>
</manifest>
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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:custom="http://schemas.android.com/apk/res-auto"
+ android:orientation="vertical" android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/histogramInfo"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/histTitle"/>
+
+ <LinearLayout
+ android:layout_marginTop="0mm"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:gravity="center_horizontal"
+ android:orientation="horizontal"
+ android:layout_weight="1">
+ <org.drrickorang.loopback.HistogramView
+ android:id="@+id/viewHistogram"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="latency"/>
+ </LinearLayout>
+
+</LinearLayout>
+
+
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 @@
<string name="buttonZoomIn"> Zoom In</string>
<string name="buttonAbout">About</string>
<string name="buttonLatency">Latency Plot</string>
+ <string name="histTitle">Distribution of Latency</string>
<!-- disabled -->
<string name="buttonZoomInFull">In Full</string>