fix macOS build (following Projucer changes made in Windows, which removed /Applications/JUCE/modules from its headers). move JUCE headers under source control, so that Windows and macOS can both build against same version of JUCE. remove AUv3 target (I think it's an iOS thing, so it will never work with this macOS fluidsynth dylib).
This commit is contained in:
999
modules/juce_core/native/java/AndroidMidi.java
Normal file
999
modules/juce_core/native/java/AndroidMidi.java
Normal file
@ -0,0 +1,999 @@
|
||||
//==============================================================================
|
||||
public class BluetoothManager extends ScanCallback
|
||||
{
|
||||
BluetoothManager()
|
||||
{
|
||||
}
|
||||
|
||||
public String[] getMidiBluetoothAddresses()
|
||||
{
|
||||
return bluetoothMidiDevices.toArray (new String[bluetoothMidiDevices.size()]);
|
||||
}
|
||||
|
||||
public String getHumanReadableStringForBluetoothAddress (String address)
|
||||
{
|
||||
BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice (address);
|
||||
return btDevice.getName();
|
||||
}
|
||||
|
||||
public int getBluetoothDeviceStatus (String address)
|
||||
{
|
||||
return getAndroidMidiDeviceManager().getBluetoothDeviceStatus (address);
|
||||
}
|
||||
|
||||
public void startStopScan (boolean shouldStart)
|
||||
{
|
||||
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
if (bluetoothAdapter == null)
|
||||
{
|
||||
Log.d ("JUCE", "BluetoothManager error: could not get default Bluetooth adapter");
|
||||
return;
|
||||
}
|
||||
|
||||
BluetoothLeScanner bluetoothLeScanner = bluetoothAdapter.getBluetoothLeScanner();
|
||||
|
||||
if (bluetoothLeScanner == null)
|
||||
{
|
||||
Log.d ("JUCE", "BluetoothManager error: could not get Bluetooth LE scanner");
|
||||
return;
|
||||
}
|
||||
|
||||
if (shouldStart)
|
||||
{
|
||||
ScanFilter.Builder scanFilterBuilder = new ScanFilter.Builder();
|
||||
scanFilterBuilder.setServiceUuid (ParcelUuid.fromString (bluetoothLEMidiServiceUUID));
|
||||
|
||||
ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder();
|
||||
scanSettingsBuilder.setCallbackType (ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
|
||||
.setScanMode (ScanSettings.SCAN_MODE_LOW_POWER)
|
||||
.setScanMode (ScanSettings.MATCH_MODE_STICKY);
|
||||
|
||||
bluetoothLeScanner.startScan (Arrays.asList (scanFilterBuilder.build()),
|
||||
scanSettingsBuilder.build(),
|
||||
this);
|
||||
}
|
||||
else
|
||||
{
|
||||
bluetoothLeScanner.stopScan (this);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean pairBluetoothMidiDevice(String address)
|
||||
{
|
||||
BluetoothDevice btDevice = BluetoothAdapter.getDefaultAdapter().getRemoteDevice (address);
|
||||
|
||||
if (btDevice == null)
|
||||
{
|
||||
Log.d ("JUCE", "failed to create buletooth device from address");
|
||||
return false;
|
||||
}
|
||||
|
||||
return getAndroidMidiDeviceManager().pairBluetoothDevice (btDevice);
|
||||
}
|
||||
|
||||
public void unpairBluetoothMidiDevice (String address)
|
||||
{
|
||||
getAndroidMidiDeviceManager().unpairBluetoothDevice (address);
|
||||
}
|
||||
|
||||
public void onScanFailed (int errorCode)
|
||||
{
|
||||
}
|
||||
|
||||
public void onScanResult (int callbackType, ScanResult result)
|
||||
{
|
||||
if (callbackType == ScanSettings.CALLBACK_TYPE_ALL_MATCHES
|
||||
|| callbackType == ScanSettings.CALLBACK_TYPE_FIRST_MATCH)
|
||||
{
|
||||
BluetoothDevice device = result.getDevice();
|
||||
|
||||
if (device != null)
|
||||
bluetoothMidiDevices.add (device.getAddress());
|
||||
}
|
||||
|
||||
if (callbackType == ScanSettings.CALLBACK_TYPE_MATCH_LOST)
|
||||
{
|
||||
Log.d ("JUCE", "ScanSettings.CALLBACK_TYPE_MATCH_LOST");
|
||||
BluetoothDevice device = result.getDevice();
|
||||
|
||||
if (device != null)
|
||||
{
|
||||
bluetoothMidiDevices.remove (device.getAddress());
|
||||
unpairBluetoothMidiDevice (device.getAddress());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onBatchScanResults (List<ScanResult> results)
|
||||
{
|
||||
for (ScanResult result : results)
|
||||
onScanResult (ScanSettings.CALLBACK_TYPE_ALL_MATCHES, result);
|
||||
}
|
||||
|
||||
private BluetoothLeScanner scanner;
|
||||
private static final String bluetoothLEMidiServiceUUID = "03B80E5A-EDE8-4B33-A751-6CE34EC4C700";
|
||||
|
||||
private HashSet<String> bluetoothMidiDevices = new HashSet<String>();
|
||||
}
|
||||
|
||||
public static class JuceMidiInputPort extends MidiReceiver implements JuceMidiPort
|
||||
{
|
||||
private native void handleReceive (long host, byte[] msg, int offset, int count, long timestamp);
|
||||
|
||||
public JuceMidiInputPort (MidiDeviceManager mm, MidiOutputPort actualPort, MidiPortPath portPathToUse, long hostToUse)
|
||||
{
|
||||
owner = mm;
|
||||
androidPort = actualPort;
|
||||
portPath = portPathToUse;
|
||||
juceHost = hostToUse;
|
||||
isConnected = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable
|
||||
{
|
||||
close();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInputPort()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
if (owner != null && androidPort != null && ! isConnected) {
|
||||
androidPort.connect(this);
|
||||
isConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
if (owner != null && androidPort != null && isConnected) {
|
||||
androidPort.disconnect(this);
|
||||
isConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if (androidPort != null) {
|
||||
try {
|
||||
androidPort.close();
|
||||
} catch (IOException exception) {
|
||||
Log.d("JUCE", "IO Exception while closing port");
|
||||
}
|
||||
}
|
||||
|
||||
if (owner != null)
|
||||
owner.removePort (portPath);
|
||||
|
||||
owner = null;
|
||||
androidPort = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSend (byte[] msg, int offset, int count, long timestamp)
|
||||
{
|
||||
if (count > 0)
|
||||
handleReceive (juceHost, msg, offset, count, timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFlush()
|
||||
{}
|
||||
|
||||
@Override
|
||||
public void sendMidi (byte[] msg, int offset, int count)
|
||||
{
|
||||
}
|
||||
|
||||
MidiDeviceManager owner;
|
||||
MidiOutputPort androidPort;
|
||||
MidiPortPath portPath;
|
||||
long juceHost;
|
||||
boolean isConnected;
|
||||
}
|
||||
|
||||
public static class JuceMidiOutputPort implements JuceMidiPort
|
||||
{
|
||||
public JuceMidiOutputPort (MidiDeviceManager mm, MidiInputPort actualPort, MidiPortPath portPathToUse)
|
||||
{
|
||||
owner = mm;
|
||||
androidPort = actualPort;
|
||||
portPath = portPathToUse;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable
|
||||
{
|
||||
close();
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInputPort()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendMidi (byte[] msg, int offset, int count)
|
||||
{
|
||||
if (androidPort != null)
|
||||
{
|
||||
try {
|
||||
androidPort.send(msg, offset, count);
|
||||
} catch (IOException exception)
|
||||
{
|
||||
Log.d ("JUCE", "send midi had IO exception");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
if (androidPort != null) {
|
||||
try {
|
||||
androidPort.close();
|
||||
} catch (IOException exception) {
|
||||
Log.d("JUCE", "IO Exception while closing port");
|
||||
}
|
||||
}
|
||||
|
||||
if (owner != null)
|
||||
owner.removePort (portPath);
|
||||
|
||||
owner = null;
|
||||
androidPort = null;
|
||||
}
|
||||
|
||||
MidiDeviceManager owner;
|
||||
MidiInputPort androidPort;
|
||||
MidiPortPath portPath;
|
||||
}
|
||||
|
||||
private static class MidiPortPath extends Object
|
||||
{
|
||||
public MidiPortPath (int deviceIdToUse, boolean direction, int androidIndex)
|
||||
{
|
||||
deviceId = deviceIdToUse;
|
||||
isInput = direction;
|
||||
portIndex = androidIndex;
|
||||
|
||||
}
|
||||
|
||||
public int deviceId;
|
||||
public int portIndex;
|
||||
public boolean isInput;
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
Integer i = new Integer ((deviceId * 128) + (portIndex < 128 ? portIndex : 127));
|
||||
return i.hashCode() * (isInput ? -1 : 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
|
||||
MidiPortPath other = (MidiPortPath) obj;
|
||||
return (portIndex == other.portIndex && isInput == other.isInput && deviceId == other.deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public class MidiDeviceManager extends MidiManager.DeviceCallback implements MidiManager.OnDeviceOpenedListener
|
||||
{
|
||||
//==============================================================================
|
||||
private class DummyBluetoothGattCallback extends BluetoothGattCallback
|
||||
{
|
||||
public DummyBluetoothGattCallback (MidiDeviceManager mm)
|
||||
{
|
||||
super();
|
||||
owner = mm;
|
||||
}
|
||||
|
||||
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState)
|
||||
{
|
||||
if (newState == BluetoothProfile.STATE_CONNECTED)
|
||||
{
|
||||
gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
|
||||
owner.pairBluetoothDeviceStepTwo (gatt.getDevice());
|
||||
}
|
||||
}
|
||||
public void onServicesDiscovered(BluetoothGatt gatt, int status) {}
|
||||
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {}
|
||||
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {}
|
||||
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {}
|
||||
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {}
|
||||
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {}
|
||||
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {}
|
||||
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {}
|
||||
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {}
|
||||
|
||||
private MidiDeviceManager owner;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
private class MidiDeviceOpenTask extends java.util.TimerTask
|
||||
{
|
||||
public MidiDeviceOpenTask (MidiDeviceManager deviceManager, MidiDevice device, BluetoothGatt gattToUse)
|
||||
{
|
||||
owner = deviceManager;
|
||||
midiDevice = device;
|
||||
btGatt = gattToUse;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean cancel()
|
||||
{
|
||||
synchronized (MidiDeviceOpenTask.class)
|
||||
{
|
||||
owner = null;
|
||||
boolean retval = super.cancel();
|
||||
|
||||
if (btGatt != null)
|
||||
{
|
||||
btGatt.disconnect();
|
||||
btGatt.close();
|
||||
|
||||
btGatt = null;
|
||||
}
|
||||
|
||||
if (midiDevice != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
midiDevice.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{}
|
||||
|
||||
midiDevice = null;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
public String getBluetoothAddress()
|
||||
{
|
||||
synchronized (MidiDeviceOpenTask.class)
|
||||
{
|
||||
if (midiDevice != null)
|
||||
{
|
||||
MidiDeviceInfo info = midiDevice.getInfo();
|
||||
if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH)
|
||||
{
|
||||
BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE);
|
||||
if (btDevice != null)
|
||||
return btDevice.getAddress();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public BluetoothGatt getGatt() { return btGatt; }
|
||||
|
||||
public int getID()
|
||||
{
|
||||
return midiDevice.getInfo().getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
synchronized (MidiDeviceOpenTask.class)
|
||||
{
|
||||
if (owner != null && midiDevice != null)
|
||||
owner.onDeviceOpenedDelayed (midiDevice);
|
||||
}
|
||||
}
|
||||
|
||||
private MidiDeviceManager owner;
|
||||
private MidiDevice midiDevice;
|
||||
private BluetoothGatt btGatt;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
public MidiDeviceManager()
|
||||
{
|
||||
manager = (MidiManager) getSystemService (MIDI_SERVICE);
|
||||
|
||||
if (manager == null)
|
||||
{
|
||||
Log.d ("JUCE", "MidiDeviceManager error: could not get MidiManager system service");
|
||||
return;
|
||||
}
|
||||
|
||||
openPorts = new HashMap<MidiPortPath, WeakReference<JuceMidiPort>> ();
|
||||
midiDevices = new ArrayList<Pair<MidiDevice,BluetoothGatt>>();
|
||||
openTasks = new HashMap<Integer, MidiDeviceOpenTask>();
|
||||
btDevicesPairing = new HashMap<String, BluetoothGatt>();
|
||||
|
||||
MidiDeviceInfo[] foundDevices = manager.getDevices();
|
||||
for (MidiDeviceInfo info : foundDevices)
|
||||
onDeviceAdded (info);
|
||||
|
||||
manager.registerDeviceCallback (this, null);
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable
|
||||
{
|
||||
manager.unregisterDeviceCallback (this);
|
||||
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
btDevicesPairing.clear();
|
||||
|
||||
for (Integer deviceID : openTasks.keySet())
|
||||
openTasks.get (deviceID).cancel();
|
||||
|
||||
openTasks = null;
|
||||
}
|
||||
|
||||
for (MidiPortPath key : openPorts.keySet())
|
||||
openPorts.get (key).get().close();
|
||||
|
||||
openPorts = null;
|
||||
|
||||
for (Pair<MidiDevice, BluetoothGatt> device : midiDevices)
|
||||
{
|
||||
if (device.second != null)
|
||||
{
|
||||
device.second.disconnect();
|
||||
device.second.close();
|
||||
}
|
||||
|
||||
device.first.close();
|
||||
}
|
||||
|
||||
midiDevices.clear();
|
||||
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
public String[] getJuceAndroidMidiInputDevices()
|
||||
{
|
||||
return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_OUTPUT);
|
||||
}
|
||||
|
||||
public String[] getJuceAndroidMidiOutputDevices()
|
||||
{
|
||||
return getJuceAndroidMidiDevices (MidiDeviceInfo.PortInfo.TYPE_INPUT);
|
||||
}
|
||||
|
||||
private String[] getJuceAndroidMidiDevices (int portType)
|
||||
{
|
||||
// only update the list when JUCE asks for a new list
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
deviceInfos = getDeviceInfos();
|
||||
}
|
||||
|
||||
ArrayList<String> portNames = new ArrayList<String>();
|
||||
|
||||
int index = 0;
|
||||
for (MidiPortPath portInfo = getPortPathForJuceIndex (portType, index); portInfo != null; portInfo = getPortPathForJuceIndex (portType, ++index))
|
||||
portNames.add (getPortName (portInfo));
|
||||
|
||||
String[] names = new String[portNames.size()];
|
||||
return portNames.toArray (names);
|
||||
}
|
||||
|
||||
private JuceMidiPort openMidiPortWithJuceIndex (int index, long host, boolean isInput)
|
||||
{
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
int portTypeToFind = (isInput ? MidiDeviceInfo.PortInfo.TYPE_OUTPUT : MidiDeviceInfo.PortInfo.TYPE_INPUT);
|
||||
MidiPortPath portInfo = getPortPathForJuceIndex (portTypeToFind, index);
|
||||
|
||||
if (portInfo != null)
|
||||
{
|
||||
// ports must be opened exclusively!
|
||||
if (openPorts.containsKey (portInfo))
|
||||
return null;
|
||||
|
||||
Pair<MidiDevice,BluetoothGatt> devicePair = getMidiDevicePairForId (portInfo.deviceId);
|
||||
|
||||
if (devicePair != null)
|
||||
{
|
||||
MidiDevice device = devicePair.first;
|
||||
if (device != null)
|
||||
{
|
||||
JuceMidiPort juceMidiPort = null;
|
||||
|
||||
if (isInput)
|
||||
{
|
||||
MidiOutputPort outputPort = device.openOutputPort(portInfo.portIndex);
|
||||
|
||||
if (outputPort != null)
|
||||
juceMidiPort = new JuceMidiInputPort(this, outputPort, portInfo, host);
|
||||
}
|
||||
else
|
||||
{
|
||||
MidiInputPort inputPort = device.openInputPort(portInfo.portIndex);
|
||||
|
||||
if (inputPort != null)
|
||||
juceMidiPort = new JuceMidiOutputPort(this, inputPort, portInfo);
|
||||
}
|
||||
|
||||
if (juceMidiPort != null)
|
||||
{
|
||||
openPorts.put(portInfo, new WeakReference<JuceMidiPort>(juceMidiPort));
|
||||
|
||||
return juceMidiPort;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public JuceMidiPort openMidiInputPortWithJuceIndex (int index, long host)
|
||||
{
|
||||
return openMidiPortWithJuceIndex (index, host, true);
|
||||
}
|
||||
|
||||
public JuceMidiPort openMidiOutputPortWithJuceIndex (int index)
|
||||
{
|
||||
return openMidiPortWithJuceIndex (index, 0, false);
|
||||
}
|
||||
|
||||
/* 0: unpaired, 1: paired, 2: pairing */
|
||||
public int getBluetoothDeviceStatus (String address)
|
||||
{
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
if (! address.isEmpty())
|
||||
{
|
||||
if (findMidiDeviceForBluetoothAddress (address) != null)
|
||||
return 1;
|
||||
|
||||
if (btDevicesPairing.containsKey (address))
|
||||
return 2;
|
||||
|
||||
if (findOpenTaskForBluetoothAddress (address) != null)
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean pairBluetoothDevice (BluetoothDevice btDevice)
|
||||
{
|
||||
String btAddress = btDevice.getAddress();
|
||||
if (btAddress.isEmpty())
|
||||
return false;
|
||||
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
if (getBluetoothDeviceStatus (btAddress) != 0)
|
||||
return false;
|
||||
|
||||
|
||||
btDevicesPairing.put (btDevice.getAddress(), null);
|
||||
BluetoothGatt gatt = btDevice.connectGatt (getApplicationContext(), true, new DummyBluetoothGattCallback (this));
|
||||
|
||||
if (gatt != null)
|
||||
{
|
||||
btDevicesPairing.put (btDevice.getAddress(), gatt);
|
||||
}
|
||||
else
|
||||
{
|
||||
pairBluetoothDeviceStepTwo (btDevice);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void pairBluetoothDeviceStepTwo (BluetoothDevice btDevice)
|
||||
{
|
||||
manager.openBluetoothDevice(btDevice, this, null);
|
||||
}
|
||||
|
||||
public void unpairBluetoothDevice (String address)
|
||||
{
|
||||
if (address.isEmpty())
|
||||
return;
|
||||
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
if (btDevicesPairing.containsKey (address))
|
||||
{
|
||||
BluetoothGatt gatt = btDevicesPairing.get (address);
|
||||
if (gatt != null)
|
||||
{
|
||||
gatt.disconnect();
|
||||
gatt.close();
|
||||
}
|
||||
|
||||
btDevicesPairing.remove (address);
|
||||
}
|
||||
|
||||
MidiDeviceOpenTask openTask = findOpenTaskForBluetoothAddress (address);
|
||||
if (openTask != null)
|
||||
{
|
||||
int deviceID = openTask.getID();
|
||||
openTask.cancel();
|
||||
openTasks.remove (deviceID);
|
||||
}
|
||||
|
||||
Pair<MidiDevice, BluetoothGatt> midiDevicePair = findMidiDeviceForBluetoothAddress (address);
|
||||
if (midiDevicePair != null)
|
||||
{
|
||||
MidiDevice midiDevice = midiDevicePair.first;
|
||||
onDeviceRemoved (midiDevice.getInfo());
|
||||
|
||||
try {
|
||||
midiDevice.close();
|
||||
}
|
||||
catch (IOException exception)
|
||||
{
|
||||
Log.d ("JUCE", "IOException while closing midi device");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<MidiDevice, BluetoothGatt> findMidiDeviceForBluetoothAddress (String address)
|
||||
{
|
||||
for (Pair<MidiDevice,BluetoothGatt> midiDevice : midiDevices)
|
||||
{
|
||||
MidiDeviceInfo info = midiDevice.first.getInfo();
|
||||
if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH)
|
||||
{
|
||||
BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE);
|
||||
if (btDevice != null && btDevice.getAddress().equals (address))
|
||||
return midiDevice;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private MidiDeviceOpenTask findOpenTaskForBluetoothAddress (String address)
|
||||
{
|
||||
for (Integer deviceID : openTasks.keySet())
|
||||
{
|
||||
MidiDeviceOpenTask openTask = openTasks.get (deviceID);
|
||||
if (openTask.getBluetoothAddress().equals (address))
|
||||
return openTask;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void removePort (MidiPortPath path)
|
||||
{
|
||||
openPorts.remove (path);
|
||||
}
|
||||
|
||||
public String getInputPortNameForJuceIndex (int index)
|
||||
{
|
||||
MidiPortPath portInfo = getPortPathForJuceIndex (MidiDeviceInfo.PortInfo.TYPE_OUTPUT, index);
|
||||
if (portInfo != null)
|
||||
return getPortName (portInfo);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public String getOutputPortNameForJuceIndex (int index)
|
||||
{
|
||||
MidiPortPath portInfo = getPortPathForJuceIndex (MidiDeviceInfo.PortInfo.TYPE_INPUT, index);
|
||||
if (portInfo != null)
|
||||
return getPortName (portInfo);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public void onDeviceAdded (MidiDeviceInfo info)
|
||||
{
|
||||
// only add standard midi devices
|
||||
if (info.getType() == info.TYPE_BLUETOOTH)
|
||||
return;
|
||||
|
||||
manager.openDevice (info, this, null);
|
||||
}
|
||||
|
||||
public void onDeviceRemoved (MidiDeviceInfo info)
|
||||
{
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
Pair<MidiDevice, BluetoothGatt> devicePair = getMidiDevicePairForId (info.getId());
|
||||
|
||||
if (devicePair != null)
|
||||
{
|
||||
MidiDevice midiDevice = devicePair.first;
|
||||
BluetoothGatt gatt = devicePair.second;
|
||||
|
||||
// close all ports that use this device
|
||||
boolean removedPort = true;
|
||||
|
||||
while (removedPort == true)
|
||||
{
|
||||
removedPort = false;
|
||||
for (MidiPortPath key : openPorts.keySet())
|
||||
{
|
||||
if (key.deviceId == info.getId())
|
||||
{
|
||||
openPorts.get(key).get().close();
|
||||
removedPort = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gatt != null)
|
||||
{
|
||||
gatt.disconnect();
|
||||
gatt.close();
|
||||
}
|
||||
|
||||
midiDevices.remove (devicePair);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeviceStatusChanged (MidiDeviceStatus status)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeviceOpened (MidiDevice theDevice)
|
||||
{
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
MidiDeviceInfo info = theDevice.getInfo();
|
||||
int deviceID = info.getId();
|
||||
BluetoothGatt gatt = null;
|
||||
boolean isBluetooth = false;
|
||||
|
||||
if (! openTasks.containsKey (deviceID))
|
||||
{
|
||||
if (info.getType() == MidiDeviceInfo.TYPE_BLUETOOTH)
|
||||
{
|
||||
isBluetooth = true;
|
||||
BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE);
|
||||
if (btDevice != null)
|
||||
{
|
||||
String btAddress = btDevice.getAddress();
|
||||
if (btDevicesPairing.containsKey (btAddress))
|
||||
{
|
||||
gatt = btDevicesPairing.get (btAddress);
|
||||
btDevicesPairing.remove (btAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unpair was called in the mean time
|
||||
try
|
||||
{
|
||||
Pair<MidiDevice, BluetoothGatt> midiDevicePair = findMidiDeviceForBluetoothAddress (btDevice.getAddress());
|
||||
if (midiDevicePair != null)
|
||||
{
|
||||
gatt = midiDevicePair.second;
|
||||
|
||||
if (gatt != null)
|
||||
{
|
||||
gatt.disconnect();
|
||||
gatt.close();
|
||||
}
|
||||
}
|
||||
|
||||
theDevice.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MidiDeviceOpenTask openTask = new MidiDeviceOpenTask (this, theDevice, gatt);
|
||||
openTasks.put (deviceID, openTask);
|
||||
|
||||
new java.util.Timer().schedule (openTask, (isBluetooth ? 2000 : 100));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onDeviceOpenedDelayed (MidiDevice theDevice)
|
||||
{
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
int deviceID = theDevice.getInfo().getId();
|
||||
|
||||
if (openTasks.containsKey (deviceID))
|
||||
{
|
||||
if (! midiDevices.contains(theDevice))
|
||||
{
|
||||
BluetoothGatt gatt = openTasks.get (deviceID).getGatt();
|
||||
openTasks.remove (deviceID);
|
||||
midiDevices.add (new Pair<MidiDevice,BluetoothGatt> (theDevice, gatt));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// unpair was called in the mean time
|
||||
MidiDeviceInfo info = theDevice.getInfo();
|
||||
BluetoothDevice btDevice = (BluetoothDevice) info.getProperties().get (info.PROPERTY_BLUETOOTH_DEVICE);
|
||||
if (btDevice != null)
|
||||
{
|
||||
String btAddress = btDevice.getAddress();
|
||||
Pair<MidiDevice, BluetoothGatt> midiDevicePair = findMidiDeviceForBluetoothAddress (btDevice.getAddress());
|
||||
if (midiDevicePair != null)
|
||||
{
|
||||
BluetoothGatt gatt = midiDevicePair.second;
|
||||
|
||||
if (gatt != null)
|
||||
{
|
||||
gatt.disconnect();
|
||||
gatt.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
theDevice.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String getPortName(MidiPortPath path)
|
||||
{
|
||||
int portTypeToFind = (path.isInput ? MidiDeviceInfo.PortInfo.TYPE_INPUT : MidiDeviceInfo.PortInfo.TYPE_OUTPUT);
|
||||
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
for (MidiDeviceInfo info : deviceInfos)
|
||||
{
|
||||
int localIndex = 0;
|
||||
if (info.getId() == path.deviceId)
|
||||
{
|
||||
for (MidiDeviceInfo.PortInfo portInfo : info.getPorts())
|
||||
{
|
||||
int portType = portInfo.getType();
|
||||
if (portType == portTypeToFind)
|
||||
{
|
||||
int portIndex = portInfo.getPortNumber();
|
||||
if (portIndex == path.portIndex)
|
||||
{
|
||||
String portName = portInfo.getName();
|
||||
if (portName.isEmpty())
|
||||
portName = (String) info.getProperties().get(info.PROPERTY_NAME);
|
||||
|
||||
return portName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public MidiPortPath getPortPathForJuceIndex (int portType, int juceIndex)
|
||||
{
|
||||
int portIdx = 0;
|
||||
for (MidiDeviceInfo info : deviceInfos)
|
||||
{
|
||||
for (MidiDeviceInfo.PortInfo portInfo : info.getPorts())
|
||||
{
|
||||
if (portInfo.getType() == portType)
|
||||
{
|
||||
if (portIdx == juceIndex)
|
||||
return new MidiPortPath (info.getId(),
|
||||
(portType == MidiDeviceInfo.PortInfo.TYPE_INPUT),
|
||||
portInfo.getPortNumber());
|
||||
|
||||
portIdx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private MidiDeviceInfo[] getDeviceInfos()
|
||||
{
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
MidiDeviceInfo[] infos = new MidiDeviceInfo[midiDevices.size()];
|
||||
|
||||
int idx = 0;
|
||||
for (Pair<MidiDevice,BluetoothGatt> midiDevice : midiDevices)
|
||||
infos[idx++] = midiDevice.first.getInfo();
|
||||
|
||||
return infos;
|
||||
}
|
||||
}
|
||||
|
||||
private Pair<MidiDevice, BluetoothGatt> getMidiDevicePairForId (int deviceId)
|
||||
{
|
||||
synchronized (MidiDeviceManager.class)
|
||||
{
|
||||
for (Pair<MidiDevice,BluetoothGatt> midiDevice : midiDevices)
|
||||
if (midiDevice.first.getInfo().getId() == deviceId)
|
||||
return midiDevice;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private MidiManager manager;
|
||||
private HashMap<String, BluetoothGatt> btDevicesPairing;
|
||||
private HashMap<Integer, MidiDeviceOpenTask> openTasks;
|
||||
private ArrayList<Pair<MidiDevice, BluetoothGatt>> midiDevices;
|
||||
private MidiDeviceInfo[] deviceInfos;
|
||||
private HashMap<MidiPortPath, WeakReference<JuceMidiPort>> openPorts;
|
||||
}
|
||||
|
||||
public MidiDeviceManager getAndroidMidiDeviceManager()
|
||||
{
|
||||
if (getSystemService (MIDI_SERVICE) == null)
|
||||
return null;
|
||||
|
||||
synchronized (JuceAppActivity.class)
|
||||
{
|
||||
if (midiDeviceManager == null)
|
||||
midiDeviceManager = new MidiDeviceManager();
|
||||
}
|
||||
|
||||
return midiDeviceManager;
|
||||
}
|
||||
|
||||
public BluetoothManager getAndroidBluetoothManager()
|
||||
{
|
||||
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
|
||||
|
||||
if (adapter == null)
|
||||
return null;
|
||||
|
||||
if (adapter.getBluetoothLeScanner() == null)
|
||||
return null;
|
||||
|
||||
synchronized (JuceAppActivity.class)
|
||||
{
|
||||
if (bluetoothManager == null)
|
||||
bluetoothManager = new BluetoothManager();
|
||||
}
|
||||
|
||||
return bluetoothManager;
|
||||
}
|
Reference in New Issue
Block a user