Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a3e33b3 authored by Paul McLean's avatar Paul McLean
Browse files

(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
parent cbeeed12
Loading
Loading
Loading
Loading
+11 −61
Original line number Diff line number Diff line
@@ -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);
}
+1 −1
Original line number Diff line number Diff line
@@ -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;
+0 −2
Original line number Diff line number Diff line
@@ -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",
+0 −50
Original line number Diff line number Diff line
/*
 * 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;
}
+25 −4
Original line number Diff line number Diff line
@@ -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",
}
Loading