Skip to Main Content

Java SE (Java Platform, Standard Edition)

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Clicking noise when streaming sound to SourceDataLine

843802Jun 17 2008 — edited Aug 24 2008
Hello,
I'm trying to stream sound to the PC's speakers using SourceDataLine, but I have trouble getting rid of a clicking noise.
It seems to occur when sourceDataLine.available() equals sourceDataLine.getBufferSize(). Is there a way to avoid this?
I am dealing with an audio of indeterminate length. Here's the test code:
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

public class PlaybackLoop implements LineListener {
   SourceDataLine sourceDataLine;

   AudioFormat format;
   public PlaybackLoop() throws LineUnavailableException {
      AudioFormat.Encoding
          encoding = AudioFormat.Encoding.PCM_SIGNED;
      int sampleRate = 8000; // samples per sec
      int sampleSizeInBits = 16; // bits per sample
      int channels = 1;
      int frameSize = 2;  // bytes per frame
      int frameRate = 8000; // frames per sec
      // size of 1 sample * # of channels = size of 1 frame
      boolean bigEndian = true;
      format = new AudioFormat(
            encoding,
            sampleRate,
            sampleSizeInBits,
            channels,
            frameSize,
            frameRate,
            bigEndian);
      // PCM_SIGNED 8000.0 Hz, 16 bit, mono, 2 bytes/frame, big-endian

      DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
      sourceDataLine = (SourceDataLine) AudioSystem.getLine(info);
   }
   
   public synchronized void play() throws LineUnavailableException, 
                                          InterruptedException {
      int bytesPerSec = (int) format.getFrameRate() * format.getFrameSize();
      int intervalMs = 200;
      int loop = 50;
      int bytesSize = bytesPerSec * intervalMs / 1000;
      byte[] bytes = new byte[bytesSize];
      // creates a high pitched sound
      for (int i = 0; i < bytesSize / 2; i++) {
         if (i % 2 == 0) {
            writeFrame(bytes, i, 0x05dc);
         } else {
            writeFrame(bytes, i, 0x059c);
         }
      }
      sourceDataLine.open(format, 16000);
      sourceDataLine.addLineListener(this);
      
      int bufferSize = sourceDataLine.getBufferSize();
      System.out.println(format.toString());
      System.out.println(bufferSize + " bytes of line buffer.");
      long nextTime = System.currentTimeMillis() + intervalMs;
      sourceDataLine.start();
      for (int i = 0; i < loop; i ++) {
         
         int available = sourceDataLine.available();
         if (available == bufferSize) {
            // clicking noise occurs here
            System.out.println("*");
         }
         int w = sourceDataLine.write(bytes, 0, bytesSize);
         long currentTime = System.currentTimeMillis();
         if (w != bytesSize) {
            System.out.println("Not all written.");
            // TODO
         }
         // time adjustment , to prevent accumulated delay.
         long delta = (nextTime - currentTime);
         long wait = intervalMs + delta;
         if (0 < wait) {
            this.wait(wait);
            nextTime += intervalMs;
         } else {
            nextTime = currentTime + intervalMs;
         }
      }
      System.out.println();
      System.out.println("End play()");

   }

   public static void main(String[] args) throws LineUnavailableException, 
                                                 InterruptedException {
      new PlaybackLoop().play();
   }

   public static void writeFrame(byte[] bytes, int halfwordOffset, int value) {
      writeFrame(bytes, 0, halfwordOffset, value);
   }

   public static void writeFrame(byte[] bytes, int byteOffset,
                                 int halfwordOffset, int value) {
      byteOffset += 2 * halfwordOffset;
      bytes[byteOffset++] = (byte) (value >> 8);
      bytes[byteOffset++] = (byte) (value >> 0);
   }

   public void update(LineEvent event) {
      System.out.println();
      System.out.print("Update:");
      System.out.println(event.getType().toString());
   }
}
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Sep 21 2008
Added on Jun 17 2008
3 comments
638 views