Android录音--AudioRecord、MediaRecorder(音频文件格式处理)

Android录⾳--AudioRecord、MediaRecorder(⾳频⽂件格式
处理)
Android提供了两个API⽤于实现录⾳功能:dia.AudioRecord、dia.MediaRecorder。
⽹上有很多谈论这两个类的资料。现在⼤致总结下:
1、AudioRecord
主要是实现边录边播(AudioRecord+AudioTrack)以及对⾳频的实时处理(如会说话的汤姆猫、语⾳)
优点:语⾳的实时处理,可以⽤代码实现各种⾳频的封装
缺点:输出是PCM语⾳数据,如果保存成⾳频⽂件,是不能够被播放器播放的,所以必须先写代码实现数据编码以及压缩
⽰例:
使⽤AudioRecord类录⾳,并实现WAV格式封装。录⾳20s,输出的⾳频⽂件⼤概为3.5M左右(已写测
试代码)
2、MediaRecorder
已经集成了录⾳、编码、压缩等,⽀持少量的录⾳⾳频格式,⼤概有.aac(API = 16) .amr .3gp
优点:⼤部分以及集成,直接调⽤相关接⼝即可,代码量⼩
缺点:⽆法实时处理⾳频;输出的⾳频格式不是很多,例如没有输出mp3格式⽂件
⽰例:
使⽤MediaRecorder类录⾳,输出amr格式⽂件。录⾳20s,输出的⾳频⽂件⼤概为33K(已写测试代码)
3、⾳频格式⽐较
WAV格式:录⾳质量⾼,但是压缩率⼩,⽂件⼤
AAC格式:相对于mp3,AAC格式的⾳质更佳,⽂件更⼩;有损压缩;⼀般苹果或者Android SDK4.1.2(API 16)及以上版本⽀持播放AMR格式:压缩⽐⽐较⼤,但相对其他的压缩格式质量⽐较
差,多⽤于⼈声,通话录⾳
⾄于常⽤的mp3格式,使⽤MediaRecorder没有该视频格式输出。⼀些⼈的做法是使⽤AudioRecord录⾳,然后编码成wav格式,再转换成mp3格式
再贴上⼀些测试⼯程。
功能描述:
1、点击“录⾳WAV⽂件”,开始录⾳。录⾳完成后,⽣成⽂件/sdcard/FinalAudio.wav
2、点击“录⾳AMR⽂件”,开始录⾳。录⾳完成后,⽣成⽂件/sdcard/FinalAudio.amr
3、点击“停⽌录⾳”,停⽌录⾳,并显⽰录⾳输出⽂件以及该⽂件⼤⼩。
⼤致代码如下:
1、AudioRecord录⾳,封装成WAV格式.
ample.audiorecordtest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
dia.AudioFormat;
dia.AudioRecord;
public class AudioRecordFunc {
// 缓冲区字节⼤⼩
private int bufferSizeInBytes = 0;
//AudioName裸⾳频数据⽂件,麦克风
private String AudioName = "";
/
/NewAudioName可播放的⾳频⽂件
private String NewAudioName = "";
private AudioRecord audioRecord;
private boolean isRecord = false;// 设置正在录制的状态
private static AudioRecordFunc mInstance;
private AudioRecordFunc(){
}
public synchronized static AudioRecordFunc getInstance()    {
if(mInstance == null)
mInstance = new AudioRecordFunc();
return mInstance;
}
public int startRecordAndFile() {
//判断是否有外部存储设备sdcard
if(AudioFileFunc.isSdcardExit())
{
if(isRecord)
{
return ErrorCode.E_STATE_RECODING;
}
else
{
if(audioRecord == null)
creatAudioRecord();
audioRecord.startRecording();
// 让录制状态为true
isRecord = true;
// 开启⾳频⽂件写⼊线程
new Thread(new AudioRecordThread()).start();
return ErrorCode.SUCCESS;
}
}
else
{
return ErrorCode.E_NOSDCARD;
}
}
public void stopRecordAndFile() {
}
public long getRecordFileSize(){
FileSize(NewAudioName);
}
private void close() {
if (audioRecord != null) {
System.out.println("stopRecord");
isRecord = false;//停⽌⽂件写⼊
audioRecord.stop();
audioRecord = null;
}
}
private void creatAudioRecord() {
// 获取⾳频⽂件路径
AudioName = RawFilePath();
NewAudioName = WavFilePath();
/
/ 获得缓冲区字节⼤⼩
bufferSizeInBytes = MinBufferSize(AudioFileFunc.AUDIO_SAMPLE_RATE,
AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT);
// 创建AudioRecord对象
audioRecord = new AudioRecord(AudioFileFunc.AUDIO_INPUT, AudioFileFunc.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 (ists()) {
file.delete();
}
fos = new FileOutputStream(file);// 建⽴⼀个可存取字节的⽂件
} catch (Exception e) {
e.printStackTrace();
}
while (isRecord == true) {
readsize = ad(audiodata, 0, bufferSizeInBytes);
if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos!=null) {
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 = AudioFileFunc.AUDIO_SAMPLE_RATE;
int channels = 2;
long byteRate = 16 * AudioFileFunc.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);
}
}
2、MediaRecorder录⾳,输出amr格式⾳频
ample.audiorecordtest;
import java.io.File;
import java.io.IOException;
dia.MediaRecorder;
public class MediaRecordFunc {
private boolean isRecord = false;
private MediaRecorder mMediaRecorder;
private MediaRecordFunc(){
}
private static MediaRecordFunc mInstance;
public synchronized static MediaRecordFunc getInstance(){        if(mInstance == null)
mInstance = new MediaRecordFunc();
return mInstance;
}
public int startRecordAndFile(){
//判断是否有外部存储设备sdcard
if(AudioFileFunc.isSdcardExit())

本文发布于:2024-09-21 18:30:10,感谢您对本站的认可!

本文链接:https://www.17tex.com/tex/2/90475.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:格式   播放   实现   输出   字节   压缩   数据   编码
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议