RaspberryPi JavaFX + Sound

Post to Twitter

Media support is not included in the current JDK8 preview. If you want to play audio files, it's maybe a problem if you think that it's not possible :)

Don't use JavaFX for the job. Simply use Java Sound API. We successfully used it for our tests with Beagleboard-xm and RaspberryPi (jdk7, jdk8 javafx preview).

Here's the source code of our, old but still good, implementation:

/*
 * Copyright 2012 SIB Visions GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 *
 *
 * History
 *
 * 15.12.2005 - [JR] - creation
 */

package com.sibvisions.apps.util;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.Vector;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

import com.sibvisions.util.type.FileUtil;

/**
 * The <code>AudioPlayer</code> plays audio files. Currently only wav, au and midi files are supported.
 *
 * @author René Jahn
 */

public final class AudioPlayer
{
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Class members
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  /** thread list for background playback. */
  private static Vector<Thread> vThreads = null;
 
  /** list of dataline connections for playback. */
  private static Vector<SourceDataLine> vSdl = new Vector<SourceDataLine>();
 
  /** Cached audio files. Reduces resource usage during repatedly playback. */
  private static Hashtable<String, byte[]> htAudioCache = new Hashtable<String, byte[]>();
 
  /** sync object. */
  private static final Object SYNC = new Object();
 
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  // Initialization
  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  /**
   * Invisible constructor because <code>AudioPlayer</code> is a utility
   * class.
   */

  private AudioPlayer()
  {
  }
 
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // User-defined methods
    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  /**
   * Gets the current player thread count.
   *
   * @return the number of player threads
   */

  public static int getPlayerThreads()
  {
    if (vThreads != null)
    {
      return vThreads.size();
    }
    else
    {
      return 0;
    }
  }
 
  /**
   * Playback an audio file.
   *
   * @param pFileName the filename
   * @param pBackground <code>true</code> to start playback as background process. The method call returns
   *                    immediately.
   */

  public static synchronized void play(final String pFileName, boolean pBackground)
  {
    AudioPlayer.play(new String[] {pFileName}, 0, pBackground);
  }

  /**
   * Playback multiple audio files.
   *
   * @param pFileName list of file names
   * @param pDelay delay between playback
   * @param pBackground <code>true</code> to start playback as background process. The method call returns
   *                    immediately.
   */

  public static synchronized void play(final String[] pFileName, final long pDelay, boolean pBackground)
  {
    Thread thPlay;
    Thread th;

   
    if (pBackground)
    {
      thPlay = new Thread()
      {
        public void run()
        {
          if (Thread.currentThread() == this)
          {
            if (pFileName != null)
            {
              for (int i = 0, anz = pFileName.length; i < anz; i++)
              {
                AudioPlayer.play(pFileName[i]);
               
                //Use defined delay between playback, but ignore delay after the last track
                if (pDelay > 0 && i + 1 < anz)
                {
                  try
                  {
                    Thread.sleep(pDelay);
                  }
                  catch (InterruptedException ie)
                  {
                    //nothing to be done
                  }
                }
              }
            }
          }
         
          vThreads.remove(this);
        }
      };
     
      if (vThreads == null)
      {
        vThreads = new Vector<Thread>();
      }
     
      //Clear zombies
      for (int i = 0; i < vThreads.size();)
      {
        th = (Thread)vThreads.get(i);
       
        if (!th.isAlive())
        {
          th.interrupt();
          vThreads.remove(i);
         
          th = null;
        }
        else
        {
          i++;
        }
      }
     
      vThreads.add(thPlay);
     
      thPlay.setPriority(Thread.MAX_PRIORITY);
      thPlay.start();
    }
    else
    {
      if (pFileName != null)
      {
        for (int i = 0, anz = pFileName.length; i < anz; i++)
        {
          AudioPlayer.play(pFileName[i]);
         
          //Use defined delay between playback, but ignore delay after the last track
          if (pDelay > 0 && i + 1 < anz)
          {
            try
            {
              Thread.sleep(pDelay);
            }
            catch (InterruptedException ie)
            {
              //nothing to be done
            }
          }
        }
      }
    }
  }
 
    /**
     * Playback a sound file.
     *
     * @param pFileName the filename
     */

