基于Handler架构的录音程序
近期我的app须要一个录音功能,于是搜到这篇文章
文章中录音线程与主线程间的通讯是通过内部类訪问外部类成员变量的方式来实现
while (isRecord == true) { //isRecord是外部类的成员变量
readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {
try {
fos.write(audiodata);
} catch (IOException e) {
e.printStackTrace();
}
}
}
一来自己对Java语法不是非常熟,二来认为这样的方法扩展性不好,所以决定用Handler来与主线程通信
但子线程要想接收主线程发来的消息,势必要调用Looper类的loop方法,该方法是个死循环。且參数为空(没法插入回调)
public void run() {
super.run();
Looper.prepare();
Looper.loop();//一旦进入这个函数,就出不来了
}
子线程无法既有Looper.loop()又有while(),所以我想到了一个workaround
将while里的语句放在一个事件里处理。处理完后调用handler再次向自身发送发送该事件,直到收到主线程的STOP事件
事实证明该方法可行,且相比Timer方式,没有时隙的浪费
上代码
package com.hp.speechclient; /**
* Created by Administrator on 15-7-16.
*/
import java.lang.Thread;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.FileNotFoundException; import android.util.Log;
import android.os.Handler;
import android.os.Message;
import android.os.Looper;
import android.os.Bundle;
import android.os.Environment;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder; public class RecordThread extends Thread {
private Context mUiCtx;
private Handler mUiHandler;
private boolean bRecording = false;
FileOutputStream mSpeechStream = null;
private AudioRecord mAudioRecord;
private int mUnitBufSize;
private static String TAG = RecordThread.class.getSimpleName(); public RecordThread(Context ctx, Handler handler){
mUiCtx = ctx;
mUiHandler = handler; mUnitBufSize = AudioRecord.getMinBufferSize(16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, 16000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, mUnitBufSize);
} private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg); switch (msg.what) {
case CommonMsg.REC_STOP: {
bRecording = false;
break;
}
case CommonMsg.REC_START: {
bRecording = true;
startRecord();
break;
}
case CommonMsg.UNIT_REC_FIN: {
if (bRecording) {
Message reply = mHandler.obtainMessage(CommonMsg.UNIT_REC_START);
mHandler.sendMessage(reply);
}else{
stopRecord();
Message reply = mUiHandler.obtainMessage(CommonMsg.REC_FIN);
mUiHandler.sendMessage(reply);
}
break;
}
case CommonMsg.UNIT_REC_START: {
recordUnit();
break;
}
default:{
assert false;
break;
}
}
}
}; public void run() {
super.run();
Looper.prepare();
Looper.loop();
} private void startRecord() {
mAudioRecord.startRecording();
try {
mSpeechStream = new FileOutputStream(CommonMsg.SPEECH_PATH + ".raw");// 建立一个可存取字节的文件
} catch (Exception e) {
assert false;
}
//開始一小段录音
recordUnit();
} private void stopRecord() {
mAudioRecord.stop(); try {
mSpeechStream.close();// 关闭写入流
mSpeechStream = null;
} catch (IOException e) {
assert false;
}
convertToWav(CommonMsg.SPEECH_PATH+".raw", CommonMsg.SPEECH_PATH+".wav");
} private void recordUnit() {
// new一个byte数组用来存一些字节数据。大小为缓冲区大小
byte[] audiodata = new byte[mUnitBufSize];
int readsize = 0;
readsize = mAudioRecord.read(audiodata, 0, mUnitBufSize);
if (AudioRecord.ERROR_INVALID_OPERATION != readsize) {
try {
mSpeechStream.write(audiodata);
} catch (IOException e) {
assert false;
}
}
Message reply = mHandler.obtainMessage(CommonMsg.UNIT_REC_FIN);
mHandler.sendMessage(reply);
} protected void finalize() {
try {
super.finalize();
mAudioRecord.release();//释放资源
mAudioRecord = null;
}catch (Throwable e) {
assert false;
}
} public Handler getHandler(){
return mHandler;
} private void convertToWav(String inFilename, String outFilename) {
FileInputStream in = null;
FileOutputStream out = null;
long totalAudioLen = 0;
long totalDataLen = totalAudioLen + 36;
int sampleRate = 16000;
int channels = 1;
byte bitDepth = 16;
long byteRate = bitDepth * sampleRate * channels / 8;
byte[] data = new byte[mUnitBufSize];
try {
in = new FileInputStream(inFilename);
out = new FileOutputStream(outFilename);
totalAudioLen = in.getChannel().size();
totalDataLen = totalAudioLen + 36;
WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
sampleRate, channels, bitDepth);
while (in.read(data) != -1) {
out.write(data);
}
in.close();
out.close();
} catch (FileNotFoundException e) {
assert false;
} catch (IOException e) {
assert false;
}
} private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,
long totalDataLen, int sampleRate, int channels, byte bitDepth)
throws IOException {
int byteRate = bitDepth * sampleRate * channels / 8;
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) (sampleRate & 0xff);
header[25] = (byte) ((sampleRate >> 8) & 0xff);
header[26] = (byte) ((sampleRate >> 16) & 0xff);
header[27] = (byte) ((sampleRate >> 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) (channels * bitDepth / 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);
} }
基于Handler架构的录音程序的更多相关文章
- 教你轻松构建基于 Serverless 架构的小程序
前言 自 2017 年第一批小程序上线以来,越来越多的移动端应用以小程序的形式呈现.小程序触手可及.用完即走的优点,大大降低了用户的使用负担,也使小程序得到了广泛的传播.在阿里巴巴,小程序也被广泛地应 ...
- 基于ALSA的WAV播放和录音程序
http://blog.csdn.net/azloong/article/details/6140824 这段时间在探索ALSA架构,从ALSA Core到ALSA Lib,再到Android Aud ...
- 基于Struts2.3.x+Spring3.2.x+Hibernate4.2.x+EasyUI1.3.4+Maven架构的示例程序
基于Struts2.3.x+Spring3.2.x+Hibernate4.2.x+EasyUI1.3.4+Maven架构的示例程序 不知道为什么,保存的时候显示有一个连接为违禁内容,可能是…………. ...
- Apworks框架实战(四):使用Visual Studio开发面向经典分层架构的应用程序:从EasyMemo案例开始
时隔一年,继续我们的Apworks框架之旅.在接下来的文章中,我将逐渐向大家介绍如何在Visual Studio中结合Apworks框架,使用ASP.NET Web API和MVC来开发面向经典分层架 ...
- 基于AgileEAS.NET企业应用平台实现基于SOA架构的应用整合方案-开篇
开篇 系统架构的文章,准备在这段时间好好的梳理和整理一下,然后发布基于AgileEAS.NET平台之上的企业级应用架构实践,结合具体的案例来说明AgileEAS.NET平 台之上如何进行系统的逻辑架构 ...
- 从零开始实现基于微信JS-SDK的录音与语音评价功能
最近接受了一个新的需求,希望制作一个基于微信的英语语音评价页面.即点击录音按钮,用户录音说出预设的英文,根据用户的发音给出对应的评价.以下是简单的Demo: 
环境配置: 开启服务器伪静态 本处以apache为例,查看apache的conf目录下httpd.conf,找到下面的代码 LoadModule rewrite_module modules/mod_ ...
- 在Autodesk应用程序商店发布基于浏览器的Web应用程序
你一定已经听说过Autodesk应用程序商店了,通过Autodesk应用程序商店,你可以免费下载或购买来自全球的优秀开发者发布的应用程序,来帮助你更快更方便的完成你的工作.而且作为开发者,您也可以在A ...
- 开源一个基于nio的java网络程序
因为最近要从公司离职,害怕用nio写的网络程序没有人能看懂(或许是因为写的不好吧),就调整成了mina(这样大家接触起来非常方便,即使没有socket基础,用起来也不难),所以之前基于nio写的网络程 ...
随机推荐
- Js的闭包,这篇写的是比较清晰明了的
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量 ...
- 一起写框架-控制反转(Ioc)概述(二)
控制反转概述 控制反转(Inversion of Control,英文缩写为IoC),就是将代码的调用的控制权,由调用方转移给被调用方. 如图:修改代码A类的代码,才能将B类的对象换成C类.代码的控制 ...
- maven构建geotools应用工程
前置条件 jdk1.7+eclipse+maven POM配置 <project xmlns="http://maven.apache.org/POM/4.0.0" xmln ...
- linux7.2系统中安装Nmon并使用
前提 安装linux系统中遇到一个问题,设置ip以后则ping不通,简单总结几步: 1.设置ip 进入 /etc/sysconfig/network-scripts目录下,修改文件名为ifcfg-en ...
- 阿里Dubbo疯狂更新,关Spring Cloud什么事?
最近,开源社区发生了一件大事,那个全国 Java 开发者使用最广的开源服务框架 Dubbo 低调重启维护,并且 3 个月连续发布了 4 个维护版本. 我上次在写放弃Dubbo,选择最流行的Spring ...
- 关于vue 框架与后台框架的混合使用的尝试
这几天我在研究前台框架和后台框架融合的问题,进行了一些尝试; 我前台选择的是 vue,当然也可以选择 react 等其他 mvvm 框架,不过 vue 对于我来说是最熟悉的; 后台话,我选择的是 ph ...
- AndroidStudio中各种常见快捷键记录
AndroidStudio中各种常用操作快捷键记录 简单方法 直接设置AS的快捷键与eclipse相同,方便直接从eclipse切到AS的人. 常用的AS的默认快捷键 ctrl + N 根据类名查找J ...
- 简单背包问题(0032)-swust oj
简单背包问题(0032) Time limit(ms): 1000 Memory limit(kb): 65535 Submission: 5657 Accepted: 1714 Accepted 搜 ...
- Activity讲解
Activity Activity 是 Android 应用的重要组成单元之一(另外三个是 Service.BroadcastReceiver 和 ContentProvider),而 Activit ...
- 使用map做数组与链表去重
#include<iostream> #include<map> using namespace std; class node{ public: node():value() ...