javafxports how to call android native Media Player

后端 未结 2 1436
面向向阳花
面向向阳花 2020-11-27 23:18

As the javafxports Media is not yet implemented I\'m looking to use the Android Native MediaPlayer instead. Does anyone know how to do this.

相关标签:
2条回答
  • 2020-11-28 00:05

    The native audio player was used in the following example:

    https://gist.github.com/bgmf/d87a2bac0a5623f359637a3da334f980

    Beside some prerequisites, the code looks like this:

    package my.application;
    
    import my.application.Constants;
    import javafx.beans.property.ReadOnlyObjectProperty;
    import javafx.beans.property.ReadOnlyObjectWrapper;
    import org.robovm.apple.avfoundation.AVAudioPlayer;
    import org.robovm.apple.foundation.NSErrorException;
    import org.robovm.apple.foundation.NSURL;
    import org.robovm.apple.foundation.NSURLScheme;
    
    import java.io.File;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    public class NativeAudioServiceIOS extends PathHelperIOS implements NativeAudioService {
        private static final Logger LOG = Logger.getLogger(NativeAudioServiceIOS.class.getName());
        private static final String DIR_NAME = Constants.OBJECTS_BASE_PATH;
    
        private final ReadOnlyObjectWrapper<Status> status = new ReadOnlyObjectWrapper<>(this, "status", Status.STOP);
        private String filename = null;
        private AVAudioPlayer player = null;
    
        public NativeAudioServiceIOS() {
            super();
        }
    
        @Override
        public void init(String filename) throws NativeServiceException {
            this.filename = filename.startsWith("/") ? filename.substring(1) : filename;
            LOG.warning("Called with file: " + filename);
            status.set(Status.STOP);
    
            try {
                if(!filename.startsWith("/")) filename = "/" + filename;
                File fullfile = new File(pathBase.getAbsolutePath() + filename);
                if(fullfile.exists()) {
                    NSURL fullurl = new NSURL(NSURLScheme.File, "", fullfile.getAbsolutePath());
                    LOG.log(Level.SEVERE, "Loading URL: " + fullurl);
    
                    // Create audio player object and initialize with URL to sound
                    player = new AVAudioPlayer(fullurl);
                    LOG.log(Level.SEVERE, "Player initialized: " + player);
    
                    status.set(Status.STOP);
                } else {
                    LOG.log(Level.WARNING, String.format("Audiofile doesn't exist: %s (%s / %s)",
                            fullfile.getAbsolutePath(),
                            pathBase.getAbsolutePath(),
                            filename));
                    player = null;
                    status.set(Status.ERROR);
                }
            } catch(NSErrorException error) {
                LOG.log(Level.SEVERE, "Audio Setup Failed: " + error.toString(), error);
                status.set(Status.ERROR);
            }
        }
    
        @Override
        public void play() throws NativeServiceException {
            if(player == null) return;
    
            player.play();
            status.set(Status.PLAY);
        }
    
        @Override
        public void pause() throws NativeServiceException {
            if(player == null) return;
    
            player.pause();
            status.set(Status.PAUSE);
        }
    
        @Override
        public void resume() throws NativeServiceException {
            if(player == null) return;
    
            player.play();
            status.set(Status.PLAY);
        }
    
        @Override
        public void stop() throws NativeServiceException {
            if(player == null) return;
    
            player.stop();
            player.setCurrentTime(0.0);
            status.set(Status.STOP);
        }
    
        @Override
        public ReadOnlyObjectProperty<Status> statusProperty() {
            return status.getReadOnlyProperty();
        }
    
        @Override
        public Status getStatus() {
            return status.get();
        }
    }
    
    0 讨论(0)
  • 2020-11-28 00:07

    If you have a look at the GoNative sample here (docs and code), you'll find a way to add Android native code to your JavaFX project.

    This is a simple example of adding android.media.MediaPlayer to a JavaFX project using the Gluon plugin.

    Based on a Single View project, let's add first an interface with the required audio method signatures:

    public interface NativeAudioService {
        void play();
        void pause();
        void resume();
        void stop();
    }
    

    Now in our View we can create the buttons to call those methods based on an instance of AndroidNativeAudio class that implements the NativeAudioService interface:

    public class BasicView extends View {
    
        private NativeAudioService service;
        private boolean pause;
    
        public BasicView(String name) {
            super(name);
    
            try {
                service = (NativeAudioService) Class.forName("com.gluonhq.nativeaudio.AndroidNativeAudio").newInstance();
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
                System.out.println("Error " + ex);
            }
    
            if (service != null) {
                final HBox hBox = new HBox(10, 
                        MaterialDesignIcon.PLAY_ARROW.button(e -> service.play()),
                        MaterialDesignIcon.PAUSE.button(e -> {
                            if (!pause) {
                                service.pause();
                                pause = true;
                            } else {
                                service.resume();
                                pause = false;
                            }
                        }),
                        MaterialDesignIcon.STOP.button(e -> service.stop()));
                hBox.setAlignment(Pos.CENTER);
                setCenter(new StackPane(hBox));
            } else {
                setCenter(new StackPane(new Label("Only for Android")));
            }
        }
    
        @Override
        protected void updateAppBar(AppBar appBar) {
            appBar.setNavIcon(MaterialDesignIcon.MUSIC_NOTE.button());
            appBar.setTitleText("Native Audio");
        }
    }
    

    Now, we create the native class under the Android folder. It will make use of the android API. It will try to find the audio file audio.mp3 that we have to place under the /src/android/assets folder:

    package com.gluonhq.nativeaudio;
    
    import android.content.res.AssetFileDescriptor;
    import android.media.AudioManager;
    import android.media.MediaPlayer;
    import java.io.IOException;
    import javafxports.android.FXActivity;
    
    public class AndroidNativeAudio implements NativeAudioService {
    
        private MediaPlayer mp;
        private int currentPosition;
    
        public AndroidNativeAudio() { }
    
        @Override
        public void play() {
            currentPosition = 0;
            try {
                if (mp != null) {
                    stop();
                }
                mp = new MediaPlayer();
                AssetFileDescriptor afd = FXActivity.getInstance().getAssets().openFd("audio.mp3");
    
                mp.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
                mp.setAudioStreamType(AudioManager.STREAM_RING);
                mp.setOnCompletionListener(mp -> stop());
                mp.prepare();
                mp.start();
            } catch (IOException e) {
                System.out.println("Error playing audio resource " + e);
            }
        }
    
        @Override
        public void stop() {
            if (mp != null) {
                if (mp.isPlaying()) {
                    mp.stop();
                }
                mp.release();
                mp = null;
            }
        }
    
        @Override
        public void pause() {
            if (mp != null) {
                mp.pause();
                currentPosition = mp.getCurrentPosition();
            }
        }
    
        @Override
        public void resume() {
            if (mp != null) {
                mp.start();
                mp.seekTo(currentPosition);
            }
        }
    }
    

    Finally, we can deploy the project to an Android device running gradlew androidInstall.

    0 讨论(0)
提交回复
热议问题