Преобразование необработанных байтов PCM в байты WAV

Я слушаю телефонные звонки в реальном времени и могу получить необработанные байты PCM. Я также могу слушать эти байты через аудио api java. Все это работает в апплете.

Теперь я хочу иметь возможность преобразовывать необработанные байты PCM телефонного звонка в байты WAV, чтобы я мог записывать их непосредственно в ServletOutputStream. Это позволит браузерам фактически прослушивать телефонные звонки.

Кто-нибудь знает, как я могу на лету конвертировать некоторые необработанные байты PCM [] в байты WAV []?

Все примеры, которые я видел, относятся к преобразованию файла в другой файл.

java pcm в wav

Как мне записать файл WAV из байтового массива в java?

Спасибо.


person Miki    schedule 07.01.2016    source источник
comment
Две ссылки, которые вы предоставляете, выглядят как допустимые решения, поскольку они создают заголовок WAVE, которого не хватает для ваших необработанных данных.   -  person maxime.bochon    schedule 07.01.2016
comment
@ maxime.bochon: да, это так. Проблема, однако, в том, что эти решения относятся к «файлам», а не к необработанным «байтам []». В моем случае у меня нет той длины данных, которая требуется для заголовка волны, по сравнению с тем, что предлагают эти решения. Опять же, у меня есть только байты PCM реального телефона, и как долго продлится этот телефонный звонок, я не знаю. Есть ли способ передать в браузер бесконечный волновой файл? Спасибо.   -  person Miki    schedule 08.01.2016
comment
На самом деле это то, что меня беспокоило, когда я читал возможность конвертировать на лету ... Я никогда не читал о потоковом режиме в заголовке WAVE. Более того, если я хорошо помню, файлы WAVE имеют ограничение по длине. Ваша проблема больше на уровне приложения, чем на уровне формирования. Здесь тема, связанная с вашей.   -  person maxime.bochon    schedule 08.01.2016
comment
PCM и WAV - это в основном одно и то же, с той лишь разницей, что файл wav имеет заголовок. Теперь заголовок требует, чтобы длина звука была создана правильно. Следовательно, я не вижу большой возможности создавать wav на лету.   -  person lCapp    schedule 09.01.2016
comment
@lCapp: Это правда, поэтому я отказался от этой функции. Мне нужно будет найти другое решение, чтобы эта функция заработала. Возможно, для этого воспользуйтесь транкодерами WebRTC. Спасибо! :)   -  person Miki    schedule 11.01.2016


Ответы (2)


Я тоже застрял в такой же ситуации, вот как я во всем разобрался.

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;

    }
}
person Dave Ranjan    schedule 15.11.2017

Прошло некоторое время, но я думаю, что это может кому-то помочь. Вот мое решение - я записываю байты обратно в любой выходной поток (в моем случае это servletoutputstream). Сначала я записываю заголовок WAV (44 байта) в выходной поток и записываю байты ПКМ (вам нужно преобразовать данные ПКМ в массив байтов). Я использовал тег audio в html и указал тег src в качестве URL-адреса api, и он работал отлично.

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;
}
}
person nagasaki    schedule 22.02.2019