基于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);
    }

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-28 18:28:00

基于Handler架构的录音程序的相关文章

轻松构建基于 Serverless 架构的小程序

前言 自 2017 年第一批小程序上线以来,越来越多的移动端应用以小程序的形式呈现.小程序拥有触手可及.用完即走的优点,这大大降低了用户的使用负担,使小程序得到了广泛的传播.在阿里巴巴,小程序也被广泛地应用在淘宝/支付宝/钉钉/高德等平台上. 为了支撑大量的小程序,服务端面临的挑战有: 大量的小程序是不活跃的,传统的至少一台服务器的方式会造成资源浪费: 在活动高峰期小程序的调用量激增,要求服务端能够快速进行弹性伸缩. 而小程序开发者往往是客户端/前端的开发者,更多的精力在开发业务代码与应用的快速

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

http://blog.csdn.net/azloong/article/details/6140824 这段时间在探索ALSA架构,从ALSA Core到ALSA Lib,再到Android Audio System.在看ALSA Lib时,写了一个比较典型的基于ALSA的播放录音程序.程序包包含四个部分: WAV Parser是对WAV文件的分析和封装,这里只针对Standard WAV File: SND Common是Playback 和Record共同操作,如SetParams.Rea

有了门面,程序会更加体面!- pos软件基于三层架构 -09

续上篇)        大鸟说道:"实际上没有学过设计模式去理解三层架构会有失偏颇的,毕竟分层是更高一级别的模式,所谓的架构模式.不过在程序中,有意识的遵循设计原则,却也可以有效的做出好的设计."      "不要告诉我,刚才讲的'迪米特法则'就会在分层中用得上?"小菜说.     "当然用得上,否则讲它干吗,你当我是在安慰你而临时编个法则来骗骗你呀?来,再来看看你上次写的代码." 先来看看之前用反射机制改良的pos程序 DataSet ds;

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

基于OpenFlow架构的IaaS云安全

编者按:云计算技术的服务型基础设施即服务(IaaS),以其可扩展性.高效性及弹性等特点正在成为资源利用的主导方式.在从云计算的IaaS应用获得便捷的同时,安全漏洞和隐患也需要被关注.在这项工作中,我们提出建议架构,并已形成论文<An OpenFlow-based Architecture for IaaS Security>,以解决云计算的安全问题以及展示我们实验活动的第一批成果. 简介 IaaS的服务模式允许在不关注底层物理基础设施的情况下,配置和运行异构应用程序.云计算技术创建出一个可以重

4-源码方式基于LAMP架构搭建BBS论坛或者博客

目录 一.项目简介 二.环境准备 三.编译安装MySQL 四.编译安装Apache 五.编译安装PHP 六.后续配置 七.启动相关服务 八.源码编译软件经验总结 九.部署web应用 排错1: 排错2: 排错3: 大功告成! 课程目标 使用源码方式基于LAMP架构搭建BBS论坛或者博客 本文成功搭建2个网站,一个个人博客,一个是web界面管理mysql数据库的应用 请耐心阅读,细心操作,你也会成功! 思考:yum工具搭建lamp环境和源码包搭建的区别 rpm版本 安装方便,升级.卸载都很灵活,很难

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

最近接受了一个新的需求,希望制作一个基于微信的英语语音评价页面.即点击录音按钮,用户录音说出预设的英文,根据用户的发音给出对应的评价.以下是简单的Demo: ![](reecode/qrcode.png) --> 最近接受了一个新的需求,希望制作一个基于微信的英语语音评价页面.即点击录音按钮,用户录音说出预设的英文,根据用户的发音给出对应的评价.以下是示例二维码,使用微信扫一扫即可查看: ? 录音 ? 录音动画 ? 录音播放 ? 英语语音评价(部分实现) ? 只允许微信客户端打开 零 技术选型

基于运营架构的办公流程能力平台

基于运营架构的办公流程能力平台服务于大.中型企事业单位,为企业业务流程重组提供信息化解决方案和支撑. 办公流程管理以流程化管理为核心,此核心包括:流程建模及其生命周期管理.流程执行管理及其生命周期管理.流程监控与分析三部分.围绕流程管理的生命周期展开,他能体现出管理的能力.效益.效率. 流程建模及其生命周期管理包括:业务需求.开发建设.上线(并形成流程目录).变更.下线.最终销毁全生命周期管理.相关的业务功能有:流程快速开发和流程建模.流程后评估: 流程执行及其生命周期管理包括:启动流程实例.流

Vertica: 基于DBMS架构的列存储数据仓库

介绍 Vertica(属 于HP公司),是一个基于DBMS架构的数据库系统,适合读密集的分析型数据库应用,比如数据仓库,白皮书中全名称为VerticaAnalytic Database.从命名中也可以看到,Vertica代表它数据存储是列式的,Analytic代表适合分析型需求,DB代表本身是数据库,支持 SQL. 优势 和传统关系型数据库系统以及其他列式数据(仓)库相比,Vertica存在下面三点最关键的优势. 列存储 Vertica对磁盘上的数据采用列式存储,显而易见,列存储可以在数据读取的