JavaFxMediaPlayer.java

  1. /*
  2.  * *********************************************************************************************************************
  3.  *
  4.  * blueMarine II: Semantic Media Centre
  5.  * http://tidalwave.it/projects/bluemarine2
  6.  *
  7.  * Copyright (C) 2015 - 2021 by Tidalwave s.a.s. (http://tidalwave.it)
  8.  *
  9.  * *********************************************************************************************************************
  10.  *
  11.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  12.  * the License. You may obtain a copy of the License at
  13.  *
  14.  *     http://www.apache.org/licenses/LICENSE-2.0
  15.  *
  16.  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  17.  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
  18.  * specific language governing permissions and limitations under the License.
  19.  *
  20.  * *********************************************************************************************************************
  21.  *
  22.  * git clone https://bitbucket.org/tidalwave/bluemarine2-src
  23.  * git clone https://github.com/tidalwave-it/bluemarine2-src
  24.  *
  25.  * *********************************************************************************************************************
  26.  */
  27. package it.tidalwave.bluemarine2.ui.audio.renderer.impl.javafx;

  28. import javax.annotation.Nullable;
  29. import javax.annotation.Nonnull;
  30. import javax.inject.Inject;
  31. import java.time.Duration;
  32. import java.nio.file.Path;
  33. import javafx.beans.value.ObservableValue;
  34. import javafx.scene.media.Media;
  35. import it.tidalwave.bluemarine2.model.MediaFileSystem;
  36. import it.tidalwave.bluemarine2.model.MediaItem;
  37. import it.tidalwave.bluemarine2.ui.audio.renderer.spi.MediaPlayerSupport;
  38. import lombok.extern.slf4j.Slf4j;

  39. /***********************************************************************************************************************
  40.  *
  41.  * @author  Fabrizio Giudici
  42.  *
  43.  **********************************************************************************************************************/
  44. @Slf4j
  45. public class JavaFxMediaPlayer extends MediaPlayerSupport
  46.   {
  47.     private static final javafx.util.Duration SKIP_DURATION = javafx.util.Duration.seconds(1);

  48.     @Nullable
  49.     private Media media;

  50.     @Nullable
  51.     private javafx.scene.media.MediaPlayer mediaPlayer;

  52.     @Inject
  53.     private MediaFileSystem fileSystem;

  54.     /*******************************************************************************************************************
  55.      *
  56.      *
  57.      *
  58.      ******************************************************************************************************************/
  59.     private final Runnable cleanup = () ->
  60.       {
  61.         log.debug(">>>> media reproduction finished");
  62.         // FIXME: remove listener from currentTimeProperty
  63.         mediaPlayer = null;
  64.         statusProperty.setValue(Status.STOPPED);
  65.       };

  66.     /*******************************************************************************************************************
  67.      *
  68.      * {@inheritDoc}
  69.      *
  70.      ******************************************************************************************************************/
  71.     @Override
  72.     public void setMediaItem (@Nonnull final MediaItem mediaItem)
  73.       throws Exception
  74.       {
  75.         log.info("setMediaItem({})", mediaItem);
  76.         checkNotPlaying();
  77.         this.mediaItem = mediaItem;
  78.         final Path path = fileSystem.getRootPath().resolve(mediaItem.getPath()).toAbsolutePath();
  79.         log.debug("path:     {}", path);
  80.         log.debug("metadata: {}", mediaItem.getMetadata());
  81.         media = new Media(path.toUri().toString());
  82.         statusProperty.set(Status.STOPPED);
  83.         playTimeProperty.set(Duration.ZERO);
  84.       }

  85.     /*******************************************************************************************************************
  86.      *
  87.      * {@inheritDoc}
  88.      *
  89.      ******************************************************************************************************************/
  90.     @Override
  91.     public synchronized void play()
  92.       throws Exception
  93.       {
  94.         log.info("play()");
  95.         checkNotPlaying();

  96.         if ((mediaPlayer != null) && mediaPlayer.getStatus().equals(javafx.scene.media.MediaPlayer.Status.PAUSED))
  97.           {
  98.             mediaPlayer.play();
  99.           }
  100.         else
  101.           {
  102.             if (mediaPlayer != null)
  103.               {
  104.                 mediaPlayer.dispose();
  105.               }

  106.             mediaPlayer = new javafx.scene.media.MediaPlayer(media);
  107.             // FIXME: bidirectional bind to an expression?
  108.             mediaPlayer.currentTimeProperty().addListener(
  109.                     (ObservableValue<? extends javafx.util.Duration> observable,
  110.                     javafx.util.Duration oldValue,
  111.                     javafx.util.Duration newValue) ->
  112.                             playTimeProperty.setValue(Duration.ofMillis((long)newValue.toMillis())));

  113.             mediaPlayer.play();
  114.             mediaPlayer.setOnEndOfMedia(cleanup);
  115.             mediaPlayer.setOnError(cleanup);
  116.             mediaPlayer.setOnHalted(cleanup);
  117.           }

  118.         statusProperty.setValue(Status.PLAYING);
  119.       }

  120.     /*******************************************************************************************************************
  121.      *
  122.      * {@inheritDoc}
  123.      *
  124.      ******************************************************************************************************************/
  125.     @Override
  126.     public void stop()
  127.       {
  128.         log.info("stop()");

  129.         if (mediaPlayer != null)
  130.           {
  131.             mediaPlayer.stop();
  132.             statusProperty.setValue(Status.STOPPED);
  133.           }
  134.       }

  135.     /*******************************************************************************************************************
  136.      *
  137.      * {@inheritDoc}
  138.      *
  139.      ******************************************************************************************************************/
  140.     @Override
  141.     public void pause()
  142.       {
  143.         log.info("pause()");

  144.         if (mediaPlayer != null)
  145.           {
  146.             mediaPlayer.pause();
  147.             statusProperty.setValue(Status.PAUSED);
  148.           }
  149.       }

  150.     /*******************************************************************************************************************
  151.      *
  152.      * {@inheritDoc}
  153.      *
  154.      ******************************************************************************************************************/
  155.     @Override
  156.     public void rewind()
  157.       {
  158.         log.info("rewind()");

  159.         if (mediaPlayer != null)
  160.           {
  161.             mediaPlayer.seek(mediaPlayer.getCurrentTime().subtract(SKIP_DURATION));
  162.           }
  163.       }

  164.     /*******************************************************************************************************************
  165.      *
  166.      * {@inheritDoc}
  167.      *
  168.      ******************************************************************************************************************/
  169.     @Override
  170.     public void fastForward()
  171.       {
  172.         log.info("fastForward()");

  173.         if (mediaPlayer != null)
  174.           {
  175.             mediaPlayer.seek(mediaPlayer.getCurrentTime().add(SKIP_DURATION));
  176.           }
  177.       }

  178.     /*******************************************************************************************************************
  179.      *
  180.      *
  181.      *
  182.      ******************************************************************************************************************/
  183.     private void checkNotPlaying()
  184.       throws Exception
  185.       {
  186.         if ((mediaPlayer != null) && mediaPlayer.getStatus().equals(javafx.scene.media.MediaPlayer.Status.PLAYING))
  187.           {
  188.             throw new Exception("Already playing");
  189.           }
  190.       }
  191.   }