做网站南宁,如何用手机免费创建网站,单位网站中文域名到期续费,哪个网站可以做英语语法题上一篇文章介绍了使用 MediaRecorder 实现录音功能 Android录音实现(MediaRecorder) #xff0c;下面我们继续看看使用 AudioRecord 实现录音功能。AudioRecord首先看看Android帮助文档中对该类的简单概述: AndioRecord 类的主要功能是让各种 Java 应用能够管理音频资源#…上一篇文章介绍了使用 MediaRecorder 实现录音功能 Android录音实现(MediaRecorder) 下面我们继续看看使用 AudioRecord 实现录音功能。AudioRecord首先看看Android帮助文档中对该类的简单概述: AndioRecord 类的主要功能是让各种 Java 应用能够管理音频资源以便它们通过此类能够录制平台的声音输入硬件所收集的声音。此功能的实现就是通过 pulling 同步(reading读取)AudioRecord 对象的声音数据来完成的。在录音过程中应用所需要做的就是通过后面三个类方法中的一个去及时地获取 AudioRecord 对象的录音数据。 AudioRecord 类提供的三个获取声音数据的方法分别是 read(byte[], int, int), read(short[], int, int), read(ByteBuffer, int)。无论选择使用那一个方法都必须事先设定方便用户的声音数据的存储格式。开始录音的时候一个 AudioRecord 需要初始化一个相关联的声音buffer这个 buffer 主要是用来保存新的声音数据。这个 buffer 的大小我们可以在对象构造期间去指定。它表明一个 AudioRecord 对象还没有被读取(同步)声音数据前能录多长的音(即一次可以录制的声音容量)。声音数据从音频硬件中被读出数据大小不超过整个录音数据的大小(可以分多次读出)即每次读取初始化 buffer 容量的数据。采集工作很简单我们只需要构造一个AudioRecord对象然后传入各种不同配置的参数即可。一般情况下录音实现的简单流程如下音频源:我们可以使用麦克风作为采集音频的数据源。采样率:一秒钟对声音数据的采样次数采样率越高音质越好。音频通道单声道双声道等音频格式:一般选用PCM格式即原始的音频样本。缓冲区大小:音频数据写入缓冲区的总数可以通过AudioRecord.getMinBufferSize获取最小的缓冲区。(将音频采集到缓冲区中然后再从缓冲区中读取)。代码实现如下import android.media.AudioFormat;import android.media.AudioRecord;import android.media.MediaRecorder;import android.text.TextUtils;import android.util.Log;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.util.ArrayList;import java.util.List;/*** 实现录音** author chenmy0709* version V001R001C01B001*/public class AudioRecorder {//音频输入-麦克风private final static int AUDIO_INPUT MediaRecorder.AudioSource.MIC;//采用频率//44100是目前的标准但是某些设备仍然支持220501600011025//采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级private final static int AUDIO_SAMPLE_RATE 16000;//声道 单声道private final static int AUDIO_CHANNEL AudioFormat.CHANNEL_IN_MONO;//编码private final static int AUDIO_ENCODING AudioFormat.ENCODING_PCM_16BIT;// 缓冲区字节大小private int bufferSizeInBytes 0;//录音对象private AudioRecord audioRecord;//录音状态private Status status Status.STATUS_NO_READY;//文件名private String fileName;//录音文件private List filesName new ArrayList();/*** 类级的内部类也就是静态类的成员式内部类该内部类的实例与外部类的实例* 没有绑定关系而且只有被调用时才会装载从而实现了延迟加载*/private static class AudioRecorderHolder {/*** 静态初始化器由JVM来保证线程安全*/private static AudioRecorder instance new AudioRecorder();}private AudioRecorder() {}public static AudioRecorder getInstance() {return AudioRecorderHolder.instance;}/*** 创建录音对象*/public void createAudio(String fileName, int audioSource, int sampleRateInHz, int channelConfig, int audioFormat) {// 获得缓冲区字节大小bufferSizeInBytes AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig, channelConfig);audioRecord new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);this.fileName fileName;}/*** 创建默认的录音对象** param fileName 文件名*/public void createDefaultAudio(String fileName) {// 获得缓冲区字节大小bufferSizeInBytes AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE,AUDIO_CHANNEL, AUDIO_ENCODING);audioRecord new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING, bufferSizeInBytes);this.fileName fileName;status Status.STATUS_READY;}/*** 开始录音** param listener 音频流的监听*/public void startRecord(final RecordStreamListener listener) {if (status Status.STATUS_NO_READY || TextUtils.isEmpty(fileName)) {throw new IllegalStateException(录音尚未初始化,请检查是否禁止了录音权限~);}if (status Status.STATUS_START) {throw new IllegalStateException(正在录音);}Log.d(AudioRecorder, startRecord audioRecord.getState());audioRecord.startRecording();new Thread(new Runnable() {Overridepublic void run() {writeDataTOFile(listener);}}).start();}/*** 暂停录音*/public void pauseRecord() {Log.d(AudioRecorder, pauseRecord);if (status ! Status.STATUS_START) {throw new IllegalStateException(没有在录音);} else {audioRecord.stop();status Status.STATUS_PAUSE;}}/*** 停止录音*/public void stopRecord() {Log.d(AudioRecorder, stopRecord);if (status Status.STATUS_NO_READY || status Status.STATUS_READY) {throw new IllegalStateException(录音尚未开始);} else {audioRecord.stop();status Status.STATUS_STOP;release();}}/*** 释放资源*/public void release() {Log.d(AudioRecorder, release);//假如有暂停录音try {if (filesName.size() 0) {List filePaths new ArrayList();for (String fileName : filesName) {filePaths.add(FileUtil.getPcmFileAbsolutePath(fileName));}//清除filesName.clear();//将多个pcm文件转化为wav文件mergePCMFilesToWAVFile(filePaths);} else {//这里由于只要录音过filesName.size都会大于0,没录音时fileName为null//会报空指针 NullPointerException// 将单个pcm文件转化为wav文件//Log.d(AudioRecorder, makePCMFileToWAVFile);//makePCMFileToWAVFile();}} catch (IllegalStateException e) {throw new IllegalStateException(e.getMessage());}if (audioRecord ! null) {audioRecord.release();audioRecord null;}status Status.STATUS_NO_READY;}/*** 取消录音*/public void canel() {filesName.clear();fileName null;if (audioRecord ! null) {audioRecord.release();audioRecord null;}status Status.STATUS_NO_READY;}/*** 将音频信息写入文件** param listener 音频流的监听*/private void writeDataTOFile(RecordStreamListener listener) {// new一个byte数组用来存一些字节数据大小为缓冲区大小byte[] audiodata new byte[bufferSizeInBytes];FileOutputStream fos null;int readsize 0;try {String currentFileName fileName;if (status Status.STATUS_PAUSE) {//假如是暂停录音 将文件名后面加个数字,防止重名文件内容被覆盖currentFileName filesName.size();}filesName.add(currentFileName);File file new File(FileUtil.getPcmFileAbsolutePath(currentFileName));if (file.exists()) {file.delete();}fos new FileOutputStream(file);// 建立一个可存取字节的文件} catch (IllegalStateException e) {Log.e(AudioRecorder, e.getMessage());throw new IllegalStateException(e.getMessage());} catch (FileNotFoundException e) {Log.e(AudioRecorder, e.getMessage());}//将录音状态设置成正在录音状态status Status.STATUS_START;while (status Status.STATUS_START) {readsize audioRecord.read(audiodata, 0, bufferSizeInBytes);if (AudioRecord.ERROR_INVALID_OPERATION ! readsize fos ! null) {try {fos.write(audiodata);if (listener ! null) {//用于拓展业务listener.recordOfByte(audiodata, 0, audiodata.length);}} catch (IOException e) {Log.e(AudioRecorder, e.getMessage());}}}try {if (fos ! null) {fos.close();// 关闭写入流}} catch (IOException e) {Log.e(AudioRecorder, e.getMessage());}}/*** 将pcm合并成wav** param filePaths*/private void mergePCMFilesToWAVFile(final List filePaths) {new Thread(new Runnable() {Overridepublic void run() {if (PcmToWav.mergePCMFilesToWAVFile(filePaths, FileUtil.getWavFileAbsolutePath(fileName))) {//操作成功} else {//操作失败Log.e(AudioRecorder, mergePCMFilesToWAVFile fail);throw new IllegalStateException(mergePCMFilesToWAVFile fail);}fileName null;}}).start();}/*** 将单个pcm文件转化为wav文件*/private void makePCMFileToWAVFile() {new Thread(new Runnable() {Overridepublic void run() {if (PcmToWav.makePCMFileToWAVFile(FileUtil.getPcmFileAbsolutePath(fileName), FileUtil.getWavFileAbsolutePath(fileName), true)) {//操作成功} else {//操作失败Log.e(AudioRecorder, makePCMFileToWAVFile fail);throw new IllegalStateException(makePCMFileToWAVFile fail);}fileName null;}}).start();}/*** 获取录音对象的状态** return*/public Status getStatus() {return status;}/*** 获取本次录音文件的个数** return*/public int getPcmFilesCount() {return filesName.size();}/*** 录音对象的状态*/public enum Status {//未开始STATUS_NO_READY,//预备STATUS_READY,//录音STATUS_START,//暂停STATUS_PAUSE,//停止STATUS_STOP}}AudioRecorder 录音声音数据从音频硬件中被读出编码格式为 PCM格式但 PCM语音数据如果保存成音频文件是不能够被播放器播放的所以必须先写代码实现数据编码以及压缩。下面实现 PCM 语音数据转为 WAV 文件。/*** 将一个pcm文件转化为wav文件* param pcmPath pcm文件路径* param destinationPath 目标文件路径(wav)* param deletePcmFile 是否删除源文件* return*/public static boolean makePCMFileToWAVFile(String pcmPath, String destinationPath, boolean deletePcmFile) {byte buffer[] null;int TOTAL_SIZE 0;File file new File(pcmPath);if (!file.exists()) {return false;}TOTAL_SIZE (int) file.length();// 填入参数比特率等等。这里用的是16位单声道 8000 hzWaveHeader header new WaveHeader();// 长度字段 内容的大小(TOTAL_SIZE) // 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)header.fileLength TOTAL_SIZE (44 - 8);header.FmtHdrLeth 16;header.BitsPerSample 16;header.Channels 2;header.FormatTag 0x0001;header.SamplesPerSec 8000;header.BlockAlign (short) (header.Channels * header.BitsPerSample / 8);header.AvgBytesPerSec header.BlockAlign * header.SamplesPerSec;header.DataHdrLeth TOTAL_SIZE;byte[] h null;try {h header.getHeader();} catch (IOException e1) {Log.e(PcmToWav, e1.getMessage());return false;}if (h.length ! 44) // WAV标准头部应该是44字节,如果不是44个字节则不进行转换文件return false;// 先删除目标文件File destfile new File(destinationPath);if (destfile.exists())destfile.delete();// 合成的pcm文件的数据写到目标文件try {buffer new byte[1024 * 4]; // Length of All Files, Total SizeInputStream inStream null;OutputStream ouStream null;ouStream new BufferedOutputStream(new FileOutputStream(destinationPath));ouStream.write(h, 0, h.length);inStream new BufferedInputStream(new FileInputStream(file));int size inStream.read(buffer);while (size ! -1) {ouStream.write(buffer);size inStream.read(buffer);}inStream.close();ouStream.close();} catch (FileNotFoundException e) {Log.e(PcmToWav, e.getMessage());return false;} catch (IOException ioe) {Log.e(PcmToWav, ioe.getMessage());return false;}if (deletePcmFile) {file.delete();}Log.i(PcmToWav, makePCMFileToWAVFile success! new SimpleDateFormat(yyyy-MM-dd hh:mm).format(new Date()));return true;}总结AudioRecorder 录音相比较 MediaRecorder 使用起来会麻烦一些但优点也是显而易见的AudioRecorder 录音时直接操纵硬件获取音频流数据该过程是实时处理可以用代码实现各种音频的封装同时也可实现暂停功能关于实现暂停录音功能今天在这里就不赘述了推荐大家阅读 imhxl 博主的分享 http://blog.csdn.net/imhxl/article/details/52190451 。