I have a problem while recording the audio. I created a servlet and I modified the java sound API demo code to some extent and finally I can record the audio. The problem is that when I play the audio I can see the total time of the audio stored as 645.45 or something like that, but I have been recording the audio only for a couple of mins. One more problem is the audio is getting saved in the Eclipse directory instead of the project directory.
This is the servlet code.
package com;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.Clip;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.TargetDataLine;
public class SoundRecorder extends HttpServlet {
private static final long serialVersionUID = 1L;
static protected boolean running;
static ByteArrayOutputStream out;
double fileName = Math.random();
//strFilename = nowLong.toString();
public SoundRecorder() {
System.out.println("Filename will be..." + fileName + ".wav");
}
public void init() {
}
public void destroy() {
}
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("call received..");
String method = request.getParameter("method");
System.out.println(method);
if("record".equalsIgnoreCase(method)) {
captureAudio(true);
}
else if("stop".equalsIgnoreCase(method)) {
captureAudio(false);
}
else if("play".equalsIgnoreCase(method)) {
System.out.println("yet to write");
playAudio();
}
}
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
System.out.println("call received..");
String method = request.getParameter("method");
System.out.println(method);
doGet(request, response);
}
private void captureAudio(boolean capturing) {
File outputFile = new File(fileName + ".wav");
AudioFormat audioFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED,44100.0F, 16, 2, 4, 44100.0F, false);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, audioFormat);
TargetDataLine targetDataLine = null;
try
{
targetDataLine = (TargetDataLine) AudioSystem.getLine(info);
targetDataLine.open(audioFormat);
}
catch (LineUnavailableException e)
{
System.out.println("unable to get a recording line");
e.printStackTrace();
System.exit(1);
}
AudioFileFormat.Type targetType = AudioFileFormat.Type.WAVE;
final Recorder recorder = new Recorder(targetDataLine,targetType,outputFile);
System.out.println("Recording...");
if(capturing){
recorder.start();
}
else {
recorder.stopRecording();
}
}
private void playAudio() {
try {
File file = new File(fileName + ".wav");
AudioInputStream stream = AudioSystem.getAudioInputStream(file);
AudioFormat format = stream.getFormat();
DataLine.Info info = new DataLine.Info(Clip.class, stream.getFormat());
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(stream);
clip.start();
} catch (Exception e) {
System.err.println("Line unavailable: " + e);
System.exit(-4);
}
}
}
And this is the recorder class
public class Recorder extends Thread {
private TargetDataLine m_line;
private AudioFileFormat.Type m_targetType;
private AudioInputStream m_audioInputStream;
private File m_outputFile;
public Recorder(TargetDataLine line,
AudioFileFormat.Type targetType,
File file)
{
m_line = line;
m_audioInputStream = new AudioInputStream(line);
m_targetType = targetType;
m_outputFile = file;
}
/** Starts the recording.
To accomplish this, (i) the line is started and (ii) the
thread is started.
*/
public void start()
{
m_line.start();
super.start();
}
/** Stops the recording.
*/
public void stopRecording()
{
m_line.stop();
m_line.close();
}
/** Main working method.
*/
public void run()
{
try
{
AudioSystem.write(
m_audioInputStream,
m_targetType,
m_outputFile);
}
catch (IOException e)
{
e.printStackTrace();
}
}
private static void closeProgram()
{
System.out.println("Program closing.....");
System.exit(1);
}
private static void out(String strMessage)
{
System.out.println(strMessage);
}
}
When developing with servlets, you need to realize that there's only one servlet instance throughout the whole webapp's lifetime, from startup until shutdown. So, the HTTP requests from all visitors, all sessions, all browser windows/tabs, etc will all share the same servlet instance. Also, when you make a variable static, it will be shared among all instances of the same class (which is not really relevant here since there's only one servlet instance anyway).
In other words, those variables which you've declared in the servlet are not threadsafe:
static protected boolean running;
static ByteArrayOutputStream out;
double fileName = Math.random();
There's only one of them and they are used by all visitors simultaneously. For the first two variables, which are continuously modified, this will lead to major threadsafety problems and for the third variable this means that all visitors record to the very same file. You need to declare them inside the doGet() block. You'd like to store the recording in the session by an unique request based token as key and then pass that key to the subsequent requests.
As to the problem of the file being saved at the unexpected location; when you use relative paths in java.io.File in a servlet, then it will be relative to the directory from where the webserver is started. If you start it from inside Eclipse, then it's saved in Eclipse directory. You'd like to use absolute path in java.io.File instead. If your intent is to save it in public webcontent (there where your JSP's and the /WEB-INF folder is located), then you need ServletContext#getRealPath() to convert a web path to an absolute disk path.
String relativeWebPath = "filename.ext";
String absoluteDiskPath = getServletContext().getRealPath(relativeWebPath);
File file = new File(absoluteDiskPath);
There's however another problem with this: all files will get erased whenever you redeploy the webapp. If you want a bit more permanent storage, then you'd like to store it outside the web project. E.g. C:/path/to/recordings.
File file = new File("C:/path/to/recordings/filename.ext");
Related
I'm trying to load a .wav file in my EnviromentAudio object, but I received only an UnsupportedAudioFileException and I don't know why. Because the file is a wav and I've tried to encode it as an unsigned 8 bit, as a signed 16 bit, with a 44100 bit rate, as a GSM, as a A-law... long story short I've tried a lot of encoding, as many people suggested, but no one worked. Probably I'm not getting something, so, I want to ask what I'm doing wrong.
EDIT:
As pointed out I should have specified some things: first of all, to set some context, I am using Java 8 to create a little pc game for a project, which must uses the basics components of java. Said that, I'm using the ClassLoader
, because I have a mess in the project folder. It does not follow the convention and I have to keep like that. It's structured like this:
-src
-app
-audio
EnviromentAudio.java // Class that need to load soundtrack.wav
-res
-audio
Soundtrack.wav // Audio to be loaded
And I know that a getResource.. should start always with a /, but if I add that slash, then every attempt to get a resource results in a NPE. Probably that's caused by the folders disposition and, by the way, the resources folder is set as source folder, so I'm not even quite sure about that, cause, also, I've already used the getResource to get other files without problems.
In this case The getResource works fine, that is it retrieves the file, but the AudioSystem generates an error. I've tried to isolate the parties involved, but the only problem seems to be here. I'm adding the AudioManager class, the Audio class inherited by EnviromentAudio, and the whole EnviromentAudio, with the hope that it will be of help for a better understanding. I also provided a main in the AudioManager class, which should be enough to replicate the error.
Audio class:
package application.core.audio;
import java.util.ArrayList;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.swing.JOptionPane;
public abstract class Audio
{
protected static final String AUDIOERROR="Error in loading audio. "
+ "Execution Failed, please, restart the game. "
protected static final String AUDIOERRORTITLE="Audio loading error";
protected ArrayList<Clip> multimedia;
protected Clip currentAudio;
protected FloatControl gainControl;
public Audio() {
multimedia=new ArrayList<Clip>();
currentAudio=null;
}
protected abstract void getResources();
public void playAudio(int index) {
try
{
currentAudio=multimedia.get(index);
gainControl=(FloatControl) currentAudio.getControl(
FloatControl.Type.MASTER_GAIN);
currentAudio.open();
} catch (LineUnavailableException e)
{
e.printStackTrace();
JOptionPane.showMessageDialog(null, AUDIOERROR,
AUDIOERRORTITLE, JOptionPane.ERROR_MESSAGE);
}
currentAudio.start();
}
public void loopAudio(int index) {
currentAudio=multimedia.get(index);
// gainControl=(FloatControl) currentAudio.getControl(
// FloatControl.Type.MASTER_GAIN);
// currentAudio.open();
// currentAudio.start();
currentAudio.loop(Clip.LOOP_CONTINUOUSLY);
}
public void repeatAudio(int index, int times) {
try
{
currentAudio=multimedia.get(index);
gainControl=(FloatControl) currentAudio.getControl(
FloatControl.Type.MASTER_GAIN);
currentAudio.open();
} catch (LineUnavailableException e)
{
e.printStackTrace();
JOptionPane.showMessageDialog(null, AUDIOERROR,
AUDIOERRORTITLE, JOptionPane.ERROR_MESSAGE);
}
currentAudio.loop(times);
}
public void stopAudio(int index) {
multimedia.get(index).stop();
multimedia.get(index).close();
}
public void setVolume(float volume) {
float range=gainControl.getMaximum()-gainControl.getMinimum();
float gain=(range-volume)+gainControl.getMinimum();
gainControl.setValue(gain);
}
public boolean currentAudioIsOpen() {return currentAudio.isOpen();}
public void openCurrentAudio() {
if (!currentAudio.isOpen())
try
{
currentAudio.open();
} catch (LineUnavailableException e)
{
e.printStackTrace();
JOptionPane.showMessageDialog(null, AUDIOERROR,
AUDIOERRORTITLE, JOptionPane.ERROR_MESSAGE);
}
}
public void openAndPlayCurrentAudio() {
if (!currentAudio.isOpen())
openCurrentAudio();
currentAudio.start();
}
public void playCurrentAudio() {currentAudio.start();}
public void loopCurrentAudio() {currentAudio.loop(Clip.LOOP_CONTINUOUSLY);}
public void repeatCurrentAudio(int times) {currentAudio.loop(times);}
public void stopCurrentAudio() {currentAudio.stop();}
public void stopAndCloseCurrentAudio() {
currentAudio.stop();
currentAudio.close();
}
}
This is my EnviromentAudio class that produce the exception:
package application.core.audio;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class EnviromentAudio extends Audio
{
public static final int SOUNDTRACK=0;
public EnviromentAudio()
{
super();
getResources();
this.gainControl=(FloatControl) currentAudio.getControl(FloatControl.Type.MASTER_GAIN);
}
#Override
protected void getResources()
{
try
{
ClassLoader loader=EnviromentAudio.class.getClassLoader();
multimedia.add(AudioSystem.getClip());
multimedia.get(SOUNDTRACK).open(AudioSystem.getAudioInputStream( // here the exception is thrown (on getAudioInputStream)
loader.getResourceAsStream("resources"+File.separator+"audio"+File.separator+
"soundtrack"+File.separator+"igpeSoundtrack.wav")));
currentAudio=multimedia.get(SOUNDTRACK);
} catch (LineUnavailableException e)
{
e.printStackTrace();
} catch (IOException | UnsupportedAudioFileException e1)
{
e1.printStackTrace();
}
}
}
AudioManager class:
package application.core.audio;
public class AudioManager
{
private static AudioManager instance=null;
private EnviromentAudio soundtrack;
private PlayerAudio playerAudio;
private AudioManager() {
soundtrack=new EnviromentAudio();
// playerAudio=new PlayerAudio();
soundtrack.loopAudio(EnviromentAudio.SOUNDTRACK);
}
public static AudioManager getInstance() {
if (instance==null)
instance=new AudioManager();
return instance;
}
public Audio getSoundtrack() {return soundtrack;}
public Audio getPlayerSounds() {return playerAudio;}
public void setVolume(float volume) {
soundtrack.setVolume(volume);
playerAudio.setVolume(volume);
}
public float getVolume() {return soundtrack.gainControl.getValue();}
public static void main(String[] args)
{
AudioManager a=AudioManager.getInstance();
}
}
And here is the error:
javax.sound.sampled.UnsupportedAudioFileException: Stream of unsupported format
at java.desktop/javax.sound.sampled.AudioSystem.getAudioInputStream(AudioSystem.java:1020)
at application.core.audio.EnviromentAudio.getResources(EnviromentAudio.java:29)
at application.core.audio.EnviromentAudio.<init>(EnviromentAudio.java:18)
at application.core.audio.AudioManager.<init>(AudioManager.java:11)
at application.core.audio.AudioManager.getInstance(AudioManager.java:19)
at application.MainApplication.audioInitialize(MainApplication.java:44)
at application.MainApplication.main(MainApplication.java:25)
This is more to help with troubleshooting than a solution (expanding on Andrew Thompson's suggestion of making an MRE. Are you using a particular framework? Or is it something of your own making? For a second I though it might be Android (due to presence of AudioManager).
Following is a more minimal example for play testing your .wav file. Put the wav file in the same folder as this class. Does your .wav file play when using this?
import java.io.IOException;
import java.net.URL;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class BasicClipExample {
public static void main(String[] args) {
try {
BasicClipExample.run();
} catch (UnsupportedAudioFileException | IOException
| LineUnavailableException | InterruptedException e) {
e.printStackTrace();
}
}
private static void run() throws UnsupportedAudioFileException,
IOException, LineUnavailableException, InterruptedException
{
String filename = "yourSound.wav";
URL url = BasicClipExample.class.getResource(filename);
AudioInputStream ais = AudioSystem.getAudioInputStream(url);
DataLine.Info info = new DataLine.Info(Clip.class, ais.getFormat());
Clip clip = (Clip) AudioSystem.getLine(info);
clip.open(ais);
clip.start();
Thread.sleep(6000); // plays up to 6 seconds of sound before exiting
clip.close();
}
}
If it works, then something is odd about your framing code. From here you can progressively check if things like the file separator logic are working. You can also add some lines to print out the AudioFormat if the file loads.
Another way I sometimes inspect files is to load them into Audacity, which is free. Info about the file format is pretty easy to inspect with that tool. If I had to wager, and the issue IS the .wav format, I'm guessing that the file is recorded at a higher quality level than Java is set to work with, e.g., 48000 (maybe Java supports?) or 96000 fps or 24- or 32-bit encoding rather than 16-bit.
I have to move huge number of file(almost 60 MB each) from folder A to folder B. Folder B is a i/p folder for a a Spring scheduled task. it picks those files and start processing in parallel. I am using Guava's file utility methods to move the files.
Files.move(sourceFile,targetFile,Charsets.UTF_8);
I do see error in my TaskScheduler class that the file is not there to read
at org.apache.commons.io.FileUtils.openInputStream(FileUtils.java:299) ~[commons-io-2.4.jar:2.4]
at org.apache.commons.io.FileUtils.lineIterator(FileUtils.java:1856) ~[commons-io-2.4.jar:2.4]
at com.varun.processor.readFile(Processor.java:342) ~[classes/:?]
My hunch is that File is in copying and hence Spring scheduled thread couldn't acquire the lock to read it.As per Guava's doc it says its move method behave like mv command on unix but I see code as copy in guava jar.
Can anyone suggest a better way to move files on unix system from spring app Where o/p directory is i/p for another downstream process.
moving files with Guava works fine. you just have to keep trying to read the file until it succeeds.
I tested moving a file with size 525 MB and Guava moved it in less than 1 second.
see below for an example (I intentionally added a delay before moving the file, so the file processor will try to open the file before and while it was being moved) :
import com.google.common.io.ByteSource;
import com.google.common.io.Files;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* <dependency>
* <groupId>com.google.guava</groupId>
* <artifactId>guava</artifactId>
* <version>22.0</version>
* </dependency>
*/
public class GuavaFileMoveExample {
private static final Logger LOGGER = Logger.getLogger("GuavaFileMoveExample");
public static void main(String[] args) throws IOException, InterruptedException {
GuavaFileMoveExample a = new GuavaFileMoveExample();
a.doTheWork();
}
private void doTheWork() throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(new FileMover());
executorService.submit(new FileProcessor());
executorService.shutdown();
executorService.awaitTermination(10, TimeUnit.SECONDS);
}
}
class FileMover implements Callable<Void> {
private static final Logger LOGGER = Logger.getLogger("FileMover");
#Override
public Void call() throws Exception {
Thread.sleep(1000);
moveFile();
return null;
}
private void moveFile() {
final File sourceFile = new File("/tmp/origin/ideaIU-2016.3-no-jdk.tar.gz");
final File targetFile = new File("/tmp/destination/ideaIU-2016.3-no-jdk.tar.gz");
try {
LOGGER.log(Level.INFO, "started moving file");
Files.move(sourceFile, targetFile);
LOGGER.log(Level.INFO, "finished moving file");
} catch (IOException e) {
LOGGER.log(Level.WARNING, "ioexception while moving file ", e);
}
}
}
class FileProcessor implements Callable<Void> {
private static final Logger LOGGER = Logger.getLogger("FileProcessor");
#Override
public Void call() throws Exception {
readBinaryFile("/tmp/destination/ideaIU-2016.3-no-jdk.tar.gz");
return null;
}
private byte[] readBinaryFile(String aFileName) {
File file = new File(aFileName);
ByteSource source = Files.asByteSource(file);
byte[] result = null;
while (result == null) {
try {
LOGGER.log(Level.INFO, "started reading file");
result = source.read();
LOGGER.log(Level.INFO, "finished reading file. size: " + result.length);
} catch (FileNotFoundException e) {
// expected if file is not yet at destination
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "error reading file", e);
break;
}
}
return result;
}
}
I've been trying to use the "Trail: Sound" from Oracle and I've gotten to this part. https://docs.oracle.com/javase/tutorial/sound/playing.html#113609
"Using a Clip"
Well I tried to follow the directions which aren't exactly specific and I made some code that seems like it should work. It basically matches examples I found online that work for other people. On my machine nothing happens the program ends without playing any sound right after I start it. It doesn't say any errors.
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Line;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Clip;
import javax.sound.sampled.AudioFormat;
import java.io.File;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
class Demo{
public static void main(String[] args) throws LineUnavailableException, UnsupportedAudioFileException, IOException{
File file = new File("song1.wav");
AudioFileFormat audioFileFormat = AudioSystem.getAudioFileFormat(file);
AudioFormat audioFormat = audioFileFormat.getFormat();
javax.sound.sampled.DataLine.Info dataLineInfo = new javax.sound.sampled.DataLine.Info(Clip.class,audioFormat);
Line theLine = AudioSystem.getLine(dataLineInfo);
Clip clip = (Clip)theLine;
AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(file);
clip.open(audioInputStream);
clip.start();
}
}
EDIT: I figured out after clip.start() I needed to keep the program open.
I use that class to play MP# sounds and works for me
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import javazoom.jl.player.Player;
import monitorbixao.Main;
/**
*
* #author C007329
*/
public class MusicPlayer extends Thread {
private File music;
private Player player;
public MusicPlayer(File music) {
this.music = music;
}
#Override
public void run() {
play();
}
public void play() {
try {
FileInputStream stream = new FileInputStream(music);
BufferedInputStream buffer = new BufferedInputStream(stream);
this.player = new Player(buffer);
//System.out.println("Executando...");
this.player.play();
//System.out.println("Terminado");
} catch (Exception e) {
//System.out.println("Erro!");
Main.logApp.addMsgLog(MusicPlayer.class.getCanonicalName(), e.getMessage());
e.printStackTrace();
}
}
public void close() {
this.player.close();
//System.out.println("Interrompido...");
}
}
I figured it out. I needed to keep the program open so after "clip.start();" I added this code
java.io.Console c = System.console();
if (c == null) {
System.err.println("No console.");
System.exit(1);
}
String nothing = c.readLine("Wait... ");
:D
So my Problem is that I have to create a Singleton pattern counter for numeric name giving. For example "1", "2", "3" etc. The idea is that every time i start the application and the Server(tomcat), it gets the last number and when I upload another image it should continue from there. Lets say the last one was "43", so the the next time I start the application it should know it and put "44" for the next image upload.
I'm not that good in Java so please give me some patience :)
This is my FileUploadServlet. It handles the request from the fileUploadForm.jsp by taking the file from the submit.
package upload;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import utils.FormatChecker;
import utils.UnzipFile;
//Servlet for handling the Upload request from the Index.jsp
#MultipartConfig
public class FileUploadServlet extends HttpServlet {
// Instace of the FileUpload object
private FileUploader uploader = new FileUploader();
// Instance of the FormatChecker object
private FormatChecker checker = new FormatChecker();
// Instance of the UnzipFile object
private UnzipFile unzip = new UnzipFile();
private static final long serialVersionUID = 1L;
private static final String SAVE_FOLDER = "C:\\Users\\cuche\\Desktop\\tomcat\\apache-tomcat-7.0.47\\webapps\\files";
/**
* #see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
response.sendRedirect("error.jsp");
}
/**
* #see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String contentType;
boolean isFormatValid;
Part filePart = request.getPart("file");
contentType = filePart.getContentType();
ServletContext context = getServletContext();
String appPath = context.getRealPath("/");
String fileNameOld = getFileName(filePart);
String fileNameNew = appPath + fileNameOld;
isFormatValid = checker.check(contentType);
pleas ignore the part with the FileUnziper
if (isFormatValid == true) {
if (contentType == ("application/x-zip-compressed")) {
unzip.FileUnziper(fileNameNew, SAVE_FOLDER);
} else {
//gets the content and saves in form of a stream
InputStream fileContent = filePart.getInputStream();
//using the uploadImage method of uploader class
uploader.uploadImage(fileNameNew, fileContent);
}
try {
response.sendRedirect("result.jsp");
} catch (IOException ex) {
response.getWriter().append(ex.getLocalizedMessage());
}
} else {
response.getWriter().append("Format is wrong");
}
}
// method for removing header for proper file upload
private String getFileName(Part part) {
for (String cd : part.getHeader("content-disposition").split(";")) {
if (cd.trim().startsWith("filename")) {
String filename = cd.substring(cd.indexOf('=') + 1).trim()
.replace("\"", "");
return filename.substring(filename.lastIndexOf('/') + 1)
.substring(filename.lastIndexOf('\\') + 1); // MSIE fix.
}
}
return null;
}
}
This is my FileUploader class
package upload;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* #author Iwan Cuche
* #date:
*/
public class FileUploader {
/**
* This method reads a File
*
* #param fileName
* #param stream
*/
public void uploadImage(String fileName, InputStream stream)
throws IOException {
try {
File file = new File(fileName);
OutputStream os = new FileOutputStream(file);
int data;
while ((data = stream.read()) != -1) {
os.write(data);
}
os.flush();
os.close();
System.out.println("Uploaded file successfully saved in "
+ file.getAbsolutePath());
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
}
This is my Singleton class
package utils;
public class ServerCounter {
private static ServerCounter INSTANCE = new ServerCounter();
private ServerCounter() {};
public static ServerCounter getInstance() {
return INSTANCE;
}
}
I hope someone can help me because I'm not sure how to go at it.
In ServerCounter, add
private final AtomicLong counter = new AtomicLong();
public String nextval() { return String.valueOf(counter.incrementAndGet()); }
Each time you call INSTANCE.nextval() you'll get a fresh numeric string.
Clearly, each time you restart your application, the counter will restart.
ok, first you have to persist your counter if you want to get it after tomcat shutdown. we need listener for tomcat:
package utils;
public class ContextListener implements ServletContextListener{
void contextInitialized(ServletContextEvent sce){ // we could call loadFromFile here as well
}
//will be executed at tomcat shutdown
void contextDestroyed(ServletContextEvent sce){
ServerCounter .getInstance().writeToFile();
}
}
now the singleton(like in Marko's answer:)):
package utils;
public class ServerCounter {
private static ServerCounter INSTANCE = new ServerCounter();
private final AtomicLong counter;
private ServerCounter() {
//load value from file, do you need help by it?
long value = this.loadCounterFromFile();
counter = new AtomicLong(value);
};
private long loadCounterFromFile(){
BufferedReader br = null;
try {
//no problem if there is no file, we will return 0 in this case
br = new BufferedReader(new FileReader("C:\\Test\\counter.txt"));
String line = br.readLine();
if(line != null && line.length() > 0)
return Long.parseLong(line);
return 0;
//catch all exceptionse, because we could get NumberFormatException or FileNotFound from parseLong
} catch (Exception e) {
return 0;
} finally {
try {
if (br != null)br.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
public static ServerCounter getInstance() {
return INSTANCE;
}
public String nextval() { return String.valueOf(counter.incrementAndGet()); }
//will be executed by listener
public void writeToFile(){
//write the counter to file
writeToFile(counter.get());
}
private void writeToFile(long value){
try{
//you need folder c:\Test, file will be created automatically if there is no file, it will override the old file
BufferedWriter bw = new BufferedWriter(new FileWriter("C:\\Test\\counter.txt"));
//need "" to create String
bw.write("" + value);
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
now you can use ServerCounter.getInstance.nextval() to increment the counter and get the value
last thing is, you need to put the listener to your webApplication:
<web-app>
...
<listener>
<listener-class>utils.ContextListener </listener-class>
</listener>
</web-app>
EDIT: ServerCounter was implementing ServletContextListener by mistake
EDIT2: added read/write file
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.