文章目录

  • Android提供了两个API用于录音的实现:
  • mediaRecorder
  • audioReccrd
    • 各类方法
    • 具体使用
  • setAudioSource failed 异常

Android提供了两个API用于录音的实现:

MediaRecorder 和AudioRecord。
参考来自https://www.jianshu.com/p/de779d509e6c

•MediaRecorder:录制的音频文件是经过压缩后的,需要设置编码器。并且录制的音频文件可以用系统自带的Music播放器播放。MediaRecorder已经集成了录音、编码、压缩等,并支持少量的录音音频格式,但是这也是他的缺点,支持的格式过少并且无法实时处理音频数据。

•AudioRecord:主要实现对音频实时处理以及边录边播功能,相对MediaRecorder比较专业,输出是PCM语音数据,如果保存成音频文件,是不能够被播放器播放的,所以必须先写代码实现数据编码以及压缩。

mediaRecorder

MediaRecorder 使用起来相对简单,音频编码可以根据自己实际需要自己设定,文件名防止重复,使用了日期_时分秒的结构,audioSaveDir 是文件存储目录,可自行设定。

public void startRecord()
{
// 开始录音 /* ①Initial:实例化MediaRecorder对象 */
if (mMediaRecorder == null)mMediaRecorder = new MediaRecorder(); try {
/* ②setAudioSource/setVedioSource */
mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
// 设置麦克风
/* ②设置输出文件的格式:THREE_GPP/MPEG-4/RAW_AMR/Default THREE_GPP(3gp格式  ,H263视频/ARM音频编码)、
MPEG-4、RAW_AMR(只支持音频且音频编码要求为AMR_NB)*/
mMediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
/* ②设置音频文件的编码:AAC/AMR_NB/AMR_MB/Default 声音的(波形)的采样 */ mMediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AAC);
fileName = DateFormat.format("yyyyMMdd_HHmmss", Calendar.getInstance(Locale.CHINA)) + ".m4a";if (!FileUtils.isFolderExist(FileUtils.getFolderName(audioSaveDir))) {FileUtils.makeFolders(audioSaveDir);}filePath = audioSaveDir + fileName; /* ③准备 */ mMediaRecorder.setOutputFile(filePath);mMediaRecorder.prepare(); /* ④开始 */ mMediaRecorder.start();} catch (IllegalStateException e) {LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());}catch (IOException e) {LogUtil.i("call startAmr(File mRecAudioFile) failed!" + e.getMessage());} } public void stopRecord(){
try {mMediaRecorder.stop();
mMediaRecorder.release();
mMediaRecorder = null;
filePath = "";
}
catch (RuntimeException e) {LogUtil.e(e.toString());
mMediaRecorder.reset();
mMediaRecorder.release();
mMediaRecorder = null;
File file = new File(filePath);
if (file.exists())file.delete();
filePath = "";
}
}

audioReccrd

AndioRecord 类的主要功能是让各种 Java 应用能够管理音频资源,以便它们通过此类能够录制平台的声音输入硬件所收集的声音。此功能的实现就是通过 “pulling 同步”(reading读取)AudioRecord 对象的声音数据来完成的。在录音过程中,应用所需要做的就是通过后面三个类方法中的一个去及时地获取 AudioRecord 对象的录音数据。 AudioRecord 类提供的三个获取声音数据的方法分别是 read(byte[], int, int), read(short[], int, int), read(ByteBuffer, int)。无论选择使用那一个方法都必须事先设定方便用户的声音数据的存储格式。

一个 AudioRecord 需要初始化一个相关联的声音buffer,这个 buffer 主要是用来保存新的声音数据。这个 buffer 的大小,我们可以在对象构造期间去指定。它表明一个 AudioRecord 对象还没有被读取(同步)声音数据前能录多长的音(即一次可以录制的声音容量)。声音数据从音频硬件中被读出,数据大小不超过整个录音数据的大小(可以分多次读出),即每次读取初始化 buffer 容量的数据。

