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