zoukankan      html  css  js  c++  java
  • Android 获取 AudioRecord 麦克风音量大小并做选择性发送

     extends:http://blog.csdn.net/alvinhuai/article/details/8955127,http://mikespook.com/2010/11/android-%E5%AE%9E%E6%97%B6%E8%8E%B7%E5%8F%96%E9%BA%A6%E5%85%8B%E9%A3%8E%E8%BE%93%E5%85%A5%E9%9F%B3%E9%87%8F%E7%9A%84%E4%BB%A3%E7%A0%81/

      前几天做一个关于录音并获取音量大小的模块,今天写一个demo和大家分享。如果有各位有更好的方法可以留言提醒我,谢谢。

        首先录音功能很容易实现,通过audiorecord或者mediarecorder都可以实现,如果要获取录音音量的大小,用audiorecord更加方便。实现录音功能可以大致分为几个步骤。一 初始化录音设备audiorecord。 二 ,开启一个线程实现录音功能。 三 获取录音的音频流对它的大小进行分析。四 将大小传递至主线程使UI做出相应的改变。

        首先初始化audiorecord 。AudioRecord (int audioSource, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes) ,初始化需要五个参数,audiosource 是指录制源在此我们选择麦克风:MediaRecorder.AudioSource.MIC。  sampleRateInHz 默认采样频率,以赫兹为单位,官方文档说44100 为目前所有设备兼容,但是如果用模拟器测试的话会有问题,所以有的也用8000。  channelConfig ,  描述音频通道设置 CHANNEL_IN_MONO保证能在所有设备上工作。audioFormat 音频流的格式,分为16bit 或8bit目前都支持的是ENCODING_PCM_16BIT.  bufferSizeInBytes 在录制过程中,音频数据写入缓冲区的总数(字节)。 从缓冲区读取的新音频数据总会小于此值. 这个值一般通过getMinBufferSize来获取。getMinBufferSize的参数可以参照audiorecord的构造函数。在oncreate中执行一下代码。 

    try {
                    mMinibuffer = AudioRecord.getMinBufferSize(sampleRates,
                                    AudioFormat.CHANNEL_IN_MONO,
                                    AudioFormat.ENCODING_PCM_16BIT);
                    if(mMinibuffer != AudioRecord.ERROR_BAD_VALUE){
                            mRecord = new AudioRecord(MediaRecorder.AudioSource.MIC,
                                          sampleRates[i],
                                          AudioFormat.CHANNEL_IN_MONO,
                                          AudioFormat.ENCODING_PCM_16BIT,
                                          mMinibuffer);
                    }
                } catch (IllegalArgumentException e) {
                    ;
                }

    这是audiorecord的初始化,下面可以实现录音

    public class RecordThread extends Thread{
            private boolean mIsRun = false;
            public RecordThread(){
                super();
            }
            public void run(){
                super.run();
                MainActivity.this.mRecord.startRecording();
                byte[]  byte_buffer = new byte[mMinibuffer];
                mIsRun = true;
                while(mIsRun){
                    int r = mRecord.read(byte_buffer,0,mMinibuffer);
                    int mShortArrayLenght = r/2;
                    short[] short_buffer = new short[mShortArrayLenght];
                    short_buffer = byteArrayToShortArray(byte_buffer,mShortArrayLenght);
                    int max =  0;
                    if(r > 0){
                        for(int i=0; i<mShortArrayLenght; i++){
                            if(Math.abs(short_buffer[i]) > max){
                                max = Math.abs(short_buffer[i]);
                            }
                        }
                        Bundle mBundle = new Bundle();
                        mBundle.putInt(mSendData, max);
                        Message Msg = new Message();
                        Msg.what = RECORDSTATE;
                        Msg.setData(mBundle);
                        mHandler.sendMessage(Msg);
                    }
                }
                MainActivity.this.mRecord.stop();
                mHandler.sendEmptyMessage(NULLBUFFER);
            }
    
            public void stopRecord(){
                mIsRun = false;
            }
        }

    这里是写一个线程实现录音功能。byte_buffer  保存录制的音频流,因为每次录制次数很多,我暂时将每次录音的最大值当作这次录音的音量,然后通过handler将最大值返回给主线程。如果需要停止这个线程可以通过调用这个线程函数 stopRecord(); 然后我们通过每次得到的音量值,可以通过view的ondraw函数,将音量变化动态的画出来。具体代码不全贴出来的,主要讲一下这个思想。 如果有人需要可以直接留言给我, 可以发给大伙。

    public class BoschAudioClient extends Thread {
    
        static final int frequency = 44100;
        static final int channelConfiguration = AudioFormat.CHANNEL_CONFIGURATION_MONO;
        static final int audioEncoding = AudioFormat.ENCODING_PCM_16BIT;
        private final int socketVol = 2000;
        private final int cycle = 8;
        protected AudioRecord m_in_rec;
        protected int m_in_buf_size;
        protected byte[] m_in_bytes;
        protected boolean m_keep_running;
        protected LinkedList<byte[]> m_in_q;
        private int volTime = 0;
        private boolean flagVol = false;
    
        public  AudioClient() {
    
            m_in_buf_size = AudioRecord.getMinBufferSize(frequency,
                    channelConfiguration, audioEncoding) * 2;
    
            m_in_rec = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    8000, channelConfiguration, audioEncoding,
                    m_in_buf_size);
    
            m_in_bytes = new byte[m_in_buf_size];
    
            m_keep_running = true;
            m_in_q = new LinkedList<byte[]>();
        }
    
        public void run() {
            try {
                byte[] bytes_pkg;
                m_in_rec.startRecording();
                while (m_keep_running) {
    
                    //从内存获取数据
                    int r = m_in_rec.read(m_in_bytes, 0, m_in_buf_size);
                    bytes_pkg = m_in_bytes.clone();
    
                    //发送socket数据
                    if (m_in_q.size() >= 2) {
                        byte[] buff = m_in_q.removeFirst();
                        ByteString socketStr = ByteString.copyFrom(buff);
                   }
    
                    //音量
                    int maxVol = getVolumeMax(r, bytes_pkg);
    //                int v = getVolume(r, bytes_pkg);
                    //如果音量大于最小值 打开开关
                    if (maxVol > socketVol) {
                        flagVol = true;
                    }
    
                    //如果开关为打开状态,开始计时,计时大约1个周期的时候 ,关闭开关,停止计时,停止发送数据
                    if (flagVol) {
                        m_in_q.add(bytes_pkg);
                        volTime++;
                        if ((volTime / cycle) > 0) {
                            flagVol = false;
                            volTime = 0;
                        }
                    }
            
                }
    
                m_in_rec.stop();
                m_in_rec = null;
                m_in_bytes = null;
    
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
        private int getVolume(int r, byte[] bytes_pkg) {
            //way 1
            int v = 0;
    //      将 buffer 内容取出,进行平方和运算
            for (byte aBytes_pkg : bytes_pkg) {
                // 这里没有做运算的优化,为了更加清晰的展示代码
                v += aBytes_pkg * aBytes_pkg;
            }
    //      平方和除以数据总长度,得到音量大小。可以获取白噪声值,然后对实际采样进行标准化。
    //      如果想利用这个数值进行操作,建议用 sendMessage 将其抛出,在 Handler 里进行处理。
            int volume = (int) (v / (float) r);
            return volume;
        }
    
        private int getVolumeMax(int r, byte[] bytes_pkg) {
    
            //way 2
            int mShortArrayLenght = r / 2;
            short[] short_buffer = byteArray2ShortArray(bytes_pkg, mShortArrayLenght);
            int max = 0;
            if (r > 0) {
                for (int i = 0; i < mShortArrayLenght; i++) {
                    if (Math.abs(short_buffer[i]) > max) {
                        max = Math.abs(short_buffer[i]);
                    }
                }
            }
            return max;
        }
    
        private short[] byteArray2ShortArray(byte[] data, int items) {
            short[] retVal = new short[items];
            for (int i = 0; i < retVal.length; i++)
                retVal[i] = (short) ((data[i * 2] & 0xff) | (data[i * 2 + 1] & 0xff) << 8);
    
            return retVal;
        }
    
        public void free() {
            m_keep_running = false;
            try {
                Thread.sleep(100);
            } catch (Exception e) {
                Log.d("sleep exceptions...
    ", "");
            }
        }
    
    }
     
  • 相关阅读:
    爬取拉勾部分求职信息+Bootstrap页面显示
    一名IT的术后
    CodeFirst-Section1之小例子
    简简单单C#爬虫小计
    分页:T-SQL存储过程和EF存储过程的使用
    利用jQuery获取数据,JSONP
    更新数据库忘记加条件
    redis学习笔记(九): replication
    redis学习笔记(八): multi
    redis学习笔记(七): pubsub
  • 原文地址:https://www.cnblogs.com/niray/p/4329347.html
Copyright © 2011-2022 走看看