•音频源:我们可以使用麦克风作为采集音频的数据源。

•采样率:一秒钟对声音数据的采样次数,采样率越高,音质越好。

•音频通道:单声道,双声道等,

•音频格式:一般选用PCM格式,即原始的音频样本。

•缓冲区大小:音频数据写入缓冲区的总数,可以通过AudioRecord.getMinBufferSize获取最小的缓冲区。(将音频采集到缓冲区中然后再从缓冲区中读取)。

各类方法

public class AudioRecorder {private static AudioRecorder audioRecorder; // 音频源:音频输入-麦克风 private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC; // 采样率 // 44100是目前的标准,但是某些设备仍然支持22050,16000,11025 // 采样频率一般共分为22.05KHz、44.1KHz、48KHz三个等级 private final static int AUDIO_SAMPLE_RATE = 16000; // 音频通道 单声道 private final static int AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_MONO; // 音频格式:PCM编码 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<String> filesName = new ArrayList<>();private AudioRecorder() {} //单例模式public static AudioRecorder getInstance() { if (audioRecorder == null){audioRecorder = new AudioRecorder();}return audioRecorder;} /*** 创建录音对象 */public void createAudio(String fileName, int audioSource, int sampleRateInHz, int channelConfig, int audioFormat) {// 获得缓冲区字节大小 bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,channelConfig, audioFormat);audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);this.fileName = fileName;} /*** 创建默认的录音对象 * @param fileName 文件名 */public void createDefaultAudio(String fileName) {mContext = ctx;mHandler = handler; // 获得缓冲区字节大小 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() { @Override public void run() {writeDataTOFile(listener);}}).start();} /*** 停止录音 */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 canel() {filesName.clear();fileName = null; if (audioRecord != null) {audioRecord.release();audioRecord = null;}status = Status.STATUS_NO_READY;}/*** 释放资源 */ public void release() {Log.d("AudioRecorder","===release==="); //假如有暂停录音 try { if (filesName.size() > 0) {List<String> filePaths = new ArrayList<>();for (String fileName : filesName) {filePaths.add(FileUtils.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;} /*** 将音频信息写入文件 * @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(FileUtils.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());}} }

具体使用

参考来自https://blog.csdn.net/qq77485042/article/details/78416935
添加权限
AndroidManifest.xml中

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_VIDEO" />
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
MediaRecorder mRecorder = new MediaRecorder();
//将mRecorder设置成空闲状态
mRecorder.reset();
//设置要用于录制的音频源。 如果没有这个方法调用,输出文件不会包含音轨。(注意该方法必须在setOutputFormat()方法之前)
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置录制时产生的输出文件的格式。(该方法不能再prepare()方法之后调用,不然会抛出IllegalStateException异常)
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);
//设置要生成的输出文件的路径。(简单的说就是生成一个什么文件名,放在哪里)
mRecorder.setOutputFile(mFileName);
//我这里的mFileName
mFileName = getExternalCacheDir().getAbsolutePath();
mFileName += "/" + System.currentTimeMillis();
//找到绝对路径,文件名取名为系统当前时间。(这里注意调用setOutputFile()方法一定要在setOutputFormat()方法之后,在prepare()之前);
//设置完路径之后调用该方法
//设置要用于录制的音频编码器。 如果没有这个方法调用,输出文件不会包含音轨。
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
//准备录音机开始捕获和编码数据。(也就是准备状态)这里需要try catch一个IOException。
mRecorder.prepare();
//开始录音
mRecorder.start();

停止的话,调用stop()方法,
release()方法是用来释放掉mRecorder的一切资源,为了不浪费内存。
if (mRecorder != null) {
mRecorder.stop();
mRecorder.release();
mRecorder = null;
}

调用了stop()方法后又重新调用start()方法会发现又生成了一个新的文件。
调用pause()方法暂停
pause()方法是在API 25(安卓版本7.1.1)的时候才出来的,而resume()方法是在API 19(安卓版本4.4)的时候出来的,如果我们的程序需要向下兼容的话怎么办呢,这个暂停的功能不就没法实现了。

