1b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood/* 2b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * Copyright (C) 2014 The Android Open Source Project 3b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * 4b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * Licensed under the Apache License, Version 2.0 (the "License"); 5b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * you may not use this file except in compliance with the License. 6b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * You may obtain a copy of the License at 7b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * 8b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * http://www.apache.org/licenses/LICENSE-2.0 9b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * 10b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * Unless required by applicable law or agreed to in writing, software 11b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * distributed under the License is distributed on an "AS IS" BASIS, 12b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * See the License for the specific language governing permissions and 14b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * limitations under the License. 15b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood */ 16b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood 17b673770f7172d4fca9bc05de1f36bc53e93eb247Mike Lockwoodpackage android.media.midi; 18b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood 194a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwoodimport android.os.IBinder; 204a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwoodimport android.os.RemoteException; 214a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwoodimport android.util.Log; 224a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood 234a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwoodimport dalvik.system.CloseGuard; 2410024b3dc12a8552c1547b67810c77b865045cc8Mike Lockwood 2510024b3dc12a8552c1547b67810c77b865045cc8Mike Lockwoodimport libcore.io.IoUtils; 2610024b3dc12a8552c1547b67810c77b865045cc8Mike Lockwood 2720821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwoodimport java.io.Closeable; 2817bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganovimport java.io.FileDescriptor; 29b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwoodimport java.io.FileOutputStream; 30b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwoodimport java.io.IOException; 31b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood 32b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood/** 33b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood * This class is used for sending data to a port on a MIDI device 34b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood */ 35be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwoodpublic final class MidiInputPort extends MidiReceiver implements Closeable { 364a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood private static final String TAG = "MidiInputPort"; 37b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood 38be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood private IMidiDeviceServer mDeviceServer; 394a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood private final IBinder mToken; 4020821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood private final int mPortNumber; 4117bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov private FileDescriptor mFileDescriptor; 4246326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood private FileOutputStream mOutputStream; 4310024b3dc12a8552c1547b67810c77b865045cc8Mike Lockwood 444a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood private final CloseGuard mGuard = CloseGuard.get(); 45be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood private boolean mIsClosed; 464a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood 473b7664589be22ddad34b72e11ced937d48660ebbMike Lockwood // buffer to use for sending data out our output stream 4820821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood private final byte[] mBuffer = new byte[MidiPortImpl.MAX_PACKET_SIZE]; 49b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood 504a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood /* package */ MidiInputPort(IMidiDeviceServer server, IBinder token, 5117bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov FileDescriptor fd, int portNumber) { 527eb441cb4abcd3230a4d243469c5044f49e707c8Mike Lockwood super(MidiPortImpl.MAX_PACKET_DATA_SIZE); 537eb441cb4abcd3230a4d243469c5044f49e707c8Mike Lockwood 544a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood mDeviceServer = server; 554a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood mToken = token; 5617bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov mFileDescriptor = fd; 5720821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood mPortNumber = portNumber; 5817bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov mOutputStream = new FileOutputStream(fd); 594a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood mGuard.open("close"); 604a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood } 614a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood 6217bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov /* package */ MidiInputPort(FileDescriptor fd, int portNumber) { 6317bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov this(null, null, fd, portNumber); 64b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood } 65b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood 66b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood /** 6720821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood * Returns the port number of this port 6820821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood * 6920821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood * @return the port's port number 7020821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood */ 7120821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood public final int getPortNumber() { 7220821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood return mPortNumber; 7320821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood } 7420821ecbe81ba52b260ae232096bc2bfb3e92ad0Mike Lockwood 7581b9f7d325a552c54e793b51f571ae3d65b26e94Mike Lockwood @Override 767eb441cb4abcd3230a4d243469c5044f49e707c8Mike Lockwood public void onSend(byte[] msg, int offset, int count, long timestamp) throws IOException { 770c7342f0153076c88ba8e6a1647999c248787906Mike Lockwood if (offset < 0 || count < 0 || offset + count > msg.length) { 780c7342f0153076c88ba8e6a1647999c248787906Mike Lockwood throw new IllegalArgumentException("offset or count out of range"); 790c7342f0153076c88ba8e6a1647999c248787906Mike Lockwood } 800c7342f0153076c88ba8e6a1647999c248787906Mike Lockwood if (count > MidiPortImpl.MAX_PACKET_DATA_SIZE) { 810c7342f0153076c88ba8e6a1647999c248787906Mike Lockwood throw new IllegalArgumentException("count exceeds max message size"); 820c7342f0153076c88ba8e6a1647999c248787906Mike Lockwood } 83cb096273734d96f4676014fa9030b57ea48b58d8Mike Lockwood 84b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood synchronized (mBuffer) { 8546326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood if (mOutputStream == null) { 8646326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood throw new IOException("MidiInputPort is closed"); 8746326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood } 88b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood int length = MidiPortImpl.packData(msg, offset, count, timestamp, mBuffer); 89b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood mOutputStream.write(mBuffer, 0, length); 90b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood } 91b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood } 92b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood 93b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood @Override 947eb441cb4abcd3230a4d243469c5044f49e707c8Mike Lockwood public void onFlush() throws IOException { 95b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood synchronized (mBuffer) { 96b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood if (mOutputStream == null) { 97b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood throw new IOException("MidiInputPort is closed"); 98b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood } 99b6f50d357bd3d4d296be6bb047f5ce93a79cbca1Mike Lockwood int length = MidiPortImpl.packFlush(mBuffer); 1000c7342f0153076c88ba8e6a1647999c248787906Mike Lockwood mOutputStream.write(mBuffer, 0, length); 101b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood } 102b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood } 10310024b3dc12a8552c1547b67810c77b865045cc8Mike Lockwood 10446326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood // used by MidiDevice.connectInputPort() to connect our socket directly to another device 10517bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov /* package */ FileDescriptor claimFileDescriptor() { 1062aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood synchronized (mGuard) { 10717bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov FileDescriptor fd; 1082aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood synchronized (mBuffer) { 10917bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov fd = mFileDescriptor; 11017bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov if (fd == null) return null; 11146326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood IoUtils.closeQuietly(mOutputStream); 11217bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov mFileDescriptor = null; 11346326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood mOutputStream = null; 11446326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood } 1152aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood 1162aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood // Set mIsClosed = true so we will not call mDeviceServer.closePort() in close(). 1172aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood // MidiDevice.MidiConnection.close() will do the cleanup instead. 1182aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood mIsClosed = true; 11917bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov return fd; 12046326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood } 12146326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood } 12246326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood 1232aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood // used by MidiDevice.MidiConnection to close this port after the connection is closed 1242aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood /* package */ IBinder getToken() { 1252aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood return mToken; 1262aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood } 1272aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood 1282aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood // used by MidiDevice.MidiConnection to close this port after the connection is closed 1292aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood /* package */ IMidiDeviceServer getDeviceServer() { 1302aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood return mDeviceServer; 1312aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood } 1322aef7e3559e9e2c78287a00b3f693b6dc19e56f0Mike Lockwood 13310024b3dc12a8552c1547b67810c77b865045cc8Mike Lockwood @Override 13410024b3dc12a8552c1547b67810c77b865045cc8Mike Lockwood public void close() throws IOException { 135be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood synchronized (mGuard) { 136be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood if (mIsClosed) return; 137be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood mGuard.close(); 13846326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood synchronized (mBuffer) { 13917bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov if (mFileDescriptor != null) { 14017bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov IoUtils.closeQuietly(mFileDescriptor); 14117bbb50edc8ccc56c4ecc932a19884c4cc1f5b6fMikhail Naganov mFileDescriptor = null; 14246326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood } 14346326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood if (mOutputStream != null) { 14446326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood mOutputStream.close(); 14546326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood mOutputStream = null; 14646326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood } 14746326e59a0a19367d4158c027d56d4b8440e8d3dMike Lockwood } 148be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood if (mDeviceServer != null) { 149be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood try { 150be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood mDeviceServer.closePort(mToken); 151be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood } catch (RemoteException e) { 152be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood Log.e(TAG, "RemoteException in MidiInputPort.close()"); 153be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood } 1544a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood } 155be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood mIsClosed = true; 1564a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood } 1574a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood } 1584a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood 1594a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood @Override 1604a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood protected void finalize() throws Throwable { 1614a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood try { 162be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood mGuard.warnIfOpen(); 163be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood // not safe to make binder calls from finalize() 164be215dd57282888b05b234c39bba44cc0a864b8aMike Lockwood mDeviceServer = null; 1654a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood close(); 1664a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood } finally { 1674a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood super.finalize(); 1684a3d7ed45d98ad2fe900221755845b87f26b554aMike Lockwood } 16910024b3dc12a8552c1547b67810c77b865045cc8Mike Lockwood } 170b6b9a91c02b7a44cf56943e5358cee68fa4aece5Mike Lockwood} 171