How do I stop audio lag in java? - java

I am making a skype like program. I have a "VoiceChat" class to handle the voice chat connections. I have a "ClientAudio" class to handle the client audio output. I also have a "ClientAudioRec" to handle receiving audio from the server and playing it. In the "ClientAudio" class I store the audio data in a buffer until it is full to try and reduce lag. Then I send it to the server. If I have two people in the call it lags unless the buffer is at 1000. When I add another person to the call it lags so much that you can't understand anyone. But I don't want to extend the buffer every time someone else joins because 1000 is already like a two-second delay. If anyone knows how to reduce the lag or make it almost instant that would really help. thank you in advance!!!
VoiceChat (Server Side)
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
public class VoiceChat extends Thread {
private Socket s;
private ObjectOutputStream out;
private ObjectInputStream in;
private Thread acceptThread;
private int VoicePort;
private int num;
public VoiceChat(Socket sVoice, int VoicePort, Thread acceptThread) {
s = sVoice;
this.VoicePort = VoicePort;
this.acceptThread = acceptThread;
num = chat.threads.indexOf(this.acceptThread)+1;
try {
out = new ObjectOutputStream(s.getOutputStream());
in = new ObjectInputStream(s.getInputStream());
if(VoicePort <= 65511) {
chat.users1_Voice.add(out);
}else {
chat.users2.add(out);
}
} catch (IOException e) {
System.out.println("ERROR2");
e.printStackTrace();
}
}
public void run() {
int bytesRead = 0;
byte[] inBytes = new byte[100];
while(bytesRead != -1) {
try {
bytesRead = in.read(inBytes, 0, inBytes.length);
}catch (IOException e) {
System.out.println("ERROR2");
if(VoicePort <= 65511) {
chat.users1_Voice.remove(out);
}else {
chat.users2.remove(out);
}
}
if(bytesRead > 0) {
System.out.println(chat.users1_Voice);
send(inBytes, bytesRead, out);
System.out.println("SENDING DATA");
}
}
}
public void send(byte[] soundData, int bytesRead, ObjectOutputStream out) {
if(VoicePort <= 65511) {
for(ObjectOutputStream o : chat.users1_Voice) {
try {
if(o != out) {
o.write(soundData, 0, bytesRead);
o.flush();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}else {
for(ObjectOutputStream o : chat.users2) {
try {
if(o != out) {
o.write(soundData, 0, bytesRead);
o.flush();
}
} catch (IOException e) {
}
}
}
}
}
ClientAudio
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
public class ClientAudio implements Runnable {
private ObjectOutputStream out = null;
private AudioFormat af;
private TargetDataLine microphone;
ClientAudio(AudioFormat af) {
this.af = af;
}
public void run() {
try {
client.voiceSocket = new Socket("***IP***", client.VoicePort);
Thread car = new Thread(new ClientAudioRec(af));
car.start();
out = new ObjectOutputStream(client.voiceSocket.getOutputStream());
DataLine.Info info = new DataLine.Info(TargetDataLine.class, af);
microphone = (TargetDataLine)AudioSystem.getLine(info);
microphone.open(af);
microphone.start();
int bytesRead = 0;
int offset = 0;
byte[] soundData = new byte[1000];
while(bytesRead != -1 && client.callRunning == true) {
bytesRead = microphone.read(soundData, 0, soundData.length);
if(bytesRead >= 0) {
offset += bytesRead;
if(offset == soundData.length) {
out.write(soundData, 0, bytesRead);
offset = 0;
}
}
}
microphone.close();
try {
client.voiceSocket.close();
} catch (IOException e1) {
e1.printStackTrace();
}
System.out.println("Client Audio Stopped Because Client Disconnected From Call");
} catch (IOException | LineUnavailableException e) {
microphone.close();
try {
client.voiceSocket.close();
} catch (IOException e1) {
System.out.println("Plug Microphone In...");
}
System.out.println("Client Audio Stopped...");
}
}
}
ClientAudioRec
import java.io.IOException;
import java.io.ObjectInputStream;
import java.net.Socket;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class ClientAudioRec implements Runnable {
private SourceDataLine inSpeaker = null;
private AudioFormat audioformat;
private ObjectInputStream in;
ClientAudioRec(AudioFormat af) {
audioformat = af;
try {
in = new ObjectInputStream(client.voiceSocket.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioformat);
try {
inSpeaker = (SourceDataLine)AudioSystem.getLine(info);
inSpeaker.open(audioformat);
} catch (LineUnavailableException e1) {
System.out.println("ERROR");
e1.printStackTrace();
}
int bytesRead = 0;
byte[] inSound = new byte[100000];
inSpeaker.start();
while(bytesRead != -1 && client.callRunning == true) {
try{bytesRead = in.read(inSound, 0, inSound.length);} catch (Exception e){
inSpeaker.close();
System.out.println("Speaker Closed");
}
if(bytesRead >= 0) {
inSpeaker.write(inSound, 0, bytesRead);
}
}
inSpeaker.close();
System.out.println("Speaker Closed Because Client Disconneted From Call");
}
}

Related

JAVA TCP Server Error

Server : package Server;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import javax.imageio.ImageIO;
public class Server extends Thread{
private ServerSocket mServer_Socket;
private ArrayList<SocketManager> managers = new ArrayList<SocketManager>();
public Server(){
try {
mServer_Socket = new ServerSocket(4242);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
Socket msocket;
try{
msocket = mServer_Socket.accept();
System.out.println("connected");
managers.add(new SocketManager(msocket));
}catch(Exception e){
e.printStackTrace();
}
}
public void SendMessage(String m, int i){
try {
managers.get(i).write(m.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
private class SocketManager{
private OutputStream mout;
private InputStream min;
public SocketManager(Socket socket){
try{
mout = socket.getOutputStream();
min = socket.getInputStream();
}catch (IOException ioe) {
ioe.printStackTrace();
}
startListen();
}
public void write(byte[] data) throws IOException{
mout.write(data);
}
public void startListen(){
new Thread() {
BufferedImage image;
public void run(){
try {
System.out.println("listen..");
while(true){
if((image = ImageIO.read(min)) != null){
while(min.read() != 'y');
System.out.println("received");
mout.write('y');
mout.flush();
Main.drawImage(image);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
Client :package Client;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.List;
import javax.imageio.ImageIO;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamResolution;
import com.github.sarxos.webcam.ds.fswebcam.FsWebcamDriver;
public class Client {
private static List<Webcam> webcams = null;
static Webcam webcam = null;
static {
Webcam.setDriver(new FsWebcamDriver());
}
public static void main(String[] args) {
try {
webcams =(List<Webcam>) Webcam.getWebcams(1000000);
} catch (Exception e) {
e.printStackTrace();
}
for(Webcam device : webcams){
String name;
System.out.println(name = device.getDevice().getName());
//if(name.equals("Logitech HD Webcam C270 1"))
webcam = device;
}
webcam.setViewSize(WebcamResolution.VGA.getSize());
webcam.open();
try{
Socket socket = new Socket("localhost", 4242);
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
byte[] buffer = new byte[10];
while(true){
ImageIO.write(webcam.getImage(), "png", out);
out.flush();
out.write('y');
out.flush();
System.out.println("read");
while(in.read() != 'y');
}
}catch(Exception e){
e.printStackTrace();
}
}
}
This Program works well about 10sec. But after that It doesn't work. Socket is Connected but It doesn't send anything. I guess it doesn't match sync, so I match sync, but it's not work too. I don't have an idea. why It doesn't work. please help. I can't find problem
Your client needs to send the size of transfered image to server prior to sending the image itself, because your server needs to know how long the image is, in order to read it from socket and start receiving the char data coming right after the image.
And since "ImageIO" has no means of specifying the number of bytes supposed to be read from the input stream, you should use InputStream instead.
See the modified code below (I put comments whenever added a new line, everything else is identical with yours):
Server:
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; //<--- added
import java.io.DataInputStream; //<--- added
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import javax.imageio.ImageIO;
public class Server extends Thread{
private ServerSocket mServer_Socket;
private ArrayList<SocketManager> managers = new ArrayList<SocketManager>();
public Server(){
try {
mServer_Socket = new ServerSocket(4242);
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void run() {
Socket msocket;
try{
msocket = mServer_Socket.accept();
System.out.println("connected");
managers.add(new SocketManager(msocket));
}catch(Exception e){
e.printStackTrace();
}
}
public void SendMessage(String m, int i){
try {
managers.get(i).write(m.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
private class SocketManager{
private OutputStream mout;
private InputStream min;
private DataInputStream din; //<--- added DataInputStream
public SocketManager(Socket socket){
try{
mout = socket.getOutputStream();
min = socket.getInputStream();
din = new DataInputStream(min); //<--- initialized DataInputStream
}catch (IOException ioe) {
ioe.printStackTrace();
}
startListen();
}
public void write(byte[] data) throws IOException{
mout.write(data);
}
public void startListen()
{
new Thread() {
BufferedImage image;
public void run(){
try {
System.out.println("listen..");
while(true)
{
int arrlen = din.readInt(); //<--- receive image size in order to prepare a buffer for it
byte[] b = new byte[arrlen]; //<--- prepare a buffer
din.readFully(b); //<--- receive image data
while(min.read() != 'y');
mout.write('y');
mout.flush();
InputStream bais = new ByteArrayInputStream(b); //<--- get ByteArrayInputStream from buffer
BufferedImage image = ImageIO.read(bais); //<--- prepare BufferedImage from ByteArrayInputStream
bais.close(); //<--- close ByteArrayInputStream
Main.drawImage(image);
}//end while true
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
Client:
import java.awt.image.BufferedImage; //<--- added
import java.io.ByteArrayOutputStream; //<--- added
import java.io.DataOutputStream; //<--- added
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.List;
import javax.imageio.ImageIO;
import com.github.sarxos.webcam.Webcam;
import com.github.sarxos.webcam.WebcamResolution;
import com.github.sarxos.webcam.ds.fswebcam.FsWebcamDriver;
public class Client {
private static List<Webcam> webcams = null;
static Webcam webcam = null;
static {
Webcam.setDriver(new FsWebcamDriver());
}
public static void main(String[] args) {
try {
webcams =(List<Webcam>) Webcam.getWebcams(1000000);
} catch (Exception e) {
e.printStackTrace();
}
for(Webcam device : webcams){
String name;
System.out.println(name = device.getDevice().getName());
//if(name.equals("Logitech HD Webcam C270 1"))
webcam = device;
}
webcam.setViewSize(WebcamResolution.VGA.getSize());
webcam.open();
try{
Socket socket = new Socket("localhost", 4242);
OutputStream out = socket.getOutputStream();
InputStream in = socket.getInputStream();
DataOutputStream dos = new DataOutputStream(out); //<--- added DataOutputStream
BufferedImage image = null; //<--- added BufferedImage to keep image from webcam
while(true){
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //<--- create ByteArrayOutputStream
image = webcam.getImage(); //<--- get BufferedImage from webcam
ImageIO.write(image, "png", baos); //<--- write image into ByteArrayOutputStream
dos.writeInt(baos.size()); //<--- send image size
dos.flush(); //<--- flush DataOutputStream
baos.close(); //<--- close ByteArrayOutputStream
ImageIO.write(image, "png", out);
out.flush();
out.write('y');
out.flush();
System.out.println("read");
while(in.read() != 'y');
}
}catch(Exception e){
e.printStackTrace();
}
}
}

How to play .wav files in java without lag for games

I have a game that I want to play audio in. What I want to be able to do is that I should be able to declare a ClipPlayer object with the arguments of a path name. Then the constructor should be able to load the sound and then I can just make a call with that object so it won't lag. This is the code that I am using currently for sound:
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
public class ClipPlayer {
AudioInputStream in;
AudioFormat decodedFormat;
AudioInputStream din;
AudioFormat baseFormat;
SourceDataLine line;
private boolean loop;
private BufferedInputStream stream;
// private ByteArrayInputStream stream;
/**
* recreate the stream
*
*/
public void reset() {
try {
stream.reset();
in = AudioSystem.getAudioInputStream(stream);
din = AudioSystem.getAudioInputStream(decodedFormat, in);
line = getLine(decodedFormat);
} catch (Exception e) {
e.printStackTrace();
}
}
public void close() {
try {
line.close();
din.close();
in.close();
} catch (IOException e) {
}
}
ClipPlayer(String filename, boolean loop) {
this(filename);
this.loop = loop;
}
ClipPlayer(String filename) {
this.loop = false;
try {
InputStream raw = Object.class.getResourceAsStream(filename);
stream = new BufferedInputStream(raw);
// ByteArrayOutputStream out = new ByteArrayOutputStream();
// byte[] buffer = new byte[1024];
// int read = raw.read(buffer);
// while( read > 0 ) {
// out.write(buffer, 0, read);
// read = raw.read(buffer);
// }
// stream = new ByteArrayInputStream(out.toByteArray());
in = AudioSystem.getAudioInputStream(stream);
din = null;
if (in != null) {
baseFormat = in.getFormat();
decodedFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED, baseFormat
.getSampleRate(), 16, baseFormat.getChannels(),
baseFormat.getChannels() * 2, baseFormat
.getSampleRate(), false);
din = AudioSystem.getAudioInputStream(decodedFormat, in);
line = getLine(decodedFormat);
}
} catch (UnsupportedAudioFileException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (LineUnavailableException e) {
e.printStackTrace();
}
}
private SourceDataLine getLine(AudioFormat audioFormat)
throws LineUnavailableException {
SourceDataLine res = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class,
audioFormat);
res = (SourceDataLine) AudioSystem.getLine(info);
res.open(audioFormat);
return res;
}
public void play() {
try {
boolean firstTime = true;
while (firstTime || loop) {
firstTime = false;
byte[] data = new byte[4096];
if (line != null) {
line.start();
int nBytesRead = 0;
while (nBytesRead != -1) {
nBytesRead = din.read(data, 0, data.length);
if (nBytesRead != -1)
line.write(data, 0, nBytesRead);
}
line.drain();
line.stop();
line.close();
reset();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Declare, load and cache the sounds as class attributes. Then when it is time to hear them, play them in a Clip.

JFrame doesn't show when music is playing?

I am using the mp3plugin.jar library and my music works great. The only problem is that when my program starts the JFrame doesn't show. Before I added the music, it worked perfectly. This is my code for the music:
package com.org.pong;
import javax.sound.sampled.*;
import javax.sound.*;
import java.io.*;
import java.net.URL;
public class Music {
Music(String url) {
int total, totalToRead, numBytesRead, numBytesToRead;
byte[] buffer;
boolean stopped;
AudioFormat wav;
TargetDataLine line;
SourceDataLine lineIn;
DataLine.Info info;
File file;
FileInputStream fis;
// AudioFormat(float sampleRate, int sampleSizeInBits,
// int channels, boolean signed, boolean bigEndian)
wav = new AudioFormat(44100, 16, 2, true, false);
info = new DataLine.Info(SourceDataLine.class, wav);
buffer = new byte[1024 * 333];
numBytesToRead = 1024 * 333;
total = 0;
stopped = false;
if (!AudioSystem.isLineSupported(info)) {
System.out.print("no support for " + wav.toString());
}
try {
// Obtain and open the line.
lineIn = (SourceDataLine) AudioSystem.getLine(info);
lineIn.open(wav);
lineIn.start();
fis = new FileInputStream(file = new File(url));
totalToRead = fis.available();
while (total < totalToRead && !stopped) {
numBytesRead = fis.read(buffer, 0, numBytesToRead);
if (numBytesRead == -1)
break;
total += numBytesRead;
lineIn.write(buffer, 0, numBytesRead);
}
} catch (LineUnavailableException ex) {
ex.printStackTrace();
} catch (FileNotFoundException nofile) {
nofile.printStackTrace();
} catch (IOException io) {
io.printStackTrace();
}
}
}
This suggest that you are blocking the Event Dispatching Thread. This will prevent any UI elements from being updated until you stop blocking.
Having only looked at you code, I would suggest that your culprit is here...
while (total < totalToRead && !stopped) {
numBytesRead = fis.read(buffer, 0, numBytesToRead);
if (numBytesRead == -1)
break;
total += numBytesRead;
lineIn.write(buffer, 0, numBytesRead);
}
Try creating a background thread in which you either run the Music class in OR run the loop within it's own background thread.
Take a look at Concurrency in Swing for more details
Updated with working example
This is a rather crude example. Normally I would have a single Thread which would be responsible for playing the music, but which could be interrupted and made to play another song, but this is just a proof of concept.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class TestMusic {
public static void main(String[] args) {
new TestMusic();
}
public TestMusic() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
Music.play("/play/some/music/white/boy");
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new JLabel("Look Ma, no hands"));
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public static class Music {
public static void play(final String url) {
new Thread(new Runnable() {
#Override
public void run() {
new Music(url);
}
}).start();
}
private int total, totalToRead, numBytesRead, numBytesToRead;
private byte[] buffer;
private boolean stopped;
private AudioFormat wav;
private TargetDataLine line;
private SourceDataLine lineIn;
private DataLine.Info info;
private File file;
private FileInputStream fis;
public Music(String url) {
// AudioFormat(float sampleRate, int sampleSizeInBits,
// int channels, boolean signed, boolean bigEndian)
wav = new AudioFormat(44100, 16, 2, true, false);
info = new DataLine.Info(SourceDataLine.class, wav);
buffer = new byte[1024 * 333];
numBytesToRead = 1024 * 333;
total = 0;
stopped = false;
if (!AudioSystem.isLineSupported(info)) {
System.out.print("no support for " + wav.toString());
}
try {
// Obtain and open the line.
lineIn = (SourceDataLine) AudioSystem.getLine(info);
lineIn.open(wav);
lineIn.start();
fis = new FileInputStream(file = new File(url));
totalToRead = fis.available();
while (total < totalToRead && !stopped) {
numBytesRead = fis.read(buffer, 0, numBytesToRead);
if (numBytesRead == -1) {
break;
}
total += numBytesRead;
lineIn.write(buffer, 0, numBytesRead);
}
} catch (LineUnavailableException ex) {
ex.printStackTrace();
} catch (FileNotFoundException nofile) {
nofile.printStackTrace();
} catch (IOException io) {
io.printStackTrace();
}
}
}
}
This is a classic example of blocking the Swing event dispatch thread with a long-running bit of code. This will cause the GUI to freeze since the thread isn't available to paint components or interact with the user. The solution: use a background thread for the music so you don't block the GUI's event thread.

java - for loop is executing more times than it should - metronome program

I am creating a metronome program and the for loop is executing +1 times than it should.
public class Tempo {
String file;
int bpm;
public Tempo(int bpm, String file){
this.bpm=bpm;
this.file=file;
}
public void tempoPlay () throws InterruptedException{
new Play(file).start();
Thread.sleep(60000/bpm);
}
public static void main(String[] args) throws InterruptedException {
Tempo t = new Tempo(120, "C:\\Users\\Korisnik\\Desktop\\dome3.wav");
for(int i=0;i<20;i++){
t.tempoPlay();
}
}
}
The first beat is rapidly followed by the second one but later as it goes it is sounding compliant. I've counted it plays 21 beats but it should play 20.
Here's the Play class:
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;
class Play extends Thread {
private String filename;
private Position curPosition;
private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb
enum Position {
LEFT, RIGHT, NORMAL
};
public Play(String wavfile) {
filename = wavfile;
curPosition = Position.NORMAL;
}
public Play(String wavfile, Position p) {
filename = wavfile;
curPosition = p;
}
#Override
public void run() {
File soundFile = new File(filename);
if (!soundFile.exists()) {
System.err.println("Wave file not found: " + filename);
return;
}
AudioInputStream audioInputStream = null;
try {
audioInputStream = AudioSystem.getAudioInputStream(soundFile);
} catch (UnsupportedAudioFileException e1) {
e1.printStackTrace();
return;
} catch (IOException e1) {
e1.printStackTrace();
return;
}
AudioFormat format = audioInputStream.getFormat();
SourceDataLine auline = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
auline = (SourceDataLine) AudioSystem.getLine(info);
auline.open(format);
} catch (LineUnavailableException e) {
e.printStackTrace();
return;
} catch (Exception e) {
e.printStackTrace();
return;
}
if (auline.isControlSupported(FloatControl.Type.PAN)) {
FloatControl pan = (FloatControl) auline
.getControl(FloatControl.Type.PAN);
if (curPosition == Position.RIGHT) {
pan.setValue(1.0f);
} else if (curPosition == Position.LEFT) {
pan.setValue(-1.0f);
}
}
auline.start();
int nBytesRead = 0;
byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
try {
while (nBytesRead != -1) {
nBytesRead = audioInputStream.read(abData, 0, abData.length);
if (nBytesRead >= 0) {
auline.write(abData, 0, nBytesRead);
}
}
} catch (IOException e) {
e.printStackTrace();
return;
} finally {
auline.drain();
auline.close();
}
}
}
Shot in the dark: It might be worthwhile to read the file into memory completely for testing purposes. A guess as to what might be happening is that the I/O from reading the file is interfering with the timing of the playback.
You might be able to get away with this to test.
Tempo t = new Tempo(120, "C:\\Users\\Korisnik\\Desktop\\dome3.wav");
t.tempoPlay() // ignore this
Thread.sleep(10);
for(int i=0;i<20;i++){
t.tempoPlay();
}
Or better yet, have Tempo cache the read in before playing the sound.

How to play .wav files with java

I am trying to play a *.wav file with Java. I want it to do the following:
When a button is pressed, play a short beep sound.
I have googled it, but most of the code wasn't working. Can someone give me a simple code snippet to play a .wav file?
Finally I managed to do the following and it works fine
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public class MakeSound {
private final int BUFFER_SIZE = 128000;
private File soundFile;
private AudioInputStream audioStream;
private AudioFormat audioFormat;
private SourceDataLine sourceLine;
/**
* #param filename the name of the file that is going to be played
*/
public void playSound(String filename){
String strFilename = filename;
try {
soundFile = new File(strFilename);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
try {
audioStream = AudioSystem.getAudioInputStream(soundFile);
} catch (Exception e){
e.printStackTrace();
System.exit(1);
}
audioFormat = audioStream.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
e.printStackTrace();
System.exit(1);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
#SuppressWarnings("unused")
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
}
}
Here is the most elegant form I could come up without using sun.*:
import java.io.*;
import javax.sound.sampled.*;
try {
File yourFile;
AudioInputStream stream;
AudioFormat format;
DataLine.Info info;
Clip clip;
stream = AudioSystem.getAudioInputStream(yourFile);
format = stream.getFormat();
info = new DataLine.Info(Clip.class, format);
clip = (Clip) AudioSystem.getLine(info);
clip.open(stream);
clip.start();
}
catch (Exception e) {
//whatevers
}
Shortest form (without having to install random libraries) ?
public static void play(String filename)
{
try
{
Clip clip = AudioSystem.getClip();
clip.open(AudioSystem.getAudioInputStream(new File(filename)));
clip.start();
}
catch (Exception exc)
{
exc.printStackTrace(System.out);
}
}
The only problem is there is no good way to make this method blocking to close and dispose the data after *.wav finishes.
clip.drain() says it's blocking but it's not. The clip isn't running RIGHT AFTER start().
The only working but UGLY way I found is:
// ...
clip.start();
while (!clip.isRunning())
Thread.sleep(10);
while (clip.isRunning())
Thread.sleep(10);
clip.close();
You can use an event listener to close the clip after it is played
import java.io.File;
import javax.sound.sampled.*;
public void play(File file)
{
try
{
final Clip clip = (Clip)AudioSystem.getLine(new Line.Info(Clip.class));
clip.addLineListener(new LineListener()
{
#Override
public void update(LineEvent event)
{
if (event.getType() == LineEvent.Type.STOP)
clip.close();
}
});
clip.open(AudioSystem.getAudioInputStream(file));
clip.start();
}
catch (Exception exc)
{
exc.printStackTrace(System.out);
}
}
The snippet here works fine, tested with windows sound:
public static void main(String[] args) {
AePlayWave aw = new AePlayWave( "C:\\WINDOWS\\Media\\tada.wav" );
aw.start();
}
A class that will play a WAV file, blocking until the sound has finished playing:
class Sound implements Playable {
private final Path wavPath;
private final CyclicBarrier barrier = new CyclicBarrier(2);
Sound(final Path wavPath) {
this.wavPath = wavPath;
}
#Override
public void play() throws LineUnavailableException, IOException, UnsupportedAudioFileException {
try (final AudioInputStream audioIn = AudioSystem.getAudioInputStream(wavPath.toFile());
final Clip clip = AudioSystem.getClip()) {
listenForEndOf(clip);
clip.open(audioIn);
clip.start();
waitForSoundEnd();
}
}
private void listenForEndOf(final Clip clip) {
clip.addLineListener(event -> {
if (event.getType() == LineEvent.Type.STOP) waitOnBarrier();
});
}
private void waitOnBarrier() {
try {
barrier.await();
} catch (final InterruptedException ignored) {
} catch (final BrokenBarrierException e) {
throw new RuntimeException(e);
}
}
private void waitForSoundEnd() {
waitOnBarrier();
}
}
Another way of doing it with AudioInputStream:
import java.io.File;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
public class CoreJavaSound extends Object implements LineListener {
File soundFile;
JDialog playingDialog;
Clip clip;
public static void main(String[] args) throws Exception {
CoreJavaSound s = new CoreJavaSound();
}
public CoreJavaSound() throws Exception {
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(null);
soundFile = chooser.getSelectedFile();
System.out.println("Playing " + soundFile.getName());
Line.Info linfo = new Line.Info(Clip.class);
Line line = AudioSystem.getLine(linfo);
clip = (Clip) line;
clip.addLineListener(this);
AudioInputStream ais = AudioSystem.getAudioInputStream(soundFile);
clip.open(ais);
clip.start();
}
public void update(LineEvent le) {
LineEvent.Type type = le.getType();
if (type == LineEvent.Type.OPEN) {
System.out.println("OPEN");
} else if (type == LineEvent.Type.CLOSE) {
System.out.println("CLOSE");
System.exit(0);
} else if (type == LineEvent.Type.START) {
System.out.println("START");
playingDialog.setVisible(true);
} else if (type == LineEvent.Type.STOP) {
System.out.println("STOP");
playingDialog.setVisible(false);
clip.close();
}
}
}
A solution without java reflection DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat)
Java reflection decrease performance.
to run: java playsound absoluteFilePathTo/file.wav
import javax.sound.sampled.*;
import java.io.*;
public class playsound {
public static void main (String args[]) throws Exception {
playSound (args[0]);
}
public static void playSound () throws Exception {
AudioInputStream
audioStream = AudioSystem.getAudioInputStream(new File (filename));
int BUFFER_SIZE = 128000;
AudioFormat audioFormat = null;
SourceDataLine sourceLine = null;
audioFormat = audioStream.getFormat();
sourceLine = AudioSystem.getSourceDataLine(audioFormat);
sourceLine.open(audioFormat);
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[BUFFER_SIZE];
while (nBytesRead != -1) {
try {
nBytesRead =
audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
e.printStackTrace();
}
if (nBytesRead >= 0) {
int nBytesWritten = sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
}
}
You can use AudioStream this way as well:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import sun.audio.AudioPlayer;
import sun.audio.AudioStream;
public class AudioWizz extends JPanel implements ActionListener {
private static final long serialVersionUID = 1L; //you like your cereal and the program likes their "serial"
static AudioWizz a;
static JButton playBuddon;
static JFrame frame;
public static void main(String arguments[]){
frame= new JFrame("AudioWizz");
frame.setSize(300,300);
frame.setVisible(true);
a= new AudioWizz();
playBuddon= new JButton("PUSH ME");
playBuddon.setBounds(10,10,80,30);
playBuddon.addActionListener(a);
frame.add(playBuddon);
frame.add(a);
}
public void actionPerformed(ActionEvent e){ //an eventListener
if (e.getSource() == playBuddon) {
try {
InputStream in = new FileInputStream("*.wav");
AudioStream sound = new AudioStream(in);
AudioPlayer.player.start(sound);
} catch(FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
I took #greenLizard's code and made it more robust.
I closed the AudioInputStream.
I used a BufferedInputStream. The AudioSystem getAudioInputStream was throwing an occasional IOException because the getAutoInputSytream method couldn't back up the input stream and start over.
Hopefully, there are no more exceptions to be found.
Here's the modified code. The ErrorDisplayDialog shows an exception as a JDialog in a Java Swing application. Just replace with e.printStackTrace();.
private void playWavFile(String fileName) {
InputStream inputStream = getClass().getResourceAsStream(fileName);
BufferedInputStream bufferedInputStream = new BufferedInputStream(
inputStream);
AudioInputStream audioStream = null;
AudioFormat audioFormat = null;
try {
audioStream = AudioSystem.getAudioInputStream(bufferedInputStream);
audioFormat = audioStream.getFormat();
} catch (UnsupportedAudioFileException e) {
new ErrorDisplayDialog(view.getFrame(),
"UnsupportedAudioFileException", e);
return;
} catch (IOException e) {
new ErrorDisplayDialog(view.getFrame(), "IOException", e);
return;
}
DataLine.Info info = new DataLine.Info(SourceDataLine.class,
audioFormat);
SourceDataLine sourceLine;
try {
sourceLine = (SourceDataLine) AudioSystem.getLine(info);
sourceLine.open(audioFormat);
} catch (LineUnavailableException e) {
new ErrorDisplayDialog(view.getFrame(), "LineUnavailableException",
e);
return;
}
sourceLine.start();
int nBytesRead = 0;
byte[] abData = new byte[128000];
while (nBytesRead != -1) {
try {
nBytesRead = audioStream.read(abData, 0, abData.length);
} catch (IOException e) {
new ErrorDisplayDialog(view.getFrame(), "IOException", e);
return;
}
if (nBytesRead >= 0) {
sourceLine.write(abData, 0, nBytesRead);
}
}
sourceLine.drain();
sourceLine.close();
try {
audioStream.close();
} catch (IOException e) {
new ErrorDisplayDialog(view.getFrame(), "IOException", e);
}
}

Categories