Search code examples
androidaudioandroid-mediacodec

Resampling audio in Android from 48kHz to 44.1kHz and vice versa - pure Java, or OpenSL ES?


I've managed to join audio tracks of video files using MediaCodec. There are no problems doing so if the channel count and the sample rate of both audio tracks are the same.

(for some reason the OMX.SEC.aac.dec always outputs 44100 Hz 2 channel audio if the original track is a 22050 Hz, and outputs 48000 Hz 2 channel audio if the original track is 24000 Hz.)

The problem comes in when I try appending a 24000 Hz audio track after a 22050 Hz audio track. Assuming I want to output a 22050 Hz audio track consisting of both said tracks, I'll have to resample the 24000 Hz one.

I tried this:

private byte[] minorDownsamplingFrom48kTo44k(byte[] origByteArray)
{
    int origLength = origByteArray.length;
    int moddedLength = origLength * 147/160;
    int delta = origLength - moddedLength;
    byte[] resultByteArray = new byte[moddedLength];
    int arrayIndex = 0;
    for(int i = 0; i < origLength; i+=11)
    {
        for(int j = i; j < i+10; j++)
        {
            resultByteArray[arrayIndex] = origByteArray[j];
            arrayIndex++;
        }
    }
    return resultByteArray;
}

It returns a byte array of 3700-something bytes and the correct audio after the encoding... behind a very loud scrambled sound.

My questions:

  1. How do I correctly downsample the audio track without leaving such artifacts? Should I use average values?
  2. Should I use a resampler implemented using OpenSL ES to make the process faster and/or better?

Solution

  • The main issue is that you're just skipping bytes when you should be skipping samples.

    Each sample is 16 bits, so two bytes. If the audio is stereo there are four bytes per sample. You have to always skip that many bytes or otherwise your samples will get completely mixed up.

    Using the same ratio (10/11) you can use 40/44 to always skip a full four-byte sample and keep the samples proper.

    As to why the resulting video is playing at a different speed, that's something completely different.