1 /* 2 * Copyright (C) 2018 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; 18 19 import android.media.midi.MidiDevice; 20 import android.media.midi.MidiDeviceInfo; 21 import android.media.midi.MidiManager; 22 import android.media.midi.MidiReceiver; 23 import android.os.Bundle; 24 import android.util.Log; 25 26 import com.android.compatibility.common.util.CddTest; 27 import com.android.cts.verifier.R; 28 import com.android.cts.verifier.audio.midilib.JavaMidiTestModule; 29 import com.android.cts.verifier.audio.midilib.MidiIODevice; 30 31 import java.io.IOException; 32 import java.util.Collection; 33 34 /* 35 * A note about the USB MIDI device. 36 * Any USB MIDI peripheral with standard female DIN jacks can be used. A standard MIDI cable 37 * plugged into both input and output is required for the USB Loopback Test. A Bluetooth MIDI 38 * device like the Yamaha MD-BT01 plugged into both input and output is required for the 39 * Bluetooth Loopback test. 40 */ 41 42 /* 43 * A note about the "virtual MIDI" device... 44 * See file MidiEchoService for implementation of the echo server itself. 45 * This service is started by the main manifest file (AndroidManifest.xml). 46 */ 47 48 /* 49 * A note about Bluetooth MIDI devices... 50 * Any Bluetooth MIDI device needs to be paired with the DUT with the "MIDI+BTLE" application 51 * available in the Play Store: 52 * (https://play.google.com/store/apps/details?id=com.mobileer.example.midibtlepairing). 53 */ 54 55 /** 56 * CTS Verifier Activity for MIDI test 57 */ 58 @CddTest(requirement = "5.9/C-1-4,C-1-2") 59 public class MidiJavaTestActivity extends MidiTestActivityBase { 60 private static final String TAG = "MidiJavaTestActivity"; 61 private static final boolean DEBUG = true; 62 MidiJavaTestActivity()63 public MidiJavaTestActivity() { 64 super(); 65 initTestModules(new JavaMidiTestActivityModule(MidiDeviceInfo.TYPE_USB), 66 new JavaMidiTestActivityModule(MidiDeviceInfo.TYPE_VIRTUAL), 67 new BTMidiTestModule()); 68 } 69 70 @Override onCreate(Bundle savedInstanceState)71 protected void onCreate(Bundle savedInstanceState) { 72 if (DEBUG) { 73 Log.i(TAG, "---- onCreate()"); 74 } 75 76 setContentView(R.layout.midi_activity); 77 78 super.onCreate(savedInstanceState); 79 80 startMidiEchoServer(); 81 scanMidiDevices(); 82 83 connectDeviceListener(); 84 } 85 86 /** 87 * Overrides parts of JavaMidiTestModule that needs a higher scope. 88 */ 89 private class JavaMidiTestActivityModule extends JavaMidiTestModule { 90 private static final String TAG = "JavaMidiTestActivityModule"; 91 JavaMidiTestActivityModule(int deviceType)92 JavaMidiTestActivityModule(int deviceType) { 93 super(deviceType); 94 } 95 96 @Override updateTestStateUIAbstract()97 protected void updateTestStateUIAbstract() { 98 updateTestStateUI(); 99 } 100 101 @Override showTimeoutMessageAbstract()102 protected void showTimeoutMessageAbstract() { 103 showTimeoutMessage(); 104 } 105 106 @Override enableTestButtonsAbstract(boolean enable)107 protected void enableTestButtonsAbstract(boolean enable) { 108 enableTestButtons(enable); 109 } 110 111 @Override openMidiDevice()112 protected void openMidiDevice() { 113 mMidiManager.openDevice(mIODevice.mSendDevInfo, new TestModuleOpenListener(), null); 114 } 115 showTimeoutMessage()116 void showTimeoutMessage() { 117 runOnUiThread(new Runnable() { 118 public void run() { 119 synchronized (mTestLock) { 120 if (mTestRunning) { 121 if (DEBUG) { 122 Log.i(TAG, "---- Test Failed - TIMEOUT"); 123 } 124 mTestStatus = TESTSTATUS_FAILED_TIMEOUT; 125 updateTestStateUIAbstract(); 126 } 127 } 128 } 129 }); 130 } 131 } /* class JavaMidiTestActivityModule */ 132 133 /** 134 * Test Module for Bluetooth Loopback. 135 * This is a specialization of JavaMidiTestModule (which has the connections for the BL device 136 * itself) with and added MidiIODevice object for the USB audio device which does the 137 * "looping back". 138 */ 139 private class BTMidiTestModule extends JavaMidiTestActivityModule { 140 private static final String TAG = "BTMidiTestModule"; 141 private MidiIODevice mUSBLoopbackDevice = new MidiIODevice(MidiDeviceInfo.TYPE_USB); 142 BTMidiTestModule()143 public BTMidiTestModule() { 144 super(MidiDeviceInfo.TYPE_BLUETOOTH ); 145 } 146 147 @Override scanDevices(Collection<MidiDeviceInfo> devInfos)148 public void scanDevices(Collection<MidiDeviceInfo> devInfos) { 149 // (normal) Scan for BT MIDI device 150 super.scanDevices(devInfos); 151 // Find a USB Loopback Device 152 mUSBLoopbackDevice.scanDevices(devInfos); 153 } 154 openUSBEchoDevice(MidiDevice device)155 private void openUSBEchoDevice(MidiDevice device) { 156 MidiDeviceInfo deviceInfo = device.getInfo(); 157 int numOutputs = deviceInfo.getOutputPortCount(); 158 if (numOutputs > 0) { 159 mUSBLoopbackDevice.mReceivePort = device.openOutputPort(0); 160 mUSBLoopbackDevice.mReceivePort.connect(new USBMidiEchoReceiver()); 161 } 162 163 int numInputs = deviceInfo.getInputPortCount(); 164 if (numInputs != 0) { 165 mUSBLoopbackDevice.mSendPort = device.openInputPort(0); 166 } 167 } 168 closePorts()169 protected void closePorts() { 170 super.closePorts(); 171 mUSBLoopbackDevice.closePorts(); 172 } 173 174 @Override startLoopbackTest(int testID)175 public void startLoopbackTest(int testID) { 176 if (DEBUG) { 177 Log.i(TAG, "---- startLoopbackTest()"); 178 } 179 180 super.startLoopbackTest(testID); 181 182 // Setup the USB Loopback Device 183 mUSBLoopbackDevice.closePorts(); 184 185 if (mIODevice.mSendDevInfo != null) { 186 mMidiManager.openDevice( 187 mUSBLoopbackDevice.mSendDevInfo, new USBLoopbackOpenListener(), null); 188 } 189 } 190 191 /** 192 * We need this OnDeviceOpenedListener to open the USB-Loopback device 193 */ 194 private class USBLoopbackOpenListener implements MidiManager.OnDeviceOpenedListener { 195 @Override onDeviceOpened(MidiDevice device)196 public void onDeviceOpened(MidiDevice device) { 197 if (DEBUG) { 198 Log.i("USBLoopbackOpenListener", "---- onDeviceOpened()"); 199 } 200 mUSBLoopbackDevice.openPorts(device, new USBMidiEchoReceiver()); 201 } 202 } /* class USBLoopbackOpenListener */ 203 204 /** 205 * MidiReceiver subclass for BlueTooth Loopback Test 206 * 207 * This class receives bytes from the USB Interface (presumably coming from the 208 * Bluetooth MIDI peripheral) and echoes them back out (presumably to the Bluetooth 209 * MIDI peripheral). 210 */ 211 //TODO - This could be pulled out into a separate class and shared with the identical 212 // code in MidiNativeTestActivity if we pass in the USB Loopback Device object rather 213 // than accessing it from the enclosing BTMidiTestModule class. 214 private class USBMidiEchoReceiver extends MidiReceiver { 215 private int mTotalBytesEchoed; 216 217 @Override onSend(byte[] msg, int offset, int count, long timestamp)218 public void onSend(byte[] msg, int offset, int count, long timestamp) throws IOException { 219 mTotalBytesEchoed += count; 220 if (DEBUG) { 221 logByteArray("echo: ", msg, offset, count); 222 } 223 if (mUSBLoopbackDevice.mSendPort == null) { 224 Log.e(TAG, "(java) mUSBLoopbackDevice.mSendPort is null"); 225 } else { 226 mUSBLoopbackDevice.mSendPort.onSend(msg, offset, count, timestamp); 227 } 228 } 229 } /* class USBMidiEchoReceiver */ 230 } /* class BTMidiTestModule */ 231 } /* class MidiActivity */ 232