¿Cómo convertir un archivo .pcm a .wav o .mp3?

Actualmente estoy desarrollando una aplicación para Android que tiene grabación y reproducción de audio. Soy nuevo en el manejo del audio y tengo problemas con la codificación y los formatos.

Puedo grabar y reproducir el audio en mi aplicación, pero al exportar no puedo reproducir el audio. La única forma que encontré fue exportar mi archivo .pcm y convertirlo usando Audacity.

Este es mi código para grabar el audio es:

private Thread recordingThread 
private AudioRecord mRecorder;
private boolean isRecording = false;

private void startRecording() {

    mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
            Constants.RECORDER_SAMPLERATE, Constants.RECORDER_CHANNELS,
            Constants.RECORDER_AUDIO_ENCODING, Constants.BufferElements2Rec * Constants.BytesPerElement);

    mRecorder.startRecording();
    isRecording = true;

    recordingThread = new Thread(new Runnable() {
        public void run() {
            writeAudioDataToFile();
        }
    }, "AudioRecorder Thread");
    recordingThread.start();
}

private void writeAudioDataToFile() {
    // Write the output audio in byte

    FileOutputStream os = null;
    try {
        os = new FileOutputStream(mFileName);
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    }

    while (isRecording) {
        // gets the voice output from microphone to byte format
        mRecorder.read(sData, 0, Constants.BufferElements2Rec);
        try {
            // // writes the data to file from buffer
            // // stores the voice buffer

            byte bData[] = short2byte(sData);

            os.write(bData, 0, Constants.BufferElements2Rec * Constants.BytesPerElement);

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    try {
        os.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Para reproducir el audio grabado, el código es:

private void startPlaying() {

    new Thread(new Runnable() {
        public void run() {

            try {

                File file = new File(mFileName);

                byte[] audioData = null;

                InputStream inputStream = new FileInputStream(mFileName);
                audioData = new byte[Constants.BufferElements2Rec];

                mPlayer = new AudioTrack(AudioManager.STREAM_MUSIC, Constants.RECORDER_SAMPLERATE,
                        AudioFormat.CHANNEL_OUT_MONO, Constants.RECORDER_AUDIO_ENCODING,
                        Constants.BufferElements2Rec * Constants.BytesPerElement, AudioTrack.MODE_STREAM);


                final float duration = (float) file.length() / Constants.RECORDER_SAMPLERATE / 2;

                Log.i(TAG, "PLAYBACK AUDIO");
                Log.i(TAG, String.valueOf(duration));


                mPlayer.setPositionNotificationPeriod(Constants.RECORDER_SAMPLERATE / 10);
                mPlayer.setNotificationMarkerPosition(Math.round(duration * Constants.RECORDER_SAMPLERATE));

                mPlayer.play();

                int i = 0;
                while ((i = inputStream.read(audioData)) != -1) {
                    try {
                        mPlayer.write(audioData, 0, i);
                    } catch (Exception e) {
                        Log.e(TAG, "Exception: " + e.getLocalizedMessage());
                    }
                }

            } catch (FileNotFoundException fe) {
                Log.e(TAG, "File not found: " + fe.getLocalizedMessage());
            } catch (IOException io) {
                Log.e(TAG, "IO Exception: " + io.getLocalizedMessage());
            }

        }

    }).start();


}

Las constantes definidas en una clase de Constantes son:

public class Constants {

    final static public int RECORDER_SAMPLERATE = 44100;
    final static public int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
    final static public int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;

    final static public int BufferElements2Rec = 1024; // want to play 2048 (2K) since 2 bytes we use only 1024
    final static public int BytesPerElement = 2; // 2 bytes in 16bit format


}

Si exporto el archivo como está, lo convierto con Audacity y se reproduce. Sin embargo, necesito exportarlo en un formato que pueda reproducirse automáticamente.

He visto respuestas para implementar Lame y actualmente estoy trabajando en ello. También he encontrado una respuesta para convertirlo usando:

private File rawToWave(final File rawFile, final String filePath) throws IOException {

    File waveFile = new File(filePath);

    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
        // see http://ccrma.stanford.edu/courses/422/projects/WaveFormat/
        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, Constants.RECORDER_SAMPLERATE); // sample rate
        writeInt(output, Constants.RECORDER_SAMPLERATE * 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();
        }
    }

    return waveFile;

}

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));
    }
}

Pero esto, cuando se exporta, juega con la duración correcta pero solo con ruido blanco.

Algunas de las respuestas que probé pero que no pude trabajar:

Android: Creando un archivo Wave usando Raw PCM, el archivo wave no se reproduce¿Cómo convertir datos en bruto PCM a un archivo mp3?convertir archivos pcm a mp3 usando liblame en android

¿Alguien puede señalar cuál es la mejor solución? ¿Realmente está implementando cojo o se puede hacer de una manera más directa? Si es así, ¿por qué la muestra de código convierte el archivo a solo ruido blanco?

Respuestas a la pregunta(3)

Su respuesta a la pregunta