src/java.desktop/share/classes/com/sun/media/sound/JavaSoundAudioClip.java
changeset 54860 1372fbbde8dd
parent 52248 2e330da7cbf4
equal deleted inserted replaced
54859:360c0955b06b 54860:1372fbbde8dd
     1 /*
     1 /*
     2  * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.  Oracle designates this
     7  * published by the Free Software Foundation.  Oracle designates this
    58  * @author Florian Bomers
    58  * @author Florian Bomers
    59  */
    59  */
    60 @SuppressWarnings("deprecation")
    60 @SuppressWarnings("deprecation")
    61 public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, LineListener {
    61 public final class JavaSoundAudioClip implements AudioClip, MetaEventListener, LineListener {
    62 
    62 
    63     private static final boolean DEBUG = false;
       
    64     private static final int BUFFER_SIZE = 16384; // number of bytes written each time to the source data line
    63     private static final int BUFFER_SIZE = 16384; // number of bytes written each time to the source data line
    65 
    64 
    66     private long lastPlayCall = 0;
    65     private long lastPlayCall = 0;
    67     private static final int MINIMUM_PLAY_DELAY = 30;
    66     private static final int MINIMUM_PLAY_DELAY = 30;
    68 
    67 
   113         }
   112         }
   114         return clip;
   113         return clip;
   115     }
   114     }
   116 
   115 
   117     private void init(InputStream in) throws IOException {
   116     private void init(InputStream in) throws IOException {
   118         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.<init>");
       
   119 
       
   120         BufferedInputStream bis = new BufferedInputStream(in, STREAM_BUFFER_SIZE);
   117         BufferedInputStream bis = new BufferedInputStream(in, STREAM_BUFFER_SIZE);
   121         bis.mark(STREAM_BUFFER_SIZE);
   118         bis.mark(STREAM_BUFFER_SIZE);
   122         try {
   119         try {
   123             AudioInputStream as = AudioSystem.getAudioInputStream(bis);
   120             AudioInputStream as = AudioSystem.getAudioInputStream(bis);
   124             // load the stream data into memory
   121             // load the stream data into memory
   163     private synchronized void startImpl(boolean loop) {
   160     private synchronized void startImpl(boolean loop) {
   164         // hack for some applets that call the start method very rapidly...
   161         // hack for some applets that call the start method very rapidly...
   165         long currentTime = System.currentTimeMillis();
   162         long currentTime = System.currentTimeMillis();
   166         long diff = currentTime - lastPlayCall;
   163         long diff = currentTime - lastPlayCall;
   167         if (diff < MINIMUM_PLAY_DELAY) {
   164         if (diff < MINIMUM_PLAY_DELAY) {
   168             if (DEBUG || Printer.debug) Printer.debug("JavaSoundAudioClip.startImpl(loop="+loop+"): abort - too rapdly");
       
   169             return;
   165             return;
   170         }
   166         }
   171         lastPlayCall = currentTime;
   167         lastPlayCall = currentTime;
   172 
       
   173         if (DEBUG || Printer.debug) Printer.debug("JavaSoundAudioClip.startImpl(loop="+loop+")");
       
   174         try {
   168         try {
   175             if (clip != null) {
   169             if (clip != null) {
   176                 // We need to disable autoclosing mechanism otherwise the clip
   170                 // We need to disable autoclosing mechanism otherwise the clip
   177                 // can be closed after "!clip.isOpen()" check, because of
   171                 // can be closed after "!clip.isOpen()" check, because of
   178                 // previous inactivity.
   172                 // previous inactivity.
   198                 } finally {
   192                 } finally {
   199                     clip.setAutoClosing(true);
   193                     clip.setAutoClosing(true);
   200                 }
   194                 }
   201             } else if (datapusher != null ) {
   195             } else if (datapusher != null ) {
   202                 datapusher.start(loop);
   196                 datapusher.start(loop);
   203                 if (DEBUG || Printer.debug)Printer.debug("Stream should be playing/looping");
       
   204 
   197 
   205             } else if (sequencer != null) {
   198             } else if (sequencer != null) {
   206                 sequencerloop = loop;
   199                 sequencerloop = loop;
   207                 if (sequencer.isRunning()) {
   200                 if (sequencer.isRunning()) {
   208                     sequencer.setMicrosecondPosition(0);
   201                     sequencer.setMicrosecondPosition(0);
   211                     try {
   204                     try {
   212                         sequencer.open();
   205                         sequencer.open();
   213                         sequencer.setSequence(sequence);
   206                         sequencer.setSequence(sequence);
   214 
   207 
   215                     } catch (InvalidMidiDataException e1) {
   208                     } catch (InvalidMidiDataException e1) {
   216                         if (DEBUG || Printer.err)e1.printStackTrace();
   209                         if (Printer.err) e1.printStackTrace();
   217                     } catch (MidiUnavailableException e2) {
   210                     } catch (MidiUnavailableException e2) {
   218                         if (DEBUG || Printer.err)e2.printStackTrace();
   211                         if (Printer.err) e2.printStackTrace();
   219                     }
   212                     }
   220                 }
   213                 }
   221                 sequencer.addMetaEventListener(this);
   214                 sequencer.addMetaEventListener(this);
   222                 try {
   215                 try {
   223                     sequencer.start();
   216                     sequencer.start();
   224                 } catch (Exception e) {
   217                 } catch (Exception e) {
   225                     if (DEBUG || Printer.err) e.printStackTrace();
   218                     if (Printer.err) e.printStackTrace();
   226                 }
   219                 }
   227                 if (DEBUG || Printer.debug)Printer.debug("Sequencer should be playing/looping");
       
   228             }
   220             }
   229         } catch (Exception e) {
   221         } catch (Exception e) {
   230             if (DEBUG || Printer.err)e.printStackTrace();
   222             if (Printer.err) e.printStackTrace();
   231         }
   223         }
   232     }
   224     }
   233 
   225 
   234     @Override
   226     @Override
   235     public synchronized void stop() {
   227     public synchronized void stop() {
   236         if (!success) {
   228         if (!success) {
   237             return;
   229             return;
   238         }
   230         }
   239 
       
   240         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip->stop()");
       
   241         lastPlayCall = 0;
   231         lastPlayCall = 0;
   242 
   232 
   243         if (clip != null) {
   233         if (clip != null) {
   244             try {
   234             try {
   245                 if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.flush()");
       
   246                 clip.flush();
   235                 clip.flush();
   247             } catch (Exception e1) {
   236             } catch (Exception e1) {
   248                 if (Printer.err) e1.printStackTrace();
   237                 if (Printer.err) e1.printStackTrace();
   249             }
   238             }
   250             try {
   239             try {
   251                 if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip: clip.stop()");
       
   252                 clip.stop();
   240                 clip.stop();
   253             } catch (Exception e2) {
   241             } catch (Exception e2) {
   254                 if (Printer.err) e2.printStackTrace();
   242                 if (Printer.err) e2.printStackTrace();
   255             }
   243             }
   256             if (DEBUG || Printer.debug)Printer.debug("Clip should be stopped");
       
   257 
       
   258         } else if (datapusher != null) {
   244         } else if (datapusher != null) {
   259             datapusher.stop();
   245             datapusher.stop();
   260             if (DEBUG || Printer.debug)Printer.debug("Stream should be stopped");
       
   261 
       
   262         } else if (sequencer != null) {
   246         } else if (sequencer != null) {
   263             try {
   247             try {
   264                 sequencerloop = false;
   248                 sequencerloop = false;
   265                 sequencer.removeMetaEventListener(this);
   249                 sequencer.removeMetaEventListener(this);
   266                 sequencer.stop();
   250                 sequencer.stop();
   270             try {
   254             try {
   271                 sequencer.close();
   255                 sequencer.close();
   272             } catch (Exception e4) {
   256             } catch (Exception e4) {
   273                 if (Printer.err) e4.printStackTrace();
   257                 if (Printer.err) e4.printStackTrace();
   274             }
   258             }
   275             if (DEBUG || Printer.debug)Printer.debug("Sequencer should be stopped");
       
   276         }
   259         }
   277     }
   260     }
   278 
   261 
   279     // Event handlers (for debugging)
   262     // Event handlers (for debugging)
   280 
   263 
   281     @Override
   264     @Override
   282     public synchronized void update(LineEvent event) {
   265     public synchronized void update(LineEvent event) {
   283         if (DEBUG || Printer.debug) Printer.debug("line event received: "+event);
       
   284     }
   266     }
   285 
   267 
   286     // handle MIDI track end meta events for looping
   268     // handle MIDI track end meta events for looping
   287 
   269 
   288     @Override
   270     @Override
   289     public synchronized void meta(MetaMessage message) {
   271     public synchronized void meta(MetaMessage message) {
   290 
       
   291         if (DEBUG || Printer.debug)Printer.debug("META EVENT RECEIVED!!!!! ");
       
   292 
       
   293         if( message.getType() == 47 ) {
   272         if( message.getType() == 47 ) {
   294             if (sequencerloop){
   273             if (sequencerloop){
   295                 //notifyAll();
   274                 //notifyAll();
   296                 sequencer.setMicrosecondPosition(0);
   275                 sequencer.setMicrosecondPosition(0);
   297                 loop();
   276                 loop();
   308 
   287 
   309     @Override
   288     @Override
   310     protected void finalize() {
   289     protected void finalize() {
   311 
   290 
   312         if (clip != null) {
   291         if (clip != null) {
   313             if (DEBUG || Printer.trace)Printer.trace("JavaSoundAudioClip.finalize: clip.close()");
       
   314             clip.close();
   292             clip.close();
   315         }
   293         }
   316 
   294 
   317         //$$fb 2001-09-26: may improve situation related to bug #4302884
   295         //$$fb 2001-09-26: may improve situation related to bug #4302884
   318         if (datapusher != null) {
   296         if (datapusher != null) {
   325     }
   303     }
   326 
   304 
   327     // FILE LOADING METHODS
   305     // FILE LOADING METHODS
   328 
   306 
   329     private boolean loadAudioData(AudioInputStream as)  throws IOException, UnsupportedAudioFileException {
   307     private boolean loadAudioData(AudioInputStream as)  throws IOException, UnsupportedAudioFileException {
   330         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip->openAsClip()");
       
   331 
       
   332         // first possibly convert this stream to PCM
   308         // first possibly convert this stream to PCM
   333         as = Toolkit.getPCMConvertedAudioInputStream(as);
   309         as = Toolkit.getPCMConvertedAudioInputStream(as);
   334         if (as == null) {
   310         if (as == null) {
   335             return false;
   311             return false;
   336         }
   312         }
   402     }
   378     }
   403 
   379 
   404     // METHODS FOR CREATING THE DEVICE
   380     // METHODS FOR CREATING THE DEVICE
   405 
   381 
   406     private boolean createClip() {
   382     private boolean createClip() {
   407 
       
   408         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.createClip()");
       
   409 
       
   410         try {
   383         try {
   411             DataLine.Info info = new DataLine.Info(Clip.class, loadedAudioFormat);
   384             DataLine.Info info = new DataLine.Info(Clip.class, loadedAudioFormat);
   412             if (!(AudioSystem.isLineSupported(info)) ) {
   385             if (!(AudioSystem.isLineSupported(info)) ) {
   413                 if (DEBUG || Printer.err)Printer.err("Clip not supported: "+loadedAudioFormat);
   386                 if (Printer.err) Printer.err("Clip not supported: "+loadedAudioFormat);
   414                 // fail silently
   387                 // fail silently
   415                 return false;
   388                 return false;
   416             }
   389             }
   417             Object line = AudioSystem.getLine(info);
   390             Object line = AudioSystem.getLine(info);
   418             if (!(line instanceof AutoClosingClip)) {
   391             if (!(line instanceof AutoClosingClip)) {
   419                 if (DEBUG || Printer.err)Printer.err("Clip is not auto closing!"+clip);
   392                 if (Printer.err) Printer.err("Clip is not auto closing!"+clip);
   420                 // fail -> will try with SourceDataLine
   393                 // fail -> will try with SourceDataLine
   421                 return false;
   394                 return false;
   422             }
   395             }
   423             clip = (AutoClosingClip) line;
   396             clip = (AutoClosingClip) line;
   424             clip.setAutoClosing(true);
   397             clip.setAutoClosing(true);
   425             if (DEBUG || Printer.debug) clip.addLineListener(this);
       
   426         } catch (Exception e) {
   398         } catch (Exception e) {
   427             if (DEBUG || Printer.err)e.printStackTrace();
   399             if (Printer.err) e.printStackTrace();
   428             // fail silently
   400             // fail silently
   429             return false;
   401             return false;
   430         }
   402         }
   431 
   403 
   432         if (clip==null) {
   404         if (clip==null) {
   433             // fail silently
   405             // fail silently
   434             return false;
   406             return false;
   435         }
   407         }
   436 
       
   437         if (DEBUG || Printer.debug)Printer.debug("Loaded clip.");
       
   438         return true;
   408         return true;
   439     }
   409     }
   440 
   410 
   441     private boolean createSourceDataLine() {
   411     private boolean createSourceDataLine() {
   442         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.createSourceDataLine()");
       
   443         try {
   412         try {
   444             DataLine.Info info = new DataLine.Info(SourceDataLine.class, loadedAudioFormat);
   413             DataLine.Info info = new DataLine.Info(SourceDataLine.class, loadedAudioFormat);
   445             if (!(AudioSystem.isLineSupported(info)) ) {
   414             if (!(AudioSystem.isLineSupported(info)) ) {
   446                 if (DEBUG || Printer.err)Printer.err("Line not supported: "+loadedAudioFormat);
   415                 if (Printer.err) Printer.err("Line not supported: "+loadedAudioFormat);
   447                 // fail silently
   416                 // fail silently
   448                 return false;
   417                 return false;
   449             }
   418             }
   450             SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info);
   419             SourceDataLine source = (SourceDataLine) AudioSystem.getLine(info);
   451             datapusher = new DataPusher(source, loadedAudioFormat, loadedAudio, loadedAudioByteLength);
   420             datapusher = new DataPusher(source, loadedAudioFormat, loadedAudio, loadedAudioByteLength);
   452         } catch (Exception e) {
   421         } catch (Exception e) {
   453             if (DEBUG || Printer.err)e.printStackTrace();
   422             if (Printer.err) e.printStackTrace();
   454             // fail silently
   423             // fail silently
   455             return false;
   424             return false;
   456         }
   425         }
   457 
   426 
   458         if (datapusher==null) {
   427         if (datapusher==null) {
   459             // fail silently
   428             // fail silently
   460             return false;
   429             return false;
   461         }
   430         }
   462 
       
   463         if (DEBUG || Printer.debug)Printer.debug("Created SourceDataLine.");
       
   464         return true;
   431         return true;
   465     }
   432     }
   466 
   433 
   467     private boolean createSequencer(BufferedInputStream in) throws IOException {
   434     private boolean createSequencer(BufferedInputStream in) throws IOException {
   468 
       
   469         if (DEBUG || Printer.debug)Printer.debug("JavaSoundAudioClip.createSequencer()");
       
   470 
       
   471         // get the sequencer
   435         // get the sequencer
   472         try {
   436         try {
   473             sequencer = MidiSystem.getSequencer( );
   437             sequencer = MidiSystem.getSequencer( );
   474         } catch(MidiUnavailableException me) {
   438         } catch(MidiUnavailableException me) {
   475             if (DEBUG || Printer.err)me.printStackTrace();
   439             if (Printer.err) me.printStackTrace();
   476             return false;
   440             return false;
   477         }
   441         }
   478         if (sequencer==null) {
   442         if (sequencer==null) {
   479             return false;
   443             return false;
   480         }
   444         }
   483             sequence = MidiSystem.getSequence(in);
   447             sequence = MidiSystem.getSequence(in);
   484             if (sequence == null) {
   448             if (sequence == null) {
   485                 return false;
   449                 return false;
   486             }
   450             }
   487         } catch (InvalidMidiDataException e) {
   451         } catch (InvalidMidiDataException e) {
   488             if (DEBUG || Printer.err)e.printStackTrace();
   452             if (Printer.err) e.printStackTrace();
   489             return false;
   453             return false;
   490         }
   454         }
   491 
       
   492         if (DEBUG || Printer.debug)Printer.debug("Created Sequencer.");
       
   493         return true;
   455         return true;
   494     }
   456     }
   495 
   457 
   496     /*
   458     /*
   497      * private inner class representing a ByteArrayOutputStream
   459      * private inner class representing a ByteArrayOutputStream