Clip skips beginning 1sec of wav
I'm having an intermittent problem using javax.sound.sampled.Clip. I have a little player that plays wav files. It is used to play small prompt files that are typically 0.5 - 5sec in duration. When a wav file is opened and played I see the following (this is somewhat intermittent, but when it gets in this state it does it all the time):
- Click Play: The prompt plays from start to finish. The Clip is then automatically reset.
- Click Play again: The first ~1.4 sec of the prompt is skipped and then plays to completion.
For prompts less than a second, when it skips it usually just goes to the end and nothing is played
I've verified this with print statements. The following is output when it is skipping.
Clip starting
Clip position: 0 usec, isRunning: false
Clip started
Clip position: 0 usec, isRunning: false
Start time: 1098464438555 msec
Clip position: 1667500 usec, isRunning: true
Timer time: 1098464438665 msec
When the Clip is started, I also start a Timer that triggers every 100 milliseconds to update a slider component with the Clips position. When the Timer first triggers this Clip's position is at 1.67 sec and the system time only shows 110 ms have elapsed. I can't figure this out. My debugger shows that class com.sun.media.source.DirectAudioDevice$DirectClip is used. I can't find source for this so I'm even more in the dark.
Has anyone seen a similar problem using Clip? I'm debating whether or not to post this as a bug. 10 Dukes are up for grabs.
The code for my player follows:
import javax.sound.sampled.*;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.Vector;
publicclass VoicePromptPlayerextends JFrameimplements ActionListener, ChangeListener
{
Player player =new Player();
AudioInputStream audioInputStream;
JSlider slider =new JSlider();// Will count by milliseconds
JButton buttonPlayPause =new JButton();
JButton buttonStop =new JButton();
JButton buttonClose =new JButton();
JLabel lblPosition =new JLabel();
JLabel lblLength =new JLabel();
JLabel lblPositionSeconds =new JLabel();
JLabel lblLengthSeconds =new JLabel();
JLabel lblSecond1 =new JLabel();
JLabel lblSecond2 =new JLabel();
JPanel topPanel =new JPanel(new BorderLayout());
JPanel positionPanel =new JPanel();
JPanel lengthPanel =new JPanel();
JPanel centerPanel =new JPanel(new FlowLayout(FlowLayout.CENTER));
JPanel bottomPanel =new JPanel(new BorderLayout());
JPanel controlButtonPanel =new JPanel(new FlowLayout(FlowLayout.LEFT, 5, 5));
JPanel buttonPanel =new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 5));
int lengthInMilliseconds, seconds;
Vector lines =new Vector();
public VoicePromptPlayer()
{
super("Player");
this.getContentPane().setLayout(new BorderLayout());
setupTopPanel();
buttonPlayPause.setText("Play");
buttonPlayPause.setActionCommand("Play");
buttonPlayPause.addActionListener(this);
buttonPlayPause.setEnabled(false);
buttonPlayPause.setFocusPainted(false);
buttonStop.setText("Stop");
buttonStop.setActionCommand("Stop");
buttonStop.addActionListener(this);
buttonStop.setEnabled(false);
buttonStop.setFocusPainted(false);
buttonClose.setText("Close");
buttonClose.addActionListener(this);
centerPanel.add(slider);
buttonPanel.add(buttonClose);
controlButtonPanel.add(buttonPlayPause);
controlButtonPanel.add(buttonStop);
controlButtonPanel.add(buttonPanel);
bottomPanel.add(controlButtonPanel, BorderLayout.WEST);
bottomPanel.add(buttonPanel, BorderLayout.EAST);
this.getContentPane().add(topPanel, BorderLayout.NORTH);
this.getContentPane().add(centerPanel, BorderLayout.CENTER);
this.getContentPane().add(bottomPanel, BorderLayout.SOUTH);
createAudioInputStream();
lblPosition.setText("Position: ");
lblPositionSeconds.setText(formatMilliseconds(0));
lblLength.setText("Length: ");
lblLengthSeconds.setText(formatMilliseconds((long)lengthInMilliseconds));
lblSecond1.setText(" sec.");
lblSecond2.setText(" sec.");
slider.setMinimum(0);
slider.setMaximum(lengthInMilliseconds);
slider.setValue(0);
slider.setPaintTrack(true);
slider.setSnapToTicks(false);
slider.setFocusable(false);
slider.addChangeListener(this);
if (audioInputStream !=null)
{
buttonPlayPause.setEnabled(true);
//buttonPlayPause.doClick(); // start playing the audio
}
this.setResizable(false);
this.addWindowListener(new MyWindowAdapter());
this.pack();
this.setLocationRelativeTo(null);
}
privatevoid setupTopPanel()
{
GridBagLayout gbLayout =new GridBagLayout();
GridBagConstraints gbc =new GridBagConstraints();
positionPanel.setLayout(gbLayout);
gbc.weightx= 0.0;
gbc.weighty= 0.0;
gbc.gridheight= 1;
gbc.gridwidth= 1;
gbc.insets=new Insets(4, 4, 0, 0);
gbc.ipadx= 0;
gbc.ipady= 0;
gbc.gridx= 0;
gbc.gridy= 0;
gbc.fill = GridBagConstraints.NONE;
gbc.anchor= GridBagConstraints.WEST;
gbLayout.setConstraints(lblPosition, gbc);
positionPanel.add(lblPosition);
//gbc.weightx= 0.0;
//gbc.weighty= 0.0;
//gbc.gridheight= 1;
//gbc.gridwidth= 1;
gbc.insets=new Insets(4, 0, 0, 0);
//gbc.ipadx= 0;
//gbc.ipady= 0;
gbc.gridx= 1;
//gbc.gridy= 0;
//gbc.fill = GridBagConstraints.NONE;
//gbc.anchor= GridBagConstraints.WEST;
gbLayout.setConstraints(lblPositionSeconds, gbc);
positionPanel.add(lblPositionSeconds);
gbc.weightx= 1.0;
//gbc.weighty= 0.0;
//gbc.gridheight= 1;
//gbc.gridwidth= 1;
//gbc.insets= new Insets(0, 0, 0, 0);
//gbc.ipadx= 0;
//gbc.ipady= 0;
gbc.gridx= 2;
//gbc.gridy= 0;
//gbc.fill = GridBagConstraints.NONE;
//gbc.anchor= GridBagConstraints.WEST;
gbLayout.setConstraints(lblSecond1, gbc);
positionPanel.add(lblSecond1);
topPanel.add(positionPanel, BorderLayout.WEST);
gbLayout =new GridBagLayout();
//gbc = new GridBagConstraints();
lengthPanel.setLayout(gbLayout);
//gbc.weightx= 1.0;
//gbc.weighty= 0.0;
//gbc.gridheight= 1;
//gbc.gridwidth= 1;
//gbc.insets= new Insets(4, 0, 0, 0);
//gbc.ipadx= 0;
//gbc.ipady= 0;
gbc.gridx= 0;
//gbc.gridy= 0;
//gbc.fill = GridBagConstraints.NONE;
gbc.anchor= GridBagConstraints.EAST;
gbLayout.setConstraints(lblLength, gbc);
lengthPanel.add(lblLength);
gbc.weightx= 0.0;
//gbc.weighty= 0.0;
//gbc.gridheight= 1;
//gbc.gridwidth= 1;
//gbc.insets= new Insets(0, 0, 0, 0);
//gbc.ipadx= 0;
//gbc.ipady= 0;
gbc.gridx= 1;
//gbc.gridy= 0;
//gbc.fill = GridBagConstraints.NONE;
//gbc.anchor= GridBagConstraints.EAST;
gbLayout.setConstraints(lblLengthSeconds, gbc);
lengthPanel.add(lblLengthSeconds);
//gbc.weightx= 0.0;
//gbc.weighty= 0.0;
//gbc.gridheight= 1;
//gbc.gridwidth= 1;
gbc.insets=new Insets(4, 0, 0, 4);
//gbc.ipadx= 0;
//gbc.ipady= 0;
gbc.gridx= 2;
//gbc.gridy= 0;
//gbc.fill = GridBagConstraints.NONE;
//gbc.anchor= GridBagConstraints.EAST;
gbLayout.setConstraints(lblSecond2, gbc);
lengthPanel.add(lblSecond2);
topPanel.add(lengthPanel, BorderLayout.EAST);
}
publicstaticvoid main(String args[])
{
VoicePromptPlayer player =new VoicePromptPlayer();
player.setVisible(true);
}
public String toString()
{
return ("Player");
}
publicvoid actionPerformed(ActionEvent e)
{
Object obj = e.getSource();
if (obj.equals(buttonPlayPause))
{
if (buttonPlayPause.getActionCommand().equals("Play"))
{
// Need to start play or resume
if (player.isPaused())
player.resume();
else
player.play();
// Either way modify the button
setPauseButton();
buttonStop.setEnabled(true);
}
else
{
player.pause();
setPlayButton();
}
pack();
}
elseif (obj.equals(buttonStop))
{
player.stop();
buttonStop.setEnabled(false);
if (buttonPlayPause.getActionCommand().equals("Pause"))
setPlayButton();
}
elseif (obj.equals(buttonClose))
{
player.stop();
this.dispose();
}
}
publicvoid stateChanged(ChangeEvent e)
{
int microSeconds = slider.getValue() * 1000;
if (player.adjustingSlider ==true)
{
player.adjustingSlider =false;
}
else
{
if (player.clip.isActive() ==false)
{
player.setPosition( (long) microSeconds);
}
else
{
player.pause();
player.setPosition( (long) microSeconds);
player.resume();
}
}
lblPositionSeconds.setText(formatMilliseconds((long) microSeconds/1000));
lblPosition.repaint();
}
private String formatMilliseconds(long milliseconds)
{
DecimalFormat format =new DecimalFormat("0.00");
double seconds = milliseconds / 1000.0;
String formattedOutput = format.format(seconds);
return formattedOutput;
}
privatevoid setPlayButton()
{
buttonPlayPause.setText("Play");
buttonPlayPause.setActionCommand("Play");
}
privatevoid setPauseButton()
{
buttonPlayPause.setText("Pause");
buttonPlayPause.setActionCommand("Pause");
}
publicvoid createAudioInputStream()
{
JFileChooser chooser =new JFileChooser();
chooser.setFileSelectionMode(ListSelectionModel.SINGLE_SELECTION);
chooser.showOpenDialog(this);
File file = chooser.getSelectedFile();
try{
audioInputStream = AudioSystem.getAudioInputStream(file);
}catch (Exception e){}
if (audioInputStream !=null)
{
player.initialize();
lengthInMilliseconds = (int)((audioInputStream.getFrameLength() * 1000) / audioInputStream.getFormat().getFrameRate());
}
}
privatevoid setSliderPosition(finalint milliseconds)
{
// Adjust slider
if (slider.getValueIsAdjusting() ==false)
{
slider.setValue(milliseconds);
slider.repaint();
}
}
/**
* Voice prompt player.
*/
publicclass Playerimplements ActionListener
{
Timer timer;
Clip clip;
boolean paused =false;
boolean adjustingSlider =false;
public Player()
{
timer =new Timer(100,this);
timer.setRepeats(true);
}
publicvoid actionPerformed(ActionEvent e)
{
System.out.println("Clip position: " + clip.getMicrosecondPosition() +" usec, isRunning: " + clip.isRunning());
System.out.println("Timer time: " + System.currentTimeMillis() +" msec");
if ( (clip.isRunning() ==false))
{
// At end of playback
if (buttonStop.isEnabled())
buttonStop.doClick();
//System.out.println(clip.getMicrosecondPosition() + " " + clip.isRunning());
}
adjustingSlider =true;
int milliseconds = (int) clip.getMicrosecondPosition() / 1000;
setSliderPosition(milliseconds);
}
publicboolean isPaused()
{
return paused;
}
publicvoid play()
{
if(clip ==null)
{
JOptionPane.showMessageDialog(null,"There is no loaded audio to playback.",
"Play Problem",JOptionPane.WARNING_MESSAGE);
return;
}
System.out.println("\nClip starting");
System.out.println("Clip position: " + clip.getMicrosecondPosition() +" usec, isRunning: " + clip.isRunning());
clip.start();
System.out.println("Clip started");
System.out.println("Clip position: " + clip.getMicrosecondPosition() +" usec, isRunning: " + clip.isRunning());
System.out.println("Start time: " + System.currentTimeMillis() +" msec");
timer.start();
}
publicvoid pause()
{
if (timer !=null)
timer.stop();
if (clip !=null)
{
clip.stop();
//System.out.println("Clip stop");
}
paused =true;
}
publicvoid resume()
{
if (clip !=null)
{
clip.start();
//System.out.println("Clip start");
}
if (timer !=null)
timer.restart();
paused =false;
}
publicvoid stop()
{
if (timer !=null)
timer.stop();
if (clip !=null)
{
clip.stop();
//System.out.println("Clip stop");
clip.setFramePosition(0);
//System.out.println("Clip setFramePosition 0");
setSliderPosition(0);
}
paused =false;
}
privatevoid shutDown(String message)
{
if (message !=null)
{
System.err.println(message);
}
setPlayButton();
buttonStop.setEnabled(false);
}
publicvoid setPosition(long microseconds)
{
clip.setMicrosecondPosition(microseconds);
//System.out.println("Clip setMicrosecondPosition " + microseconds);
}
publicvoid initialize()
{
// make sure we have something to play
if (audioInputStream ==null){
shutDown("There is no loaded audio to playback.");
return;
}
// define the required attributes for our line,
// and make sure a compatible line is supported.
AudioFormat format = audioInputStream.getFormat();
DataLine.Info clipInfo =new DataLine.Info(Clip.class, format);
if (!AudioSystem.isLineSupported(clipInfo))
{
shutDown("A line matching desired info not supported" +": " + clipInfo);
return;
}
// get and open the source data line for playback.
try
{
clip = (Clip)AudioSystem.getLine(clipInfo);// Create the clip
clip.open(audioInputStream);
//System.out.println("Clip open");
clip.setFramePosition(0);
//System.out.println("Clip setFramePosition 0");
}
catch (IOException e)
{
shutDown("Unable to open clip" +": " + e);
return;
}
catch (LineUnavailableException ex)
{
shutDown("Unable to open line" +": " + ex);
return;
}
}
}// End class Player
class MyWindowAdapterextends WindowAdapter
{
publicvoid windowClosing(WindowEvent e)
{
player.stop();
}
}
}

