【问题标题】:Convert PCM raw bytes to WAV bytes将 PCM 原始字节转换为 WAV 字节
【发布时间】:2016-04-11 16:50:12
【问题描述】:

我正在收听实时电话,并且能够获取原始 PCM 字节。 我还可以通过 java 的音频 api 收听这些字节。 这些都适用于小程序。

现在我希望能够将电话呼叫的原始 PCM 字节转换为 WAV 字节,以便将其直接写入 ServletOutputStream。这将允许浏览器实际收听电话。

有人知道我如何能够将一些原始 PCM 字节[] 即时转换为 WAV 字节[]?

我看到的例子都是关于将一​​个文件转换为另一个文件的。

java pcm to wav

How can I write a WAV file from byte array in java?

谢谢。

【问题讨论】:

  • 您提供的两个链接看起来像是有效的解决方案,因为它们创建的 WAVE 标头缺少您的原始数据。
  • @maxime.bochon:是的。但问题是这些解决方案确实与“文件”有关,而不是原始的“字节[]”。就我而言,与这些解决方案的建议相比,我没有波头所需的数据长度。同样,我只有一部实际电话的 PCM 字节,我不知道该电话会持续多长时间。有没有办法将无限波文件实际流式传输到浏览器?谢谢。
  • 当我读到“能够即时转换”时,这实际上让我担心......我从来没有在 WAVE 标头中读过关于流模式的信息。此外,如果我没记错的话,WAVE 文件的长度是有限制的。你的问题更多是在应用层而不是在格式化层。 Here 是与你相关的话题。
  • PCM 和 WAV 基本上是一回事,唯一的区别是 wav 文件有一个 header。现在,标题需要正确创建音频长度。因此,我认为“即时”创建 wav 的可能性不大。
  • @lCapp:确实如此,这就是我放弃此功能的原因。我将不得不找到另一种解决方案来使该功能正常工作。可能使用 WebRTC 转码器来完成这项工作。谢谢! :)

标签: java html5-audio wav pcm transcoding


【解决方案1】:

我也陷入了同样的境地,这就是我的解决方法。

public static boolean getWavFile(String filePath, InputStream audioStream) throws IOException {

    boolean result = false;
    try {

        byte[] decodedData = IOUtils.toByteArray(audioStream);

        System.out.println(">>Decoded Data" + Arrays.toString(decodedData));
        File outFile = new File(filePath);
        AudioFormat format = new AudioFormat(8000, 16, 1, true, false);
        AudioSystem.write(new AudioInputStream(new ByteArrayInputStream(
                decodedData), format, decodedData.length), AudioFileFormat.Type.WAVE, outFile);
        result = true;
        return result;
    } catch (IOException ex) {
        System.out.println("<<getWavFile - impl" + ex);
        return result;

    }
}

【讨论】:

    【解决方案2】:

    已经有一段时间了,但我认为这可能会对某人有所帮助。这是我的解决方案 - 我正在将字节写回任何输出流(在我的情况下是 servletoutputstream)。首先,我将 WAV 标头(44 字节)写入输出流并写入 pcm 字节(您需要将 pcm 数据转换为字节数组)。我在 html 中使用了音频标签,并将 src 标签指定为我的 api url,它工作得非常好。

    public void streamCloudObject(OutputStream stream, InputStream pcmData) throws IOException {
    
        stream.write(WAVHeader.build(44100,5242880));
        //byte_chunk_size is stream buffer size, I have it as 1MB, so at a time you are streaming 1MB of bytes
        byte[] outBytes = new byte[BYTE_CHUNK_SIZE];
    
        while(true) {   
            int r = pcmData.read(outBytes);
            if(r == -1)
                break;      
            stream.write(outBytes,0,r); 
    
        }
    
    }
    
    
    public class WAVHeader {
    
    private static final int CHUNK_SIZE = 36;
    private static final int BIT_RATE_16 = 16;
    private static final int MONO = 1;
    private static final int HEADER_SIZE = 44;
    
    //inputStreamLength - I send the pcm filesize here and I get it from s3.
    public static byte[] build(int sampleRate,int inputStreamLength) {
    
        byte[] header = new byte[HEADER_SIZE];
        int srate = resp.getSampleRate();
        int channel = MONO;
        int format = BIT_RATE_16;
        long dataLength = inputStreamLength;
    
        long totalDataLen = dataLength + CHUNK_SIZE;
        long bitrate = srate * channel * format;
    
        header[0] = 'R'; 
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f'; 
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = (byte) format; 
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1; 
        header[21] = 0;
        header[22] = (byte) channel; 
        header[23] = 0;
        header[24] = (byte) (srate & 0xff);
        header[25] = (byte) ((srate >> 8) & 0xff);
        header[26] = (byte) ((srate >> 16) & 0xff);
        header[27] = (byte) ((srate >> 24) & 0xff);
        header[28] = (byte) ((bitrate / 8) & 0xff);
        header[29] = (byte) (((bitrate / 8) >> 8) & 0xff);
        header[30] = (byte) (((bitrate / 8) >> 16) & 0xff);
        header[31] = (byte) (((bitrate / 8) >> 24) & 0xff);
        header[32] = (byte) ((channel * format) / 8); 
        header[33] = 0;
        header[34] = 16; 
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (dataLength  & 0xff);
        header[41] = (byte) ((dataLength >> 8) & 0xff);
        header[42] = (byte) ((dataLength >> 16) & 0xff);
        header[43] = (byte) ((dataLength >> 24) & 0xff);
        return header;
    }
    }
    

    【讨论】:

    • 什么是resp变量声明?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-03-20
    • 1970-01-01
    • 1970-01-01
    • 2013-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多