Android Audio Record to wav

微笑、不失礼 提交于 2021-02-11 08:32:06

问题


I recorded an audio using the audio recorder on Android and it produces a raw PCM file. I'm trying to convert it to a format I can listen to (wav or mp3 for example.

I've started with this example but don't know where to go from here: Android AudioRecord example

tried following these: http://computermusicblog.com/blog/2008/08/29/reading-and-writing-wav-files-in-java

Recording .Wav with Android AudioRecorder

Here is my code to record (note I am using Countdown Timer to tell it when to start and stop recording.

public class AudioRecordService extends Service {
    Toast toast;
    private static final int RECORDER_SAMPLERATE = 44100;
    private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
    private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
    private AudioRecord record = null;
    int BufferElements2Rec = 1024; // want to play 2048 (2K) since 2 bytes we use only 1024
    int BytesPerElement = 2; // 2 bytes in 16bit format
    private Thread recordingThread = null;
    private boolean isRecording = false;
    int buffsize = 0;

    public AudioRecordService() {
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO: Return the communication channel to the service.
        throw new UnsupportedOperationException("Not yet implemented");
    }

    public int onStartCommand(Intent intent, int flags, int startId)
    {
        try {
            buffsize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);

            record = new AudioRecord(MediaRecorder.AudioSource.MIC,
                RECORDER_SAMPLERATE, RECORDER_CHANNELS,
                RECORDER_AUDIO_ENCODING, buffsize);

            record.startRecording();

            CountDownTimer countDowntimer = new CountDownTimer(15000, 1000) {
                public void onTick(long millisUntilFinished) {
                    toast = Toast.makeText(AudioRecordService.this, "Recording", Toast.LENGTH_SHORT);
                    toast.show();
                    isRecording = true;
                    recordingThread = new Thread(new Runnable() {
                        public void run() {
                            writeAudioDataToFile();
                        }
                    }, "AudioRecorder Thread");
                    recordingThread.start();
                }

                public void onFinish() {
                    try {
                        toast.cancel();
                        Toast.makeText(AudioRecordService.this, "Done Recording ", Toast.LENGTH_SHORT).show();
                        isRecording = false;
                        record.stop();
                        record.release();
                        record = null;
                        recordingThread = null;
                    } catch (Exception e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }


            }};
            countDowntimer.start();
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
        return Service.START_STICKY;
    }

    private byte[] short2byte(short[] sData) {
        int shortArrsize = sData.length;
        byte[] bytes = new byte[shortArrsize * 2];
        for (int i = 0; i < shortArrsize; i++) {
            bytes[i * 2] = (byte) (sData[i] & 0x00FF);
            bytes[(i * 2) + 1] = (byte) (sData[i] >> 8);
            sData[i] = 0;
        }
        return bytes;

    }

    private void writeAudioDataToFile() {
        try {
            //String filePath = "/sdcard/voice8K16bitmono.pcm";
            String extState = Environment.getExternalStorageState();
            // Path to write files to
            String path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC + "/test").getAbsolutePath();

            String fileName = "audio.pcm";
            String externalStorage = Environment.getExternalStorageDirectory().getAbsolutePath();
            File file = new File(externalStorage + File.separator + fileName);

            // if file doesnt exists, then create it
            if (!file.exists()) {
                file.createNewFile();
            }
            short sData[] = new short[BufferElements2Rec];

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

            while (isRecording) {
                // gets the voice output from microphone to byte format

                record.read(sData, 0, BufferElements2Rec);
                System.out.println("Short wirting to file" + sData.toString());
                try {
                    // // writes the data to file from buffer
                    // // stores the voice buffer
                    byte bData[] = short2byte(sData);
                    os.write(bData, 0, BufferElements2Rec * BytesPerElement);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

My audio.pcm is created. However I don't know how to play it. I'm assuming bDate[] is the byte array being written. The links I created said they used the files, but showed no examples of how it was done.

If it matters, I've used GoldWave to open the file. It opens but the audio is messed up.

I also noticed my files were 2 seconds and I think it's because of the BytesPerElement and BufferElements2Rec. If you can help me out so it's going to be 15 seconds that would be great.

Thanks in advance!


回答1:


The only difference between a PCM file and a WAV file is that the PCM file has no header and the WAV file does. The WAV header has key information for playback such as sample rate, number of bits per sample and number of channels. When you load a PCM file either the app has to have prior knowledge of this information or you have to tell it. If you load a PCM file into audacity, for example, it will prompt you to fill in all of that stuff.

In order to make the existing save file a .WAV you need to prepend an appropriate header. I'm not going to go into details about it because there are already many answers on SO detailing it and it is readily available on the web (https://en.wikipedia.org/wiki/WAV)

The second issue you raise about the file length might have something to do with the fact that AudioRecord.read returns an int which is the number of samples actually read as it may be less than you asked for. This is really a second question though




回答2:


This is a Sample .WAV Header format Extracted from OMRECORDER:

private byte[] wavFileHeader(long totalAudioLen, long totalDataLen, long longSampleRate,
      int channels, long byteRate, byte bitsPerSample) {
    byte[] header = new byte[44];
    header[0] = 'R'; // RIFF/WAVE header
    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'; // 'fmt ' chunk
    header[13] = 'm';
    header[14] = 't';
    header[15] = ' ';
    header[16] = 16; // 4 bytes: size of 'fmt ' chunk
    header[17] = 0;
    header[18] = 0;
    header[19] = 0;
    header[20] = 1; // format = 1
    header[21] = 0;
    header[22] = (byte) channels;
    header[23] = 0;
    header[24] = (byte) (longSampleRate & 0xff);
    header[25] = (byte) ((longSampleRate >> 8) & 0xff);
    header[26] = (byte) ((longSampleRate >> 16) & 0xff);
    header[27] = (byte) ((longSampleRate >> 24) & 0xff);
    header[28] = (byte) (byteRate & 0xff);
    header[29] = (byte) ((byteRate >> 8) & 0xff);
    header[30] = (byte) ((byteRate >> 16) & 0xff);
    header[31] = (byte) ((byteRate >> 24) & 0xff);
    header[32] = (byte) (channels * (bitsPerSample / 8)); //
    // block align
    header[33] = 0;
    header[34] = bitsPerSample; // bits per sample
    header[35] = 0;
    header[36] = 'd';
    header[37] = 'a';
    header[38] = 't';
    header[39] = 'a';
    header[40] = (byte) (totalAudioLen & 0xff);
    header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
    header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
    header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
    return header;
  }

Below is Header format for .aac extracted from WhatsappAudioRecorder:

private byte[] createAdtsHeader(int length) {
        int frameLength = length + 7;
        byte[] adtsHeader = new byte[7];

        adtsHeader[0] = (byte) 0xFF; // Sync Word
        adtsHeader[1] = (byte) 0xF1; // MPEG-4, Layer (0), No CRC
        adtsHeader[2] = (byte) ((MediaCodecInfo.CodecProfileLevel.AACObjectLC - 1) << 6);
        adtsHeader[2] |= (((byte) SAMPLE_RATE_INDEX) << 2);
        adtsHeader[2] |= (((byte) CHANNELS) >> 2);
        adtsHeader[3] = (byte) (((CHANNELS & 3) << 6) | ((frameLength >> 11) & 0x03));
        adtsHeader[4] = (byte) ((frameLength >> 3) & 0xFF);
        adtsHeader[5] = (byte) (((frameLength & 0x07) << 5) | 0x1f);
        adtsHeader[6] = (byte) 0xFC;

        return adtsHeader;
    }


来源:https://stackoverflow.com/questions/32218360/android-audio-record-to-wav

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!