近期我的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. Red Hat 7.0 DNS服务配置笔记

    先挂载镜像,然后配置yum,然后安装yum install -y bind 配置静态 IP.DNS就是他本身的IP地址. 修改DNS的配置文件,在后面加入区域配置信息.vim /etc/named.c ...

  2. Oracle-1 - :超级适合初学者的入门级笔记,CRUD,事务,约束 ......

    Oracle 更改时间: 2017-10-25  -  21:33:49 2017-10-26  -  11:43:19 2017-10-27  -  19:06:57 2017-10-28  -  ...

  3. spring boot一个简单用户管理DEMO

    概述 该Demo旨在部署一个简单spring boot工程,包含数据编辑和查看功能 POM配置 <?xml version="1.0" encoding="UTF- ...

  4. 虚拟机通信配置与Xshell连接

    本文主要讲解虚拟机通信配置的详细步骤和Xshell工具连接,以及如何诊断网络问题并进行相应配置的问题. 1. 虚拟机通信配置 虚拟机通信配置的基本流程如图所示: 首先,我们先打开新建的虚拟机,然后输入 ...

  5. 使用wwise音效引擎的好处

    用过一段时间的wwise,做以下几个具体功能的时候比较方便: 1.当策划需求一个声音需要随机播放多个随机音源的其中一个时,例如脚步声.普通攻击声,当这类声音一直播放的都是同一个音源的时候,人会产生听觉 ...

  6. 如何添加title左侧的图标

    在titile标签上方插入以下代码,图片要求格式必须是.ico. <link rel="shortcut icon" href="images/favicon.ic ...

  7. 关于 innodb_stats_on_metadata 的设置问题

    [问题背景] 线上使用osc进行表修改的时候出现SQL执行过长被kill的问题

  8. JQuery使用笔记

    1.选择器 id选择器: $('#btnShow') class选择器: $('.banner') tag选择器: $('input') 2.常用方法 取 / 设value: $('#btnShow' ...

  9. P1132 数字生成游戏

    题目请见:传送门 以下为题解,直接从洛谷上搬过来的,还专门改了markdown,(汗) 宽搜 with 一些技巧 由于查询量很大,所以要预先处理所有答案 预处理当然是用BFS,并同时进行delete, ...

  10. 无法将类型为“System.DBNull”的对象强制转换为类型“System.String”

    在ERP中做业务类单据,有时候会遇到这样的报错. 无法将类型为"System.DBNull"的对象强制转换为类型"System.String"   去数据库中检 ...