Java TargetDataLine and SourceDataLine reopen doesn't work - java

My setup is as followed:
I have a Java applet running in a browser which records and plays audio.
My problem is:
When I refresh the browser, the SourceDataLine is reopening properly after refresh, while the TargetDataLine isn't reopening itself.
public void init() {
try {
DataLine.Info sourceDataLineInfo = new DataLine.Info(
SourceDataLine.class, audioFormat);
DataLine.Info targetDataLineInfo = new DataLine.Info(
TargetDataLine.class, audioFormat);
// Setup a Line.Info instance specifically of the TargetDataLine class.
Line.Info targetDLInfo = new Line.Info(TargetDataLine.class);
Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
Mixer currentMixer = null;
try {
for(int cnt = 0; cnt < mixerInfo.length; cnt++) {
// Get a temporary instance of the current mixer
currentMixer = AudioSystem.getMixer(mixerInfo[cnt]);
if( currentMixer.isLineSupported(targetDLInfo) ) {
Log.log("Found mixer:" + mixerInfo[cnt].getName());
System.out.println(mixerInfo[cnt].getName());
break;
}
//currentMixer = null;
}
} catch(Exception e) {
Log.log("Found no mixer");
}
if(!Client.refresh) {
try {
sourceDataLine = (SourceDataLine) AudioSystem
.getLine(sourceDataLineInfo);
}catch(Exception e){
Log.log("Unable to stream audio not starting playthread");
}
play = new PlayThread();
if(sourceDataLine != null) {
sourceDataLine.open(audioFormat);
sourceDataLine.start();
play.start();
}
try {
targetDataLine = (TargetDataLine) currentMixer.getLine(targetDataLineInfo);
}catch(Exception e) {
connection.addMessage("[WARNING] Your microphone is not working.");
}
capture = new CaptureThread();
if(currentMixer != null) {
if(targetDataLine != null) {
targetDataLine.open(audioFormat);
targetDataLine.start();
capture.start();
}
}else {
connection.addMessage("[WARNING] No compatible microphone found.");
Log.log("Not able to record data since no mixer was found");
}
} else {
sourceDataLine.open(audioFormat);
sourceDataLine.start();
targetDataLine.open(audioFormat);
targetDataLine.start();
}
} catch (Exception e) {
Log.log("An exception occured when trying to startup the audio");
}
}
What is wrong with my code?

As Andrew said, you need to close the opened sourceDataline and TargetData line. As you refresh browser the init() is called again as it's new instance of your applet. If datalines are already open and you are trying to open it again it throws you exception kinda "Line is not supported:audioFormat". As destroy() is called every time you ends the instance of an applet, you need to handle closing of opened datalines in it.

Related

How to change source data line for an audio stream?

I am trying to parse audio from a file onto my computer to a discord bot that can play the audio in a voice channel. I am unable to change where it is being sent to though and am unsure how to proceed.
public void play(String filePath) {
final File file = new File(filePath);
try (final AudioInputStream in = getAudioInputStream(file)) {
//gets the file type
final AudioFormat outFormat = getOutFormat(in.getFormat());
final Info info = new Info(SourceDataLine.class, outFormat);
// I think I want to edit this part to change where the sound is output to
try (final SourceDataLine line = (SourceDataLine) AudioSystem.getLine(info)) {
if (line != null) {
line.open(outFormat);
line.start();
stream(getAudioInputStream(outFormat, in), line);
line.drain();
line.stop();
}
}
} catch (UnsupportedAudioFileException
| LineUnavailableException
| IOException e) {
throw new IllegalStateException(e);
}
}
and I want to parse the audio to connectedChannel
public void onSlashCommandInteraction(#NotNull SlashCommandInteractionEvent event) {
super.onSlashCommandInteraction(event);
if (event.getName().equals("raid")) {
OptionMapping option = event.getOption("raid");
if (option != null) {
OptionMapping raidChannel = event.getOption("raid");
OptionMapping audioNumber = event.getOption("audio");
if (raidChannel != null) {
AudioFilePlayer player = new AudioFilePlayer();
player.play("filepath");
System.out.println("Audio file finished!");
//Connecting to discord voice channel
AudioManager audioManager = event.getGuild().getAudioManager();
VoiceChannel connectedChannel = raidChannel.getAsVoiceChannel();
audioManager.openAudioConnection(connectedChannel);
event.getGuild().getAudioManager().closeAudioConnection();
event.reply("Raided!").setEphemeral(true).queue();
}
}
}
}
I can't seem to get it working.

How can I stop an audio line from recording in another method?

