Android语音录入(MP3格式)-小白无头脑实现
来源:互联网 发布:我的世界mac存档放哪 编辑:程序博客网 时间:2024/05/17 06:29
最近项目开发中要做一个语音提问的功能,在客户端录制MP3格式文件并且上传到服务器端.小白不才,如果下述内容中有任何问题欢迎各位大佬指出,谢谢.
Android中实现录音有三种方式 :
- 通过意图捕获音频。
- MediaRecorder类实现录音.
- AudioRecord录制原始音频.
三种方式的概念,怎么实现网上大佬写了很多我就不班门弄斧了,我的实现方式是通过AudioRecord实现的,先生成RAW格式然后通过工具((com.pocketdigi.utils))转换成MP3格式.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -华丽丽的分割线- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
实现效果 : 录制音频,一般是60秒,录制时间到达50秒时候进入最后10秒倒计时,到达60秒后自动结束录音
点击录音开始按钮启动录音功能,同时检测录音的分贝,通过图片展示出来…模仿的就是微信语音那个动画
点击录音暂停按钮结束录音,启动音频文件格式转换
布局文件
<?xml version="1.0" encoding="utf-8"?><RelativeLayout android:id="@+id/activity_audio_record" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/audio_start" android:layout_width="match_parent" android:layout_height="200dp" android:text="@string/recording_start"/> <Button android:id="@+id/audio_stop" android:layout_width="match_parent" android:layout_height="200dp" android:layout_below="@id/audio_start" android:text="@string/recording_stop"/> <RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/audio_stop" android:layout_centerInParent="true" android:layout_marginTop="10dp" android:background="@color/cyan5" android:padding="10dp"> <ImageView android:id="@+id/aaa" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@mipmap/a9g"/> <ImageView android:id="@+id/mic_image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@id/aaa" android:src="@mipmap/tp"/> </RelativeLayout></RelativeLayout>
图片资源什么的你可以去某些语音APP里面借用一下
录音代码
代码里面都有注释,个人觉得这个注释小白看得懂…所以就不一一解释了
public class AudioRecord extends Activity implements View.OnClickListener, AudioRecorder2Mp3Util.DecibelObserver { AudioRecorder2Mp3Util util = null; private boolean canClean = false;//判断是否要清理本地的音频文件 private ImageView mDBImg;//显示语音分贝的View private Drawable[] micImages; //存储很多张话筒图片的数组 private int maxTime = 60;//语音录入的最大时长 private AudioRecord that; private final Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { //当录音进入最后10秒中的时候展现的不再是分贝而是倒计时 //因为分贝很难突破100你用力对着麦克吼一嗓子也就80多一点所以这里处理方式虽然不是很完美,但是可以解决问题 int mTime = msg.arg1; if (mTime == 900) { mDBImg.setImageDrawable(micImages[20]); return; } else if (mTime == 800) { mDBImg.setImageDrawable(micImages[19]); return; } else if (mTime == 700) { mDBImg.setImageDrawable(micImages[18]); return; } else if (mTime == 600) { mDBImg.setImageDrawable(micImages[17]); return; } else if (mTime == 500) { mDBImg.setImageDrawable(micImages[16]); return; } else if (mTime == 400) { mDBImg.setImageDrawable(micImages[15]); return; } else if (mTime == 300) { mDBImg.setImageDrawable(micImages[14]); return; } else if (mTime == 200) { mDBImg.setImageDrawable(micImages[13]); return; } else if (mTime == 100) { mDBImg.setImageDrawable(micImages[12]); return; } else if (mTime == 1000) { mDBImg.setImageDrawable(micImages[11]); //因为录音最大时长是60秒,所以在到达最后一秒的时候就自动结束录音 if (util != null) { util.unregisterObserver(that);//注销监听分贝变化 mHandler.sendEmptyMessage(9);//将声音还原 util.stopRecordingAndConvertFile();//停止录音并且开始转换 util.cleanFile(AudioRecorder2Mp3Util.RAW);//清理文件 // 关闭 util.close(); util = null; } return; } int what = msg.what; //根据mHandler发送what的大小决定话筒的图片是哪一张 //说话声音越大,发送过来what值越大 if (what > 0) { if (what >= 0 && what < 10) { mDBImg.setImageDrawable(micImages[0]); } else if (what >= 10 && what < 20) { mDBImg.setImageDrawable(micImages[1]); } else if (what >= 20 && what < 30) { mDBImg.setImageDrawable(micImages[2]); } else if (what >= 30 && what < 40) { mDBImg.setImageDrawable(micImages[3]); } else if (what >= 40 && what < 50) { mDBImg.setImageDrawable(micImages[4]); } else if (what >= 50 && what < 60) { mDBImg.setImageDrawable(micImages[5]); } else if (what >= 60 && what < 70) { mDBImg.setImageDrawable(micImages[6]); } else if (what >= 70 && what < 80) { mDBImg.setImageDrawable(micImages[7]); } else if (what >= 80 && what < 90) { mDBImg.setImageDrawable(micImages[8]); } else if (what >= 90 && what < 100) { mDBImg.setImageDrawable(micImages[9]); } else if (what >= 100) { mDBImg.setImageDrawable(micImages[10]); } } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_audio_record); findViewById(R.id.audio_start).setOnClickListener(this); findViewById(R.id.audio_stop).setOnClickListener(this); mDBImg = (ImageView) findViewById(R.id.mic_image); // 动画资源文件,用于录制语音时 micImages = new Drawable[]{ //分贝动画图片 getResources().getDrawable(R.mipmap.tp), getResources().getDrawable(R.mipmap.ts), getResources().getDrawable(R.mipmap.tt), getResources().getDrawable(R.mipmap.tu), getResources().getDrawable(R.mipmap.tv), getResources().getDrawable(R.mipmap.tw), getResources().getDrawable(R.mipmap.tx), getResources().getDrawable(R.mipmap.ty), getResources().getDrawable(R.mipmap.tz), getResources().getDrawable(R.mipmap.tq), getResources().getDrawable(R.mipmap.tr), //倒计时动画图片 getResources().getDrawable(R.mipmap.akn), getResources().getDrawable(R.mipmap.ako), getResources().getDrawable(R.mipmap.akp), getResources().getDrawable(R.mipmap.akq), getResources().getDrawable(R.mipmap.akr), getResources().getDrawable(R.mipmap.aks), getResources().getDrawable(R.mipmap.akt), getResources().getDrawable(R.mipmap.aku), getResources().getDrawable(R.mipmap.akv), getResources().getDrawable(R.mipmap.akw) }; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.audio_start://开始录音 if (util == null) { util = new AudioRecorder2Mp3Util(null, SDCardUtils.listAvaliableStorage(this).get(0) + "audiorecorder.raw", SDCardUtils.listAvaliableStorage(this).get(0) + "audiorecorder.mp3"); } if (canClean) { util.cleanFile(AudioRecorder2Mp3Util.MP3 | AudioRecorder2Mp3Util.RAW); } Toast.makeText(this, "请说话", Toast.LENGTH_SHORT).show(); maxTime = 60; util.registerObserver(this);//注册监分贝变化 that = this; util.startRecording(); startTime();//开始60秒计时 canClean = true; break; case R.id.audio_stop://结束录音 if (util != null) { util.unregisterObserver(this);//注销监听分贝变化 mHandler.sendEmptyMessage(9);//将声音还原 Toast.makeText(this, "正在转换", Toast.LENGTH_SHORT).show(); util.stopRecordingAndConvertFile(); util.cleanFile(AudioRecorder2Mp3Util.RAW); // 如果要关闭可以 util.close(); util = null; } break; } } /** * 分贝放生变化后收到的通知 */ @Override public void decibelSizeChanged(final int dbSize) { mHandler.sendEmptyMessage(dbSize);//向handler发送消息做动画操作 } /** * 开始自动减时 */ private void startTime() { final Timer timer = new Timer(); TimerTask task = new TimerTask() { @Override public void run() { Log.i("检查", "倒计时" + maxTime); maxTime--; if (maxTime == 9) {//如果倒计时到第九秒就不要在监听分贝变化了,已经不需要在做分贝动画了 util.unregisterObserver(that);//注销监听分贝变化 } if (maxTime <= 9) {//到达第九秒后开始发送倒计时消息 Log.i("检查", "发送消息" + maxTime); Message message = new Message(); message.arg1 = maxTime * 100;//乘以100是让数字足够大 不至于和分贝数值发生冲突 if (maxTime == 0) {//到达0秒后不在进行计时操作 timer.cancel(); message.arg1 = 1000; mHandler.sendMessage(message); return; } mHandler.sendMessage(message); } } }; //参数2:1000毫秒之后执行第一次run 参数3:之后每隔1000毫秒执行一次run timer.schedule(task, 1000, 1000); }}
音频录制和格式转换
public class AudioRecorder2Mp3Util { /** * 构造时候需要的Activity,主要用于获取文件夹的路径 */ private Activity activity; /** * 文件代号 */ public static final int RAW = 0X00000001; public static final int MP3 = 0X00000002; /** * 文件路径 */ private String rawPath = null; private String mp3Path = null; /** * 采样频率 */ private static final int SAMPLE_RATE = 8000; /** * 录音需要的一些变量 */ private short[] mBuffer; private AudioRecord mRecorder; private int bufferSize; private static ArrayList<DecibelObserver> mObservers = new ArrayList<>(); public AudioRecorder2Mp3Util(Activity activity) { this.activity = activity; } /** * 录音状态 */ private boolean isRecording = false; /** * 是否转换成功 */ private boolean convertOk = false; /** * @param activity * @param rawPath * @param mp3Path */ public AudioRecorder2Mp3Util(Activity activity, String rawPath, String mp3Path) { this.activity = activity; this.rawPath = rawPath; this.mp3Path = mp3Path; } /** * 开始录音 */ public boolean startRecording() { // 如果正在录音,则返回 if (isRecording) { return isRecording; } // 初始化 if (mRecorder == null) { initRecorder(); } getFilePath(); mRecorder.startRecording(); startBufferedWrite(new File(rawPath)); isRecording = true; return isRecording; } /** * 停止录音,并且转换文件,这很可能是个耗时操作,建议在后台中做 */ public boolean stopRecordingAndConvertFile() { if (!isRecording) { return isRecording; } // 停止 mRecorder.stop(); isRecording = false; // 开始转换 FLameUtils lameUtils = new FLameUtils(1, SAMPLE_RATE, 96); convertOk = lameUtils.raw2mp3(rawPath, mp3Path); return isRecording ^ convertOk;// convertOk==true,return true } /** * 获取文件的路径 * * @param fileAlias RAW or MP3 * @return */ public String getFilePath(int fileAlias) { if (fileAlias == RAW) { return rawPath; } else if (fileAlias == MP3) { return mp3Path; } else return null; } /** * 清理文件 */ public void cleanFile(int cleanFlag) { File f = null; try { switch (cleanFlag) { case MP3: f = new File(mp3Path); if (f.exists()) f.delete(); break; case RAW: f = new File(rawPath); if (f.exists()) f.delete(); break; case RAW | MP3: f = new File(rawPath); if (f.exists()) f.delete(); f = new File(mp3Path); if (f.exists()) f.delete(); break; } f = null; } catch (Exception e) { e.printStackTrace(); } } /** * 关闭,可以先调用cleanFile来清理文件 */ public void close() { if (mRecorder != null) mRecorder.release(); activity = null; } // -------内部的一些工具方法------- /** * 初始化 */ private void initRecorder() { bufferSize = AudioRecord.getMinBufferSize(SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); mBuffer = new short[bufferSize]; mRecorder = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); } /** * 设置路径,第一个为raw文件,第二个为mp3文件 * * @return */ private void getFilePath() { try { String folder = "audio_recorder_2_mp3"; String fileName = String.valueOf(System.currentTimeMillis()); if (rawPath == null) { File raw = new File(activity.getDir(folder, activity.MODE_PRIVATE), fileName + ".raw"); raw.createNewFile(); rawPath = raw.getAbsolutePath(); raw = null; } if (mp3Path == null) { File mp3 = new File(activity.getDir(folder, activity.MODE_PRIVATE), fileName + ".mp3"); mp3.createNewFile(); mp3Path = mp3.getAbsolutePath(); mp3 = null; } Log.d("rawPath", rawPath); Log.d("mp3Path", mp3Path); runCommand("chmod 777 " + rawPath); runCommand("chmod 777 " + mp3Path); } catch (Exception e) { e.printStackTrace(); } } /** * 执行cmd命令,并等待结果 * * @param command 命令 * @return 是否成功执行 */ private boolean runCommand(String command) { boolean ret = false; Process process = null; try { process = Runtime.getRuntime().exec(command); process.waitFor(); ret = true; } catch (Exception e) { e.printStackTrace(); } finally { try { process.destroy(); } catch (Exception e) { e.printStackTrace(); } } return ret; } /** * 写入到raw文件 * * @param file */ private void startBufferedWrite(final File file) { new Thread(new Runnable() { @Override public void run() { DataOutputStream output = null; try { output = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))); while (isRecording) { int readSize = mRecorder.read(mBuffer, 0, mBuffer.length); long v = 0; // 将 buffer 内容取出,进行平方和运算 for (int i = 0; i < mBuffer.length; i++) { v += mBuffer[i] * mBuffer[i]; } // 平方和除以数据总长度,得到音量大小。 double mean = v / (double) readSize; double volume = 10 * Math.log10(mean); notifySizeChanged((int)volume); for (int i = 0; i < readSize; i++) { output.writeShort(mBuffer[i]); } } } catch (IOException e) { e.printStackTrace(); } finally { if (output != null) { try { output.flush(); } catch (IOException e) { e.printStackTrace(); } finally { try { output.close(); } catch (IOException e) { e.printStackTrace(); } } } } } }).start(); } /** * 注册观察者 */ public void registerObserver(DecibelObserver observer) { if (observer != null) {//不为null并且不存在 mObservers.add(observer); } } /** * 注销观察者 */ public void unregisterObserver(DecibelObserver observer) { if (observer != null) { mObservers.remove(observer); } } /** * 声音分贝发生变化后通知观察者 */ public void notifySizeChanged(int dbSize) { for(int i =0; i<mObservers.size(); i++){ mObservers.get(0).decibelSizeChanged(dbSize); } } /** * 定义观察者接口 */ public interface DecibelObserver{ //录入声音分贝发生变化后通知 public void decibelSizeChanged(int dbSize); }}
到这里录音所有的代码就完成了…有了音频转换工具的轮子,所以实现起来很简单.如果发现什么问题可以给我留言,谢谢.
0 0
- Android语音录入(MP3格式)-小白无头脑实现
- Swift iOS实现把PCM语音转成MP3格式
- 微信amr格式语音转MP3
- Android录制mp3格式
- Android || IOS录制mp3语音文件方法
- Android || IOS录制mp3语音文件方法
- iOS开发通过lame将语音文件转为MP3格式
- Linux上silk微信语音转换成mp3格式
- Android MP3录音实现
- Android MP3录音实现
- Android语音播放格式问题
- Android语音播放格式问题
- java对于微信平台语音接收以及处理,语音下载以及arm格式转换MP3
- 【MP3】MP3格式分析
- Android和IOS录制mp3语音文件的方法
- Android和IOS录制mp3语音文件的方法
- Android 实现语音识别
- Android实现语音识别
- C# 事件与委托___窗口间的相互开启与关闭
- Python游戏系列之三_控制飞机移动
- 面试高级算法梳理笔记
- java实现bit-map算法存储大数据
- MUI框架中加载外部网页或服务器数据的方法
- Android语音录入(MP3格式)-小白无头脑实现
- 网易2017年秋季校招第二题
- RX系列五 | Schedulers线程控制
- 配置文件中用户更新
- Android NDK(七):JNI异常处理
- sqlite3 (Microsoft Visual Studio下32 64编绎)
- ViewPager实现页卡的最新方法--简洁的TabLayout(谷歌支持包)
- Cookie/Session机制详解
- 华为oj中级 整数与IP地址之间的转换