Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with native-image when trying to process MIDI IN events #10

Open
java71 opened this issue Jul 28, 2022 · 3 comments
Open

Problem with native-image when trying to process MIDI IN events #10

java71 opened this issue Jul 28, 2022 · 3 comments

Comments

@java71
Copy link

java71 commented Jul 28, 2022

Given source code (hereafter) works well with JDK : MIDI output works and MIDI input event are caught and traced.
But after creating a native image, progam fails as soon as a MIDI keyboard key is pressed.

Source code:

import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.sound.midi.Transmitter;

public class HelloMidi {
/** Main method. /
public static void main(String[] args) {
System.err.println("HelloMidi");
//-Recover MIDI in & out
final Receiver midiOut=pickMidiOut("ESI M4U XT");
final Transmitter midiIn=pickMidiIn("MIDIIN4 (ESI M4U XT)");
//-Define what to do with events recovere for keyboard
midiIn.setReceiver(new Receiver() {
/
* {@inheritdoc} /
@OverRide
public final void send(final MidiMessage message,final long timeStamp) {
//-A message has just been received
System.err.print("Message received->"+message.getLength()+" bytes");
for(final byte b:message.getMessage()) System.err.print(", "+Byte.toUnsignedInt(b));
System.err.println();
}
/
* {@inheritdoc} /
@OverRide
public final void close() {
//-Nothing for this test !
}
});
assert(midiOut!=null);
try {
midiOut.send(new ShortMessage(144,60,120),-1);
Thread.sleep(1000);
midiOut.send(new ShortMessage(144,67,120),-1);
Thread.sleep(1000);
midiOut.send(new ShortMessage(144,72,120),-1);
Thread.sleep(20000);
//-Print accessible devics for information
for(final MidiDevice.Info mdi:MidiSystem.getMidiDeviceInfo()) System.err.println("Device '"+mdi.getName()+"':"+mdi);
} catch(final Exception e) {
//-Any problem
e.printStackTrace();
}
//-Exit
System.err.println("ByeMidi");
System.exit(0);
}
/
* Check for requested MIDI OUT receiver. /
private static Receiver pickMidiOut(final String aName) {
//-Parse all devices
for(final MidiDevice.Info mdi:MidiSystem.getMidiDeviceInfo()) {
//-Check name
if(!mdi.getName().equals(aName)) continue;
//-Try in case there are errors
try {
//-Recover a MIDI device
final MidiDevice device=MidiSystem.getMidiDevice(mdi);
//-Try to open it
if(!device.isOpen()) device.open();
if(!device.isOpen()) continue;
//-Check receiver
final Receiver answer=device.getReceiver();
if(answer!=null) return(answer);
} catch(final Throwable e) {
//-Any problem
continue;
}
}
//-Return 'null' as none found
return(null);
}
/
* Check for requested MIDI IN transmitter. */
private static Transmitter pickMidiIn(final String aName) {
//-Parse all devices
for(final MidiDevice.Info mdi:MidiSystem.getMidiDeviceInfo()) {
//-Check name
if(!mdi.getName().equals(aName)) continue;
//-Try in case there are errors
try {
//-Recover a MIDI device
final MidiDevice device=MidiSystem.getMidiDevice(mdi);
//-Try to open it
if(!device.isOpen()) device.open();
if(!device.isOpen()) continue;
//-Check receiver
final Transmitter answer=device.getTransmitter();
if(answer!=null) return(answer);
} catch(final Throwable e) {
//-Any problem
continue;
}
}
//-Return 'null' as none found
return(null);
}
}

This simple source code is self content and does not need anything else than standard JDK.
Using exe generated program, execption is thrown as soon as a MIDI key is pressed (or any other MIDI message)

HelloMidi
Exception in thread "Java Sound MidiInDevice Thread" java.lang.NoSuchMethodError: com.sun.media.sound.MidiInDevice.callbackShortMessage(IJ)V
at com.oracle.svm.jni.functions.JNIFunctions$Support.getMethodID(JNIFunctions.java:1247)
at com.oracle.svm.jni.functions.JNIFunctions$Support.getMethodID(JNIFunctions.java:1232)
at com.oracle.svm.jni.functions.JNIFunctions.GetMethodID(JNIFunctions.java:412)
at com.sun.media.sound.MidiInDevice.nGetMessages(MidiInDevice.java)
at com.sun.media.sound.MidiInDevice.run(MidiInDevice.java:127)
at java.lang.Thread.run(Thread.java:833)
at com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:704)
at com.oracle.svm.core.windows.WindowsPlatformThreads.osThreadStartRoutine(WindowsPlatformThreads.java:143)

Operating system = windows + eclipse + jdk17

command line for native -> native-image.cmd --class-path c:\test\out HelloMidi

Thanks for your help
HelloMidi.zip

@AlexanderScherbatiy
Copy link

AlexanderScherbatiy commented Aug 24, 2022

We were able to reproduce the issues on Windows with a MIDI keyboard.

To make it work it is possible to use native-image-agent to dump JNI and reflection methods used by the application to configuration files and then use the config files to generate the native image.

Dump configuration files with native-image-agent:

<bellsoft-liberica-vm-openjdk11-21.3.1>\bin\java -agentlib:native-image-agent=config-output-dir=conf-dir HelloMidi

Press MIDI keyboard keys.
Close app and check that the file conf-dir/jni-config.json contains records about MidiInDevice.callbackLongMessage(...) methods:

{
  "name":"com.sun.media.sound.MidiInDevice",
  "methods":[
    {"name":"callbackLongMessage","parameterTypes":["byte[]","long"] }, 
    {"name":"callbackShortMessage","parameterTypes":["int","long"] }
  ]
}

Generate native image using JNI and Reflection configuration files:

call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvars64.bat"
call <bellsoft-liberica-vm-openjdk11-21.3.1>\bin\native-image.cmd -H:JNIConfigurationFiles=conf-dir/jni-config.json -H:ReflectionConfigurationFiles=conf-dir/reflect-config.json HelloMidi

@java71
Copy link
Author

java71 commented Aug 28, 2022

Great thanks ! It works...
Next and last problem is that 'jsound.dll' is not included into static native image.
Do you think it could be possible that native image generated by LIBERICA achive that so that the global static native image is really self-content.

Thanks to LIBERICA teams for the global efficient integration.

@AlexanderScherbatiy
Copy link

AlexanderScherbatiy commented Aug 29, 2022

Decision that AWT/Swing shared libraries are copied as is and are not included into a static native image on Windows has roots in AWT library static initialization order problem: AWT & Swing on Windows oracle/graal#3084
It looks like it first need to be investigated and fixed on JDK side.

@bell-sw bell-sw transferred this issue from bell-sw/Liberica Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants