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...\n", "");        }    }} 

更多相关文章

  1. Android使用GPS获取用户地理位置并监听位置变化的方法
  2. Android(安卓)定位的实现
  3. Android(安卓)版本更新的实现
  4. Java乔晓松-android中获取手机视频的缩略图
  5. [置顶] android ScrollView,ListView 截屏并保存到图库
  6. Android中dip(dp)与px之间单位转换 dip2px dp转px 无context算法
  7. 使用FileProvider共享文件
  8. getDrawable()缓存带来的问题
  9. android获取Mac地址和IP地址

随机推荐

  1. 【Android】软键盘弹出收起事件监听
  2. android初始化
  3. android studio 常见错误总结
  4. android开发实例05:新浪微博图片缩放实现
  5. 代码中修改TextView的DrawableLeft图片
  6. Android检测相同SSID下的wifi热点并切换
  7. unbuntu 下android(MT6573) 编译环境设置
  8. android 设置线程优先级 两种方式
  9. Android课程设计,生活记事本
  10. android将图片转成字符串,再将字符串转成