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.
master
Raph Levien 12 years ago
parent dedde725d2
commit dffa68cee6
  1. 4
      android/AndroidManifest.xml
  2. 51
      android/src/com/levien/synthesizer/android/ui/PianoActivity2.java
  3. 18
      android/src/com/levien/synthesizer/android/widgets/piano/PianoView.java

@ -2,8 +2,8 @@
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.levien.synthesizer"
android:versionCode="3"
android:versionName="0.91">
android:versionCode="4"
android:versionName="0.92">
<uses-sdk android:minSdkVersion="9"
android:targetSdkVersion="17"
/> <!-- 9 = Gingerbread -->

@ -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<String, UsbDevice> 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;
}
}

@ -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 {

Loading…
Cancel
Save