Checking the level of audio playback in a Mixer's Line? - java

I'm trying to figure out if sound of any kind is playing in Windows (by any application). If something is making a noise somewhere, I want to know about it!
After following the docs, I've found how to get a list of mixers on the machine, as well as lines for those mixers -- which, if I understand correctly, are what is used for input/output of the mixer.
However, the problem I'm having is that I don't know how to get the data I need from the line.
The only interface I see that has a notion of volume level is DataLine. The problem with that is that I can't figure out what returns an object that implements the dataline interface.
Enumerating all of the mixers and lines:
public static void printMixers() {
Mixer.Info[] mixers = AudioSystem.getMixerInfo();
for (Mixer.Info mixerInfo : mixers) {
Mixer mixer = AudioSystem.getMixer(mixerInfo);
try {
mixer.open();
Line.Info[] lines = mixer.getSourceLineInfo();
for (Line.Info linfo : lines) {
System.out.println(linfo);
}
}
catch (LineUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
That code enumerates and displays all of the audio devices on my machine. From that, shouldn't one of those Lines contain some kind of playback level data?

Oh you wish to find the volume? Well, not all hardware supports it, but here is how you get the dataline.
public static SourceDataLine getSourceDataLine(Line.Info lineInfo){
try{
return (SourceDataLine) AudioSystem.getLine(lineInfo);
}
catch(Exception ex){
ex.printStackTrace();
return null;
}
}
Then just call SourceDataLine.getLevel() to get the volume. I hope this helps.
NB: If the sound is originating from outside the JVM or not via the JavaSound API, this method will not detect the sound as the JVM does not have access to the OS equivalent of the SourceDataLine.
UPDATE: Upon further research, getLevel() is not implemented on most Systems. So I have manually implemented the method based off this forum discussion: https://community.oracle.com/message/5391003
Here are the classes:
public class Main {
public static void main(String[] args){
MicrophoneAnalyzer mic = new MicrophoneAnalyzer(FLACFileWriter.FLAC);
System.out.println("HELLO");
mic.open();
while(true){
byte[] buffer = new byte[mic.getTargetDataLine().getFormat().getFrameSize()];
mic.getTargetDataLine().read(buffer, 0, buffer.length);
try{
System.out.println(getLevel(mic.getAudioFormat(), buffer));
}
catch(Exception e){
System.out.println("ERROR");
e.printStackTrace();
}
}
}
public static double getLevel(AudioFormat af, byte[] chunk) throws IOException{
PCMSigned8Bit converter = new PCMSigned8Bit(af);
if(chunk.length != converter.getRequiredChunkByteSize())
return -1;
AudioInputStream ais = converter.convert(chunk);
ais.read(chunk, 0, chunk.length);
long lSum = 0;
for(int i=0; i<chunk.length; i++)
lSum = lSum + chunk[i];
double dAvg = lSum / chunk.length;
double sumMeanSquare = 0d;
for(int j=0; j<chunk.length; j++)
sumMeanSquare = sumMeanSquare + Math.pow(chunk[j] - dAvg, 2d);
double averageMeanSquare = sumMeanSquare / chunk.length;
return (Math.pow(averageMeanSquare,0.5d));
}
}
The method I used only works on 8bitPCM so we have to convert the encoding to that using these two classes. Here is the general abstract converter class.
import java.io.ByteArrayInputStream;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
abstract class AbstractSignedLevelConverter
{
private AudioFormat srcf;
public AbstractSignedLevelConverter(AudioFormat sourceFormat)
{
srcf = sourceFormat;
}
protected AudioInputStream convert(byte[] chunk)
{
AudioInputStream ais = null;
if(AudioSystem.isConversionSupported( AudioFormat.Encoding.PCM_SIGNED,
srcf))
{
if(srcf.getEncoding() != AudioFormat.Encoding.PCM_SIGNED)
ais = AudioSystem.getAudioInputStream(
AudioFormat.Encoding.PCM_SIGNED,
new AudioInputStream(new ByteArrayInputStream(chunk),
srcf,
chunk.length * srcf.getFrameSize()));
else
ais = new AudioInputStream(new ByteArrayInputStream(chunk),
srcf,
chunk.length * srcf.getFrameSize());
}
return ais;
}
abstract public double convertToLevel(byte[] chunk) throws IOException;
public int getRequiredChunkByteSize()
{
return srcf.getFrameSize();
}
}
And here is the one for 8BitPCM
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
public class PCMSigned8Bit extends AbstractSignedLevelConverter
{
PCMSigned8Bit(AudioFormat sourceFormat)
{
super(sourceFormat);
}
public double convertToLevel(byte[] chunk) throws IOException
{
if(chunk.length != getRequiredChunkByteSize())
return -1;
AudioInputStream ais = convert(chunk);
ais.read(chunk, 0, chunk.length);
return (double)chunk[0];
}
}
This is for TargetDataLine which may not work in your use case, but you could build a wrapper around SourceDataLine and use this to properly implement these methods. Hopes this helps.

Related

Extreme delay playing a audio stream from ipcam

(sorry, not an english speaker, expect lots of grammatical/syntactical error)
I'm developing a piece of software to manage D-Link Ip Cam (DCS-xxxx series and other). Because this camera expose an audio stream (some model even have a speaker for bidirectional communication), i would like to play it at user request.
All entry point are behind a http basic authentication (but weirdly enough i cant use http:\USER:PASS#192.168.1.100, because i get a 401).
I use the javax.sound.* package to do that, but for some reason the audio start playing after 15 to 20 seconds, with a total delay of 30-40 seconds EDIT: 45 seconds in average, but the audio is played from the beginning, so its even worse.
This is the class (bare minimum, just for testing purpose)
import java.io.IOException;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class AudioPlayer implements Runnable{
private URL URL;
private String USERNAME;
private String PASSWORD;
private volatile boolean stop = false;
public AudioPlayer(String url, String user, String pass) throws MalformedURLException{
this.URL = new URL(url);
this.USERNAME = user;
this.PASSWORD = pass;
}
public void shutdown() {
stop = true;
}
#Override
public void run() {
Authenticator.setDefault (new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication (USERNAME, PASSWORD.toCharArray());
}
});
try {
Clip clip = AudioSystem.getClip();
AudioInputStream inputStream = AudioSystem.getAudioInputStream(URL);
clip.open(inputStream);
clip.start();
while(!stop && clip.isRunning()) {}
clip.stop();
System.err.println("AUDIO PLAYER STOPPED");
} catch (LineUnavailableException | IOException | UnsupportedAudioFileException e) {
e.printStackTrace();
}
}
}
The Authenticator part is needed because ipcam use basic http autentication.
I've read somewhere that the AudioSystem make several pass with different algotithm to get the right one, then will reset the stream to the beginning and only then start to play.
So, because of this, maybe AudioSystem have some problem to realize what type of codec to use (maybe need some kind of header) and spent quite some time before start playing the audio.
It's worth to know that even VLC struggle to keep up with the streaming, losing up to 8 seconds before playing (8 seconds is way better than 20).
The IpCam is on a local network.
There is something wrong with my code? Some method i don't see?
Really don't know where to look with this one.
I was unable to find any meaningful answer here or elsewhere.
After fiddling with one answer, i've found the solution, wich provide 1 to 2 seconds delay (wich is the same delay of the official app or the web page configuration, so pretty much perfect).
private void playStreamedURL() throws IOException {
//to avoid 401 error
Authenticator.setDefault (new Authenticator() {
protected PasswordAuthentication getPasswordAuthentication() {
//USERNAME and PASSWORD are defined in the class
return new PasswordAuthentication (USERNAME, PASSWORD.toCharArray());
}
});
AudioInputStream AIS = null;
SourceDataLine line = null;
try {
//get the input stream
AIS = AudioSystem.getAudioInputStream(this.URL);
//get the format, Very Important!
AudioFormat format = AIS.getFormat();
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
//create the output line
line = (SourceDataLine) AudioSystem.getLine(info);
//open the line with the specified format (other solution manually create the format
//and thats is a big problem because things like sampleRate aren't standard
//For example, the IpCam i use for testing use 11205 as sample rate.
line.open(format);
int framesize = format.getFrameSize();
//NOT_SPECIFIED is -1, wich create problem with the buffer definition, so it's revalued if necessary
if(framesize == AudioSystem.NOT_SPECIFIED)
framesize = 1;
//the buffer used to read and write bytes from stream to audio line
byte[] buffer = new byte[4 * 1024 * framesize];
int total = 0;
boolean playing = false;
int r, towrite, remaining;
while( (r = AIS.read(buffer, total, buffer.length - total)) >= 0 ) { //or !=-1
total += r;
//avoid start the line more than one time
if (!playing) {
line.start();
playing = true;
}
//actually play the sound (the frames in the buffer)
towrite = (total / framesize) * framesize;
line.write(buffer, 0, towrite);
//if some byte remain, overwrite them into the buffer and change the total
remaining = total - towrite;
if (remaining > 0)
System.arraycopy(buffer, towrite, buffer, 0, remaining);
total = remaining;
}
//line.drain() can be used, but it will consume the rest of the buffer.
line.stop();
line.flush();
} catch (UnsupportedAudioFileException | IOException | LineUnavailableException e) {
e.printStackTrace();
} finally {
if (line != null)
line.close();
if (AIS != null)
AIS.close();
}
}
Still, some optimization can be done, but it work.

How to read an audio file? Which method should I use?

I have a panel with 2 buttons. When I click on the button 1, I'd simply like to read an audio file (a .WAV in that case). Then, when I click on the button 2, I'd like to stop the music.
I do some research, but I'm a little confused about the different methods.
Which one is the best in my case ? Can someone explains the difference between AudioClip, JavaSound and JavaMediaFramework please ?
I've also try an example, but it contains errors.
Here is my Main.class :
import java.io.ByteArrayInputStream;
import java.io.InputStream;
public class Main
{
public static void main(String[] args)
{
SoundPlayer player = new SoundPlayer("C:/Documents and Settings/All Users/Documents/Ma musique/Échantillons de musique/Symphonie n° 9 de Beethoven (scherzo).wma");
InputStream stream = new ByteArrayInputStream(player.getSamples());
player.play(stream);
}
}
Here is my SoundPlayer.class :
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.sound.sampled.*;
public class SoundPlayer
{
private AudioFormat format;
private byte[] samples;
/**
*
* #param filename le lien vers le fichier song (URL ou absolute path)
*/
public SoundPlayer(String filename)
{
try
{
AudioInputStream stream = AudioSystem.getAudioInputStream(new File(filename));
format = stream.getFormat();
samples = getSamples(stream);
}
catch (UnsupportedAudioFileException e){e.printStackTrace();}
catch (IOException e){e.printStackTrace();}
}
public byte[] getSamples()
{
return samples;
}
public byte[] getSamples(AudioInputStream stream)
{
int length = (int)(stream.getFrameLength() * format.getFrameSize());
byte[] samples = new byte[length];
DataInputStream in = new DataInputStream(stream);
try
{
in.readFully(samples);
}
catch (IOException e){e.printStackTrace();}
return samples;
}
public void play(InputStream source)
{
int bufferSize = format.getFrameSize() * Math.round(format.getSampleRate() / 10);
byte[] buffer = new byte[bufferSize];
SourceDataLine line;
try
{
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
line = (SourceDataLine)AudioSystem.getLine(info);
line.open(format, bufferSize);
}
catch (LineUnavailableException e)
{
e.printStackTrace();
return;
}
line.start();
try
{
int numBytesRead = 0;
while (numBytesRead != -1)
{
numBytesRead = source.read(buffer, 0, buffer.length);
if (numBytesRead != -1)
line.write(buffer, 0, numBytesRead);
}
}
catch (IOException e){e.printStackTrace();}
line.drain();
line.close();
}
}
LOGCAT :
javax.sound.sampled.UnsupportedAudioFileException: could not get audio input stream from input file
at javax.sound.sampled.AudioSystem.getAudioInputStream(Unknown Source)
at SoundPlayer.<init>(SoundPlayer.java:19)
at Main.main(Main.java:8)
Exception in thread "main" java.lang.NullPointerException
at java.io.ByteArrayInputStream.<init>(Unknown Source)
at Main.main(Main.java:9)
In advance, thanks a lot !
That exception will stay. *.wma files are not supported by standard.
Simplest solution would be to use *.wav files or other supported files
You can get more info on:
https://stackoverflow.com/tags/javasound/info
SoundPlayer player = new SoundPlayer("C:/Documents and Settings/All Users/" +
"Documents/Ma musique/Échantillons de musique/" +
"Symphonie n° 9 de Beethoven (scherzo).wma")
Ah, WMA. Great format, Java (Standard Edition) does not provide a Service Provider Interface that supports it.
You will either need to supply an SPI to allow Java Sound to support it, or use a different API. I don't know of any APIs that provide support for WMA. Can you encode it in a different format?
See the Java Sound info. page for a way to support MP3, but it requires the MP3 SPI from JMF.
Write down the full path of your music file it will works
I've found a solution to my problem.
In my case, the use of JAVAZOOM librairy is good.
Here is a sample, which only play an audio file when launching (no graphical part)
public class Sound
{
private boolean isPlaying = false;
private AdvancedPlayer player = null;
public Sound(String path) throws Exception
{
InputStream in = (InputStream)new BufferedInputStream(new FileInputStream(new File(path)));
player = new AdvancedPlayer(in);
}
public Sound(String path,PlaybackListener listener) throws Exception
{
InputStream in = (InputStream)new BufferedInputStream(new FileInputStream(new File(path)));
player = new AdvancedPlayer(in);
player.setPlayBackListener(listener);
}
public void play() throws Exception
{
if (player != null)
{
isPlaying = true;
player.play();
}
}
public void play(int begin,int end) throws Exception
{
if (player != null)
{
isPlaying = true;
player.play(begin,end);
}
}
public void stop() throws Exception
{
if (player != null)
{
player.stop();
isPlaying = false;
}
}
public boolean isPlaying()
{
return isPlaying;
}
public static void main(String[] args)
{
System.out.println("lecture de son");
try
{
Sound sound = new Sound("C:/Documents and Settings/cngo/Bureau/Stage-Save/TCPIP_AndroidJava/TCPIP_V6_Sound/OpeningSuite.mp3");
System.out.println("playing : " + sound.isPlaying());
sound.play();
System.out.println("playing : " + sound.isPlaying());
}
catch (Exception e){e.printStackTrace();}
}
}
Thanks to #murtaza.webdev for his answers !

Java Server Non Blocking Query

I am using the following code to read some data from Android client. All is going fine. But now i am asked to make this server code non blocking. Is there any suggestions for this ? I was trying to use threads but dont know how ? I am beginner in Java :)
Thanks
import java.awt.image.BufferedImage;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Calendar;
import java.util.Date;
import javax.imageio.ImageIO;
public class Server {
//Server Constructor
public Server()
{}
//Variables Initialization
private static ServerSocket server;
byte[] imagetemp;
private static Socket socket1;
private static boolean newImage;
private static Sdfdata data;
private static boolean cond;
public static int port;
private static int number = 0;
//Image Availability return method
public boolean imageAvailable()
{
return newImage;
}
public boolean clientchk()
{
return socket1.isClosed();
}
//Image Flag set by Vis group when image read.
public void setImageFlag(boolean set)
{
newImage = set;
}
// Send the data to the Vis Group
public Sdfdata getData()
{
return data;
}
//Starts the Server
public static boolean start(int port1)
{
try {
port=port1;
server = new ServerSocket(port1);
System.out.println("Waiting for Client to Connect");
//New thread here
socket1=server.accept();
} catch (IOException e) {
System.out.println("Cannot Connect");
e.printStackTrace();
return false;
}
return true;
}
//Stops the Server
public boolean stop()
{
try {
socket1.close();
}
catch (IOException e)
{
e.printStackTrace();
return false;
}
return true;
}
/**
* #param args
* #throws IOException
*/
public static void main(String[] args) throws IOException {
// Starts the server
start(4444);
// DataInput Stream for reading the data
DataInputStream in = null;
try {
in = new DataInputStream(socket1.getInputStream());
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
cond=true;
do {
try
{
//Read Image Data
int length = in.readInt();
//Create an ByteArray of length read from Client for Image transfer
Sdfdata data = new Sdfdata(length);
//for (int i=0; i<length; i++)
//{ data.image[i] = in.readbyte(); }
if (length > 0) {
in.readFully(data.image);
}
//Read Orientation
data.orientation[0] = in.readFloat(); //Orientation x
data.orientation[1] = in.readFloat(); //Orientation y
data.orientation[2] = in.readFloat(); //Orientation z
//Read GPS
data.longitude = in.readDouble();
data.latitude = in.readDouble();
data.altitude = in.readDouble();
//Display orientation and GPS data
System.out.println(data.orientation[0] + " " + data.orientation[1] + " " + data.orientation[2]);
System.out.println(data.longitude + " " + data.latitude + " " + data.altitude);
String fileName = "IMG_" + Integer.toString(++number) + ".JPG";
System.out.println("FileName: " + fileName);
FileOutputStream fos = new FileOutputStream(fileName);
fos.write(data.image);
fos.close();
/*InputStream ins = new ByteArrayInputStream(data.image);
BufferedImage image = ImageIO.read(ins);
ImageIO.write(image, "JPG", new File (fileName));
*/
//set image flag
newImage = true;
} catch (Exception e) {
//System.out.println("EOF Or ? " + e);
cond =false;
socket1.close();
server.close();
start(port);
}
}while (cond);
}
}
Your code starts a server, waits for a connection, reads some data from the first connected client, and then exits after writing this data to a file.
Being asked to make your server "non-blocking" could mean that you are being asked to change it to use asynchronous IO (probably unlikely), or it could mean that you're being asked to handle more than one client at a time - because currently you can only serve one client and then your program exits.
This question is hard to answer because your current code is very far away from where you need it to be and it seems like some reading up on networking, sockets, and Java programming in general would be a good way to start.
I'd recommend Netty for doing anything network-related in Java and their samples and documentation are good and easy to follow. Good luck!

how to play wav file in java 1.4

as title
How can i play a sound file repeatedly in java v1.4?
If you just want to play the wav file then 'org.life.java''s answer is correct. For other format types you can use JMF( http://www.oracle.com/technetwork/java/javase/tech/index-jsp-140239.html ).
Note: JMF is obsolete now... But it will work with jdk 1.4
import java.net.URL;
import javax.sound.sampled.*;
public class LoopSound {
public static void main(String[] args) throws Exception {
URL url = new URL(
"http://pscode.org/media/leftright.wav");
Clip clip = AudioSystem.getClip();
AudioInputStream ais = AudioSystem.
getAudioInputStream( url );
clip.open(ais);
clip.loop(0);
javax.swing.JOptionPane.
showMessageDialog(null, "Close to exit!");
}
}
This will work in JDK 1.4 (tested in Windows XP and JDK 1.4.2_06).
The other answer fails because as correctly stated in the comments, AudioSystem.getClip() does not exist on JDK 1.4. Below is a complete source (in the form of a main function, but it's adaptable to anything else) that uses DataLine and plays in a separate Thread for better overall performance as well:
import java.io.File;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
public class AudioTest {
public static void main(String[] args) throws Exception {
AudioInputStream ais = AudioSystem.getAudioInputStream(new File("C:/sound1.wav"));
AudioFormat format = ais.getFormat();
DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, format);
SourceDataLine sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo);
class PlayThread extends Thread {
private AudioInputStream ais;
private AudioFormat format;
private SourceDataLine sourceDataLine;
byte tempBuffer[] = new byte[10000];
public PlayThread(AudioInputStream ais, SourceDataLine sourceDataLine, AudioFormat format) {
this.ais = ais;
this.sourceDataLine = sourceDataLine;
this.format = format;
}
public void run() {
try {
sourceDataLine.open(this.format);
sourceDataLine.start();
int cnt;
while ((cnt = this.ais.read(tempBuffer, 0, tempBuffer.length)) != -1) {
if (cnt > 0) {
sourceDataLine.write(tempBuffer, 0, cnt);
}
}
sourceDataLine.drain();
sourceDataLine.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
new PlayThread(ais, sourceDataLine, format).start();
}
}
Both question and answers are really old, but I just had to make this work on a fanless mini PC that only run windows XP so... ¯\_(ツ)_/¯

Exception with Freetts when using kevin or mbrola

I am trying to run a program using freetts. I am able to compile the program however I am not able to use kevin or mbrola voices I get the follwing output message at the end
System property "mbrola.base" is undefined. Will not use MBROLA voices.
LINE UNAVAILABLE: Format is pcm_signed 16000.0 Hz 16 bits 1 channel big endian
import javax.speech.*;
import javax.speech.synthesis.*;
import java.util.*;
class freetts {
public static void main(String[] args) {
try{
Calendar calendar = new GregorianCalendar();
String sayTime = "It is " + calendar.get(Calendar.HOUR) + " " + calendar.get(Calendar.MINUTE) + " " + (calendar.get(Calendar.AM_PM)==0 ? "AM":"PM");
Synthesizer synth = Central.createSynthesizer(null);
synth.allocate();
synth.resume();
synth.speakPlainText(sayTime, null);
synth.waitEngineState(Synthesizer.QUEUE_EMPTY);
synth.deallocate();
}
catch(Exception e){
e.printStackTrace();
}
}
}
It seems that "To enable FreeTTS support for MBROLA, merely copy mbrola/mbrola.jar to lib/mbrola.jar. Then, whenever you run any FreeTTS application, specify the "mbrola.base" directory as a system property:
java -Dmbrola.base=/home/jim/mbrola -jar bin/FreeTTSHelloWorld.jar mbrola_us1"
I found this at:
http://freetts.sourceforge.net/mbrola/README.html
http://workorhobby.blogspot.com/2011/02/java-audio-freetts-line-unavailable.html
A big thanks to the author.
A program based on FreeTTS, the free text-to-speech engine for Java, was getting occasional errors
"LINE UNAVAILABLE: Format is ..."
Turns out there is no Java Exception or other mechanism to detect this error that occurs inside the FreeTTS library. All you get is the message on System.out, so there is no good way to react programatically.
Workaround: Configure the FreeTTS audio player to attempt accessing the audio device more than once until it succeeds. In this example, a short delay of 0.1 seconds is used to not miss an opportunity to grab the audio device; we keep trying for 30 seconds:
System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.openFailDelayMs", "100");
System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.totalOpenFailDelayMs", "30000");
If the audio device is permanently used by another program, there is of course no way to get access. Under Linux, this command will display the ID of the process that is currently holding the audio device, so you can then try to get rid of the offending program:
/sbin/fuser /dev/dsp
The second phrase has nothing to do with mbrola, but with a horrendous java linux sound bug that is still not fixed.
Check the third post here:
https://forums.oracle.com/forums/thread.jspa?threadID=2206163
That is happening because freetts "trusts" the sourcedataline, instead of doing the workaround on that post. The bug is in the jdk, but can be worked around by finding where in freetts that is happening and inserting the workaround & recompiling.
Here is a testcase
package util.speech;
import java.util.Iterator;
import java.util.Locale;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;
public class VoiceTest {
public VoiceTest() {
}
#BeforeClass
public static void setUpClass() throws Exception {
}
#AfterClass
public static void tearDownClass() throws Exception {
}
#Before
public void setUp() {
}
#After
public void tearDown() {
}
#Test
public void testDataLineAvailableAndBuggyInJDK() throws LineUnavailableException {
boolean failedSimpleGetLine = false;
AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
SourceDataLine line = null;
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
try {
line = (SourceDataLine) AudioSystem.getLine(info);
} catch (LineUnavailableException e) {
//ok, at least it says so
throw e;
}
try {
//if this fails the jdk is very buggy, since it just told us
//the line was available
line.open(format);
} catch (LineUnavailableException e) {
failedSimpleGetLine = true;
} finally {
if (line.isOpen()) {
line.close();
}
}
//now if this is true, test if it's possible to get a valid sourcedataline
//or the only bug is adquiring a sourcedataline doesn't throw a lineunavailable
//exception before open
Assume.assumeTrue(failedSimpleGetLine);
line = getSourceDataLine(format);
if (line == null) {
return;
}
try {
line.open(format);
} catch (LineUnavailableException e) {
//ok then it is consistent, and there is only one bug
fail("Line Unavailable after being adquired");
} finally {
if (line.isOpen()) {
line.close();
}
}
fail("line available after first test not managing to adquire it");
}
private SourceDataLine getSourceDataLine(AudioFormat format) {
try {
DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
for (Mixer.Info mi : AudioSystem.getMixerInfo()) {
SourceDataLine dataline = null;
try {
Mixer mixer = AudioSystem.getMixer(mi);
dataline = (SourceDataLine) mixer.getLine(info);
dataline.open(format);
dataline.start();
return dataline;
} catch (Exception e) {
}
if (dataline != null) {
try {
dataline.close();
} catch (Exception e) {
}
}
}
} catch (Exception e) {
}
return null;
}
}
I know i am posting it little late, but this may help someone. I tried with both kevin and mbrola, and it worked for me. Please find the code below.
package com.mani.texttospeech;
import java.beans.PropertyVetoException;
import java.util.Locale;
import javax.speech.AudioException;
import javax.speech.Central;
import javax.speech.EngineException;
import javax.speech.EngineStateError;
import javax.speech.synthesis.Synthesizer;
import javax.speech.synthesis.SynthesizerModeDesc;
import javax.speech.synthesis.Voice;
/**
*
* #author Manindar
*/
public class SpeechUtils {
SynthesizerModeDesc desc;
Synthesizer synthesizer;
Voice voice;
public void init(String voiceName) throws EngineException, AudioException, EngineStateError, PropertyVetoException {
if (desc == null) {
System.setProperty("freetts.voices", "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory");
desc = new SynthesizerModeDesc(Locale.US);
Central.registerEngineCentral("com.sun.speech.freetts.jsapi.FreeTTSEngineCentral");
synthesizer = Central.createSynthesizer(desc);
synthesizer.allocate();
synthesizer.resume();
SynthesizerModeDesc smd = (SynthesizerModeDesc) synthesizer.getEngineModeDesc();
Voice[] voices = smd.getVoices();
for (Voice voice1 : voices) {
if (voice1.getName().equals(voiceName)) {
voice = voice1;
break;
}
}
synthesizer.getSynthesizerProperties().setVoice(voice);
}
}
public void terminate() throws EngineException, EngineStateError {
synthesizer.deallocate();
}
public void doSpeak(String speakText) throws EngineException, AudioException, IllegalArgumentException, InterruptedException {
synthesizer.speakPlainText(speakText, null);
synthesizer.waitEngineState(Synthesizer.QUEUE_EMPTY);
}
public static void main(String[] args) throws Exception {
SpeechUtils su = new SpeechUtils();
su.init("kevin16");
// su.init("kevin");
// su.init("mbrola_us1");
// su.init("mbrola_us2");
// su.init("mbrola_us3");
// high quality
su.doSpeak("Hi this is Manindar. Welcome to audio world.");
su.terminate();
}
}
And add the below dependencies to your pom.xml file.
<dependencies>
<dependency>
<groupId>net.sf.sociaal</groupId>
<artifactId>freetts</artifactId>
<version>1.2.2</version>
</dependency>
</dependencies>
Hope this will be helpful.

Categories