android 录制音频wav并转码mp3

1,759 阅读6分钟

1、录制音频wav (1)准备library-com.lqe.audio

百度一搜就有相关的库 可以下载demo然后移到自己的项目 (2)配置录制音频文件流 代码如下: public class AudioFileFuncWav { //音频输入-麦克风 public final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC; //采用频率 //44100是目前的标准,但是某些设备仍然支持22050,16000,11025 public final static int AUDIO_SAMPLE_RATE = 44100; //44.1KHz,普遍使用的频率 //录音输出文件 private final static String AUDIO_RAW_FILENAME = "RawAudio.raw"; private final static String AUDIO_WAV_FILENAME = "MYRECORDER.wav";

//获取当前时间
private static String getSystemnFileName(Context context){

    Calendar cal=Calendar.getInstance();
    String year = String.valueOf(cal.get(Calendar.YEAR));
    String   month = String.valueOf(cal.get(Calendar.MONTH))+1;
    String   day = String.valueOf(cal.get(Calendar.DATE));
    String    hour;
    if (cal.get(Calendar.AM_PM) == 0)
        hour    = String.valueOf(cal.get(Calendar.HOUR));
    else
    hour = String.valueOf(cal.get(Calendar.HOUR)+12);
    String  minute = String.valueOf(cal.get(Calendar.MINUTE));
   String my_time_1 = year +   month  + day+hour+minute;
    return my_time_1;
}
/**
 * 判断是否有外部存储设备sdcard
 * @return true | false
 */
public static boolean isSdcardExit(){
    if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
        return true;
    else
        return false;
}
/**
 * 获取麦克风输入的原始音频流文件路径
 * @return
 */
public static String getRawFilePath(Context context ){
    String mAudioRawPath = "";
    if(isSdcardExit()){
        File file = new File(getDiskCachePath(context)+"/"+AUDIO_RAW_FILENAME);
        if(!file.exists()){
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        mAudioRawPath = getDiskCachePath(context)+"/"+AUDIO_RAW_FILENAME;
    }
    return mAudioRawPath;
}

/**
 * 获取编码后的WAV格式音频文件路径
 * @return
 */
public static String getWavFilePath(Context context){
    String mAudioWavPath = "";
    if(isSdcardExit()){
        File file = new File(getDiskCachePath(context)+"/"+AUDIO_WAV_FILENAME);
        if(!file.exists()){
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        mAudioWavPath = getDiskCachePath(context)+"/"+AUDIO_WAV_FILENAME;
    }
    return mAudioWavPath;
}

/**
 * 获取文件大小
 * @param path,文件的绝对路径
 * @return
 */
public static long getFileSize(String path){
    File mFile = new File(path);
    if(!mFile.exists())
        return -1;
    return mFile.length();
}

//获取缓存的地址
public static String getDiskCachePath(Context context) {
    if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
            || !Environment.isExternalStorageRemovable()) {
        return context.getExternalCacheDir().getPath();
    } else {
        return context.getCacheDir().getPath();
    }
}

} (3)获取音频文件wav public class AudioRecorderWav { // 缓冲区字节大小 private int bufferSizeInBytes = 0;

//AudioName裸音频数据文件 ,麦克风
private String AudioName = "";

//NewAudioName可播放的音频文件
private String NewAudioName = "";

private AudioRecord audioRecord;
private boolean isRecord = false;// 设置正在录制的状态


private static AudioRecorderWav mInstance;

private AudioRecorderWav(){

}

public synchronized static AudioRecorderWav getInstance()
{
    if(mInstance == null)
        mInstance = new AudioRecorderWav();
    return mInstance;
}

public int startRecordAndFile(Context context) {
    //判断是否有外部存储设备sdcard
    if(AudioFileFuncWav.isSdcardExit())
    {
        if(isRecord)
        {
            return ErrorCode.E_STATE_RECODING;
        }
        else
        {
            if(audioRecord == null)
                creatAudioRecord(context);
            audioRecord.startRecording();
            // 让录制状态为true
            isRecord = true;
            // 开启音频文件写入线程
            new Thread(new AudioRecordThread()).start();
            return ErrorCode.SUCCESS;
        }
    }
    else
    {
        return ErrorCode.E_NOSDCARD;
    }

}

public void stopRecordAndFile() {
    close();
}


public long getRecordFileSize(){
    return AudioFileFuncWav.getFileSize(NewAudioName);
}


private void close() {
    if (audioRecord != null) {
        System.out.println("stopRecord");
        isRecord = false;//停止文件写入
        audioRecord.stop();
        audioRecord.release();//释放资源
        audioRecord = null;
    }
}


private void creatAudioRecord(Context context) {
    // 获取音频文件路径
    AudioName = AudioFileFuncWav.getRawFilePath(context);
    NewAudioName = AudioFileFuncWav.getWavFilePath(context);

    // 获得缓冲区字节大小
    bufferSizeInBytes = AudioRecord.getMinBufferSize(AudioFileFuncWav.AUDIO_SAMPLE_RATE,
            AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT);

    // 创建AudioRecord对象
    audioRecord = new AudioRecord(AudioFileFuncWav.AUDIO_INPUT, AudioFileFuncWav.AUDIO_SAMPLE_RATE,
            AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, bufferSizeInBytes);
}


class AudioRecordThread implements Runnable {
    @Override
    public void run() {
        writeDateTOFile();//往文件中写入裸数据
        copyWaveFile(AudioName, NewAudioName);//给裸数据加上头文件
    }
}

/**
 * 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频,
 * 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,比如你要做一个爱说话的TOM
 * 猫在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。
 */
private void writeDateTOFile() {
    // new一个byte数组用来存一些字节数据,大小为缓冲区大小
    byte[] audiodata = new byte[bufferSizeInBytes];
    FileOutputStream fos = null;
    int readsize = 0;
    try {
        File file = new File(AudioName);
        if (file.exists()) {
            file.delete();
        }
        fos = new FileOutputStream(file);// 建立一个可存取字节的文件
    } catch (Exception e) {
        e.printStackTrace();
    }
    while (isRecord == true) {
        readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
        if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos!=null) {
            try {
                fos.write(audiodata);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    try {
        if(fos != null)
            fos.close();// 关闭写入流
    } catch (IOException e) {
        e.printStackTrace();
    }
}

// 这里得到可播放的音频文件
private void copyWaveFile(String inFilename, String outFilename) {
    FileInputStream in = null;
    FileOutputStream out = null;
    long totalAudioLen = 0;
    long totalDataLen = totalAudioLen + 36;
    long longSampleRate = AudioFileFuncWav.AUDIO_SAMPLE_RATE;
    int channels = 2;
    long byteRate = 16 * AudioFileFuncWav.AUDIO_SAMPLE_RATE * channels / 8;
    byte[] data = new byte[bufferSizeInBytes];
    try {
        in = new FileInputStream(inFilename);
        out = new FileOutputStream(outFilename);
        totalAudioLen = in.getChannel().size();
        totalDataLen = totalAudioLen + 36;
        WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
                longSampleRate, channels, byteRate);
        while (in.read(data) != -1) {
            out.write(data);
        }
        in.close();
        out.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

/**
 * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。
 * 为我为啥插入这44个字节,这个还真没深入研究,不过你随便打开一个wav
 * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有
 * 自己特有的头文件。
 */
private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,
                                 long totalDataLen, long longSampleRate, int channels, long byteRate)
        throws IOException {
    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) (2 * 16 / 8); // block align
    header[33] = 0;
    header[34] = 16; // 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);
    out.write(header, 0, 44);
}

(4)开始录制音频,结束录制音频,转码mp3 全局变量:
private int mState = -1; //-1:没再录制,0:录制wav private int mp3State = -1; //-1:没转码,0:转码成功 private final static int CMD_RECORDFAIL = 2001; private final static int CMD_RECORDING_TIME = 2000; private final static int CMD_STOP = 2002; private final static int CMD_FINISH = 2003; private UIHandler uiHandler = new UIHandler(); private UIThread uiThread; Bundle b = new Bundle();// 存放数据 File mp3File;//mp3转码文件 File externalCacheDir; String function; AnimationDrawable animationDrawable;

//开始录制 public void startRecorde(int mFlag) { if (mState != -1) { Log.e(mState + "1", "mState: " + mState); Message msg = new Message(); b.putInt("cmd", CMD_RECORDFAIL); b.putInt("msg", ErrorCode.E_STATE_RECODING); msg.setData(b); uiHandler.sendMessage(msg); // 向Handler发送消息,更新UI return; } int mResult = -1; AudioRecorderWav mRecord_1 = AudioRecorderWav.getInstance(); mResult = mRecord_1.startRecordAndFile(EcgActivity.this); if (mResult == ErrorCode.SUCCESS) { mState = mFlag; uiThread = new UIThread(); new Thread(uiThread).start(); } else { Message msg = new Message(); b.putInt("cmd", CMD_RECORDFAIL); b.putInt("msg", mResult); msg.setData(b); uiHandler.sendMessage(msg); // 向Handler发送消息,更新UI } } //结束录制 private void stopRecorder() { if(animationDrawable.isRunning()){ animationDrawable.stop(); } if (mState != -1) { AudioRecorderWav mRecord_1 = AudioRecorderWav.getInstance(); mRecord_1.stopRecordAndFile(); } if (uiThread != null) { uiThread.stopThread(); } if (uiHandler != null) uiHandler.removeCallbacks(uiThread); Message msg = new Message(); b.putInt("cmd", CMD_STOP); b.putInt("msg", mState); msg.setData(b); uiHandler.sendMessageDelayed(msg, 1000); // 向Handler发送消息,更新UI // mState = -1; } //UIHandler class UIHandler extends Handler { public UIHandler() { }

    @Override
    public void handleMessage(Message msg) {
        // TODO Auto-generated method stub
        Log.d("MyHandler", "handleMessage......");
        super.handleMessage(msg);
        Bundle b = msg.getData();
        int vCmd = b.getInt("cmd");
        Log.e("vCmd", "" + vCmd);
        switch (vCmd) {
            case CMD_RECORDING_TIME:
                int vTime = b.getInt("msg");
                Log.e("MyHandler", "正在录音中,已录制:" + vTime + " s");
                break;
            case CMD_STOP:
                AudioRecorderWav mRecord = AudioRecorderWav.getInstance();
                long mSize = mRecord.getRecordFileSize();
                Log.e("MyHandler", "录音已停止.录音文件:" + AudioFileFuncWav.getWavFilePath(EcgActivity.this) + "文件大小:" + mSize);

// ToastUtils.showShort("录音已停止.录音文件:"+AudioFileFuncWav.getWavFilePath(EcgActivity.this)+"文件大小:"+mSize); mp3File = new File(AudioFileFuncWav.getWavFilePath(EcgActivity.this)); tanstoMp3(mp3File); break; case CMD_FINISH: if (mState != -1) { stopRecorder(); } tvMailSend.setEnabled(true); tvMailSend.setClickable(true); tvRecord.setClickable(false); animationDrawable.stop(); break; default: break; } } } //UIThread class UIThread implements Runnable { int mTimeMill = 0; boolean vRun = true;

    public void stopThread() {
        vRun = false;
    }

    public void run() {
        while (vRun) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            mTimeMill++;
            Message msg = new Message();
            Bundle b = new Bundle();// 存放数据
            b.putInt("cmd", CMD_RECORDING_TIME);
            b.putInt("msg", mTimeMill);
            Log.e("xrs2", "stop: " + mTimeMill);
            msg.setData(b);
            uiHandler.sendMessage(msg); // 向Handler发送消息,更新UI
        }
    }
}

//转成mp3 private void tanstoMp3(File file) { IConvertCallback callback = new IConvertCallback() { @Override public void onSuccess(File convertedFile) { // So fast? Love it! Log.e("MyHandlers", convertedFile.getPath().toString() + convertedFile.length()); mp3State = 1; }

        @Override
        public void onFailure(Exception error) {
            // Oops! Something went wrong
            Log.e("MyHandlers", "转码失败");
        }
    };
    AndroidAudioConverter.with(this)
            // Your current audio file
            .setFile(file)

            // Your desired audio format
            .setFormat(AudioFormat.MP3)

            // An callback to know when conversion is finished
            .setCallback(callback)

            // Start conversion
            .convert();
}