7 Replies Latest reply: Nov 18, 2010 1:59 PM by captfoss RSS

    Surprise! audioFormat changed

    805365
      Hello:

      I am playing with my app looking for bugs. I can build a stereo audioInputStream or mono. Until now I didn'r realize than if I hit the stop button when it is mono, it says:

      Exception in thread "Reproductor" java.lang.IllegalArgumentException: illegal request to write non-integral number of frames (2206 bytes, frameSize = 4 bytes)
      at com.sun.media.sound.DirectAudioDevice$DirectDL.write(DirectAudioDevice.java:711)
      at generador.Reproductor$VerdaderoReproductor.reproduccion(Reproductor.java:314)

      The number of bytes of my buffer is that(2206 bytes) but my audioInputStream is mono not "frameSize = 4 bytes" like the exception says .
      The internal buffer has this length:
      bufferLengthInBytes = 1103 * audioFormat.getFrameSize();
      Even if I a do write
      System.out.println(audioFormat);
      inside the playing loop I get:

      PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian all the time.

      If I click on the pause botton it stops without problem and I can continue playing without issues.
      If I hit stop, all of these happens:
      line.stop();
      line.flush();
      line.close();
      that never threw an exception in stereo.
      A trick is to double the buffer not to get the exception but I have no clue when/where is the audioFormat changing. I am getting the lines audioFormat also from the audioInputStream.

      Do you have a clue of what's happening?

      Thanks

      Edited by: 802362 on 01-nov-2010 11:07
        • 1. Re: Surprise! audioFormat changed
          captfoss
          First off, don't flush the line... stop it, close it. There's no need to flush it manually...

          Otherwise, I have no idea what the problem might be because you didn't really post any code to look over...
          • 2. Re: Surprise! audioFormat changed
            805365
            Ok, I don't flush the line anymore when stopping the line, thanks.

            I have found the source of the problem (but it doesn't mean that I know the cause):
                        int bufferLengthInBytes = 1103 * audioFormat.getFrameSize();
                        if (true) {
                            DataLine.Info info = new DataLine.Info(SourceDataLine.class,
                                    audioFormat);
                            try {
                                line = (SourceDataLine) AudioSystem.getLine(info);
                                line.open(audioFormat, bufferLengthInBytes * 8);
                            } catch (LineUnavailableException e) {
                                e.printStackTrace();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        } else {
                            Mixer.Info[] mixers = AudioSystem.getMixerInfo();
                            for (int i = 0; i < mixers.length; i++) {
                                Mixer.Info laInfo = mixers;
            line = Preferences.getSourceDataLine(audioFormat, laInfo);
            if (line != null) {
            break;
            }
            }
            try {
            line.open(audioFormat, bufferLengthInBytes);
            } catch (LineUnavailableException e) {
            e.printStackTrace();
            } catch (IllegalArgumentException e) {
            e.printStackTrace();
            } catch (IllegalStateException e) {
            e.printStackTrace();
            } catch (SecurityException e) {
            e.printStackTrace();
            }
            }
            byte[] abData = new byte[bufferLengthInBytes];
            line.start();
            synchronized (this) {
            while (true) {
            try {
            nBytesRead = ais.read(abData, 0, abData.length);
            } catch (IOException e) {
            e.printStackTrace();
            }
            if (nBytesRead != -1) {
            line.write(abData, 0, nBytesRead);
            } else {
            break;
            }
            while (pausa) {
            if (line.isRunning()) {
            line.stop();
            }
            try {
            wait();
            } catch (InterruptedException e) {
            e.printStackTrace();
            }
            }
            if (!line.isRunning()) {
            line.start();
            }

            }
            }

            line.drain();
            line.stop();
            line.close();
            The static method getSourceDataLine(audioFormat, laInfo) is:
            public static SourceDataLine getSourceDataLine(AudioFormat desiredFormat, Mixer.Info desiredMixer) {
            SourceDataLine sourceDataLine = null;
            for (Line.Info lineInfo : AudioSystem.getMixer(desiredMixer).getSourceLineInfo()) {
            if (lineInfo instanceof SourceDataLine.Info) {
            try {
            sourceDataLine = (SourceDataLine) AudioSystem.getMixer(desiredMixer).getLine(lineInfo);
            sourceDataLine.open(desiredFormat);
            sourceDataLine.close();
            } catch (Exception ex) {
            sourceDataLine = null;
            continue;
            }
            break;
            }
            }
            return sourceDataLine;
            }
            If a write "true", I don't have any problem. If I write (false) it fails if I choose a mono audioInputStream and stop the line. I got the code for the method getSourceDataLine in order to get lines in 24,32 bits or 96000kHz or 192000kHz. I read that if you ask for a line of these types to AudioSystem, it returns nothing. I read that you have to query for the mixers and then try to open a line with the desired format.
            
            So the code of this method works to get that line but does something weird about the frame size, but only when I stop the line.
            
            Thanks in advance.
            
            Edited by: 802362 on 02-nov-2010 14:32                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        
            • 3. Re: Surprise! audioFormat changed
              captfoss
              It's my understanding that a Mixer object may not know all of its capabilities unless it's opened... and you're not opening the mixer before you're querying it for info about its lines.
              public static SourceDataLine getSourceDataLine(AudioFormat desiredFormat, Mixer.Info desiredMixer) {
                      SourceDataLine sourceDataLine = null;
              
                      Mixer dMixer = AudioSystem.getMixer(desiredMixer);
                      dMixer.open();
              
                      for (Line.Info lineInfo : dMixer.getSourceLineInfo()) {
                          if (lineInfo instanceof SourceDataLine.Info) {
                              try {
                                  sourceDataLine = (SourceDataLine) dMixer.getLine(lineInfo);
                                  sourceDataLine.open(desiredFormat);
                                  sourceDataLine.close();
                              } catch (Exception ex) {
                                  sourceDataLine = null;
                                  continue;
                              }
                              break;
                          }
                      }
                      return sourceDataLine;
                  }
              • 4. Re: Surprise! audioFormat changed
                805365
                Thanks one more for your help. The problem isn't solved yet. If I play a stereo line and I hit the stop button it stop's the line, but with a mono audioInputStream I have tested in the while(true) loop with:
                 if (nBytesRead != -1) {
                
                                        try{
                                        line.write(abData, 0, nBytesRead);
                                        }
                                        catch(IllegalArgumentException iae){
                                            System.out.println("nBytesRead are:"+nBytesRead);
                                            System.out.println("format: "+audioFormat);
                                            iae.printStackTrace();
                                        }
                
                                    } else {
                                        break;
                                    }
                and it looks that it keeps streaming data to the line until nBytesRead it's -1. It gives the following exception each time the loop executes:
                nBytesRead are:2206
                        at generador.Reproductor$VerdaderoReproductor.run(Reproductor.java:360)
                format: PCM_SIGNED 44100.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian
                        at java.lang.Thread.run(Thread.java:619)
                java.lang.IllegalArgumentException: illegal request to write non-integral number of frames (2206 bytes, frameSize = 4 bytes)
                        at com.sun.media.sound.DirectAudioDevice$DirectDL.write(DirectAudioDevice.java:711)
                        at generador.Reproductor$VerdaderoReproductor.reproduccion(Reproductor.java:331)
                What I see it's that audioFormat is 2 bytes/frame for System.out.println but when it throws the exception it changes ¿?¿?. And why it doesn't stop?

                Thanks
                • 5. Re: Surprise! audioFormat changed
                  captfoss
                  Yeah, you probably also don't want to open and close a dataline in your static function. I believe that there's no guarantee it's the same setup the next time it's opened, and in some cases, it can't be opened....
                  • 6. Re: Surprise! audioFormat changed
                    805365
                    Thanks again:

                    I made the method non static taking it to the same class,commented out the closing of the sourceDataLine, if i get to open it...why closing it?(i don't open it again then). Since I want a fixed sized I pass the size to the method to get the line I need and opened:
                        public SourceDataLine getSourceDataLine2(AudioFormat desiredFormat, Mixer.Info desiredMixer,int buffer) {
                                SourceDataLine sourceDataLine = null;
                    
                                Mixer dMixer = AudioSystem.getMixer(desiredMixer);
                                try {
                                    dMixer.open();
                                } catch (LineUnavailableException lue) {
                                    lue.printStackTrace();
                                }
                                for (Line.Info lineInfo : dMixer.getSourceLineInfo()) {
                                    if (lineInfo instanceof SourceDataLine.Info) {
                                        try {
                                            sourceDataLine = (SourceDataLine) dMixer.getLine(lineInfo);
                                            sourceDataLine.open(desiredFormat,buffer);
                    //                        sourceDataLine.close();
                                        } catch (Exception ex) {
                                            ex.printStackTrace();
                                            sourceDataLine = null;
                                            continue;
                                        }
                                        break;
                                    }
                                }
                                return sourceDataLine;
                            }
                    but still throws the same exception when the size of the array buffer is an odd number multiplied by audioFormat.getFrameSize();

                    Anymore ideas? :(

                    Thanks.
                    • 7. Re: Surprise! audioFormat changed
                      captfoss
                      802362 wrote:
                      Anymore ideas? :(
                      No, I'm fresh out of ideas.

                      You could, always, just always write an extra 2 bytes so it won't throw stupid exceptions at you.

                      I imagine there's perhaps a bug in the JVM somewhere such that it automatically converts mono to stereo for writing to the speakers, but there's a bug in the boundary condition code?