Android AudioRecord录音不正常

挤不上公交车的路人甲 2012-08-10 11:22:16

package com.example.recorder;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class AudioRecorder extends Activity {
private int audioSource = MediaRecorder.AudioSource.MIC;
// 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025

private static int sampleRateInHz = 44100;
// 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道

private static int channelConfig = AudioFormat.CHANNEL_IN_STEREO;
// 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。

private static int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
private int bufferSizeInBytes = 0;

private Button btnRecord;

// private Button Stop;

private AudioRecord audioRecord;

private boolean isRecord = false;// 设置正在录制的状态
// AudioName裸音频数据文件

private static final String AudioName = "/sdcard/love.raw";
// NewAudioName可播放的音频文件

private static final String NewAudioName = "/sdcard/new.wav";

@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.record);
initUI();
initData();
btnRecord.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if (isRecord) {
btnRecord.setText("开始录音");
stop();
} else {
btnRecord.setText("正在录音...");
startRecord();
}
}
});
}

public void initUI() {
btnRecord = (Button) findViewById(R.id.btnRecord);
}

public void initData() {
creatAudioRecord();
}

private void creatAudioRecord() {

// 获得缓冲区字节大小

bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,

channelConfig, audioFormat);

// 创建AudioRecord对象

audioRecord = new AudioRecord(audioSource, sampleRateInHz,

channelConfig, audioFormat, bufferSizeInBytes);

}

private void startRecord() {
audioRecord.startRecording();
// 让录制状态为true
isRecord = true;
// 开启音频文件写入线程
new Thread(new AudioRecordThread()).start();
}

private void stop() {
if (audioRecord != null) {

System.out.println("stopRecord");

isRecord = false;// 停止文件写入

audioRecord.stop();



}
}

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) {

try {
System.out.println("writeDateTOFile...."+readsize);
// fos.write(audiodata);
fos.write(audiodata, 0, readsize);

} catch (IOException e) {

e.printStackTrace();

}

}

}

try {

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 = sampleRateInHz;

int channels = 2;

long byteRate = 16 * sampleRateInHz * 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);
int size=0;
while ((size = in.read(data)) != -1) {
System.out.println("copyWaveFile...."+size);
out.write(data,0,size);

}

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

}

@Override
protected void onDestroy() {

stop();
audioRecord.release();// 释放资源

audioRecord = null;
super.onDestroy();

}
}

上面代码我从网上copy的,实现AudioRecord录音,并生成WAV文件保存到SDCard。
问题是生成的文件,播放时完全不对,比原来快了很多,该代码加
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
和简单布局文件即可运行,效果可自己尝试。。。。


希望有类似经验者能详细说明下出现该问题的原因和解决办法,不胜感激!
...全文
1622 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
fans0_0 2014-05-10
  • 打赏
  • 举报
回复
WriteWaveFileHeader 方法 的参数channels 的值 改成1, 这个值表示每个通道的播放速度, 你这里写的是2 , 就是2倍速度播放;
无名码农 2013-11-04
  • 打赏
  • 举报
回复
楼主解决了没?
pt621 2013-05-23
  • 打赏
  • 举报
回复
速度快了那就是编码错了,应该是8位的,用16位了
wangjimlin 2013-03-14
  • 打赏
  • 举报
回复
楼主,请问你一个问题:我只想收集到裸音频,不打算播放出来,保存路径就是设在sd卡上的呀(/sdcard/love.raw),但是为什么录完音却找到这个文件呢?希望大神给予解释呀!
wangjimlin 2013-03-14
  • 打赏
  • 举报
回复
解决了,楼主,原来是配置文件那块少了两行代码,幸亏看到你在下面列出的那三行代码,要不真得纠结半天啊!
Mical007 2013-01-07
  • 打赏
  • 举报
回复
请问楼主解决了吗?
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 的回复:]

除了播放速度,其它都对吗?用什么机子做测试?什么系统版本?
[/Quote]
可以正常播放pcm数据,google nuxe s android4.0
wdy0725 2012-09-10
  • 打赏
  • 举报
回复
除了播放速度,其它都对吗?用什么机子做测试?什么系统版本?
  • 打赏
  • 举报
回复
各位,给点建议吧!

80,350

社区成员

发帖
与我相关
我的任务
社区描述
移动平台 Android
androidandroid-studioandroidx 技术论坛(原bbs)
社区管理员
  • Android
  • yechaoa
  • 失落夏天
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