Is there anyway I can stop the line from capturing (line.stop) inside the stopCapture method?
public class Ouvir extends NewJFrame{
AudioFormat audioFormat;
TargetDataLine targetDataLine;
void captureAudio(){
Stop.setEnabled(true);
try{
audioFormat = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
AudioSystem.getLine(info);
line.open();
line.start();
}
catch (LineUnavailableException e) {}
}
void stopCapture(){
}
private AudioFormat getAudioFormat(){
float samplerate = 48000f;
return new AudioFormat(samplerate,8,1,true,true);
}
}
I'm guessing that you want to call line.stop(); or something to that effect in the stopCapture() method. If so, then the TargetDataLine line variable must be an instance field of your class and not a local variable. You'll also want to test for null before calling stop() on the field.
e.g.,
public class Ouvir extends NewJFrame{
AudioFormat audioFormat;
TargetDataLine targetDataLine;
private TargetDataLine line; // **add this field**. It starts out null
void captureAudio(){
Stop.setEnabled(true);
try{
audioFormat = getAudioFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
// change the code below
// TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info); // from this
line = (TargetDataLine) AudioSystem.getLine(info); // to this
AudioSystem.getLine(info);
line.open();
line.start();
}
catch (LineUnavailableException e) {}
}
void stopCapture(){
if (line != null && line.isRunning()) {
// here you call your stop method, if one exists
line.stop(); // ??? perhaps ???
// perhaps this would need to be called within a try/catch block as well, not sure
}
}
side note: this looks dangerous:
catch (LineUnavailableException e) {}
You shouldn't ignore exceptions, but rather should handle them when they occur.
Other issues: this looks to be part of a Swing GUI, and if so, you probably will need to take Swing threading issues into account so that you don't have any long-running code blocking the Swing event thread, freezing your GUI.

how to include sound in java

i have made a jar program that need to run an audio file
this is how i open the audio file(not in jar file)
Thread sound = new Thread(){
public void run(){
MakeSound.playSound("Raef.wav");
}
};
i run it with
sound.start();
and end it with
sound.stop();
when i run it on blue j its worked but the sound isnt play on the jar files
can someone solve this ?
i need to make a program with jar
nb : MakeSound is another class i used to play the sound
public class MakeSound {
private static final int BUFFER_SIZE = 128000;
private static File soundFile;
private static AudioInputStream audioStream;
private static AudioFormat audioFormat;
private static SourceDataLine sourceLine;
/**
* #param filename the name of the file that is going to be played
*/
public static void playSound(String filename){
String strFilename = filename;
// buka 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();
}
The exact steps to put an audio file in a jar depends on the IDE you are using.
What I normally do is to make a subfolder "audio" and put the audio files there. The subfolder is a subfolder of the code source.
Then, in the code, I create a URL that points to this subfolder.
URL url = this.getClass().getResource("audio/" + fileName);
I don't know about the specifics of MakeSound.playSound(). Hopefully it accepts a URL as a parameter. If it only accepts file names, you might need to rewrite it. Operating Systems generally aren't set up to find files that are packed in jars. URLs, though, are able to point inside of a jar.
Key point: the calling code is in a folder. I used "this" instead of invoking the class name of the calling code which is also possible. If this folder has a subfolder named "audio", the above line of code should find the file.

capturing internal audio java

i will record the sound from my programs. I use Ubuntu 14.04 and PulseAudio.
Now i try to record from pulseaudio but currently i'm only recording from my microphone.
How can i record the sound from pulseaudio instead of my microphone?
public static void captureAudio() {
try {
final AudioFormat format = getFormat();
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
final TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
Runnable runnable = new Runnable() {
int bufferSize = (int)format.getSampleRate() * format.getFrameSize();
byte buffer[] = new byte[bufferSize];
public void run() {
out = new ByteArrayOutputStream();
running = true;
try {
while (running) {
int count = line.read(buffer, 0, buffer.length);
if (count > 0) {
out.write(buffer, 0, count);
}
}
out.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
};
Thread captureThread = new Thread(runnable);
captureThread.start();
} catch (LineUnavailableException ex) {
ex.printStackTrace();
}
}
I tried some things to change this in my code:
Mixer mixer = AudioSystem.getMixer(null);
And then:
final TargetDataLine line = (TargetDataLine) mixer.getLine(info);
Hope anyone have a solution.
Greetings
Daniel
This problem cannot be solved from within Java alone. Java sees only the devices which are already there, as the following Java program demonstrates:
import javax.sound.sampled.*;
public class ListDevices {
public static void main(final String... args) throws Exception {
for (final Mixer.Info info : AudioSystem.getMixerInfo())
System.out.format("%s: %s %s %s %s%n", info, info.getName(), info.getVendor(), info.getVersion(), info.getDescription());
}
}
What you need to do is create a loopback device for your audio system. The following post shows how to do that: https://askubuntu.com/questions/257992/how-can-i-use-pulseaudio-virtual-audio-streams-to-play-music-over-skype The purpose was different, but it should be adaptable for your situation, as your situation seems simpler to me than the situation described in that post.
It should be possible to run those pactl commands from Java using Process.

Playing sound in a Java Desktop application

How do we play sound (a music file of any format like .wma, .mp3 ) in a Java desktop application? (not an applet)
I have used the following code (taken from another question on Stack Overflow) but it throws an Exception.
public class playsound {
public static void main(String[] args) {
s s=new s();
s.start();
}
}
class s extends Thread{
public void run(){
try{
InputStream in = new FileInputStream("C:\\Users\\srgf\\Desktop\\s.wma");
AudioStream as = new AudioStream(in); //line 26
AudioPlayer.player.start(as);
}
catch(Exception e){
e.printStackTrace();
System.exit(1);
}
}
}
The program when run throws the following Exception:
java.io.IOException: could not create audio stream from input stream
at sun.audio.AudioStream.<init>(AudioStream.java:82)
at s.run(delplaysound.java:26)
Use this library:
http://www.javazoom.net/javalayer/javalayer.html
public void play() {
String song = "http://www.ntonyx.com/mp3files/Morning_Flower.mp3";
Player mp3player = null;
BufferedInputStream in = null;
try {
in = new BufferedInputStream(new URL(song).openStream());
mp3player = new Player(in);
mp3player.play();
} catch (MalformedURLException ex) {
} catch (IOException e) {
} catch (JavaLayerException e) {
} catch (NullPointerException ex) {
}
}
Hope that helps everyone with a similar question :-)
Hmmm. This might look like advertisement for my stuff, but you could use my API here:
https://github.com/s4ke/HotSound
playback is quite easy with this one.
Alternative: use Java Clips (prebuffering)
... code ...
// specify the sound to play
File soundFile = new File("pathToYouFile");
//this does the conversion stuff for you if you have the correct SPIs installed
AudioInputStream inputStream =
getSupportedAudioInputStreamFromInputStream(new FileInputStream(soundFile));
// load the sound into memory (a Clip)
DataLine.Info info = new DataLine.Info(Clip.class, inputStream.getFormat());
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(sound);
// due to bug in Java Sound, explicitly exit the VM when
// the sound has stopped.
clip.addLineListener(new LineListener() {
public void update(LineEvent event) {
if (event.getType() == LineEvent.Type.STOP) {
event.getLine().close();
System.exit(0);
}
}
});
// play the sound clip
clip.start();
... code ...
Then you need this method:
public static AudioInputStream getSupportedAudioInputStreamFromInputStream(InputStream pInputStream) throws UnsupportedAudioFileException,
IOException {
AudioInputStream sourceAudioInputStream = AudioSystem
.getAudioInputStream(pInputStream);
AudioInputStream ret = sourceAudioInputStream;
AudioFormat sourceAudioFormat = sourceAudioInputStream.getFormat();
DataLine.Info supportInfo = new DataLine.Info(SourceDataLine.class,
sourceAudioFormat,
AudioSystem.NOT_SPECIFIED);
boolean directSupport = AudioSystem.isLineSupported(supportInfo);
if(!directSupport) {
float sampleRate = sourceAudioFormat.getSampleRate();
int channels = sourceAudioFormat.getChannels();
AudioFormat newFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,
sampleRate,
16,
channels,
channels * 2,
sampleRate,
false);
AudioInputStream convertedAudioInputStream = AudioSystem
.getAudioInputStream(newFormat, sourceAudioInputStream);
sourceAudioFormat = newFormat;
ret = convertedAudioInputStream;
}
return ret;
}
Source for the Clip example (with little changes by me): http://www.java2s.com/Code/Java/Development-Class/AnexampleofloadingandplayingasoundusingaClip.htm
SPIs are added via adding their .jars to the classpath
for mp3 these are:
http://www.javazoom.net/mp3spi/mp3spi.html
http://www.javazoom.net/javalayer/javalayer.html
http://www.tritonus.org/plugins.html (tritonus_share.jar)
Using JavaFX (which is bundled with your JDK) is pretty simple.
You will need the following imports:
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.util.Duration;
import java.nio.file.Paths;
Steps:
Initialize JavaFX:
new JFXPanel();
Create a Media (sound):
Media media = new Media(Paths.get(filename).toUri().toString());
Create a MediaPlayer to play the sound:
MediaPlayer player = new MediaPlayer(media);
And play the Media:
player.play();
You can set the start/stop times as well with MediaPlayer.setStartTime() and MediaPlayer.setStopTime():
player.setStartTime(new Duration(Duration.ZERO)); // Start at the beginning of the sound file
player.setStopTime(1000); // Stop one second (1000 milliseconds) into the playback
Or, you can stop playing with MediaPlayer.stop().
A sample function to play audio:
public static void playAudio(String name, double startMillis, double stopMillis) {
Media media = new Media(Paths.get(name).toUri().toString());
MediaPlayer player = new MediaPlayer(media);
player.setStartTime(new Duration(startMillis));
player.setStopTime(new Duration(stopMillis));
player.play();
}
More info can be found at the JavaFX javadoc.

Categories