他们也是点击了暂停之后调用stop();方法,每次点击开始的时候都生成了一个新的文件,只不过他们把那些录音文件拼接起来当你点击保存的时候拼接成了一个录音文件而已。

首先先创建一个集合用来装每段录音文件的路径

private ArrayList<String> list = new ArrayList<>();

每次点击开始的时候把文件路径add进集合中(也就是上面的mFileName)
因为每次点击开始的时候都给新的文件取当前的时间的毫秒值,所以不会出现文件名重复而覆盖掉的情况。

mFileName = getExternalCacheDir().getAbsolutePath();mFileName += "/" + System.currentTimeMillis();list.add(mFileName);startRecording();/*** 开始录音*/private void startRecording() {if (mRecorder == null) {mRecorder = new MediaRecorder();}mRecorder.reset();mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);mRecorder.setOutputFormat(MediaRecorder.OutputFormat.RAW_AMR);mRecorder.setOutputFile(mFileName);mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);try {mRecorder.prepare();} catch (IOException e) {Log.e(TAG, e.toString());}mRecorder.start();}

传入list以保存

第一个参数就是list集合,第二个参数就是合并后的文件名
public void getInputCollection(List list, String mMinute1) {// 创建音频文件,合并的文件放这里file1 = new File(getExternalCacheDir().getAbsolutePath(), mMinute1);FileOutputStream fileOutputStream = null;if (!file1.exists()) {try {file1.createNewFile();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}try {fileOutputStream = new FileOutputStream(file1);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}//list里面为暂停录音 所产生的 几段录音文件的名字,中间几段文件的减去前面的6个字节头文件for (int i = 0; i < list.size(); i++) {File file = new File((String) list.get(i));Log.d("list的长度", list.size() + "");try {FileInputStream fileInputStream = new FileInputStream(file);byte[] myByte = new byte[fileInputStream.available()];//文件长度int length = myByte.length;//头文件if (i == 0) {while (fileInputStream.read(myByte) != -1) {fileOutputStream.write(myByte, 0, length);}}//之后的文件,去掉头文件就可以了else {while (fileInputStream.read(myByte) != -1) {fileOutputStream.write(myByte, 6, length - 6);}}fileOutputStream.flush();fileInputStream.close();System.out.println("合成文件长度:" + file1.length());} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}//结束后关闭流try {fileOutputStream.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}//千万记住这里需要把集合给清空不然,下次录的时候会把上次录的给带上了deleteListRecord();}/*** 合成一个文件后,删除之前暂停录音所保存的零碎合成文件*/private void deleteListRecord() {for (int i = 0; i < list.size(); i++) {File file = new File(list.get(i));if (file.exists()) {file.delete();}}//正在暂停后,继续录音的这一段音频文件}

setAudioSource failed 异常

安卓6.0以上需要动态获取权限,在MainActivity中加入以下代码

if (Build.VERSION.SDK_INT >= 23) {int REQUEST_CODE_CONTACT = 101;String[] permissions = {Manifest.permission.RECORD_AUDIO,Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};//验证是否许可权限for (String str : permissions) {if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {//申请权限this.requestPermissions(permissions, REQUEST_CODE_CONTACT);return;}}}

android 录音 mediaRecorder相关推荐

  1. 【Android】【录音】Android录音--AudioRecord、MediaRecorder

    Android提供了两个API用于实现录音功能:android.media.AudioRecord.android.media.MediaRecorder. 网上有很多谈论这两个类的资料.现在大致总结 ...

  2. Android录音器实验报告,Android实现录音(MediaRecorder)

    Android提供了两个API用于录音的实现:MediaRecorder 和 AudioRecord,各有优劣. 1.MediaRecorder 已经集成了录音.编码.压缩等,支持少量的录音音频格式, ...

  3. android 录音原始文件_Android 录音详解(一)—— MediaRecorder、AudioRecord、生成wav格式、边录边播...

    Android 录音详解(一)-- MediaRecorder.AudioRecord.生成wav格式.边录边播 越来越多的 APP 都用到了手机的录音功能,比如搜索.聊天.输入.K歌等... 本系列 ...

  4. Android 录音实现(MediaRecorder)

    最近在项目中实现录音功能,并在逻辑中还有对录音文件的特殊要求,前前后后看了很多资料,学习了很多,今天在这里分享记录一下,以便后期回看. Android提供了两个API用于录音的实现:MediaReco ...

  5. android录音程序,使用MediaRecorder编写Android 录音程序

    类型:音频处理大小:2.0M语言:中文 评分:3.3 标签: 立即下载 今天工作上需要做一个一边录音一边播放的功能,大致原因是有一个外部设备输入音频到我们机器,然后我们机器需要马上把音频播放出来.所以 ...

  6. Android 录音(MediaRecorder)与播放(MediaPlayer)

    通过MediaRecorder和MediaPlayer实现声音的录制和播放,代码比较简单,直接贴代码.xml文件里面只有四个按钮就不贴了. UI 代码: VoiceActivity.class pac ...

  7. Android之mediarecorder中的方法以及工作流程的过程

    嵌套.关联的类 class MediaRecorder.AudioEncoder 定义音频编码 class MediaRecorder.AudioSource 定义声音资源 interface Med ...

  8. android 断点续录,android 录音的断点续传

    系统没有暂停的功能  只能把每次的录音进行拼接... package com.example.zrecord; import java.io.File; import java.io.FileInpu ...

  9. android录音播放并上传

    最近研究了下录音上传,各位有需要可参考下,如有不妥欢迎指出 <pre name="code" class="html">package com.ki ...

最新文章

  1. 比特币的价格今年会达到10万美元吗?有人用蒙特卡罗方法预测了一下
  2. 吴恩达老师,被曝靠「教书」实现首个IPO上市,估值50亿美元
  3. python软件是免费的吗-python软件都是免费的吗
  4. AOP 在Spring 中的应用
  5. gcc编译器java_「gcc编译器下载」gcc编译器下载各版本下载 - seo实验室
  6. concat特征融合_MSFNet:多重空间融合网络进行实时语义分割(北航和旷视联合提出)...
  7. 关于jstl中链接报红,确保什么路径正确的情况!至关重要
  8. Solr学习笔记001---solr在windows下的安装及配置
  9. sql modify 会丢失数据么_为什么U盘的数据会丢失?找对方法,轻松应对
  10. 云架构指挥调度平台技术方案建议书
  11. [Java][Android][Process] ProcessBuilder与Runtime区别
  12. 如何关闭迅雷频繁自动弹出更新到新版本的提示
  13. 史上最全Nginx面试题及答案
  14. Axure RP 8 激活
  15. YUI3 Overlay的使用
  16. 一位acm过来人的心得
  17. 用计算机绘制函数图像数学大师,用Excel来绘制数学中的函数图像
  18. linux ftw()函数使用方法 实例
  19. 2018.11.22!今天重温一遍知识点,捋一捋思路
  20. python怎么打开h5文件_python怎么查看h5文件-问答-阿里云开发者社区-阿里云

热门文章

  1. Hive从入门到放弃——Hive表DML的艺术性(八)
  2. 爬取豆瓣TOP250
  3. 51单片机入门 - I/O口直接输入输出实例
  4. Openbox+rox+feh+fbpanel+idesk构建桌面系统
  5. java猜字母游戏jsp_JSP简单练习-猜字母游戏
  6. NFT+DAO,改变流行IP难以融合的制胜法宝
  7. 40个视频素材网站分享,高清、4K、免费……你想要的的这里都有,快来收下这份安利~
  8. 性李 起一个如诗如梦一般的名字 三个字组成
  9. FPGA 黑金XC6SLX9 08.spi_flash源码分析 spi flash数据的读取擦除写入实验(1)
  10. css iohone手机端适配,【css】适配iphoneX