Advertisement
arthurassuncao

JLayerPlayerPausable

Jul 21st, 2012
1,078
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 9.29 KB | None | 0 0
  1. /* *-----------------------------------------------------------------------
  2.  *   This program is free software; you can redistribute it and/or modify
  3.  *   it under the terms of the GNU Library General Public License as published
  4.  *   by the Free Software Foundation; either version 2 of the License, or
  5.  *   (at your option) any later version.
  6.  *
  7.  *   This program is distributed in the hope that it will be useful,
  8.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  9.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10.  *   GNU Library General Public License for more details.
  11.  *
  12.  *   You should have received a copy of the GNU Library General Public
  13.  *   License along with this program; if not, write to the Free Software
  14.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  15.  *  
  16.  *   Original by: http://thiscouldbebetter.wordpress.com/2011/07/04/pausing-an-mp3-file-using-jlayer/
  17.  *   Last modified: 21-jul-2012 by Arthur Assuncao
  18.  *----------------------------------------------------------------------
  19.  */
  20.  
  21. import java.io.FileInputStream;
  22. import java.io.IOException;
  23. import java.io.InputStream;
  24. import java.net.URL;
  25.  
  26. import javazoom.jl.decoder.Bitstream;
  27. import javazoom.jl.decoder.Decoder;
  28. import javazoom.jl.decoder.Header;
  29. import javazoom.jl.decoder.JavaLayerException;
  30. import javazoom.jl.decoder.SampleBuffer;
  31. import javazoom.jl.player.AudioDevice;
  32. import javazoom.jl.player.FactoryRegistry;
  33.  
  34. //use with JLayerPausableTest
  35. public class JLayerPlayerPausable{
  36.     // This class is loosely based on javazoom.jl.player.AdvancedPlayer.
  37.  
  38.     private java.net.URL urlToStreamFrom;
  39.     private String audioPath;
  40.     private Bitstream bitstream;
  41.     private Decoder decoder;
  42.     private AudioDevice audioDevice;
  43.     private boolean closed;
  44.     private boolean complete;
  45.     private boolean paused;
  46.     private boolean stopped;
  47.     private PlaybackListener listener;
  48.     private int frameIndexCurrent;
  49.     private final int lostFrames = 20; //some fraction of a second of the sound gets "lost" after every pause. 52 in original code
  50.  
  51.     public JLayerPlayerPausable(URL urlToStreamFrom) throws JavaLayerException{
  52.         this.urlToStreamFrom = urlToStreamFrom;
  53.         this.listener = new PlaybackAdapter();
  54.     }
  55.     public JLayerPlayerPausable(String audioPath) throws JavaLayerException{
  56.         this.audioPath = audioPath;
  57.         this.listener = new PlaybackAdapter();
  58.     }
  59.    
  60.     public void setPlaybackListener(PlaybackListener newPlaybackListener){
  61.         if(newPlaybackListener != null){
  62.             this.listener = newPlaybackListener;
  63.         }
  64.         else{
  65.             throw new NullPointerException("PlaybackListener is null");
  66.         }
  67.     }
  68.  
  69.     private InputStream getAudioInputStream() throws IOException{
  70.         if(this.audioPath != null){
  71.             return new FileInputStream(this.audioPath);
  72.         }
  73.         else if(this.urlToStreamFrom != null){
  74.             this.urlToStreamFrom.openStream();
  75.         }
  76.         return null;
  77.     }
  78.  
  79.     public boolean play() throws JavaLayerException{
  80.         return this.play(0);
  81.     }
  82.  
  83.     public boolean play(int frameIndexStart) throws JavaLayerException {
  84.         //return this.play(frameIndexStart, -1, 52); //original, mas voltava num ponto anterior ao do pause. 52 Sao os frames perdidos ao dar pause
  85.         return this.play(frameIndexStart, -1, lostFrames);
  86.     }
  87.  
  88.     public boolean play(int frameIndexStart, int frameIndexFinal, int correctionFactorInFrames) throws JavaLayerException{
  89.         try {
  90.             this.bitstream = new Bitstream(this.getAudioInputStream());
  91.         }
  92.         catch (IOException e) {
  93.             e.printStackTrace();
  94.         }
  95.  
  96.         this.audioDevice = FactoryRegistry.systemRegistry().createAudioDevice();
  97.         this.decoder = new Decoder();
  98.         this.audioDevice.open(this.decoder);
  99.  
  100.         boolean shouldContinueReadingFrames = true;
  101.  
  102.         this.paused = false;
  103.         this.stopped = false;
  104.         this.frameIndexCurrent = 0;
  105.  
  106.         while (shouldContinueReadingFrames == true && this.frameIndexCurrent < frameIndexStart - correctionFactorInFrames){
  107.             shouldContinueReadingFrames = this.skipFrame();
  108.             this.frameIndexCurrent++;
  109.         }
  110.  
  111.         if (this.listener != null) {
  112.             this.listener.playbackStarted(new PlaybackEvent(this, PlaybackEvent.EventType.Instances.Started, this.audioDevice.getPosition()));
  113.         }
  114.  
  115.         if (frameIndexFinal < 0){
  116.             frameIndexFinal = Integer.MAX_VALUE;
  117.         }
  118.  
  119.         while (shouldContinueReadingFrames == true && this.frameIndexCurrent < frameIndexFinal){
  120.             if (this.paused || this.stopped){
  121.                 shouldContinueReadingFrames = false;    
  122.                 try{
  123.                     Thread.sleep(1);
  124.                 }
  125.                 catch (Exception ex){
  126.                     ex.printStackTrace();
  127.                 }
  128.             }
  129.             else{
  130.                 shouldContinueReadingFrames = this.decodeFrame();
  131.                 this.frameIndexCurrent++;
  132.             }
  133.         }
  134.  
  135.         // last frame, ensure all data flushed to the audio device.
  136.         if (this.audioDevice != null && !this.paused){
  137.             this.audioDevice.flush();
  138.  
  139.             synchronized (this){
  140.                 this.complete = (this.closed == false);
  141.                 this.close();
  142.             }
  143.  
  144.             // report to listener
  145.             if (this.listener != null) {
  146.                 int audioDevicePosition = -1;
  147.                 if(this.audioDevice != null){
  148.                     audioDevicePosition = this.audioDevice.getPosition();
  149.                 }
  150.                 else{
  151.                     //throw new NullPointerException("attribute audioDevice in " + this.getClass() + " is NULL");
  152.                 }
  153.                 PlaybackEvent playbackEvent = new PlaybackEvent(this, PlaybackEvent.EventType.Instances.Stopped, audioDevicePosition);
  154.                 this.listener.playbackFinished(playbackEvent);
  155.             }
  156.         }
  157.  
  158.         return shouldContinueReadingFrames;
  159.     }
  160.  
  161.     public boolean resume() throws JavaLayerException{
  162.         return this.play(this.frameIndexCurrent);
  163.     }
  164.  
  165.     public synchronized void close(){
  166.         if (this.audioDevice != null){
  167.             this.closed = true;
  168.  
  169.             this.audioDevice.close();
  170.  
  171.             this.audioDevice = null;
  172.  
  173.             try{
  174.                 this.bitstream.close();
  175.             }
  176.             catch (Exception ex){
  177.                 ex.printStackTrace();
  178.             }
  179.         }
  180.     }
  181.  
  182.     protected boolean decodeFrame() throws JavaLayerException{
  183.         boolean returnValue = false;
  184.         if(this.stopped){ //nothing for decode
  185.             return false;
  186.         }
  187.  
  188.         try{
  189.             if (this.audioDevice != null){
  190.                 Header header = this.bitstream.readFrame();
  191.                 if (header != null){
  192.                     // sample buffer set when decoder constructed
  193.                     SampleBuffer output = (SampleBuffer) this.decoder.decodeFrame(header, this.bitstream);
  194.  
  195.                     synchronized (this){
  196.                         if (this.audioDevice != null){
  197.                             this.audioDevice.write(output.getBuffer(), 0, output.getBufferLength());
  198.                         }
  199.                     }
  200.  
  201.                     this.bitstream.closeFrame();
  202.                     returnValue = true;
  203.                 }
  204.                 else{
  205.                     System.out.println("End of file"); //end of file
  206.                     //this.stop();
  207.                     returnValue = false;
  208.                 }
  209.             }
  210.         }
  211.         catch (RuntimeException ex){
  212.             throw new JavaLayerException("Exception decoding audio frame", ex);
  213.         }
  214.         return returnValue;
  215.     }
  216.  
  217.     public void pause(){
  218.         if(!this.stopped){
  219.             this.paused = true;
  220.             if (this.listener != null) {
  221.                 this.listener.playbackPaused(new PlaybackEvent(this, PlaybackEvent.EventType.Instances.Paused, this.audioDevice.getPosition()));
  222.             }
  223.             this.close();
  224.         }
  225.     }
  226.  
  227.     protected boolean skipFrame() throws JavaLayerException{
  228.         boolean returnValue = false;
  229.         Header header = this.bitstream.readFrame();
  230.  
  231.         if (header != null) {
  232.             this.bitstream.closeFrame();
  233.             returnValue = true;
  234.         }
  235.  
  236.         return returnValue;
  237.     }
  238.  
  239.     public void stop(){
  240.         if(!this.stopped){
  241.             if(!this.closed){
  242.                 this.listener.playbackFinished(new PlaybackEvent(this, PlaybackEvent.EventType.Instances.Stopped, this.audioDevice.getPosition()));
  243.                 this.close();
  244.             }
  245.             else if(this.paused){
  246.                 int audioDevicePosition = -1; //this.audioDevice.getPosition(), audioDevice is null
  247.                 this.listener.playbackFinished(new PlaybackEvent(this, PlaybackEvent.EventType.Instances.Stopped, audioDevicePosition));
  248.             }
  249.             this.stopped = true;
  250.         }
  251.     }
  252.  
  253.     /**
  254.      * @return the closed
  255.      */
  256.     public boolean isClosed() {
  257.         return closed;
  258.     }
  259.     /**
  260.      * @return the complete
  261.      */
  262.     public boolean isComplete() {
  263.         return complete;
  264.     }
  265.     /**
  266.      * @return the paused
  267.      */
  268.     public boolean isPaused() {
  269.         return paused;
  270.     }
  271.  
  272.     /**
  273.      * @return the stopped
  274.      */
  275.     public boolean isStopped() {
  276.         return stopped;
  277.     }
  278.  
  279.  
  280.     // inner classes
  281.     public static class PlaybackEvent{    
  282.         public JLayerPlayerPausable source;
  283.         public EventType eventType;
  284.         public int frameIndex;
  285.  
  286.         public PlaybackEvent(JLayerPlayerPausable source, EventType eventType, int frameIndex)        {
  287.             this.source = source;
  288.             this.eventType = eventType;
  289.             this.frameIndex = frameIndex;
  290.         }
  291.  
  292.         public static class EventType{
  293.             public String name;
  294.  
  295.             public EventType(String name){
  296.                 this.name = name;
  297.             }
  298.  
  299.             public static class Instances{
  300.                 public static EventType Started = new EventType("Started");
  301.                 public static EventType Paused = new EventType("Paused");
  302.                 public static EventType Stopped = new EventType("Stopped");
  303.             }
  304.         }
  305.     }
  306.  
  307.     public static class PlaybackAdapter implements PlaybackListener{
  308.         @Override
  309.         public void playbackStarted(PlaybackEvent event){
  310.             System.err.println("Playback started");
  311.         }
  312.         @Override
  313.         public void playbackPaused(PlaybackEvent event){
  314.             System.err.println("Playback paused");
  315.         }
  316.         @Override
  317.         public void playbackFinished(PlaybackEvent event){
  318.             System.err.println("Playback stopped");
  319.         }
  320.     }
  321.    
  322.     public static interface PlaybackListener{
  323.         public void playbackStarted(PlaybackEvent event);
  324.         public void playbackPaused(PlaybackEvent event);
  325.         public void playbackFinished(PlaybackEvent event);
  326.     }
  327. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement