Java Detecting when sound stops - java

I have a sound class for my application and it plays a certain sound when I tell it too. I want to be able to detect when the sound is finished playing so I can then play a different sound without them over lapping here is my sound class:
public class Sound {
public static final Sound cash = new Sound("/cash.wav");
public static final Sound snap = new Sound("/snap.wav");
public static final Sound disarm = new Sound("/disarm.wav");
public static final Sound tp = new Sound("/tp.wav");
public static final Sound select = new Sound("/selectBTN.wav");
public static final Sound scroll = new Sound("/btn.wav");
public static final Sound fire = new Sound("/fire2.wav");
private AudioClip c;
public Sound(String filename) {
try {
c = Applet.newAudioClip(Sound.class.getResource(filename));
} catch (Exception e) {
e.printStackTrace();
}
}
public void play() {
try {
new Thread() {
public void run() {
if (!title.mute) {
c.play();
}
}
}.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
then to play the sound I use this line of code:
Sound.cash.play();
How can I detect when the sound is finished playing

Try something like this (is an aproximation), with LineListener to detect the end of playing:
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineEvent.Type;
import javax.sound.sampled.LineListener;
public class Sound {
private Clip c;
public Sound(final String filename) {
try {
c = AudioSystem.getClip();
final AudioInputStream inputStream = AudioSystem.getAudioInputStream(Sound.class.getResourceAsStream(filename));
c.open(inputStream);
c.addLineListener(new LineListener() {
#Override
public void update(final LineEvent event) {
if (event.getType().equals(Type.STOP)) {
System.out.println("Do something");
}
}
});
} catch (final Exception e) {
e.printStackTrace();
}
}
public void play() {
c.start();
}
public static void main(final String[] args) throws InterruptedException {
final Sound s = new Sound("/cash.wav");
s.play();
Thread.sleep(100000);
final Sound p = new Sound("/cash.wav");
p.play();
Thread.sleep(10000);
}
}

Related

Sound handler using Clip and AudioInputstream keeps audio in RAM

A sound handler I have developed for my game handles playing musing and sound effects. In theory there should be one voice for each sfx and music, and each should only be able to play one track at a time.
However, whilst monitoring the resources used the RAM used exponentially increases when skipping through tracks, all the way to the argument limit of 8Gb - meaning that it loads tracks into memory again each time it is played and is never dumped.
Whilst debugging this, I placed an unhealthy amount of .Drains and .Flushes on the Clips in my class, and resetting the AudioInputStream to null, experimenting with no effect.
On a side note, when skipping through tracks quickly, an occasional phantom voices will appear, continuing to play in the background uncontrollably of the controlled Music voice - I feel this are likely closely related.
Below is the entire class, including all positions which .Drain etc were used during debugging. Song skipping starts from NextTrack() or PrevTrack(), both give the same result.
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
public class SoundHandler {
private static Clip sfx = null, Music = null;
public static boolean MusicEnabled = true;
private static int STIndex = 0;
private static final int TrackCount = 41;
private static AudioInputStream audioInputStream;
//Channel true = sfx, else music
private static void PlayFile(String filename, boolean Chanel){
try {
audioInputStream = AudioSystem.getAudioInputStream(new BufferedInputStream(new FileInputStream(filename)));
if (Chanel) {
try {sfx.stop(); sfx.drain();}catch (Exception e) {}
sfx = AudioSystem.getClip();
sfx.open(audioInputStream);
sfx.start();
} else {
if (!MusicEnabled) {return;}
try {Music.stop(); Music.drain();}catch (Exception e) {}
Music = AudioSystem.getClip();
Music.open(audioInputStream);
Music.start();
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
//Music Handler for external
private static void PlayTrack() {
String Location = String.valueOf(Game.ResourcePath + "/Audio/Runtime/ST" + STIndex + ".wav");
PlayFile(Location, false);
}
public static void SFX(String Effect) {
String Location = String.valueOf(Game.ResourcePath + "/Audio/Runtime/" + Effect + ".wav");
PlayFile(Location, true);
}
public static void NextTrack() {
if (STIndex >= TrackCount) {STIndex = 0;} else {STIndex++;}
Music.stop();
Music.drain();
Music.flush();
try {audioInputStream.close();} catch (IOException e) {}
audioInputStream = null;
PlayTrack();
}
public static void PrevTrack() {
if (STIndex <= 0) {STIndex = TrackCount;} else {STIndex--;}
Music.stop();
Music.drain();
Music.flush();
try {audioInputStream.close();} catch (IOException e) {}
audioInputStream = null;
PlayTrack();
}
public static void StartMusic () {
MusicEnabled = true;
STIndex = 0;
String Location = String.valueOf(Game.ResourcePath + "/Audio/Runtime/ST" + STIndex + ".wav");
PlayFile(Location, false);
}
public static void PlayIndex(int index) {
MusicEnabled = true;
STIndex = 0;
String Location = String.valueOf(Game.ResourcePath + "/Audio/Runtime/ST" + index + ".wav");
PlayFile(Location, false);
}
public static void PlayStop() {
MusicEnabled = !MusicEnabled;
if (MusicEnabled) {
StartMusic();
} else {
try {Music.stop(); Music.drain(); Music.flush();}catch (Exception e) {}
}}
public static void Tick() {
try {if ((!Music.isActive()) && MusicEnabled){NextTrack();}} catch (Exception e) {}
if (!MusicEnabled) {
try {if (!Music.isActive()){Music.stop(); Music.drain();}} catch (Exception e) {}
}}
public static int getST() {
return STIndex;
}
}

Unexpected latency in Java Sound during long executions

I'm writing a audio chat application in Java and I'm experiencing some latency/delays that mostly shows up if the application is left running for a while.
I recreated the problem in the below sample application. It simply loops sound from the microphone to the speaker. Initially it behaves as expected. When you press the button and speak into the microphone you hear yourself in the speaker with a tiny delay. However if the program is left running for a while (a week) then that delay is increased to several seconds.
I tested with different headsets. I tested with Java 8, 9, 10 and it consistently displays the same behaviour. I also experimented with drain() and flush() and so on but the only thing that gets rid of the delay is to close and recreate the TargetDataLine. Recreating the line is however not an option for my application since it takes to long and audio is unavailable while you recreate the line.
Is this a known limitation or am I doing something wrong? Very thankful for any insight or ideas!
import javax.sound.sampled.*;
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
/**
* Created by asa on 2018-04-03.
*/
public class Main {
public static void main(String[] args) throws LineUnavailableException {
String title = "";
if (args.length > 0) {
title = args[0];
}
String mixerName = "USB”; // Part of the name of my headset
if (args.length > 1) {
mixerName = args[1];
}
AudioFormat format = new AudioFormat(8000f,
16,
1,
true,
false);
DataLine.Info targetInfo = new TargetDataLine.Info(TargetDataLine.class, format);
TargetDataLine mic = null;
for (Mixer.Info info : AudioSystem.getMixerInfo()) {
if (info.getName().contains(mixerName) && !info.getName().contains("Port")) {
Mixer m = AudioSystem.getMixer(info);
if (m.isLineSupported(targetInfo)) {
mic = (TargetDataLine) m.getLine(targetInfo);
break;
}
}
}
mic.open(format, 1280);
mic.start();
DataLine.Info sourceInfo = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine speaker = null;
for (Mixer.Info info : AudioSystem.getMixerInfo()) {
if (info.getName().contains(mixerName) && !info.getName().contains("Port")) {
Mixer m = AudioSystem.getMixer(info);
if (m.isLineSupported(sourceInfo)) {
speaker = (SourceDataLine) m.getLine(sourceInfo);
break;
}
}
}
speaker.open(format, 8000);
speaker.start();
MicRunnable micRunnable = new MicRunnable(mic, speaker);
new Thread(micRunnable).start();
Frame.show(title, new Frame.PttListener() {
#Override
public void press() {
micRunnable.start();
}
#Override
public void release() {
micRunnable.stop();
}
});
}
private static class MicRunnable implements Runnable {
private final TargetDataLine _mic;
private final SourceDataLine _speaker;
private final Object runLock = new Object();
private volatile boolean running = false;
public MicRunnable(TargetDataLine mic, SourceDataLine speaker) {
_mic = mic;
_speaker = speaker;
}
public void start() {
synchronized (runLock) {
running = true;
runLock.notify();
}
}
public void stop() {
synchronized (runLock) {
running = false;
}
}
#Override
public void run() {
while (true) {
byte[] bytes = new byte[640];
_mic.read(bytes, 0, bytes.length);
if (running) {//tPeakGain(bytes) > 300) {
_speaker.write(bytes, 0, bytes.length);
}
}
}
}
private static class Frame extends JFrame {
interface PttListener {
void press();
void release();
}
private Frame(String title, PttListener listener) {
setTitle(title);
JPanel content = new JPanel();
JButton pttButton = new JButton("PTT");
pttButton.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
listener.press();
}
#Override
public void mouseReleased(MouseEvent e) {
listener.release();
}
});
content.add(pttButton);
setContentPane(content);
setSize(300, 100);
}
public static void show(String title, Frame.PttListener pttListener) {
new Frame(title, pttListener).setVisible(true);
}
}
}

jlayer.javazoom player can not stop mp3

How to stop MP3 in jlayer? (the stop() is no longer used)
My code as follows:
//main class mp3_main
private AdvancedPlayer player;
public static void main(String[] args) {
String file="C:\\cd.mp3";
mp3PlayerSample mp3 = new mp3PlayerSample(file);
mp3.play();
mp3.stop();
}
//class mp3PlayerSample
private String filename;
private BufferedInputStream buffer;
private AdvancedPlayer player;
//constructor
public mp3PlayerSample(String filename)
{
this.filename = filename;
}
//start method
public void play()
{
FileInputStream fis;
try {
fis = new FileInputStream(this.filename);
buffer = new BufferedInputStream(fis);
try {
this.player=new AdvancedPlayer(buffer);
player.play();
} catch (JavaLayerException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
//stop method
public void stop()
{
if(player != null){
player.close();
}
}
You need to run the player in its own thread, right now your main method blocks after calling play() until playback has completed.
Note, the classes Player/AdvancedPlayer included with jlayer are meant as example code to demonstrate how the decoding and output of decoded audio has to be wired up. They are not fully fledged players (e.g. there isn't even volume control).
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import java.util.Scanner;
class Music extends Thread{
public void run(){
try {
FileInputStream fileInputStream = new FileInputStream("Freedom.mp3");
Player player = new Player(fileInputStream);
player.play();
}catch(FileNotFoundException e) {
e.printStackTrace();
}catch(JavaLayerException e) {
e.printStackTrace();
}
}
}
public class Main {
public static void main (String[]args){
Scanner keyboard = new Scanner(System.in);
Music music = new Music();
music.start();
System.out.println("Stop music: ");
int off = keyboard.nextInt();
if(off == 0) {
music.stop();
}
}
}

How can I add sound to a java program

I have been trying to write a basic 'Jeopardy' game in java, and right now I'm trying to add sound to play when the player get's an answer right or wrong. I have tried to add the sound (placing the sound file in the bin folder and using the code below), but when I try to play the file there is no sound. There is no null pointer exception.
public class Overview{
static AudioClip right, wrong;
//start the game
public static void guiApp(){
right = Applet.newAudioClip(Jeopardy.class.getResource("correct.wav"));
wrong = Applet.newAudioClip(Jeopardy.class.getResource("wrong.wav"));
right.play();
intro = new Intro();
intro.start();
}
public static void main (String[ ] args)
{
javax.swing.SwingUtilities.invokeLater (new Runnable ( )
{
public void run ( )
{
guiApp();
}
}
);
}
}
The following is essentially what is happening in the method called:
public class Intro{
public Intro(){
}
public void start(){
JFrame frame = new JFrame();
frame.setSize(100, 100);
frame.setVisible(true);
}
}
This is something that i use to play sound.
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 SoundPlayer extends Thread
{
private static final int BUFFER_SIZE = 128000;
private static File soundFile;
private static AudioInputStream audioStream;
private static AudioFormat audioFormat;
private static SourceDataLine sourceLine;
private String file;
public static String turn = "data/bell.wav"; //bell sound for black jack when it is your turn (played once each turn)
/**
* Plays the sound of the sent file name
* #param file Audio File's path
*/
public SoundPlayer(String file)
{
super("SoundPlayer");
this.file = file;
start();
}
public void run()
{
String strFilename = file;
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();
this.stop();
}
public static void main(String[] args)
{
}
}

Restrict multiple instances of an application in java

I want to prevent multiple instances of application being launched in java. I know 2 methods for this:
locking file
locking socket
But which is one is more efficient and good to use? Which one should I use?
Any other solution to do the same are also welcome.
There is a library called jUnique which does that and will save you the bother of implementing it yourself.
If you deploy with Java WebStart the SingleInstanceService does this.
See http://download.oracle.com/javase/6/docs/technotes/guides/javaws/developersguide/faq.html#218
EDIT: I tried that with Win200864b(version isn't important) and alive JFrame and move toFront() or Iconified in SystemTray with JFrame.DO_NOTHING_ON_CLOSE
public interface ApplicationStartedListener {
void applicationStarted();
void foreignApplicationStarted(String name);
void messageArrived(Object obj);
}
//
import java.io.Serializable;
public class ClassCheck implements Serializable {
private static final long serialVersionUID = 1L;
private String className = null;
public ClassCheck() {
}
public ClassCheck(String className) {
setClassName(className);
}
#Override
public String toString() {
return this.className;
}
public String getClassName() {
return this.className;
}
public void setClassName(String className) {
this.className = className;
}
}
//
import java.awt.AWTException;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;
import java.io.File;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class RunOnceFromFile {
private SingleInstanceController sic = null;
private JFrame frame;
private Robot r;
private JTextField tf;
public RunOnceFromFile() {
try {
r = new Robot();
} catch (AWTException ex) {
ex.printStackTrace();
}
sic = new SingleInstanceController(new File(System.getProperty("java.io.tmpdir") + "Example.file"), "sic_example_application");
if (sic.isOtherInstanceRunning()) {
sic.sendMessageToRunningApplication("toFront");
System.exit(0);
} else {
frame = new JFrame("TEST");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 300);
tf = new JTextField("JTextFiled");
frame.add(tf, BorderLayout.NORTH);
frame.setExtendedState(Frame.ICONIFIED);
frame.setExtendedState(Frame.NORMAL);
frame.setExtendedState(frame.getExtendedState() | JFrame.ICONIFIED);
frame.setExtendedState(frame.getExtendedState() & (~JFrame.ICONIFIED));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
sic.registerApplication();
sic.addApplicationStartedListener(new ApplicationStartedListener() {
public void applicationStarted() {
Runnable doRun = new Runnable() {
public void run() {
frame.toFront();
}
};
SwingUtilities.invokeLater(doRun);
}
public void foreignApplicationStarted(final String name) {
Runnable doRun = new Runnable() {
public void run() {
frame.toFront();
}
};
SwingUtilities.invokeLater(doRun);
}
public void messageArrived(final Object obj) {
Runnable doRun = new Runnable() {//activateWindow(frame);
public void run() {
frame.toFront();
}
};
SwingUtilities.invokeLater(doRun);
}
private void activateWindow(JFrame frame) {
frame.setExtendedState(Frame.ICONIFIED);
frame.setExtendedState(Frame.NORMAL);
frame.setAlwaysOnTop(true);
frame.setAlwaysOnTop(false);
Point location = MouseInfo.getPointerInfo().getLocation();
Point locationOnScreen = frame.getLocationOnScreen();
r.mouseMove(locationOnScreen.x + 100, locationOnScreen.y + 10);
r.mousePress(InputEvent.BUTTON1_MASK);
r.mouseRelease(InputEvent.BUTTON1_MASK);
r.mouseMove(location.x, location.y);
}
});
}
}
public static void main(String[] args) {
RunOnceFromFile roff = new RunOnceFromFile();
}
}
//
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class SingleInstanceController {
private String appname = null;
private Socket client = null;
private File file = null;
private ArrayList<ApplicationStartedListener> listener = null;
private ObjectInputStream ois = null;
private ObjectOutputStream oos = null;
private boolean result = false;
private ServerSocket server = null;
public SingleInstanceController(String appname) {
this(new File(System.getProperty("java.io.tmpdir") + "/923jhakE53Kk9235b43.6m7"), appname);
}
public SingleInstanceController(File file, String appname) {
this.file = file;
this.appname = appname;
this.listener = new ArrayList<ApplicationStartedListener>();
}
public void addApplicationStartedListener(ApplicationStartedListener asl) {
this.listener.add(asl);
}
public void removeApplicationStartedListener(ApplicationStartedListener asl) {
this.listener.remove(asl);
}
public boolean isOtherInstanceRunning() {
if (!this.file.exists()) {
return false;
}
return sendMessageToRunningApplication(new ClassCheck(this.appname));
}
public boolean sendMessageToRunningApplication(final Object obj) {
this.result = false;
try {
this.client = new Socket("localhost", getPortNumber());
new Thread(new Runnable() {
public void run() {
try {
SingleInstanceController.this.oos = new ObjectOutputStream(SingleInstanceController.this.client.getOutputStream());
SingleInstanceController.this.ois = new ObjectInputStream(SingleInstanceController.this.client.getInputStream());
SingleInstanceController.this.oos.writeObject(obj);
SingleInstanceController.this.oos.flush();
SingleInstanceController.this.result = SingleInstanceController.this.ois.readBoolean();
} catch (IOException e) {
SingleInstanceController.this.result = false;
}
}
}).start();
for (int i = 0; i < 10; i++) {
if (this.result == true) {
break;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.client.close();
return this.result;
} catch (IOException e) {
return false;
}
}
public boolean registerApplication() {
try {
if (!this.file.exists()) {
if (!this.file.getParentFile().mkdirs() && !this.file.getParentFile().exists()) {
return false;
}
if (!this.file.createNewFile()) {
return false;
}
}
BufferedWriter wuffy = new BufferedWriter(new FileWriter(this.file));
int port = getFreeServerSocket();
if (port != -1) {
startServer();
}
wuffy.write(String.valueOf(port));
wuffy.close();
return true;
} catch (IOException e) {
return false;
}
}
protected void messageArrived(Object obj) {
for (ApplicationStartedListener asl : this.listener) {
asl.messageArrived(obj);
}
}
protected void applicationStartet() {
for (ApplicationStartedListener asl : this.listener) {
asl.applicationStarted();
}
}
protected void foreignApplicationStarted(String name) {
for (ApplicationStartedListener asl : this.listener) {
asl.foreignApplicationStarted(name);
}
}
private int getPortNumber() {
try {
BufferedReader buffy = new BufferedReader(new FileReader(this.file));
int port = Integer.parseInt(buffy.readLine().trim());
buffy.close();
return port;
} catch (Exception e) {
return -1;
}
}
private void startServer() {
new Thread(new Runnable() {
public void run() {
while (true) {
try {
SingleInstanceController.this.client = SingleInstanceController.this.server.accept();
if (SingleInstanceController.this.client.getInetAddress().isLoopbackAddress()) {
new Thread(new Runnable() {
public void run() {
try {
SingleInstanceController.this.oos = new ObjectOutputStream(SingleInstanceController.this.client.getOutputStream());
SingleInstanceController.this.ois = new ObjectInputStream(SingleInstanceController.this.client.getInputStream());
Object obj = SingleInstanceController.this.ois.readObject();
if (obj instanceof ClassCheck) {
if (obj.toString().equals(SingleInstanceController.this.appname)) {
SingleInstanceController.this.oos.writeBoolean(true);
applicationStartet();
} else {
SingleInstanceController.this.oos.writeBoolean(false);
foreignApplicationStarted(obj.toString());
}
} else {
messageArrived(obj);
SingleInstanceController.this.oos.writeBoolean(true);
}
SingleInstanceController.this.oos.flush();
SingleInstanceController.this.client.close();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}).start();
}
private int getFreeServerSocket() {
for (int i = 2000; i < 10000; i++) {
try {
this.server = new ServerSocket(i);
return i;
} catch (IOException ignore) {
}
}
return -1;
}
}
My vote goes to locking on a port (i think this is what you mean by socket). I don't know the exact reason for this. But in fact i come across only this as a solution in most practical projects. Though i will be happy to hear the alternative ways.
In response to your question, the port solution will keep more resources from the machine:
- You will keep a port locked: ports are limited and you may find problems with firewalls or other programs listening on the same port.
- You'll need an active thread.
The file solution will use less resources from the machine, to avoid locking the file forever you need to add a thread, to delete the file, in the addShutdownHook method from Runtime.
the serversocket solution is cross-platform . And will not be vulnerable to the program crashing and not resetting the lock.
File lock is better way to do- imo. When you create the file in User's Home directory, this will still work in a multi-user environment.
I came across - JUnique - haven't had a chance to use it
http://www.sauronsoftware.it/projects/junique/manual.php
I know that this question is pretty old, but I have to solve the same problem at the moment. I prefer the socket solution because I have never thought that such kind of task should have anything to do with the file system. It is better to solve the problem in memory and not in the file system I think.

Categories