From dffa68cee6b70e6a1362a805238b38c4f748d4c1 Mon Sep 17 00:00:00 2001 From: Raph Levien Date: Fri, 14 Jun 2013 10:47:46 -0700 Subject: [PATCH] Stability fixes Fixes various crashes, by (a) disabling the stats gathering thread and (b) only trying to open a USB device if it identifies itself as a MIDI keyboard. Disabling stats gathering should improve responsiveness and improve battery consumption as well. The crash in the stats gathering thread was a race on destruction, where the audio thread set the stats_ringbuffer to NULL, but the Java thread continued to try to read from it. This could be made more robust. --- android/AndroidManifest.xml | 4 +- .../android/ui/PianoActivity2.java | 51 ++++++++++++------- .../android/widgets/piano/PianoView.java | 18 ++++++- 3 files changed, 50 insertions(+), 23 deletions(-) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 8a10e0e..ae22936 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -2,8 +2,8 @@ + android:versionCode="4" + android:versionName="0.92"> diff --git a/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java b/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java index fc07be1..12e5d4e 100644 --- a/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java +++ b/android/src/com/levien/synthesizer/android/ui/PianoActivity2.java @@ -35,7 +35,6 @@ import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.util.Log; -import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.view.WindowManager; @@ -123,23 +122,27 @@ public class PianoActivity2 extends Activity { tryConnectUsb(); } - jitterStats_ = new JitterStats(); - jitterStats_.setNominalCb(params.bufferSize / (double)params.sampleRate); - statusHandler_ = new Handler(); - statusRunnable_ = new Runnable() { - public void run() { - int n = androidGlue_.statsBytesAvailable(); - if (n > 0) { - byte[] buf = new byte[n]; - androidGlue_.readStatsBytes(buf, 0, n); - jitterStats_.aggregate(buf); - TextView statusTextView = (TextView)findViewById(R.id.status); - statusTextView.setText(jitterStats_.report()); + final boolean doStats = false; + + if (doStats) { + jitterStats_ = new JitterStats(); + jitterStats_.setNominalCb(params.bufferSize / (double)params.sampleRate); + statusHandler_ = new Handler(); + statusRunnable_ = new Runnable() { + public void run() { + int n = androidGlue_.statsBytesAvailable(); + if (n > 0) { + byte[] buf = new byte[n]; + androidGlue_.readStatsBytes(buf, 0, n); + jitterStats_.aggregate(buf); + TextView statusTextView = (TextView)findViewById(R.id.status); + statusTextView.setText(jitterStats_.report()); + } + statusHandler_.postDelayed(statusRunnable_, 100); } - statusHandler_.postDelayed(statusRunnable_, 100); - } - }; - statusRunnable_.run(); + }; + statusRunnable_.run(); + } // Create burst of load -- test code to be removed. Ultimately we'll // be able to get this kind of functionality by hooking up the sequencer @@ -229,21 +232,31 @@ public class PianoActivity2 extends Activity { UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); HashMap deviceList = usbManager.getDeviceList(); TextView label = (TextView)findViewById(R.id.status); - if (!deviceList.isEmpty()) { - UsbDevice device = deviceList.values().iterator().next(); + Log.i("synth", "USB device count=" + deviceList.size()); + for (UsbDevice device : deviceList.values()) { //label.setText("ic:" + device.getInterfaceCount()); + Log.i("synth", "usb name=" + device.toString() + " #if=" + device.getInterfaceCount()); + if (device.getInterfaceCount() < 2) { + continue; + } UsbInterface usbIf = device.getInterface(1); + if (usbIf.getInterfaceClass() != 1 || usbIf.getInterfaceSubclass() != 3) { + continue; + } UsbDeviceConnection connection = usbManager.openDevice(device); if (connection != null) { connection.claimInterface(usbIf, true); UsbEndpoint endpoint = getInputEndpoint(usbIf); //label.setText(endpoint.toString()); + Log.i("synth", "MIDI keyboard detected, starting USB thread"); startUsbThread(connection, endpoint); } else { if (label != null) { + Log.i("synth", "error opening USB MIDI device"); label.setText("error opening device"); } } + break; } } diff --git a/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java b/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java index 18f3f8a..2ab1b19 100644 --- a/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java +++ b/android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java @@ -24,6 +24,7 @@ import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; +import android.util.Log; import android.view.MotionEvent; import android.view.View; @@ -230,6 +231,7 @@ public class PianoView extends View { public boolean onTouchEvent(MotionEvent event) { int action = event.getAction(); int actionCode = action & MotionEvent.ACTION_MASK; + //Log.i("synth", "actionCode = " + actionCode); boolean redraw = false; if (actionCode == MotionEvent.ACTION_DOWN) { int pointerId = event.getPointerId(0); @@ -238,6 +240,8 @@ public class PianoView extends View { int y = (int)event.getY(); float pressure = event.getPressure(); redraw |= onTouchDown(pointerId, x, y, pressure); + } else { + Log.i("synth", "Discarded ACTION_DOWN pointerId=" + pointerId); } } else if (actionCode == MotionEvent.ACTION_POINTER_DOWN) { int pointerIndex = (action & MotionEvent.ACTION_POINTER_INDEX_MASK) @@ -248,6 +252,8 @@ public class PianoView extends View { int y = (int)event.getY(pointerIndex); float pressure = event.getPressure(pointerIndex); redraw |= onTouchDown(pointerId, x, y, pressure); + } else { + Log.i("synth", "Discarded ACTION_POINTER_DOWN pointerId=" + pointerId); } } else if (actionCode == MotionEvent.ACTION_MOVE) { for (int pointerIndex = 0; pointerIndex < event.getPointerCount(); ++pointerIndex) { @@ -277,7 +283,11 @@ public class PianoView extends View { } } if (!found) { - redraw |= onTouchUp(pointerId); + boolean thisRedraw = onTouchUp(pointerId); + if (thisRedraw) { + Log.i("synth", "ACTION_UP cleaned up pointerId=" + pointerId); + } + redraw |= thisRedraw; } } } else if (actionCode == MotionEvent.ACTION_POINTER_UP) { @@ -296,7 +306,11 @@ public class PianoView extends View { } } if (!found) { - redraw |= onTouchUp(pointerId); + boolean thisRedraw = onTouchUp(pointerId); + if (thisRedraw) { + Log.i("synth", "ACTION_POINTER_UP cleaned up pointerId=" + pointerId); + } + redraw |= thisRedraw; } } } else {