录制音频时遇到问题。我创建了一个servlet,我在某种程度上修改了java声音API演示代码,最后我可以录制音频。问题是,当我播放音频时,我可以看到音频的总时间存储为645.45或类似的东西,但我一直只录制音频几分钟。另一个问题是音频被保存在Eclipse目录而不是项目目录中。
这是servlet代码。
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);
}
}
}
这是记录器类
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);
}
}
答案 0 :(得分:1)
使用servlet进行开发时,您需要意识到整个webapp的生命周期中只有一个servlet实例,从启动到关闭。因此,来自所有访问者,所有会话,所有浏览器窗口/选项卡等的HTTP请求都将共享相同的 servlet实例。此外,当你创建一个变量static
时,它将在同一个类的所有实例之间共享(这里没有真正相关,因为无论如何只有一个servlet实例)。
换句话说,那些在servlet中声明的变量不是线程安全的:
static protected boolean running;
static ByteArrayOutputStream out;
double fileName = Math.random();
只有其中一个,所有访问者同时使用它们。对于前两个连续修改的变量,这将导致主要的线程安全问题,对于第三个变量,这意味着所有访问者都记录到同一个文件。您需要在doGet()
块中声明它们。您希望通过基于唯一请求的令牌将记录存储在会话中作为密钥,然后将该密钥传递给后续请求。
关于文件保存在意外位置的问题;当您在servlet中使用java.io.File
中的相对路径时,它将相对于启动Web服务器的目录。如果从Eclipse内部启动它,那么它将保存在Eclipse目录中。您想在java.io.File
中使用绝对路径。如果您的目的是将其保存在公共webcontent(JSP和/WEB-INF
文件夹所在的位置),那么您需要ServletContext#getRealPath()
将Web路径转换为绝对磁盘路径。
String relativeWebPath = "filename.ext";
String absoluteDiskPath = getServletContext().getRealPath(relativeWebPath);
File file = new File(absoluteDiskPath);
然而另一个问题是:每当您重新部署Web应用程序时,所有文件都将被删除。如果您想要更多永久存储,那么您希望将其存储在外部 Web项目中。例如。 C:/path/to/recordings
。
File file = new File("C:/path/to/recordings/filename.ext");