今天在公司瞎折腾,郁闷死了,吃饱了没事干,写了一个demo程序,用于录取音源原始数据与产品软件音源数据进行比较.参考前面的一些内容:
主程序:
package com.example.audiotrackdemo; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import android.app.ActionBar; import android.app.Activity; import android.media.AudioFormat; import android.media.AudioRecord; import android.media.MediaRecorder; import android.os.Bundle; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.view.View.OnTouchListener; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.Spinner; import android.widget.Toast; public class AudioRecordAct extends Activity { private String TAG = "AudioRecordAct"; private AudioRecord mAudioRecord; private Spinner mDataSpinner; private static final String mDataSourceString[] = { "CAMCORDER", "DEFAULT", "MIC", "REMOTE_SUBMIX", "VOICE_CALL", "VOICE_COMMUNICATION", "VOICE_DOWNLINK", "VOICE_RECOGNITION", "VOICE_UPLINK" }; private int mDataSourceType; private Spinner mDeviceSpinner; private static final String mDeviceString[] = { "MIC", "Handset Mic", "Headset Mic" }; private int mDeviceType = 0; private Spinner mSampleRateSpinner; private static final String mSampleRateString[] = { "44100", "22050", "16000", "11025" }; private int mSampleRateType=44100; private Spinner mChannelSpinner; private static final String mChannelConfigString[] = { "CHANNEL_IN_MONO", "CHANNEL_IN_STEREO", }; private int mChannelConfigType=AudioFormat.CHANNEL_IN_MONO; private Spinner mEncodeSpinner; private static final String mAudioEncodeString[] = { "ENCODING_PCM_8BIT", "ENCODING_PCM_16BIT" }; private int mAudioFormatType=AudioFormat.ENCODING_PCM_8BIT; private Spinner mBufferSpinner; private static final String mBufferSizeString[] = { "AUTO", "512", "1024" }; private int mBufferSizeType; private Button mStartBtn; private Button mStopBtn; private boolean isRecording; @Override public void finish() { // TODO Auto-generated method stub super.finish(); close(); } @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); ActionBar bar = getActionBar(); bar.setDisplayHomeAsUpEnabled(true); super.onCreate(savedInstanceState); setContentView(R.layout.audio_rec); mBufferSizeType=AudioRecord.getMinBufferSize(mSampleRateType, mChannelConfigType, mAudioFormatType); mStartBtn = (Button) findViewById(R.id.startrec); mStartBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub isRecording = false; startRecordAndFile(); } }); mStopBtn = (Button) findViewById(R.id.stoprec); mStopBtn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub close(); } }); mDataSpinner = (Spinner) findViewById(R.id.datasrcspinner); ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mDataSourceString); mDataSpinner.setAdapter(adapter); mDataSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub setDataSource(arg2); } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); mDeviceSpinner = (Spinner) findViewById(R.id.devicespinner); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mDeviceString); mDeviceSpinner.setAdapter(adapter); mDeviceSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub setDevice(arg2); } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); mSampleRateSpinner = (Spinner) findViewById(R.id.samplespinner); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mSampleRateString); mSampleRateSpinner.setAdapter(adapter); mSampleRateSpinner .setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub setSampleRate(arg2); } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); mChannelSpinner = (Spinner) findViewById(R.id.channelcfgspinner); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mChannelConfigString); mChannelSpinner.setAdapter(adapter); mChannelSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub setChannelConfig(arg2); } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); mEncodeSpinner = (Spinner) findViewById(R.id.encodespinner); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mAudioEncodeString); mEncodeSpinner.setAdapter(adapter); mEncodeSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub setAudioFormat(arg2); } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); mBufferSpinner = (Spinner) findViewById(R.id.bufferspinner); adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, mBufferSizeString); mBufferSpinner.setAdapter(adapter); mBufferSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub setBufferSize(arg2); Toast.makeText( AudioRecordAct.this, "mDataSourceType : " + mDataSourceType + " mSampleRateType : " + mSampleRateType + " mChannelConfigType : " + mChannelConfigType + " mAudioFormatType : " + mAudioFormatType + " mBufferSizeType : " + mBufferSizeType, Toast.LENGTH_SHORT).show(); } @Override public void onNothingSelected(AdapterView<?> arg0) { // TODO Auto-generated method stub } }); } // AudioName裸音频数据文件 ,麦克风 private String AudioName = ""; // NewAudioName可播放的音频文件 private String NewAudioName = ""; private void creatAudioRecord() { // 获取音频文件路径 AudioName = getRawFilePath(); NewAudioName = getWavFilePath(); if(mBufferSizeType==-2){ mBufferSizeType=2048; } mAudioRecord = new AudioRecord(mDataSourceType, mSampleRateType, mChannelConfigType, mAudioFormatType, mBufferSizeType); Toast.makeText( AudioRecordAct.this, "mDataSourceType : " + mDataSourceType + " mSampleRateType : " + mSampleRateType + " mChannelConfigType : " + mChannelConfigType + " mAudioFormatType : " + mAudioFormatType + " mBufferSizeType : " + mBufferSizeType, Toast.LENGTH_SHORT).show(); } private void close() { if (mAudioRecord != null) { System.out.println("stopRecord"); isRecording = false;// 停止文件写入 mAudioRecord.stop(); mAudioRecord.release();// 释放资源 mAudioRecord = null; } } public int startRecordAndFile() { // 判断是否有外部存储设备sdcard if (isSdcardExit()) { if (isRecording) { return 0; } else { if (mAudioRecord == null) { creatAudioRecord(); } else { close(); } mAudioRecord.startRecording(); // 让录制状态为true isRecording = true; // 开启音频文件写入线程 new Thread(new AudioRecordThread()).start(); return 2; } } else { return 1; } } class AudioRecordThread implements Runnable { @Override public void run() { writeDateTOFile();// 往文件中写入裸数据 copyWaveFile(AudioName, NewAudioName);// 给裸数据加上头文件 } } // 这里得到可播放的音频文件 private void copyWaveFile(String inFilename, String outFilename) { FileInputStream in = null; FileOutputStream out = null; long totalAudioLen = 0; long totalDataLen = totalAudioLen + 36; long longSampleRate = mSampleRateType; int channels = 2; long byteRate = 16 * mSampleRateType * channels / 8; byte[] data = new byte[mBufferSizeType]; 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); } private void writeDateTOFile() { // new一个byte数组用来存一些字节数据,大小为缓冲区大小 byte[] audiodata = new byte[mBufferSizeType]; 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 (isRecording == true) { readsize = mAudioRecord.read(audiodata, 0, mBufferSizeType); 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(); } } public static boolean isSdcardExit() { return android.os.Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED); } public static String getWavFilePath() { return "/mnt/sdcard/FinalAudio.wav"; } public static String getRawFilePath() { // return "/mnt/sdcard/FinalAudio.amr"; return "/mnt/sdcard/FinalAudio.raw"; } public static long getFileSize(String file) { return (new File(file)).length(); } private void setDevice(int type) { switch (type) { case 0: tools.enterStatus(3); break; case 1: tools.enterStatus(2); break; case 2: tools.enterStatus(1); break; case 3: tools.enterStatus(0); break; } } private void setDataSource(int type) { switch (type) { case 0: mDataSourceType = MediaRecorder.AudioSource.CAMCORDER; break; case 1: mDataSourceType = MediaRecorder.AudioSource.DEFAULT; break; case 2: mDataSourceType = MediaRecorder.AudioSource.MIC; break; case 3: mDataSourceType = MediaRecorder.AudioSource.VOICE_CALL; break; case 4: mDataSourceType = MediaRecorder.AudioSource.VOICE_COMMUNICATION; break; case 5: mDataSourceType = MediaRecorder.AudioSource.VOICE_DOWNLINK; break; case 6: mDataSourceType = MediaRecorder.AudioSource.VOICE_RECOGNITION; break; case 7: mDataSourceType = MediaRecorder.AudioSource.VOICE_UPLINK; break; case 8: break; default: } } private void setSampleRate(int type) { switch (type) { case 0: mSampleRateType = 44100; break; case 1: mSampleRateType = 22050; break; case 2: mSampleRateType = 16000; break; case 3: mSampleRateType = 11025; break; } } private void setChannelConfig(int type) { switch (type) { case 0: mChannelConfigType = AudioFormat.CHANNEL_IN_MONO; break; case 1: mChannelConfigType = AudioFormat.CHANNEL_IN_STEREO; break; } } private void setAudioFormat(int type) { switch (type) { case 0: mAudioFormatType = AudioFormat.ENCODING_PCM_8BIT; break; case 1: mAudioFormatType = AudioFormat.ENCODING_PCM_16BIT; break; case 2: mAudioFormatType = AudioFormat.ENCODING_PCM_8BIT; break; } } private void setBufferSize(int type) { Toast.makeText( AudioRecordAct.this, "mDataSourceType : " + mDataSourceType + " mSampleRateType : " + mSampleRateType + " mChannelConfigType : " + mChannelConfigType + " mAudioFormatType : " + mAudioFormatType + " mBufferSizeType : " + mBufferSizeType, Toast.LENGTH_SHORT).show(); switch (type) { case 0: mBufferSizeType = AudioRecord.getMinBufferSize(mSampleRateType, mChannelConfigType, mAudioFormatType); break; case 1: mBufferSizeType = 512; break; case 2: mBufferSizeType = 1024; break; } } @Override public boolean onOptionsItemSelected(MenuItem item) { // TODO Auto-generated method stub switch (item.getItemId()) { // Respond to the action bar's Up/Home // button case android.R.id.home: finish(); return true; } return super.onOptionsItemSelected(item); } }
xml 文件如下:
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/textView1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Audio Record :" android:textAppearance="?android:attr/textAppearanceLarge" /> <TextView android:id="@+id/textView7" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Mic Device :" /> <Spinner android:id="@+id/devicespinner" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Data Source :" /> <Spinner android:id="@+id/datasrcspinner" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/textView6" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sample Rate :" /> <Spinner android:id="@+id/samplespinner" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/textView3" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Channel Config :" /> <Spinner android:id="@+id/channelcfgspinner" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/textView4" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Audio Format :" /> <Spinner android:id="@+id/encodespinner" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:id="@+id/textView5" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Buffer Size :" /> <Spinner android:id="@+id/bufferspinner" android:layout_width="match_parent" android:layout_height="wrap_content" /> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <Button android:id="@+id/startrec" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="start" /> <Button android:id="@+id/stoprec" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_marginLeft="40dp" android:layout_toRightOf="@+id/startrec" android:text="stop" /> </RelativeLayout> </LinearLayout> </ScrollView>
对于Mic Device这一项选择,是本人的,其他的不能使用,可以删除.
这个demo可以自由进行参数配置...