Android使用AudioRecord遇到的问题与解决方法

2024-01-29 22:48

本文主要是介绍Android使用AudioRecord遇到的问题与解决方法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 

问题:

1、android判断是否禁用了录音权限

      通过判断分贝值是否大于0,在代码中搜索 volume > 0

2、部分手机在调用 audioRecord.startRecording(); 和audioRecord.stop();方法时会抛出异常,例如联想手机

3、部分手机(例如联想)会抛出java.lang.IllegalStateException: startRecording() called on an uninitialized AudioRecord.

      解决方法来源于:http://www.cnblogs.com/mythou/p/3241925.html

       原因:

       

出现上面问题的原因是录音的硬件资源被申请了,但是没有释放,然后你再次申请资源,导致初始化失败。这里需要注意的是不仅仅需要调用Release()方法。还需要把AudioRecord对象置为null,否则还是释放失败。下面是Android 开发网上面的一个对于AudioRecord的释放说明。

Releases the native AudioRecord resources. The object can no longer be used and the reference should be set to null after a call to release()。

 

解决方法在代码中:

 

 

 
  1. package com.androidleaf.audiorecord;

  2.  
  3. import android.app.ProgressDialog;

  4. import android.content.Context;

  5. import android.media.AudioFormat;

  6. import android.media.AudioRecord;

  7. import android.media.MediaRecorder;

  8. import android.os.AsyncTask;

  9. import android.os.Bundle;

  10. import android.os.Handler;

  11. import android.os.Message;

  12. import android.util.Log;

  13.  
  14. import com.hisun.phone.core.voice.Device;

  15. import com.todoroo.aacenc.AACEncoder;

  16. import com.todoroo.aacenc.AACToM4A;

  17.  
  18. import java.io.DataInputStream;

  19. import java.io.File;

  20. import java.io.FileInputStream;

  21. import java.io.FileNotFoundException;

  22. import java.io.IOException;

  23. import java.io.RandomAccessFile;

  24.  
  25. import app.jimu.zhiyu.activity.question.AnswerActivity;

  26.  
  27. public class AudioRecordUtils {

  28.  
  29. private final int audioSource = MediaRecorder.AudioSource.MIC;

  30. // 设置音频采样率,44100是目前的标准,但是某些设备仍然支持22050,16000,11025

  31. private final int sampleRateInHz = 16000;

  32. // 设置音频的录制的声道CHANNEL_IN_STEREO为双声道,CHANNEL_CONFIGURATION_MONO为单声道

  33. private final int channelConfig = AudioFormat.CHANNEL_IN_STEREO;

  34. // 音频数据格式:PCM 16位每个样本。保证设备支持。PCM 8位每个样本。不一定能得到设备支持。

  35. private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT;

  36.  
  37. private int inBufSize = 0;

  38.  
  39. private AudioRecord audioRecord;

  40.  
  41. private AACEncoder encoder = null;

  42.  
  43. private ProgressDialog mProgressDialog = null;

  44.  
  45. private boolean isRecord = false;

  46.  
  47. private Context mContext;

  48. /**

  49. * 录制的音频文件名称

  50. */

  51. private String mAudioRecordFileName;

  52.  
  53. private static final int RECORDED_INIT_DELETE = 0;

  54.  
  55. private static final int RECORDED_COMPLETED_DELETE = 1;

  56.  
  57. private Handler mHandler;

  58.  
  59. /**

  60. * 是否可以录音 true 可以录音

  61. */

  62. private boolean recordEnable = false;

  63.  
  64. public AudioRecordUtils(Context context,String audioRecordFileName, Handler handler){

  65. mContext = context;

  66. mAudioRecordFileName = audioRecordFileName;

  67. mHandler = handler;

  68. initAudioRecord();

  69. }

  70.  
  71. /**

  72. * 初始化对象

  73. */

  74. private void initAudioRecord(){

  75.  
  76. inBufSize = AudioRecord.getMinBufferSize(

  77. sampleRateInHz,

  78. channelConfig,

  79. audioFormat);

  80.  
  81. audioRecord = new AudioRecord(

  82. audioSource,

  83. sampleRateInHz,

  84. channelConfig,

  85. audioFormat,

  86. inBufSize);

  87.  
  88. encoder = new AACEncoder();

  89. deleteAllFiles(RECORDED_INIT_DELETE);

  90.  
  91. mProgressDialog = new ProgressDialog(mContext);

  92. mProgressDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);

  93. mProgressDialog.setCanceledOnTouchOutside(false);

  94. mProgressDialog.setCancelable(false);

  95. mProgressDialog.setTitle("提示");

  96. mProgressDialog.setMessage("正在保存录音,请耐心等候......");

  97.  
  98. }

  99.  
  100. /**

  101. * 开始录音

  102. */

  103. public void startRecord(){

  104. new AudioRecordTask().execute();

  105. }

  106.  
  107. /**

  108. * 暂停录音

  109. */

  110. public void pauseRecord(){

  111. isRecord = false;

  112. }

  113.  
  114. /**

  115. * 停止录音

  116. */

  117. public void stopRecord(){

  118. new AudioEncoderTask().execute();

  119. }

  120.  
  121. /**

  122. * 重新录制

  123. */

  124. public void reRecord(){

  125. //重新录制时,删除录音文件夹中的全部文件

  126. deleteAllFiles(RECORDED_INIT_DELETE);

  127. }

  128.  
  129. private void encodeAudio(){

  130. try {

  131. //读取录制的pcm音频文件

  132. DataInputStream mDataInputStream = new DataInputStream(new FileInputStream(

  133. FileUtils.getPcmFilePath(mAudioRecordFileName)));

  134. byte[] b = new byte[(int) new File(FileUtils.

  135. getPcmFilePath(mAudioRecordFileName)).length()];

  136. mDataInputStream.read(b);

  137. //初始化编码配置

  138. encoder.init(32000, 2, sampleRateInHz, 16, FileUtils.

  139. getAAcFilePath(mAudioRecordFileName));

  140. //对二进制代码进行编码

  141. encoder.encode(b);

  142. //编码完成

  143. encoder.uninit();

  144. //关闭流

  145. mDataInputStream.close();

  146. try {

  147. //将aac文件转码成m4a文件

  148. new AACToM4A().convert(mContext, FileUtils.getAAcFilePath(mAudioRecordFileName),

  149. FileUtils.getM4aFilePath(mAudioRecordFileName));

  150. } catch (IOException e) {

  151. Log.e("ERROR", "error converting", e);

  152. }

  153. deleteAllFiles(RECORDED_COMPLETED_DELETE);

  154. } catch (FileNotFoundException e) {

  155. // TODO Auto-generated catch block

  156. e.printStackTrace();

  157. } catch (IOException e1) {

  158. // TODO Auto-generated catch block

  159. e1.printStackTrace();

  160. }

  161. }

  162.  
  163. class AudioRecordTask extends AsyncTask<Void, Void, Void>{

  164.  
  165. @Override

  166. protected Void doInBackground(Void... params) {

  167. // TODO Auto-generated method stub

  168. if(audioRecord == null){

  169. initAudioRecord();

  170. }

  171. RandomAccessFile mRandomAccessFile = null;

  172. try {

  173. mRandomAccessFile = new RandomAccessFile(new File(

  174. FileUtils.getPcmFilePath(mAudioRecordFileName)), "rw");

  175. byte[] b = new byte[inBufSize/4];

  176. //开始录制音频

  177. try{

  178. // 防止某些手机崩溃,例如联想

  179. audioRecord.startRecording();

  180. }catch (IllegalStateException e){

  181. e.printStackTrace();

  182. }

  183.  
  184. //判断是否正在录制

  185. isRecord = true;

  186. long wait = 0;

  187. long maxWait = 10;

  188. while(isRecord){

  189. //r是实际读取的数据长度,一般而言r会小于buffersize

  190. int r = audioRecord.read(b, 0, b.length);

  191. long v = 0;

  192. // 将 buffer 内容取出,进行平方和运算

  193. for (int i = 0; i < b.length; i++) {

  194. v += b[i] * b[i];

  195. }

  196. // 平方和除以数据总长度,得到音量大小。

  197. double mean = v / (double) r;

  198. double volume = 10 * Math.log10(mean);

  199.  
  200. wait++;

  201. if(wait > maxWait){

  202. wait = 0;

  203. Log.d(this.getClass().getName(), "分贝值:" + volume + " " + (volume > 0));

  204. if(volume > 0){

  205. recordEnable = true;

  206. }

  207. Message msg = new Message();

  208. msg.what = AnswerActivity.STATUS_PREPARE;

  209. Bundle bundle = new Bundle();

  210. bundle.putDouble(Device.VOICE_AMPLITUDE, volume);

  211. msg.obj = bundle;

  212. mHandler.sendMessage(msg);

  213. }

  214.  
  215. //向文件中追加内容

  216. mRandomAccessFile.seek(mRandomAccessFile.length());

  217. mRandomAccessFile.write(b, 0, b.length);

  218. }

  219. //停止录制

  220. try {

  221. // 防止某些手机崩溃,例如联想

  222. audioRecord.stop();

  223. // 彻底释放资源

  224. audioRecord.release();

  225. audioRecord = null;

  226. }catch (IllegalStateException e){

  227. e.printStackTrace();

  228. }

  229. mRandomAccessFile.close();

  230. } catch (FileNotFoundException e) {

  231. // TODO Auto-generated catch block

  232. e.printStackTrace();

  233. } catch (IOException e) {

  234. // TODO Auto-generated catch block

  235. e.printStackTrace();

  236. }

  237. return null;

  238. }

  239. }

  240.  
  241. class AudioEncoderTask extends AsyncTask<Void, Void, Long>{

  242.  
  243. @Override

  244. protected void onPreExecute() {

  245. // TODO Auto-generated method stub

  246. super.onPreExecute();

  247. if(mProgressDialog != null && !mProgressDialog.isShowing()){

  248. // mProgressDialog.show();

  249. Message msg = new Message();

  250. msg.what = 2;

  251. mHandler.sendMessage(msg);

  252. }

  253. }

  254.  
  255. @Override

  256. protected Long doInBackground(Void... params) {

  257. // TODO Auto-generated method stub

  258. encodeAudio();

  259. return null;

  260. }

  261.  
  262. @Override

  263. protected void onPostExecute(Long result) {

  264. // TODO Auto-generated method stub

  265. super.onPostExecute(result);

  266. if(mProgressDialog.isShowing()){

  267. mProgressDialog.cancel();

  268. mProgressDialog.dismiss();

  269. }

  270. }

  271. }

  272.  
  273. /**

  274. * 清空音频录制文件夹中的所有文件

  275. * @param isRecorded

  276. */

  277. public void deleteAllFiles(int isRecorded){

  278. File[] files = new File(FileUtils.getAudioRecordFilePath()).listFiles();

  279. switch (isRecorded) {

  280. case RECORDED_INIT_DELETE:

  281. for(File file: files){

  282. file.delete();

  283. }

  284. break;

  285. case RECORDED_COMPLETED_DELETE:

  286. for(File file: files){

  287. if(!file.getName().equals(mAudioRecordFileName + Constants.M4A_SUFFIX)){

  288. file.delete();

  289. }

  290. }

  291. break;

  292. default:

  293. break;

  294. }

  295. }

  296.  
  297. public boolean isRecordEnable() {

  298. return recordEnable;

  299. }

  300.  

