blob: 7b55d08b21eac8a338de8540978e8129a787fb24 [file] [log] [blame]
/*
* Copyright (C) 2018 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.android.cts.verifier.audio;
import java.io.IOException;
import android.media.midi.MidiDevice;
import android.media.midi.MidiDeviceInfo;
import android.media.midi.MidiManager;
import android.media.midi.MidiReceiver;
import android.os.Bundle;
import android.util.Log;
import com.android.compatibility.common.util.CddTest;
import com.android.cts.verifier.audio.midilib.MidiIODevice;
import com.android.cts.verifier.audio.midilib.NativeMidiManager;
import com.android.cts.verifier.R;
/*
* A note about the USB MIDI device.
* Any USB MIDI peripheral with standard female DIN jacks can be used. A standard MIDI cable
* plugged into both input and output is required for the USB Loopback Test. A Bluetooth MIDI
* device like the Yamaha MD-BT01 plugged into both input and output is required for the
* Bluetooth Loopback test.
*/
/*
* A note about the "virtual MIDI" device...
* See file MidiEchoService for implementation of the echo server itself.
* This service is started by the main manifest file (AndroidManifest.xml).
*/
/*
* A note about Bluetooth MIDI devices...
* Any Bluetooth MIDI device needs to be paired with the DUT with the "MIDI+BTLE" application
* available in the Play Store:
* (https://play.google.com/store/apps/details?id=com.mobileer.example.midibtlepairing).
*/
/**
* CTS Verifier Activity for MIDI test
*/
@CddTest(requirement = "5.9/C-1-3,C-1-2")
public class MidiNativeTestActivity extends MidiTestActivityBase {
private static final String TAG = "MidiNativeTestActivity";
private static final boolean DEBUG = false;
public MidiNativeTestActivity() {
super();
initTestModules(new NativeMidiTestModule(MidiDeviceInfo.TYPE_USB),
new NativeMidiTestModule(MidiDeviceInfo.TYPE_VIRTUAL),
new BTMidiTestModule());
NativeMidiManager.loadNativeAPI();
NativeMidiManager.initN();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
if (DEBUG) {
Log.i(TAG, "---- onCreate()");
}
setContentView(R.layout.ndk_midi_activity);
super.onCreate(savedInstanceState);
startMidiEchoServer();
scanMidiDevices();
connectDeviceListener();
}
@Override
protected void onPause () {
super.onPause();
if (DEBUG) {
Log.i(TAG, "---- onPause()");
}
boolean isFound = stopService(mMidiServiceIntent);
if (DEBUG) {
Log.i(TAG, "---- Stop Service: " + isFound);
}
}
/**
* A class to control and represent the state of a given test.
* It hold the data needed for IO, and the logic for sending, receiving and matching
* the MIDI data stream.
*/
public class NativeMidiTestModule extends MidiTestModule {
private static final String TAG = "NativeMidiTestModule";
private static final boolean DEBUG = true;
private NativeMidiManager mNativeMidiManager;
public NativeMidiTestModule(int deviceType) {
super(deviceType);
mNativeMidiManager = new NativeMidiManager();
// this call is just to keep the build from stripping out "endTest", because
// it is only called from JNI.
endTest(TESTSTATUS_NOTRUN);
}
protected void closePorts() {
// NOP
}
@Override
void startLoopbackTest(int testID) {
synchronized (mTestLock) {
mTestRunning = true;
enableTestButtons(false);
}
if (DEBUG) {
Log.i(TAG, "---- startLoopbackTest()");
}
mRunningTestID = testID;
synchronized (mTestLock) {
mTestStatus = TESTSTATUS_NOTRUN;
}
if (mIODevice.mSendDevInfo != null) {
mMidiManager.openDevice(mIODevice.mSendDevInfo, new TestModuleOpenListener(), null);
}
startTimeoutHandler();
}
@Override
boolean hasTestPassed() {
int status;
synchronized (mTestLock) {
status = mTestStatus;
}
return status == TESTSTATUS_PASSED;
}
public void endTest(int endCode) {
synchronized (mTestLock) {
mTestRunning = false;
mTestStatus = endCode;
}
if (endCode != TESTSTATUS_NOTRUN) {
updateTestStateUI();
enableTestButtons(true);
}
closePorts();
}
/**
* Listens for MIDI device opens. Opens I/O ports and sends out the apriori
* setup messages.
*/
class TestModuleOpenListener implements MidiManager.OnDeviceOpenedListener {
//
// This is where the logical part of the test starts
//
@Override
public void onDeviceOpened(MidiDevice device) {
if (DEBUG) {
Log.i(TAG, "---- onDeviceOpened()");
}
mNativeMidiManager.startTest(NativeMidiTestModule.this, device,
mRunningTestID == TESTID_BTLOOPBACK);
}
}
} /* class NativeMidiTestModule */
/**
* Test Module for Bluetooth Loopback.
* This is a specialization of NativeMidiTestModule (which has the connections for the BL device
* itself) with and added MidiIODevice object for the USB audio device which does the
* "looping back".
*/
private class BTMidiTestModule extends NativeMidiTestModule {
private static final String TAG = "BTMidiTestModule";
private MidiIODevice mUSBLoopbackDevice = new MidiIODevice(MidiDeviceInfo.TYPE_USB);
public BTMidiTestModule() {
super(MidiDeviceInfo.TYPE_BLUETOOTH);
}
@Override
public void scanDevices(MidiDeviceInfo[] devInfos) {
// (normal) Scan for BT MIDI device
super.scanDevices(devInfos);
// Find a USB Loopback Device
mUSBLoopbackDevice.scanDevices(devInfos);
}
protected void closePorts() {
super.closePorts();
if (mUSBLoopbackDevice != null) {
mUSBLoopbackDevice.closePorts();
}
}
@Override
void startLoopbackTest(int testID) {
if (DEBUG) {
Log.i(TAG, "---- startLoopbackTest()");
}
// Setup the USB Loopback Device
mUSBLoopbackDevice.closePorts();
if (mIODevice.mSendDevInfo != null) {
mMidiManager.openDevice(
mUSBLoopbackDevice.mSendDevInfo, new USBLoopbackOpenListener(), null);
}
// Now start the test as usual
super.startLoopbackTest(testID);
}
/**
* We need this OnDeviceOpenedListener to open the USB-Loopback device
*/
private class USBLoopbackOpenListener implements MidiManager.OnDeviceOpenedListener {
@Override
public void onDeviceOpened(MidiDevice device) {
if (DEBUG) {
Log.i("USBLoopbackOpenListener", "---- onDeviceOpened()");
}
mUSBLoopbackDevice.openPorts(device, new USBMidiEchoReceiver());
}
} /* class USBLoopbackOpenListener */
/**
* MidiReceiver subclass for BlueTooth Loopback Test
*
* This class receives bytes from the USB Interface (presumably coming from the
* Bluetooth MIDI peripheral) and echoes them back out (presumably to the Bluetooth
* MIDI peripheral).
*/
//TODO - This could be pulled out into a separate class and shared with the identical
// code in MidiJavaTestActivity is we pass in the send port
private class USBMidiEchoReceiver extends MidiReceiver {
private int mTotalBytesEchoed;
@Override
public void onSend(byte[] msg, int offset, int count, long timestamp) throws IOException {
mTotalBytesEchoed += count;
if (DEBUG) {
Log.i(TAG, "---- USBMidiEchoReceiver.onSend() count:" + count +
" total:" + mTotalBytesEchoed);
}
if (mUSBLoopbackDevice.mSendPort == null) {
Log.e(TAG, "(native) mUSBLoopbackDevice.mSendPort is null");
} else {
mUSBLoopbackDevice.mSendPort.onSend(msg, offset, count, timestamp);
}
}
} /* class USBMidiEchoReceiver */
} /* class BTMidiTestModule */
} /* class MidiNativeTestActivity */