How to change source data line for an audio stream? - java

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.

Related

How to use sound effects in Java 8? Snake eats apple

I wrote Snake code, and want to add a sound effect when snake eats an apple. I copyied a code from some guy on YT, but it doesn't work to me. Can somebody explain me how to do this?
Code:
import com.sun.tools.javac.Main;
import javax.sound.sampled.*;
import java.io.IOException;
import java.net.URL;
public class AppleEatSoundEffect {
public static Mixer mixer;
public static Clip clip;
public static void main(String[] args) {
Mixer.Info[] mixInfos = AudioSystem.getMixerInfo();
mixer = AudioSystem.getMixer(mixInfos[0]);
DataLine.Info dataInfo = new DataLine.Info(Clip.class, null);
try {
clip = (Clip) mixer.getLine(dataInfo);
} catch (LineUnavailableException lue) {
lue.printStackTrace();
}
try {
URL soundURL = Main.class.getResource("NotBad.wav");
AudioInputStream audioStream = AudioSystem.getAudioInputStream(soundURL);
clip.open(audioStream);
} catch (LineUnavailableException lue) {
lue.printStackTrace();
} catch (UnsupportedAudioFileException uafe) {
uafe.printStackTrace();
} catch (IOException ioe) {
ioe.printStackTrace();
}
clip.start();
do {
try {
Thread.sleep(100);
} catch (InterruptedException ie) {
ie.printStackTrace();
}
} while (clip.isActive());
}
}
Compiler says thas something wrong with clip = (Clip) mixer.getLine(dataInfo);:
Exception in thread "main" java.lang.IllegalArgumentException: Line unsupported: interface Clip
at java.desktop/com.sun.media.sound.PortMixer.getLine(PortMixer.java:131)
Below is a method which allows you to play audio files, in particular the common WAV or MIDI files. Try it...if you get your desired audio then let me know.
public Thread playWav(final File wavFile, final boolean... loopContinuous) {
String ls = System.lineSeparator();
// Was a file object supplied?
if (wavFile == null) {
throw new IllegalArgumentException(ls + "playWav() Method Error! "
+ "Sound file object can not be null!" + ls);
}
// Does the file exist?
if (!wavFile.exists()) {
throw new IllegalArgumentException(ls + "playWav() Method Error! "
+ "The sound file specified below can not be found!" + ls
+ "(" + wavFile.getAbsolutePath() + ")" + ls);
}
// Play the Wav file from its own Thread.
Thread t = null;
try {
t = new Thread("Audio Thread") {
#Override
public void run() {
try {
Clip clip = (Clip) AudioSystem.getLine(new Line.Info(Clip.class));
audioClip = clip;
clip.addLineListener((LineEvent event) -> {
if (event.getType() == LineEvent.Type.STOP) {
clip.drain();
clip.flush();
clip.close();
}
});
clip.open(AudioSystem.getAudioInputStream(wavFile));
// Are we to loop the audio?
if (loopContinuous.length > 0 && loopContinuous[0]) {
clip.loop(Clip.LOOP_CONTINUOUSLY);
}
clip.start();
}
catch (LineUnavailableException | UnsupportedAudioFileException | IOException ex) {
ex.printStackTrace();
}
}
};
t.start();
Thread.sleep(100);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return t;
}
To use this method simply call it wherever and whenever you want a particular sound effect to be played:
File file = new File("resources/NotBad.wav");
playWav(file);
Make sure the file object points to the correct file location. If you want to loop the audio file as for perhaps game background music then supply boolean true to the optional loopContinuous parameter:
File file = new File("resources/BackgroundMusic.mid");
playWav(file, true);

Why AudioInputStream read never returns -1?

I'm reading an AudioInputStream and using it to make a chunked POST request to a server in order to stream audio. I don't understand why read() method on the stream always returns 0, also after having called stop() and close() on TargetDataLine. I'm expecting at some point to have -1 since the stream is closed and there is no more data on it (EOF). This is causing me problems in Apache HTTP Client call that is making the POST, because at some point it expects -1 to terminate writing the output stream and in this way never terminates the write loop.
Here is the snippet:
public class MicrophoneTest {
// record duration, in milliseconds
static final long RECORD_TIME = 5000;
private static AudioFormat audioFormat = new AudioFormat(48000, 16, 1, true, false);
public static void main(String[] args) throws URISyntaxException, IOException {
final Microphone recorder = new Microphone(audioFormat);
recorder.open();
// creates a new thread that waits for a specified
// of time before stopping
Thread stopper = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(RECORD_TIME);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
recorder.close();
}
});
stopper.start();
// start recording
AudioInputStream inputStream = recorder.start();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1000];
int read = -1;
while ((read = inputStream.read(buffer)) != -1) {
System.out.println(read);
outputStream.write(buffer);
}
// Never gets here!
}
}
public class Microphone {
private static final Logger LOGGER = LoggerFactory.getLogger(Microphone.class);
// format of audio file
private static final AudioFileFormat.Type fileType = AudioFileFormat.Type.WAVE;
// the line from which audio data is captured
private TargetDataLine line;
private AudioFormat audioFormat;
public Microphone(AudioFormat audioFormat) {
this.audioFormat = audioFormat;
}
/**
* Prepare the line for recording
*
* #return
*/
public boolean open() {
try {
Info info = AudioSystem.getMixerInfo()[4];
line = (TargetDataLine) AudioSystem.getTargetDataLine(audioFormat, info);
line.open(audioFormat);
} catch (LineUnavailableException ex) {
LOGGER.error(ex.toString(), ex);
return false;
}
return true;
}
/**
* Captures the sound and return the stream
*/
public AudioInputStream start() {
if (line != null) {
line.start(); // start capturing
LOGGER.info("Start recording...");
return new AudioInputStream(line);
// AudioSystem.write(ais, fileType, outputStream);
} else {
throw new IllegalStateException("Line has not created. Cannot start recording");
}
}
/**
* Stops the recording process
*/
public void stop() {
line.stop();
LOGGER.info("Stop recording...");
}
/**
* Closes the target data line to finish capturing and recording *
*/
public void close() {
line.stop();
line.close();
LOGGER.info("Data line closed");
}
}
The microphone line never reaches the end of a file. It is either on or off. It is not reading a file from a disk or memory location.
I think you need to change your while loop to something like the following:
while(isRecording)
{
read = inputStream.read(buffer);
outputStream.write(buffer, 0, read);
}
and have your stop() method include
isRecording = false;
and your start() method include
isRecording = true;
etc. That sort of thing.

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.

Java TargetDataLine and SourceDataLine reopen doesn't work

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.

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