Androidレコーディング実装(AudioRecord)

10760 ワード

前回はMediaRecorderを使用した録音機能Android録音実装(MediaRecorder)について紹介しましたが、AudioRecordsを使用した録音機能について引き続き見ていきます.
AudioRecord
まず、Androidヘルプドキュメントの簡単な概要を見てみましょう.AndioRecordクラスの主な機能は、プラットフォームの音声を録画してハードウェアで収集した音声を入力できるように、さまざまなJavaアプリケーションがオーディオリソースを管理できるようにすることです.この機能の実現は、「pulling同期」(reading Reading)AudioRecordオブジェクトの音声データによるものである.録音の過程において、アプリケーションが必要とするのは、後の3つのクラスの方法のうちの1つによってAudioRecordオブジェクトの録音データをタイムリーに取得することである.AudioRecordクラスが提供する3つの音声データを取得する方法は、それぞれread(byte[],int,int)であり、 read(short[], int, int), read(ByteBuffer, int).いずれの方法を選択しても,ユーザの音声データを容易に格納するためのフォーマットを事前に設定しておく必要がある.
録音を開始するとき、AudioRecordは関連する音声bufferを初期化する必要があります.このbufferは主に新しい音声データを保存するために使用されます.このbufferのサイズは、オブジェクトの構築中に指定できます.これは、AudioRecordオブジェクトがまだ音声データを読み込まれていない(同期されていない)前に、どのくらいの音(すなわち、一度に録画可能な音声容量)を記録できるかを示しています.音声データは、オーディオハードウェアから読み出され、録音データ全体のサイズを超えない(複数回に分けて読み出される)、すなわちbuffer容量を初期化したデータを読み出すたびに読み出される.
収集作業は簡単で、AudioRecordオブジェクトを構築し、さまざまな構成のパラメータを入力するだけでいいです.一般的に録音の実現の簡単な流れは以下の通りである.
  • オーディオソース:オーディオを収集するデータソースとしてマイクを使用できます.
  • サンプリングレート:1秒の音声データのサンプリング回数、サンプリングレートが高いほど音質が良い.
  • オーディオチャネル:シングルチャネル、デュアルチャネルなど、
  • オーディオフォーマット:一般的にPCMフォーマット、すなわち元のオーディオサンプルを選択する.
  • バッファサイズ:オーディオデータ書き込みバッファの総数は、AudioRecord.getMinBufferSizeは最小のバッファを取得します.(オーディオをバッファに収集し、バッファから読み出す).
  • コードは次のように実装されます.
    public class AudioRecorder {
        private static AudioRecorder audioRecorder;
        //    :    -   
        private final static int AUDIO_INPUT = MediaRecorder.AudioSource.MIC;
        //    
        // 44100      ,          22050,16000,11025
        //          22.05KHz、44.1KHz、48KHz    
        private final static int AUDIO_SAMPLE_RATE = 16000;
        //         
        private final static int AUDIO_CHANNEL = AudioFormat.CHANNEL_IN_MONO;
        //     :PCM  
        private final static int AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
        //      :       
        private int bufferSizeInBytes = 0;
        //     
        private AudioRecord audioRecord;
        //     
        private Status status = Status.STATUS_NO_READY;
        //    
        private String fileName;
        //       
        private List filesName = new ArrayList<>();
    
        private AudioRecorder() {
        }
    
        //    
        public static AudioRecorder getInstance() {
            if (audioRecorder == null) {
                audioRecorder = new AudioRecorder();
            }
            return audioRecorder;
        }
    
        /**
         *       
         */
        public void createAudio(String fileName, int audioSource, int sampleRateInHz, int channelConfig, int audioFormat) {
            //          
            bufferSizeInBytes = AudioRecord.getMinBufferSize(sampleRateInHz,
                    channelConfig, audioFormat);
            audioRecord = new AudioRecord(audioSource, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes);
            this.fileName = fileName;
        }
    
        /**
         *          
         * @param fileName    
         */
        public void createDefaultAudio(String fileName) {
            mContext = ctx;
            mHandler = handler;
            //          
            bufferSizeInBytes = AudioRecord.getMinBufferSize(AUDIO_SAMPLE_RATE,
                    AUDIO_CHANNEL, AUDIO_ENCODING);
            audioRecord = new AudioRecord(AUDIO_INPUT, AUDIO_SAMPLE_RATE, AUDIO_CHANNEL, AUDIO_ENCODING, bufferSizeInBytes);
            this.fileName = fileName;
            status = Status.STATUS_READY;
        }
    
        /**
         *     
         * @param listener       
         */
        public void startRecord(final RecordStreamListener listener) {
    
            if (status == Status.STATUS_NO_READY || TextUtils.isEmpty(fileName)) {
                throw new IllegalStateException("       ,            ~");
            }
            if (status == Status.STATUS_START) {
                throw new IllegalStateException("    ");
            }
            Log.d("AudioRecorder","===startRecord==="+audioRecord.getState());
            audioRecord.startRecording();
    
            new Thread(new Runnable() {
                @Override
                public void run() {
                    writeDataTOFile(listener);
                }
            }).start();
        }
    
        /**
         *     
         */
        public void stopRecord() {
            Log.d("AudioRecorder","===stopRecord===");
            if (status == Status.STATUS_NO_READY || status == Status.STATUS_READY) {
                throw new IllegalStateException("      ");
            } else {
                audioRecord.stop();
                status = Status.STATUS_STOP;
                release();
            }
        }
    
        /**
         *     
         */
        public void canel() {
            filesName.clear();
            fileName = null;
            if (audioRecord != null) {
                audioRecord.release();
                audioRecord = null;
            }
            status = Status.STATUS_NO_READY;
        }
    
        /**
         *     
         */
        public void release() {
            Log.d("AudioRecorder","===release===");
            //       
            try {
                if (filesName.size() > 0) {
                    List filePaths = new ArrayList<>();
                    for (String fileName : filesName) {
                        filePaths.add(FileUtils.getPcmFileAbsolutePath(fileName));
                    }
                    //  
                    filesName.clear();
                    //   pcm     wav  
                    mergePCMFilesToWAVFile(filePaths);
    
                } else {
                    //         filesName.size    0,    fileName null
                    //      NullPointerException
                    //    pcm     wav  
                    //Log.d("AudioRecorder", "=====makePCMFileToWAVFile======");
                    //makePCMFileToWAVFile();
                }
            } catch (IllegalStateException e) {
                throw new IllegalStateException(e.getMessage());
            }
    
            if (audioRecord != null) {
                audioRecord.release();
                audioRecord = null;
            }
            status = Status.STATUS_NO_READY;
        }
    
        /**
         *          
         * @param listener       
         */
        private void writeDataTOFile(RecordStreamListener listener) {
            // new  byte           ,        
            byte[] audiodata = new byte[bufferSizeInBytes];
    
            FileOutputStream fos = null;
            int readsize = 0;
            try {
                String currentFileName = fileName;
                if (status == Status.STATUS_PAUSE) {
                    //                  ,           
                    currentFileName += filesName.size();
                }
                filesName.add(currentFileName);
                File file = new File(FileUtils.getPcmFileAbsolutePath(currentFileName));
                if (file.exists()) {
                    file.delete();
                }
                fos = new FileOutputStream(file);//             
            } catch (IllegalStateException e) {
                Log.e("AudioRecorder", e.getMessage());
                throw new IllegalStateException(e.getMessage());
            } catch (FileNotFoundException e) {
                Log.e("AudioRecorder", e.getMessage());
            }
            //              
            status = Status.STATUS_START;
            while (status == Status.STATUS_START) {
                readsize = audioRecord.read(audiodata, 0, bufferSizeInBytes);
                if (AudioRecord.ERROR_INVALID_OPERATION != readsize && fos != null) {
                    try {
                        fos.write(audiodata);
                        if (listener != null) {
                            //      
                            listener.recordOfByte(audiodata, 0, audiodata.length);
                        }
                    } catch (IOException e) {
                        Log.e("AudioRecorder", e.getMessage());
                    }
                }
            }
            try {
                if (fos != null) {
                    fos.close();//      
                }
            } catch (IOException e) {
                Log.e("AudioRecorder", e.getMessage());
            }
        }
    }
    

    AudioRecorder録音音声データはオーディオハードウェアから読み出され、符号化形式はPCM形式であるが、PCM音声データは、オーディオファイルとして保存されていればプレーヤーで再生できないため、先にコードを書いてデータ符号化および圧縮を実現しなければならない.以下、PCM音声データのWAVファイルへの移行を実現する.
    /**
     *    pcm     wav  
     * @param pcmPath         pcm    
     * @param destinationPath       (wav)
     * @param deletePcmFile          
     * @return
     */
    public static boolean makePCMFileToWAVFile(String pcmPath, String destinationPath, boolean deletePcmFile) {
        byte buffer[] = null;
        int TOTAL_SIZE = 0;
        File file = new File(pcmPath);
        if (!file.exists()) {
            return false;
        }
        TOTAL_SIZE = (int) file.length();
        //     ,     。     16     8000 hz
        WaveHeader header = new WaveHeader();
        //      =      (TOTAL_SIZE) +
        //        (     4      RIFF  fileLength   4  )
        header.fileLength = TOTAL_SIZE + (44 - 8);
        header.FmtHdrLeth = 16;
        header.BitsPerSample = 16;
        header.Channels = 2;
        header.FormatTag = 0x0001;
        header.SamplesPerSec = 8000;
        header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);
        header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
        header.DataHdrLeth = TOTAL_SIZE;
    
        byte[] h = null;
        try {
            h = header.getHeader();
        } catch (IOException e1) {
            Log.e("PcmToWav", e1.getMessage());
            return false;
        }
    
        if (h.length != 44) // WAV  ,     44  ,    44           
            return false;
    
        //        
        File destfile = new File(destinationPath);
        if (destfile.exists())
            destfile.delete();
    
        //    pcm     ,      
        try {
            buffer = new byte[1024 * 4]; // Length of All Files, Total Size
            InputStream inStream = null;
            OutputStream ouStream = null;
    
            ouStream = new BufferedOutputStream(new FileOutputStream(
                    destinationPath));
            ouStream.write(h, 0, h.length);
            inStream = new BufferedInputStream(new FileInputStream(file));
            int size = inStream.read(buffer);
            while (size != -1) {
                ouStream.write(buffer);
                size = inStream.read(buffer);
            }
            inStream.close();
            ouStream.close();
        } catch (FileNotFoundException e) {
            Log.e("PcmToWav", e.getMessage());
            return false;
        } catch (IOException ioe) {
            Log.e("PcmToWav", ioe.getMessage());
            return false;
        }
        if (deletePcmFile) {
            file.delete();
        }
        Log.i("PcmToWav", "makePCMFileToWAVFile  success!" + new SimpleDateFormat("yyyy-MM-dd hh:mm").format(new Date()));
        return true;
    }
    

    まとめ:AudioRecorder録音はMediaRecorderと比較して使用すると面倒になるが、利点も明らかである.AudioRecorder録音時にハードウェアを直接操作してオーディオストリームデータを取得するプロセスはリアルタイム処理であり、コードで各種オーディオのパッケージを実現できるとともに、一時停止機能を実現できる.imhxlブロガーの共有をお勧めしますhttp://blog.csdn.net/imhxl/article/details/52190451 .
    作者:DreamFishリンク:https://www.jianshu.com/p/90c4071c7768出典:簡書の著作権は作者の所有である.商業転載は著者に連絡して許可を得てください.非商業転載は出典を明記してください.