近期我的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架构的录音程序的更多相关文章

  1. 教你轻松构建基于 Serverless 架构的小程序

    前言 自 2017 年第一批小程序上线以来,越来越多的移动端应用以小程序的形式呈现.小程序触手可及.用完即走的优点,大大降低了用户的使用负担,也使小程序得到了广泛的传播.在阿里巴巴,小程序也被广泛地应 ...

  2. 基于ALSA的WAV播放和录音程序

    http://blog.csdn.net/azloong/article/details/6140824 这段时间在探索ALSA架构,从ALSA Core到ALSA Lib,再到Android Aud ...

  3. 基于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架构的示例程序 不知道为什么,保存的时候显示有一个连接为违禁内容,可能是…………. ...

  4. Apworks框架实战(四):使用Visual Studio开发面向经典分层架构的应用程序:从EasyMemo案例开始

    时隔一年,继续我们的Apworks框架之旅.在接下来的文章中,我将逐渐向大家介绍如何在Visual Studio中结合Apworks框架,使用ASP.NET Web API和MVC来开发面向经典分层架 ...

  5. 基于AgileEAS.NET企业应用平台实现基于SOA架构的应用整合方案-开篇

    开篇 系统架构的文章,准备在这段时间好好的梳理和整理一下,然后发布基于AgileEAS.NET平台之上的企业级应用架构实践,结合具体的案例来说明AgileEAS.NET平 台之上如何进行系统的逻辑架构 ...

  6. 从零开始实现基于微信JS-SDK的录音与语音评价功能

    最近接受了一个新的需求,希望制作一个基于微信的英语语音评价页面.即点击录音按钮,用户录音说出预设的英文,根据用户的发音给出对应的评价.以下是简单的Demo: ![](reecode/qrcode.pn ...

  7. Yii2 基于RESTful架构的 advanced版API接口开发 配置、实现、测试 (转)

    环境配置: 开启服务器伪静态 本处以apache为例,查看apache的conf目录下httpd.conf,找到下面的代码 LoadModule rewrite_module modules/mod_ ...

  8. 在Autodesk应用程序商店发布基于浏览器的Web应用程序

    你一定已经听说过Autodesk应用程序商店了,通过Autodesk应用程序商店,你可以免费下载或购买来自全球的优秀开发者发布的应用程序,来帮助你更快更方便的完成你的工作.而且作为开发者,您也可以在A ...

  9. 开源一个基于nio的java网络程序

    因为最近要从公司离职,害怕用nio写的网络程序没有人能看懂(或许是因为写的不好吧),就调整成了mina(这样大家接触起来非常方便,即使没有socket基础,用起来也不难),所以之前基于nio写的网络程 ...

随机推荐

  1. Power BI本地部署(10月正式版)

    Power BI安装环境要求 Windows 7/Windows Server 2008 R2 或更高版本 .NET 4.5 或更高版本 Internet Explorer 9 或更高版本 内存 (R ...

  2. [转载] 详述三种现代JVM语言--Groovy,Scala和Clojure

    转载自http://www.tuicool.com/articles/jYzuAv和http://www.importnew.com/1537.html 在我与Martin Fowler曾经合作呈现的 ...

  3. [转载] 《Hadoop基础教程》之初识Hadoop

    转载自http://blessht.iteye.com/blog/2095675 Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不适用 ...

  4. [转载] java垃圾回收机制

    转载自http://blog.csdn.net/randyjiawenjie/article/details/7551228 http://www.daniel-journey.com/archive ...

  5. 设计模式的征途—10.装饰(Decorator)模式

    虽然目前房价依旧很高,就连我所在的成都郊区(非中心城区)的房价均价都早已破万,但却还是阻挡不了大家对新房的渴望和买房的热情.如果大家买的是清水房,那么无疑还有一项艰巨的任务在等着大家,那就是装修.对新 ...

  6. radis学习总结

    Redis与Memcached的比较. 1.Memcached是多线程,而Redis使用单线程. 2.Memcached使用预分配的内存池的方式,Redis使用现场申请内存的方式来存储数据,并且可以配 ...

  7. P2757 导弹的召唤(数据加强)

    传送门 LIS的O(nlgn)模板题.加强"导弹拦截" #include <cstdio> #include <cstring> #include < ...

  8. Winform界面中实现通用工具栏按钮的事件处理

    在一个给客户做的项目中,界面要求修改增加通用工具栏按钮的事件处理,也就是在主界面中放置几个固定的功能操作按钮,打开不同的页面的时候,实现对应页面的功能处理,这种和我标准的界面处理方式有所不同,标准的列 ...

  9. 异常:Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException

    这个异常是出现在注入配置文件中配置好的属性时报错的: Injection of autowired dependencies failed; nested exception is java.lang ...

  10. SQL测试题

    一.网上收集了一些测试题,对于掌握SQL查询语句. /* Navicat MySQL Data Transfer Source Server : lizebo's MYSQL Source Serve ...