Home | History | Annotate | Download | only in voiceengine
      1 /*
      2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
      3  *
      4  *  Use of this source code is governed by a BSD-style license
      5  *  that can be found in the LICENSE file in the root of the source
      6  *  tree. An additional intellectual property rights grant can be found
      7  *  in the file PATENTS.  All contributing project authors may
      8  *  be found in the AUTHORS file in the root of the source tree.
      9  */
     10 
     11 package org.webrtc.voiceengine;
     12 
     13 import java.nio.ByteBuffer;
     14 import java.util.concurrent.locks.ReentrantLock;
     15 
     16 import android.content.Context;
     17 import android.media.AudioFormat;
     18 import android.media.AudioManager;
     19 import android.media.AudioRecord;
     20 import android.media.MediaRecorder.AudioSource;
     21 import android.util.Log;
     22 
     23 class WebRtcAudioRecord {
     24     private AudioRecord _audioRecord = null;
     25 
     26     private Context _context;
     27 
     28     private ByteBuffer _recBuffer;
     29     private byte[] _tempBufRec;
     30 
     31     private final ReentrantLock _recLock = new ReentrantLock();
     32 
     33     private boolean _doRecInit = true;
     34     private boolean _isRecording = false;
     35 
     36     private int _bufferedRecSamples = 0;
     37 
     38     WebRtcAudioRecord() {
     39         try {
     40             _recBuffer = ByteBuffer.allocateDirect(2 * 480); // Max 10 ms @ 48
     41                                                              // kHz
     42         } catch (Exception e) {
     43             DoLog(e.getMessage());
     44         }
     45 
     46         _tempBufRec = new byte[2 * 480];
     47     }
     48 
     49     @SuppressWarnings("unused")
     50     private int InitRecording(int audioSource, int sampleRate) {
     51         audioSource = AudioSource.VOICE_COMMUNICATION;
     52         // get the minimum buffer size that can be used
     53         int minRecBufSize = AudioRecord.getMinBufferSize(
     54             sampleRate,
     55             AudioFormat.CHANNEL_IN_MONO,
     56             AudioFormat.ENCODING_PCM_16BIT);
     57 
     58         // DoLog("min rec buf size is " + minRecBufSize);
     59 
     60         // double size to be more safe
     61         int recBufSize = minRecBufSize * 2;
     62         // On average half of the samples have been recorded/buffered and the
     63         // recording interval is 1/100s.
     64         _bufferedRecSamples = sampleRate / 200;
     65         // DoLog("rough rec delay set to " + _bufferedRecSamples);
     66 
     67         // release the object
     68         if (_audioRecord != null) {
     69             _audioRecord.release();
     70             _audioRecord = null;
     71         }
     72 
     73         try {
     74             _audioRecord = new AudioRecord(
     75                             audioSource,
     76                             sampleRate,
     77                             AudioFormat.CHANNEL_IN_MONO,
     78                             AudioFormat.ENCODING_PCM_16BIT,
     79                             recBufSize);
     80 
     81         } catch (Exception e) {
     82             DoLog(e.getMessage());
     83             return -1;
     84         }
     85 
     86         // check that the audioRecord is ready to be used
     87         if (_audioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
     88             // DoLog("rec not initialized " + sampleRate);
     89             return -1;
     90         }
     91 
     92         // DoLog("rec sample rate set to " + sampleRate);
     93 
     94         return _bufferedRecSamples;
     95     }
     96 
     97     @SuppressWarnings("unused")
     98     private int StartRecording() {
     99         // start recording
    100         try {
    101             _audioRecord.startRecording();
    102 
    103         } catch (IllegalStateException e) {
    104             e.printStackTrace();
    105             return -1;
    106         }
    107 
    108         _isRecording = true;
    109         return 0;
    110     }
    111 
    112     @SuppressWarnings("unused")
    113     private int StopRecording() {
    114         _recLock.lock();
    115         try {
    116             // only stop if we are recording
    117             if (_audioRecord.getRecordingState() ==
    118               AudioRecord.RECORDSTATE_RECORDING) {
    119                 // stop recording
    120                 try {
    121                     _audioRecord.stop();
    122                 } catch (IllegalStateException e) {
    123                     e.printStackTrace();
    124                     return -1;
    125                 }
    126             }
    127 
    128             // release the object
    129             _audioRecord.release();
    130             _audioRecord = null;
    131 
    132         } finally {
    133             // Ensure we always unlock, both for success, exception or error
    134             // return.
    135             _doRecInit = true;
    136             _recLock.unlock();
    137         }
    138 
    139         _isRecording = false;
    140         return 0;
    141     }
    142 
    143     @SuppressWarnings("unused")
    144     private int RecordAudio(int lengthInBytes) {
    145         _recLock.lock();
    146 
    147         try {
    148             if (_audioRecord == null) {
    149                 return -2; // We have probably closed down while waiting for rec
    150                            // lock
    151             }
    152 
    153             // Set priority, only do once
    154             if (_doRecInit == true) {
    155                 try {
    156                     android.os.Process.setThreadPriority(
    157                         android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
    158                 } catch (Exception e) {
    159                     DoLog("Set rec thread priority failed: " + e.getMessage());
    160                 }
    161                 _doRecInit = false;
    162             }
    163 
    164             int readBytes = 0;
    165             _recBuffer.rewind(); // Reset the position to start of buffer
    166             readBytes = _audioRecord.read(_tempBufRec, 0, lengthInBytes);
    167             // DoLog("read " + readBytes + "from SC");
    168             _recBuffer.put(_tempBufRec);
    169 
    170             if (readBytes != lengthInBytes) {
    171                 // DoLog("Could not read all data from sc (read = " + readBytes
    172                 // + ", length = " + lengthInBytes + ")");
    173                 return -1;
    174             }
    175 
    176         } catch (Exception e) {
    177             DoLogErr("RecordAudio try failed: " + e.getMessage());
    178 
    179         } finally {
    180             // Ensure we always unlock, both for success, exception or error
    181             // return.
    182             _recLock.unlock();
    183         }
    184 
    185         return _bufferedRecSamples;
    186     }
    187 
    188     final String logTag = "WebRTC AD java";
    189 
    190     private void DoLog(String msg) {
    191         Log.d(logTag, msg);
    192     }
    193 
    194     private void DoLogErr(String msg) {
    195         Log.e(logTag, msg);
    196     }
    197 }
    198