java中的录音机问题

时间:2010-12-18 20:04:20

标签: java servlets audio-recording

录制音频时遇到问题。我创建了一个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);
    }


}

1 个答案:

答案 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");