Path: blob/master/test/jdk/javax/sound/midi/Devices/IOLoop.java
41152 views
/*1* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223import java.io.ByteArrayOutputStream;2425import javax.sound.midi.MidiDevice;26import javax.sound.midi.MidiMessage;27import javax.sound.midi.MidiSystem;28import javax.sound.midi.Receiver;29import javax.sound.midi.ShortMessage;30import javax.sound.midi.SysexMessage;31import javax.sound.midi.Transmitter;3233/**34* @test35* @bug 478292436* @bug 481216837* @bug 435678738* @summary MIDI i/o. This is an interactive test! Start it and follow the39* instructions.40* @run main/manual IOLoop41*/42public class IOLoop {43private static final int LONG_SYSEX_LENGTH = 2000;4445private static Receiver receiver;46private static Transmitter transmitter;47private static MidiMessage receivedMessage;48private static ByteArrayOutputStream baos;49private static int expectedBytes;50private static int receivedBytes;51private static Object lock = new Object();52private static long lastTimestamp;5354public static void main(String[] args) throws Exception {55ShortMessage sMsg = new ShortMessage();56SysexMessage syMsg = new SysexMessage();57boolean isTestPassed = true;58boolean sysExTestPassed = true;59boolean isTestExecuted = true;6061out("To run this test successfully, you need to have attached");62out(" your MIDI out port with the MIDI in port.");6364MidiDevice inDev = null;65MidiDevice outDev = null;6667// setup68try {69MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();7071int devNum = Integer.decode(args[0]).intValue();72out("-> opening Transmitter from "+infos[devNum]);73inDev = MidiSystem.getMidiDevice(infos[devNum]);74inDev.open();75transmitter = inDev.getTransmitter();76Receiver testReceiver = new TestReceiver();77transmitter.setReceiver(testReceiver);7879devNum = Integer.decode(args[1]).intValue();80out("-> opening Receiver from "+infos[devNum]);81outDev = MidiSystem.getMidiDevice(infos[devNum]);82outDev.open();83receiver = outDev.getReceiver();8485} catch (Exception e) {86System.out.println(e);87System.out.println("Cannot test!");88return;89}9091// test92sMsg.setMessage(ShortMessage.NOTE_OFF | 0, 27, 100);93isTestPassed &= testMessage(sMsg);94sMsg.setMessage(ShortMessage.NOTE_OFF | 0, 0, 0);95isTestPassed &= testMessage(sMsg);96sMsg.setMessage(ShortMessage.NOTE_OFF | 15, 127, 127);97isTestPassed &= testMessage(sMsg);98sMsg.setMessage(ShortMessage.NOTE_ON | 4, 27, 0);99isTestPassed &= testMessage(sMsg);100sMsg.setMessage(ShortMessage.NOTE_ON | 0, 0, 0);101isTestPassed &= testMessage(sMsg);102sMsg.setMessage(ShortMessage.NOTE_ON | 15, 127, 127);103isTestPassed &= testMessage(sMsg);104sMsg.setMessage(ShortMessage.POLY_PRESSURE | 11, 98, 99);105isTestPassed &= testMessage(sMsg);106sMsg.setMessage(ShortMessage.POLY_PRESSURE | 0, 0, 0);107isTestPassed &= testMessage(sMsg);108sMsg.setMessage(ShortMessage.POLY_PRESSURE | 15, 127, 127);109isTestPassed &= testMessage(sMsg);110sMsg.setMessage(ShortMessage.CONTROL_CHANGE | 13, 1, 63);111isTestPassed &= testMessage(sMsg);112sMsg.setMessage(ShortMessage.CONTROL_CHANGE | 0, 0, 0);113isTestPassed &= testMessage(sMsg);114sMsg.setMessage(ShortMessage.CONTROL_CHANGE | 15, 127, 127);115isTestPassed &= testMessage(sMsg);116sMsg.setMessage(ShortMessage.PROGRAM_CHANGE | 2, 120, 0);117isTestPassed &= testMessage(sMsg);118sMsg.setMessage(ShortMessage.PROGRAM_CHANGE | 0, 0, 0);119isTestPassed &= testMessage(sMsg);120sMsg.setMessage(ShortMessage.PROGRAM_CHANGE | 15, 127, 0);121isTestPassed &= testMessage(sMsg);122sMsg.setMessage(ShortMessage.CHANNEL_PRESSURE | 6, 30, 0);123isTestPassed &= testMessage(sMsg);124sMsg.setMessage(ShortMessage.CHANNEL_PRESSURE | 0, 0, 0);125isTestPassed &= testMessage(sMsg);126sMsg.setMessage(ShortMessage.CHANNEL_PRESSURE | 15, 127, 0);127isTestPassed &= testMessage(sMsg);128129sMsg.setMessage(ShortMessage.PITCH_BEND | 6, 56, 4);130isTestPassed &= testMessage(sMsg);131sMsg.setMessage(ShortMessage.PITCH_BEND | 0, 0, 0);132isTestPassed &= testMessage(sMsg);133sMsg.setMessage(ShortMessage.PITCH_BEND | 15, 127, 127);134isTestPassed &= testMessage(sMsg);135136sMsg.setMessage(ShortMessage.MIDI_TIME_CODE, 0, 0);137isTestPassed &= testMessage(sMsg);138sMsg.setMessage(ShortMessage.MIDI_TIME_CODE, 127, 0);139isTestPassed &= testMessage(sMsg);140sMsg.setMessage(ShortMessage.SONG_POSITION_POINTER, 1, 77);141isTestPassed &= testMessage(sMsg);142sMsg.setMessage(ShortMessage.SONG_POSITION_POINTER, 0, 0);143isTestPassed &= testMessage(sMsg);144sMsg.setMessage(ShortMessage.SONG_POSITION_POINTER, 127, 127);145isTestPassed &= testMessage(sMsg);146sMsg.setMessage(ShortMessage.SONG_SELECT, 51, 0);147isTestPassed &= testMessage(sMsg);148sMsg.setMessage(ShortMessage.SONG_SELECT, 0, 0);149isTestPassed &= testMessage(sMsg);150sMsg.setMessage(ShortMessage.SONG_SELECT, 127, 0);151isTestPassed &= testMessage(sMsg);152sMsg.setMessage(ShortMessage.TUNE_REQUEST);153isTestPassed &= testMessage(sMsg);154155sMsg.setMessage(ShortMessage.TIMING_CLOCK);156isTestPassed &= testMessage(sMsg);157sMsg.setMessage(ShortMessage.START);158isTestPassed &= testMessage(sMsg);159sMsg.setMessage(ShortMessage.CONTINUE);160isTestPassed &= testMessage(sMsg);161sMsg.setMessage(ShortMessage.STOP);162isTestPassed &= testMessage(sMsg);163sMsg.setMessage(ShortMessage.ACTIVE_SENSING);164isTestPassed &= testMessage(sMsg);165sMsg.setMessage(ShortMessage.SYSTEM_RESET);166isTestPassed &= testMessage(sMsg);167168syMsg.setMessage(new byte[]{(byte) 0xF0, (byte) 0xF7}, 2);169isTestPassed &= testMessage(syMsg);170syMsg.setMessage(new byte[]{(byte) 0xF0, 0x01, (byte) 0xF7}, 3);171isTestPassed &= testMessage(syMsg);172syMsg.setMessage(new byte[]{(byte) 0xF0, 0x02, 0x03, (byte) 0xF7}, 4);173isTestPassed &= testMessage(syMsg);174syMsg.setMessage(new byte[]{(byte) 0xF0, 0x04, 0x05, 0x06, (byte) 0xF7}, 5);175isTestPassed &= testMessage(syMsg);176177if (isTestPassed) {178byte[] sysexArray = new byte[LONG_SYSEX_LENGTH];179sysexArray[0] = (byte) 0xF0;180for (int i = 1; i < sysexArray.length; i++) {181sysexArray[i] = (byte) (i % 0x80);182}183// syMsg.setMessage(new byte[]{(byte) 0xF7, (byte) ShortMessage.START}, 2);184// sMsg.setMessage(ShortMessage.START);185// isTestPassed &= testMessage(syMsg, sMsg, DEFAULT_SLEEP_INTERVALL);186for (int trial = sysexArray.length; trial > 4; trial -= 1234) {187sleep(500);188sysexArray[trial - 1] = (byte) 0xF7;189syMsg.setMessage(sysexArray, trial);190sysExTestPassed &= testMessage(syMsg);191break;192}193}194195// cleanup196receiver.close();197transmitter.close();198inDev.close();199outDev.close();200201if (isTestExecuted) {202if (isTestPassed && sysExTestPassed) {203204out("Test PASSED.");205} else {206if (isTestPassed207&& !sysExTestPassed208&& (System.getProperty("os.name").startsWith("Windows"))) {209out("Some Windows MIDI i/o drivers have a problem with larger ");210out("sys ex messages. The failing sys ex cases are OK, therefore.");211out("Test PASSED.");212} else {213throw new Exception("Test FAILED.");214}215}216} else {217out("Test NOT FAILED");218}219}220221private static boolean testMessage(MidiMessage message) {222receivedMessage = null;223baos = new ByteArrayOutputStream();224expectedBytes = message.getLength();225receivedBytes = 0;226System.out.print("Sending message " + getMessageString(message.getMessage())+"...");227receiver.send(message, -1);228/* sending 3 bytes can roughly be done in 1 millisecond,229* so this estimate waits at max 3 times longer than the message takes,230* plus a little offset to allow the MIDI subsystem some processing time231*/232int offset = 300; // standard offset 100 millis233if (message instanceof SysexMessage) {234// add a little processing time to sysex messages235offset += 1000;236}237if (receivedBytes < expectedBytes) {238sleep(expectedBytes + offset);239}240boolean equal;241byte[] data = baos.toByteArray();242if (data.length > 0) {243equal = messagesEqual(message.getMessage(), data);244} else {245equal = messagesEqual(message, receivedMessage);246if (receivedMessage != null) {247data = receivedMessage.getMessage();248} else {249data = null;250}251}252if (!equal) {253if ((message.getStatus() & 0xF0) == ShortMessage.PITCH_BEND) {254out("NOT failed (may expose a bug in ALSA)");255equal = true;256sleep(100);257}258if ((message.getStatus() == 0xF6) && (message.getLength() == 1)) {259out("NOT failed (may expose an issue on Solaris)");260equal = true;261sleep(100);262}263else if ((message.getStatus()) == 0xF0 && message.getLength() < 4) {264out("NOT failed (not a correct sys ex message)");265equal = true;266sleep(200);267} else {268out("FAILED:");269out(" received as " + getMessageString(data));270}271} else {272System.out.println("OK");273}274return equal;275}276277private static void sleep(int milliseconds) {278synchronized(lock) {279try {280lock.wait(milliseconds);281} catch (InterruptedException e) {282}283}284}285286private static String getMessageString(byte[] data) {287String s;288if (data == null) {289s = "<null>";290} else if (data.length == 0) {291s = "0-sized array";292} else {293int status = data[0] & 0xFF;294if (data.length <= 3) {295if (status < 240) {296s = "command 0x" + Integer.toHexString(status & 0xF0) + " channel " + (status & 0x0F);297} else {298s = "status 0x" + Integer.toHexString(status);299}300if (data.length > 1) {301s += " data 0x" + Integer.toHexString(data[1] & 0xFF);302if (data.length > 2) {303s += " 0x" + Integer.toHexString(data[2] & 0xFF);304}305}306} else {307s = "status " + Integer.toHexString(status)+" and length "+data.length+" bytes";308}309}310return s;311}312313private static boolean messagesEqual(MidiMessage m1, MidiMessage m2) {314if (m1 == null || m2 == null) {315return false;316}317if (m1.getLength() != m2.getLength()) {318return false;319}320byte[] array1 = m1.getMessage();321byte[] array2 = m2.getMessage();322return messagesEqual(array1, array2);323}324325private static boolean messagesEqual(byte[] a1, byte[] a2) {326if (a1.length != a2.length) return false;327for (int i = 0; i < a1.length; i++) {328if (a1[i] != a2[i]) {329return false;330}331}332return true;333}334335private static void out(String s) {336System.out.println(s);337System.out.flush();338}339340private static String canIn(MidiDevice dev) {341if (dev.getMaxTransmitters() != 0) {342return "IN ";343}344return " ";345}346347private static String canOut(MidiDevice dev) {348if (dev.getMaxReceivers() != 0) {349return "OUT ";350}351return " ";352}353354355private static void checkTimestamp(long timestamp) {356// out("checking timestamp...");357if (timestamp < 1) {358out("timestamp 0 or negative!");359}360if (timestamp < lastTimestamp) {361out("timestamp not progressive!");362}363lastTimestamp = timestamp;364}365366private static class TestReceiver implements Receiver {367public void send(MidiMessage message, long timestamp) {368//System.out.print(""+message.getLength()+"..");369checkTimestamp(timestamp);370try {371receivedMessage = message;372if (message.getStatus() == 0xF0373|| (message.getLength() > 3 && message.getStatus() != 0xF7)) {374// sys ex message375byte[] data = message.getMessage();376baos.write(data);377receivedBytes += data.length;378}379else if (message.getStatus() == 0xF7) {380// sys ex cont'd message381byte[] data = message.getMessage();382// ignore the prepended 0xF7383baos.write(data, 1, data.length-1);384receivedBytes += (data.length - 1);385} else {386receivedBytes += message.getLength();387}388if (receivedBytes >= expectedBytes) {389synchronized(lock) {390lock.notify();391}392}393System.out.print(""+receivedBytes+"..");394395} catch (Exception e) {396e.printStackTrace();397}398}399400public void close() {401}402}403}404405406