Воспроизведение обычных и циклических звуков в JDK 11?

#codenameone

#codenameone

Вопрос:

Я использую Java JDK 11.0.8 (для «Установленных JRES» в Eclipse установлено значение jdk-11.0.8), Eclipse 2020-06 и Codename One 6.0.0.

Недавно я переключился с JDK 8 на JDK 11 и заметил, что опция воспроизведения звуков в моем приложении больше не работает…

Обратите внимание, что я снимаю флажок «Java 8» при создании своего приложения и всего лишь пытаюсь разобраться в симуляторе (я не пытаюсь развернуть приложение на реальном мобильном устройстве).

Я хочу воспроизвести «обычный звук» (я хочу воспроизвести звук от начала до конца, и когда он закончится, мне не нужно воспроизводить его с начала), а также «циклический звук» (звук должен начинаться, когда он заканчивается, и, следовательно, я могу непрерывно воспроизводить его в фоновом режиме).

Следовательно, у меня есть два вопроса:

Вопрос1 — О «обычных звуках»

Я хотел бы создать медиа-объект только один раз, а затем повторно использовать его всякий раз, когда мне нужно воспроизвести тот же обычный звук.

Для этой цели я инкапсулирую создание мультимедиа внутри класса следующим образом:

 public class RegularSound {
    private Media m;
    public RegularSound(String fileName) {
        try{
        InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/" fileName);
        m = MediaManager.createMedia(is, "audio/wav");
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        
    }
    
    public void play() {
        m.setTime(0);
        m.play();
    }
}
  

Затем я создаю экземпляр объекта RegularSound и воспроизводю его следующим образом:

 mySound = new RegularSound("example.wav");
mySound.play();
  

Пожалуйста, обратите внимание на этот пример.wav копируется непосредственно в каталог «src» моего проекта.

Раньше этот код работал с JDK 8, но с JDK 11 я получаю следующие ошибки сборки:

 Exception in thread "AWT-EventQueue-0" java.lang.NoClassDefFoundError: javax/media/ControllerListener
    at com.codename1.impl.javase.JavaJMFSEPort$1.run(JavaJMFSEPort.java:67)
    at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
    at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:770)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
    at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:715)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
    at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:740)
    at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
    at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
    at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
    at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.ClassNotFoundException: javax.media.ControllerListener
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    at java.base/java.lang.ClassLoader.findSystemClass(ClassLoader.java:1247)
    at com.codename1.impl.javase.ClassPathLoader.findClass(ClassPathLoader.java:269)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
    at com.codename1.impl.javase.ClassPathLoader.loadClass(ClassPathLoader.java:115)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    at com.codename1.impl.javase.ClassPathLoader.loadClass(ClassPathLoader.java:107)
    ... 14 more
  

Вопрос2 — О «зацикливании звуков»

