用AudioRecord录制的声音是PCM编码,怎么把文件封装成WAV编码的可播放文件呢???
1 package com.example.recorder; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.io.FileNotFoundException; 6 import java.io.FileOutputStream; 7 import java.io.IOException; 8 9 import android.app.Activity; 10 import android.media.AudioFormat; 11 import android.media.AudioRecord; 12 import android.media.MediaRecorder; 13 import android.os.Bundle; 14 import android.view.View; 15 import android.view.View.OnClickListener; 16 import android.widget.Button; 17 18 public class AudioRecorder extends Activity { 19 private int audioSource = MediaRecorder.AudioSource.MIC; 20 // 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025 21 22 private static int sampleRateInHz = 44100; 23 // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道 24 25 private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO; 26 // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。 27 28 private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT; 29 private int bufferSizeInBytes = 0; 30 31 private Button btnRecord; 32 33 // private Button Stop; 34 35 private AudioRecord audioRecord; 36 37 private boolean isRecord = false;// 设置正在录制的状态 38 // AudioName裸音频数据文件 39 40 private static final String AudioName = "/sdcard/love.raw"; 41 // NewAudioName可播放的音频文件 42 43 private static final String NewAudioName = "/sdcard/new.wav"; 44 45 @Override 46 protected void onCreate(Bundle savedInstanceState) { 47 // TODO Auto-generated method stub 48 super.onCreate(savedInstanceState); 49 setContentView(R.layout.record); 50 initUI(); 51 initData(); 52 btnRecord.setOnClickListener(new OnClickListener() { 53 54 @Override 55 public void onClick(View v) { 56 // TODO Auto-generated method stub 57 if (isRecord) { 58 btnRecord.setText("开始录音"); 59 stop(); 60 } else { 61 btnRecord.setText("正在录音..."); 62 startRecord(); 63 } 64 } 65 }); 66 } 67 68 public void initUI() { 69 btnRecord = (Button) findViewById(R.id.btnRecord); 70 } 71 72 public void initData() { 73 creatAudioRecord(); 74 } 75 76 private void creatAudioRecord() { 77 78 // 获得缓冲区字节大小 79 80 bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz, 81 82 channelConfig, audioFormat); 83 84 // 创建AudioRecord对象 85 86 audioRecord = new AudioRecord(audioSource, sampleRateInHz, 87 88 channelConfig, audioFormat, bufferSizeInBytes); 89 90 } 91 92 private void startRecord() { 93 audioRecord.startRecording(); 94 // 让录制状态为true 95 isRecord = true; 96 // 开启音频文件写入线程 97 new Thread(new AudioRecordThread()).start(); 98 } 99 100 private void stop() { 101 if (audioRecord != null) { 102 103 System.out.println("stopRecord"); 104 105 isRecord = false;// 停止文件写入 106 107 audioRecord.stop(); 108 109 110 111 } 112 } 113 114 class AudioRecordThread implements Runnable { 115 116 @Override 117 public void run() { 118 119 writeDateTOFile();// 往文件中写入裸数据 120 121 copyWaveFile(AudioName, NewAudioName);// 给裸数据加上头文件 122 123 } 124 125 } 126 127 /** 128 * 129 * 这里将数据写入文件,但是并不能播放,因为AudioRecord获得的音频是原始的裸音频, 130 * 131 * 如果需要播放就必须加入一些格式或者编码的头信息。但是这样的好处就是你可以对音频的 裸数据进行处理,比如你要做一个爱说话的TOM 132 * 133 * 猫在这里就进行音频的处理,然后重新封装 所以说这样得到的音频比较容易做一些音频的处理。 134 */ 135 private void writeDateTOFile() { 136 137 // new一个byte数组用来存一些字节数据,大小为缓冲区大小 138 139 byte[] audiodata = new byte[bufferSizeInBytes]; 140 141 FileOutputStream fos = null; 142 143 int readsize = 0; 144 145 try { 146 147 File file = new File(AudioName); 148 149 if (file.exists()) { 150 151 file.delete(); 152 153 } 154 155 fos = new FileOutputStream(file);// 建立一个可存取字节的文件 156 157 } catch (Exception e) { 158 159 e.printStackTrace(); 160 161 } 162 163 while (isRecord == true) { 164 165 readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes); 166 167 if (AudioRecord.ERROR_INVALID_OPERATION != readsize) { 168 169 try { 170 System.out.println("writeDateTOFile...."+readsize); 171 // fos.write(audiodata); 172 fos.write(audiodata, 0, readsize); 173 174 } catch (IOException e) { 175 176 e.printStackTrace(); 177 178 } 179 180 } 181 182 } 183 184 try { 185 186 fos.close();// 关闭写入流 187 188 } catch (IOException e) { 189 190 e.printStackTrace(); 191 192 } 193 194 } 195 196 // 这里得到可播放的音频文件 197 198 private void copyWaveFile(String inFilename, String outFilename) { 199 200 FileInputStream in = null; 201 202 FileOutputStream out = null; 203 204 long totalAudioLen = 0; 205 206 long totalDataLen = totalAudioLen + 36; 207 208 long longSampleRate = sampleRateInHz; 209 210 int channels = 2; 211 212 long byteRate = 16 * sampleRateInHz * channels / 8; 213 214 byte[] data = new byte[bufferSizeInBytes]; 215 216 try { 217 218 in = new FileInputStream(inFilename); 219 220 out = new FileOutputStream(outFilename); 221 222 totalAudioLen = in.getChannel().size(); 223 224 totalDataLen = totalAudioLen + 36; 225 226 WriteWaveFileHeader(out, totalAudioLen, totalDataLen, 227 228 longSampleRate, channels, byteRate); 229 int size=0; 230 while ((size = in.read(data)) != -1) { 231 System.out.println("copyWaveFile...."+size); 232 out.write(data,0,size); 233 234 } 235 236 in.close(); 237 238 out.close(); 239 240 } catch (FileNotFoundException e) { 241 242 e.printStackTrace(); 243 244 } catch (IOException e) { 245 246 e.printStackTrace(); 247 248 } 249 250 } 251 252 /** 253 * 254 * 这里提供一个头信息。插入这些信息就可以得到可以播放的文件。 255 * 256 * 257 * 音频的文件,可以发现前面的头文件可以说基本一样哦。每种格式的文件都有 258 * 259 * 自己特有的头文件。 260 */ 261 262 private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen, 263 264 long totalDataLen, long longSampleRate, int channels, long byteRate) 265 266 throws IOException { 267 268 byte[] header = new byte[44]; 269 270 header[0] = 'R'; // RIFF/WAVE header 271 272 header[1] = 'I'; 273 274 header[2] = 'F'; 275 276 header[3] = 'F'; 277 278 header[4] = (byte) (totalDataLen & 0xff); 279 280 header[5] = (byte) ((totalDataLen >> 8) & 0xff); 281 282 header[6] = (byte) ((totalDataLen >> 16) & 0xff); 283 284 header[7] = (byte) ((totalDataLen >> 24) & 0xff); 285 286 header[8] = 'W'; 287 288 header[9] = 'A'; 289 290 header[10] = 'V'; 291 292 header[11] = 'E'; 293 294 header[12] = 'f'; // 'fmt ' chunk 295 296 header[13] = 'm'; 297 298 header[14] = 't'; 299 300 header[15] = ' '; 301 302 header[16] = 16; // 4 bytes: size of 'fmt ' chunk 303 304 header[17] = 0; 305 306 header[18] = 0; 307 308 header[19] = 0; 309 310 header[20] = 1; // format = 1 311 312 header[21] = 0; 313 314 header[22] = (byte) channels; 315 316 header[23] = 0; 317 318 header[24] = (byte) (longSampleRate & 0xff); 319 320 header[25] = (byte) ((longSampleRate >> 8) & 0xff); 321 322 header[26] = (byte) ((longSampleRate >> 16) & 0xff); 323 324 header[27] = (byte) ((longSampleRate >> 24) & 0xff); 325 326 header[28] = (byte) (byteRate & 0xff); 327 328 header[29] = (byte) ((byteRate >> 8) & 0xff); 329 330 header[30] = (byte) ((byteRate >> 16) & 0xff); 331 332 header[31] = (byte) ((byteRate >> 24) & 0xff); 333 334 header[32] = (byte) (2 * 16 / 8); // block align 335 336 header[33] = 0; 337 338 header[34] = 16; // bits per sample 339 340 header[35] = 0; 341 342 header[36] = 'd'; 343 344 header[37] = 'a'; 345 346 header[38] = 't'; 347 348 header[39] = 'a'; 349 350 header[40] = (byte) (totalAudioLen & 0xff); 351 352 header[41] = (byte) ((totalAudioLen >> 8) & 0xff); 353 354 header[42] = (byte) ((totalAudioLen >> 16) & 0xff); 355 356 header[43] = (byte) ((totalAudioLen >> 24) & 0xff); 357 358 out.write(header, 0, 44); 359 360 } 361 362 @Override 363 protected void onDestroy() { 364 365 stop(); 366 audioRecord.release();// 释放资源 367 368 audioRecord = null; 369 super.onDestroy();
这是我在网上的一个转换方式,但保存后文件都严重失真,不知道哪儿不对,谁错过?给点意见。。。
有没有人知道呢
请问您的问题解决了吗?我也遇到了一样的问题!