基于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: ![](reecode/qrcode.pn ...
- Yii2 基于RESTful架构的 advanced版API接口开发 配置、实现、测试 (转)
环境配置: 开启服务器伪静态 本处以apache为例,查看apache的conf目录下httpd.conf,找到下面的代码 LoadModule rewrite_module modules/mod_ ...
- 在Autodesk应用程序商店发布基于浏览器的Web应用程序
你一定已经听说过Autodesk应用程序商店了,通过Autodesk应用程序商店,你可以免费下载或购买来自全球的优秀开发者发布的应用程序,来帮助你更快更方便的完成你的工作.而且作为开发者,您也可以在A ...
- 开源一个基于nio的java网络程序
因为最近要从公司离职,害怕用nio写的网络程序没有人能看懂(或许是因为写的不好吧),就调整成了mina(这样大家接触起来非常方便,即使没有socket基础,用起来也不难),所以之前基于nio写的网络程 ...
随机推荐
- ASP.NET MVC中URL末尾斜杠的实现
在网站的SEO优化中,通常都会涉及到URL结尾斜杠的问题. http://blog.sina.com.cn/s/blog_828e7ce40100srj1.html http://www.dengyo ...
- Deploy .Net project automatically with MsBuild and MsDeploy (0)
I will use a example of my project to show how to use MS Build and MS Deploy in a real project and s ...
- C#实现阿拉伯数字(小写金额)到大写中文(大写金额)的转换
/// <summary> /// 本类实现阿拉伯数字到大写中文的转换 /// 该类没有对非法数字进行判别,请事先自己判断数字是否合法 /// </summary& ...
- C语言控制流语句
title: 2017-10-18控制流 tags: binsearch else-if, shellsort, insertsort grammar_cjkRuby: true --- 前段时间忙着 ...
- Scratch——教小孩子学编码
教小孩子学编码 http://scratch.mit.edu/ http://v.163.com/movie/2013/3/H/I/M92389L06_M9238GTHI.html
- Python手动实现k-means
import numpy as np import matplotlib.pyplot as plt def kmeans(data, cluster_num, method='mean'): poi ...
- vue 组件中数组的更新
今天写项目时遇到的问题,瞬间就卡在那了 来还原一下: parent.vue: <template> <div> <button @click="change&q ...
- (一)IDEA工具开第一个springboot应用之helloworld
(一)IDEA工具开第一个springboot应用之helloworld 一.前置知识 1.maven相关知识 2.spring注解 3.RESTful API 二.idea开发第一个springbo ...
- 《java.util.concurrent 包源码阅读》09 线程池系列之介绍篇
concurrent包中Executor接口的主要类的关系图如下: Executor接口非常单一,就是执行一个Runnable的命令. public interface Executor { void ...
- 这些工具对html5开发有很大帮助
如今H5已经在IT这块很热门,所以也就有越来越多的人自学或是报名培训班学习H5,今天写一篇关于当下html5开发工具有哪些?哪个更好一些? 浅谈2017年html5开发工具哪个好: 1.Adobe D ...