content: /*
   * Copyright (C) 2015 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.common.midi;
  
  import android.media.midi.MidiDevice;
  import android.media.midi.MidiDevice.MidiConnection;
  import android.media.midi.MidiDeviceInfo;
  import android.media.midi.MidiInputPort;
  import android.media.midi.MidiManager;
  import android.os.Handler;
  import android.util.Log;
  
  import java.io.IOException;
  
  /**
   * Tool for connecting MIDI ports on two remote devices.
   */
  public class MidiPortConnector {
      private final MidiManager mMidiManager;
      private MidiDevice mSourceDevice;
      private MidiDevice mDestinationDevice;
      private MidiConnection mConnection;
  
      /**
       * @param mMidiManager
       */
      public MidiPortConnector(MidiManager midiManager) {
          mMidiManager = midiManager;
      }
  
      public void close() throws IOException {
          if (mConnection != null) {
              Log.i(MidiConstants.TAG,
                      "MidiPortConnector closing connection " + mConnection);
              mConnection.close();
              mConnection = null;
          }
          if (mSourceDevice != null) {
              mSourceDevice.close();
              mSourceDevice = null;
          }
          if (mDestinationDevice != null) {
              mDestinationDevice.close();
              mDestinationDevice = null;
          }
      }
  
      private void safeClose() {
          try {
              close();
          } catch (IOException e) {
              Log.e(MidiConstants.TAG, "could not close resources", e);
          }
      }
  
      /**
       * Listener class used for receiving the results of
       * {@link #connectToDevicePort}
       */
      public interface OnPortsConnectedListener {
          /**
           * Called to respond to a {@link #connectToDevicePort} request
           *
           * @param connection
           *            a {@link MidiConnection} that represents the connected
           *            ports, or null if connection failed
           */
          abstract public void onPortsConnected(MidiConnection connection);
      }
  
      /**
       * Open two devices and connect their ports.
       *
       * @param sourceDeviceInfo
       * @param sourcePortIndex
       * @param destinationDeviceInfo
       * @param destinationPortIndex
       */
      public void connectToDevicePort(final MidiDeviceInfo sourceDeviceInfo,
              final int sourcePortIndex,
              final MidiDeviceInfo destinationDeviceInfo,
              final int destinationPortIndex) {
          connectToDevicePort(sourceDeviceInfo, sourcePortIndex,
                  destinationDeviceInfo, destinationPortIndex, null, null);
      }
  
      /**
       * Open two devices and connect their ports.
       *
       * @param sourceDeviceInfo
       * @param sourcePortIndex
       * @param destinationDeviceInfo
       * @param destinationPortIndex
       */
      public void connectToDevicePort(final MidiDeviceInfo sourceDeviceInfo,
              final int sourcePortIndex,
              final MidiDeviceInfo destinationDeviceInfo,
              final int destinationPortIndex,
              final OnPortsConnectedListener listener, final Handler handler) {
          safeClose();
          mMidiManager.openDevice(destinationDeviceInfo,
                  new MidiManager.OnDeviceOpenedListener() {
                      @Override
                      public void onDeviceOpened(MidiDevice destinationDevice) {
                          if (destinationDevice == null) {
                              Log.e(MidiConstants.TAG,
                                      "could not open " + destinationDeviceInfo);
                              if (listener != null) {
                                  listener.onPortsConnected(null);
                              }
                          } else {
                              mDestinationDevice = destinationDevice;
                              Log.i(MidiConstants.TAG,
                                      "connectToDevicePort opened "
                                              + destinationDeviceInfo);
                              // Destination device was opened so go to next step.
                              MidiInputPort destinationInputPort = destinationDevice
                                      .openInputPort(destinationPortIndex);
                              if (destinationInputPort != null) {
                                  Log.i(MidiConstants.TAG,
                                          "connectToDevicePort opened port on "
                                                  + destinationDeviceInfo);
                                  connectToDevicePort(sourceDeviceInfo,
                                          sourcePortIndex,
                                          destinationInputPort,
                                          listener, handler);
                              } else {
                                  Log.e(MidiConstants.TAG,
                                          "could not open port on "
                                                  + destinationDeviceInfo);
                                  safeClose();
                                  if (listener != null) {
                                      listener.onPortsConnected(null);
                                  }
                              }
                          }
                      }
                  }, handler);
      }
  
  
      /**
       * Open a source device and connect its output port to the
       * destinationInputPort.
       *
       * @param sourceDeviceInfo
       * @param sourcePortIndex
       * @param destinationInputPort
       */
      private void connectToDevicePort(final MidiDeviceInfo sourceDeviceInfo,
              final int sourcePortIndex,
              final MidiInputPort destinationInputPort,
              final OnPortsConnectedListener listener, final Handler handler) {
          mMidiManager.openDevice(sourceDeviceInfo,
                  new MidiManager.OnDeviceOpenedListener() {
                      @Override
                      public void onDeviceOpened(MidiDevice device) {
                          if (device == null) {
                              Log.e(MidiConstants.TAG,
                                      "could not open " + sourceDeviceInfo);
                              safeClose();
                              if (listener != null) {
                                  listener.onPortsConnected(null);
                              }
                          } else {
                              Log.i(MidiConstants.TAG,
                                      "connectToDevicePort opened "
                                              + sourceDeviceInfo);
                              // Device was opened so connect the ports.
                              mSourceDevice = device;
                              mConnection = device.connectPorts(
                                      destinationInputPort, sourcePortIndex);
                              if (mConnection == null) {
                                  Log.e(MidiConstants.TAG, "could not connect to "
                                          + sourceDeviceInfo);
                                  safeClose();
                              }
                              if (listener != null) {
                                  listener.onPortsConnected(mConnection);
                              }
                          }
                      }
                  }, handler);
      }
  
  }
  