For looping sound I have created another class as follows:

 public class LoopingSound implements Runnable{
    private Media m;
    String fileName;
    
    public LoopingSound(String fileName){
        try{
            InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/" fileName);
            m = MediaManager.createMedia(is, "audio/wav",this);
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        
    }
    public void pause()
        {
        m.pause();
        }
    public void play()
        {
        m.play();
        }
    
    public void run() {
        m.setTime(0);
        m.play();
            
    }
}
  

But I again get build errors when I instantiate an object of LoopingSound and try to play it…

So could you please let me know how to change code for regular and looping sounds so that I do not receive above-mentioned errors when using JDK 11?

UPDATE

Thanks for the reply @shai-almog. I have installed CEF. But I am receiving some messages on the console in runtime and I can’t hear the sound playing… I run the following code:

 try {
            InputStream is = Display.getInstance().getResourceAsStream(getClass(), "/example.wav");
            Media m = MediaManager.createMedia(is, "audio/wav");
            m.play();
    } catch (IOException e) {
            e.printStackTrace();
    }
  

and I receive the following messages on console when I run this code (it throws an exception at the end):

 Adding CEF to classpath
Retina Scale: 2.0
CEF Args: [--disable-gpu, --disable-software-rasterizer, --disable-gpu-compositing, --touch-events=enabled, --enable-media-stream, --device-scale-factor=4, --force-device-scale-factor=4, --autoplay-policy=no-user-gesture-required, --enable-usermedia-screen-capturing]
Using:
JCEF Version = 83.4.0.260
CEF Version = 83.4.0
Chromium Version = 83.0.4103.106
AppHandler.stateHasChanged: INITIALIZING
initialize on Thread[AWT-EventQueue-0,6,main] with library path C:Userspmuyan.codenameoneceflibwin64
Added scheme search://
Added scheme client://
Added scheme cn1stream://

DevTools listening on ws://127.0.0.1:8088/devtools/browser/591d3502-6fd6-4997-9131-9a2a352e47b1
AppHandler.stateHasChanged: INITIALIZED
Running ready callbacks
Exception in thread "AWT-EventQueue-0" Address changed to data:text/html,<style type%3D'text/css'>document, body%20{padding:0;margin:0; width:100%25; height:%20100%25%7D video, audio%20{margin:0; padding:0; width:100%25; height:%20100%25%7D<audio id%3D'cn1Media' width%3D'640' height%3D'480' style%3D'width:100%;height:100%' src%3D'https://cn1app/streams/1'%2F>window.cn1Media%20%3D document.getElementById('cn1Media');function callback(data){ cefQuery({request:'shouldNavigate:'+JSON.stringify(data), onSuccess: function(response){%7D, onFailure:function(error_code, error_message)%20{ console.log(error_message)%7D%7D);}cn1Media.addEventListener('pause', function(){ callback({'state':'paused'%7D)%7D);cn1Media.addEventListener('play', function(){ callback({'state':'playing'%7D)%7D);cn1Media.addEventListener('ended', function(){ callback({'state':'ended'%7D)%7D);cn1Media.addEventListener('durationchange', function(){ callback({'duration': Math.floor(cn1Media.duration%20*%201000)%7D)%7D);cn1Media.addEventListener('timeupdate', function(){ callback({'time': Math.floor(cn1Media.currentTime%20*%201000)%7D)%7D);cn1Media.addEventListener('volumechange', function(){ callback({'volume': Math.round(cn1Media.volume%20*%20100)%7D)%7D);cn1Media.addEventListener('error', function(){ var msg%20%3D%20'Unknown Error'; try%20{msg%20%3D cn1Media.error.message%20+%20'. Code='+cn1Media.error.code;}catch(e){%7D callback({'error': msg%7D)%7D);%20
  

ОБНОВЛЕНИЕ 2

Я мог бы вручную добавить Open JavaFX 11 в Eclipse и присвоить кодовому имени одному приложению, работающему под Eclipse, при использовании JDK 11 следующим образом:

 Step1) Create JavaFX11 user library under Eclipse
Download JavaFX 11 from https://gluonhq.com/products/javafx/
unzip it -> creates javafx-sdk-11.0.2 folder
Create a User Library: Eclipse -> Window -> Preferences -> Java -> Build Path -> User Libraries -> New. 
Name it JavaFX11.
Hit "Add External JARs" and include all the jars under javafx-sdk-11.0.2lib

Step 2) Add the JavaFX11 library to the project:
Right click on project.
Select Build path -> Configure Build Path 
Goto Library tab->Add Library->User Library->Check JavaFX11->Apply and Close
  

Теперь я могу слышать звуки, воспроизводимые в моем приложении Codename One.

Однако мне нужно запустить мое приложение из командной строки, а обычная командная строка для запуска приложений больше не работает (приложение не может найти классы, связанные с JavaFX, из командной строки, и я получаю те же ошибки, что перечислены выше). Итак, не могли бы вы, пожалуйста, сказать мне, как изменить командную строку, чтобы проект Codename One, использующий JavaFX, запускался из командной строки?

Вот обычная командная строка, которую я использую:

 java -cp distProj.jar;JavaSE.jar com.codename1.impl.javase.Simulator com.mycompany.hi.Main
  

Кстати, я пытался добавить javafx.media.jar в javafx-sdk-11.0.2lib в путь к классу (-cp) в командной строке, но это не сработало…

ОБНОВЛЕНИЕ 3

Мы решили проблему, используя следующую командную строку:

java —module-path C:javafx-sdk-11.0.2lib —add-modules= ALL-MODULE-PATH -cp distProj.jar ;JavaSE.jar com.codename1.impl.javase.Симулятор com.mycompany.hi.Main

(где C:javafx-sdk-11.0.2lib это наш)

Спасибо!

Ответ №1:

TL; DR

Либо установите CEF, как описано здесь, либо переключитесь на ZuluFX 11 для вашей виртуальной машины.

Объяснение:

Раньше это работало, пока мы не интегрировали поддержку CEF, мы загружали JavaFX динамически для установки JDK 11, но это вызывало множество сопутствующих проблем. Итак, мы решили перейти на CEF, это все еще продолжается, и пока это продолжается, динамическая загрузка JavaFX не работает. Как только это будет сделано, CEF будет установлен автоматически, и это снова будет без проблем.

Это влияет на компонент браузера и мультимедиа, которые являются двумя компонентами, реализованными JavaFX.

Комментарии:

1. Пожалуйста, посмотрите обновление в моем вопросе. У меня все еще есть проблемы, и я был бы признателен за вашу помощь…

2. Это может быть ошибкой в CEF. Пожалуйста, сообщите о проблеме здесь: github.com/codenameone/CodenameOne/issues В этом случае вам придется удалить CEF и использовать виртуальную машину, поддерживающую JavaFX. Возможно, вы сможете вручную установить JavaFX в свою виртуальную машину или просто загрузить ZuluFX.

3. Еще раз спасибо за ваш ответ @shai-almog. Я отправил проблему на GitHub. Кроме того, мне удалось добавить JavaFX в Eclipse и присвоить проекту Codename One, работающему под Eclipse. Однако теперь у меня возникают проблемы с запуском приложения из командной строки. Пожалуйста, смотрите ОБНОВЛЕНИЕ 2 в моем вопросе. Я снова был бы признателен за вашу помощь, спасибо!

4. Убедитесь, что java-команда — это команда из ZuluFX. Если это не сработает, попробуйте добавить jfxrt.jar из вашей установки JDK в classpath.