近期我的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. iOS内置图片瘦身思路整理

    一.前言 前段时间注意到我们APP的包大小超过100MB了,所以随口跟老板说了下能否采用字体文件(.ttf)替代PNG图片,老板对应用瘦身很感兴趣因此让我做下技术调研.这篇文章主要是将我们的各个技术方 ...

  2. 一:MySQL数据库的性能的影响分析及其优化

    MySQL数据库的性能的影响分析及其优化 MySQL数据库的性能的影响 一. 服务器的硬件的限制 二. 服务器所使用的操作系统 三. 服务器的所配置的参数设置不同 四. 数据库存储引擎的选择 五. 数 ...

  3. Unity学习资料

    前段时间刚简单接触下Spring.net,刚会简单注入,最近接手一项目确是用的Unity,网上找了一些很好的教程资料 算是入门了,高手已经写的很好了,我就转个链接吧: Unity V3 初步使用 —— ...

  4. c# 小小备忘录

    一.简述 备忘录,相信大家生活中都使用过,比如记笔记.手机备忘录等等,这些都是记录自己灵感时所想.定期内想做的事情,好像跑题了,说说我的备忘录吧,我的备忘录功能上也就是增删改查的操作,另加到时提醒.语 ...

  5. [转载] Java NIO与IO

    原文地址:http://tutorials.jenkov.com/java-nio/nio-vs-io.html 作者:Jakob Jenkov   译者:郭蕾    校对:方腾飞 当学习了Java ...

  6. linux操作系统基础篇(六)

    linux服务篇 1.samba服务的搭建 samba的功能: samba是一个网络服务器,用于Linux和Windows之间共享文件.2. samba服务的启动.停止.重启service smb s ...

  7. Vocabulary & Phrase

    Vocabulary A ANSI    美国国家标准学会,American National Standards Institute的缩写 a couple of    [口语]少数的,几个 a s ...

  8. python之socket模块

    UDP client #!/usr/bin/env python2.7 #-*-coding:utf-8 -*- import socket s=socket.socket(socket.AF_INE ...

  9. crontab中使用python无法执行

    手动执行可以的,但是在crontab中却无法执行,在网上搜了一圈,给出的结论是将相对路径改成绝对路径. 改了之后解决这个问题. 是不是依赖某些环境变量,linux 里的 cron 只有几个基本的环境变 ...

  10. 1455:An Easy Problem

    传送门:http://noi.openjudge.cn/ch0406/1455/ /-24作业 //#include "stdafx.h" #include<bits/std ...