ravi
ravi

Reputation: 2782

Out of memory exception converting raw file to wav in AudioRecorder

I am using AudioRecord to record audio in android. After the recording is finished i am converting raw file to wav file. But the app crashed due to Out of memory if the size of the file is more than 70 MB.

Below is the code which i have used to convert raw file to wav.

private void rawToWave(final File rawFile, final File waveFile) throws IOException {

    byte[] rawData = new byte[(int) rawFile.length()];
    DataInputStream input = null;
    try {
        input = new DataInputStream(new FileInputStream(rawFile));
        input.read(rawData);
    } finally {
        if (input != null) {
            input.close();
        }
    }

    DataOutputStream output = null;
    try {
        output = new DataOutputStream(new FileOutputStream(waveFile));
        // WAVE header
        writeString(output, "RIFF"); // chunk id
        writeInt(output, 36 + rawData.length); // chunk size
        writeString(output, "WAVE"); // format
        writeString(output, "fmt "); // subchunk 1 id
        writeInt(output, 16); // subchunk 1 size
        writeShort(output, (short) 1); // audio format (1 = PCM)
        writeShort(output, (short) 1); // number of channels
        writeInt(output, SAMPLE_RATE); // sample rate
        writeInt(output, SAMPLE_RATE * 2); // byte rate
        writeShort(output, (short) 2); // block align
        writeShort(output, (short) 16); // bits per sample
        writeString(output, "data"); // subchunk 2 id
        writeInt(output, rawData.length); // subchunk 2 size
        // Audio data (conversion big endian -> little endian)
        short[] shorts = new short[rawData.length / 2];
        ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
        ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2);
        for (short s : shorts) {
            bytes.putShort(s);
        }
        output.write(bytes.array());
    } finally {
        if (output != null) {
            output.close();
        }
    }
}

private void writeInt(final DataOutputStream output, final int value) throws IOException {
    output.write(value >> 0);
    output.write(value >> 8);
    output.write(value >> 16);
    output.write(value >> 24);
}

private void writeShort(final DataOutputStream output, final short value) throws IOException {
    output.write(value >> 0);
    output.write(value >> 8);
}

private void writeString(final DataOutputStream output, final String value) throws IOException {
    for (int i = 0; i < value.length(); i++) {
        output.write(value.charAt(i));
    }
}

Can anyone let me know is there any other way to convert large raw file to wav file. Or can we directly record audio to wav file using AudioRecord?

Thanks

Upvotes: 0

Views: 508

Answers (2)

AterLux
AterLux

Reputation: 4654

What you expected? You are trying to fit all the data from raw file into a one-piece single array. Of course, when the file is large, you will be given "out-of-memory".

You need to implement block-by-block reading and writing.

try (DataOutputStream output = new DataOutputStream(new FileOutputStream(waveFile))) {
    ...
    // blah-blah-blah, RIFF-headers
    ...

    try(DataInputStream input = new DataInputStream(new FileInputStream(rawFile))) {

        byte[] rawData = new byte[16384]; // 16k is enough
        int len;
        while ((len = input.read(buffer)) > 0) { // while data left in file
            short[] shorts = new short[len / 2];
            ByteBuffer.wrap(rawData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(shorts);
            ByteBuffer bytes = ByteBuffer.allocate(shorts.length * 2);
            for (short s : shorts) {
                bytes.putShort(s);
            }
            output.write(bytes.array());
        }
    }
    ...
}

Also, I suggest you to perform a much simpler byte-order change:

        byte[] rawData = new byte[16384]; // 16k is enough
        int len;
        while ((len = input.read(buffer)) > 0) { // while data left in file
            for (int i = 0; i < len; i += 2) {
               byte t = rawData[i + 1];    // just swap even and odd bytes;
               rawData[i + 1] = rawData[i];
               rawData[i] = rawData[i + 1];
            }
            output.write(rawData, 0, len); // then write the buffer to the output
        }

Upvotes: 1

Matt Clark
Matt Clark

Reputation: 28609

Try setting

android:largeHeap="true"

in your application manifest to request a larger heap..

android docs

Upvotes: 1

Related Questions