MidiDevice.java revision 9db9326ad47279709a0f7989addaf4b45221b6b9
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package android.media.midi; 18 19import android.content.Context; 20import android.content.ServiceConnection; 21import android.os.Binder; 22import android.os.IBinder; 23import android.os.ParcelFileDescriptor; 24import android.os.RemoteException; 25import android.util.Log; 26 27import dalvik.system.CloseGuard; 28 29import libcore.io.IoUtils; 30 31import java.io.Closeable; 32import java.io.IOException; 33 34/** 35 * This class is used for sending and receiving data to and from a MIDI device 36 * Instances of this class are created by {@link MidiManager#openDevice}. 37 */ 38public final class MidiDevice implements Closeable { 39 private static final String TAG = "MidiDevice"; 40 41 private final MidiDeviceInfo mDeviceInfo; 42 private final IMidiDeviceServer mDeviceServer; 43 private Context mContext; 44 private ServiceConnection mServiceConnection; 45 46 47 private final CloseGuard mGuard = CloseGuard.get(); 48 49 /** 50 * This class represents a connection between the output port of one device 51 * and the input port of another. Created by {@link #connectPorts}. 52 * Close this object to terminate the connection. 53 */ 54 public class MidiConnection implements Closeable { 55 private final IBinder mToken; 56 private final MidiInputPort mInputPort; 57 58 MidiConnection(IBinder token, MidiInputPort inputPort) { 59 mToken = token; 60 mInputPort = inputPort; 61 } 62 63 @Override 64 public void close() throws IOException { 65 try { 66 mDeviceServer.closePort(mToken); 67 IoUtils.closeQuietly(mInputPort); 68 } catch (RemoteException e) { 69 Log.e(TAG, "RemoteException in MidiConnection.close"); 70 } 71 } 72 } 73 74 /* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server) { 75 this(deviceInfo, server, null, null); 76 } 77 78 /* package */ MidiDevice(MidiDeviceInfo deviceInfo, IMidiDeviceServer server, 79 Context context, ServiceConnection serviceConnection) { 80 mDeviceInfo = deviceInfo; 81 mDeviceServer = server; 82 mContext = context; 83 mServiceConnection = serviceConnection; 84 mGuard.open("close"); 85 } 86 87 /** 88 * Returns a {@link MidiDeviceInfo} object, which describes this device. 89 * 90 * @return the {@link MidiDeviceInfo} object 91 */ 92 public MidiDeviceInfo getInfo() { 93 return mDeviceInfo; 94 } 95 96 /** 97 * Called to open a {@link MidiInputPort} for the specified port number. 98 * 99 * @param portNumber the number of the input port to open 100 * @return the {@link MidiInputPort} 101 */ 102 public MidiInputPort openInputPort(int portNumber) { 103 try { 104 IBinder token = new Binder(); 105 ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber); 106 if (pfd == null) { 107 return null; 108 } 109 return new MidiInputPort(mDeviceServer, token, pfd, portNumber); 110 } catch (RemoteException e) { 111 Log.e(TAG, "RemoteException in openInputPort"); 112 return null; 113 } 114 } 115 116 /** 117 * Called to open a {@link MidiOutputPort} for the specified port number. 118 * 119 * @param portNumber the number of the output port to open 120 * @return the {@link MidiOutputPort} 121 */ 122 public MidiOutputPort openOutputPort(int portNumber) { 123 try { 124 IBinder token = new Binder(); 125 ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber); 126 if (pfd == null) { 127 return null; 128 } 129 return new MidiOutputPort(mDeviceServer, token, pfd, portNumber); 130 } catch (RemoteException e) { 131 Log.e(TAG, "RemoteException in openOutputPort"); 132 return null; 133 } 134 } 135 136 /** 137 * Connects the supplied {@link MidiInputPort} to the output port of this device 138 * with the specified port number. Once the connection is made, the MidiInput port instance 139 * can no longer receive data via its {@link MidiReceiver#onReceive} method. 140 * This method returns a {@link MidiDevice.MidiConnection} object, which can be used to close the connection 141 * @param inputPort the inputPort to connect 142 * @param outputPortNumber the port number of the output port to connect inputPort to. 143 * @return {@link MidiDevice.MidiConnection} object if the connection is successful, or null in case of failure 144 */ 145 public MidiConnection connectPorts(MidiInputPort inputPort, int outputPortNumber) { 146 if (outputPortNumber < 0 || outputPortNumber >= mDeviceInfo.getOutputPortCount()) { 147 throw new IllegalArgumentException("outputPortNumber out of range"); 148 } 149 150 ParcelFileDescriptor pfd = inputPort.claimFileDescriptor(); 151 if (pfd == null) { 152 return null; 153 } 154 try { 155 IBinder token = new Binder(); 156 mDeviceServer.connectPorts(token, pfd, outputPortNumber); 157 // close our copy of the file descriptor 158 IoUtils.closeQuietly(pfd); 159 return new MidiConnection(token, inputPort); 160 } catch (RemoteException e) { 161 Log.e(TAG, "RemoteException in connectPorts"); 162 return null; 163 } 164 } 165 166 @Override 167 public void close() throws IOException { 168 synchronized (mGuard) { 169 mGuard.close(); 170 if (mContext != null && mServiceConnection != null) { 171 mContext.unbindService(mServiceConnection); 172 mContext = null; 173 mServiceConnection = null; 174 } 175 } 176 } 177 178 @Override 179 protected void finalize() throws Throwable { 180 try { 181 mGuard.warnIfOpen(); 182 close(); 183 } finally { 184 super.finalize(); 185 } 186 } 187 188 @Override 189 public String toString() { 190 return ("MidiDevice: " + mDeviceInfo.toString()); 191 } 192} 193