    public static void play(String pFileName)
    {
    AudioInputStream ais = null;
 
    AudioFormat adf;
   
    DataLine.Info dli;
   
    SourceDataLine sdl;
   
    byte[] byData = new byte[128000];

    int iData;
   
   
    try
    {
      byte[] byCache = (byte[])htAudioCache.get(pFileName);
     
      if (byCache != null)
      {
        ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(byCache));
      }
      else
      {
        File fiDirect = new File(pFileName);
       
        //use byte array because most InputStreams do not support "seek"
        //we avoid Exceptions
        if (fiDirect.exists())
        {
          byCache = FileUtil.getContent(new FileInputStream(fiDirect));
        }
        else
        {
          byCache = FileUtil.getContent(AudioPlayer.class.getResourceAsStream(pFileName));
        }

        if (byCache != null)
        {
          cacheFile(pFileName, byCache);

          ais = AudioSystem.getAudioInputStream(new ByteArrayInputStream(byCache));
        }
        else
        {
          throw new IllegalArgumentException("No content found for : " + pFileName);
        }
      }
     
      byCache = null;
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return;
    }

    adf = ais.getFormat();
    dli = new DataLine.Info(SourceDataLine.class, adf);

    try
    {
      sdl = (SourceDataLine) AudioSystem.getLine(dli);
      sdl.open(adf);
     
      synchronized (SYNC)
      {
        vSdl.add(sdl);
      }
    }
    catch (Exception e)
    {
      e.printStackTrace();
      return;
    }

    sdl.start();

    try
    {
      while ((iData = ais.read(byData, 0, byData.length)) != -1)
      {
        sdl.write(byData, 0, iData);
      }
    }
    catch (IOException ioe)
    {
      ioe.printStackTrace();
    }

    sdl.drain();

    synchronized (SYNC)
    {
      sdl.flush();
      sdl.stop();
     
      sdl.close();
     
      vSdl.remove(sdl);
    }

    try
    {
      ais.close();
      ais = null;
    }
    catch (IOException ioe)
    {
      //nothing to be done
    }
   
    sdl = null;
    adf = null;
    }
 
    /**
     * Stop playback of all audio files.
     */

    public static void stopSound()
    {
      synchronized (SYNC)
      {
        if (vSdl != null)
        {
        //stop all playbacks
        for (SourceDataLine sdl : vSdl)
        {
          try
          {
            sdl.flush();
            sdl.stop();
         
            //Don't call this because it crashes the VM and results in a core dump
            //sdl.close();
          }
          catch (Exception e)
          {
            //nothing to be done
          }
        }
       
        vSdl.clear();
        }
      }
    }
   
    /**
     * Caches audio data for later use. If the file is already cached the cache won't
     * be overwritten.
     *
     * @param pFileName the filename
     * @param pData audio data
     */

    public static void cacheFile(String pFileName, byte[] pData)
    {
      cacheFile(pFileName, pData, false);
    }

    /**
     * Caches audio data for later use.
     *
     * @param pFileName the filename
     * @param pData audio data
     * @param bIgnoreCache <code>true</code> to overwrite already cached data, <code>false</code>
     *                     doesn't overwrite cached data
     */

    public static void cacheFile(String pFileName, byte[] pData, boolean bIgnoreCache)
    {
      if (!bIgnoreCache && htAudioCache.containsKey(pFileName))
      {
        return;
      }
     
      if (pFileName != null && pData != null)
      {
        htAudioCache.put(pFileName, pData);
      }
    }
   
    /**
     * Caches an audio file for later use. The file content will be read automatically.
     * If the file is already cached the cache won't be overwritten.
     *
     * @param pFileName the filename
     */

    public static void cacheFile(String pFileName)
    {
      cacheFile(pFileName, false);
    }

    /**
     * Caches an audio file for later use. The file content will be read automatically.
     *
     * @param sFileName Dateiname
     * @param bIgnoreCache true um bereits gecachte Daten zu überschreiben
     */

    public static void cacheFile(String sFileName, boolean bIgnoreCache)
    {
      //don't overwrite cache, if not specified
      if (!bIgnoreCache && htAudioCache.containsKey(sFileName))
      {
        return;
      }
     
      InputStream is = AudioPlayer.class.getResourceAsStream(sFileName);
     
      ByteArrayOutputStream bos = new ByteArrayOutputStream();

    byte[] byData = new byte[128000];
     
      int iData;
     
     
      try
      {
      while ((iData = is.read(byData, 0, byData.length)) != -1)
      {
        bos.write(byData, 0, iData);
      }
   
      htAudioCache.put(sFileName, bos.toByteArray());
     
      bos.close();
      is.close();
      }
      catch (IOException ioe)
      {
        //nothing to be done
      }
    }
   
} //AudioPlayer

Example wav file.

Leave a Reply

Spam protection by WP Captcha-Free