java - java中的录音机问题

标签 java servlets audio-recording

我在录制音频时遇到问题。我创建了一个servlet,并对java sound 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);
    }


}

最佳答案

使用 Servlet 进行开发时,您需要意识到,在整个 Web 应用程序的生命周期(从启动到关闭)中只有一个 Servlet 实例。因此,来自所有访问者、所有 session 、所有浏览器窗口/选项卡等的 HTTP 请求都将共享相同 servlet 实例。另外,当您创建一个静态变量时,它将在同一类的所有实例之间共享(这在这里并不真正相关,因为无论如何只有一个 servlet 实例)。

换句话说,您在 servlet 中声明的那些变量不是线程安全的:

static protected boolean running;
static ByteArrayOutputStream out;
double fileName = Math.random(); 

只有其中一个,并且可供所有访问者同时使用。对于不断修改的前两个变量,这将导致主要的线程安全问题,而对于第三个变量,这意味着所有访问者都会记录到同一个文件。您需要在 doGet() block 内声明它们。您希望通过基于唯一请求的 token 作为 key 将录音存储在 session 中,然后将该 key 传递给后续请求。

<小时/>

关于文件保存在非预期位置的问题;当您在 servlet 中的 java.io.File 中使用相对路径时,它将相对于 Web 服务器启动的目录。如果从 Eclipse 内部启动它,那么它会保存在 Eclipse 目录中。您想在 java.io.File 中使用绝对路径。如果您的目的是将其保存在公共(public) web 内容中(您的 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");

关于java - java中的录音机问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4479893/

相关文章:

java - 错误 :CreateProcess error=216, 此版本的 %1

java - 在 Android 中使用 XML 设置启动 AccessibilitySettings

iphone - 在 iphone 应用程序中录制用户语音时降低噪音?

iphone - 我想要一个 5 分钟 300kb 的音频文件

java - 如何从扬声器获取TargetDataLine?

java - 运行应用程序编辑配置错误

java - Storm Ui 错误 kafka spout,未使用 HDP

java - 下载以 Blob 格式或二进制格式存储在 MySQL 数据库中的 PDF 文件时出现 Null 异常

java - 使用 GWT 上传前检查文件大小

java - 如何在 Tomcat 中读取我的 webapp 上下文之外的属性文件