1 /*
2  * Copyright (C) 2021 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 
17 package com.android.cts.verifier.audio.midilib;
18 
19 import android.media.midi.MidiDevice;
20 import android.media.midi.MidiDeviceInfo;
21 import android.media.midi.MidiInputPort;
22 import android.media.midi.MidiOutputPort;
23 import android.media.midi.MidiReceiver;
24 import android.os.Bundle;
25 import android.util.Log;
26 
27 import java.io.IOException;
28 import java.util.Collection;
29 
30 /**
31  * A class to hold the MidiIODevice and ports objects associated with a MIDI I/O peripheral.
32  */
33 public class MidiIODevice {
34     private static final String TAG = "MidiIODevice";
35     private static final boolean DEBUG = false;
36 
37     private final int mDeviceType;
38 
39     public MidiDeviceInfo mSendDevInfo;
40     public MidiDeviceInfo mReceiveDevInfo;
41 
42     public MidiDevice      mMidiDevice;
43     public MidiInputPort   mSendPort;
44     public MidiOutputPort  mReceivePort;
45 
MidiIODevice(int deviceType)46     public MidiIODevice(int deviceType) {
47         mDeviceType = deviceType;
48     }
49 
50     /**
51      * Sets MidiDevice and info about sender and receiver ports from a collection of
52      * MidiDeviceInfo. It uses mDeviceType to match the device.
53      *
54      * @param devInfos the set of devices to check
55      */
scanDevices(Collection<MidiDeviceInfo> devInfos)56     public void scanDevices(Collection<MidiDeviceInfo> devInfos) {
57         if (DEBUG) {
58             Log.i(TAG, "---- scanDevices() typeID: " + mDeviceType);
59         }
60         mSendDevInfo = null;
61         mReceiveDevInfo = null;
62         mSendPort = null;
63         mReceivePort = null;
64         mMidiDevice = null;
65 
66         for(MidiDeviceInfo devInfo : devInfos) {
67             Bundle devBundle = devInfo.getProperties();
68             if (DEBUG) {
69                 Log.i(TAG, "  mfg:" + devBundle.getString(MidiDeviceInfo.PROPERTY_MANUFACTURER)
70                         + " prod:" + devBundle.getString(MidiDeviceInfo.PROPERTY_PRODUCT));
71             }
72 
73             // Inputs?
74             int numInPorts = devInfo.getInputPortCount();
75             if (numInPorts <= 0) {
76                 continue; // none?
77             }
78 
79             // For virtual MIDI devices, we need to find
80             // manufacturer=AndroidCTSVerifier and product=VerifierMidiEcho or else
81             // it might be some other MIDI app providing virtual MIDI services
82             if (mDeviceType == MidiDeviceInfo.TYPE_VIRTUAL) {
83                 if (!"AndroidCTSVerifier".equals(
84                         devBundle.getString(MidiDeviceInfo.PROPERTY_MANUFACTURER))
85                         || !"VerifierMidiEcho".equals(
86                                 devBundle.getString(MidiDeviceInfo.PROPERTY_PRODUCT))) {
87                     // Virtual [but not ours]
88                     Log.d(TAG, "Virtual Midi Device:" + devInfo);
89                     continue;
90                 }
91             }
92 
93             if (devInfo.getType() == mDeviceType && mSendDevInfo == null) {
94                 mSendDevInfo = devInfo;
95             }
96 
97             // Outputs?
98             int numOutPorts = devInfo.getOutputPortCount();
99             if (numOutPorts <= 0) {
100                 continue; // none?
101             }
102             if (devInfo.getType() == mDeviceType && mReceiveDevInfo == null) {
103                 mReceiveDevInfo = devInfo;
104             }
105 
106             if (mSendDevInfo != null && mReceiveDevInfo != null) {
107                 break;  // we have an in and out device, so we can stop scanning
108             }
109         }
110 
111         if (DEBUG) {
112             Log.i(TAG, "---- mSendDevInfo: "
113                     + (mSendDevInfo != null ? mSendDevInfo.toString() : "NONE"));
114             Log.i(TAG, "---- mReceiveDevInfo: "
115                     + (mReceiveDevInfo != null ? mReceiveDevInfo.toString() : "NONE"));
116         }
117     }
118 
openPorts(MidiDevice device, MidiReceiver receiver)119     public void openPorts(MidiDevice device, MidiReceiver receiver) {
120         if (DEBUG) {
121             Log.i(TAG, "---- openPorts()");
122         }
123         MidiDeviceInfo deviceInfo = device.getInfo();
124         int numOutputs = deviceInfo.getOutputPortCount();
125         if (numOutputs > 0) {
126             mReceivePort = device.openOutputPort(0);
127             mReceivePort.connect(receiver);
128         }
129 
130         int numInputs = deviceInfo.getInputPortCount();
131         if (numInputs != 0) {
132             mSendPort = device.openInputPort(0);
133         }
134         mMidiDevice = device;
135 
136         if (DEBUG) {
137             Log.i(TAG, "---- mSendPort:" + mSendPort);
138         }
139     }
140 
closePorts()141     public void closePorts() {
142         if (DEBUG) {
143             Log.i(TAG, "---- closePorts()");
144         }
145         try {
146             if (mSendPort != null) {
147                 mSendPort.close();
148                 mSendPort = null;
149             }
150             if (mReceivePort != null) {
151                 mReceivePort.close();
152                 mReceivePort = null;
153             }
154             if (mMidiDevice != null) {
155                 mMidiDevice.close();
156                 mMidiDevice = null;
157             }
158         } catch (IOException ex) {
159             Log.e(TAG, "IOException Closing MIDI ports: " + ex);
160         }
161     }
162 
getInputName()163     public String getInputName() {
164         if (mReceiveDevInfo != null) {
165             return mDeviceType == MidiDeviceInfo.TYPE_VIRTUAL
166                     ? "Virtual MIDI Device"
167                     : mReceiveDevInfo.getProperties().getString(MidiDeviceInfo.PROPERTY_NAME);
168         } else {
169             return "";
170         }
171     }
172 
getOutputName()173     public String getOutputName() {
174         if (mSendDevInfo != null) {
175             return mDeviceType == MidiDeviceInfo.TYPE_VIRTUAL
176                     ? "Virtual MIDI Device"
177                     : mSendDevInfo.getProperties().getString(MidiDeviceInfo.PROPERTY_NAME);
178         } else {
179             return "";
180         }
181     }
182 }   /* class MidiIODevice */
183