source: josm/trunk/src/org/openstreetmap/josm/io/audio/JavaFxMediaPlayer.java @ 12715

Last change on this file since 12715 was 12715, checked in by Don-vip, 3 months ago

fix #15226 - see #2089 - support for compiling without JavaFX (modified patch by ris)

File size: 4.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.audio;
3
4import java.io.File;
5import java.io.FileNotFoundException;
6import java.io.IOException;
7import java.net.URISyntaxException;
8import java.net.URL;
9import java.util.concurrent.CountDownLatch;
10
11import org.openstreetmap.josm.io.audio.AudioPlayer.Execute;
12import org.openstreetmap.josm.io.audio.AudioPlayer.State;
13import org.openstreetmap.josm.tools.JosmRuntimeException;
14import org.openstreetmap.josm.tools.ListenerList;
15
16import com.sun.javafx.application.PlatformImpl;
17
18import javafx.scene.media.Media;
19import javafx.scene.media.MediaException;
20import javafx.scene.media.MediaPlayer;
21import javafx.scene.media.MediaPlayer.Status;
22import javafx.util.Duration;
23
24/**
25 * Default sound player based on the Java FX Media API.
26 * Used on platforms where Java FX is available. It supports the following audio codecs:<ul>
27 * <li>MP3</li>
28 * <li>AIFF containing uncompressed PCM</li>
29 * <li>WAV containing uncompressed PCM</li>
30 * <li>MPEG-4 multimedia container with Advanced Audio Coding (AAC) audio</li>
31 * </ul>
32 * @since 12328
33 */
34class JavaFxMediaPlayer implements SoundPlayer {
35
36    private final ListenerList<AudioListener> listeners = ListenerList.create();
37
38    private MediaPlayer mediaPlayer;
39
40    JavaFxMediaPlayer() throws JosmRuntimeException {
41        try {
42            initFxPlatform();
43        } catch (InterruptedException e) {
44            throw new JosmRuntimeException(e);
45        }
46    }
47
48    /**
49     * Initializes the JavaFX platform runtime.
50     * @throws InterruptedException if the current thread is interrupted while waiting
51     */
52    public static void initFxPlatform() throws InterruptedException {
53        final CountDownLatch startupLatch = new CountDownLatch(1);
54
55        // Note, this method is called on the FX Application Thread
56        PlatformImpl.startup(startupLatch::countDown);
57
58        // Wait for FX platform to start
59        startupLatch.await();
60    }
61
62    @Override
63    public synchronized void play(Execute command, State stateChange, URL playingUrl) throws AudioException, IOException {
64        try {
65            final URL url = command.url();
66            if (playingUrl != url) {
67                if (mediaPlayer != null) {
68                    mediaPlayer.stop();
69                }
70                // Fail fast in case of invalid local URI (JavaFX Media locator retries 5 times with a 1 second delay)
71                if ("file".equals(url.getProtocol()) && !new File(url.toURI()).exists()) {
72                    throw new FileNotFoundException(url.toString());
73                }
74                mediaPlayer = new MediaPlayer(new Media(url.toString()));
75                mediaPlayer.setOnPlaying(() ->
76                    listeners.fireEvent(l -> l.playing(url))
77                );
78            }
79            mediaPlayer.setRate(command.speed());
80            if (Status.PLAYING == mediaPlayer.getStatus()) {
81                Duration seekTime = Duration.seconds(command.offset());
82                if (!seekTime.equals(mediaPlayer.getCurrentTime())) {
83                    mediaPlayer.seek(seekTime);
84                }
85            }
86            mediaPlayer.play();
87        } catch (MediaException | URISyntaxException e) {
88            throw new AudioException(e);
89        }
90    }
91
92    @Override
93    public synchronized void pause(Execute command, State stateChange, URL playingUrl) throws AudioException, IOException {
94        if (mediaPlayer != null) {
95            try {
96                mediaPlayer.pause();
97            } catch (MediaException e) {
98                throw new AudioException(e);
99            }
100        }
101    }
102
103    @Override
104    public boolean playing(Execute command) throws AudioException, IOException, InterruptedException {
105        // Not used: JavaFX handles the low-level audio playback
106        return false;
107    }
108
109    @Override
110    public synchronized double position() {
111        return mediaPlayer != null ? mediaPlayer.getCurrentTime().toSeconds() : -1;
112    }
113
114    @Override
115    public synchronized double speed() {
116        return mediaPlayer != null ? mediaPlayer.getCurrentRate() : -1;
117    }
118
119    @Override
120    public void addAudioListener(AudioListener listener) {
121        listeners.addWeakListener(listener);
122    }
123}
Note: See TracBrowser for help on using the repository browser.