这篇关于Android使用AudioRecord遇到的问题与解决方法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/658404

相关文章

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

C++中std::distance使用方法示例

《C++中std::distance使用方法示例》std::distance是C++标准库中的一个函数,用于计算两个迭代器之间的距离,本文主要介绍了C++中std::distance使用方法示例,具... 目录语法使用方式解释示例输出:其他说明:总结std::distance&n编程bsp;是 C++ 标准

vue使用docxtemplater导出word

《vue使用docxtemplater导出word》docxtemplater是一种邮件合并工具,以编程方式使用并处理条件、循环,并且可以扩展以插入任何内容,下面我们来看看如何使用docxtempl... 目录docxtemplatervue使用docxtemplater导出word安装常用语法 封装导出方

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

使用Jackson进行JSON生成与解析的新手指南

《使用Jackson进行JSON生成与解析的新手指南》这篇文章主要为大家详细介绍了如何使用Jackson进行JSON生成与解析处理,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 核心依赖2. 基础用法2.1 对象转 jsON(序列化)2.2 JSON 转对象(反序列化)3.

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Elasticsearch 在 Java 中的使用教程

《Elasticsearch在Java中的使用教程》Elasticsearch是一个分布式搜索和分析引擎,基于ApacheLucene构建,能够实现实时数据的存储、搜索、和分析,它广泛应用于全文... 目录1. Elasticsearch 简介2. 环境准备2.1 安装 Elasticsearch2.2 J

使用C#代码在PDF文档中添加、删除和替换图片

《使用C#代码在PDF文档中添加、删除和替换图片》在当今数字化文档处理场景中,动态操作PDF文档中的图像已成为企业级应用开发的核心需求之一,本文将介绍如何在.NET平台使用C#代码在PDF文档中添加、... 目录引言用C#添加图片到PDF文档用C#删除PDF文档中的图片用C#替换PDF文档中的图片引言在当