summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul McLean <pmclean@google.com>2017-03-14 15:20:51 -0700
committerPaul McLean <pmclean@google.com>2018-03-15 16:20:07 -0700
commit8a3e33b36a6259708ed44a9c41078d49c0fa9da4 (patch)
tree4b0e47637cd67486224ffbc865b75e2ecf229ab2
parentcbeeed1255c0414afea45292a58bd533b67efa07 (diff)
(re)integrating Native MIDI API into NDK - base API
Implement native MIDI API (amidi) Bug: 30252756 Bug: 37090545 Test: manual - Connect PreSonus AudioBox 22VSL and run tests in NativeMidiTestbed app. Verify MIDI messages sent to external MIDI synthesizer. Verify MIDI messages received from external MIDI synthesizer. CTS Change-Id: I7bb02b8926d01090132ce873c785b5323a9fa5f8
-rw-r--r--media/java/android/media/midi/MidiDevice.java72
-rw-r--r--media/java/android/media/midi/MidiDeviceInfo.java2
-rw-r--r--media/jni/Android.bp2
-rw-r--r--media/jni/midi/android_media_midi_MidiDevice.cpp50
-rw-r--r--media/native/midi/Android.bp29
-rw-r--r--media/native/midi/include/NOTICE13
-rw-r--r--media/native/midi/include/midi.h255
-rw-r--r--media/native/midi/libamidi.map.txt18
-rw-r--r--media/native/midi/midi.cpp394
-rw-r--r--media/native/midi/midi.h182
-rw-r--r--media/native/midi/midi_internal.h22
-rw-r--r--media/tests/NativeMidiDemo/Android.mk31
-rw-r--r--media/tests/NativeMidiDemo/AndroidManifest.xml20
-rw-r--r--media/tests/NativeMidiDemo/java/com/example/android/nativemididemo/NativeMidi.java354
-rw-r--r--media/tests/NativeMidiDemo/java/com/example/android/nativemididemo/TouchableScrollView.java32
-rw-r--r--media/tests/NativeMidiDemo/jni/Android.mk35
-rw-r--r--media/tests/NativeMidiDemo/jni/messagequeue.cpp138
-rw-r--r--media/tests/NativeMidiDemo/jni/messagequeue.h30
-rw-r--r--media/tests/NativeMidiDemo/jni/nativemidi-jni.cpp286
-rw-r--r--media/tests/NativeMidiDemo/res/layout/main.xml93
-rw-r--r--media/tests/NativeMidiDemo/res/mipmap-hdpi/ic_launcher.pngbin3418 -> 0 bytes
-rw-r--r--media/tests/NativeMidiDemo/res/mipmap-mdpi/ic_launcher.pngbin2206 -> 0 bytes
-rw-r--r--media/tests/NativeMidiDemo/res/mipmap-xhdpi/ic_launcher.pngbin4842 -> 0 bytes
-rw-r--r--media/tests/NativeMidiDemo/res/mipmap-xxhdpi/ic_launcher.pngbin7718 -> 0 bytes
-rw-r--r--media/tests/NativeMidiDemo/res/values/strings.xml6
25 files changed, 633 insertions, 1431 deletions
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index a99573692664..6096355ddb05 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -37,30 +37,17 @@ import java.util.HashSet;
* Instances of this class are created by {@link MidiManager#openDevice}.
*/
public final class MidiDevice implements Closeable {
- static {
- System.loadLibrary("media_jni");
- }
-
private static final String TAG = "MidiDevice";
- private final MidiDeviceInfo mDeviceInfo;
+ private final MidiDeviceInfo mDeviceInfo; // accessed from native code
private final IMidiDeviceServer mDeviceServer;
+ private final IBinder mDeviceServerBinder; // accessed from native code
private final IMidiManager mMidiManager;
private final IBinder mClientToken;
private final IBinder mDeviceToken;
- private boolean mIsDeviceClosed;
+ private boolean mIsDeviceClosed; // accessed from native code
- // Native API Helpers
- /**
- * Keep a static list of MidiDevice objects that are mirrorToNative()'d so they
- * don't get inadvertantly garbage collected.
- */
- private static HashSet<MidiDevice> mMirroredDevices = new HashSet<MidiDevice>();
-
- /**
- * If this device is mirrorToNatived(), this is the native device handler.
- */
- private long mNativeHandle;
+ private long mNativeHandle; // accessed from native code
private final CloseGuard mGuard = CloseGuard.get();
@@ -118,6 +105,7 @@ public final class MidiDevice implements Closeable {
IMidiManager midiManager, IBinder clientToken, IBinder deviceToken) {
mDeviceInfo = deviceInfo;
mDeviceServer = server;
+ mDeviceServerBinder = mDeviceServer.asBinder();
mMidiManager = midiManager;
mClientToken = clientToken;
mDeviceToken = deviceToken;
@@ -230,50 +218,15 @@ public final class MidiDevice implements Closeable {
}
}
- /**
- * Makes Midi Device available to the Native API
- * @hide
- */
- public long mirrorToNative() throws IOException {
- if (mIsDeviceClosed || mNativeHandle != 0) {
- return 0;
- }
-
- mNativeHandle = native_mirrorToNative(mDeviceServer.asBinder(), mDeviceInfo.getId());
- if (mNativeHandle == 0) {
- throw new IOException("Failed mirroring to native");
- }
-
- synchronized (mMirroredDevices) {
- mMirroredDevices.add(this);
- }
- return mNativeHandle;
- }
-
- /**
- * Makes Midi Device no longer available to the Native API
- * @hide
- */
- public void removeFromNative() {
- if (mNativeHandle == 0) {
- return;
- }
-
- synchronized (mGuard) {
- native_removeFromNative(mNativeHandle);
- mNativeHandle = 0;
- }
-
- synchronized (mMirroredDevices) {
- mMirroredDevices.remove(this);
- }
- }
-
@Override
public void close() throws IOException {
synchronized (mGuard) {
- if (!mIsDeviceClosed) {
- removeFromNative();
+ // What if there is a native reference to this?
+ if (mNativeHandle != 0) {
+ Log.w(TAG, "MidiDevice#close() called while there is an outstanding native client 0x"
+ + Long.toHexString(mNativeHandle));
+ }
+ if (!mIsDeviceClosed && mNativeHandle == 0) {
mGuard.close();
mIsDeviceClosed = true;
try {
@@ -302,7 +255,4 @@ public final class MidiDevice implements Closeable {
public String toString() {
return ("MidiDevice: " + mDeviceInfo.toString());
}
-
- private native long native_mirrorToNative(IBinder deviceServerBinder, int id);
- private native void native_removeFromNative(long deviceHandle);
}
diff --git a/media/java/android/media/midi/MidiDeviceInfo.java b/media/java/android/media/midi/MidiDeviceInfo.java
index 5fd9006db97c..ab8af2a87092 100644
--- a/media/java/android/media/midi/MidiDeviceInfo.java
+++ b/media/java/android/media/midi/MidiDeviceInfo.java
@@ -190,7 +190,7 @@ public final class MidiDeviceInfo implements Parcelable {
}
private final int mType; // USB or virtual
- private final int mId; // unique ID generated by MidiService
+ private final int mId; // unique ID generated by MidiService. Accessed from native code.
private final int mInputPortCount;
private final int mOutputPortCount;
private final String[] mInputPortNames;
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 44e5d61361cd..272b0b7c442a 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -25,7 +25,6 @@ cc_library_shared {
"android_mtp_MtpDatabase.cpp",
"android_mtp_MtpDevice.cpp",
"android_mtp_MtpServer.cpp",
- "midi/android_media_midi_MidiDevice.cpp",
],
shared_libs: [
@@ -39,7 +38,6 @@ cc_library_shared {
"libmedia_omx",
"libmediametrics",
"libmediadrm",
- "libmidi",
"libhwui",
"libui",
"liblog",
diff --git a/media/jni/midi/android_media_midi_MidiDevice.cpp b/media/jni/midi/android_media_midi_MidiDevice.cpp
deleted file mode 100644
index 5b35453c32d0..000000000000
--- a/media/jni/midi/android_media_midi_MidiDevice.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Midi-JNI"
-
-#include <android_util_Binder.h>
-#include <jni.h>
-#include <midi_internal.h>
-#include <utils/Log.h>
-
-using namespace android;
-using namespace android::media::midi;
-
-extern "C" jlong Java_android_media_midi_MidiDevice_native_1mirrorToNative(
- JNIEnv *env, jobject, jobject midiDeviceServer, jint id)
-{
- // ALOGI("native_mirrorToNative(%p)...", midiDeviceServer);
- sp<IBinder> serverBinder = ibinderForJavaObject(env, midiDeviceServer);
- if (serverBinder.get() == NULL) {
- ALOGE("Could not obtain IBinder from passed jobject");
- return -EINVAL;
- }
-
- AMIDI_Device* devicePtr = new AMIDI_Device;
- devicePtr->server = new BpMidiDeviceServer(serverBinder);
- devicePtr->deviceId = id;
-
- return (jlong)devicePtr;
-}
-
-extern "C" void Java_android_media_midi_MidiDevice_native_removeFromNative(
- JNIEnv *, jobject , jlong nativeToken)
-{
- AMIDI_Device* devicePtr = (AMIDI_Device*)nativeToken;
- delete devicePtr;
-}
diff --git a/media/native/midi/Android.bp b/media/native/midi/Android.bp
index 11f0deabbcd5..d069bd2f6284 100644
--- a/media/native/midi/Android.bp
+++ b/media/native/midi/Android.bp
@@ -13,7 +13,7 @@
// limitations under the License.
cc_library_shared {
- name: "libmidi",
+ name: "libamidi",
srcs: [
"midi.cpp",
@@ -22,13 +22,13 @@ cc_library_shared {
aidl: {
include_dirs: ["frameworks/base/media/java"],
- export_aidl_headers: true,
+ export_aidl_headers: false,
},
cflags: [
"-Wall",
"-Werror",
- "-O0",
+ "-fvisibility=hidden",
],
shared_libs: [
@@ -36,7 +36,28 @@ cc_library_shared {
"libbinder",
"libutils",
"libmedia",
+ "libmediandk",
+ "libandroid_runtime",
],
- export_include_dirs: ["."],
+ export_include_dirs: ["include"],
+}
+
+ndk_headers {
+ name: "amidi",
+
+ from: "include",
+
+ to: "amidi",
+
+ srcs: ["include/midi.h"],
+ license: "include/NOTICE",
+}
+
+ndk_library {
+ name: "libamidi",
+
+ symbol_file: "libamidi.map.txt",
+
+ first_version: "29",
}
diff --git a/media/native/midi/include/NOTICE b/media/native/midi/include/NOTICE
new file mode 100644
index 000000000000..e72ff94a8401
--- /dev/null
+++ b/media/native/midi/include/NOTICE
@@ -0,0 +1,13 @@
+Copyright (C) 2018 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/media/native/midi/include/midi.h b/media/native/midi/include/midi.h
new file mode 100644
index 000000000000..780d8a7bfd40
--- /dev/null
+++ b/media/native/midi/include/midi.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_MIDI_H_
+#define ANDROID_MEDIA_MIDI_H_
+
+#include <stdarg.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <jni.h>
+
+#include <media/NdkMediaError.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct AMidiDevice AMidiDevice;
+typedef struct AMidiInputPort AMidiInputPort;
+typedef struct AMidiOutputPort AMidiOutputPort;
+
+#define AMIDI_API __attribute__((visibility("default")))
+
+/*
+ * Message Op Codes. Used to parse MIDI data packets
+ */
+enum {
+ AMIDI_OPCODE_DATA = 1, /* The MIDI packet contains normal MIDI data */
+ AMIDI_OPCODE_FLUSH = 2, /* The MIDI packet contains just a MIDI FLUSH command. */
+ /* Forces the send of any pending MIDI data. */
+};
+
+/*
+ * Type IDs for various MIDI devices.
+ */
+enum {
+ AMIDI_DEVICE_TYPE_USB = 1, /* A MIDI device connected to the Android USB port */
+ AMIDI_DEVICE_TYPE_VIRTUAL = 2, /* A software object implementing MidiDeviceService */
+ AMIDI_DEVICE_TYPE_BLUETOOTH = 3 /* A MIDI device connected via BlueTooth */
+};
+
+/*
+ * Device API
+ */
+/**
+ * Connects a native Midi Device object to the associated Java MidiDevice object. Use this
+ * AMidiDevice to access the rest of the native MIDI API. Use AMidiDevice_release() to
+ * disconnect from the Java object when not being used any more.
+ *
+ * @param env Points to the Java Environment.
+ * @param midiDeviceObj The Java MidiDevice Object.
+ * @param outDevicePtrPtr Points to the pointer to receive the AMidiDevice
+ *
+ * @return AMEDIA_OK on success, or a negative error value:
+ * @see AMEDIA_ERROR_INVALID_OBJECT {@link AMEDIA_ERROR_INVALID_OBJECT} - the midiDeviceObj
+ * is null or already connected to a native AMidiDevice
+ * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - an unknown error occurred.
+ */
+media_status_t AMIDI_API AMidiDevice_fromJava(
+ JNIEnv *env, jobject midiDeviceObj, AMidiDevice **outDevicePtrPtr);
+
+/**
+ * Disconnects the native Midi Device Object from the associated Java MidiDevice object.
+ *
+ * @param midiDevice Points to the native AMIDI_MidiDevice.
+ *
+ * @return AMEDIA_OK on success,
+ * or a negative error value:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER}
+ * - the device parameter is NULL.
+ * @see AMEDIA_ERROR_INVALID_OBJECT {@link AMEDIA_ERROR_INVALID_OBJECT}
+ * - the device is not consistent with the associated Java MidiDevice.
+ * @see AMEDIA_ERROR_INVALID_OBJECT {@link AMEDIA_ERROR_INVALID_OBJECT}
+ * - the JNI interface initialization to the associated java MidiDevice failed.
+ * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - couldn't retrieve the device info.
+ */
+media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *midiDevice);
+
+/**
+ * Gets the MIDI device type.
+ *
+ * @param device Specifies the MIDI device.
+ *
+ * @return The identifier of the MIDI device type:
+ * AMIDI_DEVICE_TYPE_USB
+ * AMIDI_DEVICE_TYPE_VIRTUAL
+ * AMIDI_DEVICE_TYPE_BLUETOOTH
+ * or a negative error value:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} - the device
+ * parameter is NULL.
+ * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown error.
+ */
+int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device);
+
+/**
+ * Gets the number of input (sending) ports available on the specified MIDI device.
+ *
+ * @param device Specifies the MIDI device.
+ *
+ * @return If successful, returns the number of MIDI input (sending) ports available on the
+ * device. If an error occurs, returns a negative value indicating the error:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} - the device
+ * parameter is NULL.
+ * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - couldn't retrieve the device info.
+ */
+ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device);
+
+/**
+ * Gets the number of output (receiving) ports available on the specified MIDI device.
+ *
+ * @param device Specifies the MIDI device.
+ *
+ * @return If successful, returns the number of MIDI output (receiving) ports available on the
+ * device. If an error occurs, returns a negative value indicating the error:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} - the device
+ * parameter is NULL.
+ * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN}- couldn't retrieve the device info.
+ */
+ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device);
+
+/*
+ * API for receiving data from the Output port of a device.
+ */
+/**
+ * Opens the output port so that the client can receive data from it. The port remains open and
+ * valid until AMidiOutputPort_close() is called for the returned AMidiOutputPort.
+ *
+ * @param device Specifies the MIDI device.
+ * @param portNumber Specifies the zero-based port index on the device to open. This value ranges
+ * between 0 and one less than the number of output ports reported by the
+ * AMidiDevice_getNumOutputPorts function.
+ * @param outOutputPortPtr Receives the native API port identifier of the opened port.
+ *
+ * @return AMEDIA_OK, or a negative error code:
+ * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
+ */
+media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
+ AMidiOutputPort **outOutputPortPtr);
+
+/**
+ * Closes the output port.
+ *
+ * @param outputPort The native API port identifier of the port.
+ */
+void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort);
+
+/**
+ * Receives the next pending MIDI message. To retrieve all pending messages, the client should
+ * repeatedly call this method until it returns 0.
+ *
+ * Note that this is a non-blocking call. If there are no Midi messages are available, the function
+ * returns 0 immediately (for 0 messages received).
+ *
+ * @param outputPort Identifies the port to receive messages from.
+ * @param opcodePtr Receives the message Op Code.
+ * @param buffer Points to the buffer to receive the message data bytes.
+ * @param maxBytes Specifies the size of the buffer pointed to by the buffer parameter.
+ * @param numBytesReceivedPtr On exit, receives the actual number of bytes stored in buffer.
+ * @param outTimestampPtr If non-NULL, receives the timestamp associated with the message.
+ * (the current value of the running Java Virtual Machine's high-resolution time source,
+ * in nanoseconds)
+ * @return the number of messages received (either 0 or 1), or a negative error code:
+ * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
+ */
+ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
+ uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *outTimestampPtr);
+
+/*
+ * API for sending data to the Input port of a device.
+ */
+/**
+ * Opens the input port so that the client can send data to it. The port remains open and
+ * valid until AMidiInputPort_close() is called for the returned AMidiInputPort.
+ *
+ * @param device Specifies the MIDI device.
+ * @param portNumber Specifies the zero-based port index on the device to open. This value ranges
+ * between 0 and one less than the number of input ports reported by the
+ * AMidiDevice_getNumInputPorts() function..
+ * @param outInputPortPtr Receives the native API port identifier of the opened port.
+ *
+ * @return AMEDIA_OK, or a negative error code:
+ * @see AMEDIA_ERROR_UNKNOWN {@link AMEDIA_ERROR_UNKNOWN} - Unknown Error.
+ */
+media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
+ AMidiInputPort **outInputPortPtr);
+
+/**
+ * Sends data to the specified input port.
+ *
+ * @param inputPort The identifier of the port to send data to.
+ * @param buffer Points to the array of bytes containing the data to send.
+ * @param numBytes Specifies the number of bytes to write.
+ *
+ * @return The number of bytes sent, which could be less than specified or a negative error code:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} The specified port
+ * was NULL, the specified buffer was NULL.
+ */
+ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
+ size_t numBytes);
+
+/**
+ * Sends data to the specified input port with a timestamp.
+ *
+ * @param inputPort The identifier of the port to send data to.
+ * @param buffer Points to the array of bytes containing the data to send.
+ * @param numBytes Specifies the number of bytes to write.
+ * @param timestamp The CLOCK_MONOTONIC time in nanoseconds to associate with the sent data.
+ *
+ * @return The number of bytes sent, which could be less than specified or a negative error code:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} The specified port
+ * was NULL, the specified buffer was NULL.
+ */
+ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
+ const uint8_t *buffer, size_t numBytes, int64_t timestamp);
+
+/**
+ * Sends a message with a 'MIDI flush command code' to the specified port. This should cause
+ * a receiver to discard any pending MIDI data it may have accumulated and not processed.
+ *
+ * @param inputPort The identifier of the port to send the flush command to.
+ *
+ * @returns @see AMEDIA_OK {@link AMEDIA_OK} if successful, otherwise a negative error code:
+ * @see AMEDIA_ERROR_INVALID_PARAMETER {@link AMEDIA_ERROR_INVALID_PARAMETER} The specified port
+ * was NULL
+ * @see AMEDIA_ERROR_UNSUPPORTED {@link AMEDIA_ERROR_UNSUPPORTED} The FLUSH command couldn't
+ * be sent.
+ */
+media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort);
+
+/**
+ * Closes the input port.
+ *
+ * @param inputPort Identifies the input (sending) port to close.
+ */
+void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ANDROID_MEDIA_MIDI_H_ */
diff --git a/media/native/midi/libamidi.map.txt b/media/native/midi/libamidi.map.txt
new file mode 100644
index 000000000000..62627f8c5ef7
--- /dev/null
+++ b/media/native/midi/libamidi.map.txt
@@ -0,0 +1,18 @@
+LIBAMIDI {
+ global:
+ AMidiDevice_fromJava;
+ AMidiDevice_release;
+ AMidiDevice_getType;
+ AMidiDevice_getNumInputPorts;
+ AMidiDevice_getNumOutputPorts;
+ AMidiOutputPort_open;
+ AMidiOutputPort_close;
+ AMidiOutputPort_receive;
+ AMidiInputPort_open;
+ AMidiInputPort_send;
+ AMidiInputPort_sendWithTimestamp;
+ AMidiInputPort_sendFlush;
+ AMidiInputPort_close;
+ local:
+ *;
+};
diff --git a/media/native/midi/midi.cpp b/media/native/midi/midi.cpp
index 17b92da3325e..a9b498ffe0c8 100644
--- a/media/native/midi/midi.cpp
+++ b/media/native/midi/midi.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,15 +20,19 @@
#include <unistd.h>
#include <binder/Binder.h>
-#include <utils/Errors.h>
+#include <android_util_Binder.h>
#include <utils/Log.h>
+#include <core_jni_helpers.h>
+
#include "android/media/midi/BpMidiDeviceServer.h"
#include "media/MidiDeviceInfo.h"
-#include "midi.h"
+#include "include/midi.h"
#include "midi_internal.h"
+using namespace android::media::midi;
+
using android::IBinder;
using android::BBinder;
using android::OK;
@@ -36,23 +40,26 @@ using android::sp;
using android::status_t;
using android::base::unique_fd;
using android::binder::Status;
-using android::media::midi::MidiDeviceInfo;
struct AMIDI_Port {
- std::atomic_int state;
- AMIDI_Device *device;
- sp<IBinder> binderToken;
- unique_fd ufd;
+ std::atomic_int state; // One of the port status constants below.
+ const AMidiDevice *device; // Points to the AMidiDevice associated with the port.
+ sp<IBinder> binderToken;// The Binder token associated with the port.
+ unique_fd ufd; // The unique file descriptor associated with the port.
};
-#define SIZE_MIDIRECEIVEBUFFER AMIDI_BUFFER_SIZE
-
+/*
+ * Port Status Constants
+ */
enum {
MIDI_PORT_STATE_CLOSED = 0,
MIDI_PORT_STATE_OPEN_IDLE,
MIDI_PORT_STATE_OPEN_ACTIVE
};
+/*
+ * Port Type Constants
+ */
enum {
PORTTYPE_OUTPUT = 0,
PORTTYPE_INPUT = 1
@@ -76,32 +83,192 @@ enum {
* boundaries, and delivers messages in the order that they were sent.
* So 'read()' always returns a whole message.
*/
+#define AMIDI_PACKET_SIZE 1024
+#define AMIDI_PACKET_OVERHEAD 9
+#define AMIDI_BUFFER_SIZE (AMIDI_PACKET_SIZE - AMIDI_PACKET_OVERHEAD)
+
+// MidiDevice Fields
+static jobject deviceClassGlobalRef = nullptr; // A GlobalRef for MidiDevice Class
+static jfieldID fidDeviceClosed = nullptr; // MidiDevice.mIsDeviceClosed
+static jfieldID fidNativeHandle = nullptr; // MidiDevice.mNativeHandle
+static jfieldID fidDeviceServerBinder = nullptr; // MidiDevice.mDeviceServerBinder
+static jfieldID fidDeviceInfo = nullptr; // MidiDevice.mDeviceInfo
+
+// MidiDeviceInfo Fields
+static jobject deviceInfoClassGlobalRef = nullptr; // A GlobalRef for MidiDeviceInfoClass
+static jfieldID fidDeviceId = nullptr; // MidiDeviceInfo.mId
+
+static std::mutex openMutex; // Ensure that the device can be connected just once to 1 thread
+
+static void AMIDI_initJNI(JNIEnv *env) {
+ jclass deviceClass = android::FindClassOrDie(env, "android/media/midi/MidiDevice");
+ deviceClassGlobalRef = env->NewGlobalRef(deviceClass);
+
+ // MidiDevice Field IDs
+ fidDeviceClosed = android::GetFieldIDOrDie(env, deviceClass, "mIsDeviceClosed", "Z");
+ fidNativeHandle = android::GetFieldIDOrDie(env, deviceClass, "mNativeHandle", "J");
+ fidDeviceServerBinder = android::GetFieldIDOrDie(env, deviceClass,
+ "mDeviceServerBinder", "Landroid/os/IBinder;");
+ fidDeviceInfo = android::GetFieldIDOrDie(env, deviceClass,
+ "mDeviceInfo", "Landroid/media/midi/MidiDeviceInfo;");
+
+ // MidiDeviceInfo Field IDs
+ jclass deviceInfoClass = android::FindClassOrDie(env, "android/media/midi/MidiDeviceInfo");
+ deviceInfoClassGlobalRef = env->NewGlobalRef(deviceInfoClass);
+ fidDeviceId = android::GetFieldIDOrDie(env, deviceInfoClass, "mId", "I");
+}
+
+//// Handy debugging function.
+//static void AMIDI_logBuffer(const uint8_t *data, size_t numBytes) {
+// for (size_t index = 0; index < numBytes; index++) {
+// ALOGI(" data @%zu [0x%X]", index, data[index]);
+// }
+//}
/*
* Device Functions
*/
-status_t AMIDI_getDeviceInfo(AMIDI_Device *device, AMIDI_DeviceInfo *deviceInfoPtr) {
+/**
+ * Retrieves information for the native MIDI device.
+ *
+ * device The Native API token for the device. This value is obtained from the
+ * AMidiDevice_fromJava().
+ * outDeviceInfoPtr Receives the associated device info.
+ *
+ * Returns AMEDIA_OK or a negative error code.
+ * - AMEDIA_ERROR_INVALID_PARAMETER
+ * AMEDIA_ERROR_UNKNOWN
+ */
+static media_status_t AMIDI_API AMIDI_getDeviceInfo(const AMidiDevice *device,
+ AMidiDeviceInfo *outDeviceInfoPtr) {
+ if (device == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
MidiDeviceInfo deviceInfo;
Status txResult = device->server->getDeviceInfo(&deviceInfo);
if (!txResult.isOk()) {
ALOGE("AMIDI_getDeviceInfo transaction error: %d", txResult.transactionError());
- return txResult.transactionError();
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ outDeviceInfoPtr->type = deviceInfo.getType();
+ outDeviceInfoPtr->inputPortCount = deviceInfo.getInputPortNames().size();
+ outDeviceInfoPtr->outputPortCount = deviceInfo.getOutputPortNames().size();
+
+ return AMEDIA_OK;
+}
+
+media_status_t AMIDI_API AMidiDevice_fromJava(JNIEnv *env, jobject j_midiDeviceObj,
+ AMidiDevice** devicePtrPtr)
+{
+ // Ensures JNI initialization is performed just once.
+ static std::once_flag initCallFlag;
+ std::call_once(initCallFlag, AMIDI_initJNI, env);
+
+ if (j_midiDeviceObj == nullptr) {
+ ALOGE("AMidiDevice_fromJava() invalid MidiDevice object.");
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+
+ {
+ std::lock_guard<std::mutex> guard(openMutex);
+
+ long handle = env->GetLongField(j_midiDeviceObj, fidNativeHandle);
+ if (handle != 0) {
+ // Already opened by someone.
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+
+ jobject serverBinderObj = env->GetObjectField(j_midiDeviceObj, fidDeviceServerBinder);
+ sp<IBinder> serverBinder = android::ibinderForJavaObject(env, serverBinderObj);
+ if (serverBinder.get() == nullptr) {
+ ALOGE("AMidiDevice_fromJava couldn't connect to native MIDI server.");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
+ // don't check allocation failures, just abort..
+ AMidiDevice* devicePtr = new AMidiDevice;
+ devicePtr->server = new BpMidiDeviceServer(serverBinder);
+ jobject midiDeviceInfoObj = env->GetObjectField(j_midiDeviceObj, fidDeviceInfo);
+ devicePtr->deviceId = env->GetIntField(midiDeviceInfoObj, fidDeviceId);
+
+ // Synchronize with the associated Java MidiDevice.
+ env->SetLongField(j_midiDeviceObj, fidNativeHandle, (long)devicePtr);
+ env->GetJavaVM(&devicePtr->javaVM);
+ devicePtr->midiDeviceObj = env->NewGlobalRef(j_midiDeviceObj);
+
+ if (AMIDI_getDeviceInfo(devicePtr, &devicePtr->deviceInfo) != AMEDIA_OK) {
+ // This is weird, but maybe not fatal?
+ ALOGE("AMidiDevice_fromJava couldn't retrieve attributes of native device.");
+ }
+
+ *devicePtrPtr = devicePtr;
+ }
+
+ return AMEDIA_OK;
+}
+
+media_status_t AMIDI_API AMidiDevice_release(const AMidiDevice *device)
+{
+ if (device == nullptr || device->midiDeviceObj == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
+ JNIEnv* env;
+ jint err = device->javaVM->GetEnv((void**)&env, JNI_VERSION_1_6);
+ LOG_ALWAYS_FATAL_IF(err != JNI_OK, "AMidiDevice_release Error accessing JNIEnv err:%d", err);
+
+ // Synchronize with the associated Java MidiDevice.
+ // env->CallVoidMethod(j_midiDeviceObj, midClearNativeHandle);
+ {
+ std::lock_guard<std::mutex> guard(openMutex);
+ long handle = env->GetLongField(device->midiDeviceObj, fidNativeHandle);
+ if (handle == 0) {
+ // Not opened as native.
+ ALOGE("AMidiDevice_release() device not opened in native client.");
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
+
+ env->SetLongField(device->midiDeviceObj, fidNativeHandle, 0L);
}
+ env->DeleteGlobalRef(device->midiDeviceObj);
+
+ delete device;
- deviceInfoPtr->type = deviceInfo.getType();
- deviceInfoPtr->uid = deviceInfo.getUid();
- deviceInfoPtr->isPrivate = deviceInfo.isPrivate();
- deviceInfoPtr->inputPortCount = deviceInfo.getInputPortNames().size();
- deviceInfoPtr->outputPortCount = deviceInfo.getOutputPortNames().size();
+ return AMEDIA_OK;
+}
- return OK;
+int32_t AMIDI_API AMidiDevice_getType(const AMidiDevice *device) {
+ if (device == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return device->deviceInfo.type;
+}
+
+ssize_t AMIDI_API AMidiDevice_getNumInputPorts(const AMidiDevice *device) {
+ if (device == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return device->deviceInfo.inputPortCount;
+}
+
+ssize_t AMIDI_API AMidiDevice_getNumOutputPorts(const AMidiDevice *device) {
+ if (device == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+ return device->deviceInfo.outputPortCount;
}
/*
* Port Helpers
*/
-static status_t AMIDI_openPort(AMIDI_Device *device, int portNumber, int type,
+static media_status_t AMIDI_openPort(const AMidiDevice *device, int32_t portNumber, int type,
AMIDI_Port **portPtr) {
+ if (device == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
sp<BBinder> portToken(new BBinder());
unique_fd ufd;
Status txResult = type == PORTTYPE_OUTPUT
@@ -109,10 +276,10 @@ static status_t AMIDI_openPort(AMIDI_Device *device, int portNumber, int type,
: device->server->openInputPort(portToken, portNumber, &ufd);
if (!txResult.isOk()) {
ALOGE("AMIDI_openPort transaction error: %d", txResult.transactionError());
- return txResult.transactionError();
+ return AMEDIA_ERROR_UNKNOWN;
}
- AMIDI_Port* port = new AMIDI_Port;
+ AMIDI_Port *port = new AMIDI_Port;
port->state = MIDI_PORT_STATE_OPEN_IDLE;
port->device = device;
port->binderToken = portToken;
@@ -120,155 +287,178 @@ static status_t AMIDI_openPort(AMIDI_Device *device, int portNumber, int type,
*portPtr = port;
- return OK;
+ return AMEDIA_OK;
}
-static status_t AMIDI_closePort(AMIDI_Port *port) {
+static void AMIDI_closePort(AMIDI_Port *port) {
+ if (port == nullptr) {
+ return;
+ }
+
int portState = MIDI_PORT_STATE_OPEN_IDLE;
while (!port->state.compare_exchange_weak(portState, MIDI_PORT_STATE_CLOSED)) {
if (portState == MIDI_PORT_STATE_CLOSED) {
- return -EINVAL; // Already closed
+ return; // Already closed
}
}
Status txResult = port->device->server->closePort(port->binderToken);
if (!txResult.isOk()) {
- return txResult.transactionError();
+ ALOGE("Transaction error closing MIDI port:%d", txResult.transactionError());
}
delete port;
-
- return OK;
}
/*
* Output (receiving) API
*/
-status_t AMIDI_openOutputPort(AMIDI_Device *device, int portNumber,
- AMIDI_OutputPort **outputPortPtr) {
- return AMIDI_openPort(device, portNumber, PORTTYPE_OUTPUT, (AMIDI_Port**)outputPortPtr);
+media_status_t AMIDI_API AMidiOutputPort_open(const AMidiDevice *device, int32_t portNumber,
+ AMidiOutputPort **outOutputPortPtr) {
+ return AMIDI_openPort(device, portNumber, PORTTYPE_OUTPUT, (AMIDI_Port**)outOutputPortPtr);
}
-ssize_t AMIDI_receive(AMIDI_OutputPort *outputPort, AMIDI_Message *messages, ssize_t maxMessages) {
- AMIDI_Port *port = (AMIDI_Port*)outputPort;
- int portState = MIDI_PORT_STATE_OPEN_IDLE;
- if (!port->state.compare_exchange_strong(portState, MIDI_PORT_STATE_OPEN_ACTIVE)) {
- // The port has been closed.
- return -EPIPE;
+/*
+ * A little RAII (https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)
+ * class to ensure that the port state is correct irrespective of errors.
+ */
+class MidiReceiver {
+public:
+ MidiReceiver(AMIDI_Port *port) : mPort(port) {}
+
+ ~MidiReceiver() {
+ // flag the port state to idle
+ mPort->state.store(MIDI_PORT_STATE_OPEN_IDLE);
}
- status_t result = OK;
- ssize_t messagesRead = 0;
- while (messagesRead < maxMessages) {
- struct pollfd checkFds[1] = { { port->ufd, POLLIN, 0 } };
- int pollResult = poll(checkFds, 1, 0);
- if (pollResult < 1) {
- result = android::INVALID_OPERATION;
- break;
+ ssize_t receive(int32_t *opcodePtr, uint8_t *buffer, size_t maxBytes,
+ size_t *numBytesReceivedPtr, int64_t *timestampPtr) {
+ int portState = MIDI_PORT_STATE_OPEN_IDLE;
+ // check to see if the port is idle, then set to active
+ if (!mPort->state.compare_exchange_strong(portState, MIDI_PORT_STATE_OPEN_ACTIVE)) {
+ // The port not idle or has been closed.
+ return AMEDIA_ERROR_UNKNOWN;
}
- AMIDI_Message *message = &messages[messagesRead];
- uint8_t readBuffer[AMIDI_PACKET_SIZE];
- memset(readBuffer, 0, sizeof(readBuffer));
- ssize_t readCount = read(port->ufd, readBuffer, sizeof(readBuffer));
- if (readCount == EINTR) {
- continue;
+ struct pollfd checkFds[1] = { { mPort->ufd, POLLIN, 0 } };
+ if (poll(checkFds, 1, 0) < 1) {
+ // Nothing there
+ return 0;
}
- if (readCount < 1) {
- result = android::NOT_ENOUGH_DATA;
- break;
+
+ uint8_t readBuffer[AMIDI_PACKET_SIZE];
+ ssize_t readCount = read(mPort->ufd, readBuffer, sizeof(readBuffer));
+ if (readCount == EINTR || readCount < 1) {
+ return AMEDIA_ERROR_UNKNOWN;
}
- // set Packet Format definition at the top of this file.
- size_t dataSize = 0;
- message->opcode = readBuffer[0];
- message->timestamp = 0;
- if (message->opcode == AMIDI_OPCODE_DATA && readCount >= AMIDI_PACKET_OVERHEAD) {
- dataSize = readCount - AMIDI_PACKET_OVERHEAD;
- if (dataSize) {
- memcpy(message->buffer, readBuffer + 1, dataSize);
+ // see Packet Format definition at the top of this file.
+ size_t numMessageBytes = 0;
+ *opcodePtr = readBuffer[0];
+ if (*opcodePtr == AMIDI_OPCODE_DATA && readCount >= AMIDI_PACKET_OVERHEAD) {
+ numMessageBytes = readCount - AMIDI_PACKET_OVERHEAD;
+ numMessageBytes = std::min(maxBytes, numMessageBytes);
+ memcpy(buffer, readBuffer + 1, numMessageBytes);
+ if (timestampPtr != nullptr) {
+ *timestampPtr = *(uint64_t*)(readBuffer + readCount - sizeof(uint64_t));
}
- message->timestamp = *(uint64_t*)(readBuffer + readCount - sizeof(uint64_t));
}
- message->len = dataSize;
- ++messagesRead;
+ *numBytesReceivedPtr = numMessageBytes;
+ return 1;
}
- port->state.store(MIDI_PORT_STATE_OPEN_IDLE);
+private:
+ AMIDI_Port *mPort;
+};
+
+ssize_t AMIDI_API AMidiOutputPort_receive(const AMidiOutputPort *outputPort, int32_t *opcodePtr,
+ uint8_t *buffer, size_t maxBytes, size_t* numBytesReceivedPtr, int64_t *timestampPtr) {
+
+ if (outputPort == nullptr || buffer == nullptr) {
+ return -EINVAL;
+ }
- return result == OK ? messagesRead : result;
+ return MidiReceiver((AMIDI_Port*)outputPort).receive(opcodePtr, buffer, maxBytes,
+ numBytesReceivedPtr, timestampPtr);
}
-status_t AMIDI_closeOutputPort(AMIDI_OutputPort *outputPort) {
- return AMIDI_closePort((AMIDI_Port*)outputPort);
+void AMIDI_API AMidiOutputPort_close(const AMidiOutputPort *outputPort) {
+ AMIDI_closePort((AMIDI_Port*)outputPort);
}
/*
* Input (sending) API
*/
-status_t AMIDI_openInputPort(AMIDI_Device *device, int portNumber, AMIDI_InputPort **inputPortPtr) {
- return AMIDI_openPort(device, portNumber, PORTTYPE_INPUT, (AMIDI_Port**)inputPortPtr);
-}
-
-status_t AMIDI_closeInputPort(AMIDI_InputPort *inputPort) {
- return AMIDI_closePort((AMIDI_Port*)inputPort);
+media_status_t AMIDI_API AMidiInputPort_open(const AMidiDevice *device, int32_t portNumber,
+ AMidiInputPort **outInputPortPtr) {
+ return AMIDI_openPort(device, portNumber, PORTTYPE_INPUT, (AMIDI_Port**)outInputPortPtr);
}
-ssize_t AMIDI_getMaxMessageSizeInBytes(AMIDI_InputPort */*inputPort*/) {
- return SIZE_MIDIRECEIVEBUFFER;
+void AMIDI_API AMidiInputPort_close(const AMidiInputPort *inputPort) {
+ AMIDI_closePort((AMIDI_Port*)inputPort);
}
static ssize_t AMIDI_makeSendBuffer(
- uint8_t *buffer, uint8_t *data, ssize_t numBytes,uint64_t timestamp) {
+ uint8_t *buffer, const uint8_t *data, size_t numBytes, uint64_t timestamp) {
+ // Error checking will happen in the caller since this isn't an API function.
buffer[0] = AMIDI_OPCODE_DATA;
memcpy(buffer + 1, data, numBytes);
memcpy(buffer + 1 + numBytes, &timestamp, sizeof(timestamp));
return numBytes + AMIDI_PACKET_OVERHEAD;
}
-// Handy debugging function.
-//static void AMIDI_logBuffer(uint8_t *data, size_t numBytes) {
-// for (size_t index = 0; index < numBytes; index++) {
-// ALOGI(" data @%zu [0x%X]", index, data[index]);
-// }
-//}
-
-ssize_t AMIDI_send(AMIDI_InputPort *inputPort, uint8_t *buffer, ssize_t numBytes) {
- return AMIDI_sendWithTimestamp(inputPort, buffer, numBytes, 0);
+ssize_t AMIDI_API AMidiInputPort_send(const AMidiInputPort *inputPort, const uint8_t *buffer,
+ size_t numBytes) {
+ return AMidiInputPort_sendWithTimestamp(inputPort, buffer, numBytes, 0);
}
-ssize_t AMIDI_sendWithTimestamp(AMIDI_InputPort *inputPort, uint8_t *data,
- ssize_t numBytes, int64_t timestamp) {
-
- if (numBytes > SIZE_MIDIRECEIVEBUFFER) {
- return android::BAD_VALUE;
+ssize_t AMIDI_API AMidiInputPort_sendWithTimestamp(const AMidiInputPort *inputPort,
+ const uint8_t *data, size_t numBytes, int64_t timestamp) {
+ if (inputPort == nullptr || data == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
}
// AMIDI_logBuffer(data, numBytes);
- uint8_t writeBuffer[SIZE_MIDIRECEIVEBUFFER + AMIDI_PACKET_OVERHEAD];
- ssize_t numTransferBytes = AMIDI_makeSendBuffer(writeBuffer, data, numBytes, timestamp);
- ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, writeBuffer, numTransferBytes);
+ uint8_t writeBuffer[AMIDI_BUFFER_SIZE + AMIDI_PACKET_OVERHEAD];
+ size_t numSent = 0;
+ while (numSent < numBytes) {
+ size_t blockSize = AMIDI_BUFFER_SIZE;
+ blockSize = std::min(blockSize, numBytes - numSent);
+
+ ssize_t numTransferBytes =
+ AMIDI_makeSendBuffer(writeBuffer, data + numSent, blockSize, timestamp);
+ ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, writeBuffer, numTransferBytes);
+ if (numWritten < 0) {
+ break; // error so bail out.
+ }
+ if (numWritten < numTransferBytes) {
+ ALOGE("AMidiInputPort_sendWithTimestamp Couldn't write MIDI data buffer."
+ " requested:%zu, written%zu",numTransferBytes, numWritten);
+ break; // bail
+ }
- if (numWritten < numTransferBytes) {
- ALOGE("AMIDI_sendWithTimestamp Couldn't write MIDI data buffer. requested:%zu, written%zu",
- numTransferBytes, numWritten);
+ numSent += numWritten - AMIDI_PACKET_OVERHEAD;
}
- return numWritten - AMIDI_PACKET_OVERHEAD;
+ return numSent;
}
-status_t AMIDI_flush(AMIDI_InputPort *inputPort) {
+media_status_t AMIDI_API AMidiInputPort_sendFlush(const AMidiInputPort *inputPort) {
+ if (inputPort == nullptr) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
+
uint8_t opCode = AMIDI_OPCODE_FLUSH;
ssize_t numTransferBytes = 1;
ssize_t numWritten = write(((AMIDI_Port*)inputPort)->ufd, &opCode, numTransferBytes);
if (numWritten < numTransferBytes) {
- ALOGE("AMIDI_flush Couldn't write MIDI flush. requested:%zu, written%zu",
+ ALOGE("AMidiInputPort_flush Couldn't write MIDI flush. requested:%zd, written:%zd",
numTransferBytes, numWritten);
- return android::INVALID_OPERATION;
+ return AMEDIA_ERROR_UNSUPPORTED;
}
- return OK;
+ return AMEDIA_OK;
}
diff --git a/media/native/midi/midi.h b/media/native/midi/midi.h
deleted file mode 100644
index 9332b44dddd2..000000000000
--- a/media/native/midi/midi.h
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_MEDIA_MIDI_H_
-#define ANDROID_MEDIA_MIDI_H_
-
-#include <stdarg.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <utils/Errors.h>
-
-using android::status_t;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-struct AMIDI_Device;
-struct AMIDI_InputPort;
-struct AMIDI_OutputPort;
-
-#define AMIDI_INVALID_HANDLE NULL
-
-enum {
- AMIDI_OPCODE_DATA = 1,
- AMIDI_OPCODE_FLUSH = 2,
- AMIDI_PACKET_SIZE = 1024, /* !!! Currently MidiPortImpl.MAX_PACKET_SIZE !!! */
- AMIDI_PACKET_OVERHEAD = 9,
- AMIDI_BUFFER_SIZE = AMIDI_PACKET_SIZE - AMIDI_PACKET_OVERHEAD
- /* !!! TBD, currently MidiPortImpl.MAX_PACKET_DATA_SIZE !!! */
-};
-
-typedef struct {
- uint32_t opcode;
- uint8_t buffer[AMIDI_BUFFER_SIZE];
- size_t len;
- int64_t timestamp;
-} AMIDI_Message;
-
-enum {
- AMIDI_DEVICE_TYPE_USB = 1,
- AMIDI_DEVICE_TYPE_VIRTUAL = 2,
- AMIDI_DEVICE_TYPE_BLUETOOTH = 3
-};
-
-typedef struct {
- int32_t type;
- int32_t uid;
- int32_t isPrivate;
- int32_t inputPortCount;
- int32_t outputPortCount;
-} AMIDI_DeviceInfo;
-
-/*
- * Device API
- */
-/*
- * Retrieves information for the native MIDI device.
- *
- * device The Native API token for the device.
- * deviceInfoPtr Receives the associated device info.
- *
- * Returns OK or a (negative) error code.
- */
-status_t AMIDI_getDeviceInfo(AMIDI_Device *device, AMIDI_DeviceInfo *deviceInfoPtr);
-
-/*
- * API for receiving data from the Output port of a device.
- */
-/*
- * Opens the output port.
- *
- * device Identifies the device.
- * portNumber Specifies the zero-based port index on the device to open.
- * outputPortPtr Receives the native API port identifier of the opened port.
- *
- * Returns OK, or a (negative) error code.
- */
-status_t AMIDI_openOutputPort(AMIDI_Device *device, int portNumber,
- AMIDI_OutputPort **outputPortPtr);
-
-/*
- * Receives any pending MIDI messages (up to the specified maximum number of messages).
- *
- * outputPort Identifies the port to receive messages from.
- * messages Points to an array (size maxMessages) to receive the MIDI messages.
- * maxMessages The number of messages allocated in the messages array.
- *
- * Returns the number of messages received, or a (negative) error code.
- */
-ssize_t AMIDI_receive(AMIDI_OutputPort *outputPort, AMIDI_Message *messages, ssize_t maxMessages);
-
-/*
- * Closes the output port.
- *
- * outputPort The native API port identifier of the port.
- *
- * Returns OK, or a (negative) error code.
- */
-status_t AMIDI_closeOutputPort(AMIDI_OutputPort *outputPort);
-
-/*
- * API for sending data to the Input port of a device.
- */
-/*
- * Opens the input port.
- *
- * device Identifies the device.
- * portNumber Specifies the zero-based port index on the device to open.
- * inputPortPtr Receives the native API port identifier of the opened port.
- *
- * Returns OK, or a (negative) error code.
- */
-status_t AMIDI_openInputPort(AMIDI_Device *device, int portNumber, AMIDI_InputPort **inputPortPtr);
-
-/*
- * Returns the maximum number of bytes that can be received in a single MIDI message.
- */
-ssize_t AMIDI_getMaxMessageSizeInBytes(AMIDI_InputPort *inputPort);
-
-/*
- * Sends data to the specified input port.
- *
- * inputPort The native API identifier of the port to send data to.
- * buffer Points to the array of bytes containing the data to send.
- * numBytes Specifies the number of bytes to write.
- *
- * Returns The number of bytes sent or a (negative) error code.
- */
-ssize_t AMIDI_send(AMIDI_InputPort *inputPort, uint8_t *buffer, ssize_t numBytes);
-
-/*
- * Sends data to the specified input port with a timestamp.
- *
- * inputPort The native API identifier of the port to send data to.
- * buffer Points to the array of bytes containing the data to send.
- * numBytes Specifies the number of bytes to write.
- * timestamp The time stamp to associate with the sent data.
- *
- * Returns The number of bytes sent or a (negative) error code.
- */
-ssize_t AMIDI_sendWithTimestamp(AMIDI_InputPort *inputPort, uint8_t *buffer,
- ssize_t numBytes, int64_t timestamp);
-
-/*
- * Sends a message with a 'MIDI flush command code' to the specified port.
- *
- * inputPort The native API identifier of the port to send the flush message to.
- *
- * Returns OK, or a (negative) error code.
- */
-status_t AMIDI_flush(AMIDI_InputPort *inputPort);
-
-/*
- * Closes the input port.
- *
- * inputPort The native API port identifier of the port.
- *
- *
- * Returns OK, or a (negative) error code.
- */
-status_t AMIDI_closeInputPort(AMIDI_InputPort *inputPort);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ANDROID_MEDIA_MIDI_H_ */
diff --git a/media/native/midi/midi_internal.h b/media/native/midi/midi_internal.h
index fd4770e05d6c..cb3ecce13533 100644
--- a/media/native/midi/midi_internal.h
+++ b/media/native/midi/midi_internal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,11 +17,25 @@
#ifndef ANDROID_MEDIA_MIDI_INTERNAL_H_
#define ANDROID_MEDIA_MIDI_INTERNAL_H_
+#include <jni.h>
+
#include "android/media/midi/BpMidiDeviceServer.h"
-struct AMIDI_Device {
- android::sp<android::media::midi::BpMidiDeviceServer> server;
- int32_t deviceId;
+typedef struct {
+ int32_t type; /* one of AMIDI_DEVICE_TYPE_* constants */
+ int32_t inputPortCount; /* number of input (send) ports associated with the device */
+ int32_t outputPortCount; /* number of output (received) ports associated with the device */
+} AMidiDeviceInfo;
+
+struct AMidiDevice {
+ android::sp<android::media::midi::BpMidiDeviceServer>
+ server; /* The Binder interface to the MIDI server (from the Java MidiDevice) */
+ int32_t deviceId; /* The integer id of the device assigned in the Java API */
+ JavaVM* javaVM; /* The Java VM (so we can obtain the JNIEnv in the
+ AMidiDevice_close function) */
+ jobject midiDeviceObj; /* NewGlobalRef() reference to the Java MidiDevice associated with
+ this native AMidiDevice. */
+ AMidiDeviceInfo deviceInfo; /* Attributes of the device. */
};
#endif // ANDROID_MEDIA_MIDI_INTERNAL_H_
diff --git a/media/tests/NativeMidiDemo/Android.mk b/media/tests/NativeMidiDemo/Android.mk
deleted file mode 100644
index 316858f667fd..000000000000
--- a/media/tests/NativeMidiDemo/Android.mk
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_PACKAGE_NAME := NativeMidiDemo
-
-#LOCAL_SDK_VERSION := current
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_PROGUARD_ENABLED := disabled
-LOCAL_SRC_FILES := $(call all-java-files-under, java)
-
-LOCAL_JNI_SHARED_LIBRARIES := libnativemidi_jni
-
-include $(BUILD_PACKAGE)
-
-# Include packages in subdirectories
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/tests/NativeMidiDemo/AndroidManifest.xml b/media/tests/NativeMidiDemo/AndroidManifest.xml
deleted file mode 100644
index 322873f11895..000000000000
--- a/media/tests/NativeMidiDemo/AndroidManifest.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.example.android.nativemididemo"
- android:versionCode="1"
- android:versionName="1.0">
- <application
- android:allowBackup="false"
- android:fullBackupContent="false"
- android:icon="@mipmap/ic_launcher"
- android:label="@string/app_name">
- <uses-feature android:name="android.software.midi" android:required="true"/>
- <activity android:name=".NativeMidi"
- android:label="@string/app_name">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- </application>
-</manifest>
diff --git a/media/tests/NativeMidiDemo/java/com/example/android/nativemididemo/NativeMidi.java b/media/tests/NativeMidiDemo/java/com/example/android/nativemididemo/NativeMidi.java
deleted file mode 100644
index b0ca0bb74548..000000000000
--- a/media/tests/NativeMidiDemo/java/com/example/android/nativemididemo/NativeMidi.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.example.android.nativemididemo;
-
-import android.app.Activity;
-import android.content.Context;
-import android.media.midi.MidiDevice;
-import android.media.midi.MidiDeviceInfo;
-import android.media.midi.MidiManager;
-import android.media.midi.MidiOutputPort;
-import android.media.midi.MidiReceiver;
-import android.media.AudioManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.view.View;
-import android.view.WindowManager;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.TextView;
-
-import java.io.IOException;
-
-public class NativeMidi extends Activity
-{
- private TextView mCallbackStatusTextView;
- private TextView mJavaMidiStatusTextView;
- private TextView mMessagesTextView;
- private RadioGroup mMidiDevicesRadioGroup;
- private Handler mTimerHandler = new Handler();
- private boolean mAudioWorks;
- private final int mMinFramesPerBuffer = 32; // See {min|max}PlaySamples in nativemidi-jni.cpp
- private final int mMaxFramesPerBuffer = 1000;
- private int mFramesPerBuffer;
-
- private TouchableScrollView mMessagesContainer;
- private MidiManager mMidiManager;
- private MidiOutputPortSelector mActivePortSelector;
-
- private Runnable mTimerRunnable = new Runnable() {
- private long mLastTime;
- private long mLastPlaybackCounter;
- private int mLastCallbackRate;
- private long mLastUntouchedTime;
-
- @Override
- public void run() {
- final long checkIntervalMs = 1000;
- long currentTime = System.currentTimeMillis();
- long currentPlaybackCounter = getPlaybackCounter();
- if (currentTime - mLastTime >= checkIntervalMs) {
- int callbackRate = Math.round(
- (float)(currentPlaybackCounter - mLastPlaybackCounter) /
- ((float)(currentTime - mLastTime) / (float)1000));
- if (mLastCallbackRate != callbackRate) {
- mCallbackStatusTextView.setText(
- "CB: " + callbackRate + " Hz");
- mLastCallbackRate = callbackRate;
- }
- mLastTime = currentTime;
- mLastPlaybackCounter = currentPlaybackCounter;
- }
-
- String[] newMessages = getRecentMessages();
- if (newMessages != null) {
- for (String message : newMessages) {
- mMessagesTextView.append(message);
- mMessagesTextView.append("\n");
- }
- if (!mMessagesContainer.isTouched) {
- if (mLastUntouchedTime == 0) mLastUntouchedTime = currentTime;
- if (currentTime - mLastUntouchedTime > 3000) {
- mMessagesContainer.fullScroll(View.FOCUS_DOWN);
- }
- } else {
- mLastUntouchedTime = 0;
- }
- }
-
- mTimerHandler.postDelayed(this, checkIntervalMs / 4);
- }
- };
-
- private void addMessage(final String message) {
- mTimerHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- mMessagesTextView.append(message);
- }
- }, 0);
- }
-
- private class MidiOutputPortSelector implements View.OnClickListener {
- private final MidiDeviceInfo mDeviceInfo;
- private final int mPortNumber;
- private MidiDevice mDevice;
- private MidiOutputPort mOutputPort;
-
- MidiOutputPortSelector() {
- mDeviceInfo = null;
- mPortNumber = -1;
- }
-
- MidiOutputPortSelector(MidiDeviceInfo info, int portNumber) {
- mDeviceInfo = info;
- mPortNumber = portNumber;
- }
-
- MidiDeviceInfo getDeviceInfo() { return mDeviceInfo; }
-
- @Override
- public void onClick(View v) {
- if (mActivePortSelector != null) {
- mActivePortSelector.close();
- mActivePortSelector = null;
- }
- if (mDeviceInfo == null) {
- mActivePortSelector = this;
- return;
- }
- mMidiManager.openDevice(mDeviceInfo, new MidiManager.OnDeviceOpenedListener() {
- @Override
- public void onDeviceOpened(MidiDevice device) {
- if (device == null) {
- addMessage("! Failed to open MIDI device !\n");
- } else {
- mDevice = device;
- try {
- mDevice.mirrorToNative();
- startReadingMidi(mDevice.getInfo().getId(), mPortNumber);
- } catch (IOException e) {
- addMessage("! Failed to mirror to native !\n" + e.getMessage() + "\n");
- }
-
- mActivePortSelector = MidiOutputPortSelector.this;
-
- mOutputPort = device.openOutputPort(mPortNumber);
- mOutputPort.connect(mMidiReceiver);
- }
- }
- }, null);
- }
-
- void closePortOnly() {
- stopReadingMidi();
- }
-
- void close() {
- closePortOnly();
- try {
- if (mOutputPort != null) {
- mOutputPort.close();
- }
- } catch (IOException e) {
- mMessagesTextView.append("! Port close error: " + e + "\n");
- } finally {
- mOutputPort = null;
- }
- try {
- if (mDevice != null) {
- mDevice.close();
- }
- } catch (IOException e) {
- mMessagesTextView.append("! Device close error: " + e + "\n");
- } finally {
- mDevice = null;
- }
- }
- }
-
- private MidiManager.DeviceCallback mMidiDeviceCallback = new MidiManager.DeviceCallback() {
- @Override
- public void onDeviceAdded(MidiDeviceInfo info) {
- Bundle deviceProps = info.getProperties();
- String deviceName = deviceProps.getString(MidiDeviceInfo.PROPERTY_NAME);
- if (deviceName == null) {
- deviceName = deviceProps.getString(MidiDeviceInfo.PROPERTY_MANUFACTURER);
- }
-
- for (MidiDeviceInfo.PortInfo port : info.getPorts()) {
- if (port.getType() != MidiDeviceInfo.PortInfo.TYPE_OUTPUT) continue;
- String portName = port.getName();
- int portNumber = port.getPortNumber();
- if (portName.length() == 0) portName = "[" + portNumber + "]";
- portName += "@" + deviceName;
- RadioButton outputDevice = new RadioButton(NativeMidi.this);
- outputDevice.setText(portName);
- outputDevice.setTag(info);
- outputDevice.setOnClickListener(new MidiOutputPortSelector(info, portNumber));
- mMidiDevicesRadioGroup.addView(outputDevice);
- }
-
- NativeMidi.this.updateKeepScreenOn();
- }
-
- @Override
- public void onDeviceRemoved(MidiDeviceInfo info) {
- if (mActivePortSelector != null && info.equals(mActivePortSelector.getDeviceInfo())) {
- mActivePortSelector.close();
- mActivePortSelector = null;
- }
- int removeButtonStart = -1, removeButtonCount = 0;
- final int buttonCount = mMidiDevicesRadioGroup.getChildCount();
- boolean checked = false;
- for (int i = 0; i < buttonCount; ++i) {
- RadioButton button = (RadioButton) mMidiDevicesRadioGroup.getChildAt(i);
- if (!info.equals(button.getTag())) continue;
- if (removeButtonStart == -1) removeButtonStart = i;
- ++removeButtonCount;
- if (button.isChecked()) checked = true;
- }
- if (removeButtonStart != -1) {
- mMidiDevicesRadioGroup.removeViews(removeButtonStart, removeButtonCount);
- if (checked) {
- mMidiDevicesRadioGroup.check(R.id.device_none);
- }
- }
-
- NativeMidi.this.updateKeepScreenOn();
- }
- };
-
- private class JavaMidiReceiver extends MidiReceiver implements Runnable {
- @Override
- public void onSend(byte[] data, int offset,
- int count, long timestamp) throws IOException {
- mTimerHandler.removeCallbacks(this);
- mTimerHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- mJavaMidiStatusTextView.setText("Java: MSG");
- }
- }, 0);
- mTimerHandler.postDelayed(this, 100);
- }
-
- @Override
- public void run() {
- mJavaMidiStatusTextView.setText("Java: ---");
- }
- }
-
- private JavaMidiReceiver mMidiReceiver = new JavaMidiReceiver();
-
- private void updateKeepScreenOn() {
- if (mMidiDevicesRadioGroup.getChildCount() > 1) {
- getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- } else {
- getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
- }
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
-
- mCallbackStatusTextView = findViewById(R.id.callback_status);
- mJavaMidiStatusTextView = findViewById(R.id.java_midi_status);
- mMessagesTextView = findViewById(R.id.messages);
- mMessagesContainer = findViewById(R.id.messages_scroll);
- mMidiDevicesRadioGroup = findViewById(R.id.devices);
- RadioButton deviceNone = findViewById(R.id.device_none);
- deviceNone.setOnClickListener(new MidiOutputPortSelector());
-
- AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
- String sampleRate = am.getProperty(AudioManager.PROPERTY_OUTPUT_SAMPLE_RATE);
- if (sampleRate == null) sampleRate = "48000";
- String framesPerBuffer = am.getProperty(AudioManager.PROPERTY_OUTPUT_FRAMES_PER_BUFFER);
- if (framesPerBuffer == null) framesPerBuffer = Integer.toString(mMaxFramesPerBuffer);
- mFramesPerBuffer = Integer.parseInt(framesPerBuffer);
- String audioInitResult = initAudio(Integer.parseInt(sampleRate), mFramesPerBuffer);
- mMessagesTextView.append("Open SL ES init: " + audioInitResult + "\n");
-
- if (audioInitResult.startsWith("Success")) {
- mAudioWorks = true;
- mTimerHandler.postDelayed(mTimerRunnable, 0);
- mTimerHandler.postDelayed(mMidiReceiver, 0);
- }
-
- mMidiManager = (MidiManager) getSystemService(Context.MIDI_SERVICE);
- mMidiManager.registerDeviceCallback(mMidiDeviceCallback, new Handler());
- for (MidiDeviceInfo info : mMidiManager.getDevices()) {
- mMidiDeviceCallback.onDeviceAdded(info);
- }
- }
-
- @Override
- public void onPause() {
- super.onPause();
- if (mAudioWorks) {
- mTimerHandler.removeCallbacks(mTimerRunnable);
- pauseAudio();
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
- if (mAudioWorks) {
- mTimerHandler.postDelayed(mTimerRunnable, 0);
- resumeAudio();
- }
- }
-
- @Override
- protected void onDestroy() {
- if (mActivePortSelector != null) {
- mActivePortSelector.close();
- mActivePortSelector = null;
- }
- shutdownAudio();
- super.onDestroy();
- }
-
- public void onClearMessages(View v) {
- mMessagesTextView.setText("");
- }
-
- public void onClosePort(View v) {
- if (mActivePortSelector != null) {
- mActivePortSelector.closePortOnly();
- }
- }
-
- private native String initAudio(int sampleRate, int playSamples);
- private native void pauseAudio();
- private native void resumeAudio();
- private native void shutdownAudio();
-
- private native long getPlaybackCounter();
- private native String[] getRecentMessages();
-
- private native void startReadingMidi(int deviceId, int portNumber);
- private native void stopReadingMidi();
-
- static {
- System.loadLibrary("nativemidi_jni");
- }
-}
diff --git a/media/tests/NativeMidiDemo/java/com/example/android/nativemididemo/TouchableScrollView.java b/media/tests/NativeMidiDemo/java/com/example/android/nativemididemo/TouchableScrollView.java
deleted file mode 100644
index 645aafa88507..000000000000
--- a/media/tests/NativeMidiDemo/java/com/example/android/nativemididemo/TouchableScrollView.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package com.example.android.nativemididemo;
-
-import android.content.Context;
-import android.view.MotionEvent;
-import android.util.AttributeSet;
-import android.widget.ScrollView;
-
-public class TouchableScrollView extends ScrollView {
- public boolean isTouched;
-
- public TouchableScrollView(Context context) {
- super(context);
- }
-
- public TouchableScrollView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- isTouched = true;
- break;
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_UP:
- isTouched = false;
- break;
- }
- return super.onTouchEvent(event);
- }
-}
diff --git a/media/tests/NativeMidiDemo/jni/Android.mk b/media/tests/NativeMidiDemo/jni/Android.mk
deleted file mode 100644
index 69a64bd0218b..000000000000
--- a/media/tests/NativeMidiDemo/jni/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) 2016 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_MODULE := libnativemidi_jni
-
-LOCAL_SRC_FILES := \
- nativemidi-jni.cpp \
- messagequeue.cpp
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror -O0
-
-LOCAL_C_INCLUDES += \
- frameworks/base/media/native
-
-LOCAL_CXX_STL := libc++_static
-
-LOCAL_SHARED_LIBRARIES := libOpenSLES libmidi
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/tests/NativeMidiDemo/jni/messagequeue.cpp b/media/tests/NativeMidiDemo/jni/messagequeue.cpp
deleted file mode 100644
index ffaef38bed8c..000000000000
--- a/media/tests/NativeMidiDemo/jni/messagequeue.cpp
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#include <atomic>
-#include <stdio.h>
-#include <string.h>
-
-#include "messagequeue.h"
-
-namespace nativemididemo {
-
-static const int messageBufferSize = 64 * 1024;
-static char messageBuffer[messageBufferSize];
-static std::atomic_ullong messagesLastWritePosition;
-
-void writeMessage(const char* message)
-{
- static unsigned long long lastWritePos = 0;
- size_t messageLen = strlen(message);
- if (messageLen == 0) return;
-
- messageLen += 1; // Also count in the null terminator.
- char buffer[1024];
- if (messageLen >= messageBufferSize) {
- snprintf(buffer, sizeof(buffer), "!!! Message too long: %zu bytes !!!", messageLen);
- message = buffer;
- messageLen = strlen(message);
- }
-
- size_t wrappedWritePos = lastWritePos % messageBufferSize;
- if (wrappedWritePos + messageLen >= messageBufferSize) {
- size_t tailLen = messageBufferSize - wrappedWritePos;
- memset(messageBuffer + wrappedWritePos, 0, tailLen);
- lastWritePos += tailLen;
- wrappedWritePos = 0;
- }
-
- memcpy(messageBuffer + wrappedWritePos, message, messageLen);
- lastWritePos += messageLen;
- messagesLastWritePosition.store(lastWritePos);
-}
-
-static char messageBufferCopy[messageBufferSize];
-
-jobjectArray getRecentMessagesForJava(JNIEnv* env, jobject)
-{
- static unsigned long long lastReadPos = 0;
- const char* overrunMessage = "";
- size_t messagesCount = 0;
- jobjectArray result = NULL;
-
- // First we copy the portion of the message buffer into messageBufferCopy. If after finishing
- // the copy we notice that the writer has mutated the portion of the buffer that we were
- // copying, we report an overrun. Afterwards we can safely read messages from the copy.
- memset(messageBufferCopy, 0, sizeof(messageBufferCopy));
- unsigned long long lastWritePos = messagesLastWritePosition.load();
- if (lastWritePos - lastReadPos > messageBufferSize) {
- overrunMessage = "!!! Message buffer overrun !!!";
- messagesCount = 1;
- lastReadPos = lastWritePos;
- goto create_array;
- }
- if (lastWritePos == lastReadPos) return result;
- if (lastWritePos / messageBufferSize == lastReadPos / messageBufferSize) {
- size_t wrappedReadPos = lastReadPos % messageBufferSize;
- memcpy(messageBufferCopy + wrappedReadPos,
- messageBuffer + wrappedReadPos,
- lastWritePos % messageBufferSize - wrappedReadPos);
- } else {
- size_t wrappedReadPos = lastReadPos % messageBufferSize;
- memcpy(messageBufferCopy, messageBuffer, lastWritePos % messageBufferSize);
- memcpy(messageBufferCopy + wrappedReadPos,
- messageBuffer + wrappedReadPos,
- messageBufferSize - wrappedReadPos);
- }
- {
- unsigned long long newLastWritePos = messagesLastWritePosition.load();
- if (newLastWritePos - lastReadPos > messageBufferSize) {
- overrunMessage = "!!! Message buffer overrun !!!";
- messagesCount = 1;
- lastReadPos = lastWritePos = newLastWritePos;
- goto create_array;
- }
- }
- // Otherwise we ignore newLastWritePos, since we only have a copy of the buffer
- // up to lastWritePos.
-
- for (unsigned long long readPos = lastReadPos; readPos < lastWritePos; ) {
- size_t messageLen = strlen(messageBufferCopy + (readPos % messageBufferSize));
- if (messageLen != 0) {
- readPos += messageLen + 1;
- messagesCount++;
- } else {
- // Skip to the beginning of the buffer.
- readPos = (readPos / messageBufferSize + 1) * messageBufferSize;
- }
- }
- if (messagesCount == 0) {
- lastReadPos = lastWritePos;
- return result;
- }
-
-create_array:
- result = env->NewObjectArray(
- messagesCount, env->FindClass("java/lang/String"), env->NewStringUTF(overrunMessage));
- if (lastWritePos == lastReadPos) return result;
-
- jsize arrayIndex = 0;
- while (lastReadPos < lastWritePos) {
- size_t wrappedReadPos = lastReadPos % messageBufferSize;
- if (messageBufferCopy[wrappedReadPos] != '\0') {
- jstring message = env->NewStringUTF(messageBufferCopy + wrappedReadPos);
- env->SetObjectArrayElement(result, arrayIndex++, message);
- lastReadPos += env->GetStringLength(message) + 1;
- env->DeleteLocalRef(message);
- } else {
- // Skip to the beginning of the buffer.
- lastReadPos = (lastReadPos / messageBufferSize + 1) * messageBufferSize;
- }
- }
- return result;
-}
-
-} // namespace nativemididemo
diff --git a/media/tests/NativeMidiDemo/jni/messagequeue.h b/media/tests/NativeMidiDemo/jni/messagequeue.h
deleted file mode 100644
index 20aa9e805d12..000000000000
--- a/media/tests/NativeMidiDemo/jni/messagequeue.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#ifndef NATIVEMIDIDEMO_MESSAGEQUEUE_H
-#define NATIVEMIDIDEMO_MESSAGEQUEUE_H
-
-#include <jni.h>
-
-namespace nativemididemo {
-
-void writeMessage(const char* message);
-jobjectArray getRecentMessagesForJava(JNIEnv* env, jobject thiz);
-
-} // namespace nativemididemo
-
-#endif // NATIVEMIDIDEMO_MESSAGEQUEUE_H
diff --git a/media/tests/NativeMidiDemo/jni/nativemidi-jni.cpp b/media/tests/NativeMidiDemo/jni/nativemidi-jni.cpp
deleted file mode 100644
index 0110b75b7ba4..000000000000
--- a/media/tests/NativeMidiDemo/jni/nativemidi-jni.cpp
+++ /dev/null
@@ -1,286 +0,0 @@
-#include <atomic>
-#include <inttypes.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <jni.h>
-
-#include <midi/midi.h>
-#include <SLES/OpenSLES.h>
-#include <SLES/OpenSLES_Android.h>
-
-#include "messagequeue.h"
-
-extern "C" {
-JNIEXPORT jstring JNICALL Java_com_example_android_nativemididemo_NativeMidi_initAudio(
- JNIEnv* env, jobject thiz, jint sampleRate, jint playSamples);
-JNIEXPORT void JNICALL Java_com_example_android_nativemididemo_NativeMidi_pauseAudio(
- JNIEnv* env, jobject thiz);
-JNIEXPORT void JNICALL Java_com_example_android_nativemididemo_NativeMidi_resumeAudio(
- JNIEnv* env, jobject thiz);
-JNIEXPORT void JNICALL Java_com_example_android_nativemididemo_NativeMidi_shutdownAudio(
- JNIEnv* env, jobject thiz);
-JNIEXPORT jlong JNICALL Java_com_example_android_nativemididemo_NativeMidi_getPlaybackCounter(
- JNIEnv* env, jobject thiz);
-JNIEXPORT jobjectArray JNICALL Java_com_example_android_nativemididemo_NativeMidi_getRecentMessages(
- JNIEnv* env, jobject thiz);
-JNIEXPORT void JNICALL Java_com_example_android_nativemididemo_NativeMidi_startReadingMidi(
- JNIEnv* env, jobject thiz, jint deviceId, jint portNumber);
-JNIEXPORT void JNICALL Java_com_example_android_nativemididemo_NativeMidi_stopReadingMidi(
- JNIEnv* env, jobject thiz);
-}
-
-static const char* errStrings[] = {
- "SL_RESULT_SUCCESS", // 0
- "SL_RESULT_PRECONDITIONS_VIOLATED", // 1
- "SL_RESULT_PARAMETER_INVALID", // 2
- "SL_RESULT_MEMORY_FAILURE", // 3
- "SL_RESULT_RESOURCE_ERROR", // 4
- "SL_RESULT_RESOURCE_LOST", // 5
- "SL_RESULT_IO_ERROR", // 6
- "SL_RESULT_BUFFER_INSUFFICIENT", // 7
- "SL_RESULT_CONTENT_CORRUPTED", // 8
- "SL_RESULT_CONTENT_UNSUPPORTED", // 9
- "SL_RESULT_CONTENT_NOT_FOUND", // 10
- "SL_RESULT_PERMISSION_DENIED", // 11
- "SL_RESULT_FEATURE_UNSUPPORTED", // 12
- "SL_RESULT_INTERNAL_ERROR", // 13
- "SL_RESULT_UNKNOWN_ERROR", // 14
- "SL_RESULT_OPERATION_ABORTED", // 15
- "SL_RESULT_CONTROL_LOST" }; // 16
-static const char* getSLErrStr(int code) {
- return errStrings[code];
-}
-
-static SLObjectItf engineObject;
-static SLEngineItf engineEngine;
-static SLObjectItf outputMixObject;
-static SLObjectItf playerObject;
-static SLPlayItf playerPlay;
-static SLAndroidSimpleBufferQueueItf playerBufferQueue;
-
-static const int minPlaySamples = 32;
-static const int maxPlaySamples = 1000;
-static std::atomic_int playSamples(maxPlaySamples);
-static short playBuffer[maxPlaySamples];
-
-static std::atomic_ullong sharedCounter;
-
-static AMIDI_Device* midiDevice = AMIDI_INVALID_HANDLE;
-static std::atomic<AMIDI_OutputPort*> midiOutputPort(AMIDI_INVALID_HANDLE);
-
-static int setPlaySamples(int newPlaySamples)
-{
- if (newPlaySamples < minPlaySamples) newPlaySamples = minPlaySamples;
- if (newPlaySamples > maxPlaySamples) newPlaySamples = maxPlaySamples;
- playSamples.store(newPlaySamples);
- return newPlaySamples;
-}
-
-// Amount of messages we are ready to handle during one callback cycle.
-static const size_t MAX_INCOMING_MIDI_MESSAGES = 20;
-// Static allocation to save time in the callback.
-static AMIDI_Message incomingMidiMessages[MAX_INCOMING_MIDI_MESSAGES];
-
-static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void */*context*/)
-{
- sharedCounter++;
-
- AMIDI_OutputPort* outputPort = midiOutputPort.load();
- if (outputPort != AMIDI_INVALID_HANDLE) {
- char midiDumpBuffer[1024];
- ssize_t midiReceived = AMIDI_receive(
- outputPort, incomingMidiMessages, MAX_INCOMING_MIDI_MESSAGES);
- if (midiReceived >= 0) {
- for (ssize_t i = 0; i < midiReceived; ++i) {
- AMIDI_Message* msg = &incomingMidiMessages[i];
- if (msg->opcode == AMIDI_OPCODE_DATA) {
- memset(midiDumpBuffer, 0, sizeof(midiDumpBuffer));
- int pos = snprintf(midiDumpBuffer, sizeof(midiDumpBuffer),
- "%" PRIx64 " ", msg->timestamp);
- for (uint8_t *b = msg->buffer, *e = b + msg->len; b < e; ++b) {
- pos += snprintf(midiDumpBuffer + pos, sizeof(midiDumpBuffer) - pos,
- "%02x ", *b);
- }
- nativemididemo::writeMessage(midiDumpBuffer);
- } else if (msg->opcode == AMIDI_OPCODE_FLUSH) {
- nativemididemo::writeMessage("MIDI flush");
- }
- }
- } else {
- snprintf(midiDumpBuffer, sizeof(midiDumpBuffer),
- "! MIDI Receive error: %s !", strerror(-midiReceived));
- nativemididemo::writeMessage(midiDumpBuffer);
- }
- }
-
- size_t usedBufferSize = playSamples.load() * sizeof(playBuffer[0]);
- if (usedBufferSize > sizeof(playBuffer)) {
- usedBufferSize = sizeof(playBuffer);
- }
- (*bq)->Enqueue(bq, playBuffer, usedBufferSize);
-}
-
-jstring Java_com_example_android_nativemididemo_NativeMidi_initAudio(
- JNIEnv* env, jobject, jint sampleRate, jint playSamples) {
- const char* stage;
- SLresult result;
- char printBuffer[1024];
-
- playSamples = setPlaySamples(playSamples);
-
- result = slCreateEngine(&engineObject, 0, NULL, 0, NULL, NULL);
- if (SL_RESULT_SUCCESS != result) { stage = "slCreateEngine"; goto handle_error; }
-
- result = (*engineObject)->Realize(engineObject, SL_BOOLEAN_FALSE);
- if (SL_RESULT_SUCCESS != result) { stage = "realize Engine object"; goto handle_error; }
-
- result = (*engineObject)->GetInterface(engineObject, SL_IID_ENGINE, &engineEngine);
- if (SL_RESULT_SUCCESS != result) { stage = "get Engine interface"; goto handle_error; }
-
- result = (*engineEngine)->CreateOutputMix(engineEngine, &outputMixObject, 0, NULL, NULL);
- if (SL_RESULT_SUCCESS != result) { stage = "CreateOutputMix"; goto handle_error; }
-
- result = (*outputMixObject)->Realize(outputMixObject, SL_BOOLEAN_FALSE);
- if (SL_RESULT_SUCCESS != result) { stage = "realize OutputMix object"; goto handle_error; }
-
- {
- SLDataFormat_PCM format_pcm = { SL_DATAFORMAT_PCM, 1, (SLuint32)sampleRate * 1000,
- SL_PCMSAMPLEFORMAT_FIXED_16, SL_PCMSAMPLEFORMAT_FIXED_16,
- SL_SPEAKER_FRONT_LEFT, SL_BYTEORDER_LITTLEENDIAN };
- SLDataLocator_AndroidSimpleBufferQueue loc_bufq =
- { SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 1 };
- SLDataSource audioSrc = { &loc_bufq, &format_pcm };
- SLDataLocator_OutputMix loc_outmix = { SL_DATALOCATOR_OUTPUTMIX, outputMixObject };
- SLDataSink audioSnk = { &loc_outmix, NULL };
- const SLInterfaceID ids[1] = { SL_IID_BUFFERQUEUE };
- const SLboolean req[1] = { SL_BOOLEAN_TRUE };
- result = (*engineEngine)->CreateAudioPlayer(
- engineEngine, &playerObject, &audioSrc, &audioSnk, 1, ids, req);
- if (SL_RESULT_SUCCESS != result) { stage = "CreateAudioPlayer"; goto handle_error; }
-
- result = (*playerObject)->Realize(playerObject, SL_BOOLEAN_FALSE);
- if (SL_RESULT_SUCCESS != result) { stage = "realize Player object"; goto handle_error; }
- }
-
- result = (*playerObject)->GetInterface(playerObject, SL_IID_PLAY, &playerPlay);
- if (SL_RESULT_SUCCESS != result) { stage = "get Play interface"; goto handle_error; }
-
- result = (*playerObject)->GetInterface(playerObject, SL_IID_BUFFERQUEUE, &playerBufferQueue);
- if (SL_RESULT_SUCCESS != result) { stage = "get BufferQueue interface"; goto handle_error; }
-
- result = (*playerBufferQueue)->RegisterCallback(playerBufferQueue, bqPlayerCallback, NULL);
- if (SL_RESULT_SUCCESS != result) { stage = "register BufferQueue callback"; goto handle_error; }
-
- result = (*playerBufferQueue)->Enqueue(playerBufferQueue, playBuffer, sizeof(playBuffer));
- if (SL_RESULT_SUCCESS != result) {
- stage = "enqueue into PlayerBufferQueue"; goto handle_error; }
-
- result = (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
- if (SL_RESULT_SUCCESS != result) {
- stage = "SetPlayState(SL_PLAYSTATE_PLAYING)"; goto handle_error; }
-
- snprintf(printBuffer, sizeof(printBuffer),
- "Success, sample rate %d, buffer samples %d", sampleRate, playSamples);
- return env->NewStringUTF(printBuffer);
-
-handle_error:
- snprintf(printBuffer, sizeof(printBuffer), "Error at %s: %s", stage, getSLErrStr(result));
- return env->NewStringUTF(printBuffer);
-}
-
-void Java_com_example_android_nativemididemo_NativeMidi_pauseAudio(
- JNIEnv*, jobject) {
- if (playerPlay != NULL) {
- (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PAUSED);
- }
-}
-
-void Java_com_example_android_nativemididemo_NativeMidi_resumeAudio(
- JNIEnv*, jobject) {
- if (playerBufferQueue != NULL && playerPlay != NULL) {
- (*playerBufferQueue)->Enqueue(playerBufferQueue, playBuffer, sizeof(playBuffer));
- (*playerPlay)->SetPlayState(playerPlay, SL_PLAYSTATE_PLAYING);
- }
-}
-
-void Java_com_example_android_nativemididemo_NativeMidi_shutdownAudio(
- JNIEnv*, jobject) {
- if (playerObject != NULL) {
- (*playerObject)->Destroy(playerObject);
- playerObject = NULL;
- playerPlay = NULL;
- playerBufferQueue = NULL;
- }
-
- if (outputMixObject != NULL) {
- (*outputMixObject)->Destroy(outputMixObject);
- outputMixObject = NULL;
- }
-
- if (engineObject != NULL) {
- (*engineObject)->Destroy(engineObject);
- engineObject = NULL;
- engineEngine = NULL;
- }
-}
-
-jlong Java_com_example_android_nativemididemo_NativeMidi_getPlaybackCounter(JNIEnv*, jobject) {
- return sharedCounter.load();
-}
-
-jobjectArray Java_com_example_android_nativemididemo_NativeMidi_getRecentMessages(
- JNIEnv* env, jobject thiz) {
- return nativemididemo::getRecentMessagesForJava(env, thiz);
-}
-
-void Java_com_example_android_nativemididemo_NativeMidi_startReadingMidi(
- JNIEnv*, jobject, jlong deviceHandle, jint portNumber) {
- char buffer[1024];
-
- midiDevice = (AMIDI_Device*)deviceHandle;
-// int result = AMIDI_getDeviceById(deviceId, &midiDevice);
-// if (result == 0) {
-// snprintf(buffer, sizeof(buffer), "Obtained device token for uid %d: token %d", deviceId, midiDevice);
-// } else {
-// snprintf(buffer, sizeof(buffer), "Could not obtain device token for uid %d: %d", deviceId, result);
-// }
- nativemididemo::writeMessage(buffer);
-// if (result) return;
-
- AMIDI_DeviceInfo deviceInfo;
- int result = AMIDI_getDeviceInfo(midiDevice, &deviceInfo);
- if (result == 0) {
- snprintf(buffer, sizeof(buffer), "Device info: uid %d, type %d, priv %d, ports %d I / %d O",
- deviceInfo.uid, deviceInfo.type, deviceInfo.isPrivate,
- (int)deviceInfo.inputPortCount, (int)deviceInfo.outputPortCount);
- } else {
- snprintf(buffer, sizeof(buffer), "Could not obtain device info %d", result);
- }
- nativemididemo::writeMessage(buffer);
- if (result) return;
-
- AMIDI_OutputPort* outputPort;
- result = AMIDI_openOutputPort(midiDevice, portNumber, &outputPort);
- if (result == 0) {
- snprintf(buffer, sizeof(buffer), "Opened port %d: token %p", portNumber, outputPort);
- midiOutputPort.store(outputPort);
- } else {
- snprintf(buffer, sizeof(buffer), "Could not open port %p: %d", midiDevice, result);
- }
- nativemididemo::writeMessage(buffer);
-}
-
-void Java_com_example_android_nativemididemo_NativeMidi_stopReadingMidi(
- JNIEnv*, jobject) {
- AMIDI_OutputPort* outputPort = midiOutputPort.exchange(AMIDI_INVALID_HANDLE);
- if (outputPort == AMIDI_INVALID_HANDLE) return;
- int result = AMIDI_closeOutputPort(outputPort);
- char buffer[1024];
- if (result == 0) {
- snprintf(buffer, sizeof(buffer), "Closed port by token %p", outputPort);
- } else {
- snprintf(buffer, sizeof(buffer), "Could not close port by token %p: %d", outputPort, result);
- }
- nativemididemo::writeMessage(buffer);
-}
diff --git a/media/tests/NativeMidiDemo/res/layout/main.xml b/media/tests/NativeMidiDemo/res/layout/main.xml
deleted file mode 100644
index 465d471a2de7..000000000000
--- a/media/tests/NativeMidiDemo/res/layout/main.xml
+++ /dev/null
@@ -1,93 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
- <TextView
- android:id="@+id/callback_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="13sp"
- android:typeface="monospace"
- />
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="13sp"
- android:typeface="monospace"
- android:text=" | "
- />
- <TextView
- android:id="@+id/java_midi_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textSize="13sp"
- android:typeface="monospace"
- />
- <TextView
- android:layout_width="0px"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textSize="13sp"
- android:typeface="monospace"
- android:text=" "
- />
- </LinearLayout>
- <HorizontalScrollView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:paddingTop="6sp"
- android:paddingBottom="6sp"
- >
- <RadioGroup
- android:id="@+id/devices"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:checkedButton="@+id/device_none"
- >
- <RadioButton
- android:id="@+id/device_none"
- android:text="None"
- />
- </RadioGroup>
- </HorizontalScrollView>
- <com.example.android.nativemididemo.TouchableScrollView android:id="@+id/messages_scroll"
- android:layout_width="match_parent"
- android:layout_height="0px"
- android:layout_weight="1"
- >
- <TextView android:id="@+id/messages"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textSize="13sp"
- android:typeface="monospace"
- />
- </com.example.android.nativemididemo.TouchableScrollView>
- <LinearLayout
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
- <Button android:id="@+id/clear_messages"
- android:layout_width="0px"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/clear_messages"
- android:onClick="onClearMessages"
- />
- <Button android:id="@+id/close_port"
- android:layout_width="0px"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/close_port"
- android:onClick="onClosePort"
- />
- </LinearLayout>
-</LinearLayout>
diff --git a/media/tests/NativeMidiDemo/res/mipmap-hdpi/ic_launcher.png b/media/tests/NativeMidiDemo/res/mipmap-hdpi/ic_launcher.png
deleted file mode 100644
index cde69bcccec6..000000000000
--- a/media/tests/NativeMidiDemo/res/mipmap-hdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/media/tests/NativeMidiDemo/res/mipmap-mdpi/ic_launcher.png b/media/tests/NativeMidiDemo/res/mipmap-mdpi/ic_launcher.png
deleted file mode 100644
index c133a0cbd379..000000000000
--- a/media/tests/NativeMidiDemo/res/mipmap-mdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/media/tests/NativeMidiDemo/res/mipmap-xhdpi/ic_launcher.png b/media/tests/NativeMidiDemo/res/mipmap-xhdpi/ic_launcher.png
deleted file mode 100644
index bfa42f0e7b91..000000000000
--- a/media/tests/NativeMidiDemo/res/mipmap-xhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/media/tests/NativeMidiDemo/res/mipmap-xxhdpi/ic_launcher.png b/media/tests/NativeMidiDemo/res/mipmap-xxhdpi/ic_launcher.png
deleted file mode 100644
index 324e72cdd748..000000000000
--- a/media/tests/NativeMidiDemo/res/mipmap-xxhdpi/ic_launcher.png
+++ /dev/null
Binary files differ
diff --git a/media/tests/NativeMidiDemo/res/values/strings.xml b/media/tests/NativeMidiDemo/res/values/strings.xml
deleted file mode 100644
index 5b69b52a5836..000000000000
--- a/media/tests/NativeMidiDemo/res/values/strings.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
- <string name="app_name">NativeMidiDemo</string>
- <string name="clear_messages">Clear Messages</string>
- <string name="close_port">Close Port</string>
-</resources>