实现类:

package com.ar;import android.media.AudioFormat;import android.media.AudioRecord;import android.media.MediaCodec;import android.media.MediaCodecInfo;import android.media.MediaFormat;import android.media.MediaRecorder;import android.os.Build;import android.support.annotation.RequiresApi;import android.util.Log;import android.widget.Button;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.nio.ByteBuffer;import java.util.concurrent.ArrayBlockingQueue;public class AudioRecordManager {    private final int sampleRateInHz = 44100;//44100 16000    private final int channelConfig = AudioFormat.CHANNEL_IN_MONO;    private final int audioFormat = AudioFormat.ENCODING_PCM_16BIT;    private String audioFilePath;    private String tag="AudioRecordManager";    private class AudioData {        private ByteBuffer buffer;        private int size;    }    private AudioRecorder mAudioRecorder;    private AudioEncorder mAudioEncorder;    private ArrayBlockingQueue queue;    /**     *     * @param audioFilePath 文件名     */    public AudioRecordManager(String audioFilePath) {        this.audioFilePath=audioFilePath;        queue = new ArrayBlockingQueue<>(1024);        mAudioRecorder = new AudioRecorder();        mAudioEncorder = new AudioEncorder();    }    public void startRecord() {        mAudioRecorder.start();        mAudioEncorder.start();    }    public void stopRecord() {        mAudioRecorder.stopRecording();        mAudioEncorder.stopEncording();    }    /**     * 录音线程     */    public class AudioRecorder extends Thread {        private AudioRecord mAudioRecord;        private boolean isRecording;        private int minBufferSize;        public AudioRecorder() {            isRecording = true;            initRecorder();        }        @Override        public void run() {            super.run();            startRecording();        }        /**         * 初始化录音         */        public void initRecorder() {            minBufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)*2;// 乘以2 加大缓冲区,防止其他意外            mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, sampleRateInHz, channelConfig, audioFormat, minBufferSize);            if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {                isRecording = false;                return;            }        }        /**         * 释放资源         */        public void release() {            if (mAudioRecord != null && mAudioRecord.getState() == AudioRecord.STATE_INITIALIZED) {                mAudioRecord.stop();            }        }        /**         * 开始录音         */        public void startRecording() {            if (mAudioRecord == null) {                return;            }            mAudioRecord.startRecording();            while (isRecording) {                long a=System.currentTimeMillis();                AudioData audioDate = new AudioData();                audioDate.buffer = ByteBuffer.allocateDirect(minBufferSize);                audioDate.size = mAudioRecord.read(audioDate.buffer, minBufferSize);                try {                    if (queue != null) {                        queue.put(audioDate);                    }                } catch (InterruptedException e) {                    e.printStackTrace();                }                long b=System.currentTimeMillis()-a;                Log.i(tag,"录制耗时-毫秒=="+b);            }            release();        }        /**         * 结束录音         */        public void stopRecording() {            isRecording = false;        }    }    /**     * 音频编码线程     */    public class AudioEncorder extends Thread {        private MediaCodec mEncorder;        private Boolean isEncording = false;        private int minBufferSize;        private OutputStream mFileStream;        public AudioEncorder() {            isEncording = true;            initEncorder();        }        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)        @Override        public void run() {            super.run();            startEncording();        }        /**         * 初始化编码器         */        private void initEncorder() {            minBufferSize = AudioRecord.getMinBufferSize(sampleRateInHz, channelConfig, audioFormat)*2;// 乘以2 加大缓冲区,防止其他意外            try {                mEncorder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_AUDIO_AAC);            } catch (Exception e) {                e.printStackTrace();            }            MediaFormat format = MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, sampleRateInHz, 1);            format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC);            format.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);            format.setInteger(MediaFormat.KEY_BIT_RATE, 96000);            format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, minBufferSize * 4);            mEncorder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);        }        /**         * 开始编码         */        @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)        public void startEncording() {            if (mEncorder == null) {                return;            }            mEncorder.start();            try {                mFileStream = new FileOutputStream(audioFilePath);                MediaCodec.BufferInfo mBufferInfo = new MediaCodec.BufferInfo();                AudioData audioData;                while (isEncording) {                    long a=System.currentTimeMillis();                    // 从队列中取出录音的一帧音频数据                    audioData = getAudioData();                    if (audioData == null) {                        continue;                    }                    // 取出InputBuffer,填充音频数据,然后输送到编码器进行编码                    int inputBufferIndex = mEncorder.dequeueInputBuffer(0);                    if (inputBufferIndex >= 0) {                        ByteBuffer inputBuffer = mEncorder.getInputBuffer(inputBufferIndex);                        inputBuffer.clear();                        inputBuffer.put(audioData.buffer);                        mEncorder.queueInputBuffer(inputBufferIndex, 0, audioData.size, System.nanoTime(), 0);                    }                    // 取出编码好的一帧音频数据,然后给这一帧添加ADTS头                    int outputBufferIndex = mEncorder.dequeueOutputBuffer(mBufferInfo, 0);                    while (outputBufferIndex >= 0) {//                        int outBitsSize = mBufferInfo.size;//                        int outPacketSize = outBitsSize + 7; // ADTS头部是7个字节//                        ByteBuffer outputBuffer = mEncorder.getOutputBuffer(outputBufferIndex);//                        outputBuffer.position(mBufferInfo.offset);//                        outputBuffer.limit(mBufferInfo.offset + outBitsSize);//                        byte[] outData = new byte[outPacketSize];//                        addADTStoPacket(outData, outPacketSize);//                        outputBuffer.get(outData, 7, outBitsSize);//                        outputBuffer.position(mBufferInfo.offset);//                        mFileStream.write(outData);                        ByteBuffer outputBuffer = mEncorder.getOutputBuffer(outputBufferIndex);                        int outBufferSize = outputBuffer.limit() + 7;                        byte[] aacBytes = new byte[outBufferSize];                        addADTStoPacket(aacBytes, outBufferSize);                        outputBuffer.get(aacBytes, 7, outputBuffer.limit());                        mFileStream.write(aacBytes);                        mEncorder.releaseOutputBuffer(outputBufferIndex, false);                        outputBufferIndex = mEncorder.dequeueOutputBuffer(mBufferInfo, 0);                    }                    long b=System.currentTimeMillis()-a;                    Log.i(tag,"编码耗时-毫秒=="+b);                }                release();            } catch (FileNotFoundException e) {                e.printStackTrace();            } catch (IOException e) {                e.printStackTrace();            }        }        /**         * 停止编码         */        public void stopEncording() {            isEncording = false;        }        /**         * 从队列中取出一帧待编码的音频数据         *         * @return         */        public AudioData getAudioData() {            if (queue != null) {                try {                    return (AudioData) queue.take();                } catch (InterruptedException e) {                    e.printStackTrace();                }            }            return null;        }        /**         *  Add ADTS header at the beginning of each and every AAC packet.         *  This is needed as MediaCodec encoder generates a packet of raw         *  AAC data.         *         *  Note the packetLen must count in the ADTS header itself !!! .         *注意,这里的packetLen参数为raw aac Packet Len + 7; 7 bytes adts header         **/        private void addADTStoPacket(byte[] packet, int packetLen) {            int profile = 2;  //AAC LC,MediaCodecInfo.CodecProfileLevel.AACObjectLC;            int freqIdx = 4;  //见后面注释avpriv_mpeg4audio_sample_rates中32000对应的数组下标,来自ffmpeg源码            int chanCfg = 1;  //见后面注释channel_configuration,AudioFormat.CHANNEL_IN_MONO 单声道(声道数量)        /*int avpriv_mpeg4audio_sample_rates[] = {96000, 88200, 64000, 48000, 44100, 32000,24000, 22050, 16000, 12000, 11025, 8000, 7350};        channel_configuration: 表示声道数chanCfg        0: Defined in AOT Specifc Config        1: 1 channel: front-center        2: 2 channels: front-left, front-right        3: 3 channels: front-center, front-left, front-right        4: 4 channels: front-center, front-left, front-right, back-center        5: 5 channels: front-center, front-left, front-right, back-left, back-right        6: 6 channels: front-center, front-left, front-right, back-left, back-right, LFE-channel        7: 8 channels: front-center, front-left, front-right, side-left, side-right, back-left, back-right, LFE-channel        8-15: Reserved        */            // fill in ADTS data            packet[0] = (byte)0xFF;            //packet[1] = (byte)0xF9;            packet[1] = (byte)0xF1;//解决ios 不能播放问题            packet[2] = (byte)(((profile-1)<<6) + (freqIdx<<2) +(chanCfg>>2));            packet[3] = (byte)(((chanCfg&3)<<6) + (packetLen>>11));            packet[4] = (byte)((packetLen&0x7FF) >> 3);            packet[5] = (byte)(((packetLen&7)<<5) + 0x1F);            packet[6] = (byte)0xFC;        }        /**         * 释放资源         */        public void release() {            if (mFileStream != null) {                try {                    mFileStream.flush();                    mFileStream.close();                } catch (IOException e) {                    e.printStackTrace();                }            }            if (mEncorder != null) {                mEncorder.stop();            }        }    }}

 

更多相关文章

  1. Android拍照、录像、录音代码范例
  2. android 录音
  3. Android音频系统之音量控制详解(Android(安卓)5.1)
  4. 如何向android程序添加音效或者音频文件
  5. Android支持的音频格式
  6. 快速的APK厂商快速和免费的Android应用软件,而无需编码技巧
  7. 快速的APK制作简易免费的Android应用软件,而无需编码技巧
  8. Android(安卓)二维码开发功能实现(四)------基于Zxing实现编码功
  9. Pro Android(安卓)Media:5 Android音频处理入门

随机推荐

  1. Android(安卓)培训计划:如何从功能机时代
  2. [置顶] Android异步更新UI-线程池-Future
  3. 代码中进行RelativeLayout布局的修改添加
  4. Android中的JSON详细总结
  5. Android凭什么斩杀苹果: 硬件繁荣 开源系
  6. [置顶] 关于android安装sdk时找不到jdk的
  7. Android应用性能剖析全攻略
  8. 深入解析:Android热修复技术选择和原理
  9. Android中常用的位图操作(View与Bitmap转
  10. 【Android 开发】:UI控件之 Menu 菜单的的